diff options
author | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2016-12-13 02:30:23 +0100 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2016-12-13 02:30:23 +0100 |
commit | 2ecd9abf516e5e4afc482eb0329f9304aed285b4 (patch) | |
tree | a2980c05f50df82d6d043e4e44ecaf2023220870 | |
parent | 698f3e8de2f0104dc80402ea151aae73b946a2d9 (diff) | |
parent | a04b065c010280ed1806c73cb234a2bf657a5ce9 (diff) | |
download | kernel_samsung_smdk4412-2ecd9abf516e5e4afc482eb0329f9304aed285b4.zip kernel_samsung_smdk4412-2ecd9abf516e5e4afc482eb0329f9304aed285b4.tar.gz kernel_samsung_smdk4412-2ecd9abf516e5e4afc482eb0329f9304aed285b4.tar.bz2 |
Merge branch 'cm-13.0' of https://github.com/CyanogenMod/android_kernel_samsung_smdk4412 into replicant-6.0
377 files changed, 33584 insertions, 41171 deletions
diff --git a/Documentation/ABI/testing/sysfs-block-zram b/Documentation/ABI/testing/sysfs-block-zram index c8b3b48..4cba43c 100644 --- a/Documentation/ABI/testing/sysfs-block-zram +++ b/Documentation/ABI/testing/sysfs-block-zram @@ -42,6 +42,36 @@ Description: The invalid_io file is read-only and specifies the number of non-page-size-aligned I/O requests issued to this device. +What: /sys/block/zram<id>/failed_reads +Date: February 2014 +Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> +Description: + The failed_reads file is read-only and specifies the number of + failed reads happened on this device. + +What: /sys/block/zram<id>/failed_writes +Date: February 2014 +Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> +Description: + The failed_writes file is read-only and specifies the number of + failed writes happened on this device. + +What: /sys/block/zram<id>/max_comp_streams +Date: February 2014 +Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> +Description: + The max_comp_streams file is read-write and specifies the + number of backend's zcomp_strm compression streams (number of + concurrent compress operations). + +What: /sys/block/zram<id>/comp_algorithm +Date: February 2014 +Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> +Description: + The comp_algorithm file is read-write and lets to show + available and selected compression algorithms, change + compression algorithm selection. + What: /sys/block/zram<id>/notify_free Date: August 2010 Contact: Nitin Gupta <ngupta@vflare.org> @@ -52,15 +82,6 @@ Description: is freed. This statistic is applicable only when this disk is being used as a swap disk. -What: /sys/block/zram<id>/discard -Date: August 2010 -Contact: Nitin Gupta <ngupta@vflare.org> -Description: - The discard file is read-only and specifies the number of - discard requests received by this device. These requests - provide information to block device regarding blocks which are - no longer used by filesystem. - What: /sys/block/zram<id>/zero_pages Date: August 2010 Contact: Nitin Gupta <ngupta@vflare.org> @@ -96,4 +117,4 @@ Description: overhead, allocated for this disk. So, allocator space efficiency can be calculated using compr_data_size and this statistic. - Unit: bytes
\ No newline at end of file + Unit: bytes diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt new file mode 100644 index 0000000..986b923 --- /dev/null +++ b/Documentation/blockdev/zram.txt @@ -0,0 +1,119 @@ +zram: Compressed RAM based block devices +---------------------------------------- + +Project home: http://compcache.googlecode.com/ + +* Introduction + +The zram module creates RAM based block devices named /dev/zram<id> +(<id> = 0, 1, ...). Pages written to these disks are compressed and stored +in memory itself. These disks allow very fast I/O and compression provides +good amounts of memory savings. Some of the usecases include /tmp storage, +use as swap disks, various caches under /var and maybe many more :) + +Statistics for individual zram devices are exported through sysfs nodes at +/sys/block/zram<id>/ + +* Usage + +Following shows a typical sequence of steps for using zram. + +1) Load Module: + modprobe zram num_devices=4 + This creates 4 devices: /dev/zram{0,1,2,3} + (num_devices parameter is optional. Default: 1) + +2) Set max number of compression streams + Compression backend may use up to max_comp_streams compression streams, + thus allowing up to max_comp_streams concurrent compression operations. + By default, compression backend uses single compression stream. + + Examples: + #show max compression streams number + cat /sys/block/zram0/max_comp_streams + + #set max compression streams number to 3 + echo 3 > /sys/block/zram0/max_comp_streams + +Note: +In order to enable compression backend's multi stream support max_comp_streams +must be initially set to desired concurrency level before ZRAM device +initialisation. Once the device initialised as a single stream compression +backend (max_comp_streams equals to 1), you will see error if you try to change +the value of max_comp_streams because single stream compression backend +implemented as a special case by lock overhead issue and does not support +dynamic max_comp_streams. Only multi stream backend supports dynamic +max_comp_streams adjustment. + +3) Select compression algorithm + Using comp_algorithm device attribute one can see available and + currently selected (shown in square brackets) compression algortithms, + change selected compression algorithm (once the device is initialised + there is no way to change compression algorithm). + + Examples: + #show supported compression algorithms + cat /sys/block/zram0/comp_algorithm + lzo [lz4] + + #select lzo compression algorithm + echo lzo > /sys/block/zram0/comp_algorithm + +4) Set Disksize + Set disk size by writing the value to sysfs node 'disksize'. + The value can be either in bytes or you can use mem suffixes. + Examples: + # Initialize /dev/zram0 with 50MB disksize + echo $((50*1024*1024)) > /sys/block/zram0/disksize + + # Using mem suffixes + echo 256K > /sys/block/zram0/disksize + echo 512M > /sys/block/zram0/disksize + echo 1G > /sys/block/zram0/disksize + +Note: +There is little point creating a zram of greater than twice the size of memory +since we expect a 2:1 compression ratio. Note that zram uses about 0.1% of the +size of the disk when not in use so a huge zram is wasteful. + +5) Activate: + mkswap /dev/zram0 + swapon /dev/zram0 + + mkfs.ext4 /dev/zram1 + mount /dev/zram1 /tmp + +6) Stats: + Per-device statistics are exported as various nodes under + /sys/block/zram<id>/ + disksize + num_reads + num_writes + failed_reads + failed_writes + invalid_io + notify_free + zero_pages + orig_data_size + compr_data_size + mem_used_total + +7) Deactivate: + swapoff /dev/zram0 + umount /dev/zram1 + +8) Reset: + Write any positive value to 'reset' sysfs node + echo 1 > /sys/block/zram0/reset + echo 1 > /sys/block/zram1/reset + + This frees all the memory allocated for the given device and + resets the disksize to zero. You must set the disksize again + before reusing the device. + +Please report any problems at: + - Mailing list: linux-mm-cc at laptop dot org + - Issue tracker: http://code.google.com/p/compcache/issues/list + +Nitin Gupta +ngupta@vflare.org diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index db3b1ab..6b0d098 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -354,6 +354,8 @@ is not associated with a file: [stack] = the stack of the main process [vdso] = the "virtual dynamic shared object", the kernel system call handler + [anon:<name>] = an anonymous mapping that has been + named by userspace or if empty, the mapping is anonymous. @@ -376,6 +378,7 @@ Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 374 kB +Name: name from userspace The first of these lines shows the same information as is displayed for the mapping in /proc/PID/maps. The remaining lines show the size of the mapping @@ -391,6 +394,9 @@ and a page is modified, the file page is replaced by a private anonymous copy. "Swap" shows how much would-be-anonymous memory is also used, but out on swap. +The "Name" field will only be present on a mapping that has been named by +userspace, and will show the name passed in by userspace. + This file is only present if the CONFIG_MMU kernel configuration option is enabled. diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt index 88fd7f5..9330fba 100644 --- a/Documentation/sysctl/fs.txt +++ b/Documentation/sysctl/fs.txt @@ -32,6 +32,8 @@ Currently, these files are in /proc/sys/fs: - nr_open - overflowuid - overflowgid +- pipe-user-pages-hard +- pipe-user-pages-soft - suid_dumpable - super-max - super-nr @@ -157,6 +159,27 @@ The default is 65534. ============================================================== +pipe-user-pages-hard: + +Maximum total number of pages a non-privileged user may allocate for pipes. +Once this limit is reached, no new pipes may be allocated until usage goes +below the limit again. When set to 0, no limit is applied, which is the default +setting. + +============================================================== + +pipe-user-pages-soft: + +Maximum total number of pages a non-privileged user may allocate for pipes +before the pipe size gets limited to a single page. Once this limit is reached, +new pipes will be limited to a single page in size for this user in order to +limit total memory usage, and trying to increase them using fcntl() will be +denied until usage goes below the limit again. The default value allows to +allocate up to 1024 pipes at their default size. When set to 0, no limit is +applied. + +============================================================== + suid_dumpable: This value can be used to query and set the core dump mode for setuid @@ -193,8 +193,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ # Default value for CROSS_COMPILE is not to prefix executables # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile export KBUILD_BUILDHOST := $(SUBARCH) -ARCH ?= arm -CROSS_COMPILE ?= ../../../prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- +ARCH ?= $(SUBARCH) +CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) # Architecture as present in compile.h UTS_MACHINE := $(ARCH) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6799d57..a6725f1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1777,8 +1777,6 @@ config ARM_FLUSH_CONSOLE_ON_RESTART released if it failed to be acquired, which will cause all the pending messages to be flushed. -source "arch/arm/mvp/Kconfig" - endmenu menu "Boot options" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 32d0cc3..f05679a 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -249,7 +249,6 @@ endif core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) core-$(CONFIG_VFP) += arch/arm/vfp/ -core-$(CONFIG_VMWARE_MVP) += arch/arm/mvp/ # If we have a machine-specific directory, then include it in the build. core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ diff --git a/arch/arm/configs/cyanogenmod_d710_defconfig b/arch/arm/configs/cyanogenmod_d710_defconfig index e5945d3..ecc7052 100644 --- a/arch/arm/configs/cyanogenmod_d710_defconfig +++ b/arch/arm/configs/cyanogenmod_d710_defconfig @@ -660,7 +660,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set # CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set -# CONFIG_VMWARE_MVP is not set # # Boot options @@ -1206,7 +1205,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 # CONFIG_SENSORS_LIS3LV02D is not set CONFIG_MISC_DEVICES=y # CONFIG_AD525X_DPOT is not set -# CONFIG_ANDROID_PMEM is not set # CONFIG_INTEL_MID_PTI is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set @@ -2328,7 +2326,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y diff --git a/arch/arm/configs/cyanogenmod_i777_defconfig b/arch/arm/configs/cyanogenmod_i777_defconfig index 49d5e4d..12a6419 100644 --- a/arch/arm/configs/cyanogenmod_i777_defconfig +++ b/arch/arm/configs/cyanogenmod_i777_defconfig @@ -86,12 +86,14 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_RESOURCE_COUNTERS=y CONFIG_CGROUP_MEM_RES_CTLR=y CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y +CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y CONFIG_CGROUP_SCHED=y CONFIG_FAIR_GROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y # CONFIG_BLK_CGROUP is not set # CONFIG_NAMESPACES is not set # CONFIG_SCHED_AUTOGROUP is not set +CONFIG_MM_OWNER=y # CONFIG_SYSFS_DEPRECATED is not set # CONFIG_RELAY is not set CONFIG_BLK_DEV_INITRD=y @@ -103,6 +105,7 @@ CONFIG_RD_GZIP=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set CONFIG_INITRAMFS_COMPRESSION_NONE=y # CONFIG_INITRAMFS_COMPRESSION_GZIP is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -144,6 +147,7 @@ CONFIG_COMPAT_BRK=y CONFIG_SLUB=y # CONFIG_SLOB is not set CONFIG_PROFILING=y +# CONFIG_OPROFILE is not set CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set CONFIG_HAVE_KPROBES=y @@ -452,12 +456,15 @@ CONFIG_PANEL_U1=y # CONFIG_GC1_00_BD is not set # CONFIG_T0_00_BD is not set # CONFIG_T0_04_BD is not set +# CONFIG_KONA_00_BD is not set +# CONFIG_KONA_01_BD is not set # CONFIG_IRON_BD is not set # CONFIG_GRANDE_BD is not set # CONFIG_WRITEBACK_ENABLED is not set # CONFIG_EXYNOS_SOUND_PLATFORM_DATA is not set # CONFIG_JACK_FET is not set # CONFIG_JACK_GROUND_DET is not set +# CONFIG_USE_ADC_DET is not set CONFIG_SAMSUNG_ANALOG_UART_SWITCH=1 # CONFIG_EXYNOS5_DEV_BTS is not set @@ -508,6 +515,7 @@ CONFIG_SEC_LOG=y CONFIG_SEC_LOG_NONCACHED=y CONFIG_SEC_LOG_LAST_KMSG=y CONFIG_EHCI_IRQ_DISTRIBUTION=y +CONFIG_EHCI_MODEM_PORTNUM=2 # # Samsung Modem Feature @@ -531,6 +539,11 @@ CONFIG_SEC_MODEM_U1=y # CONFIG_SEC_MODEM_P8LTE is not set # CONFIG_SEC_MODEM_T0_TD_DUAL is not set # CONFIG_SEC_MODEM_U1_SPR is not set + +# +# Connectivity Feature +# +# CONFIG_GPS_BRCM_475X is not set # CONFIG_BT_CSR8811 is not set CONFIG_BT_BCM4330=y # CONFIG_BT_BCM4334 is not set @@ -549,6 +562,7 @@ CONFIG_BT_MGMT=y CONFIG_USB_CDFS_SUPPORT=y CONFIG_SAMSUNG_PRODUCT_SHIP=y # CONFIG_CORESIGHT_ETM is not set +# CONFIG_MACH_KONA_SENSOR is not set # # Processor Type @@ -662,6 +676,8 @@ CONFIG_VIRT_TO_BUS=y # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 # CONFIG_CLEANCACHE is not set +CONFIG_ZSMALLOC=y +# CONFIG_PGTABLE_MAPPING is not set CONFIG_CMA=y # CONFIG_CMA_DEVELOPEMENT is not set CONFIG_CMA_BEST_FIT=y @@ -673,7 +689,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set # CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set -# CONFIG_VMWARE_MVP is not set # # Boot options @@ -719,6 +734,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE_MAX_DURATION=100 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set CONFIG_CPU_FREQ_GOV_PEGASUSQ=y +# CONFIG_CPU_FREQ_GOV_PEGASUSQ_BOOST is not set # CONFIG_CPU_FREQ_GOV_SLP is not set # CONFIG_CPU_FREQ_DVFS_MONITOR is not set CONFIG_CPU_IDLE=y @@ -763,6 +779,7 @@ CONFIG_EARLYSUSPEND=y # CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set # CONFIG_CONSOLE_EARLYSUSPEND is not set CONFIG_FB_EARLYSUSPEND=y +# CONFIG_HIBERNATION is not set CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y CONFIG_PM_RUNTIME=y @@ -773,6 +790,7 @@ CONFIG_ARCH_HAS_OPP=y CONFIG_PM_OPP=y CONFIG_PM_RUNTIME_CLK=y # CONFIG_SUSPEND_TIME is not set +CONFIG_CPU_PM=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y @@ -1173,6 +1191,14 @@ CONFIG_RFKILL_PM=y # # Device Drivers # +CONFIG_MALI400=y +CONFIG_MALI_VER_R3P2=y +# CONFIG_MALI400_DEBUG is not set +# CONFIG_MALI400_PROFILING is not set +CONFIG_MALI_DVFS=y +CONFIG_MALI400_UMP=y +# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_UMP_DEBUG is not set # # Generic Driver Options @@ -1196,6 +1222,9 @@ CONFIG_SW_SYNC_USER=y # CONFIG_MTD is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +# CONFIG_ZRAM_LZ4_COMPRESS is not set +# CONFIG_ZRAM_DEBUG is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -1216,7 +1245,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 # CONFIG_SENSORS_LIS3LV02D is not set CONFIG_MISC_DEVICES=y # CONFIG_AD525X_DPOT is not set -# CONFIG_ANDROID_PMEM is not set # CONFIG_INTEL_MID_PTI is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set @@ -1253,6 +1281,7 @@ CONFIG_PN544=y # CONFIG_STMPE811_ADC is not set # CONFIG_MPU_SENSORS_MPU3050 is not set # CONFIG_MPU_SENSORS_MPU6050 is not set +CONFIG_UID_CPUTIME=y # CONFIG_C2PORT is not set # @@ -1276,10 +1305,13 @@ CONFIG_UMTS_MODEM_XMM6260=y # CONFIG_UMTS_MODEM_XMM6262 is not set # CONFIG_CDMA_MODEM_CBP71 is not set # CONFIG_CDMA_MODEM_CBP72 is not set +# CONFIG_CDMA_MODEM_CBP82 is not set # CONFIG_LTE_MODEM_CMC221 is not set +# CONFIG_UMTS_MODEM_SS222 is not set # CONFIG_CDMA_MODEM_MDM6600 is not set # CONFIG_TDSCDMA_MODEM_SPRD8803 is not set # CONFIG_GSM_MODEM_ESC6270 is not set +# CONFIG_CDMA_MODEM_QSC6085 is not set # CONFIG_LINK_DEVICE_MIPI is not set # CONFIG_LINK_DEVICE_DPRAM is not set # CONFIG_LINK_DEVICE_PLD is not set @@ -1287,6 +1319,7 @@ CONFIG_UMTS_MODEM_XMM6260=y CONFIG_LINK_DEVICE_HSIC=y # CONFIG_LINK_DEVICE_C2C is not set # CONFIG_LINK_DEVICE_SPI is not set +# CONFIG_BOOT_DEVICE_SPI is not set # CONFIG_WORKQUEUE_FRONT is not set # CONFIG_IPC_CMC22x_OLD_RFS is not set # CONFIG_SIPC_VER_5 is not set @@ -1375,6 +1408,8 @@ CONFIG_WIFI_CONTROL_FUNC=y CONFIG_BCM4330=m # CONFIG_BCM4334 is not set # CONFIG_BCM4335 is not set +# CONFIG_BCM4339 is not set +# CONFIG_BCM4354 is not set # CONFIG_BCM43241 is not set CONFIG_BROADCOM_WIFI=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/fw_bcmdhd.bin" @@ -1465,7 +1500,10 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set -CONFIG_KEYBOARD_CYPRESS_TOUCH=y +# CONFIG_SENSORS_HALL is not set +# CONFIG_KEYBOARD_CYPRESS_TOUCH is not set +CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN=y +CONFIG_TOUCHKEY_BLN=y # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set @@ -1521,8 +1559,12 @@ CONFIG_TOUCHSCREEN_ATMEL_MXT224_U1=y # CONFIG_TOUCHSCREEN_MXT1386 is not set # CONFIG_TOUCHSCREEN_MXT768E is not set # CONFIG_TOUCHSCREEN_SYNAPTICS_S7301 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYS is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_WORKAROUND is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYLED is not set # CONFIG_TOUCHSCREEN_CYTTSP4 is not set # CONFIG_SEC_TOUCHSCREEN_DVFS_LOCK is not set +# CONFIG_SEC_TOUCHSCREEN_SURFACE_TOUCH is not set # CONFIG_KEYPAD_MELFAS_TOUCH is not set # CONFIG_TOUCHSCREEN_ATMEL_MXT540S is not set # CONFIG_INPUT_WACOM is not set @@ -1760,6 +1802,7 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_MAX17043_FUELGAUGE is not set # CONFIG_BATTERY_MAX17042_FUELGAUGE is not set # CONFIG_BATTERY_MAX17047_FUELGAUGE is not set +# CONFIG_BATTERY_MAX17047_C_FUELGAUGE is not set # CONFIG_BATTERY_SMB136_CHARGER is not set # CONFIG_BATTERY_SAMSUNG_P1X is not set # CONFIG_CHARGER_MAX8903 is not set @@ -1983,6 +2026,7 @@ CONFIG_VIDEO_S5K5BAFX=y # CONFIG_VIDEO_S5K4EA is not set # CONFIG_VIDEO_S5C73M3 is not set # CONFIG_VIDEO_SLP_S5C73M3 is not set +# CONFIG_VIDEO_SR130PC20 is not set CONFIG_VIDEO_IMPROVE_STREAMOFF=y CONFIG_CSI_C=y # CONFIG_CSI_D is not set @@ -2049,7 +2093,6 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USB_ZR364XX is not set # CONFIG_USB_STKWEBCAM is not set # CONFIG_USB_S2255 is not set -CONFIG_MALI_400MP_UMP=y CONFIG_VIDEO_SAMSUNG=y CONFIG_VIDEO_SAMSUNG_V4L2=y CONFIG_VIDEO_FIMC=y @@ -2078,6 +2121,8 @@ CONFIG_VIDEO_MFC5X=y CONFIG_VIDEO_MFC_MAX_INSTANCE=4 CONFIG_VIDEO_MFC_MEM_PORT_COUNT=2 # CONFIG_VIDEO_MFC5X_DEBUG is not set +# CONFIG_VIDEO_MALI400MP is not set +# CONFIG_VIDEO_UMP is not set CONFIG_VIDEO_FIMG2D=y # CONFIG_VIDEO_FIMG2D_DEBUG is not set CONFIG_VIDEO_FIMG2D3X=y @@ -2114,19 +2159,12 @@ CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE=y # # Graphics support # -# CONFIG_MALI_VER_BEFORE_R3P2 is not set # CONFIG_DRM is not set CONFIG_ION=y CONFIG_ION_EXYNOS=y CONFIG_ION_EXYNOS_CONTIGHEAP_SIZE=71680 # CONFIG_ION_EXYNOS_CONTIGHEAP_DEBUG is not set -CONFIG_MALI400=y -CONFIG_MALI_VER_R3P2=y -# CONFIG_MALI400_DEBUG is not set -# CONFIG_MALI400_PROFILING is not set -CONFIG_MALI_DVFS=y -CONFIG_MALI400_UMP=y -# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set @@ -2201,6 +2239,7 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_PWM is not set # CONFIG_BACKLIGHT_ADP8860 is not set # CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set # # Display device support @@ -2357,7 +2396,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2663,8 +2702,6 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y # CONFIG_LINE6_USB is not set # CONFIG_VT6656 is not set # CONFIG_IIO is not set -# CONFIG_XVMALLOC is not set -CONFIG_ZRAM=y # CONFIG_FB_SM7XX is not set # CONFIG_LIRC_STAGING is not set # CONFIG_EASYCAP is not set @@ -2706,10 +2743,15 @@ CONFIG_SENSORS_CM3663=y # CONFIG_SENSORS_CM36651 is not set # CONFIG_SENSORS_BH1721 is not set # CONFIG_SENSORS_AL3201 is not set +# CONFIG_SENSORS_K2DH is not set CONFIG_SENSORS_K3DH=y +# CONFIG_SENSOR_K3DH_INPUTDEV is not set CONFIG_SENSORS_K3G=y # CONFIG_SENSORS_LSM330DLC is not set # CONFIG_SENSORS_LPS331 is not set +# CONFIG_SENSORS_YAS532 is not set +# CONFIG_SENSORS_YAS_ORI is not set +CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=0 # CONFIG_SENSORS_SYSFS is not set # CONFIG_SENSORS_SSP is not set # CONFIG_SENSORS_SSP_LSM330 is not set @@ -2824,6 +2866,12 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_PSTORE is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +CONFIG_F2FS_FS=y +# CONFIG_F2FS_STAT_FS is not set +CONFIG_F2FS_FS_XATTR=y +# CONFIG_F2FS_FS_POSIX_ACL is not set +CONFIG_F2FS_FS_SECURITY=y +# CONFIG_F2FS_CHECK_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=m CONFIG_NFS_V3=y @@ -2922,7 +2970,6 @@ CONFIG_NLS_UTF8=y # CONFIG_PRINTK_TIME=y CONFIG_PRINTK_CPU_ID=y -CONFIG_UID_CPUTIME=y # CONFIG_PRINTK_PID is not set CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 CONFIG_ENABLE_WARN_DEPRECATED=y @@ -3139,7 +3186,9 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y # CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set -# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_LZ4=y +# CONFIG_CRYPTO_LZ4HC is not set # # Random Number Generation @@ -3165,6 +3214,10 @@ CONFIG_LIBCRC32C=y CONFIG_AUDIT_GENERIC=y CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y # CONFIG_XZ_DEC is not set # CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y diff --git a/arch/arm/configs/cyanogenmod_i9100_defconfig b/arch/arm/configs/cyanogenmod_i9100_defconfig index 56c3eff..16ec98c 100644 --- a/arch/arm/configs/cyanogenmod_i9100_defconfig +++ b/arch/arm/configs/cyanogenmod_i9100_defconfig @@ -105,6 +105,7 @@ CONFIG_RD_GZIP=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set CONFIG_INITRAMFS_COMPRESSION_NONE=y # CONFIG_INITRAMFS_COMPRESSION_GZIP is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -675,6 +676,8 @@ CONFIG_VIRT_TO_BUS=y # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 # CONFIG_CLEANCACHE is not set +CONFIG_ZSMALLOC=y +# CONFIG_PGTABLE_MAPPING is not set CONFIG_CMA=y # CONFIG_CMA_DEVELOPEMENT is not set CONFIG_CMA_BEST_FIT=y @@ -686,7 +689,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set # CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set -# CONFIG_VMWARE_MVP is not set # # Boot options @@ -732,6 +734,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND_FLEXRATE_MAX_DURATION=100 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set CONFIG_CPU_FREQ_GOV_PEGASUSQ=y +# CONFIG_CPU_FREQ_GOV_PEGASUSQ_BOOST is not set # CONFIG_CPU_FREQ_GOV_SLP is not set # CONFIG_CPU_FREQ_DVFS_MONITOR is not set CONFIG_CPU_IDLE=y @@ -1219,6 +1222,9 @@ CONFIG_SW_SYNC_USER=y # CONFIG_MTD is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +# CONFIG_ZRAM_LZ4_COMPRESS is not set +# CONFIG_ZRAM_DEBUG is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -1239,7 +1245,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 # CONFIG_SENSORS_LIS3LV02D is not set CONFIG_MISC_DEVICES=y # CONFIG_AD525X_DPOT is not set -# CONFIG_ANDROID_PMEM is not set # CONFIG_INTEL_MID_PTI is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set @@ -1300,10 +1305,13 @@ CONFIG_UMTS_MODEM_XMM6260=y # CONFIG_UMTS_MODEM_XMM6262 is not set # CONFIG_CDMA_MODEM_CBP71 is not set # CONFIG_CDMA_MODEM_CBP72 is not set +# CONFIG_CDMA_MODEM_CBP82 is not set # CONFIG_LTE_MODEM_CMC221 is not set +# CONFIG_UMTS_MODEM_SS222 is not set # CONFIG_CDMA_MODEM_MDM6600 is not set # CONFIG_TDSCDMA_MODEM_SPRD8803 is not set # CONFIG_GSM_MODEM_ESC6270 is not set +# CONFIG_CDMA_MODEM_QSC6085 is not set # CONFIG_LINK_DEVICE_MIPI is not set # CONFIG_LINK_DEVICE_DPRAM is not set # CONFIG_LINK_DEVICE_PLD is not set @@ -1311,6 +1319,7 @@ CONFIG_UMTS_MODEM_XMM6260=y CONFIG_LINK_DEVICE_HSIC=y # CONFIG_LINK_DEVICE_C2C is not set # CONFIG_LINK_DEVICE_SPI is not set +# CONFIG_BOOT_DEVICE_SPI is not set # CONFIG_WORKQUEUE_FRONT is not set # CONFIG_IPC_CMC22x_OLD_RFS is not set # CONFIG_SIPC_VER_5 is not set @@ -1492,7 +1501,9 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_SENSORS_HALL is not set -CONFIG_KEYBOARD_CYPRESS_TOUCH=y +# CONFIG_KEYBOARD_CYPRESS_TOUCH is not set +CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN=y +CONFIG_TOUCHKEY_BLN=y # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set @@ -2384,7 +2395,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2690,10 +2701,6 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y # CONFIG_LINE6_USB is not set # CONFIG_VT6656 is not set # CONFIG_IIO is not set -CONFIG_XVMALLOC=y -CONFIG_ZRAM=y -# CONFIG_ZRAM_DEBUG is not set -# CONFIG_ZRAM_FOR_ANDROID is not set # CONFIG_FB_SM7XX is not set # CONFIG_LIRC_STAGING is not set # CONFIG_EASYCAP is not set @@ -3178,7 +3185,9 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y # CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set -# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_LZ4=y +# CONFIG_CRYPTO_LZ4HC is not set # # Random Number Generation @@ -3206,6 +3215,8 @@ CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_LZO_COMPRESS=y CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y # CONFIG_XZ_DEC is not set # CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y diff --git a/arch/arm/configs/cyanogenmod_i925_defconfig b/arch/arm/configs/cyanogenmod_i925_defconfig index 4737aab..08b4ef3 100644 --- a/arch/arm/configs/cyanogenmod_i925_defconfig +++ b/arch/arm/configs/cyanogenmod_i925_defconfig @@ -681,8 +681,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -2429,7 +2427,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2896,7 +2894,7 @@ CONFIG_MOBICORE_SUPPORT=y CONFIG_MOBICORE_API=y CONFIG_IOMMU_SUPPORT=y # CONFIG_FELICA is not set -CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR=m +# CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR is not set # # File systems diff --git a/arch/arm/configs/cyanogenmod_i9300_defconfig b/arch/arm/configs/cyanogenmod_i9300_defconfig index e243ac4..e4d7e46 100644 --- a/arch/arm/configs/cyanogenmod_i9300_defconfig +++ b/arch/arm/configs/cyanogenmod_i9300_defconfig @@ -108,6 +108,7 @@ CONFIG_RD_GZIP=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_CHECK_WARNING_STRICTLY is not set CONFIG_SYSCTL=y @@ -688,9 +689,11 @@ CONFIG_MIGRATION=y CONFIG_ZONE_DMA_FLAG=0 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y -# CONFIG_KSM is not set +CONFIG_KSM=y CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 # CONFIG_CLEANCACHE is not set +CONFIG_ZSMALLOC=y +# CONFIG_PGTABLE_MAPPING is not set CONFIG_CMA=y # CONFIG_CMA_DEVELOPEMENT is not set CONFIG_CMA_BEST_FIT=y @@ -702,7 +705,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -# CONFIG_VMWARE_MVP is not set # # Boot options @@ -1244,6 +1246,9 @@ CONFIG_CMA_AREAS=7 # CONFIG_MTD is not set # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +# CONFIG_ZRAM_DEBUG is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -1327,10 +1332,13 @@ CONFIG_SEC_MODEM=y CONFIG_UMTS_MODEM_XMM6262=y # CONFIG_CDMA_MODEM_CBP71 is not set # CONFIG_CDMA_MODEM_CBP72 is not set +# CONFIG_CDMA_MODEM_CBP82 is not set # CONFIG_LTE_MODEM_CMC221 is not set +# CONFIG_UMTS_MODEM_SS222 is not set # CONFIG_CDMA_MODEM_MDM6600 is not set # CONFIG_TDSCDMA_MODEM_SPRD8803 is not set # CONFIG_GSM_MODEM_ESC6270 is not set +# CONFIG_CDMA_MODEM_QSC6085 is not set # CONFIG_LINK_DEVICE_MIPI is not set # CONFIG_LINK_DEVICE_DPRAM is not set # CONFIG_LINK_DEVICE_PLD is not set @@ -1338,6 +1346,7 @@ CONFIG_UMTS_MODEM_XMM6262=y CONFIG_LINK_DEVICE_HSIC=y # CONFIG_LINK_DEVICE_C2C is not set # CONFIG_LINK_DEVICE_SPI is not set +# CONFIG_BOOT_DEVICE_SPI is not set # CONFIG_WORKQUEUE_FRONT is not set # CONFIG_IPC_CMC22x_OLD_RFS is not set # CONFIG_SIPC_VER_5 is not set @@ -1525,6 +1534,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_SENSORS_HALL is not set CONFIG_KEYBOARD_CYPRESS_TOUCH=y +# CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set @@ -2478,7 +2488,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2866,16 +2876,14 @@ CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d CONFIG_ANDROID_TIMED_OUTPUT=y CONFIG_ANDROID_TIMED_GPIO=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_LMK_ADJ_RBTREE=y # CONFIG_POHMELFS is not set # CONFIG_LINE6_USB is not set # CONFIG_USB_SERIAL_QUATECH2 is not set # CONFIG_USB_SERIAL_QUATECH_USB2 is not set # CONFIG_VT6656 is not set # CONFIG_IIO is not set -CONFIG_XVMALLOC=y -CONFIG_ZRAM=y -# CONFIG_ZRAM_DEBUG is not set -CONFIG_ZRAM_FOR_ANDROID=y # CONFIG_FB_SM7XX is not set # CONFIG_LIRC_STAGING is not set # CONFIG_EASYCAP is not set @@ -3042,35 +3050,7 @@ CONFIG_F2FS_FS_XATTR=y CONFIG_F2FS_FS_POSIX_ACL=y CONFIG_F2FS_FS_SECURITY=y # CONFIG_F2FS_CHECK_FS is not set -CONFIG_NETWORK_FILESYSTEMS=y -CONFIG_NFS_FS=m -CONFIG_NFS_V3=y -# CONFIG_NFS_V3_ACL is not set -CONFIG_NFS_V4=y -# CONFIG_NFS_V4_1 is not set -# CONFIG_NFS_USE_LEGACY_DNS is not set -CONFIG_NFS_USE_KERNEL_DNS=y -# CONFIG_NFS_USE_NEW_IDMAPPER is not set -# CONFIG_NFSD is not set -CONFIG_LOCKD=m -CONFIG_LOCKD_V4=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=m -CONFIG_SUNRPC_GSS=m -# CONFIG_CEPH_FS is not set -CONFIG_CIFS=m -CONFIG_CIFS_STATS=y -CONFIG_CIFS_STATS2=y -CONFIG_CIFS_WEAK_PW_HASH=y -CONFIG_CIFS_UPCALL=y -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -# CONFIG_CIFS_DEBUG2 is not set -CONFIG_CIFS_DFS_UPCALL=y -CONFIG_CIFS_ACL=y -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set # # Partition Types @@ -3358,7 +3338,9 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y # CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set -# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_LZ4=y +# CONFIG_CRYPTO_LZ4HC is not set # # Random Number Generation @@ -3386,6 +3368,8 @@ CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y CONFIG_LZO_COMPRESS=y CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y # CONFIG_XZ_DEC is not set # CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y diff --git a/arch/arm/configs/cyanogenmod_i9305_defconfig b/arch/arm/configs/cyanogenmod_i9305_defconfig index 5c640cc..75b99a1 100755..100644 --- a/arch/arm/configs/cyanogenmod_i9305_defconfig +++ b/arch/arm/configs/cyanogenmod_i9305_defconfig @@ -30,7 +30,6 @@ CONFIG_ARM_PATCH_PHYS_VIRT=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" CONFIG_HAVE_IRQ_WORK=y -CONFIG_IRQ_WORK=y # # General setup @@ -70,6 +69,7 @@ CONFIG_GENERIC_IRQ_CHIP=y # RCU Subsystem # CONFIG_TREE_PREEMPT_RCU=y +# CONFIG_TINY_RCU is not set CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 @@ -106,6 +106,7 @@ CONFIG_RD_GZIP=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_CHECK_WARNING_STRICTLY is not set CONFIG_SYSCTL=y @@ -145,6 +146,7 @@ CONFIG_COMPAT_BRK=y CONFIG_SLUB=y # CONFIG_SLOB is not set CONFIG_PROFILING=y +# CONFIG_OPROFILE is not set CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set CONFIG_HAVE_KPROBES=y @@ -154,7 +156,6 @@ CONFIG_HAVE_DMA_CONTIGUOUS=y CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y CONFIG_HAVE_CLK=y CONFIG_HAVE_DMA_API_DEBUG=y -CONFIG_HAVE_HW_BREAKPOINT=y # # GCOV-based kernel profiling @@ -185,6 +186,8 @@ CONFIG_IOSCHED_ROW=y CONFIG_IOSCHED_SIO=y # CONFIG_DEFAULT_DEADLINE is not set CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_TRYLOCK is not set @@ -422,7 +425,6 @@ CONFIG_SEC_THERMISTOR=y # CONFIG_EXYNOS_SYSREG_PM is not set CONFIG_ANDROID_WIP=y # CONFIG_COMPACTION_RETRY is not set -# CONFIG_COMPACTION_RETRY_DEBUG is not set # # EXYNOS4 Machines @@ -435,11 +437,11 @@ CONFIG_ANDROID_WIP=y # CONFIG_MACH_U1_NA_SPR is not set # CONFIG_MACH_U1_NA_USCC is not set # CONFIG_MACH_U1 is not set +# CONFIG_TARGET_LOCALE_NAATT_TEMP is not set # CONFIG_MACH_PX is not set CONFIG_TARGET_LOCALE_EUR=y # CONFIG_TARGET_LOCALE_LTN is not set # CONFIG_TARGET_LOCALE_KOR is not set -# CONFIG_TARGET_LOCALE_NAATT_TEMP is not set # CONFIG_TARGET_LOCALE_P2EUR_TEMP is not set # CONFIG_TARGET_LOCALE_P2TMO_TEMP is not set # CONFIG_TARGET_LOCALE_NA is not set @@ -456,6 +458,7 @@ CONFIG_MACH_M3=y # CONFIG_MACH_P4NOTE is not set # CONFIG_MACH_GC1 is not set # CONFIG_MACH_T0 is not set +# CONFIG_MACH_KONA is not set # CONFIG_MACH_IRON is not set # CONFIG_MACH_GRANDE is not set # CONFIG_MACH_BAFFIN is not set @@ -464,12 +467,15 @@ CONFIG_MIDAS_COMMON_BD=y # CONFIG_GC1_00_BD is not set # CONFIG_T0_00_BD is not set # CONFIG_T0_04_BD is not set +# CONFIG_KONA_00_BD is not set +# CONFIG_KONA_01_BD is not set # CONFIG_IRON_BD is not set # CONFIG_GRANDE_BD is not set # CONFIG_WRITEBACK_ENABLED is not set # CONFIG_EXYNOS_SOUND_PLATFORM_DATA is not set # CONFIG_JACK_FET is not set # CONFIG_JACK_GROUND_DET is not set +# CONFIG_USE_ADC_DET is not set CONFIG_SAMSUNG_ANALOG_UART_SWITCH=1 # CONFIG_EXYNOS5_DEV_BTS is not set @@ -522,6 +528,11 @@ CONFIG_SEC_LOG=y CONFIG_SEC_LOG_NONCACHED=y CONFIG_SEC_LOG_LAST_KMSG=y # CONFIG_EHCI_IRQ_DISTRIBUTION is not set + +# +# Connectivity Feature +# +# CONFIG_GPS_BRCM_475X is not set # CONFIG_BT_CSR8811 is not set # CONFIG_BT_BCM4330 is not set CONFIG_BT_BCM4334=y @@ -536,10 +547,12 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_QC_MODEM_MDM9X15=y CONFIG_MDM_HSIC_PM=y # CONFIG_EMI_ERROR_RECOVERY is not set +# CONFIG_SIM_DETECT is not set CONFIG_QC_MODEM_M3=y CONFIG_USB_CDFS_SUPPORT=y CONFIG_SAMSUNG_PRODUCT_SHIP=y # CONFIG_CORESIGHT_ETM is not set +# CONFIG_MACH_KONA_SENSOR is not set # # Processor Type @@ -594,6 +607,9 @@ CONFIG_ARM_ERRATA_761320=y # CONFIG_ARM_ERRATA_761171 is not set # CONFIG_ARM_ERRATA_762974 is not set # CONFIG_ARM_ERRATA_763722 is not set +CONFIG_ARM_ERRATA_764369=y +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set CONFIG_ARM_GIC=y CONFIG_PL330=y # CONFIG_FIQ_DEBUGGER is not set @@ -604,8 +620,6 @@ CONFIG_PL330=y # CONFIG_PCI_SYSCALL is not set # CONFIG_ARCH_SUPPORTS_MSI is not set # CONFIG_PCCARD is not set -CONFIG_ARM_ERRATA_764369=y -# CONFIG_PL310_ERRATA_769419 is not set # # Kernel Features @@ -637,14 +651,13 @@ CONFIG_HAVE_ARCH_PFN_VALID=y CONFIG_ARCH_SKIP_SECONDARY_CALIBRATE=y CONFIG_HIGHMEM=y # CONFIG_HIGHPTE is not set -CONFIG_HW_PERF_EVENTS=y CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_HAVE_MEMBLOCK=y CONFIG_PAGEFLAGS_EXTENDED=y -CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_SPLIT_PTLOCK_CPUS=999999 CONFIG_COMPACTION=y CONFIG_MIGRATION=y # CONFIG_PHYS_ADDR_T_64BIT is not set @@ -654,6 +667,7 @@ CONFIG_VIRT_TO_BUS=y # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 # CONFIG_CLEANCACHE is not set +# CONFIG_ZSMALLOC is not set CONFIG_CMA=y # CONFIG_CMA_DEVELOPEMENT is not set CONFIG_CMA_BEST_FIT=y @@ -665,8 +679,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -711,8 +723,9 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set CONFIG_CPU_FREQ_GOV_PEGASUSQ=y +# CONFIG_CPU_FREQ_GOV_PEGASUSQ_BOOST is not set # CONFIG_CPU_FREQ_GOV_SLP is not set -# CONFIG_CPU_FREQ_DVFS_MONITOR is not set +CONFIG_CPU_FREQ_DVFS_MONITOR=y CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_CPU_IDLE_GOV_MENU=y @@ -762,6 +775,7 @@ CONFIG_ARCH_HAS_OPP=y CONFIG_PM_OPP=y CONFIG_PM_RUNTIME_CLK=y # CONFIG_SUSPEND_TIME is not set +CONFIG_CPU_PM=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y @@ -1096,7 +1110,6 @@ CONFIG_XPS=y # Network testing # # CONFIG_NET_PKTGEN is not set -# CONFIG_NET_DROP_MONITOR is not set # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set @@ -1150,6 +1163,7 @@ CONFIG_WIRELESS_EXT_SYSFS=y # CONFIG_LIB80211 is not set # CONFIG_CFG80211_ALLOW_RECONNECT is not set # CONFIG_MAC80211 is not set +# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set # CONFIG_WIMAX is not set CONFIG_RFKILL=y CONFIG_RFKILL_PM=y @@ -1163,6 +1177,14 @@ CONFIG_RFKILL_PM=y # # Device Drivers # +CONFIG_MALI400=y +CONFIG_MALI_VER_R3P2=y +# CONFIG_MALI400_DEBUG is not set +# CONFIG_MALI400_PROFILING is not set +CONFIG_MALI_DVFS=y +CONFIG_MALI400_UMP=y +# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_UMP_DEBUG is not set # # Generic Driver Options @@ -1244,6 +1266,7 @@ CONFIG_MUIC_MAX77693_SUPPORT_CAR_DOCK=y # CONFIG_STMPE811_ADC is not set # CONFIG_MPU_SENSORS_MPU3050 is not set # CONFIG_MPU_SENSORS_MPU6050 is not set +CONFIG_UID_CPUTIME=y # CONFIG_C2PORT is not set # @@ -1344,11 +1367,19 @@ CONFIG_WLAN=y # CONFIG_USB_NET_RNDIS_WLAN is not set CONFIG_WIFI_CONTROL_FUNC=y # CONFIG_ATH_COMMON is not set -CONFIG_BCM4334=m +# CONFIG_B43LEGACY_DMA_AND_PIO_MODE is not set +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set # CONFIG_BCM4330 is not set +CONFIG_BCM4334=m +# CONFIG_BCM4335 is not set +# CONFIG_BCM4339 is not set +# CONFIG_BCM4354 is not set # CONFIG_BCM43241 is not set +CONFIG_BROADCOM_WIFI=y +CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/bcmdhd.cal" CONFIG_BROADCOM_WIFI_RESERVED_MEM=y -# CONFIG_WLAN_COUNTRY_CODE is not set CONFIG_WLAN_REGION_CODE=100 # CONFIG_HOSTAP is not set # CONFIG_IWM is not set @@ -1418,7 +1449,7 @@ CONFIG_SLHC=y # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set # CONFIG_ISDN is not set -# CONFIG_PHONE is not set +CONFIG_PHONE=y # # Input device support @@ -1464,7 +1495,9 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_SENSORS_HALL is not set CONFIG_KEYBOARD_CYPRESS_TOUCH=y +# CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set @@ -1519,8 +1552,12 @@ CONFIG_TOUCHSCREEN_MELFAS=y # CONFIG_TOUCHSCREEN_MXT1386 is not set # CONFIG_TOUCHSCREEN_MXT768E is not set # CONFIG_TOUCHSCREEN_SYNAPTICS_S7301 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYS is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_WORKAROUND is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYLED is not set # CONFIG_TOUCHSCREEN_CYTTSP4 is not set # CONFIG_SEC_TOUCHSCREEN_DVFS_LOCK is not set +# CONFIG_SEC_TOUCHSCREEN_SURFACE_TOUCH is not set # CONFIG_KEYPAD_MELFAS_TOUCH is not set # CONFIG_TOUCHSCREEN_ATMEL_MXT540S is not set # CONFIG_INPUT_WACOM is not set @@ -1760,6 +1797,7 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_MAX17043_FUELGAUGE is not set # CONFIG_BATTERY_MAX17042_FUELGAUGE is not set CONFIG_BATTERY_MAX17047_FUELGAUGE=y +# CONFIG_BATTERY_MAX17047_C_FUELGAUGE is not set # CONFIG_BATTERY_SMB136_CHARGER is not set CONFIG_BATTERY_MAX77693_CHARGER=y CONFIG_BATTERY_WPC_CHARGER=y @@ -1791,10 +1829,103 @@ CONFIG_BATTERY_SAMSUNG=y # CONFIG_SMB328_CHARGER is not set # CONFIG_SMB347_CHARGER is not set # CONFIG_CHARGER_MANAGER is not set -# CONFIG_HWMON is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_S3C is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set CONFIG_THERMAL=y +# CONFIG_THERMAL_HWMON is not set # CONFIG_CPU_THERMAL is not set -# CONFIG_SENSORS_EXYNOS4_TMU is not set +CONFIG_SENSORS_EXYNOS4_TMU=y CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -2012,6 +2143,7 @@ CONFIG_S5K6A3_CSI_D=y CONFIG_VIDEO_S5C73M3=y CONFIG_VIDEO_S5C73M3_SPI=y # CONFIG_VIDEO_SLP_S5C73M3 is not set +# CONFIG_VIDEO_SR130PC20 is not set # CONFIG_VIDEO_IMPROVE_STREAMOFF is not set # @@ -2078,7 +2210,6 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USB_ZR364XX is not set # CONFIG_USB_STKWEBCAM is not set # CONFIG_USB_S2255 is not set -CONFIG_MALI_400MP_UMP=y CONFIG_VIDEO_SAMSUNG=y CONFIG_VIDEO_SAMSUNG_V4L2=y CONFIG_VIDEO_FIMC=y @@ -2107,6 +2238,8 @@ CONFIG_LSI_HDMI_AUDIO_CH_EVENT=y CONFIG_VIDEO_MFC5X=y CONFIG_VIDEO_MFC_MAX_INSTANCE=4 # CONFIG_VIDEO_MFC5X_DEBUG is not set +# CONFIG_VIDEO_MALI400MP is not set +# CONFIG_VIDEO_UMP is not set CONFIG_VIDEO_FIMG2D=y # CONFIG_VIDEO_FIMG2D_DEBUG is not set CONFIG_VIDEO_FIMG2D4X=y @@ -2160,19 +2293,12 @@ CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE=y # # Graphics support # -# CONFIG_MALI_VER_BEFORE_R3P2 is not set # CONFIG_DRM is not set CONFIG_ION=y CONFIG_ION_EXYNOS=y CONFIG_ION_EXYNOS_CONTIGHEAP_SIZE=71680 # CONFIG_ION_EXYNOS_CONTIGHEAP_DEBUG is not set -CONFIG_MALI400=y -CONFIG_MALI_VER_R3P2=y -# CONFIG_MALI400_DEBUG is not set -# CONFIG_MALI400_PROFILING is not set -CONFIG_MALI_DVFS=y -CONFIG_MALI400_UMP=y -# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set @@ -2224,6 +2350,7 @@ CONFIG_FB_S5P_S6E8AA0=y # CONFIG_FB_S5P_S6EVR02 is not set # CONFIG_FB_S5P_S6D6AA1 is not set # CONFIG_FB_S5P_S6E63M0 is not set +# CONFIG_FB_S5P_NT71391 is not set # CONFIG_S6E8AA0_AMS529HA01 is not set CONFIG_S6E8AA0_AMS480GYXX=y CONFIG_AID_DIMMING=y @@ -2233,10 +2360,13 @@ CONFIG_FB_S5P_EXTDSP=y CONFIG_FB_S5P_EXTDSP_NR_BUFFERS=3 # CONFIG_S5P_DSIM_SWITCHABLE_DUAL_LCD is not set # CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_CARMINE_DRAM_EVAL is not set +# CONFIG_CARMINE_DRAM_CUSTOM is not set # CONFIG_FB_TMIO is not set # CONFIG_FB_UDL is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX_PCI_GDC is not set # CONFIG_FB_BROADSHEET is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y @@ -2258,6 +2388,7 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_PWM is not set # CONFIG_BACKLIGHT_ADP8860 is not set # CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LP855X is not set # # Display device support @@ -2419,7 +2550,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2457,6 +2588,8 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_HWA_HCD is not set # CONFIG_USB_S3C_OTG_HOST is not set # CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MUSB_HOST is not set +# CONFIG_USB_MUSB_PERIPHERAL is not set # # USB Device Class drivers @@ -2488,7 +2621,6 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_STORAGE_ENE_UB6250 is not set -# CONFIG_USB_UAS is not set # CONFIG_USB_LIBUSUAL is not set # @@ -2592,6 +2724,12 @@ CONFIG_USB_GADGET_SELECTED=y CONFIG_USB_GADGET_S3C_OTGD=y # CONFIG_USB_GADGET_PXA_U2O is not set # CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_CI13XXX_PCI is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LANGWELL is not set +# CONFIG_USB_GADGET_EG20T is not set # CONFIG_USB_GADGET_DUMMY_HCD is not set # @@ -2621,6 +2759,8 @@ CONFIG_USB_DUN_SUPPORT=y # CONFIG_USB_G_MULTI is not set # CONFIG_USB_G_HID is not set # CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_DBGP_PRINTK is not set +# CONFIG_USB_G_DBGP_SERIAL is not set # CONFIG_USB_G_WEBCAM is not set # @@ -2649,6 +2789,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y # CONFIG_SDIO_UART is not set # CONFIG_MMC_TEST is not set CONFIG_MMC_SELECTIVE_PACKED_CMD_POLICY=y +# CONFIG_MMC_CPRM is not set # # MMC/SD/SDIO Host Controller Drivers @@ -2694,6 +2835,7 @@ CONFIG_LEDS_AAT1290A=y # # LED Triggers # +# CONFIG_LEDS_TRIGGER_NOTIFICATION is not set CONFIG_NFC_DEVICES=y # CONFIG_PN544_NFC is not set CONFIG_PN65N_NFC=y @@ -2808,14 +2950,19 @@ CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d CONFIG_ANDROID_TIMED_OUTPUT=y CONFIG_ANDROID_TIMED_GPIO=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_LMK_ADJ_RBTREE=y # CONFIG_POHMELFS is not set # CONFIG_LINE6_USB is not set # CONFIG_USB_SERIAL_QUATECH2 is not set # CONFIG_USB_SERIAL_QUATECH_USB2 is not set # CONFIG_VT6656 is not set # CONFIG_IIO is not set -# CONFIG_XVMALLOC is not set -# CONFIG_ZRAM is not set +# CONFIG_LIS3L02DQ_BUF_KFIFO is not set +# CONFIG_LIS3L02DQ_BUF_RING_SW is not set +# CONFIG_AD2S1210_GPIO_INPUT is not set +# CONFIG_AD2S1210_GPIO_OUTPUT is not set +# CONFIG_AD2S1210_GPIO_NONE is not set # CONFIG_FB_SM7XX is not set # CONFIG_LIRC_STAGING is not set # CONFIG_EASYCAP is not set @@ -2855,10 +3002,15 @@ CONFIG_SENSORS_AK8975C=y CONFIG_SENSORS_CM36651=y # CONFIG_SENSORS_BH1721 is not set # CONFIG_SENSORS_AL3201 is not set +# CONFIG_SENSORS_K2DH is not set # CONFIG_SENSORS_K3DH is not set # CONFIG_SENSORS_K3G is not set CONFIG_SENSORS_LSM330DLC=y +CONFIG_SENSORS_LSM330DLC_USE_INPUT_DEV=y CONFIG_SENSORS_LPS331=y +# CONFIG_SENSORS_YAS532 is not set +# CONFIG_SENSORS_YAS_ORI is not set +CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=0 # CONFIG_SENSORS_SYSFS is not set # CONFIG_SENSORS_SSP is not set # CONFIG_SENSORS_SSP_LSM330 is not set @@ -2868,6 +3020,20 @@ CONFIG_SENSORS_LPS331=y # CONFIG_SENSORS_SSP_AT32UC3L0128 is not set # CONFIG_SENSORS_SSP_SENSORHUB is not set # CONFIG_PM_DEVFREQ is not set + +# +# DEVFREQ Governors +# +# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set + +# +# DEVFREQ Drivers +# +# CONFIG_ARM_EXYNOS4_BUS_DEVFREQ is not set +# CONFIG_ARM_EXYNOS4_DISPLAY_DEVFREQ is not set # CONFIG_SAMSUNG_PHONE_SVNET is not set CONFIG_ACCESSORY=y # CONFIG_30PIN_CONN is not set @@ -2878,8 +3044,12 @@ CONFIG_ACCESSORY=y # CONFIG_IR_REMOCON is not set # CONFIG_EXTCON is not set # CONFIG_BARCODE_EMUL is not set +# CONFIG_SAMSUNG_PHONE_TTY is not set +# CONFIG_SAMSUNG_PHONE_TTY_RAFFAELLO is not set +# CONFIG_SAMSUNG_PHONE_TTY_RAFFAELLO_RECOVERY is not set CONFIG_MOBICORE_SUPPORT=y -# CONFIG_MOBICORE_DEBUG is not set +CONFIG_MOBICORE_DEBUG=y +CONFIG_MOBICORE_VERBOSE=y CONFIG_MOBICORE_API=y CONFIG_IOMMU_SUPPORT=y # CONFIG_FELICA is not set @@ -2963,6 +3133,10 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set # CONFIG_LOGFS is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set @@ -2972,9 +3146,13 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set +# CONFIG_ROMFS_BACKED_BY_BLOCK is not set +# CONFIG_ROMFS_BACKED_BY_MTD is not set +# CONFIG_ROMFS_BACKED_BY_BOTH is not set # CONFIG_PSTORE is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=m CONFIG_NFS_V3=y @@ -3072,7 +3250,6 @@ CONFIG_NLS_UTF8=y # CONFIG_PRINTK_TIME=y CONFIG_PRINTK_CPU_ID=y -CONFIG_UID_CPUTIME=y # CONFIG_PRINTK_PID is not set CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 CONFIG_ENABLE_WARN_DEPRECATED=y @@ -3102,11 +3279,12 @@ CONFIG_TIMER_STATS=y # CONFIG_DEBUG_OBJECTS is not set # CONFIG_SLUB_STATS is not set # CONFIG_DEBUG_KMEMLEAK is not set -# CONFIG_DEBUG_PREEMPT is not set -# CONFIG_DEBUG_RT_MUTEXES is not set +CONFIG_DEBUG_PREEMPT=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_PI_LIST=y # CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_MUTEXES is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_LOCK_ALLOC is not set # CONFIG_PROVE_LOCKING is not set # CONFIG_SPARSE_RCU_POINTER is not set @@ -3155,6 +3333,9 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_C_RECORDMCOUNT=y CONFIG_TRACING_SUPPORT=y # CONFIG_FTRACE is not set +# CONFIG_BRANCH_PROFILE_NONE is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set # CONFIG_DYNAMIC_DEBUG is not set # CONFIG_DMA_API_DEBUG is not set # CONFIG_ATOMIC64_SELFTEST is not set @@ -3193,6 +3374,9 @@ CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_SECURITY_APPARMOR is not set # CONFIG_IMA is not set CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +# CONFIG_DEFAULT_SECURITY_APPARMOR is not set # CONFIG_DEFAULT_SECURITY_DAC is not set CONFIG_DEFAULT_SECURITY="selinux" CONFIG_CRYPTO=y @@ -3293,6 +3477,8 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set # # Random Number Generation diff --git a/arch/arm/configs/cyanogenmod_n5100_defconfig b/arch/arm/configs/cyanogenmod_n5100_defconfig index c8fa884..98e0b72 100644 --- a/arch/arm/configs/cyanogenmod_n5100_defconfig +++ b/arch/arm/configs/cyanogenmod_n5100_defconfig @@ -70,6 +70,7 @@ CONFIG_GENERIC_IRQ_CHIP=y # RCU Subsystem # CONFIG_TREE_PREEMPT_RCU=y +# CONFIG_TINY_RCU is not set CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 @@ -107,6 +108,7 @@ CONFIG_RD_GZIP=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_CHECK_WARNING_STRICTLY is not set CONFIG_SYSCTL=y @@ -189,6 +191,8 @@ CONFIG_IOSCHED_ROW=y CONFIG_IOSCHED_SIO=y # CONFIG_DEFAULT_DEADLINE is not set CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_TRYLOCK is not set @@ -219,7 +223,7 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_WRITE_UNLOCK_BH is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -CONFIG_MUTEX_SPIN_ON_OWNER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set CONFIG_FREEZER=y # @@ -355,6 +359,7 @@ CONFIG_S5P_DEV_USB_EHCI=y CONFIG_S5P_DEV_FIMD_S5P=y CONFIG_S5P_DEV_USBGADGET=y CONFIG_S5P_MEM_CMA=y +CONFIG_S5P_DEV_MIPI_DSI=y # CONFIG_S5P_BTS is not set # CONFIG_S3C_DEV_TSI is not set CONFIG_ARCH_EXYNOS4=y @@ -369,7 +374,6 @@ CONFIG_EXYNOS4_LOWPWR_IDLE=y CONFIG_EXYNOS_MCT=y CONFIG_EXYNOS_DEV_PD=y CONFIG_EXYNOS4_DEV_FIMC_LITE=y -CONFIG_EXYNOS4_DEV_FIMC_IS=y CONFIG_EXYNOS4_SETUP_I2C1=y CONFIG_EXYNOS4_SETUP_I2C3=y CONFIG_EXYNOS4_SETUP_I2C4=y @@ -385,13 +389,13 @@ CONFIG_EXYNOS4_SETUP_FIMC0=y CONFIG_EXYNOS4_SETUP_FIMC1=y CONFIG_EXYNOS4_SETUP_FIMC2=y CONFIG_EXYNOS4_SETUP_FIMC3=y -CONFIG_EXYNOS4_SETUP_FIMC_IS=y CONFIG_EXYNOS4_SETUP_USB_PHY=y CONFIG_EXYNOS4_SETUP_CSIS=y CONFIG_EXYNOS4_SETUP_FB_S5P=y CONFIG_EXYNOS4_SETUP_TVOUT=y CONFIG_EXYNOS4_SETUP_THERMAL=y # CONFIG_EXYNOS_SETUP_THERMAL is not set +CONFIG_EXYNOS4_SETUP_MIPI_DSI=y CONFIG_EXYNOS4_SETUP_JPEG=y CONFIG_EXYNOS4_ENABLE_CLOCK_DOWN=y CONFIG_EXYNOS4_CPUFREQ=y @@ -420,7 +424,6 @@ CONFIG_BUSFREQ_QOS_1280X800=y # CONFIG_BUSFREQ_DEBUG is not set # CONFIG_BUSFREQ_L2_160M is not set CONFIG_SEC_THERMISTOR=y -# CONFIG_SEC_SUBTHERMISTOR is not set # CONFIG_EXYNOS_SYSREG_PM is not set CONFIG_ANDROID_WIP=y # CONFIG_COMPACTION_RETRY is not set @@ -449,6 +452,11 @@ CONFIG_TARGET_LOCALE_EUR=y # CONFIG_TARGET_LOCALE_JPN is not set # CONFIG_TARGET_LOCALE_CHN is not set # CONFIG_TARGET_LOCALE_USA is not set +CONFIG_MACH_KONA_EUR_OPEN=y +# CONFIG_MACH_KONA_EUR_WIFI is not set +# CONFIG_MACH_KONA_EUR_LTE is not set +# CONFIG_MACH_KONALTE_USA_ATT is not set +# CONFIG_MACH_KONA_KOR_WIFI is not set # CONFIG_MACH_SMDK4X12 is not set CONFIG_MACH_MIDAS=y # CONFIG_MACH_M0 is not set @@ -458,7 +466,6 @@ CONFIG_MACH_MIDAS=y # CONFIG_MACH_GC1 is not set # CONFIG_MACH_T0 is not set CONFIG_MACH_KONA=y -CONFIG_MACH_KONA_SENSOR=y # CONFIG_MACH_IRON is not set # CONFIG_MACH_GRANDE is not set # CONFIG_MACH_BAFFIN is not set @@ -471,21 +478,12 @@ CONFIG_MACH_KONA_SENSOR=y CONFIG_KONA_01_BD=y # CONFIG_IRON_BD is not set # CONFIG_GRANDE_BD is not set -# CONFIG_SLP is not set -# CONFIG_MACH_REDWOOD is not set -# CONFIG_GPS_BCM47511 is not set -# CONFIG_GPS_BCM4752 is not set -# CONFIG_GPS_GSD4T is not set -# CONFIG_GPIO_NAPLES_00_BD is not set -# CONFIG_SLP_DISP_DEBUG is not set -# CONFIG_EXYNOS4_DEV_TMU is not set -# CONFIG_BT_TIZEN is not set # CONFIG_WRITEBACK_ENABLED is not set CONFIG_EXYNOS_SOUND_PLATFORM_DATA=y -CONFIG_USE_ADC_DET=y # CONFIG_JACK_FET is not set # CONFIG_JACK_GROUND_DET is not set -# CONFIG_SAMSUNG_ANALOG_UART_SWITCH is not set +CONFIG_USE_ADC_DET=y +CONFIG_SAMSUNG_ANALOG_UART_SWITCH=1 # CONFIG_EXYNOS5_DEV_BTS is not set # @@ -522,6 +520,7 @@ CONFIG_EXYNOS4_MSHC_DDR=y # CONFIG_SEC_DEBUG=y CONFIG_SEC_DEBUG_SCHED_LOG=y +# CONFIG_SEC_DEBUG_HRTIMER_LOG is not set # CONFIG_SEC_DEBUG_SOFTIRQ_LOG is not set CONFIG_SEC_DEBUG_SCHED_LOG_NONCACHED=y # CONFIG_SEC_DEBUG_SEMAPHORE_LOG is not set @@ -538,6 +537,7 @@ CONFIG_SEC_LOG=y CONFIG_SEC_LOG_NONCACHED=y CONFIG_SEC_LOG_LAST_KMSG=y CONFIG_EHCI_IRQ_DISTRIBUTION=y +CONFIG_EHCI_MODEM_PORTNUM=2 # # Samsung Modem Feature @@ -565,7 +565,7 @@ CONFIG_SEC_MODEM_M0=y # # Connectivity Feature # -# CONFIG_GPS_BRCM_475X is not set +CONFIG_GPS_BRCM_475X=y # CONFIG_BT_CSR8811 is not set # CONFIG_BT_BCM4330 is not set CONFIG_BT_BCM4334=y @@ -576,14 +576,15 @@ CONFIG_BT_MGMT=y # Qualcomm Modem Feature # # CONFIG_QC_MODEM is not set -# CONFIG_CPU_FREQ_TETHERING is not set # CONFIG_MSM_SUBSYSTEM_RESTART is not set # CONFIG_QC_MODEM_MDM9X15 is not set # CONFIG_MDM_HSIC_PM is not set # CONFIG_EMI_ERROR_RECOVERY is not set +# CONFIG_SIM_DETECT is not set CONFIG_USB_CDFS_SUPPORT=y # CONFIG_SAMSUNG_PRODUCT_SHIP is not set # CONFIG_CORESIGHT_ETM is not set +CONFIG_MACH_KONA_SENSOR=y # # Processor Type @@ -638,6 +639,9 @@ CONFIG_ARM_ERRATA_761320=y # CONFIG_ARM_ERRATA_761171 is not set # CONFIG_ARM_ERRATA_762974 is not set # CONFIG_ARM_ERRATA_763722 is not set +CONFIG_ARM_ERRATA_764369=y +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set CONFIG_ARM_GIC=y CONFIG_PL330=y # CONFIG_FIQ_DEBUGGER is not set @@ -648,8 +652,6 @@ CONFIG_PL330=y # CONFIG_PCI_SYSCALL is not set # CONFIG_ARCH_SUPPORTS_MSI is not set # CONFIG_PCCARD is not set -CONFIG_ARM_ERRATA_764369=y -# CONFIG_PL310_ERRATA_769419 is not set # # Kernel Features @@ -698,20 +700,18 @@ CONFIG_VIRT_TO_BUS=y # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 # CONFIG_CLEANCACHE is not set +# CONFIG_ZSMALLOC is not set CONFIG_CMA=y # CONFIG_CMA_DEVELOPEMENT is not set CONFIG_CMA_BEST_FIT=y # CONFIG_DEBUG_VMALLOC is not set -# CONFIG_LOWMEM_CHECK is not set -CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORCE_MAX_ZONEORDER=12 CONFIG_ALIGNMENT_TRAP=y # CONFIG_UACCESS_WITH_MEMCPY is not set # CONFIG_SECCOMP is not set # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -756,6 +756,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set CONFIG_CPU_FREQ_GOV_PEGASUSQ=y +# CONFIG_CPU_FREQ_GOV_PEGASUSQ_BOOST is not set # CONFIG_CPU_FREQ_GOV_SLP is not set CONFIG_CPU_FREQ_DVFS_MONITOR=y CONFIG_CPU_IDLE=y @@ -807,6 +808,7 @@ CONFIG_ARCH_HAS_OPP=y CONFIG_PM_OPP=y CONFIG_PM_RUNTIME_CLK=y # CONFIG_SUSPEND_TIME is not set +CONFIG_CPU_PM=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y @@ -849,6 +851,8 @@ CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_TCP_MD5SIG is not set CONFIG_IPV6=y @@ -1195,6 +1199,7 @@ CONFIG_WIRELESS_EXT_SYSFS=y # CONFIG_LIB80211 is not set # CONFIG_CFG80211_ALLOW_RECONNECT is not set # CONFIG_MAC80211 is not set +# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set # CONFIG_WIMAX is not set CONFIG_RFKILL=y CONFIG_RFKILL_PM=y @@ -1208,6 +1213,14 @@ CONFIG_RFKILL_PM=y # # Device Drivers # +CONFIG_MALI400=y +CONFIG_MALI_VER_R3P2=y +# CONFIG_MALI400_DEBUG is not set +# CONFIG_MALI400_PROFILING is not set +CONFIG_MALI_DVFS=y +CONFIG_MALI400_UMP=y +# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_UMP_DEBUG is not set # # Generic Driver Options @@ -1263,7 +1276,6 @@ CONFIG_MISC_DEVICES=y # CONFIG_SENSORS_APDS990X is not set # CONFIG_HMC6352 is not set # CONFIG_SENSORS_AK8975 is not set -# CONFIG_SENSORS_AK8963 is not set # CONFIG_DS1682 is not set # CONFIG_TI_DAC7512 is not set CONFIG_UID_STAT=y @@ -1273,19 +1285,24 @@ CONFIG_UID_STAT=y # CONFIG_JACK_MON is not set # CONFIG_UART_SELECT is not set # CONFIG_SWITCH_DUAL_MODEM is not set -# CONFIG_SWITCH_USB_PATH_AUTO is not set # CONFIG_WIMAX_CMC is not set # CONFIG_SEC_DEV_JACK is not set # CONFIG_MUIC_DET_JACK is not set # CONFIG_FM34_WE395 is not set # CONFIG_AUDIENCE_ES305 is not set # CONFIG_2MIC_FM34_WE395 is not set +# CONFIG_MUIC_MAX77693_SEPARATE_MHL_PORT is not set +CONFIG_MUIC_MAX77693_SUPPORT_OTG_AUDIO_DOCK=y +CONFIG_MUIC_MAX77693_SUPPORT_SMART_DOCK=y +# CONFIG_MUIC_MAX77693_SUPPORT_CAR_DOCK is not set # CONFIG_USBHUB_USB3503 is not set # CONFIG_USBHUB_USB3503_OTG_CONN is not set # CONFIG_USBHUB_USB3803 is not set # CONFIG_PN544 is not set +# CONFIG_STMPE811_ADC is not set # CONFIG_MPU_SENSORS_MPU3050 is not set # CONFIG_MPU_SENSORS_MPU6050 is not set +CONFIG_UID_CPUTIME=y # CONFIG_C2PORT is not set # @@ -1310,10 +1327,13 @@ CONFIG_SEC_MODEM=y CONFIG_UMTS_MODEM_XMM6262=y # CONFIG_CDMA_MODEM_CBP71 is not set # CONFIG_CDMA_MODEM_CBP72 is not set +# CONFIG_CDMA_MODEM_CBP82 is not set # CONFIG_LTE_MODEM_CMC221 is not set +# CONFIG_UMTS_MODEM_SS222 is not set # CONFIG_CDMA_MODEM_MDM6600 is not set # CONFIG_TDSCDMA_MODEM_SPRD8803 is not set # CONFIG_GSM_MODEM_ESC6270 is not set +# CONFIG_CDMA_MODEM_QSC6085 is not set # CONFIG_LINK_DEVICE_MIPI is not set # CONFIG_LINK_DEVICE_DPRAM is not set # CONFIG_LINK_DEVICE_PLD is not set @@ -1321,13 +1341,13 @@ CONFIG_UMTS_MODEM_XMM6262=y CONFIG_LINK_DEVICE_HSIC=y # CONFIG_LINK_DEVICE_C2C is not set # CONFIG_LINK_DEVICE_SPI is not set +# CONFIG_BOOT_DEVICE_SPI is not set # CONFIG_WORKQUEUE_FRONT is not set # CONFIG_IPC_CMC22x_OLD_RFS is not set # CONFIG_SIPC_VER_5 is not set # CONFIG_SIM_SLOT_SWITCH is not set # CONFIG_LTE_MODEM_CMC220 is not set # CONFIG_INTERNAL_MODEM_IF is not set -# CONFIG_CDMA_MODEM_QSC6085 is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -1408,18 +1428,25 @@ CONFIG_WLAN=y # CONFIG_USB_NET_RNDIS_WLAN is not set CONFIG_WIFI_CONTROL_FUNC=y # CONFIG_ATH_COMMON is not set +# CONFIG_B43LEGACY_DMA_AND_PIO_MODE is not set +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set # CONFIG_BCM4330 is not set CONFIG_BCM4334=m +# CONFIG_BCM4335 is not set +# CONFIG_BCM4339 is not set +# CONFIG_BCM4354 is not set # CONFIG_BCM43241 is not set +CONFIG_BROADCOM_WIFI=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/bcmdhd.cal" CONFIG_BROADCOM_WIFI_RESERVED_MEM=y CONFIG_WLAN_REGION_CODE=100 +CONFIG_WIFI_BROADCOM_COB=y # CONFIG_HOSTAP is not set # CONFIG_IWM is not set # CONFIG_LIBERTAS is not set # CONFIG_MWIFIEX is not set -# CONFIG_LGUIWLAN is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -1481,8 +1508,6 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_SECBRIDGE is not set CONFIG_INPUT_KEYRESET=y # CONFIG_INPUT_FBSUSPEND is not set -# CONFIG_INPUT_MPU6050 is not set -# CONFIG_INPUT_MPU6050_POLLING is not set # # Input Device Drivers @@ -1506,7 +1531,9 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set +CONFIG_SENSORS_HALL=y # CONFIG_KEYBOARD_CYPRESS_TOUCH is not set +# CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set @@ -1564,7 +1591,7 @@ CONFIG_TOUCHSCREEN_SYNAPTICS_S7301=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYS=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_WORKAROUND=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYLED=y -# CONFIG_TOUCHSCREEN_CYPRESS_TMA46X is not set +# CONFIG_TOUCHSCREEN_CYTTSP4 is not set CONFIG_SEC_TOUCHSCREEN_DVFS_LOCK=y CONFIG_SEC_TOUCHSCREEN_SURFACE_TOUCH=y # CONFIG_KEYPAD_MELFAS_TOUCH is not set @@ -1572,27 +1599,6 @@ CONFIG_SEC_TOUCHSCREEN_SURFACE_TOUCH=y CONFIG_INPUT_WACOM=y # CONFIG_EPEN_WACOM_G5SP is not set # CONFIG_EPEN_WACOM_G9PM is not set -CONFIG_EPEN_WACOM_G9PL=y -# CONFIG_RMI4_DEBUG is not set -# CONFIG_RMI4_BUS is not set -# CONFIG_RMI4_GENERIC is not set -# CONFIG_RMI4_F09 is not set -# CONFIG_RMI4_F1A is not set -# CONFIG_RMI4_F11 is not set -# CONFIG_RMI4_VIRTUAL_BUTTONS is not set -# CONFIG_RMI4_F17 is not set -# CONFIG_RMI4_F19 is not set -# CONFIG_RMI4_F21 is not set -# CONFIG_RMI4_F30 is not set -# CONFIG_RMI4_F31 is not set -# CONFIG_RMI4_F34 is not set -# CONFIG_RMI4_F41 is not set -# CONFIG_RMI4_F54 is not set -# CONFIG_RMI4_SMB is not set -# CONFIG_RMI4_I2C is not set -# CONFIG_RMI4_SPI is not set -# CONFIG_RMI4_DEV is not set -# CONFIG_RMI4_FWLIB is not set CONFIG_INPUT_MISC=y # CONFIG_SENSORS_BH1721FVC is not set # CONFIG_INPUT_AD714X is not set @@ -1615,7 +1621,6 @@ CONFIG_INPUT_GPIO=y # CONFIG_INPUT_FLIP is not set # CONFIG_INPUT_KR3DH is not set - # # Hardware I/O ports # @@ -1827,10 +1832,15 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_MAX17042_FUELGAUGE is not set # CONFIG_BATTERY_MAX17047_FUELGAUGE is not set CONFIG_BATTERY_MAX17047_C_FUELGAUGE=y -CONFIG_BATTERY_MAX77693_CHARGER=y # CONFIG_BATTERY_SMB136_CHARGER is not set +CONFIG_BATTERY_MAX77693_CHARGER=y +# CONFIG_BATTERY_WPC_CHARGER is not set # CONFIG_BATTERY_SAMSUNG_P1X is not set +# CONFIG_FUELGAUGE_DUMMY is not set +# CONFIG_FUELGAUGE_MAX17048 is not set +# CONFIG_CHARGER_DUMMY is not set # CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_SMB328 is not set # CONFIG_POWER_SUPPLY_DEBUG is not set # CONFIG_PDA_POWER is not set # CONFIG_TEST_POWER is not set @@ -1853,16 +1863,13 @@ CONFIG_BATTERY_SAMSUNG=y # CONFIG_SMB328_CHARGER is not set # CONFIG_SMB347_CHARGER is not set # CONFIG_CHARGER_MANAGER is not set -CONFIG_SAMSUNG_LPM_MODE=y # CONFIG_HWMON is not set CONFIG_THERMAL=y # CONFIG_CPU_THERMAL is not set # CONFIG_SENSORS_EXYNOS4_TMU is not set CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set -# CONFIG_CHARGER_NCP1851 is not set -# CONFIG_FUELGAUGE_MAX17050 is not set -# CONFIG_FUELGAUGE_MAX17050_COULOMB_COUNTING is not set + # # Watchdog Device Drivers # @@ -2058,12 +2065,6 @@ CONFIG_VIDEO_IR_I2C=y # CONFIG_VIDEO_TVP5150 is not set # CONFIG_VIDEO_TVP7002 is not set # CONFIG_VIDEO_VPX3220 is not set -# CONFIG_VIDEO_S5K3H2 is not set -# CONFIG_VIDEO_S5K3H7 is not set -# CONFIG_VIDEO_S5K4E5 is not set -# CONFIG_VIDEO_S5K6A3 is not set -# CONFIG_S5K6A3_CSI_C is not set -# CONFIG_S5K6A3_CSI_D is not set # CONFIG_VIDEO_M5MO is not set # CONFIG_VIDEO_M9MO is not set # CONFIG_VIDEO_S5K5BAFX is not set @@ -2071,12 +2072,12 @@ CONFIG_VIDEO_IR_I2C=y # CONFIG_VIDEO_SR200PC20 is not set # CONFIG_VIDEO_SR200PC20M is not set CONFIG_VIDEO_ISX012=y -CONFIG_VIDEO_SR130PC20=y # CONFIG_VIDEO_SLP_S5K4ECGX is not set # CONFIG_VIDEO_SLP_DB8131M is not set # CONFIG_VIDEO_S5K4EA is not set # CONFIG_VIDEO_S5C73M3 is not set # CONFIG_VIDEO_SLP_S5C73M3 is not set +CONFIG_VIDEO_SR130PC20=y CONFIG_VIDEO_IMPROVE_STREAMOFF=y # @@ -2143,7 +2144,6 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USB_ZR364XX is not set # CONFIG_USB_STKWEBCAM is not set # CONFIG_USB_S2255 is not set -CONFIG_MALI_400MP_UMP=y CONFIG_VIDEO_SAMSUNG=y CONFIG_VIDEO_SAMSUNG_V4L2=y CONFIG_VIDEO_FIMC=y @@ -2172,6 +2172,8 @@ CONFIG_LSI_HDMI_AUDIO_CH_EVENT=y CONFIG_VIDEO_MFC5X=y CONFIG_VIDEO_MFC_MAX_INSTANCE=4 # CONFIG_VIDEO_MFC5X_DEBUG is not set +# CONFIG_VIDEO_MALI400MP is not set +# CONFIG_VIDEO_UMP is not set CONFIG_VIDEO_FIMG2D=y # CONFIG_VIDEO_FIMG2D_DEBUG is not set CONFIG_VIDEO_FIMG2D4X=y @@ -2193,20 +2195,10 @@ CONFIG_VIDEO_SAMSUNG_MEMSIZE_JPEG=0 CONFIG_VIDEO_SAMSUNG_MEMSIZE_TVOUT=0 CONFIG_VIDEO_EXYNOS=y CONFIG_VIDEO_EXYNOS_MEMSIZE_FIMC_IS=12288 -CONFIG_EXYNOS_MEDIA_DEVICE=y -# CONFIG_VIDEO_EXYNOS_FIMC_LITE is not set - -# -# Reserved memory configurations -# -CONFIG_VIDEO_SAMSUNG_MEMSIZE_FLITE0=10240 -CONFIG_VIDEO_SAMSUNG_MEMSIZE_FLITE1=10240 -# CONFIG_VIDEO_EXYNOS_MIPI_CSIS is not set +# CONFIG_VIDEO_EXYNOS_FIMC_LITE is not set # CONFIG_VIDEO_EXYNOS_TV is not set # CONFIG_VIDEO_EXYNOS_ROTATOR is not set -# CONFIG_VIDEO_EXYNOS_FIMC_IS is not set -# CONFIG_VIDEO_EXYNOS_FIMC_IS_BAYER is not set -CONFIG_MEDIA_EXYNOS=y +# CONFIG_VIDEO_EXYNOS_FIMC_IS is not set CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_VIDEO_MEM2MEM_TESTDEV is not set @@ -2223,29 +2215,14 @@ CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE=y # CONFIG_ISDBT is not set # -# MUIC device -# -# CONFIG_STMPE811_ADC is not set -CONFIG_MUIC_MAX77693_SUPPORT_OTG_AUDIO_DOCK=y -CONFIG_MUIC_MAX77693_SUPPORT_SMART_DOCK=y - -# # Graphics support # -# CONFIG_MALI_VER_BEFORE_R3P2 is not set # CONFIG_DRM is not set CONFIG_ION=y CONFIG_ION_EXYNOS=y CONFIG_ION_EXYNOS_CONTIGHEAP_SIZE=81920 # CONFIG_ION_EXYNOS_CONTIGHEAP_DEBUG is not set -# CONFIG_VITHAR is not set -CONFIG_MALI400=y -CONFIG_MALI_VER_R3P2=y -# CONFIG_MALI400_DEBUG is not set -# CONFIG_MALI400_PROFILING is not set -CONFIG_MALI_DVFS=y -CONFIG_MALI400_UMP=y -# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set @@ -2276,6 +2253,7 @@ CONFIG_FB_S5P_SPLASH_SCREEN=y # CONFIG_FB_S5P_LCD_INIT is not set # CONFIG_FB_S5P_DEBUG is not set CONFIG_FB_S5P_VSYNC_THREAD=y +# CONFIG_FB_S5P_VSYNC_SEND_UEVENTS is not set CONFIG_FB_S5P_VSYNC_SYSFS=y # CONFIG_FB_S5P_TRACE_UNDERRUN is not set CONFIG_FB_S5P_DEFAULT_WINDOW=3 @@ -2284,12 +2262,18 @@ CONFIG_FB_S5P_NR_BUFFERS=2 CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMD=8192 CONFIG_FB_S5P_MDNIE=y CONFIG_FB_MDNIE_PWM=y -CONFIG_FB_EBOOK_PANEL_SCENARIO=y CONFIG_FB_S5P_MIPI_DSIM=y CONFIG_FB_BGRA_ORDER=y # CONFIG_FB_RGBA_ORDER is not set # CONFIG_FB_S5P_S6C1372 is not set # CONFIG_FB_S5P_LD9040 is not set +# CONFIG_FB_S5P_LMS501XX is not set +# CONFIG_FB_S5P_DUMMY_MIPI_LCD is not set +# CONFIG_FB_S5P_S6E8AA0 is not set +# CONFIG_FB_S5P_EA8061 is not set +# CONFIG_FB_S5P_S6EVR02 is not set +# CONFIG_FB_S5P_S6D6AA1 is not set +# CONFIG_FB_S5P_S6E63M0 is not set CONFIG_FB_S5P_NT71391=y # CONFIG_LCD_FREQ_SWITCH is not set CONFIG_FB_S5P_EXTDSP=y @@ -2298,10 +2282,10 @@ CONFIG_FB_S5P_EXTDSP_NR_BUFFERS=3 # CONFIG_S5P_DSIM_SWITCHABLE_DUAL_LCD is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_TMIO is not set -# CONFIG_S5P_MIPI_DSI2 is not set # CONFIG_FB_UDL is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX_PCI_GDC is not set # CONFIG_FB_BROADSHEET is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y @@ -2353,7 +2337,6 @@ CONFIG_SND_JACK=y # CONFIG_SND_VERBOSE_PROCFS is not set # CONFIG_SND_VERBOSE_PRINTK is not set # CONFIG_SND_DEBUG is not set -# CONFIG_SND_DEBUG_VERBOSE is not set # CONFIG_SND_RAWMIDI_SEQ is not set # CONFIG_SND_OPL3_LIB_SEQ is not set # CONFIG_SND_OPL4_LIB_SEQ is not set @@ -2371,6 +2354,7 @@ CONFIG_SND_SOC=y # CONFIG_SND_SOC_CACHE_LZO is not set CONFIG_SND_SOC_SAMSUNG=y CONFIG_SND_SAMSUNG_I2S=y +# CONFIG_SND_SOC_SAMSUNG_MIDAS_WM1811 is not set CONFIG_SND_SOC_SAMSUNG_KONA_WM1811=y # CONFIG_SND_SOC_SAMSUNG_USE_DMA_WRAPPER is not set CONFIG_SND_SOC_SAMSUNG_I2S_SEC=y @@ -2408,7 +2392,6 @@ CONFIG_USB_HID=y # # Special HID drivers # -CONFIG_UHID=y CONFIG_HID_A4TECH=y CONFIG_HID_ACRUX=y # CONFIG_HID_ACRUX_FF is not set @@ -2485,7 +2468,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2554,7 +2537,6 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_STORAGE_ENE_UB6250 is not set -# CONFIG_USB_UAS is not set # CONFIG_USB_LIBUSUAL is not set # @@ -2656,6 +2638,12 @@ CONFIG_USB_GADGET_SELECTED=y CONFIG_USB_GADGET_S3C_OTGD=y # CONFIG_USB_GADGET_PXA_U2O is not set # CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_CI13XXX_PCI is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LANGWELL is not set +# CONFIG_USB_GADGET_EG20T is not set # CONFIG_USB_GADGET_DUMMY_HCD is not set # @@ -2752,12 +2740,14 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_LT3593 is not set # CONFIG_LEDS_SWITCH is not set +# CONFIG_LEDS_MAX77693 is not set # CONFIG_LEDS_AAT1290A is not set # CONFIG_LEDS_TRIGGERS is not set # # LED Triggers # +# CONFIG_LEDS_TRIGGER_NOTIFICATION is not set # CONFIG_NFC_DEVICES is not set CONFIG_SWITCH=y CONFIG_SWITCH_GPIO=y @@ -2870,14 +2860,14 @@ CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d CONFIG_ANDROID_TIMED_OUTPUT=y # CONFIG_ANDROID_TIMED_GPIO is not set CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_LMK_ADJ_RBTREE=y # CONFIG_POHMELFS is not set # CONFIG_LINE6_USB is not set # CONFIG_USB_SERIAL_QUATECH2 is not set # CONFIG_USB_SERIAL_QUATECH_USB2 is not set # CONFIG_VT6656 is not set # CONFIG_IIO is not set -# CONFIG_XVMALLOC is not set -# CONFIG_ZRAM is not set # CONFIG_FB_SM7XX is not set # CONFIG_LIRC_STAGING is not set # CONFIG_EASYCAP is not set @@ -2903,7 +2893,6 @@ CONFIG_CLKDEV_LOOKUP=y CONFIG_VIBETONZ=y CONFIG_MOTOR_DRV_MAX77693=y # CONFIG_MOTOR_DRV_ISA1200 is not set -# CONFIG_MOTOR_DRV_DRV2603 is not set # CONFIG_FM_RADIO is not set CONFIG_SENSORS_CORE=y # CONFIG_SENSORS_AK8975C is not set @@ -2911,10 +2900,7 @@ CONFIG_SENSORS_CORE=y # CONFIG_SENSORS_BMP180 is not set # CONFIG_SENSORS_CM3663 is not set # CONFIG_SENSORS_PAS2M110 is not set -CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=2 # CONFIG_SENSORS_BMA254 is not set -CONFIG_SENSORS_YAS532=y -CONFIG_SENSORS_YAS_ORI=y # CONFIG_SENSORS_TAOS is not set CONFIG_SENSORS_GP2A=y # CONFIG_SENSORS_GP2A_ANALOG is not set @@ -2927,6 +2913,9 @@ CONFIG_SENSOR_K3DH_INPUTDEV=y # CONFIG_SENSORS_K3G is not set # CONFIG_SENSORS_LSM330DLC is not set # CONFIG_SENSORS_LPS331 is not set +CONFIG_SENSORS_YAS532=y +CONFIG_SENSORS_YAS_ORI=y +CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=2 # CONFIG_SENSORS_SYSFS is not set # CONFIG_SENSORS_SSP is not set # CONFIG_SENSORS_SSP_LSM330 is not set @@ -2948,13 +2937,13 @@ CONFIG_IR_REMOCON=y CONFIG_IR_REMOCON_MC96=y # CONFIG_EXTCON is not set # CONFIG_BARCODE_EMUL is not set +# CONFIG_SAMSUNG_PHONE_TTY is not set CONFIG_MOBICORE_SUPPORT=y # CONFIG_MOBICORE_DEBUG is not set CONFIG_MOBICORE_API=y CONFIG_IOMMU_SUPPORT=y # CONFIG_FELICA is not set # CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR is not set -# CONFIG_J4FS is not set # # File systems @@ -2971,6 +2960,7 @@ CONFIG_EXT4_FS_SECURITY=y # CONFIG_EXT4_DEBUG is not set CONFIG_JBD2=y # CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_XFS_FS is not set @@ -3033,6 +3023,10 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set # CONFIG_LOGFS is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set @@ -3042,9 +3036,13 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set +# CONFIG_ROMFS_BACKED_BY_BLOCK is not set +# CONFIG_ROMFS_BACKED_BY_MTD is not set +# CONFIG_ROMFS_BACKED_BY_BOTH is not set # CONFIG_PSTORE is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=m CONFIG_NFS_V3=y @@ -3142,7 +3140,6 @@ CONFIG_NLS_UTF8=y # CONFIG_PRINTK_TIME=y CONFIG_PRINTK_CPU_ID=y -CONFIG_UID_CPUTIME=y # CONFIG_PRINTK_PID is not set CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 CONFIG_ENABLE_WARN_DEPRECATED=y @@ -3288,6 +3285,9 @@ CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_SECURITY_APPARMOR is not set # CONFIG_IMA is not set CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +# CONFIG_DEFAULT_SECURITY_APPARMOR is not set # CONFIG_DEFAULT_SECURITY_DAC is not set CONFIG_DEFAULT_SECURITY="selinux" CONFIG_CRYPTO=y @@ -3388,6 +3388,8 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set # # Random Number Generation @@ -3417,6 +3419,9 @@ CONFIG_ZLIB_DEFLATE=y # CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y CONFIG_TEXTSEARCH=y CONFIG_TEXTSEARCH_KMP=y CONFIG_TEXTSEARCH_BM=y @@ -3426,5 +3431,3 @@ CONFIG_HAS_DMA=y CONFIG_CPU_RMAP=y CONFIG_NLATTR=y # CONFIG_AVERAGE is not set - -CONFIG_SENSORS_HALL=y diff --git a/arch/arm/configs/cyanogenmod_n5110_defconfig b/arch/arm/configs/cyanogenmod_n5110_defconfig index 64c01c7..800b023 100644 --- a/arch/arm/configs/cyanogenmod_n5110_defconfig +++ b/arch/arm/configs/cyanogenmod_n5110_defconfig @@ -70,6 +70,7 @@ CONFIG_GENERIC_IRQ_CHIP=y # RCU Subsystem # CONFIG_TREE_PREEMPT_RCU=y +# CONFIG_TINY_RCU is not set CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 @@ -107,6 +108,7 @@ CONFIG_RD_GZIP=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_CHECK_WARNING_STRICTLY is not set CONFIG_SYSCTL=y @@ -189,6 +191,8 @@ CONFIG_IOSCHED_ROW=y CONFIG_IOSCHED_SIO=y # CONFIG_DEFAULT_DEADLINE is not set CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_TRYLOCK is not set @@ -219,7 +223,7 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_WRITE_UNLOCK_BH is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set -CONFIG_MUTEX_SPIN_ON_OWNER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set CONFIG_FREEZER=y # @@ -355,6 +359,7 @@ CONFIG_S5P_DEV_USB_EHCI=y CONFIG_S5P_DEV_FIMD_S5P=y CONFIG_S5P_DEV_USBGADGET=y CONFIG_S5P_MEM_CMA=y +CONFIG_S5P_DEV_MIPI_DSI=y # CONFIG_S5P_BTS is not set # CONFIG_S3C_DEV_TSI is not set CONFIG_ARCH_EXYNOS4=y @@ -369,7 +374,6 @@ CONFIG_EXYNOS4_LOWPWR_IDLE=y CONFIG_EXYNOS_MCT=y CONFIG_EXYNOS_DEV_PD=y CONFIG_EXYNOS4_DEV_FIMC_LITE=y -CONFIG_EXYNOS4_DEV_FIMC_IS=y CONFIG_EXYNOS4_SETUP_I2C1=y CONFIG_EXYNOS4_SETUP_I2C3=y CONFIG_EXYNOS4_SETUP_I2C4=y @@ -385,13 +389,13 @@ CONFIG_EXYNOS4_SETUP_FIMC0=y CONFIG_EXYNOS4_SETUP_FIMC1=y CONFIG_EXYNOS4_SETUP_FIMC2=y CONFIG_EXYNOS4_SETUP_FIMC3=y -CONFIG_EXYNOS4_SETUP_FIMC_IS=y CONFIG_EXYNOS4_SETUP_USB_PHY=y CONFIG_EXYNOS4_SETUP_CSIS=y CONFIG_EXYNOS4_SETUP_FB_S5P=y CONFIG_EXYNOS4_SETUP_TVOUT=y CONFIG_EXYNOS4_SETUP_THERMAL=y # CONFIG_EXYNOS_SETUP_THERMAL is not set +CONFIG_EXYNOS4_SETUP_MIPI_DSI=y CONFIG_EXYNOS4_SETUP_JPEG=y CONFIG_EXYNOS4_ENABLE_CLOCK_DOWN=y CONFIG_EXYNOS4_CPUFREQ=y @@ -420,7 +424,6 @@ CONFIG_BUSFREQ_QOS_1280X800=y # CONFIG_BUSFREQ_DEBUG is not set # CONFIG_BUSFREQ_L2_160M is not set CONFIG_SEC_THERMISTOR=y -# CONFIG_SEC_SUBTHERMISTOR is not set # CONFIG_EXYNOS_SYSREG_PM is not set CONFIG_ANDROID_WIP=y # CONFIG_COMPACTION_RETRY is not set @@ -449,6 +452,11 @@ CONFIG_TARGET_LOCALE_EUR=y # CONFIG_TARGET_LOCALE_JPN is not set # CONFIG_TARGET_LOCALE_CHN is not set # CONFIG_TARGET_LOCALE_USA is not set +CONFIG_MACH_KONA_EUR_OPEN=y +# CONFIG_MACH_KONA_EUR_WIFI is not set +# CONFIG_MACH_KONA_EUR_LTE is not set +# CONFIG_MACH_KONALTE_USA_ATT is not set +# CONFIG_MACH_KONA_KOR_WIFI is not set # CONFIG_MACH_SMDK4X12 is not set CONFIG_MACH_MIDAS=y # CONFIG_MACH_M0 is not set @@ -458,7 +466,6 @@ CONFIG_MACH_MIDAS=y # CONFIG_MACH_GC1 is not set # CONFIG_MACH_T0 is not set CONFIG_MACH_KONA=y -CONFIG_MACH_KONA_SENSOR=y # CONFIG_MACH_IRON is not set # CONFIG_MACH_GRANDE is not set # CONFIG_MACH_BAFFIN is not set @@ -471,21 +478,12 @@ CONFIG_MACH_KONA_SENSOR=y CONFIG_KONA_01_BD=y # CONFIG_IRON_BD is not set # CONFIG_GRANDE_BD is not set -# CONFIG_SLP is not set -# CONFIG_MACH_REDWOOD is not set -# CONFIG_GPS_BCM47511 is not set -# CONFIG_GPS_BCM4752 is not set -# CONFIG_GPS_GSD4T is not set -# CONFIG_GPIO_NAPLES_00_BD is not set -# CONFIG_SLP_DISP_DEBUG is not set -# CONFIG_EXYNOS4_DEV_TMU is not set -# CONFIG_BT_TIZEN is not set # CONFIG_WRITEBACK_ENABLED is not set CONFIG_EXYNOS_SOUND_PLATFORM_DATA=y -CONFIG_USE_ADC_DET=y # CONFIG_JACK_FET is not set # CONFIG_JACK_GROUND_DET is not set -# CONFIG_SAMSUNG_ANALOG_UART_SWITCH is not set +CONFIG_USE_ADC_DET=y +CONFIG_SAMSUNG_ANALOG_UART_SWITCH=1 # CONFIG_EXYNOS5_DEV_BTS is not set # @@ -539,6 +537,7 @@ CONFIG_SEC_LOG=y CONFIG_SEC_LOG_NONCACHED=y CONFIG_SEC_LOG_LAST_KMSG=y CONFIG_EHCI_IRQ_DISTRIBUTION=y +CONFIG_EHCI_MODEM_PORTNUM=2 # # Samsung Modem Feature @@ -566,7 +565,7 @@ CONFIG_SEC_MODEM_M0=y # # Connectivity Feature # -# CONFIG_GPS_BRCM_475X is not set +CONFIG_GPS_BRCM_475X=y # CONFIG_BT_CSR8811 is not set # CONFIG_BT_BCM4330 is not set CONFIG_BT_BCM4334=y @@ -577,7 +576,6 @@ CONFIG_BT_MGMT=y # Qualcomm Modem Feature # # CONFIG_QC_MODEM is not set -# CONFIG_CPU_FREQ_TETHERING is not set # CONFIG_MSM_SUBSYSTEM_RESTART is not set # CONFIG_QC_MODEM_MDM9X15 is not set # CONFIG_MDM_HSIC_PM is not set @@ -586,6 +584,7 @@ CONFIG_SIM_DETECT=y CONFIG_USB_CDFS_SUPPORT=y # CONFIG_SAMSUNG_PRODUCT_SHIP is not set # CONFIG_CORESIGHT_ETM is not set +CONFIG_MACH_KONA_SENSOR=y # # Processor Type @@ -640,6 +639,9 @@ CONFIG_ARM_ERRATA_761320=y # CONFIG_ARM_ERRATA_761171 is not set # CONFIG_ARM_ERRATA_762974 is not set # CONFIG_ARM_ERRATA_763722 is not set +CONFIG_ARM_ERRATA_764369=y +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set CONFIG_ARM_GIC=y CONFIG_PL330=y # CONFIG_FIQ_DEBUGGER is not set @@ -650,8 +652,6 @@ CONFIG_PL330=y # CONFIG_PCI_SYSCALL is not set # CONFIG_ARCH_SUPPORTS_MSI is not set # CONFIG_PCCARD is not set -CONFIG_ARM_ERRATA_764369=y -# CONFIG_PL310_ERRATA_769419 is not set # # Kernel Features @@ -700,20 +700,18 @@ CONFIG_VIRT_TO_BUS=y # CONFIG_KSM is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 # CONFIG_CLEANCACHE is not set +# CONFIG_ZSMALLOC is not set CONFIG_CMA=y # CONFIG_CMA_DEVELOPEMENT is not set CONFIG_CMA_BEST_FIT=y # CONFIG_DEBUG_VMALLOC is not set -# CONFIG_LOWMEM_CHECK is not set -CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORCE_MAX_ZONEORDER=12 CONFIG_ALIGNMENT_TRAP=y # CONFIG_UACCESS_WITH_MEMCPY is not set # CONFIG_SECCOMP is not set # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -758,6 +756,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set CONFIG_CPU_FREQ_GOV_PEGASUSQ=y +# CONFIG_CPU_FREQ_GOV_PEGASUSQ_BOOST is not set # CONFIG_CPU_FREQ_GOV_SLP is not set CONFIG_CPU_FREQ_DVFS_MONITOR=y CONFIG_CPU_IDLE=y @@ -809,6 +808,7 @@ CONFIG_ARCH_HAS_OPP=y CONFIG_PM_OPP=y CONFIG_PM_RUNTIME_CLK=y # CONFIG_SUSPEND_TIME is not set +CONFIG_CPU_PM=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y @@ -851,6 +851,8 @@ CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_TCP_MD5SIG is not set CONFIG_IPV6=y @@ -1197,6 +1199,7 @@ CONFIG_WIRELESS_EXT_SYSFS=y # CONFIG_LIB80211 is not set # CONFIG_CFG80211_ALLOW_RECONNECT is not set # CONFIG_MAC80211 is not set +# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set # CONFIG_WIMAX is not set CONFIG_RFKILL=y CONFIG_RFKILL_PM=y @@ -1210,6 +1213,14 @@ CONFIG_RFKILL_PM=y # # Device Drivers # +CONFIG_MALI400=y +CONFIG_MALI_VER_R3P2=y +# CONFIG_MALI400_DEBUG is not set +# CONFIG_MALI400_PROFILING is not set +CONFIG_MALI_DVFS=y +CONFIG_MALI400_UMP=y +# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_UMP_DEBUG is not set # # Generic Driver Options @@ -1265,7 +1276,6 @@ CONFIG_MISC_DEVICES=y # CONFIG_SENSORS_APDS990X is not set # CONFIG_HMC6352 is not set # CONFIG_SENSORS_AK8975 is not set -# CONFIG_SENSORS_AK8963 is not set # CONFIG_DS1682 is not set # CONFIG_TI_DAC7512 is not set CONFIG_UID_STAT=y @@ -1275,19 +1285,24 @@ CONFIG_UID_STAT=y # CONFIG_JACK_MON is not set # CONFIG_UART_SELECT is not set # CONFIG_SWITCH_DUAL_MODEM is not set -# CONFIG_SWITCH_USB_PATH_AUTO is not set # CONFIG_WIMAX_CMC is not set # CONFIG_SEC_DEV_JACK is not set # CONFIG_MUIC_DET_JACK is not set # CONFIG_FM34_WE395 is not set # CONFIG_AUDIENCE_ES305 is not set # CONFIG_2MIC_FM34_WE395 is not set +# CONFIG_MUIC_MAX77693_SEPARATE_MHL_PORT is not set +CONFIG_MUIC_MAX77693_SUPPORT_OTG_AUDIO_DOCK=y +CONFIG_MUIC_MAX77693_SUPPORT_SMART_DOCK=y +# CONFIG_MUIC_MAX77693_SUPPORT_CAR_DOCK is not set # CONFIG_USBHUB_USB3503 is not set # CONFIG_USBHUB_USB3503_OTG_CONN is not set # CONFIG_USBHUB_USB3803 is not set # CONFIG_PN544 is not set +# CONFIG_STMPE811_ADC is not set # CONFIG_MPU_SENSORS_MPU3050 is not set # CONFIG_MPU_SENSORS_MPU6050 is not set +CONFIG_UID_CPUTIME=y # CONFIG_C2PORT is not set # @@ -1312,10 +1327,13 @@ CONFIG_SEC_MODEM=y CONFIG_UMTS_MODEM_XMM6262=y # CONFIG_CDMA_MODEM_CBP71 is not set # CONFIG_CDMA_MODEM_CBP72 is not set +# CONFIG_CDMA_MODEM_CBP82 is not set # CONFIG_LTE_MODEM_CMC221 is not set +# CONFIG_UMTS_MODEM_SS222 is not set # CONFIG_CDMA_MODEM_MDM6600 is not set # CONFIG_TDSCDMA_MODEM_SPRD8803 is not set # CONFIG_GSM_MODEM_ESC6270 is not set +# CONFIG_CDMA_MODEM_QSC6085 is not set # CONFIG_LINK_DEVICE_MIPI is not set # CONFIG_LINK_DEVICE_DPRAM is not set # CONFIG_LINK_DEVICE_PLD is not set @@ -1323,13 +1341,13 @@ CONFIG_UMTS_MODEM_XMM6262=y CONFIG_LINK_DEVICE_HSIC=y # CONFIG_LINK_DEVICE_C2C is not set # CONFIG_LINK_DEVICE_SPI is not set +# CONFIG_BOOT_DEVICE_SPI is not set # CONFIG_WORKQUEUE_FRONT is not set # CONFIG_IPC_CMC22x_OLD_RFS is not set # CONFIG_SIPC_VER_5 is not set # CONFIG_SIM_SLOT_SWITCH is not set # CONFIG_LTE_MODEM_CMC220 is not set # CONFIG_INTERNAL_MODEM_IF is not set -# CONFIG_CDMA_MODEM_QSC6085 is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -1410,18 +1428,25 @@ CONFIG_WLAN=y # CONFIG_USB_NET_RNDIS_WLAN is not set CONFIG_WIFI_CONTROL_FUNC=y # CONFIG_ATH_COMMON is not set +# CONFIG_B43LEGACY_DMA_AND_PIO_MODE is not set +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set # CONFIG_BCM4330 is not set CONFIG_BCM4334=m +# CONFIG_BCM4335 is not set +# CONFIG_BCM4339 is not set +# CONFIG_BCM4354 is not set # CONFIG_BCM43241 is not set +CONFIG_BROADCOM_WIFI=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/bcmdhd.cal" CONFIG_BROADCOM_WIFI_RESERVED_MEM=y CONFIG_WLAN_REGION_CODE=100 +CONFIG_WIFI_BROADCOM_COB=y # CONFIG_HOSTAP is not set # CONFIG_IWM is not set # CONFIG_LIBERTAS is not set # CONFIG_MWIFIEX is not set -# CONFIG_LGUIWLAN is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -1483,8 +1508,6 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_SECBRIDGE is not set CONFIG_INPUT_KEYRESET=y # CONFIG_INPUT_FBSUSPEND is not set -# CONFIG_INPUT_MPU6050 is not set -# CONFIG_INPUT_MPU6050_POLLING is not set # # Input Device Drivers @@ -1508,7 +1531,9 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set +CONFIG_SENSORS_HALL=y # CONFIG_KEYBOARD_CYPRESS_TOUCH is not set +# CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set @@ -1566,7 +1591,7 @@ CONFIG_TOUCHSCREEN_SYNAPTICS_S7301=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYS=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_WORKAROUND=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYLED=y -# CONFIG_TOUCHSCREEN_CYPRESS_TMA46X is not set +# CONFIG_TOUCHSCREEN_CYTTSP4 is not set CONFIG_SEC_TOUCHSCREEN_DVFS_LOCK=y CONFIG_SEC_TOUCHSCREEN_SURFACE_TOUCH=y # CONFIG_KEYPAD_MELFAS_TOUCH is not set @@ -1574,27 +1599,6 @@ CONFIG_SEC_TOUCHSCREEN_SURFACE_TOUCH=y CONFIG_INPUT_WACOM=y # CONFIG_EPEN_WACOM_G5SP is not set # CONFIG_EPEN_WACOM_G9PM is not set -CONFIG_EPEN_WACOM_G9PL=y -# CONFIG_RMI4_DEBUG is not set -# CONFIG_RMI4_BUS is not set -# CONFIG_RMI4_GENERIC is not set -# CONFIG_RMI4_F09 is not set -# CONFIG_RMI4_F1A is not set -# CONFIG_RMI4_F11 is not set -# CONFIG_RMI4_VIRTUAL_BUTTONS is not set -# CONFIG_RMI4_F17 is not set -# CONFIG_RMI4_F19 is not set -# CONFIG_RMI4_F21 is not set -# CONFIG_RMI4_F30 is not set -# CONFIG_RMI4_F31 is not set -# CONFIG_RMI4_F34 is not set -# CONFIG_RMI4_F41 is not set -# CONFIG_RMI4_F54 is not set -# CONFIG_RMI4_SMB is not set -# CONFIG_RMI4_I2C is not set -# CONFIG_RMI4_SPI is not set -# CONFIG_RMI4_DEV is not set -# CONFIG_RMI4_FWLIB is not set CONFIG_INPUT_MISC=y # CONFIG_SENSORS_BH1721FVC is not set # CONFIG_INPUT_AD714X is not set @@ -1828,10 +1832,15 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_MAX17042_FUELGAUGE is not set # CONFIG_BATTERY_MAX17047_FUELGAUGE is not set CONFIG_BATTERY_MAX17047_C_FUELGAUGE=y -CONFIG_BATTERY_MAX77693_CHARGER=y # CONFIG_BATTERY_SMB136_CHARGER is not set +CONFIG_BATTERY_MAX77693_CHARGER=y +# CONFIG_BATTERY_WPC_CHARGER is not set # CONFIG_BATTERY_SAMSUNG_P1X is not set +# CONFIG_FUELGAUGE_DUMMY is not set +# CONFIG_FUELGAUGE_MAX17048 is not set +# CONFIG_CHARGER_DUMMY is not set # CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_SMB328 is not set # CONFIG_POWER_SUPPLY_DEBUG is not set # CONFIG_PDA_POWER is not set # CONFIG_TEST_POWER is not set @@ -1854,16 +1863,13 @@ CONFIG_BATTERY_SAMSUNG=y # CONFIG_SMB328_CHARGER is not set # CONFIG_SMB347_CHARGER is not set # CONFIG_CHARGER_MANAGER is not set -CONFIG_SAMSUNG_LPM_MODE=y # CONFIG_HWMON is not set CONFIG_THERMAL=y # CONFIG_CPU_THERMAL is not set # CONFIG_SENSORS_EXYNOS4_TMU is not set CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set -# CONFIG_CHARGER_NCP1851 is not set -# CONFIG_FUELGAUGE_MAX17050 is not set -# CONFIG_FUELGAUGE_MAX17050_COULOMB_COUNTING is not set + # # Watchdog Device Drivers # @@ -2059,12 +2065,6 @@ CONFIG_VIDEO_IR_I2C=y # CONFIG_VIDEO_TVP5150 is not set # CONFIG_VIDEO_TVP7002 is not set # CONFIG_VIDEO_VPX3220 is not set -# CONFIG_VIDEO_S5K3H2 is not set -# CONFIG_VIDEO_S5K3H7 is not set -# CONFIG_VIDEO_S5K4E5 is not set -# CONFIG_VIDEO_S5K6A3 is not set -# CONFIG_S5K6A3_CSI_C is not set -# CONFIG_S5K6A3_CSI_D is not set # CONFIG_VIDEO_M5MO is not set # CONFIG_VIDEO_M9MO is not set # CONFIG_VIDEO_S5K5BAFX is not set @@ -2072,12 +2072,12 @@ CONFIG_VIDEO_IR_I2C=y # CONFIG_VIDEO_SR200PC20 is not set # CONFIG_VIDEO_SR200PC20M is not set CONFIG_VIDEO_ISX012=y -CONFIG_VIDEO_SR130PC20=y # CONFIG_VIDEO_SLP_S5K4ECGX is not set # CONFIG_VIDEO_SLP_DB8131M is not set # CONFIG_VIDEO_S5K4EA is not set # CONFIG_VIDEO_S5C73M3 is not set # CONFIG_VIDEO_SLP_S5C73M3 is not set +CONFIG_VIDEO_SR130PC20=y CONFIG_VIDEO_IMPROVE_STREAMOFF=y # @@ -2144,7 +2144,6 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USB_ZR364XX is not set # CONFIG_USB_STKWEBCAM is not set # CONFIG_USB_S2255 is not set -CONFIG_MALI_400MP_UMP=y CONFIG_VIDEO_SAMSUNG=y CONFIG_VIDEO_SAMSUNG_V4L2=y CONFIG_VIDEO_FIMC=y @@ -2173,6 +2172,8 @@ CONFIG_LSI_HDMI_AUDIO_CH_EVENT=y CONFIG_VIDEO_MFC5X=y CONFIG_VIDEO_MFC_MAX_INSTANCE=4 # CONFIG_VIDEO_MFC5X_DEBUG is not set +# CONFIG_VIDEO_MALI400MP is not set +# CONFIG_VIDEO_UMP is not set CONFIG_VIDEO_FIMG2D=y # CONFIG_VIDEO_FIMG2D_DEBUG is not set CONFIG_VIDEO_FIMG2D4X=y @@ -2194,20 +2195,10 @@ CONFIG_VIDEO_SAMSUNG_MEMSIZE_JPEG=0 CONFIG_VIDEO_SAMSUNG_MEMSIZE_TVOUT=0 CONFIG_VIDEO_EXYNOS=y CONFIG_VIDEO_EXYNOS_MEMSIZE_FIMC_IS=12288 -CONFIG_EXYNOS_MEDIA_DEVICE=y -# CONFIG_VIDEO_EXYNOS_FIMC_LITE is not set - -# -# Reserved memory configurations -# -CONFIG_VIDEO_SAMSUNG_MEMSIZE_FLITE0=10240 -CONFIG_VIDEO_SAMSUNG_MEMSIZE_FLITE1=10240 -# CONFIG_VIDEO_EXYNOS_MIPI_CSIS is not set +# CONFIG_VIDEO_EXYNOS_FIMC_LITE is not set # CONFIG_VIDEO_EXYNOS_TV is not set # CONFIG_VIDEO_EXYNOS_ROTATOR is not set -# CONFIG_VIDEO_EXYNOS_FIMC_IS is not set -# CONFIG_VIDEO_EXYNOS_FIMC_IS_BAYER is not set -CONFIG_MEDIA_EXYNOS=y +# CONFIG_VIDEO_EXYNOS_FIMC_IS is not set CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_VIDEO_MEM2MEM_TESTDEV is not set @@ -2224,29 +2215,14 @@ CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE=y # CONFIG_ISDBT is not set # -# MUIC device -# -# CONFIG_STMPE811_ADC is not set -CONFIG_MUIC_MAX77693_SUPPORT_OTG_AUDIO_DOCK=y -CONFIG_MUIC_MAX77693_SUPPORT_SMART_DOCK=y - -# # Graphics support # -# CONFIG_MALI_VER_BEFORE_R3P2 is not set # CONFIG_DRM is not set CONFIG_ION=y CONFIG_ION_EXYNOS=y CONFIG_ION_EXYNOS_CONTIGHEAP_SIZE=81920 # CONFIG_ION_EXYNOS_CONTIGHEAP_DEBUG is not set -# CONFIG_VITHAR is not set -CONFIG_MALI400=y -CONFIG_MALI_VER_R3P2=y -# CONFIG_MALI400_DEBUG is not set -# CONFIG_MALI400_PROFILING is not set -CONFIG_MALI_DVFS=y -CONFIG_MALI400_UMP=y -# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set @@ -2277,6 +2253,7 @@ CONFIG_FB_S5P_SPLASH_SCREEN=y # CONFIG_FB_S5P_LCD_INIT is not set # CONFIG_FB_S5P_DEBUG is not set CONFIG_FB_S5P_VSYNC_THREAD=y +# CONFIG_FB_S5P_VSYNC_SEND_UEVENTS is not set CONFIG_FB_S5P_VSYNC_SYSFS=y # CONFIG_FB_S5P_TRACE_UNDERRUN is not set CONFIG_FB_S5P_DEFAULT_WINDOW=3 @@ -2285,12 +2262,18 @@ CONFIG_FB_S5P_NR_BUFFERS=2 CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMD=8192 CONFIG_FB_S5P_MDNIE=y CONFIG_FB_MDNIE_PWM=y -CONFIG_FB_EBOOK_PANEL_SCENARIO=y CONFIG_FB_S5P_MIPI_DSIM=y CONFIG_FB_BGRA_ORDER=y # CONFIG_FB_RGBA_ORDER is not set # CONFIG_FB_S5P_S6C1372 is not set # CONFIG_FB_S5P_LD9040 is not set +# CONFIG_FB_S5P_LMS501XX is not set +# CONFIG_FB_S5P_DUMMY_MIPI_LCD is not set +# CONFIG_FB_S5P_S6E8AA0 is not set +# CONFIG_FB_S5P_EA8061 is not set +# CONFIG_FB_S5P_S6EVR02 is not set +# CONFIG_FB_S5P_S6D6AA1 is not set +# CONFIG_FB_S5P_S6E63M0 is not set CONFIG_FB_S5P_NT71391=y # CONFIG_LCD_FREQ_SWITCH is not set CONFIG_FB_S5P_EXTDSP=y @@ -2299,10 +2282,10 @@ CONFIG_FB_S5P_EXTDSP_NR_BUFFERS=3 # CONFIG_S5P_DSIM_SWITCHABLE_DUAL_LCD is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_TMIO is not set -# CONFIG_S5P_MIPI_DSI2 is not set # CONFIG_FB_UDL is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX_PCI_GDC is not set # CONFIG_FB_BROADSHEET is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y @@ -2372,6 +2355,7 @@ CONFIG_SND_SOC=y # CONFIG_SND_SOC_CACHE_LZO is not set CONFIG_SND_SOC_SAMSUNG=y CONFIG_SND_SAMSUNG_I2S=y +# CONFIG_SND_SOC_SAMSUNG_MIDAS_WM1811 is not set CONFIG_SND_SOC_SAMSUNG_KONA_WM1811=y # CONFIG_SND_SOC_SAMSUNG_USE_DMA_WRAPPER is not set CONFIG_SND_SOC_SAMSUNG_I2S_SEC=y @@ -2485,7 +2469,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2554,7 +2538,6 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_STORAGE_ENE_UB6250 is not set -# CONFIG_USB_UAS is not set # CONFIG_USB_LIBUSUAL is not set # @@ -2656,6 +2639,12 @@ CONFIG_USB_GADGET_SELECTED=y CONFIG_USB_GADGET_S3C_OTGD=y # CONFIG_USB_GADGET_PXA_U2O is not set # CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_CI13XXX_PCI is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LANGWELL is not set +# CONFIG_USB_GADGET_EG20T is not set # CONFIG_USB_GADGET_DUMMY_HCD is not set # @@ -2752,12 +2741,14 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_LT3593 is not set # CONFIG_LEDS_SWITCH is not set +# CONFIG_LEDS_MAX77693 is not set # CONFIG_LEDS_AAT1290A is not set # CONFIG_LEDS_TRIGGERS is not set # # LED Triggers # +# CONFIG_LEDS_TRIGGER_NOTIFICATION is not set # CONFIG_NFC_DEVICES is not set CONFIG_SWITCH=y CONFIG_SWITCH_GPIO=y @@ -2870,14 +2861,14 @@ CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d CONFIG_ANDROID_TIMED_OUTPUT=y # CONFIG_ANDROID_TIMED_GPIO is not set CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_LMK_ADJ_RBTREE=y # CONFIG_POHMELFS is not set # CONFIG_LINE6_USB is not set # CONFIG_USB_SERIAL_QUATECH2 is not set # CONFIG_USB_SERIAL_QUATECH_USB2 is not set # CONFIG_VT6656 is not set # CONFIG_IIO is not set -# CONFIG_XVMALLOC is not set -# CONFIG_ZRAM is not set # CONFIG_FB_SM7XX is not set # CONFIG_LIRC_STAGING is not set # CONFIG_EASYCAP is not set @@ -2903,7 +2894,6 @@ CONFIG_CLKDEV_LOOKUP=y CONFIG_VIBETONZ=y CONFIG_MOTOR_DRV_MAX77693=y # CONFIG_MOTOR_DRV_ISA1200 is not set -# CONFIG_MOTOR_DRV_DRV2603 is not set # CONFIG_FM_RADIO is not set CONFIG_SENSORS_CORE=y # CONFIG_SENSORS_AK8975C is not set @@ -2911,10 +2901,7 @@ CONFIG_SENSORS_CORE=y # CONFIG_SENSORS_BMP180 is not set # CONFIG_SENSORS_CM3663 is not set # CONFIG_SENSORS_PAS2M110 is not set -CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=2 # CONFIG_SENSORS_BMA254 is not set -CONFIG_SENSORS_YAS532=y -CONFIG_SENSORS_YAS_ORI=y # CONFIG_SENSORS_TAOS is not set # CONFIG_SENSORS_GP2A is not set # CONFIG_SENSORS_GP2A_ANALOG is not set @@ -2927,6 +2914,9 @@ CONFIG_SENSOR_K3DH_INPUTDEV=y # CONFIG_SENSORS_K3G is not set # CONFIG_SENSORS_LSM330DLC is not set # CONFIG_SENSORS_LPS331 is not set +CONFIG_SENSORS_YAS532=y +CONFIG_SENSORS_YAS_ORI=y +CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=2 # CONFIG_SENSORS_SYSFS is not set # CONFIG_SENSORS_SSP is not set # CONFIG_SENSORS_SSP_LSM330 is not set @@ -2948,13 +2938,13 @@ CONFIG_IR_REMOCON=y CONFIG_IR_REMOCON_MC96=y # CONFIG_EXTCON is not set # CONFIG_BARCODE_EMUL is not set +# CONFIG_SAMSUNG_PHONE_TTY is not set CONFIG_MOBICORE_SUPPORT=y # CONFIG_MOBICORE_DEBUG is not set CONFIG_MOBICORE_API=y CONFIG_IOMMU_SUPPORT=y # CONFIG_FELICA is not set # CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR is not set -# CONFIG_J4FS is not set # # File systems @@ -2971,6 +2961,7 @@ CONFIG_EXT4_FS_SECURITY=y # CONFIG_EXT4_DEBUG is not set CONFIG_JBD2=y # CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_XFS_FS is not set @@ -3033,6 +3024,10 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set # CONFIG_LOGFS is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set @@ -3042,9 +3037,13 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set +# CONFIG_ROMFS_BACKED_BY_BLOCK is not set +# CONFIG_ROMFS_BACKED_BY_MTD is not set +# CONFIG_ROMFS_BACKED_BY_BOTH is not set # CONFIG_PSTORE is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=m CONFIG_NFS_V3=y @@ -3142,7 +3141,6 @@ CONFIG_NLS_UTF8=y # CONFIG_PRINTK_TIME=y CONFIG_PRINTK_CPU_ID=y -CONFIG_UID_CPUTIME=y # CONFIG_PRINTK_PID is not set CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 CONFIG_ENABLE_WARN_DEPRECATED=y @@ -3288,6 +3286,9 @@ CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_SECURITY_APPARMOR is not set # CONFIG_IMA is not set CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +# CONFIG_DEFAULT_SECURITY_APPARMOR is not set # CONFIG_DEFAULT_SECURITY_DAC is not set CONFIG_DEFAULT_SECURITY="selinux" CONFIG_CRYPTO=y @@ -3388,6 +3389,8 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set # # Random Number Generation @@ -3417,6 +3420,9 @@ CONFIG_ZLIB_DEFLATE=y # CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y CONFIG_TEXTSEARCH=y CONFIG_TEXTSEARCH_KMP=y CONFIG_TEXTSEARCH_BM=y @@ -3426,5 +3432,3 @@ CONFIG_HAS_DMA=y CONFIG_CPU_RMAP=y CONFIG_NLATTR=y # CONFIG_AVERAGE is not set - -CONFIG_SENSORS_HALL=y diff --git a/arch/arm/configs/cyanogenmod_n5120_defconfig b/arch/arm/configs/cyanogenmod_n5120_defconfig index 541a128..445e41a 100644 --- a/arch/arm/configs/cyanogenmod_n5120_defconfig +++ b/arch/arm/configs/cyanogenmod_n5120_defconfig @@ -70,6 +70,7 @@ CONFIG_GENERIC_IRQ_CHIP=y # RCU Subsystem # CONFIG_TREE_PREEMPT_RCU=y +# CONFIG_TINY_RCU is not set CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 @@ -107,6 +108,7 @@ CONFIG_RD_GZIP=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_CHECK_WARNING_STRICTLY is not set CONFIG_SYSCTL=y @@ -189,6 +191,8 @@ CONFIG_IOSCHED_ROW=y CONFIG_IOSCHED_SIO=y # CONFIG_DEFAULT_DEADLINE is not set CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_ROW is not set +# CONFIG_DEFAULT_SIO is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_TRYLOCK is not set @@ -355,6 +359,7 @@ CONFIG_S5P_DEV_USB_EHCI=y CONFIG_S5P_DEV_FIMD_S5P=y CONFIG_S5P_DEV_USBGADGET=y CONFIG_S5P_MEM_CMA=y +CONFIG_S5P_DEV_MIPI_DSI=y # CONFIG_S5P_BTS is not set # CONFIG_S3C_DEV_TSI is not set CONFIG_ARCH_EXYNOS4=y @@ -369,7 +374,6 @@ CONFIG_EXYNOS4_LOWPWR_IDLE=y CONFIG_EXYNOS_MCT=y CONFIG_EXYNOS_DEV_PD=y CONFIG_EXYNOS4_DEV_FIMC_LITE=y -CONFIG_EXYNOS4_DEV_FIMC_IS=y CONFIG_EXYNOS4_SETUP_I2C1=y CONFIG_EXYNOS4_SETUP_I2C3=y CONFIG_EXYNOS4_SETUP_I2C4=y @@ -385,13 +389,13 @@ CONFIG_EXYNOS4_SETUP_FIMC0=y CONFIG_EXYNOS4_SETUP_FIMC1=y CONFIG_EXYNOS4_SETUP_FIMC2=y CONFIG_EXYNOS4_SETUP_FIMC3=y -CONFIG_EXYNOS4_SETUP_FIMC_IS=y CONFIG_EXYNOS4_SETUP_USB_PHY=y CONFIG_EXYNOS4_SETUP_CSIS=y CONFIG_EXYNOS4_SETUP_FB_S5P=y CONFIG_EXYNOS4_SETUP_TVOUT=y CONFIG_EXYNOS4_SETUP_THERMAL=y # CONFIG_EXYNOS_SETUP_THERMAL is not set +CONFIG_EXYNOS4_SETUP_MIPI_DSI=y CONFIG_EXYNOS4_SETUP_JPEG=y CONFIG_EXYNOS4_ENABLE_CLOCK_DOWN=y CONFIG_EXYNOS4_CPUFREQ=y @@ -420,7 +424,6 @@ CONFIG_BUSFREQ_QOS_1280X800=y # CONFIG_BUSFREQ_DEBUG is not set # CONFIG_BUSFREQ_L2_160M is not set CONFIG_SEC_THERMISTOR=y -# CONFIG_SEC_SUBTHERMISTOR is not set # CONFIG_EXYNOS_SYSREG_PM is not set CONFIG_ANDROID_WIP=y # CONFIG_COMPACTION_RETRY is not set @@ -449,6 +452,11 @@ CONFIG_TARGET_LOCALE_EUR=y # CONFIG_TARGET_LOCALE_JPN is not set # CONFIG_TARGET_LOCALE_CHN is not set # CONFIG_TARGET_LOCALE_USA is not set +# CONFIG_MACH_KONA_EUR_OPEN is not set +# CONFIG_MACH_KONA_EUR_WIFI is not set +CONFIG_MACH_KONA_EUR_LTE=y +# CONFIG_MACH_KONALTE_USA_ATT is not set +# CONFIG_MACH_KONA_KOR_WIFI is not set # CONFIG_MACH_SMDK4X12 is not set CONFIG_MACH_MIDAS=y # CONFIG_MACH_M0 is not set @@ -458,7 +466,6 @@ CONFIG_MACH_MIDAS=y # CONFIG_MACH_GC1 is not set # CONFIG_MACH_T0 is not set CONFIG_MACH_KONA=y -CONFIG_MACH_KONA_SENSOR=y # CONFIG_MACH_IRON is not set # CONFIG_MACH_GRANDE is not set # CONFIG_MACH_BAFFIN is not set @@ -469,24 +476,14 @@ CONFIG_MACH_KONA_SENSOR=y # CONFIG_T0_04_BD is not set # CONFIG_KONA_00_BD is not set CONFIG_KONA_01_BD=y -CONFIG_MACH_KONA_EUR_LTE=y # CONFIG_IRON_BD is not set # CONFIG_GRANDE_BD is not set -# CONFIG_SLP is not set -# CONFIG_MACH_REDWOOD is not set -# CONFIG_GPS_BCM47511 is not set -# CONFIG_GPS_BCM4752 is not set -# CONFIG_GPS_GSD4T is not set -# CONFIG_GPIO_NAPLES_00_BD is not set -# CONFIG_SLP_DISP_DEBUG is not set -# CONFIG_EXYNOS4_DEV_TMU is not set -# CONFIG_BT_TIZEN is not set # CONFIG_WRITEBACK_ENABLED is not set CONFIG_EXYNOS_SOUND_PLATFORM_DATA=y -CONFIG_USE_ADC_DET=y # CONFIG_JACK_FET is not set # CONFIG_JACK_GROUND_DET is not set -# CONFIG_SAMSUNG_ANALOG_UART_SWITCH is not set +CONFIG_USE_ADC_DET=y +CONFIG_SAMSUNG_ANALOG_UART_SWITCH=1 # CONFIG_EXYNOS5_DEV_BTS is not set # @@ -523,7 +520,6 @@ CONFIG_EXYNOS4_MSHC_DDR=y # CONFIG_SEC_DEBUG=y CONFIG_SEC_DEBUG_SCHED_LOG=y -CONFIG_SEC_DEBUG_HRTIMER_LOG=y # CONFIG_SEC_DEBUG_SOFTIRQ_LOG is not set CONFIG_SEC_DEBUG_SCHED_LOG_NONCACHED=y # CONFIG_SEC_DEBUG_SEMAPHORE_LOG is not set @@ -542,29 +538,6 @@ CONFIG_SEC_LOG_LAST_KMSG=y CONFIG_EHCI_IRQ_DISTRIBUTION=y # -# Samsung Modem Feature -# -# CONFIG_LTE_VIA_SWITCH is not set -# CONFIG_SEC_DUAL_MODEM_MODE is not set -# CONFIG_SEC_MODEM_M0_C2C is not set -# CONFIG_SEC_MODEM_M0 is not set -# CONFIG_SEC_MODEM_M0_CTC is not set -# CONFIG_SEC_MODEM_T0_CU_DUOS is not set -# CONFIG_SEC_MODEM_T0_OPEN_DUOS is not set -# CONFIG_SEC_MODEM_M0_GRANDECTC is not set -# CONFIG_SEC_MODEM_M1 is not set -# CONFIG_SEC_MODEM_C1 is not set -# CONFIG_SEC_MODEM_C1_LGT is not set -# CONFIG_SEC_MODEM_M2 is not set -# CONFIG_SEC_MODEM_U1 is not set -# CONFIG_SEC_MODEM_U1_LGT is not set -# CONFIG_SEC_MODEM_GAIA is not set -# CONFIG_SEC_MODEM_IRON is not set -# CONFIG_SEC_MODEM_P8LTE is not set -# CONFIG_SEC_MODEM_T0_TD_DUAL is not set -# CONFIG_SEC_MODEM_U1_SPR is not set - -# # Connectivity Feature # # CONFIG_GPS_BRCM_475X is not set @@ -578,16 +551,16 @@ CONFIG_BT_MGMT=y # Qualcomm Modem Feature # CONFIG_QC_MODEM=y -# CONFIG_CPU_FREQ_TETHERING is not set -# CONFIG_MSM_SUBSYSTEM_RESTART is not set -# CONFIG_QC_MODEM_MDM9X15 is not set -# CONFIG_MDM_HSIC_PM is not set +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_QC_MODEM_MDM9X15=y +CONFIG_MDM_HSIC_PM=y # CONFIG_EMI_ERROR_RECOVERY is not set CONFIG_SIM_DETECT=y +CONFIG_QC_MODEM_M3=y CONFIG_USB_CDFS_SUPPORT=y -# CONFIG_SAMSUNG_PRODUCT_SHIP is not set +CONFIG_SAMSUNG_PRODUCT_SHIP=y # CONFIG_CORESIGHT_ETM is not set -CONFIG_HSIC_EURONLY_APPLY=y +CONFIG_MACH_KONA_SENSOR=y # # Processor Type @@ -642,6 +615,9 @@ CONFIG_ARM_ERRATA_761320=y # CONFIG_ARM_ERRATA_761171 is not set # CONFIG_ARM_ERRATA_762974 is not set # CONFIG_ARM_ERRATA_763722 is not set +CONFIG_ARM_ERRATA_764369=y +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_ARM_ERRATA_775420 is not set CONFIG_ARM_GIC=y CONFIG_PL330=y # CONFIG_FIQ_DEBUGGER is not set @@ -652,8 +628,6 @@ CONFIG_PL330=y # CONFIG_PCI_SYSCALL is not set # CONFIG_ARCH_SUPPORTS_MSI is not set # CONFIG_PCCARD is not set -CONFIG_ARM_ERRATA_764369=y -# CONFIG_PL310_ERRATA_769419 is not set # # Kernel Features @@ -699,23 +673,21 @@ CONFIG_MIGRATION=y CONFIG_ZONE_DMA_FLAG=0 CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y -# CONFIG_KSM is not set +CONFIG_KSM=y CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 # CONFIG_CLEANCACHE is not set +# CONFIG_ZSMALLOC is not set CONFIG_CMA=y # CONFIG_CMA_DEVELOPEMENT is not set CONFIG_CMA_BEST_FIT=y # CONFIG_DEBUG_VMALLOC is not set -# CONFIG_LOWMEM_CHECK is not set -CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORCE_MAX_ZONEORDER=12 CONFIG_ALIGNMENT_TRAP=y # CONFIG_UACCESS_WITH_MEMCPY is not set # CONFIG_SECCOMP is not set # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -760,6 +732,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set CONFIG_CPU_FREQ_GOV_PEGASUSQ=y +# CONFIG_CPU_FREQ_GOV_PEGASUSQ_BOOST is not set # CONFIG_CPU_FREQ_GOV_SLP is not set CONFIG_CPU_FREQ_DVFS_MONITOR=y CONFIG_CPU_IDLE=y @@ -811,6 +784,7 @@ CONFIG_ARCH_HAS_OPP=y CONFIG_PM_OPP=y CONFIG_PM_RUNTIME_CLK=y # CONFIG_SUSPEND_TIME is not set +CONFIG_CPU_PM=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_NET=y @@ -853,6 +827,8 @@ CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_RENO is not set CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_TCP_MD5SIG is not set CONFIG_IPV6=y @@ -877,6 +853,7 @@ CONFIG_IPV6_TUNNEL=y CONFIG_IPV6_MULTIPLE_TABLES=y # CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set CONFIG_ANDROID_PARANOID_NETWORK=y CONFIG_NET_ACTIVITY_STATS=y CONFIG_NETWORK_SECMARK=y @@ -893,6 +870,7 @@ CONFIG_NETFILTER_NETLINK_QUEUE=y CONFIG_NETFILTER_NETLINK_LOG=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_SECMARK is not set CONFIG_NF_CONNTRACK_EVENTS=y # CONFIG_NF_CONNTRACK_TIMESTAMP is not set CONFIG_NF_CT_PROTO_DCCP=y @@ -923,6 +901,7 @@ CONFIG_NETFILTER_XT_CONNMARK=y # # Xtables targets # +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set # CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y @@ -938,6 +917,7 @@ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y # CONFIG_NETFILTER_XT_TARGET_TEE is not set CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y +# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set CONFIG_NETFILTER_XT_TARGET_TCPMSS=y # CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set @@ -1024,6 +1004,7 @@ CONFIG_IP_NF_MANGLE=y # CONFIG_IP_NF_TARGET_ECN is not set # CONFIG_IP_NF_TARGET_TTL is not set CONFIG_IP_NF_RAW=y +# CONFIG_IP_NF_SECURITY is not set CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y @@ -1050,6 +1031,7 @@ CONFIG_IP6_NF_TARGET_REJECT=y CONFIG_IP6_NF_TARGET_REJECT_SKERR=y CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y +# CONFIG_IP6_NF_SECURITY is not set # CONFIG_IP_DCCP is not set # CONFIG_IP_SCTP is not set # CONFIG_RDS is not set @@ -1193,6 +1175,7 @@ CONFIG_WIRELESS_EXT_SYSFS=y # CONFIG_LIB80211 is not set # CONFIG_CFG80211_ALLOW_RECONNECT is not set # CONFIG_MAC80211 is not set +# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set # CONFIG_WIMAX is not set CONFIG_RFKILL=y CONFIG_RFKILL_PM=y @@ -1206,6 +1189,14 @@ CONFIG_RFKILL_PM=y # # Device Drivers # +CONFIG_MALI400=y +CONFIG_MALI_VER_R3P2=y +# CONFIG_MALI400_DEBUG is not set +# CONFIG_MALI400_PROFILING is not set +CONFIG_MALI_DVFS=y +CONFIG_MALI400_UMP=y +# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_UMP_DEBUG is not set # # Generic Driver Options @@ -1261,7 +1252,6 @@ CONFIG_MISC_DEVICES=y # CONFIG_SENSORS_APDS990X is not set # CONFIG_HMC6352 is not set # CONFIG_SENSORS_AK8975 is not set -# CONFIG_SENSORS_AK8963 is not set # CONFIG_DS1682 is not set # CONFIG_TI_DAC7512 is not set CONFIG_UID_STAT=y @@ -1271,19 +1261,24 @@ CONFIG_UID_STAT=y # CONFIG_JACK_MON is not set # CONFIG_UART_SELECT is not set # CONFIG_SWITCH_DUAL_MODEM is not set -# CONFIG_SWITCH_USB_PATH_AUTO is not set # CONFIG_WIMAX_CMC is not set # CONFIG_SEC_DEV_JACK is not set # CONFIG_MUIC_DET_JACK is not set # CONFIG_FM34_WE395 is not set # CONFIG_AUDIENCE_ES305 is not set # CONFIG_2MIC_FM34_WE395 is not set +# CONFIG_MUIC_MAX77693_SEPARATE_MHL_PORT is not set +CONFIG_MUIC_MAX77693_SUPPORT_OTG_AUDIO_DOCK=y +CONFIG_MUIC_MAX77693_SUPPORT_SMART_DOCK=y +# CONFIG_MUIC_MAX77693_SUPPORT_CAR_DOCK is not set # CONFIG_USBHUB_USB3503 is not set # CONFIG_USBHUB_USB3503_OTG_CONN is not set # CONFIG_USBHUB_USB3803 is not set # CONFIG_PN544 is not set +# CONFIG_STMPE811_ADC is not set # CONFIG_MPU_SENSORS_MPU3050 is not set # CONFIG_MPU_SENSORS_MPU6050 is not set +CONFIG_UID_CPUTIME=y # CONFIG_C2PORT is not set # @@ -1304,28 +1299,6 @@ CONFIG_UID_STAT=y # CONFIG_SENSORS_LIS3_I2C is not set # CONFIG_SAMSUNG_C2C is not set # CONFIG_SEC_MODEM is not set -# CONFIG_UMTS_MODEM_XMM6260 is not set -# CONFIG_UMTS_MODEM_XMM6262 is not set -# CONFIG_CDMA_MODEM_CBP71 is not set -# CONFIG_CDMA_MODEM_CBP72 is not set -# CONFIG_LTE_MODEM_CMC221 is not set -# CONFIG_CDMA_MODEM_MDM6600 is not set -# CONFIG_TDSCDMA_MODEM_SPRD8803 is not set -# CONFIG_GSM_MODEM_ESC6270 is not set -# CONFIG_LINK_DEVICE_MIPI is not set -# CONFIG_LINK_DEVICE_DPRAM is not set -# CONFIG_LINK_DEVICE_PLD is not set -# CONFIG_LINK_DEVICE_USB is not set -# CONFIG_LINK_DEVICE_HSIC is not set -# CONFIG_LINK_DEVICE_C2C is not set -# CONFIG_LINK_DEVICE_SPI is not set -# CONFIG_WORKQUEUE_FRONT is not set -# CONFIG_IPC_CMC22x_OLD_RFS is not set -# CONFIG_SIPC_VER_5 is not set -# CONFIG_SIM_SLOT_SWITCH is not set -# CONFIG_LTE_MODEM_CMC220 is not set -# CONFIG_INTERNAL_MODEM_IF is not set -# CONFIG_CDMA_MODEM_QSC6085 is not set CONFIG_HAVE_IDE=y # CONFIG_IDE is not set @@ -1406,18 +1379,25 @@ CONFIG_WLAN=y # CONFIG_USB_NET_RNDIS_WLAN is not set CONFIG_WIFI_CONTROL_FUNC=y # CONFIG_ATH_COMMON is not set +# CONFIG_B43LEGACY_DMA_AND_PIO_MODE is not set +# CONFIG_B43LEGACY_DMA_MODE is not set +# CONFIG_B43LEGACY_PIO_MODE is not set # CONFIG_BCM4330 is not set CONFIG_BCM4334=m +# CONFIG_BCM4335 is not set +# CONFIG_BCM4339 is not set +# CONFIG_BCM4354 is not set # CONFIG_BCM43241 is not set +CONFIG_BROADCOM_WIFI=y CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/fw_bcmdhd.bin" CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/bcmdhd.cal" CONFIG_BROADCOM_WIFI_RESERVED_MEM=y CONFIG_WLAN_REGION_CODE=100 +CONFIG_WIFI_BROADCOM_COB=y # CONFIG_HOSTAP is not set # CONFIG_IWM is not set # CONFIG_LIBERTAS is not set # CONFIG_MWIFIEX is not set -# CONFIG_LGUIWLAN is not set # # Enable WiMAX (Networking options) to see the WiMAX drivers @@ -1431,9 +1411,35 @@ CONFIG_WLAN_REGION_CODE=100 # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set # CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set # CONFIG_USB_CDC_PHONET is not set # CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +CONFIG_MSM_RMNET_USB=y # CONFIG_WAN is not set # @@ -1479,8 +1485,6 @@ CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_SECBRIDGE is not set CONFIG_INPUT_KEYRESET=y # CONFIG_INPUT_FBSUSPEND is not set -# CONFIG_INPUT_MPU6050 is not set -# CONFIG_INPUT_MPU6050_POLLING is not set # # Input Device Drivers @@ -1504,7 +1508,9 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_KEYBOARD_STOWAWAY is not set # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set +CONFIG_SENSORS_HALL=y # CONFIG_KEYBOARD_CYPRESS_TOUCH is not set +# CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TABLET is not set @@ -1562,7 +1568,7 @@ CONFIG_TOUCHSCREEN_SYNAPTICS_S7301=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYS=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_WORKAROUND=y CONFIG_TOUCHSCREEN_SYNAPTICS_S7301_KEYLED=y -# CONFIG_TOUCHSCREEN_CYPRESS_TMA46X is not set +# CONFIG_TOUCHSCREEN_CYTTSP4 is not set CONFIG_SEC_TOUCHSCREEN_DVFS_LOCK=y CONFIG_SEC_TOUCHSCREEN_SURFACE_TOUCH=y # CONFIG_KEYPAD_MELFAS_TOUCH is not set @@ -1570,27 +1576,6 @@ CONFIG_SEC_TOUCHSCREEN_SURFACE_TOUCH=y CONFIG_INPUT_WACOM=y # CONFIG_EPEN_WACOM_G5SP is not set # CONFIG_EPEN_WACOM_G9PM is not set -CONFIG_EPEN_WACOM_G9PL=y -# CONFIG_RMI4_DEBUG is not set -# CONFIG_RMI4_BUS is not set -# CONFIG_RMI4_GENERIC is not set -# CONFIG_RMI4_F09 is not set -# CONFIG_RMI4_F1A is not set -# CONFIG_RMI4_F11 is not set -# CONFIG_RMI4_VIRTUAL_BUTTONS is not set -# CONFIG_RMI4_F17 is not set -# CONFIG_RMI4_F19 is not set -# CONFIG_RMI4_F21 is not set -# CONFIG_RMI4_F30 is not set -# CONFIG_RMI4_F31 is not set -# CONFIG_RMI4_F34 is not set -# CONFIG_RMI4_F41 is not set -# CONFIG_RMI4_F54 is not set -# CONFIG_RMI4_SMB is not set -# CONFIG_RMI4_I2C is not set -# CONFIG_RMI4_SPI is not set -# CONFIG_RMI4_DEV is not set -# CONFIG_RMI4_FWLIB is not set CONFIG_INPUT_MISC=y # CONFIG_SENSORS_BH1721FVC is not set # CONFIG_INPUT_AD714X is not set @@ -1673,11 +1658,12 @@ CONFIG_SERIAL_CORE_CONSOLE=y # # Diag Support # -# CONFIG_DIAG_CHAR is not set +CONFIG_DIAG_CHAR=y # # DIAG traffic over USB # +CONFIG_DIAG_OVER_USB=y # # SDIO support for DIAG @@ -1686,6 +1672,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y # # HSIC support for DIAG # +CONFIG_DIAG_HSIC_PIPE=y # CONFIG_TTY_PRINTK is not set # CONFIG_HVC_DCC is not set # CONFIG_IPMI_HANDLER is not set @@ -1824,10 +1811,15 @@ CONFIG_POWER_SUPPLY=y # CONFIG_BATTERY_MAX17042_FUELGAUGE is not set # CONFIG_BATTERY_MAX17047_FUELGAUGE is not set CONFIG_BATTERY_MAX17047_C_FUELGAUGE=y -CONFIG_BATTERY_MAX77693_CHARGER=y # CONFIG_BATTERY_SMB136_CHARGER is not set +CONFIG_BATTERY_MAX77693_CHARGER=y +# CONFIG_BATTERY_WPC_CHARGER is not set # CONFIG_BATTERY_SAMSUNG_P1X is not set +# CONFIG_FUELGAUGE_DUMMY is not set +# CONFIG_FUELGAUGE_MAX17048 is not set +# CONFIG_CHARGER_DUMMY is not set # CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_SMB328 is not set # CONFIG_POWER_SUPPLY_DEBUG is not set # CONFIG_PDA_POWER is not set # CONFIG_TEST_POWER is not set @@ -1850,16 +1842,13 @@ CONFIG_BATTERY_SAMSUNG=y # CONFIG_SMB328_CHARGER is not set # CONFIG_SMB347_CHARGER is not set # CONFIG_CHARGER_MANAGER is not set -CONFIG_SAMSUNG_LPM_MODE=y # CONFIG_HWMON is not set CONFIG_THERMAL=y # CONFIG_CPU_THERMAL is not set # CONFIG_SENSORS_EXYNOS4_TMU is not set CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set -# CONFIG_CHARGER_NCP1851 is not set -# CONFIG_FUELGAUGE_MAX17050 is not set -# CONFIG_FUELGAUGE_MAX17050_COULOMB_COUNTING is not set + # # Watchdog Device Drivers # @@ -2055,12 +2044,6 @@ CONFIG_VIDEO_IR_I2C=y # CONFIG_VIDEO_TVP5150 is not set # CONFIG_VIDEO_TVP7002 is not set # CONFIG_VIDEO_VPX3220 is not set -# CONFIG_VIDEO_S5K3H2 is not set -# CONFIG_VIDEO_S5K3H7 is not set -# CONFIG_VIDEO_S5K4E5 is not set -# CONFIG_VIDEO_S5K6A3 is not set -# CONFIG_S5K6A3_CSI_C is not set -# CONFIG_S5K6A3_CSI_D is not set # CONFIG_VIDEO_M5MO is not set # CONFIG_VIDEO_M9MO is not set # CONFIG_VIDEO_S5K5BAFX is not set @@ -2068,12 +2051,12 @@ CONFIG_VIDEO_IR_I2C=y # CONFIG_VIDEO_SR200PC20 is not set # CONFIG_VIDEO_SR200PC20M is not set CONFIG_VIDEO_ISX012=y -CONFIG_VIDEO_SR130PC20=y # CONFIG_VIDEO_SLP_S5K4ECGX is not set # CONFIG_VIDEO_SLP_DB8131M is not set # CONFIG_VIDEO_S5K4EA is not set # CONFIG_VIDEO_S5C73M3 is not set # CONFIG_VIDEO_SLP_S5C73M3 is not set +CONFIG_VIDEO_SR130PC20=y CONFIG_VIDEO_IMPROVE_STREAMOFF=y # @@ -2140,7 +2123,6 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USB_ZR364XX is not set # CONFIG_USB_STKWEBCAM is not set # CONFIG_USB_S2255 is not set -CONFIG_MALI_400MP_UMP=y CONFIG_VIDEO_SAMSUNG=y CONFIG_VIDEO_SAMSUNG_V4L2=y CONFIG_VIDEO_FIMC=y @@ -2169,6 +2151,8 @@ CONFIG_LSI_HDMI_AUDIO_CH_EVENT=y CONFIG_VIDEO_MFC5X=y CONFIG_VIDEO_MFC_MAX_INSTANCE=4 # CONFIG_VIDEO_MFC5X_DEBUG is not set +# CONFIG_VIDEO_MALI400MP is not set +# CONFIG_VIDEO_UMP is not set CONFIG_VIDEO_FIMG2D=y # CONFIG_VIDEO_FIMG2D_DEBUG is not set CONFIG_VIDEO_FIMG2D4X=y @@ -2190,20 +2174,10 @@ CONFIG_VIDEO_SAMSUNG_MEMSIZE_JPEG=0 CONFIG_VIDEO_SAMSUNG_MEMSIZE_TVOUT=0 CONFIG_VIDEO_EXYNOS=y CONFIG_VIDEO_EXYNOS_MEMSIZE_FIMC_IS=12288 -CONFIG_EXYNOS_MEDIA_DEVICE=y -# CONFIG_VIDEO_EXYNOS_FIMC_LITE is not set - -# -# Reserved memory configurations -# -CONFIG_VIDEO_SAMSUNG_MEMSIZE_FLITE0=10240 -CONFIG_VIDEO_SAMSUNG_MEMSIZE_FLITE1=10240 -# CONFIG_VIDEO_EXYNOS_MIPI_CSIS is not set +# CONFIG_VIDEO_EXYNOS_FIMC_LITE is not set # CONFIG_VIDEO_EXYNOS_TV is not set # CONFIG_VIDEO_EXYNOS_ROTATOR is not set -# CONFIG_VIDEO_EXYNOS_FIMC_IS is not set -# CONFIG_VIDEO_EXYNOS_FIMC_IS_BAYER is not set -CONFIG_MEDIA_EXYNOS=y +# CONFIG_VIDEO_EXYNOS_FIMC_IS is not set CONFIG_V4L_MEM2MEM_DRIVERS=y # CONFIG_VIDEO_MEM2MEM_TESTDEV is not set @@ -2220,29 +2194,14 @@ CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE=y # CONFIG_ISDBT is not set # -# MUIC device -# -# CONFIG_STMPE811_ADC is not set -CONFIG_MUIC_MAX77693_SUPPORT_OTG_AUDIO_DOCK=y -CONFIG_MUIC_MAX77693_SUPPORT_SMART_DOCK=y - -# # Graphics support # -# CONFIG_MALI_VER_BEFORE_R3P2 is not set # CONFIG_DRM is not set CONFIG_ION=y CONFIG_ION_EXYNOS=y CONFIG_ION_EXYNOS_CONTIGHEAP_SIZE=81920 # CONFIG_ION_EXYNOS_CONTIGHEAP_DEBUG is not set -# CONFIG_VITHAR is not set -CONFIG_MALI400=y -CONFIG_MALI_VER_R3P2=y -# CONFIG_MALI400_DEBUG is not set -# CONFIG_MALI400_PROFILING is not set -CONFIG_MALI_DVFS=y -CONFIG_MALI400_UMP=y -# CONFIG_MALI_SHARED_INTERRUPTS is not set +# CONFIG_VGASTATE is not set # CONFIG_VIDEO_OUTPUT_CONTROL is not set CONFIG_FB=y # CONFIG_FIRMWARE_EDID is not set @@ -2273,6 +2232,7 @@ CONFIG_FB_S5P_SPLASH_SCREEN=y # CONFIG_FB_S5P_LCD_INIT is not set # CONFIG_FB_S5P_DEBUG is not set CONFIG_FB_S5P_VSYNC_THREAD=y +# CONFIG_FB_S5P_VSYNC_SEND_UEVENTS is not set CONFIG_FB_S5P_VSYNC_SYSFS=y # CONFIG_FB_S5P_TRACE_UNDERRUN is not set CONFIG_FB_S5P_DEFAULT_WINDOW=3 @@ -2281,12 +2241,18 @@ CONFIG_FB_S5P_NR_BUFFERS=2 CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMD=8192 CONFIG_FB_S5P_MDNIE=y CONFIG_FB_MDNIE_PWM=y -CONFIG_FB_EBOOK_PANEL_SCENARIO=y CONFIG_FB_S5P_MIPI_DSIM=y CONFIG_FB_BGRA_ORDER=y # CONFIG_FB_RGBA_ORDER is not set # CONFIG_FB_S5P_S6C1372 is not set # CONFIG_FB_S5P_LD9040 is not set +# CONFIG_FB_S5P_LMS501XX is not set +# CONFIG_FB_S5P_DUMMY_MIPI_LCD is not set +# CONFIG_FB_S5P_S6E8AA0 is not set +# CONFIG_FB_S5P_EA8061 is not set +# CONFIG_FB_S5P_S6EVR02 is not set +# CONFIG_FB_S5P_S6D6AA1 is not set +# CONFIG_FB_S5P_S6E63M0 is not set CONFIG_FB_S5P_NT71391=y # CONFIG_LCD_FREQ_SWITCH is not set CONFIG_FB_S5P_EXTDSP=y @@ -2295,10 +2261,10 @@ CONFIG_FB_S5P_EXTDSP_NR_BUFFERS=3 # CONFIG_S5P_DSIM_SWITCHABLE_DUAL_LCD is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_TMIO is not set -# CONFIG_S5P_MIPI_DSI2 is not set # CONFIG_FB_UDL is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX_PCI_GDC is not set # CONFIG_FB_BROADSHEET is not set CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y @@ -2368,6 +2334,7 @@ CONFIG_SND_SOC=y # CONFIG_SND_SOC_CACHE_LZO is not set CONFIG_SND_SOC_SAMSUNG=y CONFIG_SND_SAMSUNG_I2S=y +# CONFIG_SND_SOC_SAMSUNG_MIDAS_WM1811 is not set CONFIG_SND_SOC_SAMSUNG_KONA_WM1811=y # CONFIG_SND_SOC_SAMSUNG_USE_DMA_WRAPPER is not set CONFIG_SND_SOC_SAMSUNG_I2S_SEC=y @@ -2405,7 +2372,6 @@ CONFIG_USB_HID=y # # Special HID drivers # -CONFIG_UHID=y CONFIG_HID_A4TECH=y CONFIG_HID_ACRUX=y # CONFIG_HID_ACRUX_FF is not set @@ -2482,7 +2448,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2551,7 +2517,6 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_KARMA is not set # CONFIG_USB_STORAGE_CYPRESS_ATACB is not set # CONFIG_USB_STORAGE_ENE_UB6250 is not set -# CONFIG_USB_UAS is not set # CONFIG_USB_LIBUSUAL is not set # @@ -2608,6 +2573,7 @@ CONFIG_USB_SERIAL_QUALCOMM=y # CONFIG_USB_SERIAL_TI is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set +CONFIG_USB_SERIAL_WWAN=y # CONFIG_USB_SERIAL_OPTION is not set # CONFIG_USB_SERIAL_OMNINET is not set # CONFIG_USB_SERIAL_OPTICON is not set @@ -2640,8 +2606,9 @@ CONFIG_USB_SERIAL_CSVT=y # CONFIG_USB_TEST is not set # CONFIG_USB_ISIGHTFW is not set # CONFIG_USB_YUREX is not set -# CONFIG_USB_QCOM_DIAG_BRIDGE is not set -# CONFIG_USB_QCOM_MDM_BRIDGE is not set +CONFIG_USB_QCOM_DIAG_BRIDGE=y +# CONFIG_USB_QCOM_DIAG_BRIDGE_TEST is not set +CONFIG_USB_QCOM_MDM_BRIDGE=y CONFIG_USB_GADGET=y # CONFIG_USB_GADGET_DEBUG is not set # CONFIG_USB_GADGET_DEBUG_FILES is not set @@ -2653,6 +2620,12 @@ CONFIG_USB_GADGET_SELECTED=y CONFIG_USB_GADGET_S3C_OTGD=y # CONFIG_USB_GADGET_PXA_U2O is not set # CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_CI13XXX_PCI is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LANGWELL is not set +# CONFIG_USB_GADGET_EG20T is not set # CONFIG_USB_GADGET_DUMMY_HCD is not set # @@ -2749,12 +2722,14 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_LT3593 is not set # CONFIG_LEDS_SWITCH is not set +# CONFIG_LEDS_MAX77693 is not set # CONFIG_LEDS_AAT1290A is not set # CONFIG_LEDS_TRIGGERS is not set # # LED Triggers # +# CONFIG_LEDS_TRIGGER_NOTIFICATION is not set # CONFIG_NFC_DEVICES is not set CONFIG_SWITCH=y CONFIG_SWITCH_GPIO=y @@ -2867,14 +2842,14 @@ CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d CONFIG_ANDROID_TIMED_OUTPUT=y # CONFIG_ANDROID_TIMED_GPIO is not set CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_LMK_ADJ_RBTREE=y # CONFIG_POHMELFS is not set # CONFIG_LINE6_USB is not set # CONFIG_USB_SERIAL_QUATECH2 is not set # CONFIG_USB_SERIAL_QUATECH_USB2 is not set # CONFIG_VT6656 is not set # CONFIG_IIO is not set -# CONFIG_XVMALLOC is not set -# CONFIG_ZRAM is not set # CONFIG_FB_SM7XX is not set # CONFIG_LIRC_STAGING is not set # CONFIG_EASYCAP is not set @@ -2900,7 +2875,6 @@ CONFIG_CLKDEV_LOOKUP=y CONFIG_VIBETONZ=y CONFIG_MOTOR_DRV_MAX77693=y # CONFIG_MOTOR_DRV_ISA1200 is not set -# CONFIG_MOTOR_DRV_DRV2603 is not set # CONFIG_FM_RADIO is not set CONFIG_SENSORS_CORE=y # CONFIG_SENSORS_AK8975C is not set @@ -2908,10 +2882,7 @@ CONFIG_SENSORS_CORE=y # CONFIG_SENSORS_BMP180 is not set # CONFIG_SENSORS_CM3663 is not set # CONFIG_SENSORS_PAS2M110 is not set -CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=2 # CONFIG_SENSORS_BMA254 is not set -CONFIG_SENSORS_YAS532=y -CONFIG_SENSORS_YAS_ORI=y # CONFIG_SENSORS_TAOS is not set CONFIG_SENSORS_GP2A=y # CONFIG_SENSORS_GP2A_ANALOG is not set @@ -2924,6 +2895,9 @@ CONFIG_SENSOR_K3DH_INPUTDEV=y # CONFIG_SENSORS_K3G is not set # CONFIG_SENSORS_LSM330DLC is not set # CONFIG_SENSORS_LPS331 is not set +CONFIG_SENSORS_YAS532=y +CONFIG_SENSORS_YAS_ORI=y +CONFIG_INPUT_YAS_MAGNETOMETER_POSITION=2 # CONFIG_SENSORS_SYSFS is not set # CONFIG_SENSORS_SSP is not set # CONFIG_SENSORS_SSP_LSM330 is not set @@ -2945,13 +2919,13 @@ CONFIG_IR_REMOCON=y CONFIG_IR_REMOCON_MC96=y # CONFIG_EXTCON is not set # CONFIG_BARCODE_EMUL is not set +# CONFIG_SAMSUNG_PHONE_TTY is not set CONFIG_MOBICORE_SUPPORT=y # CONFIG_MOBICORE_DEBUG is not set CONFIG_MOBICORE_API=y CONFIG_IOMMU_SUPPORT=y # CONFIG_FELICA is not set # CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR is not set -# CONFIG_J4FS is not set # # File systems @@ -2968,6 +2942,7 @@ CONFIG_EXT4_FS_SECURITY=y # CONFIG_EXT4_DEBUG is not set CONFIG_JBD2=y # CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_XFS_FS is not set @@ -3030,6 +3005,10 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS2_CMODE_NONE is not set +# CONFIG_JFFS2_CMODE_PRIORITY is not set +# CONFIG_JFFS2_CMODE_SIZE is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set # CONFIG_LOGFS is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set @@ -3039,9 +3018,13 @@ CONFIG_WTL_ENCRYPTION_FILTER=y # CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set +# CONFIG_ROMFS_BACKED_BY_BLOCK is not set +# CONFIG_ROMFS_BACKED_BY_MTD is not set +# CONFIG_ROMFS_BACKED_BY_BOTH is not set # CONFIG_PSTORE is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=m CONFIG_NFS_V3=y @@ -3139,7 +3122,6 @@ CONFIG_NLS_UTF8=y # CONFIG_PRINTK_TIME=y CONFIG_PRINTK_CPU_ID=y -CONFIG_UID_CPUTIME=y # CONFIG_PRINTK_PID is not set CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 CONFIG_ENABLE_WARN_DEPRECATED=y @@ -3285,6 +3267,9 @@ CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_SECURITY_APPARMOR is not set # CONFIG_IMA is not set CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +# CONFIG_DEFAULT_SECURITY_APPARMOR is not set # CONFIG_DEFAULT_SECURITY_DAC is not set CONFIG_DEFAULT_SECURITY="selinux" CONFIG_CRYPTO=y @@ -3385,6 +3370,8 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_ZLIB is not set # CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set # # Random Number Generation @@ -3414,6 +3401,9 @@ CONFIG_ZLIB_DEFLATE=y # CONFIG_XZ_DEC_BCJ is not set CONFIG_DECOMPRESS_GZIP=y CONFIG_GENERIC_ALLOCATOR=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y CONFIG_TEXTSEARCH=y CONFIG_TEXTSEARCH_KMP=y CONFIG_TEXTSEARCH_BM=y @@ -3423,5 +3413,3 @@ CONFIG_HAS_DMA=y CONFIG_CPU_RMAP=y CONFIG_NLATTR=y # CONFIG_AVERAGE is not set - -CONFIG_SENSORS_HALL=y diff --git a/arch/arm/configs/cyanogenmod_n7000_defconfig b/arch/arm/configs/cyanogenmod_n7000_defconfig index 0ac33a0..ca6968c 100644 --- a/arch/arm/configs/cyanogenmod_n7000_defconfig +++ b/arch/arm/configs/cyanogenmod_n7000_defconfig @@ -685,7 +685,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set # CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set -# CONFIG_VMWARE_MVP is not set # # Boot options @@ -1228,7 +1227,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 # CONFIG_SENSORS_LIS3LV02D is not set CONFIG_MISC_DEVICES=y # CONFIG_AD525X_DPOT is not set -# CONFIG_ANDROID_PMEM is not set # CONFIG_INTEL_MID_PTI is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set @@ -2376,7 +2374,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y diff --git a/arch/arm/configs/cyanogenmod_n7100_defconfig b/arch/arm/configs/cyanogenmod_n7100_defconfig index 9b0dd73..124066d 100644 --- a/arch/arm/configs/cyanogenmod_n7100_defconfig +++ b/arch/arm/configs/cyanogenmod_n7100_defconfig @@ -145,7 +145,7 @@ CONFIG_COMPAT_BRK=y # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set -# CONFIG_PROFILING is not set +CONFIG_PROFILING=y CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set CONFIG_HAVE_KPROBES=y @@ -688,8 +688,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -734,6 +732,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # CONFIG_CPU_FREQ_GOV_ADAPTIVE is not set CONFIG_CPU_FREQ_GOV_PEGASUSQ=y +CONFIG_CPU_FREQ_GOV_PEGASUSQ_BOOST=y # CONFIG_CPU_FREQ_GOV_SLP is not set # CONFIG_CPU_FREQ_DVFS_MONITOR is not set CONFIG_CPU_IDLE=y @@ -2449,7 +2448,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -3107,6 +3106,7 @@ CONFIG_NLS_UTF8=y # CONFIG_PRINTK_TIME=y CONFIG_PRINTK_CPU_ID=y +CONFIG_UID_CPUTIME=y # CONFIG_PRINTK_PID is not set CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 CONFIG_ENABLE_WARN_DEPRECATED=y diff --git a/arch/arm/configs/cyanogenmod_n8000_defconfig b/arch/arm/configs/cyanogenmod_n8000_defconfig index bb6f24e..45cf051 100644 --- a/arch/arm/configs/cyanogenmod_n8000_defconfig +++ b/arch/arm/configs/cyanogenmod_n8000_defconfig @@ -684,8 +684,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -2425,7 +2423,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y diff --git a/arch/arm/configs/cyanogenmod_n8013_defconfig b/arch/arm/configs/cyanogenmod_n8013_defconfig index 37bc308..f55906c 100644 --- a/arch/arm/configs/cyanogenmod_n8013_defconfig +++ b/arch/arm/configs/cyanogenmod_n8013_defconfig @@ -663,8 +663,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -2385,7 +2383,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y diff --git a/arch/arm/configs/cyanogenmod_t0lte_defconfig b/arch/arm/configs/cyanogenmod_t0lte_defconfig index b69d4fe..7a07860 100755 --- a/arch/arm/configs/cyanogenmod_t0lte_defconfig +++ b/arch/arm/configs/cyanogenmod_t0lte_defconfig @@ -687,8 +687,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -2438,7 +2436,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2891,7 +2889,7 @@ CONFIG_MOBICORE_SUPPORT=y CONFIG_MOBICORE_API=y CONFIG_IOMMU_SUPPORT=y # CONFIG_FELICA is not set -CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR=m +# CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR is not set # # File systems diff --git a/arch/arm/configs/cyanogenmod_t0ltecdma_defconfig b/arch/arm/configs/cyanogenmod_t0ltecdma_defconfig index 43e473a..4a914ff 100755 --- a/arch/arm/configs/cyanogenmod_t0ltecdma_defconfig +++ b/arch/arm/configs/cyanogenmod_t0ltecdma_defconfig @@ -687,8 +687,6 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_CC_STACKPROTECTOR is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y -CONFIG_VMWARE_MVP=y -# CONFIG_VMWARE_MVP_DEBUG is not set # # Boot options @@ -2438,7 +2436,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # # Miscellaneous USB options # -CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICEFS is not set CONFIG_USB_DEVICE_CLASS=y # CONFIG_USB_DYNAMIC_MINORS is not set CONFIG_USB_SUSPEND=y @@ -2891,7 +2889,7 @@ CONFIG_MOBICORE_SUPPORT=y CONFIG_MOBICORE_API=y CONFIG_IOMMU_SUPPORT=y # CONFIG_FELICA is not set -CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR=m +# CONFIG_AUTHENTEC_VPNCLIENT_INTERCEPTOR is not set # # File systems diff --git a/arch/arm/mach-exynos/board-m0-modems.c b/arch/arm/mach-exynos/board-m0-modems.c index 4139c79..50d475e 100644 --- a/arch/arm/mach-exynos/board-m0-modems.c +++ b/arch/arm/mach-exynos/board-m0-modems.c @@ -28,7 +28,12 @@ #include <linux/usb/hcd.h> #include <linux/usb/ehci_def.h> +#ifdef CONFIG_SEC_MODEM_M0 +#include "../../../drivers/misc/modem_if/modem.h" +#else #include <linux/platform_data/modem.h> +#endif + #include <mach/sec_modem.h> extern int s3c_gpio_slp_cfgpin(unsigned int pin, unsigned int config); diff --git a/arch/arm/mach-exynos/board-trats.c b/arch/arm/mach-exynos/board-trats.c index cf725ab..ed62092 100644 --- a/arch/arm/mach-exynos/board-trats.c +++ b/arch/arm/mach-exynos/board-trats.c @@ -47,9 +47,6 @@ #ifdef CONFIG_JACK_MON #include <linux/jack.h> #endif -#ifdef CONFIG_ANDROID_PMEM -#include <linux/android_pmem.h> -#endif #include <linux/k3g.h> #include <asm/mach/arch.h> @@ -4844,53 +4841,6 @@ static struct platform_device s3c_device_i2c17 = { }; #endif -#ifdef CONFIG_ANDROID_PMEM -static struct android_pmem_platform_data pmem_pdata = { - .name = "pmem", - .no_allocator = 1, - .cached = 0, - .start = 0, - .size = 0 -}; - -static struct android_pmem_platform_data pmem_gpu1_pdata = { - .name = "pmem_gpu1", - .no_allocator = 1, - .cached = 0, - .start = 0, - .size = 0, -}; - -static struct platform_device pmem_device = { - .name = "android_pmem", - .id = 0, - .dev = { - .platform_data = &pmem_pdata}, -}; - -static struct platform_device pmem_gpu1_device = { - .name = "android_pmem", - .id = 1, - .dev = { - .platform_data = &pmem_gpu1_pdata}, -}; - -static void __init android_pmem_set_platdata(void) -{ -#if defined(CONFIG_S5P_MEM_CMA) - pmem_pdata.size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM * SZ_1K; - pmem_gpu1_pdata.size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 * SZ_1K; -#else - pmem_pdata.start = (u32) s5p_get_media_memory_bank(S5P_MDEV_PMEM, 0); - pmem_pdata.size = (u32) s5p_get_media_memsize_bank(S5P_MDEV_PMEM, 0); - pmem_gpu1_pdata.start = - (u32) s5p_get_media_memory_bank(S5P_MDEV_PMEM_GPU1, 0); - pmem_gpu1_pdata.size = - (u32) s5p_get_media_memsize_bank(S5P_MDEV_PMEM_GPU1, 0); -#endif -} -#endif - /* USB EHCI */ #ifdef CONFIG_USB_EHCI_S5P static struct s5p_ehci_platdata smdkc210_ehci_pdata; @@ -5187,10 +5137,6 @@ static struct platform_device *smdkc210_devices[] __initdata = { &ipc_spi_device, #endif -#ifdef CONFIG_ANDROID_PMEM - &pmem_device, - &pmem_gpu1_device, -#endif #ifdef CONFIG_VIDEO_FIMC &s3c_device_fimc0, &s3c_device_fimc1, @@ -5350,20 +5296,6 @@ static void __init exynos4_reserve_mem(void) .start = 0 }, #endif -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM - { - .name = "pmem", - .size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM * SZ_1K, - .start = 0, - }, -#endif -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 - { - .name = "pmem_gpu1", - .size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 * SZ_1K, - .start = 0, - }, -#endif #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC0 { .name = "fimc0", @@ -5453,7 +5385,6 @@ static void __init exynos4_reserve_mem(void) #ifdef CONFIG_DRM_EXYNOS "exynos-drm=drm;" #endif - "android_pmem.0=pmem;android_pmem.1=pmem_gpu1;" "s3c-fimc.0=fimc0;s3c-fimc.1=fimc1;s3c-fimc.2=fimc2;s3c-fimc.3=fimc3;" "exynos4210-fimc.0=fimc0;exynos4210-fimc.1=fimc1;exynos4210-fimc.2=fimc2;exynos4210-fimc3=fimc3;" #ifdef CONFIG_ION_EXYNOS @@ -5726,9 +5657,6 @@ static void __init trats_machine_init(void) s5p_device_jpeg.dev.parent = &exynos4_device_pd[PD_CAM].dev; #endif #endif -#ifdef CONFIG_ANDROID_PMEM - android_pmem_set_platdata(); -#endif #ifdef CONFIG_VIDEO_FIMC /* fimc */ s3c_fimc0_set_platdata(&fimc_plat); diff --git a/arch/arm/mach-exynos/include/mach/busfreq_exynos4.h b/arch/arm/mach-exynos/include/mach/busfreq_exynos4.h index f8f377d..ab75f55 100644 --- a/arch/arm/mach-exynos/include/mach/busfreq_exynos4.h +++ b/arch/arm/mach-exynos/include/mach/busfreq_exynos4.h @@ -27,6 +27,11 @@ #define PRIME_DMC_MAX_THRESHOLD 30 #define EXYNOS4412_DMC_MAX_THRESHOLD 30 #define EXYNOS4212_DMC_MAX_THRESHOLD 30 +#if defined(CONFIG_MACH_P4NOTE) || defined(CONFIG_MACH_SP7160LTE) || defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_C1) || defined(CONFIG_MACH_T0) +#define DECODING_LOAD 5 +#else +#define DECODING_LOAD 10 +#endif extern unsigned int up_threshold; extern unsigned int ppmu_threshold; diff --git a/arch/arm/mach-exynos/mach-px.c b/arch/arm/mach-exynos/mach-px.c index eaec80f..cc26a75 100644 --- a/arch/arm/mach-exynos/mach-px.c +++ b/arch/arm/mach-exynos/mach-px.c @@ -57,9 +57,6 @@ #if defined(CONFIG_S5P_MEM_CMA) #include <linux/cma.h> #endif -#ifdef CONFIG_ANDROID_PMEM -#include <linux/android_pmem.h> -#endif #include <asm/mach/arch.h> #include <asm/mach-types.h> @@ -5914,53 +5911,6 @@ static void __init mipi_fb_init(void) } #endif -#ifdef CONFIG_ANDROID_PMEM -static struct android_pmem_platform_data pmem_pdata = { - .name = "pmem", - .no_allocator = 1, - .cached = 0, - .start = 0, - .size = 0 -}; - -static struct android_pmem_platform_data pmem_gpu1_pdata = { - .name = "pmem_gpu1", - .no_allocator = 1, - .cached = 0, - .start = 0, - .size = 0, -}; - -static struct platform_device pmem_device = { - .name = "android_pmem", - .id = 0, - .dev = { - .platform_data = &pmem_pdata}, -}; - -static struct platform_device pmem_gpu1_device = { - .name = "android_pmem", - .id = 1, - .dev = { - .platform_data = &pmem_gpu1_pdata}, -}; - -static void __init android_pmem_set_platdata(void) -{ -#if defined(CONFIG_S5P_MEM_CMA) - pmem_pdata.size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM * SZ_1K; - pmem_gpu1_pdata.size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 * SZ_1K; -#else - pmem_pdata.start = (u32) s5p_get_media_memory_bank(S5P_MDEV_PMEM, 0); - pmem_pdata.size = (u32) s5p_get_media_memsize_bank(S5P_MDEV_PMEM, 0); - pmem_gpu1_pdata.start = - (u32) s5p_get_media_memory_bank(S5P_MDEV_PMEM_GPU1, 0); - pmem_gpu1_pdata.size = - (u32) s5p_get_media_memsize_bank(S5P_MDEV_PMEM_GPU1, 0); -#endif -} -#endif - /* USB EHCI */ #ifdef CONFIG_USB_EHCI_S5P static struct s5p_ehci_platdata smdkc210_ehci_pdata; @@ -6753,10 +6703,6 @@ static struct platform_device *smdkc210_devices[] __initdata = { #ifdef CONFIG_BATTERY_SEC_PX &sec_battery_device, #endif -#ifdef CONFIG_ANDROID_PMEM - &pmem_device, - &pmem_gpu1_device, -#endif #ifdef CONFIG_INTERNAL_MODEM_IF &sec_idpram_pm_device, @@ -7132,20 +7078,6 @@ static void __init exynos4_cma_region_reserve(struct cma_region *regions_normal, static void __init exynos4_reserve_mem(void) { static struct cma_region regions[] = { -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM - { - .name = "pmem", - .size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM * SZ_1K, - .start = 0, - }, -#endif -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 - { - .name = "pmem_gpu1", - .size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 * SZ_1K, - .start = 0, - }, -#endif #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMD { .name = "fimd", @@ -7245,7 +7177,6 @@ static void __init exynos4_reserve_mem(void) }; static const char map[] __initconst = - "android_pmem.0=pmem;android_pmem.1=pmem_gpu1;" "s3cfb.0=fimd;exynos4-fb.0=fimd;samsung-pd.1=fimd;" "s3c-fimc.0=fimc0;s3c-fimc.1=fimc1;s3c-fimc.2=fimc2;s3c-fimc.3=fimc3;" "exynos4210-fimc.0=fimc0;exynos4210-fimc.1=fimc1;exynos4210-fimc.2=fimc2;exynos4210-fimc.3=fimc3;" @@ -7674,9 +7605,6 @@ static void __init smdkc210_machine_init(void) s3c24xx_ts1_set_platdata(&s3c_ts_platform); #endif #endif -#ifdef CONFIG_ANDROID_PMEM - android_pmem_set_platdata(); -#endif #ifdef CONFIG_VIDEO_FIMC /* fimc */ s3c_fimc0_set_platdata(&fimc_plat); diff --git a/arch/arm/mach-exynos/mach-smdk5210.c b/arch/arm/mach-exynos/mach-smdk5210.c index 16ccba4..9ed28fa 100644 --- a/arch/arm/mach-exynos/mach-smdk5210.c +++ b/arch/arm/mach-exynos/mach-smdk5210.c @@ -947,20 +947,6 @@ static void __init exynos5_cma_region_reserve( static void __init exynos5_reserve_mem(void) { static struct cma_region regions[] = { -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM - { - .name = "pmem", - .size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM * SZ_1K, - .start = 0, - }, -#endif -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 - { - .name = "pmem_gpu1", - .size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 * SZ_1K, - .start = 0, - }, -#endif #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMD { .name = "fimd", @@ -1021,7 +1007,6 @@ static void __init exynos5_reserve_mem(void) }, }; static const char map[] __initconst = - "android_pmem.0=pmem;android_pmem.1=pmem_gpu1;" "s3cfb.0=fimd;" "exynos-gsc.0=gsc0;exynos-gsc.1=gsc1;exynos-gsc.2=gsc2;exynos-gsc.3=gsc3;" "ion-exynos=fimd,gsc0,gsc1,gsc2,gsc3;" diff --git a/arch/arm/mach-exynos/mach-u1.c b/arch/arm/mach-exynos/mach-u1.c index ab756ab..ba440d2 100644 --- a/arch/arm/mach-exynos/mach-u1.c +++ b/arch/arm/mach-exynos/mach-u1.c @@ -55,9 +55,6 @@ #if defined(CONFIG_S5P_MEM_CMA) #include <linux/cma.h> #endif -#ifdef CONFIG_ANDROID_PMEM -#include <linux/android_pmem.h> -#endif #include <asm/mach/arch.h> #include <asm/mach-types.h> @@ -198,7 +195,7 @@ static struct wacom_g5_callbacks *wacom_callbacks; #endif /* CONFIG_EPEN_WACOM_G5SP */ -#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH +#if defined(CONFIG_KEYBOARD_CYPRESS_TOUCH) || defined(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN) #include <linux/i2c/touchkey_i2c.h> #endif @@ -3095,7 +3092,11 @@ REGULATOR_INIT(ldo17, "VTF_2.8V", 2800000, 2800000, 0, REGULATOR_INIT(ldo18, "TOUCH_LED_3.3V", 3300000, 3300000, 0, REGULATOR_CHANGE_STATUS, 1); #else +#if defined(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN) && defined(CONFIG_TOUCHKEY_BLN) +REGULATOR_INIT(ldo18, "TOUCH_LED_3.3V", 2500000, 3300000, 0, +#else REGULATOR_INIT(ldo18, "TOUCH_LED_3.3V", 3000000, 3300000, 0, +#endif REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, 1); #endif REGULATOR_INIT(ldo21, "VDDQ_M1M2_1.2V", 1200000, 1200000, 1, @@ -6194,7 +6195,7 @@ static void p6_wacom_register_callbacks(struct wacom_g5_callbacks *cb) #ifdef CONFIG_S3C_DEV_I2C8_EMUL static struct i2c_board_info i2c_devs8_emul[]; #endif -#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH +#if defined(CONFIG_KEYBOARD_CYPRESS_TOUCH) || defined(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN) static void touchkey_init_hw(void) { gpio_request(GPIO_3_TOUCH_INT, "3_TOUCH_INT"); @@ -6295,7 +6296,7 @@ static struct touchkey_platform_data touchkey_pdata = { .power_on = touchkey_power_on, .led_power_on = touchkey_led_power_on, }; -#endif /*CONFIG_KEYBOARD_CYPRESS_TOUCH*/ +#endif /*(CONFIG_KEYBOARD_CYPRESS_TOUCH) || (CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN)*/ @@ -6448,7 +6449,7 @@ struct platform_device s3c_device_i2c8 = { /* I2C8 */ static struct i2c_board_info i2c_devs8_emul[] = { -#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH +#if defined(CONFIG_KEYBOARD_CYPRESS_TOUCH) || defined(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN) { I2C_BOARD_INFO("sec_touchkey", 0x20), .platform_data = &touchkey_pdata, @@ -7128,53 +7129,6 @@ static void __init mipi_fb_init(void) } #endif -#ifdef CONFIG_ANDROID_PMEM -static struct android_pmem_platform_data pmem_pdata = { - .name = "pmem", - .no_allocator = 1, - .cached = 0, - .start = 0, - .size = 0 -}; - -static struct android_pmem_platform_data pmem_gpu1_pdata = { - .name = "pmem_gpu1", - .no_allocator = 1, - .cached = 0, - .start = 0, - .size = 0, -}; - -static struct platform_device pmem_device = { - .name = "android_pmem", - .id = 0, - .dev = { - .platform_data = &pmem_pdata}, -}; - -static struct platform_device pmem_gpu1_device = { - .name = "android_pmem", - .id = 1, - .dev = { - .platform_data = &pmem_gpu1_pdata}, -}; - -static void __init android_pmem_set_platdata(void) -{ -#if defined(CONFIG_S5P_MEM_CMA) - pmem_pdata.size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM * SZ_1K; - pmem_gpu1_pdata.size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 * SZ_1K; -#else - pmem_pdata.start = (u32) s5p_get_media_memory_bank(S5P_MDEV_PMEM, 0); - pmem_pdata.size = (u32) s5p_get_media_memsize_bank(S5P_MDEV_PMEM, 0); - pmem_gpu1_pdata.start = - (u32) s5p_get_media_memory_bank(S5P_MDEV_PMEM_GPU1, 0); - pmem_gpu1_pdata.size = - (u32) s5p_get_media_memsize_bank(S5P_MDEV_PMEM_GPU1, 0); -#endif -} -#endif - /* USB EHCI */ #ifdef CONFIG_USB_EHCI_S5P static struct s5p_ehci_platdata smdkc210_ehci_pdata; @@ -7479,10 +7433,6 @@ static struct platform_device *smdkc210_devices[] __initdata = { &s5p_device_cec, &s5p_device_hpd, #endif -#ifdef CONFIG_ANDROID_PMEM - &pmem_device, - &pmem_gpu1_device, -#endif #ifdef CONFIG_VIDEO_FIMC &s3c_device_fimc0, &s3c_device_fimc1, @@ -7645,20 +7595,6 @@ static void __init exynos4_cma_region_reserve(struct cma_region *regions_normal, static void __init exynos4_reserve_mem(void) { static struct cma_region regions[] = { -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM - { - .name = "pmem", - .size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM * SZ_1K, - .start = 0, - }, -#endif -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 - { - .name = "pmem_gpu1", - .size = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 * SZ_1K, - .start = 0, - }, -#endif #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMD { .name = "fimd", @@ -7766,7 +7702,6 @@ static void __init exynos4_reserve_mem(void) }; static const char map[] __initconst = - "android_pmem.0=pmem;android_pmem.1=pmem_gpu1;" "s3cfb.0=fimd;exynos4-fb.0=fimd;samsung-pd.1=fimd;" "s3c-fimc.0=fimc0;s3c-fimc.1=fimc1;s3c-fimc.2=fimc2;s3c-fimc.3=fimc3;" "exynos4210-fimc.0=fimc0;exynos4210-fimc.1=fimc1;" @@ -7983,7 +7918,7 @@ static void __init smdkc210_machine_init(void) ARRAY_SIZE(tuna_i2c15_boardinfo)); #endif #ifdef CONFIG_S3C_DEV_I2C8_EMUL -#ifdef CONFIG_KEYBOARD_CYPRESS_TOUCH +#if defined(CONFIG_KEYBOARD_CYPRESS_TOUCH) || defined(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN) touchkey_init_hw(); #endif i2c_register_board_info(8, i2c_devs8_emul, ARRAY_SIZE(i2c_devs8_emul)); @@ -8095,9 +8030,6 @@ static void __init smdkc210_machine_init(void) s3c24xx_ts1_set_platdata(&s3c_ts_platform); #endif #endif -#ifdef CONFIG_ANDROID_PMEM - android_pmem_set_platdata(); -#endif #ifdef CONFIG_VIDEO_FIMC /* fimc */ s3c_fimc0_set_platdata(&fimc_plat); diff --git a/arch/arm/mach-exynos/reserve_mem-exynos4.c b/arch/arm/mach-exynos/reserve_mem-exynos4.c index c48c64f..bd0d332 100644 --- a/arch/arm/mach-exynos/reserve_mem-exynos4.c +++ b/arch/arm/mach-exynos/reserve_mem-exynos4.c @@ -49,28 +49,6 @@ struct s5p_media_device media_devs[] = { }, #endif -#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS) -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM - { - .id = S5P_MDEV_PMEM, - .name = "pmem", - .bank = 0, - .memsize = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM * SZ_1K, - .paddr = 0, - }, -#endif - -#ifdef CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 - { - .id = S5P_MDEV_PMEM_GPU1, - .name = "pmem_gpu1", - .bank = 0, - .memsize = CONFIG_ANDROID_PMEM_MEMSIZE_PMEM_GPU1 * SZ_1K, - .paddr = 0, - }, -#endif -#endif - #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC0 { .id = S5P_MDEV_FIMC0, diff --git a/arch/arm/mach-exynos/sec_watchdog.c b/arch/arm/mach-exynos/sec_watchdog.c index b903b80..4ee118a 100644 --- a/arch/arm/mach-exynos/sec_watchdog.c +++ b/arch/arm/mach-exynos/sec_watchdog.c @@ -69,7 +69,7 @@ static spinlock_t wdt_lock; #if defined(PET_BY_WORKQUEUE) static void watchdog_workfunc(struct work_struct *work) { - pr_info("%s kicking...%x\n", __func__, readl(S3C2410_WTCNT)); + pr_debug("%s kicking...%x\n", __func__, readl(S3C2410_WTCNT)); writel(watchdog_reset * TPS, S3C2410_WTCNT); queue_delayed_work_on(0, watchdog_wq, &watchdog_work, watchdog_pet * HZ); @@ -77,7 +77,7 @@ static void watchdog_workfunc(struct work_struct *work) #elif defined(PET_BY_DIRECT_TIMER) static void pet_watchdog_timer_fn(unsigned long data) { - pr_info("%s kicking...%x\n", __func__, readl(S3C2410_WTCNT)); + pr_debug("%s kicking...%x\n", __func__, readl(S3C2410_WTCNT)); writel(watchdog_reset * TPS, S3C2410_WTCNT); pet_watchdog_timer.expires += watchdog_pet * HZ; add_timer_on(&pet_watchdog_timer, 0); @@ -85,7 +85,7 @@ static void pet_watchdog_timer_fn(unsigned long data) #else static enum hrtimer_restart watchdog_timerfunc(struct hrtimer *timer) { - pr_info("%s kicking...%x\n", __func__, readl(S3C2410_WTCNT)); + pr_debug("%s kicking...%x\n", __func__, readl(S3C2410_WTCNT)); writel(watchdog_reset * TPS, S3C2410_WTCNT); hrtimer_start(&watchdog_timer, ktime_set(watchdog_pet, 0), HRTIMER_MODE_REL); diff --git a/arch/arm/mvp/Kconfig b/arch/arm/mvp/Kconfig deleted file mode 100644 index 4f2c5c7..0000000 --- a/arch/arm/mvp/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config VMWARE_MVP - bool "Build VMware Mobile Virtualization Platform modules" - select MODULES - select MODULE_UNLOAD - select SYSFS - select NAMESPACES - select NET_NS - select INET - select IPV6 - select TUN - select NETFILTER - help - Say Y here to enable the building of kernel modules - for VMware's Mobile Virtualization Platform - -config VMWARE_MVP_DEBUG - bool "Enable debug for VMware Mobile Virtualization Platform modules" - depends on VMWARE_MVP - select IKCONFIG - select IKCONFIG_PROC - help - Say Y here to enable debug on kernel modules - for VMware's Mobile Virtualization Platform. - This should be enabled for eng or userdebug builds. diff --git a/arch/arm/mvp/Makefile b/arch/arm/mvp/Makefile deleted file mode 100644 index cd38d75..0000000 --- a/arch/arm/mvp/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-y += mvpkm/ -obj-y += commkm/ -obj-y += pvtcpkm/ diff --git a/arch/arm/mvp/commkm/COPYING b/arch/arm/mvp/commkm/COPYING deleted file mode 100644 index 10828e0..0000000 --- a/arch/arm/mvp/commkm/COPYING +++ /dev/null @@ -1,341 +0,0 @@ - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/arch/arm/mvp/commkm/Kbuild b/arch/arm/mvp/commkm/Kbuild deleted file mode 100644 index de43a5c..0000000 --- a/arch/arm/mvp/commkm/Kbuild +++ /dev/null @@ -1,9 +0,0 @@ -# Warning: autogenerated -obj-m := commkm.o -commkm-objs := check_kconfig.o comm_ev_kernel.o comm.o comm_os_linux.o comm_os_mod_linux.o comm_svc.o comm_transp_mvp.o - -ccflags-y += -fno-pic -fno-dwarf2-cfi-asm -march=armv7-a -D__linux__ -ccflags-y += -DCOMM_BUILDING_SERVER -ccflags-y += -mfpu=neon -DIN_MODULE -DGPLED_CODE -ccflags-y += --std=gnu89 -O2 -g2 -ggdb -mapcs -fno-optimize-sibling-calls -mno-sched-prolog -ccflags-$(CONFIG_VMWARE_MVP_DEBUG) += -DMVP_DEBUG diff --git a/arch/arm/mvp/commkm/Makefile b/arch/arm/mvp/commkm/Makefile deleted file mode 100644 index 16eb389..0000000 --- a/arch/arm/mvp/commkm/Makefile +++ /dev/null @@ -1 +0,0 @@ -# Warning: autogenerated diff --git a/arch/arm/mvp/commkm/check_kconfig.c b/arch/arm/mvp/commkm/check_kconfig.c deleted file mode 100644 index 0867d74..0000000 --- a/arch/arm/mvp/commkm/check_kconfig.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * @brief Check for required kernel configuration - * - * Check to make sure that the kernel options that the MVP hypervisor requires - * have been enabled in the kernel that this kernel module is being built - * against. - */ -#include <linux/version.h> - -/* - * Minimum kernel version - * - network namespace support is only really functional starting in 2.6.29 - * - Android Gingerbread requires 2.6.35 - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) -#error "MVP requires a host kernel newer than 2.6.35" -#endif - -/* module loading ability */ -#ifndef CONFIG_MODULES -#error "MVP requires kernel loadable module support be enabled (CONFIG_MODULES)" -#endif -#ifndef CONFIG_MODULE_UNLOAD -#error "MVP requires kernel module unload support be enabled (CONFIG_MODULE_UNLOAD)" -#endif - -/* sysfs */ -#ifndef CONFIG_SYSFS -#error "MVP requires sysfs support (CONFIG_SYSFS)" -#endif - -/* network traffic isolation */ -#ifndef CONFIG_NAMESPACES -#error "MVP networking support requires namespace support (CONFIG_NAMESPACES)" -#endif -#ifndef CONFIG_NET_NS -#error "MVP networking support requires Network Namespace support to be enabled (CONFIG_NET_NS)" -#endif - -/* TCP/IP networking */ -#ifndef CONFIG_INET -#error "MVP networking requires IPv4 support (CONFIG_INET)" -#endif -#ifndef CONFIG_IPV6 -#error "MVP networking requires IPv6 support (CONFIG_IPV6)" -#endif - -/* VPN support */ -#if !defined(CONFIG_TUN) && !defined(CONFIG_TUN_MODULE) -#error "MVP VPN support requires TUN device support (CONFIG_TUN)" -#endif - -#if !defined(CONFIG_NETFILTER) && !defined(PVTCP_DISABLE_NETFILTER) -#error "MVP networking support requires netfilter support (CONFIG_NETFILTER)" -#endif - -/* Force /proc/config.gz support for eng/userdebug builds */ -#ifdef MVP_DEBUG -#if !defined(CONFIG_IKCONFIG) || !defined(CONFIG_IKCONFIG_PROC) -#error "MVP kernel /proc/config.gz support required for debuggability (CONFIG_IKCONFIG_PROC)" -#endif -#endif - -/* Sanity check we're only dealing with the memory hotplug + migrate and/or - * compaction combo */ -#ifdef CONFIG_MIGRATION -#if defined(CONFIG_NUMA) || defined(CONFIG_CPUSETS) || defined(CONFIG_MEMORY_FAILURE) -#error "MVP not tested with migration features other than CONFIG_MEMORY_HOTPLUG and CONFIG_COMPACTION" -#endif -#endif diff --git a/arch/arm/mvp/commkm/comm.c b/arch/arm/mvp/commkm/comm.c deleted file mode 100644 index 8fd591c..0000000 --- a/arch/arm/mvp/commkm/comm.c +++ /dev/null @@ -1,1457 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Communication functions based on transport functionality. - */ - -#include "comm.h" -#include "comm_transp_impl.h" - - -/* Constant and macro definitions */ - -#if defined(COMM_INSTRUMENT) -static CommOSAtomic commMaxCoalesceSize; -static CommOSAtomic commPacketsReceived; -static CommOSAtomic commCommittedPacketsReceived; -static CommOSAtomic commOpCalls; -#endif - -#define COMM_DISPATCH_EXTRA_WRITER_WAKEUP 1 - -#define COMM_CHANNEL_MAX_CAPACITY 2048 -#define COMM_CHANNEL_FREE 0x0 -#define COMM_CHANNEL_INITIALIZED 0x1 -#define COMM_CHANNEL_OPENED 0x2 -#define COMM_CHANNEL_ACTIVE 0x4 -#define COMM_CHANNEL_ZOMBIE 0x8 - -#define CommIsFree(chan) \ - ((chan)->lifecycleState == COMM_CHANNEL_FREE) -#define CommIsInitialized(chan) \ - ((chan)->lifecycleState == COMM_CHANNEL_INITIALIZED) -#define CommIsOpened(chan) \ - ((chan)->lifecycleState == COMM_CHANNEL_OPENED) -#define CommIsActive(chan) \ - ((chan)->lifecycleState == COMM_CHANNEL_ACTIVE) -#define CommIsZombie(chan) \ - ((chan)->lifecycleState == COMM_CHANNEL_ZOMBIE) - -#define CommSetFree(chan) \ - SetLifecycleState(chan, COMM_CHANNEL_FREE) -#define CommSetInitialized(chan) \ - SetLifecycleState(chan, COMM_CHANNEL_INITIALIZED) -#define CommSetOpened(chan) \ - SetLifecycleState(chan, COMM_CHANNEL_OPENED) -#define CommSetActive(chan) \ - SetLifecycleState(chan, COMM_CHANNEL_ACTIVE) -#define CommSetZombie(chan) \ - SetLifecycleState(chan, COMM_CHANNEL_ZOMBIE) - -#define CommGlobalLock() CommOS_SpinLock(&commGlobalLock) -#define CommGlobalUnlock() CommOS_SpinUnlock(&commGlobalLock) -#define CommGlobalLockBH() CommOS_SpinLockBH(&commGlobalLock) -#define CommGlobalUnlockBH() CommOS_SpinUnlockBH(&commGlobalLock) - -#define DispatchTrylock(chan) CommOS_MutexTrylock(&(chan)->dispatchMutex) -#define DispatchUnlock(chan) CommOS_MutexUnlock(&(chan)->dispatchMutex) - -#define WriteLock(chan) CommOS_MutexLock(&(chan)->writeMutex) -#define WriteTrylock(chan) CommOS_MutexTrylock(&(chan)->writeMutex) -#define WriteUnlock(chan) CommOS_MutexUnlock(&(chan)->writeMutex) - -#define StateLock(chan) CommOS_MutexLock(&(chan)->stateMutex) -#define StateTrylock(chan) CommOS_MutexTrylock(&(chan)->stateMutex) -#define StateUnlock(chan) CommOS_MutexUnlock(&(chan)->stateMutex) - -#define CommHoldInit(chan) CommOS_WriteAtomic(&(chan)->holds, 0) -#define CommHold(chan) CommOS_AddReturnAtomic(&(chan)->holds, 1) -#define CommRelease(chan) CommOS_SubReturnAtomic(&(chan)->holds, 1) -#define CommIsHeld(chan) (CommOS_ReadAtomic(&(chan)->holds) > 0) - -#define PacketLenOverLimit(chan, len) \ - (((len) - sizeof (CommPacket)) > ((chan)->transpArgs.capacity / 4)) - - -/* - * Data structure describing the offload <-> paravirtualized module - * communication channel. - */ - -struct CommChannelPriv { - CommOSAtomic holds; // Active readers and writers - CommTranspInitArgs transpArgs; // Transport initialization arguments - CommTransp transp; // Transport handle - CommOSMutex dispatchMutex; // Dispatch mutex - CommOSMutex writeMutex; // Non-BH write mutex - CommOSMutex stateMutex; // Upper-layer state mutex - CommOSWaitQueue availableWaitQ; // Available write space wait data - unsigned int desiredWriteSpace; // Size of write space needed - const CommImpl *impl; // Implementation - unsigned int implNmbOps; // Number of implementation operations - unsigned int lifecycleState; // Lifecycle state - void *state; // Upper layer-specific state -}; - - -static volatile int running; // Initialized and running. -static CommOSWaitQueue exitWaitQ; // Exit wait queue. -static CommOSSpinlock commGlobalLock; // Global lock. - - -/* Communication channel slots. */ - -static unsigned int commChannelCapacity; // Maximum number of channels. -static unsigned int commChannelSize; // Current size of channel array. -static unsigned int commChannelAllocated; // Nmb. entries currently in use. -static struct CommChannelPriv *commChannels; // Allocated channel array. - - -/** - * @brief Callback function called when the other side created a transport - * handle to which we need to potentially attach. - * @param[in,out] transpArgs arguments used when shared memory area was created. - * @param probeData our callback data, an implementation block. - * @return 0 if successful, -1 otherwise. - * @sideeffects May allocate a channel. - */ - -static int -DefaultTranspListener(CommTranspInitArgs *transpArgs, - void *probeData) -{ - int rc = -1; - const int inBH = 1; - const CommImpl *impl; - - if (!transpArgs || !probeData) { - CommOS_Debug(("%s: NULL args [0x%p, 0x%p].\n", - __FUNCTION__, transpArgs, probeData)); - goto out; - } - - impl = probeData; - CommOS_Debug(("%s: Received attach info [%u,%u,%u:%u].\n", - __FUNCTION__, - transpArgs->capacity, transpArgs->type, - transpArgs->id.d32[0], transpArgs->id.d32[1])); - - if (impl->checkArgs(transpArgs)) { - goto out; - } - transpArgs->mode = COMM_TRANSP_INIT_ATTACH; /* Ensure we attach. */ - - /* We recognized it, so don't let others waste any time. Even if we fail. */ - - rc = 0; - if (Comm_Alloc(transpArgs, impl, inBH, NULL)) { - impl->closeNtf(impl->closeNtfData, transpArgs, inBH); - CommOS_Log(("%s: Can't allocate new channel!\n", __FUNCTION__)); - } - -out: - return rc; -} - - -/** - * @brief Sets the lifecycle state of a channel entry - * @param channel channel to update - * @param newState state to update to - */ - -static inline void -SetLifecycleState(CommChannel channel, - unsigned int newState) -{ - - channel->lifecycleState = newState; -} - - -/* Wait conditions: functions returning 1: true, 0: false, < 0: error. */ - -/** - * @brief Wait condition function to check whether module can be unloaded. - * @param arg1 dummy - * @param arg2 dummy - * @return 1 if no channels are currently allocated, 0 if there are - */ - -static int -ExitCondition(void *arg1, - void *arg2) -{ - unsigned int i; - int rc; - - (void)arg1; - (void)arg2; - CommOS_Debug(("%s: running [%d] " - "commChannelAllocated [%u] commChannelSize [%u].\n", - __FUNCTION__, running, commChannelAllocated, commChannelSize)); - rc = !running && (commChannelAllocated == 0); - if (!rc) { - for (i = 0; i < commChannelCapacity; i++) { - CommOS_Debug(("%s: channel[%u] state [0x%x].\n", - __FUNCTION__, i, commChannels[i].lifecycleState)); - } - } - return rc; -} - - -/** - * @brief Wait condition function to check available write space. - * @param arg1 pointer to CommChannel struct - * @param arg2 size argument - * @return 1 if there is enough write space, 0 if not, -ENOMEM if comm down. - */ - -static int -WriteSpaceCondition(void *arg1, - void *arg2) -{ - CommChannel channel = arg1; - - if (!CommIsActive(channel)) { - return -ENOMEM; - } - return channel->desiredWriteSpace < CommTransp_EnqueueSpace(channel->transp); -} - - -/** - * @brief Registers an implementation block used when attaching to channels - * in response to transport attach events. - * @param impl implementation block. - * @return 0 if successful, non-zero otherwise. - */ - -int -Comm_RegisterImpl(const CommImpl *impl) -{ - CommTranspListener listener = { - .probe = DefaultTranspListener, - .probeData = (void *)impl - }; - - return CommTransp_Register(&listener); -} - - -/** - * @brief Unregisters an implementation block used when attaching to channels - * in response to transport attach events. - * @param impl implementation block. - */ - -void -Comm_UnregisterImpl(const CommImpl *impl) -{ - CommTranspListener listener = { - .probe = DefaultTranspListener, - .probeData = (void *)impl - }; - - CommTransp_Unregister(&listener); -} - - -/** - * @brief Allocates and initializes comm global state. Single-threaded use. - * @param maxChannels maximum number of channels. - * @return zero if successful, non-zero otherwise. - */ - -int -Comm_Init(unsigned int maxChannels) -{ - int rc = -1; - unsigned int i; - - if (running || commChannels || - (maxChannels == 0) || (maxChannels > COMM_CHANNEL_MAX_CAPACITY)) { - goto out; - } - -#if defined(COMM_INSTRUMENT) - CommOS_WriteAtomic(&commMaxCoalesceSize, 0); - CommOS_WriteAtomic(&commPacketsReceived, 0); - CommOS_WriteAtomic(&commCommittedPacketsReceived, 0); - CommOS_WriteAtomic(&commOpCalls, 0); -#endif - - CommOS_WaitQueueInit(&exitWaitQ); - CommOS_SpinlockInit(&commGlobalLock); - commChannelCapacity = maxChannels; - commChannelAllocated = 0; - commChannels = CommOS_Kmalloc((sizeof *commChannels) * commChannelCapacity); - if (!commChannels) { - goto out; - } - - memset(commChannels, 0, (sizeof *commChannels) * commChannelCapacity); - for (i = 0; i < commChannelCapacity; i++ ) { - CommChannel channel; - - channel = &commChannels[i]; - CommHoldInit(channel); - channel->transp = NULL; - CommOS_MutexInit(&channel->dispatchMutex); - CommOS_MutexInit(&channel->writeMutex); - CommOS_MutexInit(&channel->stateMutex); - CommOS_WaitQueueInit(&channel->availableWaitQ); - channel->desiredWriteSpace = -1U; - channel->state = NULL; - CommSetFree(channel); - } - - rc = CommTransp_Init(); - if (!rc) { - commChannelSize = 0; - running = 1; - rc = 0; - } else { - CommOS_Kfree(commChannels); - } - -out: - return rc; -} - - -/** - * @brief Initiates and finishes, comm global state deallocations. - * @param timeoutMillis initialization timeout in milliseconds - * @return zero if deallocations done, non-zero if more calls are needed. - */ - -int -Comm_Finish(unsigned long long *timeoutMillis) -{ - int rc; - unsigned int i; - unsigned long long timeout; - - for (i = 0; i < commChannelSize; i++) { - Comm_Zombify(&commChannels[i], 0); - } - - running = 0; - timeout = timeoutMillis ? *timeoutMillis : 0; - /* coverity[var_deref_model] */ - rc = CommOS_Wait(&exitWaitQ, ExitCondition, NULL, NULL, &timeout); - if (rc == 1) { - /* - * Didn't time out, task wasn't interrupted, we can wrap it up.. - */ - - CommTransp_Exit(); - CommOS_Kfree(commChannels); - commChannels = NULL; - commChannelSize = 0; -#if defined(COMM_INSTRUMENT) - CommOS_Log(("%s: commMaxCoalesceSize = %lu.\n", - __FUNCTION__, - CommOS_ReadAtomic(&commMaxCoalesceSize))); - CommOS_Log(("%s: commPacketsReceived = %lu.\n", - __FUNCTION__, - CommOS_ReadAtomic(&commPacketsReceived))); - CommOS_Log(("%s: commCommittedPacketsReceived = %lu.\n", - __FUNCTION__, - CommOS_ReadAtomic(&commCommittedPacketsReceived))); - CommOS_Log(("%s: commOpCalls = %lu.\n", - __FUNCTION__, - CommOS_ReadAtomic)(&commOpCalls))); -#endif - rc = 0; - } else { - rc = -1; - } - return rc; -} - - -/** - * @brief Finds a free entry and initializes it with the information provided. - * May be called from BH. It doesn't call potentially blocking functions. - * - * @note Depending on the choice of shared memory transport (VMCI or MVP QP), - * the 'inBH' distinction is important. VMCI datagrams are received under - * some circumstances in bottom-half context, so 'inBH' should be set. This - * is not a restriction on MVP. - * - * @param transpArgs transport initialization arguments. - * @param impl implementation block. - * @param inBH non-zero if called in bottom half. - * @param[out] newChannel newly allocated channel. - * @return zero if successful, non-zero otherwise. - * @sideeffects Initializes the communications channel with given parameters - */ - -int -Comm_Alloc(const CommTranspInitArgs *transpArgs, - const CommImpl *impl, - int inBH, - CommChannel *newChannel) -{ - unsigned int i; - CommChannel channel = NULL; - int restoreSize = 0; - int modHeld = 0; - int rc = -1; - - if (inBH) { - CommGlobalLock(); - } else { - CommGlobalLockBH(); - } - - if (!running || !transpArgs || !impl) { - goto out; - } - - if (CommOS_ModuleGet(impl->owner)) { - goto out; - } - modHeld = 1; - - for (i = 0; i < commChannelSize; i++) { - /* - * Check if this channel is already allocated. We don't match against - * ANY because those channels are in the process of being opened; after - * that happens, they'll get proper IDs. - */ - - if (!CommIsFree(&commChannels[i]) && - (transpArgs->id.d64 != COMM_TRANSP_ID_64_ANY) && - (transpArgs->id.d64 == commChannels[i].transpArgs.id.d64)) { - goto out; - } - if (!channel && CommIsFree(&commChannels[i])) { - channel = &commChannels[i]; - } - } - if (!channel) { - if (commChannelSize == commChannelCapacity) { - goto out; - } - channel = &commChannels[commChannelSize]; - commChannelSize++; - restoreSize = 1; - } - - if (channel->transp) { /* Inconsistency! */ - if (restoreSize) { - commChannelSize--; - } - goto out; - } - - channel->transpArgs = *transpArgs; - channel->impl = impl; - for (i = 0; impl->operations[i]; i++) { - ; - } - channel->implNmbOps = i; - channel->desiredWriteSpace = -1U; - commChannelAllocated++; - CommSetInitialized(channel); - if (newChannel) { - *newChannel = channel; - } - rc = 0; - CommOS_ScheduleDisp(); - -out: - if (inBH) { - CommGlobalUnlock(); - } else { - CommGlobalUnlockBH(); - } - if (rc && modHeld) { - CommOS_ModulePut(impl->owner); - } - return rc; -} - - -/** - * @brief Zombifies a channel. May fail if channel isn't active. - * @param[in,out] channel channel to zombify. - * @param inBH non-zero if called in bottom half. - * @return zero if channel zombified, non-zero otherwise. - */ - -int -Comm_Zombify(CommChannel channel, - int inBH) -{ - int rc = -1; - - if (!running) { - goto out; - } - if (inBH) { - CommGlobalLock(); - } else { - CommGlobalLockBH(); - } - if (CommIsActive(channel) || CommIsOpened(channel)) { - CommSetZombie(channel); - rc = 0; - } - if (inBH) { - CommGlobalUnlock(); - } else { - CommGlobalUnlockBH(); - } - -out: - if (!rc) { - CommOS_ScheduleDisp(); - } - return rc; -} - - -/** - * @brief Reports whether a channel is active. - * @param channel channel to report on. - * @return non-zero if channel active, zero otherwise. - */ - -int -Comm_IsActive(CommChannel channel) -{ - return channel ? CommIsActive(channel) : 0; -} - - -/** - * @brief Wakes up potential writer on the channel. This function must be - * called on an active channel, with either the dispatch lock taken, or - * the channel ref count incremented. - * @param channel CommChannel structure on which potential writer waits. - */ - -static inline void -WakeUpWriter(CommChannel channel) -{ - if (WriteSpaceCondition(channel, NULL)) { - CommOS_WakeUp(&channel->availableWaitQ); - } -} - - -/** - * @brief Transport event handler for comm channels. - * @param transp transport handle. - * @param event type of event. - * @param data callback data. - * @sideeffects may put the channel into zombie state, or schedule it for I/O. - */ - -static void -TranspEventHandler(CommTransp transp, - CommTranspIOEvent event, - void *data) -{ - CommChannel channel = (CommChannel)data; - - switch (event) { - case COMM_TRANSP_IO_DETACH: - CommOS_Debug(("%s: Detach event. Zombifying channel.\n", __FUNCTION__)); - Comm_Zombify(channel, 1); - break; - - case COMM_TRANSP_IO_IN: - case COMM_TRANSP_IO_INOUT: - /* - * The dispatch threads may not have been started because either: - * a) we're not running in the CommSvc service, or - * b) the Comm client didn't create them explicitly (CommOS_StartIO()). - * - * If so, the CommOS_ScheduleDisp() call is ineffective. This is - * the intended behavior: the client obviously wants to call the Comm - * dispatch function(s) directly. - */ - - CommOS_ScheduleDisp(); - break; - - case COMM_TRANSP_IO_OUT: - CommHold(channel); - if (CommIsActive(channel)) { - WakeUpWriter(channel); - } - CommRelease(channel); - if (CommIsZombie(channel)) { - /* - * After releasing the hold on the channel, we must check if it was - * set to zombie and the dispatcher was supposed to nuke it. If the - * dispatcher had made its run while we were holding the channel, it - * gave up. So schedule it. - */ - - CommOS_ScheduleDisp(); - } - break; - - default: - CommOS_Debug(("%s: Unhandled event [%u, %p, %p].\n", - __FUNCTION__, event, transp, data)); - } -} - - -/** - * @brief Destroys upper layer state, unregisters event handlers and - * detaches from or deletes shared memory. - * @param[in,out] channel CommChannel structure to close. - */ - -static void -CommClose(CommChannel channel) -{ - const CommImpl *impl = channel->impl; - - StateLock(channel); - if (impl->stateDtor && channel->state) { - impl->stateDtor(channel->state); - } - channel->state = NULL; - StateUnlock(channel); - - CommOS_ModulePut(impl->owner); - - if (channel->transp) { - CommTransp_Close(channel->transp); - channel->transp = NULL; - } - - CommGlobalLockBH(); - CommSetFree(channel); - commChannelAllocated--; - if (channel == &commChannels[commChannelSize - 1]) { - commChannelSize--; - } - CommGlobalUnlockBH(); - if (!running && (commChannelAllocated == 0)) { - CommOS_WakeUp(&exitWaitQ); - } -} - - -/** - * @brief Allocates upper layer state, registers transport event handler - * and creates or attaches to shared memory. - * @param[in,out] channel CommChannel structure to open. - * @return zero if successful, -1 otherwise - * @sideeffects Memory may be allocated, event handlers registered and - * QP allocated or attached to. - */ - -static int -CommOpen(CommChannel channel) -{ - int rc = -1; - CommTranspEvent transpEvent = { - .ioEvent = TranspEventHandler, - .ioEventData = channel - }; - const CommImpl *impl; - - if (!channel || !CommIsInitialized(channel)) { - return rc; - } - - if (!running) { /* Ok, toggle it back to FREE. */ - goto out; - } - - impl = channel->impl; - if (impl->stateCtor) { - channel->state = impl->stateCtor(channel); - if (!channel->state) { - goto out; - } - } - - if (!CommTransp_Open(&channel->transp, &channel->transpArgs, &transpEvent)) { - rc = 0; - } else { - channel->transp = NULL; - } - -out: - if (!rc) { - CommSetOpened(channel); - } else { - CommClose(channel); - } - return rc; -} - - -/** - * @brief Retrieves a channel's transport initialization arguments. - * It doesn't lock, the caller must ensure the channel may be accessed. - * @param channel CommChannel structure to get initialization arguments from. - * @return initialization arguments used to allocate/attach to channel. - */ - -CommTranspInitArgs -Comm_GetTranspInitArgs(CommChannel channel) -{ - if (!channel) { - CommTranspInitArgs res = { .capacity = 0 }; - - return res; - } - return channel->transpArgs; -} - - -/** - * @brief Retrieves upper layer state (pointer). It doesn't lock, the caller - * must ensure the channel may be accessed. - * @param channel CommChannel structure to get state from. - * @return pointer to upper layer state. - */ - -void * -Comm_GetState(CommChannel channel) -{ - if (!channel) { - return NULL; - } - return channel->state; -} - - -/** - * @brief Main input processing function operating on a given channel. - * @param channel CommChannel structure to process. - * @return number of processed channels (0 or 1), or -1 if channel closed. - * @sideeffects Lifecycle states are transitioned to and from. Channel may - * be opened or destroyed, waiting writers may be woken up, and input - * may be handed off to operation callbacks. - */ - -int -Comm_Dispatch(CommChannel channel) -{ - int rc = 0; - int zombify = 0; - CommPacket packet; - CommPacket firstPacket; - unsigned int dataLen; -#define VEC_SIZE 32 - struct kvec vec[VEC_SIZE]; - unsigned int vecLen; - - /* - * Taking the reader mutex is safe in all cases: entries, including - * free ones, are guaranteed to have initialized mutexes and locks. - * Locking empty entries may seem wasteful, but those entries are rare. - */ - - if (DispatchTrylock(channel)) { - return 0; - } - - /* Process input and writer wake-up. */ - - if (CommIsActive(channel)) { - /* - * The entry may have transitioned to ZOMBIE, somehow. That's OK - * since it can't be freed just yet (it's currently locked). - */ - - /* Wake up any waiting writers, if necessary. */ - - WakeUpWriter(channel); - - /* Read packets, payloads. */ - CommTransp_DequeueReset(channel->transp); - - for (vecLen = 0; vecLen < VEC_SIZE; vecLen++) { - if (!running) { - break; - } - - /* Read header. */ - - rc = CommTransp_DequeueSegment(channel->transp, - &packet, sizeof packet); - if (rc <= 0) { - /* No packet (header). */ - - rc = vecLen == 0 ? 0 : 1; - break; - } -#if defined(COMM_INSTRUMENT) - CommOS_AddReturnAtomic(commPacketsReceived, 1); -#endif - if ((rc != sizeof packet) || (packet.len < sizeof packet)) { - rc = -1; /* Fatal protocol error, close down comm. */ - break; - } - rc = 1; - - /* Read payload, if any. */ - - dataLen = packet.len - sizeof packet; - if (vecLen == 0) { - /* Save header of first packet. */ - - firstPacket = packet; - if (dataLen == 0) { - /* Commit no-payload packet read and we're done. */ - - CommTransp_DequeueCommit(channel->transp); -#if defined(COMM_INSTRUMENT) - CommOS_AddReturnAtomic(&commCommittedPacketsReceived, 1); -#endif - break; - } - } else { - /* - * Check if non-equivalent packet or above coalescing limit. - * If so, don't commit the read. - */ - - if (memcmp(&packet.opCode, &firstPacket.opCode, - sizeof packet - offsetof(CommPacket, opCode)) || - PacketLenOverLimit(channel, firstPacket.len + dataLen)) { - break; - } - } - - if (dataLen == 0) { - /* - * Received equivalent packet with zero-sized payload. This may - * happen in certain cases, such as pvtcp forwarding zero-sized - * datagrams. So don't break the loop, but keep going for as - * along as we can. - */ - - vec[vecLen].iov_base = NULL; - goto dequeueCommit; - } - - /* The packet has a payload (dataLen > 0). */ - - if (!(vec[vecLen].iov_base = channel->impl->dataAlloc(dataLen))) { - /* - * We treat out-of-(net?-)memory errors as "nothing to read". - * Memory pressure may either subside, in which case a future - * read may be successful, or be severe enough for the kernel - * to oops, anyway. Leave packet uncommitted. - */ - - CommOS_Debug(("%s: COULD NOT ALLOC PAYLOAD BYTES!\n", - __FUNCTION__)); - rc = vecLen == 0 ? 0 : 1; - break; - } - - /* Read payload and commit (packet and payload). */ - - rc = CommTransp_DequeueSegment(channel->transp, - vec[vecLen].iov_base, dataLen); - if (rc != dataLen) { - channel->impl->dataFree(vec[vecLen].iov_base); - CommOS_Log(("%s: BOOG -- COULD NOT DEQUEUE PAYLOAD! [%d != %u]", - __FUNCTION__, rc, dataLen)); - rc = -1; /* Fatal protocol error, close down comm. */ - break; - } - rc = 1; - -dequeueCommit: - CommTransp_DequeueCommit(channel->transp); -#if defined(COMM_INSTRUMENT) - CommOS_AddReturnAtomic(&commCommittedPacketsReceived, 1); -#endif - vec[vecLen].iov_len = dataLen; - if (vecLen > 0) { - firstPacket.len += dataLen; - if (packet.flags) { - /* Update to latest flags _iff_ latter non-zero. */ - - firstPacket.flags = packet.flags; - } - } -#if defined(COMM_INSTRUMENT) - if (firstPacket.len > - CommOS_ReadAtomic(&commMaxCoalesceSize)) { - CommOS_WriteAtomic(&commMaxCoalesceSize, firstPacket.len); - } -#endif - if (COMM_OPF_TEST_ERR(packet.flags)) { - /* If error bit is set, we're done (no more coalescing). */ - - vecLen++; - break; - } - } - - if (rc <= 0) { - if (rc < 0) { - zombify = 1; - rc = 1; - } - goto outUnlockAndFreeIovec; - } - -#if defined(COMM_DISPATCH_EXTRA_WRITER_WAKEUP) - /* Check again if we need to wake up any writers. */ - - WakeUpWriter(channel); -#endif - - if (firstPacket.opCode >= channel->implNmbOps) { - CommOS_Debug(("%s: Ignoring illegal opCode [%u]!\n", - __FUNCTION__, (unsigned int)firstPacket.opCode)); - CommOS_Debug(("%s: Max opCode: %u\n", - __FUNCTION__, channel->implNmbOps)); - goto outUnlockAndFreeIovec; - } - - /* - * NOTE: - * DispatchUnlock() _must_ be called from the operation callback. - * The reason for doing so is that, for better scalability, we want - * it released as soon as possible, BUT: - * - releasing it here, before calling into the operation, doesn't - * let the latter coordinate its own lock acquisition, such as - * potential socket or state locks. - * - alternatively, always releasing the dispatch lock after the - * operation completes, ties up the channel and imposes too much - * serialization between sockets. - * - to prevent the channel from being torn down while an operation - * is in flight (and potentially having released the dispatch lock), - * we increment the ref count on the channel and then release it - * after the function returns. - */ - -#if defined(COMM_INSTRUMENT) - CommOS_AddReturnAtomic(&commOpCalls, 1); -#endif - - CommHold(channel); - channel->impl->operations[firstPacket.opCode](channel, channel->state, - &firstPacket, vec, vecLen); - CommRelease(channel); - goto out; /* No unlocking, see comment above. */ - } - - /* Process state changes. */ - - if (CommIsZombie(channel) && !CommIsHeld(channel)) { - CommTranspInitArgs transpArgs = channel->transpArgs; - void (*closeNtf)(void *, - const CommTranspInitArgs *, - int inBH) = channel->impl->closeNtf; - void *closeNtfData = channel->impl->closeNtfData; - - while (WriteTrylock(channel)) { - /* Take the write lock; kick writers out if necessary. */ - - CommOS_Debug(("%s: Kicking writers out...\n", __FUNCTION__)); - CommOS_WakeUp(&channel->availableWaitQ); - } - WriteUnlock(channel); - - CommOS_Debug(("%s: Nuking zombie channel.\n", __FUNCTION__)); - CommClose(channel); - if (closeNtf) { - closeNtf(closeNtfData, &transpArgs, 0); - } - rc = -1; - } else if (CommIsInitialized(channel) && - (channel->impl->openAtMillis <= - CommOS_GetCurrentMillis())) { - if (!CommOpen(channel)) { - if (channel->transpArgs.mode == COMM_TRANSP_INIT_CREATE) { - /* - * If the attach side doesn't get notified, the entry will - * time out in OPENED and will be collected. - * Note that during the CommOpen(Transp_Open) call, the IDs - * in the transpArgs may have changed. Use those. - */ - - CommTransp_Notify(&channel->impl->ntfCenterID, - &channel->transpArgs); - } else { /* Attach mode */ - packet.len = sizeof packet; - packet.opCode = 0xff; - packet.flags = 0x00; - - /* - * Send out control packet, attach ack, and transition straight - * to ACTIVE. - */ - - rc = CommTransp_EnqueueAtomic(channel->transp, - &packet, sizeof packet); - if (rc == sizeof packet) { - /* Guard against potentially concurrent zombify. */ - - CommGlobalLockBH(); - if (CommIsOpened(channel)) { - CommOS_Debug(("%s: Sent attach ack. Activating channel.\n", - __FUNCTION__)); - CommSetActive(channel); - } - CommGlobalUnlockBH(); - } - } - rc = 1; - } - } else if (CommIsOpened(channel) && - (channel->transpArgs.mode == COMM_TRANSP_INIT_CREATE)) { - /* - * Get control packet (opCode == 0xff), attach ack (flags == 0x0), - * or check whether the channel timed out in OPENED. - */ - - rc = CommTransp_DequeueAtomic(channel->transp, - &packet, sizeof packet); - if (rc == sizeof packet) { - void (*activateNtf)(void *activateNtfData, CommChannel) = NULL; - void *activateNtfData = NULL; - - /* Guard against potentially concurrent zombify. */ - - CommGlobalLockBH(); - if (CommIsOpened(channel) && - (packet.opCode == 0xff) && (packet.flags == 0x0)) { - activateNtf = channel->impl->activateNtf; - activateNtfData = channel->impl->activateNtfData; - - CommSetActive(channel); - CommOS_Debug(("%s: Received attach ack. Activating channel.\n", - __FUNCTION__)); - } - CommHold(channel); - CommGlobalUnlockBH(); - - if (activateNtf) { - /* The callback must be short and 'put' the channel when done. */ - - activateNtf(activateNtfData, channel); - } else { - /* Don't forget to put back the channel if no activate callback. */ - - CommRelease(channel); - } - } else if ((channel->impl->openTimeoutAtMillis <= - CommOS_GetCurrentMillis()) || - !running) { - zombify = 1; - CommOS_Debug(("%s: Zombifying expired opened channel.\n", - __FUNCTION__)); - } - rc = 1; - } - DispatchUnlock(channel); - -out: - if (zombify) { - Comm_Zombify(channel, 0); - } - return rc; - -outUnlockAndFreeIovec: - DispatchUnlock(channel); - for ( ; vecLen; ) { - if (vec[--vecLen].iov_base) { - channel->impl->dataFree(vec[vecLen].iov_base); - vec[vecLen].iov_base = NULL; - } - vec[vecLen].iov_len = 0; - } - goto out; -#undef VEC_SIZE -} - - -/** - * @brief Main input processing function operating on all channels. - * @return number of processed channels. - * @sideeffects Lifecycle states are transitioned to and from. Channels may - * be opened and destroyed, waiting writers may be woken up, and input - * may be handed off to operation callbacks. - */ - -unsigned int -Comm_DispatchAll(void) -{ - unsigned int i; - unsigned int hits; - - for (hits = 0, i = 0; running && (i < commChannelSize); i++) { - hits += !!Comm_Dispatch(&commChannels[i]); - } - return hits; -} - - -/** - * @brief Writes a fully formatted packet (containing payload data, if - * applicable) to the specified channel. - * - * The operation may block until enough write space is available, but no - * more than the specified interval. The operation either writes the full - * amount of bytes, or it fails. Warning: callers must _not_ use the - * _Lock/_Unlock functions to bracket calls to this function. - * @param[in,out] channel channel to write to. - * @param packet packet to write. - * @param[in,out] timeoutMillis interval in milliseconds to wait. - * @return number of bytes written, 0 if it times out, -1 error. - * @sideeffects Data may be written to the channel. - */ - -int -Comm_Write(CommChannel channel, - const CommPacket *packet, - unsigned long long *timeoutMillis) -{ - int rc = -1; - int zombify; - - if (!channel || !timeoutMillis || - !packet || (packet->len < sizeof *packet)) { - return rc; - } - - zombify = (*timeoutMillis >= COMM_MAX_TO); - - WriteLock(channel); - if (!CommIsActive(channel)) { - goto out; - } - - CommTransp_EnqueueReset(channel->transp); - channel->desiredWriteSpace = packet->len; - rc = CommOS_DoWait(&channel->availableWaitQ, WriteSpaceCondition, - channel, NULL, timeoutMillis, - (*timeoutMillis != COMM_MAX_TO_UNINT)); - channel->desiredWriteSpace = -1U; - - if (rc) { /* Don't zombify, if it didn't time out. */ - zombify = 0; - } - if (rc == 1) { /* Enough write space, enqueue the packet. */ - rc = CommTransp_EnqueueAtomic(channel->transp, packet, packet->len); - if (rc != packet->len) { - zombify = 1; - rc = -1; /* Fatal protocol error. */ - } - } - -out: - WriteUnlock(channel); - if (zombify) { - Comm_Zombify(channel, 0); - } - return rc; -} - - -/** - * @brief Writes a packet and associated payload data to the specified channel. - * The operation may block until enough write space is available, but - * not more than the specified interval. - * The operation either writes the full amount of bytes, or it fails. - * If there is not enough data in the vector, padding will be added to - * reach the specified packet length, if the flags parameter requires it. - * Users may call this function successively to write several packets - * from large {io|k}vecs, when the flags parameter indicates it. If this - * is the case, the packet header needs to be updated accordingly in - * between calls, for the different (total) lengths. - * Warning: callers must _not_ use the _Lock/_Unlock functions to bracket - * calls to this function. - * @param[in,out] channel the specified channel. - * @param packet packet to write. - * @param[in,out] vec kvec to write from. - * @param[in,out] vecLen length of kvec. - * @param[in,out] timeoutMillis interval in milliseconds to wait. - * @param[in,out] iovOffset must be set to 0 before first call (internal cookie) - * @return number of bytes written, 0 if it timed out, -1 error. - * @sideeffects data may be written to the channel. - */ - -int -Comm_WriteVec(CommChannel channel, - const CommPacket *packet, - struct kvec **vec, - unsigned int *vecLen, - unsigned long long *timeoutMillis, - unsigned int *iovOffset) -{ - int rc; - int zombify; - unsigned int dataLen; - unsigned int vecDataLen; - unsigned int vecNdx; - unsigned int iovLen; - void *iovBase; - - if (!channel || !timeoutMillis || !iovOffset || - !packet || (packet->len < sizeof *packet) || - (((dataLen = packet->len - sizeof *packet) > 0) && - (!*vec || !*vecLen))) { - return -1; - } - - zombify = (*timeoutMillis >= COMM_MAX_TO); - - WriteLock(channel); - if (!CommIsActive(channel)) { - rc = -1; - goto out; - } - - CommTransp_EnqueueReset(channel->transp); - channel->desiredWriteSpace = packet->len; - rc = CommOS_DoWait(&channel->availableWaitQ, WriteSpaceCondition, - channel, NULL, timeoutMillis, - (*timeoutMillis != COMM_MAX_TO_UNINT)); - channel->desiredWriteSpace = -1U; - - if (rc) { /* Don't zombify, if it didn't time out. */ - zombify = 0; - } - if (rc == 1) { /* Enough write space, enqueue the packet. */ - iovLen = 0; - rc = CommTransp_EnqueueSegment(channel->transp, packet, sizeof *packet); - if (rc != sizeof *packet) { - zombify = 1; - rc = -1; /* Fatal protocol error. */ - goto out; - } - - if (dataLen > 0) { - int done = 0; - - for (vecDataLen = 0, vecNdx = 0; vecNdx < *vecLen; vecNdx++) { - if (vecNdx) { - *iovOffset = 0; - } - iovLen = (*vec)[vecNdx].iov_len - *iovOffset; - iovBase = (*vec)[vecNdx].iov_base + *iovOffset; - - if (!iovLen) { - continue; - } - - vecDataLen += iovLen; - if (vecDataLen >= dataLen) { - iovLen -= (vecDataLen - dataLen); - done = 1; - } - - rc = CommTransp_EnqueueSegment(channel->transp, iovBase, iovLen); - if (rc != iovLen) { - zombify = 1; - rc = -1; /* Fatal protocol error, close down comm. */ - goto out; - } - - if (done) { - CommTransp_EnqueueCommit(channel->transp); - if (vecDataLen == dataLen) { - vecNdx++; - *iovOffset = 0; - } else { - *iovOffset += iovLen; - } - *vecLen -= vecNdx; - *vec += vecNdx; - break; - } - } - - if (!done) { - /* - * We exhausted all the bytes in the given vector, but total length - * in the packet header is more than we sent (was available). - * If so, we pad by sending zero bytes to reach length required. - */ - - static char pad[1024]; - unsigned int delta; - unsigned int toSend; - - while (vecDataLen < dataLen) { - delta = dataLen - vecDataLen; - toSend = delta <= sizeof pad ? delta : sizeof pad; - if (toSend == delta) { - done = 1; - } - vecDataLen += toSend; - - rc = CommTransp_EnqueueSegment(channel->transp, pad, toSend); - if (rc != toSend) { - zombify = 1; - rc = -1; /* Fatal protocol error, close down comm. */ - goto out; - } - - if (done) { - CommTransp_EnqueueCommit(channel->transp); - *vec = NULL; - *vecLen = 0; - *iovOffset = 0; - break; - } - } - } - } else { - CommTransp_EnqueueCommit(channel->transp); - } - rc = (int)packet->len; - } else { - CommOS_Debug(("%s: timed out...\n", __FUNCTION__)); - } - -out: - WriteUnlock(channel); - if (zombify) { - Comm_Zombify(channel, 0); - } - return rc; -} - - -/** - * @brief Releases channel ref count. This function is exported for the upper - * layer's 'activateNtf' callback which may be run asynchronously. The - * callback is protected from concurrent channel releases until it calls - * this function. - * @param[in,out] channel CommChannel structure to release. - */ - -void -Comm_Put(CommChannel channel) -{ - if (channel) { - CommRelease(channel); - } -} - - -/** - * @brief Uses the read lock. This function is exported for the upper layer - * such that it can order acquisition of a different lock (socket) with - * the release of the dispatch lock. - * @param[in,out] channel CommChannel structure to unlock. - */ - -void -Comm_DispatchUnlock(CommChannel channel) -{ - if (channel) { - DispatchUnlock(channel); - } -} - - -/** - * @brief Lock the channel for upper layer state. - * This function is exported for the upper layer to ensure that channel - * isn't closed while updating the layer state. Operations using this - * function are expected to be short, since unlike the _Write functions, - * these callers cannot be signaled. - * @param[in,out] channel CommChannel structure to lock. - * @return zero if successful, -1 otherwise. - */ - -int -Comm_Lock(CommChannel channel) -{ - if (!channel) { - return -1; - } - StateLock(channel); - if (!CommIsActive(channel) && !CommIsZombie(channel)) { - StateUnlock(channel); - return -1; - } - return 0; -} - - -/** - * @brief Uses the writer lock. This function is exported for the upper layer - * to ensure that channel isn't closed while updating the layer state. - * See Comm_Lock for details). - * @param[in,out] channel CommChannel structure to unlock. - */ - -void -Comm_Unlock(CommChannel channel) -{ - if (channel) { - StateUnlock(channel); - } -} - - -/** - * @brief Requests events be posted in-line after the function completes. - * @param channel channel object. - * @return current number of requests for inline event posting, or -1 on error. - */ - -unsigned int -Comm_RequestInlineEvents(CommChannel channel) -{ - if (channel->transp) { - return CommTransp_RequestInlineEvents(channel->transp); - } else { - return (unsigned int)-1; - } -} - - -/** - * @brief Requests events be posted out-of-band after the function completes. - * @param channel channel object. - * @return current number of requests for inline event posting, or -1 on error. - */ - -unsigned int -Comm_ReleaseInlineEvents(CommChannel channel) -{ - if (channel->transp) { - return CommTransp_ReleaseInlineEvents(channel->transp); - } else { - return (unsigned int)-1; - } -} diff --git a/arch/arm/mvp/commkm/comm.h b/arch/arm/mvp/commkm/comm.h deleted file mode 100644 index 8291ae4..0000000 --- a/arch/arm/mvp/commkm/comm.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Communication functions based on queue pair transport APIs. - * - * Comm is a shared memory-based mechanism that facilitates the implementation - * of kernel components that require host-to-guest, or guest-to-guest - * communication. - * This facility assumes the availability of a minimal shared memory queue pair - * implementation, such as MVP queue pairs or VMCI queue pairs. The latter must - * provide primitives for queue pair creation and destruction, and reading and - * writing from/to queue pairs. - * Comm assumes that the queue pair (transport) layer is not concerned with - * multi-threading, locking or flow control, and does not require such features. - */ - -#ifndef _COMM_H_ -#define _COMM_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "comm_os.h" -#include "comm_transp.h" - - -/* Default/maximum Comm timeouts (in milliseconds). */ -#define COMM_MAX_TO 60000ULL -#define COMM_MAX_TO_UNINT (COMM_MAX_TO + 1) - -#define COMM_OPF_SET_ERR(flags) ((flags) |= 128) -#define COMM_OPF_CLEAR_ERR(flags) ((flags) &= 127) -#define COMM_OPF_TEST_ERR(flags) ((flags) & 128) - -#define COMM_OPF_SET_VAL(flags, val) ((flags) |= ((val) & 127)) -#define COMM_OPF_GET_VAL(flags) ((flags) & 127) - -/** - * Packet (header) structure. - * NB: Do not change this structure, especially the first three fields; there - * will be consequences. It may be extended, but it's not recommended: all - * operations carry this header, so it's better kept in its minimal form. - */ - -typedef struct CommPacket { - unsigned int len; // Total length - unsigned char flags; // Operation flags - unsigned char opCode; // Operation to call - unsigned short data16; // Auxiliary data - unsigned long long data64; - unsigned long long data64ex; - union { - struct { - unsigned int data32; - unsigned int data32ex; - }; - unsigned long long data64ex2; - }; -} CommPacket; - - -/* Opaque structure representing a communication channel. */ - -struct CommChannelPriv; -typedef struct CommChannelPriv *CommChannel; - - -/* Input operations associated with a comm channel. */ - -typedef void (*CommOperationFunc)(CommChannel channel, - void *state, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen); - - -/* Helper macros */ - -#define COMM_DEFINE_OP(funcName) \ -void \ -funcName(CommChannel channel, \ - void *state, \ - CommPacket *packet, \ - struct kvec *vec, \ - unsigned int vecLen) - - -/* Comm-based implementations. */ - -typedef struct CommImpl { - struct module *owner; - int (*checkArgs)(CommTranspInitArgs *transpArgs); - void *(*stateCtor)(CommChannel channel); - void (*stateDtor)(void *state); - void *(*dataAlloc)(unsigned int dataLen); - void (*dataFree)(void *data); - const CommOperationFunc *operations; - void (*closeNtf)(void *closeNtfData, - const CommTranspInitArgs *transpArgs, - int inBH); - void *closeNtfData; - void (*activateNtf)(void *activateNtfData, - CommChannel channel); - void *activateNtfData; - unsigned long long openAtMillis; - unsigned long long openTimeoutAtMillis; - CommTranspID ntfCenterID; -} CommImpl; - - -int Comm_Init(unsigned int maxChannels); -int Comm_Finish(unsigned long long *timeoutMillis); -int Comm_RegisterImpl(const CommImpl *impl); -void Comm_UnregisterImpl(const CommImpl *impl); -int Comm_IsActive(CommChannel channel); -CommTranspInitArgs Comm_GetTranspInitArgs(CommChannel channel); -void *Comm_GetState(CommChannel channel); -int Comm_Dispatch(CommChannel channel); -unsigned int Comm_DispatchAll(void); -void Comm_Put(CommChannel channel); -void Comm_DispatchUnlock(CommChannel channel); -int Comm_Lock(CommChannel channel); -void Comm_Unlock(CommChannel channel); -int Comm_Zombify(CommChannel channel, int inBH); - -int -Comm_Alloc(const CommTranspInitArgs *transpArgs, - const CommImpl *impl, - int inBH, - CommChannel *newChannel); - - -int -Comm_Write(CommChannel channel, - const CommPacket *packet, - unsigned long long *timeoutMillis); - -int -Comm_WriteVec(CommChannel channel, - const CommPacket *packet, - struct kvec **vec, - unsigned int *vecLen, - unsigned long long *timeoutMillis, - unsigned int *iovOffset); - -unsigned int Comm_RequestInlineEvents(CommChannel channel); -unsigned int Comm_ReleaseInlineEvents(CommChannel channel); - -#endif // _COMM_H_ diff --git a/arch/arm/mvp/commkm/comm_ev.h b/arch/arm/mvp/commkm/comm_ev.h deleted file mode 100644 index bf629c3..0000000 --- a/arch/arm/mvp/commkm/comm_ev.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief various comm event signaling types and signatures - */ - -#ifndef _COMM_EV_H -#define _COMM_EV_H - -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_MODULE -#include "include_check.h" - -/** - * @name Identifiers of comm event signaling class methods - * @{ - */ -#define MVP_COMM_EV_SIGNATURE 0x4d4d4f43 ///< 'COMM' -#define MVP_COMM_EV_SIGNAL (MVP_OBJECT_CUSTOM_BASE + 0) ///< Signal host -#define MVP_COMM_EV_READ_EVENT_DATA (MVP_OBJECT_CUSTOM_BASE + 1) ///< read event data -#define MVP_COMM_EV_LAST (MVP_OBJECT_CUSTOM_BASE + 2) ///< Number of methods -/**@}*/ - -typedef struct CommEvent { - CommTranspID id; - CommTranspIOEvent event; -} CommEvent; - -#endif diff --git a/arch/arm/mvp/commkm/comm_ev_kernel.c b/arch/arm/mvp/commkm/comm_ev_kernel.c deleted file mode 100644 index 0701945..0000000 --- a/arch/arm/mvp/commkm/comm_ev_kernel.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Comm event signaling, host kernel side. - */ - -#include <linux/net.h> - -#include "mvp_types.h" -#include "comm_os.h" -#include "comm_transp_impl.h" -#include "mksck_sockaddr.h" -#include "comm_ev.h" -#include "mvpkm_comm_ev.h" - -static struct socket *sock; - -/** - * @brief Raises a transport event on the provided event ID (address). This - * function is called from a comm_transp provider, such as comm_transp_mvp, - * when it needs to signal an event on a given channel. - * @param targetEvID opaque event channel ID (interpreted by implementation). - * @param transpID ID of transport to signal. - * @param eventType event type to raise. - * @return 0 if successful, -1 otherwise. - */ - -int -CommTranspEvent_Raise(unsigned int targetEvID, // unused - CommTranspID *transpID, - CommTranspIOEvent eventType) -{ - struct sockaddr_mk guestAddr; - struct msghdr msg; - struct kvec vec[1]; - int rc; - CommEvent event; - - if (!transpID) { - return -1; - } - - guestAddr.mk_family = AF_MKSCK; - guestAddr.mk_addr.addr = Mksck_AddrInit(transpID->d32[0], MKSCK_PORT_COMM_EV); - - memset(&msg, 0, sizeof (struct msghdr)); - msg.msg_name = &guestAddr; - msg.msg_namelen = sizeof (guestAddr); - - event.id = *transpID; - event.event = eventType; - - vec[0].iov_base = &event; - vec[0].iov_len = sizeof (CommEvent); - - rc = kernel_sendmsg(sock, - &msg, - vec, - 1, - sizeof (CommEvent)); - rc = (rc < 0) ? -1 : 0; - return rc; -} - - -/** - * @brief Performs one-time, global initialization of event provider. - * @return 0 if successful, -1 otherwise. - */ -int -CommTranspEvent_Init(void) -{ - struct sockaddr_mk addr = { AF_MKSCK, { .addr = MKSCK_ADDR_UNDEF } }; - int rc; - - rc = sock_create_kern(AF_MKSCK, SOCK_DGRAM, 0, &sock); - if (rc < 0) { - goto out; - } - - rc = kernel_bind(sock, (struct sockaddr *) &addr, sizeof addr); - if (rc < 0) { - sock_release(sock); - sock = NULL; - goto out; - } - - Mvpkm_CommEvRegisterProcessCB(CommTranspEvent_Process); - -out: - if (rc) { - CommOS_Log(("%s: Failed to initialize transport event signaling\n", - __FUNCTION__)); - } else { - CommOS_Log(("%s: Transport event signaling initialization successful\n", - __FUNCTION__)); - } - return rc; -} - - -/** - * @brief Performs global clean-up of event provider. - */ - -void -CommTranspEvent_Exit(void) -{ - Mvpkm_CommEvUnregisterProcessCB(); - if (sock) { - sock_release(sock); - sock = NULL; - } - - CommOS_Debug(("%s: done.\n", __FUNCTION__)); -} diff --git a/arch/arm/mvp/commkm/comm_os.h b/arch/arm/mvp/commkm/comm_os.h deleted file mode 100644 index f98c8d4..0000000 --- a/arch/arm/mvp/commkm/comm_os.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Cross-platform base type definitions and function declarations. - * Includes OS-specific base type definitions and function declarations. - */ - -#ifndef _COMM_OS_H_ -#define _COMM_OS_H_ - -/* For-ever timeout constant (in milliseconds). */ -#define COMM_OS_4EVER_TO ((unsigned long long)(~0UL >> 1)) - -/* Condition function prototype. Returns 1: true, 0: false, < 0: error code. */ -typedef int (*CommOSWaitConditionFunc)(void *arg1, void *arg2); - -/* Dispatch function prototype. Called by input (dispatch) kernel threads. */ -typedef unsigned int (*CommOSDispatchFunc)(void); - -/* Module initialization and exit callback functions. */ -extern int (*commOSModInit)(void *args); -extern void (*commOSModExit)(void); - -/* Macro to assign Init and Exit callbacks. */ -#define COMM_OS_MOD_INIT(init, exit) \ - int (*commOSModInit)(void *args) = init; \ - void (*commOSModExit)(void) = exit - - -/* - * OS-specific implementations must provide the following: - * 1. Types: - * CommOSAtomic - * CommOSSpinlock - * CommOSMutex - * CommOSWaitQueue - * CommOSWork - * CommOSWorkFunc - * CommOSList - * CommOSModule - * struct kvec - * - * 2. Definition, initializers: - * CommOSSpinlock_Define() - * - * 3. Functions: - * void CommOS_Debug(const char *format, ...); - * void CommOS_Log(const char *format, ...); - * void CommOS_WriteAtomic(CommOSAtomic *atomic, int val); - * int CommOS_ReadAtomic(CommOSAtomic *atomic); - * int CommOS_AddReturnAtomic(CommOSAtomic *atomic, int val); - * int CommOS_SubReturnAtomic(CommOSAtomic *atomic, int val); - * void CommOS_SpinlockInit(CommOSSpinlock *lock); - * void CommOS_SpinLockBH(CommOSSpinlock *lock); - * int CommOS_SpinTrylockBH(CommOSSpinlock *lock); - * void CommOS_SpinUnlockBH(CommOSSpinlock *lock); - * void CommOS_SpinLock(CommOSSpinlock *lock); - * int CommOS_SpinTrylock(CommOSSpinlock *lock); - * void CommOS_SpinUnlock(CommOSSpinlock *lock); - * void CommOS_MutexInit(CommOSMutex *mutex); - * void CommOS_MutexLock(CommOSMutex *mutex); - * int CommOS_MutexLockUninterruptible(CommOSMutex *mutex); - * int CommOS_MutexTrylock(CommOSMutex *mutex); - * void CommOS_MutexUnlock(CommOSMutex *mutex); - * void CommOS_WaitQueueInit(CommOSWaitQueue *wq); - * CommOS_DoWait(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc cond, - * void *condArg1, - * void *condArg2, - * unsigned long long *timeoutMillis, - * int interruptible); - * int CommOS_Wait(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc func, - * void *funcArg1, - * void *funcArg2, - * unsigned long long *timeoutMillis); - * int CommOS_WaitUninterruptible(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc func, - * void *funcArg1, - * void *funcArg2, - * unsigned long long *timeoutMillis); - * void CommOS_WakeUp(CommOSWaitQueue *wq); - * void *CommOS_KmallocNoSleep(unsigned int size); - * void *CommOS_Kmalloc(unsigned int size); - * void CommOS_Kfree(void *arg); - * void CommOS_Yield(void); - * unsigned long long CommOS_GetCurrentMillis(void); - * void CommOS_ListInit(CommOSList *list); - * int CommOS_ListEmpty(CommOSList *list); - * void CommOS_ListAdd(CommOSList *list, CommOSList *listElem); - * void CommOS_ListAddTail(CommOSList *list, CommOSList *listElem); - * void int CommOS_ListDel(CommOSList *listElem); - * Macros: - * CommOS_ListForEach(*list, *item, itemListFieldName); - * CommOS_ListForEachSafe(*list, *item, *tmp, itemListFieldName); - * void CommOS_ListSplice(CommOSList *list, CommOSList *listToAdd); - * void CommOS_ListSpliceTail(CommOSList *list, CommOSList *listToAdd); - * CommOSModule CommOS_ModuleSelf(void); - * int CommOS_ModuleGet(CommOSModule module); - * void CommOS_ModulePut(CommOSModule module); - * void CommOS_MemBarrier(void); - * - * These cannot be defined here: a) non-pointer type definitions need size - * information, and b) functions may or may not be inlined, or macros may - * be used instead. - */ - - -#ifdef __linux__ -#include "comm_os_linux.h" -#else -#error "Unsupported OS" -#endif - -/* Functions to start and stop the dispatch and aio kernel threads. */ -void CommOS_StopIO(void); -void CommOS_ScheduleDisp(void); -void CommOS_InitWork(CommOSWork *work, CommOSWorkFunc func); -int CommOS_ScheduleAIOWork(CommOSWork *work); -void CommOS_FlushAIOWork(CommOSWork *work); - -int -CommOS_StartIO(const char *dispatchTaskName, - CommOSDispatchFunc dispatchHandler, - unsigned int interval, - unsigned int maxCycles, - const char *aioTaskName); - - -#endif /* _COMM_OS_H_ */ diff --git a/arch/arm/mvp/commkm/comm_os_linux.c b/arch/arm/mvp/commkm/comm_os_linux.c deleted file mode 100644 index 74f99f5..0000000 --- a/arch/arm/mvp/commkm/comm_os_linux.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Linux-specific functions/types. - */ - -#include "comm_os.h" - -#define DISPATCH_MAX_CYCLES 8192 - -/* Type definitions */ - -typedef struct workqueue_struct CommOSWorkQueue; - - -/* Static data */ - -static volatile int running; -static int numCpus; -static CommOSWorkQueue *dispatchWQ; -static CommOSDispatchFunc dispatch; -static CommOSWork dispatchWorksNow[NR_CPUS]; -static CommOSWork dispatchWorks[NR_CPUS]; -static unsigned int dispatchInterval = 1; -static unsigned int dispatchMaxCycles = 2048; -static CommOSWorkQueue *aioWQ; - - -/** - * @brief Initializes a workqueue consisting of per-cpu kernel threads. - * @param name workqueue name - * @return workqueue handle if successful, NULL otherwise - */ - -static inline CommOSWorkQueue * -CreateWorkqueue(const char *name) -{ - return create_workqueue(name); -} - - -/** - * @brief Destroys a workqueue and stops its threads. - * @param[in,out] wq workqueue to destroy. - * @return workqueue handle is successful, NULL otherwise. - */ - -static inline void -DestroyWorkqueue(CommOSWorkQueue *wq) -{ - destroy_workqueue(wq); -} - - -/** - * @brief Force execution of a work item. - * @param[in,out] work work item to dequeue. - */ - -static inline void -FlushDelayedWork(CommOSWork *work) -{ - flush_delayed_work(work); -} - - -/** - * @brief Enqueue a work item to a workqueue for execution on a given cpu - * and after the specified interval. - * @param cpu cpu number. If negative, work item is enqueued on current cpu. - * @param[in,out] wq target work queue. - * @param[in,out] work work item to enqueue. - * @param jif delay interval. - * @return zero if successful, non-zero otherwise. - */ - -static inline int -QueueDelayedWorkOn(int cpu, - CommOSWorkQueue *wq, - CommOSWork *work, - unsigned long jif) -{ - if (cpu < 0) { - return !queue_delayed_work(wq, work, jif) ? -1 : 0; - } else { - return !queue_delayed_work_on(cpu, wq, work, jif) ? -1 : 0; - } -} - - -/** - * @brief Enqueues a work item to a workqueue for execution on the current cpu - * and after the specified interval. - * @param[in,out] wq target work queue. - * @param[in,out] work work item to enqueue. - * @param jif delay interval. - * @return zero if successful, non-zero otherwise. - */ - -static inline int -QueueDelayedWork(CommOSWorkQueue *wq, - CommOSWork *work, - unsigned long jif) -{ - return QueueDelayedWorkOn(-1, wq, work, jif); -} - - -/** - * @brief Cancels a queued delayed work item and synchronizes with its - * completion. - * @param[in,out] work work item to cancel - */ - -static inline void -WaitForDelayedWork(CommOSWork *work) -{ - cancel_delayed_work_sync(work); -} - - -/** - * @brief Discards work items queued to the specified workqueue. - * @param[in,out] wq work queue to flush. - */ - -static inline void -FlushWorkqueue(CommOSWorkQueue *wq) -{ - flush_workqueue(wq); -} - - -/** - * @brief Schedules dispatcher threads for immediate execution. - */ - -void -CommOS_ScheduleDisp(void) -{ - CommOSWork *work = &dispatchWorksNow[get_cpu()]; - - put_cpu(); - if (running) { - QueueDelayedWork(dispatchWQ, work, 0); - } -} - - -/** - * @brief Default delayed work callback function implementation. - * Calls the input function specified at initialization. - * @param[in,out] work work item. - */ - -static void -DispatchWrapper(CommOSWork *work) -{ - unsigned int misses; - - for (misses = 0; running && (misses < dispatchMaxCycles); ) { - /* We run for at most dispatchMaxCycles worth of channel no-ops. */ - - if (!dispatch()) { - /* No useful work was done, on any of the channels. */ - - misses++; - if ((misses % 32) == 0) { - CommOS_Yield(); - } - } else { - misses = 0; - } - } - - if (running && - (work >= &dispatchWorks[0]) && - (work <= &dispatchWorks[NR_CPUS - 1])) { - /* - * If still running _and_ this was a regular, time-based run, then - * re-arm the timer. - */ - - QueueDelayedWork(dispatchWQ, work, dispatchInterval); - } -} - - -/** - * @brief Initializes work item with specified callback function. - * @param[in,out] work work queue to initialize. - * @param func work item to initialize the queue with. - */ - -void -CommOS_InitWork(CommOSWork *work, - CommOSWorkFunc func) -{ - INIT_DELAYED_WORK(work, (work_func_t)func); -} - - -/** - * @brief Flush execution of a work item - * @param{in,out] work work item to dequeue - */ -void -CommOS_FlushAIOWork(CommOSWork *work) -{ - if (aioWQ && work) { - FlushDelayedWork(work); - } -} - - -/** - * @brief Queue a work item to the AIO workqueue. - * @param[in,out] work work item to enqueue. - * @return zero if work enqueued, non-zero otherwise. - */ - -int -CommOS_ScheduleAIOWork(CommOSWork *work) -{ - if (running && aioWQ && work) { - return QueueDelayedWork(aioWQ, work, 0); - } - return -1; -} - - -/** - * @brief Initializes the base IO system. - * @param dispatchTaskName dispatch thread(s) name. - * @param dispatchFunc dispatch function. - * @param intervalMillis periodic interval in milliseconds to call dispatch. - * The floor is 1 jiffy, regardless of how small intervalMillis is - * @param maxCycles number of cycles to do adaptive polling before scheduling. - * The maximum number of cycles is DISPATCH_MAX_CYCLES. - * @param aioTaskName AIO thread(s) name. If NULL, AIO threads aren't started. - * @return zero is successful, -1 otherwise. - * @sideeffects Dispatch threads, and if applicable, AIO threads are started. - */ - -int -CommOS_StartIO(const char *dispatchTaskName, // IN - CommOSDispatchFunc dispatchFunc, // IN - unsigned int intervalMillis, // IN - unsigned int maxCycles, // IN - const char *aioTaskName) // IN -{ - int rc; - int cpu; - - if (running) { - CommOS_Debug(("%s: I/O tasks already running.\n", __FUNCTION__)); - return 0; - } - - /* - * OK, let's test the handler against NULL. Though, the whole concept - * of checking for NULL pointers, outside cases where NULL is meaningful - * to the implementation, is relatively useless: garbage, random pointers - * rarely happen to be all-zeros. - */ - - if (!dispatchFunc) { - CommOS_Log(("%s: a NULL Dispatch handler was passed.\n", __FUNCTION__)); - return -1; - } - dispatch = dispatchFunc; - - if (intervalMillis == 0) { - intervalMillis = 4; - } - if ((dispatchInterval = msecs_to_jiffies(intervalMillis)) < 1) { - dispatchInterval = 1; - } - if (maxCycles > DISPATCH_MAX_CYCLES) { - dispatchMaxCycles = DISPATCH_MAX_CYCLES; - } else if (maxCycles > 0) { - dispatchMaxCycles = maxCycles; - } - CommOS_Debug(("%s: Interval millis %u (jif:%u).\n", __FUNCTION__, - intervalMillis, dispatchInterval)); - CommOS_Debug(("%s: Max cycles %u.\n", __FUNCTION__, dispatchMaxCycles)); - - numCpus = num_present_cpus(); - dispatchWQ = CreateWorkqueue(dispatchTaskName); - if (!dispatchWQ) { - CommOS_Log(("%s: Couldn't create %s task(s).\n", __FUNCTION__, - dispatchTaskName)); - return -1; - } - - if (aioTaskName) { - aioWQ = CreateWorkqueue(aioTaskName); - if (!aioWQ) { - CommOS_Log(("%s: Couldn't create %s task(s).\n", __FUNCTION__, - aioTaskName)); - DestroyWorkqueue(dispatchWQ); - return -1; - } - } else { - aioWQ = NULL; - } - - running = 1; - for (cpu = 0; cpu < numCpus; cpu++) { - CommOS_InitWork(&dispatchWorksNow[cpu], DispatchWrapper); - CommOS_InitWork(&dispatchWorks[cpu], DispatchWrapper); - rc = QueueDelayedWorkOn(cpu, dispatchWQ, - &dispatchWorks[cpu], - dispatchInterval); - if (rc != 0) { - CommOS_StopIO(); - return -1; - } - } - CommOS_Log(("%s: Created I/O task(s) successfully.\n", __FUNCTION__)); - return 0; -} - - -/** - * @brief Stops the base IO system. - * @sideeffects Dispatch threads, and if applicable, AIO threads are stopped. - */ - -void -CommOS_StopIO(void) -{ - int cpu; - - if (running) { - running = 0; - if (aioWQ) { - FlushWorkqueue(aioWQ); - DestroyWorkqueue(aioWQ); - aioWQ = NULL; - } - FlushWorkqueue(dispatchWQ); - for (cpu = 0; cpu < numCpus; cpu++) { - WaitForDelayedWork(&dispatchWorksNow[cpu]); - WaitForDelayedWork(&dispatchWorks[cpu]); - } - DestroyWorkqueue(dispatchWQ); - dispatchWQ = NULL; - CommOS_Log(("%s: I/O tasks stopped.\n", __FUNCTION__)); - } -} diff --git a/arch/arm/mvp/commkm/comm_os_linux.h b/arch/arm/mvp/commkm/comm_os_linux.h deleted file mode 100644 index f92c8bd..0000000 --- a/arch/arm/mvp/commkm/comm_os_linux.h +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Contains linux-specific type definitions and function declarations - */ - -#ifndef _COMM_OS_LINUX_H_ -#define _COMM_OS_LINUX_H_ - -#include <linux/types.h> -#include <linux/version.h> - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -#error "Kernel versions lower than 2.6.20 are not supported" -#endif - -#include <linux/kernel.h> -#include <linux/workqueue.h> -#include <linux/sched.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/slab.h> - - -/* - * Type definitions. - */ - -typedef atomic_t CommOSAtomic; -typedef spinlock_t CommOSSpinlock; -typedef struct mutex CommOSMutex; -typedef wait_queue_head_t CommOSWaitQueue; -typedef struct delayed_work CommOSWork; -typedef void (*CommOSWorkFunc)(CommOSWork *work); -typedef struct list_head CommOSList; -typedef struct module *CommOSModule; - - -/* - * Initializers. - */ - -#define CommOSSpinlock_Define DEFINE_SPINLOCK - - -#define COMM_OS_DOLOG(...) printk(KERN_INFO __VA_ARGS__) - - -/** - * @brief Logs given arguments in debug builds. - */ - -#if defined(COMM_OS_DEBUG) - #define CommOS_Debug(args) COMM_OS_DOLOG args -#else - #define CommOS_Debug(args) -#endif - - -/** - * @brief Logs given arguments. - */ - -#define CommOS_Log(args) COMM_OS_DOLOG args - - -/** - * @brief Logs function name and location. - */ - -#if defined(COMM_OS_TRACE) -#define TRACE(ptr) \ - do { \ - CommOS_Debug(("%p:%s: at [%s:%d] with arg ptr [0x%p].\n", current, \ - __FUNCTION__, __FILE__, __LINE__, (ptr))); \ - } while (0) -#else -#define TRACE(ptr) -#endif - - -/** - * @brief Write atomic variable - * @param[in,out] atomic variable to write - * @param val new value - */ - -static inline void -CommOS_WriteAtomic(CommOSAtomic *atomic, - int val) -{ - atomic_set(atomic, val); -} - - -/** - * @brief Reads atomic variable - * @param atomic variable to read - * @return value - */ - -static inline int -CommOS_ReadAtomic(CommOSAtomic *atomic) -{ - return atomic_read(atomic); -} - - -/** - * @brief Atomically add value to atomic variable, return new value. - * @param[in,out] atomic variable - * @param val value to add - * @return new value - */ - -static inline int -CommOS_AddReturnAtomic(CommOSAtomic *atomic, - int val) -{ - return atomic_add_return(val, atomic); -} - - -/** - * @brief Atomically substract value from atomic variable, return new value. - * @param[in,out] atomic variable - * @param val value to substract - * @return new value - */ - -static inline int -CommOS_SubReturnAtomic(CommOSAtomic *atomic, - int val) -{ - return atomic_sub_return(val, atomic); -} - - -/** - * @brief Initializes a given lock. - * @param[in,out] lock lock to initialize - */ - -static inline void -CommOS_SpinlockInit(CommOSSpinlock *lock) -{ - spin_lock_init(lock); -} - - -/** - * @brief Locks given lock and disables bottom half processing. - * @param[in,out] lock lock to lock - */ - -static inline void -CommOS_SpinLockBH(CommOSSpinlock *lock) -{ - spin_lock_bh(lock); -} - - -/** - * @brief Attempts to lock the given lock and disable BH processing. - * @param[in,out] lock lock to lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_SpinTrylockBH(CommOSSpinlock *lock) -{ - return !spin_trylock_bh(lock); -} - - -/** - * @brief Unlocks given lock and re-enables BH processing. - * @param[in,out] lock lock to unlock - */ - -static inline void -CommOS_SpinUnlockBH(CommOSSpinlock *lock) -{ - spin_unlock_bh(lock); -} - - -/** - * @brief Locks the given lock. - * @param[in,out] lock lock to lock - */ - -static inline void -CommOS_SpinLock(CommOSSpinlock *lock) -{ - spin_lock(lock); -} - - -/** - * @brief Attempts to lock the given lock. - * @param[in,out] lock lock to try-lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_SpinTrylock(CommOSSpinlock *lock) -{ - return !spin_trylock(lock); -} - - -/** - * @brief Unlocks given lock. - * @param[in,out] lock lock to unlock - */ - -static inline void -CommOS_SpinUnlock(CommOSSpinlock *lock) -{ - spin_unlock(lock); -} - - -/** - * @brief Initializes given mutex. - * @param[in,out] mutex mutex to initialize - */ - -static inline void -CommOS_MutexInit(CommOSMutex *mutex) -{ - mutex_init(mutex); -} - - -/** - * @brief Acquires mutex. - * @param[in,out] mutex mutex to lock - * @return zero if successful, non-zero otherwise (interrupted) - */ - -static inline int -CommOS_MutexLock(CommOSMutex *mutex) -{ - return mutex_lock_interruptible(mutex); -} - - -/** - * @brief Acquires mutex in uninterruptible mode. - * @param[in,out] mutex mutex to lock - */ - -static inline void -CommOS_MutexLockUninterruptible(CommOSMutex *mutex) -{ - mutex_lock(mutex); -} - - -/** - * @brief Attempts to acquire given mutex. - * @param[in,out] mutex mutex to try-lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_MutexTrylock(CommOSMutex *mutex) -{ - return !mutex_trylock(mutex); -} - - -/** - * @brief Releases a given mutex. - * @param[in,out] mutex mutex to unlock - */ - -static inline void -CommOS_MutexUnlock(CommOSMutex *mutex) -{ - mutex_unlock(mutex); -} - - -/** - * @brief Initializes a wait queue. - * @param[in,out] wq workqueue to initialize - */ - -static inline void -CommOS_WaitQueueInit(CommOSWaitQueue *wq) -{ - init_waitqueue_head(wq); -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * - a signal is pending - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @param interruptible enable/disable signal pending check - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, if a signal is pending or other error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_DoWait(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis, - int interruptible) -{ - int rc; - DEFINE_WAIT(wait); - long timeout; -#if defined(COMM_OS_LINUX_WAIT_WORKAROUND) - long tmpTimeout; - long retTimeout; - const unsigned int interval = 50; -#endif - - if (!timeoutMillis) { - return -1; - } - if ((rc = cond(condArg1, condArg2)) != 0) { - return rc; - } - -#if defined(COMM_OS_LINUX_WAIT_WORKAROUND) - timeout = msecs_to_jiffies(interval < *timeoutMillis ? - interval : (unsigned int)*timeoutMillis); - retTimeout = msecs_to_jiffies((unsigned int)(*timeoutMillis)); - - for (; retTimeout >= 0; ) { - prepare_to_wait(wq, &wait, - (interruptible?TASK_INTERRUPTIBLE:TASK_UNINTERRUPTIBLE)); - if ((rc = cond(condArg1, condArg2))) { - break; - } - if (interruptible && signal_pending(current)) { - rc = -EINTR; - break; - } - if ((tmpTimeout = schedule_timeout(timeout))) { - retTimeout -= (timeout - tmpTimeout); - } else { - retTimeout -= timeout; - } - if (retTimeout < 0) { - retTimeout = 0; - } - } - finish_wait(wq, &wait); - if (rc == 0) { - rc = cond(condArg1, condArg2); - if (rc && (retTimeout == 0)) { - retTimeout = 1; - } - } - *timeoutMillis = (unsigned long long)jiffies_to_msecs(retTimeout); -#else // !defined(COMM_OS_LINUX_WAIT_WORKAROUND) - timeout = msecs_to_jiffies((unsigned int)(*timeoutMillis)); - - for (;;) { - prepare_to_wait(wq, &wait, - (interruptible?TASK_INTERRUPTIBLE:TASK_UNINTERRUPTIBLE)); - if ((rc = cond(condArg1, condArg2)) != 0) { - break; - } - if (interruptible && signal_pending(current)) { - rc = -EINTR; - break; - } - if ((timeout = schedule_timeout(timeout)) == 0) { - rc = 0; - break; - } - } - finish_wait(wq, &wait); - if (rc == 0) { - rc = cond(condArg1, condArg2); - if (rc && (timeout == 0)) { - timeout = 1; - } - } - *timeoutMillis = (unsigned long long)jiffies_to_msecs(timeout); -#endif - - return rc; -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * - a signal is pending - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, if a signal is pending or other error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_Wait(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis) -{ - return CommOS_DoWait(wq, cond, condArg1, condArg2, timeoutMillis, 1); -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_WaitUninterruptible(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis) -{ - return CommOS_DoWait(wq, cond, condArg1, condArg2, timeoutMillis, 0); -} - - -/** - * @brief Wakes up task(s) waiting on the given wait queue. - * @param[in,out] wq wait queue. - */ - -static inline void -CommOS_WakeUp(CommOSWaitQueue *wq) -{ - wake_up(wq); -} - - -/** - * @brief Allocates kernel memory of specified size; does not sleep. - * @param size size to allocate. - * @return Address of allocated memory or NULL if the allocation fails. - */ - -static inline void * -CommOS_KmallocNoSleep(unsigned int size) -{ - return kmalloc(size, GFP_ATOMIC); -} - - -/** - * @brief Allocates kernel memory of specified size; may sleep. - * @param size size to allocate. - * @return Address of allocated memory or NULL if the allocation fails. - */ - -static inline void * -CommOS_Kmalloc(unsigned int size) -{ - return kmalloc(size, GFP_KERNEL); -} - - -/** - * @brief Frees previously allocated kernel memory. - * @param obj object to free. - */ - -static inline void -CommOS_Kfree(void *obj) -{ - if (obj) { - kfree(obj); - } -} - - -/** - * @brief Yields the current cpu to other runnable tasks. - */ - -static inline void -CommOS_Yield(void) -{ - cond_resched(); -} - - -/** - * @brief Gets the current time in milliseconds. - * @return Current time in milliseconds, with precision of at most one tick. - */ - -static inline unsigned long long -CommOS_GetCurrentMillis(void) -{ - return (unsigned long long)jiffies_to_msecs(jiffies); -} - - -/** - * @brief Initializes given list. - * @param list list to initialize. - */ - -static inline void -CommOS_ListInit(CommOSList *list) -{ - INIT_LIST_HEAD(list); -} - - -/** - * @brief Tests if list is empty. - * @param list list to test. - * @return non-zero if empty, zero otherwise. - */ - -#define CommOS_ListEmpty(list) list_empty((list)) - - -/** - * @brief Adds given element to beginning of list. - * @param list list to add to. - * @param elem element to add. - */ - -#define CommOS_ListAdd(list, elem) list_add((elem), (list)) - - -/** - * @brief Adds given element to end of list. - * @param list list to add to. - * @param elem element to add. - */ - -#define CommOS_ListAddTail(list, elem) list_add_tail((elem), (list)) - - -/** - * @brief Deletes given element from its list. - * @param elem element to delete. - */ - -#define CommOS_ListDel(elem) \ - do { \ - list_del((elem)); \ - INIT_LIST_HEAD((elem)); \ - } while (0) - - -/** - * @brief Iterates over a list. - * @param list list to iterate over. - * @param[out] item stores next element. - * @param itemListFieldName name in the item structure storing the list head. - */ - -#define CommOS_ListForEach(list, item, itemListFieldName) \ - list_for_each_entry((item), (list), itemListFieldName) - - -/** - * @brief Iterates safely over a list. - * @param list list to iterate over. - * @param[out] item stores next element. May be deleted in the loop. - * @param[out] tmpItem saves iteration element. - * @param itemListFieldName name in the item structure storing the list head. - */ - -#define CommOS_ListForEachSafe(list, item, tmpItem, itemListFieldName) \ - list_for_each_entry_safe((item), (tmpItem), (list), itemListFieldName) - - -/** - * @brief Combines two lists, adds second list to beginning of first one. - * @param list list to add to. - * @param list2 list to add. - */ - -#define CommOS_ListSplice(list, list2) list_splice((list2), (list)) - - -/** - * @brief Combines two lists, adds second list to end of first one. - * @param list list to add to. - * @param list2 list to add. - */ - -#define CommOS_ListSpliceTail(list, list2) list_splice_tail((list2), (list)) - - -/** - * @brief Gets current module handle. - * @return module handle. - */ - -static inline CommOSModule -CommOS_ModuleSelf(void) -{ - return THIS_MODULE; -} - - -/** - * @brief Retains module. - * @param[in,out] module to retain. - * @return zero if successful, non-zero otherwise. - */ - -static inline int -CommOS_ModuleGet(CommOSModule module) -{ - int rc = 0; - - if (!module) { - goto out; - } - if (!try_module_get(module)) { - rc = -1; - } - -out: - return rc; -} - - -/** - * @brief Releases module. - * @param[in,out] module to release. - */ - -static inline void -CommOS_ModulePut(CommOSModule module) -{ - if (module) { - module_put(module); - } -} - - -/** - * @brief Inserts r/w memory barrier. - */ - -#define CommOS_MemBarrier smp_mb - -#endif /* _COMM_OS_LINUX_H_ */ diff --git a/arch/arm/mvp/commkm/comm_os_mod_linux.c b/arch/arm/mvp/commkm/comm_os_mod_linux.c deleted file mode 100644 index 8470de6..0000000 --- a/arch/arm/mvp/commkm/comm_os_mod_linux.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Linux-specific module loading, unloading functions. - */ - -#include "comm_os.h" -#include "comm_os_mod_ver.h" - -#include <linux/moduleparam.h> - - -/* Module parameters -- passed as one 'name=value'-list string. */ - -static char modParams[256]; -module_param_string(COMM_OS_MOD_SHORT_NAME, modParams, sizeof modParams, 0644); - - -/** - * @brief Module initialization entry point. Calls the commOSModInit - * function pointer to perform upper layer initialization. - * @return zero if successful, non-zero otherwise. - */ - -static int __init -ModInit(void) -{ - int rc; - - if (!commOSModInit) { - CommOS_Log(("%s: Can't find \'init\' function for module \'" \ - COMM_OS_MOD_SHORT_NAME_STRING "\'.\n", __FUNCTION__)); - return -1; - } - - CommOS_Debug(("%s: Module parameters: [%s].\n", __FUNCTION__, modParams)); - - rc = (*commOSModInit)(modParams); - if (rc == 0) { - CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \ - "\' has been successfully initialized.\n", __FUNCTION__)); - } else { - CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \ - "\' could not be initialized [%d].\n", __FUNCTION__, rc)); - } - - return rc > 0 ? -rc : rc; -} - - -/** - * @brief Module exit function. Calls the commOSModExit function pointer - * to perform upper layer cleanup. - */ - -static void __exit -ModExit(void) -{ - if (!commOSModExit) { - CommOS_Log(("%s: Can't find \'fini\' function for module \'" \ - COMM_OS_MOD_SHORT_NAME_STRING "\'.\n", __FUNCTION__)); - return; - } - - (*commOSModExit)(); - CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \ - "\' has been stopped.\n", __FUNCTION__)); -} - - -module_init(ModInit); -module_exit(ModExit); - -/* Module information. */ -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION(COMM_OS_MOD_NAME_STRING); -MODULE_VERSION(COMM_OS_MOD_VERSION_STRING); -MODULE_LICENSE("GPL v2"); -/* - * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement - * with them and mark their kernel modules as externally supported via a - * change to the module header. If this isn't done, the module will not load - * by default (i.e., neither mkinitrd nor modprobe will accept it). - */ -MODULE_INFO(supported, "external"); diff --git a/arch/arm/mvp/commkm/comm_os_mod_ver.h b/arch/arm/mvp/commkm/comm_os_mod_ver.h deleted file mode 100644 index 059854c..0000000 --- a/arch/arm/mvp/commkm/comm_os_mod_ver.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Version definitions for the Comm module. - */ - -#ifndef _COMM_OS_MOD_VER_H_ -#define _COMM_OS_MOD_VER_H_ - -#define COMM_OS_MOD_NAME_STRING "VMware communication module" -#define COMM_OS_MOD_SHORT_NAME comm -#define COMM_OS_MOD_SHORT_NAME_STRING "comm" - -#define COMM_OS_MOD_VERSION 1.0.0.0 -#define COMM_OS_MOD_VERSION_COMMAS 1,0,0,0 -#define COMM_OS_MOD_VERSION_STRING "1.0.0.0" - -#endif /* _COM_OS_MOD_VER_H_ */ diff --git a/arch/arm/mvp/commkm/comm_svc.c b/arch/arm/mvp/commkm/comm_svc.c deleted file mode 100644 index 18f62bd..0000000 --- a/arch/arm/mvp/commkm/comm_svc.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Communication functions based on transport functionality. - */ - -#include "comm_os.h" -#include "comm_os_mod_ver.h" -#include "comm_svc.h" - - -/* - * Initialization of module entry and exit callbacks expected by module - * loading/unloading functions in comm_os. - */ - -static int Init(void *args); -static void Exit(void); - -COMM_OS_MOD_INIT(Init, Exit); - -static volatile int running; // Initialized and running. - - -/** - * @brief Allocates and initializes comm global state. - * Starts input dispatch and aio threads. - * @param argsIn arguments - * @return zero if successful, non-zero otherwise. - */ - -static int -Init(void *argsIn) -{ - int rc = -1; - unsigned int maxChannels = 8; - /* - * Infinite timeout, 1 polling cycle - * see kernel/time.c: msecs_to_jiffies() - */ - unsigned int pollingMillis = (unsigned int)-1; - unsigned int pollingCycles = 1; - const char *args = argsIn; - - if (args && *args) { - /* coverity[secure_coding] */ - sscanf(args, - "max_channels:%u,poll_millis:%u,poll_cycles:%u", - &maxChannels, &pollingMillis, &pollingCycles); - CommOS_Debug(("%s: arguments [%s].\n", __FUNCTION__, args)); - } - - rc = Comm_Init(maxChannels); - if (rc) { - goto out; - } - - rc = CommOS_StartIO(COMM_OS_MOD_SHORT_NAME_STRING "-disp", - Comm_DispatchAll, pollingMillis, pollingCycles, - COMM_OS_MOD_SHORT_NAME_STRING "-aio"); - if (rc) { - unsigned long long timeout = 0; - - Comm_Finish(&timeout); /* Nothing started, guaranteed to succeed. */ - goto out; - } - running = 1; - rc = 0; - -out: - return rc; -} - - -/** - * @brief Attempts to close all channels. - * @return zero if successful, non-zero otherwise. - */ - -static int -Halt(void) -{ - unsigned int maxTries = 10; - int rc = -1; - - if (!running) { - rc = 0; - goto out; - } - - for ( ; maxTries; maxTries--) { - unsigned long long timeout = 2000ULL; - - CommOS_Debug(("%s: Attempting to halt...\n", __FUNCTION__)); - if (!Comm_Finish(&timeout)) { - running = 0; - rc = 0; - break; - } - } - -out: - return rc; -} - - -/** - * @brief Stops the comm_rt module. - * If Halt() call successful, stops input dispatch and aio threads. - */ - -static void -Exit(void) -{ - if (!Halt()) { - CommOS_StopIO(); - } -} - - -/** - * @brief Registers an implementation block used when attaching to channels - * in response to transport attach events. - * @param impl implementation block. - * @return 0 if successful, non-zero otherwise. - */ - -int -CommSvc_RegisterImpl(const CommImpl *impl) -{ - return Comm_RegisterImpl(impl); -} - - -/** - * @brief Unregisters an implementation block used when attaching to channels - * in response to transport attach events. - * @param impl implementation block. - */ - -void -CommSvc_UnregisterImpl(const CommImpl *impl) -{ - Comm_UnregisterImpl(impl); -} - - -/** - * @brief Finds a free entry and initializes it with the information provided. - * May be called from BH. It doesn't call potentially blocking functions. - * @param transpArgs transport initialization arguments. - * @param impl implementation block. - * @param inBH non-zero if called in bottom half. - * @param[out] newChannel newly allocated channel. - * @return zero if successful, non-zero otherwise. - * @sideeffects Initializes the communications channel with given parameters - */ - -int -CommSvc_Alloc(const CommTranspInitArgs *transpArgs, - const CommImpl *impl, - int inBH, - CommChannel *newChannel) -{ - return Comm_Alloc(transpArgs, impl, inBH, newChannel); -} - - -/** - * @brief Zombifies a channel. May fail if channel isn't active. - * @param channel channel to zombify. - * @param inBH non-zero if called in bottom half. - * @return zero if channel zombified, non-zero otherwise. - */ - -int -CommSvc_Zombify(CommChannel channel, - int inBH) -{ - return Comm_Zombify(channel, inBH); -} - - -/** - * @brief Reports whether a channel is active. - * @param channel channel to report on. - * @return non-zero if channel active, zero otherwise. - */ - -int -CommSvc_IsActive(CommChannel channel) -{ - return Comm_IsActive(channel); -} - - -/** - * @brief Retrieves a channel's transport initialization arguments. - * It doesn't lock, the caller must ensure the channel may be accessed. - * @param channel CommChannel structure to get initialization arguments from. - * @return initialization arguments used to allocate/attach to channel. - */ - -CommTranspInitArgs -CommSvc_GetTranspInitArgs(CommChannel channel) -{ - return Comm_GetTranspInitArgs(channel); -} - - -/** - * @brief Retrieves upper layer state (pointer). It doesn't lock, the caller - * must ensure the channel may be accessed. - * @param channel CommChannel structure to get state from. - * @return pointer to upper layer state. - */ - -void * -CommSvc_GetState(CommChannel channel) -{ - return Comm_GetState(channel); -} - - -/** - * @brief Writes a fully formatted packet (containing payload data, if - * applicable) to the specified channel. - * - * The operation may block until enough write space is available, but no - * more than the specified interval. The operation either writes the full - * amount of bytes, or it fails. Warning: callers must _not_ use the - * _Lock/_Unlock functions to bracket calls to this function. - * @param[in,out] channel channel to write to. - * @param packet packet to write. - * @param[in,out] timeoutMillis interval in milliseconds to wait. - * @return number of bytes written, 0 if it times out, -1 error. - * @sideeffects Data may be written to the channel. - */ - -int -CommSvc_Write(CommChannel channel, - const CommPacket *packet, - unsigned long long *timeoutMillis) -{ - return Comm_Write(channel, packet, timeoutMillis); -} - - -/** - * @brief Writes a packet and associated payload data to the specified channel. - * - * The operation may block until enough write space is available, but not - * more than the specified interval. The operation either writes the full - * amount of bytes, or it fails. Users may call this function successively - * to write several packets from large {io|k}vecs. If that's the case, the - * packet header needs to be updated in between calls, for the different - * (total) lengths. Warning: callers must _not_ use the _Lock/_Unlock - * functions to bracket calls to this function. - * @param[in,out] channel the specified channel - * @param packet packet to write - * @param[in,out] vec kvec to write from - * @param[in,out] vecLen length of kvec - * @param[in,out] timeoutMillis interval in milliseconds to wait - * @param[in,out] iovOffset must be set to 0 before first call (internal cookie) - * @return number of bytes written, 0 if it timed out, -1 error - * @sideeffects data may be written to the channel - */ - -int -CommSvc_WriteVec(CommChannel channel, - const CommPacket *packet, - struct kvec **vec, - unsigned int *vecLen, - unsigned long long *timeoutMillis, - unsigned int *iovOffset) -{ - return Comm_WriteVec(channel, packet, vec, vecLen, timeoutMillis, iovOffset); -} - - -/** - * @brief Releases channel ref count. This function is exported for the upper - * layer's 'activateNtf' callback which may be run asynchronously. The - * callback is protected from concurrent channel releases until it calls - * this function. - * @param[in,out] channel CommChannel structure to release. - */ - -void -CommSvc_Put(CommChannel channel) -{ - Comm_Put(channel); -} - - -/** - * @brief Uses the read lock. This function is exported for the upper layer - * such that it can order acquisition of a different lock (socket) with - * the release of the dispatch lock. - * @param[in,out] channel CommChannel structure to unlock. - */ - -void -CommSvc_DispatchUnlock(CommChannel channel) -{ - Comm_DispatchUnlock(channel); -} - - -/** - * @brief Lock the channel. - * - * Uses the writer lock. This function is exported for the upper layer - * to ensure that channel isn't closed while updating the layer state. - * It also guarantees that if the lock is taken, the entry is either ACTIVE - * or ZOMBIE. Operations using this function are expected to be short, - * since unlike the _Write functions, these callers cannot be signaled. - * @param[in,out] channel CommChannel structure to lock. - * @return zero if successful, -1 otherwise. - */ - -int -CommSvc_Lock(CommChannel channel) -{ - return Comm_Lock(channel); -} - - -/** - * @brief Unlock the channel. - * - * Uses the writer lock. This function is exported for the upper layer - * to ensure that channel isn't closed while updating the layer state. - * See Comm_WriteLock for details). - * @param[in,out] channel CommChannel structure to unlock. - */ - -void -CommSvc_Unlock(CommChannel channel) -{ - Comm_Unlock(channel); -} - - -/** - * @brief Schedules a work item on the AIO thread(s). - * @param[in,out] work work item to be scheduled. - * @return zero if successful, -1 otherwise. - */ - -int -CommSvc_ScheduleAIOWork(CommOSWork *work) -{ - return CommOS_ScheduleAIOWork(work); -} - - -/** - * @brief Requests events be posted in-line after the function completes. - * @param channel channel object. - * @return current number of requests for inline event posting, or -1 on error. - */ - -unsigned int -CommSvc_RequestInlineEvents(CommChannel channel) -{ - return Comm_RequestInlineEvents(channel); -} - - -/** - * @brief Requests events be posted out-of-band after the function completes. - * @param channel channel object. - * @return current number of requests for inline event posting, or -1 on error. - */ - -unsigned int -CommSvc_ReleaseInlineEvents(CommChannel channel) -{ - return Comm_ReleaseInlineEvents(channel); -} - - -#if defined(__linux__) -EXPORT_SYMBOL(CommSvc_RegisterImpl); -EXPORT_SYMBOL(CommSvc_UnregisterImpl); -EXPORT_SYMBOL(CommSvc_Alloc); -EXPORT_SYMBOL(CommSvc_Zombify); -EXPORT_SYMBOL(CommSvc_IsActive); -EXPORT_SYMBOL(CommSvc_GetTranspInitArgs); -EXPORT_SYMBOL(CommSvc_GetState); -EXPORT_SYMBOL(CommSvc_Write); -EXPORT_SYMBOL(CommSvc_WriteVec); -EXPORT_SYMBOL(CommSvc_Put); -EXPORT_SYMBOL(CommSvc_DispatchUnlock); -EXPORT_SYMBOL(CommSvc_Lock); -EXPORT_SYMBOL(CommSvc_Unlock); -EXPORT_SYMBOL(CommSvc_ScheduleAIOWork); -EXPORT_SYMBOL(CommSvc_RequestInlineEvents); -EXPORT_SYMBOL(CommSvc_ReleaseInlineEvents); -#endif // defined(__linux__) diff --git a/arch/arm/mvp/commkm/comm_svc.h b/arch/arm/mvp/commkm/comm_svc.h deleted file mode 100644 index c4f3292..0000000 --- a/arch/arm/mvp/commkm/comm_svc.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Communication functions exported by the comm_rt module. - */ - -#ifndef _COMM_SVC_H_ -#define _COMM_SVC_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "comm.h" - -int CommSvc_RegisterImpl(const CommImpl *impl); -void CommSvc_UnregisterImpl(const CommImpl *impl); -int CommSvc_Zombify(CommChannel channel, int inBH); -int CommSvc_IsActive(CommChannel channel); -CommTranspInitArgs CommSvc_GetTranspInitArgs(CommChannel channel); -void *CommSvc_GetState(CommChannel channel); -void CommSvc_Put(CommChannel channel); -void CommSvc_DispatchUnlock(CommChannel channel); -int CommSvc_Lock(CommChannel channel); -void CommSvc_Unlock(CommChannel channel); -int CommSvc_ScheduleAIOWork(CommOSWork *work); - -int -CommSvc_Alloc(const CommTranspInitArgs *transpArgs, - const CommImpl *impl, - int inBH, - CommChannel *newChannel); - -int -CommSvc_Write(CommChannel channel, - const CommPacket *packet, - unsigned long long *timeoutMillis); - -int -CommSvc_WriteVec(CommChannel channel, - const CommPacket *packet, - struct kvec **vec, - unsigned int *vecLen, - unsigned long long *timeoutMillis, - unsigned int *iovOffset); - -unsigned int CommSvc_RequestInlineEvents(CommChannel channel); -unsigned int CommSvc_ReleaseInlineEvents(CommChannel channel); - -#endif // _COMM_SVC_H_ diff --git a/arch/arm/mvp/commkm/comm_transp.h b/arch/arm/mvp/commkm/comm_transp.h deleted file mode 100644 index 6cc58ae..0000000 --- a/arch/arm/mvp/commkm/comm_transp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Generic shared memory transport API. - */ - -#ifndef _COMM_TRANSP_H_ -#define _COMM_TRANSP_H_ - -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/* - * Common shared memory identifier. - * External handle that makes sense to both hypervisor and guest. - */ - -#define COMM_TRANSP_ID_8_ANY ((unsigned char)-1) -#define COMM_TRANSP_ID_32_ANY ((unsigned int)-1) -#define COMM_TRANSP_ID_64_ANY ((unsigned long long)-1) - - -typedef struct CommTranspID { - union { - unsigned char d8[8]; - unsigned int d32[2]; - unsigned long long d64; - }; -} CommTranspID; - - -/* Basic initialization arguments. */ - -typedef enum CommTranspInitMode { - COMM_TRANSP_INIT_CREATE = 0x0, - COMM_TRANSP_INIT_ATTACH = 0x1 -} CommTranspInitMode; - -typedef struct CommTranspInitArgs { - unsigned int capacity; // Shared memory capacity. - unsigned int type; // Type / implementation using this area. - CommTranspID id; // ID (name) of shared memory area. - CommTranspInitMode mode; // Init mode (above). -} CommTranspInitArgs; - - -/** - * @brief Generate a type id from description (protocol) string. This function - * uses djb2, a string hashing algorithm by Dan Bernstein. - * (see http://www.cse.yorku.ca/~oz/hash.html) - * @param str string to hash - * @return 32-bit hash value - */ - -static inline unsigned int -CommTransp_GetType(const char *str) -{ - unsigned int hash = 5381; - int c; - - while ((c = *str++)) { - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - } - return hash; -} - -#endif // _COMM_TRANSP_H_ diff --git a/arch/arm/mvp/commkm/comm_transp_impl.h b/arch/arm/mvp/commkm/comm_transp_impl.h deleted file mode 100644 index 113cd21..0000000 --- a/arch/arm/mvp/commkm/comm_transp_impl.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Generic shared memory transport private API. - */ - -#ifndef _COMM_TRANSP_IMPL_H_ -#define _COMM_TRANSP_IMPL_H_ - -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "comm_transp.h" - - -/* Shared memory opaque descriptor/handle. Only meaningful locally. */ - -typedef struct CommTranspPriv *CommTransp; - - -/* Asynchronous signaling initialization arguments. */ - -typedef enum CommTranspIOEvent { - COMM_TRANSP_IO_DETACH = 0x0, - COMM_TRANSP_IO_IN = 0x1, - COMM_TRANSP_IO_OUT = 0x2, - COMM_TRANSP_IO_INOUT = 0x3 -} CommTranspIOEvent; - -typedef struct CommTranspEvent { - void (*ioEvent)(CommTransp transp, CommTranspIOEvent event, void *data); - void *ioEventData; -} CommTranspEvent; - - -/* - * Mechanism to detect and optionally attach to, created shared memory regions. - */ - -typedef struct CommTranspListener { - int (*probe)(CommTranspInitArgs *transpArgs, void *probeData); - void *probeData; -} CommTranspListener; - - - -/* - * Function prototypes. - */ - -int CommTranspEvent_Init(void); -void CommTranspEvent_Exit(void); -int CommTranspEvent_Process(CommTranspID *transpID, CommTranspIOEvent event); -int -CommTranspEvent_Raise(unsigned int peerEvID, - CommTranspID *transpID, - CommTranspIOEvent event); - -int CommTransp_Init(void); -void CommTransp_Exit(void); - -int CommTransp_Register(const CommTranspListener *listener); -void CommTransp_Unregister(const CommTranspListener *listener); -int -CommTransp_Notify(const CommTranspID *notificationCenterID, - CommTranspInitArgs *transpArgs); - -int -CommTransp_Open(CommTransp *transp, - CommTranspInitArgs *transpArgs, - CommTranspEvent *transpEvent); -void CommTransp_Close(CommTransp transp); - -int CommTransp_EnqueueSpace(CommTransp transp); -int CommTransp_EnqueueReset(CommTransp transp); -int CommTransp_EnqueueCommit(CommTransp transp); -int -CommTransp_EnqueueSegment(CommTransp transp, - const void *buf, - unsigned int bufLen); - -int CommTransp_DequeueSpace(CommTransp transp); -int CommTransp_DequeueReset(CommTransp transp); -int CommTransp_DequeueCommit(CommTransp transp); -int -CommTransp_DequeueSegment(CommTransp transp, - void *buf, - unsigned int bufLen); - -unsigned int CommTransp_RequestInlineEvents(CommTransp transp); -unsigned int CommTransp_ReleaseInlineEvents(CommTransp transp); - - -/** - * @brief Enqueues data into the transport object, data is available for - * reading immediately. - * @param transp handle to the transport object. - * @param buf bytes to enqueue. - * @param bufLen number of bytes to enqueue. - * @return number of bytes enqueued on success, < 0 otherwise. - */ - -static inline int -CommTransp_EnqueueAtomic(CommTransp transp, - const void *buf, - unsigned int bufLen) -{ - int rc; - - CommTransp_EnqueueReset(transp); - rc = CommTransp_EnqueueSegment(transp, buf, bufLen); - if (CommTransp_EnqueueCommit(transp)) { - rc = -1; - } - return rc; -} - - -/** - * @brief Dequeues data from the transport object into a buffer. - * @param transp handle to the transport object. - * @param[out] buf buffer to copy to. - * @param bufLen number of bytes to dequeue. - * @return number of bytes dequeued on success, < 0 otherwise, - */ - -static inline int -CommTransp_DequeueAtomic(CommTransp transp, - void *buf, - unsigned int bufLen) -{ - int rc; - - CommTransp_DequeueReset(transp); - rc = CommTransp_DequeueSegment(transp, buf, bufLen); - if (CommTransp_DequeueCommit(transp)) { - rc = -1; - } - return rc; -} - -#endif // _COMM_TRANSP_IMPL_H_ diff --git a/arch/arm/mvp/commkm/comm_transp_mvp.c b/arch/arm/mvp/commkm/comm_transp_mvp.c deleted file mode 100644 index f755de9..0000000 --- a/arch/arm/mvp/commkm/comm_transp_mvp.c +++ /dev/null @@ -1,944 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Generic shared memory transport API. - */ -#include <linux/wait.h> - -#include "comm_os.h" -#include "comm_transp_impl.h" - -#include "mvp_types.h" -#include "qp.h" - - -/* - * Opaque CommTransp structure. See comm_transp.h - */ - -struct CommTranspPriv { - QPHandle *qp; - CommTranspEvent event; - unsigned int peerEvID; - unsigned int writeSize; - unsigned int readSize; - uint32 backRef; - CommOSWork work; - CommOSAtomic raiseInline; -}; - -/* - * Transport table object accounting - */ - -typedef struct TranspTableEntry { - CommOSAtomic holds; - CommTransp transp; - CommOSWaitQueue wq; -} TranspTableEntry; - -TranspTableEntry transpTable[QP_MAX_QUEUE_PAIRS]; -static CommOSSpinlock_Define(transpTableLock); - -/** - * @brief Destroy the transport object - * @param transp transport object to destroy - * @sideeffects detaches from queue pair - */ - -static void -DestroyTransp(CommTransp transp) -{ - CommTranspID transpID; - int32 rc; - - if (!transp) { - CommOS_Debug(("Failed to close channel: Bad handle\n")); - return; - } - - CommOS_Log(("%s: Detaching channel [%u:%u]\n", - __FUNCTION__, - transp->qp->id.context, - transp->qp->id.resource)); - - transpID.d32[0] = transp->qp->id.context; - transpID.d32[1] = transp->qp->id.resource; - -#if !defined(COMM_BUILDING_SERVER) - /* - * Tell the host to detach, will block in the host - * until the host has unmapped memory. Once the - * host has unmapped, it is safe to free. - */ - CommTranspEvent_Raise(transp->peerEvID, - &transpID, - COMM_TRANSP_IO_DETACH); -#endif - - rc = QP_Detach(transp->qp); - -#if defined(COMM_BUILDING_SERVER) - /* - * Wake up waiters now that unmapping is complete - */ - CommOS_WakeUp(&transpTable[transp->backRef].wq); -#endif - - CommOS_Kfree(transp); - if (rc != QP_SUCCESS) { - CommOS_Log(("%s: Failed to detach. rc: %d\n", __FUNCTION__, rc)); - } else { - CommOS_Log(("%s: Channel detached.\n", __FUNCTION__)); - } -} - - -/** - * @brief Initialize the transport object table - */ - -static void -TranspTableInit(void) -{ - uint32 i; - CommOS_SpinLock(&transpTableLock); - for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) { - CommOS_WriteAtomic(&transpTable[i].holds, -1); - transpTable[i].transp = NULL; - } - CommOS_SpinUnlock(&transpTableLock); -} - - -/** - * @brief Add a transport object into the table - * @param transp handle to the transport object - * @return 0 on success, -1 otherwise - * @sideeffects increments entry refcount - */ - -static inline int32 -TranspTableAdd(CommTransp transp) -{ - uint32 i; - - if (!transp) { - return -1; - } - - CommOS_SpinLock(&transpTableLock); - for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) { - if ((transpTable[i].transp) == NULL) { - transpTable[i].transp = transp; - CommOS_WriteAtomic(&transpTable[i].holds, 1); - CommOS_WaitQueueInit(&transpTable[i].wq); - transp->backRef = i; - break; - } - } - CommOS_SpinUnlock(&transpTableLock); - - return 0; -} - -/** - * @brief retrieve a transport object and increment its ref count - * @param id transport id to retrieve - * @return transport object, or NULL if not found - * @sideeffects increments entry ref count - */ - -static inline CommTransp -TranspTableGet(CommTranspID *id) -{ - CommTransp transp; - uint32 i; - - if (!id) { - return NULL; - } - - for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) { - transp = transpTable[i].transp; - if (transp && - (transp->qp->id.context == id->d32[0]) && - (transp->qp->id.resource == id->d32[1])) { - CommOS_AddReturnAtomic(&transpTable[i].holds, 1); - return transp; - } - } - CommOS_Debug(("%s: couldn't find transport object\n", __FUNCTION__)); - - return NULL; -} - -/** - * @brief Puts back a previously TranspGet-ed transport object. - * @param transp the transport object. - * @sideeffects decrements the transport reference count. - * frees object if refcount now zero - */ - -static inline void -TranspTablePut(CommTransp transp) -{ - int32 holds; - int32 backRef; - if (!transp) { - return; - } - - backRef = transp->backRef; - BUG_ON(backRef >= QP_MAX_QUEUE_PAIRS); - - holds = CommOS_SubReturnAtomic(&transpTable[backRef].holds, 1); - if (holds > 0) { - return; - } - BUG_ON(holds < 0); - - CommOS_SpinLock(&transpTableLock); - CommOS_WriteAtomic(&transpTable[backRef].holds, -1); - transpTable[backRef].transp = NULL; - CommOS_SpinUnlock(&transpTableLock); - DestroyTransp(transp); -} - - -/** - * @brief Puts back a previously TranspGet-ed transport object. - * @param transp the transport object. - * @sideeffects decrements the transport reference count. - * asserts that remaining count > 0 - */ - -static inline void -TranspTablePutNF(CommTransp transp) -{ - int32 holds; - int32 backRef; - if (!transp) { - return; - } - - backRef = transp->backRef; - BUG_ON(backRef >= QP_MAX_QUEUE_PAIRS); - - holds = CommOS_SubReturnAtomic(&transpTable[backRef].holds, 1); - BUG_ON(holds <= 0); -} - - -/** - * @brief Raises INOUT event in-line or out-of-band. Note that this function - * expects the transport object to be held prior to being called. - * @param arg work item of transport object. - */ - -static void -RaiseEvent(CommOSWork *arg) -{ -#if !defined(__linux__) -#error "RaiseEvent() is only supported on linux. Port 'container_of'!" -#endif - CommTransp transp = container_of(arg, struct CommTranspPriv, work); - CommTranspID transpID = {{ - .d32 = { - [0] = transp->qp->id.context, - [1] = transp->qp->id.resource - } - }}; - - CommTranspEvent_Raise(transp->peerEvID, - &transpID, - COMM_TRANSP_IO_INOUT); - TranspTablePut(transp); -} - - -/** - * @brief Requests events be posted in-line after the function completes. - * @param transp transport object. - * @return current number of requests for inline event posting. - * @sideeffects posts an event on the first transition to in-line processing. - */ - -unsigned int -CommTransp_RequestInlineEvents(CommTransp transp) -{ - unsigned int res = CommOS_AddReturnAtomic(&transp->raiseInline, 1); - if (res == 1) { - /* On the first (effective) transition, make sure an event is raised. */ - - CommOS_AddReturnAtomic(&transpTable[transp->backRef].holds, 1); - RaiseEvent(&transp->work); - } - return res; -} - - -/** - * @brief Requests events be posted out-of-band after the function completes. - * @param transp transport object. - * @return current number of requests for inline event posting. - */ - -unsigned int -CommTransp_ReleaseInlineEvents(CommTransp transp) -{ - return CommOS_SubReturnAtomic(&transp->raiseInline, 1); -} - - -/* - * Comm Offload server callbacks. - */ - -#if defined(COMM_BUILDING_SERVER) - -#define COMM_MAX_LISTENERS QP_MAX_LISTENERS - -static int32 NotifyCB(const QPInitArgs *args); -static void DetachCB(void *data); - -static CommOSSpinlock_Define(listenersLock); -static CommTranspListener listeners[COMM_MAX_LISTENERS]; -static uint32 numListeners = 0; - - -/** - * @brief Notify callback when guests attach to queue pairs. Notifies any - * registered listeners (e.g. Comm layer). - * @param args Initialization arguments used by the guest to initialize - * its queue pair - * @return 0 on success, <0 otherwise. see qp.h for error codes. - */ - -static int32 -NotifyCB(const QPInitArgs* args) -{ - CommTranspInitArgs transpArgs; - uint32 i; - int32 rc = -1; - - if (!args) { - return QP_ERROR_INVALID_ARGS; - } - - transpArgs.id.d32[0] = args->id.context; - transpArgs.id.d32[1] = args->id.resource; - transpArgs.capacity = args->capacity; - transpArgs.type = args->type; - - CommOS_SpinLock(&listenersLock); - for (i = 0; i < COMM_MAX_LISTENERS; i++) { - if (listeners[i].probe && - (listeners[i].probe(&transpArgs, listeners[i].probeData) == 0)) { - CommOS_Debug(("%s: Delivered notify event to listener %u\n", - __FUNCTION__, - i)); - rc = 0; - break; - } - } - CommOS_SpinUnlock(&listenersLock); - return rc; -} - - -/** - * @brief Detach callback when guests detach from queue pairs. Notifies - * any registered listeners (e.g. CommComm layer). - * @param data Transport object passed when the callback was registered - */ - -static void -DetachCB(void *data) -{ - CommTransp transp = data; - if (!transp || !(transp->event.ioEvent)) { - return; - } - CommOS_Debug(("%s: Guest detached from [%u:%u]\n", - __FUNCTION__, - transp->qp->id.context, - transp->qp->id.resource)); - transp->event.ioEvent(transp, COMM_TRANSP_IO_DETACH, transp->event.ioEventData); -} -#endif - - -/** - * @brief Performs one-time initialization of mvp transport provider. - * @return 0 on success, < 0 otherwise. - */ - -int -CommTransp_Init(void) -{ - int32 rc; - TranspTableInit(); - - rc = CommTranspEvent_Init(); - -#if defined(COMM_BUILDING_SERVER) - if (!rc) { - QP_RegisterListener(NotifyCB); - } -#endif - return rc; -} - - -/** - * @brief Performs clean-up of mvp transport provider. - */ - -void -CommTransp_Exit(void) -{ - CommTranspEvent_Exit(); -#if defined(COMM_BUILDING_SERVER) - QP_UnregisterListener(NotifyCB); -#endif -} - -#if defined(COMM_BUILDING_SERVER) - -/** - * @brief Checks for a successful detach from Comm - * @param arg1 back reference index for channel in transport table - * @param arg2 ignored - * @return 1 if detach completed, 0 otherwise - */ - -static int -DetachCondition(void *arg1, void *arg2) -{ - uint32 backRef = (uint32)arg1; - - return (CommOS_ReadAtomic(&transpTable[backRef].holds) == -1); -} -#endif - - -/** - * @brief Processes a raised signal event. This is a callback function called - * from a comm_transp_ev plugin when a signal is received. Delivers an event - * to one or more channels. If id->d32[1] == COMM_TRANSP_ID_32_ANY, the event - * will be delivered to all registered channels associated with vmID - * id->d32[0]. - * @param id identifies a transport object to signal. - * @param event type of event. - * @return 0 if delivered to at least one channel, -1 on failure. - */ - -int -CommTranspEvent_Process(CommTranspID *id, - CommTranspIOEvent event) -{ - int rc = 0; - unsigned int delivered = 0; - unsigned int backRef; - int i = 0; - - CommTransp transp; - uint32 raiseOnAllChannels = (id->d32[1] == COMM_TRANSP_ID_32_ANY); - uint32 channels = raiseOnAllChannels ? QP_MAX_QUEUE_PAIRS : 1; - - while (channels--) { - if (raiseOnAllChannels) { - id->d32[1] = i++; - } - transp = TranspTableGet(id); - if (transp) { - if (transp->event.ioEvent) { - transp->event.ioEvent(transp, event, transp->event.ioEventData); - } - backRef = transp->backRef; - TranspTablePut(transp); - -#if defined(COMM_BUILDING_SERVER) - /* - * Wait for unmap on IO_DETACH, return to monitor. - */ - if (event == COMM_TRANSP_IO_DETACH) { - unsigned long long timeout = 30000; - - rc = CommOS_Wait(&transpTable[backRef].wq, - DetachCondition, - (void*)backRef, - NULL, - &timeout); - switch (rc) { - case 1: // Memory successfully unmapped - rc = 0; - break; - default: // Timed out or other error. - return -1; - } - } -#endif - delivered++; - } - } - - rc = (delivered > 0) ? 0 : -1; - return rc; -} - - -/** - * @brief Register a listener to be notified when guests attach to the Comm - * offload server - * @param listener the listener to be notified - * @return 0 on success, -1 on failure - */ - -int -CommTransp_Register(const CommTranspListener *listener) -{ - int32 rc = -1; -#if defined(COMM_BUILDING_SERVER) - uint32 i; - - if (!listener) { - return -1; - } - - CommOS_SpinLock(&listenersLock); - for (i = 0; i < COMM_MAX_LISTENERS; i++) { - if ((listeners[i].probe == NULL) && - (listeners[i].probeData == NULL)) { - listeners[i] = *listener; - numListeners++; - rc = 0; - CommOS_Debug(("%s: Registered listener %u\n", __FUNCTION__, i)); - break; - } - } - CommOS_SpinUnlock(&listenersLock); -#endif - return rc; -} - - -/** - * @brief Unregisters a listener from the transport event notification system - * @param listener listener to unregister - * @return 0 on success - */ - -void -CommTransp_Unregister(const CommTranspListener *listener) -{ -#if defined(COMM_BUILDING_SERVER) - uint32 i; - - if (!listener || !listener->probe) { - return; - } - - - CommOS_SpinLock(&listenersLock); - for (i = 0; i < COMM_MAX_LISTENERS; i++) { - if ((listeners[i].probe == listener->probe) && - (listeners[i].probeData == listener->probeData)) { - listeners[i].probe = NULL; - listeners[i].probeData = NULL; - numListeners--; - CommOS_Debug(("%s: Unregistered listener %u\n", __FUNCTION__, i)); - } - } - CommOS_SpinUnlock(&listenersLock); -#endif -} - - -/** - * @brief Allocates and initializes a transport object - * @param[in,out] transp handle to the transport to allocate and initialize - * @param transpArgs initialization arguments (see pvtcpTransp.h) - * @param transpEvent event callback to be delivered when events occur (e.g. - * detach events) - * @return 0 on success, <0 otherwise. See qp.h for error codes. - * @sideeffects Allocates memory - */ - -int -CommTransp_Open(CommTransp *transp, - CommTranspInitArgs *transpArgs, - CommTranspEvent *transpEvent) -{ - int32 rc = -1; - QPHandle *qp = NULL; - CommTransp transpOut = NULL; - QPInitArgs qpInitArgs; - - if (!transp || !transpArgs) { - return -1; - } - - CommOS_Log(("%s: Attaching to [%u:%u]. Capacity: %u\n", - __FUNCTION__, - transpArgs->id.d32[1], - transpArgs->id.d32[0], - transpArgs->capacity)); - - qpInitArgs.id.context = transpArgs->id.d32[0]; - qpInitArgs.id.resource = transpArgs->id.d32[1]; - qpInitArgs.capacity = transpArgs->capacity; - qpInitArgs.type = transpArgs->type; - - if (!(transpOut = CommOS_Kmalloc(sizeof *transpOut))) { - rc = -1; - goto out; - } - - /* - * Attach to the queue pair - */ - rc = QP_Attach(&qpInitArgs, &qp); - if (rc < 0) { - rc = -1; - goto out; - } - - transpOut->qp = qp; - - /* - * Reassign ID so Comm knows what ID was actually given - */ - transpArgs->id.d32[0] = qp->id.context; - transpArgs->id.d32[1] = qp->id.resource; - - if (transpEvent) { - transpOut->event = *transpEvent; - } else { - transpOut->event.ioEvent = NULL; - transpOut->event.ioEventData = NULL; - } - -#if defined(COMM_BUILDING_SERVER) - CommOS_Debug(("%s: Registering detach CB on id %u...\n", - __FUNCTION__, transpArgs->id.d32[1])); - QP_RegisterDetachCB(transpOut->qp, DetachCB, transpOut); -#endif - - transpOut->peerEvID = COMM_TRANSP_ID_32_ANY; - transpOut->writeSize = 0; - transpOut->readSize = 0; - CommOS_InitWork(&transpOut->work, RaiseEvent); - CommOS_WriteAtomic(&transpOut->raiseInline, 0); - - if (TranspTableAdd(transpOut)) { - CommOS_Log(("%s: Exceeded max limit of transport objects!\n", - __FUNCTION__)); - DestroyTransp(transpOut); - rc = -1; - goto out; - } - - *transp = transpOut; - rc = 0; - - CommOS_Log(("%s: Channel attached.\n", __FUNCTION__)); - -out: - if (rc && transpOut) { - CommOS_Log(("%s: Failed to attach: %d\n", __FUNCTION__, rc)); - CommOS_Kfree(transpOut); - } - - return rc; -} - - -/** - * @brief Tear down the transport channel, destroy the object if the refcount - * drops to zero - * @param transp handle to the transport channel - * @sideeffects decrements the entry's refcount - */ - -void -CommTransp_Close(CommTransp transp) { - if (!transp) { - return; - } - CommOS_FlushAIOWork(&transp->work); - TranspTablePut(transp); -} - - -/** - * @brief Returns available space for enqueue, in bytes - * @param transp handle to the transport object - * @return available space in the queue for enqueue operations, <0 - * on error conditions. see qp.h for error codes. - */ - -int -CommTransp_EnqueueSpace(CommTransp transp) -{ - if (!transp) { - return -1; - } - return QP_EnqueueSpace(transp->qp); -} - - -/** - * @brief Discards any pending enqueues - * @param transp handle to the transport object - * @return 0 on success, <0 otherwise. see qp.h for error codes - */ - -int -CommTransp_EnqueueReset(CommTransp transp) -{ - if (!transp) { - return -1; - } - transp->writeSize = 0; - return QP_EnqueueReset(transp->qp); -} - - -/** - * @brief Enqueues a segment of data into the transport object - * @param transp handle to the transport object - * @param buf data to enqueue - * @param bufLen number of bytes to enqueue - * @return number of bytes enqueued on success, <0 otherwise. see qp.h - * for error codes - */ - -int -CommTransp_EnqueueSegment(CommTransp transp, - const void *buf, - unsigned int bufLen) -{ - int rc; - - if (!transp) { - return -1; - } - rc = QP_EnqueueSegment(transp->qp, (void*)buf, bufLen); - if (rc >= 0) { - transp->writeSize += (unsigned int)rc; - } else { - transp->writeSize = 0; - } - return rc; -} - - -/** - * @brief Commits any previous EnqueueSegment operations to the transport - * object. - * @param transp handle to the transport object. - * @return 0 on success, < 0 otherwise. - */ - -int -CommTransp_EnqueueCommit(CommTransp transp) -{ - int rc; - - if (!transp) { - return -1; - } - - rc = QP_EnqueueCommit(transp->qp); - if (rc >= 0) { - const unsigned int fudge = 4; - int writable = CommTransp_EnqueueSpace(transp); - - if ((writable >= 0) && - ((transp->writeSize + (unsigned int)writable + fudge) >= - transp->qp->queueSize)) { - /* - * If bytes written since last commit + writable space 'almost' - * equal write queue size, then signal. The 'almost' fudge factor - * accounts for a possibly inaccurate CommTransp_EnqueueSpace() - * return value. Most of the time, this is inconsequential. In - * rare, borderline occasions, it results in a few extra signals. - * The scheme essentially means this: if this is the first packet - * to be write-committed, we signal. Otherwise, the remote end is - * supposed to keep going for as long as it can read. - * - */ - - BUG_ON(transp->backRef >= QP_MAX_QUEUE_PAIRS); - CommOS_AddReturnAtomic(&transpTable[transp->backRef].holds, 1); - if (CommOS_ReadAtomic(&transp->raiseInline)) { - RaiseEvent(&transp->work); - } else if (CommOS_ScheduleAIOWork(&transp->work)) { - TranspTablePutNF(transp); - } - } - } else { - rc = -1; - } - transp->writeSize = 0; - return rc; -} - - -/** - * @brief Returns any available bytes for dequeue - * @param transp handle to the transport object - * @return available bytes for dequeue, <0 otherwise. see qp.h for error codes - */ - -int -CommTransp_DequeueSpace(CommTransp transp) -{ - if (!transp) { - return -1; - } - return QP_DequeueSpace(transp->qp); -} - - -/** - * @brief Discards any pending dequeues - * @param transp handle to the transport object - * @return 0 on success, <0 otherwise, see qp.h for error codes - */ - -int -CommTransp_DequeueReset(CommTransp transp) -{ - if (!transp) { - return -1; - } - transp->readSize = 0; - return QP_DequeueReset(transp->qp); -} - - -/** - * @brief Dequeues a segment of data from the consumer queue into - * a buffer - * @param transp handle to the transport object - * @param[out] buf buffer to copy to - * @param bufLen number of bytes to dequeue - * @return number of bytes dequeued on success, <0 otherwise, - * see qp.h for error codes - */ - -int -CommTransp_DequeueSegment(CommTransp transp, - void *buf, - unsigned bufLen) -{ - int rc; - - if (!transp) { - return -1; - } - rc = QP_DequeueSegment(transp->qp, buf, bufLen); - if (rc >= 0) { - transp->readSize += (unsigned int)rc; - } else { - transp->readSize = 0; - } - return rc; -} - - -/** - * @brief Commits any previous DequeueSegment operations to the - * transport object. - * @param transp handle to the transport object. - * @return 0 on success, < 0 otherwise. - */ - -int -CommTransp_DequeueCommit(CommTransp transp) -{ - int rc; - - if (!transp) { - return -1; - } - rc = QP_DequeueCommit(transp->qp); - if (rc >= 0) { - int readable = CommTransp_DequeueSpace(transp); - const unsigned int limit = transp->qp->queueSize / 2; - - if ((readable >= 0) && - (transp->readSize + (unsigned int)readable >= limit) && - ((unsigned int)readable < limit)) { - /* - * Minimize the number of likely 'peer write OK' signalling: - * only do it, if reading crossed half-way down. - * - */ - - BUG_ON(transp->backRef >= QP_MAX_QUEUE_PAIRS); - CommOS_AddReturnAtomic(&transpTable[transp->backRef].holds, 1); - if (CommOS_ReadAtomic(&transp->raiseInline)) { - RaiseEvent(&transp->work); - } else if (CommOS_ScheduleAIOWork(&transp->work)) { - TranspTablePut(transp); - } - } - } else { - rc = -1; - } - /* coverity[deref_after_free] */ - transp->readSize = 0; - return rc; -} - - -/** - * @brief Notify any registered listeners for the given queue pair - * @param notificationCenterID noop, unused on MVP - * @param transpArgs initialization arguments used by the guest for this - * channel - * @sideeffects the host may attach to the queue pair - */ - -int -CommTransp_Notify(const CommTranspID *notificationCenterID, - CommTranspInitArgs *transpArgs) -{ - QPInitArgs args; - - args.id.context = transpArgs->id.d32[0]; - args.id.resource = transpArgs->id.d32[1]; - args.capacity = transpArgs->capacity; - args.type = transpArgs->type; - - CommOS_Debug(("%s: d32[0]: %u d32[1]: %u\n", - __FUNCTION__, - transpArgs->id.d32[0], - transpArgs->id.d32[1])); - QP_Notify(&args); - return 0; -} diff --git a/arch/arm/mvp/commkm/fatalerror.h b/arch/arm/mvp/commkm/fatalerror.h deleted file mode 100644 index 9676ff3..0000000 --- a/arch/arm/mvp/commkm/fatalerror.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief fatal error handlers. They all post fatal errors regardless of build - * type. - */ - -#ifndef _FATALERROR_H -#define _FATALERROR_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mvp_compiler.h" - -#ifdef __cplusplus -extern "C" { -#endif - -enum FECode { - FECodeMisc, ///< generic FATAL() call of sorts - FECodeOOM, ///< FATAL_OOM() call of sorts - FECodeAssert, ///< ASSERT() call of sorts - FECodeNR, ///< NOT_REACHED() call of sorts - FECodeNI, ///< NOT_IMPLEMENTED() call of sorts - FECodeNT, ///< NOT_TESTED() call of sorts - FECodeCF ///< COMPILE_FAIL() call of sorts -}; -typedef enum FECode FECode; - -#define FATAL() FatalError(__FILE__, __LINE__, FECodeMisc, 0, NULL) -#define FATAL_IF(x) do { if (UNLIKELY(x)) FATAL(); } while (0) -#define FATAL_OOM() FatalError(__FILE__, __LINE__, FECodeOOM, 0, NULL) -#define FATAL_OOM_IF(x) do { if (UNLIKELY(x)) FATAL_OOM(); } while (0) - -extern _Bool FatalError_hit; - -void NORETURN FatalError(char const *file, - int line, - FECode feCode, - int bugno, - char const *fmt, - ...) FORMAT(printf,5,6); - -#define FATALERROR_COMMON(printFunc, \ - printFuncV, \ - file, \ - line, \ - feCode, \ - bugno, \ - fmt) { \ - va_list ap; \ - \ - printFunc("FatalError: %s:%d, code %d, bugno %d\n", \ - file, line, feCode, bugno); \ - if (fmt != NULL) { \ - va_start(ap, fmt); \ - printFuncV(fmt, ap); \ - va_end(ap); \ - } \ - } - -#if defined IN_HOSTUSER || defined IN_GUESTUSER || defined IN_WORKSTATION - -#define FATALERROR_POSIX_USER \ -void \ -FatalError_VErrPrintf(const char *fmt, va_list ap) \ -{ \ - vfprintf(stderr, fmt, ap); \ -} \ -\ -void \ -FatalError_ErrPrintf(const char *fmt, ...) \ -{ \ - va_list ap; \ - va_start(ap, fmt); \ - FatalError_VErrPrintf(fmt, ap); \ - va_end(ap); \ -} \ -\ -void NORETURN \ -FatalError(char const *file, \ - int line, \ - FECode feCode, \ - int bugno, \ - const char *fmt, \ - ...) \ -{ \ - FATALERROR_COMMON(FatalError_ErrPrintf, FatalError_VErrPrintf, file, line, feCode, bugno, fmt); \ - exit(EXIT_FAILURE); \ -} -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/arch/arm/mvp/commkm/include_check.h b/arch/arm/mvp/commkm/include_check.h deleted file mode 100644 index 2eeafe7..0000000 --- a/arch/arm/mvp/commkm/include_check.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for Empty File Placeholder - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ diff --git a/arch/arm/mvp/commkm/mksck.h b/arch/arm/mvp/commkm/mksck.h deleted file mode 100644 index e9e10bc..0000000 --- a/arch/arm/mvp/commkm/mksck.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -#ifndef _MKSCK_H -#define _MKSCK_H - -/** - * @file - * - * @brief The monitor-kernel socket interface definitions. - * - * The monitor kernel socket interface was created for (what the name - * says) communications between the monitor and host processes. On the - * monitor side a special API is introduced, see mksck_vmm.h. On the - * host side the API is the standard Berkeley socket interface. Host - * process to host process or monitor to monitor communication is not - * supported. - * - * A generic address consists of two 16 bit fields: the vm id and the - * port id. Both hosts (vmx) and monitors (vmm) get their vm id - * automatically. The host vm id is assigned at the time the host - * process opens the mvpkm file descriptor, while the monitor vm id is - * assigned when the vmx.c:SetupWorldSwitchPage() calls - * Mvpkm_SetupIds(). As a vmx may create multiple monitors to service - * an MP guest, a vmx vm id may be associated with multiple monitor vm - * ids. A monitor id, however, has a single associated vmx host id, - * the id of its canonical vmx. - * - * Sockets on the host get their addresses either by explicit user - * call (the bind command) or implicitly by (issuing a send command - * first). At an explicit bind the user may omit one or both fields by - * providing MKSCK_VMID_UNDEF/MKSCK_PORT_UNDEF respectively. An - * implicit bind behaves as if both fields were omitted in an explicit - * bind. The default value of the vmid field is the vmid computed from - * the thread group id while that of a port is a new number. It is not - * invalid to bind a host process socket with a vm id different from - * the vmid computed from the tgid. - * - * Sockets of the monitor are automatically assigned a vmid, that of their - * monitor, at the time of their creation. The port id can be assigned by the - * user or left to the implementation to assign an unused one (by specifying - * MKSCK_PORT_UNDEF at @ref Mksck_Open). - * - * Host unconnected sockets may receive from any monitor sender, may send to any - * monitor socket. A socket can be connected to a peer address, that enables the - * use of the send command. - * - * One of many special predefined port (both host and monitor) is - * MKSCK_PORT_MASTER. It is used for initialization. - * - * Monitor sockets have to send their peer address explicitly (by - * Mksck_SetPeer()) or implicitly by receiving first. After the peer - * is set, monitor sockets may send or receive only to/from their - * peer. - */ - - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "vmid.h" - -/* - * The interface limits the size of transferable packets. - */ -#define MKSCK_XFER_MAX 1024 - -#define MKSCK_ADDR_UNDEF (uint32)0xffffffff - -#define MKSCK_PORT_UNDEF (uint16)0xffff -#define MKSCK_PORT_MASTER (MKSCK_PORT_UNDEF-1) -#define MKSCK_PORT_HOST_FB (MKSCK_PORT_UNDEF-2) -#define MKSCK_PORT_BALLOON (MKSCK_PORT_UNDEF-3) -#define MKSCK_PORT_HOST_HID (MKSCK_PORT_UNDEF-4) -#define MKSCK_PORT_CHECKPOINT (MKSCK_PORT_UNDEF-5) -#define MKSCK_PORT_COMM_EV (MKSCK_PORT_UNDEF-6) -#define MKSCK_PORT_HIGH (MKSCK_PORT_UNDEF-7) - -#define MKSCK_VMID_UNDEF VMID_UNDEF -#define MKSCK_VMID_HIGH (MKSCK_VMID_UNDEF-1) - -#define MKSCK_DETACH 3 - -typedef uint16 Mksck_Port; -typedef VmId Mksck_VmId; - -/** - * @brief Page descriptor for typed messages. Each page describes a region of - * the machine address space with base mpn and size 2^(12 + order) bytes. - */ -typedef struct { - uint32 mpn : 20; ///< Base MPN of region described by page - uint32 order : 12; ///< Region is 2^(12 + order) bytes. -} Mksck_PageDesc; - -/** - * @brief Typed message template macro. Allows us to avoid having two message - * types, one with page descriptor vector (for VMM), one without (for - * VMX). - * - * @param type C type of uninterpreted component of the message (following the - * page descriptor vector). - * @param pages number of page descriptors in vector. - */ -#define MKSCK_DESC_TYPE(type,pages) \ - struct { \ - type umsg; \ - Mksck_PageDesc page[pages]; \ - } - -/** - * @brief The monitor kernel socket interface address format - */ -typedef union { - uint32 addr; ///< the address - struct { /* The address is decomposed to two shorts */ - Mksck_Port port; ///< port unique within a vmid - Mksck_VmId vmId; ///< unique vmid - }; -} Mksck_Address; - -static inline uint32 -Mksck_AddrInit(Mksck_VmId vmId, Mksck_Port port) -{ - Mksck_Address aa; - aa.vmId = vmId; - aa.port = port; - return aa.addr; -} -#endif diff --git a/arch/arm/mvp/commkm/mksck_sockaddr.h b/arch/arm/mvp/commkm/mksck_sockaddr.h deleted file mode 100644 index 82df240..0000000 --- a/arch/arm/mvp/commkm/mksck_sockaddr.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Host user space definitions for mksck sockets. - */ - -#ifndef _MKSCK_SOCKADDR_H_ -#define _MKSCK_SOCKADDR_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mksck.h" - -/* no one ever uses DECnet anymore? */ -#define AF_MKSCK AF_DECnet -#define PF_MKSCK PF_DECnet - -/* Address structure used by the host user socket interface. */ -struct sockaddr_mk { - sa_family_t mk_family; - Mksck_Address mk_addr; -}; - -#endif diff --git a/arch/arm/mvp/commkm/mvp.h b/arch/arm/mvp/commkm/mvp.h deleted file mode 100644 index a57f8cc..0000000 --- a/arch/arm/mvp/commkm/mvp.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief top-level include for all basic includes. - * This file should not define anything of its own. - */ - -#ifndef _MVP_H -#define _MVP_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mvp_compiler.h" -#include "utils.h" -#include "mvp_assert.h" -#include "mvp_types.h" -#include "platdefx.h" - -#endif diff --git a/arch/arm/mvp/commkm/mvp_assert.h b/arch/arm/mvp/commkm/mvp_assert.h deleted file mode 100644 index cbc5ed8..0000000 --- a/arch/arm/mvp/commkm/mvp_assert.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief ASSERT() and related macros. - */ - -#ifndef _MVP_ASSERT_H -#define _MVP_ASSERT_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define ASSERT(_x) ASSERT_BUG((_x),0) - -#ifndef NDEBUG -#define ASSERT_BUG(_x,_tkt) do { \ - if (UNLIKELY(!(_x))) { \ - FatalError(__FILE__, __LINE__, FECodeAssert, _tkt, NULL); \ - } \ -} while (0) - -#define ASSERTF(_x, ...) do { \ - if (UNLIKELY(!(_x))) { \ - FatalError(__FILE__, \ - __LINE__, \ - FECodeAssert, \ - 0, \ - __VA_ARGS__); \ - } \ -} while (0) -#else - -#define ASSERT_BUG(_x,_tkt) (void)sizeof((int)(_x)) -#define ASSERTF(_x, ...) ASSERT_BUG(_x, 0) - -#endif - -/* - * Compile-time assertions. - * - * ASSERT_ON_COMPILE does not use the common - * switch (0) { case 0: case (e): ; } trick because some compilers (e.g. MSVC) - * generate code for it. - * - * The implementation uses both enum and typedef because the typedef alone is - * insufficient; gcc allows arrays to be declared with non-constant expressions - * (even in typedefs, where it makes no sense). - */ -#ifdef __COVERITY__ -#define ASSERT_ON_COMPILE(e) ASSERT(e) -#else -#define ASSERT_ON_COMPILE(e) \ - do { \ - enum { AssertOnCompileMisused = ((e) ? 1 : -1) }; \ - typedef char AssertOnCompileFailed[AssertOnCompileMisused]; \ - } while (0) -#endif - -/* - * To put an ASSERT_ON_COMPILE() outside a function, wrap it - * in MY_ASSERTS(). The first parameter must be unique in - * each .c file where it appears. For example, - * - * MY_ASSERTS(FS3_INT, - * ASSERT_ON_COMPILE(sizeof(FS3_DiskLock) == 128); - * ASSERT_ON_COMPILE(sizeof(FS3_DiskLockReserved) == DISK_BLOCK_SIZE); - * ASSERT_ON_COMPILE(sizeof(FS3_DiskBlock) == DISK_BLOCK_SIZE); - * ASSERT_ON_COMPILE(sizeof(Hardware_DMIUUID) == 16); - * ) - * - * Caution: ASSERT() within MY_ASSERTS() is silently ignored. - * The same goes for anything else not evaluated at compile time. - */ - -#define MY_ASSERTS(name, assertions) \ - static inline void name(void) { \ - assertions \ - } - -#define KNOWN_BUG(_tkt) - -#define NOT_IMPLEMENTED() NOT_IMPLEMENTED_JIRA(0) -#define NOT_IMPLEMENTED_JIRA(_tkt,...) FatalError(__FILE__, __LINE__, FECodeNI, _tkt, NULL) - -#define NOT_IMPLEMENTED_IF(_x) NOT_IMPLEMENTED_IF_JIRA((_x),0) -#define NOT_IMPLEMENTED_IF_JIRA(_x,_tkt,...) do { if (UNLIKELY(_x)) NOT_IMPLEMENTED_JIRA(_tkt); } while (0) -/* - * All sites tagged with this are @knownjira{MVP-1855}. - */ -#define NOT_IMPLEMENTEDF(...) FatalError(__FILE__, __LINE__, FECodeNI, 0, __VA_ARGS__) - -#define NOT_REACHED() FatalError(__FILE__, __LINE__, FECodeNR, 0, NULL) - -#include "fatalerror.h" -#include "nottested.h" - -#endif diff --git a/arch/arm/mvp/commkm/mvp_compiler.h b/arch/arm/mvp/commkm/mvp_compiler.h deleted file mode 100644 index 21af455..0000000 --- a/arch/arm/mvp/commkm/mvp_compiler.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Compiler-related definitions and directives. - */ - -#ifndef _MVP_COMPILER_H_ -#define _MVP_COMPILER_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#ifdef __GNUC__ -#include "mvp_compiler_gcc.h" -#else /* __GNUC__ */ -#include "mvp_compiler_other.h" -#endif /* __GNUC__ */ - -/** - * @brief Find last set bit. - * - * @param n unsigned 32-bit integer. - * - * @return 0 if n == 0 otherwise 32 - the number of leading zeroes in n. - */ -#define FLS(n) (32 - CLZ(n)) - -#endif /// ifndef _MVP_COMPILER_H_ diff --git a/arch/arm/mvp/commkm/mvp_compiler_gcc.h b/arch/arm/mvp/commkm/mvp_compiler_gcc.h deleted file mode 100644 index fbc96e3..0000000 --- a/arch/arm/mvp/commkm/mvp_compiler_gcc.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief common definitions for GCC - */ - -#ifndef _MVP_COMPILER_GCC_H -#define _MVP_COMPILER_GCC_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/** - * @brief Count leading zeroes. - * - * @param n unsigned 32-bit integer. - * - * @return 32 if n == 0 otherwise 31 - the bit position of the most significant 1 - * in n. - */ -#ifdef __COVERITY__ -static inline int -CLZ(unsigned int n) -{ - unsigned int r = 0; - - while (n) { - r++; - n >>= 1; - } - - return 32 - r; -} -#else -#define CLZ(n) __builtin_clz(n) -#endif - -#define PACKED __attribute__ ((packed)) -#define ALLOC __attribute__ ((malloc, warn_unused_result)) -#define UNUSED __attribute__ ((unused)) -#define PURE __attribute__ ((pure)) -#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) -#define FORMAT(x,y,z) __attribute__ ((format(x,y,z))) -#define LIKELY(x) __builtin_expect(!!(x), 1) -#define UNLIKELY(x) __builtin_expect((x), 0) - -/* - * For debug builds, we want to omit __attribute__((noreturn)) so that gcc will - * keep stack linkages and then we will have useful core dumps. For non-debug - * builds, we don't care about the stack frames and want the little bit of - * optimization that noreturn gives us. - */ -#if defined(__COVERITY__) || !defined(MVP_DEBUG) -#define NORETURN __attribute__((noreturn)) -#else -#define NORETURN -#endif - -#endif diff --git a/arch/arm/mvp/commkm/mvp_types.h b/arch/arm/mvp/commkm/mvp_types.h deleted file mode 100644 index ba5c04c..0000000 --- a/arch/arm/mvp/commkm/mvp_types.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief basic type definitions. - * These may need to be conditionalized for different compilers/platforms. - */ - -#ifndef _MVPTYPES_H -#define _MVPTYPES_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef unsigned long long uint64; - -typedef signed char int8; -typedef short int16; -typedef int int32; -typedef long long int64; - -typedef uint32 CVA; // whatever we are compiling the code as -typedef uint32 GVA; // guest virtual addresses -typedef uint32 MVA; // monitor virtual addresses -typedef uint32 HKVA; // host kernel virtual addresses -typedef uint32 HUVA; // host user virtual addresses -typedef uint64 PA; // (guest) physical addresses (40-bit) -typedef uint32 MA; // (host) machine addresses - -typedef uint32 PPN; // PA/PAGE_SIZE -typedef uint32 MPN; // MA/PAGE_SIZE - -typedef uint64 cycle_t; - -/** - * @brief Page segment. - * - * Specifies a segment within a single page. - */ -typedef struct { - uint16 off; - uint16 len; -} PageSeg; - -/* - * GCC's argument checking for printf-like functions - * - * fmtPos is the position of the format string argument, beginning at 1 - * varPos is the position of the variable argument, beginning at 1 - */ - -#if defined(__GNUC__) -# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos))) -#else -# define PRINTF_DECL(fmtPos, varPos) -#endif - -#if defined(__GNUC__) -# define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos))) -#else -# define SCANF_DECL(fmtPos, varPos) -#endif - -#endif /* _MVPTYPES_H */ diff --git a/arch/arm/mvp/commkm/mvpkm_comm_ev.h b/arch/arm/mvp/commkm/mvpkm_comm_ev.h deleted file mode 100644 index b220a9b..0000000 --- a/arch/arm/mvp/commkm/mvpkm_comm_ev.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief mvpkm kernel hooks for comm event signaling - */ - -#ifndef _MVPKM_COMM_EV_H -#define _MVPKM_COMM_EV_H - -extern int (*CommTranspEvProcess)(CommTranspID* id, CommTranspIOEvent event); - -/** - * @brief Forward any guest signal requests to the commkm module - * @param id transport channel id - * @param event comm event type - */ - -static inline void -Mvpkm_CommEvSignal(CommTranspID *id, CommTranspIOEvent event) -{ - if (CommTranspEvProcess) { - CommTranspEvProcess(id, event); - } -} - -void -Mvpkm_CommEvRegisterProcessCB(int (*commProcessFunc)(CommTranspID*, - CommTranspIOEvent)); -void Mvpkm_CommEvUnregisterProcessCB(void); - - - -#endif diff --git a/arch/arm/mvp/commkm/nottested.h b/arch/arm/mvp/commkm/nottested.h deleted file mode 100644 index c5c1e26..0000000 --- a/arch/arm/mvp/commkm/nottested.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief NOT_TESTED() and related. - */ - -#ifndef _NOTTESTED_H -#define _NOTTESTED_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include <stdbool.h> - -#ifdef NOT_TESTED_ENABLED -#define NotTestedEnabled true -#else -#define NotTestedEnabled false -#endif - -#define NOT_TESTED() NOT_TESTED_JIRA(0) -#define NOT_TESTED_JIRA(_tkt,...) NotTested(_tkt, __FILE__, __LINE__) - -void NotTested(int tkt, char const *file, int line); - -#endif diff --git a/arch/arm/mvp/commkm/platdefx.h b/arch/arm/mvp/commkm/platdefx.h deleted file mode 100644 index 42953e6..0000000 --- a/arch/arm/mvp/commkm/platdefx.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Basic platform definitions needed various places. - */ - -#ifndef _PLATDEFX_H -#define _PLATDEFX_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define PAGE_ORDER 12 - -#ifndef PAGE_SIZE -#define PAGE_SIZE (1UL << PAGE_ORDER) -#endif -#if PAGE_SIZE != 4096 -#error bad page size PAGE_SIZE -#endif - -#define PA_2_PPN(_pa) ((_pa) / PAGE_SIZE) -#define PPN_2_PA(_ppn) ((_ppn) * PAGE_SIZE) - -#define VMM_DOMAIN 0x0 -#define VMM_DOMAIN_NO_ACCESS 0x3 -#define VMM_DOMAIN_CLIENT 0x1 -#define VMM_DOMAIN_MANAGER 0x4 - -#define INVALID_CVA (-(CVA)1) -#define INVALID_GVA (-(GVA)1) -#define INVALID_MVA (-(MVA)1) -#define INVALID_HKVA (-(HKVA)1) -#define INVALID_HUVA (-(HUVA)1) - -#define INVALID_MPN (((MPN)-1) >> ARM_L2D_SMALL_ORDER) -#define INVALID_PPN (((PPN)-1) >> ARM_L2D_SMALL_ORDER) - -#endif diff --git a/arch/arm/mvp/commkm/qp.h b/arch/arm/mvp/commkm/qp.h deleted file mode 100644 index d4a50ec..0000000 --- a/arch/arm/mvp/commkm/qp.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MVP Queue Pairs function and structure declarations - * - * MVP Queue Pairs: - * - * Queue pairs are intended to be a generic bulk data transport mechanism - * between the guest and host kernels. The queue pair abstraction is based - * on two ring buffers (queues) placed on a shared memory region mapped - * into both guest and host kernel address spaces. - * - * NOTE: Queue pairs are SINGLE-READER, SINGLE-WRITER. Any caller is - * responsible for multi-reader/writer serialization!!! - * - * There are a maximum of QP_MAX_QUEUE_PAIRS in the system, with a maximum - * size of QP_MAX_CAPACITY per pair. Each queue pair is identified by - * an ID. - * - * Each peer follows a producer-consumer model in which one side is the - * producer on one queue, and the other side is the consumer on that queue - * (and vice-versa for its pair). - * - * Data is enqueued and dequeued into the pair in transactional stages, - * meaning each enqueue/dequeue can be followed by zero or more - * enqueue/dequeues, but the enqueue/dequeue is not visible to the peer - * until it has been committed with the *Commit() function. - * In PVTCP, for example, this is used to enqueue a short header, then - * followed by 'segments' of iovecs, then followed by a commit. This - * model prevents a peer from reading the header, expecting a payload, - * but not being able to read the payload because it hasn't been - * enqueued yet. - * - * Queue Pair setup: - * - * Before data can be passed, the guest and host kernel must perform - * the following connection handshake: - * - * 1). A host kernel service registers a listener with the queue pair - * subsystem with a callback to be called when guests create - * and attach to a shared memory region. - * - * 2). Guest initiates an QP_Attach() operation to a shared memory region - * keyed by ID. This step allocates memory, maps it into the host - * address space, and optionally notifies any host services who are - * listening for attach requests from the guest (see previous step). - * Host listeners are provided with a copy of the initialization - * arguments used by the guest (id, size, service type). All registered - * listeners are iterated over until one of them handles the attach - * request and acknowledges with QP_SUCCESS. - * - * 3). The registered host callback is called, notifying the host that - * the guest has attached. - * - * 4). The host can now QP_Attach() to the shared memory region with the same - * arguments as the guest. The queue pair is now well formed and enqueues - * and dequeues can proceed on either side. - * - * Queue Pair teardown: - * - * 1). As before, teardowns are initiated by the guest. Hosts can register - * a callback to be called upon detach. Guests initiate a teardown - * through a call to QP_Detach(). - * - * 2). Registered hosts are notified through the aforementioned callback. - * 3). The host service can call QP_Detach() at its own leisure. Memory - * is freed, the queue pair is destroyed. - * - * If at any point the guest unexpectedly shuts down, the host will be - * notified at monitor shutdown time. Memory is freed, and the queue - * pair is destroyed. - * - */ - -#ifndef _QP_H -#define _QP_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -//#define QP_DEBUG 1 - -typedef enum QPState { - QP_STATE_FREE = 0x1, ///< No peers, not memory-backed - QP_STATE_CONNECTED, ///< Both peers attached , memory backed - QP_STATE_GUEST_ATTACHED, ///< Guest allocated memory, host not yet attached - QP_STATE_MAX // leave this at the end! -} QPState; - -typedef struct QPId { - uint32 context; - uint32 resource; -} QPId; - -/* - * Initialization arguments for each queue pair - */ -typedef struct QPInitArgs { - QPId id; ///< Shared memory region ID - uint32 capacity; ///< Total size of shared region in bytes - uint32 type; ///< Type of queue pair (PVTCP, other)... -} QPInitArgs; - -/* - * Placed on the shared region, two per region - */ -typedef struct QHandle { - volatile uint32 head; ///< queue head offset - volatile uint32 tail; ///< queue tail offset - volatile uint32 phantom_head; ///< queue shadow head offset - volatile uint32 phantom_tail; ///< queue shadow tail offset - uint8 data[0]; ///< start of data, runs off - // the struct -} QHandle; - -/* - * Local to each peer - */ -typedef struct QPHandle { - QPId id; ///< shared memory region ID - uint32 capacity; ///< size of region in bytes - QHandle *produceQ; ///< producer queue - QHandle *consumeQ; ///< consumer queue - uint32 queueSize; ///< size of each queue in bytes - uint32 type; ///< type of queue pair - - /* - * Following fields unused by guest - */ - QPState state; - void (*peerDetachCB)(void* data); ///< detach notification callback - void *detachData; ///< data for the detach cb - struct page **pages; ///< page pointers for shared region -} QPHandle; - -/* - * QP Error codes - */ -#define QP_SUCCESS 0 -#define QP_ERROR_NO_MEM (-1) -#define QP_ERROR_INVALID_HANDLE (-2) -#define QP_ERROR_INVALID_ARGS (-3) -#define QP_ERROR_ALREADY_ATTACHED (-4) - -/* - * Hard-coded limits - */ -#define QP_MIN_CAPACITY (PAGE_SIZE * 2) -#define QP_MAX_CAPACITY (1024*1024) // 1M -#define QP_MAX_QUEUE_PAIRS 32 -#define QP_MAX_ID QP_MAX_QUEUE_PAIRS -#define QP_MAX_LISTENERS QP_MAX_QUEUE_PAIRS -#define QP_MAX_PAGES (QP_MAX_CAPACITY/PAGE_SIZE) // 256 pages - -#define QP_INVALID_ID 0xFFFFFFFF -#define QP_INVALID_SIZE 0xFFFFFFFF -#define QP_INVALID_REGION 0xFFFFFFFF -#define QP_INVALID_TYPE 0xFFFFFFFF - -#ifdef __KERNEL__ -/** - * @brief Utility function to sanity check arguments - * @param args argument structure to check - * @return true if arguments are sane, false otherwise - */ -static inline -_Bool QP_CheckArgs(QPInitArgs *args) -{ - if (!args || - !is_power_of_2(args->capacity) || - (args->capacity < QP_MIN_CAPACITY) || - (args->capacity > QP_MAX_CAPACITY) || - !(args->id.resource < QP_MAX_ID || args->id.resource == QP_INVALID_ID) || - (args->type == QP_INVALID_TYPE)) { - return false; - } else { - return true; - } -} -#endif - - -/** - * @brief Utility function to sanity check a queue pair handle - * @param qp handle to the queue pair - * @return true if the handle is sane, false otherwise - */ -static inline -_Bool QP_CheckHandle(QPHandle *qp) -{ -#ifdef MVP_DEBUG - if (!(qp) || - !(qp->produceQ) || - !(qp->consumeQ) || - (qp->state >= (uint32)QP_STATE_MAX) || - !(qp->queueSize < (QP_MAX_CAPACITY/2))) { - return false; - } else { - return true; - } -#else - return true; -#endif -} - - -/** - * @brief Initializes an invalid handle - * @param[in, out] qp handle to the queue pair - */ -static inline void -QP_MakeInvalidQPHandle(QPHandle *qp) -{ - if (!qp) { - return; - } - - qp->id.context = QP_INVALID_ID; - qp->id.resource = QP_INVALID_ID; - qp->capacity = QP_INVALID_SIZE; - qp->produceQ = NULL; - qp->consumeQ = NULL; - qp->queueSize = QP_INVALID_SIZE; - qp->type = QP_INVALID_TYPE; - qp->state = QP_STATE_FREE; - qp->peerDetachCB = NULL; - qp->detachData = NULL; -} - -/* - * Host only - */ -typedef int32 (*QPListener)(const QPInitArgs*); -int32 QP_RegisterListener(const QPListener); -int32 QP_UnregisterListener(const QPListener); -int32 QP_RegisterDetachCB(QPHandle *qp, void (*callback)(void*), void *data); - - -/* - * Host and guest specific implementations, see qp_host.c and qp_guest.c - */ -int32 QP_Attach(QPInitArgs *args, QPHandle** qp); -int32 QP_Detach(QPHandle* qp); -int32 QP_Notify(QPInitArgs *args); - -/* - * Common implementation, see qp_common.c - */ -int32 QP_EnqueueSpace(QPHandle *qp); -int32 QP_EnqueueSegment(QPHandle *qp, const void *buf, size_t length); -int32 QP_EnqueueCommit(QPHandle *qp); -int32 QP_EnqueueReset(QPHandle *qp); - -static inline int32 -QP_EnqueueAtomic(QPHandle *qp, const void *buf, size_t length) -{ - int32 rc; - QP_EnqueueReset(qp); - rc = QP_EnqueueSegment(qp, buf, length); - if (rc < 0) { - return rc; - } else { - QP_EnqueueCommit(qp); - } - return rc; -} - -int32 QP_DequeueSpace(QPHandle *qp); -int32 QP_DequeueSegment(QPHandle *qp, const void *buf, size_t length); -int32 QP_DequeueReset(QPHandle *qp); -int32 QP_DequeueCommit(QPHandle *qp); - -static inline int32 -QP_DequeueAtomic(QPHandle *qp, const void *buf, size_t length) -{ - int32 rc; - QP_DequeueReset(qp); - rc = QP_DequeueSegment(qp, buf, length); - if (rc < 0) { - return rc; - } else { - QP_DequeueCommit(qp); - } - return rc; -} - -/* - * HVC methods and signatures - */ -#define MVP_QP_SIGNATURE 0x53525051 ///< 'QPRS' -#define MVP_QP_ATTACH (MVP_OBJECT_CUSTOM_BASE + 0) ///< attach to a queue pair -#define MVP_QP_DETACH (MVP_OBJECT_CUSTOM_BASE + 1) ///< detach from a queue pair -#define MVP_QP_NOTIFY (MVP_OBJECT_CUSTOM_BASE + 2) ///< notify host of attach -#define MVP_QP_LAST (MVP_OBJECT_CUSTOM_BASE + 3) ///< Number of methods - -/* - * Debug macros - */ -#ifdef QP_DEBUG - #ifdef IN_MONITOR - #define QP_DBG(...) Log(__VA_ARGS__) - #else - #define QP_DBG(...) printk(KERN_INFO __VA_ARGS__) - #endif -#else - #define QP_DBG(...) -#endif - -#endif diff --git a/arch/arm/mvp/commkm/utils.h b/arch/arm/mvp/commkm/utils.h deleted file mode 100644 index b5f1e18..0000000 --- a/arch/arm/mvp/commkm/utils.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief General architecture-independent definitions, typedefs, and macros. - */ - -#ifndef _UTILS_H -#define _UTILS_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define MAX_FILENAME 128 - -// Round address up to given size boundary -// Note: ALIGN() conflicts with Linux - -#define MVP_ALIGN(_v, _n) (((_v) + (_n) - 1) & -(_n)) - -#define ALIGNVA(_addr, _size) MVP_ALIGN(_addr, _size) - -#define alignof(t) offsetof(struct { char c; typeof(t) x; }, x) - -#define MIN(x,y) ((x) < (y) ? (x) : (y)) -#define MAX(x,y) ((x) > (y) ? (x) : (y)) - -#ifndef NULL -#define NULL ((void *)0) -#endif - -#define KB(_X_) ((_X_)*1024U) -#define MB(_X_) (KB(_X_)*1024) -#define GB(_X_) (MB(_X_)*1024) - -#define NELEM(x) (sizeof(x)/sizeof((x)[0])) - -/* - * x in [low,high) - * args evaluated once - */ -#define RANGE(x,low,high) \ - ({ \ - typeof(x) _x = (x); \ - typeof(x) _low = (typeof(x))(low); \ - typeof(x) _high =(typeof(x))(high); \ - (_Bool)( (_low <= _x) && (_x < _high)); \ - }) - -#define OBJECTS_PER_PAGE(_type) (PAGE_SIZE / sizeof(_type)) - -#define MA_2_MPN(_ma) ((MPN)((_ma) / PAGE_SIZE)) -#define MPN_2_MA(_mpn) ((MA)((_mpn) * PAGE_SIZE)) - -#define VA_2_VPN(_va) ((_va) / PAGE_SIZE) -#define VPN_2_vA(_vpn) ((_vpn) * PAGE_SIZE) - -/* - * The following convenience macro can be used in a following situation - * - * send(..., &foo, sizeof(foo)) --> send(..., PTR_N_SIZE(foo)) - */ - -#define PTR_N_SIZE(_var) &(_var), sizeof(_var) - - -/* - * - * BIT-PULLING macros - * - */ -#define MVP_BIT(val,n) ( ((val)>>(n))&1) -#define MVP_BITS(val,m,n) (((val)<<(31-(n))) >> ((31-(n))+(m)) ) -#define MVP_EXTRACT_FIELD(w, m, n) MVP_BITS((w), (m), ((m) + (n) - 1)) -#define MVP_MASK(m, n) (MVP_EXTRACT_FIELD(~(uint32)0U, (m), (n)) << (m)) -#define MVP_UPDATE_FIELD(old_val, field_val, m, n) \ - (((old_val) & ~MVP_MASK((m), (n))) | (MVP_EXTRACT_FIELD((field_val), 0, (n)) << (m))) - -/* - * - * 64BIT-PULLING macros - * - */ -#define MVP_BITS64(val,m,n) (((val)<<(63-(n))) >> ((63-(n))+(m)) ) -#define MVP_EXTRACT_FIELD64(w, m, n) MVP_BITS64((w), (m), ((m) + (n) - 1)) -#define MVP_MASK64(m, n) (MVP_EXTRACT_FIELD64(~(uint64)0ULL, (m), (n)) << (m)) -#define MVP_UPDATE_FIELD64(old_val, field_val, m, n) \ - (((old_val) & ~MVP_MASK64((m), (n))) | (MVP_EXTRACT_FIELD64(((uint64)(field_val)), 0ULL, (n)) << (m))) - -/* - * - * BIT-CHANGING macros - * - */ -#define MVP_SETBIT(val,n) ((val)|=(1<<(n))) -#define MVP_CLRBIT(val,n) ((val)&=(~(1<<(n)))) - -/* - * Fixed bit-width sign extension. - */ -#define MVP_SIGN_EXTEND(val,width) \ - (((val) ^ (1 << ((width) - 1))) - (1 << ((width) - 1))) - - -/* - * Assembler helpers. - */ -#define _MVP_HASH # -#define MVP_HASH() _MVP_HASH - -#define _MVP_STRINGIFY(...) #__VA_ARGS__ -#define MVP_STRINGIFY(...) _MVP_STRINGIFY(__VA_ARGS__) - -#ifndef __ASSEMBLER__ - -#include <stddef.h> -#include <stdbool.h> - -/* - * Constant equivalents of build-flags. - * - * Test these when possible instead of using #ifdef so that your code - * gets parsed. - */ -#ifdef MVP_DEBUG -static const _Bool mvpDebug = true; -#else -static const _Bool mvpDebug = false; -#endif - -#ifdef MVP_STATS -static const _Bool mvpStats = true; -#else -static const _Bool mvpStats = false; -#endif - -#ifdef MVP_DEVEL -static const _Bool mvpDevel = true; -#else -static const _Bool mvpDevel = false; -#endif - -#endif - -#endif diff --git a/arch/arm/mvp/commkm/vmid.h b/arch/arm/mvp/commkm/vmid.h deleted file mode 100644 index f24a650..0000000 --- a/arch/arm/mvp/commkm/vmid.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Guest Communications - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -#ifndef _VMID_H -#define _VMID_H - -/** - * @file - * - * @brief The vmid definition - */ - - - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define VMID_UNDEF (uint16)0xffff -typedef uint16 VmId; - -#endif diff --git a/arch/arm/mvp/mvpkm/COPYING b/arch/arm/mvp/mvpkm/COPYING deleted file mode 100644 index 10828e0..0000000 --- a/arch/arm/mvp/mvpkm/COPYING +++ /dev/null @@ -1,341 +0,0 @@ - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/arch/arm/mvp/mvpkm/Kbuild b/arch/arm/mvp/mvpkm/Kbuild deleted file mode 100644 index 7b2dc10..0000000 --- a/arch/arm/mvp/mvpkm/Kbuild +++ /dev/null @@ -1,32 +0,0 @@ -# Warning: autogenerated -obj-m := mvpkm.o -mvpkm-objs := check_kconfig.o cpufreq_kernel.o mksck_kernel.o montimer_kernel.o mutex_kernel.o mvpkm_comm_ev.o mvpkm_main.o qp_host_kernel.o qp_common.o mksck_shared.o vfp_switch.o - -ccflags-y += -fno-pic -fno-dwarf2-cfi-asm -march=armv7-a -D__linux__ -ccflags-y += -mfpu=neon -DLIB_ARM_VERSION=7 -DIN_MODULE -DGPLED_CODE -ccflags-y += --std=gnu89 -O2 -g2 -ggdb -mapcs -fno-optimize-sibling-calls -mno-sched-prolog -ccflags-$(CONFIG_VMWARE_MVP_DEBUG) += -DMVP_DEBUG - -asflags-y += -mfpu=neon -DLIB_ARM_VERSION=7 -DIN_MODULE -DGPLED_CODE -asflags-y += -mfloat-abi=softfp - -# Detect MD5SUM executable -HOST_OS := $(shell uname -s) -ifeq ($(HOST_OS),Darwin) - MD5SUM_EXEC := md5 -else - MD5SUM_EXEC := md5sum -endif - -LOWMEMKILLER_PATH := $(srctree)/drivers/staging/android/lowmemorykiller.c -ifeq ($(wildcard $(LOWMEMKILLER_PATH)),) -$(error "Unable to find lowmemorykiller.c at $(LOWMEMKILLER_PATH)") -endif -LOWMEMKILLER_MD5 := $(shell $(MD5SUM_EXEC) $(LOWMEMKILLER_PATH) | cut -f1 -d\ ) -LOWMEMKILLER_SUPPORT := $(srctree)/arch/arm/mvp/mvpkm/lowmemkiller_variant.sh -LOWMEMKILLER_SHRINK_MD5 := $(shell $(SHELL) $(LOWMEMKILLER_SUPPORT) $(LOWMEMKILLER_PATH) | cut -f1 -d\ ) -LOWMEMKILLER_VARIANT := $(shell $(SHELL) $(LOWMEMKILLER_SUPPORT) $(LOWMEMKILLER_PATH) | cut -f2 -d\ ) -ccflags-y += \ - -DLOWMEMKILLER_VARIANT=$(LOWMEMKILLER_VARIANT) \ - -DLOWMEMKILLER_SHRINK_MD5=$(LOWMEMKILLER_SHRINK_MD5) \ - -DLOWMEMKILLER_MD5=$(LOWMEMKILLER_MD5) diff --git a/arch/arm/mvp/mvpkm/Makefile b/arch/arm/mvp/mvpkm/Makefile deleted file mode 100644 index 16eb389..0000000 --- a/arch/arm/mvp/mvpkm/Makefile +++ /dev/null @@ -1 +0,0 @@ -# Warning: autogenerated diff --git a/arch/arm/mvp/mvpkm/actions.h b/arch/arm/mvp/mvpkm/actions.h deleted file mode 100644 index 0e89892..0000000 --- a/arch/arm/mvp/mvpkm/actions.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Bit definitions for instrBActions. - */ - -#ifndef _ACTIONS_H -#define _ACTIONS_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define L2_ACTION_GDB 0 ///< drop into guest debugger GDB -#define L2_ACTION_MKSCK 1 ///< scan the mksck pipes for incoming messages -#define L2_ACTION_ABORT 2 ///< abort the monitor cleanly -#define L2_ACTION_HALT 3 ///< halt the monitor -#define L2_ACTION_FIQ 6 ///< the VCPU's FIQ pin is active -#define L2_ACTION_IRQ 7 ///< the VCPU's IRQ pin is active -#define L2_ACTION_CKPT 8 ///< do a checkpoint -#define L2_ACTION_WFI 9 ///< wait for interrupt -#define L2_ACTION_TIMER 10 ///< timer event -#define L2_ACTION_BALLOON 11 ///< balloon trigger - -#define ACTION_GDB (1 << L2_ACTION_GDB) -#define ACTION_MKSCK (1 << L2_ACTION_MKSCK) -#define ACTION_ABORT (1 << L2_ACTION_ABORT) -#define ACTION_HALT (1 << L2_ACTION_HALT) -#define ACTION_IRQ (1 << L2_ACTION_IRQ) -#define ACTION_FIQ (1 << L2_ACTION_FIQ) -#define ACTION_CKPT (1 << L2_ACTION_CKPT) -#define ACTION_WFI (1 << L2_ACTION_WFI) -#define ACTION_TIMER (1 << L2_ACTION_TIMER) -#define ACTION_BALLOON (1 << L2_ACTION_BALLOON) - -#endif diff --git a/arch/arm/mvp/mvpkm/arm_as_macros.h b/arch/arm/mvp/mvpkm/arm_as_macros.h deleted file mode 100644 index 5a0b7fc..0000000 --- a/arch/arm/mvp/mvpkm/arm_as_macros.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Macro definitions meta-ops to be used in assembler files - * - * This header contains asm macro definitions to be used in asm - * files only. This is intended to be the equivalent of arm_gcc_inline.h - */ - -#ifndef _ARM_AS_MACROS_H_ -#define _ARM_AS_MACROS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "coproc_defs.h" - -/** - * @name The following macros re-arrange the order of the mcr/mrc operands - * making it suitable to be used with the macros defined in coproc_defs.h - * - * @par For example - * mcr_p15 DOMAIN_CONTROL, r3 - * @par replaces - * mcr p15, 0, r3, c3, c0, 0 - * @{ - */ -.macro mcr_p15 op1, op2, op3, op4, reg, cond=al - mcr\cond p15, \op1, \reg, \op2, \op3, \op4 -.endm - -.macro mrc_p15 op1, op2, op3, op4, reg, cond=al - mrc\cond p15, \op1, \reg, \op2, \op3, \op4 -.endm - -.macro mcrr_p15 op1, op2, reg1, reg2 - mcrr p15, \op1, \reg1, \reg2, \op2 -.endm - -.macro mrrc_p15 op1, op2, reg1, reg2 - mrrc p15, \op1, \reg1, \reg2, \op2 -.endm -/*@}*/ - -/** - * @name Our toolchain does not include support for the VE instructions yet. - * @{ - */ -.macro hvc imm16 - .word ARM_INSTR_HVC_A1_ENC(\imm16) -.endm - -.macro eret - .word ARM_INSTR_ERET_A1_ENC(ARM_INSTR_COND_AL) -.endm - -.macro msr_ext rm, rn - .word ARM_INSTR_MSR_EXT_A1_ENC(ARM_INSTR_COND_AL, \rm, \rn) -.endm - -.macro mrs_ext rd, rm - .word ARM_INSTR_MRS_EXT_A1_ENC(ARM_INSTR_COND_AL, \rd, \rm) -.endm -/*@}*/ - -#endif /// ifndef _ARM_AS_MACROS_H_ diff --git a/arch/arm/mvp/mvpkm/arm_defs.h b/arch/arm/mvp/mvpkm/arm_defs.h deleted file mode 100644 index 2c39f6a..0000000 --- a/arch/arm/mvp/mvpkm/arm_defs.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Umbrella header file for all ARM-related definitions. By - * including this you gain access to all such definitions in - * lib/arm and are guaranteed a stable include. - */ - -#ifndef _ARM_DEFS_H_ -#define _ARM_DEFS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define ARM_V4 4 -#define ARM_V5 5 -#define ARM_V6 6 -#define ARM_V7 7 -#define ARM_V8 8 - -#include "coproc_defs.h" -#include "exc_defs.h" -#include "instr_defs.h" -#include "mmu_defs.h" -#include "lpae_defs.h" -#include "ve_defs.h" -#include "psr_defs.h" - -#endif /// _ARM_DEFS_H_ diff --git a/arch/arm/mvp/mvpkm/arm_gcc_inline.h b/arch/arm/mvp/mvpkm/arm_gcc_inline.h deleted file mode 100644 index 33ffe69..0000000 --- a/arch/arm/mvp/mvpkm/arm_gcc_inline.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief GCC inline stubs for ARM assembler instructions. - */ - -#ifndef _ARM_GCC_INLINE_H_ -#define _ARM_GCC_INLINE_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "coproc_defs.h" - -/* - * Macros for accessing CP10. - */ -#define _ARM_CP10_MRCMCR_STR(_op1,_cr1,_cr2,_op2,_var) \ - " p10, " #_op1 ","#_var"," #_cr1 "," #_cr2 "," #_op2 "\n\t" - -#define _ARM_MRC_CP10(_op1,_cr1,_cr2,_op2,_var) \ - asm volatile ("mrc" _ARM_CP10_MRCMCR_STR(_op1,_cr1,_cr2,_op2,%0) \ - : "=r" (_var) ) - -#define ARM_MRC_CP10(_cp_reg,_var) _ARM_MRC_CP10(_cp_reg,_var) - -#define _ARM_MCR_CP10(_op1,_cr1,_cr2,_op2,_val) \ - asm volatile ("mcr" _ARM_CP10_MRCMCR_STR(_op1,_cr1,_cr2,_op2,%0) \ - : \ - : "r" (_val) ) - -#define ARM_MCR_CP10(_cp_reg,_val) _ARM_MCR_CP10(_cp_reg,_val) - - -/* - * Macros for accessing CP15. - */ -#define _ARM_CP15_MRCMCR_STR(_op1,_cr1,_cr2,_op2,_var) \ - " p15, " #_op1 ","#_var"," #_cr1 "," #_cr2 "," #_op2 "\n\t" - -#define ARM_CP15_MRCMCR_STR(_cp_reg,_var) _ARM_CP15_MRCMCR_STR(_cp_reg,_var) - -#ifdef __COVERITY__ -static uint32 __cp15; -#define _ARM_MRC_CP15(_op1,_cr1,_cr2,_op2,_var) \ - (_var) = (uint32)__cp15 -#else -#define _ARM_MRC_CP15(_op1,_cr1,_cr2,_op2,_var) \ - asm volatile ("mrc" _ARM_CP15_MRCMCR_STR(_op1,_cr1,_cr2,_op2,%0) \ - : "=r" (_var) \ - : \ - : "memory") -#endif - -#define ARM_MRC_CP15(_cp_reg,_var) _ARM_MRC_CP15(_cp_reg,_var) - - -#ifdef __COVERITY__ -#define _ARM_MCR_CP15(_op1,_cr1,_cr2,_op2,_val) \ - __cp15 = (_val) -#else -#define _ARM_MCR_CP15(_op1,_cr1,_cr2,_op2,_val) \ - asm volatile ("mcr" _ARM_CP15_MRCMCR_STR(_op1,_cr1,_cr2,_op2,%0) \ - : \ - : "r" (_val)\ - : "memory") -#endif - -#define ARM_MCR_CP15(_cp_reg,_val) _ARM_MCR_CP15(_cp_reg,_val) - -#define _ARM_MRRC_CP15(_op,_cr,_val1,_val2) \ - asm volatile ("mrrc p15, " #_op ",%0,%1," #_cr "\n\t" \ - : "=r" (_val1), "=r" (_val2) \ - : \ - : "memory") - -#define ARM_MRRC_CP15(_cp_reg,_val1,_val2) _ARM_MRRC_CP15(_cp_reg,_val1,_val2) - -#define ARM_MRRC64_CP15(_cp_reg,_val) \ - _ARM_MRRC_CP15(_cp_reg,_val,*((uint8 *)&(_val) + 4)) - -#define _ARM_MCRR_CP15(_op,_cr,_val1,_val2) \ - asm volatile ("mcrr p15, " #_op ",%0,%1," #_cr "\n\t" \ - : \ - : "r" (_val1), "r" (_val2) \ - : "memory") - -#define ARM_MCRR_CP15(_cp_reg,_val1,_val2) _ARM_MCRR_CP15(_cp_reg,_val1,_val2) - -#define ARM_MCRR64_CP15(_cp_reg,_val) \ - _ARM_MCRR_CP15(_cp_reg,_val,*((uint8 *)&(_val) + 4)) - -#define DMB() asm volatile ("dmb" : : : "memory") -#define DSB() asm volatile ("dsb" : : : "memory") -#define ISB() asm volatile ("isb" : : : "memory") - -/** - * @name 64-bit multiplies - * @{ - */ - -// rdhi:rdlo = rm * rs + rdhi + rdlo -#define ARM_UMAAL(rdlo,rdhi,rm,rs) asm ("umaal %0,%1,%2,%3" \ - : "+r" (rdlo), "+r" (rdhi) \ - : "r" (rm), "r" (rs)) - -// rdhi:rdlo += rm * rs -#define ARM_UMLAL(rdlo,rdhi,rm,rs) asm ("umlal %0,%1,%2,%3" \ - : "+r" (rdlo), "+r" (rdhi) \ - : "r" (rm), "r" (rs)) - -// rdhi:rdlo = rm * rs -#define ARM_UMULL(rdlo,rdhi,rm,rs) asm ("umull %0,%1,%2,%3" \ - : "=r" (rdlo), "=r" (rdhi) \ - : "r" (rm), "r" (rs)) -/*@}*/ - -/** - * @brief Disable interrupts (IRQ + FIQ) - * - * @return CPSR status prior to disabling - suitable for passing to - * ARM_RestoreInterrupts() to restore IRQ/FIQ levels to - * pre-call values - */ -static inline uint32 -ARM_DisableInterrupts(void) -{ - register uint32 status; - - asm volatile ("mrs %0, cpsr \n\t" - "orr r1, %0, %1 \n\t" - "msr cpsr_c, r1 \n\t" - : "=&r" (status) - : "i" (ARM_PSR_I | ARM_PSR_F) - : "r1", "memory"); - - return status; -} - -/** - * @brief Restore interrupts - * - * @param status return value from a previous call to ARM_DisableInterrupts() - */ -static inline void -ARM_RestoreInterrupts(uint32 status) -{ - asm volatile ("msr cpsr_c, %0 \n\t" : : "r" (status) : "memory"); -} - -/** - * @brief Read current CPSR value - * - * @return current CPSR value - */ -static inline uint32 -ARM_ReadCPSR(void) -{ - uint32 status; - - asm volatile ("mrs %0, cpsr \n\t" : "=r" (status)); - - return status; -} - -/** - * @brief Read current stack pointer - * - * @return stack pointer value - */ -static inline uint32 -ARM_ReadSP(void) -{ - uint32 sp; - - asm volatile ("mov %0, sp \n\t" : "=r" (sp)); - - return sp; -} - -#endif /// ifndef _ARM_GCC_INLINE_H_ diff --git a/arch/arm/mvp/mvpkm/arm_inline.h b/arch/arm/mvp/mvpkm/arm_inline.h deleted file mode 100644 index 3689a7f..0000000 --- a/arch/arm/mvp/mvpkm/arm_inline.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Inline stubs for ARM assembler instructions. - */ - -#ifndef _ARM_INLINE_H_ -#define _ARM_INLINE_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "arm_types.h" -#include "arm_defs.h" - -/* - * Compiler specific include - we get the actual inline assembler macros here. - */ -#include "arm_gcc_inline.h" - -/* - * Some non-compiler specific helper functions for inline assembler macros - * included above. - */ - -/** - * @brief Predicate giving whether interrupts are currently enabled - * - * @return TRUE if enabled, FALSE otherwise - */ -static inline _Bool -ARM_InterruptsEnabled(void) -{ - return !(ARM_ReadCPSR() & ARM_PSR_I); -} - -/** - * @brief Read current TTBR0 base machine address - * - * @return machine address given by translation table base register 0 - */ -static inline MA -ARM_ReadTTBase0(void) -{ - MA ttbase; - - ARM_MRC_CP15(TTBASE0_POINTER, ttbase); - - return ttbase & ARM_CP15_TTBASE_MASK; -} - -/** - * @brief Read VFP/Adv.SIMD Extension System Register - * - * @param specReg which VFP/Adv. SIMD Extension System Register - * - * @return Read value - */ -static inline uint32 -ARM_ReadVFPSystemRegister(uint8 specReg) -{ - uint32 value = 0; - - /* - * VMRS is the instruction used to read VFP System Registers. - * VMRS is the new UAL-syntax equivalent for the FMRX instruction. - * At the end of the day, all these are just synonyms for MRC - * instructions on CP10, as the VFP system registers sit in CP10 - * and MRC is the Co-processor register read instruction. - * We use the primitive MRC synonym for VMRS here as VMRS/FMRX - * don't seem to be working when used inside asm volatile blocks, - * as, for some reason, the inline assembler seems to be setting - * the VFP mode to soft-float. Moreover, we WANT the monitor code - * to be compiled with soft-float so that the compiler doesn't use - * VFP instructions for the monitor's own use, such as for 64-bit - * integer operations, etc., since we pass-through the use of the - * underlying hardware's VFP/SIMD state to the guest. - */ - - switch (specReg) { - case ARM_VFP_SYSTEM_REG_FPSID: - ARM_MRC_CP10(VFP_FPSID, value); - break; - case ARM_VFP_SYSTEM_REG_MVFR0: - ARM_MRC_CP10(VFP_MVFR0, value); - break; - case ARM_VFP_SYSTEM_REG_MVFR1: - ARM_MRC_CP10(VFP_MVFR1, value); - break; - case ARM_VFP_SYSTEM_REG_FPEXC: - ARM_MRC_CP10(VFP_FPEXC, value); - break; - case ARM_VFP_SYSTEM_REG_FPSCR: - ARM_MRC_CP10(VFP_FPSCR, value); - break; - case ARM_VFP_SYSTEM_REG_FPINST: - ARM_MRC_CP10(VFP_FPINST, value); - break; - case ARM_VFP_SYSTEM_REG_FPINST2: - ARM_MRC_CP10(VFP_FPINST2, value); - break; - default: - NOT_IMPLEMENTED_JIRA(1849); - break; - } - - return value; -} - -/** - * @brief Write to VFP/Adv.SIMD Extension System Register - * - * @param specReg which VFP/Adv. SIMD Extension System Register - * @param value desired value to be written to the System Register - */ -static inline void -ARM_WriteVFPSystemRegister(uint8 specReg, uint32 value) -{ - /* - * VMSR is the instruction used to write to VFP System Registers. - * VMSR is the new UAL-syntax equivalent for the FMXR instruction. - * At the end of the day, all these are just synonyms for MCR - * instructions on CP10, as the VFP system registers sit in CP10 - * and MCR is the Co-processor register write instruction. - * We use the primitive MCR synonym for VMSR here as VMSR/FMXR - * don't seem to be working when used inside asm volatile blocks, - * as, for some reason, the inline assembler seems to be setting - * the VFP mode to soft-float. Moreover, we WANT the monitor code - * to be compiled with soft-float so that the compiler doesn't use - * VFP instructions for the monitor's own use, such as for 64-bit - * integer operations, etc., since we pass-through the use of the - * underlying hardware's VFP/SIMD state to the guest. - */ - - switch (specReg) { - case ARM_VFP_SYSTEM_REG_FPEXC: - ARM_MCR_CP10(VFP_FPEXC, value); - break; - case ARM_VFP_SYSTEM_REG_FPSCR: - ARM_MCR_CP10(VFP_FPSCR, value); - break; - case ARM_VFP_SYSTEM_REG_FPINST: - ARM_MCR_CP10(VFP_FPINST, value); - break; - case ARM_VFP_SYSTEM_REG_FPINST2: - ARM_MCR_CP10(VFP_FPINST2, value); - break; - default: - NOT_IMPLEMENTED_JIRA(1849); - break; - } -} - -#endif /// ifndef _ARM_INLINE_H_ diff --git a/arch/arm/mvp/mvpkm/arm_types.h b/arch/arm/mvp/mvpkm/arm_types.h deleted file mode 100644 index 2075860..0000000 --- a/arch/arm/mvp/mvpkm/arm_types.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Umbrella header file for all ARM-related types. - */ - -#ifndef _ARM_TYPES_H_ -#define _ARM_TYPES_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "exc_types.h" -#include "mmu_types.h" -#include "lpae_types.h" - -#endif /// _ARM_TYPES_H_ diff --git a/arch/arm/mvp/mvpkm/atomic.h b/arch/arm/mvp/mvpkm/atomic.h deleted file mode 100644 index 987860f..0000000 --- a/arch/arm/mvp/mvpkm/atomic.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief bus-atomic operators. - * - * The 'atm' argument is the atomic memory cell being operated on and the - * remainder of the arguments are the values being applied to the atomic cell - * which is assumed to be located in shared normal memory. The operation is - * both atomic and visible to the default share-ability domain upon completion. - * - * The design of each macro is such that the compiler should check types - * correctly. For those macros that return a value, the return type should be - * the same as the 'atm' argument (with the exception of ATOMIC_SETIF which - * returns an int value of 0 or 1). - * - * Those names ending in 'M' return the modified value of 'atm'. - * Those names ending in 'O' return the original value of 'atm'. - * Those names ending in 'V' return void (ie, nothing). - */ - -#ifndef _ATOMIC_H -#define _ATOMIC_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#include "include_check.h" - -/* - * Wrap type 't' in an atomic struct. - * Eg, 'static ATOMIC(uint8) counter;'. - * - * The function macros use the atm_Normal member to clone the atom's type - * when the volatile semantic is not required. They use the atm_Volatl member - * when the volatile semantic is required. - */ -#define ATOMIC(t) union { t atm_Normal; t volatile atm_Volatl; } - -/* - * Static atomic variable initialization. - * Eg, 'static ATOMIC(uint8) counter = ATOMIC_INI(35);'. - */ -#define ATOMIC_INI(v) { .atm_Normal = v } - -/* - * Some commonly used atomic types. - */ -typedef ATOMIC(int32) AtmSInt32 __attribute__ ((aligned (4))); -typedef ATOMIC(uint32) AtmUInt32 __attribute__ ((aligned (4))); -typedef ATOMIC(uint64) AtmUInt64 __attribute__ ((aligned (8))); - -/* - * Architecture-dependent implementations. - */ -#if defined(__COVERITY__) -#include "atomic_coverity.h" -#elif defined(__arm__) -#include "atomic_arm.h" -#elif defined(__i386) || defined(__x86_64) -#include "atomic_x86.h" -#endif - -#endif diff --git a/arch/arm/mvp/mvpkm/atomic_arm.h b/arch/arm/mvp/mvpkm/atomic_arm.h deleted file mode 100644 index 447aa55..0000000 --- a/arch/arm/mvp/mvpkm/atomic_arm.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief bus-atomic operators, ARM implementation. - * Do not include directly, include 'atomic.h' instead. - * Memory where the atomic reside must be shared. - * - * These operations assume that the exclusive access monitor is cleared during - * abort entry but they do not assume that cooperative scheduling (e.g. Linux - * schedule()) clears the monitor and hence the use of "clrex" when required. - */ - -#ifndef _ATOMIC_ARM_H -#define _ATOMIC_ARM_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#include "include_check.h" - -#include "mvp_assert.h" - -/** - * @brief Atomic Add - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @return the original value of 'atm' - */ -#define ATOMIC_ADDO(atm,modval) ATOMIC_OPO_PRIVATE(atm,modval,add) - -/** - * @brief Atomic Add - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @return nothing - */ -#define ATOMIC_ADDV(atm,modval) ATOMIC_OPV_PRIVATE(atm,modval,add) - -/** - * @brief Atomic And - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @return the original value of 'atm' - */ -#define ATOMIC_ANDO(atm,modval) ATOMIC_OPO_PRIVATE(atm,modval,and) - -/** - * @brief Atomic And - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @return nothing - */ -#define ATOMIC_ANDV(atm,modval) ATOMIC_OPV_PRIVATE(atm,modval,and) - -/** - * @brief Retrieve an atomic value - * @param atm atomic cell to operate on - * @return the value of 'atm' - */ -#define ATOMIC_GETO(atm) ({ \ - typeof((atm).atm_Normal) _oldval; \ - switch (sizeof _oldval) { \ - case 4: \ - asm volatile ("ldrex %0, [%1]\n" \ - "clrex" \ - : "=&r" (_oldval) \ - : "r" (&((atm).atm_Volatl))); \ - break; \ - case 8: \ - asm volatile ("ldrexd %0, %H0, [%1]\n" \ - "clrex" \ - : "=&r" (_oldval) \ - : "r" (&((atm).atm_Volatl))); \ - break; \ - default: \ - FATAL(); \ - } \ - _oldval; \ -}) - -/** - * @brief Atomic Or - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @return the original value of 'atm' - */ -#define ATOMIC_ORO(atm,modval) ATOMIC_OPO_PRIVATE(atm,modval,orr) - -/** - * @brief Atomic Or - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @return nothing - */ -#define ATOMIC_ORV(atm,modval) ATOMIC_OPV_PRIVATE(atm,modval,orr) - -/** - * @brief Atomic Conditional Write, ie, - * set 'atm' to 'newval' iff it was 'oldval'. - * @param atm atomic cell to operate on - * @param newval value to possibly write to atomic cell - * @param oldval value that atomic cell must equal - * @return 0 if failed; 1 if successful - */ -#define ATOMIC_SETIF(atm,newval,oldval) ({ \ - int _failed; \ - typeof((atm).atm_Normal) _newval = newval; \ - typeof((atm).atm_Normal) _oldval = oldval; \ - ASSERT_ON_COMPILE(sizeof _newval == 4); \ - asm volatile ("1: ldrex %0, [%1] \n" \ - " cmp %0, %2 \n" \ - " mov %0, #2 \n" \ - " IT eq \n" \ - " strexeq %0, %3, [%1] \n" \ - " cmp %0, #1 \n" \ - " beq 1b \n" \ - " clrex" \ - : "=&r" (_failed) \ - : "r" (&((atm).atm_Volatl)), \ - "r" (_oldval), \ - "r" (_newval) \ - : "cc", "memory"); \ - !_failed; \ -}) - - -/** - * @brief Atomic Write (unconditional) - * @param atm atomic cell to operate on - * @param newval value to write to atomic cell - * @return the original value of 'atm' - */ -#define ATOMIC_SETO(atm,newval) ({ \ - int _failed; \ - typeof((atm).atm_Normal) _newval = newval; \ - typeof((atm).atm_Normal) _oldval; \ - switch (sizeof _newval) { \ - case 4: \ - asm volatile ("1: ldrex %0, [%2]\n" \ - " strex %1, %3, [%2]\n" \ - " teq %1, #0\n" \ - " bne 1b" \ - : "=&r" (_oldval), \ - "=&r" (_failed) \ - : "r" (&((atm).atm_Volatl)), \ - "r" (_newval) \ - : "cc", "memory"); \ - break; \ - case 8: \ - asm volatile ("1: ldrexd %0, %H0, [%2]\n" \ - " strexd %1, %3, %H3, [%2]\n"\ - " teq %1, #0\n" \ - " bne 1b" \ - : "=&r" (_oldval), \ - "=&r" (_failed) \ - : "r" (&((atm).atm_Volatl)), \ - "r" (_newval) \ - : "cc", "memory"); \ - break; \ - default: \ - FATAL(); \ - } \ - _oldval; \ -}) - -/** - * @brief Atomic Write (unconditional) - * @param atm atomic cell to operate on - * @param newval value to write to atomic cell - * @return nothing - */ -#define ATOMIC_SETV(atm,newval) do { ATOMIC_SETO((atm),(newval)); } while (0) - -/** - * @brief Atomic Subtract - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @return the original value of 'atm' - */ -#define ATOMIC_SUBO(atm,modval) ATOMIC_OPO_PRIVATE(atm,modval,sub) - -/** - * @brief Atomic Subtract - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @return nothing - */ -#define ATOMIC_SUBV(atm,modval) ATOMIC_OPV_PRIVATE(atm,modval,sub) - -/** - * @brief Atomic Generic Binary Operation - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @param op ARM instruction (add, and, orr, etc) - * @return the original value of 'atm' - */ -#define ATOMIC_OPO_PRIVATE(atm,modval,op) ({ \ - int _failed; \ - typeof((atm).atm_Normal) _modval = modval; \ - typeof((atm).atm_Normal) _oldval; \ - typeof((atm).atm_Normal) _newval; \ - ASSERT_ON_COMPILE(sizeof _modval == 4); \ - asm volatile ("1: ldrex %0, [%3]\n" \ - #op " %1, %0, %4\n" \ - " strex %2, %1, [%3]\n" \ - " teq %2, #0\n" \ - " bne 1b" \ - : "=&r" (_oldval), \ - "=&r" (_newval), \ - "=&r" (_failed) \ - : "r" (&((atm).atm_Volatl)), \ - "r" (_modval) \ - : "memory"); \ - _oldval; \ -}) - -/** - * @brief Atomic Generic Binary Operation - * @param atm atomic cell to operate on - * @param modval value to apply to atomic cell - * @param op ARM instruction (add, and, orr, etc) - * @return nothing - */ -#define ATOMIC_OPV_PRIVATE(atm,modval,op) do { \ - int _failed; \ - typeof((atm).atm_Normal) _modval = modval; \ - typeof((atm).atm_Normal) _sample; \ - ASSERT_ON_COMPILE(sizeof _modval == 4); \ - asm volatile ("1: ldrex %0, [%2]\n" \ - #op " %0, %3\n" \ - " strex %1, %0, [%2]\n" \ - " teq %1, #0\n" \ - " bne 1b" \ - : "=&r" (_sample), \ - "=&r" (_failed) \ - : "r" (&((atm).atm_Volatl)), \ - "r" (_modval) \ - : "memory"); \ -} while (0) - -/** - * @brief Single-copy atomic word write. - * - * ARMv7 defines world-aligned word writes to be single-copy atomic. See - * A3-26 ARM DDI 0406A. - * - * @param p word aligned location to write to - * @param val word-sized value to write to p - */ -#define ATOMIC_SINGLE_COPY_WRITE32(p,val) \ - do { \ - ASSERT(sizeof(val) == 4); \ - ASSERT((MVA)(p) % sizeof(val) == 0); \ - asm volatile("str %0, [%1]" \ - : \ - : "r" (val), "r" (p) \ - : "memory"); \ - } while (0); - - -/** - * @brief Single-copy atomic word read. - * - * ARMv7 defines world-aligned word reads to be single-copy atomic. See - * A3-26 ARM DDI 0406A. - * - * @param p word aligned location to read from - * - * @return word-sized value from p - */ -#define ATOMIC_SINGLE_COPY_READ32(p) ({ \ - ASSERT((MVA)(p) % sizeof(uint32) == 0); \ - uint32 _val; \ - asm volatile("ldr %0, [%1]" \ - : "=r" (_val) \ - : "r" (p) \ - ); \ - _val; \ -}) - -/** - * @brief Single-copy atomic double word write. - * - * LPAE defines double world-aligned double word writes to be single-copy - * atomic. See 6.7 ARM PRD03-GENC-008469 13.0. - * - * @param p double word aligned location to write to - * @param val double word-sized value to write to p - */ -#define ATOMIC_SINGLE_COPY_WRITE64(p,val) \ - do { \ - ASSERT(sizeof(val) == 8); \ - ASSERT((MVA)(p) % sizeof(val) == 0); \ - asm volatile("mov r0, %0 \n" \ - "mov r1, %1 \n" \ - "strd r0, r1, [%2]" \ - : \ - : "r" ((uint32)(val)), \ - "r" (((uint64)(val)) >> 32),\ - "r" (p) \ - : "r0", "r1", "memory"); \ - } while (0); - -#endif diff --git a/arch/arm/mvp/mvpkm/check_kconfig.c b/arch/arm/mvp/mvpkm/check_kconfig.c deleted file mode 100644 index bab1b6e..0000000 --- a/arch/arm/mvp/mvpkm/check_kconfig.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * @brief Check for required kernel configuration - * - * Check to make sure that the kernel options that the MVP hypervisor requires - * have been enabled in the kernel that this kernel module is being built - * against. - */ -#include <linux/version.h> - -/* - * Minimum kernel version - * - network namespace support is only really functional starting in 2.6.29 - * - Android Gingerbread requires 2.6.35 - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) -#error "MVP requires a host kernel newer than 2.6.35" -#endif - -/* module loading ability */ -#ifndef CONFIG_MODULES -#error "MVP requires kernel loadable module support be enabled (CONFIG_MODULES)" -#endif -#ifndef CONFIG_MODULE_UNLOAD -#error "MVP requires kernel module unload support be enabled (CONFIG_MODULE_UNLOAD)" -#endif - -/* sysfs */ -#ifndef CONFIG_SYSFS -#error "MVP requires sysfs support (CONFIG_SYSFS)" -#endif - -/* network traffic isolation */ -#ifndef CONFIG_NAMESPACES -#error "MVP networking support requires namespace support (CONFIG_NAMESPACES)" -#endif -#ifndef CONFIG_NET_NS -#error "MVP networking support requires Network Namespace support to be enabled (CONFIG_NET_NS)" -#endif - -/* TCP/IP networking */ -#ifndef CONFIG_INET -#error "MVP networking requires IPv4 support (CONFIG_INET)" -#endif -#ifndef CONFIG_IPV6 -#error "MVP networking requires IPv6 support (CONFIG_IPV6)" -#endif - -/* VPN support */ -#if !defined(CONFIG_TUN) && !defined(CONFIG_TUN_MODULE) -#error "MVP VPN support requires TUN device support (CONFIG_TUN)" -#endif - -#if !defined(CONFIG_NETFILTER) && !defined(PVTCP_DISABLE_NETFILTER) -#error "MVP networking support requires netfilter support (CONFIG_NETFILTER)" -#endif - -/* Force /proc/config.gz support for eng/userdebug builds */ -#ifdef MVP_DEBUG -#if !defined(CONFIG_IKCONFIG) || !defined(CONFIG_IKCONFIG_PROC) -#error "MVP kernel /proc/config.gz support required for debuggability (CONFIG_IKCONFIG_PROC)" -#endif -#endif - -/* Sanity check we're only dealing with the memory hotplug + migrate and/or - * compaction combo */ -#ifdef CONFIG_MIGRATION -#if defined(CONFIG_NUMA) || defined(CONFIG_CPUSETS) || defined(CONFIG_MEMORY_FAILURE) -#error "MVP not tested with migration features other than CONFIG_MEMORY_HOTPLUG and CONFIG_COMPACTION" -#endif -#endif diff --git a/arch/arm/mvp/mvpkm/comm_os.h b/arch/arm/mvp/mvpkm/comm_os.h deleted file mode 100644 index cf858f6..0000000 --- a/arch/arm/mvp/mvpkm/comm_os.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Cross-platform base type definitions and function declarations. - * Includes OS-specific base type definitions and function declarations. - */ - -#ifndef _COMM_OS_H_ -#define _COMM_OS_H_ - -/* For-ever timeout constant (in milliseconds). */ -#define COMM_OS_4EVER_TO ((unsigned long long)(~0UL >> 1)) - -/* Condition function prototype. Returns 1: true, 0: false, < 0: error code. */ -typedef int (*CommOSWaitConditionFunc)(void *arg1, void *arg2); - -/* Dispatch function prototype. Called by input (dispatch) kernel threads. */ -typedef unsigned int (*CommOSDispatchFunc)(void); - -/* Module initialization and exit callback functions. */ -extern int (*commOSModInit)(void *args); -extern void (*commOSModExit)(void); - -/* Macro to assign Init and Exit callbacks. */ -#define COMM_OS_MOD_INIT(init, exit) \ - int (*commOSModInit)(void *args) = init; \ - void (*commOSModExit)(void) = exit - - -/* - * OS-specific implementations must provide the following: - * 1. Types: - * CommOSAtomic - * CommOSSpinlock - * CommOSMutex - * CommOSWaitQueue - * CommOSWork - * CommOSWorkFunc - * CommOSList - * CommOSModule - * struct kvec - * - * 2. Definition, initializers: - * CommOSSpinlock_Define() - * - * 3. Functions: - * void CommOS_Debug(const char *format, ...); - * void CommOS_Log(const char *format, ...); - * void CommOS_WriteAtomic(CommOSAtomic *atomic, int val); - * int CommOS_ReadAtomic(CommOSAtomic *atomic); - * int CommOS_AddReturnAtomic(CommOSAtomic *atomic, int val); - * int CommOS_SubReturnAtomic(CommOSAtomic *atomic, int val); - * void CommOS_SpinlockInit(CommOSSpinlock *lock); - * void CommOS_SpinLockBH(CommOSSpinlock *lock); - * int CommOS_SpinTrylockBH(CommOSSpinlock *lock); - * void CommOS_SpinUnlockBH(CommOSSpinlock *lock); - * void CommOS_SpinLock(CommOSSpinlock *lock); - * int CommOS_SpinTrylock(CommOSSpinlock *lock); - * void CommOS_SpinUnlock(CommOSSpinlock *lock); - * void CommOS_MutexInit(CommOSMutex *mutex); - * void CommOS_MutexLock(CommOSMutex *mutex); - * int CommOS_MutexLockUninterruptible(CommOSMutex *mutex); - * int CommOS_MutexTrylock(CommOSMutex *mutex); - * void CommOS_MutexUnlock(CommOSMutex *mutex); - * void CommOS_WaitQueueInit(CommOSWaitQueue *wq); - * CommOS_DoWait(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc cond, - * void *condArg1, - * void *condArg2, - * unsigned long long *timeoutMillis, - * int interruptible); - * int CommOS_Wait(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc func, - * void *funcArg1, - * void *funcArg2, - * unsigned long long *timeoutMillis); - * int CommOS_WaitUninterruptible(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc func, - * void *funcArg1, - * void *funcArg2, - * unsigned long long *timeoutMillis); - * void CommOS_WakeUp(CommOSWaitQueue *wq); - * void *CommOS_KmallocNoSleep(unsigned int size); - * void *CommOS_Kmalloc(unsigned int size); - * void CommOS_Kfree(void *arg); - * void CommOS_Yield(void); - * unsigned long long CommOS_GetCurrentMillis(void); - * void CommOS_ListInit(CommOSList *list); - * int CommOS_ListEmpty(CommOSList *list); - * void CommOS_ListAdd(CommOSList *list, CommOSList *listElem); - * void CommOS_ListAddTail(CommOSList *list, CommOSList *listElem); - * void int CommOS_ListDel(CommOSList *listElem); - * Macros: - * CommOS_ListForEach(*list, *item, itemListFieldName); - * CommOS_ListForEachSafe(*list, *item, *tmp, itemListFieldName); - * void CommOS_ListSplice(CommOSList *list, CommOSList *listToAdd); - * void CommOS_ListSpliceTail(CommOSList *list, CommOSList *listToAdd); - * CommOSModule CommOS_ModuleSelf(void); - * int CommOS_ModuleGet(CommOSModule module); - * void CommOS_ModulePut(CommOSModule module); - * void CommOS_MemBarrier(void); - * - * These cannot be defined here: a) non-pointer type definitions need size - * information, and b) functions may or may not be inlined, or macros may - * be used instead. - */ - - -#ifdef __linux__ -#include "comm_os_linux.h" -#else -#error "Unsupported OS" -#endif - -/* Functions to start and stop the dispatch and aio kernel threads. */ -void CommOS_StopIO(void); -void CommOS_ScheduleDisp(void); -void CommOS_InitWork(CommOSWork *work, CommOSWorkFunc func); -int CommOS_ScheduleAIOWork(CommOSWork *work); -void CommOS_FlushAIOWork(CommOSWork *work); - -int -CommOS_StartIO(const char *dispatchTaskName, - CommOSDispatchFunc dispatchHandler, - unsigned int interval, - unsigned int maxCycles, - const char *aioTaskName); - - -#endif /* _COMM_OS_H_ */ diff --git a/arch/arm/mvp/mvpkm/comm_os_linux.h b/arch/arm/mvp/mvpkm/comm_os_linux.h deleted file mode 100644 index c9d4f26..0000000 --- a/arch/arm/mvp/mvpkm/comm_os_linux.h +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Contains linux-specific type definitions and function declarations - */ - -#ifndef _COMM_OS_LINUX_H_ -#define _COMM_OS_LINUX_H_ - -#include <linux/types.h> -#include <linux/version.h> - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -#error "Kernel versions lower than 2.6.20 are not supported" -#endif - -#include <linux/kernel.h> -#include <linux/workqueue.h> -#include <linux/sched.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/slab.h> - - -/* - * Type definitions. - */ - -typedef atomic_t CommOSAtomic; -typedef spinlock_t CommOSSpinlock; -typedef struct mutex CommOSMutex; -typedef wait_queue_head_t CommOSWaitQueue; -typedef struct delayed_work CommOSWork; -typedef void (*CommOSWorkFunc)(CommOSWork *work); -typedef struct list_head CommOSList; -typedef struct module *CommOSModule; - - -/* - * Initializers. - */ - -#define CommOSSpinlock_Define DEFINE_SPINLOCK - - -#define COMM_OS_DOLOG(...) printk(KERN_INFO __VA_ARGS__) - - -/** - * @brief Logs given arguments in debug builds. - */ - -#if defined(COMM_OS_DEBUG) - #define CommOS_Debug(args) COMM_OS_DOLOG args -#else - #define CommOS_Debug(args) -#endif - - -/** - * @brief Logs given arguments. - */ - -#define CommOS_Log(args) COMM_OS_DOLOG args - - -/** - * @brief Logs function name and location. - */ - -#if defined(COMM_OS_TRACE) -#define TRACE(ptr) \ - do { \ - CommOS_Debug(("%p:%s: at [%s:%d] with arg ptr [0x%p].\n", current, \ - __FUNCTION__, __FILE__, __LINE__, (ptr))); \ - } while (0) -#else -#define TRACE(ptr) -#endif - - -/** - * @brief Write atomic variable - * @param[in,out] atomic variable to write - * @param val new value - */ - -static inline void -CommOS_WriteAtomic(CommOSAtomic *atomic, - int val) -{ - atomic_set(atomic, val); -} - - -/** - * @brief Reads atomic variable - * @param atomic variable to read - * @return value - */ - -static inline int -CommOS_ReadAtomic(CommOSAtomic *atomic) -{ - return atomic_read(atomic); -} - - -/** - * @brief Atomically add value to atomic variable, return new value. - * @param[in,out] atomic variable - * @param val value to add - * @return new value - */ - -static inline int -CommOS_AddReturnAtomic(CommOSAtomic *atomic, - int val) -{ - return atomic_add_return(val, atomic); -} - - -/** - * @brief Atomically substract value from atomic variable, return new value. - * @param[in,out] atomic variable - * @param val value to substract - * @return new value - */ - -static inline int -CommOS_SubReturnAtomic(CommOSAtomic *atomic, - int val) -{ - return atomic_sub_return(val, atomic); -} - - -/** - * @brief Initializes a given lock. - * @param[in,out] lock lock to initialize - */ - -static inline void -CommOS_SpinlockInit(CommOSSpinlock *lock) -{ - spin_lock_init(lock); -} - - -/** - * @brief Locks given lock and disables bottom half processing. - * @param[in,out] lock lock to lock - */ - -static inline void -CommOS_SpinLockBH(CommOSSpinlock *lock) -{ - spin_lock_bh(lock); -} - - -/** - * @brief Attempts to lock the given lock and disable BH processing. - * @param[in,out] lock lock to lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_SpinTrylockBH(CommOSSpinlock *lock) -{ - return !spin_trylock_bh(lock); -} - - -/** - * @brief Unlocks given lock and re-enables BH processing. - * @param[in,out] lock lock to unlock - */ - -static inline void -CommOS_SpinUnlockBH(CommOSSpinlock *lock) -{ - spin_unlock_bh(lock); -} - - -/** - * @brief Locks the given lock. - * @param[in,out] lock lock to lock - */ - -static inline void -CommOS_SpinLock(CommOSSpinlock *lock) -{ - spin_lock(lock); -} - - -/** - * @brief Attempts to lock the given lock. - * @param[in,out] lock lock to try-lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_SpinTrylock(CommOSSpinlock *lock) -{ - return !spin_trylock(lock); -} - - -/** - * @brief Unlocks given lock. - * @param[in,out] lock lock to unlock - */ - -static inline void -CommOS_SpinUnlock(CommOSSpinlock *lock) -{ - spin_unlock(lock); -} - - -/** - * @brief Initializes given mutex. - * @param[in,out] mutex mutex to initialize - */ - -static inline void -CommOS_MutexInit(CommOSMutex *mutex) -{ - mutex_init(mutex); -} - - -/** - * @brief Acquires mutex. - * @param[in,out] mutex mutex to lock - * @return zero if successful, non-zero otherwise (interrupted) - */ - -static inline int -CommOS_MutexLock(CommOSMutex *mutex) -{ - return mutex_lock_interruptible(mutex); -} - - -/** - * @brief Acquires mutex in uninterruptible mode. - * @param[in,out] mutex mutex to lock - */ - -static inline void -CommOS_MutexLockUninterruptible(CommOSMutex *mutex) -{ - mutex_lock(mutex); -} - - -/** - * @brief Attempts to acquire given mutex. - * @param[in,out] mutex mutex to try-lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_MutexTrylock(CommOSMutex *mutex) -{ - return !mutex_trylock(mutex); -} - - -/** - * @brief Releases a given mutex. - * @param[in,out] mutex mutex to unlock - */ - -static inline void -CommOS_MutexUnlock(CommOSMutex *mutex) -{ - mutex_unlock(mutex); -} - - -/** - * @brief Initializes a wait queue. - * @param[in,out] wq workqueue to initialize - */ - -static inline void -CommOS_WaitQueueInit(CommOSWaitQueue *wq) -{ - init_waitqueue_head(wq); -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * - a signal is pending - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @param interruptible enable/disable signal pending check - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, if a signal is pending or other error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_DoWait(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis, - int interruptible) -{ - int rc; - DEFINE_WAIT(wait); - long timeout; -#if defined(COMM_OS_LINUX_WAIT_WORKAROUND) - long tmpTimeout; - long retTimeout; - const unsigned int interval = 50; -#endif - - if (!timeoutMillis) { - return -1; - } - if ((rc = cond(condArg1, condArg2)) != 0) { - return rc; - } - -#if defined(COMM_OS_LINUX_WAIT_WORKAROUND) - timeout = msecs_to_jiffies(interval < *timeoutMillis ? - interval : (unsigned int)*timeoutMillis); - retTimeout = msecs_to_jiffies((unsigned int)(*timeoutMillis)); - - for (; retTimeout >= 0; ) { - prepare_to_wait(wq, &wait, - (interruptible?TASK_INTERRUPTIBLE:TASK_UNINTERRUPTIBLE)); - if ((rc = cond(condArg1, condArg2))) { - break; - } - if (interruptible && signal_pending(current)) { - rc = -EINTR; - break; - } - if ((tmpTimeout = schedule_timeout(timeout))) { - retTimeout -= (timeout - tmpTimeout); - } else { - retTimeout -= timeout; - } - if (retTimeout < 0) { - retTimeout = 0; - } - } - finish_wait(wq, &wait); - if (rc == 0) { - rc = cond(condArg1, condArg2); - if (rc && (retTimeout == 0)) { - retTimeout = 1; - } - } - *timeoutMillis = (unsigned long long)jiffies_to_msecs(retTimeout); -#else // !defined(COMM_OS_LINUX_WAIT_WORKAROUND) - timeout = msecs_to_jiffies((unsigned int)(*timeoutMillis)); - - for (;;) { - prepare_to_wait(wq, &wait, - (interruptible?TASK_INTERRUPTIBLE:TASK_UNINTERRUPTIBLE)); - if ((rc = cond(condArg1, condArg2)) != 0) { - break; - } - if (interruptible && signal_pending(current)) { - rc = -EINTR; - break; - } - if ((timeout = schedule_timeout(timeout)) == 0) { - rc = 0; - break; - } - } - finish_wait(wq, &wait); - if (rc == 0) { - rc = cond(condArg1, condArg2); - if (rc && (timeout == 0)) { - timeout = 1; - } - } - *timeoutMillis = (unsigned long long)jiffies_to_msecs(timeout); -#endif - - return rc; -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * - a signal is pending - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, if a signal is pending or other error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_Wait(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis) -{ - return CommOS_DoWait(wq, cond, condArg1, condArg2, timeoutMillis, 1); -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_WaitUninterruptible(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis) -{ - return CommOS_DoWait(wq, cond, condArg1, condArg2, timeoutMillis, 0); -} - - -/** - * @brief Wakes up task(s) waiting on the given wait queue. - * @param[in,out] wq wait queue. - */ - -static inline void -CommOS_WakeUp(CommOSWaitQueue *wq) -{ - wake_up(wq); -} - - -/** - * @brief Allocates kernel memory of specified size; does not sleep. - * @param size size to allocate. - * @return Address of allocated memory or NULL if the allocation fails. - */ - -static inline void * -CommOS_KmallocNoSleep(unsigned int size) -{ - return kmalloc(size, GFP_ATOMIC); -} - - -/** - * @brief Allocates kernel memory of specified size; may sleep. - * @param size size to allocate. - * @return Address of allocated memory or NULL if the allocation fails. - */ - -static inline void * -CommOS_Kmalloc(unsigned int size) -{ - return kmalloc(size, GFP_KERNEL); -} - - -/** - * @brief Frees previously allocated kernel memory. - * @param obj object to free. - */ - -static inline void -CommOS_Kfree(void *obj) -{ - if (obj) { - kfree(obj); - } -} - - -/** - * @brief Yields the current cpu to other runnable tasks. - */ - -static inline void -CommOS_Yield(void) -{ - cond_resched(); -} - - -/** - * @brief Gets the current time in milliseconds. - * @return Current time in milliseconds, with precision of at most one tick. - */ - -static inline unsigned long long -CommOS_GetCurrentMillis(void) -{ - return (unsigned long long)jiffies_to_msecs(jiffies); -} - - -/** - * @brief Initializes given list. - * @param list list to initialize. - */ - -static inline void -CommOS_ListInit(CommOSList *list) -{ - INIT_LIST_HEAD(list); -} - - -/** - * @brief Tests if list is empty. - * @param list list to test. - * @return non-zero if empty, zero otherwise. - */ - -#define CommOS_ListEmpty(list) list_empty((list)) - - -/** - * @brief Adds given element to beginning of list. - * @param list list to add to. - * @param elem element to add. - */ - -#define CommOS_ListAdd(list, elem) list_add((elem), (list)) - - -/** - * @brief Adds given element to end of list. - * @param list list to add to. - * @param elem element to add. - */ - -#define CommOS_ListAddTail(list, elem) list_add_tail((elem), (list)) - - -/** - * @brief Deletes given element from its list. - * @param elem element to delete. - */ - -#define CommOS_ListDel(elem) \ - do { \ - list_del((elem)); \ - INIT_LIST_HEAD((elem)); \ - } while (0) - - -/** - * @brief Iterates over a list. - * @param list list to iterate over. - * @param[out] item stores next element. - * @param itemListFieldName name in the item structure storing the list head. - */ - -#define CommOS_ListForEach(list, item, itemListFieldName) \ - list_for_each_entry((item), (list), itemListFieldName) - - -/** - * @brief Iterates safely over a list. - * @param list list to iterate over. - * @param[out] item stores next element. May be deleted in the loop. - * @param[out] tmpItem saves iteration element. - * @param itemListFieldName name in the item structure storing the list head. - */ - -#define CommOS_ListForEachSafe(list, item, tmpItem, itemListFieldName) \ - list_for_each_entry_safe((item), (tmpItem), (list), itemListFieldName) - - -/** - * @brief Combines two lists, adds second list to beginning of first one. - * @param list list to add to. - * @param list2 list to add. - */ - -#define CommOS_ListSplice(list, list2) list_splice((list2), (list)) - - -/** - * @brief Combines two lists, adds second list to end of first one. - * @param list list to add to. - * @param list2 list to add. - */ - -#define CommOS_ListSpliceTail(list, list2) list_splice_tail((list2), (list)) - - -/** - * @brief Gets current module handle. - * @return module handle. - */ - -static inline CommOSModule -CommOS_ModuleSelf(void) -{ - return THIS_MODULE; -} - - -/** - * @brief Retains module. - * @param[in,out] module to retain. - * @return zero if successful, non-zero otherwise. - */ - -static inline int -CommOS_ModuleGet(CommOSModule module) -{ - int rc = 0; - - if (!module) { - goto out; - } - if (!try_module_get(module)) { - rc = -1; - } - -out: - return rc; -} - - -/** - * @brief Releases module. - * @param[in,out] module to release. - */ - -static inline void -CommOS_ModulePut(CommOSModule module) -{ - if (module) { - module_put(module); - } -} - - -/** - * @brief Inserts r/w memory barrier. - */ - -#define CommOS_MemBarrier smp_mb - -#endif /* _COMM_OS_LINUX_H_ */ diff --git a/arch/arm/mvp/mvpkm/comm_transp.h b/arch/arm/mvp/mvpkm/comm_transp.h deleted file mode 100644 index a90eb40..0000000 --- a/arch/arm/mvp/mvpkm/comm_transp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Generic shared memory transport API. - */ - -#ifndef _COMM_TRANSP_H_ -#define _COMM_TRANSP_H_ - -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/* - * Common shared memory identifier. - * External handle that makes sense to both hypervisor and guest. - */ - -#define COMM_TRANSP_ID_8_ANY ((unsigned char)-1) -#define COMM_TRANSP_ID_32_ANY ((unsigned int)-1) -#define COMM_TRANSP_ID_64_ANY ((unsigned long long)-1) - - -typedef struct CommTranspID { - union { - unsigned char d8[8]; - unsigned int d32[2]; - unsigned long long d64; - }; -} CommTranspID; - - -/* Basic initialization arguments. */ - -typedef enum CommTranspInitMode { - COMM_TRANSP_INIT_CREATE = 0x0, - COMM_TRANSP_INIT_ATTACH = 0x1 -} CommTranspInitMode; - -typedef struct CommTranspInitArgs { - unsigned int capacity; // Shared memory capacity. - unsigned int type; // Type / implementation using this area. - CommTranspID id; // ID (name) of shared memory area. - CommTranspInitMode mode; // Init mode (above). -} CommTranspInitArgs; - - -/** - * @brief Generate a type id from description (protocol) string. This function - * uses djb2, a string hashing algorithm by Dan Bernstein. - * (see http://www.cse.yorku.ca/~oz/hash.html) - * @param str string to hash - * @return 32-bit hash value - */ - -static inline unsigned int -CommTransp_GetType(const char *str) -{ - unsigned int hash = 5381; - int c; - - while ((c = *str++)) { - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - } - return hash; -} - -#endif // _COMM_TRANSP_H_ diff --git a/arch/arm/mvp/mvpkm/comm_transp_impl.h b/arch/arm/mvp/mvpkm/comm_transp_impl.h deleted file mode 100644 index 6438ac9..0000000 --- a/arch/arm/mvp/mvpkm/comm_transp_impl.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Generic shared memory transport private API. - */ - -#ifndef _COMM_TRANSP_IMPL_H_ -#define _COMM_TRANSP_IMPL_H_ - -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "comm_transp.h" - - -/* Shared memory opaque descriptor/handle. Only meaningful locally. */ - -typedef struct CommTranspPriv *CommTransp; - - -/* Asynchronous signaling initialization arguments. */ - -typedef enum CommTranspIOEvent { - COMM_TRANSP_IO_DETACH = 0x0, - COMM_TRANSP_IO_IN = 0x1, - COMM_TRANSP_IO_OUT = 0x2, - COMM_TRANSP_IO_INOUT = 0x3 -} CommTranspIOEvent; - -typedef struct CommTranspEvent { - void (*ioEvent)(CommTransp transp, CommTranspIOEvent event, void *data); - void *ioEventData; -} CommTranspEvent; - - -/* - * Mechanism to detect and optionally attach to, created shared memory regions. - */ - -typedef struct CommTranspListener { - int (*probe)(CommTranspInitArgs *transpArgs, void *probeData); - void *probeData; -} CommTranspListener; - - - -/* - * Function prototypes. - */ - -int CommTranspEvent_Init(void); -void CommTranspEvent_Exit(void); -int CommTranspEvent_Process(CommTranspID *transpID, CommTranspIOEvent event); -int -CommTranspEvent_Raise(unsigned int peerEvID, - CommTranspID *transpID, - CommTranspIOEvent event); - -int CommTransp_Init(void); -void CommTransp_Exit(void); - -int CommTransp_Register(const CommTranspListener *listener); -void CommTransp_Unregister(const CommTranspListener *listener); -int -CommTransp_Notify(const CommTranspID *notificationCenterID, - CommTranspInitArgs *transpArgs); - -int -CommTransp_Open(CommTransp *transp, - CommTranspInitArgs *transpArgs, - CommTranspEvent *transpEvent); -void CommTransp_Close(CommTransp transp); - -int CommTransp_EnqueueSpace(CommTransp transp); -int CommTransp_EnqueueReset(CommTransp transp); -int CommTransp_EnqueueCommit(CommTransp transp); -int -CommTransp_EnqueueSegment(CommTransp transp, - const void *buf, - unsigned int bufLen); - -int CommTransp_DequeueSpace(CommTransp transp); -int CommTransp_DequeueReset(CommTransp transp); -int CommTransp_DequeueCommit(CommTransp transp); -int -CommTransp_DequeueSegment(CommTransp transp, - void *buf, - unsigned int bufLen); - -unsigned int CommTransp_RequestInlineEvents(CommTransp transp); -unsigned int CommTransp_ReleaseInlineEvents(CommTransp transp); - - -/** - * @brief Enqueues data into the transport object, data is available for - * reading immediately. - * @param transp handle to the transport object. - * @param buf bytes to enqueue. - * @param bufLen number of bytes to enqueue. - * @return number of bytes enqueued on success, < 0 otherwise. - */ - -static inline int -CommTransp_EnqueueAtomic(CommTransp transp, - const void *buf, - unsigned int bufLen) -{ - int rc; - - CommTransp_EnqueueReset(transp); - rc = CommTransp_EnqueueSegment(transp, buf, bufLen); - if (CommTransp_EnqueueCommit(transp)) { - rc = -1; - } - return rc; -} - - -/** - * @brief Dequeues data from the transport object into a buffer. - * @param transp handle to the transport object. - * @param[out] buf buffer to copy to. - * @param bufLen number of bytes to dequeue. - * @return number of bytes dequeued on success, < 0 otherwise, - */ - -static inline int -CommTransp_DequeueAtomic(CommTransp transp, - void *buf, - unsigned int bufLen) -{ - int rc; - - CommTransp_DequeueReset(transp); - rc = CommTransp_DequeueSegment(transp, buf, bufLen); - if (CommTransp_DequeueCommit(transp)) { - rc = -1; - } - return rc; -} - -#endif // _COMM_TRANSP_IMPL_H_ diff --git a/arch/arm/mvp/mvpkm/coproc_defs.h b/arch/arm/mvp/mvpkm/coproc_defs.h deleted file mode 100644 index 26218cf..0000000 --- a/arch/arm/mvp/mvpkm/coproc_defs.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Constant definitions for ARM CP15 coprocessor registers. - * - * Derived from tweety hypervisor/src/armv6/trango_macros.inc file - */ - -#ifndef _COPROC_DEFS_H_ -#define _COPROC_DEFS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/** - * @name CP10 registers. - * - * MCR/MRC format: @code #define <name> <opcode_1>, <CRn>, <CRm>, <opcode_2> @endcode - * @{ - */ -#define VFP_FPSID 7, c0, c0, 0 -#define VFP_MVFR0 7, c7, c0, 0 -#define VFP_MVFR1 7, c6, c0, 0 -#define VFP_FPEXC 7, c8, c0, 0 -#define VFP_FPSCR 7, c1, c0, 0 -#define VFP_FPINST 7, c9, c0, 0 -#define VFP_FPINST2 7, c10, c0, 0 -/*@}*/ - - -/** - * @name CP15 registers. - * - * MCR/MRC format: @code #define <name> <opcode_1>, <CRn>, <CRm>, <opcode_2> @endcode - * MCRR format: @code #define <name> <opcode>, <CRm>@endcode - * @{ - */ -#define ID_CODE 0, c0, c0, 0 -#define CACHE_TYPE 0, c0, c0, 1 -#define MPIDR 0, c0, c0, 5 -#define CACHE_SIZE_ID 1, c0, c0, 0 -#define CACHE_LEVEL_ID 1, c0, c0, 1 -#define CACHE_SIZE_SELECTION 2, c0, c0, 0 -#define MEM_MODEL_FEATURE_0 0, c0, c1, 4 -#define CONTROL_REGISTER 0, c1, c0, 0 -#define TTBASE0_POINTER 0, c2, c0, 0 -#define TTBASE1_POINTER 0, c2, c0, 1 -#define TTCONTROL 0, c2, c0, 2 -#define DOMAIN_CONTROL 0, c3, c0, 0 -#define DATA_FAULT_STATUS 0, c5, c0, 0 -#define INST_FAULT_STATUS 0, c5, c0, 1 -#define AUX_DATA_FAULT_STATUS 0, c5, c1, 0 -#define AUX_INST_FAULT_STATUS 0, c5, c1, 1 -#define DATA_FAULT_ADDRESS 0, c6, c0, 0 -#define INST_FAULT_ADDRESS 0, c6, c0, 2 -#define WAIT_FOR_INTERRUPT 0, c7, c0, 4 -#define PHYSICAL_ADDRESS 0, c7, c4, 0 -#define ICACHE_INVALIDATE_POU 0, c7, c5, 0 -#define ICACHE_INVALIDATE_MVA_POU 0, c7, c5, 1 -#define ICACHE_INVALIDATE_INDEX 0, c7, c5, 2 -#define BTAC_INVALIDATE 0, c7, c5, 6 -#define BTAC_INVALIDATE_MVA 0, c7, c5, 7 -#define DCACHE_INVALIDATE 0, c7, c6, 0 -#define DCACHE_INVALIDATE_MVA_POC 0, c7, c6, 1 -#define DCACHE_INVALIDATE_INDEX 0, c7, c6, 2 -#define UCACHE_INVALIDATE 0, c7, c7, 0 -#define V2P_CURRENT_PRIV_READ 0, c7, c8, 0 -#define V2P_CURRENT_PRIV_WRITE 0, c7, c8, 1 -#define V2P_CURRENT_USER_READ 0, c7, c8, 2 -#define V2P_CURRENT_USER_WRITE 0, c7, c8, 3 -#define V2P_OTHER_PRIV_READ 0, c7, c8, 4 -#define V2P_OTHER_PRIV_WRITE 0, c7, c8, 5 -#define V2P_OTHER_USER_READ 0, c7, c8, 6 -#define V2P_OTHER_USER_WRITE 0, c7, c8, 7 -#define DCACHE_CLEAN 0, c7, c10, 0 -#define DCACHE_CLEAN_MVA_POC 0, c7, c10, 1 -#define DCACHE_CLEAN_INDEX 0, c7, c10, 2 -#define DCACHE_CLEAN_MVA_POU 0, c7, c11, 1 -#define DCACHE_CLEAN_INVALIDATE 0, c7, c14, 0 -#define DCACHE_CLEAN_INVALIDATE_MVA_POC 0, c7, c14, 1 -#define DCACHE_CLEAN_INVALIDATE_INDEX 0, c7, c14, 2 -#define ITLB_INVALIDATE_ALL 0, c8, c5, 0 -#define ITLB_INVALIDATE_SINGLE 0, c8, c5, 1 -#define ITLB_INVALIDATE_ASID 0, c8, c5, 2 -#define DTLB_INVALIDATE_ALL 0, c8, c6, 0 -#define DTLB_INVALIDATE_SINGLE 0, c8, c6, 1 -#define DTLB_INVALIDATE_ASID 0, c8, c6, 2 -#define UTLB_INVALIDATE_ALL 0, c8, c7, 0 -#define UTLB_INVALIDATE_SINGLE 0, c8, c7, 1 -#define UTLB_INVALIDATE_ASID 0, c8, c7, 2 -#define TLB_LOCKDOWN 0, c10, c0, 0 -#define PRIMARY_REGION_REMAP 0, c10, c2, 0 -#define MAIR0 PRIMARY_REGION_REMAP -#define NORMAL_MEMORY_REMAP 0, c10, c2, 1 -#define MAIR1 NORMAL_MEMORY_REMAP -#define VECTOR_BASE 0, c12, c0, 0 -#define INTERRUPT_STATUS 0, c12, c1, 0 -#define CONTEXT_ID 0, c13, c0, 1 -#define TID_USER_RW 0, c13, c0, 2 -#define TID_USER_RO 0, c13, c0, 3 -#define TID_PRIV_RW 0, c13, c0, 4 -#define CLEAR_FAULT_IN_EFSR 7, c15, c0, 1 -#define VBAR 0, c12, c0, 0 - -/* - * ARMv7 performance counters' registers (MVP related) - * - ARM Architecture Reference Manual v7-A and v7-R: DDI0406B - * - Cortex-A8 TRM, rev.r1p1: DDI0344B - */ -#define PERF_MON_CONTROL_REGISTER 0, c9, c12, 0 -#define CYCLE_COUNT 0, c9, c13, 0 -#define PERF_MON_COUNT_SET 0, c9, c12, 1 -#define PERF_MON_COUNT_CLR 0, c9, c12, 2 -#define PERF_MON_FLAG_RDCLR 0, c9, c12, 3 -#define PERF_MON_EVENT_SELECT 0, c9, c12, 5 -#define PERF_MON_EVENT_TYPE 0, c9, c13, 1 -#define PERF_MON_EVENT_COUNT 0, c9, c13, 2 -#define PERF_MON_INTEN_SET 0, c9, c14, 1 -#define PERF_MON_INTEN_CLR 0, c9, c14, 2 - -#define COPROC_ACCESS_CONTROL 0, c1, c0, 2 -#define NON_SECURE_ACCESS_CONTROL 0, c1, c1, 2 - -#define HYP_CFG 4, c1, c1, 0 -#define HYP_DEBUG_CONTROL 4, c1, c1, 1 -#define HYP_COPROC_TRAP 4, c1, c1, 2 -#define HYP_SYS_TRAP 4, c1, c1, 3 -#define VIRT_TCR 4, c2, c1, 2 -#define HYP_SYNDROME 4, c5, c2, 0 -#define HYP_DATA_FAULT_ADDRESS 4, c6, c0, 0 -#define HYP_INST_FAULT_ADDRESS 4, c6, c0, 2 -#define HYP_IPA_FAULT_ADDRESS 4, c6, c0, 4 -#define UTLB_INVALIDATE_ALL_HYP 4, c8, c7, 0 -#define UTLB_INVALIDATE_SINGLE_HYP 4, c8, c7, 1 -#define UTLB_INVALIDATE_ALL_NS_NON_HYP 4, c8, c7, 4 - -#define EXT_TTBR0 0, c2 -#define EXT_TTBR1 1, c2 -#define HYP_TTBR 4, c2 -#define VIRT_TTBR 6, c2 -#define EXT_PHYSICAL_ADDRESS 0, c7 -/*@}*/ - -/** - * @name CP15 configuration control register bits. - * @{ - */ -#define ARM_CP15_CNTL_M (1 << 0) -#define ARM_CP15_CNTL_A (1 << 1) -#define ARM_CP15_CNTL_C (1 << 2) -#define ARM_CP15_CNTL_B (1 << 7) -#define ARM_CP15_CNTL_Z (1 << 11) -#define ARM_CP15_CNTL_I (1 << 12) -#define ARM_CP15_CNTL_V (1 << 13) -#define ARM_CP15_CNTL_U (1 << 22) -#define ARM_CP15_CNTL_VE (1 << 24) -#define ARM_CP15_CNTL_EE (1 << 25) -#define ARM_CP15_CNTL_TRE (1 << 28) -#define ARM_CP15_CNTL_AFE (1 << 29) -#define ARM_CP15_CNTL_TE (1 << 30) - -/*@}*/ - -/** - * @brief Initial System Control Register (SCTLR) value. - * - * Magic described on B3-97 ARM DDI 0406B, it's the power-on - * value, e.g. caches/MMU/alignment checking/TEX remap etc. disabled. - */ -#define ARM_CP15_CNTL_INIT 0x00c50078 - -/** - * @name System control coprocessor primary registers. - * Each primary register is backed by potentially multiple - * physical registers in the vCPU CP15 register file. - * @{ - */ -#define ARM_CP15_CRN_ID 0 ///< Processor ID, cache, TCM and TLB type -#define ARM_CP15_CRN_CNTL 1 ///< System configuration bits -#define ARM_CP15_CRN_PT 2 ///< Page table control -#define ARM_CP15_CRN_DACR 3 ///< Domain access control -#define ARM_CP15_CRN_F_STATUS 5 ///< Fault status -#define ARM_CP15_CRN_F_ADDR 6 ///< Fault address -#define ARM_CP15_CRN_CACHE 7 ///< Cache/write buffer control -#define ARM_CP15_CRN_TLB 8 ///< TLB control -#define ARM_CP15_CRN_REMAP 10 ///< Memory Remap registers -#define ARM_CP15_CRN_SER 12 ///< Security Extension registers -#define ARM_CP15_CRN_PID 13 ///< Process ID -#define ARM_CP15_CRN_TIMER 14 ///< Architecture timers - -#define ARM_CP15_CRM_INVALIDATE_D_CACHE_RANGE 6 -#define ARM_CP15_CRM_CLEAN_AND_INVALIDATE_D_CACHE_RANGE 14 -/*@}*/ - -/** - * @name ARMv7 performance counter control/status register bits (MVP related) - * INTEN: counters overflow interrupt enable - * CNTEN: counters enable - * @{ - */ -#define ARMV7_PMNC_E (1 << 0) -#define ARMV7_PMNC_INTEN_P0 (1 << 0) -#define ARMV7_PMNC_INTEN_P1 (1 << 1) -#define ARMV7_PMNC_INTEN_P2 (1 << 2) -#define ARMV7_PMNC_INTEN_P3 (1 << 3) -#define ARMV7_PMNC_INTEN_C (1 << 31) -#define ARMV7_PMNC_INTEN_MASK 0x8000000f -#define ARMV7_PMNC_CNTEN_P0 (1 << 0) -#define ARMV7_PMNC_CNTEN_P1 (1 << 1) -#define ARMV7_PMNC_CNTEN_P2 (1 << 2) -#define ARMV7_PMNC_CNTEN_P3 (1 << 3) -#define ARMV7_PMNC_CNTEN_C (1 << 31) -#define ARMV7_PMNC_FLAG_P0 (1 << 0) -#define ARMV7_PMNC_FLAG_P1 (1 << 1) -#define ARMV7_PMNC_FLAG_P2 (1 << 2) -#define ARMV7_PMNC_FLAG_P3 (1 << 3) -#define ARMV7_PMNC_FLAG_C (1 << 31) -/*@}*/ - -/** - * @name TTBR masks. - * See B4.9.2 ARM DDI 0100I and B3.12.24 ARM DDI 0406A. - * @{ - */ -#define ARM_CP15_TTBASE_MASK MVP_MASK(14, 18) -#define ARM_CP15_TTBASE_SPLIT_MASK(ttbcrn) MVP_MASK(14-ttbcrn, 18+ttbcrn) -#define ARM_CP15_TTATTRIB_MASK MVP_MASK(0, 6) -/*@}*/ - -/** - * @name ARM fault status register encoding/decoding. - * See B4.6 and B4.9.6 in ARM DDI 0100I. - * @{ - */ -#define ARM_CP15_FSR_STATUS_POS 0 -#define ARM_CP15_FSR_STATUS_POS2 10 -#define ARM_CP15_FSR_DOMAIN_POS 4 -#define ARM_CP15_FSR_WR_POS 11 - -#define ARM_CP15_FSR_STATUS_LEN 4 -#define ARM_CP15_FSR_DOMAIN_LEN 4 - -#define ARM_CP15_FSR_STATUS_DEBUG_EVENT 0x2 -#define ARM_CP15_FSR_STATUS_ALIGNMENT 0x1 -#define ARM_CP15_FSR_STATUS_ICACHE_MAINT 0x4 -#define ARM_CP15_FSR_STATUS_TRANSLATION_SECT 0x5 -#define ARM_CP15_FSR_STATUS_TRANSLATION_PAGE 0x7 -#define ARM_CP15_FSR_STATUS_DOMAIN_SECT 0x9 -#define ARM_CP15_FSR_STATUS_DOMAIN_PAGE 0xb -#define ARM_CP15_FSR_STATUS_PERMISSION_SECT 0xd -#define ARM_CP15_FSR_STATUS_PERMISSION_PAGE 0xf -#define ARM_CP15_FSR_STATUS_ACCESS_FLAG_SECT 0x3 -#define ARM_CP15_FSR_STATUS_ACCESS_FLAG_PAGE 0x6 -#define ARM_CP15_FSR_STATUS_SYNC_EXT_ABORT 0x8 -#define ARM_CP15_FSR_STATUS_ASYNC_EXT_ABORT 0x16 -/*@}*/ - -/** - * @brief Generate ARM fault status register value. - * - * @param fs status from Table B4-1. Only implemented for fs <= 0xf. - * @param domain domain accessed when abort occurred. - * @param write write access caused abort. - */ -#define ARM_CP15_FSR(fs,domain,write) \ - (((fs) << ARM_CP15_FSR_STATUS_POS) | \ - ((domain) << ARM_CP15_FSR_DOMAIN_POS) | \ - ((write) ? (1 << ARM_CP15_FSR_WR_POS) : 0)) - -#define ARM_CP15_FSR_STATUS(r) \ - (MVP_EXTRACT_FIELD((r), ARM_CP15_FSR_STATUS_POS, ARM_CP15_FSR_STATUS_LEN) | \ - (MVP_BIT((r), ARM_CP15_FSR_STATUS_POS2) << ARM_CP15_FSR_STATUS_LEN)) -#define ARM_CP15_FSR_DOMAIN(r) \ - MVP_EXTRACT_FIELD((r), ARM_CP15_FSR_DOMAIN_POS, ARM_CP15_FSR_DOMAIN_LEN) -#define ARM_CP15_FSR_WR(r) \ - MVP_BIT((r), ARM_CP15_FSR_WR_POS) -/*@}*/ - -/* - * This should mask out the major and minor revision numbers. - * As per http://infocenter.arm.com/help/topic/com.arm.doc.ddi0211k/I65012.html - */ -#define ARM_CP15_MAIN_ID_NOREVISION_MASK 0xFF0FFFF0 - -// 2-8 ARM DDI 0151C -#define ARM_CP15_MAIN_ID_920_T 0x41129200 -// 3-18 ARM DDI 0211H -#define ARM_CP15_MAIN_ID_1136J_S 0x4107B362 - -/* Coprocessor Access Control Register */ -#define CPACR_ASEDIS (1 << 31) -#define CPACR_D32DIS (1 << 30) -#define CPACR_CP10_MASK (0x3 << (10*2)) -#define CPACR_CP10_CP11_MASK ( (0x3 << (10*2)) | (0x3 << (11*2)) ) -#define CPACR_CP10_CP11_PRIV_ONLY ( (0x1 << (10*2)) | (0x1 << (11*2)) ) - /* 2-bit access permission per Co-Proc */ - -/** - * @name ARM VFP/Adv. SIMD Extension System Registers - * @{ - */ -#define ARM_VFP_SYSTEM_REG_FPSID 0x0 -#define ARM_VFP_SYSTEM_REG_FPSCR 0x1 -#define ARM_VFP_SYSTEM_REG_MVFR1 0x6 -#define ARM_VFP_SYSTEM_REG_MVFR0 0x7 -#define ARM_VFP_SYSTEM_REG_FPEXC 0x8 -#define ARM_VFP_SYSTEM_REG_FPINST 0x9 -#define ARM_VFP_SYSTEM_REG_FPINST2 0xa - -#define ARM_VFP_SYSTEM_REG_FPEXC_EX (1 << 31) -#define ARM_VFP_SYSTEM_REG_FPEXC_EN (1 << 30) -#define ARM_VFP_SYSTEM_REG_FPEXC_FP2V (1 << 28) - -#define ARM_VFP_SYSTEM_REG_MVFR0_A_SIMD_BIT (0) -#define ARM_VFP_SYSTEM_REG_MVFR0_A_SIMD_MASK (0xf << ARM_VFP_SYSTEM_REG_MVFR0_A_SIMD_BIT) -/*@}*/ - -/** - * @name ARM Multi Processor ID Register (MPIDR) decoding - * @{ - */ -#define ARM_CP15_MPIDR_MP (0x1 << 31) -#define ARM_CP15_MPIDR_U (0x1 << 30) -/*@}*/ - -#endif /// ifndef _COPROC_DEFS_H_ diff --git a/arch/arm/mvp/mvpkm/cpufreq_kernel.c b/arch/arm/mvp/mvpkm/cpufreq_kernel.c deleted file mode 100644 index 4ba71f2..0000000 --- a/arch/arm/mvp/mvpkm/cpufreq_kernel.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MVP host kernel cpufreq related - * - * Track CPU frequency changes. - */ - -#include <linux/module.h> -#include <linux/notifier.h> -#include <linux/cpu.h> -#include <linux/cpufreq.h> -#include <linux/rwsem.h> -#include <linux/smp.h> - -#include "mvp.h" -#include "cpufreq_kernel.h" -#include "mvp_timer.h" - -DEFINE_PER_CPU(struct TscToRate64Cb, tscToRate64); - - -/** - * @brief Return current CPU frequency - * @param cpu CPU number - * @return CPU frequency in Hz - * - * When CPU_FREQ is not available, it uses hardcoded frequencies. - */ -static uint32 -GetCpuFrequency(unsigned int cpu) -{ - unsigned int counterKHZ; - -#ifdef CONFIG_CPU_FREQ - counterKHZ = cpufreq_quick_get(cpu); - if (counterKHZ == 0) { - counterKHZ = cpufreq_get(cpu); - FATAL_IF(counterKHZ == 0); - } -#elif defined(MVP_HOST_BOARD_ve) - /** - * @knownjira{MVP-143} - * We're only using this under the simulator, and it's almost non perceptible to - * provide a fixed TSC frequency as the instructions / second executed widely - * varies depending over time. While we resolve this issue we can use the - * BogoMIPS reported at boot for now. - */ - KNOWN_BUG(MVP-143); - counterKHZ = 125e3; - printk(KERN_INFO "mvpkm: CPU_FREQ not available, forcing TSC to %d KHz\n", counterKHZ); -#elif defined(MVP_HOST_BOARD_panda) - counterKHZ = 1e6; -#else - /* - * If the kernel can't tell us and we have no further host knowledge, - * time to die. - */ -#error "host TSC frequency unknown." -#endif - - return counterKHZ * 1000; -} - -/** - * @brief Compute TSC to RATE64 ratio - * @param cpuFreq TSC frequency in Hz - * @param[out] ttr tscToRate64 pointer - */ -static void -TscToRate64(uint32 cpuFreq, struct TscToRate64Cb *ttr) -{ - uint32 shift; - uint64 mult; - - /* - * A little bit of math ! - * - * We need here to convert the TSC value to our RATE64 timebase. - * - * In other words: - * - * tsc * MVP_TIMER_RATE64 - * rate64 = ---------------------- - * cpuFreq - * - * But we are limited by CPU performance (does not divide easily), CPU - * instruction set, and CPU register file width. To fit performance - * requirement, the math becomes: - * - * rate64 = (cpuFreq * mult) >> shift - * - * To respect instruction set, both cpuFreq and mult must be 32-bit - * numbers. Thus (cpuFreq * mult) will be a 64-bit number. - * - * - * Log2 rate64 = Log2 cpuFreq + Log2 mult - shift - * - * shift = Log2 mult + Log2 cpuFreq - Log2 rate64 - * - * && Log2 mult < 32 - * - * => shift < 32 + Log2 cpuFreq - Log2 rate64 - * - * rate64 << shift - * => mult = --------------- - * cpuFreq - * - * (rate64 << shift) must be a 64-bit number: - * - * Log2 rate64 + shift < 64 - * - * => shift < 64 - Log2 rate64 - * - * While cpuFreq is lower than 2^32 Hz, we have: - * - * shift < 32 + Log2 cpuFreq - Log2 rate64 < 64 - Log2 rate64 - * - * As (31 - CLZ32 x) <= Log2 x < (32 - CLZ32 x): - * - * 31 - CLZ32 cpuFreq <= Log2 cpuFreq && - * - * CLZ32 rate64 - 32 < - Log2 rate64 - * - * 31 + CLZ32 rate64 - CLZ32 cpuFreq < 32 + Log2 cpuFreq - Log2 rate64 - * - * As we want shift to be as great as possible: - * - * => shift = 31 + CLZ32 rate64 - CLZ32 cpuFreq - * - * rate64 << shift - * && mult = --------------- - * cpuFreq - * - * - */ - - /* CLZ(MVP_TIMER_RATE64) is optimized by compiler in a constant */ - shift = 31 + CLZ(MVP_TIMER_RATE64) - CLZ(cpuFreq); - mult = MVP_TIMER_RATE64; - mult <<= shift; - do_div(mult, cpuFreq); - - /* verify Log2 mult < 32 */ - ASSERT(mult < (1ULL<<32)); - - /* update global variables */ - ttr->mult = mult; - ttr->shift = shift; -} - -/** - * @brief Compute TSC to RATE64 ratio for the current cpu - * @param info TSC frequency in Hz - * @sideeffect Update local cpu tscToRate64 - */ -static void -TscToRate64IPI(void *info) -{ - uint32 cpuFreq = (uint32)info; - - TscToRate64(cpuFreq, &__get_cpu_var(tscToRate64)); -} - -/** - * @brief Handle cpufreq transition notifications. - * @param nb Notifier block - * @param val Notified event - * @param data Linux cpufreq_freqs info - * @return NOTIFY_OK - * - * @note A frequency change can fail in which case PRECHANGE and POSTCHANGE - * will not be paired and you get any number of PRECHANGE and maybe never a - * POSTCHANGE (i.e. there is not enough battery voltage available to support a - * high frequency). - * @note This is called once per cpu core that is changing but not always on - * the core that is changing. - */ -static int -CpuFreqNotifier(struct notifier_block *nb, - unsigned long val, - void *data) -{ - struct cpufreq_freqs *freq = data; - bool updateRequired; - - /* ASSUMPTION: Only freq. increases can fail and that it is ok to tell the - * guest a higher frequency than it really is but not the other way around - * as that just leads to time "jumping" forward in the guest not backwards. - */ - updateRequired = (val == CPUFREQ_PRECHANGE && freq->new > freq->old) || - (val == CPUFREQ_POSTCHANGE && freq->new < freq->old); - - /* Call TscToRate64() on the correct CPU core so that locking is not - * required. This also has the side-effect of forcing any currently running - * vCPU's to worldswitch back to the host and correctly update the world - * switch page. - */ - if (updateRequired) { - uint32 hz = freq->new * 1000; - smp_call_function_single(freq->cpu, TscToRate64IPI, (void *)hz, false); - } - - return NOTIFY_OK; -} - -/** - * @brief Notifier block for cpufreq transitions - */ -static struct notifier_block cpuFreqNotifierBlock = { - .notifier_call = CpuFreqNotifier -}; - -/** - * @brief Handle cpuUp notifications. - * @param nb Notifier block - * @param action Notified action, e.g., CPU_ONLINE - * @param hcpu cpu no - * @return NOTIFY_OK - */ -static int -CpuUpNotifier(struct notifier_block *nb, - unsigned long action, - void *hcpu) -{ - long cpu = (long)hcpu; - - switch (action) { - case CPU_ONLINE: - /* The new CPU core is not yet executing normal tasks, so it is safe - * to update it's scaling factors from a different core. */ - TscToRate64(GetCpuFrequency(cpu), &per_cpu(tscToRate64, cpu)); - break; - default: - /* - * Ignore all other action notifications, - * such as CPU_UP_PREPARE, CPU_UP_CANCELED, - * CPU_DOWN_PREPARE, CPU_DOWN_FAILED, - * CPU_DYING, CPU_DEAD, CPU_POST_DEAD, etc. - * as they are irrelevant here. - */ - break; - } - - return NOTIFY_OK; -} - -/** - * @brief Notifier block for cpus going online - */ -static struct notifier_block cpuUpNotifierBlock = { - .notifier_call = CpuUpNotifier -}; - -/** - * @brief Initialize TSC ratio and register cpufreq transitions. - */ -void -CpuFreq_Init(void) -{ - int ret; - int cpu; - - /* register callback on frequency change */ - ret = cpufreq_register_notifier(&cpuFreqNotifierBlock, - CPUFREQ_TRANSITION_NOTIFIER); - FATAL_IF(ret < 0); - - /* register callback on cpu core online */ - ret = register_cpu_notifier(&cpuUpNotifierBlock); - FATAL_IF(ret < 0); - - /* Make sure that things are correctly initialized. */ - for_each_online_cpu(cpu) { - TscToRate64(GetCpuFrequency(cpu), &per_cpu(tscToRate64, cpu)); - } -} - -/** - * @brief Exit cpufreq, unregister cpufreq transitions - */ -void -CpuFreq_Exit(void) -{ - cpufreq_unregister_notifier(&cpuFreqNotifierBlock, - CPUFREQ_TRANSITION_NOTIFIER); - unregister_cpu_notifier(&cpuUpNotifierBlock); -} diff --git a/arch/arm/mvp/mvpkm/cpufreq_kernel.h b/arch/arm/mvp/mvpkm/cpufreq_kernel.h deleted file mode 100644 index a84b6dd..0000000 --- a/arch/arm/mvp/mvpkm/cpufreq_kernel.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The monitor-kernel socket interface kernel-only definitions. - */ - -#ifndef _CPUFREQ_KERNEL_H -#define _CPUFREQ_KERNEL_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/* Scaling factors to convert CPU clock cycles to Rate64 value */ -struct TscToRate64Cb { - uint32 mult; - uint32 shift; -}; - -/* It is assumed that this is only accessed from the current CPU core and not - * "across cores" */ -DECLARE_PER_CPU(struct TscToRate64Cb, tscToRate64); - -void CpuFreq_Init(void); -void CpuFreq_Exit(void); - -#endif diff --git a/arch/arm/mvp/mvpkm/exc_defs.h b/arch/arm/mvp/mvpkm/exc_defs.h deleted file mode 100644 index 1d5d063..0000000 --- a/arch/arm/mvp/mvpkm/exc_defs.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Exception-related definitions. See A2.6 ARM DDI 0100I. - */ - -#ifndef _EXC_DEFS_H_ -#define _EXC_DEFS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define EXC_VECTOR_SIZE 0x20 - -#define EXC_RESET_VECTOR_OFFSET 0x00 -#define EXC_UNDEFINED_VECTOR_OFFSET 0x04 -#define EXC_SWI_VECTOR_OFFSET 0x08 -#define EXC_PREFETCH_ABORT_VECTOR_OFFSET 0x0c -#define EXC_DATA_ABORT_VECTOR_OFFSET 0x10 -#define EXC_HYP_VECTOR_OFFSET 0x14 -#define EXC_IRQ_VECTOR_OFFSET 0x18 -#define EXC_FIQ_VECTOR_OFFSET 0x1c - -#define EXC_ARM_UNDEFINED_SAVED_PC_OFFSET 4 -#define EXC_ARM_SWI_SAVED_PC_OFFSET 4 -#define EXC_ARM_PREFETCH_ABORT_SAVED_PC_OFFSET 4 -#define EXC_ARM_DATA_ABORT_SAVED_PC_OFFSET 8 -#define EXC_ARM_IRQ_SAVED_PC_OFFSET 4 -#define EXC_ARM_FIQ_SAVED_PC_OFFSET 4 - -#define EXC_THUMB_UNDEFINED_SAVED_PC_OFFSET 2 -#define EXC_THUMB_SWI_SAVED_PC_OFFSET 2 -#define EXC_THUMB_PREFETCH_ABORT_SAVED_PC_OFFSET 4 -#define EXC_THUMB_DATA_ABORT_SAVED_PC_OFFSET 8 -#define EXC_THUMB_IRQ_SAVED_PC_OFFSET 4 -#define EXC_THUMB_FIQ_SAVED_PC_OFFSET 4 - -#define EXC_SAVED_PC_OFFSET(exc, cpsr) \ - (((cpsr) & ARM_PSR_T) ? EXC_THUMB_##exc##_SAVED_PC_OFFSET : \ - EXC_ARM_##exc##_SAVED_PC_OFFSET) - -#endif /// _EXC_DEFS_H_ diff --git a/arch/arm/mvp/mvpkm/exc_types.h b/arch/arm/mvp/mvpkm/exc_types.h deleted file mode 100644 index ba835e5..0000000 --- a/arch/arm/mvp/mvpkm/exc_types.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Exception-related types. See A2.6 ARM DDI 0100I. - */ - -#ifndef _EXC_TYPES_H_ -#define _EXC_TYPES_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/** - * @brief ARM hardware exception enumeration. EXC_NONE is added to provide - * a distinguished value to flag non-exception states. - */ -typedef enum { - EXC_NONE, - EXC_RESET, - EXC_UNDEFINED, - EXC_SWI, - EXC_PREFETCH_ABORT, - EXC_DATA_ABORT, - EXC_IRQ, - EXC_FIQ -} ARM_Exception; - -#endif /// _EXC_TYPES_H_ diff --git a/arch/arm/mvp/mvpkm/exitstatus.h b/arch/arm/mvp/mvpkm/exitstatus.h deleted file mode 100644 index c53827a..0000000 --- a/arch/arm/mvp/mvpkm/exitstatus.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Exit Status values - */ - -#ifndef _EXITSTATUS_H -#define _EXITSTATUS_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#define INCLUDE_ALLOW_HOSTUSER -#include "include_check.h" - - -#define _EXIT_STATUS_DEF \ - _EXIT_STATUS_ITEM(Success, 0) \ - _EXIT_STATUS_ITEM(ReturnToHost, 1) \ - _EXIT_STATUS_ITEM(GuestExit, 2) \ - _EXIT_STATUS_ITEM(HostRequest, 3) \ - _EXIT_STATUS_ITEM(VMXFatalError, 4) \ - _EXIT_STATUS_ITEM(VMMFatalError, 5) \ - _EXIT_STATUS_ITEM(MVPDFatalError, 6) \ - _EXIT_STATUS_ITEM(VPNFatalError, 7) \ - _EXIT_STATUS_ITEM(VMXFindCause, 8) - - -enum ExitStatus { -#define _EXIT_STATUS_ITEM(name,num) ExitStatus##name = num, -_EXIT_STATUS_DEF -#undef _EXIT_STATUS_ITEM -}; - -typedef enum ExitStatus ExitStatus; - -#ifndef __cplusplus -static const char * ExitStatusName[] UNUSED = { -#define _EXIT_STATUS_ITEM(name,num) [ExitStatus##name] = #name, -_EXIT_STATUS_DEF -#undef _EXIT_STATUS_ITEM -}; -#endif - -#endif diff --git a/arch/arm/mvp/mvpkm/fatalerror.h b/arch/arm/mvp/mvpkm/fatalerror.h deleted file mode 100644 index 58e1f98..0000000 --- a/arch/arm/mvp/mvpkm/fatalerror.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief fatal error handlers. They all post fatal errors regardless of build - * type. - */ - -#ifndef _FATALERROR_H -#define _FATALERROR_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mvp_compiler.h" - -#ifdef __cplusplus -extern "C" { -#endif - -enum FECode { - FECodeMisc, ///< generic FATAL() call of sorts - FECodeOOM, ///< FATAL_OOM() call of sorts - FECodeAssert, ///< ASSERT() call of sorts - FECodeNR, ///< NOT_REACHED() call of sorts - FECodeNI, ///< NOT_IMPLEMENTED() call of sorts - FECodeNT, ///< NOT_TESTED() call of sorts - FECodeCF ///< COMPILE_FAIL() call of sorts -}; -typedef enum FECode FECode; - -#define FATAL() FatalError(__FILE__, __LINE__, FECodeMisc, 0, NULL) -#define FATAL_IF(x) do { if (UNLIKELY(x)) FATAL(); } while (0) -#define FATAL_OOM() FatalError(__FILE__, __LINE__, FECodeOOM, 0, NULL) -#define FATAL_OOM_IF(x) do { if (UNLIKELY(x)) FATAL_OOM(); } while (0) - -extern _Bool FatalError_hit; - -void NORETURN FatalError(char const *file, - int line, - FECode feCode, - int bugno, - char const *fmt, - ...) FORMAT(printf,5,6); - -#define FATALERROR_COMMON(printFunc, \ - printFuncV, \ - file, \ - line, \ - feCode, \ - bugno, \ - fmt) { \ - va_list ap; \ - \ - printFunc("FatalError: %s:%d, code %d, bugno %d\n", \ - file, line, feCode, bugno); \ - if (fmt != NULL) { \ - va_start(ap, fmt); \ - printFuncV(fmt, ap); \ - va_end(ap); \ - } \ - } - -#if defined IN_HOSTUSER || defined IN_GUESTUSER || defined IN_WORKSTATION - -#define FATALERROR_POSIX_USER \ -void \ -FatalError_VErrPrintf(const char *fmt, va_list ap) \ -{ \ - vfprintf(stderr, fmt, ap); \ -} \ -\ -void \ -FatalError_ErrPrintf(const char *fmt, ...) \ -{ \ - va_list ap; \ - va_start(ap, fmt); \ - FatalError_VErrPrintf(fmt, ap); \ - va_end(ap); \ -} \ -\ -void NORETURN \ -FatalError(char const *file, \ - int line, \ - FECode feCode, \ - int bugno, \ - const char *fmt, \ - ...) \ -{ \ - FATALERROR_COMMON(FatalError_ErrPrintf, FatalError_VErrPrintf, file, line, feCode, bugno, fmt); \ - exit(EXIT_FAILURE); \ -} -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/arch/arm/mvp/mvpkm/include_check.h b/arch/arm/mvp/mvpkm/include_check.h deleted file mode 100644 index 2eeafe7..0000000 --- a/arch/arm/mvp/mvpkm/include_check.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for Empty File Placeholder - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ diff --git a/arch/arm/mvp/mvpkm/instr_defs.h b/arch/arm/mvp/mvpkm/instr_defs.h deleted file mode 100644 index ce6b1c9..0000000 --- a/arch/arm/mvp/mvpkm/instr_defs.h +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief ARM instruction encoding/decoding macros. - */ - -#ifndef _INSTR_DEFS_H_ -#define _INSTR_DEFS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "utils.h" - -/** - * @name ARM register synonyms. - * @{ - */ -#define ARM_REG_R0 0 -#define ARM_REG_R1 1 -#define ARM_REG_R2 2 -#define ARM_REG_R3 3 -#define ARM_REG_R4 4 -#define ARM_REG_R5 5 -#define ARM_REG_R6 6 -#define ARM_REG_R7 7 -#define ARM_REG_R8 8 -#define ARM_REG_R9 9 -#define ARM_REG_R10 10 -#define ARM_REG_FP 11 -#define ARM_REG_IP 12 -#define ARM_REG_SP 13 -#define ARM_REG_LR 14 -#define ARM_REG_PC 15 -/*@}*/ - -/** - * @name Data-processing + load/store instruction register field decoding. - * - * @note The following constants and masks used to fetch register operands - * are meant to be used in strictly the following sets of instructions: - * data processing instructions and load/store instructions. - * If you want to fetch the RN, RD, RS and RM fields for some other - * type of instructions, please verify before using -- you may have - * to introduce special constants just for those sets of instructions. - * For instance, all the multiply and signed multiply instructions have - * RN and RD reversed. So, @b BEWARE ! - * - * @{ - */ -#define ARM_INSTR_RN_BIT_POS 16 -#define ARM_INSTR_RD_BIT_POS 12 -#define ARM_INSTR_RS_BIT_POS 8 -#define ARM_INSTR_RM_BIT_POS 0 - -#define ARM_INSTR_RN_LENGTH 4 -#define ARM_INSTR_RD_LENGTH 4 -#define ARM_INSTR_RS_LENGTH 4 -#define ARM_INSTR_RM_LENGTH 4 - -#define ARM_INSTR_RN(r) \ - MVP_EXTRACT_FIELD((r), ARM_INSTR_RN_BIT_POS, ARM_INSTR_RN_LENGTH) -#define ARM_INSTR_RD(r) \ - MVP_EXTRACT_FIELD((r), ARM_INSTR_RD_BIT_POS, ARM_INSTR_RD_LENGTH) -#define ARM_INSTR_RS(r) \ - MVP_EXTRACT_FIELD((r), ARM_INSTR_RS_BIT_POS, ARM_INSTR_RS_LENGTH) -#define ARM_INSTR_RM(r) \ - MVP_EXTRACT_FIELD((r), ARM_INSTR_RM_BIT_POS, ARM_INSTR_RM_LENGTH) - -#define ARM_INSTR_RN_SHIFT(word) ((word) << ARM_INSTR_RN_BIT_POS) -#define ARM_INSTR_RD_SHIFT(word) ((word) << ARM_INSTR_RD_BIT_POS) -#define ARM_INSTR_RS_SHIFT(word) ((word) << ARM_INSTR_RS_BIT_POS) -#define ARM_INSTR_RM_SHIFT(word) ((word) << ARM_INSTR_RM_BIT_POS) - -#define ARM_INSTR_RN_MASK (~(ARM_INSTR_RN_SHIFT(0xf))) -#define ARM_INSTR_RD_MASK (~(ARM_INSTR_RD_SHIFT(0xf))) -#define ARM_INSTR_RS_MASK (~(ARM_INSTR_RS_SHIFT(0xf))) -#define ARM_INSTR_RM_MASK (~(ARM_INSTR_RM_SHIFT(0xf))) -/*@}*/ - -/** - * @name Condition field -- common bit layout across all ARM instructions. - * @{ - */ -#define ARM_INSTR_COND(instr) (MVP_EXTRACT_FIELD(instr, 28, 4)) - -#define ARM_INSTR_COND_EQ 0x0 ///< Equal -#define ARM_INSTR_COND_NE 0x1 ///< Not equal -#define ARM_INSTR_COND_CS 0x2 ///< Carry set/unsigned higher or same -#define ARM_INSTR_COND_CC 0x3 ///< Carry clear/unsigned lower -#define ARM_INSTR_COND_MI 0x4 ///< Minus/negative -#define ARM_INSTR_COND_PL 0x5 ///< Plus/positive or zero -#define ARM_INSTR_COND_VS 0x6 ///< Overflow -#define ARM_INSTR_COND_VC 0x7 ///< No overflow -#define ARM_INSTR_COND_HI 0x8 ///< Unsigned higher -#define ARM_INSTR_COND_LS 0x9 ///< Unsigned lower or same -#define ARM_INSTR_COND_GE 0xa ///< Signed greater than or equal -#define ARM_INSTR_COND_LT 0xb ///< Signed less than -#define ARM_INSTR_COND_GT 0xc ///< Signed greater than -#define ARM_INSTR_COND_LE 0xd ///< Signed less than or equal -#define ARM_INSTR_COND_AL 0xe ///< Always (unconditional) -#define ARM_INSTR_COND_NV 0xf ///< Invalid -/*@}*/ - -/** - * @name Load/store instruction decoding. - * @{ - */ - -/* - * I bit indicating Register(1)/Immediate(0) addressing modes. - */ -#define ARM_INSTR_LDST_IBIT(instr) (MVP_BIT(instr, 25)) - -/* - * U bit indicating whether the offset is added to the base (U == 1) - * or is subtracted from the base (U == 0). - */ -#define ARM_INSTR_LDST_UBIT(instr) (MVP_BIT(instr, 23)) - -/* - * B bit indicating byte(1)/word(0). - */ -#define ARM_INSTR_LDST_BBIT(instr) (MVP_BIT(instr, 22)) - -/* - * L bit indicating ld(1)/st(0). - */ -#define ARM_INSTR_LDST_LBIT(instr) (MVP_BIT(instr, 20)) - -/* - * Shifter operand. - */ -#define ARM_INSTR_LDST_SHIFTER_OPERAND(instr) (MVP_EXTRACT_FIELD(instr, 0, 12)) - -/* - * Immediate offset (12-bits wide) for load/store. - */ -#define ARM_INSTR_LDST_IMMEDIATE(instr) (MVP_EXTRACT_FIELD(instr, 0, 12)) - -/* - * Register List for multiple ld/st. - */ -#define ARM_INSTR_LDMSTM_REGLIST(instr) (MVP_EXTRACT_FIELD(instr, 0, 16)) - -/* - * Immediate Offset for Miscellaneous ld/st instructions. - */ -#define ARM_INSTR_MISC_LDST_IMM_OFFSET(instr) \ - ((MVP_EXTRACT_FIELD(instr, 8, 4) << 4) | MVP_EXTRACT_FIELD(instr, 0, 4)) - -/*@}*/ - -/** - * @name Thumb ldrt/strt instruction decoding. - * @{ - */ - -/* - * L bit indicating ld(1)/st(0). - */ -#define ARM_THUMB_INSTR_LDST_LBIT(instr) (MVP_BIT(instr, 20)) - -/* - * W bit indicating word(1)/byte(0). - */ -#define ARM_THUMB_INSTR_LDST_WBIT(instr) (MVP_BIT(instr, 22)) - -/* - * Immediate offset (8-bits wide) for load/store. - */ -#define ARM_THUMB_INSTR_LDST_IMMEDIATE(instr) (MVP_EXTRACT_FIELD(instr, 0, 8)) - -/*@}*/ - -/** - * @name ARM instruction opcodes. - * @{ - */ -#define ARM_OP_BR_A1 0x0a000000 -#define ARM_OP_BX_A1 0x012fff10 -#define ARM_OP_LDR_LIT_A1 0x051f0000 -#define ARM_OP_MOV_A1 0x01a00000 -#define ARM_OP_MOVW_A2 0x03000000 -#define ARM_OP_MOVT_A1 0x03400000 -#define ARM_OP_MRS_A1 0x01000000 -#define ARM_OP_MSR_T1 0x8000f380 -#define ARM_OP_MSR_A1 0x0120f000 -#define ARM_OP_HVC_A1 0x01400070 -#define ARM_OP_ERET_T1 0x8f00f3de -#define ARM_OP_ERET_A1 0x0160006e - -/* - * Set SYSm[5] = 1 for VE MSR/MRS, see p77-78 ARM PRD03-GENC-008353 10.0. - */ -#define ARM_OP_MRS_EXT_A1 (ARM_OP_MRS_A1 | (1 << 9)) -#define ARM_OP_MSR_EXT_T1 (ARM_OP_MSR_T1 | (1 << 21)) -#define ARM_OP_MSR_EXT_A1 (ARM_OP_MSR_A1 | (1 << 9)) - -#define ARM_OP_I 0x02000000 -#define ARM_OP_S 0x00100000 -#define ARM_OP_W 0x00200000 -/*@}*/ - -/** - * @name ARM instruction class - see Figure A3-1 ARM DDI 0100I. - * @{ - */ -#define ARM_INSTR_CLASS(instr) MVP_BITS(instr, 25, 27) - -#define ARM_INSTR_CLASS_BRANCH 0x5 -/*@}*/ - -/** - * @name ARM instruction opcode - see Figure A3-1 ARM DDI 0100I. Does not - * include extension bits 4-7. - * @{ - */ -#define ARM_INSTR_OPCODE(instr) MVP_EXTRACT_FIELD(instr, 20, 8) - -#define ARM_INSTR_OPCODE_EQ(instr1, instr2) \ - (ARM_INSTR_OPCODE(instr1) == ARM_INSTR_OPCODE(instr2)) -/*@}*/ - -/** - * @brief Extract the offset in a branch instruction - i.e., the least - * significant 24 bits sign extended. - */ -#define ARM_INSTR_BRANCH_TARGET(inst) (((int32)(inst) << 8) >> 6) - -/** - * @brief Check if a potential branch target is outside the encodable distance. - */ -#define ARM_INSTR_BRANCH_TARGET_OVERFLOWS(v) ((v) + (1 << 25) >= (1<< 26)) - -/** - * @brief Modify branch instruction encoding 'ins' with 'offset' as the - * new target. - */ -#define ARM_INSTR_BRANCH_UPDATE_OFFSET(ins, offset) \ - (((ins) & MVP_MASK(24, 8)) | (((offset) >> 2) & MVP_MASK(0, 24))) - -/** - * @brief B instruction encoding - see A8.6.16 ARM DDI 0406A. - */ -#define ARM_INSTR_BR_ENC(cond, offset) \ - (((cond) << 28) | ARM_OP_BR_A1 | MVP_BITS(((uint32)offset) >> 2, 0, 23)) - -/** - * @brief BX instruction encoding - */ -#define ARM_INSTR_BX_ENC(cond, rm) \ - (((cond) << 28) | ARM_OP_BX_A1 | (rm)) - -/** - * @brief LDR +literal instruction encoding - see ARM8.6.59 DDI 0506A. - */ -#define ARM_INSTR_LDR_LIT_ADD_ENC(cond, reg, offset) \ - (((cond) << 28) | ARM_OP_LDR_LIT_A1 | (1 << 23) | ((reg) << 12) | (offset)) - -/** - * @brief Generate encoding of the instruction mov rd, rn. - */ -#define ARM_INSTR_MOV_A1_ENC(cond, rd, rn) \ - ((((cond) << 28) | ARM_OP_MOV_A1 | ((rd) << 12) | (rn))) - -/** - * @name Encoding/decoding of MOVT/W instructions. - * @{ - */ -#define ARM_INSTR_MOVTW_IMMED(instr) \ - (MVP_BITS(instr, 0, 11) | (MVP_BITS(instr, 16, 19) << 12)) - -#define ARM_INSTR_MOVW_A2_ENC(cond,rd,immed) \ - (((cond) << 28) | ARM_OP_MOVW_A2 | (MVP_BITS(immed, 12, 15) << 16) | \ - ((rd) << 12) | MVP_BITS(immed, 0, 11)) - -#define ARM_INSTR_MOVT_A1_ENC(cond,rd,immed) \ - (((cond) << 28) | ARM_OP_MOVT_A1 | \ - (MVP_BITS(((immed) >> 16), 12, 15) << 16) | \ - ((rd) << 12) | MVP_BITS(((immed) >> 16), 0, 11)) -/*@}*/ - -/** - * @brief BKPT instruction encoding - see A4.1.7 ARM DDI 0100I. - */ -#define ARM_INSTR_BKPT_ENC(immed) \ - (0xe1200070 | \ - MVP_EXTRACT_FIELD(immed, 0, 4) | \ - (MVP_EXTRACT_FIELD(immed, 4, 12) << 8)) - -/** - * @name VE instruction encodings - see section 13 ARM PRD03-GENC-008353 10.0. - * @{ - */ -#define ARM_INSTR_HVC_A1_ENC(immed) \ - ((ARM_INSTR_COND_AL << 28) | ARM_OP_HVC_A1 | \ - MVP_EXTRACT_FIELD(immed, 0, 4) | \ - (MVP_EXTRACT_FIELD(immed, 4, 12) << 8)) - -#define ARM_INSTR_ERET_A1_ENC(cond) \ - (((cond) << 28) | ARM_OP_ERET_A1) - -/* - * R=0 - */ -#define ARM_REG_R8_USR 0 -#define ARM_REG_R9_USR 1 -#define ARM_REG_R10_USR 2 -#define ARM_REG_R11_USR 3 -#define ARM_REG_R12_USR 4 -#define ARM_REG_SP_USR 5 -#define ARM_REG_LR_USR 6 -#define ARM_REG_R8_FIQ 8 -#define ARM_REG_R9_FIQ 9 -#define ARM_REG_R10_FIQ 10 -#define ARM_REG_FP_FIQ 11 -#define ARM_REG_IP_FIQ 12 -#define ARM_REG_SP_FIQ 13 -#define ARM_REG_LR_FIQ 14 -#define ARM_REG_LR_IRQ 16 -#define ARM_REG_SP_IRQ 17 -#define ARM_REG_LR_SVC 18 -#define ARM_REG_SP_SVC 19 -#define ARM_REG_LR_ABT 20 -#define ARM_REG_SP_ABT 21 -#define ARM_REG_LR_UND 22 -#define ARM_REG_SP_UND 23 -#define ARM_REG_LR_MON 28 -#define ARM_REG_SP_MON 29 -#define ARM_REG_ELR_HYP 30 -#define ARM_REG_SP_HYP 31 - -/* - * R=1 - */ -#define R_EXTEND(x) ((1 << 5) | (x)) -#define ARM_REG_SPSR_FIQ R_EXTEND(ARM_REG_LR_FIQ) -#define ARM_REG_SPSR_IRQ R_EXTEND(ARM_REG_LR_IRQ) -#define ARM_REG_SPSR_SVC R_EXTEND(ARM_REG_LR_SVC) -#define ARM_REG_SPSR_ABT R_EXTEND(ARM_REG_LR_ABT) -#define ARM_REG_SPSR_UND R_EXTEND(ARM_REG_LR_UND) -#define ARM_REG_SPSR_MON R_EXTEND(ARM_REG_LR_MON) -#define ARM_REG_SPSR_HYP R_EXTEND(ARM_REG_ELR_HYP) - -#define ARM_INSTR_MSR_EXT_T1_ENC(rm,rn) \ - (ARM_OP_MSR_EXT_T1 | (MVP_BIT(rm, 5) << 4) | \ - (MVP_BIT(rm, 4) << 20) | (MVP_EXTRACT_FIELD(rm, 0, 4) << 24) | ((rn) << 0)) - -#define ARM_INSTR_MSR_EXT_A1_ENC(cond,rm,rn) \ - (((cond) << 28) | ARM_OP_MSR_EXT_A1 | (MVP_BIT(rm, 5) << 22) | \ - (MVP_BIT(rm, 4) << 8) | (MVP_EXTRACT_FIELD(rm, 0, 4) << 16) | ((rn) << 0)) - -#define ARM_INSTR_MRS_EXT_A1_ENC(cond,rd,rm) \ - (((cond) << 28) | ARM_OP_MRS_EXT_A1 | (MVP_BIT(rm, 5) << 22) | \ - (MVP_BIT(rm, 4) << 8) | (MVP_EXTRACT_FIELD(rm, 0, 4) << 16) | ((rd) << 12)) -/*@}*/ - -/** - * @name ARM MCR/MRC/MCRR instruction decoding. - * @{ - */ -#define ARM_INSTR_COPROC_CR_LEN 4 -#define ARM_INSTR_COPROC_CR_MAX (1 << ARM_INSTR_COPROC_CR_LEN) -#define ARM_INSTR_COPROC_OPCODE_LEN 3 -#define ARM_INSTR_COPROC_OPCODE_MAX (1 << ARM_INSTR_COPROC_OPCODE_LEN) - -#define ARM_INSTR_COPROC_CRM(instr) MVP_EXTRACT_FIELD(instr, 0, 4) -#define ARM_INSTR_COPROC_CRN(instr) MVP_EXTRACT_FIELD(instr, 16, 4) -#define ARM_INSTR_COPROC_OPCODE1(instr) MVP_EXTRACT_FIELD(instr, 21, 3) -#define ARM_INSTR_COPROC_OPCODE2(instr) MVP_EXTRACT_FIELD(instr, 5, 3) -#define ARM_INSTR_COPROC_OPCODE(instr) MVP_EXTRACT_FIELD(instr, 4, 4) -#define ARM_INSTR_COPROC_CPNUM(instr) MVP_EXTRACT_FIELD(instr, 8, 4) -/*@}*/ - -/** - * @name ARM VMRS/VMSR instruction decoding -- See VMRS (B6.1.14) - * and VMSR (B6.1.15) in ARM DDI 0406B. - * @{ - */ -#define ARM_INSTR_IS_VMRS(instr) ((MVP_EXTRACT_FIELD(instr, 0, 12) == 0xa10) && \ - (ARM_INSTR_OPCODE(instr) == 0xef)) - -#define ARM_INSTR_IS_VMSR(instr) ((MVP_EXTRACT_FIELD(instr, 0, 12) == 0xa10) && \ - (ARM_INSTR_OPCODE(instr) == 0xee)) - -#define ARM_INSTR_VMRS_SPECREG(instr) MVP_EXTRACT_FIELD(instr, 16, 4) -#define ARM_INSTR_VMRS_RT(instr) MVP_EXTRACT_FIELD(instr, 12, 4) - -#define ARM_INSTR_VMSR_SPECREG(instr) MVP_EXTRACT_FIELD(instr, 16, 4) -#define ARM_INSTR_VMSR_RT(instr) MVP_EXTRACT_FIELD(instr, 12, 4) -/*@}*/ - -/** - * @name ARM SWP{B} instruction checking. - * @{ - */ -#define ARM_INSTR_IS_SWP(instr) ((instr & 0x0fb00ff0) == 0x01000090) -/*@}*/ - -#endif /// _INSTR_DEFS_H_ diff --git a/arch/arm/mvp/mvpkm/lowmemkiller_variant.sh b/arch/arm/mvp/mvpkm/lowmemkiller_variant.sh deleted file mode 100644 index 7721e57..0000000 --- a/arch/arm/mvp/mvpkm/lowmemkiller_variant.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash -# -# Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support -# -# Copyright (C) 2010-2012 VMware, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 as published by -# the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program; see the file COPYING. If not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# @brief Script providing the variant of the low memory killer implementation -# to assist in mvpkm's export of the other_file calculation. - -if [ -z "$1" ] -then - echo "Usage: $0 <path to lowmemorykiller.c>" - exit 1 -fi - -# We look at the relevant section of the lowmem_shrink function here. This -# pattern is sufficient to distinguish between the known variants without -# introducing too many false positives for new variants. I.e. we can spot the -# lines that matter for the other_file calculation. In some cases the -# lowmemorykiller uses only the other_file calculation instead of max(free, -# file) - in the cases we've seen this is OK with the balloon policy, since the -# free term isn't really significant when we get into low memory states anyway. - -tmp_file="lmk_md5sum_$RANDOM" - -cat $1 | tr -d '\ \t\n\r' > $tmp_file -sed -i -e 's/.*\(intother_file.*other_file<\).*/;\1/' \ - -e 's/[;][^;]*other_file[^;]*/#<#&#>#/g' \ - -e 's/#>#[^#]*//g' $tmp_file - -# Detect MD5SUM executable -HOST_OS=`uname -s` -if [ "$HOST_OS" = "Darwin" ] -then - MD5SUM_EXEC=md5 -else - MD5SUM_EXEC=md5sum -fi - -MD5=`${MD5SUM_EXEC} $tmp_file | cut -f1 -d\ ` - -rm $tmp_file - -case $MD5 in -4af66fafb5e4cbd7b4092e29e071f152|\ -a0f18472eb53e52b38d6f85d4ec66842|\ -590b89af56f57146edffceba60845ad8|\ -fddbb73a58e82ba1966fd862a561c2bd) - #/* - # * This is the same as the non-exported global_reclaimable_pages() when there - # * is no swap. - # */ - #other_file = global_page_state(NR_ACTIVE_FILE) + - # global_page_state(NR_INACTIVE_FILE); - V=1 -;; -943372c447dd868845d71781292eae17|\ -14d0cc4189c1f4fd7818c3393cc8c311) - # other_file = global_page_state(NR_FILE_PAGES); - V=2 -;; -59f3bb678a855acfea2365b7a904bc5b|\ -df96cbb1784869ac7d017dd343e4e8f2) - # other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM); - V=3 -;; -ed03b69361c2881ed1a031c9b9a24d8a|\ -8639aca416d3014d68548d6cb538405b) - # other_file = global_page_state(NR_FREE_PAGES) + global_page_state(NR_FILE_PAGES); - # (other_free not used, but max(other_free, other_file) = other_file in this - # case. - V=4 -;; -*) - V=0 -;; -esac - -echo "$MD5 $V" diff --git a/arch/arm/mvp/mvpkm/lpae_defs.h b/arch/arm/mvp/mvpkm/lpae_defs.h deleted file mode 100644 index 7729268..0000000 --- a/arch/arm/mvp/mvpkm/lpae_defs.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Large physical address extension definitions. - * - * See ARM PRD03-GENC-008469 11.0. - */ -#ifndef _LPAE_DEFS_H_ -#define _LPAE_DEFS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define ARM_LPAE_PT_ORDER 12 - -#define ARM_LPAE_PT_SIZE (1 << ARM_LPAE_PT_ORDER) -#define ARM_LPAE_ENTRY_ORDER 3 -#define ARM_LPAE_PT_ENTRIES_ORDER (ARM_LPAE_PT_ORDER - ARM_LPAE_ENTRY_ORDER) -#define ARM_LPAE_PT_ENTRIES (1 << ARM_LPAE_PT_ENTRIES_ORDER) - -#define ARM_LPAE_L1D_BLOCK_ORDER 30 -#define ARM_LPAE_L2D_BLOCK_ORDER 21 -#define ARM_LPAE_L3D_BLOCK_ORDER 12 - -#define ARM_LPAE_L1D_BLOCK_BITS (40 - ARM_LPAE_L1D_BLOCK_ORDER) -#define ARM_LPAE_L2D_BLOCK_BITS (40 - ARM_LPAE_L2D_BLOCK_ORDER) -#define ARM_LPAE_L3D_BLOCK_BITS (40 - ARM_LPAE_L3D_BLOCK_ORDER) - -/* - * Currently supporting up to 16GB PA spaces. - */ -#define ARM_LPAE_L1PT_INDX(addr) \ - MVP_EXTRACT_FIELD64(addr, ARM_LPAE_L1D_BLOCK_ORDER, 4) -#define ARM_LPAE_L2PT_INDX(addr) \ - MVP_EXTRACT_FIELD64(addr, ARM_LPAE_L2D_BLOCK_ORDER, ARM_LPAE_PT_ENTRIES_ORDER) -#define ARM_LPAE_L3PT_INDX(addr) \ - MVP_EXTRACT_FIELD64(addr, ARM_LPAE_L3D_BLOCK_ORDER, ARM_LPAE_PT_ENTRIES_ORDER) - -#define ARM_LPAE_L1D_BLOCK_BASE_ADDR(base) ((base) << ARM_LPAE_L1D_BLOCK_ORDER) -#define ARM_LPAE_L1D_BLOCK_ADDR_BASE(addr) ((addr) >> ARM_LPAE_L1D_BLOCK_ORDER) -#define ARM_LPAE_L2D_BLOCK_BASE_ADDR(base) ((base) << ARM_LPAE_L2D_BLOCK_ORDER) -#define ARM_LPAE_L2D_BLOCK_ADDR_BASE(addr) ((addr) >> ARM_LPAE_L2D_BLOCK_ORDER) -#define ARM_LPAE_L3D_BLOCK_BASE_ADDR(base) ((base) << ARM_LPAE_L3D_BLOCK_ORDER) -#define ARM_LPAE_L3D_BLOCK_ADDR_BASE(addr) ((addr) >> ARM_LPAE_L3D_BLOCK_ORDER) - -#define ARM_LPAE_TABLE_BASE_ADDR(base) ((base) << ARM_LPAE_PT_ORDER) -#define ARM_LPAE_TABLE_ADDR_BASE(addr) ((addr) >> ARM_LPAE_PT_ORDER) - -#define ARM_LPAE_TYPE_INVALID 0 -#define ARM_LPAE_TYPE_TABLE 3 -#define ARM_LPAE_L1D_TYPE_BLOCK 1 -#define ARM_LPAE_L2D_TYPE_BLOCK 1 -#define ARM_LPAE_L3D_TYPE_BLOCK 3 - -/** - * @name Second stage permission model. - * - * @{ - */ -#define ARM_LPAE_S2_PERM_NONE 0 -#define ARM_LPAE_S2_PERM_RO 1 -#define ARM_LPAE_S2_PERM_WO 2 -#define ARM_LPAE_S2_PERM_RW 3 -/*@}*/ - - -#endif /// ifndef _LPAE_DEFS_H_ diff --git a/arch/arm/mvp/mvpkm/lpae_types.h b/arch/arm/mvp/mvpkm/lpae_types.h deleted file mode 100644 index 292f0d9..0000000 --- a/arch/arm/mvp/mvpkm/lpae_types.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Large physical address extension types. - * - * See ARM PRD03-GENC-008469 11.0. - */ -#ifndef _LPAE_TYPES_H_ -#define _LPAE_TYPES_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "lpae_defs.h" - -/** - * @name ARM LPAE page table descriptors. See p7-8 ARM PRD03-GENC-008469 11.0. - * @{ - */ - -#define LOWER_PAGE_ATTRIBUTES_STAGE1 \ - uint64 attrIndx : 3; \ - uint64 ns : 1; \ - uint64 ap : 2; \ - uint64 sh : 2; \ - uint64 af : 1; \ - uint64 ng : 1; - -#define LOWER_PAGE_ATTRIBUTES_STAGE2 \ - uint64 memAttr : 4; \ - uint64 hap : 2; \ - uint64 sh : 2; \ - uint64 af : 1; \ - uint64 sbzL : 1; - -#define UPPER_PAGE_ATTRIBUTES_STAGE1 \ - uint64 contig : 1; \ - uint64 pxn : 1; \ - uint64 xn : 1; \ - uint64 sw : 4; \ - uint64 ignU : 5; - -#define UPPER_PAGE_ATTRIBUTES_STAGE2 \ - uint64 contig : 1; \ - uint64 sbzU : 1; \ - uint64 xn : 1; \ - uint64 sw : 4; \ - uint64 ignU : 5; - - -#define ARM_LPAE_DESC_TYPE(lvl,blen,sbzpad) \ - typedef union { \ - uint64 u; \ - \ - struct { \ - uint64 type : 2;\ - uint64 ign : 62; \ - } x; \ - \ - struct { \ - uint64 type : 2;\ - LOWER_PAGE_ATTRIBUTES_STAGE1 \ - sbzpad \ - uint64 base : blen; \ - uint64 sbz : 12; \ - UPPER_PAGE_ATTRIBUTES_STAGE1 \ - } blockS1; \ - \ - struct { \ - uint64 type : 2;\ - LOWER_PAGE_ATTRIBUTES_STAGE2 \ - sbzpad \ - uint64 base : blen; \ - uint64 sbz : 12; \ - UPPER_PAGE_ATTRIBUTES_STAGE2 \ - } blockS2; \ - \ - struct { \ - uint64 type : 2;\ - uint64 ign0 : 10; \ - uint64 base : 28; \ - uint64 sbz : 12; \ - uint64 ign1 : 7; \ - uint64 pxn : 1; \ - uint64 xn : 1; \ - uint64 ap : 2; \ - uint64 ns : 1; \ - } table; \ - \ - } ARM_LPAE_L##lvl##D; - - -ARM_LPAE_DESC_TYPE(1, ARM_LPAE_L1D_BLOCK_BITS, uint64 sbzP : 18;) -ARM_LPAE_DESC_TYPE(2, ARM_LPAE_L2D_BLOCK_BITS, uint64 sbzP : 9;) -ARM_LPAE_DESC_TYPE(3, ARM_LPAE_L3D_BLOCK_BITS, ) - -/*@}*/ - -#endif /// ifndef _LPAE_TYPES_H_ diff --git a/arch/arm/mvp/mvpkm/mksck.h b/arch/arm/mvp/mvpkm/mksck.h deleted file mode 100644 index aac00f7..0000000 --- a/arch/arm/mvp/mvpkm/mksck.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -#ifndef _MKSCK_H -#define _MKSCK_H - -/** - * @file - * - * @brief The monitor-kernel socket interface definitions. - * - * The monitor kernel socket interface was created for (what the name - * says) communications between the monitor and host processes. On the - * monitor side a special API is introduced, see mksck_vmm.h. On the - * host side the API is the standard Berkeley socket interface. Host - * process to host process or monitor to monitor communication is not - * supported. - * - * A generic address consists of two 16 bit fields: the vm id and the - * port id. Both hosts (vmx) and monitors (vmm) get their vm id - * automatically. The host vm id is assigned at the time the host - * process opens the mvpkm file descriptor, while the monitor vm id is - * assigned when the vmx.c:SetupWorldSwitchPage() calls - * Mvpkm_SetupIds(). As a vmx may create multiple monitors to service - * an MP guest, a vmx vm id may be associated with multiple monitor vm - * ids. A monitor id, however, has a single associated vmx host id, - * the id of its canonical vmx. - * - * Sockets on the host get their addresses either by explicit user - * call (the bind command) or implicitly by (issuing a send command - * first). At an explicit bind the user may omit one or both fields by - * providing MKSCK_VMID_UNDEF/MKSCK_PORT_UNDEF respectively. An - * implicit bind behaves as if both fields were omitted in an explicit - * bind. The default value of the vmid field is the vmid computed from - * the thread group id while that of a port is a new number. It is not - * invalid to bind a host process socket with a vm id different from - * the vmid computed from the tgid. - * - * Sockets of the monitor are automatically assigned a vmid, that of their - * monitor, at the time of their creation. The port id can be assigned by the - * user or left to the implementation to assign an unused one (by specifying - * MKSCK_PORT_UNDEF at @ref Mksck_Open). - * - * Host unconnected sockets may receive from any monitor sender, may send to any - * monitor socket. A socket can be connected to a peer address, that enables the - * use of the send command. - * - * One of many special predefined port (both host and monitor) is - * MKSCK_PORT_MASTER. It is used for initialization. - * - * Monitor sockets have to send their peer address explicitly (by - * Mksck_SetPeer()) or implicitly by receiving first. After the peer - * is set, monitor sockets may send or receive only to/from their - * peer. - */ - - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "vmid.h" - -/* - * The interface limits the size of transferable packets. - */ -#define MKSCK_XFER_MAX 1024 - -#define MKSCK_ADDR_UNDEF (uint32)0xffffffff - -#define MKSCK_PORT_UNDEF (uint16)0xffff -#define MKSCK_PORT_MASTER (MKSCK_PORT_UNDEF-1) -#define MKSCK_PORT_HOST_FB (MKSCK_PORT_UNDEF-2) -#define MKSCK_PORT_BALLOON (MKSCK_PORT_UNDEF-3) -#define MKSCK_PORT_HOST_HID (MKSCK_PORT_UNDEF-4) -#define MKSCK_PORT_CHECKPOINT (MKSCK_PORT_UNDEF-5) -#define MKSCK_PORT_COMM_EV (MKSCK_PORT_UNDEF-6) -#define MKSCK_PORT_HIGH (MKSCK_PORT_UNDEF-7) - -#define MKSCK_VMID_UNDEF VMID_UNDEF -#define MKSCK_VMID_HIGH (MKSCK_VMID_UNDEF-1) - -#define MKSCK_DETACH 3 - -typedef uint16 Mksck_Port; -typedef VmId Mksck_VmId; - -/** - * @brief Page descriptor for typed messages. Each page describes a region of - * the machine address space with base mpn and size 2^(12 + order) bytes. - */ -typedef struct { - uint32 mpn : 20; ///< Base MPN of region described by page - uint32 order : 12; ///< Region is 2^(12 + order) bytes. -} Mksck_PageDesc; - -/** - * @brief Typed message template macro. Allows us to avoid having two message - * types, one with page descriptor vector (for VMM), one without (for - * VMX). - * - * @param type C type of uninterpreted component of the message (following the - * page descriptor vector). - * @param pages number of page descriptors in vector. - */ -#define MKSCK_DESC_TYPE(type,pages) \ - struct { \ - type umsg; \ - Mksck_PageDesc page[pages]; \ - } - -/** - * @brief The monitor kernel socket interface address format - */ -typedef union { - uint32 addr; ///< the address - struct { /* The address is decomposed to two shorts */ - Mksck_Port port; ///< port unique within a vmid - Mksck_VmId vmId; ///< unique vmid - }; -} Mksck_Address; - -static inline uint32 -Mksck_AddrInit(Mksck_VmId vmId, Mksck_Port port) -{ - Mksck_Address aa; - aa.vmId = vmId; - aa.port = port; - return aa.addr; -} -#endif diff --git a/arch/arm/mvp/mvpkm/mksck_kernel.c b/arch/arm/mvp/mvpkm/mksck_kernel.c deleted file mode 100644 index 6811a68..0000000 --- a/arch/arm/mvp/mvpkm/mksck_kernel.c +++ /dev/null @@ -1,2589 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The monitor/kernel socket interface kernel extension. - */ - -#define __KERNEL_SYSCALLS__ -#include <linux/version.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/fcntl.h> -#include <linux/syscalls.h> -#include <linux/kmod.h> -#include <linux/socket.h> -#include <linux/net.h> -#include <linux/skbuff.h> -#include <linux/miscdevice.h> -#include <linux/poll.h> -#include <linux/rcupdate.h> -#include <linux/smp.h> -#include <linux/spinlock.h> - -#include <linux/mm.h> -#include <linux/mman.h> -#include <linux/file.h> -#include <linux/vmalloc.h> - -#include <linux/debugfs.h> -#include <linux/seq_file.h> - -#include <net/sock.h> - -#include <asm/memory.h> -#include <asm/system.h> -#include <asm/uaccess.h> - -#include "mvp.h" -#include "actions.h" -#include "mvpkm_kernel.h" -#include "mksck_kernel.h" -#include "mksck_sockaddr.h" -#include "mutex_kernel.h" - -void NORETURN FatalError(char const *file, - int line, - FECode feCode, - int bugno, - char const *fmt, - ...) -{ - /* Lock around printing the error details so that the messages from multiple - * threads are not interleaved. */ - static DEFINE_MUTEX(fatalErrorMutex); - mutex_lock(&fatalErrorMutex); - - FATALERROR_COMMON(printk, vprintk, file, line, feCode, bugno, fmt); - - dump_stack(); - - /* done printing */ - mutex_unlock(&fatalErrorMutex); - - /* do_exit below exits the current thread but does not crash the kernel. - * Hence the stack dump will actually be readable from other user threads. - */ - do_exit(1); -} - - -/* - * The project uses a new address family: AF_MKSCK. Optimally this address - * family were accepted with the Linux community and a permanent number - * were assigned. This, however, is a dream only, not even the x86 team - * has been able to pull it off. - * - * Instead we ASSUME that DECnet is dead and re-use it's address family number. - * This is what the x86 world is moving too in the latest versions. - */ - -static struct proto mksckProto = { - .name = "AF_MKSCK", - .owner = THIS_MODULE, - .obj_size = sizeof (struct sock), -}; - -static int MksckCreate(struct net *net, - struct socket *sock, - int protocol, - int kern); - -static struct net_proto_family mksckFamilyOps = { - .family = AF_MKSCK, - .owner = THIS_MODULE, - .create = MksckCreate, -}; - -static int MksckFault(struct vm_area_struct *vma, struct vm_fault *vmf); - - -/** - * @brief Linux vma operations for receive windows established via Mksck - * mmap. - */ -static struct vm_operations_struct mksckVMOps = { - .fault = MksckFault -}; - -/* - * List of hosts and guests we know about. - */ -static spinlock_t mksckPageListLock; -static MksckPage *mksckPages[MKSCK_MAX_SHARES]; - -/* - * The following functions form the AF_MKSCK DGRAM operations. - */ -static int MksckRelease(struct socket *sock); -static int MksckBacklogRcv(struct sock *sk, struct sk_buff *skb); -static void MksckSkDestruct(struct sock *sk); -static int MksckBind(struct socket *sock, - struct sockaddr *addr, - int addrLen); -static int MksckBindGeneric(struct sock *sk, - Mksck_Address addr); -static int MksckDgramRecvMsg(struct kiocb *kiocb, - struct socket *sock, - struct msghdr *msg, - size_t len, - int flags); -static int MksckDgramSendMsg(struct kiocb *kiocb, - struct socket *sock, - struct msghdr *msg, - size_t len); -static int MksckGetName(struct socket *sock, - struct sockaddr *addr, - int *addrLen, - int peer); -static unsigned int MksckPoll(struct file *filp, - struct socket *sock, - poll_table *wait); -static int MksckDgramConnect(struct socket *sock, - struct sockaddr *addr, - int addrLen, - int flags); -static int MksckMMap(struct file *file, - struct socket *sock, - struct vm_area_struct *vma); - -static void MksckPageRelease(MksckPage *mksckPage); - -static struct proto_ops mksckDgramOps = { - .family = AF_MKSCK, - .owner = THIS_MODULE, - .release = MksckRelease, - .bind = MksckBind, - .connect = MksckDgramConnect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = MksckGetName, - .poll = MksckPoll, - .ioctl = sock_no_ioctl, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, /* MksckShutdown, */ - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .sendmsg = MksckDgramSendMsg, - .recvmsg = MksckDgramRecvMsg, - .mmap = MksckMMap, - .sendpage = sock_no_sendpage, -}; - - -/** - * @brief Initialize the MKSCK protocol - * - * @return 0 on success, -errno on failure - */ -int -Mksck_Init(void) -{ - int err; - - spin_lock_init(&mksckPageListLock); - - /* - * Create a slab to allocate socket structs from. - */ - err = proto_register(&mksckProto, 1); - if (err != 0) { - printk(KERN_INFO - "Mksck_Init: Cannot register MKSCK protocol, errno = %d.\n", err); - return err; - } - - /* - * Register the socket family - */ - err = sock_register(&mksckFamilyOps); - if (err < 0) { - printk(KERN_INFO - "Mksck_Init: Could not register address family AF_MKSCK" - " (errno = %d).\n", err); - return err; - } - - return 0; -} - - -/** - * @brief De-register the MKSCK protocol - */ -void -Mksck_Exit(void) -{ - sock_unregister(mksckFamilyOps.family); - proto_unregister(&mksckProto); -} - - -/** - * @brief Create a new MKSCK socket - * - * @param net network namespace (2.6.24 or above) - * @param sock user socket structure - * @param protocol protocol to be used - * @param kern called from kernel mode - * - * @return 0 on success, -errno on failure - */ -static int -MksckCreate(struct net *net, - struct socket *sock, - int protocol, - int kern) -{ - struct sock *sk; - uid_t currentUid = current_euid(); - - if (!(currentUid == 0 || - currentUid == Mvpkm_vmwareUid)) { - printk(KERN_WARNING - "MksckCreate: rejected from process %s tgid=%d, pid=%d euid:%d.\n", - current->comm, - task_tgid_vnr(current), - task_pid_vnr(current), - currentUid); - return -EPERM; - } - - if (!sock) { - return -EINVAL; - } - - if (protocol) { - return -EPROTONOSUPPORT; - } - - switch (sock->type) { - case SOCK_DGRAM: { - sock->ops = &mksckDgramOps; - break; - } - default: { - return -ESOCKTNOSUPPORT; - } - } - - sock->state = SS_UNCONNECTED; - - /* - * Most recently (in 2.6.24), sk_alloc() was changed to expect the - * network namespace, and the option to zero the sock was dropped. - */ - sk = sk_alloc(net, mksckFamilyOps.family, GFP_KERNEL, &mksckProto); - - if (!sk) { - return -ENOMEM; - } - - sock_init_data(sock, sk); - - sk->sk_type = SOCK_DGRAM; - sk->sk_destruct = MksckSkDestruct; - sk->sk_backlog_rcv = MksckBacklogRcv; - - /* - * On socket lock... - * - * A bound socket will have an associated private area, the Mksck - * structure part of MksckPage. That area is pointed to by - * sk->sk_protinfo. In addition, a connected socket will have the - * peer field in its associated area set to point to the associated - * private area of the peer socket. A mechanism is needed to ensure - * that these private areas area not freed while they are being - * accessed within the scope of a function. A simple lock would not - * suffice as the interface functions (like MksckDgramRecvMsg()) - * may block. Hence a reference count mechanism is employed. When - * the mentioned references (sk->sk_protinfo and mksck->peer) to - * the respective private areas are set a refcount is incremented, - * and decremented when the references are deleted. - * - * The refcounts of areas pointed to by sk->sk_protinfo and - * mksck->peer will be decremented under the lock of the socket. - * Hence these private areas cannot disappear as long as the socket - * lock is held. - * - * The interface functions will have one of the following - * structures: - * - * simpleFn(sk) - * { - * lock_sock(sk); - * if ((mksck = sk->sk_protinfo)) { - * <non-blocking use of mksck> - * } - * release_sock(sk); - * } - * - * complexFn(sk) - * { - * lock_sock(sk); - * if ((mksck = sk->sk_protinfo)) { - * IncRefc(mksck); - * } - * release_sock(sk); - * - * if (mksck) { - * <use of mksck in a potentially blocking manner> - * DecRefc(mksck); - * } - * } - */ - sk->sk_protinfo = NULL; - sock_reset_flag(sk, SOCK_DONE); - - return 0; -} - - -/** - * @brief Delete a MKSCK socket - * - * @param sock user socket structure - * - * @return 0 on success, -errno on failure - */ -static int -MksckRelease(struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (sk) { - lock_sock(sk); - sock_orphan(sk); - release_sock(sk); - sock_put(sk); - } - - sock->sk = NULL; - sock->state = SS_FREE; - - return 0; -} - - -static int -MksckBacklogRcv(struct sock *sk, struct sk_buff *skb) -{ - /* - * We should never get these as we never queue an skb. - */ - printk("MksckBacklogRcv: should never get here\n"); - return -EIO; -} - - -/** - * @brief Callback at socket destruction - * - * @param sk pointer to kernel socket structure - */ -static void -MksckSkDestruct(struct sock *sk) -{ - Mksck *mksck; - - lock_sock(sk); - mksck = sk->sk_protinfo; - - if (mksck != NULL) { - sk->sk_protinfo = NULL; - Mksck_CloseCommon(mksck); - } - - if (sk->sk_user_data != NULL) { - sock_kfree_s(sk, sk->sk_user_data, sizeof(int)); - sk->sk_user_data = NULL; - } - - release_sock(sk); -} - - -/** - * @brief Set the local address of a MKSCK socket - * - * @param sk kernel socket structure - * @param addr the new address of the socket - * - * @return 0 on success, -errno on failure - * - * If addr.port is undefined a new random port is assigned. - * If addr.vmId is undefined then the vmId computed from the tgid is used. - * Hence the vmId of a socket does not determine the host all the time. - * - * Assumed that the socket is locked. - * This function is called by explicit set (MksckBind) and implicit (Send). - */ -static int -MksckBindGeneric(struct sock *sk, - Mksck_Address addr) -{ - int err; - Mksck *mksck; - MksckPage *mksckPage; - - if (sk->sk_protinfo != NULL) { - return -EISCONN; - } - - /* - * Locate the page for the given host and increment its reference - * count so it can't get freed off while we are working on it. - */ - if (addr.vmId == MKSCK_VMID_UNDEF) { - mksckPage = MksckPage_GetFromTgidIncRefc(); - } else { - printk(KERN_WARNING "MksckBind: host bind called on vmid 0x%X\n", addr.vmId); - mksckPage = MksckPage_GetFromVmIdIncRefc(addr.vmId); - } - - if (mksckPage == NULL) { - printk(KERN_INFO "MksckBind: no mksckPage for vm 0x%X\n", addr.vmId); - return -ENETUNREACH; - } - addr.vmId = mksckPage->vmId; - - /* - * Before we can find an unused socket port on the page we have to - * lock the page for exclusive access so another thread can't - * allocate the same port. - */ - err = Mutex_Lock(&mksckPage->mutex, MutexModeEX); - if (err < 0) { - goto outDec; - } - - addr.port = MksckPage_GetFreePort(mksckPage, addr.port); - if (addr.port == MKSCK_PORT_UNDEF) { - err = -EINVAL; - goto outUnlockDec; - } - - /* - * At this point we have the mksckPage locked for exclusive access - * and its reference count incremented. Also, addr is completely - * filled in with vmId and port that we want to bind. - * - * Find an available mksck struct on the shared page and initialize - * it. - */ - mksck = MksckPage_AllocSocket(mksckPage, addr); - if (mksck == NULL) { - err = -EMFILE; - goto outUnlockDec; - } - - /* - * Stable, release mutex. Leave mksckPage->refCount incremented so - * mksckPage can't be freed until socket is closed. - */ - Mutex_Unlock(&mksckPage->mutex, MutexModeEX); - - /* - * This is why we start mksck->refCount at 1. When sk_protinfo gets - * cleared, we decrement mksck->refCount. - */ - sk->sk_protinfo = mksck; - - PRINTK(KERN_DEBUG "MksckBind: socket bound to %08X\n", mksck->addr.addr); - - return 0; - -outUnlockDec: - Mutex_Unlock(&mksckPage->mutex, MutexModeEX); -outDec: - MksckPage_DecRefc(mksckPage); - return err; -} - - -/** - * @brief Test if the socket is already bound to a local address and, - * if not, bind it to an unused address. - * - * @param sk kernel socket structure - * @return 0 on success, -errno on failure - * - * Assumed that the socket is locked. - */ -static inline int -MksckTryBind(struct sock *sk) -{ - int err = 0; - - if (!sk->sk_protinfo) { - static const Mksck_Address addr = { .addr = MKSCK_ADDR_UNDEF }; - err = MksckBindGeneric(sk, addr); - } - return err; -} - - - -/** - * @brief Set the address of a MKSCK socket (user call) - * - * @param sock user socket structure - * @param addr the new address of the socket - * @param addrLen length of the address - * - * @return 0 on success, -errno on failure - */ -static int -MksckBind(struct socket *sock, - struct sockaddr *addr, - int addrLen) -{ - int err; - struct sock *sk = sock->sk; - struct sockaddr_mk *addrMk = (struct sockaddr_mk *)addr; - - if (addrLen != sizeof *addrMk) { - return -EINVAL; - } - if (addrMk->mk_family != AF_MKSCK) { - return -EAFNOSUPPORT; - } - - /* - * Obtain the socket lock and call the generic Bind function. - */ - lock_sock(sk); - err = MksckBindGeneric(sk, addrMk->mk_addr); - release_sock(sk); - - return err; -} - -/** - * @brief Lock the peer socket by locating it, incrementing its refc - * @param addr the address of the peer socket - * @param[out] peerMksckR set to the locked peer socket pointer - * upon successful lookup - * @return 0 on success, -errno on failure - */ -static int -LockPeer(Mksck_Address addr, Mksck **peerMksckR) -{ - int err = 0; - MksckPage *peerMksckPage = MksckPage_GetFromVmIdIncRefc(addr.vmId); - Mksck *peerMksck; - - /* - * Find corresponding destination shared page and increment its - * reference count so it can't be freed while we are sending to the - * socket. Make sure that the address is indeed an address of a - * monitor/guest socket. - */ - if (peerMksckPage == NULL) { - printk(KERN_INFO "LockPeer: vmId %x is not in use!\n", addr.vmId); - return -ENETUNREACH; - } - if (!peerMksckPage->isGuest) { - MksckPage_DecRefc(peerMksckPage); - printk(KERN_INFO "LockPeer: vmId %x does not belong to a guest!\n", - addr.vmId); - return -ENETUNREACH; - } - - - err = Mutex_Lock(&peerMksckPage->mutex, MutexModeSH); - if (err < 0) { - MksckPage_DecRefc(peerMksckPage); - return err; - } - - /* - * Find corresponding destination socket on that shared page and - * increment its reference count so it can't be freed while we are - * trying to send to it. - */ - peerMksck = MksckPage_GetFromAddr(peerMksckPage, addr); - - if (peerMksck) { - ATOMIC_ADDV(peerMksck->refCount, 1); - *peerMksckR = peerMksck; - } else { - printk(KERN_INFO "LockPeer: addr %x is not a defined socket!\n", - addr.addr); - err = -ENETUNREACH; - } - - Mutex_Unlock(&peerMksckPage->mutex, MutexModeSH); - MksckPage_DecRefc(peerMksckPage); - return err; -} - -/** - * @brief Set the peer address of a MKSCK socket - * - * @param sock user socket structure - * @param addr the new address of the socket - * @param addrLen length of the address - * @param flags flags - * - * @return 0 on success, -errno on failure - */ -static int -MksckDgramConnect(struct socket *sock, - struct sockaddr *addr, - int addrLen, - int flags) -{ - struct sock *sk = sock->sk; - Mksck *mksck; - struct sockaddr_mk *peerAddrMk = (struct sockaddr_mk *)addr; - int err = 0; - - if (addrLen != sizeof *peerAddrMk) { - printk(KERN_INFO "MksckConnect: wrong address length!\n"); - return -EINVAL; - } - if (peerAddrMk->mk_family != AF_MKSCK) { - printk(KERN_INFO "MksckConnect: wrong address family!\n"); - return -EAFNOSUPPORT; - } - - lock_sock(sk); - - if ((err = MksckTryBind(sk))) { - goto releaseSock; - } - mksck = sk->sk_protinfo; - - /* - * First severe any past peer connections - */ - Mksck_DisconnectPeer(mksck); - sock->state = SS_UNCONNECTED; - - /* - * Then build new connections ... - */ - if (peerAddrMk->mk_addr.addr != MKSCK_ADDR_UNDEF) { - sock->state = SS_CONNECTED; - mksck->peerAddr = peerAddrMk->mk_addr; - err = LockPeer(mksck->peerAddr, &mksck->peer); - PRINTK(KERN_DEBUG "MksckConnect: socket %x is connected to %x!\n", - mksck->addr.addr, mksck->peerAddr.addr); - } - -releaseSock: - release_sock(sk); - - return err; -} - - -/** - * @brief returns the address of a MKSCK socket/peer address - * - * @param sock user socket structure - * @param addr the new address of the socket - * @param addrLen length of the address - * @param peer 1 if the peer address is sought - * - * @return 0 on success, -errno on failure - */ -static int -MksckGetName(struct socket *sock, - struct sockaddr *addr, - int *addrLen, - int peer) -{ - int err; - Mksck *mksck; - struct sock *sk = sock->sk; - - // MAX_SOCK_ADDR is size of *addr, Linux doesn't export it! - // ASSERT_ON_COMPILE(sizeof (struct sockaddr_mk) <= MAX_SOCK_ADDR); - - lock_sock(sk); - mksck = sk->sk_protinfo; - - if (mksck == NULL) { - if (peer) { - err = -ENOTCONN; - } else { - ((struct sockaddr_mk *)addr)->mk_family = AF_MKSCK; - ((struct sockaddr_mk *)addr)->mk_addr.addr = MKSCK_ADDR_UNDEF; - *addrLen = sizeof (struct sockaddr_mk); - err = 0; - } - } else if (!peer) { - ((struct sockaddr_mk *)addr)->mk_family = AF_MKSCK; - ((struct sockaddr_mk *)addr)->mk_addr = mksck->addr; - *addrLen = sizeof (struct sockaddr_mk); - err = 0; - } else if (mksck->peerAddr.addr == MKSCK_ADDR_UNDEF) { - err = -ENOTCONN; - } else { - ((struct sockaddr_mk *)addr)->mk_family = AF_MKSCK; - ((struct sockaddr_mk *)addr)->mk_addr = mksck->peerAddr; - *addrLen = sizeof (struct sockaddr_mk); - err = 0; - } - - release_sock(sk); - - return err; -} - - -/** - * @brief VMX polling a receipted packet from VMM. - * - * @param filp kernel file pointer to poll for - * @param sock user socket structure - * @param wait kernel polling table where to poll if not null - * - * @return poll mask state given from socket state. - */ -static unsigned int MksckPoll(struct file *filp, - struct socket *sock, - poll_table *wait) -{ - struct sock *sk = sock->sk; - unsigned int mask = 0; - Mksck *mksck = NULL; - uint32 read; - int err; - - lock_sock(sk); - if ((err = MksckTryBind(sk))) { - release_sock(sk); - return err; - } - mksck = sk->sk_protinfo; - - /* - * To avoid mksck disappearing right after the release_sock the - * refcount needs to be incremented. For more details read the - * block comment on locking in MksckCreate. - */ - ATOMIC_ADDV(mksck->refCount, 1); - release_sock(sk); - - /* - * Wait to make sure this is the only thread trying to access socket. - */ - if ((err = Mutex_Lock(&mksck->mutex, MutexModeEX)) < 0) { - /* we might get in this situation if we are signaled - (select() may handle this, so leave) */ - PRINTK(KERN_INFO "MksckPoll: try to abort\n"); - return mask; - } - - /* - * See if packet in ring. - */ - read = mksck->read; - if (read != mksck->write) { - mask |= POLLIN | POLLRDNORM; /* readable, socket is unlocked */ - /* Note that if we are implementing support for POLLOUT, we SHOULD - change this Mutex_Unlock by Mutex_UnlPoll, because there is no - obvious knowledge about the sleepy reason that is intended by user */ - Mutex_Unlock(&mksck->mutex, MutexModeEX); - } else { - Mutex_UnlPoll(&mksck->mutex, MutexModeEX, MKSCK_CVAR_FILL, filp, wait); - } - - /* - * Note that locking rules differ a little inside MksckPoll, since we are - * not only given a pointer to the struct socket but also a pointer to a - * struct file. This means that during the whole operation of this function - * and during any pending wait (registered with poll_wait()), the file itself - * is reference counted up, and we should rely on that 'upper' reference - * counting to prevent from tearing the Mksck down. That holds true since one - * never re-bind sockets ! - */ - Mksck_DecRefc(mksck); - return mask; -} - -/** - * @brief Manage a set of Mksck_PageDesc from a message or a stored array. - * - * @param pd set of Mksck_PageDesc - * @param pages Mksck_PageDesc pages count for this management operation - * @param incr ternary used to indicate if we want to reference (+1), or - * dereference (-1), or count (0) 4k pages - * - * @return length of bytes processed. - */ -static size_t -MksckPageDescManage(Mksck_PageDesc *pd, - uint32 pages, - int incr) -{ - size_t payloadLen = 0; - uint32 i; - - for (i = 0; i < pages && pd[i].mpn != INVALID_MPN; ++i) { - uint32 j; - - for (j = 0; j < 1 << pd[i].order; ++j) { - struct page *page; - MPN currMPN = pd[i].mpn + j; - - /* - * The monitor tried to send an invalid MPN, bad. - */ - if (!pfn_valid(currMPN)) { - printk("MksckPageDescManage: Invalid MPN %x\n", currMPN); - } else { - page = pfn_to_page(currMPN); - - if (incr == +1) { - get_page(page); - } - if (incr == -1) { - put_page(page); - } - } - - payloadLen += PAGE_SIZE; - } - } - - return payloadLen; -} - -/** - * @brief Management values to be used as third parameter of MksckPageDescManage - */ -#define MANAGE_INCREMENT +1 -#define MANAGE_DECREMENT -1 -#define MANAGE_COUNT 0 - - -/** - * @brief Map a set of Mksck_PageDesc from a message or a stored array. - * - * @param pd set of Mksck_PageDesc - * @param pages pages count for this mapping - * @param iov vectored user virtual addresses of the recv commands - * @param iovCount size for iov parameter - * @param vma virtual memory area used for the mapping, note that - * this is mandatorily required MksckPageDescMap is used - * on an indirect PageDesc context (i.e whenever iov is - * not computed by the kernel but by ourselves). - * - * Since find_vma() and vm_insert_page() are used, this function must - * be called with current's mmap_sem locked, or inside an MMap operation. - * - * @return length of bytes mapped. - */ -static size_t -MksckPageDescMap(Mksck_PageDesc *pd, - uint32 pages, - struct iovec *iov, - int iovCount, - struct vm_area_struct *vma) -{ - size_t payloadLen = 0; - uint32 i; - - for (i = 0; i < pages && pd[i].mpn != INVALID_MPN; ++i) { - uint32 j; - - for (j = 0; j < 1 << pd[i].order; ++j) { - HUVA huva = 0; - struct page *page; - MPN currMPN = pd[i].mpn + j; - - while (iovCount > 0 && iov->iov_len == 0) { - iovCount--; - iov++; - } - - if (iovCount == 0) { - printk("MksckPageDescMap: Invalid iov length\n"); - goto map_done; - } - - huva = (HUVA)iov->iov_base; - - /* - * iovecs for receiving the typed component of the message should - * have page aligned base and size sufficient for page descriptor's - * mappings. - */ - if (huva & (PAGE_SIZE - 1) || iov->iov_len < PAGE_SIZE) { - printk("MksckPageDescMap: Invalid huva %x or iov_len %d\n", - huva, - iov->iov_len); - goto map_done; - } - - /* - * Might be in a new vma... - */ - if (vma == NULL || huva < vma->vm_start || huva >= vma->vm_end) { - vma = find_vma(current->mm, huva); - - /* - * Couldn't find a matching vma for huva. - */ - if (vma == NULL || - huva < vma->vm_start || - vma->vm_ops != &mksckVMOps) { - printk("MksckPageDescMap: Invalid vma\n"); - goto map_done; - } - } - - /* - * The monitor tried to send an invalid MPN, bad. - */ - if (!pfn_valid(currMPN)) { - printk("MksckPageDescMap: Invalid MPN %x\n", currMPN); - } else { - int rc; - - page = pfn_to_page(currMPN); - - /* - * Map into the receive window. - */ - rc = vm_insert_page(vma, huva, page); - if (rc) { - printk("MksckPageDescMap: Failed to insert %x at %x, error %d\n", - currMPN, - huva, - rc); - goto map_done; - } - - ASSERT(iov->iov_len >= PAGE_SIZE); - iov->iov_base += PAGE_SIZE; - iov->iov_len -= PAGE_SIZE; - } - - payloadLen += PAGE_SIZE; - } - } - -map_done: - return payloadLen; -} - - -/** - * @brief Check if the provided MsgHdr has still room for a receive operation. - * - * @param msg user buffer - * @return 1 if MsgHdr has IO space room in order to receive a mapping, 0 otherwise. - */ -static int -MsgHdrHasAvailableRoom(struct msghdr *msg) -{ - struct iovec *vec = msg->msg_iov; - uint32 count = msg->msg_iovlen; - - while (count > 0 && vec->iov_len == 0) { - count--; - vec++; - } - - return (count != 0); -} - - -/** - * Whenever a typed message is received from the monitor, we may choose to store - * all the page descriptor content in a linked state of descriptors, through the - * following information context - */ -typedef struct MksckPageDescInfo { - struct MksckPageDescInfo *next; - uint32 flags; - uint32 pages; - uint32 mapCounts; - Mksck_PageDesc descs[0]; -} MksckPageDescInfo; - -static void MksckPageDescSkDestruct(struct sock *sk); -static int MksckPageDescMMap(struct file *file, - struct socket *sock, - struct vm_area_struct *vma); -static int MksckPageDescIoctl(struct socket *sock, - unsigned int cmd, - unsigned long arg); - -/** - * @brief Delete a page descriptor container socket - * - * @param sock user socket structure - * @return 0 on success, -errno on failure - */ -static int -MksckPageDescRelease(struct socket *sock) -{ - /* This is generic socket release */ - struct sock *sk = sock->sk; - - if (sk) { - lock_sock(sk); - sock_orphan(sk); - release_sock(sk); - sock_put(sk); - } - - sock->sk = NULL; - sock->state = SS_FREE; - - return 0; -} - - -/** - * Whenever a typed message is received from the monitor, we may choose to store - * all the page descriptor content for a future mapping. One shall put a context - * usable by host userland, that means trough a file descriptor, and as a secure - * implementation we choose to define a strict set of operations that are used - * only for that purpose. This set of operation is reduced to leaving the - * default "PageDesc(s) accumulating" mode (inside ioctl), mapping the context, - * and generic socket destruction. - */ -static struct proto_ops mksckPageDescOps = { - .family = AF_MKSCK, - .owner = THIS_MODULE, - .release = MksckPageDescRelease, - .bind = sock_no_bind, - .connect = sock_no_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = sock_no_getname, - .poll = sock_no_poll, - .ioctl = MksckPageDescIoctl, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .sendmsg = sock_no_sendmsg, - .recvmsg = sock_no_recvmsg, - .mmap = MksckPageDescMMap, - .sendpage = sock_no_sendpage, -}; - - -/** - * @brief Create or accumulate to a PageDesc context, backed as a descriptor. - * - * @param sock user socket structure - * @param msg user buffer to receive the file descriptor as ancillary data - * @param pd source descriptor part of a message - * @param pages pages count for this mapping - * - * @return error if negative, 0 otherwise - * - */ -static int -MksckPageDescToFd(struct socket *sock, - struct msghdr *msg, - Mksck_PageDesc *pd, - uint32 pages) -{ - int retval; - int newfd; - struct socket *newsock; - struct sock *newsk; - struct sock *sk = sock->sk; - MksckPageDescInfo **pmpdi, *mpdi; - lock_sock(sk); - - /* - * Relation between any mk socket and the PageDesc context is as follow: - * - * From the mk socket to the PageDesc context: - * - sk->sk_user_data is a WEAK LINK, containing only a file descriptor - * numerical value such that accumulating is keyed on it. - * - * From the PageDesc context to the mk socket: - * - sk->sk_protinfo contains a MksckPageDescInfo struct. - * - sk->sk_user_data is a pointer REF-COUNTED sock_hold() LINK, also it is - * rarely dereferenced but usually used to check that the - * right socket pair is used. Full dereferencing is used - * only to break the described links. - */ - if (sk->sk_user_data) { - MksckPageDescInfo *mpdi2; - - /* continue any previous on-going mapping, i.e accumulate */ - newfd = *((int *)sk->sk_user_data); - newsock = sockfd_lookup(newfd, &retval); // promote the weak link - if (!newsock) { - retval = -EINVAL; - goto endProcessingReleaseSock; - } - - newsk = newsock->sk; - lock_sock(newsk); - sockfd_put(newsock); - - if (((struct sock *)newsk->sk_user_data) != sk) { - /* One way of going into this situation would be for userland to dup - the file descriptor just received, close the original number, and - open a new mk socket in the very same spot. The userland code have - a lot of way of interacting with the kernel without this driver - code to be notified. */ - retval = -EINVAL; - release_sock(newsk); - goto endProcessingReleaseSock; - } - - mpdi = sock_kmalloc(newsk, sizeof(MksckPageDescInfo) + - pages*sizeof(Mksck_PageDesc), GFP_KERNEL); - if (IS_ERR(mpdi)) { - retval = PTR_ERR(mpdi); - release_sock(newsk); - goto endProcessingReleaseSock; - } - - /* There is no mandatory needs for us to notify userland from - the progress in "appending" to the file descriptor, but it - would feel strange if the userland would have no mean to - tell if the received message was just not thrown away. So, in - order to be consistent one fill the ancillary message while - "creating" and "appending to" file descriptors. */ - retval = put_cmsg(msg, SOL_DECNET, 0, sizeof(int), &newfd); - if (retval < 0) { - goto endProcessingKFreeReleaseSock; - } - - release_sock(sk); - - mpdi2 = (MksckPageDescInfo *)newsk->sk_protinfo; - while (mpdi2->next) { - mpdi2 = mpdi2->next; - } - pmpdi = &(mpdi2->next); - - } else { - /* Create a new socket, new context and a new file descriptor. */ - retval = sock_create(sk->sk_family, sock->type, 0, &newsock); - if (retval < 0) { - goto endProcessingReleaseSock; - } - - newsk = newsock->sk; - lock_sock(newsk); - newsk->sk_destruct = &MksckPageDescSkDestruct; - newsk->sk_user_data = sk; - sock_hold(sk); // keeps a reference to parent mk socket - newsock->ops = &mksckPageDescOps; - - mpdi = sock_kmalloc(newsk, sizeof(MksckPageDescInfo) + - pages*sizeof(Mksck_PageDesc), GFP_KERNEL); - if (IS_ERR(mpdi)) { - retval = PTR_ERR(mpdi); - goto endProcessingFreeNewSock; - } - - sk->sk_user_data = sock_kmalloc(sk, sizeof(int), GFP_KERNEL); - if (IS_ERR(sk->sk_user_data)) { - retval = PTR_ERR(sk->sk_user_data); - sk->sk_user_data = NULL; - goto endProcessingKFreeAndNewSock; - } - - /* mapping to a file descriptor may fail if a thread is closing - in parallel of sock_map_fd/sock_alloc_fd, or kernel memory is full */ - newfd = sock_map_fd(newsock, O_CLOEXEC); - if (newfd < 0) { - retval = newfd; - sock_kfree_s(sk, sk->sk_user_data, sizeof(int)); - sk->sk_user_data = NULL; - goto endProcessingKFreeAndNewSock; - } - - /* notify userland from a new file descriptor, alike AF_UNIX ancillary */ - retval = put_cmsg(msg, SOL_DECNET, 0, sizeof(int), &newfd); - if (retval < 0) { - sock_kfree_s(sk, sk->sk_user_data, sizeof(int)); - sk->sk_user_data = NULL; - sock_kfree_s(newsk, mpdi, sizeof(MksckPageDescInfo) + - mpdi->pages*sizeof(Mksck_PageDesc)); - release_sock(newsk); - sockfd_put(newsock); - sock_release(newsock); - put_unused_fd(newfd); - goto endProcessingReleaseSock; - } - - *(int*)sk->sk_user_data = newfd; - release_sock(sk); - pmpdi = (MksckPageDescInfo **)(&(newsk->sk_protinfo)); - } - - mpdi->next = NULL; - mpdi->flags = 0; - mpdi->mapCounts = 0; - mpdi->pages = pages; - memcpy(mpdi->descs, pd, pages*sizeof(Mksck_PageDesc)); - - *pmpdi = mpdi; // link - release_sock(newsk); - - /* increment all reference counters for the pages */ - MksckPageDescManage(pd, pages, MANAGE_INCREMENT); - return 0; - -endProcessingKFreeAndNewSock: - sock_kfree_s(newsk, mpdi, sizeof(MksckPageDescInfo) + - mpdi->pages*sizeof(Mksck_PageDesc)); -endProcessingFreeNewSock: - release_sock(newsk); - sock_release(newsock); - release_sock(sk); - return retval; - -endProcessingKFreeReleaseSock: - sock_kfree_s(newsk, mpdi, sizeof(MksckPageDescInfo) + - mpdi->pages*sizeof(Mksck_PageDesc)); - release_sock(newsk); -endProcessingReleaseSock: - release_sock(sk); - return retval; -} - -/** - * @brief Callback at socket destruction - * - * @param sk pointer to kernel socket structure - */ -static void -MksckPageDescSkDestruct(struct sock *sk) -{ - struct sock *mkSk = NULL; - MksckPageDescInfo *mpdi; - lock_sock(sk); - mpdi = sk->sk_protinfo; - while (mpdi) { - MksckPageDescInfo *next = mpdi->next; - MksckPageDescManage(mpdi->descs, mpdi->pages, - MANAGE_DECREMENT); - sock_kfree_s(sk, mpdi, sizeof(MksckPageDescInfo) + - mpdi->pages*sizeof(Mksck_PageDesc)); - mpdi = next; - } - if (sk->sk_user_data) { - mkSk = (struct sock *)sk->sk_user_data; - sk->sk_user_data = NULL; - } - sk->sk_protinfo = NULL; - release_sock(sk); - /* clean the monki socket that we are holding */ - if (mkSk) { - lock_sock(mkSk); - sock_kfree_s(mkSk, mkSk->sk_user_data, sizeof(int)); - mkSk->sk_user_data = NULL; - release_sock(mkSk); - sock_put(mkSk); // revert of sock_hold() - } -} - -/** - * @brief The mmap operation of the PageDesc context file descriptor. - * - * The mmap command is used to mmap any detached (i.e. no more accumulating) - * PageDesc context, full of the content from its parent communication mk - * socket. Mapping may be done a specified number of times, so that the - * PageDesc context could become useless (as a security restriction). - * - * Also note that mapping from an offset different from zero is considered - * as a userland invalid operation. - * - * @param file user file structure - * @param sock user socket structure - * @param vma virtual memory area structure - * - * @return error code, 0 on success - */ -static int -MksckPageDescMMap(struct file *file, - struct socket *sock, - struct vm_area_struct *vma) -{ - struct sock *sk = sock->sk; - MksckPageDescInfo *mpdi; - struct iovec iov; - unsigned long vm_flags; - int freed = 0; - - iov.iov_base = (void*)vma->vm_start; - iov.iov_len = vma->vm_end - vma->vm_start; - - lock_sock(sk); - mpdi = sk->sk_protinfo; - - // vma->vm_pgoff is checked, since offsetting the map is not supported - if (!mpdi || sk->sk_user_data || vma->vm_pgoff) { - release_sock(sk); - printk(KERN_INFO "MMAP failed for virt %lx size %lx\n", - vma->vm_start, vma->vm_end - vma->vm_start); - return -EINVAL; - } - - vm_flags = mpdi->flags; - if ((vma->vm_flags & ~vm_flags) & (VM_READ|VM_WRITE)) { - release_sock(sk); - return -EACCES; - } - - while (mpdi) { - MksckPageDescInfo *next = mpdi->next; - MksckPageDescMap(mpdi->descs, mpdi->pages, &iov, 1, vma); - if (mpdi->mapCounts && !--mpdi->mapCounts) { - MksckPageDescManage(mpdi->descs, mpdi->pages, - MANAGE_DECREMENT); - sock_kfree_s(sk, mpdi, sizeof(MksckPageDescInfo) + - mpdi->pages*sizeof(Mksck_PageDesc)); - freed = 1; - } - mpdi = next; - } - - if (freed) { - sk->sk_protinfo = NULL; - } - vma->vm_ops = &mksckVMOps; - release_sock(sk); - return 0; -} - -/** - * @brief The ioctl operation of the PageDesc context file descriptor. - * - * The ioctl MKSCK_DETACH command is used to detach the PageDesc context - * from its parent communication mk socket. Once done, the context - * is able to remap the transferred PageDesc(s) of typed messages accumulated - * into the context. - * - * @param sock user socket structure - * @param cmd select which cmd function needs to be performed - * @param arg argument for command - * - * @return error code, 0 on success - */ -static int -MksckPageDescIoctl(struct socket *sock, - unsigned int cmd, - unsigned long arg) -{ - struct sock *monkiSk = NULL; - struct sock *sk = sock->sk; - MksckPageDescInfo *mpdi; - int retval = 0; - - switch (cmd) { - /** - * ioctl MKSCK_DETACH (in and out): - * Detach, compute size and define allowed protection access rights - * - * [in]: unsigned long flags, similar to prot argument of mmap() - * unsigned long number of available further mappings - * with 0 meaning unlimited number of mappings - * [out]: unsigned long size of the available mappable area - */ - case MKSCK_DETACH: { - unsigned long ul[2]; - lock_sock(sk); - mpdi = sk->sk_protinfo; - // read unsigned long argument that contains the mmap alike flags - if (copy_from_user(ul, (void *)arg, sizeof ul)) { - retval = -EFAULT; - // check that the file descriptor has a parent and some context there - } else if (!mpdi || !sk->sk_user_data) { - retval = -EINVAL; - } else { - /* compute mapping protection bits from argument and size of the - * mapping, that is also given back to userland as unsigned long. - */ - uint32 flags = calc_vm_prot_bits(ul[0]); - ul[0] = 0; - while (mpdi) { - MksckPageDescInfo *next = mpdi->next; - ul[0] += MksckPageDescManage(mpdi->descs, mpdi->pages, - MANAGE_COUNT); - mpdi->mapCounts = ul[1]; - mpdi = next; - } - if (copy_to_user((void *)arg, ul, sizeof(ul[0]))) { - retval = -EFAULT; - } else { - mpdi = sk->sk_protinfo; - mpdi->flags = flags; - monkiSk = (struct sock *)sk->sk_user_data; - sk->sk_user_data = NULL; - } - } - release_sock(sk); - // clean the monki socket that we are holding - if ((sk = monkiSk)) { - lock_sock(sk); - sock_kfree_s(sk, sk->sk_user_data, sizeof(int)); - sk->sk_user_data = NULL; - release_sock(sk); - sock_put(sk); - } - break; - } - default: { - retval = -EINVAL; - break; - } - } - return retval; -} - - -/** - * @brief VMX receiving a packet from VMM. - * - * @param kiocb kernel io control block (unused) - * @param sock user socket structure - * @param msg user buffer to receive the packet - * @param len size of the user buffer - * @param flags flags - * - * @return -errno on failure, else length of untyped portion + total number - * of bytes mapped for typed portion. - */ -static int -MksckDgramRecvMsg(struct kiocb *kiocb, - struct socket *sock, - struct msghdr *msg, - size_t len, - int flags) -{ - int err = 0; - struct sock *sk = sock->sk; - Mksck *mksck; - Mksck_Datagram *dg; - struct sockaddr_mk *fromAddr; - uint32 read; - struct iovec *iov; - size_t payloadLen, untypedLen; - uint32 iovCount; - - if (flags & MSG_OOB || flags & MSG_ERRQUEUE) { - return -EOPNOTSUPP; - } - - if ((msg->msg_name != NULL) && (msg->msg_namelen < sizeof *fromAddr)) { - return -EINVAL; - } - - lock_sock(sk); - if ((err = MksckTryBind(sk))) { - release_sock(sk); - return err; - } - mksck = sk->sk_protinfo; - - /* - * To avoid mksck disappearing right after the release_sock the - * refcount needs to be incremented. For more details read the - * block comment on locking in MksckCreate. - */ - ATOMIC_ADDV(mksck->refCount, 1); - release_sock(sk); - - /* - * Get pointer to next packet in ring to be dequeued. - */ - while (1) { - - /* - * Wait to make sure this is the only thread trying to access socket. - */ - if ((err = Mutex_Lock(&mksck->mutex, MutexModeEX)) < 0) { - goto decRefc; - } - - /* - * See if packet in ring. - */ - read = mksck->read; - if (read != mksck->write) { - break; - } - - /* - * Nothing there, if user wants us not to block then just return EAGAIN. - */ - if (flags & MSG_DONTWAIT) { - Mutex_Unlock(&mksck->mutex, MutexModeEX); - err = -EAGAIN; - goto decRefc; - } - - /* - * Nothing there, unlock socket and wait for data. - */ - mksck->foundEmpty ++; - err = Mutex_UnlSleep(&mksck->mutex, MutexModeEX, MKSCK_CVAR_FILL); - if (err < 0) { - PRINTK(KERN_INFO "MksckDgramRecvMsg: aborted\n"); - goto decRefc; - } - } - - /* - * Point to packet in ring. - */ - dg = (void *)&mksck->buff[read]; - - /* - * Provide the address of the sender. - */ - if (msg->msg_name != NULL) { - fromAddr = (void *)msg->msg_name; - fromAddr->mk_addr = dg->fromAddr; - fromAddr->mk_family = AF_MKSCK; - msg->msg_namelen = sizeof *fromAddr; - } else { - msg->msg_namelen = 0; - } - - /* - * Copy data from ring buffer to caller's buffer and remove packet from - * ring buffer. - */ - iov = msg->msg_iov; - iovCount = msg->msg_iovlen; - payloadLen = untypedLen = - dg->len - dg->pages * sizeof(Mksck_PageDesc) - dg->pad; - - /* - * Handle the untyped portion of the message. - */ - if (untypedLen <= len) { - err = memcpy_toiovec(iov, - dg->data, - untypedLen); - if (err < 0) { - printk("MksckDgramRecvMsg: Failed to memcpy_to_iovec untyped message component " - "(buf len %d datagram len %d (untyped %d))\n", - len, - dg->len, - untypedLen); - } - } else { - err = -EINVAL; - } - - /* - * Map in the typed descriptor. - */ - if (err >= 0 && dg->pages > 0) { - Mksck_PageDesc *pd = (Mksck_PageDesc *)(dg->data + untypedLen + dg->pad); - - /* - * There are 3 ways of receiving typed messages from the monitor. - * - The typed message is mapped directly into a VMA. To indicate this the - * userland sets msg_controllen == 0. - * - The typed message is mapped directly into a VMA and a file descriptor - * created for further mappings on the host (in same userland address - * space or an alternate userland address space). In this case - * msg_controllen should be set to sizeof(fd). - * - The typed message is not mapped directly into a VMA, but a file - * descriptor is created for later mapping on the host. In this case - * msg_controllen should be set to sizeof(fd) and the supplied iovec - * shall not specify a receive window. - * - * The conjuncts below decide on which of these 3 cases we've encountered. - */ - - if ((msg->msg_controllen <= 0) || - ((err = MksckPageDescToFd(sock, msg, pd, dg->pages)) != 0) || - (MsgHdrHasAvailableRoom(msg) != 0)) { - - down_write(¤t->mm->mmap_sem); // lock for a change of mapping - payloadLen += MksckPageDescMap(pd, dg->pages, iov, iovCount, NULL); - up_write(¤t->mm->mmap_sem); - } - } - - /* - * Now that packet is removed, it is safe to unlock socket so another thread - * can do a recv(). We also want to wake someone waiting for room to insert - * a new packet. - */ - if ((err >= 0) && Mksck_IncReadIndex(mksck, read, dg)) { - Mutex_UnlWake(&mksck->mutex, MutexModeEX, MKSCK_CVAR_ROOM, true); - } else { - Mutex_Unlock(&mksck->mutex, MutexModeEX); - } - - /* - * If memcpy error, return error status. - * Otherwise, return number of bytes copied. - */ - if (err >= 0) { - err = payloadLen; - } - -decRefc: - Mksck_DecRefc(mksck); - return err; -} - - -/** - * @brief VMX sending a packet to VMM. - * - * @param kiocb kernel io control block - * @param sock user socket structure - * @param msg packet to be transmitted - * @param len length of the packet - * - * @return length of the sent msg on success, -errno on failure - */ -static int -MksckDgramSendMsg(struct kiocb *kiocb, - struct socket *sock, - struct msghdr *msg, - size_t len) -{ - int err = 0; - struct sock *sk = sock->sk; - Mksck *peerMksck; - Mksck_Datagram *dg; - uint32 needed; - uint32 write; - Mksck_Address fromAddr; - - if (msg->msg_flags & MSG_OOB) { - return -EOPNOTSUPP; - } - - if (len > MKSCK_XFER_MAX) { - return -EMSGSIZE; - } - - /* - * In the next locked section peerMksck pointer needs to be set and - * its refcount needs to be incremented. - */ - lock_sock(sk); - do { - Mksck *mksck; - Mksck_Address peerAddr = - { .addr = (msg->msg_name ? - ((struct sockaddr_mk *)msg->msg_name)->mk_addr.addr : - MKSCK_ADDR_UNDEF) }; - - if ((err = MksckTryBind(sk))) { - break; - } - mksck = sk->sk_protinfo; - fromAddr = mksck->addr; - - /* - * If the socket is connected, use that address (no sendto for - * connected sockets). Otherwise, use the provided address if any. - */ - if ((peerMksck = mksck->peer)) { - if (peerAddr.addr != MKSCK_ADDR_UNDEF && - peerAddr.addr != mksck->peerAddr.addr) { - err = -EISCONN; - break; - } - /* - * To avoid mksckPeer disappearing right after the - * release_sock the refcount needs to be incremented. For - * more details read the block comment on locking in - * MksckCreate. - */ - ATOMIC_ADDV(peerMksck->refCount, 1); - } else if (peerAddr.addr == MKSCK_ADDR_UNDEF) { - err = -ENOTCONN; - } else { - /* - * LockPeer also increments the refc on the peer. - */ - err = LockPeer(peerAddr, &peerMksck); - } - } while(0); - release_sock(sk); - - if (err) { - return err; - } - - /* - * Get pointer to sufficient empty space in ring buffer. - */ - needed = MKSCK_DGSIZE(len); - while (1) { - /* - * Wait to make sure this is the only thread trying to write to ring. - */ - if ((err = Mutex_Lock(&peerMksck->mutex, MutexModeEX)) < 0) { - goto decRefc; - } - - /* - * Check if socket can receive data. - */ - if (peerMksck->shutDown & MKSCK_SHUT_RD) { - err = -ENOTCONN; - goto unlockDecRefc; - } - - /* - * See if there is room for the packet. - */ - write = Mksck_FindSendRoom(peerMksck, needed); - if (write != MKSCK_FINDSENDROOM_FULL) { - break; - } - - /* - * No room, unlock socket and maybe wait for room. - */ - if (msg->msg_flags & MSG_DONTWAIT) { - err = -EAGAIN; - goto unlockDecRefc; - } - - peerMksck->foundFull ++; - err = Mutex_UnlSleep(&peerMksck->mutex, - MutexModeEX, - MKSCK_CVAR_ROOM); - if (err < 0) { - PRINTK(KERN_INFO "MksckDgramSendMsg: aborted\n"); - goto decRefc; - } - } - - /* - * Point to room in ring and fill in message. - */ - dg = (void *)&peerMksck->buff[write]; - - dg->fromAddr = fromAddr; - dg->len = len; - - if ((err = memcpy_fromiovec(dg->data, msg->msg_iov, len)) != 0) { - goto unlockDecRefc; - } - - /* - * Increment past message. - */ - Mksck_IncWriteIndex(peerMksck, write, needed); - - /* - * Unlock socket and wake someone trying to receive, ie, we filled - * in a message. - */ - Mutex_UnlWake(&peerMksck->mutex, MutexModeEX, MKSCK_CVAR_FILL, false); - - /* - * Maybe guest is in a general 'wait for interrupt' wait or - * grinding away executing guest instructions. - * - * If it has a receive callback armed for the socket and is - * waiting a message, just wake it up. Else send an IPI to the CPU - * running the guest so it will interrupt whatever it is doing and - * read the message. - * - * Holding the mksckPage->mutex prevents mksckPage->vmHKVA from - * clearing on us. - */ - if (peerMksck->rcvCBEntryMVA != 0) { - MksckPage *peerMksckPage = Mksck_ToSharedPage(peerMksck); - - if ((err = Mutex_Lock(&peerMksckPage->mutex, MutexModeSH)) == 0) { - uint32 sockIdx = peerMksck->index; - MvpkmVM *vm = (MvpkmVM *) peerMksckPage->vmHKVA; - - /* - * The destruction of vm and wsp is blocked by the - * mksckPage->mutex. - */ - if (vm) { - WorldSwitchPage *wsp = vm->wsp; - - ASSERT(sockIdx < 8 * sizeof peerMksckPage->wakeVMMRecv); - ATOMIC_ORV(peerMksckPage->wakeVMMRecv, 1U << sockIdx); - - if (wsp) { - Mvpkm_WakeGuest(vm, ACTION_MKSCK); - } - } - Mutex_Unlock(&peerMksckPage->mutex, MutexModeSH); - } - } - - /* - * If all are happy tell the caller the number of transferred bytes. - */ - if (!err) { - err = len; - } - - /* - * Now that we are done with target socket, allow it to be freed. - */ -decRefc: - Mksck_DecRefc(peerMksck); - return err; - -unlockDecRefc: - Mutex_Unlock(&peerMksck->mutex, MutexModeEX); - goto decRefc; -} - - -/** - * @brief Page fault handler for receive windows. Since the host process - * should not be faulting in this region and only be accessing - * memory that has been established via a typed message transfer, - * we always signal the fault back to the process. - */ -static int -MksckFault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - return VM_FAULT_SIGBUS; -} - -/** - * @brief Establish a region in the host process suitable for use as a - * receive window. - * - * @param file file reference (ignored). - * @param sock user socket structure. - * @param vma Linux virtual memory area defining the region. - * - * @return 0 on success, otherwise error code. - */ -static int -MksckMMap(struct file *file, struct socket *sock, struct vm_area_struct *vma) -{ - /* - * All the hard work is done in MksckDgramRecvMsg. Here we simply mark the - * vma as belonging to Mksck. - */ - vma->vm_ops = &mksckVMOps; - - return 0; -} - -/** - * @brief This gets called after returning from the monitor. - * Since the monitor doesn't directly wake VMX threads when it sends - * something to VMX (for efficiency), this routine checks for the - * omitted wakes and does them. - * @param mksckPage some shared page that the monitor writes packets to, ie - * an host shared page - */ -void -Mksck_WakeBlockedSockets(MksckPage *mksckPage) -{ - Mksck *mksck; - uint32 i, wakeHostRecv; - - wakeHostRecv = mksckPage->wakeHostRecv; - if (wakeHostRecv != 0) { - mksckPage->wakeHostRecv = 0; - for (i = 0; wakeHostRecv != 0; i ++) { - if (wakeHostRecv & 1) { - mksck = &mksckPage->sockets[i]; - Mutex_CondSig(&mksck->mutex, MKSCK_CVAR_FILL, true); - } - wakeHostRecv >>= 1; - } - } -} - -/** - * @brief allocate and initialize a shared page. - * @return pointer to shared page.<br> - * NULL on error - */ -MksckPage * -MksckPageAlloc(void) -{ - uint32 jj; - /* - * Ask for pages in the virtual kernel space. There is no - * requirement to be physically contiguous. - */ - MksckPage *mksckPage = vmalloc(MKSCKPAGE_SIZE); - - if (mksckPage) { - - /* - * Initialize its contents. Start refCount at 1 and decrement it - * when the worldswitch or VM page gets freed. - */ - memset(mksckPage, 0, MKSCKPAGE_SIZE); - ATOMIC_SETV(mksckPage->refCount, 1); - mksckPage->portStore = MKSCK_PORT_HIGH; - - Mutex_Init(&mksckPage->mutex); - for (jj = 0; jj<MKSCK_SOCKETS_PER_PAGE; jj++) { - Mutex_Init(&mksckPage->sockets[jj].mutex); - } - } - - return mksckPage; -} - -/** - * @brief Release the allocated pages. - * @param mksckPage the address of the mksckPage to be released - */ -static void -MksckPageRelease(MksckPage *mksckPage) -{ - int ii; - - for (ii = 0; ii<MKSCK_SOCKETS_PER_PAGE; ii++) { - Mutex_Destroy(&mksckPage->sockets[ii].mutex); - } - Mutex_Destroy(&mksckPage->mutex); - - vfree(mksckPage); -} - -/** - * @brief Using the tgid locate the vmid of this process. - * Assumed that mksckPageListLock is held - * @return the vmId if page is already allocated, - * the first vacant vmid if not yet allocated.<br> - * MKSCK_PORT_UNDEF if no slot is vacant - */ -static inline Mksck_VmId -GetHostVmId(void) -{ - uint32 jj; - Mksck_VmId vmId, vmIdFirstVacant = MKSCK_VMID_UNDEF; - MksckPage *mksckPage; - uint32 tgid = task_tgid_vnr(current); - /* - * Assign an unique vmId to the shared page. Start the search from - * the vmId that is the result of hashing tgid to 15 bits. As a - * used page with a given vmId can occupy only a given slot in the - * mksckPages array, it is enough to search through the - * MKSCK_MAX_SHARES slots for a vacancy. - */ - for (jj = 0, vmId = MKSCK_TGID2VMID(tgid); - jj < MKSCK_MAX_SHARES; - jj++, vmId++) { - if (vmId > MKSCK_VMID_HIGH) { - vmId = 0; - } - mksckPage = mksckPages[MKSCK_VMID2IDX(vmId)]; - - if (mksckPage) { - if (mksckPage->tgid == tgid && - !mksckPage->isGuest) { - return mksckPage->vmId; - } - - } else if (vmIdFirstVacant == MKSCK_VMID_UNDEF) { - vmIdFirstVacant = vmId; - } - } - return vmIdFirstVacant; -} - - -/** - * @brief Locate the first empty slot - * Assumed that mksckPageListLock is held - * @return the first vacant vmid.<br> - * MKSCK_PORT_UNDEF if no slot is vacant - */ -static inline Mksck_VmId -GetNewGuestVmId(void) -{ - Mksck_VmId vmId; - - for (vmId = 0; vmId < MKSCK_MAX_SHARES; vmId++) { - if (!mksckPages[MKSCK_VMID2IDX(vmId)]) { - return vmId; - } - } - return MKSCK_VMID_UNDEF; -} - - -/** - * @brief Find shared page for a given idx. The page referred to be the - * idx should exist and be locked by the caller. - * @param idx index of the page in the array - * @return pointer to shared page - */ -MksckPage * -MksckPage_GetFromIdx(uint32 idx) -{ - MksckPage *mksckPage = mksckPages[idx]; - ASSERT(mksckPage); - ASSERT(idx<MKSCK_MAX_SHARES); - ASSERT(ATOMIC_GETO(mksckPage->refCount)); - return mksckPage; -} - -/** - * @brief find shared page for a given vmId - * The vmid should exist and be locked by the caller. - * @param vmId vmId to look for, either an host vmId or a guest vmId - * @return pointer to shared page - */ -MksckPage * -MksckPage_GetFromVmId(Mksck_VmId vmId) -{ - MksckPage *mksckPage = mksckPages[MKSCK_VMID2IDX(vmId)]; - ASSERT(mksckPage); - ASSERT(mksckPage->vmId == vmId); - ASSERT(ATOMIC_GETO(mksckPage->refCount)); - return mksckPage; -} - - -/** - * @brief find shared page for a given vmId - * @param vmId vmId to look for, either an host vmId or a guest vmId - * @return NULL: no such shared page exists<br> - * else: pointer to shared page. - * Call Mksck_DecRefc() when done with pointer - */ -MksckPage * -MksckPage_GetFromVmIdIncRefc(Mksck_VmId vmId) -{ - MksckPage *mksckPage; - - spin_lock(&mksckPageListLock); - mksckPage = mksckPages[MKSCK_VMID2IDX(vmId)]; - - if (!mksckPage || (mksckPage->vmId != vmId)) { - printk(KERN_INFO "MksckPage_GetFromVmIdIncRefc: vmId %04X not found\n", - vmId); - mksckPage = NULL; - } else { - ATOMIC_ADDV(mksckPage->refCount, 1); - } - spin_unlock(&mksckPageListLock); - return mksckPage; -} - - -/** - * @brief find or allocate shared page using tgid - * @return NULL: no such shared page exists<br> - * else: pointer to shared page. - * Call Mksck_DecRefc() when done with pointer - */ -MksckPage * -MksckPage_GetFromTgidIncRefc(void) -{ - MksckPage *mksckPage; - Mksck_VmId vmId; - - while (1) { - spin_lock(&mksckPageListLock); - vmId = GetHostVmId(); - - if (vmId == MKSCK_VMID_UNDEF) { - /* - * No vmId has been allocated yet and there is no free slot. - */ - spin_unlock(&mksckPageListLock); - return NULL; - } - - mksckPage = mksckPages[MKSCK_VMID2IDX(vmId)]; - if (mksckPage != NULL) { - /* - * There is a vmid already allocated, increment the refc on it. - */ - ATOMIC_ADDV(mksckPage->refCount, 1); - spin_unlock(&mksckPageListLock); - return mksckPage; - } - - /* - * Have to release spinlock to allocate a new page. - */ - spin_unlock(&mksckPageListLock); - mksckPage = MksckPageAlloc(); - if (mksckPage == NULL) { - return NULL; - } - - /* - * Re-lock and make sure no one else allocated while unlocked. - * If someone else did allocate, free ours off and use theirs. - */ - spin_lock(&mksckPageListLock); - vmId = GetHostVmId(); - if ((vmId != MKSCK_VMID_UNDEF) && - (mksckPages[MKSCK_VMID2IDX(vmId)] == NULL)) { - break; - } - spin_unlock(&mksckPageListLock); - MksckPageRelease(mksckPage); - } - - /* - * This is a successful new allocation. insert it into the table - * and initialize the fields. - */ - mksckPages[MKSCK_VMID2IDX(vmId)] = mksckPage; - mksckPage->vmId = vmId; - mksckPage->isGuest = false; - mksckPage->vmHKVA = 0; - mksckPage->tgid = task_tgid_vnr(current); - printk(KERN_DEBUG "New host mksck page is allocated: idx %x, vmId %x, tgid %d\n", - MKSCK_VMID2IDX(vmId), vmId, mksckPage->tgid); - - spin_unlock(&mksckPageListLock); - return mksckPage; -} - -/** - * @brief Initialize the VMX provided wsp. Allocate communication page. - * @param vm which virtual machine we're running - * @return 0 if all OK, error value otherwise - */ -int -Mksck_WspInitialize(MvpkmVM *vm) -{ - WorldSwitchPage *wsp = vm->wsp; - int err; - Mksck_VmId vmId; - MksckPage *mksckPage; - - if (wsp->guestId) { - err = -EBUSY; - } else if (!(mksckPage = MksckPageAlloc())) { - err = -ENOMEM; - } else { - spin_lock(&mksckPageListLock); - - if ((vmId = GetNewGuestVmId()) == MKSCK_VMID_UNDEF) { - - err = -EMFILE; - MksckPageRelease(mksckPage); - - printk(KERN_INFO "Mksck_WspInitialize: Cannot allocate vmId\n"); - - } else { - /* - * Now that the mksckPage is all initialized, let others see it. - */ - mksckPages[MKSCK_VMID2IDX(vmId)] = mksckPage; - mksckPage->vmId = vmId; - mksckPage->isGuest = true; - mksckPage->vmHKVA = (HKVA)vm; - /* mksckPage->tgid is undefined when isGuest is true */ - - wsp->guestId = vmId; - - printk(KERN_DEBUG "New guest mksck page is allocated: idx %x, vmId %x\n", - MKSCK_VMID2IDX(vmId), vmId); - - err = 0; - } - - /* - * All stable, ie, mksckPages[] written, ok to unlock now. - */ - spin_unlock(&mksckPageListLock); - } - - return err; -} - -/** - * @brief Release the wsp. Clean up after the monitor. Free the - * associated communication page. - * @param wsp which worldswitch page (VCPU) - */ -void -Mksck_WspRelease(WorldSwitchPage *wsp) -{ - int ii; - int err; - MksckPage *mksckPage = MksckPage_GetFromVmId(wsp->guestId); - - /* - * The worldswitch page for a particular VCPU is about to be freed - * off, so we know the monitor will never execute again. But the - * monitor most likely left some sockets open. Those may have - * outbound connections to host sockets that we must close. - * - * Loop through all possibly open sockets. - */ - uint32 isOpened = wsp->isOpened; - Mksck *mksck = mksckPage->sockets; - while (isOpened) { - if (isOpened & 1) { - ASSERT(ATOMIC_GETO(mksck->refCount) != 0); - /* - * The socket may be connected to a peer (host) socket, so we - * have to decrement that target socket's reference - * count. Unfortunately, Mksck_DisconnectPeer(mksck) cannot - * be called as mksck->peer is an mva not an hkva. Translate - * the address first. - */ - if (mksck->peer) { - MksckPage *mksckPagePeer = MksckPage_GetFromVmId(mksck->peerAddr.vmId); - ASSERT(mksckPagePeer); - mksck->peer = MksckPage_GetFromAddr(mksckPagePeer, mksck->peerAddr); - ASSERT(mksck->peer); - /* mksck->peer is now a hkva */ - } - - Mksck_CloseCommon(mksck); - } - isOpened >>= 1; - mksck++; - } - - /* - * A host socket may be in the process of sending to the guest. It - * will attempt to wake up the guest using mksckPage->vmHKVA and - * mksckPage->vmHKVA->wsp. To assure that the vm and wsp structures - * are not disappearing from under the sending thread we lock the - * page here. - */ - err = Mutex_Lock(&mksckPage->mutex, MutexModeEX); - ASSERT(!err); - mksckPage->vmHKVA = 0; - Mutex_Unlock(&mksckPage->mutex, MutexModeEX); - /* - * Decrement refcount set by MksckPageAlloc() call in - * Mksck_WspInitialize(). - */ - MksckPage_DecRefc(mksckPage); - - /* - * Decrement refcount set by VMM:Mksck_Init() referring to the local - * variable guestMksckPage. - */ - if (wsp->guestPageMapped) { - wsp->guestPageMapped = false; - MksckPage_DecRefc(mksckPage); - } - - /* - * Another task is to decrement the reference count on the mksck - * pages the monitor accessed. Those pages are listed in the - * wsp->isPageMapped list. They were locked by the monitor - * calling WSCALL_GET_PAGE_FROM_VMID - */ - for (ii = 0; ii < MKSCK_MAX_SHARES; ii++) { - if (wsp->isPageMapped[ii]) { - MksckPage *mksckPageOther = MksckPage_GetFromIdx(ii); - - wsp->isPageMapped[ii] = false; - MksckPage_DecRefc(mksckPageOther); - } - } -} - -/** - * @brief disconnect from peer by decrementing - * peer socket's reference count and clearing the pointer. - * @param mksck local socket to check for connection - */ -void -Mksck_DisconnectPeer(Mksck *mksck) -{ - Mksck *peerMksck = mksck->peer; - if (peerMksck != NULL) { - mksck->peer = NULL; - mksck->peerAddr.addr = MKSCK_ADDR_UNDEF; - Mksck_DecRefc(peerMksck); - } -} - - -/** - * @brief decrement shared page reference count, free page if it goes zero. - * also do a dmb first to make sure all activity on the struct is - * finished before decrementing the ref count. - * @param mksckPage shared page - */ -void -MksckPage_DecRefc(MksckPage *mksckPage) -{ - uint32 oldRefc; - - DMB(); - do { - while ((oldRefc = ATOMIC_GETO(mksckPage->refCount)) == 1) { - - /* - * Find corresponding entry in list of known shared pages and - * clear it so we can't open any new sockets on this shared - * page, thus preventing its refCount from being incremented. - */ - spin_lock(&mksckPageListLock); - if (ATOMIC_SETIF(mksckPage->refCount, 0, 1)) { - uint32 ii = MKSCK_VMID2IDX(mksckPage->vmId); - ASSERT(ii < MKSCK_MAX_SHARES); - ASSERT(mksckPages[ii] == mksckPage); - mksckPages[ii] = NULL; - spin_unlock(&mksckPageListLock); - printk(KERN_DEBUG "%s mksck page is released: idx %x, vmId %x, tgid %d\n", - mksckPage->isGuest?"Guest":"Host", - ii, mksckPage->vmId, mksckPage->tgid); - MksckPageRelease(mksckPage); - return; - } - spin_unlock(&mksckPageListLock); - } - ASSERT(oldRefc != 0); - } while (!ATOMIC_SETIF(mksckPage->refCount, oldRefc - 1, oldRefc)); -} - -/** - * @brief Lookup if the provided mpn belongs to one of the Mksck pages. Map if found. - * @return 0 if all OK, error value otherwise - */ -int -MksckPage_LookupAndInsertPage(struct vm_area_struct *vma, - unsigned long address, - MPN mpn) -{ - int ii, jj; - MksckPage **mksckPagePtr = mksckPages; - - spin_lock(&mksckPageListLock); - for (jj = MKSCK_MAX_SHARES; jj--; mksckPagePtr++) { - if (*mksckPagePtr) { - for (ii = 0; ii < MKSCKPAGE_TOTAL; ii++) { - if (vmalloc_to_pfn((void*)(((HKVA)*mksckPagePtr) + ii*PAGE_SIZE)) == mpn && - vm_insert_page(vma, address, pfn_to_page(mpn)) == 0) { - spin_unlock(&mksckPageListLock); - return 0; - } - } - } - } - spin_unlock(&mksckPageListLock); - return -1; -} - - -/** - * @brief Print information on the allocated shared pages - * - * This function reports (among many other things) on the use of locks - * on the mksck page (page lock and individual socket locks). To avoid - * the Hiesenberg effect it avoids using locks unless there is a - * danger of dereferencing freed memory. In particular, holding - * mksckPageListLock ensures that the mksck page is not freed while it - * is read. But under very rare conditions this function may report - * inconsistent or garbage data. - */ -static int -MksckPageInfoShow(struct seq_file *m, void *private) -{ - int ii, jj; - uint32 isPageMapped = 0; - int err; - MvpkmVM *vm; - - /* - * Lock is needed to atomize the test and dereference of - * mksckPages[ii] - */ - spin_lock(&mksckPageListLock); - for (ii = 0; ii < MKSCK_MAX_SHARES; ii++) { - MksckPage *mksckPage = mksckPages[ii]; - if (mksckPage != NULL && mksckPage->isGuest) { - /* - * After the refcount is incremented mksckPage will not be - * freed and it can continued to be dereferenced after the - * unlock of mksckPageListLock. - */ - ATOMIC_ADDV(mksckPage->refCount, 1); - spin_unlock(&mksckPageListLock); - - /* - * To dereference mksckPage->vmHKVA, we need to have the page - * lock. - */ - err = Mutex_Lock(&mksckPage->mutex, MutexModeEX); - vm = (MvpkmVM *) mksckPage->vmHKVA; - - if (err == 0 && vm && vm->wsp) { - for (jj = 0; jj < MKSCK_MAX_SHARES; jj++) { - if (vm->wsp->isPageMapped[jj]) isPageMapped |= 1<<jj; - } - } - Mutex_Unlock(&mksckPage->mutex, MutexModeEX); - /* - * Decrement the page refcount and relock the - * mksckPageListLock for the next for loop. - */ - MksckPage_DecRefc(mksckPage); - spin_lock(&mksckPageListLock); - break; - } - } - - /* mksckPageListLock is still locked, mksckPages[ii] can be dereferenced */ - for (ii = 0; ii < MKSCK_MAX_SHARES; ii++) { - MksckPage *mksckPage = mksckPages[ii]; - if (mksckPage != NULL) { - uint32 lState = ATOMIC_GETO(mksckPage->mutex.state); - uint32 isOpened = 0; /* guest has an implicit ref */ - - seq_printf(m, "MksckPage[%02d]: { vmId = %4x(%c), refC = %2d%s", - ii, mksckPage->vmId, - mksckPage->isGuest?'G':'H', - ATOMIC_GETO(mksckPage->refCount), - (isPageMapped&(1<<ii) ? "*" : "")); - - if (lState) { - seq_printf(m, ", lock=%x locked by line %d, unlocked by %d", - lState, mksckPage->mutex.line, mksckPage->mutex.lineUnl); - } - - - if (!mksckPage->isGuest) { - struct task_struct *target; - seq_printf(m, ", tgid = %d", mksckPage->tgid); - - rcu_read_lock(); - - target = pid_task(find_vpid(mksckPage->tgid), PIDTYPE_PID); - seq_printf(m, "(%s)", target ? target->comm : "no such process"); - - rcu_read_unlock(); - } else { - ATOMIC_ADDV(mksckPage->refCount, 1); - spin_unlock(&mksckPageListLock); - - err = Mutex_Lock(&mksckPage->mutex, MutexModeEX); - vm = (MvpkmVM *) mksckPage->vmHKVA; - - if (err == 0 && vm && vm->wsp) { - isOpened = vm->wsp->isOpened; - } - Mutex_Unlock(&mksckPage->mutex, MutexModeEX); - MksckPage_DecRefc(mksckPage); - spin_lock(&mksckPageListLock); - /* - * As the mksckPageListLock was unlocked, nothing - * prevented the MksckPage_DecRefc from actually freeing - * the page. Lets verify that the page is still there. - */ - if (mksckPage != mksckPages[ii]) { - seq_printf(m, " released }\n"); - continue; - } - } - seq_printf(m, ", sockets[] = {"); - - for (jj = 0; jj < mksckPage->numAllocSocks; jj++, isOpened >>= 1) { - Mksck *mksck = mksckPage->sockets + jj; - - if (ATOMIC_GETO(mksck->refCount)) { - uint32 blocked; - lState = ATOMIC_GETO(mksck->mutex.state); - seq_printf(m, "\n { addr = %8x, refC = %2d%s%s%s", - mksck->addr.addr, - ATOMIC_GETO(mksck->refCount), - (isOpened & 1 ? "*" : ""), - (mksck->shutDown & MKSCK_SHUT_RD ? " SHUTD_RD":""), - (mksck->shutDown & MKSCK_SHUT_WR ? " SHUTD_WR":"")); - - if (mksck->peer) { - seq_printf(m, ", peerAddr = %8x", - mksck->peerAddr.addr); - } - - if (lState) { - seq_printf(m, ", lock=%x locked by line %d, unlocked by %d", - lState, mksck->mutex.line, mksck->mutex.lineUnl); - } - - if ((blocked = ATOMIC_GETO(mksck->mutex.blocked))) { - seq_printf(m, ", blocked=%d", blocked); - } - - seq_printf(m, " }"); - } - } - seq_printf(m, " } }\n"); - } - } - spin_unlock(&mksckPageListLock); - - return 0; -} - - -static int -MksckPageInfoOpen(struct inode *inode, struct file *file) -{ - return single_open(file, MksckPageInfoShow, inode->i_private); -} - -static const struct file_operations mksckPageInfoFops = { - .open = MksckPageInfoOpen, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static struct dentry *mksckPageDentry = NULL; - -void -MksckPageInfo_Init(void) -{ - mksckPageDentry = debugfs_create_file("mksckPage", - S_IROTH, - NULL, - NULL, - &mksckPageInfoFops); -} - -void -MksckPageInfo_Exit(void) -{ - if (mksckPageDentry) { - debugfs_remove(mksckPageDentry); - } -} diff --git a/arch/arm/mvp/mvpkm/mksck_kernel.h b/arch/arm/mvp/mvpkm/mksck_kernel.h deleted file mode 100644 index 233b780..0000000 --- a/arch/arm/mvp/mvpkm/mksck_kernel.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The monitor-kernel socket interface kernel-only definitions. - */ - -#ifndef _MKSCK_KERNEL_H -#define _MKSCK_KERNEL_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mksck_shared.h" - -/* - * prototypes - */ -int Mksck_Init(void); -void Mksck_Exit(void); -void Mksck_WakeBlockedSockets(MksckPage *mksckPage); -MksckPage *MksckPage_GetFromTgidIncRefc(void); -MksckPage *MksckPage_GetFromVmIdIncRefc(Mksck_VmId vmId); -MksckPage *MksckPage_GetFromIdx(uint32 idx); -void MksckPageInfo_Init(void); -void MksckPageInfo_Exit(void); -int Mksck_WspInitialize(MvpkmVM *vm); -void Mksck_WspRelease(WorldSwitchPage *wsp); -int MksckPage_LookupAndInsertPage(struct vm_area_struct *vma, - unsigned long address, - MPN mpn); - -/* - * Mksck open request must come from this uid. - */ -extern uid_t Mvpkm_vmwareUid; - -#define MKSCK_DEVEL 0 - -#if MKSCK_DEVEL -#define PRINTK printk -#else -#define PRINTK if (0) printk -#endif - -#define HOST_CPUID_UNDEF (~0) - -#endif diff --git a/arch/arm/mvp/mvpkm/mksck_shared.c b/arch/arm/mvp/mvpkm/mksck_shared.c deleted file mode 100644 index 68c38fc6..0000000 --- a/arch/arm/mvp/mvpkm/mksck_shared.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -#include "mvp.h" -#include "mksck_shared.h" - -/** - * @file - * - * @brief The mksck shared area functions used by the monitor and the - * kernel extension. - * - */ - -/** - * @brief try to locate a socket using an address. - * @param mksckPage which shared page to look on. - * ASSUMED: locked for shared access - * @param addr address to check - * @return pointer to mksck page with addr. - * NULL if not found - */ -Mksck * -MksckPage_GetFromAddr(MksckPage *mksckPage, Mksck_Address addr) -{ - Mksck *mksck = mksckPage->sockets; - uint32 ii; - - ASSERT(addr.vmId == mksckPage->vmId); - - for (ii = mksckPage->numAllocSocks; ii--; mksck++) { - if ((ATOMIC_GETO(mksck->refCount) != 0) && - (mksck->addr.addr == addr.addr)) { - return mksck; - } - } - return NULL; -} - -/** - * @brief Close a monitor socket. - * - * @param mksck pointer to the socket control block - */ -void -Mksck_CloseCommon(Mksck *mksck) -{ - /* - * If a peer was connected, release the peer. - */ - Mksck_DisconnectPeer(mksck); - - /* - * Signal senders that this socket won't be read anymore. - */ - while (Mutex_Lock(&mksck->mutex, MutexModeEX) < 0); - mksck->shutDown = MKSCK_SHUT_WR | MKSCK_SHUT_RD; - Mutex_UnlWake(&mksck->mutex, MutexModeEX, MKSCK_CVAR_ROOM, true); - - /* - * Decrement reference count because it was set to 1 when opened. It could - * still be non-zero after this if some other thread is currently sending to - * this socket. - */ - Mksck_DecRefc(mksck); -} - - -/** - * @brief decrement socket reference count, free if it goes zero. Also do a - * dmb first to make sure all activity on the struct is finished before - * decrementing the ref count. - * @param mksck socket - */ -void -Mksck_DecRefc(Mksck *mksck) -{ - uint32 oldRefc; - - DMB(); - do { - while ((oldRefc = ATOMIC_GETO(mksck->refCount)) == 1) { - - MksckPage *mksckPage = Mksck_ToSharedPage(mksck); - - /* - * Socket refcount is going zero on a socket that locks mksckPage in. - * Lock shared page exclusive to make sure no one is trying to look - * for this socket, thus preventing socket's refcount from being - * incremented non-zero once we decrement it to zero. - */ - - /* - * Lock failed probably because of an interrupt. Keep trying - * to lock until we succeed. - */ - while (Mutex_Lock(&mksckPage->mutex, MutexModeEX) < 0); - - /* - * No one is doing any lookups, so set refcount zero. - */ - if (ATOMIC_SETIF(mksck->refCount, 0, 1)) { -#if 0 - /** - * @knownjira{MVP-1349} - * The standard Log is not yet implemented in the kernel space. - */ - KNOWN_BUG(MVP-1349); - PRINTK(KERN_INFO "Mksck_DecRefc: %08X shutDown %u, foundEmpty %u," - " foundFull %u, blocked %u\n", - mksck->addr.addr, mksck->shutDown, - mksck->foundEmpty, mksck->foundFull, - ATOMIC_GETO(mksck->mutex.blocked)); -#endif - - /* - * Sockets can't have connected peers by the time their - * refc hits 0. The owner should have cleaned that up by - * now. - */ - ASSERT(mksck->peer == 0); - - /* - * Successfully set to zero, release mutex and decrement - * shared page ref count as it was incremented when the - * socket was opened. This may free the shared page. - */ - Mutex_Unlock(&mksckPage->mutex, MutexModeEX); - MksckPage_DecRefc(mksckPage); - return; - } - - /* - * Someone incremented refcount just before we locked the mutex, so - * try it all again. - */ - Mutex_Unlock(&mksckPage->mutex, MutexModeEX); - } - - /* - * Not going zero or doesn't lock mksckPage, simple decrement. - */ - ASSERT(oldRefc != 0); - } while (!ATOMIC_SETIF(mksck->refCount, oldRefc - 1, oldRefc)); -} - - -/** - * @brief Find an unused port. - * @param mksckPage which shared page to look in. - * Locked for exclusive access - * @param port if not MKSCK_PORT_UNDEF test only this port - * @return port allocated or MKSCK_PORT_UNDEF if none was found - */ -Mksck_Port -MksckPage_GetFreePort(MksckPage *mksckPage, Mksck_Port port) -{ - Mksck_Address addr = { .addr = Mksck_AddrInit(mksckPage->vmId, port) }; - uint32 ii; - - if (port == MKSCK_PORT_UNDEF) { - for (ii = 0; ii<MKSCK_SOCKETS_PER_PAGE; ii++) { - - /* - * Find an unused local socket number. - */ - addr.port = mksckPage->portStore--; - if (!addr.port) { - - /* - * Wrapped around, reset portStore - */ - mksckPage->portStore = MKSCK_PORT_HIGH; - } - - if (!MksckPage_GetFromAddr(mksckPage, addr)) { - return addr.port; - } - } - - } else if (!MksckPage_GetFromAddr(mksckPage, addr)) { - return addr.port; - } - - return MKSCK_PORT_UNDEF; -} - -/** - * @brief Find an unused slot in the sockets[] array and allocate it. - * @param mksckPage which shared page to look in. - * Locked for exclusive access - * @param addr what local address to assign to the socket - * @return NULL: no slots available <br> - * else: pointer to allocated socket - */ -Mksck * -MksckPage_AllocSocket(MksckPage *mksckPage, Mksck_Address addr) -{ - Mksck *mksck; - uint32 i; - - for (i = 0; (offsetof(MksckPage, sockets[i+1]) <= MKSCKPAGE_SIZE) && - (i < 8 * sizeof mksckPage->wakeHostRecv) && - (i < 8 * sizeof mksckPage->wakeVMMRecv); i ++) { - mksck = &mksckPage->sockets[i]; - if (ATOMIC_GETO(mksck->refCount) == 0) { - ATOMIC_SETV(mksck->refCount, 1); - mksck->addr = addr; - mksck->peerAddr.addr = MKSCK_ADDR_UNDEF; - mksck->peer = NULL; - mksck->index = i; - mksck->write = 0; - mksck->read = 0; - mksck->shutDown = 0; - mksck->foundEmpty = 0; - mksck->foundFull = 0; - ATOMIC_SETV(mksck->mutex.blocked, 0); - mksck->rcvCBEntryMVA = 0; - mksck->rcvCBParamMVA = 0; - - if (mksckPage->numAllocSocks < ++ i) { - mksckPage->numAllocSocks = i; - } - - return mksck; - } - } - return NULL; -} - - -/** - * @brief increment read index over the packet just read - * @param mksck socket packet was read from. - * Locked for exclusive access - * @param read current value of mksck->read - * @param dg datagram at current mksck->read - * @return with mksck->read updated to next packet <br> - * false: buffer not empty <br> - * true: buffer now empty - */ -_Bool -Mksck_IncReadIndex(Mksck *mksck, uint32 read, Mksck_Datagram *dg) -{ - ASSERT(read == mksck->read); - ASSERT((void *)dg == (void *)&mksck->buff[read]); - - read += MKSCK_DGSIZE(dg->len); - if ((read > mksck->write) && (read >= mksck->wrap)) { - ASSERT(read == mksck->wrap); - read = 0; - } - mksck->read = read; - - return read == mksck->write; -} - - -/** - * @brief find index in buffer that has enough room for a packet - * @param mksck socket message is being sent to. - * Locked for exclusive access - * @param needed room needed, including dg header and rounded up - * @return MKSCK_FINDSENDROOM_FULL: not enough room available <br> - * else: index in mksck->buff for packet - */ -uint32 -Mksck_FindSendRoom(Mksck *mksck, uint32 needed) -{ - uint32 read, write; - - /* - * We must leave at least one byte unused so receiver can distinguish full - * from empty. - */ - read = mksck->read; - write = mksck->write; - if (write == read) { - if (needed < MKSCK_BUFSIZE) { - mksck->read = 0; - mksck->write = 0; - return 0; - } - } else if (write < read) { - if (write + needed < read) { - return write; - } - } else { - if (write + needed < MKSCK_BUFSIZE) { - return write; - } - if ((write + needed == MKSCK_BUFSIZE) && (read > 0)) { - return write; - } - if (needed < read) { - mksck->wrap = write; - mksck->write = 0; - return 0; - } - } - - return MKSCK_FINDSENDROOM_FULL; -} - - -/** - * @brief increment read index over the packet just written - * @param mksck socket packet was written to. - * Locked for exclusive access - * @param write as returned by @ref Mksck_FindSendRoom - * @param needed as passed to @ref Mksck_FindSendRoom - * @return with mksck->write updated to next packet - */ -void -Mksck_IncWriteIndex(Mksck *mksck, uint32 write, uint32 needed) -{ - ASSERT(write == mksck->write); - write += needed; - if (write >= MKSCK_BUFSIZE) { - ASSERT(write == MKSCK_BUFSIZE); - mksck->wrap = MKSCK_BUFSIZE; - write = 0; - } - ASSERT(write != mksck->read); - mksck->write = write; -} diff --git a/arch/arm/mvp/mvpkm/mksck_shared.h b/arch/arm/mvp/mvpkm/mksck_shared.h deleted file mode 100644 index 2677ec1..0000000 --- a/arch/arm/mvp/mvpkm/mksck_shared.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The monitor-kernel socket interface shared area definitions. - */ - -#ifndef _MKSCK_SHARED_H -#define _MKSCK_SHARED_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/* - * Allocated MksckPages are stored in an array of size - * MKSCK_MAX_SHARES. The vmid and the slot index of a shared page is - * not unrelated: vmid = idx%MKSCK_MAX_SHARES. - */ -#define MKSCK_MAX_SHARES_LOG2 4 // 16: one per VM + one per VCPU -#define MKSCK_MAX_SHARES (1U << MKSCK_MAX_SHARES_LOG2) -#define MKSCK_VMID2IDX(idx) ((idx)%MKSCK_MAX_SHARES) -#define MKSCK_TGID2VMID(tgid) (((((tgid)<<1)^((tgid)>>15))&0xfffe)|1) -/* - * The size of a shared page determines how many sockets can be open - * concurrently. - */ -#define MKSCKPAGE_TOTAL 8 // number of shared pages -#define MKSCKPAGE_SIZE (PAGE_SIZE * MKSCKPAGE_TOTAL) -#define MKSCK_SOCKETS_PER_PAGE ((MKSCKPAGE_SIZE-offsetof(MksckPage, sockets[0])) / \ - sizeof(Mksck)) - -/* - * Individual datagrams are aligned on a MKSCK_ALIGNMENT byte boundary - * in the data receive area of a socket. - */ -#define MKSCK_ALIGNMENT 8 // data packet alignment -#define MKSCK_ALIGN(x) MVP_ALIGN(x, MKSCK_ALIGNMENT) -#define MKSCK_DGSIZE(len) offsetof(Mksck_Datagram, data[MKSCK_ALIGN(len)]) -#define MKSCK_BUFSIZE MKSCK_DGSIZE(MKSCK_XFER_MAX + 1) - -/* - * Conditional variables for sleeping on. - */ -#define MKSCK_CVAR_ROOM 0 // senders waiting for room for message -#define MKSCK_CVAR_FILL 1 // receivers waiting for a message to fetch - -#define MKSCK_FINDSENDROOM_FULL 0xFFFFFFFFU - -/* - * Shutdown bits - */ -#define MKSCK_SHUT_WR (1 << 0) // socket can't send data anymore -#define MKSCK_SHUT_RD (1 << 1) // socket can't receive data anymore - -typedef struct Mksck Mksck; -typedef struct Mksck_Datagram Mksck_Datagram; -typedef struct MksckPage MksckPage; - -#include "atomic.h" -#include "mksck.h" -#include "mmu_defs.h" -#include "mutex.h" -#include "arm_inline.h" - -/** - * @brief Monitor-kernel socket datagram structure - */ -struct Mksck_Datagram { - Mksck_Address fromAddr; ///< source address - uint32 len : 16; ///< length of the data - uint32 pad : 3; ///< padding between untyped message and mpn - ///< array. - uint32 pages : 13; ///< number of pages in mpn array - uint8 data[1] ///< start of the data - __attribute__((aligned(MKSCK_ALIGNMENT))); -}; - -/** - * @brief one particular socket's shared page data. - */ -struct Mksck { - AtmUInt32 refCount; ///< when zero, struct is free - ///< ... increment only with mksckPage->mutex - ///< ... decrement at any time - Mksck_Address addr; ///< this socket's address if open - ///< ... MKSCK_ADDR_UNDEF if closed - ///< ... open only with mksckPage->mutex - Mksck_Address peerAddr; ///< peer's address if connected - ///< ... MKSCK_ADDR_UNDEF if not - struct Mksck *peer; ///< connected peer's ptr or NULL if not - ///< ... ptr is MVA for monitor sockets and - ///< ... HKVA for sockets of host processes - ///< ... holds ref count on target socket - uint32 index; ///< index of this socket in page - - ///< empty ring indicated by read == write - ///< ring never completely fills, always at - ///< least room for one more byte so we can tell - ///< empty from full - - uint32 write; ///< index within buff to insert next data - ///< ... always < MKSCK_BUFSIZE - uint32 read; ///< index within buff to remove next data - ///< ... always < MKSCK_BUFSIZE - uint32 wrap; ///< current wrapping point - ///< ... valid only whenever write < read - uint32 shutDown; ///< MKSCK_SHUT_RD, MKSCK_SHUT_WR bitfield - uint32 foundEmpty; ///< number of times a receive has blocked - uint32 foundFull; ///< number of times a send has blocked - Mutex mutex; ///< locks the ring buffer - MVA rcvCBEntryMVA; ///< monitor's receive callback entrypoint - MVA rcvCBParamMVA; ///< monitor's receive callback parameter - uint8 buff[MKSCK_BUFSIZE] ///< data going TO this socket - __attribute__((aligned(MKSCK_ALIGNMENT))); -}; - - -/** - * @brief the shared page of an address domain (vmId) - */ -struct MksckPage { - _Bool isGuest; ///< the page belongs to a monitor/guest - uint32 tgid; ///< thread group id if isGuest=true - ///< undefined otherwise - volatile HKVA vmHKVA; ///< host side local data structure for vm - AtmUInt32 refCount; ///< page cannot be freed unless this is zero - ///< ... increment only with mksckPageListLock - ///< ... decrement at any time - ///< ... initialized to 1 for wsp->mksckPage* pointers - uint32 wakeHostRecv; ///< bitmask of sockets[] to be woken for receive - ///< ... access from VCPU thread only - AtmUInt32 wakeVMMRecv; ///< likewise for monitor receive callbacks - Mutex mutex; ///< locks list of open sockets - Mksck_VmId vmId; ///< hostId or guestId these sockets are for - Mksck_Port portStore; ///< used to assign ephemeral port numbers - uint32 numAllocSocks; ///< number of elements in sockets[] array - Mksck sockets[1]; ///< array of sockets (to fill MKSCKPAGE_SIZE) -}; - -MksckPage *MksckPage_GetFromVmId(Mksck_VmId vmId); -Mksck_Port MksckPage_GetFreePort(MksckPage *mksckPage, Mksck_Port port); -Mksck *MksckPage_GetFromAddr(MksckPage *mksckPage, Mksck_Address addr); -Mksck *MksckPage_AllocSocket(MksckPage *mksckPage, Mksck_Address addr); -void MksckPage_DecRefc(MksckPage *mksckPage); - -void Mksck_DecRefc(Mksck *mksck); -void Mksck_CloseCommon(Mksck *mksck); -_Bool Mksck_IncReadIndex(Mksck *mksck, uint32 read, Mksck_Datagram *dg); -uint32 Mksck_FindSendRoom(Mksck *mksck, uint32 needed); -void Mksck_IncWriteIndex(Mksck *mksck, uint32 write, uint32 needed); -void Mksck_DisconnectPeer(Mksck *mksck); - - -/** - * @brief determine which shared page a given socket is on - * Note that this process does not rely on any directory. - * @param mksck pointer to socket - * @return pointer to shared page - */ -static inline MksckPage * -Mksck_ToSharedPage(Mksck *mksck) -{ - return (MksckPage*)((char*)(mksck - mksck->index) - - offsetof(MksckPage, sockets)); -} -#endif diff --git a/arch/arm/mvp/mvpkm/mksck_sockaddr.h b/arch/arm/mvp/mvpkm/mksck_sockaddr.h deleted file mode 100644 index e99d1f5..0000000 --- a/arch/arm/mvp/mvpkm/mksck_sockaddr.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Host user space definitions for mksck sockets. - */ - -#ifndef _MKSCK_SOCKADDR_H_ -#define _MKSCK_SOCKADDR_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mksck.h" - -/* no one ever uses DECnet anymore? */ -#define AF_MKSCK AF_DECnet -#define PF_MKSCK PF_DECnet - -/* Address structure used by the host user socket interface. */ -struct sockaddr_mk { - sa_family_t mk_family; - Mksck_Address mk_addr; -}; - -#endif diff --git a/arch/arm/mvp/mvpkm/mmu_defs.h b/arch/arm/mvp/mvpkm/mmu_defs.h deleted file mode 100644 index 340b91b..0000000 --- a/arch/arm/mvp/mvpkm/mmu_defs.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MMU-related definitions. - */ - -#ifndef _MMU_DEFS_H_ -#define _MMU_DEFS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/** - * @name ARM address space identifier. - * @{ - */ -#define ARM_ASID_BITS 8 -#define ARM_ASID_NUM (1 << ARM_ASID_BITS) -#define ARM_ASID_MASK (ARM_ASID_NUM - 1) -/*@}*/ - -/** - * @name ARM level 1 and 2 page table sizes. - * @{ - */ -#define ARM_L1PT_ORDER 14 -#define ARM_L2PT_FINE_ORDER 12 -#define ARM_L2PT_COARSE_ORDER 10 - -#define ARM_L1D_SECTION_ORDER 20 -#define ARM_L1D_SUPERSECTION_ORDER 24 - -#define ARM_L2D_SMALL_ORDER 12 -#define ARM_L2D_LARGE_ORDER 16 - -#define ARM_L1PT_SIZE (1 << ARM_L1PT_ORDER) -#define ARM_L2PT_FINE_SIZE (1 << ARM_L2PT_FINE_ORDER) -#define ARM_L2PT_COARSE_SIZE (1 << ARM_L2PT_COARSE_ORDER) - -#define ARM_L1D_SECTION_SIZE (1 << ARM_L1D_SECTION_ORDER) -#define ARM_L1D_SUPERSECTION_SIZE (1 << ARM_L1D_SUPERSECTION_ORDER) - -#define ARM_L2D_SMALL_SIZE (1 << ARM_L2D_SMALL_ORDER) -#define ARM_L2D_LARGE_SIZE (1 << ARM_L2D_LARGE_ORDER) - -#define ARM_L2PT_COARSE_PER_PAGE (PAGE_SIZE / ARM_L2PT_COARSE_SIZE) - -#define ARM_L1PT_ENTRIES (ARM_L1PT_SIZE / sizeof(ARM_L1D)) -#define ARM_L2PT_FINE_ENTRIES (ARM_L2PT_FINE_SIZE / sizeof(ARM_L2D)) -#define ARM_L2PT_COARSE_ENTRIES (ARM_L2PT_COARSE_SIZE / sizeof(ARM_L2D)) -/*@}*/ - -/** - * @brief Level 1 descriptor type field values. - * @{ - */ -#define ARM_L1D_TYPE_INVALID 0 -#define ARM_L1D_TYPE_COARSE 1 -#define ARM_L1D_TYPE_SECTION 2 -#define ARM_L1D_TYPE_SUPERSECTION 2 -/*@}*/ - -/** - * @name Decomposition of virtual addresses for page table indexing. - * @{ - */ -#define ARM_L1PT_INDX(addr) MVP_EXTRACT_FIELD((addr), 20, 12) -#define ARM_L2PT_COARSE_INDX(addr) MVP_EXTRACT_FIELD((addr), 12, 8) -/*@}*/ - -/** - * @name Mapping from the VA/PA/MA of a LxD entry to its table index. - * @{ - */ -#define ARM_L1D_PTR_INDX(l1dp) MVP_BITS((uint32)(l1dp), 2, ARM_L1PT_ORDER - 1) -#define ARM_L2D_PTR_INDX(l2dp) MVP_BITS((uint32)(l2dp), 2, ARM_L2PT_COARSE_ORDER - 1) -/*@}*/ - -/** - * @name L1D base index <-> MA. - * @{ - */ -#define ARM_L1D_BASE_ADDR(base) ((base) << ARM_L1PT_ORDER) -#define ARM_L1D_ADDR_BASE(addr) ((addr) >> ARM_L1PT_ORDER) -/*@}*/ - -/** - * @brief Which 1 MB section of a 16 MB supersection does the given addr lie in? - */ -#define ARM_SUPER_SECTION_INDEX(addr) MVP_EXTRACT_FIELD((addr), 20, 4) - -/** - * @name L1D entry base <-> either MA or MA of a second-level table. - * @{ - */ -#define ARM_L1D_SUPERSECTION_BASE_ADDR(base) ((base) << ARM_L1D_SUPERSECTION_ORDER) -#define ARM_L1D_SUPERSECTION_ADDR_BASE(addr) ((addr) >> ARM_L1D_SUPERSECTION_ORDER) -#define ARM_L1D_SECTION_BASE_ADDR(base) ((base) << ARM_L1D_SECTION_ORDER) -#define ARM_L1D_SECTION_ADDR_BASE(addr) ((addr) >> ARM_L1D_SECTION_ORDER) -#define ARM_L1D_COARSE_BASE_ADDR(base) ((base) << ARM_L2PT_COARSE_ORDER) -#define ARM_L1D_COARSE_ADDR_BASE(addr) ((addr) >> ARM_L2PT_COARSE_ORDER) -#define ARM_L1D_FINE_BASE_ADDR(base) ((base) << ARM_L2PT_FINE_ORDER) -#define ARM_L1D_FINE_ADDR_BASE(addr) ((addr) >> ARM_L2PT_FINE_ORDER) -/*@}*/ - -/* - * The number of L1 page directory pages the service the entire - * virtual space - */ -#define ARM_L1PT_PAGES (1<<(ARM_L1PT_ORDER - PAGE_ORDER)) - - -/** - * @name Level 2 descriptor type field values. - * @{ - */ -#define ARM_L2D_TYPE_INVALID 0 -#define ARM_L2D_TYPE_LARGE 0 -#define ARM_L2D_TYPE_SMALL 1 -#define ARM_L2D_XTYPE_LARGE 1 -#define ARM_L2D_XTYPE_SMALL 2 -#define ARM_L2D_XTYPE_SMALL_NX 3 -/*@}*/ - -/** - * @name Small/Large L2D (in coarse table) base <-> MA conversion. - * @{ - */ -#define ARM_L2D_LARGE_BASE_ADDR(base) ((base) << ARM_L2D_LARGE_ORDER) -#define ARM_L2D_LARGE_ADDR_BASE(addr) ((addr) >> ARM_L2D_LARGE_ORDER) -#define ARM_L2D_SMALL_BASE_ADDR(base) ((base) << ARM_L2D_SMALL_ORDER) -#define ARM_L2D_SMALL_ADDR_BASE(addr) ((addr) >> ARM_L2D_SMALL_ORDER) - -#define ARM_L2D_SMALL_PAGE_NUMBER(addr) ARM_L2D_SMALL_ADDR_BASE(addr) -#define ARM_L2D_SMALL_PAGE_OFFSET(addr) ((addr) & (PAGE_SIZE - 1)) -/* @}*/ - -/** - * @brief ARM page table descriptor access permissions for the AP field. - * @{ - */ -#define ARM_PERM_NONE 0 -#define ARM_PERM_PRIV_RW 1 -#define ARM_PERM_USER_RO 2 -#define ARM_PERM_USER_RW 3 -/*@}*/ - -/** - * @name Simplified access permission model introduced in ARMv7. - * - * AP[0] is an access flag, AP[2:1] are one of the following. - * - * @{ - */ -#define ARM_SIMPLE_PERM_KERN_RW 0 -#define ARM_SIMPLE_PERM_USER_RW 1 -#define ARM_SIMPLE_PERM_KERN_RO 2 -#define ARM_SIMPLE_PERM_USER_RO 3 - -#define ARM_SIMPLE_PERM_AP_KERN 1 -#define ARM_SIMPLE_PERM_AP_USER 3 - -#define ARM_SIMPLE_PERM_APX_RW 0 -#define ARM_SIMPLE_PERM_APX_RO 1 - -#define ARM_SIMPLE_PERM_AP(x) ((MVP_BIT(x, 0) << 1) | 1) -#define ARM_SIMPLE_PERM_APX(x) MVP_BIT(x, 1) -/*@}*/ - -/** - * @name ARM domains. - * @{ - */ -#define ARM_DOMAINS 16 - -#define ARM_DOMAIN_NOACCESS 0 -#define ARM_DOMAIN_CLIENT 1 -#define ARM_DOMAIN_RESERVED 2 -#define ARM_DOMAIN_MANAGER 3 -/*@}*/ - -#define ARM_DOMAIN_INDEX(dacr,dom) MVP_EXTRACT_FIELD((dacr), 2*(dom), 2) -#define ARM_DOMAIN_ACCESS(dom,access) ((access) << (2*(dom))) - -/* - * Cache-related definitions. - */ -#define ARM_CACHE_LEVELS_MAX 8 -#define ARM_CACHE_LINE_SIZE_MAX 2048 - -#endif /// _MMU_DEFS_H_ diff --git a/arch/arm/mvp/mvpkm/mmu_types.h b/arch/arm/mvp/mvpkm/mmu_types.h deleted file mode 100644 index da8a6fa..0000000 --- a/arch/arm/mvp/mvpkm/mmu_types.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MMU-related types. - */ - -#ifndef _MMU_TYPES_H_ -#define _MMU_TYPES_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mmu_defs.h" - -/** - * @brief ARM level 1 page table descriptor. See B3-8 ARM DDI 0406B. - */ -typedef union { - uint32 u; - - struct { - uint32 type : 2; - uint32 xx : 30; - } x; - - struct { - uint32 type : 2; - uint32 sbz1 : 1; - uint32 ns : 1; - uint32 sbz2 : 1; - uint32 domain : 4; - uint32 imp : 1; - uint32 base : 22; - } coarse; - - struct { - uint32 type : 2; - uint32 cb : 2; - uint32 xn : 1; - uint32 domain : 4; - uint32 imp : 1; - uint32 ap : 2; - uint32 tex : 3; - uint32 apx : 1; - uint32 s : 1; - uint32 ng : 1; - uint32 sbz : 1; - uint32 ns : 1; - uint32 base : 12; - } section; - - struct { - uint32 type : 2; - uint32 cb : 2; - uint32 xn : 1; - uint32 xbase2 : 4; - uint32 imp : 1; - uint32 ap : 2; - uint32 tex : 3; - uint32 apx : 1; - uint32 s : 1; - uint32 ng : 1; - uint32 sbo : 1; - uint32 ns : 1; - uint32 xbase1 : 4; - uint32 base : 8; - } supersection; -} ARM_L1D; - -/** - * @brief ARM level 2 page table descriptor. See B3-10 ARM DDI 0406B. - */ -typedef union { - uint32 u; - - struct { - uint32 type : 2; - uint32 cb : 2; - uint32 xx : 28; - } x; - - struct { - uint32 type : 2; - uint32 cb : 2; - uint32 ap : 2; - uint32 sbz : 3; - uint32 apx : 1; - uint32 s : 1; - uint32 ng : 1; - uint32 tex : 3; - uint32 xn : 1; - uint32 base : 16; - } large; - - struct { - uint32 xn : 1; - uint32 type : 1; - uint32 cb : 2; - uint32 ap : 2; - uint32 tex : 3; - uint32 apx : 1; - uint32 s : 1; - uint32 ng : 1; - uint32 base : 20; - } small; -} ARM_L2D; - -/** - * @brief Get the simplified access permissions from a small L2 descriptor. - * - * @param l2D value of L2 descriptor. - * - * @return Simplified access permissions. - */ -static inline uint8 -ARM_L2DSimpleAP(ARM_L2D l2D) -{ - ASSERT(l2D.small.type == ARM_L2D_TYPE_SMALL); - return (l2D.small.apx << 1) | (l2D.small.ap >> 1); -} - -/** - * @brief Permissions for a page - intermediate format. - */ -typedef struct { - uint8 ap : 2; - uint8 apx : 1; - uint8 xn : 1; -} ARM_AccessPerms; - -/** - * @brief ARM domain (0-15). - */ -typedef uint8 ARM_Domain; - -/** - * @brief ARM Domain Access Control Register, see B4.9.4 ARM DDI 0100I. - */ -typedef uint32 ARM_DACR; - -/** - * @brief ARM address space identifier. - * 8-bits with an "invalid ASID" value - * representation. - */ -typedef uint32 ARM_ASID; - -#define ARM_INVALID_ASID ((uint32)(-1)) - -/** - * @brief Page shareability property. - * - * LPAE encoding, see p8 ARM PRD03-GENC-008469 11.0. - */ -typedef enum { - ARM_SHARE_ATTR_NONE, - ARM_SHARE_ATTR_RESERVED, - ARM_SHARE_ATTR_OUTER, - ARM_SHARE_ATTR_INNER, -} PACKED ARM_ShareAttr; - -/** - * @brief Page cacheability property (TEX Remap disabled). - * - * ARM C/B bits, see B4.4.1 ARM DDI 0100I. - */ -typedef enum { - ARM_CB_UNBUFFERED = 0, - ARM_CB_UNCACHED = 1, - ARM_CB_WRITETHROUGH = 2, - ARM_CB_WRITEBACK = 3 -} PACKED ARM_CB; - -/** - * @brief Normal page cacheability property (TEX Remap enabled). - * - * NMRR encoding, see B3-146 ARM DDI 0406B. - */ -typedef enum { - ARM_CACHE_ATTR_NORMAL_NONE, - ARM_CACHE_ATTR_NORMAL_WB_WALLOC, - ARM_CACHE_ATTR_NORMAL_WT, - ARM_CACHE_ATTR_NORMAL_WB -} PACKED ARM_CacheAttrNormal; - -/** - * @brief Normal page memory attributes. - * - * Captures the general case of distinct inner/outer cacheability/shareability. - * See A3-30 ARM DDI 0406B for a discussion of shareability domains and - * cacheability attributes. - */ -typedef struct { - ARM_ShareAttr share; - ARM_CacheAttrNormal innerCache; - ARM_CacheAttrNormal outerCache; -} ARM_MemAttrNormal; - -#endif /// _MMU_TYPES_H_ diff --git a/arch/arm/mvp/mvpkm/montimer_kernel.c b/arch/arm/mvp/mvpkm/montimer_kernel.c deleted file mode 100644 index e2f8ef8..0000000 --- a/arch/arm/mvp/mvpkm/montimer_kernel.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MVP host kernel implementation of monitor timers - * - * The monitor sends requests that are simply a 64-bit absolute time that it - * wants a reply. If it changes its mind, it simply sends a different 64-bit - * absolute time. It is tolerant of us replying too soon, so if we miss the - * update to a later time, it doesn't matter, the monitor will re-send the - * request for the later time. The only time we should miss an update to a - * sooner time is when we are about to send the reply to the old time anyway, - * in which case the monitor sees a reply as quickly as we can generate them, - * so no harm there either. - */ - -#include <linux/module.h> -#include <linux/hrtimer.h> - -#include "mvp.h" -#include "mvp_timer.h" -#include "actions.h" -#include "mvpkm_kernel.h" - -/** - * @brief Linux timer callback - * @param timer The linux timer raised - * @return Status to not restart the timer - */ -static enum hrtimer_restart -MonitorTimerCB(struct hrtimer *timer) -{ - MvpkmVM *vm = container_of(timer, MvpkmVM, monTimer.timer); - Mvpkm_WakeGuest(vm, ACTION_TIMER); - return HRTIMER_NORESTART; -} - -/** - * @brief Initialize vm associated timer - * @param vm which virtual machine we're running - */ -void -MonitorTimer_Setup(MvpkmVM *vm) -{ - MonTimer *monTimer = &vm->monTimer; - monTimer->vm = vm; - - hrtimer_init(&monTimer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - monTimer->timer.function = MonitorTimerCB; -} - -/** - * @brief New timer request from monitor - * @param monTimer Monitor timer - * @param when64 Timer target value - */ -void -MonitorTimer_Request(MonTimer *monTimer, uint64 when64) -{ - if (when64) { - ktime_t kt; - - /* - * Simple conversion, assuming RATE64 is 1e+9 - */ - kt = ns_to_ktime(when64); - ASSERT_ON_COMPILE(MVP_TIMER_RATE64 == 1000000000); - - /* - * Start the timer. If it was already active, it will remove - * the previous expiration time. Linux handles correctly timer - * with deadline in the past, and forces a safety minimal delta - * for closer timer deadlines. - */ - hrtimer_start(&monTimer->timer, kt, HRTIMER_MODE_ABS); - } else { - /* - * Cancel a pending request. If there is none, this will do nothing. - * If it's too late, monitor tolerance will forgive us. - */ - hrtimer_cancel(&monTimer->timer); - } -} diff --git a/arch/arm/mvp/mvpkm/montimer_kernel.h b/arch/arm/mvp/mvpkm/montimer_kernel.h deleted file mode 100644 index 6817a83..0000000 --- a/arch/arm/mvp/mvpkm/montimer_kernel.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The monitor-kernel socket interface kernel-only definitions. - */ - -#ifndef _MONITOR_TIMER_KERNEL_H -#define _MONITOR_TIMER_KERNEL_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include <linux/hrtimer.h> - -/** - * @brief Monitor Timer structure - */ -typedef struct { - struct MvpkmVM *vm; ///< Associated vm - struct hrtimer timer; ///< Linux timer -} MonTimer; - -void MonitorTimer_Setup(struct MvpkmVM *vm); -void MonitorTimer_Request(MonTimer *monTimer, uint64 when64); - -#endif diff --git a/arch/arm/mvp/mvpkm/monva_common.h b/arch/arm/mvp/mvpkm/monva_common.h deleted file mode 100644 index de3dd1a..0000000 --- a/arch/arm/mvp/mvpkm/monva_common.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Constant definitions that describing the monitor memory layout - * (common to both LPV and VE monitors). - * - */ - -#ifndef _MONVA_COMMON_H_ -#define _MONVA_COMMON_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mmu_defs.h" -#include "mmu_types.h" - -/* - * The monitor occupies a hole in the guest virtual address space. - * The following macros define that hole. - */ - -#define MONITOR_VA_START ((MVA)0xE8000000) -#define MONITOR_VA_LEN 0x03000000 - -/* - * Worldswitch page gets mapped right after the stack guard. - */ -#define MONITOR_VA_WORLDSWITCH \ - ((MVA)(MONITOR_VA_START + 3 * PAGE_SIZE)) - -#define MONITOR_VA_WORLDSWITCH_CODE \ - (MONITOR_VA_WORLDSWITCH + PAGE_SIZE) - -#define MONITOR_VA_UART \ - (MONITOR_VA_WORLDSWITCH_CODE + PAGE_SIZE) - -/** - * @brief Type of physmem region mapping that we want the VMX to know about. - * Helps to identify Guest page allocations. - */ -typedef enum { - MEMREGION_MAINMEM = 1, - MEMREGION_MODULE = 2, - MEMREGION_WSP = 3, - MEMREGION_MONITOR_MISC = 4, - MEMREGION_DEFAULT = 0 -} PACKED PhysMem_RegionType; - -typedef struct MonVA { /* Note that this struct is VE only */ - MA l2BaseMA; ///< MA of monitor L2 page table page - MVA excVec; ///< Monitor exception vector virtual address -} MonVA; - -/** - * @brief Monitor VA mapping type, device or memory. - * - * These values are used to index HMAIR0 in the VE monitor - do not change - * without making the required update to HMAIR0. - */ -typedef enum { - MVA_MEMORY = 0, - MVA_DEVICE = 1 -} MVAType; - -/** - * @name Monitor types, used in VMX, Mvpkm and monitors. - * - * This is not a C enumeration, as we may want to use the values in CPP macros. - * - * @{ - */ -#define MONITOR_TYPE_LPV 0 -#define MONITOR_TYPE_VE 1 -#define MONITOR_TYPE_UNKNOWN 0xf - -typedef uint32 MonitorType; -/*@}*/ - -#endif diff --git a/arch/arm/mvp/mvpkm/mutex.h b/arch/arm/mvp/mvpkm/mutex.h deleted file mode 100644 index 30de97d..0000000 --- a/arch/arm/mvp/mvpkm/mutex.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Common mutex definitions. - */ - -#ifndef _MUTEX_H -#define _MUTEX_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define MUTEX_CVAR_MAX 2 ///< maximum number of condition variables supported - ///< on a given mutex - -typedef enum MutexMode MutexMode; -typedef struct HKWaitQ HKWaitQ; -typedef struct Mutex Mutex; - -/** - * @brief modes for locking - */ -enum MutexMode { - MutexModeSH = 1, ///< minimum value that can be saved in low - ///< 16 bits of 'state', ie, it won't allow - ///< any other EXs in there without overflowing. - ///< it also will block if there are already - ///< 0xFFFF other shared accesses, but it should - ///< be of little consequence. - - MutexModeEX = 0xFFFF ///< maximum value that can be saved in low - ///< 16 bits of 'state', ie, it won't allow - ///< any other EXs or SHs in there without - ///< overflowing, thus causing a block. -}; - -#include "atomic.h" - -typedef union Mutex_State { - uint32 state; ///< for atomic setting/reading - struct { - uint16 mode; ///< the sum of mode values of MutexMode - uint16 blck; ///< The number of threads blocked - }; -} Mutex_State; - -/** - * @brief shareable mutex struct. - */ -struct Mutex { - HKVA mtxHKVA; ///< mutex's host kernel virtual address - AtmUInt32 state; ///< low 16 bits: # of granted shared accessors - ///< or FFFF if granted exclusive - ///< high 16 bits: # of blocked threads - AtmUInt32 waiters; ///< number of threads on all condWaitQs - ///< ... increment only with mutex locked EX - ///< ... decrement any time - AtmUInt32 blocked; ///< number times blocked (stats only) - HKVA lockWaitQ; ///< threads blocked for mutex to be unlocked - HKVA cvarWaitQs[MUTEX_CVAR_MAX]; ///< condition variables - /* - * Padding to keep binary compatibility @see{MVP-1876} - * These padding bytes can be used for debugging. - */ - int line; - int lineUnl; - uint32 pad3; - uint32 pad4; - uint32 pad5; - uint32 pad6; -}; - -#define Mutex_Lock(a, b) Mutex_LockLine(a, b, __FILE__, __LINE__) -#define Mutex_Unlock(a, b) Mutex_UnlockLine(a, b, __LINE__) -#define Mutex_UnlSleep(a, b, c) Mutex_UnlSleepLine(a, b, c, __FILE__, __LINE__) -#define Mutex_UnlSleepTest(a, b, c, d, e) Mutex_UnlSleepTestLine(a, b, c, d, e, __FILE__, __LINE__) -int Mutex_LockLine(Mutex *mutex, MutexMode mode, const char *file, int line); -void Mutex_UnlockLine(Mutex *mutex, MutexMode mode, int line); -int Mutex_UnlSleepLine(Mutex *mutex, MutexMode mode, uint32 cvi, const char *file, int line); -int Mutex_UnlSleepTestLine(Mutex *mutex, MutexMode mode, uint32 cvi, AtmUInt32 *test, uint32 mask, const char *file, int line); -void Mutex_UnlWake(Mutex *mutex, MutexMode mode, uint32 cvi, _Bool all); - -#endif diff --git a/arch/arm/mvp/mvpkm/mutex_kernel.c b/arch/arm/mvp/mvpkm/mutex_kernel.c deleted file mode 100644 index 7b76bfcf..0000000 --- a/arch/arm/mvp/mvpkm/mutex_kernel.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The host kernel mutex functions. These mutexes can be located in - * shared address space with the monitor. - */ - -#include <linux/kernel.h> - -#include <asm/string.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/poll.h> -#include <linux/slab.h> -#include <linux/hardirq.h> - -#include "mvp.h" - -#include "arm_inline.h" -#include "coproc_defs.h" -#include "mutex_kernel.h" - -#define POLL_IN_PROGRESS_FLAG (1<<(30-MUTEX_CVAR_MAX)) - -#define INITWAITQ(waitQ) do { \ - init_waitqueue_head((wait_queue_head_t *)(waitQ)); \ -} while (0) - -#define WAKEUPALL(waitQ) do { \ - wake_up_all((wait_queue_head_t *)(waitQ)); \ -} while (0) - -#define WAKEUPONE(waitQ) do { \ - wake_up((wait_queue_head_t *)(waitQ)); \ -} while (0) - -/** - * @brief initialize mutex - * @param[in,out] mutex mutex to initialize - */ -void -Mutex_Init(Mutex *mutex) -{ - wait_queue_head_t *wq; - int i; - - wq = kcalloc(MUTEX_CVAR_MAX + 1, sizeof(wait_queue_head_t), 0); - FATAL_IF(wq == NULL); - - memset(mutex, 0, sizeof *mutex); - mutex->mtxHKVA = (HKVA)mutex; - mutex->lockWaitQ = (HKVA)&wq[0]; - INITWAITQ(mutex->lockWaitQ); - for (i = 0; i < MUTEX_CVAR_MAX; i ++) { - mutex->cvarWaitQs[i] = (HKVA)&wq[i + 1]; - INITWAITQ(mutex->cvarWaitQs[i]); - } -} - -/** - * @brief Check if it is ok to sleep - * @param file the file of the caller code - * @param line the line number of the caller code - */ -static void -MutexCheckSleep(const char *file, int line) -{ -#ifdef MVP_DEVEL - static unsigned long prev_jiffy; /* ratelimiting: 1/s */ - -#ifdef CONFIG_PREEMPT - if (preemptible() && !irqs_disabled()) { - return; - } -#else - if (!irqs_disabled()) { - return; - } -#endif - if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) { - return; - } - prev_jiffy = jiffies; - printk(KERN_ERR - "BUG: sleeping function called from invalid context at %s:%d\n", - file, line); - printk(KERN_ERR - "irqs_disabled(): %d, preemtible(): %d, pid: %d, name: %s\n", - irqs_disabled(), - preemptible(), - current->pid, current->comm); - dump_stack(); -#endif -} - -/** - * @brief destroy mutex - * @param[in,out] mutex mutex to destroy - */ -void -Mutex_Destroy(Mutex *mutex) -{ - kfree((void*)mutex->lockWaitQ); -} - -/** - * @brief Lock the mutex. Also does a data barrier after locking so the - * locking is complete before any shared data is accessed. - * @param[in,out] mutex which mutex to lock - * @param mode mutex lock mode - * @param file the file of the caller code - * @param line the line number of the code that called this function - * @return rc = 0: mutex now locked by caller<br> - * < 0: interrupted - */ -int -Mutex_LockLine(Mutex *mutex, MutexMode mode, const char *file, int line) -{ - Mutex_State newState, oldState; - - MutexCheckSleep(file, line); - - /* - * If uncontended, just set new lock state and return success status. - * If contended, mark state saying there is a waiting thread to wake. - */ - do { -lock_start: - /* - * Get current state and calculate what new state would be. - * New state adds 1 for shared and 0xFFFF for exclusive. - * If the 16 bit field overflows, there is contention. - */ - oldState.state = ATOMIC_GETO(mutex->state); - newState.mode = oldState.mode + mode; - newState.blck = oldState.blck; - - /* - * So we are saying there is no contention if new state - * indicates no overflow. - * - * On fairness: The test here allows a new-comer thread to grab - * the lock even if there is a blocked thread. For example 2 - * threads repeatedly obtaining shared access can starve a third - * wishing to obtain an exclusive lock. Currently this is only a - * hypothetical situation as mksck use exclusive lock only and - * the code never has more than 2 threads using the same mutex. - */ - if ((uint32)newState.mode >= (uint32)mode) { - if (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)) { - goto lock_start; - } - DMB(); - mutex->line = line; - mutex->lineUnl = -1; - return 0; - } - - /* - * There is contention, so increment the number of blocking threads. - */ - newState.mode = oldState.mode; - newState.blck = oldState.blck + 1; - } while (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)); - - /* - * Statistics... - */ - ATOMIC_ADDV(mutex->blocked, 1); - - /* - * Mutex is contended, state has been updated to say there is a blocking - * thread. - * - * So now we block till someone wakes us up. - */ - do { - DEFINE_WAIT(waiter); - - /* - * This will make sure we catch any wakes done after we check the lock - * state again. - */ - prepare_to_wait((wait_queue_head_t *)mutex->lockWaitQ, - &waiter, - TASK_INTERRUPTIBLE); - - /* - * Now that we will catch wakes, check the lock state again. If now - * uncontended, mark it locked, abandon the wait and return success. - */ - -set_new_state: - /* - * Same as the original check for contention above, except that we - * must decrement the number of waiting threads by one - * if we are successful in locking the mutex. - */ - oldState.state = ATOMIC_GETO(mutex->state); - newState.mode = oldState.mode + mode; - newState.blck = oldState.blck - 1; - ASSERT(oldState.blck); - - if ((uint32)newState.mode >= (uint32)mode) { - if (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)) { - goto set_new_state; - } - /* - * Mutex is no longer contended and we were able to lock it. - */ - finish_wait((wait_queue_head_t *)mutex->lockWaitQ, &waiter); - DMB(); - mutex->line = line; - mutex->lineUnl = -1; - return 0; - } - - /* - * Wait for a wake that happens any time after prepare_to_wait() - * returned. - */ - WARN(!schedule_timeout(10*HZ), "Mutex_Lock: soft lockup - stuck for 10s!\n"); - finish_wait((wait_queue_head_t *)mutex->lockWaitQ, &waiter); - } while (!signal_pending(current)); - - /* - * We aren't waiting anymore, so decrement the number of waiting threads. - */ - do { - oldState.state = ATOMIC_GETO(mutex->state); - newState.mode = oldState.mode; - newState.blck = oldState.blck - 1; - - ASSERT(oldState.blck); - - } while (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)); - - return -ERESTARTSYS; -} - - -/** - * @brief Unlock the mutex. Also does a data barrier before unlocking so any - * modifications made before the lock gets released will be completed - * before the lock is released. - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param line the line number of the code that called this function - */ -void -Mutex_UnlockLine(Mutex *mutex, MutexMode mode, int line) -{ - Mutex_State newState, oldState; - - DMB(); - do { - oldState.state = ATOMIC_GETO(mutex->state); - newState.mode = oldState.mode - mode; - newState.blck = oldState.blck; - mutex->lineUnl = line; - - ASSERT(oldState.mode >= mode); - } while (!ATOMIC_SETIF(mutex->state, newState.state, oldState.state)); - - /* - * If another thread was blocked, then wake it up. - */ - if (oldState.blck) { - if (mode == MutexModeSH) { - WAKEUPONE(mutex->lockWaitQ); - } else { - WAKEUPALL(mutex->lockWaitQ); - } - } -} - - -/** - * @brief Unlock the mutex and sleep. Also does a data barrier before - * unlocking so any modifications made before the lock gets released - * will be completed before the lock is released. - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param cvi which condition variable to sleep on - * @param file the file of the caller code - * @param line the line number of the caller code - * @return rc = 0: successfully waited<br> - * < 0: error waiting - */ -int -Mutex_UnlSleepLine(Mutex *mutex, MutexMode mode, uint32 cvi, const char *file, int line) -{ - return Mutex_UnlSleepTestLine(mutex, mode, cvi, NULL, 0, file, line); -} - -/** - * @brief Unlock the mutex and sleep. Also does a data barrier before - * unlocking so any modifications made before the lock gets released - * will be completed before the lock is released. - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param cvi which condition variable to sleep on - * @param test sleep only if null or pointed atomic value mismatches mask - * @param mask bitfield to check test against before sleeping - * @param file the file of the caller code - * @param line the line number of the caller code - * @return rc = 0: successfully waited<br> - * < 0: error waiting - */ -int -Mutex_UnlSleepTestLine(Mutex *mutex, MutexMode mode, uint32 cvi, AtmUInt32 *test, uint32 mask, const char *file, int line) -{ - DEFINE_WAIT(waiter); - - MutexCheckSleep(file, line); - - ASSERT(cvi < MUTEX_CVAR_MAX); - - /* - * Tell anyone who might try to wake us that they need to actually call - * WAKEUP***(). - */ - ATOMIC_ADDV(mutex->waiters, 1); - - /* - * Be sure to catch any wake that comes along just after we unlock the mutex - * but before we call schedule(). - */ - prepare_to_wait_exclusive((wait_queue_head_t *)mutex->cvarWaitQs[cvi], - &waiter, - TASK_INTERRUPTIBLE); - - /* - * Release the mutex, someone can wake us up now. - * They will see mutex->waiters non-zero so will actually do the wake. - */ - Mutex_Unlock(mutex, mode); - - /* - * Wait to be woken or interrupted. - */ - if (test == NULL || (ATOMIC_GETO(*test) & mask) == 0) { - schedule(); - } - finish_wait((wait_queue_head_t *)mutex->cvarWaitQs[cvi], &waiter); - - /* - * Done waiting, don't need a wake any more. - */ - ATOMIC_SUBV(mutex->waiters, 1); - - /* - * If interrupted, return error status. - */ - if (signal_pending(current)) { - return -ERESTARTSYS; - } - - /* - * Wait completed, return success status. - */ - return 0; -} - - -/** - * @brief Unlock the mutex and prepare to sleep on a kernel polling table - * given as anonymous parameters for poll_wait - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param cvi which condition variable to sleep on - * @param filp which file to poll_wait upon - * @param wait which poll_table to poll_wait upon - */ -void -Mutex_UnlPoll(Mutex *mutex, MutexMode mode, uint32 cvi, void *filp, void *wait) -{ - ASSERT(cvi < MUTEX_CVAR_MAX); - - /* poll_wait is done with mutex locked to prevent any wake that comes and - * defer them just after we unlock the mutex but before kernel polling - * tables are used - * Note that the kernel is probably avoiding an exclusive wait in that case - * and also increments the usage for the file given in filp - */ - poll_wait(filp, (wait_queue_head_t *)mutex->cvarWaitQs[cvi], wait); - - /* - * Tell anyone who might try to wake us that they need to actually call - * WAKEUP***(). This is done in putting ourselves in a "noisy" mode since - * there is no guaranty that we would really sleep, or if we would be - * wakening the sleeping thread with that socket or condition. This is - * done using a POLL_IN_PROGRESS_FLAG, but unfortunately it has to be - * a per-cvi flag, in case we would poll independently on different cvi - */ - DMB(); - ATOMIC_ORO(mutex->waiters, (POLL_IN_PROGRESS_FLAG << cvi)); - - /* - * Release the mutex, someone can wake us up now. - * They will see mutex->waiters non-zero so will actually do the wake. - */ - Mutex_Unlock(mutex, mode); -} - - -/** - * @brief Unlock the semaphore and wake sleeping threads. Also does a data - * barrier before unlocking so any modifications made before the lock - * gets released will be completed before the lock is released. - * @param mutex as passed to Mutex_Lock() - * @param mode as passed to Mutex_Lock() - * @param cvi which condition variable to signal - * @param all false: wake a single thread<br> - * true: wake all threads - */ -void -Mutex_UnlWake(Mutex *mutex, MutexMode mode, uint32 cvi, _Bool all) -{ - Mutex_Unlock(mutex, mode); - Mutex_CondSig(mutex, cvi, all); -} - - -/** - * @brief Signal condition variable, ie, wake up anyone waiting. - * @param mutex mutex that holds the condition variable - * @param cvi which condition variable to signal - * @param all false: wake a single thread<br> - * true: wake all threads - */ -void -Mutex_CondSig(Mutex *mutex, uint32 cvi, _Bool all) -{ - uint32 waiters; - - ASSERT(cvi < MUTEX_CVAR_MAX); - - waiters = ATOMIC_GETO(mutex->waiters); - if (waiters != 0) { - /* Cleanup the effects of Mutex_UnlPoll() but only when it is SMP safe, - * considering that atomic and wakeup operations should also do memory - * barriers accordingly. This is mandatory otherwise rare SMP races are - * even possible, since Mutex_CondSig is called with the associated mutex - * unlocked, and that does not prevent from select() to run parallel ! - */ - if ((waiters >= POLL_IN_PROGRESS_FLAG) && - !waitqueue_active((wait_queue_head_t *)mutex->cvarWaitQs[cvi])) { - ATOMIC_ANDO(mutex->waiters, ~(POLL_IN_PROGRESS_FLAG << cvi)); - } - DMB(); - - if (all) { - WAKEUPALL(mutex->cvarWaitQs[cvi]); - } else { - WAKEUPONE(mutex->cvarWaitQs[cvi]); - } - } -} diff --git a/arch/arm/mvp/mvpkm/mutex_kernel.h b/arch/arm/mvp/mvpkm/mutex_kernel.h deleted file mode 100644 index 4bdf0e1..0000000 --- a/arch/arm/mvp/mvpkm/mutex_kernel.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The host kernel mutex definitions. - */ - -#ifndef _MUTEX_KERNEL_H -#define _MUTEX_KERNEL_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mutex.h" - -void Mutex_Init(Mutex *mutex); -void Mutex_Destroy(Mutex *mutex); -void Mutex_CondSig(Mutex *mutex, uint32 cvi, _Bool all); -void Mutex_UnlPoll(Mutex *mutex, MutexMode mode, uint32 cvi, void *filp, void *wait); - -#endif diff --git a/arch/arm/mvp/mvpkm/mvp.h b/arch/arm/mvp/mvpkm/mvp.h deleted file mode 100644 index e21b8a0..0000000 --- a/arch/arm/mvp/mvpkm/mvp.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief top-level include for all basic includes. - * This file should not define anything of its own. - */ - -#ifndef _MVP_H -#define _MVP_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "mvp_compiler.h" -#include "utils.h" -#include "mvp_assert.h" -#include "mvp_types.h" -#include "platdefx.h" - -#endif diff --git a/arch/arm/mvp/mvpkm/mvp_assert.h b/arch/arm/mvp/mvpkm/mvp_assert.h deleted file mode 100644 index 9ee6fc0..0000000 --- a/arch/arm/mvp/mvpkm/mvp_assert.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief ASSERT() and related macros. - */ - -#ifndef _MVP_ASSERT_H -#define _MVP_ASSERT_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define ASSERT(_x) ASSERT_BUG((_x),0) - -#ifndef NDEBUG -#define ASSERT_BUG(_x,_tkt) do { \ - if (UNLIKELY(!(_x))) { \ - FatalError(__FILE__, __LINE__, FECodeAssert, _tkt, NULL); \ - } \ -} while (0) - -#define ASSERTF(_x, ...) do { \ - if (UNLIKELY(!(_x))) { \ - FatalError(__FILE__, \ - __LINE__, \ - FECodeAssert, \ - 0, \ - __VA_ARGS__); \ - } \ -} while (0) -#else - -#define ASSERT_BUG(_x,_tkt) (void)sizeof((int)(_x)) -#define ASSERTF(_x, ...) ASSERT_BUG(_x, 0) - -#endif - -/* - * Compile-time assertions. - * - * ASSERT_ON_COMPILE does not use the common - * switch (0) { case 0: case (e): ; } trick because some compilers (e.g. MSVC) - * generate code for it. - * - * The implementation uses both enum and typedef because the typedef alone is - * insufficient; gcc allows arrays to be declared with non-constant expressions - * (even in typedefs, where it makes no sense). - */ -#ifdef __COVERITY__ -#define ASSERT_ON_COMPILE(e) ASSERT(e) -#else -#define ASSERT_ON_COMPILE(e) \ - do { \ - enum { AssertOnCompileMisused = ((e) ? 1 : -1) }; \ - typedef char AssertOnCompileFailed[AssertOnCompileMisused]; \ - } while (0) -#endif - -/* - * To put an ASSERT_ON_COMPILE() outside a function, wrap it - * in MY_ASSERTS(). The first parameter must be unique in - * each .c file where it appears. For example, - * - * MY_ASSERTS(FS3_INT, - * ASSERT_ON_COMPILE(sizeof(FS3_DiskLock) == 128); - * ASSERT_ON_COMPILE(sizeof(FS3_DiskLockReserved) == DISK_BLOCK_SIZE); - * ASSERT_ON_COMPILE(sizeof(FS3_DiskBlock) == DISK_BLOCK_SIZE); - * ASSERT_ON_COMPILE(sizeof(Hardware_DMIUUID) == 16); - * ) - * - * Caution: ASSERT() within MY_ASSERTS() is silently ignored. - * The same goes for anything else not evaluated at compile time. - */ - -#define MY_ASSERTS(name, assertions) \ - static inline void name(void) { \ - assertions \ - } - -#define KNOWN_BUG(_tkt) - -#define NOT_IMPLEMENTED() NOT_IMPLEMENTED_JIRA(0) -#define NOT_IMPLEMENTED_JIRA(_tkt,...) FatalError(__FILE__, __LINE__, FECodeNI, _tkt, NULL) - -#define NOT_IMPLEMENTED_IF(_x) NOT_IMPLEMENTED_IF_JIRA((_x),0) -#define NOT_IMPLEMENTED_IF_JIRA(_x,_tkt,...) do { if (UNLIKELY(_x)) NOT_IMPLEMENTED_JIRA(_tkt); } while (0) -/* - * All sites tagged with this are @knownjira{MVP-1855}. - */ -#define NOT_IMPLEMENTEDF(...) FatalError(__FILE__, __LINE__, FECodeNI, 0, __VA_ARGS__) - -#define NOT_REACHED() FatalError(__FILE__, __LINE__, FECodeNR, 0, NULL) - -#include "fatalerror.h" -#include "nottested.h" - -#endif diff --git a/arch/arm/mvp/mvpkm/mvp_balloon.h b/arch/arm/mvp/mvpkm/mvp_balloon.h deleted file mode 100644 index 9df5669..0000000 --- a/arch/arm/mvp/mvpkm/mvp_balloon.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Common guest/host balloon state machine. - */ -#ifndef _MVP_BALLOON_H -#define _MVP_BALLOON_H - -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_MODULE -#include "include_check.h" - -/** - * @brief Balloon watchdog timeout (in seconds). - * - * If we don't hear back from the guest balloon driver in this amount of time, - * we terminate the guest. - * - * This can sound arbitrary long but we need to deal with checkpointing. The - * watchdog goal is only to not let not-responding VM running for ages. - */ -#define BALLOON_WATCHDOG_TIMEOUT_SECS 90 - -/** - * @brief MVP_BALLOON_GET_DELTA return. - */ -typedef union { - struct { - int32 delta : 21; ///< Number/direction balloon adjustment in pages. - }; - uint32 u; -} Balloon_GetDeltaRet; - -/** - * @name Guest settings for lowmemorykiller oom_adj and minfree thresholds, as reflected in - * the guest's /sys/module/lowmemorykiller/parameters/{minfree,adj}. - * - * @{ - */ - -/** - * @brief Android oom_adj levels for the various thresholds. - */ -typedef enum { - BALLOON_ANDROID_GUEST_OOM_ADJ_FOREGROUND_APP = 0, - BALLOON_ANDROID_GUEST_OOM_ADJ_VISIBLE_APP = 1, - BALLOON_ANDROID_GUEST_OOM_ADJ_SECONDARY_SERVER = 2, - BALLOON_ANDROID_GUEST_OOM_ADJ_BACKUP_APP = 2, - BALLOON_ANDROID_GUEST_OOM_ADJ_HOME_APP = 4, - BALLOON_ANDROID_GUEST_OOM_ADJ_HIDDEN_APP_MIN = 7, - BALLOON_ANDROID_GUEST_OOM_ADJ_CONTENT_PROVIDER = 14, - BALLOON_ANDROID_GUEST_OOM_ADJ_EMPTY_APP = 15 -} Balloon_AndroidGuestOOMAdj; - -/** - * @brief Android low memory killer thresholds (in pages). - */ -typedef enum { - BALLOON_ANDROID_GUEST_MIN_FREE_FOREGROUND_APP_PAGES = 1536, - BALLOON_ANDROID_GUEST_MIN_FREE_VISIBLE_APP_PAGES = 2048, - BALLOON_ANDROID_GUEST_MIN_FREE_SECONDARY_SERVER_PAGES = 4096, - BALLOON_ANDROID_GUEST_MIN_FREE_BACKUP_APP_PAGES = 4096, - BALLOON_ANDROID_GUEST_MIN_FREE_HOME_APP_PAGES = 4096, - BALLOON_ANDROID_GUEST_MIN_FREE_HIDDEN_APP_PAGES = 5120, - BALLOON_ANDROID_GUEST_MIN_FREE_CONTENT_PROVIDER_PAGES = 5632, - BALLOON_ANDROID_GUEST_MIN_FREE_EMPTY_APP_MEM_PAGES = 6144 -} Balloon_AndroidGuestMinFreePages; - -/* @} */ -/** - * @brief Calculate distance to the point at which Android will terminate - * processes. - * - * In the balloon policy we strive to maintain the low memory killer minfree - * value (e.g. max(freePages, filePages)) above the threshold for terminating - * empty apps (as per the Android low memory killer's logic). Here we measure - * the number of pages we have buffering us from this point. - * - * We chose the empty app threshold instead instead of the home app threshold, - * the threshold we ultimately want to avoid crossing for two reasons: - * - We want to avoid any error introduced by the use of max(free, file) when - * between the two thresholds from interfering with the errorBackground term - * in the balloon policy. If we instead measure the distance to the home app - * threshold, we can get into the situation that even when both sides have - * balanced background pages and the same low memory distance, different - * free/file ratios in the two worlds introduces a further bias. - * - It's helpful in avoiding extreme situations where the balloon won't be able - * to adapt quickly to leave a buffer. With empty app minfree as the target, - * when background pages drops to zero, and both worlds are below the empty - * app minfree target, the balloon will stop adjusting, leaving each world to - * fend for itself. At this point, the worlds have a maximum of 8192 pages - * (using the above logic) until they start killing services and foreground - * apps, which seems like a reasonable buffer to have in place. Another way of - * putting it is that at this point, we are unsure that rebalancing the - * balloon won't harm the side it balances against by eating into its buffer. - * - * We assume that normally filePages only decreases as a result of freePages - * being close to zero, when vmscan reclaiming kicks in. Based on this, - * there are two cases when computing the distance. - * - * - filePages >= emptyAppPages: - * freePages + filePages - emptyAppPages - * - filePages < emptyAppPages: - * MAX(0, freePages - emptyAppPages) - * - * @param freePages number of free pages. - * @param filePages number of pages in the page cache. - * @param emptyAppPages number of free/file pages at which the - * lowmemorykiller will start killing empty apps. - * - * @return Low memory distance measure (in pages). - */ -static inline uint32 -Balloon_LowMemDistance(uint32 freePages, uint32 filePages, uint32 emptyAppPages) -{ - return filePages >= emptyAppPages ? - freePages + (filePages - emptyAppPages) : - (freePages > emptyAppPages ? freePages - emptyAppPages : 0); -} - -#ifdef __KERNEL__ -/** - * @brief Obtain approximation of # anonymous pages belonging to Android - * background processes. - * - * Used to inform balloon policy. Note that this is a coarse approximation only, - * since we use RSS. More precise accounting is possible but potentially costly - * as it's not available directly in the task struct. - * - * @param hiddenAppOOMAdj minimum oom_adj for hidden apps. - * - * @return sum of empty, content provider and hidden app anon resident pages. - */ -static uint32 -Balloon_AndroidBackgroundPages(uint32 minHiddenAppOOMAdj) -{ - uint32 backgroundPages = 0, nonBackgroundPages = 0; - struct task_struct *t; - - /* - * Traverse the tasklist to replicate the behavior of the Android low memory - * killer. - */ - rcu_read_lock(); - - for_each_process(t) { - int oom_adj = 0; - - task_lock(t); - - if (t->signal == NULL) { - task_unlock(t); - continue; - } else { - oom_adj = t->signal->oom_adj; - } - - if (t->mm != NULL) { -#ifdef BALLOON_DEBUG_PRINT_ANDROID_PAGES - printk("Balloon_AndroidBackgroundPages: %d %d %s\n", - oom_adj, - (int)get_mm_counter(t->mm, MM_ANONPAGES), - t->comm); -#endif - - if (oom_adj >= (int)minHiddenAppOOMAdj) { - /* - * Unlike the Android low memory killer, we only consider anonymous - * memory here, since we already account for file pages in the - * balloon policy using global_page_state(NR_FILE_PAGES). - */ - backgroundPages += get_mm_counter(t->mm, MM_ANONPAGES); - } else { - nonBackgroundPages += get_mm_counter(t->mm, MM_ANONPAGES); - } - } - - task_unlock(t); - } - - rcu_read_unlock(); - -#ifdef BALLOON_DEBUG_PRINT_ANDROID_PAGES - printk("Balloon_AndroidBackgroundPages: non-background pages: %d " - "background pages: %d\n", - nonBackgroundPages, - backgroundPages); -#endif - - return backgroundPages; -} -#endif - -#endif diff --git a/arch/arm/mvp/mvpkm/mvp_compiler.h b/arch/arm/mvp/mvpkm/mvp_compiler.h deleted file mode 100644 index 58825a0..0000000 --- a/arch/arm/mvp/mvpkm/mvp_compiler.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Compiler-related definitions and directives. - */ - -#ifndef _MVP_COMPILER_H_ -#define _MVP_COMPILER_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#ifdef __GNUC__ -#include "mvp_compiler_gcc.h" -#else /* __GNUC__ */ -#include "mvp_compiler_other.h" -#endif /* __GNUC__ */ - -/** - * @brief Find last set bit. - * - * @param n unsigned 32-bit integer. - * - * @return 0 if n == 0 otherwise 32 - the number of leading zeroes in n. - */ -#define FLS(n) (32 - CLZ(n)) - -#endif /// ifndef _MVP_COMPILER_H_ diff --git a/arch/arm/mvp/mvpkm/mvp_compiler_gcc.h b/arch/arm/mvp/mvpkm/mvp_compiler_gcc.h deleted file mode 100644 index ab35ebd..0000000 --- a/arch/arm/mvp/mvpkm/mvp_compiler_gcc.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief common definitions for GCC - */ - -#ifndef _MVP_COMPILER_GCC_H -#define _MVP_COMPILER_GCC_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/** - * @brief Count leading zeroes. - * - * @param n unsigned 32-bit integer. - * - * @return 32 if n == 0 otherwise 31 - the bit position of the most significant 1 - * in n. - */ -#ifdef __COVERITY__ -static inline int -CLZ(unsigned int n) -{ - unsigned int r = 0; - - while (n) { - r++; - n >>= 1; - } - - return 32 - r; -} -#else -#define CLZ(n) __builtin_clz(n) -#endif - -#define PACKED __attribute__ ((packed)) -#define ALLOC __attribute__ ((malloc, warn_unused_result)) -#define UNUSED __attribute__ ((unused)) -#define PURE __attribute__ ((pure)) -#define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) -#define FORMAT(x,y,z) __attribute__ ((format(x,y,z))) -#define LIKELY(x) __builtin_expect(!!(x), 1) -#define UNLIKELY(x) __builtin_expect((x), 0) - -/* - * For debug builds, we want to omit __attribute__((noreturn)) so that gcc will - * keep stack linkages and then we will have useful core dumps. For non-debug - * builds, we don't care about the stack frames and want the little bit of - * optimization that noreturn gives us. - */ -#if defined(__COVERITY__) || !defined(MVP_DEBUG) -#define NORETURN __attribute__((noreturn)) -#else -#define NORETURN -#endif - -#endif diff --git a/arch/arm/mvp/mvpkm/mvp_math.h b/arch/arm/mvp/mvpkm/mvp_math.h deleted file mode 100644 index 7017bc8..0000000 --- a/arch/arm/mvp/mvpkm/mvp_math.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Math library. - */ - -#ifndef _MVP_MATH_H_ -#define _MVP_MATH_H_ - -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#define INCLUDE_ALLOW_HOSTUSER -#include "include_check.h" - -#include "mvp_compiler_gcc.h" - -/** - * @brief Compute floor log2 of a given 32-bit unsigned integer. - * - * @param n 32-bit unsigned integer, n > 0. - * - * @return floor(log2(n)). - */ -#define LOG2(n) \ -( \ - __builtin_constant_p(n) ? ( \ - (n) & (1UL << 31) ? 31 : \ - (n) & (1UL << 30) ? 30 : \ - (n) & (1UL << 29) ? 29 : \ - (n) & (1UL << 28) ? 28 : \ - (n) & (1UL << 27) ? 27 : \ - (n) & (1UL << 26) ? 26 : \ - (n) & (1UL << 25) ? 25 : \ - (n) & (1UL << 24) ? 24 : \ - (n) & (1UL << 23) ? 23 : \ - (n) & (1UL << 22) ? 22 : \ - (n) & (1UL << 21) ? 21 : \ - (n) & (1UL << 20) ? 20 : \ - (n) & (1UL << 19) ? 19 : \ - (n) & (1UL << 18) ? 18 : \ - (n) & (1UL << 17) ? 17 : \ - (n) & (1UL << 16) ? 16 : \ - (n) & (1UL << 15) ? 15 : \ - (n) & (1UL << 14) ? 14 : \ - (n) & (1UL << 13) ? 13 : \ - (n) & (1UL << 12) ? 12 : \ - (n) & (1UL << 11) ? 11 : \ - (n) & (1UL << 10) ? 10 : \ - (n) & (1UL << 9) ? 9 : \ - (n) & (1UL << 8) ? 8 : \ - (n) & (1UL << 7) ? 7 : \ - (n) & (1UL << 6) ? 6 : \ - (n) & (1UL << 5) ? 5 : \ - (n) & (1UL << 4) ? 4 : \ - (n) & (1UL << 3) ? 3 : \ - (n) & (1UL << 2) ? 2 : \ - (n) & (1UL << 1) ? 1 : \ - (n) & (1UL << 0) ? 0 : \ - 0xffffffff \ - ) : (uint32)(CLZ(1) - CLZ(n)) \ -) - -/** - * @brief Multiplicative hash function for 32-bit key and p-bit range. See p229 - * Introduction to Algorithms, Cormen, Leiserson and Rivest, 1996. - * - * @param key 32-bit key. - * @param p range order, <= 32. - * - * @return hash value in range [0..2^p) - */ -static inline uint32 -Math_MultiplicativeHash(uint32 key, uint32 p) -{ - return (key * 2654435769UL) >> (32 - p); -} - -/** - * @brief Compute ceiling log2 of a given 32-bit unsigned integer. - * - * @param n 32-bit unsigned integer, n > 0. - * - * @return ceiling(log2(n)). - */ -static inline uint32 CLOG2(uint32 n) -{ - return LOG2(n) + ((n & -n) != n); -} - - -/** - * @brief djb2 String hashing function by Dan Bernstein, see - * http://www.cse.yorku.ca/~oz/hash.html - * @param str String to hash - * @return 32-bit hash value - */ -static inline -uint32 Math_Djb2Hash(uint8 *str) -{ - uint32 hash = 5381; - int32 c; - - while ((c = *str++)) { - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - } - - return hash; -} - -#endif // ifndef _MVP_MATH_H_ diff --git a/arch/arm/mvp/mvpkm/mvp_timer.h b/arch/arm/mvp/mvpkm/mvp_timer.h deleted file mode 100644 index 0bd073a..0000000 --- a/arch/arm/mvp/mvpkm/mvp_timer.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief timer definitions - */ - -#ifndef _MVP_TIMER_H -#define _MVP_TIMER_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/** - * @brief timer tick rate as returned by MVPTimer_Now64 as a uint64 and used by - * MVPTimer.when64. - * - * For example 1,000,000 means the counter is in microseconds. - * - * Current implementation requires MVP_TIMER_RATE64 <= 1,000,000,000 and that - * it evenly divide 1,000,000,000. Currently 1,000,000,000 to avoid a multiply - * or divide in MVPTimer_Now64. - */ -#define MVP_TIMER_RATE64 1000000000 - -/* - * Extract current UNIX-style time_t date/time from the 64-bit time as returned - * by MVPTimer_Now64(). - */ -#define MVP_TIMER_RATE64_TIME_T(time64) ((time_t)((time64) / MVP_TIMER_RATE64)) - -typedef struct MVPTimer MVPTimer; - -/** - * @brief timer entry struct - */ -struct MVPTimer { - MVPTimer *next; ///< next in timers list - uint64 when64; ///< absolute expiration - void (*entry)(uint64 now64, MVPTimer *timer); ///< callback entrypoint - void *param; ///< callback parameter -}; - -void MVPTimer_InitVMX(void); -uint64 MVPTimer_Now64(void); -void MVPTimer_Start(MVPTimer *timer); -_Bool MVPTimer_Cancel(MVPTimer *timer); - -#endif diff --git a/arch/arm/mvp/mvpkm/mvp_types.h b/arch/arm/mvp/mvpkm/mvp_types.h deleted file mode 100644 index 035efd7..0000000 --- a/arch/arm/mvp/mvpkm/mvp_types.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief basic type definitions. - * These may need to be conditionalized for different compilers/platforms. - */ - -#ifndef _MVPTYPES_H -#define _MVPTYPES_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef unsigned long long uint64; - -typedef signed char int8; -typedef short int16; -typedef int int32; -typedef long long int64; - -typedef uint32 CVA; // whatever we are compiling the code as -typedef uint32 GVA; // guest virtual addresses -typedef uint32 MVA; // monitor virtual addresses -typedef uint32 HKVA; // host kernel virtual addresses -typedef uint32 HUVA; // host user virtual addresses -typedef uint64 PA; // (guest) physical addresses (40-bit) -typedef uint32 MA; // (host) machine addresses - -typedef uint32 PPN; // PA/PAGE_SIZE -typedef uint32 MPN; // MA/PAGE_SIZE - -typedef uint64 cycle_t; - -/** - * @brief Page segment. - * - * Specifies a segment within a single page. - */ -typedef struct { - uint16 off; - uint16 len; -} PageSeg; - -/* - * GCC's argument checking for printf-like functions - * - * fmtPos is the position of the format string argument, beginning at 1 - * varPos is the position of the variable argument, beginning at 1 - */ - -#if defined(__GNUC__) -# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos))) -#else -# define PRINTF_DECL(fmtPos, varPos) -#endif - -#if defined(__GNUC__) -# define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos))) -#else -# define SCANF_DECL(fmtPos, varPos) -#endif - -#endif /* _MVPTYPES_H */ diff --git a/arch/arm/mvp/mvpkm/mvp_version.h b/arch/arm/mvp/mvpkm/mvp_version.h deleted file mode 100644 index 31274dd..0000000 --- a/arch/arm/mvp/mvpkm/mvp_version.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief What version is this? - * - */ - -#ifndef _MVP_VERSION_H_ -#define _MVP_VERSION_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#define INCLUDE_ALLOW_HOSTUSER -#include "include_check.h" -#include "utils.h" - -/* - * MVP Internal Version Numbering - * - * - * There are 4 different usage areas of version information. - * - * Version Name. This is a marketing string that is used to sell the - * product. The update of this string has legal consequences, it - * should be done infrequently. Currently we use "V1.0" like - * terms. Developer builds have E.X.P as Version Name. - * - * Android Version Code. This is an integer associated with - * com.vmware.mvp.apk on Google Play (a.k.a Android Market). If our - * product is multi-apk (that is, we release individual apks for the - * different Android versions) then the Android Version Code must - * satisfy certain constrains. Typically the Android API level is - * the high order 2 digits. - * - * Engineering Version Code. During an update process of one of the - * 3 components on the handset (MVP, VVP, OEK) compatibility needs - * to be verified. The Engineering Version Code is a single number - * associated with each of the 4 components and it serves as a basis - * of this compatibility test. It reflects time, bigger number is - * associated with newer code. - * - * Git Revision. The git hash is a unique identifier of the - * source. If picked up from a log, engineers can go to the code - * depos and check out the exact code used for the build. For MVP, - * VVP, and OEK this is the main/mvp.git, for HMM it is - * main/mdm.git. Note that git hash is not ordered, it cannot be - * used to directly determine precedence. - * - */ - -#define MVP_VERSION_CODE 16800005 -#define MVP_VERSION_CODE_FORMATSTR "%s_%d" -#define MVP_VERSION_CODE_FORMATARGSV(V_) MVP_STRINGIFY(1.1.3), (V_) -#define MVP_VERSION_CODE_FORMATARGS \ - MVP_VERSION_CODE_FORMATARGSV(MVP_VERSION_CODE) - -#define MVP_VERSION_FORMATSTR \ - MVP_VERSION_CODE_FORMATSTR \ - " compiled at %s based on revision %s by user %s." - -#define MVP_VERSION_FORMATARGS \ - MVP_VERSION_CODE_FORMATARGS, \ - __DATE__, \ - MVP_STRINGIFY(5c995a85564cd060562bdbcd1422709e7a326301), \ - MVP_STRINGIFY() - -#define MvpVersion_Map(map_, version_) \ - ({ \ - uint32 ii_; \ - uint32 versionApi_ = 0; \ - for (ii_ = 0; ii_ < NELEM(map_); ii_++) { \ - if (map_[ii_] <= version_) { \ - versionApi_ = map_[ii_]; \ - } \ - } \ - versionApi_; \ - }) - -/* - * MVP.apk must communicate to VVP and OEK on many of its APIs. To - * ensure compatibility, it is mandated that any VVP and OEK version - * younger than the minimums defined below can be serviced on all of - * the various APIs. - * - * During the deprecation process, first a marketing decision is made - * that the limit below can be raised. After the new minimums are - * determined, they must be entered here. Then the various APIs can - * remove code that has been obsoleted before the new minimum versions. - */ -#define VVP_VERSION_CODE_MIN 0x0100020e -#define OEK_VERSION_CODE_MIN 0x01000001 - -#endif /* _MVP_VERSION_H_ */ diff --git a/arch/arm/mvp/mvpkm/mvpkm_comm_ev.c b/arch/arm/mvp/mvpkm/mvpkm_comm_ev.c deleted file mode 100644 index cb0ce26..0000000 --- a/arch/arm/mvp/mvpkm/mvpkm_comm_ev.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief mvpkm kernel hooks for Comm event signaling - */ - -#include <linux/module.h> -#include "comm_transp_impl.h" - -int (*CommTranspEvProcess)(CommTranspID* id, CommTranspIOEvent event); - - -/** - * @brief Register a processing callback for the host when a signal - * is received from the guest. Supports only a single comm "service" - * on the host. - * @param commProcessFunc function pointer to process a signal - */ - -void -Mvpkm_CommEvRegisterProcessCB(int (*commProcessFunc)(CommTranspID*, - CommTranspIOEvent)) -{ - CommTranspEvProcess = commProcessFunc; -} - -/** - * @brief Unregister the processing callback for the host when a signal - * is received from the guest. - */ - -void -Mvpkm_CommEvUnregisterProcessCB(void) -{ - CommTranspEvProcess = NULL; -} - - -EXPORT_SYMBOL(Mvpkm_CommEvRegisterProcessCB); -EXPORT_SYMBOL(Mvpkm_CommEvUnregisterProcessCB); diff --git a/arch/arm/mvp/mvpkm/mvpkm_comm_ev.h b/arch/arm/mvp/mvpkm/mvpkm_comm_ev.h deleted file mode 100644 index 2e3c960..0000000 --- a/arch/arm/mvp/mvpkm/mvpkm_comm_ev.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief mvpkm kernel hooks for comm event signaling - */ - -#ifndef _MVPKM_COMM_EV_H -#define _MVPKM_COMM_EV_H - -extern int (*CommTranspEvProcess)(CommTranspID* id, CommTranspIOEvent event); - -/** - * @brief Forward any guest signal requests to the commkm module - * @param id transport channel id - * @param event comm event type - */ - -static inline void -Mvpkm_CommEvSignal(CommTranspID *id, CommTranspIOEvent event) -{ - if (CommTranspEvProcess) { - CommTranspEvProcess(id, event); - } -} - -void -Mvpkm_CommEvRegisterProcessCB(int (*commProcessFunc)(CommTranspID*, - CommTranspIOEvent)); -void Mvpkm_CommEvUnregisterProcessCB(void); - - - -#endif diff --git a/arch/arm/mvp/mvpkm/mvpkm_kernel.h b/arch/arm/mvp/mvpkm/mvpkm_kernel.h deleted file mode 100644 index 19ba6ce..0000000 --- a/arch/arm/mvp/mvpkm/mvpkm_kernel.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -#ifndef _MVPKM_KERNEL_H -#define _MVPKM_KERNEL_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include <linux/rwsem.h> -#include <linux/kobject.h> -#include <linux/rbtree.h> - -#ifdef CONFIG_HAS_WAKELOCK -#include <linux/wakelock.h> -#endif - -#include "atomic.h" -#include "montimer_kernel.h" -#include "worldswitch.h" - -/** - * @file - * - * @brief The kernel level driver. - */ - -struct MvpkmVM { - struct kobject kobj; ///< used to hook into sysfs - struct kset *devicesKSet; ///< kset to list virtual device entries - struct kset *miscKSet; ///< kset to list miscellaneous entries - _Bool haveKObj; ///< used to properly release instance - struct rb_root lockedRoot; ///< locked page RB tree root - struct rw_semaphore lockedSem; ///< linked list rw semaphore - AtmUInt32 usedPages; ///< number of MEMREGION_MAINMEM pages - _Bool isMonitorInited; ///< Has SetupMonitor been called already? - WorldSwitchPage *wsp; ///< worldswitch page - wait_queue_head_t wfiWaitQ; ///< guest VCPU is waiting-for-interrupt - struct rw_semaphore wspSem; /*< prevents entries the WFI - wait Q from disappearing - underneath us in - MvpkmShrink. */ - MonTimer monTimer; /*< monitor timers, there - should be one of these - per VCPU */ - MPN stubPageMPN; /*< stub page to be used for - unmappable pages */ - struct vm_struct *wspHkvaArea; ///< VM area struct for wspHkvaArea - HKVA wspHKVADummyPage;///< Dummy page used for backing wspHkvaArea -#ifdef CONFIG_HAS_WAKELOCK - struct wake_lock wakeLock; ///< guest running wake lock -#endif - struct rw_semaphore monThreadTaskSem;/*< prevents monThreadTask from - disappearing underneath us */ - struct task_struct *monThreadTask; - struct timer_list balloonWDTimer; /// Balloon watchdog timer - _Bool balloonWDEnabled; /// Balloon watchdog enabled? -}; - -typedef struct MvpkmVM MvpkmVM; - -void Mvpkm_WakeGuest(MvpkmVM *vm, int why); -struct kset *Mvpkm_FindVMNamedKSet(int vmID, const char *name); - -#endif diff --git a/arch/arm/mvp/mvpkm/mvpkm_main.c b/arch/arm/mvp/mvpkm/mvpkm_main.c deleted file mode 100644 index d32a4c1..0000000 --- a/arch/arm/mvp/mvpkm/mvpkm_main.c +++ /dev/null @@ -1,2691 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief The kernel level driver. - */ - -#define __KERNEL_SYSCALLS__ -#include <linux/version.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/fcntl.h> -#include <linux/syscalls.h> -#include <linux/kmod.h> -#include <linux/socket.h> -#include <linux/net.h> -#include <linux/skbuff.h> -#include <linux/miscdevice.h> -#include <linux/poll.h> -#include <linux/smp.h> -#include <linux/capability.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/sysfs.h> -#include <linux/pid.h> -#include <linux/highmem.h> -#include <linux/syscalls.h> - -#ifdef CONFIG_HAS_WAKELOCK -#include <linux/wakelock.h> -#endif - -#include <net/sock.h> - -#include <asm/cacheflush.h> -#include <asm/memory.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/uaccess.h> - -#include "mvp.h" -#include "mvp_version.h" -#include "mvpkm_types.h" -#include "mvpkm_private.h" -#include "mvpkm_kernel.h" -#include "actions.h" -#include "wscalls.h" -#include "arm_inline.h" -#include "tsc.h" -#include "mksck_kernel.h" -#include "mmu_types.h" -#include "mvp_timer.h" -#include "qp.h" -#include "qp_host_kernel.h" -#include "cpufreq_kernel.h" -#include "mvpkm_comm_ev.h" -#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER -#include "mvp_balloon.h" -#endif - - -/********************************************************************* - * - * Definition of the file operations - * - *********************************************************************/ -static _Bool LockedListAdd(MvpkmVM *vm, - __u32 mpn, - __u32 order, - PhysMem_RegionType forRegion); -static _Bool LockedListDel(MvpkmVM *vm, __u32 mpn); -static void LockedListUnlockAll(MvpkmVM *vm); -static _Bool LockedListLookup(MvpkmVM *vm, __u32 mpn); -static int SetupMonitor(MvpkmVM *vm); -static int RunMonitor(MvpkmVM *vm); -static MPN AllocZeroedFreePages(MvpkmVM *vm, - uint32 order, - _Bool highmem, - PhysMem_RegionType forRegion, - HKVA *hkvaRet); -static HKVA MapWSPHKVA(MvpkmVM *vm, HkvaMapInfo *mapInfo); -static void UnmapWSPHKVA(MvpkmVM *vm); -static int MvpkmWaitForInt(MvpkmVM *vm, _Bool suspend); -static void ReleaseVM(MvpkmVM *vm); - -/* - * Mksck open request must come from this uid. It must be root until - * it is set via an ioctl from mvpd. - */ -uid_t Mvpkm_vmwareUid = 0; -EXPORT_SYMBOL(Mvpkm_vmwareUid); - -/* - * Minimum hidden app oom_adj, provided by mvpd, since we can't get it directly - * from the lowmemorykiller module. - */ -static int minHiddenAppOOMAdj; - -/* - * vCPU cpu affinity to let monitor/guest run on some CPUs only (when possible) - */ -static DECLARE_BITMAP(vcpuAffinity, NR_CPUS); - -/********************************************************************* - * - * Sysfs nodes - * - *********************************************************************/ -/* - * kobject for our sysfs representation, used for global nodes. - */ -static struct kobject *mvpkmKObj; - -/* - * kobject for the balloon exports. - */ -static struct kobject *balloonKObj; - -/** - * @brief sysfs show function for global version attribute. - * - * @param kobj reference to kobj nested in MvpkmVM struct. - * @param attr kobj_attribute reference, not used. - * @param buf PAGE_SIZEd buffer to write to. - * - * @return number of characters printed (not including trailing null character). - */ -static ssize_t -version_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, MVP_VERSION_FORMATSTR "\n", MVP_VERSION_FORMATARGS); -} - -static struct kobj_attribute versionAttr = __ATTR_RO(version); - -/** - * @brief sysfs show function for global background_pages attribute. - * - * Used by vmx balloon policy controller to gauge the amount of freeable - * anonymous memory. - * - * @param kobj reference to kobj nested in MvpkmVM struct. - * @param attr kobj_attribute reference, not used. - * @param buf PAGE_SIZEd buffer to write to. - * - * @return number of characters printed (not including trailing null character). - */ -static ssize_t -background_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -{ -#ifndef CONFIG_ANDROID_LOW_MEMORY_KILLER - return snprintf(buf, PAGE_SIZE, "0\n"); -#else - return snprintf(buf, PAGE_SIZE, "%d\n", Balloon_AndroidBackgroundPages(minHiddenAppOOMAdj)); -#endif -} - -static struct kobj_attribute backgroundAttr = __ATTR_RO(background); - -/** - * @brief sysfs show function to export the other_file calculation in - * lowmemorykiller. - * - * It's helpful, in the balloon controller, to know what the lowmemorykiller - * module is using to know when the system has crossed a minfree threshold. - * Since there exists a number of different other_file calculations in various - * lowmemorykiller patches (@see{MVP-1674}), and the module itself doesn't - * provide a clean export of this figure, we provide it on a case-by-case basis - * for the various supported hosts here. - * - * @param kobj reference to kobj nested in MvpkmVM struct. - * @param attr kobj_attribute reference, not used. - * @param buf PAGE_SIZEd buffer to write to. - * - * @return number of characters printed (not including trailing null character). - */ -static ssize_t -other_file_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -{ - int32 other_file = 0; - -#ifndef LOWMEMKILLER_VARIANT -#define LOWMEMKILLER_VARIANT 0 -#endif - -#ifndef LOWMEMKILLER_MD5 -#define LOWMEMKILLER_MD5 0 -#endif - -#ifndef LOWMEMKILLER_SHRINK_MD5 -#define LOWMEMKILLER_SHRINK_MD5 0 -#endif - - /* - * The build system hashes the lowmemorykiller section related to the - * other_file calculation in the kernel source for us, here we have to - * provide the code. - */ -#if LOWMEMKILLER_VARIANT == 1 - /* - * This is the same as the non-exported global_reclaimable_pages() when there - * is no swap. - */ - other_file = global_page_state(NR_ACTIVE_FILE) + - global_page_state(NR_INACTIVE_FILE); -#elif LOWMEMKILLER_VARIANT == 2 - other_file = global_page_state(NR_FILE_PAGES); -#elif LOWMEMKILLER_VARIANT == 3 - other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM); -#elif LOWMEMKILLER_VARIANT == 4 - /* - * Here free/file pages are fungible and max(free, file) isn't used, but we - * can continue to use max(free, file) since max(free, file) = other_file in - * this case. - */ - other_file = global_page_state(NR_FREE_PAGES) + global_page_state(NR_FILE_PAGES); -#elif defined(NONANDROID) - /* - * Non-Android host platforms don't have ballooning enabled. - */ -#else - /* - * If you get this message, you need to run 'make lowmem-info' and inspect - * lowmemorykiller.c. If the "other_file = ..." calculation in lowmem_shrink - * appears above, simply add the "Shrink#" to an existing entry in - * lowmemkiller-variant.sh, pointing to the variant number above. Otherwise, - * provide a new entry above and variant number, with the appropriate - * other_file calculation and update lowmemkiller-variant.sh accordingly. - */ -//#warning "Unknown lowmemorykiller variant in hosted/module/mvpkm_main.c, falling back on default (see other_file_show for the remedy)" - /* - * Fall back on default - this may bias strangely for/against the host, but - * nothing catastrophic should result. - */ - other_file = global_page_state(NR_FILE_PAGES); -#endif - -#define _STRINGIFY(x) #x -#define STRINGIFY(x) _STRINGIFY(x) - return snprintf(buf, - PAGE_SIZE, - "%d %d %s %s\n", - other_file, - LOWMEMKILLER_VARIANT, - STRINGIFY(LOWMEMKILLER_MD5), - STRINGIFY(LOWMEMKILLER_SHRINK_MD5)); -#undef _STRINGIFY -#undef STRINGIFY -} - -static struct kobj_attribute otherFileAttr = __ATTR_RO(other_file); - -/* - * kset for our sysfs representation, used for per-VM nodes. - */ -static struct kset *mvpkmKSet; - -static ssize_t MvpkmAttrShow(struct kobject *kobj, - struct attribute *attr, - char *buf); -static ssize_t MvpkmAttrStore(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t count); - -static void MvpkmKObjRelease(struct kobject *kobj) - __attribute__ ((optimize ("-fomit-frame-pointer"))); - - -/** - * @brief Releases the vm structure containing the kobject. - * - * @param kobj the vm's kobject. - */ - -static void -MvpkmKObjRelease(struct kobject *kobj) -{ - MvpkmVM *vm = container_of(kobj, MvpkmVM, kobj); - - ReleaseVM(vm); - - module_put(THIS_MODULE); -} - - -/** - * @name mvpkm ktype attribute structures for locked_pages. - * - * @{ - */ -static struct sysfs_ops mvpkmSysfsOps = { - .show = MvpkmAttrShow, - .store = MvpkmAttrStore -}; - -static struct attribute mvpkmLockedPagesAttr = { - .name = "locked_pages", - .mode = 0444, -}; - -static struct attribute mvpkmBalloonWatchdogAttr = { - .name = "balloon_watchdog", - .mode = 0666 -}; - -static struct attribute mvpkmMonitorAttr = { - .name = "monitor", - .mode = 0400, -}; - -static struct attribute *mvpkmDefaultAttrs[] = { - &mvpkmLockedPagesAttr, - &mvpkmBalloonWatchdogAttr, - &mvpkmMonitorAttr, - NULL, -}; - -static struct kobj_type mvpkmKType = { - .sysfs_ops = &mvpkmSysfsOps, - .release = MvpkmKObjRelease, - .default_attrs = mvpkmDefaultAttrs, -}; -/*@}*/ - -/* - * As it is not very common for host kernels to have SYS_HYPERVISOR enabled and - * you have to "hack" a Kconfig file to enable it, just include the - * functionality inline if it is not enabled. - */ -#ifndef CONFIG_SYS_HYPERVISOR -struct kobject *hypervisor_kobj; -EXPORT_SYMBOL_GPL(hypervisor_kobj); -#endif - - -/* - * kobject and kset utilities. - */ - -extern struct kobject *kset_find_obj(struct kset *, const char *) - __attribute__((weak)); - - -/** - * @brief Finds a kobject in a kset. The actual implementation is copied from - * kernel source in lib/kobject.c. Although the symbol is extern-declared, - * it is not EXPORT_SYMBOL-ed. We use a weak reference in case the symbol - * might be exported in future kernel versions. - * - * @param kset set to search. - * @param name object name. - * - * @return retained kobject if found, NULL otherwise. - */ - -struct kobject * -kset_find_obj(struct kset *kset, - const char *name) -{ - struct kobject *k; - struct kobject *ret = NULL; - - spin_lock(&kset->list_lock); - list_for_each_entry(k, &kset->list, entry) { - if (kobject_name(k) && !strcmp(kobject_name(k), name)) { - ret = kobject_get(k); - break; - } - } - spin_unlock(&kset->list_lock); - return ret; -} - - -/** - * @brief Finds one of the VM's pre-defined ksets. - * - * @param vmID a VM ID. - * @param name name of one of the VM's pre-defined ksets. - * - * @return retained kset if found, NULL otherwise. - */ - -struct kset * -Mvpkm_FindVMNamedKSet(int vmID, - const char *name) -{ - MvpkmVM *vm; - struct kobject *kobj; - char vmName[32] = {}; /* Large enough to hold externally-formatted int32. */ - struct kset *res = NULL; - - if (!mvpkmKSet) { - return NULL; - } - - snprintf(vmName, sizeof vmName, "%d", vmID); - vmName[sizeof vmName - 1] = '\0'; /* Always null-terminate, no overflow. */ - - kobj = kset_find_obj(mvpkmKSet, vmName); - if (!kobj) { - return NULL; - } - - vm = container_of(kobj, MvpkmVM, kobj); - - if (!strcmp(name, "devices")) { - res = kset_get(vm->devicesKSet); - } else if (!strcmp(name, "misc")) { - res = kset_get(vm->miscKSet); - } - - kobject_put(kobj); - return res; -} - -EXPORT_SYMBOL(Mvpkm_FindVMNamedKSet); - - - -/********************************************************************* - * - * Standard Linux miscellaneous device registration - * - *********************************************************************/ - -MODULE_LICENSE("GPL"); // for kallsyms_lookup_name - -static int MvpkmFault(struct vm_area_struct *vma, struct vm_fault *vmf); - - -/** - * @brief Linux vma operations for /dev/mem-like kernel module mmap. We - * enforce the restriction that only MPNs that have been allocated - * to the opened VM may be mapped and also increment the reference - * count (via vm_insert_page), so that even if the memory is later - * freed by the VM, host process vma's containing the MPN can't - * compromise the system. - * - * However, only trusted host processes (e.g. the vmx) should be allowed - * to use this interface, since you can mmap the monitor's code/data/ - * page tables etc. with it. Untrusted host processes are limited to - * typed messages for sharing memory with the monitor. Unix file system - * access permissions are the intended method of restricting access. - * Unfortunately, today _any_ host process utilizing Mksck requires - * access to mvpkm to setup its Mksck pages and obtain socket info via - * ioctls - we probably should be exporting two devices, one for trusted - * and one for arbitrary host processes to avoid this confusion of - * concerns. - */ -static struct vm_operations_struct mvpkmVMOps = { - .fault = MvpkmFault -}; - -/* - * Generic kernel module file ops. These functions will be registered - * at the time the kernel module is loaded. - */ -static long MvpkmUnlockedIoctl(struct file *filep, - unsigned int cmd, - unsigned long arg); -static int MvpkmOpen(struct inode *inode, struct file *filp); -static int MvpkmRelease(struct inode *inode, struct file *filp); -static int MvpkmMMap(struct file *file, struct vm_area_struct *vma); - -/** - * @brief the file_operation structure contains the callback functions - * that are registered with Linux to handle file operations on - * the mvpkm device. - * - * The structure contains other members that the mvpkm device - * does not use. Those members are auto-initialized to NULL. - * - * WARNING, this structure has changed after Linux kernel 2.6.19: - * readv/writev are changed to aio_read/aio_write (neither is used here). - */ -static const struct file_operations mvpkmFileOps = { - .owner = THIS_MODULE, - .unlocked_ioctl = MvpkmUnlockedIoctl, - .open = MvpkmOpen, - .release = MvpkmRelease, - .mmap = MvpkmMMap -}; - -/** - * @brief The mvpkm device identifying information to be used to register - * the device with the Linux kernel. - */ -static struct miscdevice mvpkmDev = { - .minor = 165, - .name = "mvpkm", - .fops = &mvpkmFileOps -}; - -/** - * Mvpkm is loaded by mvpd and only mvpd will be allowed to open - * it. There is a very simple way to verify that: record the process - * id (thread group id) at the time the module is loaded and test it - * at the time the module is opened. - */ -static struct pid *initTgid; - - -#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER -/** - * @name Slab shrinker for triggering balloon adjustment. - * - * @note shrinker us used as a trigger for guest balloon. - * - * @{ - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) -static int MvpkmShrink(struct shrinker *this, struct shrink_control *sc); -#else -static int MvpkmShrink(struct shrinker *this, int nrToScan, gfp_t gfpMask); -#endif - -static struct shrinker mvpkmShrinker = { - .shrink = MvpkmShrink, - .seeks = DEFAULT_SEEKS -}; -/*@}*/ -#endif - -module_param_array(vcpuAffinity, ulong, NULL, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(vcpuAffinity, "vCPU affinity"); - - -/** - * @brief Initialize the mvpkm device, register it with the Linux kernel. - * - * @return A zero is returned on success and a negative errno code for failure. - * (Same as the return policy of misc_register(9).) - */ - -static int __init -MvpkmInit(void) -{ - int err = 0; - _Bool mksckInited = false; - _Bool cpuFreqInited = false; - - printk(KERN_INFO "Mvpkm: " MVP_VERSION_FORMATSTR "\n", MVP_VERSION_FORMATARGS); - printk(KERN_INFO "Mvpkm: loaded from process %s tgid=%d, pid=%d\n", - current->comm, - task_tgid_vnr(current), - task_pid_vnr(current)); - - if (bitmap_empty(vcpuAffinity, NR_CPUS)) { - bitmap_copy(vcpuAffinity, cpumask_bits(cpu_possible_mask), NR_CPUS); - } - - if ((err = misc_register(&mvpkmDev))) { - return -ENOENT; - } - - if ((err = Mksck_Init())) { - goto error; - } else { - mksckInited = true; - } - - QP_HostInit(); - - CpuFreq_Init(); - cpuFreqInited = true; - - /* - * Reference mvpd (module loader) tgid struct, so that we can avoid - * attacks based on pid number wraparound. - */ - initTgid = get_pid(task_tgid(current)); - -#ifndef CONFIG_SYS_HYPERVISOR - hypervisor_kobj = kobject_create_and_add("hypervisor", NULL); - if (!hypervisor_kobj) { - err = -ENOMEM; - goto error; - } -#endif - - if (!(mvpkmKObj = kobject_create_and_add("mvp", hypervisor_kobj)) || - !(balloonKObj = kobject_create_and_add("lowmem", mvpkmKObj)) || - !(mvpkmKSet = kset_create_and_add("vm", NULL, mvpkmKObj))) { - err = -ENOMEM; - goto error; - } - - if ((err = sysfs_create_file(mvpkmKObj, &versionAttr.attr))) { - goto error; - } - - if ((err = sysfs_create_file(balloonKObj, &backgroundAttr.attr))) { - goto error; - } - - if ((err = sysfs_create_file(balloonKObj, &otherFileAttr.attr))) { - goto error; - } - -#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER - register_shrinker(&mvpkmShrinker); -#endif - - MksckPageInfo_Init(); - - return 0; - -error: - if (mvpkmKSet) { - kset_unregister(mvpkmKSet); - } - - if (balloonKObj) { - kobject_del(balloonKObj); - kobject_put(balloonKObj); - } - - if (mvpkmKObj) { - kobject_del(mvpkmKObj); - kobject_put(mvpkmKObj); - } - -#ifndef CONFIG_SYS_HYPERVISOR - if (hypervisor_kobj) { - kobject_del(hypervisor_kobj); - kobject_put(hypervisor_kobj); - } -#endif - - if (cpuFreqInited) { - CpuFreq_Exit(); - } - - if (mksckInited) { - Mksck_Exit(); - } - - if (initTgid) { - put_pid(initTgid); - } - - misc_deregister(&mvpkmDev); - return err; -} - -/** - * @brief De-register the mvpkm device with the Linux kernel. - */ -void -MvpkmExit(void) -{ - PRINTK(KERN_INFO "MvpkmExit called !\n"); - - MksckPageInfo_Exit(); - -#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER - unregister_shrinker(&mvpkmShrinker); -#endif - - kset_unregister(mvpkmKSet); - kobject_del(balloonKObj); - kobject_put(balloonKObj); - kobject_del(mvpkmKObj); - kobject_put(mvpkmKObj); -#ifndef CONFIG_SYS_HYPERVISOR - kobject_del(hypervisor_kobj); - kobject_put(hypervisor_kobj); -#endif - - CpuFreq_Exit(); - - Mksck_Exit(); - - put_pid(initTgid); - - misc_deregister(&mvpkmDev); -} - -/* - * The standard module registration macros of Linux. - */ -module_init(MvpkmInit); -module_exit(MvpkmExit); - -module_param_named(minHiddenAppOOMAdj, minHiddenAppOOMAdj, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(minHiddenAppOOMAdj, "minimum hidden app oom_adj, as per lowmemorykiller"); - -#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER -/** - * @brief Balloon watchdog timeout callback. - * - * Terminate the VM since it's not responsive. - * - * @param data vm reference representation. - */ -static void -WatchdogCB(unsigned long data) -{ - MvpkmVM *vm = (MvpkmVM *)data; - - printk("Balloon watchdog expired (%d s)!\n", BALLOON_WATCHDOG_TIMEOUT_SECS); - - Mvpkm_WakeGuest(vm, ACTION_ABORT); -} - -/** - * @brief Slab shrinker. - * - * Called by Linux kernel when we're under memory pressure. We treat all locked - * pages as a slab for this purpose, similar to the Android low memory killer. - * - * @param this reference to registered shrinker for callback context. - * @param nrToScan number of entries to scan. If 0 then just return the number - * of present entries. We ignore the value of nrToScan when > 1 - * since the shrinker is a trigger to readjust guest balloons, - * where the actual balloon size is determined in conjunction - * with the guest. - * @param gfpMask ignored. - * - * @return number of locked pages. - */ -static int -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) -MvpkmShrink(struct shrinker *this, struct shrink_control *sc) -#else -MvpkmShrink(struct shrinker *this, int nrToScan, gfp_t gfpMask) -#endif -{ - uint32 locked = 0; - struct kobject *k; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) - int nrToScan = sc->nr_to_scan; -#endif - - spin_lock(&mvpkmKSet->list_lock); - - list_for_each_entry(k, &mvpkmKSet->list, entry) { - MvpkmVM *vm = container_of(k, MvpkmVM, kobj); - - locked += ATOMIC_GETO(vm->usedPages); - - /* - * Try and grab the WSP semaphore - if we fail, we must be VM setup or - * teardown, no point trying to wake the guest. - */ - if (nrToScan > 0 && - down_read_trylock(&vm->wspSem)) { - - if (vm->wsp) { - Mvpkm_WakeGuest(vm, ACTION_BALLOON); - - /* - * Balloon watchdog. - */ - if (vm->balloonWDEnabled) { - struct timer_list *t = &vm->balloonWDTimer; - - if (!timer_pending(t)) { - t->data = (unsigned long)vm; - t->function = WatchdogCB; - t->expires = jiffies + BALLOON_WATCHDOG_TIMEOUT_SECS * HZ; - add_timer(t); - } - } - } - - up_read(&vm->wspSem); - } - } - - spin_unlock(&mvpkmKSet->list_lock); - - return locked; -} -#endif - - -/** - * @brief The open file operation. Initializes the vm specific structure. - */ -int -MvpkmOpen(struct inode *inode, struct file *filp) -{ - MvpkmVM *vm; - - if (initTgid != task_tgid(current)) { - printk(KERN_ERR "%s: MVPKM can be opened only from MVPD (process %d).\n", - __FUNCTION__, pid_vnr(initTgid)); - return -EPERM; - } - printk(KERN_DEBUG "%s: Allocating an MvpkmVM structure from process %s tgid=%d, pid=%d\n", - __FUNCTION__, - current->comm, - task_tgid_vnr(current), - task_pid_vnr(current)); - - vm = kmalloc(sizeof(MvpkmVM), GFP_KERNEL); - if (!vm) { - return -ENOMEM; - } - - memset(vm, 0, sizeof *vm); - - init_timer(&vm->balloonWDTimer); - init_rwsem(&vm->lockedSem); - init_rwsem(&vm->wspSem); - init_rwsem(&vm->monThreadTaskSem); - vm->monThreadTask = NULL; - vm->isMonitorInited = false; - - filp->private_data = vm; - - if (!Mvpkm_vmwareUid) { - Mvpkm_vmwareUid = current_euid(); - } - - return 0; -} - -/** - * @brief Releases a VMs resources - * @param vm vm to release - */ -static void -ReleaseVM(MvpkmVM *vm) -{ - del_timer_sync(&vm->balloonWDTimer); - - down_write(&vm->wspSem); - - if (vm->isMonitorInited) { - MonitorTimer_Request(&vm->monTimer, 0); -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_destroy(&vm->wakeLock); -#endif - Mksck_WspRelease(vm->wsp); - vm->wsp = NULL; - } - - up_write(&vm->wspSem); - - LockedListUnlockAll(vm); - - UnmapWSPHKVA(vm); - - /* - * All sockets potentially connected to sockets of this vm's vmId will fail - * at send now. DGRAM sockets are note required to tear down connection - * explicitly. - */ - - kfree(vm); -} - -/** - * @brief The release file operation. Releases the vm specific - * structure including all the locked pages. - * - * @param inode Unused - * @param filp which VM we're dealing with - * @return 0 - */ -int -MvpkmRelease(struct inode *inode, struct file *filp) -{ - MvpkmVM *vm = filp->private_data; - - /* - * Tear down any queue pairs associated with this VM - */ - if (vm->isMonitorInited) { - ASSERT(vm->wsp); - QP_DetachAll(vm->wsp->guestId); - } - - /* - * Release the VM's ksets. - */ - - kset_unregister(vm->miscKSet); - kset_unregister(vm->devicesKSet); - - if (vm->haveKObj) { - /* - * Release the VM's kobject. - * 'vm' will be kfree-d in its kobject's release function. - */ - - kobject_del(&vm->kobj); - kobject_put(&vm->kobj); - } else { - ReleaseVM(vm); - } - - filp->private_data = NULL; - - printk(KERN_INFO "%s: Released MvpkmVM structure from process %s tgid=%d, pid=%d\n", - __FUNCTION__, - current->comm, - task_tgid_vnr(current), - task_pid_vnr(current)); - - return 0; -} - -/** - * @brief Page fault handler for /dev/mem-like regions (see mvpkmVMOps - * block comment). - */ -static int -MvpkmFault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - unsigned long address = (unsigned long)vmf->virtual_address; - MPN mpn = vmf->pgoff; - MvpkmVM *vm = vma->vm_file->private_data; - - - /* - * Only insert pages belonging to the VM. The check is slow, O(n) in the - * number of MPNs associated with the VM, but it doesn't matter - the mmap - * interface should only be used by trusted processes at initialization - * time and for debugging. - * - * The mpn can be either in the memory reserved the monitor or mvpd - * through the regular mechanisms or it could be a mksck page. - */ - if (!pfn_valid(mpn)) { - printk(KERN_ERR "MvpkmMMap: Failed to insert %x @ %lx, mpn invalid\n", - mpn, - address); - } else if (LockedListLookup(vm, mpn)) { - if (vm_insert_page(vma, address, pfn_to_page(mpn)) == 0) { - return VM_FAULT_NOPAGE; - } - - printk(KERN_ERR "MvpkmMMap: Failed to insert %x @ %lx \n", - mpn, - address); - } else if (MksckPage_LookupAndInsertPage(vma, address, mpn) == 0) { - return VM_FAULT_NOPAGE; - } - - if (vm->stubPageMPN) { - if (vm_insert_page(vma, address, pfn_to_page(vm->stubPageMPN)) == 0) { - printk(KERN_INFO "MvpkmMMap: mapped the stub page at %x @ %lx \n", - mpn, - address); - return VM_FAULT_NOPAGE; - } - - printk(KERN_ERR "MvpkmMMap: Could not insert stub page %x @ %lx \n", - mpn, - address); - - } - - return VM_FAULT_SIGBUS; -} - -/** - * @brief sysfs show function for per-VM locked_pages attribute. - * - * @param kobj reference to kobj nested in MvpkmVM struct. - * @param attr attribute reference. - * @param buf PAGE_SIZEd buffer to write to. - * - * @return number of characters printed (not including trailing null character). - */ -static ssize_t -MvpkmAttrShow(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - if (attr == &mvpkmLockedPagesAttr) { - MvpkmVM *vm = container_of(kobj, MvpkmVM, kobj); - - return snprintf(buf, PAGE_SIZE, "%d\n", ATOMIC_GETO(vm->usedPages)); - } else if (attr == &mvpkmMonitorAttr) { - MvpkmVM *vm = container_of(kobj, MvpkmVM, kobj); - - return snprintf(buf, - PAGE_SIZE, - "hostActions %x callno %d\n", - ATOMIC_GETO(vm->wsp->hostActions), - WSP_Params(vm->wsp)->callno); - } else { - return -EPERM; - } -} - -/** - * @brief sysfs store function for per-VM locked_pages attribute. - * - * @param kobj reference to kobj nested in MvpkmVM struct. - * @param attr attribute reference. - * @param buf PAGE_SIZEd buffer to write to. - * @param buf input buffer. - * @param count input buffer length. - * - * @return number of bytes consumed or negative error code. - */ -static ssize_t -MvpkmAttrStore(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t count) -{ - if (attr == &mvpkmBalloonWatchdogAttr) { - MvpkmVM *vm = container_of(kobj, MvpkmVM, kobj); - - /* - * Enable balloon watchdog on first write. This includes all ballooning - * capable guest. - */ - vm->balloonWDEnabled = true; - del_timer_sync(&vm->balloonWDTimer); - - return 1; - } else { - return -EPERM; - } -} - -/** - * @brief Map machine address space region into host process. - * - * @param file file reference (ignored). - * @param vma Linux virtual memory area defining the region. - * - * @return 0 on success, otherwise error code. - */ -static int -MvpkmMMap(struct file *file, struct vm_area_struct *vma) -{ - vma->vm_ops = &mvpkmVMOps; - - return 0; -} - -#ifdef CONFIG_ARM_LPAE -/** - * @brief Determine host cacheability/shareability attributes. - * - * Used to ensure monitor/guest shared mappings are consistent with - * those of host user/kernel. - * - * @param[out] attribMAN when setting up the HW monitor this provides the - * attributes in the generic ARM_MemAttrNormal form, - * suitable for configuring the monitor and guest's - * [H]MAIR0 and setting the shareability attributes of - * the LPAE descriptors. - */ -static void -DetermineMemAttrLPAE(ARM_MemAttrNormal *attribMAN) -{ - /* - * We use set_pte_ext to sample what {S,TEX,CB} bits Linux is using for - * normal kernel/user L2D mappings. These bits should be consistent both - * with each other and what we use in the monitor since we share various - * pages with both host processes, the kernel module and monitor, and the - * ARM ARM requires that synonyms have the same cacheability attributes, - * see end of A3.5.{4,7} ARM DDI 0406A. - */ - HKVA hkva = __get_free_pages(GFP_KERNEL, 0); - - ARM_LPAE_L3D *pt = (ARM_LPAE_L3D *)hkva; - ARM_LPAE_L3D *kernL3D = &pt[0], *userL3D = &pt[1]; - uint32 attr, mair0, mair1; - - set_pte_ext((pte_t *)kernL3D, pfn_pte(0, PAGE_KERNEL), 0); - set_pte_ext((pte_t *)userL3D, pfn_pte(0, PAGE_NONE), 0); - - printk(KERN_INFO - "DetermineMemAttr: Kernel L3D AttrIndx=%x SH=%x\n", - kernL3D->blockS1.attrIndx, - kernL3D->blockS1.sh); - - printk(KERN_INFO - "DetermineMemAttr: User L3D AttrIndx=%x SH=%x\n", - userL3D->blockS1.attrIndx, - userL3D->blockS1.sh); - - ASSERT(kernL3D->blockS1.attrIndx == userL3D->blockS1.attrIndx); - ASSERT(kernL3D->blockS1.sh == userL3D->blockS1.sh); - - switch (kernL3D->blockS1.sh) { - case 0: { - attribMAN->share = ARM_SHARE_ATTR_NONE; - break; - } - case 2: { - attribMAN->share = ARM_SHARE_ATTR_OUTER; - break; - } - case 3: { - attribMAN->share = ARM_SHARE_ATTR_INNER; - break; - } - default: { - FATAL(); - } - } - - ARM_MRC_CP15(MAIR0, mair0); - ARM_MRC_CP15(MAIR1, mair1); - - attr = MVP_EXTRACT_FIELD(kernL3D->blockS1.attrIndx >= 4 ? mair1 : mair0, - 8 * (kernL3D->blockS1.attrIndx % 4), - 8); - - /* - * See B4-1615 ARM DDI 0406C-2c for magic. - */ -#define MAIR_ATTR_2_CACHE_ATTR(x, y) \ - switch (x) { \ - case 2: { \ - (y) = ARM_CACHE_ATTR_NORMAL_WT; \ - break; \ - } \ - case 3: { \ - (y) = ARM_CACHE_ATTR_NORMAL_WB; \ - break; \ - } \ - default: { \ - FATAL(); \ - } \ - } - - MAIR_ATTR_2_CACHE_ATTR(MVP_EXTRACT_FIELD(attr, 2, 2), attribMAN->innerCache); - MAIR_ATTR_2_CACHE_ATTR(MVP_EXTRACT_FIELD(attr, 6, 2), attribMAN->outerCache); - -#undef MAIR_ATTR_2_CACHE_ATTR - - printk(KERN_INFO - "DetermineMemAttr: innerCache %x outerCache %x share %x\n", - attribMAN->innerCache, - attribMAN->outerCache, - attribMAN->share); - - free_pages(hkva, 0); -} - -#else - -/** - * @brief Determine host cacheability/shareability attributes. - * - * Used to ensure monitor/guest shared mappings are consistent with - * those of host user/kernel. - * - * @param[out] attribL2D when setting up the LPV monitor a template L2D - * containing cacheability attributes {S, TEX,CB} used by - * host kernel for normal memory mappings. These may be - * used directly for monitor/guest mappings, since both - * worlds share a common {TRE, PRRR, NMRR}. - * @param[out] attribMAN when setting up TTBR0 in the LPV monitor and the page - * tables for the HW monitor this provides the attributes - * in the generic ARM_MemAttrNormal form, suitable for - * configuring TTBR0 + the monitor and guest's [H]MAIR0 - * and setting the shareability attributes of the LPAE - * descriptors. - */ -static void -DetermineMemAttrNonLPAE(ARM_L2D *attribL2D, ARM_MemAttrNormal *attribMAN) -{ - /* - * We use set_pte_ext to sample what {S,TEX,CB} bits Linux is using for - * normal kernel/user L2D mappings. These bits should be consistent both - * with each other and what we use in the monitor since we share various - * pages with both host processes, the kernel module and monitor, and the - * ARM ARM requires that synonyms have the same cacheability attributes, - * see end of A3.5.{4,7} ARM DDI 0406A. - */ - HKVA hkva = __get_free_pages(GFP_KERNEL, 0); - uint32 sctlr; - ARM_L2D *pt = (ARM_L2D *)hkva; - ARM_L2D *kernL2D = &pt[0], *userL2D = &pt[1]; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) - /* - * Linux uses the magic 2048 offset in set_pte_ext. See include/asm/pgtable.h - * for PAGE_NONE and PAGE_KERNEL semantics. - */ - const uint32 set_pte_ext_offset = 2048; -#else - /* - * Linux 2.6.38 switched the order of Linux vs hardware page tables. - * See mainline d30e45eeabefadc6039d7f876a59e5f5f6cb11c6. - */ - const uint32 set_pte_ext_offset = 0; -#endif - - set_pte_ext((pte_t *)(kernL2D + set_pte_ext_offset/sizeof(ARM_L2D)), - pfn_pte(0, PAGE_KERNEL), - 0); - set_pte_ext((pte_t *)(userL2D + set_pte_ext_offset/sizeof(ARM_L2D)), - pfn_pte(0, PAGE_NONE), - 0); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) - /* - * Linux 2.6.38 switched the order of Linux vs hardware page tables. - * See mainline d30e45eeabefadc6039d7f876a59e5f5f6cb11c6. - */ - kernL2D += 2048/sizeof(ARM_L2D); - userL2D += 2048/sizeof(ARM_L2D); -#endif - - printk(KERN_INFO - "DetermineMemAttr: Kernel L2D TEX=%x CB=%x S=%x\n", - kernL2D->small.tex, - kernL2D->small.cb, - kernL2D->small.s); - - printk(KERN_INFO - "DetermineMemAttr: User L2D TEX=%x CB=%x S=%x\n", - userL2D->small.tex, - userL2D->small.cb, - userL2D->small.s); - - ASSERT((kernL2D->small.tex & 1) == (userL2D->small.tex & 1)); - ASSERT(kernL2D->small.cb == userL2D->small.cb); - ASSERT(kernL2D->small.s == userL2D->small.s); - - *attribL2D = *kernL2D; - - /* - * We now decode TEX remap and obtain the more generic form for use in - * the LPV monitor's TTBR0 initialization and the HW monitor. - */ - - ARM_MRC_CP15(CONTROL_REGISTER, sctlr); - - if (sctlr & ARM_CP15_CNTL_TRE) { - uint32 prrr, nmrr, indx, type, innerCache, outerCache, outerShare, - share; - - printk(KERN_INFO - "DetermineMemAttr: TEX remapping enabled\n"); - - ARM_MRC_CP15(PRIMARY_REGION_REMAP, prrr); - ARM_MRC_CP15(NORMAL_MEMORY_REMAP, nmrr); - - printk(KERN_INFO - "DetermineMemAttr: PRRR=%x NMRR=%x\n", - prrr, - nmrr); - - /* - * Decode PRRR/NMRR below. See B3.7 ARM DDI 0406B for register - * encodings, tables and magic numbers. - */ - - indx = (MVP_BIT(kernL2D->small.tex, 0) << 2) | kernL2D->small.cb; - - /* - * Only normal memory makes sense here. - */ - type = MVP_EXTRACT_FIELD(prrr, 2 * indx, 2); - ASSERT(type == 2); - - innerCache = MVP_EXTRACT_FIELD(nmrr, 2 * indx, 2); - outerCache = MVP_EXTRACT_FIELD(nmrr, 16 + 2 * indx, 2); - outerShare = !MVP_BIT(prrr, 24 + indx); - share = MVP_BIT(prrr, 18 + kernL2D->small.s); - - printk(KERN_INFO - "DetermineMemAttr: type %x innerCache %x outerCache %x" - " share %x outerShare %x\n", - type, - innerCache, - outerCache, - share, - outerShare); - - if (share) { - if (outerShare) { - attribMAN->share = ARM_SHARE_ATTR_OUTER; - } else { - attribMAN->share = ARM_SHARE_ATTR_INNER; - } - } else { - attribMAN->share = ARM_SHARE_ATTR_NONE; - } - - attribMAN->innerCache = innerCache; - attribMAN->outerCache = outerCache; - } else { - NOT_IMPLEMENTED_JIRA(1849); - } - - free_pages(hkva, 0); -} -#endif - -/** - * @brief The ioctl file operation. - * - * The ioctl command is the main communication method between the - * vmx and the mvpkm kernel module. - * - * @param filp which VM we're dealing with - * @param cmd select which cmd function needs to be performed - * @param arg argument for command - * @return error code, 0 on success - */ -long -MvpkmUnlockedIoctl(struct file *filp, - unsigned int cmd, - unsigned long arg) -{ - MvpkmVM *vm = filp->private_data; - int retval = 0; - - switch (cmd) { - - - case MVPKM_DISABLE_FAULT: { - if (!vm->stubPageMPN) { - uint32 *ptr; - - vm->stubPageMPN = - AllocZeroedFreePages(vm, 0, false, MEMREGION_MAINMEM, (HKVA*)&ptr); - if (!vm->stubPageMPN) { - break; - } - ptr[0] = MVPKM_STUBPAGE_BEG; - ptr[PAGE_SIZE/sizeof(uint32) - 1] = MVPKM_STUBPAGE_END; - } - break; - } - - /* - * Allocate some pinned pages from kernel. - * Returns -ENOMEM if no host pages available for allocation. - */ - case MVPKM_LOCK_MPN: { - struct MvpkmLockMPN buf; - - if (copy_from_user(&buf, (void *)arg, sizeof buf)) { - return -EFAULT; - } - - buf.mpn = AllocZeroedFreePages(vm, - buf.order, - false, - buf.forRegion, - NULL); - if (buf.mpn == 0) { - return -ENOMEM; - } - - if (copy_to_user((void *)arg, &buf, sizeof buf)) { - return -EFAULT; - } - break; - } - - case MVPKM_UNLOCK_MPN: { - struct MvpkmLockMPN buf; - - if (copy_from_user(&buf, (void *)arg, sizeof buf)) { - return -EFAULT; - } - - if (!LockedListDel(vm, buf.mpn)) { - return -EINVAL; - } - break; - } - - case MVPKM_MAP_WSPHKVA: { - MvpkmMapHKVA mvpkmMapInfo; - HkvaMapInfo mapInfo[WSP_PAGE_COUNT]; - - if (copy_from_user(&mvpkmMapInfo, (void *)arg, sizeof mvpkmMapInfo)) { - return -EFAULT; - } - - if (copy_from_user(mapInfo, (void *)mvpkmMapInfo.mapInfo, sizeof mapInfo)) { - return -EFAULT; - } - - mvpkmMapInfo.hkva = MapWSPHKVA(vm, mapInfo); - BUG_ON(mvpkmMapInfo.hkva == 0); - - if (mvpkmMapInfo.forRegion == MEMREGION_WSP) { - vm->wsp = (WorldSwitchPage *) mvpkmMapInfo.hkva; - } - - if (copy_to_user((void *)arg, &mvpkmMapInfo, sizeof mvpkmMapInfo)) { - return -EFAULT; - } - break; - } - - case MVPKM_RUN_MONITOR: { - if (!vm->isMonitorInited) { - vm->isMonitorInited = ((retval = SetupMonitor(vm)) == 0); - } - - if (vm->isMonitorInited) { - retval = RunMonitor(vm); - } - - break; - } - - case MVPKM_ABORT_MONITOR: { - if (!vm->isMonitorInited) { - return -EINVAL; - } - - ASSERT(vm->wsp != NULL); - - Mvpkm_WakeGuest(vm, ACTION_ABORT); - break; - } - - case MVPKM_CPU_INFO: { - struct MvpkmCpuInfo buf; - uint32 mpidr; - -#ifdef CONFIG_ARM_LPAE - DetermineMemAttrLPAE(&buf.attribMAN); - /** - * We need to add support to the LPV monitor for LPAE page tables if we - * want to use it on a LPAE host, due to the costs involved in - * transitioning between LPAE and non-LPAE page tables without Hyp - * assistance. - * - * @knownjira{MVP-2184} - */ - buf.attribL2D.u = 0; -#else - DetermineMemAttrNonLPAE(&buf.attribL2D, &buf.attribMAN); -#endif - /* - * Are MP extensions implemented? See B4-1618 ARM DDI 0406C-2c for - * magic. - */ - ARM_MRC_CP15(MPIDR, mpidr); - - buf.mpExt = mpidr & ARM_CP15_MPIDR_MP; - - if (copy_to_user((int *)arg, &buf, sizeof(struct MvpkmCpuInfo))) { - retval = -EFAULT; - } - break; - } - - default: { - retval = -EINVAL; - break; - } - } - - PRINTK(KERN_INFO "returning from IOCTL(%d) retval = %d %s\n", - cmd, retval, signal_pending(current)?"(pending signal)":"" ); - - return retval; -} - - - -/********************************************************************* - * - * Locked page management - * - *********************************************************************/ - -/* - * Pages locked by the kernel module are remembered so an unlockAll - * operation can be performed when the vmm is closed. The locked page - * identifiers are stored in a red-black tree to support O(log n) - * removal and search (required for /dev/mem-like mmap). - */ - -/** - * @brief Descriptor of a locked page range - */ -typedef struct { - struct { - __u32 mpn : 20; ///< MPN. - __u32 order : 6; ///< Size/alignment exponent for page. - __u32 forRegion : 6; ///< Annotation to identify guest page allocation - } page; - struct rb_node rb; -} LockedPage; - -static void FreeLockedPages(LockedPage *lp); - -/** - * @brief Search for an mpn inside a RB tree of LockedPages. The mpn - * will match a LockedPage as long as it is covered by the - * entry, i.e. in a non-zero order entry it doesn't have to be - * the base MPN. - * - * This must be called with the relevant vm->lockedSem held. - * - * @param root RB tree root. - * @param mpn MPN to search for. - * - * @return reference to LockedPage entry if found, otherwise NULL. - */ -static LockedPage * -LockedListSearch(struct rb_root *root, __u32 mpn) -{ - struct rb_node *n = root->rb_node; - - while (n) { - LockedPage *lp = rb_entry(n, LockedPage, rb); - - if (lp->page.mpn == (mpn & (~0UL << lp->page.order))) { - return lp; - } - - if (mpn < lp->page.mpn) { - n = n->rb_left; - } else { - n = n->rb_right; - } - } - - return NULL; -} - -/** - * @brief Delete an mpn from the list of locked pages. - * - * @param vm Mvpkm module control structure pointer - * @param mpn MPN to be unlocked and freed for reuse - * @return true if list contained MPN and it was deleted from list - */ - -static _Bool -LockedListDel(MvpkmVM *vm, __u32 mpn) -{ - LockedPage *lp; - - down_write(&vm->lockedSem); - - lp = LockedListSearch(&vm->lockedRoot, mpn); - - /* - * The MPN should be in the locked pages RB tree and it should be the - * base of an entry, i.e. we can't fragment existing allocations for - * a VM. - */ - if (lp == NULL || lp->page.mpn != mpn) { - up_write(&vm->lockedSem); - return false; - } - - FreeLockedPages(lp); - - if (lp->page.forRegion == MEMREGION_MAINMEM) { - ATOMIC_SUBV(vm->usedPages, 1U << lp->page.order); - } - - rb_erase(&lp->rb, &vm->lockedRoot); - kfree(lp); - - up_write(&vm->lockedSem); - - return true; -} - -/** - * @brief Scan the list of locked pages to see if an MPN matches. - * - * @param vm Mvpkm module control structure pointer - * @param mpn MPN to check - * - * @return true iff list contains MPN. - */ -static _Bool -LockedListLookup(MvpkmVM *vm, __u32 mpn) -{ - LockedPage *lp; - - down_read(&vm->lockedSem); - - lp = LockedListSearch(&vm->lockedRoot, mpn); - - up_read(&vm->lockedSem); - - return lp != NULL; -} - -/** - * @brief Add a new mpn to the locked pages RB tree. - * - * @param vm control structure pointer - * - * @param mpn mpn of page that was locked with get_user_pages or some sort of - * get that is undone by put_page. - * The mpn is assumed to be non-zero - * @param order size/alignment exponent for page - * @param forRegion Annotation for Page pool to identify guest page allocations - * - * @return false: couldn't allocate internal memory to record mpn in<br> - * true: successful. - */ -static _Bool -LockedListAdd(MvpkmVM *vm, - __u32 mpn, - __u32 order, - PhysMem_RegionType forRegion) -{ - struct rb_node *parent, **p; - LockedPage *tp, *lp = kmalloc(sizeof *lp, GFP_KERNEL); - - if (!lp) { - return false; - } - - lp->page.mpn = mpn; - lp->page.order = order; - lp->page.forRegion = forRegion; - - down_write(&vm->lockedSem); - - if (forRegion == MEMREGION_MAINMEM) { - ATOMIC_ADDV(vm->usedPages, 1U << order); - } - - /* - * Insert as a red leaf in the tree (see include/linux/rbtree.h). - */ - p = &vm->lockedRoot.rb_node; - parent = NULL; - - while (*p) { - parent = *p; - tp = rb_entry(parent, LockedPage, rb); - - /* - * MPN should not already exist in the tree. - */ - ASSERT(tp->page.mpn != (mpn & (~0UL << tp->page.order))); - - if (mpn < tp->page.mpn) { - p = &(*p)->rb_left; - } else { - p = &(*p)->rb_right; - } - } - - rb_link_node(&lp->rb, parent, p); - - /* - * Restructure tree if necessary (see include/linux/rbtree.h). - */ - rb_insert_color(&lp->rb, &vm->lockedRoot); - - up_write(&vm->lockedSem); - - return true; -} - -/** - * @brief Traverse RB locked tree, freeing every entry. - * - * This must be called with the relevant vm->lockedSem held. - * - * @param node reference to RB node at root of subtree. - */ -static void -LockedListNuke(struct rb_node *node) -{ - while (node) { - if (node->rb_left) { - node = node->rb_left; - } else if (node->rb_right) { - node = node->rb_right; - } else { - /* - * We found a leaf, free it and go back to parent. - */ - LockedPage *lp = rb_entry(node, LockedPage, rb); - - if ((node = rb_parent(node))) { - if (node->rb_left) { - node->rb_left = NULL; - } else { - node->rb_right = NULL; - } - } - - FreeLockedPages(lp); - kfree(lp); - } - } -} - -/** - * @brief Unlock all pages at vm close time. - * - * @param vm control structure pointer - */ -static void -LockedListUnlockAll(MvpkmVM *vm) -{ - - down_write(&vm->lockedSem); - - LockedListNuke(vm->lockedRoot.rb_node); - - ATOMIC_SETV(vm->usedPages, 0); - - up_write(&vm->lockedSem); -} - - -/** - * @brief Allocate zeroed free pages - * - * @param[in] vm which VM the pages are for so they will be freed when the vm - * closes - * @param[in] order log2(number of contiguous pages to allocate) - * @param[in] highmem is it OK to allocate this page in ZONE_HIGHMEM? This - * option should only be specified for pages the host kernel - * will not need to address directly. - * @param[out] hkvaRet where to return host kernel virtual address of the - * allocated pages, if non-NULL, and ONLY IF !highmem. - * @param forRegion Annotation for Page pool to identify guest page allocations - * @return 0: no host memory available<br> - * else: starting MPN<br> - * *hkvaRet = filled in - */ -static MPN -AllocZeroedFreePages(MvpkmVM *vm, - uint32 order, - _Bool highmem, - PhysMem_RegionType forRegion, - HKVA *hkvaRet) -{ - MPN mpn; - struct page *page; - - if (order > PAGE_ALLOC_COSTLY_ORDER) { - printk(KERN_WARNING "Order %d allocation for region %d exceeds the safe " - "maximum order %d\n", - order, - forRegion, - PAGE_ALLOC_COSTLY_ORDER); - } - - /* - * Get some pages for the requested range. They will be physically - * contiguous and have the requested alignment. They will also - * have a kernel virtual mapping if !highmem. - * - * We allocate out of ZONE_MOVABLE even though we can't just pick up our - * bags. We do this to support platforms that explicitly configure - * ZONE_MOVABLE, such as the Qualcomm MSM8960, to enable deep power down of - * memory banks. When the kernel attempts to take a memory bank offline, it - * will try and place the pages on the isolate LRU - only pages already on an - * LRU, such as anon/file, can get there, so it will not be able to - * migrate/move our pages (and hence the bank will not be offlined). The - * other alternative is to live withing ZONE_NORMAL, and only have available - * a small fraction of system memory. Long term we plan on hooking the - * offlining callback in mvpkm and perform our own migration with the - * cooperation of the monitor, but we don't have dev board to support this - * today. - * - * @knownjira{MVP-3477} - */ - page = alloc_pages(GFP_USER | __GFP_COMP | __GFP_ZERO | - (highmem ? __GFP_HIGHMEM | __GFP_MOVABLE : 0), - order); - - if (page == NULL) { - return 0; - } - - /* - * Return the corresponding page number. - */ - mpn = page_to_pfn(page); - ASSERT(mpn != 0); - - /* - * Remember to unlock the pages when the FD is closed. - */ - if (!LockedListAdd(vm, mpn, order, forRegion)) { - __free_pages(page, order); - return 0; - } - - if (hkvaRet) { - *hkvaRet = highmem ? 0 : __phys_to_virt(page_to_phys(page)); - } - - return mpn; -} - -/** - * @brief Map already-pinned WSP memory in host kernel virtual address(HKVA) - * space. Assumes 2 world switch pages on an 8k boundary. - * - * @param[in] vm which VM the HKVA Area is to be mapped for - * @param[in] mapInfo array of MPNs and execute permission flags to be used in - inserting a new contiguous map in HKVA space - * @return 0: HKVA space could not be mapped - else: HKVA where mapping was inserted - */ -static HKVA -MapWSPHKVA(MvpkmVM *vm, HkvaMapInfo *mapInfo) -{ - unsigned int i; - struct page **pages = NULL; - struct page **pagesPtr; - pgprot_t prot; - int retval; - int allocateCount = WSP_PAGE_COUNT + 1; // Reserve one page for alignment - int pageIndex = 0; - HKVA dummyPage = (HKVA)NULL; - HKVA start; - HKVA startSegment; - HKVA endSegment; - - /* - * Add one page for alignment purposes in case __get_vm_area returns an - * unaligned address. - */ - ASSERT(allocateCount == 3); - ASSERT_ON_COMPILE(WSP_PAGE_COUNT == 2); - - /* - * NOT_IMPLEMENTED if MapHKVA is called more than once. - */ - BUG_ON(vm->wspHkvaArea); - - /* - * Reserve virtual address space. - */ - vm->wspHkvaArea = __get_vm_area((allocateCount * PAGE_SIZE), VM_ALLOC, MODULES_VADDR, MODULES_END); - if (!vm->wspHkvaArea) { - return 0; - } - - pages = kmalloc(allocateCount * sizeof(struct page *), GFP_TEMPORARY); - if (!pages) { - goto err; - } - pagesPtr = pages; - - /* - * Use a dummy page to boundary align the section, if needed. - */ - dummyPage = __get_free_pages(GFP_KERNEL, 0); - if (!dummyPage) { - goto err; - } - vm->wspHKVADummyPage = dummyPage; - - /* - * Back every entry with the dummy page. - */ - for (i = 0; i < allocateCount; i++) { - pages[i] = virt_to_page(dummyPage); - } - - /* - * World switch pages must not span a 1MB boundary in order to maintain only - * a single L2 page table. - */ - start = (HKVA)vm->wspHkvaArea->addr; - startSegment = start & ~(ARM_L1D_SECTION_SIZE - 1); - endSegment = (start + PAGE_SIZE) & ~(ARM_L1D_SECTION_SIZE - 1); - /* - * Insert dummy page at pageIndex, if needed. - */ - pageIndex = (startSegment != endSegment); - - /* - * Back the rest with the actual world switch pages - */ - for (i = pageIndex; i < pageIndex + WSP_PAGE_COUNT; i++) { - pages[i] = pfn_to_page(mapInfo[i - pageIndex].mpn); - } - - /* - * Given the lack of functionality in the kernel for being able to mark - * mappings for a given vm area with different sets of protection bits, - * we simply mark the entire vm area as PAGE_KERNEL_EXEC for now - * (i.e., union of all the protection bits). Given that the kernel - * itself does something similar while loading modules, this should be a - * reasonable workaround for now. In the future, we should set the - * protection bits to strictly adhere to what has been requested in the - * mapInfo parameter. - */ - prot = PAGE_KERNEL_EXEC; - - retval = map_vm_area(vm->wspHkvaArea, prot, &pagesPtr); - if (retval < 0) { - goto err; - } - - kfree(pages); - - return (HKVA)(vm->wspHkvaArea->addr) + pageIndex * PAGE_SIZE; - -err: - if (dummyPage) { - free_pages(dummyPage, 0); - vm->wspHKVADummyPage = (HKVA)NULL; - } - - if (pages) { - kfree(pages); - } - - free_vm_area(vm->wspHkvaArea); - vm->wspHkvaArea = (HKVA)NULL; - - return 0; -} - -static void -UnmapWSPHKVA(MvpkmVM *vm) -{ - if (vm->wspHkvaArea) { - free_vm_area(vm->wspHkvaArea); - } - - if (vm->wspHKVADummyPage) { - free_pages(vm->wspHKVADummyPage, 0); - vm->wspHKVADummyPage = (HKVA)NULL; - } -} - -/** - * @brief Clean and release locked pages - * - * @param lp Reference to the locked pages - */ -static void -FreeLockedPages(LockedPage *lp) -{ - struct page *page; - int count; - - page = pfn_to_page(lp->page.mpn); - count = page_count(page); - - if (count == 0) { - printk(KERN_ERR "%s: found locked page with 0 reference (mpn %05x)\n", - __func__, lp->page.mpn); - return; - } - - if (count == 1) { - int i; - - /* - * There is no other user for this page, clean it. - * - * We don't bother checking if the page was highmem or not, clear_highmem - * works for both. - * We clear the content of the page, and rely on the fact that the previous - * worldswitch has cleaned the potential VIVT I-CACHE. - */ - for (i = 0; i < (1 << lp->page.order); i++) { - clear_highpage(page + i); - } - } else if (lp->page.forRegion != MEMREGION_MAINMEM) { - printk(KERN_WARNING "%s: mpn 0x%05x for region %d is still in use\n", - __func__, lp->page.mpn, lp->page.forRegion); - } - - __free_pages(page, lp->page.order); -} - -/********************************************************************* - * - * Communicate with monitor - * - *********************************************************************/ - -/** - * @brief Register a new monitor page. - * - * @param vm which virtual machine we're running - * @return 0: successful<br> - * else: -errno - */ -static int -SetupMonitor(MvpkmVM *vm) -{ - int retval; - WorldSwitchPage *wsp = vm->wsp; - - if (!wsp || - wsp->wspHKVA != (HKVA)wsp) { - return -EINVAL; - } - - if ((retval = Mksck_WspInitialize(vm))) { - return retval; - } - - vm->kobj.kset = mvpkmKSet; - retval = kobject_init_and_add(&vm->kobj, &mvpkmKType, NULL, "%d", wsp->guestId); - if (retval) { - goto error; - } - - /* - * Get a reference to this module such that it cannot be unloaded until - * our kobject's release function completes. - */ - - __module_get(THIS_MODULE); - vm->haveKObj = true; - - /* - * Caution: From here on, if we fail, we must not call kobject_put() - * on vm->kobj since that may / will deallocate 'vm'. Unregistering VM - * ksets on failures, is fine and should be done for proper ref counting. - */ - - vm->devicesKSet = kset_create_and_add("devices", NULL, &vm->kobj); - if (!vm->devicesKSet) { - retval = -ENOMEM; - goto error; - } - - vm->miscKSet = kset_create_and_add("misc", NULL, &vm->kobj); - if (!vm->miscKSet) { - kset_unregister(vm->devicesKSet); - vm->devicesKSet = NULL; - retval = -ENOMEM; - goto error; - } - - down_write(&vm->wspSem); - - /* - * The VE monitor needs to issue a SMC to bootstrap Hyp mode. - */ - if (wsp->monType == MONITOR_TYPE_VE) { - /* - * Here we assemble the monitor's HMAIR0 based on wsp->memAttr. We map - * from the inner/outer normal page cacheability attributes obtained - * from DetermineCacheabilityAttribs to the format required in 4.2.8 - * ARM PRD03-GENC-008469 13.0 (see this document for the magic numbers). - * - * Where a choice is available, we opt for read and/or write allocation. - */ - static const uint32 normalCacheAttr2MAIR[4] = { 0x4, 0xf, 0xa, 0xe }; - - uint32 hmair0 = - ((normalCacheAttr2MAIR[wsp->memAttr.innerCache] | - (normalCacheAttr2MAIR[wsp->memAttr.outerCache] << 4)) - << 8 * MVA_MEMORY) | - (0x4 << 8 * MVA_DEVICE); - - /* - * See B4.1.74 ARM DDI 0406C-2c for the HTCR magic. - */ - uint32 htcr = - 0x80000000 | - (wsp->memAttr.innerCache << 8) | - (wsp->memAttr.outerCache << 10) | - (wsp->memAttr.share << 12); - - /** - * @knownjira{MVP-377} - * Set HSCTLR to enable MMU and caches. We should really run the - * monitor WXN, in non-MVP_DEVEL builds. See - * 13.18 ARM PRD03-GENC-008353 11.0 for the magic. - */ - static const uint32 hsctlr = 0x30c5187d; - - register uint32 r0 asm("r0") = wsp->monVA.excVec; - register uint32 r1 asm("r1") = wsp->regSave.ve.mHTTBR; - register uint32 r2 asm("r2") = htcr; - register uint32 r3 asm("r3") = hmair0; - register uint32 r4 asm("r4") = hsctlr; - - asm volatile ( - ".arch_extension sec\n" - "smc 0" - : - : "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4) - : "memory" - ); - } - - /* - * Initialize guest wait-for-interrupt waitqueue. - */ - init_waitqueue_head(&vm->wfiWaitQ); - - MonitorTimer_Setup(vm); - -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_init(&vm->wakeLock, WAKE_LOCK_SUSPEND, "mvpkm"); -#endif - - wsp->mvpkmVersion = MVP_VERSION_CODE; - up_write(&vm->wspSem); - /* - * Ensure coherence of monitor loading and page tables. - */ - flush_cache_all(); - return 0; - -error: - Mksck_WspRelease(wsp); - vm->wsp = NULL; - return retval; -} - -/** - * @brief dummy function to drop the info parameter - * @param info ignored - */ -static -void FlushAllCpuCaches(void *info) -{ - flush_cache_all(); -} - -/** - * @brief return to where monitor called worldswitch - * - * @param vm which virtual machine we're running - * @return 0: successful, just call back when ready<br> - * 1: successful, process code in WSP_Params(wsp)->callno<br> - * else: -errno - */ -static int -RunMonitor(MvpkmVM *vm) -{ - int ii; - unsigned long flags; - WorldSwitchPage *wsp = vm->wsp; - int retval = 0; - - ASSERT(wsp); - -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&vm->wakeLock); -#endif - - /* - * Set VCPUThread affinity - */ - if (cpumask_intersects(to_cpumask(vcpuAffinity), cpu_active_mask)) { - set_cpus_allowed_ptr(current, to_cpumask(vcpuAffinity)); - } - - /* - * Record the the current task structure, so an ABORT will know, - * who to wake. - */ - down_write(&vm->monThreadTaskSem); - vm->monThreadTask = get_current(); - up_write(&vm->monThreadTaskSem); - - /* - * Keep going as long as the monitor is in critical section or - * there are no pending signals such as SIGINT or SIGKILL. Block - * interrupts before checking so any IPI sent will remain pending - * if our check just misses detecting the signal. - */ - local_irq_save(flags); - while (wsp->critSecCount > 0 || - (!signal_pending(current) && - !(ATOMIC_GETO(wsp->hostActions) & ACTION_ABORT))) { - /* - * ARMv7 Performance counters are per CPU core and might be disabled over - * CPU core sleep if there is nothing else in the system to re-enable - * them, so now that we have been allocated a CPU core to run the guest, - * enable them and in particular the TSC (CCNT) which is used for monitor - * timing between world switches. - */ - { - uint32 pmnc; - uint32 pmcnt; - - /* make sure that the Performance Counters are enabled */ - ARM_MRC_CP15(PERF_MON_CONTROL_REGISTER, pmnc); - if ((pmnc & (ARM_PMNC_E | ARM_PMNC_D)) != (ARM_PMNC_E)) { - pmnc |= ARM_PMNC_E; // Enable TSC - pmnc &= ~ARM_PMNC_D; // Disable cycle count divider - ARM_MCR_CP15(PERF_MON_CONTROL_REGISTER, pmnc); - } - - /* make sure that the CCNT is enabled */ - ARM_MRC_CP15(PERF_MON_COUNT_SET, pmcnt); - if ((pmcnt & ARM_PMCNT_C) != ARM_PMCNT_C) { - pmcnt |= ARM_PMCNT_C; - ARM_MCR_CP15(PERF_MON_COUNT_SET, pmcnt); - } - } - - /* - * Update TSC to RATE64 ratio - */ - { - struct TscToRate64Cb *ttr = &__get_cpu_var(tscToRate64); - wsp->tscToRate64Mult = ttr->mult; - wsp->tscToRate64Shift = ttr->shift; - } - - /* - * Save the time of day for the monitor's timer facility. The timing - * facility in the vmm needs to compute current time in the host linux's - * time representation. It uses the formula: - * now = wsp->switchedAt64 + (uint32)(TSC_READ() - wsp->lowerTSC) - * - * Read the timestamp counter *immediately after* ktime_get() as that - * will give the most consistent offset between reading the hardware - * clock register in ktime_get() and reading the hardware timestamp - * counter with TSC_READ(). - */ - ASSERT_ON_COMPILE(MVP_TIMER_RATE64 == NSEC_PER_SEC); - { - ktime_t now = ktime_get(); - TSC_READ(wsp->switchedAtTSC); - wsp->switchedAt64 = ktime_to_ns(now); - } - - /* - * Save host FPU contents and load monitor contents. - */ - SWITCH_VFP_TO_MONITOR; - - /* - * Call into the monitor to run guest instructions until it wants us to - * do something for it. Note that any hardware interrupt request will - * cause it to volunteer. - */ - switch (wsp->monType) { - case MONITOR_TYPE_LPV: { - uint32 hostVBAR; - - ARM_MRC_CP15(VECTOR_BASE, hostVBAR); - (*wsp->switchToMonitor)(&wsp->regSave); - ARM_MCR_CP15(VECTOR_BASE, hostVBAR); - break; - } - case MONITOR_TYPE_VE: { - register uint32 r1 asm("r1") = wsp->regSave.ve.mHTTBR; - - asm volatile ( - ".word " MVP_STRINGIFY(ARM_INSTR_HVC_A1_ENC(0)) - : "=r" (r1) : "r" (r1) : "r0", "r2", "memory" - ); - break; - } - default: FATAL(); - } - - /* - * Save monitor FPU contents and load host contents. - */ - SWITCH_VFP_TO_HOST; - - /* - * Re-enable local interrupts now that we are back in the host world - */ - local_irq_restore(flags); - - - /* - * Maybe the monitor wrote some messages to monitor->host sockets. - * This will wake the corresponding host threads to receive them. - */ - /** - * @todo This lousy loop is in the critical path. It should be changed - * to some faster algorithm to wake blocked host sockets. - */ - for (ii = 0; ii < MKSCK_MAX_SHARES; ii++) { - if (wsp->isPageMapped[ii]) { - Mksck_WakeBlockedSockets(MksckPage_GetFromIdx(ii)); - } - } - - switch (WSP_Params(wsp)->callno) { - case WSCALL_ACQUIRE_PAGE: { - uint32 i; - - for (i = 0; i < WSP_Params(wsp)->pages.pages; ++i) { - MPN mpn = AllocZeroedFreePages(vm, - WSP_Params(wsp)->pages.order, - true, - WSP_Params(wsp)->pages.forRegion, - NULL); - if (mpn == 0) { - printk(KERN_WARNING "WSCALL_ACQUIRE_PAGE: no order %u pages available\n", - WSP_Params(wsp)->pages.order); - WSP_Params(wsp)->pages.pages = i; - break; - } - - WSP_Params(wsp)->pages.mpns[i] = mpn; - } - - break; - } - case WSCALL_RELEASE_PAGE: { - uint32 i; - - for (i = 0; i < WSP_Params(wsp)->pages.pages; ++i) { - if (!LockedListDel(vm, WSP_Params(wsp)->pages.mpns[i])) { - WSP_Params(wsp)->pages.pages = i; - break; - } - } - - break; - } - case WSCALL_MUTEXLOCK: { - retval = Mutex_Lock((void *)WSP_Params(wsp)->mutex.mtxHKVA, - WSP_Params(wsp)->mutex.mode); - - if (retval < 0) { - WSP_Params(wsp)->mutex.ok = false; - goto monitorExit; - } - - /* - * The locking succeeded. From this point on the monitor - * is in critical section. Even if an interrupt comes - * right here, it must return to the monitor to unlock the - * mutex. - */ - wsp->critSecCount++; - WSP_Params(wsp)->mutex.ok = true; - break; - } - case WSCALL_MUTEXUNLOCK: { - Mutex_Unlock((void *)WSP_Params(wsp)->mutex.mtxHKVA, - WSP_Params(wsp)->mutex.mode); - break; - } - case WSCALL_MUTEXUNLSLEEP: { - /* - * The vcpu has just come back from the monitor. During - * the transition interrupts were disabled. Above, - * however, interrupts were enabled again and it is - * possible that a context switch happened into a thread - * (serve_vmx) that instructed the vcpu thread to - * abort. After returning to this thread the vcpu may - * enter a sleep below never to return from it. To avoid - * this deadlock we need to test the abort flag in - * Mutex_UnlSleepTest. - */ - retval = - Mutex_UnlSleepTest((void *)WSP_Params(wsp)->mutex.mtxHKVA, - WSP_Params(wsp)->mutex.mode, - WSP_Params(wsp)->mutex.cvi, - &wsp->hostActions, - ACTION_ABORT); - if (retval < 0) { - goto monitorExit; - } - break; - } - case WSCALL_MUTEXUNLWAKE: { - Mutex_UnlWake((void *)WSP_Params(wsp)->mutex.mtxHKVA, - WSP_Params(wsp)->mutex.mode, - WSP_Params(wsp)->mutex.cvi, - WSP_Params(wsp)->mutex.all); - break; - } - - /* - * The monitor wants us to block (allowing other host threads to run) - * until an async message is waiting for the monitor to process. - * - * If MvpkmWaitForInt() returns an error, it should only be if there - * is another signal pending (such as SIGINT). So we pretend it - * completed normally, as the monitor is ready to be called again (it - * will see no messages to process and wait again), and return to user - * mode so the signals can be processed. - */ - case WSCALL_WAIT: { -#ifdef CONFIG_HAS_WAKELOCK - if (WSP_Params(wsp)->wait.suspendMode) { - /* guest has ok'ed suspend mode, so release SUSPEND wakelock */ - wake_unlock(&vm->wakeLock); - retval = MvpkmWaitForInt(vm, true); - wake_lock(&vm->wakeLock); - WSP_Params(wsp)->wait.suspendMode = 0; - } else { - /* guest has asked for WFI not suspend so keep holding SUSPEND - * wakelock */ - retval = MvpkmWaitForInt(vm, false); - } -#else - retval = MvpkmWaitForInt(vm, WSP_Params(wsp)->wait.suspendMode); -#endif - if (retval < 0) { - goto monitorExit; - } - break; - } - - /* - * The only reason the monitor returned was because there was a - * pending hardware interrupt. The host serviced and cleared that - * interrupt when we enabled interrupts above. Now we call the - * scheduler in case that interrupt woke another thread, we want to - * allow that thread to run before returning to do more guest code. - */ - case WSCALL_IRQ: { - break; - } - - case WSCALL_GET_PAGE_FROM_VMID: { - MksckPage *mksckPage; - mksckPage = MksckPage_GetFromVmIdIncRefc(WSP_Params(wsp)->pageMgmnt.vmId); - - if (mksckPage) { - int ii; - - WSP_Params(wsp)->pageMgmnt.found = true; - for (ii = 0; ii < MKSCKPAGE_TOTAL; ii++) { - WSP_Params(wsp)->pageMgmnt.mpn[ii] = - vmalloc_to_pfn( (void*)(((HKVA)mksckPage) + ii*PAGE_SIZE) ); - } - - ASSERT(!wsp->isPageMapped[MKSCK_VMID2IDX(mksckPage->vmId)]); - wsp->isPageMapped[MKSCK_VMID2IDX(mksckPage->vmId)] = true; - } else { - WSP_Params(wsp)->pageMgmnt.found = false; - } - break; - } - - case WSCALL_REMOVE_PAGE_FROM_VMID: { - MksckPage *mksckPage; - mksckPage = MksckPage_GetFromVmId(WSP_Params(wsp)->pageMgmnt.vmId); - ASSERT(wsp->isPageMapped[MKSCK_VMID2IDX(mksckPage->vmId)]); - wsp->isPageMapped[MKSCK_VMID2IDX(mksckPage->vmId)] = false; - MksckPage_DecRefc(mksckPage); - break; - } - - /* - * Read current wallclock time. - */ - case WSCALL_READTOD: { - struct timeval nowTV; - do_gettimeofday(&nowTV); - WSP_Params(wsp)->tod.now = nowTV.tv_sec; - WSP_Params(wsp)->tod.nowusec = nowTV.tv_usec; - break; - } - - case WSCALL_LOG: { - int len = strlen(WSP_Params(wsp)->log.messg); - printk(KERN_INFO - "VMM: %s%s", - WSP_Params(wsp)->log.messg, - (WSP_Params(wsp)->log.messg[len-1] == '\n') ? "" : "\n"); - break; - } - - case WSCALL_ABORT: { - retval = WSP_Params(wsp)->abort.status; - goto monitorExit; - } - - case WSCALL_QP_GUEST_ATTACH: { - int32 rc; - QPInitArgs args; - uint32 base; - uint32 nrPages; - - args.id = WSP_Params(wsp)->qp.id; - args.capacity = WSP_Params(wsp)->qp.capacity; - args.type = WSP_Params(wsp)->qp.type; - base = WSP_Params(wsp)->qp.base; - nrPages = WSP_Params(wsp)->qp.nrPages; - - rc = QP_GuestAttachRequest(vm, &args, base, nrPages); - - WSP_Params(wsp)->qp.rc = rc; - WSP_Params(wsp)->qp.id = args.id; - break; - } - - case WSCALL_QP_NOTIFY: { - QPInitArgs args; - - args.id = WSP_Params(wsp)->qp.id; - args.capacity = WSP_Params(wsp)->qp.capacity; - args.type = WSP_Params(wsp)->qp.type; - - WSP_Params(wsp)->qp.rc = QP_NotifyListener(&args); - break; - } - - case WSCALL_MONITOR_TIMER: { - MonitorTimer_Request(&vm->monTimer, WSP_Params(wsp)->timer.when64); - break; - } - - case WSCALL_COMM_SIGNAL: { - Mvpkm_CommEvSignal(&WSP_Params(wsp)->commEvent.transpID, - WSP_Params(wsp)->commEvent.event); - break; - } - - case WSCALL_FLUSH_ALL_DCACHES: { - /* - * Broadcast Flush DCache request to all cores. - * Block while waiting for all of them to get done. - */ - on_each_cpu(FlushAllCpuCaches, NULL, 1); - break; - } - default: { - retval = -EPIPE; - goto monitorExit; - } - } - - /* - * The params.callno callback was handled in kernel mode and completed - * successfully. Repeat for another call without returning to user mode, - * unless there are signals pending. - * - * But first, call the Linux scheduler to switch threads if there is - * some other thread Linux wants to run now. - */ - if (need_resched()) { - schedule(); - } - - /* - * Check if cpus allowed mask has to be updated. - * Updating it must be done outside of an atomic context. - */ - if (cpumask_intersects(to_cpumask(vcpuAffinity), cpu_active_mask) && - !cpumask_equal(to_cpumask(vcpuAffinity), ¤t->cpus_allowed)) { - set_cpus_allowed_ptr(current, to_cpumask(vcpuAffinity)); - } - - local_irq_save(flags); - } - - /* - * There are signals pending so don't try to do any more monitor/guest - * stuff. But since we were at the point of just about to run the monitor, - * return success status as user mode can simply call us back to run the - * monitor again. - */ - local_irq_restore(flags); - -monitorExit: - ASSERT(wsp->critSecCount == 0); - - if (ATOMIC_GETO(wsp->hostActions) & ACTION_ABORT) { - PRINTK(KERN_INFO "Monitor has ABORT flag set.\n"); - retval = ExitStatusHostRequest; - } - -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&vm->wakeLock); -#endif - - down_write(&vm->monThreadTaskSem); - vm->monThreadTask = NULL; - up_write(&vm->monThreadTaskSem); - - return retval; -} - -/** - * @brief Guest is waiting for interrupts, sleep if necessary - * - * @param vm which virtual machine we're running - * @param suspend is the guest entering suspend or just WFI? - * @return 0: woken up, hostActions should have pending events - * -ERESTARTSYS: broke out because other signals are pending - * - * This function is called in the VCPU context after the world switch to wait - * for an incoming message. If any message gets queued to this VCPU, the - * sender will wake us up. - */ -int -MvpkmWaitForInt(MvpkmVM *vm, _Bool suspend) -{ - WorldSwitchPage *wsp = vm->wsp; - wait_queue_head_t *q = &vm->wfiWaitQ; - - if (suspend) { - return wait_event_interruptible(*q, ATOMIC_GETO(wsp->hostActions) != 0); - } else { - int ret; - ret = wait_event_interruptible_timeout(*q, ATOMIC_GETO(wsp->hostActions) != 0, 10*HZ); - if (ret == 0) { - printk("MvpkmWaitForInt: guest stuck for 10s in WFI! (hostActions %08x)\n", - ATOMIC_GETO(wsp->hostActions)); - } - return ret > 0 ? 0 : ret; - } -} - - -/** - * @brief Force the guest to evaluate its hostActions flag field - * - * @param vm which guest needs waking - * @param why why should be guest be woken up? - * - * This function updates the hostAction flag field as and wakes up the guest as - * required so that it can evaluate it. The guest could be executing guest - * code in an SMP system, in that case send an IPI; or it could be sleeping, in - * the case wake it up. - */ -void -Mvpkm_WakeGuest(MvpkmVM *vm, int why) -{ - ASSERT(why != 0); - - /* set the host action */ - if (ATOMIC_ORO(vm->wsp->hostActions, why) & why) { - /* guest has already been woken up so no need to do it again */ - return; - } - - /* - * VCPU is certainly in 'wait for interrupt' wait. Wake it up ! - */ -#ifdef CONFIG_HAS_WAKELOCK - /* - * To prevent the system to go in suspend mode before the monitor had a - * chance on being scheduled, we will hold the VM wakelock from now. - * As the wakelocks are not managed as reference counts, this is not an - * an issue to take a wake_lock twice in a row. - */ - wake_lock(&vm->wakeLock); -#endif - - /* - * On a UP system, we ensure the monitor thread isn't blocked. - * - * On an MP system the other CPU might be running the guest. This - * is noop on UP. - * - * When the guest is running, it is an invariant that monThreadTaskSem is not - * held as a write lock, so we should not fail to acquire the lock. - * Mvpkm_WakeGuest may be called from an atomic context, so we can't sleep - * here. - */ - if (down_read_trylock(&vm->monThreadTaskSem)) { - if (vm->monThreadTask) { - wake_up_process(vm->monThreadTask); - kick_process(vm->monThreadTask); - } - up_read(&vm->monThreadTaskSem); - } else { - printk("Unexpected failure to acquire monThreadTaskSem!\n"); - } -} diff --git a/arch/arm/mvp/mvpkm/mvpkm_private.h b/arch/arm/mvp/mvpkm/mvpkm_private.h deleted file mode 100644 index 3dfc8d4..0000000 --- a/arch/arm/mvp/mvpkm/mvpkm_private.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Private interface between user level wrappers and kernel module. - * The communication uses the ioctl linux call. The command operand is one - * of the MVPKM_xxx macros defined below, the custom operand is a pointer - * to the respective structure below. - */ - - -#ifndef _MVPKMPRIVATE_H -#define _MVPKMPRIVATE_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include <linux/ioctl.h> -/* - * For details how to create ioctl numbers, see - * Documentation/ioctl/ioctl-number.txt. The letter '9' is - * unused. The 0xa0-0xaf block is even more unused. Note however, that - * ioctl numbers are desired to be unique for debug purposes, they - * may conflict. - */ -#define MVP_IOCTL_LETTER '9' -#define MVPKM_DISABLE_FAULT _IO( MVP_IOCTL_LETTER, 0xa0) -#define MVPKM_LOCK_MPN _IOW(MVP_IOCTL_LETTER, 0xa1, MvpkmLockMPN) -#define MVPKM_UNLOCK_MPN _IOW(MVP_IOCTL_LETTER, 0xa2, MvpkmLockMPN) -#define MVPKM_RUN_MONITOR _IO( MVP_IOCTL_LETTER, 0xa3) -#define MVPKM_CPU_INFO _IOR(MVP_IOCTL_LETTER, 0xa4, MvpkmCpuInfo) -#define MVPKM_ABORT_MONITOR _IO( MVP_IOCTL_LETTER, 0xa5) -#define MVPKM_MAP_WSPHKVA _IOW(MVP_IOCTL_LETTER, 0xa7, MvpkmMapHKVA) - -#include "mksck.h" -#include "monva_common.h" -#include "mvpkm_types.h" - -/** - * @brief Operand for the MVPKM_LOCK_MPN call - */ -typedef struct MvpkmLockMPN { - uint32 order; /* IN */ - PhysMem_RegionType forRegion; /* IN */ - uint32 mpn; /* OUT */ -} MvpkmLockMPN; - -/** - * @brief Operand for the MVPKM_MAP_HKVA call - */ -typedef struct MvpkmMapHKVA { - HkvaMapInfo *mapInfo; /* IN */ - PhysMem_RegionType forRegion; /* IN */ - HKVA hkva; /* OUT */ -} MvpkmMapHKVA; - -#define WSP_PAGE_COUNT 2 - -/** - * @brief Operand for the MVPKM_CPU_INFO call - */ -typedef struct MvpkmCpuInfo { - ARM_L2D attribL2D; /* OUT */ - ARM_MemAttrNormal attribMAN; /* OUT */ - _Bool mpExt; /* OUT */ -} MvpkmCpuInfo; - -/** - * @brief These magic numbers mark the beginning and end of the - * special page that is mapped into the virtual address space of MVPD - * when it's monitor coredumper requests an unavailable page. - */ -#define MVPKM_STUBPAGE_BEG 0x78d10c67 -#define MVPKM_STUBPAGE_END 0x8378f3dd -#endif diff --git a/arch/arm/mvp/mvpkm/mvpkm_types.h b/arch/arm/mvp/mvpkm/mvpkm_types.h deleted file mode 100644 index ce23554..0000000 --- a/arch/arm/mvp/mvpkm/mvpkm_types.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Types used in the interface between users, user level wrappers, - * and the kernel module implementation. - */ - - -#ifndef _MVPKMTYPES_H -#define _MVPKMTYPES_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - - -/** - * @brief HkvaMapInfo structure describing the mpn and execute permission - * flag to use to map a given page in HKVA space - */ -typedef struct HkvaMapInfo { - uint32 mpn; - _Bool write; - _Bool exec; -} HkvaMapInfo; - -#endif diff --git a/arch/arm/mvp/mvpkm/nottested.h b/arch/arm/mvp/mvpkm/nottested.h deleted file mode 100644 index 5226a22..0000000 --- a/arch/arm/mvp/mvpkm/nottested.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief NOT_TESTED() and related. - */ - -#ifndef _NOTTESTED_H -#define _NOTTESTED_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include <stdbool.h> - -#ifdef NOT_TESTED_ENABLED -#define NotTestedEnabled true -#else -#define NotTestedEnabled false -#endif - -#define NOT_TESTED() NOT_TESTED_JIRA(0) -#define NOT_TESTED_JIRA(_tkt,...) NotTested(_tkt, __FILE__, __LINE__) - -void NotTested(int tkt, char const *file, int line); - -#endif diff --git a/arch/arm/mvp/mvpkm/platdefx.h b/arch/arm/mvp/mvpkm/platdefx.h deleted file mode 100644 index 70fb8d7..0000000 --- a/arch/arm/mvp/mvpkm/platdefx.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Basic platform definitions needed various places. - */ - -#ifndef _PLATDEFX_H -#define _PLATDEFX_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define PAGE_ORDER 12 - -#ifndef PAGE_SIZE -#define PAGE_SIZE (1UL << PAGE_ORDER) -#endif -#if PAGE_SIZE != 4096 -#error bad page size PAGE_SIZE -#endif - -#define PA_2_PPN(_pa) ((_pa) / PAGE_SIZE) -#define PPN_2_PA(_ppn) ((_ppn) * PAGE_SIZE) - -#define VMM_DOMAIN 0x0 -#define VMM_DOMAIN_NO_ACCESS 0x3 -#define VMM_DOMAIN_CLIENT 0x1 -#define VMM_DOMAIN_MANAGER 0x4 - -#define INVALID_CVA (-(CVA)1) -#define INVALID_GVA (-(GVA)1) -#define INVALID_MVA (-(MVA)1) -#define INVALID_HKVA (-(HKVA)1) -#define INVALID_HUVA (-(HUVA)1) - -#define INVALID_MPN (((MPN)-1) >> ARM_L2D_SMALL_ORDER) -#define INVALID_PPN (((PPN)-1) >> ARM_L2D_SMALL_ORDER) - -#endif diff --git a/arch/arm/mvp/mvpkm/psr_defs.h b/arch/arm/mvp/mvpkm/psr_defs.h deleted file mode 100644 index 4fa53bc..0000000 --- a/arch/arm/mvp/mvpkm/psr_defs.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Constant definitions for ARM CPSR/SPSR registers. See A2.5 - * ARM DDI 0100I. - */ - -#ifndef _PSR_DEFS_H_ -#define _PSR_DEFS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define ARM_PSR_MODE_USER 0x10 -#define ARM_PSR_MODE_FIQ 0x11 -#define ARM_PSR_MODE_IRQ 0x12 -#define ARM_PSR_MODE_SUPERVISOR 0x13 -#define ARM_PSR_MODE_ABORT 0x17 -#define ARM_PSR_MODE_HVC 0x1a -#define ARM_PSR_MODE_UNDEFINED 0x1b -#define ARM_PSR_MODE_SYSTEM 0x1f - -/* Bit 31: N */ -#define ARM_PSR_N (1 << 31) - -/* Bit 30: Z */ -#define ARM_PSR_Z (1 << 30) - -/* Bit 29: C */ -#define ARM_PSR_C (1 << 29) - -/* Bit 28: V */ -#define ARM_PSR_V (1 << 28) - -/* Bit 27: Q */ -#define ARM_PSR_Q (1 << 27) - -#define ARM_PSR_COND_FLAGS \ - (ARM_PSR_N | ARM_PSR_Z | ARM_PSR_C | ARM_PSR_V | ARM_PSR_Q) - -/* Bits 26..25: ITSTATE<1..0> */ -#define ARM_PSR_ITSTATE_LOW MVP_MASK(25, 2) - -/* Bit 24: J */ -#define ARM_PSR_J (1 << 24) - -/* Bits 23..20 are reserved as of ARMv7 */ -#define ARM_PSR_RESERVED MVP_MASK(20, 4) - -/* Bits 19..16: GE<3..0> */ -#define ARM_PSR_GE MVP_MASK(16, 4) - -/* Bits 15..10: ITSTATE<7..2> */ -#define ARM_PSR_ITSTATE_HIGH MVP_MASK(10, 6) -#define ARM_PSR_ITSTATE (ARM_PSR_ITSTATE_LOW | ARM_PSR_ITSTATE_HIGH) - -/* Bit 9: E */ -#define ARM_PSR_E_POS (9) -#define ARM_PSR_E (1 << ARM_PSR_E_POS) - -/* Bit 8: A */ -#define ARM_PSR_A_POS (8) -#define ARM_PSR_A (1 << ARM_PSR_A_POS) - -/* Bit 7: I */ -#define ARM_PSR_I_POS (7) -#define ARM_PSR_I (1 << ARM_PSR_I_POS) - -/* Bit 6: F */ -#define ARM_PSR_F_POS (6) -#define ARM_PSR_F (1 << ARM_PSR_F_POS) - -/* Bit 5: T */ -#define ARM_PSR_T_POS (5) -#define ARM_PSR_T (1 << ARM_PSR_T_POS) - -/* Bits 4..0: Mode */ -#define ARM_PSR_MODE_MASK 0x1f - -#define ARM_PSR_MODE(cpsr) ((cpsr) & ARM_PSR_MODE_MASK) -#define ARM_PSR_USER_MODE(cpsr) (ARM_PSR_MODE(cpsr) == ARM_PSR_MODE_USER) - - -/* - * We shadow the 10 LSBs in the CPSR, with the exception of the T bit, as they - * are managed by the VMM on behalf of the guest and are potentially different - * than the physical CPSR during DE. - */ -#define ARM_PSR_MONITOR_BITS 10 -#define ARM_PSR_MONITOR_MASK (((1 << ARM_PSR_MONITOR_BITS) - 1) & ~ARM_PSR_T) - -#endif /// ifndef _PSR_DEFS_H_ diff --git a/arch/arm/mvp/mvpkm/qp.h b/arch/arm/mvp/mvpkm/qp.h deleted file mode 100644 index a8d7ac1..0000000 --- a/arch/arm/mvp/mvpkm/qp.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MVP Queue Pairs function and structure declarations - * - * MVP Queue Pairs: - * - * Queue pairs are intended to be a generic bulk data transport mechanism - * between the guest and host kernels. The queue pair abstraction is based - * on two ring buffers (queues) placed on a shared memory region mapped - * into both guest and host kernel address spaces. - * - * NOTE: Queue pairs are SINGLE-READER, SINGLE-WRITER. Any caller is - * responsible for multi-reader/writer serialization!!! - * - * There are a maximum of QP_MAX_QUEUE_PAIRS in the system, with a maximum - * size of QP_MAX_CAPACITY per pair. Each queue pair is identified by - * an ID. - * - * Each peer follows a producer-consumer model in which one side is the - * producer on one queue, and the other side is the consumer on that queue - * (and vice-versa for its pair). - * - * Data is enqueued and dequeued into the pair in transactional stages, - * meaning each enqueue/dequeue can be followed by zero or more - * enqueue/dequeues, but the enqueue/dequeue is not visible to the peer - * until it has been committed with the *Commit() function. - * In PVTCP, for example, this is used to enqueue a short header, then - * followed by 'segments' of iovecs, then followed by a commit. This - * model prevents a peer from reading the header, expecting a payload, - * but not being able to read the payload because it hasn't been - * enqueued yet. - * - * Queue Pair setup: - * - * Before data can be passed, the guest and host kernel must perform - * the following connection handshake: - * - * 1). A host kernel service registers a listener with the queue pair - * subsystem with a callback to be called when guests create - * and attach to a shared memory region. - * - * 2). Guest initiates an QP_Attach() operation to a shared memory region - * keyed by ID. This step allocates memory, maps it into the host - * address space, and optionally notifies any host services who are - * listening for attach requests from the guest (see previous step). - * Host listeners are provided with a copy of the initialization - * arguments used by the guest (id, size, service type). All registered - * listeners are iterated over until one of them handles the attach - * request and acknowledges with QP_SUCCESS. - * - * 3). The registered host callback is called, notifying the host that - * the guest has attached. - * - * 4). The host can now QP_Attach() to the shared memory region with the same - * arguments as the guest. The queue pair is now well formed and enqueues - * and dequeues can proceed on either side. - * - * Queue Pair teardown: - * - * 1). As before, teardowns are initiated by the guest. Hosts can register - * a callback to be called upon detach. Guests initiate a teardown - * through a call to QP_Detach(). - * - * 2). Registered hosts are notified through the aforementioned callback. - * 3). The host service can call QP_Detach() at its own leisure. Memory - * is freed, the queue pair is destroyed. - * - * If at any point the guest unexpectedly shuts down, the host will be - * notified at monitor shutdown time. Memory is freed, and the queue - * pair is destroyed. - * - */ - -#ifndef _QP_H -#define _QP_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -//#define QP_DEBUG 1 - -typedef enum QPState { - QP_STATE_FREE = 0x1, ///< No peers, not memory-backed - QP_STATE_CONNECTED, ///< Both peers attached , memory backed - QP_STATE_GUEST_ATTACHED, ///< Guest allocated memory, host not yet attached - QP_STATE_MAX // leave this at the end! -} QPState; - -typedef struct QPId { - uint32 context; - uint32 resource; -} QPId; - -/* - * Initialization arguments for each queue pair - */ -typedef struct QPInitArgs { - QPId id; ///< Shared memory region ID - uint32 capacity; ///< Total size of shared region in bytes - uint32 type; ///< Type of queue pair (PVTCP, other)... -} QPInitArgs; - -/* - * Placed on the shared region, two per region - */ -typedef struct QHandle { - volatile uint32 head; ///< queue head offset - volatile uint32 tail; ///< queue tail offset - volatile uint32 phantom_head; ///< queue shadow head offset - volatile uint32 phantom_tail; ///< queue shadow tail offset - uint8 data[0]; ///< start of data, runs off - // the struct -} QHandle; - -/* - * Local to each peer - */ -typedef struct QPHandle { - QPId id; ///< shared memory region ID - uint32 capacity; ///< size of region in bytes - QHandle *produceQ; ///< producer queue - QHandle *consumeQ; ///< consumer queue - uint32 queueSize; ///< size of each queue in bytes - uint32 type; ///< type of queue pair - - /* - * Following fields unused by guest - */ - QPState state; - void (*peerDetachCB)(void* data); ///< detach notification callback - void *detachData; ///< data for the detach cb - struct page **pages; ///< page pointers for shared region -} QPHandle; - -/* - * QP Error codes - */ -#define QP_SUCCESS 0 -#define QP_ERROR_NO_MEM (-1) -#define QP_ERROR_INVALID_HANDLE (-2) -#define QP_ERROR_INVALID_ARGS (-3) -#define QP_ERROR_ALREADY_ATTACHED (-4) - -/* - * Hard-coded limits - */ -#define QP_MIN_CAPACITY (PAGE_SIZE * 2) -#define QP_MAX_CAPACITY (1024*1024) // 1M -#define QP_MAX_QUEUE_PAIRS 32 -#define QP_MAX_ID QP_MAX_QUEUE_PAIRS -#define QP_MAX_LISTENERS QP_MAX_QUEUE_PAIRS -#define QP_MAX_PAGES (QP_MAX_CAPACITY/PAGE_SIZE) // 256 pages - -#define QP_INVALID_ID 0xFFFFFFFF -#define QP_INVALID_SIZE 0xFFFFFFFF -#define QP_INVALID_REGION 0xFFFFFFFF -#define QP_INVALID_TYPE 0xFFFFFFFF - -#ifdef __KERNEL__ -/** - * @brief Utility function to sanity check arguments - * @param args argument structure to check - * @return true if arguments are sane, false otherwise - */ -static inline -_Bool QP_CheckArgs(QPInitArgs *args) -{ - if (!args || - !is_power_of_2(args->capacity) || - (args->capacity < QP_MIN_CAPACITY) || - (args->capacity > QP_MAX_CAPACITY) || - !(args->id.resource < QP_MAX_ID || args->id.resource == QP_INVALID_ID) || - (args->type == QP_INVALID_TYPE)) { - return false; - } else { - return true; - } -} -#endif - - -/** - * @brief Utility function to sanity check a queue pair handle - * @param qp handle to the queue pair - * @return true if the handle is sane, false otherwise - */ -static inline -_Bool QP_CheckHandle(QPHandle *qp) -{ -#ifdef MVP_DEBUG - if (!(qp) || - !(qp->produceQ) || - !(qp->consumeQ) || - (qp->state >= (uint32)QP_STATE_MAX) || - !(qp->queueSize < (QP_MAX_CAPACITY/2))) { - return false; - } else { - return true; - } -#else - return true; -#endif -} - - -/** - * @brief Initializes an invalid handle - * @param[in, out] qp handle to the queue pair - */ -static inline void -QP_MakeInvalidQPHandle(QPHandle *qp) -{ - if (!qp) { - return; - } - - qp->id.context = QP_INVALID_ID; - qp->id.resource = QP_INVALID_ID; - qp->capacity = QP_INVALID_SIZE; - qp->produceQ = NULL; - qp->consumeQ = NULL; - qp->queueSize = QP_INVALID_SIZE; - qp->type = QP_INVALID_TYPE; - qp->state = QP_STATE_FREE; - qp->peerDetachCB = NULL; - qp->detachData = NULL; -} - -/* - * Host only - */ -typedef int32 (*QPListener)(const QPInitArgs*); -int32 QP_RegisterListener(const QPListener); -int32 QP_UnregisterListener(const QPListener); -int32 QP_RegisterDetachCB(QPHandle *qp, void (*callback)(void*), void *data); - - -/* - * Host and guest specific implementations, see qp_host.c and qp_guest.c - */ -int32 QP_Attach(QPInitArgs *args, QPHandle** qp); -int32 QP_Detach(QPHandle* qp); -int32 QP_Notify(QPInitArgs *args); - -/* - * Common implementation, see qp_common.c - */ -int32 QP_EnqueueSpace(QPHandle *qp); -int32 QP_EnqueueSegment(QPHandle *qp, const void *buf, size_t length); -int32 QP_EnqueueCommit(QPHandle *qp); -int32 QP_EnqueueReset(QPHandle *qp); - -static inline int32 -QP_EnqueueAtomic(QPHandle *qp, const void *buf, size_t length) -{ - int32 rc; - QP_EnqueueReset(qp); - rc = QP_EnqueueSegment(qp, buf, length); - if (rc < 0) { - return rc; - } else { - QP_EnqueueCommit(qp); - } - return rc; -} - -int32 QP_DequeueSpace(QPHandle *qp); -int32 QP_DequeueSegment(QPHandle *qp, const void *buf, size_t length); -int32 QP_DequeueReset(QPHandle *qp); -int32 QP_DequeueCommit(QPHandle *qp); - -static inline int32 -QP_DequeueAtomic(QPHandle *qp, const void *buf, size_t length) -{ - int32 rc; - QP_DequeueReset(qp); - rc = QP_DequeueSegment(qp, buf, length); - if (rc < 0) { - return rc; - } else { - QP_DequeueCommit(qp); - } - return rc; -} - -/* - * HVC methods and signatures - */ -#define MVP_QP_SIGNATURE 0x53525051 ///< 'QPRS' -#define MVP_QP_ATTACH (MVP_OBJECT_CUSTOM_BASE + 0) ///< attach to a queue pair -#define MVP_QP_DETACH (MVP_OBJECT_CUSTOM_BASE + 1) ///< detach from a queue pair -#define MVP_QP_NOTIFY (MVP_OBJECT_CUSTOM_BASE + 2) ///< notify host of attach -#define MVP_QP_LAST (MVP_OBJECT_CUSTOM_BASE + 3) ///< Number of methods - -/* - * Debug macros - */ -#ifdef QP_DEBUG - #ifdef IN_MONITOR - #define QP_DBG(...) Log(__VA_ARGS__) - #else - #define QP_DBG(...) printk(KERN_INFO __VA_ARGS__) - #endif -#else - #define QP_DBG(...) -#endif - -#endif diff --git a/arch/arm/mvp/mvpkm/qp_common.c b/arch/arm/mvp/mvpkm/qp_common.c deleted file mode 100644 index 8d121a1..0000000 --- a/arch/arm/mvp/mvpkm/qp_common.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MVP Queue Pairs common enqueue and dequeue functions. - * Does not include Attach(), and Detach(), as this will be specific - * to host/guest - * implementations. - */ - -#include <linux/module.h> - -#include "mvp_types.h" -#include "comm_os.h" -#include "qp.h" - - -/** - * @brief Calculate free space in the queue, convenience function - * @param head queue head offset - * @param tail queue tail offset - * @param queueSize size of queue - * @return free space in the queue - */ -static inline int32 -FreeSpace(uint32 head, uint32 tail, uint32 queueSize) { - /* Leave 1 byte free to resolve ambiguity between empty - * and full conditions */ - return (tail >= head) ? (queueSize - (tail - head) - 1) : - (head - tail - 1); -} - - -/** - * @brief Returns available space for enqueue, in bytes - * @param qp handle to the queue pair - * @return available space in bytes in the queue for enqueue operations, - * QP_ERROR_INVALID_HANDLE if the handle is malformed - */ -int32 -QP_EnqueueSpace(QPHandle *qp) -{ - uint32 head; - uint32 phantom; - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - head = qp->produceQ->head; - phantom = qp->produceQ->phantom_tail; - - if (head >= qp->queueSize || - phantom >= qp->queueSize) { - return QP_ERROR_INVALID_HANDLE; - } - - return FreeSpace(head, phantom, qp->queueSize); -} - - -/** - * @brief Enqueues a segment of data into the producer queue - * @param qp handle to the queue pair - * @param buf data to enqueue - * @param bufSize size in bytes to enqueue - * @return number of bytes enqueued on success, appropriate error - * code otherwise - * @sideeffects May move phantom tail pointer - */ -int32 -QP_EnqueueSegment(QPHandle *qp, const void *buf, size_t bufSize) -{ - int32 freeSpace; - uint32 head; - uint32 phantom; - - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - head = qp->produceQ->head; - phantom = qp->produceQ->phantom_tail; - - /* - * This check must go after the assignment above, - * otherwise a malicious guest could write bogus - * offsets to the queue and cause the memcpy to - * copy into unpleasant places. - */ - if (head >= qp->queueSize || - phantom >= qp->queueSize) { - return QP_ERROR_INVALID_HANDLE; - } - - freeSpace = FreeSpace(head, phantom, qp->queueSize); - - if (bufSize <= freeSpace) { - if (bufSize + phantom < qp->queueSize) { - memcpy(qp->produceQ->data + phantom, buf, bufSize); - phantom += bufSize; - } else { - uint32 written = qp->queueSize - phantom; - memcpy(qp->produceQ->data + phantom, buf, written); - memcpy(qp->produceQ->data, (uint8*)buf + written, bufSize - written); - phantom = bufSize - written; - } - } else { - return QP_ERROR_NO_MEM; - } - - qp->produceQ->phantom_tail = phantom; - - return bufSize; -} - - -/** - * @brief Commits any previous EnqueueSegment operations to the queue - * pair - * @param qp handle to the queue pair. - * @return QP_SUCCESS on success, appropriate error code otherwise. - * @sideeffects May move tail pointer - */ -int32 -QP_EnqueueCommit(QPHandle *qp) -{ - uint32 phantom; - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - phantom = qp->produceQ->phantom_tail; - if (phantom >= qp->queueSize) { - return QP_ERROR_INVALID_HANDLE; - } - - qp->produceQ->tail = phantom; - return QP_SUCCESS; -} - - -/** - * @brief Returns any available bytes for dequeue - * @param qp handle to the queue pair - * @return available bytes for dequeue, appropriate error code - * otherwise - */ -int32 -QP_DequeueSpace(QPHandle *qp) -{ - uint32 tail; - uint32 phantom; - int32 bytesAvailable; - - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - tail = qp->consumeQ->tail; - phantom = qp->consumeQ->phantom_head; - - if (tail >= qp->queueSize || - phantom >= qp->queueSize) { - return QP_ERROR_INVALID_HANDLE; - } - - bytesAvailable = (tail - phantom); - if ((int32)bytesAvailable < 0) { - bytesAvailable += qp->queueSize; - } - return bytesAvailable; -} - - -/** - * @brief Dequeues a segment of data from the consumer queue into - * a buffer - * @param qp handle to the queue pair - * @param[out] buf buffer to copy to - * @param bytesDesired number of bytes to dequeue - * @return number of bytes dequeued on success, appropriate error - * code otherwise - * @sideeffects May move phantom head pointer - */ -int32 -QP_DequeueSegment(QPHandle *qp, const void *buf, size_t bytesDesired) -{ - uint32 tail; - uint32 phantom; - int32 bytesAvailable = 0; - - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - tail = qp->consumeQ->tail; - phantom = qp->consumeQ->phantom_head; - - /* - * This check must go after the assignment above, - * otherwise a malicious guest could write bogus - * offsets to the queue and cause the memcpy to - * copy into unpleasant places. - */ - if (tail >= qp->queueSize || - phantom >= qp->queueSize) { - return QP_ERROR_INVALID_HANDLE; - } - - bytesAvailable = (tail - phantom); - if ((int32)bytesAvailable < 0) { - bytesAvailable += qp->queueSize; - } - - if (bytesDesired <= bytesAvailable) { - if (bytesDesired + phantom < qp->queueSize) { - memcpy((void*)buf, qp->consumeQ->data + phantom, bytesDesired); - phantom += bytesDesired; - } else { - uint32 written = qp->queueSize - phantom; - memcpy((void*)buf, qp->consumeQ->data + phantom, written); - memcpy((uint8*)buf + written, qp->consumeQ->data, bytesDesired - written); - phantom = bytesDesired - written; - } - } else { - return QP_ERROR_NO_MEM; - } - - qp->consumeQ->phantom_head = phantom; - - return bytesDesired; -} - - -/** - * @brief Commits any previous DequeueSegment operations to the queue - * pair - * @param qp handle to the queue pair - * @return QP_SUCCESS on success, QP_ERROR_INVALID_HANDLE if the handle - * is malformed - * @sideeffects Moves the head pointer - */ -int32 -QP_DequeueCommit(QPHandle *qp) -{ - uint32 phantom; - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - phantom = qp->consumeQ->phantom_head; - if (phantom >= qp->queueSize) { - return QP_ERROR_INVALID_HANDLE; - } - - qp->consumeQ->head = phantom; - return QP_SUCCESS; -} - - -/** - * @brief Resets the phantom tail pointer and discards any pending - * enqueues - * @param qp handle to the queue pair - * @return QP_SUCCESS on success, QP_ERROR_INVALID_HANDLE if the handle - * is malformed - * @sideeffects Resets the phantom tail pointer - */ -int32 -QP_EnqueueReset(QPHandle *qp) -{ - uint32 tail; - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - tail = qp->produceQ->tail; - if (tail >= qp->queueSize) { - return QP_ERROR_INVALID_HANDLE; - } - - qp->produceQ->phantom_tail = tail; - return QP_SUCCESS; -} - -/** - * @brief Resets the phantom head pointer and discards any pending - * dequeues - * @param qp handle to the queue pair - * @return QP_SUCCESS on success, QP_ERROR_INVALID_HANDLE if the handle - * is malformed - * @sideeffects Resets the phantom head pointer - */ -int32 -QP_DequeueReset(QPHandle *qp) -{ - uint32 head; - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - head = qp->consumeQ->head; - if (head >= qp->queueSize) { - return QP_ERROR_INVALID_HANDLE; - } - - qp->consumeQ->phantom_head = head; - return QP_SUCCESS; -} - -EXPORT_SYMBOL(QP_EnqueueSpace); -EXPORT_SYMBOL(QP_EnqueueSegment); -EXPORT_SYMBOL(QP_EnqueueCommit); -EXPORT_SYMBOL(QP_DequeueSpace); -EXPORT_SYMBOL(QP_DequeueSegment); -EXPORT_SYMBOL(QP_DequeueCommit); -EXPORT_SYMBOL(QP_EnqueueReset); -EXPORT_SYMBOL(QP_DequeueReset); diff --git a/arch/arm/mvp/mvpkm/qp_host_kernel.c b/arch/arm/mvp/mvpkm/qp_host_kernel.c deleted file mode 100644 index c53f315..0000000 --- a/arch/arm/mvp/mvpkm/qp_host_kernel.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief MVP host kernel implementation of the queue pairs API - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/highmem.h> -#include <linux/slab.h> - -#include "mvp.h" -#include "mvpkm_kernel.h" -#include "qp.h" -#include "qp_host_kernel.h" - -static QPHandle queuePairs[QP_MAX_QUEUE_PAIRS]; -static QPListener listeners[QP_MAX_LISTENERS]; - -/* - * Protect listeners and queuePairs. - */ -static DEFINE_MUTEX(qpLock); - -#define QPLock() mutex_lock(&qpLock) -#define QPUnlock() mutex_unlock(&qpLock) - -/** - * @brief Map a vector of pages into virtually contiguous kernel space - * @param vm this vm's vm struct - * @param base base machine page number that lists pages to map - * @param nrPages number of pages to map - * @param[out] qp handle to qp to set up - * @param[out] hkva virtual address mapping - * @return QP_SUCCESS on success, error code otherwise. Mapped address - * is returned in hkva - */ - -static int32 -MapPages(MvpkmVM *vm, - MPN base, - uint32 nrPages, - QPHandle *qp, - HKVA *hkva) -{ - HKVA *va; - uint32 i; - uint32 rc; - struct page *basepfn = pfn_to_page(base); - struct page **pages; - - BUG_ON(!vm); // this would be very bad. - - if (!hkva) { - return QP_ERROR_INVALID_ARGS; - } - - pages = kmalloc(nrPages * sizeof (MPN), GFP_KERNEL); - if (!pages) { - return QP_ERROR_NO_MEM; - } - - /* - * Map in the first page, read out the MPN vector - */ - down_write(&vm->lockedSem); - va = kmap(basepfn); - if (!va) { - rc = QP_ERROR_INVALID_ARGS; - kfree(pages); - qp->pages = NULL; - goto out; - } - - /* - * Grab references and translate MPNs->PFNs - */ - for (i = 0; i < nrPages; i++) { - pages[i] = pfn_to_page(((MPN*)va)[i]); - get_page(pages[i]); - } - - /* - * Clean up the first mapping and remap the entire vector - */ - kunmap(basepfn); - va = vmap(pages, nrPages, VM_MAP, PAGE_KERNEL); - if (!va) { - rc = QP_ERROR_NO_MEM; - for (i = 0; i < nrPages; i++) { - put_page(pages[i]); - } - kfree(pages); - qp->pages = NULL; - goto out; - } else { - *hkva = (HKVA)va; - qp->pages = pages; - } - - /* - * Let's not leak mpns.. - */ - memset(va, 0x0, nrPages * PAGE_SIZE); - - rc = QP_SUCCESS; - -out: - up_write(&vm->lockedSem); - return rc; -} - -/** - * @brief Initialize all free queue pair entries and listeners - */ - -void -QP_HostInit(void) -{ - uint32 i; - - for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) { - QP_MakeInvalidQPHandle(&queuePairs[i]); - } - - for (i = 0; i < QP_MAX_LISTENERS; i++) { - listeners[i] = NULL; - } -} - - -/** - * @brief Detaches a guest from a queue pair and notifies - * any registered listeners through the detach callback - * @param id id that guest requested a detach from, detaches all - * queue pairs associated with a VM if the resource id == QP_INVALID_ID - * @return QP_SUCCESS on success, appropriate error code otherwise - */ - -int32 -QP_GuestDetachRequest(QPId id) -{ - QPHandle *qp; - uint32 i; - - if (id.resource >= QP_MAX_ID && id.resource != QP_INVALID_ID) { - return QP_ERROR_INVALID_ARGS; - } - - QPLock(); - - /* - * Invalidate all queue pairs associated with this VM if - * resource == QP_INVALID_ID - */ - if (id.resource == QP_INVALID_ID) { - for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) { - qp = &queuePairs[i]; - if (qp->id.context == id.context && qp->peerDetachCB) { - qp->peerDetachCB(qp->detachData); - } - } - } else { - qp = &queuePairs[id.resource]; - if (qp->peerDetachCB) { - qp->peerDetachCB(qp->detachData); - } - } - - QPUnlock(); - - return QP_SUCCESS; -} - - -/** - * @brief Attaches a guest to shared memory region - * @param vm guest to attach - * @param args queue pair args structure: - * - args->id: id of the region to attach to, if id.resource == QP_INVALID_ID, then - * an id is assigned - * - args->capacity: total size of the region in bytes - * - args->type: type of queue pair (e.g PVTCP) - * @param base base machine page number that lists pages to map - * @param nrPages number of pages to map - * @return QP_SUCCESS on success, appropriate error code otherwise. - */ - -int32 -QP_GuestAttachRequest(MvpkmVM *vm, - QPInitArgs *args, - MPN base, - uint32 nrPages) -{ - int32 rc; - HKVA hkva = 0; - QPHandle *qp; - uint32 i; - - if ((!QP_CheckArgs(args)) || - (vm->wsp->guestId != (Mksck_VmId)args->id.context) || - (args->capacity != (nrPages * PAGE_SIZE))) { - return QP_ERROR_INVALID_ARGS; - } - - QP_DBG("%s: Guest requested attach to [%u:%u] capacity: %u type: %x base: %x nrPages: %u\n", - __FUNCTION__, - args->id.context, - args->id.resource, - args->capacity, - args->type, - base, - nrPages); - - QPLock(); - - /* - * Assign a resource id if id == QP_INVALID_ID - */ - if (args->id.resource == QP_INVALID_ID) { - for (i = 0; i < QP_MAX_QUEUE_PAIRS; i++) { - if (queuePairs[i].state == QP_STATE_FREE) { - args->id.resource = i; - QP_DBG("%s: Guest requested anonymous region, assigning resource id %u\n", - __FUNCTION__, args->id.resource); - goto found; - } - } - - rc = QP_ERROR_NO_MEM; - goto out; - } - -found: - qp = queuePairs + args->id.resource; - - if (qp->state != QP_STATE_FREE) { - rc = QP_ERROR_ALREADY_ATTACHED; - goto out; - } - - /* - * Brand new queue pair, allocate some memory to back it and - * initialize the entry - */ - rc = MapPages(vm, base, nrPages, qp, &hkva); - if (rc != QP_SUCCESS) { - goto out; - } - - /* NB: reversed from the guest */ - qp->id = args->id; - qp->capacity = args->capacity; - qp->produceQ = (QHandle*)hkva; - qp->consumeQ = (QHandle*)(hkva + args->capacity/2); - qp->queueSize = args->capacity/2 - sizeof(QHandle); - qp->type = args->type; - qp->state = QP_STATE_GUEST_ATTACHED; - - /* - * The qp is now assumed to be well-formed - */ - QP_DBG("%s: Guest attached to region [%u:%u] capacity: %u HKVA: %x\n", - __FUNCTION__, - args->id.context, - args->id.resource, - args->capacity, - (uint32)hkva); - rc = QP_SUCCESS; - -out: - QPUnlock(); - if (rc != QP_SUCCESS) { - QP_DBG("%s: Failed to attach: %u\n", __FUNCTION__, rc); - } - return rc; -} - - -/** - * @brief Attaches the host to the shared memory region. The guest - * MUST have allocated the shmem region already or else this will fail. - * @param args structure with the shared memory region id to attach to, - * total size of the region in bytes, and type of queue pair (e.g PVTCP) - * @param[in, out] qp handle to the queue pair to return - * @return QP_SUCCESS on success, appropriate error code otherwise - */ - -int32 -QP_Attach(QPInitArgs *args, - QPHandle** qp) -{ - uint32 rc; - - if (!qp || !QP_CheckArgs(args)) { - return QP_ERROR_INVALID_ARGS; - } - - QP_DBG("%s: Attaching to id: [%u:%u] capacity: %u\n", - __FUNCTION__, - args->id.context, - args->id.resource, - args->capacity); - - QPLock(); - *qp = queuePairs + args->id.resource; - - if (!QP_CheckHandle(*qp)) { - *qp = NULL; - rc = QP_ERROR_INVALID_HANDLE; - goto out; - } - - if ((*qp)->state == QP_STATE_CONNECTED) { - rc = QP_ERROR_ALREADY_ATTACHED; - goto out; - } - - if ((*qp)->state != QP_STATE_GUEST_ATTACHED) { - rc = QP_ERROR_INVALID_HANDLE; - goto out; - } - - (*qp)->state = QP_STATE_CONNECTED; - - QP_DBG("%s: Attached!\n", __FUNCTION__); - rc = QP_SUCCESS; - -out: - QPUnlock(); - return rc; -} - -/** - * @brief Detaches the host to the shared memory region. - * @param[in, out] qp handle to the queue pair - * @return QP_SUCCESS on success, appropriate error code otherwise - * @sideeffects Frees memory - */ - -int32 -QP_Detach(QPHandle* qp) -{ - uint32 rc; - uint32 i; - - QPLock(); - if (!QP_CheckHandle(qp)) { - rc = QP_ERROR_INVALID_HANDLE; - goto out; - } - - QP_DBG("%s: Freeing queue pair [%u:%u]\n", - __FUNCTION__, - qp->id.context, - qp->id.resource); - - BUG_ON(!qp->produceQ); - BUG_ON(!qp->pages); - BUG_ON((qp->state != QP_STATE_CONNECTED) && - (qp->state != QP_STATE_GUEST_ATTACHED)); - - vunmap(qp->produceQ); - - for (i = 0; i < qp->capacity/PAGE_SIZE; i++) { - put_page(qp->pages[i]); - } - kfree(qp->pages); - - QP_DBG("%s: Host detached from [%u:%u]\n", - __FUNCTION__, - qp->id.context, - qp->id.resource); - - QP_MakeInvalidQPHandle(qp); - rc = QP_SUCCESS; - -out: - QPUnlock(); - return rc; -} - - -/** - * @brief Detaches and destroys all queue pairs associated with a given guest - * @param vmID which VM to clean up - * @sideeffects Destroys all queue pairs for guest vmID - */ - -void QP_DetachAll(Mksck_VmId vmID) { - QPId id = { - .context = (uint32)vmID, - .resource = QP_INVALID_ID - }; - - QP_DBG("%s: Detaching all queue pairs from vmId context %u\n", __FUNCTION__, vmID); - QP_GuestDetachRequest(id); -} - -/** - * @brief Registers a listener into the queue pair system. Callbacks are - * called with interrupts disabled and must not sleep. - * @param listener listener to be called - * @return QP_SUCCESS on success, QP_ERROR_NO_MEM if no more - * listeners can be registered - */ - -int32 -QP_RegisterListener(const QPListener listener) -{ - uint32 i; - int32 rc = QP_ERROR_NO_MEM; - - QPLock(); - for (i = 0; i < QP_MAX_LISTENERS; i++) { - if (!listeners[i]) { - listeners[i] = listener; - QP_DBG("%s: Registered listener\n", __FUNCTION__); - rc = QP_SUCCESS; - break; - } - } - QPUnlock(); - - return rc; -} - - -/** - * @brief Unregister a listener service from the queue pair system. - * @param listener listener to unregister - * @return QP_SUCCESS on success, appropriate error code otherwise - */ - -int32 -QP_UnregisterListener(const QPListener listener) -{ - uint32 i; - int32 rc = QP_ERROR_INVALID_HANDLE; - - QPLock(); - for (i = 0; i < QP_MAX_LISTENERS; i++) { - if (listeners[i] == listener) { - listeners[i] = NULL; - QP_DBG("%s: Unregistered listener\n", __FUNCTION__); - rc = QP_SUCCESS; - break; - } - } - QPUnlock(); - - return rc; -} - - -/** - * @brief Registers a callback to be called when the guest detaches - * from a queue pair. Callbacks are called with interrupts and - * must not sleep. - * @param qp handle to the queue pair - * @param callback callback to be called - * @param data data to deliver to the callback - * @return QP_SUCCESS on success, appropriate error code otherwise - */ - -int32 -QP_RegisterDetachCB(QPHandle *qp, - void (*callback)(void*), - void *data) -{ - if (!QP_CheckHandle(qp)) { - return QP_ERROR_INVALID_HANDLE; - } - - if (!callback) { - return QP_ERROR_INVALID_ARGS; - } - - qp->peerDetachCB = callback; - qp->detachData = data; - QP_DBG("%s: Registered detach callback\n", __FUNCTION__); - return QP_SUCCESS; -} - - -/** - * @brief Noop on the host, only guests can initiate a notify - * @param args noop - * @return QP_SUCCESS - */ - - -int32 QP_Notify(QPInitArgs *args) { - return QP_SUCCESS; -} - - -/** - * @brief Notify any registered listeners for the given queue pair - * @param args initialization arguments used by the guest - * @return QP_SUCCESS on success, error otherwise - */ - -int32 QP_NotifyListener(QPInitArgs *args) { - int32 i; - QPHandle *qp = NULL; - - if (!QP_CheckArgs(args)) { - return QP_ERROR_INVALID_ARGS; - } - - /* - * Iterate over listeners until one of them reports they handled it - */ - QPLock(); - for (i = 0; i < QP_MAX_LISTENERS; i++) { - if (listeners[i]) { - QP_DBG("Delivering attach event to listener...\n"); - if (listeners[i](args) == QP_SUCCESS) { - break; - } - } - } - - if (i == QP_MAX_LISTENERS) { - /* - * No listener successfully probed this QP. - * The guest DETACH HVC isn't implemented; we need compensate for it - * by deallocating the QP here. - * This is a workaround which assumes, more-or-less correctly, that - * unsuccessful QP probes never lead to subsequent host-attaching. - */ - - qp = &queuePairs[args->id.resource]; - } - - QPUnlock(); - - if (qp) { - QP_Detach(qp); - } - return QP_SUCCESS; -} - - -EXPORT_SYMBOL(QP_Attach); -EXPORT_SYMBOL(QP_Detach); -EXPORT_SYMBOL(QP_RegisterListener); -EXPORT_SYMBOL(QP_UnregisterListener); -EXPORT_SYMBOL(QP_RegisterDetachCB); -EXPORT_SYMBOL(QP_Notify); diff --git a/arch/arm/mvp/mvpkm/qp_host_kernel.h b/arch/arm/mvp/mvpkm/qp_host_kernel.h deleted file mode 100644 index 111524a..0000000 --- a/arch/arm/mvp/mvpkm/qp_host_kernel.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief QP host function prototypes - */ - - -#ifndef _QP_HOST_KERNEL_H -#define _QP_HOST_KERNEL_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -void QP_HostInit(void); -int32 QP_GuestAttachRequest(MvpkmVM *vm, - QPInitArgs *args, - MPN base, - uint32 nr_pages); -int32 QP_GuestDetachRequest(QPId id); -void QP_DetachAll(Mksck_VmId vmID); -int32 QP_NotifyListener(QPInitArgs *args); - -#endif diff --git a/arch/arm/mvp/mvpkm/tsc.h b/arch/arm/mvp/mvpkm/tsc.h deleted file mode 100644 index 0b3149b..0000000 --- a/arch/arm/mvp/mvpkm/tsc.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Time stamp and event counters. - */ - -#ifndef _TSC_H_ -#define _TSC_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "arm_inline.h" - -#define ARM_PMNC_E (1 << 0) -#define ARM_PMNC_D (1 << 3) - -#define ARM_PMCNT_C (1 << 31) - -#define ARM_PMNC_INVALID_EVENT -1 - -#define TSC_READ(_reg) ARM_MRC_CP15(CYCLE_COUNT, (_reg)) -#define TSC_WRITE(_reg) ARM_MCR_CP15(CYCLE_COUNT, (_reg)) - -#endif // ifndef _TSC_H_ diff --git a/arch/arm/mvp/mvpkm/utils.h b/arch/arm/mvp/mvpkm/utils.h deleted file mode 100644 index 1fc56e9..0000000 --- a/arch/arm/mvp/mvpkm/utils.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief General architecture-independent definitions, typedefs, and macros. - */ - -#ifndef _UTILS_H -#define _UTILS_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_WORKSTATION -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define MAX_FILENAME 128 - -// Round address up to given size boundary -// Note: ALIGN() conflicts with Linux - -#define MVP_ALIGN(_v, _n) (((_v) + (_n) - 1) & -(_n)) - -#define ALIGNVA(_addr, _size) MVP_ALIGN(_addr, _size) - -#define alignof(t) offsetof(struct { char c; typeof(t) x; }, x) - -#define MIN(x,y) ((x) < (y) ? (x) : (y)) -#define MAX(x,y) ((x) > (y) ? (x) : (y)) - -#ifndef NULL -#define NULL ((void *)0) -#endif - -#define KB(_X_) ((_X_)*1024U) -#define MB(_X_) (KB(_X_)*1024) -#define GB(_X_) (MB(_X_)*1024) - -#define NELEM(x) (sizeof(x)/sizeof((x)[0])) - -/* - * x in [low,high) - * args evaluated once - */ -#define RANGE(x,low,high) \ - ({ \ - typeof(x) _x = (x); \ - typeof(x) _low = (typeof(x))(low); \ - typeof(x) _high =(typeof(x))(high); \ - (_Bool)( (_low <= _x) && (_x < _high)); \ - }) - -#define OBJECTS_PER_PAGE(_type) (PAGE_SIZE / sizeof(_type)) - -#define MA_2_MPN(_ma) ((MPN)((_ma) / PAGE_SIZE)) -#define MPN_2_MA(_mpn) ((MA)((_mpn) * PAGE_SIZE)) - -#define VA_2_VPN(_va) ((_va) / PAGE_SIZE) -#define VPN_2_vA(_vpn) ((_vpn) * PAGE_SIZE) - -/* - * The following convenience macro can be used in a following situation - * - * send(..., &foo, sizeof(foo)) --> send(..., PTR_N_SIZE(foo)) - */ - -#define PTR_N_SIZE(_var) &(_var), sizeof(_var) - - -/* - * - * BIT-PULLING macros - * - */ -#define MVP_BIT(val,n) ( ((val)>>(n))&1) -#define MVP_BITS(val,m,n) (((val)<<(31-(n))) >> ((31-(n))+(m)) ) -#define MVP_EXTRACT_FIELD(w, m, n) MVP_BITS((w), (m), ((m) + (n) - 1)) -#define MVP_MASK(m, n) (MVP_EXTRACT_FIELD(~(uint32)0U, (m), (n)) << (m)) -#define MVP_UPDATE_FIELD(old_val, field_val, m, n) \ - (((old_val) & ~MVP_MASK((m), (n))) | (MVP_EXTRACT_FIELD((field_val), 0, (n)) << (m))) - -/* - * - * 64BIT-PULLING macros - * - */ -#define MVP_BITS64(val,m,n) (((val)<<(63-(n))) >> ((63-(n))+(m)) ) -#define MVP_EXTRACT_FIELD64(w, m, n) MVP_BITS64((w), (m), ((m) + (n) - 1)) -#define MVP_MASK64(m, n) (MVP_EXTRACT_FIELD64(~(uint64)0ULL, (m), (n)) << (m)) -#define MVP_UPDATE_FIELD64(old_val, field_val, m, n) \ - (((old_val) & ~MVP_MASK64((m), (n))) | (MVP_EXTRACT_FIELD64(((uint64)(field_val)), 0ULL, (n)) << (m))) - -/* - * - * BIT-CHANGING macros - * - */ -#define MVP_SETBIT(val,n) ((val)|=(1<<(n))) -#define MVP_CLRBIT(val,n) ((val)&=(~(1<<(n)))) - -/* - * Fixed bit-width sign extension. - */ -#define MVP_SIGN_EXTEND(val,width) \ - (((val) ^ (1 << ((width) - 1))) - (1 << ((width) - 1))) - - -/* - * Assembler helpers. - */ -#define _MVP_HASH # -#define MVP_HASH() _MVP_HASH - -#define _MVP_STRINGIFY(...) #__VA_ARGS__ -#define MVP_STRINGIFY(...) _MVP_STRINGIFY(__VA_ARGS__) - -#ifndef __ASSEMBLER__ - -#include <stddef.h> -#include <stdbool.h> - -/* - * Constant equivalents of build-flags. - * - * Test these when possible instead of using #ifdef so that your code - * gets parsed. - */ -#ifdef MVP_DEBUG -static const _Bool mvpDebug = true; -#else -static const _Bool mvpDebug = false; -#endif - -#ifdef MVP_STATS -static const _Bool mvpStats = true; -#else -static const _Bool mvpStats = false; -#endif - -#ifdef MVP_DEVEL -static const _Bool mvpDevel = true; -#else -static const _Bool mvpDevel = false; -#endif - -#endif - -#endif diff --git a/arch/arm/mvp/mvpkm/ve_defs.h b/arch/arm/mvp/mvpkm/ve_defs.h deleted file mode 100644 index bd1d975..0000000 --- a/arch/arm/mvp/mvpkm/ve_defs.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Virtualization extension definitions. - * - * See ARM PRD03-GENC-008353 11.0. - */ -#ifndef _VE_DEFS_H_ -#define _VE_DEFS_H_ - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define ARM_VE_HSR_EC_BIT_POS 26 -#define ARM_VE_HSR_EC_LENGTH 6 - -#define ARM_VE_HSR_EC_UNKNOWN 0x00 -#define ARM_VE_HSR_EC_WFI_WFE 0x01 -#define ARM_VE_HSR_EC_MCR_MRC_CP15 0x03 -#define ARM_VE_HSR_EC_MCRR_MRRC_CP15 0x04 -#define ARM_VE_HSR_EC_MCR_MRC_CP14 0x05 -#define ARM_VE_HSR_EC_LDC_STC_CP14 0x06 -#define ARM_VE_HSR_EC_HCPTR 0x07 -#define ARM_VE_HSR_EC_MRC_CP10 0x08 -#define ARM_VE_HSR_EC_JAZELLE 0x09 -#define ARM_VE_HSR_EC_BXJ 0x0a -#define ARM_VE_HSR_EC_MRRC_CP14 0x0c -#define ARM_VE_HSR_EC_SVC_HYP 0x11 -#define ARM_VE_HSR_EC_HVC 0x12 -#define ARM_VE_HSR_EC_SMC 0x13 -#define ARM_VE_HSR_EC_IABORT_SND 0x20 -#define ARM_VE_HSR_EC_IABORT_HYP 0x21 -#define ARM_VE_HSR_EC_DABORT_SND 0x24 -#define ARM_VE_HSR_EC_DABORT_HYP 0x25 - -#define ARM_VE_HSR_FS_BIT_POS 0 -#define ARM_VE_HSR_FS_LENGTH 6 - -#define ARM_VE_HSR_FS_TRANS_L1 0x5 -#define ARM_VE_HSR_FS_TRANS_L2 0x6 -#define ARM_VE_HSR_FS_TRANS_L3 0x7 - -#define ARM_VE_HSR_FS_PERM_L1 0xd -#define ARM_VE_HSR_FS_PERM_L2 0xe -#define ARM_VE_HSR_FS_PERM_L3 0xf - -#endif /// ifndef _VE_DEFS_H_ diff --git a/arch/arm/mvp/mvpkm/vfp_switch.S b/arch/arm/mvp/mvpkm/vfp_switch.S deleted file mode 100644 index 49d3987..0000000 --- a/arch/arm/mvp/mvpkm/vfp_switch.S +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -#include "arm_defs.h" -#include "platdefx.h" -#include "arm_as_macros.h" - -/** - * @file - * - * @brief Save and Load VFP entire VFP state. - */ - - .text - -/** - * @brief Save VFP context - * @param R0 = save area pointer: - * .long fpexc,fpscr,fpinst,fpinst2,cpacr,fpexc' - * .double d0..d15 - * .double d16..d31 - * Note: VFP is left in an enable state regardless of initial state. - */ - .align 4 - .global SaveVFP -SaveVFP: - /* - * Save registers. GCC does not expect us to preserve R0..R3,R12,LR. - */ - stmdb sp!, {r4-r6} - - /* - * Save Coproc Access Control register. - */ - mrc_p15 COPROC_ACCESS_CONTROL, r5 - - /* - * If CP10/11 are disabled, enable them so we can save VFP state. - * The host (or guest) may have left data in the data registers that - * must be preserved. - */ - orr r2, r5, #CPACR_CP10_CP11_PRIV_ONLY - mcr_p15 COPROC_ACCESS_CONTROL, r2 - isb - - /* - * Follow procedure on AppxB-22 ARM DDI0406B to save FPINST[2]. - * Also enable VFP access with FPEXC_EN. - */ - fmrx r1, fpexc @ get existing FPEXC system register - orr r6, r1, #ARM_VFP_SYSTEM_REG_FPEXC_EX|ARM_VFP_SYSTEM_REG_FPEXC_FP2V|ARM_VFP_SYSTEM_REG_FPEXC_EN -#if !defined(MVP_HOST_CODE_forceon) - fmxr fpexc, r6 @ set FPEXC.EX, .FP2V and .EN - fmrx r6, fpexc @ read them back - tst r6, #ARM_VFP_SYSTEM_REG_FPEXC_EX @ see if either one is valid - beq 1000f @ neither, skip it all - fmrx r3, FPINST @ FPINST is valid, save it - tst r6, #ARM_VFP_SYSTEM_REG_FPEXC_FP2V @ see if FPINST2 is valid - beq 1000f - fmrx r4, FPINST2 @ FPINST2 is valid, save it -1000: -#else - mov r6, r1 -#endif - fmrx r2, FPSCR @ always save FPSCR system register - - /* - * At this point: - * R1 = original FPEXC - * R2 = FPSCR - * R3 = FPINST - * R4 = FPINST2 - * R5 = original CPACR - * R6 = FPEXC readback with FPEXC.EX, .FP2V and .EN set - * telling us whether FPINST/2 are valid - */ - stmia r0!, {r1-r6} - - /* - * Save floating point data registers. - */ - vstmia r0!, {d0-d15} @ Save d0 thru d15 - - /** - * @todo We should probably just read MVFR0 once at boot/initialization - * time and store it in some variable, to save having to do what might - * be expensive coprocessor accesses. - */ - fmrx r1, MVFR0 @ Read Media and VFP Feature Register 0 - and r1, r1, #ARM_VFP_SYSTEM_REG_MVFR0_A_SIMD_MASK @ A_SIMD field - cmp r1, #2 @ 32 x 64bit registers? - bne 2000f - vstmia r0!, {d16-d31} -2000: - - /* - * Restore scratch registers and return. - */ - ldmia sp!, {r4-r6} - mov pc, lr - - -/** - * @brief Load VFP context - * @param R0 = load area pointer: - * .long fpexc,fpscr,fpinst,fpinst2,cpacr,fpexc' - * .double d0..d15 - * .double d16..d31 - * @note VFP is assumed to be in an enabled state on entry. - */ - .align 4 - .global LoadVFP -LoadVFP: - /* - * Save registers. GCC does not expect us to preserve R0..R3,R12,LR. - */ - stmdb sp!, {r4-r6} - - /* - * Get status register contents: - * R1 = original FPEXC - * R2 = FPSCR - * R3 = FPINST - * R4 = FPINST2 - * R5 = original CPACR - * R6 = FPEXC readback with FPEXC.EX, .FP2V and .EN set - * telling us whether FPINST/2 are valid - */ - ldmia r0!, {r1-r6} - - /* - * Restore some initial FP status registers. - */ - fmxr fpexc, r6 @ with FPEXC.EX, .FP2V and .EN set - fmxr FPSCR, r2 @ always load FPSCR system register - - /* - * Follow procedure on AppxB-22 ARM DDI0406B to load FPINST[2]. - */ -#if !defined(MVP_HOST_CODE_forceon) - fmrx r6, fpexc @ initial call might have different bits - @ ... because FPEXC.EX, .FP2V and .EN - @ are forced set by init code in - @ mvpd.c SetupMonitor() - tst r6, #ARM_VFP_SYSTEM_REG_FPEXC_EX @ see if either one is valid - beq 1000f @ neither, skip it all - fmxr FPINST, r3 @ FPINST is valid, save it - tst r6, #ARM_VFP_SYSTEM_REG_FPEXC_FP2V @ see if FPINST2 is valid - beq 1000f - fmxr FPINST2, r4 @ FPINST2 is valid, save it -1000: -#endif - - /* - * Load floating point data registers. - */ - vldmia r0!, {d0-d15} - - /** - * @todo We should probably just read MVFR0 once at boot/initialization - * time and store it in some variable, to save having to do what might - * be expensive coprocessor accesses. - */ - fmrx r3, MVFR0 @ Read Media and VFP Feature Register 0 - and r3, r3, #ARM_VFP_SYSTEM_REG_MVFR0_A_SIMD_MASK @ A_SIMD field - cmp r3, #2 @ 32 x 64bit registers? - bne 2000f - vldmia r0!, {d16-d31} -2000: - - /* - * Now that VFP registers are all loaded, we put the restored values - * back in the registers, possibly disabling the VFP. - */ - fmxr fpexc, r1 @ with original FPEXC.EX, FPEXC.FP2V - @ and FPEXC.EN values - - /* - * Load Coproc Access Control CP10/CP11 enable bits, possibly disabling - * VFP access. - */ - mrc_p15 COPROC_ACCESS_CONTROL, r0 - bic r0, r0, #CPACR_CP10_CP11_MASK - and r5, r5, #CPACR_CP10_CP11_MASK - orr r0, r0, r5 - mcr_p15 COPROC_ACCESS_CONTROL, r0 - isb - - /* - * Restore scratch registers and return. - */ - ldmia sp!, {r4-r6} - mov pc, lr - - .align 4 - .global GetFPEXC -GetFPEXC: - fmrx r0, fpexc @ get existing FPEXC system register - mov pc, lr diff --git a/arch/arm/mvp/mvpkm/vmid.h b/arch/arm/mvp/mvpkm/vmid.h deleted file mode 100644 index dd89965..0000000 --- a/arch/arm/mvp/mvpkm/vmid.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -#ifndef _VMID_H -#define _VMID_H - -/** - * @file - * - * @brief The vmid definition - */ - - - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_HOSTUSER -#define INCLUDE_ALLOW_GUESTUSER -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define VMID_UNDEF (uint16)0xffff -typedef uint16 VmId; - -#endif diff --git a/arch/arm/mvp/mvpkm/worldswitch.h b/arch/arm/mvp/mvpkm/worldswitch.h deleted file mode 100644 index 785f2cd..0000000 --- a/arch/arm/mvp/mvpkm/worldswitch.h +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Definition of the world switch page - * - * Two pages are maintained to facilitate switching from the vmx to - * the monitor - a data and code page. The data page contains: - * - the necessary information about itself (its MPN, KVA, ...) - * - the saved register file of the other world (including some cp15 regs) - * - some information about the monitor's address space (the monVA member) - * that needed right after the w.s before any communication channels - * could have been established - * - a world switch related L2 table of the monitor -- this could be - * elsewhere. - * - * The code page contains: - * - the actual switching code that saves/restores the registers - * - * The world switch data page is mapped into the user, kernel, and the monitor - * address spaces. In case of the user and monitor spaces the global variable - * wsp points to the world switch page (in the vmx and the monitor - * respectively). The kernel address of the world switch page is saved on - * the page itself: wspHKVA. - * - * The kernel virtual address for both code and data pages is mapped into - * the monitor's space temporarily at the time of the actual switch. This is - * needed to provide a stable code and data page while the L1 page table - * base is changing. As the monitor does not need the world switch data page - * at its KVA for its internal operation, that map is severed right after the - * switching to the monitor and re-established before switching back. - */ -#ifndef _WORLDSWITCH_H -#define _WORLDSWITCH_H - -#define INCLUDE_ALLOW_MVPD -#define INCLUDE_ALLOW_VMX -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/** - * @brief Area for saving the monitor/kernel register files. - * - * The order of the registers in this structure was designed to - * facilitate the organization of the switching code. For example - * all Supervisor Mode registers are grouped together allowing the - * @code - * switch to svc, - * stm old svc regs - * ldm new svc regs - * @endcode - * code to work using a single base register for both the store and - * load area. - */ -#define MAX_REGISTER_SAVE_SIZE 464 - -#ifndef __ASSEMBLER__ -typedef struct { - uint32 kSPSR_svc; - uint32 kr13_svc; - uint32 kr14_svc; - uint32 mSPSR_svc; - uint32 mR13_svc; - uint32 mR14_svc; - - uint32 kSPSR_abt; - uint32 kr13_abt; - uint32 kr14_abt; - uint32 mSPSR_abt; - uint32 mR13_abt; - uint32 mR14_abt; - - uint32 kSPSR_und; - uint32 kr13_und; - uint32 kr14_und; - uint32 mSPSR_und; - uint32 mR13_und; - uint32 mR14_und; - - uint32 kSPSR_irq; - uint32 kr13_irq; - uint32 kr14_irq; - uint32 mSPSR_irq; - uint32 mR13_irq; - uint32 mR14_irq; - - uint32 kSPSR_fiq; - uint32 kr8_fiq; - uint32 kr9_fiq; - uint32 kr10_fiq; - uint32 kr11_fiq; - uint32 kr12_fiq; - uint32 kr13_fiq; - uint32 kr14_fiq; - uint32 mSPSR_fiq; - uint32 mR8_fiq; - uint32 mR9_fiq; - uint32 mR10_fiq; - uint32 mR11_fiq; - uint32 mR12_fiq; - uint32 mR13_fiq; - uint32 mR14_fiq; -} BankedRegisterSave; - -/** - * @brief Registers for monitor execution context. - */ -typedef struct { - uint32 mCPSR; - uint32 mR1; - uint32 mR4; - uint32 mR5; - uint32 mR6; - uint32 mR7; - uint32 mR8; - uint32 mR9; - uint32 mR10; - uint32 mR11; - uint32 mSP; - uint32 mLR; // =mPC -} MonitorRegisterSave; - -/** - * @brief LPV monitor register save/restore. - */ -typedef struct { - uint32 kR2; // =kCPSR - uint32 kR4; - uint32 kR5; - uint32 kR6; - uint32 kR7; - uint32 kR8; - uint32 kR9; - uint32 kR10; - uint32 kR11; - uint32 kR13; - uint32 kR14; // =kPC - - BankedRegisterSave bankedRegs; - - uint32 kCtrlReg; - uint32 kTTBR0; - uint32 kDACR; - uint32 kASID; - uint32 kTIDUserRW; - uint32 kTIDUserRO; - uint32 kTIDPrivRW; - uint32 kCSSELR; - uint32 kPMNCIntEn; - uint32 kPMNCCCCNT; - uint32 kPMNCOvFlag; - uint32 kOpEnabled; - uint32 mCtrlReg; - uint32 mTTBR0; - uint32 mASID; - uint32 mTIDUserRW; - uint32 mTIDUserRO; - uint32 mTIDPrivRW; - uint32 mCSSELR; - - MonitorRegisterSave monRegs; -} RegisterSaveLPV; - -/** - * @brief VE monitor register save/restore. - */ -typedef struct { - uint32 mHTTBR; - - uint32 kR3; - uint32 kR4; - uint32 kR5; - uint32 kR6; - uint32 kR7; - uint32 kR8; - uint32 kR9; - uint32 kR10; - uint32 kR11; - uint32 kR12; - uint32 kCPSR; - uint32 kRet; - - BankedRegisterSave bankedRegs; - - uint32 kCSSELR; - uint32 kCtrlReg; - uint32 kTTBR0[2]; - uint32 kTTBR1[2]; - uint32 kTTBRC; - uint32 kDACR; - uint32 kDFSR; - uint32 kIFSR; - uint32 kAuxDFSR; - uint32 kAuxIFSR; - uint32 kDFAR; - uint32 kIFAR; - uint32 kPAR[2]; - uint32 kPRRR; - uint32 kNMRR; - uint32 kASID; - uint32 kTIDUserRW; - uint32 kTIDUserRO; - uint32 kTIDPrivRW; - uint32 mCSSELR; - uint32 mCtrlReg; - uint32 mTTBR0[2]; - uint32 mTTBR1[2]; - uint32 mTTBRC; - uint32 mDACR; - uint32 mDFSR; - uint32 mIFSR; - uint32 mAuxDFSR; - uint32 mAuxIFSR; - uint32 mDFAR; - uint32 mIFAR; - uint32 mPAR[2]; - uint32 mPRRR; - uint32 mNMRR; - uint32 mASID; - uint32 mTIDUserRW; - uint32 mTIDUserRO; - uint32 mTIDPrivRW; - - uint32 mHCR; - uint32 mHDCR; - uint32 mHCPTR; - uint32 mHSTR; - uint32 mVTTBR[2]; - uint32 mVTCR; - - MonitorRegisterSave monRegs; -} RegisterSaveVE; - -typedef union { - unsigned char reserve_space[MAX_REGISTER_SAVE_SIZE]; - RegisterSaveLPV lpv; - RegisterSaveVE ve; -} RegisterSave; - -MY_ASSERTS(REGSAVE, - ASSERT_ON_COMPILE(sizeof(RegisterSave) == MAX_REGISTER_SAVE_SIZE); -) - -/** - * @brief Area for saving the monitor/kernel VFP state. - */ -typedef struct VFPSave { - uint32 fpexc, fpscr, fpinst, fpinst2, cpacr, fpexc_; - - uint64 fpregs[32]; // Hardware requires that this must be 8-byte (64-bit) - // aligned, however the SaveVFP/LoadVFP code does not - // align its pointer before accessing so we don't have - // an 'aligned(8)' attribute here. However, the - // alignment is checked via asserts in SetupMonitor() - // where it initializes the contents. - - // So if the preceding uint32's are changed and fpregs[] - // is no longer 8-byte aligned, the assert will fire. - // Then the uint32's will have to be fixed AND THE CODE - // in SaveVFP/LoadVFP will have to be CHANGED EQUALLY to - // compensate, as simply padding the uint32's (or - // sticking an aligned(8) attribute here) will leave the - // this structure mismatched with the code. - -} VFPSave __attribute__((aligned(8))); - // Keep the aligned(8) attribute here though so the - // VFPSave structures begin on an 8-byte boundary. - -typedef struct WorldSwitchPage WorldSwitchPage; -typedef void (SwitchToMonitor)(RegisterSave *regSave); -typedef void (SwitchToUser)(RegisterSave *regSaveEnd); - -#include "atomic.h" -#include "monva_common.h" -#include "mksck_shared.h" - -struct WorldSwitchPage { - uint32 mvpkmVersion; ///< The version number of mvpkm - - HKVA wspHKVA; ///< host kernel virtual address of this page - ARM_L1D wspKVAL1D; ///< The l1D entry at the above location - - SwitchToMonitor*switchToMonitor;///< entrypoint of the switching function - SwitchToUser *switchToUser; ///< ditto - - MonVA monVA; ///< monitor virtual address space description - union { - ARM_L2D monAttribL2D; ///< {S,TEX,CB} attributes for monitor mappings (LPV) - ARM_MemAttrNormal memAttr; ///< Normal memory attributes for monitor (VE) - }; - - MonitorType monType; ///< the type of the monitor. Used by mvpkm - _Bool allowInts; ///< true: monitor runs with ints enabled as much as possible (normal) - ///< false: monitor runs with ints blocked as much as possible (debug) - - struct { - uint64 switchedAt64; ///< approx time CP15 TSC was set to... - uint32 switchedAtTSC; ///< CP15 TSC value on entry from monitor - uint32 tscToRate64Mult; ///< multiplier to convert TSC_READ()s to our RATE64s - uint32 tscToRate64Shift; ///< shift to convert TSC_READ()s to our RATE64s - }; - - struct { - AtmUInt32 hostActions; ///< actions for monitor on instruction boundary - Mksck_VmId guestId; ///< vmId of the monitor page - }; - - struct { ///< Mksck attributes needed by Mksck_WspRelease() - uint32 critSecCount; ///< if >0 the monitor is in critical section - ///< and expects to regain control - _Bool isPageMapped[MKSCK_MAX_SHARES]; ///< host mksckPages known to the monitor - _Bool guestPageMapped;///< the guest Mksck page has been mapped in MVA space - uint32 isOpened; ///< bitfield indicating which mkscks - ///< are open on the guest's mksckPage. - /* Note that isOpened is per VM not per VCPU. Also note - * that this and other bitfields in the MksckPage structure - * limit the number of sockets to 32. - */ - }; - -#define WSP_PARAMS_SIZE 512 - uint8 params_[WSP_PARAMS_SIZE]; ///< opaque worldswitch call parameters - - RegisterSave regSave; ///< Save area for the worldswitch code below - VFPSave hostVFP; ///< Save areas for monitor/kernel VFP state - VFPSave monVFP; - -__attribute__((aligned(ARM_L2PT_COARSE_SIZE))) - ARM_L2D wspDoubleMap[ARM_L2PT_COARSE_ENTRIES]; ///< maps worldswitch page at its HKVA - uint8 secondHalfPadding[ARM_L2PT_COARSE_SIZE]; -}; - -/* - * These asserts duplicate the assert at the beginning of SetL1L2esc. - */ -MY_ASSERTS(WSP, - ASSERT_ON_COMPILE(offsetof(struct WorldSwitchPage, wspDoubleMap) % - ARM_L2PT_COARSE_SIZE == 0); -) - -extern void SaveVFP(VFPSave *); -extern void LoadVFP(VFPSave *); - -#define SWITCH_VFP_TO_MONITOR \ - do { \ - SaveVFP(&wsp->hostVFP); \ - LoadVFP(&wsp->monVFP); \ - } while(0) - -#define SWITCH_VFP_TO_HOST \ - do { \ - SaveVFP(&wsp->monVFP); \ - LoadVFP(&wsp->hostVFP); \ - } while(0) - -#endif /// __ASSEMBLER__ - -#define OFFSETOF_KR3_REGSAVE_VE_WSP 616 - -#endif /// _WORLDSWITCH_H diff --git a/arch/arm/mvp/mvpkm/wscalls.h b/arch/arm/mvp/mvpkm/wscalls.h deleted file mode 100644 index 4864f21..0000000 --- a/arch/arm/mvp/mvpkm/wscalls.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP Hypervisor Support - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Worldswitch call parameters - */ - -#ifndef _WSCALLS_H -#define _WSCALLS_H - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#define WSCALL_ACQUIRE_PAGE 1 -#define WSCALL_FLUSH_ALL_DCACHES 2 -#define WSCALL_IRQ 3 -#define WSCALL_ABORT 4 -#define WSCALL_LOG 5 -#define WSCALL_WAIT 6 -#define WSCALL_MUTEXLOCK 7 -#define WSCALL_MUTEXUNLOCK 8 -#define WSCALL_MUTEXUNLSLEEP 9 -#define WSCALL_MUTEXUNLWAKE 10 -#define WSCALL_GET_PAGE_FROM_VMID 11 -#define WSCALL_REMOVE_PAGE_FROM_VMID 12 -#define WSCALL_RELEASE_PAGE 13 -#define WSCALL_READTOD 14 -#define WSCALL_QP_GUEST_ATTACH 15 -#define WSCALL_MONITOR_TIMER 16 -#define WSCALL_COMM_SIGNAL 17 -#define WSCALL_QP_NOTIFY 18 -/* - * MVPKM V0.5.2.0 supports all the calls above. If new API calls are - * introduced then make sure that the calling function (probably in - * mkhost.c) checks the mvpkm's version stored in wsp->mvpkmVersion - * and invokes the wscall only when it is supported. - */ - -#define WSCALL_MAX_CALLNO 20 - -#define WSCALL_LOG_MAX 256 - -#define WSCALL_MAX_MPNS 16 - -#include "exitstatus.h" -#include "mutex.h" -#include "mksck_shared.h" -#include "qp.h" -#include "comm_transp.h" -#include "comm_transp_impl.h" - -typedef struct WSParams { - uint32 callno; - union { - /** - * @brief Used for both WSCALL_ACQUIRE_PAGE and WSCALL_RELEASE_PAGE. - */ - struct { - uint16 pages; ///< IN Number of pages - uint16 order; /**< IN Size of each page - - 2^(12+order) sized and aligned - in machine space. - (WSCALL_ACQUIRE_PAGE only) */ - PhysMem_RegionType forRegion; /**< IN Region identifier for pages - (WSCALL_ACQUIRE_PAGE only) */ - MPN mpns[WSCALL_MAX_MPNS]; /**< OUT (on WSCALL_ACQUIRE_PAGE) - IN (on WSCALL_RELEASE_PAGE) - Vector of page base MPNs. */ - } pages; - - union { - MPN mpn; ///< IN MPN to query refcount. - _Bool referenced; ///< OUT Do host page tables contain the MPN? - } refCount; - - struct { - ExitStatus status; ///< IN the final status of the monitor - } abort; - - struct { - int level; - char messg[WSCALL_LOG_MAX]; - } log; - - struct { - HKVA mtxHKVA; ///< IN mutex's host kernel virt addr - MutexMode mode; ///< IN shared or exclusive - uint32 cvi; ///< IN condition variable index - _Bool all; ///< IN wake all waiting threads? - _Bool ok; ///< OUT Mutex_Lock completed - } mutex; - - struct { - Mksck_VmId vmId; ///< IN translate and lock this vmID - _Bool found; /**< OUT true if the lookup was successful, - page is found, and refc incremented */ - MPN mpn[MKSCKPAGE_TOTAL]; ///< OUT array of MPNs of the requested vmId - } pageMgmnt; - - struct { - unsigned int now; ///< OUT current time-of-day seconds - unsigned int nowusec; ///< OUT current time-of-day microseconds - } tod; - - struct { - QPId id; ///< IN/OUT shared memory id - uint32 capacity; ///< IN size of shared region requested - uint32 type; ///< IN type of queue pair - uint32 base; ///< IN base MPN of PA vector page - uint32 nrPages; ///< IN number of pages to map - int32 rc; ///< OUT return code - } qp; - - struct { - CommTranspID transpID; - CommTranspIOEvent event; - } commEvent; - - struct { - uint64 when64; ///< IN timer request - } timer; - - struct { - _Bool suspendMode; ///< Is the guest in suspend mode? - } wait; - - }; ///< anonymous union -} WSParams; - - -/** - * @brief Cast the opaque param_ member of the wsp to WSParams type - * @param wsp_ the world switch page structure pointer - * @return the cast pointer - */ -static inline WSParams* UNUSED -WSP_Params(WorldSwitchPage *wsp_) { - return (WSParams*)(wsp_->params_); -} - -MY_ASSERTS(WSParFn, - ASSERT_ON_COMPILE(sizeof(WSParams) <= WSP_PARAMS_SIZE); -) -#endif diff --git a/arch/arm/mvp/pvtcpkm/COPYING b/arch/arm/mvp/pvtcpkm/COPYING deleted file mode 100644 index 10828e0..0000000 --- a/arch/arm/mvp/pvtcpkm/COPYING +++ /dev/null @@ -1,341 +0,0 @@ - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/arch/arm/mvp/pvtcpkm/Kbuild b/arch/arm/mvp/pvtcpkm/Kbuild deleted file mode 100644 index d2ec844..0000000 --- a/arch/arm/mvp/pvtcpkm/Kbuild +++ /dev/null @@ -1,9 +0,0 @@ -# Warning: autogenerated -obj-m := pvtcpkm.o -pvtcpkm-objs := check_kconfig.o pvtcp_off_io_linux.o pvtcp_off_linux.o comm_os_linux.o comm_os_mod_linux.o pvtcp.o pvtcp_off.o pvtcp_off_linux_shim.o - -ccflags-y += -fno-pic -fno-dwarf2-cfi-asm -march=armv7-a -D__linux__ -ccflags-y += -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -DPVTCP_BUILDING_SERVER -ccflags-y += -mfpu=neon -DIN_MODULE -DGPLED_CODE -ccflags-y += --std=gnu89 -O2 -g2 -ggdb -mapcs -fno-optimize-sibling-calls -mno-sched-prolog -ccflags-$(CONFIG_VMWARE_MVP_DEBUG) += -DMVP_DEBUG diff --git a/arch/arm/mvp/pvtcpkm/Makefile b/arch/arm/mvp/pvtcpkm/Makefile deleted file mode 100644 index 16eb389..0000000 --- a/arch/arm/mvp/pvtcpkm/Makefile +++ /dev/null @@ -1 +0,0 @@ -# Warning: autogenerated diff --git a/arch/arm/mvp/pvtcpkm/check_kconfig.c b/arch/arm/mvp/pvtcpkm/check_kconfig.c deleted file mode 100644 index 6fc27a1..0000000 --- a/arch/arm/mvp/pvtcpkm/check_kconfig.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * @brief Check for required kernel configuration - * - * Check to make sure that the kernel options that the MVP hypervisor requires - * have been enabled in the kernel that this kernel module is being built - * against. - */ -#include <linux/version.h> - -/* - * Minimum kernel version - * - network namespace support is only really functional starting in 2.6.29 - * - Android Gingerbread requires 2.6.35 - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) -#error "MVP requires a host kernel newer than 2.6.35" -#endif - -/* module loading ability */ -#ifndef CONFIG_MODULES -#error "MVP requires kernel loadable module support be enabled (CONFIG_MODULES)" -#endif -#ifndef CONFIG_MODULE_UNLOAD -#error "MVP requires kernel module unload support be enabled (CONFIG_MODULE_UNLOAD)" -#endif - -/* sysfs */ -#ifndef CONFIG_SYSFS -#error "MVP requires sysfs support (CONFIG_SYSFS)" -#endif - -/* network traffic isolation */ -#ifndef CONFIG_NAMESPACES -#error "MVP networking support requires namespace support (CONFIG_NAMESPACES)" -#endif -#ifndef CONFIG_NET_NS -#error "MVP networking support requires Network Namespace support to be enabled (CONFIG_NET_NS)" -#endif - -/* TCP/IP networking */ -#ifndef CONFIG_INET -#error "MVP networking requires IPv4 support (CONFIG_INET)" -#endif -#ifndef CONFIG_IPV6 -#error "MVP networking requires IPv6 support (CONFIG_IPV6)" -#endif - -/* VPN support */ -#if !defined(CONFIG_TUN) && !defined(CONFIG_TUN_MODULE) -#error "MVP VPN support requires TUN device support (CONFIG_TUN)" -#endif - -#if !defined(CONFIG_NETFILTER) && !defined(PVTCP_DISABLE_NETFILTER) -#error "MVP networking support requires netfilter support (CONFIG_NETFILTER)" -#endif - -/* Force /proc/config.gz support for eng/userdebug builds */ -#ifdef MVP_DEBUG -#if !defined(CONFIG_IKCONFIG) || !defined(CONFIG_IKCONFIG_PROC) -#error "MVP kernel /proc/config.gz support required for debuggability (CONFIG_IKCONFIG_PROC)" -#endif -#endif - -/* Sanity check we're only dealing with the memory hotplug + migrate and/or - * compaction combo */ -#ifdef CONFIG_MIGRATION -#if defined(CONFIG_NUMA) || defined(CONFIG_CPUSETS) || defined(CONFIG_MEMORY_FAILURE) -#error "MVP not tested with migration features other than CONFIG_MEMORY_HOTPLUG and CONFIG_COMPACTION" -#endif -#endif diff --git a/arch/arm/mvp/pvtcpkm/comm.h b/arch/arm/mvp/pvtcpkm/comm.h deleted file mode 100644 index 877731d..0000000 --- a/arch/arm/mvp/pvtcpkm/comm.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Communication functions based on queue pair transport APIs. - * - * Comm is a shared memory-based mechanism that facilitates the implementation - * of kernel components that require host-to-guest, or guest-to-guest - * communication. - * This facility assumes the availability of a minimal shared memory queue pair - * implementation, such as MVP queue pairs or VMCI queue pairs. The latter must - * provide primitives for queue pair creation and destruction, and reading and - * writing from/to queue pairs. - * Comm assumes that the queue pair (transport) layer is not concerned with - * multi-threading, locking or flow control, and does not require such features. - */ - -#ifndef _COMM_H_ -#define _COMM_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "comm_os.h" -#include "comm_transp.h" - - -/* Default/maximum Comm timeouts (in milliseconds). */ -#define COMM_MAX_TO 60000ULL -#define COMM_MAX_TO_UNINT (COMM_MAX_TO + 1) - -#define COMM_OPF_SET_ERR(flags) ((flags) |= 128) -#define COMM_OPF_CLEAR_ERR(flags) ((flags) &= 127) -#define COMM_OPF_TEST_ERR(flags) ((flags) & 128) - -#define COMM_OPF_SET_VAL(flags, val) ((flags) |= ((val) & 127)) -#define COMM_OPF_GET_VAL(flags) ((flags) & 127) - -/** - * Packet (header) structure. - * NB: Do not change this structure, especially the first three fields; there - * will be consequences. It may be extended, but it's not recommended: all - * operations carry this header, so it's better kept in its minimal form. - */ - -typedef struct CommPacket { - unsigned int len; // Total length - unsigned char flags; // Operation flags - unsigned char opCode; // Operation to call - unsigned short data16; // Auxiliary data - unsigned long long data64; - unsigned long long data64ex; - union { - struct { - unsigned int data32; - unsigned int data32ex; - }; - unsigned long long data64ex2; - }; -} CommPacket; - - -/* Opaque structure representing a communication channel. */ - -struct CommChannelPriv; -typedef struct CommChannelPriv *CommChannel; - - -/* Input operations associated with a comm channel. */ - -typedef void (*CommOperationFunc)(CommChannel channel, - void *state, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen); - - -/* Helper macros */ - -#define COMM_DEFINE_OP(funcName) \ -void \ -funcName(CommChannel channel, \ - void *state, \ - CommPacket *packet, \ - struct kvec *vec, \ - unsigned int vecLen) - - -/* Comm-based implementations. */ - -typedef struct CommImpl { - struct module *owner; - int (*checkArgs)(CommTranspInitArgs *transpArgs); - void *(*stateCtor)(CommChannel channel); - void (*stateDtor)(void *state); - void *(*dataAlloc)(unsigned int dataLen); - void (*dataFree)(void *data); - const CommOperationFunc *operations; - void (*closeNtf)(void *closeNtfData, - const CommTranspInitArgs *transpArgs, - int inBH); - void *closeNtfData; - void (*activateNtf)(void *activateNtfData, - CommChannel channel); - void *activateNtfData; - unsigned long long openAtMillis; - unsigned long long openTimeoutAtMillis; - CommTranspID ntfCenterID; -} CommImpl; - - -int Comm_Init(unsigned int maxChannels); -int Comm_Finish(unsigned long long *timeoutMillis); -int Comm_RegisterImpl(const CommImpl *impl); -void Comm_UnregisterImpl(const CommImpl *impl); -int Comm_IsActive(CommChannel channel); -CommTranspInitArgs Comm_GetTranspInitArgs(CommChannel channel); -void *Comm_GetState(CommChannel channel); -int Comm_Dispatch(CommChannel channel); -unsigned int Comm_DispatchAll(void); -void Comm_Put(CommChannel channel); -void Comm_DispatchUnlock(CommChannel channel); -int Comm_Lock(CommChannel channel); -void Comm_Unlock(CommChannel channel); -int Comm_Zombify(CommChannel channel, int inBH); - -int -Comm_Alloc(const CommTranspInitArgs *transpArgs, - const CommImpl *impl, - int inBH, - CommChannel *newChannel); - - -int -Comm_Write(CommChannel channel, - const CommPacket *packet, - unsigned long long *timeoutMillis); - -int -Comm_WriteVec(CommChannel channel, - const CommPacket *packet, - struct kvec **vec, - unsigned int *vecLen, - unsigned long long *timeoutMillis, - unsigned int *iovOffset); - -unsigned int Comm_RequestInlineEvents(CommChannel channel); -unsigned int Comm_ReleaseInlineEvents(CommChannel channel); - -#endif // _COMM_H_ diff --git a/arch/arm/mvp/pvtcpkm/comm_os.h b/arch/arm/mvp/pvtcpkm/comm_os.h deleted file mode 100644 index 91305f1..0000000 --- a/arch/arm/mvp/pvtcpkm/comm_os.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Cross-platform base type definitions and function declarations. - * Includes OS-specific base type definitions and function declarations. - */ - -#ifndef _COMM_OS_H_ -#define _COMM_OS_H_ - -/* For-ever timeout constant (in milliseconds). */ -#define COMM_OS_4EVER_TO ((unsigned long long)(~0UL >> 1)) - -/* Condition function prototype. Returns 1: true, 0: false, < 0: error code. */ -typedef int (*CommOSWaitConditionFunc)(void *arg1, void *arg2); - -/* Dispatch function prototype. Called by input (dispatch) kernel threads. */ -typedef unsigned int (*CommOSDispatchFunc)(void); - -/* Module initialization and exit callback functions. */ -extern int (*commOSModInit)(void *args); -extern void (*commOSModExit)(void); - -/* Macro to assign Init and Exit callbacks. */ -#define COMM_OS_MOD_INIT(init, exit) \ - int (*commOSModInit)(void *args) = init; \ - void (*commOSModExit)(void) = exit - - -/* - * OS-specific implementations must provide the following: - * 1. Types: - * CommOSAtomic - * CommOSSpinlock - * CommOSMutex - * CommOSWaitQueue - * CommOSWork - * CommOSWorkFunc - * CommOSList - * CommOSModule - * struct kvec - * - * 2. Definition, initializers: - * CommOSSpinlock_Define() - * - * 3. Functions: - * void CommOS_Debug(const char *format, ...); - * void CommOS_Log(const char *format, ...); - * void CommOS_WriteAtomic(CommOSAtomic *atomic, int val); - * int CommOS_ReadAtomic(CommOSAtomic *atomic); - * int CommOS_AddReturnAtomic(CommOSAtomic *atomic, int val); - * int CommOS_SubReturnAtomic(CommOSAtomic *atomic, int val); - * void CommOS_SpinlockInit(CommOSSpinlock *lock); - * void CommOS_SpinLockBH(CommOSSpinlock *lock); - * int CommOS_SpinTrylockBH(CommOSSpinlock *lock); - * void CommOS_SpinUnlockBH(CommOSSpinlock *lock); - * void CommOS_SpinLock(CommOSSpinlock *lock); - * int CommOS_SpinTrylock(CommOSSpinlock *lock); - * void CommOS_SpinUnlock(CommOSSpinlock *lock); - * void CommOS_MutexInit(CommOSMutex *mutex); - * void CommOS_MutexLock(CommOSMutex *mutex); - * int CommOS_MutexLockUninterruptible(CommOSMutex *mutex); - * int CommOS_MutexTrylock(CommOSMutex *mutex); - * void CommOS_MutexUnlock(CommOSMutex *mutex); - * void CommOS_WaitQueueInit(CommOSWaitQueue *wq); - * CommOS_DoWait(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc cond, - * void *condArg1, - * void *condArg2, - * unsigned long long *timeoutMillis, - * int interruptible); - * int CommOS_Wait(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc func, - * void *funcArg1, - * void *funcArg2, - * unsigned long long *timeoutMillis); - * int CommOS_WaitUninterruptible(CommOSWaitQueue *wq, - * CommOSWaitConditionFunc func, - * void *funcArg1, - * void *funcArg2, - * unsigned long long *timeoutMillis); - * void CommOS_WakeUp(CommOSWaitQueue *wq); - * void *CommOS_KmallocNoSleep(unsigned int size); - * void *CommOS_Kmalloc(unsigned int size); - * void CommOS_Kfree(void *arg); - * void CommOS_Yield(void); - * unsigned long long CommOS_GetCurrentMillis(void); - * void CommOS_ListInit(CommOSList *list); - * int CommOS_ListEmpty(CommOSList *list); - * void CommOS_ListAdd(CommOSList *list, CommOSList *listElem); - * void CommOS_ListAddTail(CommOSList *list, CommOSList *listElem); - * void int CommOS_ListDel(CommOSList *listElem); - * Macros: - * CommOS_ListForEach(*list, *item, itemListFieldName); - * CommOS_ListForEachSafe(*list, *item, *tmp, itemListFieldName); - * void CommOS_ListSplice(CommOSList *list, CommOSList *listToAdd); - * void CommOS_ListSpliceTail(CommOSList *list, CommOSList *listToAdd); - * CommOSModule CommOS_ModuleSelf(void); - * int CommOS_ModuleGet(CommOSModule module); - * void CommOS_ModulePut(CommOSModule module); - * void CommOS_MemBarrier(void); - * - * These cannot be defined here: a) non-pointer type definitions need size - * information, and b) functions may or may not be inlined, or macros may - * be used instead. - */ - - -#ifdef __linux__ -#include "comm_os_linux.h" -#else -#error "Unsupported OS" -#endif - -/* Functions to start and stop the dispatch and aio kernel threads. */ -void CommOS_StopIO(void); -void CommOS_ScheduleDisp(void); -void CommOS_InitWork(CommOSWork *work, CommOSWorkFunc func); -int CommOS_ScheduleAIOWork(CommOSWork *work); -void CommOS_FlushAIOWork(CommOSWork *work); - -int -CommOS_StartIO(const char *dispatchTaskName, - CommOSDispatchFunc dispatchHandler, - unsigned int interval, - unsigned int maxCycles, - const char *aioTaskName); - - -#endif /* _COMM_OS_H_ */ diff --git a/arch/arm/mvp/pvtcpkm/comm_os_linux.c b/arch/arm/mvp/pvtcpkm/comm_os_linux.c deleted file mode 100644 index 61ce929..0000000 --- a/arch/arm/mvp/pvtcpkm/comm_os_linux.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Linux-specific functions/types. - */ - -#include "comm_os.h" - -#define DISPATCH_MAX_CYCLES 8192 - -/* Type definitions */ - -typedef struct workqueue_struct CommOSWorkQueue; - - -/* Static data */ - -static volatile int running; -static int numCpus; -static CommOSWorkQueue *dispatchWQ; -static CommOSDispatchFunc dispatch; -static CommOSWork dispatchWorksNow[NR_CPUS]; -static CommOSWork dispatchWorks[NR_CPUS]; -static unsigned int dispatchInterval = 1; -static unsigned int dispatchMaxCycles = 2048; -static CommOSWorkQueue *aioWQ; - - -/** - * @brief Initializes a workqueue consisting of per-cpu kernel threads. - * @param name workqueue name - * @return workqueue handle if successful, NULL otherwise - */ - -static inline CommOSWorkQueue * -CreateWorkqueue(const char *name) -{ - return create_workqueue(name); -} - - -/** - * @brief Destroys a workqueue and stops its threads. - * @param[in,out] wq workqueue to destroy. - * @return workqueue handle is successful, NULL otherwise. - */ - -static inline void -DestroyWorkqueue(CommOSWorkQueue *wq) -{ - destroy_workqueue(wq); -} - - -/** - * @brief Force execution of a work item. - * @param[in,out] work work item to dequeue. - */ - -static inline void -FlushDelayedWork(CommOSWork *work) -{ - flush_delayed_work(work); -} - - -/** - * @brief Enqueue a work item to a workqueue for execution on a given cpu - * and after the specified interval. - * @param cpu cpu number. If negative, work item is enqueued on current cpu. - * @param[in,out] wq target work queue. - * @param[in,out] work work item to enqueue. - * @param jif delay interval. - * @return zero if successful, non-zero otherwise. - */ - -static inline int -QueueDelayedWorkOn(int cpu, - CommOSWorkQueue *wq, - CommOSWork *work, - unsigned long jif) -{ - if (cpu < 0) { - return !queue_delayed_work(wq, work, jif) ? -1 : 0; - } else { - return !queue_delayed_work_on(cpu, wq, work, jif) ? -1 : 0; - } -} - - -/** - * @brief Enqueues a work item to a workqueue for execution on the current cpu - * and after the specified interval. - * @param[in,out] wq target work queue. - * @param[in,out] work work item to enqueue. - * @param jif delay interval. - * @return zero if successful, non-zero otherwise. - */ - -static inline int -QueueDelayedWork(CommOSWorkQueue *wq, - CommOSWork *work, - unsigned long jif) -{ - return QueueDelayedWorkOn(-1, wq, work, jif); -} - - -/** - * @brief Cancels a queued delayed work item and synchronizes with its - * completion. - * @param[in,out] work work item to cancel - */ - -static inline void -WaitForDelayedWork(CommOSWork *work) -{ - cancel_delayed_work_sync(work); -} - - -/** - * @brief Discards work items queued to the specified workqueue. - * @param[in,out] wq work queue to flush. - */ - -static inline void -FlushWorkqueue(CommOSWorkQueue *wq) -{ - flush_workqueue(wq); -} - - -/** - * @brief Schedules dispatcher threads for immediate execution. - */ - -void -CommOS_ScheduleDisp(void) -{ - CommOSWork *work = &dispatchWorksNow[get_cpu()]; - - put_cpu(); - if (running) { - QueueDelayedWork(dispatchWQ, work, 0); - } -} - - -/** - * @brief Default delayed work callback function implementation. - * Calls the input function specified at initialization. - * @param[in,out] work work item. - */ - -static void -DispatchWrapper(CommOSWork *work) -{ - unsigned int misses; - - for (misses = 0; running && (misses < dispatchMaxCycles); ) { - /* We run for at most dispatchMaxCycles worth of channel no-ops. */ - - if (!dispatch()) { - /* No useful work was done, on any of the channels. */ - - misses++; - if ((misses % 32) == 0) { - CommOS_Yield(); - } - } else { - misses = 0; - } - } - - if (running && - (work >= &dispatchWorks[0]) && - (work <= &dispatchWorks[NR_CPUS - 1])) { - /* - * If still running _and_ this was a regular, time-based run, then - * re-arm the timer. - */ - - QueueDelayedWork(dispatchWQ, work, dispatchInterval); - } -} - - -/** - * @brief Initializes work item with specified callback function. - * @param[in,out] work work queue to initialize. - * @param func work item to initialize the queue with. - */ - -void -CommOS_InitWork(CommOSWork *work, - CommOSWorkFunc func) -{ - INIT_DELAYED_WORK(work, (work_func_t)func); -} - - -/** - * @brief Flush execution of a work item - * @param{in,out] work work item to dequeue - */ -void -CommOS_FlushAIOWork(CommOSWork *work) -{ - if (aioWQ && work) { - FlushDelayedWork(work); - } -} - - -/** - * @brief Queue a work item to the AIO workqueue. - * @param[in,out] work work item to enqueue. - * @return zero if work enqueued, non-zero otherwise. - */ - -int -CommOS_ScheduleAIOWork(CommOSWork *work) -{ - if (running && aioWQ && work) { - return QueueDelayedWork(aioWQ, work, 0); - } - return -1; -} - - -/** - * @brief Initializes the base IO system. - * @param dispatchTaskName dispatch thread(s) name. - * @param dispatchFunc dispatch function. - * @param intervalMillis periodic interval in milliseconds to call dispatch. - * The floor is 1 jiffy, regardless of how small intervalMillis is - * @param maxCycles number of cycles to do adaptive polling before scheduling. - * The maximum number of cycles is DISPATCH_MAX_CYCLES. - * @param aioTaskName AIO thread(s) name. If NULL, AIO threads aren't started. - * @return zero is successful, -1 otherwise. - * @sideeffects Dispatch threads, and if applicable, AIO threads are started. - */ - -int -CommOS_StartIO(const char *dispatchTaskName, // IN - CommOSDispatchFunc dispatchFunc, // IN - unsigned int intervalMillis, // IN - unsigned int maxCycles, // IN - const char *aioTaskName) // IN -{ - int rc; - int cpu; - - if (running) { - CommOS_Debug(("%s: I/O tasks already running.\n", __FUNCTION__)); - return 0; - } - - /* - * OK, let's test the handler against NULL. Though, the whole concept - * of checking for NULL pointers, outside cases where NULL is meaningful - * to the implementation, is relatively useless: garbage, random pointers - * rarely happen to be all-zeros. - */ - - if (!dispatchFunc) { - CommOS_Log(("%s: a NULL Dispatch handler was passed.\n", __FUNCTION__)); - return -1; - } - dispatch = dispatchFunc; - - if (intervalMillis == 0) { - intervalMillis = 4; - } - if ((dispatchInterval = msecs_to_jiffies(intervalMillis)) < 1) { - dispatchInterval = 1; - } - if (maxCycles > DISPATCH_MAX_CYCLES) { - dispatchMaxCycles = DISPATCH_MAX_CYCLES; - } else if (maxCycles > 0) { - dispatchMaxCycles = maxCycles; - } - CommOS_Debug(("%s: Interval millis %u (jif:%u).\n", __FUNCTION__, - intervalMillis, dispatchInterval)); - CommOS_Debug(("%s: Max cycles %u.\n", __FUNCTION__, dispatchMaxCycles)); - - numCpus = num_present_cpus(); - dispatchWQ = CreateWorkqueue(dispatchTaskName); - if (!dispatchWQ) { - CommOS_Log(("%s: Couldn't create %s task(s).\n", __FUNCTION__, - dispatchTaskName)); - return -1; - } - - if (aioTaskName) { - aioWQ = CreateWorkqueue(aioTaskName); - if (!aioWQ) { - CommOS_Log(("%s: Couldn't create %s task(s).\n", __FUNCTION__, - aioTaskName)); - DestroyWorkqueue(dispatchWQ); - return -1; - } - } else { - aioWQ = NULL; - } - - running = 1; - for (cpu = 0; cpu < numCpus; cpu++) { - CommOS_InitWork(&dispatchWorksNow[cpu], DispatchWrapper); - CommOS_InitWork(&dispatchWorks[cpu], DispatchWrapper); - rc = QueueDelayedWorkOn(cpu, dispatchWQ, - &dispatchWorks[cpu], - dispatchInterval); - if (rc != 0) { - CommOS_StopIO(); - return -1; - } - } - CommOS_Log(("%s: Created I/O task(s) successfully.\n", __FUNCTION__)); - return 0; -} - - -/** - * @brief Stops the base IO system. - * @sideeffects Dispatch threads, and if applicable, AIO threads are stopped. - */ - -void -CommOS_StopIO(void) -{ - int cpu; - - if (running) { - running = 0; - if (aioWQ) { - FlushWorkqueue(aioWQ); - DestroyWorkqueue(aioWQ); - aioWQ = NULL; - } - FlushWorkqueue(dispatchWQ); - for (cpu = 0; cpu < numCpus; cpu++) { - WaitForDelayedWork(&dispatchWorksNow[cpu]); - WaitForDelayedWork(&dispatchWorks[cpu]); - } - DestroyWorkqueue(dispatchWQ); - dispatchWQ = NULL; - CommOS_Log(("%s: I/O tasks stopped.\n", __FUNCTION__)); - } -} diff --git a/arch/arm/mvp/pvtcpkm/comm_os_linux.h b/arch/arm/mvp/pvtcpkm/comm_os_linux.h deleted file mode 100644 index 81ee9d1..0000000 --- a/arch/arm/mvp/pvtcpkm/comm_os_linux.h +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Contains linux-specific type definitions and function declarations - */ - -#ifndef _COMM_OS_LINUX_H_ -#define _COMM_OS_LINUX_H_ - -#include <linux/types.h> -#include <linux/version.h> - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -#error "Kernel versions lower than 2.6.20 are not supported" -#endif - -#include <linux/kernel.h> -#include <linux/workqueue.h> -#include <linux/sched.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/slab.h> - - -/* - * Type definitions. - */ - -typedef atomic_t CommOSAtomic; -typedef spinlock_t CommOSSpinlock; -typedef struct mutex CommOSMutex; -typedef wait_queue_head_t CommOSWaitQueue; -typedef struct delayed_work CommOSWork; -typedef void (*CommOSWorkFunc)(CommOSWork *work); -typedef struct list_head CommOSList; -typedef struct module *CommOSModule; - - -/* - * Initializers. - */ - -#define CommOSSpinlock_Define DEFINE_SPINLOCK - - -#define COMM_OS_DOLOG(...) printk(KERN_INFO __VA_ARGS__) - - -/** - * @brief Logs given arguments in debug builds. - */ - -#if defined(COMM_OS_DEBUG) - #define CommOS_Debug(args) COMM_OS_DOLOG args -#else - #define CommOS_Debug(args) -#endif - - -/** - * @brief Logs given arguments. - */ - -#define CommOS_Log(args) COMM_OS_DOLOG args - - -/** - * @brief Logs function name and location. - */ - -#if defined(COMM_OS_TRACE) -#define TRACE(ptr) \ - do { \ - CommOS_Debug(("%p:%s: at [%s:%d] with arg ptr [0x%p].\n", current, \ - __FUNCTION__, __FILE__, __LINE__, (ptr))); \ - } while (0) -#else -#define TRACE(ptr) -#endif - - -/** - * @brief Write atomic variable - * @param[in,out] atomic variable to write - * @param val new value - */ - -static inline void -CommOS_WriteAtomic(CommOSAtomic *atomic, - int val) -{ - atomic_set(atomic, val); -} - - -/** - * @brief Reads atomic variable - * @param atomic variable to read - * @return value - */ - -static inline int -CommOS_ReadAtomic(CommOSAtomic *atomic) -{ - return atomic_read(atomic); -} - - -/** - * @brief Atomically add value to atomic variable, return new value. - * @param[in,out] atomic variable - * @param val value to add - * @return new value - */ - -static inline int -CommOS_AddReturnAtomic(CommOSAtomic *atomic, - int val) -{ - return atomic_add_return(val, atomic); -} - - -/** - * @brief Atomically substract value from atomic variable, return new value. - * @param[in,out] atomic variable - * @param val value to substract - * @return new value - */ - -static inline int -CommOS_SubReturnAtomic(CommOSAtomic *atomic, - int val) -{ - return atomic_sub_return(val, atomic); -} - - -/** - * @brief Initializes a given lock. - * @param[in,out] lock lock to initialize - */ - -static inline void -CommOS_SpinlockInit(CommOSSpinlock *lock) -{ - spin_lock_init(lock); -} - - -/** - * @brief Locks given lock and disables bottom half processing. - * @param[in,out] lock lock to lock - */ - -static inline void -CommOS_SpinLockBH(CommOSSpinlock *lock) -{ - spin_lock_bh(lock); -} - - -/** - * @brief Attempts to lock the given lock and disable BH processing. - * @param[in,out] lock lock to lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_SpinTrylockBH(CommOSSpinlock *lock) -{ - return !spin_trylock_bh(lock); -} - - -/** - * @brief Unlocks given lock and re-enables BH processing. - * @param[in,out] lock lock to unlock - */ - -static inline void -CommOS_SpinUnlockBH(CommOSSpinlock *lock) -{ - spin_unlock_bh(lock); -} - - -/** - * @brief Locks the given lock. - * @param[in,out] lock lock to lock - */ - -static inline void -CommOS_SpinLock(CommOSSpinlock *lock) -{ - spin_lock(lock); -} - - -/** - * @brief Attempts to lock the given lock. - * @param[in,out] lock lock to try-lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_SpinTrylock(CommOSSpinlock *lock) -{ - return !spin_trylock(lock); -} - - -/** - * @brief Unlocks given lock. - * @param[in,out] lock lock to unlock - */ - -static inline void -CommOS_SpinUnlock(CommOSSpinlock *lock) -{ - spin_unlock(lock); -} - - -/** - * @brief Initializes given mutex. - * @param[in,out] mutex mutex to initialize - */ - -static inline void -CommOS_MutexInit(CommOSMutex *mutex) -{ - mutex_init(mutex); -} - - -/** - * @brief Acquires mutex. - * @param[in,out] mutex mutex to lock - * @return zero if successful, non-zero otherwise (interrupted) - */ - -static inline int -CommOS_MutexLock(CommOSMutex *mutex) -{ - return mutex_lock_interruptible(mutex); -} - - -/** - * @brief Acquires mutex in uninterruptible mode. - * @param[in,out] mutex mutex to lock - */ - -static inline void -CommOS_MutexLockUninterruptible(CommOSMutex *mutex) -{ - mutex_lock(mutex); -} - - -/** - * @brief Attempts to acquire given mutex. - * @param[in,out] mutex mutex to try-lock - * @return zero if successful, non-zero otherwise - */ - -static inline int -CommOS_MutexTrylock(CommOSMutex *mutex) -{ - return !mutex_trylock(mutex); -} - - -/** - * @brief Releases a given mutex. - * @param[in,out] mutex mutex to unlock - */ - -static inline void -CommOS_MutexUnlock(CommOSMutex *mutex) -{ - mutex_unlock(mutex); -} - - -/** - * @brief Initializes a wait queue. - * @param[in,out] wq workqueue to initialize - */ - -static inline void -CommOS_WaitQueueInit(CommOSWaitQueue *wq) -{ - init_waitqueue_head(wq); -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * - a signal is pending - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @param interruptible enable/disable signal pending check - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, if a signal is pending or other error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_DoWait(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis, - int interruptible) -{ - int rc; - DEFINE_WAIT(wait); - long timeout; -#if defined(COMM_OS_LINUX_WAIT_WORKAROUND) - long tmpTimeout; - long retTimeout; - const unsigned int interval = 50; -#endif - - if (!timeoutMillis) { - return -1; - } - if ((rc = cond(condArg1, condArg2)) != 0) { - return rc; - } - -#if defined(COMM_OS_LINUX_WAIT_WORKAROUND) - timeout = msecs_to_jiffies(interval < *timeoutMillis ? - interval : (unsigned int)*timeoutMillis); - retTimeout = msecs_to_jiffies((unsigned int)(*timeoutMillis)); - - for (; retTimeout >= 0; ) { - prepare_to_wait(wq, &wait, - (interruptible?TASK_INTERRUPTIBLE:TASK_UNINTERRUPTIBLE)); - if ((rc = cond(condArg1, condArg2))) { - break; - } - if (interruptible && signal_pending(current)) { - rc = -EINTR; - break; - } - if ((tmpTimeout = schedule_timeout(timeout))) { - retTimeout -= (timeout - tmpTimeout); - } else { - retTimeout -= timeout; - } - if (retTimeout < 0) { - retTimeout = 0; - } - } - finish_wait(wq, &wait); - if (rc == 0) { - rc = cond(condArg1, condArg2); - if (rc && (retTimeout == 0)) { - retTimeout = 1; - } - } - *timeoutMillis = (unsigned long long)jiffies_to_msecs(retTimeout); -#else // !defined(COMM_OS_LINUX_WAIT_WORKAROUND) - timeout = msecs_to_jiffies((unsigned int)(*timeoutMillis)); - - for (;;) { - prepare_to_wait(wq, &wait, - (interruptible?TASK_INTERRUPTIBLE:TASK_UNINTERRUPTIBLE)); - if ((rc = cond(condArg1, condArg2)) != 0) { - break; - } - if (interruptible && signal_pending(current)) { - rc = -EINTR; - break; - } - if ((timeout = schedule_timeout(timeout)) == 0) { - rc = 0; - break; - } - } - finish_wait(wq, &wait); - if (rc == 0) { - rc = cond(condArg1, condArg2); - if (rc && (timeout == 0)) { - timeout = 1; - } - } - *timeoutMillis = (unsigned long long)jiffies_to_msecs(timeout); -#endif - - return rc; -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * - a signal is pending - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, if a signal is pending or other error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_Wait(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis) -{ - return CommOS_DoWait(wq, cond, condArg1, condArg2, timeoutMillis, 1); -} - - -/** - * @brief Puts the caller on a wait queue until either of the following occurs: - * - the condition function (predicate) evaluates to TRUE - * - the specified timeout interval elapsed - * @param[in,out] wq wait queue to put item on - * @param cond predicate to test - * @param condArg1 argument 1 for cond - * @param condArg2 argument 2 for cond - * @param[in,out] timeoutMillis timeout interval in milliseconds - * @return 1 if condition was met - * 0 if the timeout interval elapsed - * <0, error set by condition - * @sideeffect timeoutMillis is updated to time remaining - */ - -static inline int -CommOS_WaitUninterruptible(CommOSWaitQueue *wq, - CommOSWaitConditionFunc cond, - void *condArg1, - void *condArg2, - unsigned long long *timeoutMillis) -{ - return CommOS_DoWait(wq, cond, condArg1, condArg2, timeoutMillis, 0); -} - - -/** - * @brief Wakes up task(s) waiting on the given wait queue. - * @param[in,out] wq wait queue. - */ - -static inline void -CommOS_WakeUp(CommOSWaitQueue *wq) -{ - wake_up(wq); -} - - -/** - * @brief Allocates kernel memory of specified size; does not sleep. - * @param size size to allocate. - * @return Address of allocated memory or NULL if the allocation fails. - */ - -static inline void * -CommOS_KmallocNoSleep(unsigned int size) -{ - return kmalloc(size, GFP_ATOMIC); -} - - -/** - * @brief Allocates kernel memory of specified size; may sleep. - * @param size size to allocate. - * @return Address of allocated memory or NULL if the allocation fails. - */ - -static inline void * -CommOS_Kmalloc(unsigned int size) -{ - return kmalloc(size, GFP_KERNEL); -} - - -/** - * @brief Frees previously allocated kernel memory. - * @param obj object to free. - */ - -static inline void -CommOS_Kfree(void *obj) -{ - if (obj) { - kfree(obj); - } -} - - -/** - * @brief Yields the current cpu to other runnable tasks. - */ - -static inline void -CommOS_Yield(void) -{ - cond_resched(); -} - - -/** - * @brief Gets the current time in milliseconds. - * @return Current time in milliseconds, with precision of at most one tick. - */ - -static inline unsigned long long -CommOS_GetCurrentMillis(void) -{ - return (unsigned long long)jiffies_to_msecs(jiffies); -} - - -/** - * @brief Initializes given list. - * @param list list to initialize. - */ - -static inline void -CommOS_ListInit(CommOSList *list) -{ - INIT_LIST_HEAD(list); -} - - -/** - * @brief Tests if list is empty. - * @param list list to test. - * @return non-zero if empty, zero otherwise. - */ - -#define CommOS_ListEmpty(list) list_empty((list)) - - -/** - * @brief Adds given element to beginning of list. - * @param list list to add to. - * @param elem element to add. - */ - -#define CommOS_ListAdd(list, elem) list_add((elem), (list)) - - -/** - * @brief Adds given element to end of list. - * @param list list to add to. - * @param elem element to add. - */ - -#define CommOS_ListAddTail(list, elem) list_add_tail((elem), (list)) - - -/** - * @brief Deletes given element from its list. - * @param elem element to delete. - */ - -#define CommOS_ListDel(elem) \ - do { \ - list_del((elem)); \ - INIT_LIST_HEAD((elem)); \ - } while (0) - - -/** - * @brief Iterates over a list. - * @param list list to iterate over. - * @param[out] item stores next element. - * @param itemListFieldName name in the item structure storing the list head. - */ - -#define CommOS_ListForEach(list, item, itemListFieldName) \ - list_for_each_entry((item), (list), itemListFieldName) - - -/** - * @brief Iterates safely over a list. - * @param list list to iterate over. - * @param[out] item stores next element. May be deleted in the loop. - * @param[out] tmpItem saves iteration element. - * @param itemListFieldName name in the item structure storing the list head. - */ - -#define CommOS_ListForEachSafe(list, item, tmpItem, itemListFieldName) \ - list_for_each_entry_safe((item), (tmpItem), (list), itemListFieldName) - - -/** - * @brief Combines two lists, adds second list to beginning of first one. - * @param list list to add to. - * @param list2 list to add. - */ - -#define CommOS_ListSplice(list, list2) list_splice((list2), (list)) - - -/** - * @brief Combines two lists, adds second list to end of first one. - * @param list list to add to. - * @param list2 list to add. - */ - -#define CommOS_ListSpliceTail(list, list2) list_splice_tail((list2), (list)) - - -/** - * @brief Gets current module handle. - * @return module handle. - */ - -static inline CommOSModule -CommOS_ModuleSelf(void) -{ - return THIS_MODULE; -} - - -/** - * @brief Retains module. - * @param[in,out] module to retain. - * @return zero if successful, non-zero otherwise. - */ - -static inline int -CommOS_ModuleGet(CommOSModule module) -{ - int rc = 0; - - if (!module) { - goto out; - } - if (!try_module_get(module)) { - rc = -1; - } - -out: - return rc; -} - - -/** - * @brief Releases module. - * @param[in,out] module to release. - */ - -static inline void -CommOS_ModulePut(CommOSModule module) -{ - if (module) { - module_put(module); - } -} - - -/** - * @brief Inserts r/w memory barrier. - */ - -#define CommOS_MemBarrier smp_mb - -#endif /* _COMM_OS_LINUX_H_ */ diff --git a/arch/arm/mvp/pvtcpkm/comm_os_mod_linux.c b/arch/arm/mvp/pvtcpkm/comm_os_mod_linux.c deleted file mode 100644 index e196108..0000000 --- a/arch/arm/mvp/pvtcpkm/comm_os_mod_linux.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Linux-specific module loading, unloading functions. - */ - -#include "comm_os.h" -#include "comm_os_mod_ver.h" - -#include <linux/moduleparam.h> - - -/* Module parameters -- passed as one 'name=value'-list string. */ - -static char modParams[256]; -module_param_string(COMM_OS_MOD_SHORT_NAME, modParams, sizeof modParams, 0644); - - -/** - * @brief Module initialization entry point. Calls the commOSModInit - * function pointer to perform upper layer initialization. - * @return zero if successful, non-zero otherwise. - */ - -static int __init -ModInit(void) -{ - int rc; - - if (!commOSModInit) { - CommOS_Log(("%s: Can't find \'init\' function for module \'" \ - COMM_OS_MOD_SHORT_NAME_STRING "\'.\n", __FUNCTION__)); - return -1; - } - - CommOS_Debug(("%s: Module parameters: [%s].\n", __FUNCTION__, modParams)); - - rc = (*commOSModInit)(modParams); - if (rc == 0) { - CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \ - "\' has been successfully initialized.\n", __FUNCTION__)); - } else { - CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \ - "\' could not be initialized [%d].\n", __FUNCTION__, rc)); - } - - return rc > 0 ? -rc : rc; -} - - -/** - * @brief Module exit function. Calls the commOSModExit function pointer - * to perform upper layer cleanup. - */ - -static void __exit -ModExit(void) -{ - if (!commOSModExit) { - CommOS_Log(("%s: Can't find \'fini\' function for module \'" \ - COMM_OS_MOD_SHORT_NAME_STRING "\'.\n", __FUNCTION__)); - return; - } - - (*commOSModExit)(); - CommOS_Log(("%s: Module \'" COMM_OS_MOD_SHORT_NAME_STRING \ - "\' has been stopped.\n", __FUNCTION__)); -} - - -module_init(ModInit); -module_exit(ModExit); - -/* Module information. */ -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION(COMM_OS_MOD_NAME_STRING); -MODULE_VERSION(COMM_OS_MOD_VERSION_STRING); -MODULE_LICENSE("GPL v2"); -/* - * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement - * with them and mark their kernel modules as externally supported via a - * change to the module header. If this isn't done, the module will not load - * by default (i.e., neither mkinitrd nor modprobe will accept it). - */ -MODULE_INFO(supported, "external"); diff --git a/arch/arm/mvp/pvtcpkm/comm_os_mod_ver.h b/arch/arm/mvp/pvtcpkm/comm_os_mod_ver.h deleted file mode 100644 index 5e14c62..0000000 --- a/arch/arm/mvp/pvtcpkm/comm_os_mod_ver.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Version definitions for the pvTCP module. - */ - -#ifndef _COMM_OS_MOD_VER_H_ -#define _COMM_OS_MOD_VER_H_ - -#define COMM_OS_MOD_NAME_STRING "VMware paravirtualized tcp/ip module" -#define COMM_OS_MOD_SHORT_NAME pvtcp -#define COMM_OS_MOD_SHORT_NAME_STRING "pvtcp" - -#define COMM_OS_MOD_VERSION 1.0.0.0 -#define COMM_OS_MOD_VERSION_COMMAS 1,0,0,0 -#define COMM_OS_MOD_VERSION_STRING "1.0.0.0" - -#endif /* _COM_OS_MOD_VER_H_ */ diff --git a/arch/arm/mvp/pvtcpkm/comm_svc.h b/arch/arm/mvp/pvtcpkm/comm_svc.h deleted file mode 100644 index 784ec76..0000000 --- a/arch/arm/mvp/pvtcpkm/comm_svc.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Communication functions exported by the comm_rt module. - */ - -#ifndef _COMM_SVC_H_ -#define _COMM_SVC_H_ - -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -#include "comm.h" - -int CommSvc_RegisterImpl(const CommImpl *impl); -void CommSvc_UnregisterImpl(const CommImpl *impl); -int CommSvc_Zombify(CommChannel channel, int inBH); -int CommSvc_IsActive(CommChannel channel); -CommTranspInitArgs CommSvc_GetTranspInitArgs(CommChannel channel); -void *CommSvc_GetState(CommChannel channel); -void CommSvc_Put(CommChannel channel); -void CommSvc_DispatchUnlock(CommChannel channel); -int CommSvc_Lock(CommChannel channel); -void CommSvc_Unlock(CommChannel channel); -int CommSvc_ScheduleAIOWork(CommOSWork *work); - -int -CommSvc_Alloc(const CommTranspInitArgs *transpArgs, - const CommImpl *impl, - int inBH, - CommChannel *newChannel); - -int -CommSvc_Write(CommChannel channel, - const CommPacket *packet, - unsigned long long *timeoutMillis); - -int -CommSvc_WriteVec(CommChannel channel, - const CommPacket *packet, - struct kvec **vec, - unsigned int *vecLen, - unsigned long long *timeoutMillis, - unsigned int *iovOffset); - -unsigned int CommSvc_RequestInlineEvents(CommChannel channel); -unsigned int CommSvc_ReleaseInlineEvents(CommChannel channel); - -#endif // _COMM_SVC_H_ diff --git a/arch/arm/mvp/pvtcpkm/comm_transp.h b/arch/arm/mvp/pvtcpkm/comm_transp.h deleted file mode 100644 index c46f849..0000000 --- a/arch/arm/mvp/pvtcpkm/comm_transp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Generic shared memory transport API. - */ - -#ifndef _COMM_TRANSP_H_ -#define _COMM_TRANSP_H_ - -#define INCLUDE_ALLOW_PV -#define INCLUDE_ALLOW_MODULE -#define INCLUDE_ALLOW_MONITOR -#define INCLUDE_ALLOW_GPL -#include "include_check.h" - -/* - * Common shared memory identifier. - * External handle that makes sense to both hypervisor and guest. - */ - -#define COMM_TRANSP_ID_8_ANY ((unsigned char)-1) -#define COMM_TRANSP_ID_32_ANY ((unsigned int)-1) -#define COMM_TRANSP_ID_64_ANY ((unsigned long long)-1) - - -typedef struct CommTranspID { - union { - unsigned char d8[8]; - unsigned int d32[2]; - unsigned long long d64; - }; -} CommTranspID; - - -/* Basic initialization arguments. */ - -typedef enum CommTranspInitMode { - COMM_TRANSP_INIT_CREATE = 0x0, - COMM_TRANSP_INIT_ATTACH = 0x1 -} CommTranspInitMode; - -typedef struct CommTranspInitArgs { - unsigned int capacity; // Shared memory capacity. - unsigned int type; // Type / implementation using this area. - CommTranspID id; // ID (name) of shared memory area. - CommTranspInitMode mode; // Init mode (above). -} CommTranspInitArgs; - - -/** - * @brief Generate a type id from description (protocol) string. This function - * uses djb2, a string hashing algorithm by Dan Bernstein. - * (see http://www.cse.yorku.ca/~oz/hash.html) - * @param str string to hash - * @return 32-bit hash value - */ - -static inline unsigned int -CommTransp_GetType(const char *str) -{ - unsigned int hash = 5381; - int c; - - while ((c = *str++)) { - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - } - return hash; -} - -#endif // _COMM_TRANSP_H_ diff --git a/arch/arm/mvp/pvtcpkm/include_check.h b/arch/arm/mvp/pvtcpkm/include_check.h deleted file mode 100644 index 2eeafe7..0000000 --- a/arch/arm/mvp/pvtcpkm/include_check.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for Empty File Placeholder - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ diff --git a/arch/arm/mvp/pvtcpkm/pvtcp.c b/arch/arm/mvp/pvtcpkm/pvtcp.c deleted file mode 100644 index fdfb0d2..0000000 --- a/arch/arm/mvp/pvtcpkm/pvtcp.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Pvtcp common code. - */ - -#include "pvtcp.h" - - -/* - * Operation table. - */ - -CommOperationFunc pvtcpOperations[] = { - [PVTCP_OP_FLOW] = PvtcpFlowOp, - [PVTCP_OP_IO] = PvtcpIoOp, - [PVTCP_OP_CREATE] = PvtcpCreateOp, - [PVTCP_OP_RELEASE] = PvtcpReleaseOp, - [PVTCP_OP_BIND] = PvtcpBindOp, - [PVTCP_OP_LISTEN] = PvtcpListenOp, - [PVTCP_OP_ACCEPT] = PvtcpAcceptOp, - [PVTCP_OP_CONNECT] = PvtcpConnectOp, - [PVTCP_OP_SHUTDOWN] = PvtcpShutdownOp, - [PVTCP_OP_SETSOCKOPT] = PvtcpSetSockOptOp, - [PVTCP_OP_GETSOCKOPT] = PvtcpGetSockOptOp, - [PVTCP_OP_IOCTL] = PvtcpIoctlOp, - [PVTCP_OP_INVALID] = NULL -}; - - -/* - * Implementation block. - */ - -CommImpl pvtcpImpl = { - .owner = NULL, - .checkArgs = PvtcpCheckArgs, - .stateCtor = PvtcpStateAlloc, - .stateDtor = PvtcpStateFree, - .dataAlloc = PvtcpBufAlloc, - .dataFree = PvtcpBufFree, - .operations = pvtcpOperations, - .closeNtf = PvtcpCloseNtf, - .closeNtfData = &pvtcpImpl, - .ntfCenterID = {{ - .d32[0] = 2U /* x86 host context (vmci, only). */, - .d32[1] = 10000 /* Default, not yet reserved, resource (vmci, only). */ - }} -}; - - -/* - * Version array. - */ - -const char *pvtcpVersions[] = { - [PVTCP_VERS_1_1] = PVTCP_COMM_IMPL_VERS_1_1, - [PVTCP_VERS_1_0] = PVTCP_COMM_IMPL_VERS_1_0 -}; - -const unsigned int pvtcpVersionsSize = - (sizeof pvtcpVersions / sizeof pvtcpVersions[0]); - - -/* - * Client (pv) channel to offload side. We choose to define it here, although - * it's only applicable to the pv implementation. The reason is that we can - * share a common close notification function which does the right thing - * depending on the channel configuration. - */ - -CommChannel pvtcpClientChannel; - - -/* - * Built-in state interfaces. - */ - -static PvtcpIfConf ifUnbound = { - .family = PVTCP_PF_UNBOUND -}; -const PvtcpIfConf *pvtcpIfUnbound = &ifUnbound; - -static PvtcpIfConf ifDeathRow = { - .family = PVTCP_PF_DEATH_ROW -}; -const PvtcpIfConf *pvtcpIfDeathRow = &ifDeathRow; - -static PvtcpIfConf ifLoopbackInet4 = { - .family = PVTCP_PF_LOOPBACK_INET4 -}; -const PvtcpIfConf *pvtcpIfLoopbackInet4 = &ifLoopbackInet4; - - -/* Functions */ - -/** - * @brief Checks if the IF configuration has reasonable values. - * @param conf configuration to check - * @return zero if successful, -1 otherwise - */ - -static int -IfCheck(const PvtcpIfConf *conf) -{ - if (!conf || - ((conf->family != PF_INET) && - (conf->family != PF_INET6) && - (conf->family != PVTCP_PF_UNBOUND) && - (conf->family != PVTCP_PF_DEATH_ROW) && - (conf->family != PVTCP_PF_LOOPBACK_INET4))) { - return -1; - } - - /** @todo Need more checks for IP/netmask format validity. */ - return 0; -} - - -/** - * @brief Checks if the IF has reasonable values, but restricts types to - * AF_INET and AF_INET6 - * @param conf IF to check - * @return zero if successful, -1 otherwise - */ - -static int -IfRestrictedCheck(const PvtcpIfConf *conf) -{ - if (IfCheck(conf) || - ((conf->family != PF_INET) && - (conf->family != PF_INET6))) { - return -1; - } - return 0; -} - - -/** - * @brief Finds a netif given a state and a configuration. The configuration - * must have already been checked. This function doesn't lock, so it - * should not be called when the state, or the netif for the passed - * configuration may be deleted. - * @param state state to look for. - * @param conf configuration to look for. - * @return netif matching configuration, or NULL. - */ - -PvtcpIf * -PvtcpStateFindIf(PvtcpState *state, - const PvtcpIfConf *conf) -{ - PvtcpIf *netif; - - if (!state) { - return NULL; - } - - if (conf->family == PVTCP_PF_UNBOUND) { - return &state->ifUnbound; - } - - if (conf->family == PVTCP_PF_DEATH_ROW) { - return &state->ifDeathRow; - } - - if (conf->family == PVTCP_PF_LOOPBACK_INET4) { - return &state->ifLoopbackInet4; - } - - CommOS_ListForEach(&state->ifList, netif, stateLink) { - if (netif->conf.family == conf->family) { - if ((conf->family == PF_INET && - !memcmp(&netif->conf.addr.in, &conf->addr.in, - sizeof conf->addr.in)) || - (conf->family == PF_INET6 && - !memcmp(&netif->conf.addr.in6, &conf->addr.in6, - sizeof conf->addr.in6))) { - return netif; - } - } - } - return NULL; -} - - -/** - * @brief Creates and initializes a new netif for a given channel and with - * the specified configuration. Death row and unbound netifs may not - * be added using this function. - * @param[in,out] channel channel to make a new netif in - * @param conf configuration to set netif to - * @return 0 if successful, -1 otherwise - * @sideeffect May allocate memory - */ - -int -PvtcpStateAddIf(CommChannel channel, - const PvtcpIfConf *conf) -{ - int rc = -1; - PvtcpState *state; - PvtcpIf *netif; - - if (!channel || IfRestrictedCheck(conf)) { - return rc; - } - - if (CommSvc_Lock(channel)) { - return rc; /* channel isn't active. */ - } - - state = CommSvc_GetState(channel); - if (!state) { - goto out; - } - - if (PvtcpStateFindIf(state, conf)) { - goto out; /* Already configured. */ - } - - netif = CommOS_Kmalloc(sizeof *netif); - if (!netif) { - goto out; - } - - INIT_LIST_HEAD(&netif->stateLink); - INIT_LIST_HEAD(&netif->sockList); - netif->state = state; - netif->conf = *conf; - CommOS_ListAddTail(&state->ifList, &netif->stateLink); - rc = 0; - -out: - CommSvc_Unlock(channel); - return rc; -} - - -/** - * @brief Removes and potentially deallocates all sockets associated with the - * given netif and deallocates the latter. - * @param[in,out] netif netif to deallocate - * @sideeffect Closes sockets, deallocates memory - */ - -static void -IfFree(PvtcpIf *netif) -{ - PvtcpSock *pvsk; - PvtcpSock *tmp; - - if (netif) { - CommOS_ListForEachSafe(&netif->sockList, pvsk, tmp, ifLink) { - CommOS_ListDel(&pvsk->ifLink); - PvtcpReleaseSocket(pvsk); - } - if ((netif->conf.family != PVTCP_PF_UNBOUND) && - (netif->conf.family != PVTCP_PF_DEATH_ROW) && - (netif->conf.family != PVTCP_PF_LOOPBACK_INET4)) { - CommOS_ListDel(&netif->stateLink); - CommOS_Kfree(netif); - } - } -} - - -/** - * @brief Closes all sockets associated with, and deallocates the netif - * in the given channel and with the specified configuration. - * Death row and unbound netifs may not be removed using this function. - * @param[in,out] channel channel to remove from - * @param conf configuration specified - * @return zero if successful, error code otherwise - * @sideeffect Closes sockets, deallocates memory - */ - -void -PvtcpStateRemoveIf(CommChannel channel, - const PvtcpIfConf *conf) -{ - PvtcpState *state; - PvtcpIf *netif; - - if (!channel || IfRestrictedCheck(conf)) { - return; - } - - if (CommSvc_Lock(channel)) { - return; /* channel isn't active. */ - } - - state = CommSvc_GetState(channel); - if (state && (netif = PvtcpStateFindIf(state, conf))) { - if (netif->state == state) { - IfFree(netif); - } - } - - CommSvc_Unlock(channel); -} - - -/** - * @brief Adds a socket to an existing netif. If the socket is already on a - * different netif, it is removed from that netif. - * It locks the must-be-active channel. We use that lock to guard - * against concurrent removal of the netif. - * @param[in,out] channel channel to add to - * @param conf specified configuration - * @param[in,out] sock socket to add - * @return zero if successful, -1 otherwise - */ - -int -PvtcpStateAddSocket(CommChannel channel, - const PvtcpIfConf *conf, - PvtcpSock *sock) -{ - int rc = -1; - PvtcpState *state; - PvtcpIf *netif; - - if (!channel || !sock || (sock->channel != channel) || IfCheck(conf)) { - return rc; - } - - if (CommSvc_Lock(channel)) { - return rc; /* channel isn't active. */ - } - - state = CommSvc_GetState(channel); - if (!state) { - goto out; - } - - netif = PvtcpStateFindIf(state, conf); - if (!netif) { - goto out; - } - - CommOS_ListDel(&sock->ifLink); - sock->netif = netif; - CommOS_ListAddTail(&netif->sockList, &sock->ifLink); - rc = 0; - -out: - CommSvc_Unlock(channel); - return rc; -} - - -/** - * @brief Removes a socket from its netif. - * It locks the must-be-active channel. We use that lock to guard - * against concurrent removal of the netif. - * @param[in,out] channel channel to remove from - * @param[in,out] sock socket to remove - * @return zero if successful, -1 otherwise - */ - -int -PvtcpStateRemoveSocket(CommChannel channel, - PvtcpSock *sock) -{ - if (!channel || !sock || - (sock->channel && (sock->channel != channel))) { - return -1; - } - - if (CommSvc_Lock(channel)) { - return -1; /* channel isn't active. */ - } - - CommOS_ListDel(&sock->ifLink); - sock->channel = NULL; - sock->state = NULL; - sock->netif = NULL; - - CommSvc_Unlock(channel); - return 0; -} - - -/** - * @brief State constructor called when a channel is created. The netifs - * 'death row' and 'unbound' are always initialized. - * @param[in,out] channel channel to initialize - * @return pointer to a new state structure or NULL - * @sideeffect Allocates memory - */ - -void * -PvtcpStateAlloc(CommChannel channel) -{ - PvtcpState *state; - - state = CommOS_Kmalloc(sizeof *state); - if (state) { - state->channel = channel; - INIT_LIST_HEAD(&state->ifList); - - /* Initialize always-present netifs. */ - INIT_LIST_HEAD(&state->ifDeathRow.stateLink); /* Irrelevant */ - INIT_LIST_HEAD(&state->ifDeathRow.sockList); - state->ifDeathRow.state = state; - state->ifDeathRow.conf.family = PVTCP_PF_DEATH_ROW; - - INIT_LIST_HEAD(&state->ifUnbound.stateLink); /* Irrelevant */ - INIT_LIST_HEAD(&state->ifUnbound.sockList); - state->ifUnbound.state = state; - state->ifUnbound.conf.family = PVTCP_PF_UNBOUND; - - INIT_LIST_HEAD(&state->ifLoopbackInet4.stateLink); /* Irrelevant */ - INIT_LIST_HEAD(&state->ifLoopbackInet4.sockList); - state->ifLoopbackInet4.state = state; - state->ifLoopbackInet4.conf.family = PVTCP_PF_LOOPBACK_INET4; - - state->namespace = NULL; - state->mask = ((unsigned int)channel << 4) ^ (unsigned int)state; -#if defined(__linux__) - state->id = ((unsigned long long)random32() << 32) | - (unsigned long long)random32(); -#else - state->id = (unsigned long long)state; -#endif - } - return state; -} - - -/** - * @brief State destructor called when a channel is closed. - * The caller (Comm) guarantees proper locking. - * @param arg pointer to state structure - * @sideeffect Destroys all netifs and their sockets, deallocates memory - */ - -void -PvtcpStateFree(void *arg) -{ - PvtcpState *state = arg; - PvtcpIf *netif; - PvtcpIf *tmp; - - if (state) { - CommOS_ListForEachSafe(&state->ifList, netif, tmp, stateLink) { - IfFree(netif); - } - /* coverity[address_free] */ - IfFree(&state->ifLoopbackInet4); - /* coverity[address_free] */ - IfFree(&state->ifUnbound); - /* coverity[address_free] */ - IfFree(&state->ifDeathRow); - CommOS_Kfree(state); - } -} - - -/** - * @brief Checks transport arguments. - * @param transpArgs transport arguments. - * @return zero if successful, < 0 otherwise. - */ - -int -PvtcpCheckArgs(CommTranspInitArgs *transpArgs) -{ - int rc = -1; - const unsigned int minCapacity = - (PVTCP_SOCK_BUF_SIZE + sizeof(CommPacket)) * 2; - unsigned int versionIndex = pvtcpVersionsSize; - - if (transpArgs->capacity < minCapacity) { - return rc; - } - - while (versionIndex--) { - if (transpArgs->type == CommTransp_GetType(pvtcpVersions[versionIndex])) { - /* If a match, overwrite the hash with the actual version (index). */ - - transpArgs->type = versionIndex; - rc = 0; - break; - } - } - - return rc; -} - - -/** - * @brief Called after a channel is freed. - * @param ntfData callback data from implementation block. - * @param transpArgs transport arguments of closed channel. - * @param inBH whether called in bottom half. - */ - -void -PvtcpCloseNtf(void *ntfData, - const CommTranspInitArgs *transpArgs, - int inBH) -{ - CommImpl *impl = (CommImpl *)ntfData; - - pvtcpClientChannel = NULL; - CommOS_Log(("%s: Channel was reset!\n", __FUNCTION__)); - - /* - * If the impl. block owner is NULL, we're pv client: we attempt to - * reopen the channel in a few seconds. - */ - - if (impl && !impl->owner && !inBH) { - CommOS_Log(("%s: Attempting to re-initialize channel.\n", __FUNCTION__)); - impl->openAtMillis = CommOS_GetCurrentMillis(); - impl->openTimeoutAtMillis = - CommOS_GetCurrentMillis() + PVTCP_CHANNEL_OPEN_TIMEOUT; - if (CommSvc_Alloc(transpArgs, impl, inBH, &pvtcpClientChannel)) { - CommOS_Log(("%s: Failed to initialize channel!\n", __FUNCTION__)); - } - } -} - - -/** - * @brief Initializes the Pvtcp socket common fields. - * @param pvsk pvtcp socket. - * @param channel Comm channel this socket is associated with. - * @return 0 if successful, -1 otherwise. - */ - -int -PvtcpSockInit(PvtcpSock *pvsk, - CommChannel channel) -{ - PvtcpState *state; - int rc = -1; - - if (pvsk && channel && (state = CommSvc_GetState(channel))) { - /* Must _not_ zero out pvsk! */ - - CommOS_MutexInit(&pvsk->inLock); - CommOS_MutexInit(&pvsk->outLock); - CommOS_SpinlockInit(&pvsk->stateLock); - CommOS_ListInit(&pvsk->ifLink); - CommOS_InitWork(&pvsk->work, PvtcpProcessAIO); - pvsk->netif = NULL; - pvsk->state = state; - pvsk->stateID = state->id; - pvsk->channel = channel; - pvsk->peerSock = PVTCP_PEER_SOCK_NULL; - pvsk->peerSockSet = 0; - CommOS_WriteAtomic(&pvsk->deltaAckSize, - (1 << PVTCP_SOCK_SMALL_ACK_ORDER)); - CommOS_WriteAtomic(&pvsk->rcvdSize, 0); - CommOS_WriteAtomic(&pvsk->sentSize, 0); - CommOS_WriteAtomic(&pvsk->queueSize, 0); - CommOS_ListInit(&pvsk->queue); - pvsk->rpcReply = NULL; - pvsk->rpcStatus = 0; - pvsk->err = 0; - rc = 0; - } - return rc; -} diff --git a/arch/arm/mvp/pvtcpkm/pvtcp.h b/arch/arm/mvp/pvtcpkm/pvtcp.h deleted file mode 100644 index 7f4f2f5..0000000 --- a/arch/arm/mvp/pvtcpkm/pvtcp.h +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Pvtcp common APIs. - */ - -#ifndef _PVTCP_H_ -#define _PVTCP_H_ - -/* - * Pvtcp state store ipv4 and ipv6 address structures. - * Platform-specific headers where these are defined, must be included here. - * Implementation-related header files should not be included in this file. - * - * NOTE: Pvtcp is not an API and none of its functions are exported. - */ - -#if defined(__linux__) -#include <linux/in.h> -#include <linux/in6.h> -#else -#error "Unsupported OS." -#endif - -#include "comm_svc.h" - -/* Max time to wait for a channel to be created. */ -#define PVTCP_CHANNEL_OPEN_TIMEOUT 2000 - -/* Max payload size. Used to allocate offload per-cpu bounce buffers. */ -#define PVTCP_SOCK_BUF_SIZE (8 << 10) /* 8K */ - -#define PVTCP_SOCK_DGRAM_BUF_SIZE PVTCP_SOCK_BUF_SIZE -#define PVTCP_SOCK_STREAM_BUF_SIZE PVTCP_SOCK_BUF_SIZE - -/* Dgram payloads include a pseudo (udp/ip) header. */ -typedef struct PvtcpDgramPseudoHeader { - unsigned long long d0; - unsigned long long d1; - unsigned long long d2; - unsigned long long d3; -} PvtcpDgramPseudoHeader; - - -/* - * Flow control constants for pv/offload sockets. - * We are defining a receive size model: 1) small, 2) medium, 3)large. - * This seems sufficient in addressing most target environments, but more - * models may be defined. A smaller minimum model (1) cannot be defined. - * - * Short description of socket-level flow control. This applies to both - * dgram and stream sockets, in both directions. It follows that, with regard - * to 'comm' writes, dgram and stream writes are: a) lossless and b) ordered. - * - * 0. Both sides (offload, pv) of a socket maintain (almost) mirror values - * of input/output queue sizes. We say 'almost', because they're allowed - * to conservatively converge in time. - * 1. Senders never write out to the shmem channel, and destined to a socket - * (be it offload or pv), more bytes than that socket can hold/enqueue. - * This is based on socket fields storing information mentioned above. - * The upper limit is PVTCP_SOCK_RCVSIZE and cannot be exceeded under - * any circumstances. - * 2. There is a 'safe' limit value (per socket) which can be tested prior - * to writing one more max-sized packet to that socket. - * This value is PVTCP_SOCK_SAFE_RCVSIZE. - * 3. There is also a notion of 'large' acks, which controls the frequency of - * reporting socket queue size changes when bytes are consumed from it. - * When a sender is about to write out (to the channel, for a given socket) - * in excess of PVTCP_SOCK_LARGE_ACK_WM bytes, it sets, in the packet - * header flag field, the PVTCP_SOCK_LARGE_ACK_ORDER value. The other end - * updates its 'delta ack' value accordingly (1 << flag value). - * 4. As bytes are consumed (again, at either end), the operation or function, - * will send a size ack packet with the consumed size since the last ack, - * _iff_ that size is larger than, or equal to the 'delta ack' value. - * If an ack was sent, the 'delta ack' is decreased by half, to a minimum - * indicated by PVTCP_SOCK_SMALL_ACK_ORDER. - * Note that concurrently setting the 'delta ack' to its high value - * because of condition 3) above, is fine since the sender already has, - * or is about to put pressure on the socket. - */ - -#if !defined(PVTCP_SOCK_RCVSIZE_MODEL) - #define PVTCP_SOCK_RCVSIZE_MODEL 1 -#endif - -#if PVTCP_SOCK_RCVSIZE_MODEL == 1 - #define PVTCP_SOCK_LARGE_ACK_WM (64 << 10) /* 64K */ - #define PVTCP_SOCK_LARGE_ACK_ORDER 15 - #define PVTCP_SOCK_SMALL_ACK_ORDER 11 - #define PVTCP_SOCK_SAFE_RCVSIZE (128 << 10) /* 128K */ -#elif PVTCP_SOCK_RCVSIZE_MODEL == 2 - #define PVTCP_SOCK_LARGE_ACK_WM (128 << 10) /* 128K */ - #define PVTCP_SOCK_LARGE_ACK_ORDER 16 - #define PVTCP_SOCK_SMALL_ACK_ORDER 12 - #define PVTCP_SOCK_SAFE_RCVSIZE (256 << 10) /* 256K */ -#elif PVTCP_SOCK_RCVSIZE_MODEL == 3 - #define PVTCP_SOCK_LARGE_ACK_WM (128 << 10) /* 128K */ - #define PVTCP_SOCK_LARGE_ACK_ORDER 16 - #define PVTCP_SOCK_SMALL_ACK_ORDER 12 - #define PVTCP_SOCK_SAFE_RCVSIZE (512 << 10) /* 512K */ -#else - #error "Invalid PVTCP_SOCK_RCVSIZE_MODEL (one of 1, 2, 3)" -#endif - -#define PVTCP_SOCK_RCVSIZE \ - (PVTCP_SOCK_SAFE_RCVSIZE + \ - PVTCP_SOCK_BUF_SIZE + sizeof (PvtcpDgramPseudoHeader)) - - -/* - * Operation codes - */ - -enum PvtcpOpCodes { - PVTCP_OP_FLOW = 0, - PVTCP_OP_IO, - PVTCP_OP_CREATE, - PVTCP_OP_RELEASE, - PVTCP_OP_BIND, - PVTCP_OP_LISTEN, - PVTCP_OP_ACCEPT, - PVTCP_OP_CONNECT, - PVTCP_OP_SHUTDOWN, - PVTCP_OP_SETSOCKOPT, - PVTCP_OP_GETSOCKOPT, - PVTCP_OP_IOCTL, - PVTCP_OP_INVALID -}; - -#define PVTCP_FLOW_OP_INVALID_SIZE 0xffffffff - - -/* - * Operation functions - */ - -COMM_DEFINE_OP(PvtcpFlowOp); -COMM_DEFINE_OP(PvtcpIoOp); -COMM_DEFINE_OP(PvtcpCreateOp); -COMM_DEFINE_OP(PvtcpReleaseOp); -COMM_DEFINE_OP(PvtcpBindOp); -COMM_DEFINE_OP(PvtcpListenOp); -COMM_DEFINE_OP(PvtcpAcceptOp); -COMM_DEFINE_OP(PvtcpConnectOp); -COMM_DEFINE_OP(PvtcpShutdownOp); -COMM_DEFINE_OP(PvtcpSetSockOptOp); -COMM_DEFINE_OP(PvtcpGetSockOptOp); -COMM_DEFINE_OP(PvtcpIoctlOp); - - -/* - * Pvtcp/Comm type and supported versions. - */ - -#define PVTCP_COMM_IMPL_TYPE "com.vmware.comm.protocol.pvTCP@" - -#define PVTCP_COMM_IMPL_VERS_1_0 (PVTCP_COMM_IMPL_TYPE "1.0") -#define PVTCP_COMM_IMPL_VERS_1_1 (PVTCP_COMM_IMPL_TYPE "1.1") - -typedef enum { - PVTCP_VERS_1_0 = 0, - PVTCP_VERS_1_1 -} PvtcpVersion; - -extern const char *pvtcpVersions[]; -extern const unsigned int pvtcpVersionsSize; - - -/* - * State interface markers - */ - -#define PVTCP_PF_UNBOUND 0x0 -#define PVTCP_PF_DEATH_ROW 0xffffffff -#define PVTCP_PF_LOOPBACK_INET4 (PVTCP_PF_DEATH_ROW - 1) - - -/* - * Interface and interface configuration structures. - */ - -typedef struct PvtcpIfConf { - int family; // Values: - // unbound (PVTCP_PF_UNBOUND) - // deathRow (PVTCP_PF_DEATH_ROW) - // loopback (PVTCP_PF_LOOPBACK_INET4) - // inet4 (PF_INET) - // inet6 (PF_INET6) - union { - struct in_addr in; - struct in6_addr in6; - } addr; // inet4 or inet6 address. - union { - struct in_addr in; - struct in6_addr in6; - } mask; // inet4 or inet6 netmask. -} PvtcpIfConf; - - -struct PvtcpState; - -typedef struct PvtcpIf { - CommOSList sockList; // List of sockets. - CommOSList stateLink; // Link in PvtcpState.ifList. - struct PvtcpState *state; // Back reference to state. - PvtcpIfConf conf; // Interface configuration. -} PvtcpIf; - - -/* - * General pvtcp state associated with a channel. - */ - -typedef struct PvtcpState { - unsigned long long id; // Randomly generated state ID. - CommOSList ifList; // List of active interfaces. - CommChannel channel; // Comm channel back reference. - PvtcpIf ifDeathRow; // Always-present netif. - PvtcpIf ifUnbound; // Ditto. - PvtcpIf ifLoopbackInet4; // Ditto. - void *namespace; // Name space, where supported. - void *extra; // Used by upper layer to extend state as needed. - unsigned int mask; // Mask used to obfuscate socket pointers. -} PvtcpState; - - -/* - * Define pvtcp socket common fields and include the pv or offload header - * to get the right PvtcpSock definition. - */ - -#define PVTCP_SOCK_COMMON_FIELDS \ - CommOSMutex inLock; /* Input lock. */ \ - CommOSMutex outLock; /* Output lock. */ \ - CommOSSpinlock stateLock; /* State update lock. */ \ - CommOSList ifLink; /* Link in PvtcpIf.sockList. */ \ - CommOSWork work; /* Work item for AIO processing. */ \ - PvtcpIf *netif; /* Netif reference. */ \ - PvtcpState *state; /* State reference. */ \ - unsigned long long stateID; /* State ID. */ \ - CommChannel channel; /* Comm channel reference. */ \ - unsigned long long peerSock; /* Peer socket, opaque. */ \ - volatile int peerSockSet; /* Peer socket valid. */ \ - CommOSAtomic deltaAckSize; /* Recv size updates required by peer. */ \ - CommOSAtomic rcvdSize; /* Bytes received since last ack. */ \ - CommOSAtomic sentSize; /* Bytes sent; also updated by peer. */ \ - CommOSAtomic queueSize; /* Queue size. */ \ - CommOSList queue; /* Send queue (off) or recv queue (pv). */ \ - void *rpcReply; /* RPC reply. */ \ - int rpcStatus; /* RPC completion status. */ \ - int err /* Socket error. */ - -#define PVTCP_PEER_SOCK_NULL ((unsigned long long)0) - - -/* - * Helper macros - */ - -#define SOCK_STATE_LOCK(pvsk) CommOS_SpinLock(&(pvsk)->stateLock) -#define SOCK_STATE_UNLOCK(pvsk) CommOS_SpinUnlock(&(pvsk)->stateLock) - -#define SOCK_IN_TRYLOCK(pvsk) CommOS_MutexTrylock(&(pvsk)->inLock) -#define SOCK_IN_LOCK(pvsk) CommOS_MutexLock(&(pvsk)->inLock) -#define SOCK_IN_UNLOCK(pvsk) CommOS_MutexUnlock(&(pvsk)->inLock) - -#define SOCK_OUT_TRYLOCK(pvsk) CommOS_MutexTrylock(&(pvsk)->outLock) -#define SOCK_OUT_LOCK(pvsk) CommOS_MutexLock(&(pvsk)->outLock) -#define SOCK_OUT_LOCK_UNINT(pvsk) \ - CommOS_MutexLockUninterruptible(&(pvsk)->outLock) -#define SOCK_OUT_UNLOCK(pvsk) CommOS_MutexUnlock(&(pvsk)->outLock) - -#define PVTCP_UNLOCK_DISP_DISCARD_VEC() \ - CommSvc_DispatchUnlock(channel); \ - while (vecLen) { \ - PvtcpBufFree(vec[--vecLen].iov_base); \ - } - - -#if defined(PVTCP_BUILDING_SERVER) -#include "pvtcp_off.h" -#else -#include "pvtcp_pv.h" -#endif // defined(PVTCP_BUILDING_SERVER) - - -/* - * Data declarations - */ - -extern const PvtcpIfConf *pvtcpIfUnbound; -extern const PvtcpIfConf *pvtcpIfDeathRow; -extern const PvtcpIfConf *pvtcpIfLoopbackInet4; - -extern CommImpl pvtcpImpl; -extern CommOperationFunc pvtcpOperations[]; - -extern CommChannel pvtcpClientChannel; - - -/* - * Common state manipulation functions. - */ - -void *PvtcpStateAlloc(CommChannel channel); -void PvtcpStateFree(void *arg); - -int PvtcpStateAddIf(CommChannel channel, const PvtcpIfConf *conf); -void PvtcpStateRemoveIf(CommChannel channel, const PvtcpIfConf *conf); -PvtcpIf *PvtcpStateFindIf(PvtcpState *state, const PvtcpIfConf *conf); - -int -PvtcpStateAddSocket(CommChannel channel, - const PvtcpIfConf *conf, - PvtcpSock *sock); -int PvtcpStateRemoveSocket(CommChannel channel, PvtcpSock *sock); - - -/* - * Common Pvtcp functions. - */ - -int PvtcpCheckArgs(CommTranspInitArgs *transpArgs); - -void -PvtcpCloseNtf(void *ntfData, - const CommTranspInitArgs *transpArgs, - int inBH); - -void *PvtcpBufAlloc(unsigned int size); -void PvtcpBufFree(void *buf); - -void PvtcpReleaseSocket(PvtcpSock *pvsk); -int PvtcpSockInit(PvtcpSock *pvsk, CommChannel channel); - -void PvtcpProcessAIO(CommOSWork *work); - - -/** - * @brief Packs an IPV6 address stored in an array of four 32-bit elements, - * into two 64-bit variables. - * @param addr IPV6 address as an array of 32-bit elements. - * @param[out] d64_0 pointer to 64-bit variable. - * @param[out] d64_1 pointer to 64-bit variable. - */ - -static inline void -PvtcpI6AddrPack(const unsigned int addr[4], - unsigned long long *d64_0, - unsigned long long *d64_1) -{ - *d64_0 = *(unsigned long long *)&addr[0]; - *d64_1 = *(unsigned long long *)&addr[2]; -} - - -/** - * @brief Unpacks two 64-bit values into an IPV6 address-storing array of - * four 32-bit elements, - * @param[out] addr IPV6 address as an array of 32-bit elements. - * @param d64_0 64-bit value. - * @param d64_1 64-bit value. - */ - -static inline void -PvtcpI6AddrUnpack(unsigned int addr[4], - unsigned long long d64_0, - unsigned long long d64_1) -{ - *(unsigned long long *)&addr[0] = d64_0; - *(unsigned long long *)&addr[2] = d64_1; -} - - -/** - * @brief Verifies whether the argument is a valid socket. If yes, it returns - * the actual pointer. Otherwise, it returns from the calling function. - * WARNING: This macro must ONLY be used in operation functions, as its - * implementation assumes. - * @param handle socket handle to verify. - * @param container state supposed to contain the socket handle. - * @return 32-bit or 64-bit PvtcpSock*, depending on __LP64__ or __LLP64__. - */ - -#if defined(__LP64__) || defined(__LLP64__) - -#define PvtcpGetPvskOrReturn(handle, container) \ - ({ \ - PvtcpState *__state = (PvtcpState *)(container); \ - PvtcpSock *__pvsk = \ - (PvtcpSock *)((handle) ^ (unsigned long long)__state->mask); \ - \ - if (__pvsk->stateID != __state->id) { \ - PVTCP_UNLOCK_DISP_DISCARD_VEC(); \ - CommSvc_Zombify(__state->channel, 0); \ - return; \ - } \ - (__pvsk); \ - }) - -#else // __LP64__ || __LLP64__ - -#define PvtcpGetPvskOrReturn(handle, container) \ - ({ \ - PvtcpState *__state = (PvtcpState *)(container); \ - PvtcpSock *__pvsk = \ - (PvtcpSock *)((unsigned int)(handle) ^ __state->mask); \ - \ - if (__pvsk->stateID != __state->id) { \ - PVTCP_UNLOCK_DISP_DISCARD_VEC(); \ - CommSvc_Zombify(__state->channel, 0); \ - return; \ - } \ - (__pvsk); \ - }) - -#endif // __LP64__ || __LLP64__ - - -/** - * @brief Masks a socket pointer to be passed to the peer module. - * @param pvsk socket pointer to mask. - * @return 64-bit pvtcp socket handle. - */ - -#if defined(__LP64__) || defined(__LLP64__) - -#define PvtcpGetHandle(pvsk) \ - ((unsigned long long)(pvsk) ^ (unsigned long long)(pvsk)->state->mask) - -#else // __LP64__ || __LLP64__ - -#define PvtcpGetHandle(pvsk) \ - ((unsigned int)(pvsk) ^ (pvsk)->state->mask) - -#endif // __LP64__ || __LLP64__ - -#endif // _PVTCP_H_ diff --git a/arch/arm/mvp/pvtcpkm/pvtcp_off.c b/arch/arm/mvp/pvtcpkm/pvtcp_off.c deleted file mode 100644 index 053d9c2..0000000 --- a/arch/arm/mvp/pvtcpkm/pvtcp_off.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Server (offload) side code. - */ - -#include "pvtcp.h" - -/** - * @brief Allocates the net buffer. - * @param size buffer size - * @return address of buffer or NULL - */ -void * -PvtcpBufAlloc(unsigned int size) -{ - PvtcpOffBuf *buf; - - /* coverity[alloc_fn] */ - /* coverity[var_assign] */ - buf = CommOS_Kmalloc(size + sizeof *buf - sizeof buf->data); - if (buf) { - CommOS_ListInit(&buf->link); - buf->len = (unsigned short)size; - buf->off = 0; - return PvtcpOffBufFromInternal(buf); - } - return NULL; -} - - -/** - * @brief Deallocates given net buffer. - * @param buf buffer to deallocate - * @sideeffect Frees memory - */ - -void -PvtcpBufFree(void *buf) -{ - CommOS_Kfree(PvtcpOffInternalFromBuf(buf)); -} - - -/** - * @brief Initializes the Pvtcp socket offload common fields. - * @param pvsk pvtcp socket. - * @param channel Comm channel this socket is associated with. - * @return 0 if successful, -1 otherwise. - */ - -int -PvtcpOffSockInit(PvtcpSock *pvsk, - CommChannel channel) -{ - int rc = PvtcpSockInit(pvsk, channel); - - pvsk->opFlags = 0; - pvsk->flags = 0; - return rc; -} diff --git a/arch/arm/mvp/pvtcpkm/pvtcp_off.h b/arch/arm/mvp/pvtcpkm/pvtcp_off.h deleted file mode 100644 index f183968..0000000 --- a/arch/arm/mvp/pvtcpkm/pvtcp_off.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Offload common definitions. - * This file is meant to only be included via pvtcp.h. - */ - -#ifndef _PVTCP_OFF_H_ -#define _PVTCP_OFF_H_ - - -#define PVTCP_OFF_SOCK_COMMON_FIELDS \ - volatile unsigned int opFlags; /* Saves op codes as bit mask. */ \ - volatile unsigned int flags /* General purpose flags. */ - - -/* General purpose socket flags */ - -enum PvtcpOffPvskFlags { - PVTCP_OFF_PVSKF_IPV6_LOOP = 0, /* Used for IPV6 loopback morphing/reset. */ - PVTCP_OFF_PVSKF_SHUT_RD, /* Set to initiate socket recv shutdown. */ - PVTCP_OFF_PVSKF_SHUT_WR, /* Set to initiate socket send shutdown. */ - PVTCP_OFF_PVSKF_TCP_NODELAY, /* Caches the TCP_NODELAY socket option. */ - PVTCP_OFF_PVSKF_TCP_CORK, /* Caches the TCP_CORK socket option. */ - PVTCP_OFF_PVSKF_DISCONNECT, /* Set do indicate connect()/AF_UNSPEC. */ - PVTCP_OFF_PVSKF_INVALID = 32 -}; - - -/* - * Include OS-dependent PvtcpSock structure and functions. - */ - -#if defined(__linux__) -#include "pvtcp_off_linux.h" -#else -#error "Unsupported OS." -#endif - - -/* - * Offload packet payload data structure. - */ - -typedef struct PvtcpOffBuf { - CommOSList link; // Link in socket queue. - unsigned short len; - unsigned short off; - char data[1]; -} PvtcpOffBuf; - - -/** - * @brief Returns net buffer given private data structure pointer and based - * on the internal offset pointer - * @param arg pointer to PvtcpOffBuf wrapper structure - * @return address of buffer or NULL - */ - -static inline void * -PvtcpOffBufFromInternalOff(PvtcpOffBuf *arg) -{ - return arg ? - &arg->data[arg->off] : - NULL; -} - - -/** - * @brief Returns net buffer given private data structure pointer - * @param arg pointer to PvtcpOffBuf wrapper structure - * @return address of buffer or NULL - */ - -static inline void * -PvtcpOffBufFromInternal(PvtcpOffBuf *arg) -{ - return arg ? - &arg->data[0] : - NULL; -} - - -/** - * @brief Returns internal data structure given net buffer pointer - * @param arg pointer to PvtcpOffBuf wrapper structure - * @return address of internal data structure or NULL - */ - -static inline PvtcpOffBuf * -PvtcpOffInternalFromBuf(void *arg) -{ - return arg ? - (PvtcpOffBuf *)((char *)arg - offsetof(PvtcpOffBuf, data)) : - NULL; -} - - -/** - * @brief Tests operation flag for AIO processing. - * @param pvsk socket to test operation on. - * @param op operation to test if set. - * @return non-zero if operation set, zero otherwise. - * @sideeffect socket processing by AIO threads affected according to operation. - */ - -static inline int -PvskTestOpFlag(struct PvtcpSock *pvsk, - int op) -{ - return pvsk->opFlags & (1 << op); -} - - -/** - * @brief Sets operation flag for AIO processing; acquires the state lock. - * @param[in,out] pvsk socket to set operation on. - * @param op operation to set. - * @sideeffect socket processing by AIO threads affected according to operation. - */ - -static inline void -PvskSetOpFlag(struct PvtcpSock *pvsk, - int op) -{ - unsigned int ops; - - SOCK_STATE_LOCK(pvsk); - ops = pvsk->opFlags | (1 << op); - pvsk->opFlags = ops; - SOCK_STATE_UNLOCK(pvsk); -} - - -/** - * @brief Resets operation flag for AIO processing; acquires the state lock. - * @param[in,out] pvsk socket to reset operation on. - * @param op operation to reset. - * @sideeffect socket processing by AIO threads affected according to operation. - */ - -static inline void -PvskResetOpFlag(struct PvtcpSock *pvsk, - int op) -{ - unsigned int ops; - - SOCK_STATE_LOCK(pvsk); - ops = pvsk->opFlags & ~(1 << op); - pvsk->opFlags = ops; - SOCK_STATE_UNLOCK(pvsk); -} - - -/** - * @brief Tests general purpose socket flags. - * @param pvsk socket. - * @param flag flag to test. - * @return non-zero if flag set, zero otherwise. - */ - -static inline int -PvskTestFlag(struct PvtcpSock *pvsk, - int flag) -{ - return (flag < PVTCP_OFF_PVSKF_INVALID) && (pvsk->flags & (1 << flag)); -} - - -/** - * @brief Sets general purpose socket flags; acquires the state lock. - * @param[in,out] pvsk socket. - * @param flag flag to set or clear. - * @param onOff whether to set or clear the flag. - */ - -static inline void -PvskSetFlag(struct PvtcpSock *pvsk, - int flag, - int onOff) -{ - unsigned int flags; - - SOCK_STATE_LOCK(pvsk); - if (flag < PVTCP_OFF_PVSKF_INVALID) { - if (onOff) { - flags = pvsk->flags | (1 << flag); - } else { - flags = pvsk->flags & ~(1 << flag); - } - pvsk->flags = flags; - } - SOCK_STATE_UNLOCK(pvsk); -} - - -int PvtcpOffSockInit(PvtcpSock *pvsk, CommChannel channel); - -#endif // _PVTCP_OFF_H_ diff --git a/arch/arm/mvp/pvtcpkm/pvtcp_off_io_linux.c b/arch/arm/mvp/pvtcpkm/pvtcp_off_io_linux.c deleted file mode 100644 index 9958c39..0000000 --- a/arch/arm/mvp/pvtcpkm/pvtcp_off_io_linux.c +++ /dev/null @@ -1,831 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Server (offload) side Linux-specific socket I/O functions. - */ - -#include "pvtcp.h" - -/* - * Data. - */ - -/* Used to check if OutputAIO()-ing is likely in progress. */ - -CommOSAtomic PvtcpOutputAIOSection; - - -/* - * Large datagram bounce buffer (PVTCP_SOCK_BUF_SIZE < size <= 64K). - * Only one such buffer is available, shared across cpus via get/put. - * A preallocated, smaller buffer is used for most over-size 'allocs'. - * A larger, 64K-buffer may need to be __vmalloc()-ed. - */ - -typedef struct LargeDgramBuf { - unsigned char buf[PVTCP_SOCK_BUF_SIZE << 1]; /* Fast buffer. */ - void *spareBuf; /* Dynamically allocated. */ - CommOSMutex lock; -} LargeDgramBuf; - -static LargeDgramBuf largeDgramBuf; - - -/** - * @brief One time initialization of large datagram buffer. - */ - -void -PvtcpOffLargeDgramBufInit(void) -{ - largeDgramBuf.spareBuf = NULL; - CommOS_MutexInit(&largeDgramBuf.lock); -} - - -/** - * @brief Reserves/holds the large datagram buffer. - * @param size size of buffer. - * @sizeeffect may sleep until the buffer is available. - * @return address of buffer, or NULL if size too large or allocation failed. - */ - -static inline void * -LargeDgramBufGet(int size) -{ - static const unsigned int maxSize = 64 * 1024; - - /* coverity[alloc_fn] */ - /* coverity[var_assign] */ - - CommOS_MutexLockUninterruptible(&largeDgramBuf.lock); - - if (size <= sizeof largeDgramBuf.buf) { - return largeDgramBuf.buf; - } - - if (size <= maxSize) { - if (!largeDgramBuf.spareBuf) { - largeDgramBuf.spareBuf = __vmalloc(maxSize, - (GFP_ATOMIC | __GFP_HIGHMEM), - PAGE_KERNEL); - } - if (largeDgramBuf.spareBuf) { - return largeDgramBuf.spareBuf; - } - } - - CommOS_MutexUnlock(&largeDgramBuf.lock); - return NULL; -} - - -/** - * @brief Releases hold on the large datagram buffer. - * @param buf buffer to put back. - */ - -static inline void -LargeDgramBufPut(void *buf) -{ - static unsigned int spareBufPuts = 0; - - BUG_ON((buf != largeDgramBuf.buf) && (buf != largeDgramBuf.spareBuf)); - - if (largeDgramBuf.spareBuf && (++spareBufPuts % 2) == 0) { - /* Deallocate the spare buffer every now and then. */ - - vfree(largeDgramBuf.spareBuf); - largeDgramBuf.spareBuf = NULL; - } - - CommOS_MutexUnlock(&largeDgramBuf.lock); -} - - -/* - * I/O offload operations. - */ - -/** - * @brief Flow control notification received when more (enough) data was - * consumed from a PV socket. - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled - */ - -void -PvtcpFlowOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - - PvtcpHoldSock(pvsk); - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - CommOS_SubReturnAtomic(&pvsk->rcvdSize, (int)packet->data32); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); -} - - -/** - * @brief Outputs bytes to socket. - * @param channel communication channel with offloader. - * @param upperLayerState state associated with this channel. - * @param packet received packet header. - * @param vec payload buffer descriptors. - * @param vecLen payload buffer descriptor count. - * @sideeffect Changes send size/capacity ratio. May schedule AIO processing - * for enqueued bytes, if applicable. - */ - -void -PvtcpIoOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - int rc; - unsigned int vecOff; - PvtcpOffBuf *internalBuf; - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - struct sock *sk = SkFromPvsk(pvsk); - struct socket *sock = sk->sk_socket; - unsigned int dataLen = packet->len - sizeof *packet; - struct msghdr msg = { - .msg_controllen = 0, - .msg_control = NULL - }; - int tmpSize; - int needSched = 0; - - PvtcpHoldSock(pvsk); - rc = 0; - - if (!pvsk->peerSockSet || PvskTestFlag(pvsk, PVTCP_OFF_PVSKF_SHUT_WR)) { - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - goto out; - } - - tmpSize = (int)COMM_OPF_GET_VAL(packet->flags); - if (tmpSize) { - /* It was requested that we update deltaAckSize. */ - - tmpSize = 1 << tmpSize; - CommOS_WriteAtomic(&pvsk->deltaAckSize, tmpSize); - } - - if (sk->sk_type == SOCK_STREAM) { - unsigned int queueSize = 0; - - if (!SOCK_OUT_TRYLOCK(pvsk)) { - if (pvsk->peerSockSet && - (sk->sk_state == TCP_ESTABLISHED) && - (CommOS_ReadAtomic(&pvsk->queueSize) == 0)) { - /* Attempt to write directly as many bytes as we can. */ - - msg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; - rc = kernel_sendmsg(sock, &msg, vec, vecLen, dataLen); - - if (rc == -EAGAIN) { - rc = 0; - } - if (rc >= 0) { - dataLen = rc; - for (vecOff = 0; vecOff < vecLen; vecOff++) { - if (rc >= vec[vecOff].iov_len) { - /* Dispose of all fully consumed buffers. */ - - PvtcpBufFree(vec[vecOff].iov_base); - rc -= vec[vecOff].iov_len; - } else { - /* Place partly consumed / unconsumed buffers in queue. */ - - internalBuf = - PvtcpOffInternalFromBuf(vec[vecOff].iov_base); - BUG_ON(internalBuf == NULL); - if (rc > 0) { - internalBuf->len -= rc; - internalBuf->off += rc; - rc = 0; - } - CommOS_ListAddTail(&pvsk->queue, &internalBuf->link); - queueSize += internalBuf->len; - } - } - if (queueSize > 0) { - CommOS_AddReturnAtomic(&pvsk->queueSize, queueSize); - needSched = 1; - } - } else { - /* - * We never close offload sockets unless told by the PV side, - * or when the comm goes down. Getting out of sync with PV - * sockets is a dangerously bad idea. - * This is very likely an EPIPE/ECONNRESET. - */ - - dataLen = 0; - for ( vecOff = 0; vecOff < vecLen; vecOff++) { - PvtcpBufFree(vec[vecOff].iov_base); - } - } - SOCK_OUT_UNLOCK(pvsk); - } else { - SOCK_OUT_UNLOCK(pvsk); - goto enqueueBytes; - } - } else { - /* - * We enqueue the bytes for aio processing. Note that request - * level ordering is preserved since we're still under the dispatch - * lock. However, accessing 'queue' must be protected via - * the state lock to serialize with aio changes. - * Note that the struct socket *sock may have been released, but here - * we only access sk which is held (albeit potentially orphaned). - */ - - CommOSList bufList; - -enqueueBytes: - dataLen = 0; - if (pvsk->peerSockSet && (sk->sk_state == TCP_ESTABLISHED)) { - queueSize = 0; - CommOS_ListInit(&bufList); - for (vecOff = 0; vecOff < vecLen; vecOff++) { - internalBuf = PvtcpOffInternalFromBuf(vec[vecOff].iov_base); - BUG_ON(internalBuf == NULL); - CommOS_ListAddTail(&bufList, &internalBuf->link); - queueSize += internalBuf->len; - } - - if (queueSize > 0) { - SOCK_STATE_LOCK(pvsk); - CommOS_ListSpliceTail(&pvsk->queue, &bufList); - SOCK_STATE_UNLOCK(pvsk); - CommOS_AddReturnAtomic(&pvsk->queueSize, queueSize); - needSched = 1; - } - } else { - for ( vecOff = 0; vecOff < vecLen; vecOff++) { - PvtcpBufFree(vec[vecOff].iov_base); - } - } - } - } else { /* SOCK_DGRAM || SOCK_RAW */ - struct sockaddr *addr; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - int addrLen; - - /* - * Non-stream sockets don't use the send queue, packets are sent - * directly and they must _not_ be merged. - */ - - if (sk->sk_family == AF_INET) { - sin.sin_family = AF_INET; - sin.sin_port = packet->data16; - addr = (struct sockaddr *)&sin; - addrLen = sizeof sin; - sin.sin_addr.s_addr = (unsigned int)packet->data64ex; - PvtcpTestAndBindLoopbackInet4(pvsk, &sin.sin_addr.s_addr, 0); - } else { /* AF_INET6 */ - sin6.sin6_family = AF_INET6; - sin6.sin6_port = packet->data16; - addr = (struct sockaddr *)&sin6; - addrLen = sizeof sin6; - PvtcpTestAndBindLoopbackInet6(pvsk, &packet->data64ex, - &packet->data64ex2, 0); - PvtcpI6AddrUnpack(&sin6.sin6_addr.s6_addr32[0], - packet->data64ex, packet->data64ex2); - } - msg.msg_flags = packet->data32 | MSG_DONTWAIT | MSG_NOSIGNAL; - msg.msg_name = addr; - msg.msg_namelen = addrLen; - - if (pvsk->peerSockSet) { - /* - * Flow-control already done, based on PVTCP_SOCK_SAFE_RCVSIZE, just - * as with stream sockets. Meaning that we block the senders in the - * guest (if applicable). - * - * The send buffer size was set high enough, at socket creation time, - * to avoid dropping datagrams during the (non-blocking) write. - */ - - if (vecLen == 0) { - /* - * Allow zero-sized datagram sending. - */ - - struct kvec dummy = { .iov_base = NULL, .iov_len = 0 }; - - rc = kernel_sendmsg(sock, &msg, &dummy, 0, 0); - if (rc != dummy.iov_len) { -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Dgram [0x%p] sent [%d], expected [%d]\n", - __FUNCTION__, sk, rc, dummy.iov_len)); -#endif - if (rc == -EAGAIN) { /* As if lost on the wire. */ - rc = 0; - } - } - } - - for (vecOff = 0; vecOff < vecLen; vecOff++) { - rc = kernel_sendmsg(sock, &msg, &vec[vecOff], 1, - vec[vecOff].iov_len); - PvtcpBufFree(vec[vecOff].iov_base); - if (rc != vec[vecOff].iov_len) { -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Dgram [0x%p] sent [%d], expected [%d]\n", - __FUNCTION__, sk, rc, vec[vecOff].iov_len)); -#endif - if (rc == -EAGAIN) { /* As if lost on the wire. */ - rc = 0; - } - } - } - - if (COMM_OPF_TEST_ERR(packet->flags)) { - /* PV client wants an automatic bind. */ - - PvskSetOpFlag(pvsk, PVTCP_OP_BIND); - PvtcpSchedSock(pvsk); - } - } else { - for ( vecOff = 0; vecOff < vecLen; vecOff++) { - PvtcpBufFree(vec[vecOff].iov_base); - } - } - } - CommSvc_DispatchUnlock(channel); - -out: - if (rc < 0) { - pvsk->err = -rc; - } - tmpSize = CommOS_AddReturnAtomic(&pvsk->sentSize, dataLen); - if ((tmpSize >= CommOS_ReadAtomic(&pvsk->deltaAckSize)) || - pvsk->err || needSched) { - if (CommOS_AddReturnAtomic(&PvtcpOutputAIOSection, 1) == 1) { - /* OutputAIO() (likely) not running. */ - - PvtcpSchedSock(pvsk); - } - CommOS_SubReturnAtomic(&PvtcpOutputAIOSection, 1); - } - - PvtcpPutSock(pvsk); -} - - -/* - * AI/O functions called from the main AIO processing function. - */ - -/** - * @brief Processes socket flow control acks and error notifications in an - * AIO thread. This function is called with the socket 'in' lock taken. - * @param[in,out] pvsk socket to process. - * @param err non-zero if offload was closed, zero otherwise. - * @sideeffect May resume PV socket sending or raise errors. - */ - -void -PvtcpFlowAIO(PvtcpSock *pvsk, - int err) -{ - CommPacket packet = { .flags = 0 }; - unsigned long long timeout; - int tmpSize; - - COMM_OPF_CLEAR_ERR(packet.flags); - packet.data32 = PVTCP_FLOW_OP_INVALID_SIZE; - if (pvsk->err || err) { - COMM_OPF_SET_ERR(packet.flags); - packet.data32ex = !pvsk->err ? 0 : xchg(&pvsk->err, 0); - if (!packet.data32ex) { - packet.data32ex = -err; - } -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Sending socket error [%u] on [0x%p -> 0x%0x].\n", - __FUNCTION__, packet.data32ex, pvsk, - (unsigned)(pvsk->peerSock))); -#endif - } else { - SOCK_STATE_LOCK(pvsk); - tmpSize = CommOS_ReadAtomic(&pvsk->deltaAckSize); - if (CommOS_ReadAtomic(&pvsk->sentSize) >= tmpSize) { - if ((SkFromPvsk(pvsk)->sk_type != SOCK_STREAM) && - !sock_writeable(SkFromPvsk(pvsk))) { - /* Don't send dgram flow op until WriteSpaceCB tells us to do so. */ - - packet.data32 = PVTCP_FLOW_OP_INVALID_SIZE; - } else { - packet.data32 = CommOS_ReadAtomic(&pvsk->sentSize); - CommOS_WriteAtomic(&pvsk->sentSize, 0); - if (tmpSize > (1 << (PVTCP_SOCK_SMALL_ACK_ORDER + 1))) { - tmpSize >>= 1; - CommOS_WriteAtomic(&pvsk->deltaAckSize, tmpSize); - } - } - } - SOCK_STATE_UNLOCK(pvsk); - packet.data32ex = 0; - } - - if (((packet.data32 != PVTCP_FLOW_OP_INVALID_SIZE) || - COMM_OPF_TEST_ERR(packet.flags)) && - pvsk->peerSockSet) { - packet.len = sizeof packet; - packet.opCode = PVTCP_OP_FLOW; - packet.data64 = pvsk->peerSock; - timeout = COMM_MAX_TO; - CommSvc_Write(pvsk->channel, &packet, &timeout); - } -} - - -/** - * @brief Processes queued socket output in an AIO thread. This function is - * called with the socket 'out' lock taken. - * @param[in,out] pvsk socket to process. - * @sideeffect Changes send size/capacity ratio. - */ - -void -PvtcpOutputAIO(PvtcpSock *pvsk) -{ - struct sock *sk; - struct socket *sock; - PvtcpOffBuf *internalBuf; - PvtcpOffBuf *tmp; - CommOSList queue; -#define VEC_SIZE 32 - struct kvec vec[VEC_SIZE]; - unsigned int vecLen; - unsigned int dataLen; - struct msghdr msg = { - .msg_controllen = 0, - .msg_control = NULL, - .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL - }; - int queueDelta = 0; - int done = 0; - int rc; - - sk = SkFromPvsk(pvsk); - if (!sk) { - /* This is an error socket, we don't process it. */ - - return; - } - - sock = sk->sk_socket; - -again: - CommOS_AddReturnAtomic(&PvtcpOutputAIOSection, 1); - while (!done && CommOS_ReadAtomic(&pvsk->queueSize) > 0) { - /* Note: only stream sockets can have a positive send queue size. - * Similar to PvtcpIoOp: we must check if sock (struct socket *) is - * still valid. - */ - - /* Take the current queue private. */ - - SOCK_STATE_LOCK(pvsk); - queue = pvsk->queue; - if (CommOS_ListEmpty(&queue)) { - SOCK_STATE_UNLOCK(pvsk); - return; - } - queue.next->prev = &queue; - queue.prev->next = &queue; - CommOS_ListInit(&pvsk->queue); - SOCK_STATE_UNLOCK(pvsk); - - vecLen = 0; - dataLen = 0; - - if (sk->sk_state == TCP_ESTABLISHED) { - CommOS_ListForEach(&queue, internalBuf, link) { - if (vecLen == VEC_SIZE) { - break; - } - vec[vecLen].iov_base = PvtcpOffBufFromInternalOff(internalBuf); - vec[vecLen].iov_len = internalBuf->len; - dataLen += internalBuf->len; - vecLen++; - } - - rc = kernel_sendmsg(sock, &msg, vec, vecLen, dataLen); - - if (rc == -EAGAIN) { - rc = 0; - } - if (rc >= 0) { - /* If we wrote anything, dispose of the buffers in question. */ - - queueDelta = rc; - if (queueDelta > 0) { - CommOS_ListForEachSafe(&queue, internalBuf, tmp, link) { - if (rc >= internalBuf->len) { - rc -= internalBuf->len; - CommOS_ListDel(&internalBuf->link); - PvtcpBufFree(PvtcpOffBufFromInternal(internalBuf)); - } else { - internalBuf->len -= rc; - internalBuf->off += rc; - break; - } - } - } - if (!CommOS_ListEmpty(&queue)) { - /* Add the remaining bytes to the beginning of the queue. */ - - SOCK_STATE_LOCK(pvsk); - CommOS_ListSplice(&pvsk->queue, &queue); - SOCK_STATE_UNLOCK(pvsk); - } - if (queueDelta == 0) { - /* Bail out if no bytes written, WriteSpaceCB() will resched. */ - - done = 1; - break; - } - CommOS_AddReturnAtomic(&pvsk->sentSize, queueDelta); - CommOS_SubReturnAtomic(&pvsk->queueSize, queueDelta); - } else { - /* - * Very likely, this is due to the socket being closed, so fine. - */ - - goto discardOutput; - } - } else { - /* Dispose of all buffers in the queue and mark it empty. */ - -discardOutput: - if (!CommOS_ListEmpty(&queue)) { - CommOS_ListForEachSafe(&queue, internalBuf, tmp, link) { - CommOS_ListDel(&internalBuf->link); - PvtcpBufFree(PvtcpOffBufFromInternal(internalBuf)); - } - } - CommOS_WriteAtomic(&pvsk->queueSize, 0); - break; - } - } - if (CommOS_SubReturnAtomic(&PvtcpOutputAIOSection, 1) > 0) { - if (!done) { - goto again; - } - } - - if (PvskTestFlag(pvsk, PVTCP_OFF_PVSKF_SHUT_WR)) { - kernel_sock_shutdown(sock, SHUT_WR); - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_SHUT_WR, 0); - } -#undef VEC_SIZE -} - - -/** - * @brief Processes socket input in an AIO thread. This function is - * called with the socket 'in' lock taken. - * @param[in,out] pvsk socket to process. - * @param[in,out] perCpuBuf per-cpu socket read buffer. - * @return zero if eof was not detected, non-zero otherwise. - * @sideeffect Changes receive size/capacity ratio. - */ - -int -PvtcpInputAIO(PvtcpSock *pvsk, - void *perCpuBuf) -{ - struct sock *sk; - struct socket *sock; - int err = 0; - CommPacket packet = { - .opCode = PVTCP_OP_IO - }; - unsigned long long timeout; - - sk = SkFromPvsk(pvsk); - if (!sk) { - /* IO processing is skipped on socket create-error sockets. */ - - return -1; - } - if (!perCpuBuf) { - /* No read buffer. */ - - return -1; - } - - sock = sk->sk_socket; - packet.data64 = pvsk->peerSock; - COMM_OPF_CLEAR_ERR(packet.flags); - - if (sk->sk_state == TCP_LISTEN) { - /* Process stream listen 'input'. */ - - packet.len = sizeof packet; - packet.data16 = sk->sk_ack_backlog; - timeout = COMM_MAX_TO; - if (pvsk->peerSockSet) { - CommSvc_Write(pvsk->channel, &packet, &timeout); - CommOS_Debug(("%s: Listen sock [0x%p] 'ack_backlog' [%hu].\n", - __FUNCTION__, sk, packet.data16)); - } - } else { - /* Common path for both stream and datagram sockets. */ - - int rc; - int tmpSize; - struct kvec vec[2]; - void *ioBuf = perCpuBuf; - struct kvec *inVec; - unsigned int inVecLen; - unsigned int iovOffset = 0; - unsigned int inputSize = 0; - unsigned int coalescingSize = PVTCP_SOCK_RCVSIZE >> 2; - struct sockaddr_in sin = { .sin_family = AF_INET }; - struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6 }; - struct msghdr msg = { - .msg_controllen = 0, - .msg_control = NULL, - .msg_flags = MSG_DONTWAIT - }; - int tmpFlags = msg.msg_flags; - PvtcpDgramPseudoHeader dgramHeader; - - tmpSize = CommOS_ReadAtomic(&pvsk->rcvdSize); - while ((tmpSize < PVTCP_SOCK_SAFE_RCVSIZE) && pvsk->peerSockSet) { - if (ioBuf != perCpuBuf) { - LargeDgramBufPut(ioBuf); - ioBuf = perCpuBuf; - } - vec[0].iov_base = (char *)ioBuf; - - if (sk->sk_type == SOCK_STREAM) { - if (PvskTestFlag(pvsk, PVTCP_OFF_PVSKF_SHUT_RD)) { - break; - } - - msg.msg_name = NULL; - msg.msg_namelen = 0; - vec[0].iov_len = PVTCP_SOCK_STREAM_BUF_SIZE; - } else { /* SOCK_DGRAM || SOCK_RAW */ - if (sk->sk_family == AF_INET) { - msg.msg_name = &sin; - msg.msg_namelen = sizeof sin; - } else { - msg.msg_name = &sin6; - msg.msg_namelen = sizeof sin6; - } - - /* - * Check if datagram larger than the per cpu buffer; if so, - * allocate a large enough buffer. This should happen quite - * rarely, as well-behaved applications don't rely on IP - * fragmentation to accommodate large sizes. - */ - - vec[0].iov_len = 1; - msg.msg_flags |= (MSG_PEEK | MSG_TRUNC); - rc = kernel_recvmsg(sock, &msg, vec, 1, 1, msg.msg_flags); - if (rc < 0) { - break; - } - msg.msg_flags = tmpFlags; - if (rc > PVTCP_SOCK_DGRAM_BUF_SIZE) { - /* - * Track large datagram allocations, whether allocation succeeds - * or not. No need for atomic overhead, approximating is OK. - */ - - pvtcpOffDgramAllocations++; - ioBuf = LargeDgramBufGet(rc); - if (!ioBuf) { - /* - * We reset it to the per-cpu buffer such that we can still - * consume the datagram in the next recvmsg, which will set - * MSG_TRUNC so we won't put it on the channel. - */ - - CommOS_Debug(("%s: Dropping datagram (alloc failure)!\n", - __FUNCTION__)); - ioBuf = perCpuBuf; - vec[0].iov_len = PVTCP_SOCK_DGRAM_BUF_SIZE; - } else { - vec[0].iov_len = rc; - } - } else { - vec[0].iov_len = PVTCP_SOCK_DGRAM_BUF_SIZE; - } - vec[0].iov_base = (char *)ioBuf; - } - - rc = kernel_recvmsg(sock, &msg, vec, 1, vec[0].iov_len, msg.msg_flags); - if (rc < 0) { - break; - } - - if ((rc == 0) && (sk->sk_type == SOCK_STREAM)) { - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_SHUT_RD, 1); - err = -ECONNRESET; - break; - } - - if (msg.msg_flags & MSG_TRUNC) { - continue; - } - - inputSize += rc; - tmpSize = CommOS_AddReturnAtomic(&pvsk->rcvdSize, rc); - if (tmpSize >= PVTCP_SOCK_LARGE_ACK_WM) { - COMM_OPF_SET_VAL(packet.flags, PVTCP_SOCK_LARGE_ACK_ORDER); - } else { - COMM_OPF_SET_VAL(packet.flags, 0); - } - - if (sk->sk_type == SOCK_STREAM) { - vec[0].iov_base = ioBuf; - vec[0].iov_len = rc; - inVecLen = 1; - packet.len = sizeof packet + rc; - } else { /* SOCK_DGRAM || SOCK_RAW */ - if (sk->sk_family == AF_INET) { - dgramHeader.d0 = (unsigned long long)sin.sin_port; - PvtcpResetLoopbackInet4(pvsk, &sin.sin_addr.s_addr); - dgramHeader.d1 = (unsigned long long)sin.sin_addr.s_addr; - } else { /* AF_INET6 */ - dgramHeader.d0 = (unsigned long long)sin6.sin6_port; - PvtcpResetLoopbackInet6(pvsk, &sin6.sin6_addr); - PvtcpI6AddrPack(&sin6.sin6_addr.s6_addr32[0], - &dgramHeader.d1, &dgramHeader.d2); - } - vec[0].iov_base = &dgramHeader; - vec[0].iov_len = sizeof dgramHeader; - vec[1].iov_base = ioBuf; - vec[1].iov_len = rc; - inVecLen = 2; - packet.len = sizeof packet + sizeof dgramHeader + rc; - } - - inVec = vec; - timeout = COMM_MAX_TO; - rc = CommSvc_WriteVec(pvsk->channel, &packet, - &inVec, &inVecLen, &timeout, &iovOffset); - if (rc != packet.len) { - CommOS_Log(("%s: BOOG -- WROTE INCOMPLETE PACKET [%u->%d]!\n", - __FUNCTION__, packet.len, rc)); - break; - } - - /* - * If the write failed, we could print a warning. But if this - * happened, the comm channel went down. - */ - if (inputSize >= coalescingSize) { - PvtcpSchedSock(pvsk); /* We must schedule ourselves back in. */ - break; - } - } - if (ioBuf != perCpuBuf) { - LargeDgramBufPut(ioBuf); - } - } - return err; -} diff --git a/arch/arm/mvp/pvtcpkm/pvtcp_off_linux.c b/arch/arm/mvp/pvtcpkm/pvtcp_off_linux.c deleted file mode 100644 index 047547f..0000000 --- a/arch/arm/mvp/pvtcpkm/pvtcp_off_linux.c +++ /dev/null @@ -1,2858 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Server (offload) side Linux-specific functions and callbacks. - */ - - -#include "pvtcp.h" - -#if defined(CONFIG_NET_NS) -#include <linux/nsproxy.h> -#include <linux/un.h> -#endif - -#include <net/ipv6.h> -#include <linux/kobject.h> -#include <linux/netfilter_ipv4.h> -#include <linux/netfilter_ipv6.h> -#include <linux/cred.h> - - -/* The PVSock address (127.238.0.1) in binary form, host byte order. */ -#define PVTCP_PVSOCK_ADDR 0x7fee0001 -#define PVTCP_PVSOCK_NET 0x7fee0000 -#define PVTCP_PVSOCK_MASK 0x000000ff - -/* From mvpkm */ -extern uid_t Mvpkm_vmwareUid; - -/* - * Credentials to back socket file pointer. Used in Android ICS network - * data usage accounting to bill guest data to MVP. - */ -static struct cred _cred; -static struct file _file = { - .f_cred = &_cred, -}; - -/* From pvtcp_off_io_linux.c */ -extern CommOSAtomic PvtcpOutputAIOSection; -extern void PvtcpOffLargeDgramBufInit(void); - -static const unsigned short portRangeBase = 7000; -static const unsigned int portRangeSize = 31; -static int hooksRegistered = 0; - -static inline int PvtcpTestPortIndexBit(unsigned int addr, - unsigned int portIdx); -/** - * @note - * Netfilter hooks: - * - * We decide to drop each packet based on the following criteria: - * 1) Destination address is to a pvsock address AND - * 3) (NOT(uid == 0 OR uid == vmwareUid)) OR - * 4) (type == UDP AND NOT(port-in-pvsock-range))) - */ - -/** - * @brief Netfilter hook. Restricts LOCAL_OUT packets. - * See note above to filter policy. - * @param skb skbuff - * @param inet6 is this socket ipv4 or ipv6? - * @return NF_ACCEPT if the packet is allowed through, NF_DROP otherwise - */ -static inline unsigned int -PvsockNfHook(struct sk_buff *skb, int inet6) -{ - uid_t uid; - unsigned int port; - struct socket *sock; - unsigned int addr = inet6 ? - ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]) : - ntohl(ip_hdr(skb)->daddr); - - if (likely((addr ^ PVTCP_PVSOCK_NET) & ~PVTCP_PVSOCK_MASK)) { - /* Not a pvsock address. */ - return NF_ACCEPT; - } - - sock = skb->sk->sk_socket; - if (unlikely(!sock)) { - return NF_ACCEPT; - } - - /* - * Guest (kernel) sockets can send to other guest sockets, - * Root can send to whoever it wants, no checks. - */ - uid = (sock->file ? sock->file->f_cred->uid : 0); - if (uid == 0 || (sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM)) { - return NF_ACCEPT; - } - - /* - * Only vmware can send to guest. - */ - if (likely(uid == Mvpkm_vmwareUid)) { - if (sock->type == SOCK_DGRAM) { - /* - * Deny sending to UDP port in pvsock range, if receiving socket was - * not created by the guest with this pvsock address. Drop all other - * UDP packets. - */ - port = ntohs(udp_hdr(skb)->dest) - portRangeBase; - if ((port < portRangeSize) && - PvtcpTestPortIndexBit(htonl(addr), port)) { - return NF_ACCEPT; - } - return NF_DROP; - } - /* - * TCP is all-good. - */ - return NF_ACCEPT; - } - - return NF_DROP; -} - - -/** - * @brief AF_INET4 Netfilter hook. Restricts LOCAL_OUT packets. - * See note above to filter policy. - * @param hooknum netfilter hook number - * @param skb skbuff - * @param in rx net_device - * @param out out net_device - * @param okfn ignored - * @return NF_ACCEPT if the packet is allowed through, NF_DROP otherwise - */ -static unsigned int -Inet4NfHook(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return PvsockNfHook(skb, 0); -} - -/** - * @brief AF_INET6 Netfilter hook. Restricts LOCAL_OUT packets. - * See note above to filter policy. - * @param hooknum netfilter hook number - * @param skb skbuff - * @param in rx net_device - * @param out out net_device - * @param okfn ignored - * @return NF_ACCEPT if the packet is allowed through, NF_DROP otherwise - */ -static unsigned int -Inet6NfHook(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - if (!ipv6_addr_v4mapped(&ipv6_hdr(skb)->daddr)) { - /* Not ipv4-mapped, so not a pvsock address. */ - return NF_ACCEPT; - } - - return PvsockNfHook(skb, 1); -} - - -static struct nf_hook_ops netfilterHooks[] = { - { - .hook = Inet4NfHook, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP_PRI_SECURITY - }, - { - .hook = Inet6NfHook, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_INET_LOCAL_OUT, - .priority = NF_IP6_PRI_SECURITY - } -}; - - -#if !defined(CONFIG_SYSFS) -#error "The pvTCP offload module requires sysfs!" -#endif - -/* - * State kobject, attributes and type. - */ - -typedef struct PvtcpStateKObj { - struct kobject kobj; - CommTranspInitArgs transpArgs; - unsigned int pvsockAddr; - int useNS; - int haveNS; -} PvtcpStateKObj; - - -typedef struct PvtcpStateKObjAttr { - struct attribute attr; - ssize_t (*show)(PvtcpStateKObj *stateKObj, char *buf); - ssize_t (*store)(PvtcpStateKObj *stateKObj, const char *buf, size_t count); -} PvtcpStateKObjAttr; - - -/** - * @brief Releases state a kobject. - * @param kobj (embedded) state kobject. - */ - -static void -StateKObjRelease(struct kobject *kobj) -{ - kfree(container_of(kobj, PvtcpStateKObj, kobj)); -} - - -/** - * @brief Sysfs show function for all pvtcp attributes. - * @param kobj (embedded) state kobject. - * @param attr pvtcp attribute to show. - * @param buf output buffer. - * @return number of bytes written or negative error code. - */ - -static ssize_t -StateKObjShow(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - PvtcpStateKObjAttr *stateAttr = container_of(attr, PvtcpStateKObjAttr, attr); - PvtcpStateKObj *stateKObj = container_of(kobj, PvtcpStateKObj, kobj); - - if (stateAttr->show) { - return stateAttr->show(stateKObj, buf); - } - - return -EIO; -} - - -/** - * @brief Sysfs store function for all pvtcp attributes. - * @param kobj (embedded) state kobject. - * @param attr pvtcp attribute to show. - * @param buf input buffer. - * @param count input buffer length. - * @return number of bytes consumed or negative error code. - */ - -static ssize_t -StateKObjStore(struct kobject *kobj, - struct attribute *attr, - const char *buf, - size_t count) -{ - PvtcpStateKObjAttr *stateAttr = container_of(attr, PvtcpStateKObjAttr, attr); - PvtcpStateKObj *stateKObj = container_of(kobj, PvtcpStateKObj, kobj); - - if (stateAttr->store) { - return stateAttr->store(stateKObj, buf, count); - } - - return -EIO; -} - - -static struct sysfs_ops StateKObjSysfsOps = { - .show = StateKObjShow, - .store = StateKObjStore -}; - - -/** - * @brief Show function for the comm_info pvtcp attribute. - * @param stateKObj state kobject. - * @param buf output buffer. - * @return number of bytes written or negative error code. - */ - -static ssize_t -StateKObjCommInfoShow(PvtcpStateKObj *stateKObj, - char *buf) -{ - unsigned int typeHash; - - /* - * In the offload module, the transport arguments' type field has been - * assigned the matching index in the versions array at probe time. - * Recover and print out the type hash. - */ - - typeHash = CommTransp_GetType(pvtcpVersions[stateKObj->transpArgs.type]); - - return snprintf(buf, PAGE_SIZE, "ID=%u,%u\nCAPACITY=%u\nTYPE=0x%0x\n", - stateKObj->transpArgs.id.d32[0], - stateKObj->transpArgs.id.d32[1], - stateKObj->transpArgs.capacity, - typeHash); -} - - -/** - * @brief Show function for the pvsock_addr pvtcp attribute. - * @param stateKObj state kobject. - * @param buf output buffer. - * @return number of bytes written or negative error code. - */ - -static ssize_t -StateKObjPvsockAddrShow(PvtcpStateKObj *stateKObj, - char *buf) -{ - union { - unsigned int raw; - unsigned char bytes[4]; - } addr; - - addr.raw = stateKObj->pvsockAddr; - return snprintf(buf, PAGE_SIZE, "%u.%u.%u.%u\n", - (unsigned int)addr.bytes[0], (unsigned int)addr.bytes[1], - (unsigned int)addr.bytes[2], (unsigned int)addr.bytes[3]); -} - - -/** - * @brief Show function for the use_ns pvtcp attribute. - * @param stateKObj state kobject. - * @param buf output buffer. - * @return number of bytes written or negative error code. - */ - -static ssize_t -StateKObjUseNSShow(PvtcpStateKObj *stateKObj, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", stateKObj->useNS); -} - - -/** - * @brief Store function for the use_ns pvtcp attribute. - * @param stateKObj state kobject. - * @param buf input buffer. - * @param count input buffer length. - * @return number of bytes consumed or negative error code. - */ - -static ssize_t -StateKObjUseNSStore(PvtcpStateKObj *stateKObj, - const char *buf, - size_t count) -{ - int rc = -EINVAL; - - /* coverity[secure_coding] */ - if (stateKObj->haveNS && (sscanf(buf, "%d", &stateKObj->useNS) == 1)) { - stateKObj->useNS = !!stateKObj->useNS; - rc = count; - } - - return rc; -} - - -static PvtcpStateKObjAttr stateKObjCommInfoAttr = - __ATTR(comm_info, 0444, StateKObjCommInfoShow, NULL); - -static PvtcpStateKObjAttr stateKObjPvsockAddrAttr = - __ATTR(pvsock_addr, 0444, StateKObjPvsockAddrShow, NULL); - -static PvtcpStateKObjAttr stateKObjUseNSAttr = - __ATTR(use_ns, 0644, StateKObjUseNSShow, StateKObjUseNSStore); - - -static struct attribute *stateKObjDefaultAttrs[] = { - &stateKObjCommInfoAttr.attr, - &stateKObjPvsockAddrAttr.attr, - &stateKObjUseNSAttr.attr, - NULL -}; - - -static struct kobj_type stateKType = { - .sysfs_ops = &StateKObjSysfsOps, - .release = StateKObjRelease, - .default_attrs = stateKObjDefaultAttrs -}; - - -/* - * Initialization of module entry and exit callbacks. - */ - -static int Init(void *args); -static void Exit(void); - -COMM_OS_MOD_INIT(Init, Exit); - - -/* - * AIO socket read buffers, stats and other global state. - */ - -static CommOSMutex globalLock; -static char perCpuBuf[NR_CPUS][PVTCP_SOCK_BUF_SIZE]; - -#define PVTCP_OFF_MAX_LB_ADDRS 255 -static unsigned int loopbackAddrs[PVTCP_OFF_MAX_LB_ADDRS] = { - 0xffffffff, // Network address always on, all ports allowed. - 0x7fffffff // Host address not yet on, all ports allowed. - // All the rest zeroed out. -}; - -static const unsigned int loopbackReserved = 0x00000001 << 31; - - -#define PvtcpTestLoopbackBit(entry, mask) \ - ((entry) & (mask)) - -#define PvtcpSetLoopbackBit(entry, mask) \ - ((entry) |= (mask)) - -#define PvtcpResetLoopbackBit(entry, mask) \ - ((entry) &= ~(mask)) - - -static inline int -PvtcpTestPortIndexBit(unsigned int addr, - unsigned int portIdx) -{ - return PvtcpTestLoopbackBit(loopbackAddrs[*((unsigned char *)&addr + 3)], - BIT(portIdx)); -} - - -static inline void -PvtcpSetPortIndexBit(unsigned int addr, - unsigned int portIdx) -{ - PvtcpSetLoopbackBit(loopbackAddrs[*((unsigned char *)&addr + 3)], - BIT(portIdx)); -} - - -static inline void -PvtcpResetPortIndexBit(unsigned int addr, - unsigned int portIdx) -{ - PvtcpResetLoopbackBit(loopbackAddrs[*((unsigned char *)&addr + 3)], - BIT(portIdx)); -} - - -unsigned int pvtcpLoopbackOffAddr; - -unsigned long long pvtcpOffDgramAllocations = 0; - -/* - * Destructor shim addresses and function pointer - */ - -extern void asmDestructorShim(struct sock*); - - -/* - * Functions. - */ - -/** - * @brief Release a socket, NULLing out the fake file field to avoid confusing - * Linux on the release path - * @param sock socket to release - */ -static void -SockReleaseWrapper(struct socket *sock) -{ - sock->file = NULL; - sock_release(sock); -} - -/** - * @brief Gets a new loopback address in the 127.238.0.255 network. - * Note that the first address, 127.238.0.1, is always the host's. - * @return new address or -1U if none is available. - */ - -static unsigned int -GetLoopbackAddr(void) -{ - static unsigned char addrTempl[4] = { 127, 238, 0, 0 }; - unsigned int rc = -1U; - unsigned int idx; - struct socket *sock; - - CommOS_MutexLock(&globalLock); - for (idx = 1; idx < PVTCP_OFF_MAX_LB_ADDRS; idx++) { - if (!PvtcpTestLoopbackBit(loopbackAddrs[idx], loopbackReserved)) { - addrTempl[3] = (unsigned char)idx; - memcpy(&rc, addrTempl, sizeof rc); - - /* Create a dgram socket to configure/bring-up the lo:N interface. */ - - if (!sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock)) { - int err; - struct sockaddr_in sin = { - .sin_family = AF_INET, - .sin_addr = { .s_addr = rc } - }; - struct ifreq ifr = { - .ifr_flags = IFF_UP - }; - - snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "lo:%u", idx); - memcpy(&ifr.ifr_addr, &sin, sizeof ifr.ifr_addr); - err = kernel_sock_ioctl(sock, SIOCSIFADDR, (unsigned long)&ifr); - sock_release(sock); - if (err) { - CommOS_Log(("%s: Could not set loopback address (ioctl)!\n", - __FUNCTION__)); - rc = -1U; - continue; /* Try next address. */ - } else { - PvtcpSetLoopbackBit(loopbackAddrs[idx], loopbackReserved); - CommOS_Debug(("%s: Allocated loopback address [%u.%u.%u.%u].\n", - __FUNCTION__, - addrTempl[0], addrTempl[1], - addrTempl[2], addrTempl[3])); - break; - } - } else { - CommOS_Log(("%s: Could not set loopback address (create)!\n", - __FUNCTION__)); - rc = -1U; - break; - } - } - } - if (idx == PVTCP_OFF_MAX_LB_ADDRS) { - CommOS_Log(("%s: loopback address range exceeded!\n", __FUNCTION__)); - } - - CommOS_MutexUnlock(&globalLock); - return rc; -} - - -/** - * @brief Puts back a loopback address in the 127.238.0.255 network. - * @param uaddr address to put back. - */ - -static void -PutLoopbackAddr(unsigned int uaddr) -{ - const unsigned char addrTempl[3] = { 127, 238, 0 }; - unsigned char addr[4]; - unsigned int idx; - struct socket *sock; - - memcpy(addr, &uaddr, sizeof uaddr); - if (memcmp(addrTempl, addr, sizeof addrTempl)) { - return; - } - - idx = addr[3]; - if ((idx == 0) || (idx >= PVTCP_OFF_MAX_LB_ADDRS)) { - return; - } - - CommOS_MutexLock(&globalLock); - if (!PvtcpTestLoopbackBit(loopbackAddrs[idx], loopbackReserved)) { - CommOS_Debug(("%s: loopback entry [%u] already freed.\n", - __FUNCTION__, idx)); - goto out; - } - - if (!sock_create_kern(AF_INET, SOCK_DGRAM, 0, &sock)) { - struct sockaddr_in sin = { - .sin_family = AF_INET, - .sin_addr = { .s_addr = uaddr } - }; - struct ifreq ifr = { - .ifr_flags = 0 - }; - - snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "lo:%u", idx); - memcpy(&ifr.ifr_addr, &sin, sizeof ifr.ifr_addr); - kernel_sock_ioctl(sock, SIOCSIFFLAGS, (unsigned long)&ifr); - sock_release(sock); - loopbackAddrs[idx] = 0; // Zero everything out. - CommOS_Debug(("%s: Deallocated loopback address [%u.%u.%u.%u].\n", - __FUNCTION__, addr[0], addr[1], addr[2], addr[3])); - } else { - CommOS_Log(("%s: Could not delete loopback address!\n", - __FUNCTION__)); - } - -out: - CommOS_MutexUnlock(&globalLock); -} - - -/** - * @brief Retrieves and retains the namespace associated with a channel. - * A server must be listening for requests to retrieve the pid of the - * process owning the net namespace for the passed context/vm id. - * Communication takes place over a datagram socket in the AF_UNIX family, - * bound to "/usr/lib/vmware/pvtcp/config/serv_addr". - * @param state channel state for which to retrieve the network namespace. - * @sideeffect If an associated namespace is found, it is retained and saved - * in the state object. - */ - -static void -GetNetNamespace(PvtcpState *state) -{ -#if defined(CONFIG_NET_NS) && !defined(PVTCP_NET_NS_DISABLE) - CommTranspInitArgs args; - pid_t pidn; - struct pid *pid; - struct task_struct *tsk; - struct nsproxy *nsproxy; - struct net *ns; - struct socket *sock; - struct sockaddr_un addr = { - .sun_family = AF_UNIX - }; - struct timeval timeout = { - .tv_sec = 3000, - .tv_usec = 0 - }; - const int passcred = 1; - char buf[64]; - struct kvec vec; - const char *sockname = "pvtcp-vpn"; /* abstract namespace for AF_UNIX/LOCAL sockets */ - const size_t socknamelen = strlen(sockname); - - struct msghdr msg = { - .msg_name = (struct sockaddr *)&addr, - .msg_namelen = 1 + offsetof(struct sockaddr_un, sun_path) + socknamelen - }; - - - if (!state) { - return; - } - - args = CommSvc_GetTranspInitArgs(state->channel); - ns = NULL; - pidn = 0; - - if (sock_create_kern(AF_UNIX, SOCK_DGRAM, 0, &sock)) { - CommOS_Debug(("%s: Can't create config socket!\n", __FUNCTION__)); - goto out; - } - if (kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, - (char *)&timeout, sizeof timeout)) { - sock_release(sock); - CommOS_Debug(("%s: Can't set timeout on config socket!\n", __FUNCTION__)); - goto out; - } - if (kernel_setsockopt(sock, SOL_SOCKET, SO_PASSCRED, - (char *)&passcred, sizeof passcred)) { - sock_release(sock); - CommOS_Debug(("%s: Can't set passcred on config socket!\n", - __FUNCTION__)); - goto out; - } - - /* - * Send the configuration request and receive the reply: - * - the request carries the VM/guest ID as used in the transport - * arguments used to create the channel. - * - the reply is expected to contain the pid of the namespace owner. - */ - - memset(buf, 0, sizeof buf); - snprintf(buf, sizeof buf, "%u\n", args.id.d32[0]); - buf[sizeof buf - 1] = '\0'; - vec.iov_base = buf; - vec.iov_len = strlen(buf); - - /* use anonymous name */ - addr.sun_path[0] = 0; - memcpy(addr.sun_path+1, sockname, socknamelen); - - if (kernel_sendmsg(sock, &msg, &vec, 1, vec.iov_len) <= 0) { - sock_release(sock); - CommOS_Debug(("%s: Could not send config request for vm [%u]!\n", - __FUNCTION__, args.id.d32[0])); - goto out; - } - - memset(buf, 0, sizeof buf); - vec.iov_base = buf; - vec.iov_len = sizeof buf; - if (kernel_recvmsg(sock, &msg, &vec, 1, vec.iov_len, 0) <= 0) { - CommOS_Debug(("%s: Could not receive config reply for vm [%u]!\n", - __FUNCTION__, args.id.d32[0])); - } else { - buf[sizeof buf - 1] = '\0'; - /* coverity[secure_coding] */ - sscanf(buf, "%d", &pidn); - } - sock_release(sock); - - if (!pidn) { - goto out; - } - - pid = find_get_pid(pidn); - if (pid) { - tsk = pid_task(pid, PIDTYPE_PID); - if (tsk) { - rcu_read_lock(); - nsproxy = task_nsproxy(tsk); - if (nsproxy && nsproxy->net_ns) { - ns = maybe_get_net(nsproxy->net_ns); - } - rcu_read_unlock(); - } - put_pid(pid); - } - -out: - if (!ns) { - CommOS_Debug(("%s: Not using a namespace for vm [%u].\n", - __FUNCTION__, args.id.d32[0])); - ns = &init_net; - } else { - CommOS_Debug(("%s: Found the net namespace for vm [%u].\n", - __FUNCTION__, args.id.d32[0])); - } -#else - void *ns = NULL; -#endif - - state->namespace = ns; -} - - -/** - * @brief Releases the network namespace associated with a channel state. - * @param namespace namespace to be released. - * @sideeffect If the namespace is not the initial one, it is released. - */ - -static void -PutNetNamespace(void *namespace) -{ -#if defined(CONFIG_NET_NS) && !defined(PVTCP_NET_NS_DISABLE) - if (namespace && (namespace != &init_net)) { - put_net((struct net *)namespace); - } -#endif -} - - -/** - * @brief Offload state constructor called when a channel is created. - * The function first calls the default state allocator; it then retrieves - * the n/w namespace associated with this client, retains it and stores it - * in the state object. Finally, it creates a sysfs node. - * @param[in,out] channel channel to initialize. - * @return pointer to a new state structure or NULL. - * @sideeffect Allocates memory. - */ - -static void * -StateAlloc(CommChannel channel) -{ - extern struct kset *Mvpkm_FindVMNamedKSet(int, const char *); - PvtcpState *state = NULL; - PvtcpIf *loopbackNetif = NULL; - PvtcpStateKObj *stateKObj = NULL; - struct kset *kset = NULL; - int rc; - CommTranspInitArgs transpArgs; - - transpArgs = CommSvc_GetTranspInitArgs(channel); - - /* - * The transport ID is assigned in an implementation-dependent way. - * (see lib/comm/comm_transp.h for transport type definitions.) - * However, the first 32 bits are expected to denote the guest/VM ID, - * while the last 32 bits are a resource handle within that VM. On MVP, - * transports map to queue pairs, which follow this convention. - */ - - kset = Mvpkm_FindVMNamedKSet((int)transpArgs.id.d32[0], "devices"); - if (!kset) { - CommOS_Debug(("%s: Could not find sysfs '.../vm/N/devices' kset!\n", - __FUNCTION__)); - goto error; - } - - state = PvtcpStateAlloc(channel); - if (!state) { - CommOS_Debug(("%s: Could not allocate state!\n", __FUNCTION__)); - goto error; - } - - /* coverity[leaked_storage] */ - stateKObj = kzalloc(sizeof *stateKObj, GFP_KERNEL); - if (!stateKObj) { - CommOS_Debug(("%s: Could not allocate state kobject!\n", __FUNCTION__)); - goto error; - } - - stateKObj->kobj.kset = kset; - /* coverity[leaked_storage] */ - rc = kobject_init_and_add(&stateKObj->kobj, &stateKType, NULL, "pvtcp"); - if (rc) { - CommOS_Debug(("%s: Could not add state kobject to parent kset [%d]!\n", - __FUNCTION__, rc)); - goto error; - } - - loopbackNetif = PvtcpStateFindIf(state, pvtcpIfLoopbackInet4); - BUG_ON(loopbackNetif == NULL); - loopbackNetif->conf.addr.in.s_addr = GetLoopbackAddr(); - if (loopbackNetif->conf.addr.in.s_addr == -1U) { - CommOS_Log(("%s: Could not allocate loopback address!\n", __FUNCTION__)); - goto error; - } - - GetNetNamespace(state); - - stateKObj->transpArgs = transpArgs; - stateKObj->pvsockAddr = loopbackNetif->conf.addr.in.s_addr; -#if defined(CONFIG_NET_NS) - stateKObj->haveNS = (state->namespace != &init_net); - stateKObj->useNS = stateKObj->haveNS; -#endif - state->extra = stateKObj; - - _cred.uid = _cred.gid = _cred.suid = _cred.sgid = - _cred.euid = _cred.egid = _cred.fsuid = _cred.fsgid = Mvpkm_vmwareUid; - - -out: - if (kset) { - kset_put(kset); - } - return state; - -error: - if (stateKObj) { - kobject_del(&stateKObj->kobj); - kobject_put(&stateKObj->kobj); - } - if (loopbackNetif && (loopbackNetif->conf.addr.in.s_addr != -1U)) { - PutLoopbackAddr(loopbackNetif->conf.addr.in.s_addr); - } - if (state) { - PvtcpStateFree(state); - state = NULL; - } - goto out; -} - - -/** - * @brief Offload state destructor called when a channel is closed. - * The function releases this client's n/w namespace and then calls the - * default state deallocator. - * @param arg pointer to state structure. - * @sideeffect Destroys all netifs and their sockets, deallocates memory. - */ - -static void -StateFree(void *arg) -{ - PvtcpState *state = arg; - PvtcpIf *loopbackNetif; - void *namespace; - - if (!state) { - return; - } - - if (state->extra) { - PvtcpStateKObj *stateKObj = state->extra; - - kobject_del(&stateKObj->kobj); - kobject_put(&stateKObj->kobj); - } - - namespace = state->namespace; - loopbackNetif = PvtcpStateFindIf(state, pvtcpIfLoopbackInet4); - BUG_ON(loopbackNetif == NULL); - PutLoopbackAddr(loopbackNetif->conf.addr.in.s_addr); - PvtcpStateFree(state); - PutNetNamespace(namespace); -} - - -/** - * @brief Releases socket. This function is called when the channel state - * owning the socket is closed. - * @param[in,out] pvsk PV socket to release. - * @sideeffect the socket eventually gets deallocated. - */ - -void -PvtcpReleaseSocket(PvtcpSock *pvsk) -{ - struct socket *sock = SkFromPvsk(pvsk)->sk_socket; - - SOCK_IN_LOCK(pvsk); - SOCK_OUT_LOCK(pvsk); - pvsk->peerSockSet = 0; - SockReleaseWrapper(sock); - SOCK_OUT_UNLOCK(pvsk); - SOCK_IN_UNLOCK(pvsk); - CommOS_Debug(("%s: [0x%p].\n", __FUNCTION__, pvsk)); -} - - -/** - * @brief Tests if the passed address is 127.238.0.1 or 127.0.0.1. - * @param pvsk socket to test. - * @param addr inet4 address to test. - * @return > 1: morph and propagate new address to caller, 1: just morph, - * 0: don't morph, < 0 (-EADDRNOTAVAIL): bad loopback. - */ - -static inline int -TestLoopbackInet4(PvtcpSock *pvsk, - unsigned int addr) -{ - if (!ipv4_is_loopback(addr)) { - return 0; - } - - if (addr != htonl(PVTCP_PVSOCK_ADDR)) { - if (addr != htonl(INADDR_LOOPBACK)) { - return -EADDRNOTAVAIL; - } - if (PvtcpHasSockNamespace(pvsk)) { - /* We don't morph normal 127.0.0.1 when NS present. */ - - return 0; - } - return 2; - } - - return 1; -} - - -/** - * @brief Tests if the passed address is 127.238.0.1 or 127.0.0.1 and the - * socket has a namespace. If yes, the address will be morphed into - * the actual loopback address, then a bind() is performed. - * Note that the function returns EADDRNOTAVAIL for any other loopbacks. - * @param pvsk socket to test. - * @param[in,out] addr inet4 address to test. - * @param port port to bind, or zero for any port. - * @return 1 if bind should be performed by caller, bind return code otherwise. - */ - -int -PvtcpTestAndBindLoopbackInet4(PvtcpSock *pvsk, - unsigned int *addr, - unsigned short port) -{ - int rc; - struct sockaddr_in sin; - unsigned int morphedAddr; - int propagate = 0; - - rc = TestLoopbackInet4(pvsk, *addr); - switch (rc) { - case 2: - propagate = 1; // Fall through. - case 1: - break; // Proceed with morphing. - case 0: - return 1; // Don't morph, let bind() be done by caller. - default: - return rc; - } - - if (pvsk->netif->conf.family == PVTCP_PF_LOOPBACK_INET4) { - /* The socket has already been morphed/bound. */ - - morphedAddr = pvsk->netif->conf.addr.in.s_addr; - rc = 0; - goto out; - } - - /* - * Move the socket to the initial namespace before binding it - * such that the loopback address is accessible to the host. - */ - - PvtcpSwitchSock(pvsk, PVTCP_SOCK_NAMESPACE_INITIAL); - PvtcpStateAddSocket(pvsk->channel, pvtcpIfLoopbackInet4, pvsk); - morphedAddr = pvsk->netif->conf.addr.in.s_addr; - memset(&sin, 0, sizeof sin); - sin.sin_family = AF_INET; - sin.sin_port = port; - sin.sin_addr.s_addr = morphedAddr; - - /* Bind to the channel loopback address. */ - - rc = kernel_bind(SkFromPvsk(pvsk)->sk_socket, - (struct sockaddr *)&sin, sizeof sin); - if (rc) { - PvtcpSwitchSock(pvsk, PVTCP_SOCK_NAMESPACE_CHANNEL); - PvtcpStateAddSocket(pvsk->channel, pvtcpIfUnbound, pvsk); - } else { - /* - * Bind succeeded on pvsock address. - * If this is a pvsock UDP reserved port, record it. - */ - - port = ntohs(port) - portRangeBase; - if ((SkFromPvsk(pvsk)->sk_socket->type == SOCK_DGRAM) && - (port < portRangeSize)) { - CommOS_MutexLock(&globalLock); - PvtcpSetPortIndexBit(pvsk->netif->conf.addr.in.s_addr, port); - CommOS_MutexUnlock(&globalLock); - } - - /* - * pvsock data usage shouldn't be counted as MVP external traffic. - */ - SkFromPvsk(pvsk)->sk_socket->file = NULL; - } - -out: - if (propagate) { - *addr = morphedAddr; - } - return rc; -} - - -/** - * @brief Tests if the passed address is IPV4-mapped 127.238.0.1 or 127.0.0.1, - * clean ::1, and whether the socket has a namespace. - * If needed, the address will be morphed into the actual loopback address, - * then a bind() is performed. - * Note that the function returns EADDRNOTAVAIL for any other loopbacks. - * @param pvsk socket to test. - * @param[in,out] addr0 first 64 bits of inet6 address to test. - * @param[in,out] addr1 last 64 bits of inet6 address to test. - * @param port port to bind, or zero for any port. - * @return 1 if bind should be performed by caller, bind return code otherwise. - */ - -int -PvtcpTestAndBindLoopbackInet6(PvtcpSock *pvsk, - unsigned long long *addr0, - unsigned long long *addr1, - unsigned short port) -{ - int rc; - struct sockaddr_in6 sin6; - union { - unsigned long long halves[2]; - struct in6_addr in6; - } in6Addr = { - .halves = { *addr0, *addr1 } - }; - int propagate = 0; - const int ipv6Only = 0; - - if (ipv6_addr_loopback(&in6Addr.in6)) { - if (PvtcpHasSockNamespace(pvsk)) { - return 1; - } - - /* Remember that we were passed '::1'. */ - - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_IPV6_LOOP, 1); - ipv6_addr_set_v4mapped(htonl(INADDR_LOOPBACK), &in6Addr.in6); - } - - if (!ipv6_addr_v4mapped(&in6Addr.in6)) { - /* If the address is not ipv4-mapped, stop testing. */ - - return 1; - } - - rc = TestLoopbackInet4(pvsk, in6Addr.in6.s6_addr32[3]); - switch (rc) { - case 2: - propagate = 1; // Fall through. - case 1: - break; // Proceed with morphing. - case 0: - return 1; // Don't morph, let bind() be done by caller. - default: - return rc; - } - - if (pvsk->netif->conf.family == PVTCP_PF_LOOPBACK_INET4) { - /* The socket has already been morphed/bound. */ - - ipv6_addr_set_v4mapped(pvsk->netif->conf.addr.in.s_addr, &in6Addr.in6); - rc = 0; - goto out; - } - - /* - * Move the socket to the initial namespace before binding it - * such that the loopback address is accessible to the host. - */ - - PvtcpSwitchSock(pvsk, PVTCP_SOCK_NAMESPACE_INITIAL); - PvtcpStateAddSocket(pvsk->channel, pvtcpIfLoopbackInet4, pvsk); - ipv6_addr_set_v4mapped(pvsk->netif->conf.addr.in.s_addr, &in6Addr.in6); - memset(&sin6, 0, sizeof sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = port; - sin6.sin6_addr = in6Addr.in6; - - /* - * Ensure we can use ipv4 mapped addresses and bind to the channel - * loopback address. - */ - - (void)kernel_setsockopt(SkFromPvsk(pvsk)->sk_socket, IPPROTO_IPV6, - IPV6_V6ONLY, (char *)&ipv6Only, sizeof ipv6Only); - rc = kernel_bind(SkFromPvsk(pvsk)->sk_socket, - (struct sockaddr *)&sin6, sizeof sin6); - if (rc) { - PvtcpSwitchSock(pvsk, PVTCP_SOCK_NAMESPACE_CHANNEL); - PvtcpStateAddSocket(pvsk->channel, pvtcpIfUnbound, pvsk); - } else { - /* - * Bind succeeded on pvsock address. - * If this is a pvsock UDP reserved port, record it. - */ - - port = ntohs(port) - portRangeBase; - if ((SkFromPvsk(pvsk)->sk_socket->type == SOCK_DGRAM) && - (port < portRangeSize)) { - CommOS_MutexLock(&globalLock); - PvtcpSetPortIndexBit(pvsk->netif->conf.addr.in.s_addr, port); - CommOS_MutexUnlock(&globalLock); - } - - /* - * pvsock data usage shouldn't be counted as MVP external traffic. - */ - SkFromPvsk(pvsk)->sk_socket->file = NULL; - } - -out: - if (propagate) { - *addr0 = in6Addr.halves[0]; - *addr1 = in6Addr.halves[1]; - } - return rc; -} - - -/** - * @brief Resets a 127.238.0.N address to 127.0.0.1. - * @param pvsk socket whose address needs resetting. - * @param[in,out] addr inet4 address to reset. - */ - -void -PvtcpResetLoopbackInet4(PvtcpSock *pvsk, - unsigned int *addr) -{ - if (!PvtcpHasSockNamespace(pvsk)) { - static const unsigned int pvsockAddr = htonl(PVTCP_PVSOCK_ADDR); - - if (!memcmp(&pvsockAddr, addr, 3) && memcmp(&pvsockAddr, addr, 4)) { - /* If it's a pvsock address but _not_ the host's, overwrite it. */ - - *addr = htonl(INADDR_LOOPBACK); - } - } -} - - -/** - * @brief Resets an IPV4-mapped ::ffff:127.238.0.N IPV6 address to loopback. - * @param pvsk socket whose address needs resetting. - * @param[in,out] in6 inet6 address to reset. - */ - -void -PvtcpResetLoopbackInet6(PvtcpSock *pvsk, - struct in6_addr *in6) -{ - if (!PvtcpHasSockNamespace(pvsk) && ipv6_addr_v4mapped(in6)) { - if (PvskTestFlag(pvsk, PVTCP_OFF_PVSKF_IPV6_LOOP)) { - /* If the original address came in as ::1, we reset as such. */ - - static const struct in6_addr in6Loopback = IN6ADDR_LOOPBACK_INIT; - - *in6 = in6Loopback; - } else { - PvtcpResetLoopbackInet4(pvsk, &in6->s6_addr32[3]); - } - } -} - - -/** - * @brief Called at module load time. It registers with the Comm runtime. - * @param args initialization arguments - * @return zero if successful, -1 otherwise - * @sideeffect Leaves the module loaded - */ - -static int -Init(void *args) -{ - int rc = -1; - -#if !defined(PVTCP_DISABLE_NETFILTER) - rc = nf_register_hooks(netfilterHooks, ARRAY_SIZE(netfilterHooks)); - if (rc) { - CommOS_Log(("%s: Could not register netfilter hooks!\n", __FUNCTION__)); - goto out; - } else { - CommOS_Debug(("%s: Registered netfilter hooks.\n", __FUNCTION__)); - } - hooksRegistered = 1; -#else - CommOS_Log(("%s: Netfilter hooks disabled.\n", __FUNCTION__)); -#endif - - CommOS_MutexInit(&globalLock); - CommOS_WriteAtomic(&PvtcpOutputAIOSection, 0); - PvtcpOffLargeDgramBufInit(); - - pvtcpImpl.owner = CommOS_ModuleSelf(); - pvtcpImpl.stateCtor = StateAlloc; - pvtcpImpl.stateDtor = StateFree; - if (CommSvc_RegisterImpl(&pvtcpImpl) == 0) { - rc = 0; - pvtcpLoopbackOffAddr = GetLoopbackAddr(); - if (pvtcpLoopbackOffAddr == -1U) { - CommOS_Log(("%s: Could not allocate offload loopback address!\n", - __FUNCTION__)); - rc = -1; - CommSvc_UnregisterImpl(&pvtcpImpl); - } - } - -out: - if (rc) { - if (hooksRegistered) { - nf_unregister_hooks(netfilterHooks, ARRAY_SIZE(netfilterHooks)); - } - } - return rc; -} - - -/** - * @brief Called at module unload time. It shuts down pvtcp. - * @sideeffect Total and utter destruction. - */ - -static void -Exit(void) -{ - PutLoopbackAddr(pvtcpLoopbackOffAddr); - CommSvc_UnregisterImpl(&pvtcpImpl); -#if !defined(PVTCP_DISABLE_NETFILTER) - if (hooksRegistered) { - nf_unregister_hooks(netfilterHooks, ARRAY_SIZE(netfilterHooks)); - CommOS_Debug(("%s: Netfilter hooks unregistered.\n", __FUNCTION__)); - } -#endif - CommOS_Log(("%s: Allocations of large datagrams: %llu.\n", - __FUNCTION__, pvtcpOffDgramAllocations)); -} - - -/* - * Socket callback interceptors. - */ - -/** - * @brief Callback called when socket is destroyed. - * @param[in,out] sk socket to cleanup - * @return 0 if socket memory is freed, < 0 otherwise (no-op) - * @sideeffect Send queue buffers are deallocated - */ - -int -DestructCB(struct sock *sk) -{ - PvtcpOffBuf *internalBuf; - PvtcpOffBuf *tmp; - PvtcpSock *pvsk = PvskFromSk(sk); - - if (!pvsk || - (SkFromPvsk(pvsk) != sk) || - (pvsk->destruct == asmDestructorShim)) { - /* Module put _not_ to be performed by asmDestructorShim. */ - - CommOS_Debug(("%s: pvsk / sk inconsistency. Ignored.\n", __FUNCTION__)); - return -1; - } - - CommOS_ListForEachSafe(&pvsk->queue, internalBuf, tmp, link) { - CommOS_ListDel(&internalBuf->link); - PvtcpBufFree(PvtcpOffBufFromInternal(internalBuf)); - } - if (pvsk->destruct) { - pvsk->destruct(sk); - } - - if (pvsk->rpcReply) { - CommOS_Kfree(pvsk->rpcReply); - } - CommOS_Kfree(pvsk); - - /* - * Module put is performed by asmDestructorShim. - */ - - return 0; -} - - -/** - * @brief Callback called when socket state changes occur. - * @param sk socket specified socket which changed state - * @sideeffect A writer task may be scheduled - */ - -static void -StateChangeCB(struct sock *sk) -{ - PvtcpSock *pvsk = PvskFromSk(sk); - - if (!pvsk || - (SkFromPvsk(pvsk) != sk) || - (pvsk->stateChange == StateChangeCB)) { - CommOS_Debug(("%s: pvsk / sk inconsistency. Ignored.\n", __FUNCTION__)); - return; - } - - /* - * The socket (spin) lock is held when this function is called. - */ - - CommOS_Debug(("%s: [0x%p] sk_state [%u] sk_err [%d] sk_err_soft [%d].\n", - __FUNCTION__, pvsk, sk->sk_state, - sk->sk_err, sk->sk_err_soft)); - if (pvsk->stateChange) { - pvsk->stateChange(sk); - } - if (sk->sk_state == TCP_ESTABLISHED) { - PvskSetOpFlag(pvsk, PVTCP_OP_CONNECT); - } - PvtcpSchedSock(pvsk); -} - - -/** - * @brief Callback called when an error is set on the socket. - * @param sk socket the error happened on - * @sideeffect A writer task may be scheduled - */ - -static void -ErrorReportCB(struct sock *sk) -{ - PvtcpSock *pvsk = PvskFromSk(sk); - - if (!pvsk || - (SkFromPvsk(pvsk) != sk) || - (pvsk->errorReport == ErrorReportCB)) { - CommOS_Debug(("%s: pvsk / sk inconsistency. Ignored\n", __FUNCTION__)); - return; - } - - /* - * The socket (spin) lock is held when this function is called. - * Interesting sk_err-s: - * ECONNRESET - tcp_disconnect(), tcp_reset() - * ECONNREFUSED - tcp_reset() - * EPIPE - tcp_reset() - * ETIMEDOUT - tcp_write_error() - * EHOSTUNREACH, etc. - tcp_v4_error()??, icmp errors - * etc. - __udp4_lib_err(), icmp errors - */ - - CommOS_Debug(("%s: [0x%p] sk_err [%d] sk_err_soft [%d].\n", - __FUNCTION__, pvsk, sk->sk_err, sk->sk_err_soft)); - if (pvsk->errorReport) { - pvsk->errorReport(sk); - } - pvsk->err = sk->sk_err; - PvtcpSchedSock(pvsk); -} - - -/** - * @brief Callback called when data is available to be read from a socket. - * @param sk socket in question - * @param bytes number of bytes to read - * @sideeffect A writer task is scheduled _iff_ the peer can safely - * receive. - */ - -static void -DataReadyCB(struct sock *sk, - int bytes) -{ - PvtcpSock *pvsk = PvskFromSk(sk); - - if (!pvsk || - (SkFromPvsk(pvsk) != sk) || - (pvsk->dataReady == DataReadyCB)) { - CommOS_Debug(("%s: pvsk / sk inconsistency. Ignored.\n", __FUNCTION__)); - return; - } - - /* - * The socket (spin) lock is held when this function is called. - */ - - if (pvsk->dataReady) { - pvsk->dataReady(sk, bytes); - } - if (sk->sk_state == TCP_LISTEN) { - CommOS_Debug(("%s: Listen socket ready to accept [0x%p].\n", - __FUNCTION__, pvsk)); - } - PvtcpSchedSock(pvsk); -} - - -/** - * @brief Callback called when writing is possible on a socket. - * @param sk socket in question - * @sideeffect An AIO thread is scheduled. - */ - -static void -WriteSpaceCB(struct sock *sk) -{ - PvtcpSock *pvsk = PvskFromSk(sk); - - if (!pvsk || - (SkFromPvsk(pvsk) != sk) || - (pvsk->writeSpace == WriteSpaceCB)) { - CommOS_Debug(("%s: pvsk / sk inconsistency. Ignored.\n", __FUNCTION__)); - return; - } - - /* - * The socket (spin) lock is held when this function is called. - */ - - if (pvsk->writeSpace) { - pvsk->writeSpace(sk); - } - PvtcpSchedSock(pvsk); -} - - -/** - * @brief Initializes a newly created socket for offload operations. - * @param[in,out] sock socket to initialize - * @param channel channel to update - * @param peerSock peer PV socket of this socket - * @param parentPvsk parent of this socket or NULL - * @return zero on success, error code otherwise - */ - -static int -SockAllocInit(struct socket *sock, - CommChannel channel, - unsigned long long peerSock, - PvtcpSock *parentPvsk) -{ - struct sock *sk; - PvtcpSock *pvsk; - int sndBuf = PVTCP_SOCK_RCVSIZE * 4; - - if (!sock || !channel || !peerSock) { - return -EINVAL; - } - - sk = sock->sk; - sk->sk_user_data = NULL; - - pvsk = CommOS_Kmalloc(sizeof *pvsk); - if (!pvsk) { - return -ENOMEM; - } - - if (PvtcpOffSockInit(pvsk, channel)) { - CommOS_Kfree(pvsk); - return -ENOMEM; - } - - /* - * PVTCP sockets should be billed against the vmware uid. - */ - sk->sk_socket->file = &_file; - - /* Set peer (pv) socket. */ - pvsk->peerSock = peerSock; - pvsk->peerSockSet = 1; - - /* Set up back pointer. */ - pvsk->sk = sk; - - /* Keep track of new socket. */ - if (PvtcpStateAddSocket(channel, pvtcpIfUnbound, pvsk) != 0) { - CommOS_Kfree(pvsk); - return -ENOMEM; - } - - /* - * Keep pvtcp around for at least the lifetime of this socket - */ - CommOS_ModuleGet(pvtcpImpl.owner); - - if (!parentPvsk) { - pvsk->destruct = sk->sk_destruct; - sk->sk_destruct = asmDestructorShim; - pvsk->stateChange = sk->sk_state_change; - sk->sk_state_change = StateChangeCB; - pvsk->errorReport = sk->sk_error_report; - sk->sk_error_report = ErrorReportCB; - pvsk->dataReady = sk->sk_data_ready; - sk->sk_data_ready = DataReadyCB; - pvsk->writeSpace = sk->sk_write_space; - sk->sk_write_space = WriteSpaceCB; - } else { - /* - * Copy the parent's saved callbacks. The parent pvsk is only passed - * when creating/initializing a socket after an 'accept'. - */ - - pvsk->destruct = parentPvsk->destruct; - sk->sk_destruct = asmDestructorShim; - pvsk->stateChange = parentPvsk->stateChange; - sk->sk_state_change = StateChangeCB; - pvsk->errorReport = parentPvsk->errorReport; - sk->sk_error_report = ErrorReportCB; - pvsk->dataReady = parentPvsk->dataReady; - sk->sk_data_ready = DataReadyCB; - pvsk->writeSpace = parentPvsk->writeSpace; - sk->sk_write_space = WriteSpaceCB; - - if (parentPvsk->netif->conf.family == PVTCP_PF_LOOPBACK_INET4) { - /* The parent socket was morphed/bound. */ - - PvtcpSwitchSock(pvsk, PVTCP_SOCK_NAMESPACE_INITIAL); - PvtcpStateAddSocket(pvsk->channel, pvtcpIfLoopbackInet4, pvsk); - } - } - - /* Install forward socket reference. */ - sk->sk_user_data = pvsk; - - /* - * Force the send buffer size high enough, such that we don't lose the - * just-a-bit-over-the-limit bytes. This is mainly needed for datagrams. - * Note that we always apply flow control between host and guest modules, - * according to the sizing model; so this is not artificially inflated. - */ - - kernel_setsockopt(sock, SOL_SOCKET, SO_SNDBUFFORCE, - (void *)&sndBuf, sizeof sndBuf); - - return 0; -} - - -/** - * @brief Allocates a pvsk socket for error reporting (create operation). - * @param err error code to report to PV side - * @param channel channel error socket belongs to - * @param peerSock peer PV socket of this socket - * @return error socket on success, NULL otherwise - */ - -static PvtcpSock * -SockAllocErrInit(int err, - CommChannel channel, - unsigned long long peerSock) -{ - PvtcpSock *pvsk; - - if (!channel || !peerSock) { - return NULL; - } - - pvsk = CommOS_Kmalloc(sizeof *pvsk); - if (!pvsk) { - return NULL; - } - - if (PvtcpOffSockInit(pvsk, channel)) { - CommOS_Kfree(pvsk); - return NULL; - } - - /* Set peer (pv) socket and error. */ - pvsk->peerSock = peerSock; - pvsk->peerSockSet = 1; - pvsk->err = err; - - /* Set up back pointer to NULL such that PvtcpPutSock deallocates it. */ - pvsk->sk = NULL; - return pvsk; -} - - -/* - * Offload operations. - */ - -/** - * @brief Creates an offload socket and schedules it for reply. - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled, which will send reply back. - */ - -void -PvtcpCreateOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - int rc; - struct socket *sock; - PvtcpSock *pvsk; - PvtcpState *state = (PvtcpState *)upperLayerState; - const int enable = 1; - - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - -#if defined(PVTCP_IPV6_DISABLE) - if (packet->data16 == AF_INET6) { - CommOS_Debug(("%s: AF_INET6 support is disabled.\n", __FUNCTION__)); - rc = -EAFNOSUPPORT; - } else -#endif - { - rc = sock_create_kern(packet->data16, packet->data32, - packet->data32ex, &sock); - } - - if (!rc) { - rc = SockAllocInit(sock, channel, packet->data64, NULL); - if (rc) { - SockReleaseWrapper(sock); - goto fail; - } - kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (void *)&enable, sizeof enable); - pvsk = PvskFromSk(sock->sk); - if (state->extra && - ((PvtcpStateKObj *)(state->extra))->useNS) { - PvtcpSwitchSock(pvsk, PVTCP_SOCK_NAMESPACE_CHANNEL); - } else { - PvtcpSwitchSock(pvsk, PVTCP_SOCK_NAMESPACE_INITIAL); - } - PvtcpStateAddSocket(pvsk->channel, pvtcpIfUnbound, pvsk); - PvskSetOpFlag(pvsk, PVTCP_OP_CREATE); - } else { - CommOS_Debug(("%s: Error creating offload socket: %d\n", - __FUNCTION__, rc)); - /* - * Pass -rc so we follow error conventions for other reply ops. - * The error code is fixed by the PV side so error codes are properly - * reported. - */ - pvsk = SockAllocErrInit(-rc, channel, packet->data64); - if (!pvsk) { - goto fail; - } - } - - PvtcpSchedSock(pvsk); - return; - -fail: - CommOS_Log(("%s: BOOG ** FAILED TO CREATE OFFLOAD SOCKET [%d] " - "_AND_ ERROR REPORTING SOCKET!\n" - " PV SIDE MAY BE LOCKED UP UNTIL CREATE RPC TIMES OUT!", - __FUNCTION__, rc)); -} - - -/** - * @brief Schedules an offload socket to be removed. - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled, which will send reply back and - * then release the socket. - */ - -void -PvtcpReleaseOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - struct sock *sk = SkFromPvsk(pvsk); - - /* - * Check if this is a pvsock datagram socket bound on a reserved port. - * If so, reset the bit such that filtering drops rogue packets. - */ - - if ((sk->sk_socket->type == SOCK_DGRAM) && - (pvsk->netif->conf.family == PVTCP_PF_LOOPBACK_INET4)) { - unsigned short port = 0; - - if (sk->sk_family == AF_INET) { - struct sockaddr_in sin = { .sin_family = AF_INET }; - int addrLen = sizeof sin; - - if(!kernel_getsockname(sk->sk_socket, - (struct sockaddr *)&sin, &addrLen)) { - port = sin.sin_port; - } - } else { /* AF_INET6 */ - struct sockaddr_in6 sin = { .sin6_family = AF_INET6 }; - int addrLen = sizeof sin; - - if(!kernel_getsockname(sk->sk_socket, - (struct sockaddr *)&sin, &addrLen)) { - port = sin.sin6_port; - } - } - - port = ntohs(port) - portRangeBase; - if (port < portRangeSize) { - CommOS_MutexLock(&globalLock); - PvtcpResetPortIndexBit(pvsk->netif->conf.addr.in.s_addr, port); - CommOS_MutexUnlock(&globalLock); - } - } - - /* - * - hold the socket before setting the 'release' flag and until after - * the call to PvtcpSchedSock(): if the socket had already been scheduled - * ReleaseAIO may run, find the flag set and release this socket while - * it's being unlocked here. - * - * - hold the dispatch lock until done to ensure that subsequent Ops for - * this socket see peerSockSet == 0. - */ - - PvtcpHoldSock(pvsk); - SOCK_STATE_LOCK(pvsk); - pvsk->peerSockSet = 0; - SOCK_STATE_UNLOCK(pvsk); - PvskSetOpFlag(pvsk, PVTCP_OP_RELEASE); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); - PVTCP_UNLOCK_DISP_DISCARD_VEC(); -} - - -/** - * @brief Binds an offload socket to a given address - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled, which will send reply back - */ - -void -PvtcpBindOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - struct sock *sk = SkFromPvsk(pvsk); - struct sockaddr *addr; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - int reuseAddr; - int addrLen; - int rc; - - PvtcpHoldSock(pvsk); - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - - /* - * The socket-level option SO_REUSEADDR is set in the common socket code, - * meaning that we cannot intercept it in the guest pvtcp implementation. - * In order to respect the setting, the guest would pass the current - * setting in 'bind' requests. - * If the guest requires 'reuse address' setting, the value is incremented - * such that we differentiate between: 0) not requested, 1) 'false' and - * 2) 'true'. - */ - - reuseAddr = COMM_OPF_GET_VAL(packet->flags); - if ((reuseAddr == 1) || (reuseAddr == 2)) { - /* Explicit request, so decrement the value. */ - - reuseAddr--; - kernel_setsockopt(sk->sk_socket, SOL_SOCKET, SO_REUSEADDR, - (void *)&reuseAddr, sizeof reuseAddr); - } - - if (sk->sk_family == AF_INET) { - memset(&sin, 0, sizeof sin); - sin.sin_family = AF_INET; - sin.sin_port = packet->data16; - sin.sin_addr.s_addr = (unsigned int)packet->data64ex; - addr = (struct sockaddr *)&sin; - addrLen = sizeof sin; - - rc = PvtcpTestAndBindLoopbackInet4(pvsk, &sin.sin_addr.s_addr, - sin.sin_port); - if (rc <= 0) { - /* Bind has already happened. */ - - pvsk->err = -rc; - goto out; - } - } else { /* AF_INET6 */ - memset(&sin6, 0, sizeof sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_port = packet->data16; - addr = (struct sockaddr *)&sin6; - addrLen = sizeof sin6; - - rc = PvtcpTestAndBindLoopbackInet6(pvsk, &packet->data64ex, - &packet->data64ex2, sin6.sin6_port); - if (rc <= 0) { - /* Bind has already happened. */ - - pvsk->err = -rc; - goto out; - } - PvtcpI6AddrUnpack(&sin6.sin6_addr.s6_addr32[0], - packet->data64ex, packet->data64ex2); - } - - /* coverity[check_return] */ - pvsk->err = -kernel_bind(sk->sk_socket, addr, addrLen); - -out: - PvskSetOpFlag(pvsk, PVTCP_OP_BIND); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); -} - - -/** - * @brief Sets a socket option. - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled, which will send reply back - */ -void -PvtcpSetSockOptOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - struct sock *sk = SkFromPvsk(pvsk); - struct socket *sock = sk->sk_socket; - unsigned int optlen = packet->len - sizeof *packet; - - PvtcpHoldSock(pvsk); - - if ((vecLen != 1) || (vec[0].iov_len != optlen) || (optlen < sizeof(int))) { - pvsk->rpcStatus = -EINVAL; - goto out; - } - - if (packet->data32 == SOL_TCP) { - /* - * The back-end implementation must always run in 'nodelay' mode. - * Consequently, we ignore, but we cache the TCP_NODELAY and TCP_CORK - * settings such that getsockopt() can return them as they were 'set'. - * Applications use these settings for performance; pvtcp does quite - * well if it's not interfered with. - */ - - int on; - - switch (packet->data32ex) { - case TCP_NODELAY: - memcpy(&on, vec[0].iov_base, sizeof on); - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_TCP_NODELAY, on); - pvsk->rpcStatus = 0; - goto out; - case TCP_CORK: - memcpy(&on, vec[0].iov_base, sizeof on); - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_TCP_CORK, on); - pvsk->rpcStatus = 0; - goto out; - } - } - - pvsk->rpcStatus = kernel_setsockopt(sock, - packet->data32, - packet->data32ex, - vec[0].iov_base, - optlen); - -out: - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - PvskSetOpFlag(pvsk, PVTCP_OP_SETSOCKOPT); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); -} - - -/** - * @brief Retrieves a socket option. - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled, which will send reply back - */ -void -PvtcpGetSockOptOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - struct sock *sk = SkFromPvsk(pvsk); - struct socket *sock = sk->sk_socket; - unsigned int optLen = (unsigned int)(packet->data64ex); - char *optBuf; - int rc = 0; - - PvtcpHoldSock(pvsk); - - if ((optLen < sizeof(int)) || (optLen > PVTCP_SOCK_SAFE_RCVSIZE)) { - pvsk->rpcStatus = -EINVAL; - goto out; - } - - optBuf = CommOS_Kmalloc(optLen); - if (!optBuf) { - pvsk->rpcStatus = -EINVAL; - goto out; - } - - if (packet->data32 == SOL_TCP) { - /* - * See comment in PvtcpSetSockOptOp() regarding special treatment for - * the TCP_NODELAY and TCP_CORK settings. - */ - - int on; - - switch (packet->data32ex) { - case TCP_NODELAY: - on = PvskTestFlag(pvsk, PVTCP_OFF_PVSKF_TCP_NODELAY); - optLen = sizeof on; - memcpy(optBuf, &on, optLen); - goto done; - case TCP_CORK: - on = PvskTestFlag(pvsk, PVTCP_OFF_PVSKF_TCP_CORK); - optLen = sizeof on; - memcpy(optBuf, &on, optLen); - goto done; - } - } - - rc = kernel_getsockopt(sock, packet->data32, - packet->data32ex, optBuf, &optLen); - -done: - if (!rc) { - pvsk->rpcReply = optBuf; - CommOS_MemBarrier(); - pvsk->rpcStatus = (int)optLen; - } else { - CommOS_Kfree(optBuf); - pvsk->rpcStatus = rc; - } - -out: - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - PvskSetOpFlag(pvsk, PVTCP_OP_GETSOCKOPT); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); -} - - -/** - * @brief Performs ioctl on offload socket. - * @param channel communication channel with offloader - * @param state state associated with this channel - * @param packet packet header received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - */ - -void -PvtcpIoctlOp(CommChannel channel, - void *state, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, state); - struct sock *sk = SkFromPvsk(pvsk); - struct socket *sock = sk->sk_socket; - - PvtcpHoldSock(pvsk); - - /* Not implemented yet. */ - - (void)sock; - pvsk->rpcStatus = -ENOIOCTLCMD; - - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - PvskSetOpFlag(pvsk, PVTCP_OP_IOCTL); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); -} - - -/** - * @brief Marks a socket for listening to incoming connections - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled, which will send reply back - */ - -void -PvtcpListenOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - struct sock *sk = SkFromPvsk(pvsk); - int backlog = (int)packet->data32; - - PvtcpHoldSock(pvsk); - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - - pvsk->err = -kernel_listen(sk->sk_socket, backlog); - PvskSetOpFlag(pvsk, PVTCP_OP_LISTEN); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); -} - - -/** - * @brief Accepts a connected socket - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled, which will send reply back. - */ - -void -PvtcpAcceptOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - int rc; - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - struct sock *sk = SkFromPvsk(pvsk); - struct socket *newsock = NULL; - - PvtcpHoldSock(pvsk); - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - - rc = kernel_accept(sk->sk_socket, &newsock, O_NONBLOCK); - if (rc == 0) { - rc = SockAllocInit(newsock, channel, packet->data64ex, pvsk); - if (rc) { - SockReleaseWrapper(newsock); - } - } - - if (rc == 0) { - struct sock *newsk = newsock->sk; - PvtcpSock *newpvsk = PvskFromSk(newsk); - - /* We temporarily use the state field to cache parent socket. */ - - newpvsk->state = (PvtcpState *)pvsk; - PvskSetOpFlag(newpvsk, PVTCP_OP_ACCEPT); - PvtcpSchedSock(newpvsk); - } else { - pvsk->err = -rc; - PvskSetOpFlag(pvsk, PVTCP_OP_ACCEPT); - PvtcpSchedSock(pvsk); - } - - PvtcpPutSock(pvsk); -} - - -/** - * @brief Connects an offload socket to given address - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect A writer task is scheduled, which will send reply back - */ - -void -PvtcpConnectOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - struct sock *sk = SkFromPvsk(pvsk); - struct sockaddr *addr; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - int addrLen; - int flags = 0; - int rc = 0; - int disconnect = 0; - - PvtcpHoldSock(pvsk); - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - - if (sk->sk_family == AF_INET) { - addr = (struct sockaddr *)&sin; - addrLen = sizeof sin; - memset(&sin, 0, sizeof sin); - sin.sin_port = packet->data16; - sin.sin_addr.s_addr = (unsigned int)packet->data64ex; - if (COMM_OPF_GET_VAL(packet->flags)) { - sin.sin_family = AF_UNSPEC; - disconnect = 1; - goto connect; - } - sin.sin_family = AF_INET; - PvtcpTestAndBindLoopbackInet4(pvsk, &sin.sin_addr.s_addr, 0); - } else { /* AF_INET6 */ - addr = (struct sockaddr *)&sin6; - addrLen = sizeof sin6; - memset(&sin6, 0, sizeof sin6); - sin6.sin6_port = packet->data16; - if (COMM_OPF_GET_VAL(packet->flags)) { - sin6.sin6_family = AF_UNSPEC; - PvtcpI6AddrUnpack(&sin6.sin6_addr.s6_addr32[0], - packet->data64ex, packet->data64ex2); - disconnect = 1; - goto connect; - } - sin6.sin6_family = AF_INET6; - PvtcpTestAndBindLoopbackInet6(pvsk, &packet->data64ex, - &packet->data64ex2, 0); - PvtcpI6AddrUnpack(&sin6.sin6_addr.s6_addr32[0], - packet->data64ex, packet->data64ex2); - } - -connect: - rc = kernel_connect(sk->sk_socket, addr, addrLen, flags | O_NONBLOCK); - - /* - * For datagram sockets, ErrorReportCB is not called, so we need to - * explicitly set the pvsk error to be returned back to the guest. - * This should not be used on SOCK_STREAM sockets. You have been - * warned. - */ - - if (rc && (sk->sk_socket->type == SOCK_DGRAM)) { - pvsk->err = -rc; - } - - /* - * Quite likely, stream actual connect requests will set err to EINPROGRESS. - * That's fine, error_report will trigger an AIO/flow-op reply. When the - * connection is established, state_change schedules an AIO/connect reply. - * Record whether the request was a disconnect. - */ - - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_DISCONNECT, disconnect); - PvskSetOpFlag(pvsk, PVTCP_OP_CONNECT); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); -} - - -/** - * @brief Initiates socket shutdown on an offload socket - * @param channel communication channel with offloader - * @param upperLayerState state associated with this channel - * @param packet first packet received in reply - * @param vec payload buffer descriptors - * @param vecLen payload buffer descriptor count - * @sideeffect Socket queue will be drained and socket shutdown performed. - */ - -void -PvtcpShutdownOp(CommChannel channel, - void *upperLayerState, - CommPacket *packet, - struct kvec *vec, - unsigned int vecLen) -{ - PvtcpSock *pvsk = PvtcpGetPvskOrReturn(packet->data64, upperLayerState); - int how = (int)packet->data32; - - PvtcpHoldSock(pvsk); - if ((how == SHUT_RD) || (how == SHUT_RDWR)) { - kernel_sock_shutdown(SkFromPvsk(pvsk)->sk_socket, SHUT_RD); - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_SHUT_RD, 1); - } - if ((how == SHUT_WR) || (how == SHUT_RDWR)) { - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_SHUT_WR, 1); - } - PVTCP_UNLOCK_DISP_DISCARD_VEC(); - PvtcpSchedSock(pvsk); - PvtcpPutSock(pvsk); -} - - -/* - * AIO functions called from the main AIO processing function. - * Most of these functions complete processing initiated by the corresponding - * offload operations above. - */ - -/** - * @brief Processes socket release in an AIO thread. This function is - * called with the socket 'in' lock taken. - * @param[in,out] pvsk socket to release. - * @sideeffect the socket will be released upon return from this function. - */ - -static inline void -ReleaseAIO(PvtcpSock *pvsk) -{ - struct sock *sk = SkFromPvsk(pvsk); - struct socket *sock = sk->sk_socket; - CommPacket packet = { - .len = sizeof packet, - .flags = 0, - .opCode = PVTCP_OP_RELEASE, - .data64 = pvsk->peerSock, - .data64ex = PvtcpGetHandle(pvsk) - }; - unsigned long long timeout = COMM_MAX_TO; - - SOCK_OUT_LOCK(pvsk); - CommSvc_Write(pvsk->channel, &packet, &timeout); -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Sent 'Release' [0x%p] -> 0x%0x] reply.\n", - __FUNCTION__, pvsk, (unsigned)(pvsk->peerSock))); -#endif - /* - * 'sk' goes away in the final ProcessAIO::sock_put() - */ - SockReleaseWrapper(sock); - SOCK_OUT_UNLOCK(pvsk); - - PvtcpStateRemoveSocket(pvsk->channel, pvsk); -} - - -/** - * @brief Processes socket create reply in an AIO thread. This function is - * called with the socket 'in' lock taken. - * @param[in,out] pvsk newly created socket to send ack for. - */ - -static inline void -CreateAIO(PvtcpSock *pvsk) -{ - struct sock *sk; - struct socket *sock; - CommPacket packet = { - .len = sizeof packet, - .flags = 0, - .opCode = PVTCP_OP_CREATE, - .data64 = pvsk->peerSock, - }; - unsigned long long timeout = COMM_MAX_TO; - int rc; - - sk = SkFromPvsk(pvsk); - if (!sk) { - /* - * This is a create-error socket. The error reply has been sent out - * already, by PvtcpFlowAIO(). This is a paranoid safety measure, as - * PVTCP_OP_CREATE OpFlag should not have been set. - */ - - return; - } - - sock = sk->sk_socket; - packet.data64ex = PvtcpGetHandle(pvsk); - - rc = CommSvc_Write(pvsk->channel, &packet, &timeout); - if (rc != packet.len) { - /* We mustn't leak it if PV can't get a hold of it. */ - - PvtcpStateRemoveSocket(pvsk->channel, pvsk); - SockReleaseWrapper(sock); - CommOS_Log(("%s: BOOG -- Couldn't send 'Create' reply [0x%p]!\n", - __FUNCTION__, sk)); - } else { -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Sent 'Create' [0x%p] reply [%d].\n", - __FUNCTION__, pvsk, rc)); -#endif - } -} - - -/** - * @brief Processes socket bind in an AIO thread. This function is - * called with the socket 'in' lock taken. - * @param[in,out] pvsk socket being bound. - */ - -static inline void -BindAIO(PvtcpSock *pvsk) -{ - struct sock *sk = SkFromPvsk(pvsk); - struct socket *sock = sk->sk_socket; - CommPacket packet = { - .len = sizeof packet, - .flags = 0, - .opCode = PVTCP_OP_BIND, - .data64 = pvsk->peerSock - }; - unsigned long long timeout = COMM_MAX_TO; - int rc; - - if (pvsk->peerSockSet) { - if (sk->sk_family == AF_INET) { - struct sockaddr_in sin = { .sin_family = AF_INET }; - int addrLen = sizeof sin; - - rc = kernel_getsockname(sock, (struct sockaddr *)&sin, &addrLen); - if (rc == 0) { - packet.data16 = sin.sin_port; - PvtcpResetLoopbackInet4(pvsk, &sin.sin_addr.s_addr); - packet.data64ex = (unsigned long long)sin.sin_addr.s_addr; - } - } else { /* AF_INET6 */ - struct sockaddr_in6 sin = { .sin6_family = AF_INET6 }; - int addrLen = sizeof sin; - - rc = kernel_getsockname(sock, (struct sockaddr *)&sin, &addrLen); - if (rc == 0) { - packet.data16 = sin.sin6_port; - PvtcpResetLoopbackInet6(pvsk, &sin.sin6_addr); - PvtcpI6AddrPack(&sin.sin6_addr.s6_addr32[0], - &packet.data64ex, &packet.data64ex2); - } - } - - if (rc) { - COMM_OPF_SET_ERR(packet.flags); - packet.data32ex = (unsigned int)(-rc); - packet.opCode = PVTCP_OP_FLOW; - } - CommSvc_Write(pvsk->channel, &packet, &timeout); -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Sent 'Bind' [0x%p, %d] reply.\n", - __FUNCTION__, pvsk, rc)); -#endif - } -} - - -/** - * @brief Sends result of setsockopt back to guest. - * called with the socket 'in' lock taken. - * @param[in,out] pvsk socket that was modified. - */ - -static inline void -SetSockOptAIO(PvtcpSock *pvsk) -{ - CommPacket packet; - unsigned long long timeout; - - packet.len = sizeof packet; - packet.flags = 0; - packet.opCode = PVTCP_OP_SETSOCKOPT; - packet.data64 = pvsk->peerSock; - packet.data32 = (unsigned int)(pvsk->rpcStatus); - timeout = COMM_MAX_TO; - CommSvc_Write(pvsk->channel, &packet, &timeout); - pvsk->rpcStatus = 0; -} - - -/** - * @brief Sends result of getsockopt back to guest. - * called with the socket 'in' lock taken. - * @param[in,out] pvsk socket that was modified. - */ - -static inline void -GetSockOptAIO(PvtcpSock *pvsk) -{ - CommPacket packet = { - .opCode = PVTCP_OP_GETSOCKOPT, - .flags = 0 - }; - unsigned long long timeout = COMM_MAX_TO; - - struct kvec vec[1]; - struct kvec *inVec = vec; - unsigned int vecLen = 1; - unsigned int iovOffset = 0; - - if (pvsk->rpcStatus > 0) { - packet.len = sizeof packet + pvsk->rpcStatus; - vec[0].iov_base = pvsk->rpcReply; - vec[0].iov_len = pvsk->rpcStatus; - } else { - vecLen = 0; - } - - packet.data64 = pvsk->peerSock; - packet.data32 = pvsk->rpcStatus; - - CommSvc_WriteVec(pvsk->channel, &packet, &inVec, &vecLen, - &timeout, &iovOffset); - - if (pvsk->rpcReply) { - CommOS_Kfree(pvsk->rpcReply); - pvsk->rpcReply = NULL; - } - pvsk->rpcStatus = 0; -} - - -/** - * @brief Sends result of ioctl back to guest. - * called with the socket 'in' lock taken. - * @param[in,out] pvsk socket that was modified. - */ - -static inline void -IoctlAIO(PvtcpSock *pvsk) -{ - CommPacket packet = { - .len = sizeof packet, - .opCode = PVTCP_OP_IOCTL, - .flags = 0 - }; - unsigned long long timeout = COMM_MAX_TO; - - packet.data64 = pvsk->peerSock; - packet.data32 = pvsk->rpcStatus; - CommSvc_Write(pvsk->channel, &packet, &timeout); - pvsk->rpcStatus = 0; -} - - -/** - * @brief Processes socket listen reply in an AIO thread. This function is - * called with the socket 'in' lock taken. - * @param[in,out] pvsk socket being put in listen mode. - */ - -static inline void -ListenAIO(PvtcpSock *pvsk) -{ - struct sock *sk = SkFromPvsk(pvsk); - CommPacket packet = { - .len = sizeof packet, - .flags = 0, - .opCode = PVTCP_OP_LISTEN, - .data64 = pvsk->peerSock - }; - unsigned long long timeout = COMM_MAX_TO; - - if (pvsk->peerSockSet) { - if (sk->sk_state != TCP_LISTEN) { - COMM_OPF_SET_ERR(packet.flags); - packet.data32ex = (unsigned int)pvsk->err; - packet.opCode = PVTCP_OP_FLOW; - } - - CommSvc_Write(pvsk->channel, &packet, &timeout); -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Sent 'Listen' [0x%p] reply.\n", __FUNCTION__, pvsk)); -#endif - } -} - - -/** - * @brief Processes socket accept reply in an AIO thread. This function is - * called with the socket 'in' lock taken. - * @param[in,out] pvsk new socket or socket to accept on (see PvtcpAcceptOp). - */ - -static inline void -AcceptAIO(PvtcpSock *pvsk) -{ - struct sock *sk = SkFromPvsk(pvsk); - struct socket *sock = sk->sk_socket; - CommPacket packet = { - .len = sizeof packet, - .flags = 0, - .opCode = PVTCP_OP_ACCEPT - }; - unsigned long long timeout = COMM_MAX_TO; - const int enable = 1; - int rc; - - if (pvsk->peerSockSet) { - unsigned long long payloadSocks[2] = { 0, 0 }; - struct kvec payloadVec[] = { - { .iov_base = &payloadSocks, .iov_len = sizeof payloadSocks } - }; - struct kvec *payload = payloadVec; - unsigned int payloadLen = 1; - unsigned int iovOffset = 0; - - packet.len = sizeof packet + sizeof payloadSocks; - - /* - * accept() succeeded, so this is the child socket; its state field - * was temporarily changed to hold the parent/accepting socket. - * The newly accepted socket and its peer need to be put in a - * payload since we use up all available header fields with - * addressing information. Finally, the state field is restored. - */ - - packet.data64 = ((PvtcpSock *)pvsk->state)->peerSock; - pvsk->state = CommSvc_GetState(pvsk->channel); - - payloadSocks[0] = pvsk->peerSock; - payloadSocks[1] = PvtcpGetHandle(pvsk); - - rc = 0; - if (sk->sk_family == AF_INET) { - struct sockaddr_in sin = { .sin_family = AF_INET }; - int addrLen = sizeof sin; - - rc = kernel_getpeername(sock, (struct sockaddr *)&sin, &addrLen); - if (rc == 0) { - packet.data16 = sin.sin_port; - PvtcpResetLoopbackInet4(pvsk, &sin.sin_addr.s_addr); - packet.data64ex = (unsigned long long)sin.sin_addr.s_addr; - } - } else { /* AF_INET6 */ - struct sockaddr_in6 sin = { .sin6_family = AF_INET6 }; - int addrLen = sizeof sin; - - rc = kernel_getpeername(sock, (struct sockaddr *)&sin, &addrLen); - if (rc == 0) { - packet.data16 = sin.sin6_port; - PvtcpResetLoopbackInet6(pvsk, &sin.sin6_addr); - PvtcpI6AddrPack(&sin.sin6_addr.s6_addr32[0], - &packet.data64ex, &packet.data64ex2); - } - } - - if (rc == 0) { - kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, - (void *)&enable, sizeof enable); - kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - (void *)&enable, sizeof enable); - kernel_setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, - (void *)&enable, sizeof enable); - } else { - PvtcpStateRemoveSocket(pvsk->channel, pvsk); - SockReleaseWrapper(sock); - COMM_OPF_SET_ERR(packet.flags); - packet.data32ex = (unsigned int)ECONNABORTED; - packet.len = sizeof packet; - packet.opCode = PVTCP_OP_FLOW; - } - - rc = CommSvc_WriteVec(pvsk->channel, &packet, - &payload, &payloadLen, &timeout, &iovOffset); - if ((rc != packet.len) && !COMM_OPF_TEST_ERR(packet.flags)) { - /* Mustn't leak the new socket if PV can't get a hold of it. */ - - PvtcpStateRemoveSocket(pvsk->channel, pvsk); - SockReleaseWrapper(sock); - } -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Sent 'Accept' [0x%p] reply.\n", __FUNCTION__, pvsk)); -#endif - } -} - - -/** - * @brief Processes socket connect in an AIO thread. This function is - * called with the socket 'in' lock taken. - * @param[in,out] pvsk socket being connected. - */ - -static inline void -ConnectAIO(PvtcpSock *pvsk) -{ - struct sock *sk = SkFromPvsk(pvsk); - struct socket *sock = sk->sk_socket; - CommPacket packet = { - .len = sizeof packet, - .flags = 0, - .opCode = PVTCP_OP_CONNECT, - .data64 = pvsk->peerSock - }; - unsigned long long timeout = COMM_MAX_TO; - const int enable = 1; - int rc; - - if (!pvsk->peerSockSet || - (!PvskTestFlag(pvsk, PVTCP_OFF_PVSKF_DISCONNECT) && - (sk->sk_state != TCP_ESTABLISHED))) { - return; - } - - if (PvskTestFlag(pvsk, PVTCP_OFF_PVSKF_DISCONNECT)) { - COMM_OPF_SET_VAL(packet.flags, 1); - PvskSetFlag(pvsk, PVTCP_OFF_PVSKF_DISCONNECT, 0); - } else if (sk->sk_state == TCP_ESTABLISHED) { - if (sk->sk_family == AF_INET) { - struct sockaddr_in sin = { .sin_family = AF_INET }; - int addrLen = sizeof sin; - - rc = kernel_getsockname(sock, (struct sockaddr *)&sin, &addrLen); - if (rc == 0) { - packet.data16 = sin.sin_port; - PvtcpResetLoopbackInet4(pvsk, &sin.sin_addr.s_addr); - packet.data64ex = (unsigned long long)sin.sin_addr.s_addr; - } - } else { /* AF_INET6 */ - struct sockaddr_in6 sin = { .sin6_family = AF_INET6 }; - int addrLen = sizeof sin; - - rc = kernel_getsockname(sock, (struct sockaddr *)&sin, &addrLen); - if (rc == 0) { - packet.data16 = sin.sin6_port; - PvtcpResetLoopbackInet6(pvsk, &sin.sin6_addr); - PvtcpI6AddrPack(&sin.sin6_addr.s6_addr32[0], - &packet.data64ex, &packet.data64ex2); - } - } - - if (rc == 0) { - kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, - (void *)&enable, sizeof enable); - kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - (void *)&enable, sizeof enable); - kernel_setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, - (void *)&enable, sizeof enable); - } else { - COMM_OPF_SET_ERR(packet.flags); - packet.data32ex = ECONNABORTED; - packet.opCode = PVTCP_OP_FLOW; - } - } - - CommSvc_Write(pvsk->channel, &packet, &timeout); -#if defined(PVTCP_FULL_DEBUG) - CommOS_Debug(("%s: Sent 'Connect' [0x%p] reply.\n", __FUNCTION__, pvsk)); -#endif -} - - -/** - * @brief Server side main asynchronous processing function. It writes to - * socket queued output buffers, it reads from socket and outputs to PV; it - * also completes operation processing and sends applicable replies to PV. - * Finally, processes error reporting and delta size acks. - * @param arg socket work item. - */ - -void -PvtcpProcessAIO(CommOSWork *arg) -{ - PvtcpSock *pvsk = container_of(arg, PvtcpSock, work); - struct sock *sk = SkFromPvsk(pvsk); - - if (!SOCK_OUT_TRYLOCK(pvsk)) { - /* - * Queued output processing. If trylock failed, we don't retry. - * There are only two reasons for not being able to take the lock: - * - IoOp() has it -- when done, it reschedules us if we're not running. - * - OutputAIO() is already running on another core. - */ - - if (sk && sk->sk_socket) { - PvtcpOutputAIO(pvsk); - } - SOCK_OUT_UNLOCK(pvsk); - } - - /* All other processing needs the socket IN lock. */ - - if (!SOCK_IN_TRYLOCK(pvsk)) { - - if (sk && sk->sk_socket) { - int err; - - /* Input processing. */ - - /* - * Workqueue handlers are pinned to a CPU core and therefore not - * migratable. No need to disable preemption. - */ - err = PvtcpInputAIO(pvsk, perCpuBuf[smp_processor_id()]); - - /* Error and ack notifications. */ - - PvtcpFlowAIO(pvsk, err); - - if (!pvsk->opFlags) { - /* No other operations need to be completed. */ - - goto doneInUnlock; - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_RELEASE)) { - PvskResetOpFlag(pvsk, PVTCP_OP_RELEASE); - ReleaseAIO(pvsk); - - /* All possible in-flight operations must be dropped. */ - goto doneInUnlock; - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_CREATE)) { - /* No state locking required. */ - - PvskResetOpFlag(pvsk, PVTCP_OP_CREATE); - CreateAIO(pvsk); - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_BIND)) { - PvskResetOpFlag(pvsk, PVTCP_OP_BIND); - BindAIO(pvsk); - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_SETSOCKOPT)) { - PvskResetOpFlag(pvsk, PVTCP_OP_SETSOCKOPT); - SetSockOptAIO(pvsk); - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_GETSOCKOPT)) { - PvskResetOpFlag(pvsk, PVTCP_OP_GETSOCKOPT); - GetSockOptAIO(pvsk); - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_IOCTL)) { - PvskResetOpFlag(pvsk, PVTCP_OP_IOCTL); - IoctlAIO(pvsk); - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_LISTEN)) { - PvskResetOpFlag(pvsk, PVTCP_OP_LISTEN); - ListenAIO(pvsk); - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_ACCEPT)) { - PvskResetOpFlag(pvsk, PVTCP_OP_ACCEPT); - AcceptAIO(pvsk); - } - - if (PvskTestOpFlag(pvsk, PVTCP_OP_CONNECT)) { - PvskResetOpFlag(pvsk, PVTCP_OP_CONNECT); - ConnectAIO(pvsk); - } - -doneInUnlock: - SOCK_IN_UNLOCK(pvsk); - } else { - /* - * Special case for error sockets which don't have a sk. - * Note that this socket was created by SockAllocErrInit() and so - * no 'real' socket sits atop it and is not present on any state - * netif list. The socket has a refcnt of one and it will get - * deallocated by the PvtcpPutSock() call below, so we don't need - * to unlock it. - */ - - PvtcpFlowAIO(pvsk, -ENETDOWN); - } - } else { - if ((pvsk->peerSockSet || PvskTestOpFlag(pvsk, PVTCP_OP_RELEASE)) && - sk && sk->sk_socket) { - PvtcpSchedSock(pvsk); - } - } - - PvtcpPutSock(pvsk); -} diff --git a/arch/arm/mvp/pvtcpkm/pvtcp_off_linux.h b/arch/arm/mvp/pvtcpkm/pvtcp_off_linux.h deleted file mode 100644 index 34992da..0000000 --- a/arch/arm/mvp/pvtcpkm/pvtcp_off_linux.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief Linux Offload definitions. - * This file is only meant to be included via pvtcp_off.h. - */ - -#ifndef _PVTCP_OFF_LINUX_H_ -#define _PVTCP_OFF_LINUX_H_ - -#include <linux/socket.h> -#include <net/sock.h> -#include <net/tcp_states.h> -#include <net/tcp.h> -#include <linux/in.h> -#include <linux/in6.h> -#include <linux/skbuff.h> -#include <linux/random.h> -#include <linux/fs.h> -#include <linux/cred.h> - - -typedef struct PvtcpSock { - struct sock *sk; - PVTCP_SOCK_COMMON_FIELDS; - PVTCP_OFF_SOCK_COMMON_FIELDS; - void (*destruct)(struct sock *sk); - void (*stateChange)(struct sock *sk); - void (*dataReady)(struct sock *sk, int bytes); - void (*writeSpace)(struct sock *sk); - void (*errorReport)(struct sock *sk); -} PvtcpSock; - - -typedef enum PvtcpSockNamespace { - PVTCP_SOCK_NAMESPACE_INITIAL, - PVTCP_SOCK_NAMESPACE_CHANNEL -} PvtcpSockNamespace; - - -/* Number of large datagram allocations. */ -extern unsigned long long pvtcpOffDgramAllocations; - -/* Inet4 loopback addresses. */ -extern unsigned int pvtcpLoopbackOffAddr; - -/* Get the 'struct sock' from a PvtcpSock. */ -#define SkFromPvsk(pvsk) ((pvsk)->sk) - -/* Get the PvtcpSock from a 'struct sock'. */ -#define PvskFromSk(sk) ((PvtcpSock *)(sk)->sk_user_data) - -int -PvtcpTestAndBindLoopbackInet4(PvtcpSock *pvsk, - unsigned int *addr, - unsigned short port); -int -PvtcpTestAndBindLoopbackInet6(PvtcpSock *pvsk, - unsigned long long *addr0, - unsigned long long *addr1, - unsigned short port); - -void PvtcpResetLoopbackInet4(PvtcpSock *pvsk, unsigned int *addr); -void PvtcpResetLoopbackInet6(PvtcpSock *pvsk, struct in6_addr *in6); - -void PvtcpFlowAIO(PvtcpSock *pvsk, int eof); -void PvtcpOutputAIO(PvtcpSock *pvsk); -int PvtcpInputAIO(PvtcpSock *pvsk, void *perCpuBuf); - - -/** - * @brief Switches a socket to the channel, or the initial name space. - * @param pvsk socket to switch. - * @param ns which namespace to switch to. - */ - -static inline void -PvtcpSwitchSock(PvtcpSock *pvsk, - PvtcpSockNamespace ns) -{ -#if defined(CONFIG_NET_NS) && !defined(PVTCP_NET_NS_DISABLE) - struct sock *sk; - struct net *prevNet; - - if (!pvsk) { - return; - } - sk = SkFromPvsk(pvsk); - if (!sk) { - /* If this is a phony, create fail reporting pvsk, just return. */ - - return; - } - - prevNet = sock_net(sk); - switch (ns) { - case PVTCP_SOCK_NAMESPACE_INITIAL: - sock_net_set(sk, get_net(&init_net)); - break; - case PVTCP_SOCK_NAMESPACE_CHANNEL: - sock_net_set(sk, get_net(pvsk->state->namespace)); - break; - } - put_net(prevNet); -#endif -} - - -/** - * @brief Tests whether a socket has an explicit namespace. - * @param pvsk socket to test. - * @return 1 if the socket has a namespace, 0 otherwise. - */ - -static inline int -PvtcpHasSockNamespace(PvtcpSock *pvsk) -{ -#if defined(CONFIG_NET_NS) && !defined(PVTCP_NET_NS_DISABLE) - struct sock *sk; - int rc = 0; - - if (!pvsk) { - return rc; - } - sk = SkFromPvsk(pvsk); - if (!sk) { - /* If this is a phony, create fail reporting pvsk, just return 0. */ - - return rc; - } - - rc = (sock_net(sk) != &init_net); - return rc; -#else - return 0; -#endif -} - - -/** - * @brief Retains the pvsock's underlying socket. - * @param pvsk socket to retain. - */ - -static inline void -PvtcpHoldSock(PvtcpSock *pvsk) -{ - struct sock *sk = SkFromPvsk(pvsk); - - if (likely(sk)) { - sock_hold(sk); - } -} - - -/** - * @brief Releases a hold on the pvsock's underlying socket. If the underlying - * socket is NULL, this is an error socket and we deallocate it. - * @param pvsk socket to release hold on. - */ - -static inline void -PvtcpPutSock(PvtcpSock *pvsk) -{ - struct sock *sk = SkFromPvsk(pvsk); - - if (likely(sk)) { - sock_put(sk); - } else { - /* - * This is an error socket, which does _not_ have an underlying socket. - * We simply need to free it. - */ - - CommOS_Kfree(pvsk); - } -} - - -/** - * @brief Schedules an offload socket for AIO. - * @param pvsk socket to schedule. - * @sideeffect the socket will be processed by AIO threads. - */ - -static inline void -PvtcpSchedSock(PvtcpSock *pvsk) -{ - /* - * We must hold the socket before we enqueue it for AIO, such that it may - * not be released while in the workqueue. If CommSvc_ScheduleAIOWork() - * returned non-zero, it means the socket had already been enqueued. In - * that case, we release the hold. Otherwise, the hold is released by the - * AIO function (PvtcpProcessAIO()). - * Note that error pv sockets may only originate from synchronized RPCs, - * or to be more precise, from PvtcpCreateOp(), and not from IO processing; - * this means that they cannot be attempted to be enqueued more than once. - */ - - PvtcpHoldSock(pvsk); - if (CommSvc_ScheduleAIOWork(&pvsk->work)) { - PvtcpPutSock(pvsk); - } -} - -#endif // _PVTCP_OFF_LINUX_H_ diff --git a/arch/arm/mvp/pvtcpkm/pvtcp_off_linux_shim.S b/arch/arm/mvp/pvtcpkm/pvtcp_off_linux_shim.S deleted file mode 100644 index 824286b..0000000 --- a/arch/arm/mvp/pvtcpkm/pvtcp_off_linux_shim.S +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Linux 2.6.32 and later Kernel module for VMware MVP PVTCP Server - * - * Copyright (C) 2010-2012 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; see the file COPYING. If not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#line 5 - -/** - * @file - * - * @brief PVTCP socket destructor shim. - * - * The module reference accounting code for socket destruction in the core - * Linux kernel does not know about PVTCP sockets, so it does not properly - * increment/decrement the reference count on pvtcpkm when calling through a - * function pointer into our destructor. If a module unload is requested on - * pvtcpkm while a socket is being destroyed, it is possible for the destructor - * to be preempted after decrementing the module reference count but before - * returning to the core kernel. If the module code is unmapped before the - * function return, it is possible that we will attempt to execute unmapped - * code, resulting in a host crash. - * - * This shim proxies socket destruction requests through to the PVTCP socket - * destructor, then jumps directly to module_put to drop the reference count. - * module_put will return directly to the caller, eliminating the race. - */ - -.text -.p2align 4 - -.global asmDestructorShim - -/** - * @brief Socket destructor callback. Calls into pvtcpkm to destroy a socket - * and then decrements the refcount. - * @param r0 pointer to struct sock - */ - -asmDestructorShim: - push {lr} - ldr r1, targetAddr @ Destroy socket - blx r1 - pop {lr} - cmp r0, #0 - bxne lr @ We shouldn't module_put, just return. - ldr r0, owner - ldr r1, modulePutAddr @ Jump to module_put. module_put - bx r1 @ returns directly to caller - -owner: - .word __this_module - -targetAddr: - .word DestructCB - -modulePutAddr: - .word module_put diff --git a/block/genhd.c b/block/genhd.c index 6ece7ab..6c93aa1 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -831,6 +831,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v) if (iter) { class_dev_iter_exit(iter); kfree(iter); + seqf->private = NULL; } } diff --git a/crypto/Kconfig b/crypto/Kconfig index 0d12110..efd8816 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -865,6 +865,22 @@ config CRYPTO_LZO help This is the LZO algorithm. +config CRYPTO_LZ4 + tristate "LZ4 compression algorithm" + select CRYPTO_ALGAPI + select LZ4_COMPRESS + select LZ4_DECOMPRESS + help + This is the LZ4 algorithm. + +config CRYPTO_LZ4HC + tristate "LZ4HC compression algorithm" + select CRYPTO_ALGAPI + select LZ4HC_COMPRESS + select LZ4_DECOMPRESS + help + This is the LZ4 high compression mode algorithm. + comment "Random Number Generation" config CRYPTO_ANSI_CPRNG diff --git a/crypto/Makefile b/crypto/Makefile index 69c46ed..a6c3035 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -85,6 +85,8 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o obj-$(CONFIG_CRYPTO_LZO) += lzo.o +obj-$(CONFIG_CRYPTO_LZ4) += lz4.o +obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o obj-$(CONFIG_CRYPTO_RNG2) += rng.o obj-$(CONFIG_CRYPTO_RNG2) += krng.o obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o diff --git a/crypto/lz4.c b/crypto/lz4.c new file mode 100644 index 0000000..34d072b --- /dev/null +++ b/crypto/lz4.c @@ -0,0 +1,106 @@ +/* + * Cryptographic API. + * + * Copyright (c) 2013 Chanho Min <chanho.min@lge.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/crypto.h> +#include <linux/vmalloc.h> +#include <linux/lz4.h> + +struct lz4_ctx { + void *lz4_comp_mem; +}; + +static int lz4_init(struct crypto_tfm *tfm) +{ + struct lz4_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->lz4_comp_mem = vmalloc(LZ4_MEM_COMPRESS); + if (!ctx->lz4_comp_mem) + return -ENOMEM; + + return 0; +} + +static void lz4_exit(struct crypto_tfm *tfm) +{ + struct lz4_ctx *ctx = crypto_tfm_ctx(tfm); + vfree(ctx->lz4_comp_mem); +} + +static int lz4_compress_crypto(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + struct lz4_ctx *ctx = crypto_tfm_ctx(tfm); + size_t tmp_len = *dlen; + int err; + + err = lz4_compress(src, slen, dst, &tmp_len, ctx->lz4_comp_mem); + + if (err < 0) + return -EINVAL; + + *dlen = tmp_len; + return 0; +} + +static int lz4_decompress_crypto(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + int err; + size_t tmp_len = *dlen; + size_t __slen = slen; + + err = lz4_decompress_unknownoutputsize(src, __slen, dst, &tmp_len); + if (err < 0) + return -EINVAL; + + *dlen = tmp_len; + return err; +} + +static struct crypto_alg alg_lz4 = { + .cra_name = "lz4", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct lz4_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg_lz4.cra_list), + .cra_init = lz4_init, + .cra_exit = lz4_exit, + .cra_u = { .compress = { + .coa_compress = lz4_compress_crypto, + .coa_decompress = lz4_decompress_crypto } } +}; + +static int __init lz4_mod_init(void) +{ + return crypto_register_alg(&alg_lz4); +} + +static void __exit lz4_mod_fini(void) +{ + crypto_unregister_alg(&alg_lz4); +} + +module_init(lz4_mod_init); +module_exit(lz4_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LZ4 Compression Algorithm"); diff --git a/crypto/lz4hc.c b/crypto/lz4hc.c new file mode 100644 index 0000000..9218b3f --- /dev/null +++ b/crypto/lz4hc.c @@ -0,0 +1,106 @@ +/* + * Cryptographic API. + * + * Copyright (c) 2013 Chanho Min <chanho.min@lge.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/crypto.h> +#include <linux/vmalloc.h> +#include <linux/lz4.h> + +struct lz4hc_ctx { + void *lz4hc_comp_mem; +}; + +static int lz4hc_init(struct crypto_tfm *tfm) +{ + struct lz4hc_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->lz4hc_comp_mem = vmalloc(LZ4HC_MEM_COMPRESS); + if (!ctx->lz4hc_comp_mem) + return -ENOMEM; + + return 0; +} + +static void lz4hc_exit(struct crypto_tfm *tfm) +{ + struct lz4hc_ctx *ctx = crypto_tfm_ctx(tfm); + + vfree(ctx->lz4hc_comp_mem); +} + +static int lz4hc_compress_crypto(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + struct lz4hc_ctx *ctx = crypto_tfm_ctx(tfm); + size_t tmp_len = *dlen; + int err; + + err = lz4hc_compress(src, slen, dst, &tmp_len, ctx->lz4hc_comp_mem); + + if (err < 0) + return -EINVAL; + + *dlen = tmp_len; + return 0; +} + +static int lz4hc_decompress_crypto(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + int err; + size_t tmp_len = *dlen; + size_t __slen = slen; + + err = lz4_decompress_unknownoutputsize(src, __slen, dst, &tmp_len); + if (err < 0) + return -EINVAL; + + *dlen = tmp_len; + return err; +} + +static struct crypto_alg alg_lz4hc = { + .cra_name = "lz4hc", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct lz4hc_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg_lz4hc.cra_list), + .cra_init = lz4hc_init, + .cra_exit = lz4hc_exit, + .cra_u = { .compress = { + .coa_compress = lz4hc_compress_crypto, + .coa_decompress = lz4hc_decompress_crypto } } +}; + +static int __init lz4hc_mod_init(void) +{ + return crypto_register_alg(&alg_lz4hc); +} + +static void __exit lz4hc_mod_fini(void) +{ + crypto_unregister_alg(&alg_lz4hc); +} + +module_init(lz4hc_mod_init); +module_exit(lz4hc_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LZ4HC Compression Algorithm"); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 717d6e4..b7ac932 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -116,6 +116,8 @@ config PARIDE source "drivers/block/paride/Kconfig" +source "drivers/block/zram/Kconfig" + config BLK_CPQ_DA tristate "Compaq SMART2 support" depends on PCI && VIRT_TO_BUS diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 76646e9..edc9543 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -40,4 +40,5 @@ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += xen-blkback/ obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ obj-$(CONFIG_BLK_DEV_RBD) += rbd.o +obj-$(CONFIG_ZRAM) += zram/ swim_mod-y := swim.o swim_asm.o diff --git a/drivers/staging/zram/Kconfig b/drivers/block/zram/Kconfig index 06f741a..0f95557 100644 --- a/drivers/staging/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -1,11 +1,6 @@ -config XVMALLOC - bool - default n - config ZRAM tristate "Compressed RAM block device support" - depends on BLOCK && SYSFS - select XVMALLOC + depends on BLOCK && SYSFS && ZSMALLOC select LZO_COMPRESS select LZO_DECOMPRESS default n @@ -19,7 +14,17 @@ config ZRAM disks and maybe many more. See zram.txt for more information. - Project home: http://compcache.googlecode.com/ + Project home: <https://compcache.googlecode.com/> + +config ZRAM_LZ4_COMPRESS + bool "Enable LZ4 algorithm support" + depends on ZRAM + select LZ4_COMPRESS + select LZ4_DECOMPRESS + default n + help + This option enables LZ4 compression algorithm support. Compression + algorithm can be changed using `comp_algorithm' device attribute. config ZRAM_DEBUG bool "Compressed RAM block device debug support" @@ -28,10 +33,3 @@ config ZRAM_DEBUG help This option adds additional debugging code to the compressed RAM block device driver. - -config ZRAM_FOR_ANDROID - bool "Optimize zram behavior for android" - depends on ZRAM && ANDROID - default n - help - This option enables modified zram behavior optimized for android diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile new file mode 100644 index 0000000..be0763f --- /dev/null +++ b/drivers/block/zram/Makefile @@ -0,0 +1,5 @@ +zram-y := zcomp_lzo.o zcomp.o zram_drv.o + +zram-$(CONFIG_ZRAM_LZ4_COMPRESS) += zcomp_lz4.o + +obj-$(CONFIG_ZRAM) += zram.o diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c new file mode 100644 index 0000000..54d946a --- /dev/null +++ b/drivers/block/zram/zcomp.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2014 Sergey Senozhatsky. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/wait.h> +#include <linux/sched.h> + +#include "zcomp.h" +#include "zcomp_lzo.h" +#ifdef CONFIG_ZRAM_LZ4_COMPRESS +#include "zcomp_lz4.h" +#endif + +/* + * single zcomp_strm backend + */ +struct zcomp_strm_single { + struct mutex strm_lock; + struct zcomp_strm *zstrm; +}; + +/* + * multi zcomp_strm backend + */ +struct zcomp_strm_multi { + /* protect strm list */ + spinlock_t strm_lock; + /* max possible number of zstrm streams */ + int max_strm; + /* number of available zstrm streams */ + int avail_strm; + /* list of available strms */ + struct list_head idle_strm; + wait_queue_head_t strm_wait; +}; + +static struct zcomp_backend *backends[] = { + &zcomp_lzo, +#ifdef CONFIG_ZRAM_LZ4_COMPRESS + &zcomp_lz4, +#endif + NULL +}; + +static struct zcomp_backend *find_backend(const char *compress) +{ + int i = 0; + while (backends[i]) { + if (sysfs_streq(compress, backends[i]->name)) + break; + i++; + } + return backends[i]; +} + +static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm) +{ + if (zstrm->private) + comp->backend->destroy(zstrm->private); + free_pages((unsigned long)zstrm->buffer, 1); + kfree(zstrm); +} + +/* + * allocate new zcomp_strm structure with ->private initialized by + * backend, return NULL on error + */ +static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp) +{ + struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL); + if (!zstrm) + return NULL; + + zstrm->private = comp->backend->create(); + /* + * allocate 2 pages. 1 for compressed data, plus 1 extra for the + * case when compressed size is larger than the original one + */ + zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); + if (!zstrm->private || !zstrm->buffer) { + zcomp_strm_free(comp, zstrm); + zstrm = NULL; + } + return zstrm; +} + +/* + * get idle zcomp_strm or wait until other process release + * (zcomp_strm_release()) one for us + */ +static struct zcomp_strm *zcomp_strm_multi_find(struct zcomp *comp) +{ + struct zcomp_strm_multi *zs = comp->stream; + struct zcomp_strm *zstrm; + + while (1) { + spin_lock(&zs->strm_lock); + if (!list_empty(&zs->idle_strm)) { + zstrm = list_entry(zs->idle_strm.next, + struct zcomp_strm, list); + list_del(&zstrm->list); + spin_unlock(&zs->strm_lock); + return zstrm; + } + /* zstrm streams limit reached, wait for idle stream */ + if (zs->avail_strm >= zs->max_strm) { + spin_unlock(&zs->strm_lock); + wait_event(zs->strm_wait, !list_empty(&zs->idle_strm)); + continue; + } + /* allocate new zstrm stream */ + zs->avail_strm++; + spin_unlock(&zs->strm_lock); + + zstrm = zcomp_strm_alloc(comp); + if (!zstrm) { + spin_lock(&zs->strm_lock); + zs->avail_strm--; + spin_unlock(&zs->strm_lock); + wait_event(zs->strm_wait, !list_empty(&zs->idle_strm)); + continue; + } + break; + } + return zstrm; +} + +/* add stream back to idle list and wake up waiter or free the stream */ +static void zcomp_strm_multi_release(struct zcomp *comp, struct zcomp_strm *zstrm) +{ + struct zcomp_strm_multi *zs = comp->stream; + + spin_lock(&zs->strm_lock); + if (zs->avail_strm <= zs->max_strm) { + list_add(&zstrm->list, &zs->idle_strm); + spin_unlock(&zs->strm_lock); + wake_up(&zs->strm_wait); + return; + } + + zs->avail_strm--; + spin_unlock(&zs->strm_lock); + zcomp_strm_free(comp, zstrm); +} + +/* change max_strm limit */ +static bool zcomp_strm_multi_set_max_streams(struct zcomp *comp, int num_strm) +{ + struct zcomp_strm_multi *zs = comp->stream; + struct zcomp_strm *zstrm; + + spin_lock(&zs->strm_lock); + zs->max_strm = num_strm; + /* + * if user has lowered the limit and there are idle streams, + * immediately free as much streams (and memory) as we can. + */ + while (zs->avail_strm > num_strm && !list_empty(&zs->idle_strm)) { + zstrm = list_entry(zs->idle_strm.next, + struct zcomp_strm, list); + list_del(&zstrm->list); + zcomp_strm_free(comp, zstrm); + zs->avail_strm--; + } + spin_unlock(&zs->strm_lock); + return true; +} + +static void zcomp_strm_multi_destroy(struct zcomp *comp) +{ + struct zcomp_strm_multi *zs = comp->stream; + struct zcomp_strm *zstrm; + + while (!list_empty(&zs->idle_strm)) { + zstrm = list_entry(zs->idle_strm.next, + struct zcomp_strm, list); + list_del(&zstrm->list); + zcomp_strm_free(comp, zstrm); + } + kfree(zs); +} + +static int zcomp_strm_multi_create(struct zcomp *comp, int max_strm) +{ + struct zcomp_strm *zstrm; + struct zcomp_strm_multi *zs; + + comp->destroy = zcomp_strm_multi_destroy; + comp->strm_find = zcomp_strm_multi_find; + comp->strm_release = zcomp_strm_multi_release; + comp->set_max_streams = zcomp_strm_multi_set_max_streams; + zs = kmalloc(sizeof(struct zcomp_strm_multi), GFP_KERNEL); + if (!zs) + return -ENOMEM; + + comp->stream = zs; + spin_lock_init(&zs->strm_lock); + INIT_LIST_HEAD(&zs->idle_strm); + init_waitqueue_head(&zs->strm_wait); + zs->max_strm = max_strm; + zs->avail_strm = 1; + + zstrm = zcomp_strm_alloc(comp); + if (!zstrm) { + kfree(zs); + return -ENOMEM; + } + list_add(&zstrm->list, &zs->idle_strm); + return 0; +} + +static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp) +{ + struct zcomp_strm_single *zs = comp->stream; + mutex_lock(&zs->strm_lock); + return zs->zstrm; +} + +static void zcomp_strm_single_release(struct zcomp *comp, + struct zcomp_strm *zstrm) +{ + struct zcomp_strm_single *zs = comp->stream; + mutex_unlock(&zs->strm_lock); +} + +static bool zcomp_strm_single_set_max_streams(struct zcomp *comp, int num_strm) +{ + /* zcomp_strm_single support only max_comp_streams == 1 */ + return false; +} + +static void zcomp_strm_single_destroy(struct zcomp *comp) +{ + struct zcomp_strm_single *zs = comp->stream; + zcomp_strm_free(comp, zs->zstrm); + kfree(zs); +} + +static int zcomp_strm_single_create(struct zcomp *comp) +{ + struct zcomp_strm_single *zs; + + comp->destroy = zcomp_strm_single_destroy; + comp->strm_find = zcomp_strm_single_find; + comp->strm_release = zcomp_strm_single_release; + comp->set_max_streams = zcomp_strm_single_set_max_streams; + zs = kmalloc(sizeof(struct zcomp_strm_single), GFP_KERNEL); + if (!zs) + return -ENOMEM; + + comp->stream = zs; + mutex_init(&zs->strm_lock); + zs->zstrm = zcomp_strm_alloc(comp); + if (!zs->zstrm) { + kfree(zs); + return -ENOMEM; + } + return 0; +} + +/* show available compressors */ +ssize_t zcomp_available_show(const char *comp, char *buf) +{ + ssize_t sz = 0; + int i = 0; + + while (backends[i]) { + if (sysfs_streq(comp, backends[i]->name)) + sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2, + "[%s] ", backends[i]->name); + else + sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2, + "%s ", backends[i]->name); + i++; + } + sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n"); + return sz; +} + +bool zcomp_set_max_streams(struct zcomp *comp, int num_strm) +{ + return comp->set_max_streams(comp, num_strm); +} + +struct zcomp_strm *zcomp_strm_find(struct zcomp *comp) +{ + return comp->strm_find(comp); +} + +void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm) +{ + comp->strm_release(comp, zstrm); +} + +int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm, + const unsigned char *src, size_t *dst_len) +{ + return comp->backend->compress(src, zstrm->buffer, dst_len, + zstrm->private); +} + +int zcomp_decompress(struct zcomp *comp, const unsigned char *src, + size_t src_len, unsigned char *dst) +{ + return comp->backend->decompress(src, src_len, dst); +} + +void zcomp_destroy(struct zcomp *comp) +{ + comp->destroy(comp); + kfree(comp); +} + +/* + * search available compressors for requested algorithm. + * allocate new zcomp and initialize it. return compressing + * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL) + * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in + * case of allocation error, or any other error potentially + * returned by functions zcomp_strm_{multi,single}_create. + */ +struct zcomp *zcomp_create(const char *compress, int max_strm) +{ + struct zcomp *comp; + struct zcomp_backend *backend; + int error; + + backend = find_backend(compress); + if (!backend) + return ERR_PTR(-EINVAL); + + comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL); + if (!comp) + return ERR_PTR(-ENOMEM); + + comp->backend = backend; + if (max_strm > 1) + error = zcomp_strm_multi_create(comp, max_strm); + else + error = zcomp_strm_single_create(comp); + if (error) { + kfree(comp); + return ERR_PTR(error); + } + return comp; +} diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h new file mode 100644 index 0000000..c59d1fc --- /dev/null +++ b/drivers/block/zram/zcomp.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 Sergey Senozhatsky. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ZCOMP_H_ +#define _ZCOMP_H_ + +#include <linux/mutex.h> + +struct zcomp_strm { + /* compression/decompression buffer */ + void *buffer; + /* + * The private data of the compression stream, only compression + * stream backend can touch this (e.g. compression algorithm + * working memory) + */ + void *private; + /* used in multi stream backend, protected by backend strm_lock */ + struct list_head list; +}; + +/* static compression backend */ +struct zcomp_backend { + int (*compress)(const unsigned char *src, unsigned char *dst, + size_t *dst_len, void *private); + + int (*decompress)(const unsigned char *src, size_t src_len, + unsigned char *dst); + + void *(*create)(void); + void (*destroy)(void *private); + + const char *name; +}; + +/* dynamic per-device compression frontend */ +struct zcomp { + void *stream; + struct zcomp_backend *backend; + + struct zcomp_strm *(*strm_find)(struct zcomp *comp); + void (*strm_release)(struct zcomp *comp, struct zcomp_strm *zstrm); + bool (*set_max_streams)(struct zcomp *comp, int num_strm); + void (*destroy)(struct zcomp *comp); +}; + +ssize_t zcomp_available_show(const char *comp, char *buf); + +struct zcomp *zcomp_create(const char *comp, int max_strm); +void zcomp_destroy(struct zcomp *comp); + +struct zcomp_strm *zcomp_strm_find(struct zcomp *comp); +void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm); + +int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm, + const unsigned char *src, size_t *dst_len); + +int zcomp_decompress(struct zcomp *comp, const unsigned char *src, + size_t src_len, unsigned char *dst); + +bool zcomp_set_max_streams(struct zcomp *comp, int num_strm); +#endif /* _ZCOMP_H_ */ diff --git a/drivers/block/zram/zcomp_lz4.c b/drivers/block/zram/zcomp_lz4.c new file mode 100644 index 0000000..f2afb7e --- /dev/null +++ b/drivers/block/zram/zcomp_lz4.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Sergey Senozhatsky. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/lz4.h> + +#include "zcomp_lz4.h" + +static void *zcomp_lz4_create(void) +{ + return kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL); +} + +static void zcomp_lz4_destroy(void *private) +{ + kfree(private); +} + +static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst, + size_t *dst_len, void *private) +{ + /* return : Success if return 0 */ + return lz4_compress(src, PAGE_SIZE, dst, dst_len, private); +} + +static int zcomp_lz4_decompress(const unsigned char *src, size_t src_len, + unsigned char *dst) +{ + size_t dst_len = PAGE_SIZE; + /* return : Success if return 0 */ + return lz4_decompress_unknownoutputsize(src, src_len, dst, &dst_len); +} + +struct zcomp_backend zcomp_lz4 = { + .compress = zcomp_lz4_compress, + .decompress = zcomp_lz4_decompress, + .create = zcomp_lz4_create, + .destroy = zcomp_lz4_destroy, + .name = "lz4", +}; diff --git a/drivers/block/zram/zcomp_lz4.h b/drivers/block/zram/zcomp_lz4.h new file mode 100644 index 0000000..60613fb --- /dev/null +++ b/drivers/block/zram/zcomp_lz4.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2014 Sergey Senozhatsky. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ZCOMP_LZ4_H_ +#define _ZCOMP_LZ4_H_ + +#include "zcomp.h" + +extern struct zcomp_backend zcomp_lz4; + +#endif /* _ZCOMP_LZ4_H_ */ diff --git a/drivers/block/zram/zcomp_lzo.c b/drivers/block/zram/zcomp_lzo.c new file mode 100644 index 0000000..da1bc47 --- /dev/null +++ b/drivers/block/zram/zcomp_lzo.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Sergey Senozhatsky. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/lzo.h> + +#include "zcomp_lzo.h" + +static void *lzo_create(void) +{ + return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); +} + +static void lzo_destroy(void *private) +{ + kfree(private); +} + +static int lzo_compress(const unsigned char *src, unsigned char *dst, + size_t *dst_len, void *private) +{ + int ret = lzo1x_1_compress(src, PAGE_SIZE, dst, dst_len, private); + return ret == LZO_E_OK ? 0 : ret; +} + +static int lzo_decompress(const unsigned char *src, size_t src_len, + unsigned char *dst) +{ + size_t dst_len = PAGE_SIZE; + int ret = lzo1x_decompress_safe(src, src_len, dst, &dst_len); + return ret == LZO_E_OK ? 0 : ret; +} + +struct zcomp_backend zcomp_lzo = { + .compress = lzo_compress, + .decompress = lzo_decompress, + .create = lzo_create, + .destroy = lzo_destroy, + .name = "lzo", +}; diff --git a/drivers/block/zram/zcomp_lzo.h b/drivers/block/zram/zcomp_lzo.h new file mode 100644 index 0000000..128c580 --- /dev/null +++ b/drivers/block/zram/zcomp_lzo.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2014 Sergey Senozhatsky. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _ZCOMP_LZO_H_ +#define _ZCOMP_LZO_H_ + +#include "zcomp.h" + +extern struct zcomp_backend zcomp_lzo; + +#endif /* _ZCOMP_LZO_H_ */ diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c new file mode 100644 index 0000000..a4eb55d --- /dev/null +++ b/drivers/block/zram/zram_drv.c @@ -0,0 +1,1081 @@ +/* + * Compressed RAM block device + * + * Copyright (C) 2008, 2009, 2010 Nitin Gupta + * 2012, 2013 Minchan Kim + * + * This code is released using a dual license strategy: BSD/GPL + * You can choose the licence that better fits your requirements. + * + * Released under the terms of 3-clause BSD License + * Released under the terms of GNU General Public License Version 2.0 + * + * Project home: http://compcache.googlecode.com + */ + +#define KMSG_COMPONENT "zram" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#ifdef CONFIG_ZRAM_DEBUG +#define DEBUG +#endif + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/bio.h> +#include <linux/bitops.h> +#include <linux/blkdev.h> +#include <linux/buffer_head.h> +#include <linux/device.h> +#include <linux/genhd.h> +#include <linux/highmem.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/vmalloc.h> +#include <linux/ratelimit.h> +#include <linux/err.h> + +#include "zram_drv.h" + +/* Globals */ +static int zram_major; +static struct zram *zram_devices; +#ifdef CONFIG_ZRAM_LZ4_COMPRESS +static const char *default_compressor = "lz4"; +#else +static const char *default_compressor = "lzo"; +#endif + +/* + * We don't need to see memory allocation errors more than once every 1 + * second to know that a problem is occurring. + */ +#define ALLOC_ERROR_LOG_RATE_MS 1000 + +/* Module params (documentation at end) */ +static unsigned int num_devices = 1; + +#define ZRAM_ATTR_RO(name) \ +static ssize_t zram_attr_##name##_show(struct device *d, \ + struct device_attribute *attr, char *b) \ +{ \ + struct zram *zram = dev_to_zram(d); \ + return scnprintf(b, PAGE_SIZE, "%llu\n", \ + (u64)atomic64_read(&zram->stats.name)); \ +} \ +static struct device_attribute dev_attr_##name = \ + __ATTR(name, S_IRUGO, zram_attr_##name##_show, NULL); + +static inline int init_done(struct zram *zram) +{ + return zram->meta != NULL; +} + +static inline struct zram *dev_to_zram(struct device *dev) +{ + return (struct zram *)dev_to_disk(dev)->private_data; +} + +static ssize_t disksize_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct zram *zram = dev_to_zram(dev); + + return scnprintf(buf, PAGE_SIZE, "%llu\n", zram->disksize); +} + +static ssize_t initstate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 val; + struct zram *zram = dev_to_zram(dev); + + down_read(&zram->init_lock); + val = init_done(zram); + up_read(&zram->init_lock); + + return scnprintf(buf, PAGE_SIZE, "%u\n", val); +} + +static ssize_t orig_data_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct zram *zram = dev_to_zram(dev); + + return scnprintf(buf, PAGE_SIZE, "%llu\n", + (u64)(atomic64_read(&zram->stats.pages_stored)) << PAGE_SHIFT); +} + +static ssize_t mem_used_total_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u64 val = 0; + struct zram *zram = dev_to_zram(dev); + struct zram_meta *meta = zram->meta; + + down_read(&zram->init_lock); + if (init_done(zram)) + val = zs_get_total_pages(meta->mem_pool); + up_read(&zram->init_lock); + + return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT); +} + +static ssize_t max_comp_streams_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int val; + struct zram *zram = dev_to_zram(dev); + + down_read(&zram->init_lock); + val = zram->max_comp_streams; + up_read(&zram->init_lock); + + return scnprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t max_comp_streams_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int num; + struct zram *zram = dev_to_zram(dev); + int ret; + + ret = kstrtoint(buf, 0, &num); + if (ret < 0) + return ret; + if (num < 1) + return -EINVAL; + + down_write(&zram->init_lock); + if (init_done(zram)) { + if (!zcomp_set_max_streams(zram->comp, num)) { + pr_info("Cannot change max compression streams\n"); + ret = -EINVAL; + goto out; + } + } + + zram->max_comp_streams = num; + ret = len; +out: + up_write(&zram->init_lock); + return ret; +} + +static ssize_t comp_algorithm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t sz; + struct zram *zram = dev_to_zram(dev); + + down_read(&zram->init_lock); + sz = zcomp_available_show(zram->compressor, buf); + up_read(&zram->init_lock); + + return sz; +} + +static ssize_t comp_algorithm_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct zram *zram = dev_to_zram(dev); + down_write(&zram->init_lock); + if (init_done(zram)) { + up_write(&zram->init_lock); + pr_info("Can't change algorithm for initialized device\n"); + return -EBUSY; + } + strlcpy(zram->compressor, buf, sizeof(zram->compressor)); + up_write(&zram->init_lock); + return len; +} + +/* flag operations needs meta->tb_lock */ +static int zram_test_flag(struct zram_meta *meta, u32 index, + enum zram_pageflags flag) +{ + return meta->table[index].value & BIT(flag); +} + +static void zram_set_flag(struct zram_meta *meta, u32 index, + enum zram_pageflags flag) +{ + meta->table[index].value |= BIT(flag); +} + +static void zram_clear_flag(struct zram_meta *meta, u32 index, + enum zram_pageflags flag) +{ + meta->table[index].value &= ~BIT(flag); +} + +static size_t zram_get_obj_size(struct zram_meta *meta, u32 index) +{ + return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1); +} + +static void zram_set_obj_size(struct zram_meta *meta, + u32 index, size_t size) +{ + unsigned long flags = meta->table[index].value >> ZRAM_FLAG_SHIFT; + + meta->table[index].value = (flags << ZRAM_FLAG_SHIFT) | size; +} + +static inline int is_partial_io(struct bio_vec *bvec) +{ + return bvec->bv_len != PAGE_SIZE; +} + +/* + * Check if request is within bounds and aligned on zram logical blocks. + */ +static inline int valid_io_request(struct zram *zram, struct bio *bio) +{ + u64 start, end, bound; + + /* unaligned request */ + if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) + return 0; + if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) + return 0; + + start = bio->bi_sector; + end = start + (bio->bi_size >> SECTOR_SHIFT); + bound = zram->disksize >> SECTOR_SHIFT; + /* out of range range */ + if (unlikely(start >= bound || end > bound || start > end)) + return 0; + + /* I/O request is valid */ + return 1; +} + +static void zram_meta_free(struct zram_meta *meta) +{ + zs_destroy_pool(meta->mem_pool); + vfree(meta->table); + kfree(meta); +} + +static struct zram_meta *zram_meta_alloc(u64 disksize) +{ + size_t num_pages; + struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL); + if (!meta) + goto out; + + num_pages = disksize >> PAGE_SHIFT; + meta->table = vzalloc(num_pages * sizeof(*meta->table)); + if (!meta->table) { + pr_err("Error allocating zram address table\n"); + goto free_meta; + } + + meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM | + __GFP_NOWARN); + if (!meta->mem_pool) { + pr_err("Error creating memory pool\n"); + goto free_table; + } + + return meta; + +free_table: + vfree(meta->table); +free_meta: + kfree(meta); + meta = NULL; +out: + return meta; +} + +static void update_position(u32 *index, int *offset, struct bio_vec *bvec) +{ + if (*offset + bvec->bv_len >= PAGE_SIZE) + (*index)++; + *offset = (*offset + bvec->bv_len) % PAGE_SIZE; +} + +static int page_zero_filled(void *ptr) +{ + unsigned int pos; + unsigned long *page; + + page = (unsigned long *)ptr; + + for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) { + if (page[pos]) + return 0; + } + + return 1; +} + +static void handle_zero_page(struct bio_vec *bvec) +{ + struct page *page = bvec->bv_page; + void *user_mem; + + user_mem = kmap_atomic(page); + if (is_partial_io(bvec)) + memset(user_mem + bvec->bv_offset, 0, bvec->bv_len); + else + clear_page(user_mem); + kunmap_atomic(user_mem); + + flush_dcache_page(page); +} + + +/* + * To protect concurrent access to the same index entry, + * caller should hold this table index entry's bit_spinlock to + * indicate this index entry is accessing. + */ +static void zram_free_page(struct zram *zram, size_t index) +{ + struct zram_meta *meta = zram->meta; + unsigned long handle = meta->table[index].handle; + + if (unlikely(!handle)) { + /* + * No memory is allocated for zero filled pages. + * Simply clear zero page flag. + */ + if (zram_test_flag(meta, index, ZRAM_ZERO)) { + zram_clear_flag(meta, index, ZRAM_ZERO); + atomic64_dec(&zram->stats.zero_pages); + } + return; + } + + zs_free(meta->mem_pool, handle); + + atomic64_sub(zram_get_obj_size(meta, index), + &zram->stats.compr_data_size); + atomic64_dec(&zram->stats.pages_stored); + + meta->table[index].handle = 0; + zram_set_obj_size(meta, index, 0); +} + +static int zram_decompress_page(struct zram *zram, char *mem, u32 index) +{ + int ret = 0; + unsigned char *cmem; + struct zram_meta *meta = zram->meta; + unsigned long handle; + size_t size; + + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + handle = meta->table[index].handle; + size = zram_get_obj_size(meta, index); + + if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) { + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + clear_page(mem); + return 0; + } + + cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO); + if (size == PAGE_SIZE) + copy_page(mem, cmem); + else + ret = zcomp_decompress(zram->comp, cmem, size, mem); + zs_unmap_object(meta->mem_pool, handle); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + + /* Should NEVER happen. Return bio error if it does. */ + if (unlikely(ret)) { + pr_err("Decompression failed! err=%d, page=%u\n", ret, index); + return ret; + } + + return 0; +} + +static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, + u32 index, int offset, struct bio *bio) +{ + int ret; + struct page *page; + unsigned char *user_mem, *uncmem = NULL; + struct zram_meta *meta = zram->meta; + page = bvec->bv_page; + + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + if (unlikely(!meta->table[index].handle) || + zram_test_flag(meta, index, ZRAM_ZERO)) { + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + handle_zero_page(bvec); + return 0; + } + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + + if (is_partial_io(bvec)) + /* Use a temporary buffer to decompress the page */ + uncmem = kmalloc(PAGE_SIZE, GFP_NOIO); + + user_mem = kmap_atomic(page); + if (!is_partial_io(bvec)) + uncmem = user_mem; + + if (!uncmem) { + pr_info("Unable to allocate temp memory\n"); + ret = -ENOMEM; + goto out_cleanup; + } + + ret = zram_decompress_page(zram, uncmem, index); + /* Should NEVER happen. Return bio error if it does. */ + if (unlikely(ret)) + goto out_cleanup; + + if (is_partial_io(bvec)) + memcpy(user_mem + bvec->bv_offset, uncmem + offset, + bvec->bv_len); + + flush_dcache_page(page); + ret = 0; +out_cleanup: + kunmap_atomic(user_mem); + if (is_partial_io(bvec)) + kfree(uncmem); + return ret; +} + +static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, + int offset) +{ + int ret = 0; + size_t clen; + unsigned long handle; + struct page *page; + unsigned char *user_mem, *cmem, *src, *uncmem = NULL; + struct zram_meta *meta = zram->meta; + static unsigned long zram_rs_time; + struct zcomp_strm *zstrm; + bool locked = false; + + page = bvec->bv_page; + if (is_partial_io(bvec)) { + /* + * This is a partial IO. We need to read the full page + * before to write the changes. + */ + uncmem = kmalloc(PAGE_SIZE, GFP_NOIO); + if (!uncmem) { + ret = -ENOMEM; + goto out; + } + ret = zram_decompress_page(zram, uncmem, index); + if (ret) + goto out; + } + + zstrm = zcomp_strm_find(zram->comp); + locked = true; + user_mem = kmap_atomic(page); + + if (is_partial_io(bvec)) { + memcpy(uncmem + offset, user_mem + bvec->bv_offset, + bvec->bv_len); + kunmap_atomic(user_mem); + user_mem = NULL; + } else { + uncmem = user_mem; + } + + if (page_zero_filled(uncmem)) { + kunmap_atomic(user_mem); + /* Free memory associated with this sector now. */ + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + zram_free_page(zram, index); + zram_set_flag(meta, index, ZRAM_ZERO); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + + atomic64_inc(&zram->stats.zero_pages); + ret = 0; + goto out; + } + + ret = zcomp_compress(zram->comp, zstrm, uncmem, &clen); + if (!is_partial_io(bvec)) { + kunmap_atomic(user_mem); + user_mem = NULL; + uncmem = NULL; + } + + if (unlikely(ret)) { + pr_err("Compression failed! err=%d\n", ret); + goto out; + } + src = zstrm->buffer; + if (unlikely(clen > max_zpage_size)) { + clen = PAGE_SIZE; + if (is_partial_io(bvec)) + src = uncmem; + } + + handle = zs_malloc(meta->mem_pool, clen); + if (!handle) { + if (printk_timed_ratelimit(&zram_rs_time, + ALLOC_ERROR_LOG_RATE_MS)) + pr_info("Error allocating memory for compressed page: %u, size=%zu\n", + index, clen); + ret = -ENOMEM; + goto out; + } + cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO); + + if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) { + src = kmap_atomic(page); + copy_page(cmem, src); + kunmap_atomic(src); + } else { + memcpy(cmem, src, clen); + } + + zcomp_strm_release(zram->comp, zstrm); + locked = false; + zs_unmap_object(meta->mem_pool, handle); + + /* + * Free memory associated with this sector + * before overwriting unused sectors. + */ + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + zram_free_page(zram, index); + + meta->table[index].handle = handle; + zram_set_obj_size(meta, index, clen); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + + /* Update stats */ + atomic64_add(clen, &zram->stats.compr_data_size); + atomic64_inc(&zram->stats.pages_stored); +out: + if (locked) + zcomp_strm_release(zram->comp, zstrm); + if (is_partial_io(bvec)) + kfree(uncmem); + return ret; +} + +static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index, + int offset, struct bio *bio) +{ + int ret; + int rw = bio_data_dir(bio); + + if (rw == READ) { + atomic64_inc(&zram->stats.num_reads); + ret = zram_bvec_read(zram, bvec, index, offset, bio); + } else { + atomic64_inc(&zram->stats.num_writes); + ret = zram_bvec_write(zram, bvec, index, offset); + } + + if (unlikely(ret)) { + if (rw == READ) + atomic64_inc(&zram->stats.failed_reads); + else + atomic64_inc(&zram->stats.failed_writes); + } + + return ret; +} + +/* + * zram_bio_discard - handler on discard request + * @index: physical block index in PAGE_SIZE units + * @offset: byte offset within physical block + */ +static void zram_bio_discard(struct zram *zram, u32 index, + int offset, struct bio *bio) +{ + size_t n = bio->bi_size; + struct zram_meta *meta = zram->meta; + + /* + * zram manages data in physical block size units. Because logical block + * size isn't identical with physical block size on some arch, we + * could get a discard request pointing to a specific offset within a + * certain physical block. Although we can handle this request by + * reading that physiclal block and decompressing and partially zeroing + * and re-compressing and then re-storing it, this isn't reasonable + * because our intent with a discard request is to save memory. So + * skipping this logical block is appropriate here. + */ + if (offset) { + if (n <= (PAGE_SIZE - offset)) + return; + + n -= (PAGE_SIZE - offset); + index++; + } + + while (n >= PAGE_SIZE) { + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + zram_free_page(zram, index); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + index++; + n -= PAGE_SIZE; + } +} + +static void zram_reset_device(struct zram *zram, bool reset_capacity) +{ + size_t index; + struct zram_meta *meta; + + down_write(&zram->init_lock); + if (!init_done(zram)) { + up_write(&zram->init_lock); + return; + } + + meta = zram->meta; + /* Free all pages that are still in this zram device */ + for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) { + unsigned long handle = meta->table[index].handle; + if (!handle) + continue; + + zs_free(meta->mem_pool, handle); + } + + zcomp_destroy(zram->comp); + zram->max_comp_streams = 1; + + zram_meta_free(zram->meta); + zram->meta = NULL; + /* Reset stats */ + memset(&zram->stats, 0, sizeof(zram->stats)); + + zram->disksize = 0; + if (reset_capacity) + set_capacity(zram->disk, 0); + + up_write(&zram->init_lock); + + /* + * Revalidate disk out of the init_lock to avoid lockdep splat. + * It's okay because disk's capacity is protected by init_lock + * so that revalidate_disk always sees up-to-date capacity. + */ + if (reset_capacity) + revalidate_disk(zram->disk); +} + +static ssize_t disksize_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + u64 disksize; + struct zcomp *comp; + struct zram_meta *meta; + struct zram *zram = dev_to_zram(dev); + int err; + + disksize = memparse(buf, NULL); + if (!disksize) + return -EINVAL; + + disksize = PAGE_ALIGN(disksize); + meta = zram_meta_alloc(disksize); + if (!meta) + return -ENOMEM; + + comp = zcomp_create(zram->compressor, zram->max_comp_streams); + if (IS_ERR(comp)) { + pr_info("Cannot initialise %s compressing backend\n", + zram->compressor); + err = PTR_ERR(comp); + goto out_free_meta; + } + + down_write(&zram->init_lock); + if (init_done(zram)) { + pr_info("Cannot change disksize for initialized device\n"); + err = -EBUSY; + goto out_destroy_comp; + } + + zram->meta = meta; + zram->comp = comp; + zram->disksize = disksize; + set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT); + up_write(&zram->init_lock); + + /* + * Revalidate disk out of the init_lock to avoid lockdep splat. + * It's okay because disk's capacity is protected by init_lock + * so that revalidate_disk always sees up-to-date capacity. + */ + revalidate_disk(zram->disk); + + return len; + +out_destroy_comp: + up_write(&zram->init_lock); + zcomp_destroy(comp); +out_free_meta: + zram_meta_free(meta); + return err; +} + +static ssize_t reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int ret; + unsigned short do_reset; + struct zram *zram; + struct block_device *bdev; + + zram = dev_to_zram(dev); + bdev = bdget_disk(zram->disk, 0); + + if (!bdev) + return -ENOMEM; + + /* Do not reset an active device! */ + if (bdev->bd_holders) { + ret = -EBUSY; + goto out; + } + + ret = kstrtou16(buf, 10, &do_reset); + if (ret) + goto out; + + if (!do_reset) { + ret = -EINVAL; + goto out; + } + + /* Make sure all pending I/O is finished */ + fsync_bdev(bdev); + bdput(bdev); + + zram_reset_device(zram, true); + return len; + +out: + bdput(bdev); + return ret; +} + +static void __zram_make_request(struct zram *zram, struct bio *bio) +{ + int i, offset; + u32 index; + struct bio_vec *bvec; + + index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT; + offset = (bio->bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; + + if (unlikely(bio->bi_rw & REQ_DISCARD)) { + zram_bio_discard(zram, index, offset, bio); + bio_endio(bio, 0); + return; + } + + bio_for_each_segment(bvec, bio, i) { + int max_transfer_size = PAGE_SIZE - offset; + + if (bvec->bv_len > max_transfer_size) { + /* + * zram_bvec_rw() can only make operation on a single + * zram page. Split the bio vector. + */ + struct bio_vec bv; + + bv.bv_page = bvec->bv_page; + bv.bv_len = max_transfer_size; + bv.bv_offset = bvec->bv_offset; + + if (zram_bvec_rw(zram, &bv, index, offset, bio) < 0) + goto out; + + bv.bv_len = bvec->bv_len - max_transfer_size; + bv.bv_offset += max_transfer_size; + if (zram_bvec_rw(zram, &bv, index + 1, 0, bio) < 0) + goto out; + } else + if (zram_bvec_rw(zram, bvec, index, offset, bio) < 0) + goto out; + + update_position(&index, &offset, bvec); + } + + set_bit(BIO_UPTODATE, &bio->bi_flags); + bio_endio(bio, 0); + return; + +out: + bio_io_error(bio); +} + +/* + * Handler function for all zram I/O requests. + */ +static int zram_make_request(struct request_queue *queue, struct bio *bio) +{ + struct zram *zram = queue->queuedata; + + down_read(&zram->init_lock); + if (unlikely(!init_done(zram))) + goto error; + + if (!valid_io_request(zram, bio)) { + atomic64_inc(&zram->stats.invalid_io); + goto error; + } + + __zram_make_request(zram, bio); + up_read(&zram->init_lock); + + return 0; + +error: + up_read(&zram->init_lock); + bio_io_error(bio); + + return 0; +} + +static void zram_slot_free_notify(struct block_device *bdev, + unsigned long index) +{ + struct zram *zram; + struct zram_meta *meta; + + zram = bdev->bd_disk->private_data; + meta = zram->meta; + + bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value); + zram_free_page(zram, index); + bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value); + atomic64_inc(&zram->stats.notify_free); +} + +static const struct block_device_operations zram_devops = { + .swap_slot_free_notify = zram_slot_free_notify, + .owner = THIS_MODULE +}; + +static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR, + disksize_show, disksize_store); +static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL); +static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store); +static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL); +static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL); +static DEVICE_ATTR(max_comp_streams, S_IRUGO | S_IWUSR, + max_comp_streams_show, max_comp_streams_store); +static DEVICE_ATTR(comp_algorithm, S_IRUGO | S_IWUSR, + comp_algorithm_show, comp_algorithm_store); + +ZRAM_ATTR_RO(num_reads); +ZRAM_ATTR_RO(num_writes); +ZRAM_ATTR_RO(failed_reads); +ZRAM_ATTR_RO(failed_writes); +ZRAM_ATTR_RO(invalid_io); +ZRAM_ATTR_RO(notify_free); +ZRAM_ATTR_RO(zero_pages); +ZRAM_ATTR_RO(compr_data_size); + +static struct attribute *zram_disk_attrs[] = { + &dev_attr_disksize.attr, + &dev_attr_initstate.attr, + &dev_attr_reset.attr, + &dev_attr_num_reads.attr, + &dev_attr_num_writes.attr, + &dev_attr_failed_reads.attr, + &dev_attr_failed_writes.attr, + &dev_attr_invalid_io.attr, + &dev_attr_notify_free.attr, + &dev_attr_zero_pages.attr, + &dev_attr_orig_data_size.attr, + &dev_attr_compr_data_size.attr, + &dev_attr_mem_used_total.attr, + &dev_attr_max_comp_streams.attr, + &dev_attr_comp_algorithm.attr, + NULL, +}; + +static struct attribute_group zram_disk_attr_group = { + .attrs = zram_disk_attrs, +}; + +static int create_device(struct zram *zram, int device_id) +{ + int ret = -ENOMEM; + + init_rwsem(&zram->init_lock); + + zram->queue = blk_alloc_queue(GFP_KERNEL); + if (!zram->queue) { + pr_err("Error allocating disk queue for device %d\n", + device_id); + goto out; + } + + blk_queue_make_request(zram->queue, zram_make_request); + zram->queue->queuedata = zram; + + /* gendisk structure */ + zram->disk = alloc_disk(1); + if (!zram->disk) { + pr_warn("Error allocating disk structure for device %d\n", + device_id); + goto out_free_queue; + } + + zram->disk->major = zram_major; + zram->disk->first_minor = device_id; + zram->disk->fops = &zram_devops; + zram->disk->queue = zram->queue; + zram->disk->private_data = zram; + snprintf(zram->disk->disk_name, 16, "zram%d", device_id); + + __set_bit(QUEUE_FLAG_FAST, &zram->queue->queue_flags); + /* Actual capacity set using syfs (/sys/block/zram<id>/disksize */ + set_capacity(zram->disk, 0); + /* zram devices sort of resembles non-rotational disks */ + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue); + /* + * To ensure that we always get PAGE_SIZE aligned + * and n*PAGE_SIZED sized I/O requests. + */ + blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE); + blk_queue_logical_block_size(zram->disk->queue, + ZRAM_LOGICAL_BLOCK_SIZE); + blk_queue_io_min(zram->disk->queue, PAGE_SIZE); + blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); + zram->disk->queue->limits.discard_granularity = PAGE_SIZE; + zram->disk->queue->limits.max_discard_sectors = UINT_MAX; + /* + * zram_bio_discard() will clear all logical blocks if logical block + * size is identical with physical block size(PAGE_SIZE). But if it is + * different, we will skip discarding some parts of logical blocks in + * the part of the request range which isn't aligned to physical block + * size. So we can't ensure that all discarded logical blocks are + * zeroed. + */ + if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE) + zram->disk->queue->limits.discard_zeroes_data = 1; + else + zram->disk->queue->limits.discard_zeroes_data = 0; + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue); + + add_disk(zram->disk); + + ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj, + &zram_disk_attr_group); + if (ret < 0) { + pr_warn("Error creating sysfs group"); + goto out_free_disk; + } + strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor)); + zram->meta = NULL; + zram->max_comp_streams = 1; + return 0; + +out_free_disk: + del_gendisk(zram->disk); + put_disk(zram->disk); +out_free_queue: + blk_cleanup_queue(zram->queue); +out: + return ret; +} + +static void destroy_device(struct zram *zram) +{ + sysfs_remove_group(&disk_to_dev(zram->disk)->kobj, + &zram_disk_attr_group); + + del_gendisk(zram->disk); + put_disk(zram->disk); + + blk_cleanup_queue(zram->queue); +} + +static int __init zram_init(void) +{ + int ret, dev_id; + + if (num_devices > max_num_devices) { + pr_warn("Invalid value for num_devices: %u\n", + num_devices); + ret = -EINVAL; + goto out; + } + + zram_major = register_blkdev(0, "zram"); + if (zram_major <= 0) { + pr_warn("Unable to get major number\n"); + ret = -EBUSY; + goto out; + } + + /* Allocate the device array and initialize each one */ + zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL); + if (!zram_devices) { + ret = -ENOMEM; + goto unregister; + } + + for (dev_id = 0; dev_id < num_devices; dev_id++) { + ret = create_device(&zram_devices[dev_id], dev_id); + if (ret) + goto free_devices; + } + + pr_info("Created %u device(s) ...\n", num_devices); + + return 0; + +free_devices: + while (dev_id) + destroy_device(&zram_devices[--dev_id]); + kfree(zram_devices); +unregister: + unregister_blkdev(zram_major, "zram"); +out: + return ret; +} + +static void __exit zram_exit(void) +{ + int i; + struct zram *zram; + + for (i = 0; i < num_devices; i++) { + zram = &zram_devices[i]; + + destroy_device(zram); + /* + * Shouldn't access zram->disk after destroy_device + * because destroy_device already released zram->disk. + */ + zram_reset_device(zram, false); + } + + unregister_blkdev(zram_major, "zram"); + + kfree(zram_devices); + pr_debug("Cleanup done!\n"); +} + +module_init(zram_init); +module_exit(zram_exit); + +module_param(num_devices, uint, 0); +MODULE_PARM_DESC(num_devices, "Number of zram devices"); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>"); +MODULE_DESCRIPTION("Compressed RAM Block Device"); diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h new file mode 100644 index 0000000..2a4f29c --- /dev/null +++ b/drivers/block/zram/zram_drv.h @@ -0,0 +1,118 @@ +/* + * Compressed RAM block device + * + * Copyright (C) 2008, 2009, 2010 Nitin Gupta + * 2012, 2013 Minchan Kim + * + * This code is released using a dual license strategy: BSD/GPL + * You can choose the licence that better fits your requirements. + * + * Released under the terms of 3-clause BSD License + * Released under the terms of GNU General Public License Version 2.0 + * + * Project home: http://compcache.googlecode.com + */ + +#ifndef _ZRAM_DRV_H_ +#define _ZRAM_DRV_H_ + +#include <linux/spinlock.h> +#include <linux/zsmalloc.h> + +#include "zcomp.h" + +/* + * Some arbitrary value. This is just to catch + * invalid value for num_devices module parameter. + */ +static const unsigned max_num_devices = 32; + +/*-- Configurable parameters */ + +/* + * Pages that compress to size greater than this are stored + * uncompressed in memory. + */ +static const size_t max_zpage_size = PAGE_SIZE / 10 * 9; + +/* + * NOTE: max_zpage_size must be less than or equal to: + * ZS_MAX_ALLOC_SIZE. Otherwise, zs_malloc() would + * always return failure. + */ + +/*-- End of configurable params */ + +#define SECTOR_SHIFT 9 +#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) +#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT) +#define ZRAM_LOGICAL_BLOCK_SHIFT 12 +#define ZRAM_LOGICAL_BLOCK_SIZE (1 << ZRAM_LOGICAL_BLOCK_SHIFT) +#define ZRAM_SECTOR_PER_LOGICAL_BLOCK \ + (1 << (ZRAM_LOGICAL_BLOCK_SHIFT - SECTOR_SHIFT)) + + +/* + * The lower ZRAM_FLAG_SHIFT bits of table.value is for + * object size (excluding header), the higher bits is for + * zram_pageflags. + * + * zram is mainly used for memory efficiency so we want to keep memory + * footprint small so we can squeeze size and flags into a field. + * The lower ZRAM_FLAG_SHIFT bits is for object size (excluding header), + * the higher bits is for zram_pageflags. + */ +#define ZRAM_FLAG_SHIFT 24 + +/* Flags for zram pages (table[page_no].value) */ +enum zram_pageflags { + /* Page consists entirely of zeros */ + ZRAM_ZERO = ZRAM_FLAG_SHIFT + 1, + ZRAM_ACCESS, /* page in now accessed */ + + __NR_ZRAM_PAGEFLAGS, +}; + +/*-- Data structures */ + +/* Allocated for each disk page */ +struct zram_table_entry { + unsigned long handle; + unsigned long value; +}; + +struct zram_stats { + atomic64_t compr_data_size; /* compressed size of pages stored */ + atomic64_t num_reads; /* failed + successful */ + atomic64_t num_writes; /* --do-- */ + atomic64_t failed_reads; /* can happen when memory is too low */ + atomic64_t failed_writes; /* can happen when memory is too low */ + atomic64_t invalid_io; /* non-page-aligned I/O requests */ + atomic64_t notify_free; /* no. of swap slot free notifications */ + atomic64_t zero_pages; /* no. of zero filled pages */ + atomic64_t pages_stored; /* no. of pages currently stored */ +}; + +struct zram_meta { + struct zram_table_entry *table; + struct zs_pool *mem_pool; +}; + +struct zram { + struct zram_meta *meta; + struct request_queue *queue; + struct gendisk *disk; + struct zcomp *comp; + + /* Prevent concurrent execution of device init, reset and R/W request */ + struct rw_semaphore init_lock; + /* + * This is the limit on amount of *uncompressed* worth of data + * we can store in a disk. + */ + u64 disksize; /* bytes */ + int max_comp_streams; + struct zram_stats stats; + char compressor[10]; +}; +#endif diff --git a/drivers/gpu/mali400/r3p2/mali/__malidrv_build_info.c b/drivers/gpu/mali400/r3p2/mali/__malidrv_build_info.c index af5e808..485ad26 100644 --- a/drivers/gpu/mali400/r3p2/mali/__malidrv_build_info.c +++ b/drivers/gpu/mali400/r3p2/mali/__malidrv_build_info.c @@ -1 +1 @@ -const char *__malidrv_build_info(void) { return "malidrv: API_VERSION=23 REPO_URL=heads/master REVISION=r3p2-01rel3-137c649 CHANGED_REVISION=137c649 CHANGE_DATE=2013-08-22 17:45:49 +0900 BUILD_DATE=Fri Aug 23 20:48:48 KST 2013 BUILD=release TARGET_PLATFORM=pegasus-m400 MALI_PLATFORM=pegasus-m400 KDIR= OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=16 USING_UMP=y USING_PROFILING= USING_INTERNAL_PROFILING= USING_GPU_UTILIZATION=1 MALI_UPPER_HALF_SCHEDULING=1";} +const char *__malidrv_build_info(void) { return "mali: BUILD=RELEASE ARCH=arch_011_udd PLATFORM=default_7a TRACE=0 THREAD= GEOM=mali_gp_geometry_common CORES=MALI400 USING_MALI400=1 TARGET_CORE_REVISION=0x0101 TOPLEVEL_REPO_URL=Linux-r3p2-01rel3 REVISION=Linux-r3p2-01rel3 CHANGED_REVISION=Linux-r3p2-01rel3 REPO_URL=Linux-r3p2-01rel3 BUILD_DATE=Tue Aug 26 17:05:16 KST 2014 CHANGE_DATE=Linux-r3p2-01rel3 TARGET_TOOLCHAIN=arm-linux-gcc HOST_TOOLCHAIN=gcc TARGET_TOOLCHAIN_VERSION=gcc version 4.6.x-google 20120106 (prerelease) (GCC) HOST_TOOLCHAIN_VERSION=gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5.1) TARGET_SYSTEM=gcc-arm-linux HOST_SYSTEM=gcc-x86_64-linux CPPFLAGS= CUSTOMER=internal VARIANT=mali400-r1p1-gles11-gles20-linux-android-max_pp_split_count_4-ump-smp-rgb_is_xrgb-jellybean_mr2-gp_cache_alloc HOSTLIB=direct INSTRUMENTED=FALSE USING_MRI=FALSE MALI_TEST_API= UDD_OS=linux";} diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8f8728b..9d09e9e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -977,6 +977,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, /* Ignore report if ErrorRollOver */ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && value[n] >= min && value[n] <= max && + value[n] - min < field->maxusage && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) goto exit; } @@ -989,11 +990,13 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, } if (field->value[n] >= min && field->value[n] <= max + && field->value[n] - min < field->maxusage && field->usage[field->value[n] - min].hid && search(value, field->value[n], count)) hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); if (value[n] >= min && value[n] <= max + && value[n] - min < field->maxusage && field->usage[value[n] - min].hid && search(field->value, value[n], count)) hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 7c1188b..fd78f2b 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -515,13 +515,13 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, goto inval; } else if (uref->usage_index >= field->report_count) goto inval; - - else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && - (uref_multi->num_values > HID_MAX_MULTI_USAGES || - uref->usage_index + uref_multi->num_values > field->report_count)) - goto inval; } + if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && + (uref_multi->num_values > HID_MAX_MULTI_USAGES || + uref->usage_index + uref_multi->num_values > field->report_count)) + goto inval; + switch (cmd) { case HIDIOCGUSAGE: uref->value = field->value[uref->usage_index]; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 61e680e..83820c0 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -570,4 +570,6 @@ config SENSORS_HALL source "drivers/input/keyboard/cypress/Kconfig" +source "drivers/input/keyboard/cypressbln/Kconfig" + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 9ac639a..5664d66 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o obj-$(CONFIG_KEYBOARD_CYPRESS_TOUCH) += cypress/ +obj-$(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN)+= cypressbln/ ifeq ($(TARGET_BUILD_VARIANT), eng) KBUILD_CFLAGS += -DSEC_TKEY_EVENT_DEBUG diff --git a/drivers/input/keyboard/cypressbln/Kconfig b/drivers/input/keyboard/cypressbln/Kconfig new file mode 100644 index 0000000..e1c0a8a --- /dev/null +++ b/drivers/input/keyboard/cypressbln/Kconfig @@ -0,0 +1,16 @@ +# +# Cypress touchkey configuration +# + +config KEYBOARD_CYPRESS_TOUCH_BLN + tristate "Cypress touchkey support" + help + Say Y here to enable the cypress touchkey with BLN support. + + To compile this driver as a module, choose M here. + +config TOUCHKEY_BLN + bool "BLN Support" + depends on KEYBOARD_CYPRESS_TOUCH_BLN + help + BLN support. diff --git a/drivers/input/keyboard/cypressbln/Makefile b/drivers/input/keyboard/cypressbln/Makefile new file mode 100644 index 0000000..a50c126 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Cypress touchkey driver +# + +obj-$(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN) += cypress-touchkey.o issp_driver_routines.o issp_main.o issp_routines.o diff --git a/drivers/input/keyboard/cypressbln/cypress-touchkey.c b/drivers/input/keyboard/cypressbln/cypress-touchkey.c new file mode 100644 index 0000000..f06eca5 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/cypress-touchkey.c @@ -0,0 +1,2466 @@ +/* + * Driver for keys on GPIO lines capable of generating interrupts. + * + * Copyright 2005 Phil Blundell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * BLN code originally by neldar. Adapted for SGSII by creams. Ported + * by gokhanmoral. + */ + +#include <linux/module.h> + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/sysctl.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <mach/regs-gpio.h> +#include <plat/gpio-cfg.h> +#include <asm/gpio.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> +#include <linux/earlysuspend.h> +#include <asm/io.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include "u1-cypress-gpio.h" + +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <plat/gpio-cfg.h> +#include <mach/gpio.h> + +#include "issp_extern.h" +#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT540E +#include <linux/i2c/mxt540e.h> +#else +#include <linux/i2c/mxt224_u1.h> +#endif + +/* +touchkey register +*/ +#define KEYCODE_REG 0x00 +#define FIRMWARE_VERSION 0x01 +#define TOUCHKEY_MODULE_VERSION 0x02 +#define TOUCHKEY_ADDRESS 0x20 + +#define UPDOWN_EVENT_BIT 0x08 +#define KEYCODE_BIT 0x07 + +#define I2C_M_WR 0 /* for i2c */ + +#define DEVICE_NAME "sec_touchkey" +#define TOUCH_FIRMWARE_V04 0x04 +#define TOUCH_FIRMWARE_V07 0x07 +#define DOOSUNGTECH_TOUCH_V1_2 0x0C + +#if defined(CONFIG_MACH_Q1_BD) +#define TK_FIRMWARE_VER 0x12 +#define TK_MODULE_VER 0x11 +#elif defined(CONFIG_MACH_C1_NA_USCC_REV05) +#define TK_FIRMWARE_VER 0x0E +#define TK_MODULE_VER 0x08 +#else +#define TK_FIRMWARE_VER 0x04 +#define TK_MODULE_VER 0x00 +#endif + +/* + * Standard CM7 LED Notification functionality. + */ +#include <linux/wakelock.h> + +#define BL_STANDARD 3000 + +int notification_timeout = -1; +int led_timeout; + +static DEFINE_SEMAPHORE(enable_sem); + +static struct timer_list breathing_timer; +static void breathe(struct work_struct *breathe_work); +static DECLARE_WORK(breathe_work, breathe); +//breathing variables +#define MAX_BREATHING_STEPS 10 +static unsigned int breathing = 0; +static int breathing_step_count = 0; +struct breathing_step { + int start; //mV + int end; //mV + int period; //ms + int step; //mV +}; +struct breathing_step breathing_steps[MAX_BREATHING_STEPS]; +static int breathing_idx = 0; +static int breathing_step_idx = 0; + + +static unsigned int touchkey_voltage = 3000; + +#if defined(CONFIG_TARGET_LOCALE_NAATT_TEMP) +/* Temp Fix NAGSM_SEL_ANDROID_MOHAMMAD_ANSARI_20111224*/ +#define CONFIG_TARGET_LOCALE_NAATT +#endif + +#if defined(CONFIG_TARGET_LOCALE_NAATT) +static int touchkey_keycode[5] = { 0, + KEY_MENU, KEY_ENTER, KEY_BACK, KEY_END }; +#elif defined(CONFIG_TARGET_LOCALE_NA) +static int touchkey_keycode[5] = { NULL, + KEY_SEARCH, KEY_BACK, KEY_HOME, KEY_MENU }; +#else +static int touchkey_keycode[3] = { 0, KEY_MENU, KEY_BACK }; +#endif +/* timer related declares */ +static struct timer_list led_timer; +static void bl_off(struct work_struct *bl_off_work); +static DECLARE_WORK(bl_off_work, bl_off); +static struct timer_list notification_timer; +static void notification_off(struct work_struct *notification_off_work); +static DECLARE_WORK(notification_off_work, notification_off); +static const int touchkey_count = sizeof(touchkey_keycode) / sizeof(int); + +#if defined(CONFIG_TARGET_LOCALE_NAATT)\ + || defined(CONFIG_TARGET_LOCALE_NA)\ + || defined(CONFIG_MACH_Q1_BD) + +static u8 home_sensitivity; +static u8 search_sensitivity; +static u16 raw_data0; +static u16 raw_data1; +static u16 raw_data2; +static u16 raw_data3; +static u8 idac0; +static u8 idac1; +static u8 idac2; +static u8 idac3; +static u8 touchkey_threshold; + +static int touchkey_autocalibration(void); +#endif +static int get_touchkey_module_version(void); + +static u8 menu_sensitivity; +static u8 back_sensitivity; + +static int touchkey_enable; +static bool touchkey_probe = true; + +struct device *sec_touchkey; + +#ifdef CONFIG_TOUCHKEY_BLN +#include <linux/miscdevice.h> +#include <linux/wakelock.h> +#define BLN_VERSION 9 + +bool bln_enabled = false; +bool BLN_ongoing = false; +bool bln_blink_enabled = false; +bool bln_suspended = false; + +static void enable_led_notification(void); +static void disable_led_notification(void); + +static struct wake_lock bln_wake_lock; +#endif + +struct i2c_touchkey_driver { + struct i2c_client *client; + struct input_dev *input_dev; + struct early_suspend early_suspend; +}; +struct i2c_touchkey_driver *touchkey_driver; +struct work_struct touchkey_work; +struct workqueue_struct *touchkey_wq; + +struct work_struct touch_update_work; +struct delayed_work touch_resume_work; + +#ifdef WHY_DO_WE_NEED_THIS +static void __iomem *gpio_pend_mask_mem; +#define INT_PEND_BASE 0xE0200A54 +#endif + +static const struct i2c_device_id sec_touchkey_id[] = { + {"sec_touchkey", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, sec_touchkey_id); + +static void init_hw(void); +static int i2c_touchkey_probe(struct i2c_client *client, + const struct i2c_device_id *id); + +extern int get_touchkey_firmware(char *version); +static int touchkey_led_status; +static int touchled_cmd_reversed; + +struct i2c_driver touchkey_i2c_driver = { + .driver = { + .name = "sec_touchkey_driver", + }, + .id_table = sec_touchkey_id, + .probe = i2c_touchkey_probe, +}; + +static int touchkey_debug_count; +static char touchkey_debug[104]; +static int touch_version; +static int module_version; +#ifdef CONFIG_TARGET_LOCALE_NA +static int store_module_version; +#endif + +static int touchkey_update_status; + +int touchkey_led_ldo_on(bool on) +{ + struct regulator *regulator; + +#if defined(CONFIG_MACH_S2PLUS) + if (on) { + gpio_direction_output(GPIO_3_TOUCH_EN, 1); + } else { + gpio_direction_output(GPIO_3_TOUCH_EN, 0); + } +#else + if (on) { + regulator = regulator_get(NULL, "touch_led"); + if (IS_ERR(regulator)) + return 0; + regulator_enable(regulator); + regulator_put(regulator); + } else { + regulator = regulator_get(NULL, "touch_led"); + if (IS_ERR(regulator)) + return 0; + if (regulator_is_enabled(regulator)) + regulator_force_disable(regulator); + regulator_put(regulator); + } +#endif + return 0; +} + +int touchkey_ldo_on(bool on) +{ + struct regulator *regulator; + +#if defined(CONFIG_MACH_S2PLUS) + if (on) { + regulator = regulator_get(NULL, "3_touch_1.8v"); + if (IS_ERR(regulator)) + return 0; + regulator_enable(regulator); + regulator_put(regulator); + } else { + regulator = regulator_get(NULL, "3_touch_1.8v"); + if (IS_ERR(regulator)) + return 0; + if (regulator_is_enabled(regulator)) + regulator_force_disable(regulator); + regulator_put(regulator); + } +#else + if (on) { + regulator = regulator_get(NULL, "touch"); + if (IS_ERR(regulator)) + return 0; + regulator_enable(regulator); + regulator_put(regulator); + } else { + regulator = regulator_get(NULL, "touch"); + if (IS_ERR(regulator)) + return 0; + if (regulator_is_enabled(regulator)) + regulator_force_disable(regulator); + regulator_put(regulator); + } +#endif + + return 1; +} + +static void change_touch_key_led_voltage(int vol_mv) +{ + struct regulator *tled_regulator; + + tled_regulator = regulator_get(NULL, "touch_led"); + if (IS_ERR(tled_regulator)) { + pr_err("%s: failed to get resource %s\n", __func__, + "touch_led"); + return; + } + regulator_set_voltage(tled_regulator, vol_mv * 1000, vol_mv * 1000); + regulator_put(tled_regulator); +} + +static ssize_t brightness_control(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int data; + + if (sscanf(buf, "%d\n", &data) == 1) { + printk(KERN_ERR "[TouchKey] touch_led_brightness: %d\n", data); + change_touch_key_led_voltage(data); + touchkey_voltage = data; + } else { + printk(KERN_ERR "[TouchKey] touch_led_brightness Error\n"); + } + + return size; +} + +void stop_breathing(void) +{ + del_timer(&breathing_timer); + change_touch_key_led_voltage(touchkey_voltage); +} + +static void set_touchkey_debug(char value) +{ + if (touchkey_debug_count == 100) + touchkey_debug_count = 0; + + touchkey_debug[touchkey_debug_count] = value; + touchkey_debug_count++; +} + +static int i2c_touchkey_read(u8 reg, u8 *val, unsigned int len) +{ + int err = 0; + int retry = 2; + struct i2c_msg msg[1]; + + if ((touchkey_driver == NULL) || !(touchkey_enable == 1) + || !touchkey_probe) { + printk(KERN_ERR "[TouchKey] touchkey is not enabled. %d\n", + __LINE__); + return -ENODEV; + } + + while (retry--) { + msg->addr = touchkey_driver->client->addr; + msg->flags = I2C_M_RD; + msg->len = len; + msg->buf = val; + err = i2c_transfer(touchkey_driver->client->adapter, msg, 1); + + if (err >= 0) + return 0; + printk(KERN_ERR "[TouchKey] %s %d i2c transfer error\n", + __func__, __LINE__); + mdelay(10); + } + return err; + +} + +static int i2c_touchkey_write(u8 *val, unsigned int len) +{ + int err = 0; + struct i2c_msg msg[1]; + int retry = 2; + + if ((touchkey_driver == NULL) || !(touchkey_enable == 1) + || !touchkey_probe) { + printk(KERN_ERR "[TouchKey] touchkey is not enabled. %d\n", + __LINE__); + return -ENODEV; + } + + while (retry--) { + msg->addr = touchkey_driver->client->addr; + msg->flags = I2C_M_WR; + msg->len = len; + msg->buf = val; + err = i2c_transfer(touchkey_driver->client->adapter, msg, 1); + + if (err >= 0) + return 0; + + printk(KERN_DEBUG "[TouchKey] %s %d i2c transfer error\n", + __func__, __LINE__); + mdelay(10); + } + return err; +} + +#if defined(CONFIG_TARGET_LOCALE_NAATT) \ +|| defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) +static int touchkey_autocalibration(void) +{ + u8 data[6] = { 0, }; + int count = 0; + int ret = 0; + unsigned short retry = 0; + + while (retry < 3) { + ret = i2c_touchkey_read(KEYCODE_REG, data, 4); + if (ret < 0) { + printk(KERN_ERR "[TouchKey]i2c read fail.\n"); + return ret; + } + printk(KERN_DEBUG + "[TouchKey] %s : data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", + __func__, data[0], data[1], data[2], data[3]); + + /* Send autocal Command */ + data[0] = 0x50; + data[3] = 0x01; + + count = i2c_touchkey_write(data, 4); + + msleep(100); + + /* Check autocal status */ + ret = i2c_touchkey_read(KEYCODE_REG, data, 6); + + if ((data[5] & 0x80)) { + printk(KERN_DEBUG "[Touchkey] autocal Enabled\n"); + break; + } else + printk(KERN_DEBUG + "[Touchkey] autocal disabled, retry %d\n", + retry); + + retry = retry + 1; + } + + if (retry == 3) + printk(KERN_DEBUG "[Touchkey] autocal failed\n"); + + return count; +} +#endif + +#ifdef CONFIG_TARGET_LOCALE_NAATT +static ssize_t set_touchkey_autocal_testmode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int count = 0; + u8 set_data; + int on_off; + + if (sscanf(buf, "%d\n", &on_off) == 1) { + printk(KERN_ERR "[TouchKey] Test Mode : %d\n", on_off); + + if (on_off == 1) { + set_data = 0x40; + count = i2c_touchkey_write(&set_data, 1); + } else { + touchkey_ldo_on(0); + msleep(50); + touchkey_ldo_on(1); + msleep(50); + init_hw(); + msleep(50); +#if defined(CONFIG_TARGET_LOCALE_NAATT) \ +|| defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) + touchkey_autocalibration(); +#endif + } + } else { + printk(KERN_ERR "[TouchKey] touch_led_brightness Error\n"); + } + + return count; +} +#endif + +#if defined(CONFIG_TARGET_LOCALE_NAATT) \ +|| defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) +static ssize_t touchkey_raw_data0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[26] = { 0, }; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 26); +#if defined(CONFIG_TARGET_LOCALE_NA) + printk(KERN_DEBUG "called %s data[18] =%d,data[19] = %d\n", __func__, + data[18], data[19]); + raw_data0 = ((0x00FF & data[18]) << 8) | data[19]; +#elif defined(CONFIG_MACH_Q1_BD) + printk(KERN_DEBUG "called %s data[16] =%d,data[17] = %d\n", __func__, + data[16], data[17]); + raw_data0 = ((0x00FF & data[14]) << 8) | data[15]; +#else + printk(KERN_DEBUG "called %s data[18] =%d,data[19] = %d\n", __func__, + data[10], data[11]); + raw_data0 = ((0x00FF & data[10]) << 8) | data[11]; +#endif + return sprintf(buf, "%d\n", raw_data0); +} + +static ssize_t touchkey_raw_data1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[26] = { 0, }; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 26); +#if defined(CONFIG_TARGET_LOCALE_NA) + printk(KERN_DEBUG "called %s data[20] =%d,data[21] = %d\n", __func__, + data[20], data[21]); + raw_data1 = ((0x00FF & data[20]) << 8) | data[21]; +#elif defined(CONFIG_MACH_Q1_BD) + printk(KERN_DEBUG "called %s data[14] =%d,data[15] = %d\n", __func__, + data[14], data[15]); + raw_data1 = ((0x00FF & data[16]) << 8) | data[17]; +#else + printk(KERN_DEBUG "called %s data[20] =%d,data[21] = %d\n", __func__, + data[12], data[13]); + raw_data1 = ((0x00FF & data[12]) << 8) | data[13]; +#endif /* CONFIG_TARGET_LOCALE_NA */ + return sprintf(buf, "%d\n", raw_data1); +} + +static ssize_t touchkey_raw_data2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[26] = { 0, }; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 26); +#if defined(CONFIG_TARGET_LOCALE_NA) + printk(KERN_DEBUG "called %s data[22] =%d,data[23] = %d\n", __func__, + data[22], data[23]); + raw_data2 = ((0x00FF & data[22]) << 8) | data[23]; +#else + printk(KERN_DEBUG "called %s data[22] =%d,data[23] = %d\n", __func__, + data[14], data[15]); + raw_data2 = ((0x00FF & data[14]) << 8) | data[15]; +#endif /* CONFIG_TARGET_LOCALE_NA */ + return sprintf(buf, "%d\n", raw_data2); +} + +static ssize_t touchkey_raw_data3_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[26] = { 0, }; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 26); +#if defined(CONFIG_TARGET_LOCALE_NA) + printk(KERN_DEBUG "called %s data[24] =%d,data[25] = %d\n", __func__, + data[24], data[25]); + raw_data3 = ((0x00FF & data[24]) << 8) | data[25]; +#else + printk(KERN_DEBUG "called %s data[24] =%d,data[25] = %d\n", __func__, + data[16], data[17]); + raw_data3 = ((0x00FF & data[16]) << 8) | data[17]; +#endif /* CONFIG_TARGET_LOCALE_NA */ + return sprintf(buf, "%d\n", raw_data3); +} + +static ssize_t touchkey_idac0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[10]; + int ret; +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) + return 0; +#endif + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 10); + printk(KERN_DEBUG "called %s data[6] =%d\n", __func__, data[6]); + idac0 = data[6]; + return sprintf(buf, "%d\n", idac0); +} + +static ssize_t touchkey_idac1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[10]; + int ret; +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) + return 0; +#endif + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 10); + printk(KERN_DEBUG "called %s data[7] = %d\n", __func__, data[7]); + idac1 = data[7]; + return sprintf(buf, "%d\n", idac1); +} + +static ssize_t touchkey_idac2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[10]; + int ret; +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) + return 0; +#endif + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 10); + printk(KERN_DEBUG "called %s data[8] =%d\n", __func__, data[8]); + idac2 = data[8]; + return sprintf(buf, "%d\n", idac2); +} + +static ssize_t touchkey_idac3_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[10]; + int ret; +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) + return 0; +#endif + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 10); + printk(KERN_DEBUG "called %s data[9] = %d\n", __func__, data[9]); + idac3 = data[9]; + return sprintf(buf, "%d\n", idac3); +} + +static ssize_t touchkey_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[10]; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 10); + printk(KERN_DEBUG "called %s data[4] = %d\n", __func__, data[4]); + touchkey_threshold = data[4]; + return sprintf(buf, "%d\n", touchkey_threshold); +} +#endif + +#if defined(CONFIG_MACH_C1_NA_SPR_EPIC2_REV00) \ + || defined(CONFIG_MACH_Q1_BD) \ + || defined(CONFIG_MACH_C1_NA_USCC_REV05) \ + || defined(CONFIG_TARGET_LOCALE_NA) +void touchkey_firmware_update(void) +{ + char data[3]; + int retry = 3; + int ret = 0; + + ret = i2c_touchkey_read(KEYCODE_REG, data, 3); + if (ret < 0) { + printk(KERN_DEBUG + "[TouchKey] i2c read fail. do not excute firm update.\n"); + return; + } + + touch_version = data[1]; + module_version = data[2]; + +#ifdef CONFIG_MACH_C1_NA_SPR_EPIC2_REV00 + if (system_rev > 6) { + printk(KERN_DEBUG "[TouchKey] not firmup hw(system_rev=%d)\n", + system_rev); + return; + } +#endif + + if ((touch_version < TK_FIRMWARE_VER) && + (module_version == TK_MODULE_VER)) { + printk(KERN_DEBUG "[TouchKey] firmware auto update excute\n"); + disable_irq(IRQ_TOUCH_INT); + touchkey_update_status = 1; + + while (retry--) { + if (ISSP_main() == 0) { + printk(KERN_DEBUG + "[TouchKey]firmware update succeeded\n"); + touchkey_update_status = 0; + break; + } + msleep(100); + printk(KERN_DEBUG + "[TouchKey] firmware update failed. retry\n"); + } + if (retry <= 0) { + touchkey_ldo_on(0); + touchkey_update_status = -1; + printk(KERN_DEBUG + "[TouchKey] firmware update failed.\n"); + msleep(300); + } + enable_irq(IRQ_TOUCH_INT); + init_hw(); + } else { + printk(KERN_DEBUG + "[TouchKey] firmware auto update do not excute\n"); + printk(KERN_DEBUG + "[TouchKey] firmware_ver(banary=%d, current=%d)\n", + TK_FIRMWARE_VER, touch_version); + printk(KERN_DEBUG + "[TouchKey] module_ver(banary=%d, current=%d)\n", + TK_MODULE_VER, module_version); + return; + } + msleep(100); + i2c_touchkey_read(KEYCODE_REG, data, 3); + touch_version = data[1]; + module_version = data[2]; + printk(KERN_DEBUG "[TouchKey] firm ver = %d, module ver = %d\n", + touch_version, module_version); +} +#else +void touchkey_firmware_update(void) +{ + char data[3]; + int retry; + int ret = 0; + + ret = i2c_touchkey_read(KEYCODE_REG, data, 3); + if (ret < 0) { + printk(KERN_DEBUG + "[TouchKey] i2c read fail. do not excute firm update.\n"); + return; + } + + printk(KERN_ERR "%s F/W version: 0x%x, Module version:0x%x\n", __func__, + data[1], data[2]); + retry = 3; + + touch_version = data[1]; + module_version = data[2]; + + if (touch_version < 0x0A) { + touchkey_update_status = 1; + while (retry--) { + if (ISSP_main() == 0) { + printk(KERN_ERR + "[TOUCHKEY]Touchkey_update succeeded\n"); + touchkey_update_status = 0; + break; + } + printk(KERN_ERR "touchkey_update failed...retry...\n"); + } + if (retry <= 0) { + touchkey_ldo_on(0); + touchkey_update_status = -1; + msleep(300); + } + + init_hw(); + } else { + if (touch_version >= 0x0A) { + printk(KERN_ERR + "[TouchKey] Not F/W update. Cypess touch-key F/W version is latest\n"); + } else { + printk(KERN_ERR + "[TouchKey] Not F/W update. Cypess touch-key version(module or F/W) is not valid\n"); + } + } +} +#endif + +#ifndef TEST_JIG_MODE +void touchkey_work_func(struct work_struct *p) +{ + u8 data[3]; + int ret; + int retry = 10; + int keycode_type = 0; + int pressed; + int status; + + set_touchkey_debug('a'); + + retry = 3; + while (retry--) { + ret = i2c_touchkey_read(KEYCODE_REG, data, 3); + if (!ret) + break; + else { + printk(KERN_DEBUG + "[TouchKey] i2c read failed, ret:%d, retry: %d\n", + ret, retry); + continue; + } + } + if (ret < 0) { + enable_irq(IRQ_TOUCH_INT); + return; + } + set_touchkey_debug(data[0]); + + keycode_type = (data[0] & KEYCODE_BIT); + pressed = !(data[0] & UPDOWN_EVENT_BIT); + + if (keycode_type <= 0 || keycode_type >= touchkey_count) { + printk(KERN_DEBUG "[Touchkey] keycode_type err\n"); + enable_irq(IRQ_TOUCH_INT); + return; + } + + if (pressed) + set_touchkey_debug('P'); + + if (get_tsp_status() && pressed) + printk(KERN_DEBUG "[TouchKey] touchkey pressed but don't send event because touch is pressed.\n"); + else { + input_report_key(touchkey_driver->input_dev, + touchkey_keycode[keycode_type], pressed); + input_sync(touchkey_driver->input_dev); + /* printk(KERN_DEBUG "[TouchKey] keycode:%d pressed:%d\n", + touchkey_keycode[keycode_index], pressed); */ + } + + /* we have timed out or the lights should be on */ + if (led_timeout > 0) { + status = 1; + i2c_touchkey_write((u8 *)&status, 1); /* turn on */ + } + + /* restart the timer */ + if (led_timeout > 0) { + mod_timer(&led_timer, jiffies + msecs_to_jiffies(led_timeout)); + } + + set_touchkey_debug('A'); + enable_irq(IRQ_TOUCH_INT); +} +#else +void touchkey_work_func(struct work_struct *p) +{ + u8 data[18]; + int ret; + int retry = 10; + int keycode_type = 0; + int pressed; + +#if 0 + if (gpio_get_value(_3_GPIO_TOUCH_INT)) { + printk(KERN_DEBUG "[TouchKey] Unknown state.\n", __func__); + enable_irq(IRQ_TOUCH_INT); + return; + } +#endif + + set_touchkey_debug('a'); + +#ifdef CONFIG_CPU_FREQ + /* set_dvfs_target_level(LEV_800MHZ); */ +#endif + + retry = 3; + while (retry--) { +#if defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) + ret = i2c_touchkey_read(KEYCODE_REG, data, 18); +#else + ret = i2c_touchkey_read(KEYCODE_REG, data, 10); +#endif + if (!ret) + break; + else { + printk(KERN_DEBUG + "[TouchKey] i2c read failed, ret:%d, retry: %d\n", + ret, retry); + continue; + } + } + if (ret < 0) { + enable_irq(IRQ_TOUCH_INT); + return; + } +#if defined(CONFIG_TARGET_LOCALE_NA) +#if defined(CONFIG_MACH_C1_NA_SPR_EPIC2_REV00) + menu_sensitivity = data[11]; + home_sensitivity = data[13]; + search_sensitivity = data[15]; + back_sensitivity = data[17]; +#else + if (store_module_version >= 8) { + menu_sensitivity = data[17]; + home_sensitivity = data[15]; + search_sensitivity = data[11]; + back_sensitivity = data[13]; + } else { + menu_sensitivity = data[6]; + home_sensitivity = data[7]; + search_sensitivity = data[8]; + back_sensitivity = data[9]; + } +#endif +#elif defined(CONFIG_MACH_Q1_BD) + menu_sensitivity = data[13]; + back_sensitivity = data[11]; +#else + menu_sensitivity = data[7]; + back_sensitivity = data[9]; +#endif /* CONFIG_TARGET_LOCALE_NA */ + + set_touchkey_debug(data[0]); + + keycode_type = (data[0] & KEYCODE_BIT); + pressed = !(data[0] & UPDOWN_EVENT_BIT); + + if (keycode_type <= 0 || keycode_type >= touchkey_count) { + printk(KERN_DEBUG "[Touchkey] keycode_type err\n"); + enable_irq(IRQ_TOUCH_INT); + return; + } + + if (pressed) + set_touchkey_debug('P'); + + if (get_tsp_status() && pressed) + printk(KERN_DEBUG "[TouchKey] touchkey pressed" + " but don't send event because touch is pressed.\n"); + else { + input_report_key(touchkey_driver->input_dev, + touchkey_keycode[keycode_type], pressed); + input_sync(touchkey_driver->input_dev); + /* printk(KERN_DEBUG "[TouchKey] keycode:%d pressed:%d\n", + touchkey_keycode[keycode_index], pressed); */ + } + + if (keycode_type == 1) + printk(KERN_DEBUG "search key sensitivity = %d\n", + search_sensitivity); + if (keycode_type == 2) + printk(KERN_DEBUG "back key sensitivity = %d\n", + back_sensitivity); +#ifdef CONFIG_TARGET_LOCALE_NA + if (keycode_type == 3) + printk(KERN_DEBUG "home key sensitivity = %d\n", + home_sensitivity); + if (keycode_type == 4) + printk(KERN_DEBUG "menu key sensitivity = %d\n", + menu_sensitivity); +#endif + +#ifdef WHY_DO_WE_NEED_THIS + /* clear interrupt */ + if (readl(gpio_pend_mask_mem) & (0x1 << 1)) { + writel(readl(gpio_pend_mask_mem) | (0x1 << 1), + gpio_pend_mask_mem); + } +#endif + set_touchkey_debug('A'); + enable_irq(IRQ_TOUCH_INT); +} +#endif + +static irqreturn_t touchkey_interrupt(int irq, void *dummy) +{ +#ifdef CONFIG_TOUCHKEY_BLN + printk(KERN_ERR "[TouchKey] interrupt touchkey\n"); +#endif + set_touchkey_debug('I'); + disable_irq_nosync(IRQ_TOUCH_INT); + queue_work(touchkey_wq, &touchkey_work); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static int sec_touchkey_early_suspend(struct early_suspend *h) +{ + int ret; + int i; + + disable_irq(IRQ_TOUCH_INT); + ret = cancel_work_sync(&touchkey_work); + if (ret) { + printk(KERN_DEBUG "[Touchkey] enable_irq ret=%d\n", ret); + enable_irq(IRQ_TOUCH_INT); + } + + /* release keys */ + for (i = 1; i < touchkey_count; ++i) { + input_report_key(touchkey_driver->input_dev, + touchkey_keycode[i], 0); + } + + touchkey_enable = 0; + set_touchkey_debug('S'); + printk(KERN_DEBUG "[TouchKey] sec_touchkey_early_suspend\n"); + if (touchkey_enable < 0) { + printk(KERN_DEBUG "[TouchKey] ---%s---touchkey_enable: %d\n", + __func__, touchkey_enable); + return 0; + } + + gpio_direction_input(_3_GPIO_TOUCH_INT); +#if 0 + gpio_direction_output(_3_GPIO_TOUCH_EN, 0); + gpio_direction_output(_3_TOUCH_SDA_28V, 0); + gpio_direction_output(_3_TOUCH_SCL_28V, 0); + s3c_gpio_setpull(_3_GPIO_TOUCH_INT, S3C_GPIO_PULL_DOWN); +#endif + + /* disable ldo18 */ + touchkey_led_ldo_on(0); + + /* disable ldo11 */ + touchkey_ldo_on(0); + + bln_suspended = 1; + return 0; +} + +static int sec_touchkey_late_resume(struct early_suspend *h) +{ +#ifdef TEST_JIG_MODE + unsigned char get_touch = 0x40; +#endif + int status; + + set_touchkey_debug('R'); + printk(KERN_DEBUG "[TouchKey] sec_touchkey_late_resume\n"); + + /* Avoid race condition with LED notification disable */ + down(&enable_sem); + + /* enable ldo11 */ + touchkey_ldo_on(1); + + if (touchkey_enable < 0) { + printk(KERN_DEBUG "[TouchKey] ---%s---touchkey_enable: %d\n", + __func__, touchkey_enable); + return 0; + } + gpio_direction_output(_3_GPIO_TOUCH_EN, 1); + gpio_direction_output(_3_TOUCH_SDA_28V, 1); + gpio_direction_output(_3_TOUCH_SCL_28V, 1); + + gpio_direction_output(_3_GPIO_TOUCH_INT, 1); + irq_set_irq_type(IRQ_TOUCH_INT, IRQF_TRIGGER_FALLING); + s3c_gpio_cfgpin(_3_GPIO_TOUCH_INT, _3_GPIO_TOUCH_INT_AF); + s3c_gpio_setpull(_3_GPIO_TOUCH_INT, S3C_GPIO_PULL_NONE); + msleep(50); + touchkey_led_ldo_on(1); + +#ifdef WHY_DO_WE_NEED_THIS + /* clear interrupt */ + if (readl(gpio_pend_mask_mem) & (0x1 << 1)) { + writel(readl(gpio_pend_mask_mem) | (0x1 << 1), + gpio_pend_mask_mem); + } +#endif + + touchkey_enable = 1; + + bln_suspended = 0; + /* see if late_resume is running before DISABLE_BL */ + if (BLN_ongoing) { + /* if a notification timeout was set, disable the timer */ + if (notification_timeout > 0) { + del_timer(¬ification_timer); + } + if (breathing) stop_breathing(); + + /* we were using a wakelock, unlock it */ + if( wake_lock_active(&bln_wake_lock) ){ + printk(KERN_DEBUG "[TouchKey] touchkey clear wake_lock\n"); + wake_unlock(&bln_wake_lock); + } + /* force DISABLE_BL to ignore the led state because we want it left on */ + BLN_ongoing = 0; + } + +#if defined(CONFIG_TARGET_LOCALE_NAATT) \ +|| defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) +#if defined(CONFIG_TARGET_LOCALE_NA) + if (store_module_version >= 8) { +#endif + msleep(50); + touchkey_autocalibration(); + msleep(200); +#if defined(CONFIG_TARGET_LOCALE_NA) + } +#endif /* CONFIG_TARGET_LOCALE_NA */ +#endif + + if (touchled_cmd_reversed) { + touchled_cmd_reversed = 0; + i2c_touchkey_write((u8 *) &touchkey_led_status, 1); + printk(KERN_DEBUG "LED returned on\n"); + } +#ifdef TEST_JIG_MODE + i2c_touchkey_write(&get_touch, 1); +#endif + + /* restart the timer if needed */ + if (led_timeout > 0) { + mod_timer(&led_timer, jiffies + msecs_to_jiffies(led_timeout)); + } + + /* all done, turn on IRQ */ + enable_irq(IRQ_TOUCH_INT); + + /* Avoid race condition with LED notification disable */ + up(&enable_sem); + + return 0; +} +#endif + +#ifdef CONFIG_TOUCHKEY_BLN + +static void touchkey_activate(void){ + + if( !wake_lock_active(&bln_wake_lock) ){ + printk(KERN_DEBUG "[TouchKey] touchkey get wake_lock\n"); + wake_lock(&bln_wake_lock); + } + + printk(KERN_DEBUG "[TouchKey] touchkey activate.\n"); + touchkey_ldo_on(1); + + msleep(50); + touchkey_led_ldo_on(1); + + touchkey_enable = 1; +} + +static void touchkey_deactivate(void){ + + touchkey_led_ldo_on(0); + touchkey_ldo_on(0); + + if( wake_lock_active(&bln_wake_lock) ){ + printk(KERN_DEBUG "[TouchKey] touchkey clear wake_lock\n"); + wake_unlock(&bln_wake_lock); + } + + touchkey_enable = 0; +} + +static void bln_late_resume(struct early_suspend *h){ + + /* the lights should be off */ + //we only need this part to disable lights way before ROM specific parts interfere -gm + int status; + status = 2; + i2c_touchkey_write((u8 *)&status, 1); /* turn off */ +} + +static struct early_suspend bln_suspend_data = { + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, + .resume = bln_late_resume, +}; + +static void enable_touchkey_backlights(void){ + int status = 1; + printk(KERN_ERR "[TouchKey] enable LED from BLN app\n"); + i2c_touchkey_write((u8 *)&status, 1 ); +} + +static void disable_touchkey_backlights(void){ + int status = 2; + printk(KERN_ERR "[TouchKey] disable LED from BLN app\n"); + i2c_touchkey_write((u8 *)&status, 1 ); +} + +static void enable_led_notification(void){ + + if( bln_enabled ){ + if( touchkey_enable != 1 ){ + if( bln_suspended ){ + touchkey_activate(); + } + } + if( touchkey_enable == 1 ){ + printk(KERN_DEBUG "[TouchKey] BLN_ongoing set to true\n"); + BLN_ongoing = true; + enable_touchkey_backlights(); + } + /* See if a timeout value has been set for the notification */ + if (notification_timeout > 0) { + /* restart the timer */ + mod_timer(¬ification_timer, jiffies + msecs_to_jiffies(notification_timeout)); + } + if ( breathing ) mod_timer(&breathing_timer, jiffies + 4); + + } + +} + +static void disable_led_notification(void){ + + down(&enable_sem); + bln_blink_enabled = false; + BLN_ongoing = false; + printk(KERN_DEBUG "[TouchKey] BLN_ongoing set to false\n"); + + if( touchkey_enable == 1 ){ + disable_touchkey_backlights(); + if( bln_suspended ){ + touchkey_deactivate(); + } + /* a notification timeout was set, disable the timer */ + if (notification_timeout > 0) { + del_timer(¬ification_timer); + } + if (breathing) stop_breathing(); + } + up(&enable_sem); +} + +static ssize_t bln_status_read( struct device *dev, struct device_attribute *attr, char *buf ){ + return sprintf(buf,"%u\n", (bln_enabled ? 1 : 0 )); +} + +static ssize_t bln_status_write( struct device *dev, struct device_attribute *attr, const char *buf, size_t size ){ + unsigned int data; + + if(sscanf(buf,"%u\n", &data) == 1 ){ + if( data == 0 || data == 1 ){ + + if( data == 1 ){ + bln_enabled = true; + } + + if( data == 0 ){ + bln_enabled = false; + if( BLN_ongoing ) + disable_led_notification(); + } + + }else{ + /* error */ + } + }else{ + if( !strncmp(buf, "on", 2) ) bln_enabled = true; + if( !strncmp(buf, "off", 3) ) { + bln_enabled = false; + if( BLN_ongoing ) + disable_led_notification(); + } + } + + return size; +} + +static ssize_t notification_led_status_read( struct device *dev, struct device_attribute *attr, char *buf ){ + return sprintf(buf,"%u\n", (BLN_ongoing ? 1 : 0 )); +} + +static ssize_t notification_led_status_write( struct device *dev, struct device_attribute *attr, const char *buf, size_t size ){ + unsigned int data; + + + if(sscanf(buf,"%u\n", &data ) == 1 ){ + if( data == 0 || data == 1 ){ + if( data == 1 ) + enable_led_notification(); + + if( data == 0 ) + disable_led_notification(); + }else{ + /* error */ + } + }else{ + /* error */ + } + + return size; +} + +static ssize_t blink_control_read( struct device *dev, struct device_attribute *attr, char *buf ){ + return sprintf( buf, "%u\n", (bln_blink_enabled ? 1 : 0 ) ); +} + +static ssize_t blink_control_write( struct device *dev, struct device_attribute *attr, const char *buf, size_t size ){ + unsigned int data; + + if( sscanf(buf, "%u\n", &data ) == 1 ){ + if( data == 0 || data == 1 ){ + if (data == 1){ + bln_blink_enabled = true; + disable_touchkey_backlights(); + } + + if(data == 0){ + bln_blink_enabled = false; + enable_touchkey_backlights(); + } + } + } + + return size; +} + +static ssize_t bln_version( struct device *dev, struct device_attribute *attr, char *buf ){ + return sprintf(buf,"%u\n", BLN_VERSION); +} + +static DEVICE_ATTR(blink_control, S_IRUGO | S_IWUGO, blink_control_read, blink_control_write ); +static DEVICE_ATTR(enabled, S_IRUGO | S_IWUGO, bln_status_read, bln_status_write ); +static DEVICE_ATTR(notification_led, S_IRUGO | S_IWUGO, notification_led_status_read, notification_led_status_write ); +static DEVICE_ATTR(version, S_IRUGO, bln_version, NULL ); + +static struct attribute *bln_notification_attributes[] = { + &dev_attr_blink_control.attr, + &dev_attr_enabled.attr, + &dev_attr_notification_led.attr, + &dev_attr_version.attr, + NULL +}; + + +/* + * Start of the main LED Notify code block + */ +static void bl_off(struct work_struct *bl_off_work) +{ + int status; + + /* do nothing if there is an active notification */ + if (BLN_ongoing == 1 || touchkey_enable != 1) + return; + + /* we have timed out, turn the lights off */ + status = 2; + i2c_touchkey_write((u8 *)&status, 1); + + return; +} + +static void handle_led_timeout(unsigned long data) +{ + /* we cannot call the timeout directly as it causes a kernel spinlock BUG, schedule it instead */ + schedule_work(&bl_off_work); +} + +static void notification_off(struct work_struct *notification_off_work) +{ + /* do nothing if there is no active notification */ + if (BLN_ongoing != 1 || touchkey_enable != 1) + return; + + disable_touchkey_backlights(); + touchkey_deactivate(); + BLN_ongoing = 0; +} + +static void handle_notification_timeout(unsigned long data) +{ + /* we cannot call the timeout directly as it causes a kernel spinlock BUG, schedule it instead */ + schedule_work(¬ification_off_work); +} + +static ssize_t led_timeout_read( struct device *dev, struct device_attribute *attr, char *buf ) +{ + return sprintf(buf,"%d\n", led_timeout); +} + +static ssize_t led_timeout_write( struct device *dev, struct device_attribute *attr, const char *buf, size_t size ) +{ + sscanf(buf,"%d\n", &led_timeout); + if(led_timeout == 0) del_timer(&led_timer); + else mod_timer(&led_timer, jiffies + msecs_to_jiffies(led_timeout)); + return size; +} + +static ssize_t notification_timeout_read( struct device *dev, struct device_attribute *attr, char *buf ) +{ + return sprintf(buf,"%d\n", notification_timeout); +} + +static ssize_t notification_timeout_write( struct device *dev, struct device_attribute *attr, const char *buf, size_t size ) +{ + sscanf(buf,"%d\n", ¬ification_timeout); + return size; +} + +static void breathe(struct work_struct *notification_off_work) +{ + int data; + if (BLN_ongoing != 1 || touchkey_enable != 1) + return; + + if( breathing_steps[breathing_step_idx].start <= breathing_steps[breathing_step_idx].end ) + { + data = breathing_steps[breathing_step_idx].start + + breathing_idx++ * breathing_steps[breathing_step_idx].step; + if( data > breathing_steps[breathing_step_idx].end ) + { + breathing_idx = 0; + breathing_step_idx++; + if( breathing_step_idx >= breathing_step_count ) breathing_step_idx = 0; + data = breathing_steps[breathing_step_idx].start; + } + } + else + { + data = breathing_steps[breathing_step_idx].start - + breathing_idx++ * breathing_steps[breathing_step_idx].step; + if( data < breathing_steps[breathing_step_idx].end ) + { + breathing_idx = 0; + breathing_step_idx++; + if( breathing_step_idx >= breathing_step_count ) breathing_step_idx = 0; + data = breathing_steps[breathing_step_idx].start; + } + } + + change_touch_key_led_voltage(data); + mod_timer(&breathing_timer, jiffies + msecs_to_jiffies(breathing_steps[breathing_step_idx].period)); +} + +static void handle_breathe(unsigned long data) +{ + schedule_work(&breathe_work); +} + +static ssize_t breathing_read( struct device *dev, struct device_attribute *attr, char *buf ) +{ + return sprintf(buf,"%d\n", breathing); +} +static ssize_t breathing_write( struct device *dev, struct device_attribute *attr, const char *buf, size_t size ) +{ + if( !strncmp(buf, "on", 2) ) breathing = 1; + else if( !strncmp(buf, "off", 3) ) breathing = 0; + else sscanf(buf,"%d\n", &breathing); + if( breathing != 1 ) stop_breathing(); + return size; +} + +void reset_breathing_steps(void) +{ + //this will reset steps to have steady bln + breathing_step_count = 0; + breathing_steps[0].start = 3000; + breathing_steps[0].end = 3000; + breathing_steps[0].period = 1000; + breathing_steps[0].step = 50; +} + +static ssize_t breathing_steps_read( struct device *dev, struct device_attribute *attr, char *buf ) +{ + int count = ( breathing_step_count == 0 ? 1 : breathing_step_count ); + int i, len = 0; + for(i=0; i<count; i++) + { + len += sprintf(buf + len, "%dmV %dmV %dms %dmV\n", breathing_steps[i].start, breathing_steps[i].end, + breathing_steps[i].period, breathing_steps[i].step); + } + return len; +} + +static ssize_t breathing_steps_write( struct device *dev, struct device_attribute *attr, const char *buf, size_t size ) +{ + int ret; + int bstart, bend, bperiod, bstep; + + if(!strncmp(buf, "reset", 5)) { + reset_breathing_steps(); + return size; + } + if(breathing_step_count >= MAX_BREATHING_STEPS) return -EINVAL; + ret = sscanf(buf, "%d %d %d %d", &bstart, &bend, &bperiod, &bstep); + if(ret != 4) return -EINVAL; + breathing_steps[breathing_step_count].start = bstart; + breathing_steps[breathing_step_count].end = bend; + breathing_steps[breathing_step_count].period = bperiod; + breathing_steps[breathing_step_count].step = bstep; + breathing_step_count++; + breathing_idx = 0; + breathing_step_idx = 0; + return size; +} + +static struct miscdevice led_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "notification", +}; + +static DEVICE_ATTR(led, S_IRUGO | S_IWUGO, notification_led_status_read, notification_led_status_write ); +static DEVICE_ATTR(notification_timeout, S_IRUGO | S_IWUGO, notification_timeout_read, notification_timeout_write ); +static DEVICE_ATTR(led_timeout, S_IRUGO | S_IWUGO, led_timeout_read, led_timeout_write ); +static DEVICE_ATTR(bl_timeout, S_IRUGO | S_IWUGO, led_timeout_read, led_timeout_write ); +static DEVICE_ATTR(notification_enabled, S_IRUGO | S_IWUGO, bln_status_read, bln_status_write ); +static DEVICE_ATTR(breathing, S_IRUGO | S_IWUGO, breathing_read, breathing_write ); +static DEVICE_ATTR(breathing_steps, S_IRUGO | S_IWUGO, breathing_steps_read, breathing_steps_write ); + +static struct attribute *led_notification_attributes[] = { + &dev_attr_led.attr, + &dev_attr_led_timeout.attr, + &dev_attr_bl_timeout.attr, + &dev_attr_notification_timeout.attr, + &dev_attr_notification_enabled.attr, + &dev_attr_breathing.attr, + &dev_attr_breathing_steps.attr, + NULL +}; + +static struct attribute_group led_notification_group = { + .attrs = led_notification_attributes, +}; + +static struct attribute_group bln_notification_group = { + .attrs = bln_notification_attributes, +}; + +static struct miscdevice bln_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "backlightnotification", +}; + +extern void (*mxt224_touch_cb)(void); + +void cypress_notify_touch(void) +{ + unsigned int status; + if (led_timeout > 0) { + status = 1; + i2c_touchkey_write((u8 *)&status, 1); /* turn on */ + } + if (led_timeout > 0) { + mod_timer(&led_timer, jiffies + msecs_to_jiffies(led_timeout)); + } +} + +#endif + +extern int mcsdl_download_binary_data(void); +static int i2c_touchkey_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct input_dev *input_dev; + int err = 0; + unsigned char data; + int i; + int module_version; + int status; + + printk(KERN_DEBUG "[TouchKey] i2c_touchkey_probe\n"); + + touchkey_driver = + kzalloc(sizeof(struct i2c_touchkey_driver), GFP_KERNEL); + if (touchkey_driver == NULL) { + dev_err(dev, "failed to create our state\n"); + return -ENOMEM; + } + + touchkey_driver->client = client; + touchkey_driver->client->irq = IRQ_TOUCH_INT; + strlcpy(touchkey_driver->client->name, "sec_touchkey", I2C_NAME_SIZE); + + input_dev = input_allocate_device(); + + if (!input_dev) + return -ENOMEM; + + touchkey_driver->input_dev = input_dev; + + input_dev->name = DEVICE_NAME; + input_dev->phys = "sec_touchkey/input0"; + input_dev->id.bustype = BUS_HOST; + + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_LED, input_dev->evbit); + set_bit(LED_MISC, input_dev->ledbit); + set_bit(EV_KEY, input_dev->evbit); + + for (i = 1; i < touchkey_count; i++) + set_bit(touchkey_keycode[i], input_dev->keybit); + + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } +#ifdef WHY_DO_WE_NEED_THIS + gpio_pend_mask_mem = ioremap(INT_PEND_BASE, 0x10); +#endif + +#if defined(CONFIG_MACH_S2PLUS) + gpio_request(GPIO_3_TOUCH_EN, "gpio_3_touch_en"); +#endif + + /* enable ldo18 */ + touchkey_ldo_on(1); + + msleep(50); + + touchkey_enable = 1; + data = 1; + + module_version = get_touchkey_module_version(); + if (module_version < 0) { + printk(KERN_ERR "[TouchKey] Probe fail\n"); + input_unregister_device(input_dev); + touchkey_probe = false; + return -ENODEV; + } + +#ifdef CONFIG_TARGET_LOCALE_NA + store_module_version = module_version; +#endif /* CONFIG_TARGET_LOCALE_NA */ + if (request_irq + (IRQ_TOUCH_INT, touchkey_interrupt, IRQF_TRIGGER_FALLING, + DEVICE_NAME, NULL)) { + printk(KERN_ERR "[TouchKey] %s Can't allocate irq ..\n", + __func__); + return -EBUSY; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + touchkey_driver->early_suspend.suspend = + (void *)sec_touchkey_early_suspend; + touchkey_driver->early_suspend.resume = + (void *)sec_touchkey_late_resume; + register_early_suspend(&touchkey_driver->early_suspend); +#endif + + touchkey_led_ldo_on(1); + +#if defined(CONFIG_MACH_C1_NA_SPR_EPIC2_REV00)\ + || defined(CONFIG_MACH_Q1_BD) \ + || defined(CONFIG_MACH_C1_NA_USCC_REV05) + + touchkey_firmware_update(); +#endif + +#if defined(CONFIG_TARGET_LOCALE_NAATT) \ +|| defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) + /*touchkey_firmware_update(); */ +#if defined(CONFIG_TARGET_LOCALE_NA) + if (store_module_version >= 8) { +#endif + msleep(100); + err = touchkey_autocalibration(); + if (err < 0) { + printk(KERN_ERR + "[TouchKey] probe autocalibration fail\n"); + return err; + } +#if defined(CONFIG_TARGET_LOCALE_NA) + } +#endif /* CONFIG_TARGET_LOCALE_NA */ +#endif + set_touchkey_debug('K'); + +#ifdef CONFIG_TOUCHKEY_BLN + err = misc_register( &bln_device ); + if( err ){ + printk(KERN_ERR "[BLN] sysfs misc_register failed.\n"); + }else{ + if( sysfs_create_group( &bln_device.this_device->kobj, &bln_notification_group) < 0){ + printk(KERN_ERR "[BLN] sysfs create group failed.\n"); + } + } + + /* BLN early suspend */ + register_early_suspend(&bln_suspend_data); + + //this miscdevice is for cm9 + err = misc_register( &led_device ); + if( err ){ + printk(KERN_ERR "[LED] sysfs misc_register failed.\n"); + }else{ + if( sysfs_create_group( &led_device.this_device->kobj, &led_notification_group) < 0){ + printk(KERN_ERR "[LED] sysfs create group failed.\n"); + } + } + + /* Setup the timer for the timeouts */ + setup_timer(&led_timer, handle_led_timeout, 0); + setup_timer(¬ification_timer, handle_notification_timeout, 0); + setup_timer(&breathing_timer, handle_breathe, 0); + + led_timeout = 0; + reset_breathing_steps(); + + /* wake lock for BLN */ + wake_lock_init(&bln_wake_lock, WAKE_LOCK_SUSPEND, "bln_wake_lock"); + /* turn off the LED on probe */ + status = 2; + i2c_touchkey_write((u8 *)&status, 1); + + mxt224_touch_cb = cypress_notify_touch; +#endif + + return 0; +} + +static void init_hw(void) +{ + gpio_direction_output(_3_GPIO_TOUCH_EN, 1); + msleep(200); + s3c_gpio_setpull(_3_GPIO_TOUCH_INT, S3C_GPIO_PULL_NONE); + irq_set_irq_type(IRQ_TOUCH_INT, IRQF_TRIGGER_FALLING); + s3c_gpio_cfgpin(_3_GPIO_TOUCH_INT, _3_GPIO_TOUCH_INT_AF); +} + +static int get_touchkey_module_version() +{ + char data[3] = { 0, }; + int ret = 0; + + ret = i2c_touchkey_read(KEYCODE_REG, data, 3); + if (ret < 0) { + printk(KERN_ERR "[TouchKey] module version read fail\n"); + return ret; + } else { + printk(KERN_DEBUG "[TouchKey] Module Version: %d\n", data[2]); + return data[2]; + } +} + +int touchkey_update_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +ssize_t touchkey_update_read(struct file *filp, char *buf, size_t count, + loff_t *f_pos) +{ + char data[3] = { 0, }; + + get_touchkey_firmware(data); + put_user(data[1], buf); + + return 1; +} + +int touchkey_update_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static ssize_t touch_version_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char data[3] = { 0, }; + int count; + + init_hw(); + i2c_touchkey_read(KEYCODE_REG, data, 3); + + count = sprintf(buf, "0x%x\n", data[1]); + + printk(KERN_DEBUG "[TouchKey] touch_version_read 0x%x\n", data[1]); + printk(KERN_DEBUG "[TouchKey] module_version_read 0x%x\n", data[2]); + + return count; +} + +static ssize_t touch_version_write(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + printk(KERN_DEBUG "[TouchKey] input data --> %s\n", buf); + + return size; +} + +void touchkey_update_func(struct work_struct *p) +{ + int retry = 10; +#if defined(CONFIG_TARGET_LOCALE_NAATT) + char data[3]; + i2c_touchkey_read(KEYCODE_REG, data, 3); + printk(KERN_DEBUG "[%s] F/W version: 0x%x, Module version:0x%x\n", + __func__, data[1], data[2]); +#endif + touchkey_update_status = 1; + printk(KERN_DEBUG "[TouchKey] %s start\n", __func__); + touchkey_enable = 0; + while (retry--) { + if (ISSP_main() == 0) { + printk(KERN_DEBUG + "[TouchKey] touchkey_update succeeded\n"); + init_hw(); + enable_irq(IRQ_TOUCH_INT); + touchkey_enable = 1; +#if defined(CONFIG_MACH_Q1_BD) + touchkey_autocalibration(); +#else +#if defined(CONFIG_TARGET_LOCALE_NA) + if (store_module_version >= 8) + touchkey_autocalibration(); +#endif +#endif + touchkey_update_status = 0; + return; + } +#if defined(CONFIG_TARGET_LOCALE_NAATT) \ +|| defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) + touchkey_ldo_on(0); + msleep(300); + init_hw(); +#endif + } + + touchkey_update_status = -1; + printk(KERN_DEBUG "[TouchKey] touchkey_update failed\n"); + return; +} + +static ssize_t touch_update_write(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) { + printk(KERN_DEBUG + "[TouchKey] Skipping f/w update : module_version =%d\n", + store_module_version); + touchkey_update_status = 0; + return 1; + } else { +#endif /* CONFIG_TARGET_LOCALE_NA */ + printk(KERN_DEBUG "[TouchKey] touchkey firmware update\n"); + + if (*buf == 'S') { + disable_irq(IRQ_TOUCH_INT); + INIT_WORK(&touch_update_work, touchkey_update_func); + queue_work(touchkey_wq, &touch_update_work); + } + return size; +#ifdef CONFIG_TARGET_LOCALE_NA + } +#endif /* CONFIG_TARGET_LOCALE_NA */ +} + +static ssize_t touch_update_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count = 0; + + printk(KERN_DEBUG + "[TouchKey] touch_update_read: touchkey_update_status %d\n", + touchkey_update_status); + + if (touchkey_update_status == 0) + count = sprintf(buf, "PASS\n"); + else if (touchkey_update_status == 1) + count = sprintf(buf, "Downloading\n"); + else if (touchkey_update_status == -1) + count = sprintf(buf, "Fail\n"); + + return count; +} + +static ssize_t touch_led_control(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + int data; + int errnum; + + if (sscanf(buf, "%d\n", &data) == 1) { +#if defined(CONFIG_MACH_Q1_BD) + if (data == 1) + data = 0x10; + else if (data == 2) + data = 0x20; +#elif defined(CONFIG_TARGET_LOCALE_NA) + if (store_module_version >= 8) { + if (data == 1) + data = 0x10; + else if (data == 2) + data = 0x20; + } +#endif +#ifdef CONFIG_TOUCHKEY_BLN + printk(KERN_ERR "[TouchKey] system calling LED Notification control\n"); +#endif + errnum = i2c_touchkey_write((u8 *) &data, 1); + if( data == 1 && led_timeout > 0 ) + mod_timer(&led_timer, jiffies + msecs_to_jiffies(led_timeout)); + if (errnum == -ENODEV) + touchled_cmd_reversed = 1; + + touchkey_led_status = data; + } else { + printk(KERN_DEBUG "[TouchKey] touch_led_control Error\n"); + } + + return size; +} + +static ssize_t touchkey_enable_disable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return size; +} + +#if defined(CONFIG_TARGET_LOCALE_NAATT) || defined(CONFIG_TARGET_LOCALE_NA) +static ssize_t touchkey_menu_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[18] = { 0, }; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 18); +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) { + printk(KERN_DEBUG "called %s data[12] =%d,data[13] = %d\n", + __func__, data[12], data[13]); + menu_sensitivity = ((0x00FF & data[12]) << 8) | data[13]; + } else { + printk(KERN_DEBUG "called %s data[17] =%d\n", __func__, + data[17]); + menu_sensitivity = data[17]; + } +#else + printk(KERN_DEBUG "called %s data[10] =%d,data[11] = %d\n", __func__, + data[10], data[11]); + menu_sensitivity = ((0x00FF & data[10]) << 8) | data[11]; +#endif /* CONFIG_TARGET_LOCALE_NA */ + return sprintf(buf, "%d\n", menu_sensitivity); +} + +static ssize_t touchkey_home_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[18] = { 0, }; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 18); +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) { + printk(KERN_DEBUG "called %s data[10] =%d,data[11] = %d\n", + __func__, data[10], data[11]); + home_sensitivity = ((0x00FF & data[10]) << 8) | data[11]; + } else { + printk(KERN_DEBUG "called %s data[15] =%d\n", __func__, + data[15]); + home_sensitivity = data[15]; + } +#else + printk(KERN_DEBUG "called %s data[12] =%d,data[13] = %d\n", __func__, + data[12], data[13]); + home_sensitivity = ((0x00FF & data[12]) << 8) | data[13]; +#endif /* CONFIG_TARGET_LOCALE_NA */ + return sprintf(buf, "%d\n", home_sensitivity); +} + +static ssize_t touchkey_back_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[18] = { 0, }; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 18); +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) { + printk(KERN_DEBUG "called %s data[8] =%d,data[9] = %d\n", + __func__, data[8], data[9]); + back_sensitivity = ((0x00FF & data[8]) << 8) | data[9]; + } else { + printk(KERN_DEBUG "called %s data[13] =%d\n", __func__, + data[13]); + back_sensitivity = data[13]; + } +#else + printk(KERN_DEBUG "called %s data[14] =%d,data[15] = %d\n", __func__, + data[14], data[15]); + back_sensitivity = ((0x00FF & data[14]) << 8) | data[15]; +#endif /* CONFIG_TARGET_LOCALE_NA */ + return sprintf(buf, "%d\n", back_sensitivity); +} + +static ssize_t touchkey_search_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[18] = { 0, }; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 18); +#ifdef CONFIG_TARGET_LOCALE_NA + if (store_module_version < 8) { + printk(KERN_DEBUG "called %s data[6] =%d,data[7] = %d\n", + __func__, data[6], data[7]); + search_sensitivity = ((0x00FF & data[6]) << 8) | data[7]; + } else { + printk(KERN_DEBUG "called %s data[11] =%d\n", __func__, + data[11]); + search_sensitivity = data[11]; + } +#else + printk(KERN_DEBUG "called %s data[16] =%d,data[17] = %d\n", __func__, + data[16], data[17]); + search_sensitivity = ((0x00FF & data[16]) << 8) | data[17]; +#endif /* CONFIG_TARGET_LOCALE_NA */ + return sprintf(buf, "%d\n", search_sensitivity); +} +#else +static ssize_t touchkey_menu_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if defined(CONFIG_MACH_Q1_BD) + u8 data[14] = { 0, }; + int ret; + + ret = i2c_touchkey_read(KEYCODE_REG, data, 14); + + printk(KERN_DEBUG "called %s data[13] =%d\n", __func__, data[13]); + menu_sensitivity = data[13]; +#else + u8 data[10]; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 10); + menu_sensitivity = data[7]; +#endif + return sprintf(buf, "%d\n", menu_sensitivity); +} + +static ssize_t touchkey_back_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#if defined(CONFIG_MACH_Q1_BD) + u8 data[14] = { 0, }; + int ret; + + ret = i2c_touchkey_read(KEYCODE_REG, data, 14); + + printk(KERN_DEBUG "called %s data[11] =%d\n", __func__, data[11]); + back_sensitivity = data[11]; +#else + u8 data[10]; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + ret = i2c_touchkey_read(KEYCODE_REG, data, 10); + back_sensitivity = data[9]; +#endif + return sprintf(buf, "%d\n", back_sensitivity); +} +#endif + +#if defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) +static ssize_t autocalibration_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int data; + + sscanf(buf, "%d\n", &data); + + if (data == 1) + touchkey_autocalibration(); + + return size; +} + +static ssize_t autocalibration_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data[6]; + int ret; + + printk(KERN_DEBUG "called %s\n", __func__); + + ret = i2c_touchkey_read(KEYCODE_REG, data, 6); + if ((data[5] & 0x80)) + return sprintf(buf, "Enabled\n"); + else + return sprintf(buf, "Disabled\n"); + +} +#endif /* CONFIG_TARGET_LOCALE_NA */ + +static ssize_t touch_sensitivity_control(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned char data = 0x40; + i2c_touchkey_write(&data, 1); + return size; +} + +static ssize_t set_touchkey_firm_version_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "0x%x\n", TK_FIRMWARE_VER); +} + +static ssize_t set_touchkey_update_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* TO DO IT */ + int count = 0; + int retry = 3; + touchkey_update_status = 1; + +#ifdef TEST_JIG_MODE + unsigned char get_touch = 0x40; +#endif + + while (retry--) { + if (ISSP_main() == 0) { + printk(KERN_ERR + "[TOUCHKEY]Touchkey_update succeeded\n"); + touchkey_update_status = 0; + count = 1; + break; + } + printk(KERN_ERR "touchkey_update failed... retry...\n"); + } + if (retry <= 0) { + /* disable ldo11 */ + touchkey_ldo_on(0); + msleep(300); + count = 0; + printk(KERN_ERR "[TOUCHKEY]Touchkey_update fail\n"); + touchkey_update_status = -1; + return count; + } + + init_hw(); /* after update, re initalize. */ + +#ifdef TEST_JIG_MODE + i2c_touchkey_write(&get_touch, 1); +#endif + + return count; + +} + +static ssize_t set_touchkey_firm_version_read_show(struct device *dev, + struct device_attribute + *attr, char *buf) +{ + char data[3] = { 0, }; + int count; + + init_hw(); + /*if (get_touchkey_firmware(data) != 0) { */ + i2c_touchkey_read(KEYCODE_REG, data, 3); + /*} */ + count = sprintf(buf, "0x%x\n", data[1]); + + printk(KERN_DEBUG "[TouchKey] touch_version_read 0x%x\n", data[1]); + printk(KERN_DEBUG "[TouchKey] module_version_read 0x%x\n", data[2]); + return count; +} + +static ssize_t set_touchkey_firm_status_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int count = 0; + + printk(KERN_DEBUG + "[TouchKey] touch_update_read: touchkey_update_status %d\n", + touchkey_update_status); + + if (touchkey_update_status == 0) + count = sprintf(buf, "PASS\n"); + else if (touchkey_update_status == 1) + count = sprintf(buf, "Downloading\n"); + else if (touchkey_update_status == -1) + count = sprintf(buf, "Fail\n"); + + return count; +} + +static DEVICE_ATTR(recommended_version, S_IRUGO | S_IWUSR | S_IWGRP, + touch_version_read, touch_version_write); +static DEVICE_ATTR(updated_version, S_IRUGO | S_IWUSR | S_IWGRP, + touch_update_read, touch_update_write); +static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + touch_led_control); +static DEVICE_ATTR(enable_disable, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + touchkey_enable_disable); +static DEVICE_ATTR(touchkey_menu, S_IRUGO | S_IWUSR | S_IWGRP, + touchkey_menu_show, NULL); +static DEVICE_ATTR(touchkey_back, S_IRUGO | S_IWUSR | S_IWGRP, + touchkey_back_show, NULL); +#if defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_TARGET_LOCALE_NAATT) +static DEVICE_ATTR(touchkey_home, S_IRUGO, touchkey_home_show, NULL); +static DEVICE_ATTR(touchkey_search, S_IRUGO, touchkey_search_show, NULL); +#endif /* CONFIG_TARGET_LOCALE_NA */ +static DEVICE_ATTR(touch_sensitivity, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + touch_sensitivity_control); +/*20110223N1 firmware sync*/ +static DEVICE_ATTR(touchkey_firm_update, S_IRUGO | S_IWUSR | S_IWGRP, + set_touchkey_update_show, NULL);/* firmware update */ +static DEVICE_ATTR(touchkey_firm_update_status, S_IRUGO | S_IWUSR | S_IWGRP, + set_touchkey_firm_status_show, NULL);/* firmware update status */ +static DEVICE_ATTR(touchkey_firm_version_phone, S_IRUGO | S_IWUSR | S_IWGRP, + set_touchkey_firm_version_show, NULL);/* PHONE */ +static DEVICE_ATTR(touchkey_firm_version_panel, S_IRUGO | S_IWUSR | S_IWGRP, + set_touchkey_firm_version_read_show, NULL); +/*PART*/ +/*end N1 firmware sync*/ +static DEVICE_ATTR(touchkey_brightness, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + brightness_control); + +#if defined(CONFIG_TARGET_LOCALE_NAATT) +static DEVICE_ATTR(touchkey_autocal_start, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + set_touchkey_autocal_testmode); +#endif + +#if defined(CONFIG_TARGET_LOCALE_NAATT) \ +|| defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) +static DEVICE_ATTR(touchkey_raw_data0, S_IRUGO, touchkey_raw_data0_show, NULL); +static DEVICE_ATTR(touchkey_raw_data1, S_IRUGO, touchkey_raw_data1_show, NULL); +static DEVICE_ATTR(touchkey_raw_data2, S_IRUGO, touchkey_raw_data2_show, NULL); +static DEVICE_ATTR(touchkey_raw_data3, S_IRUGO, touchkey_raw_data3_show, NULL); +static DEVICE_ATTR(touchkey_idac0, S_IRUGO, touchkey_idac0_show, NULL); +static DEVICE_ATTR(touchkey_idac1, S_IRUGO, touchkey_idac1_show, NULL); +static DEVICE_ATTR(touchkey_idac2, S_IRUGO, touchkey_idac2_show, NULL); +static DEVICE_ATTR(touchkey_idac3, S_IRUGO, touchkey_idac3_show, NULL); +static DEVICE_ATTR(touchkey_threshold, S_IRUGO, touchkey_threshold_show, NULL); +#endif + +#if defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) +static DEVICE_ATTR(autocal_enable, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + autocalibration_enable); +static DEVICE_ATTR(autocal_stat, S_IRUGO | S_IWUSR | S_IWGRP, + autocalibration_status, NULL); +#endif /* CONFIG_TARGET_LOCALE_NA */ +static int __init touchkey_init(void) +{ + int ret = 0; + +#ifdef TEST_JIG_MODE + unsigned char get_touch = 0x40; +#endif + + sec_touchkey = device_create(sec_class, NULL, 0, NULL, "sec_touchkey"); + + if (IS_ERR(sec_touchkey)) + printk(KERN_ERR "Failed to create device(sec_touchkey)!\n"); + + if (device_create_file(sec_touchkey, &dev_attr_touchkey_firm_update) < + 0) { + printk(KERN_ERR "Failed to create device file(%s)!\n", + dev_attr_touchkey_firm_update.attr.name); + } + if (device_create_file + (sec_touchkey, &dev_attr_touchkey_firm_update_status) < 0) { + printk(KERN_ERR "Failed to create device file(%s)!\n", + dev_attr_touchkey_firm_update_status.attr.name); + } + if (device_create_file + (sec_touchkey, &dev_attr_touchkey_firm_version_phone) < 0) { + printk(KERN_ERR "Failed to create device file(%s)!\n", + dev_attr_touchkey_firm_version_phone.attr.name); + } + if (device_create_file + (sec_touchkey, &dev_attr_touchkey_firm_version_panel) < 0) { + printk(KERN_ERR "Failed to create device file(%s)!\n", + dev_attr_touchkey_firm_version_panel.attr.name); + } + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_brightness) < 0) { + printk(KERN_ERR "Failed to create device file(%s)!\n", + dev_attr_touchkey_brightness.attr.name); + } +#if defined(CONFIG_TARGET_LOCALE_NAATT) + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_autocal_start) < + 0) { + printk(KERN_ERR "Failed to create device file(%s)!\n", + dev_attr_touchkey_brightness.attr.name); + } +#endif + + if (device_create_file(sec_touchkey, + &dev_attr_recommended_version) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_recommended_version.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_updated_version) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_updated_version.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_brightness) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_brightness.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_enable_disable) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_enable_disable.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_menu) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_menu.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_back) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_back.attr.name); + } +#if defined(CONFIG_TARGET_LOCALE_NAATT) \ +|| defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_raw_data0) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_raw_data0.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_raw_data1) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_raw_data1.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_raw_data2) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_raw_data2.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_raw_data3) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_raw_data3.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_idac0) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_idac0.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_idac1) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_idac1.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_idac2) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_idac2.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_idac3) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_idac3.attr.name); + } + + if (device_create_file(sec_touchkey, + &dev_attr_touchkey_threshold) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_threshold.attr.name); + } +#endif + +#if defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_TARGET_LOCALE_NAATT) + if (device_create_file(sec_touchkey, &dev_attr_touchkey_home) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_home.attr.name); + } + + if (device_create_file(sec_touchkey, &dev_attr_touchkey_search) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touchkey_search.attr.name); + } +#endif /* CONFIG_TARGET_LOCALE_NA */ + +#if defined(CONFIG_TARGET_LOCALE_NA) || defined(CONFIG_MACH_Q1_BD) + if (device_create_file(sec_touchkey, &dev_attr_autocal_enable) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_autocal_enable.attr.name); + } + + if (device_create_file(sec_touchkey, &dev_attr_autocal_stat) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_autocal_stat.attr.name); + } +#endif /* CONFIG_TARGET_LOCALE_NA */ + + if (device_create_file(sec_touchkey, + &dev_attr_touch_sensitivity) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_touch_sensitivity.attr.name); + } + touchkey_wq = create_singlethread_workqueue("sec_touchkey_wq"); + if (!touchkey_wq) + return -ENOMEM; + + INIT_WORK(&touchkey_work, touchkey_work_func); + + init_hw(); + + ret = i2c_add_driver(&touchkey_i2c_driver); + + if (ret) { + printk(KERN_ERR + "[TouchKey] registration failed, module not inserted.ret= %d\n", + ret); + } +#ifdef TEST_JIG_MODE + i2c_touchkey_write(&get_touch, 1); +#endif + return ret; + +} + +static void __exit touchkey_exit(void) +{ + printk(KERN_DEBUG "[TouchKey] %s\n", __func__); + i2c_del_driver(&touchkey_i2c_driver); + +#ifdef CONFIG_TOUCHKEY_BLN + misc_deregister(&bln_device); + wake_lock_destroy(&bln_wake_lock); + del_timer(&led_timer); + del_timer(¬ification_timer); + del_timer(&breathing_timer); +#endif + + if (touchkey_wq) + destroy_workqueue(touchkey_wq); + +#ifndef CONFIG_MACH_Q1_BD + gpio_free(_3_TOUCH_SDA_28V); + gpio_free(_3_TOUCH_SCL_28V); + gpio_free(_3_GPIO_TOUCH_EN); +#endif + gpio_free(_3_GPIO_TOUCH_INT); +} + +late_initcall(touchkey_init); +module_exit(touchkey_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("@@@"); +MODULE_DESCRIPTION("touch keypad"); diff --git a/drivers/input/keyboard/cypressbln/issp_defs.h b/drivers/input/keyboard/cypressbln/issp_defs.h new file mode 100644 index 0000000..5878300 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_defs.h @@ -0,0 +1,101 @@ +// filename: ISSP_Defs.h +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress� product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +--------------------------------------------------------------------------*/ +#ifndef INC_ISSP_DEFS +#define INC_ISSP_DEFS + +#include "issp_directives.h" + +// Block-Verify Uses 64-Bytes of RAM +// #define TARGET_DATABUFF_LEN 64 +#define TARGET_DATABUFF_LEN 128 // **** CY8C20x66 Device **** + +// The number of Flash blocks in each part is defined here. This is used in +// main programming loop when programming and verifying the blocks. + +#ifdef CY8CTMx30x // **** CY8C20x66 Device **** +#define NUM_BANKS 1 +#define BLOCKS_PER_BANK 256 +#define SECURITY_BYTES_PER_BANK 64 +#endif + +#ifdef CY8C20x66 // **** CY8C20x66 Device **** +#ifdef CY8C20246 // **** CY8C20x66 Device **** +#define NUM_BANKS 1 +#define BLOCKS_PER_BANK 128 +#define SECURITY_BYTES_PER_BANK 64 +#elif defined(CY8C20236) +#define NUM_BANKS 1 +#define BLOCKS_PER_BANK 64 +#define SECURITY_BYTES_PER_BANK 64 +#else +#define NUM_BANKS 1 +#define BLOCKS_PER_BANK 256 +#define SECURITY_BYTES_PER_BANK 64 +#endif +#endif +#ifdef CY8C21x23 +#define NUM_BANKS 1 +#define BLOCKS_PER_BANK 64 +#define SECURITY_BYTES_PER_BANK 64 +#endif +#ifdef CY8C21x34 +#define NUM_BANKS 1 +#define BLOCKS_PER_BANK 128 +#define SECURITY_BYTES_PER_BANK 64 +#endif +#ifdef CY8C24x23A +#define NUM_BANKS 1 +#define BLOCKS_PER_BANK 64 +#define SECURITY_BYTES_PER_BANK 64 +#endif +#ifdef CY8C24x94 +#define NUM_BANKS 2 +#define BLOCKS_PER_BANK 128 +#define SECURITY_BYTES_PER_BANK 32 +#endif +#ifdef CY8C27x43 +#define NUM_BANKS 1 +#define BLOCKS_PER_BANK 256 +#define SECURITY_BYTES_PER_BANK 64 +#endif +#ifdef CY8C29x66 +#define NUM_BANKS 4 +#define BLOCKS_PER_BANK 128 +#define SECURITY_BYTES_PER_BANK 32 +#endif +#endif //(INC_ISSP_DEFS) +#endif //(PROJECT_REV_) +//end of file ISSP_Defs.h diff --git a/drivers/input/keyboard/cypressbln/issp_delays.h b/drivers/input/keyboard/cypressbln/issp_delays.h new file mode 100644 index 0000000..e727310 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_delays.h @@ -0,0 +1,87 @@ +// filename: ISSP_Delays.h +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress� product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +-----------------------------------------------------------------------------*/ +#ifndef INC_ISSP_DELAYS +#define INC_ISSP_DELAYS + +// The Delay() routine, in ISSP_Driver_Routines.c, has a delay of n+3 usec, +// where n is the value passed to the routine. This is true for the m8c micro- +// processor in the PSoC when it is running at a CPU clock of 24MHz. +// +// PROCESSOR_SPECIFIC +// If another processor is used, or if the m8c is running at a slower clock +// speed, then the delay parameters will be different. This file makes changing +// the delays simpiler when porting the program to other processors. + +// DELAY_M is the slope of the Delay = Mx + B equation +#define DELAY_M 1 +// DELAY_B is the offset of the delay in Delay = Mx + B. +#define DELAY_B 3 + +/////////////////////////////////////////////////////////////////////////////// +// CAUTION: +// For the above parameters the minimum delay value is 3 (this would result in +// 0 being passed for a minimum delay. A value less than 3 would actually +// create a negative number, causing a very long delay +/////////////////////////////////////////////////////////////////////////////// + +// TRANSITION_TIMEOUT is a loop counter for a 100msec timeout when waiting for +// a high-to-low transition. This is used in the polling loop of +// fDetectHiLoTransition(). Each pass through the loop takes approximately 15 +// usec. 100 msec is about 6740 loops. 13480 +#define TRANSITION_TIMEOUT 0x100000 //6740 + +// XRES_DELAY is the time duration for which XRES is asserted. This defines +// a 63 usec delay. +// The minimum Xres time (from the device datasheet) is 10 usec. +//mhsong #define XRES_CLK_DELAY ((63 - DELAY_B) / DELAY_M) +#define XRES_CLK_DELAY 63 + +// POWER_CYCLE_DELAY is the time required when power is cycled to the target +// device to create a power reset after programming has been completed. The +// actual time of this delay will vary from system to system depending on the +// bypass capacitor size. A delay of 150 usec is used here. +//mhsong #define POWER_CYCLE_DELAY ((150 - DELAY_B) / DELAY_M) +#define POWER_CYCLE_DELAY 150 + +// DELAY_100us delays 100 usec. This is used in fXRESInitializeTargetForISSP to +// time the wait for Vdd to become stable after a power up. A loop runs 10 of +// these for a total delay of 1 msec. +//mhsong #define DELAY100us ((100 - DELAY_B) / DELAY_M) +#define DELAY100us 100 + +#endif //(INC_ISSP_DELAYS) +#endif //(PROJECT_REV_) +//end of file ISSP_Delays.h diff --git a/drivers/input/keyboard/cypressbln/issp_directives.h b/drivers/input/keyboard/cypressbln/issp_directives.h new file mode 100644 index 0000000..b6cdddc --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_directives.h @@ -0,0 +1,474 @@ +// filename: ISSP_Directives.h +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress� product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +----------------------------------------------------------------------------*/ + +// --------------------- Compiler Directives ---------------------------------- +#ifndef INC_ISSP_DIRECTIVES +#define INC_ISSP_DIRECTIVES + +// This directive will enable a Genral Purpose test-point on P1.7 +// It can be toggled as needed to measure timing, execution, etc... +// A "Test Point" sets a GPIO pin of the host processor high or low. This GPIO +// pin can be observed with an oscilloscope to verify the timing of key +// programming steps. TPs have been added in main() that set Port 0, pin 1 +// high during bulk erase, during each block write and during security write. +// The timing of these programming steps should be verified as correct as part +// of the validation process of the final program. + +//JBA +//#define USE_TP + +// **************************************************************************** +// ************* USER ATTENTION REQUIRED: TARGET SUPPLY VOLTAGE *************** +// **************************************************************************** +// This directive causes the proper Initialization vector #3 to be sent +// to the Target, based on what the Target Vdd programming voltage will +// be. Either 5V (if #define enabled) or 3.3V (if #define disabled). + +//JBA +//#define TARGET_VOLTAGE_IS_5V + +// **************************************************************************** +// **************** USER ATTENTION REQUIRED: PROGRAMMING MODE ***************** +// **************************************************************************** +// This directive selects whether code that uses reset programming mode or code +// that uses power cycle programming is use. Reset programming mode uses the +// external reset pin (XRES) to enter programming mode. Power cycle programming +// mode uses the power-on reset to enter programming mode. +// Applying signals to various pins on the target device must be done in a +// deliberate order when using power cycle mode. Otherwise, high signals to GPIO +// pins on the target will power the PSoC through the protection diodes. + +//JBA +// choose the RESET MODE or POWER MODE +// #define RESET_MODE + +// **************************************************************************** +// ****************** USER ATTENTION REQUIRED: TARGET PSOC ******************** +// **************************************************************************** +// The directives below enable support for various PSoC devices. The root part +// number to be programmed should be un-commented so that its value becomes +// defined. All other devices should be commented out. +// Select one device to be supported below: + +/*************** CY8CTMA30x, CY8CTMG30x, CY8CTST30x series by KIMC, 2009.08.11 ***********************************/ +//#define CY8CTST300_36 // CY8CTST300_36LQXI // 2009.08.11, not tested. +//#define CY8CTST300_48 // CY8CTST300_48LTXI // 2009.08.11, not tested. +//#define CY8CTST300_49 // CY8CTST300_49FNXI // 2009.08.11, not tested. +//#define CY8CTMA300_36 // CY8CTMA300_36LQXI // 2009.08.11, Test OK. +//#define CY8CTMA300_48 // CY8CTMA300_48LTXI // 2009.08.11, not tested. +//#define CY8CTMA300_49 // CY8CTMA300_49FNXI // 2009.08.11, not tested. +//#define CY8CTMG300_36 // CY8CTMG300_36LQXI // 2009.08.11, not tested. +//#define CY8CTMG300_48 // CY8CTMG300_48LTXI // 2009.08.11, not tested. +//#define CY8CTMG300_49 // CY8CTMG300_49FNXI // 2009.08.11, not tested. +//#define CY8CTMG300B_36 // CY8CTMG300B_36LQXI // 2009.08.11, not tested. +//#define CY8CTMA300B_36 // CY8CTMA300B_36LQXI // 2009.08.11, not tested. +//#define CY8CTST300B_36 // CY8CTST300B_36LQXI // 2009.08.11, not tested. +//#define CY8CTMA301_36 // CY8CTMA301_36LQXI // 2009.08.11, not tested. +//#define CY8CTMA301_48 // CY8CTMA301_48LTXI // 2009.08.11, not tested. +//#define CY8CTMA301D_36 // CY8CTMA301D_36LQXI // 2009.08.11, not tested. +//#define CY8CTMA301D_48 // CY8CTMA301D_48LTXI // 2009.08.11, not tested. +//#define CY8CTMA300D_36 // CY8CTMA300D_36LQXI // 2009.08.11, not tested. +//#define CY8CTMA300D_48 // CY8CTMA300D_48LTXI // 2009.08.11, not tested. +//#define CY8CTMA300D_49 // CY8CTMA300D_49FNXIT // 2009.08.11, not tested. +/****************************************************************************************************/ + +/*************** CY8CTMG/TST series modified by KJHW, 2009.08.14 *********************************************/ +//#define CY8CTMG110 +//#define CY8CTST200_24PIN +//#define CY8CTST200_32PIN +//#define CY8CTMG200_24PIN +//#define CY8CTMG200_32PIN +/***************************************************************************************************/ + +#define CY8C20236 +// **** CY8C20x66 devices **** +//#define CY8C20246 /// 2009.03.26. kimc +//#define CY8C20266 +//#define CY8C20366 +//#define CY8C20466 +//#define CY8C20566 +//#define CY8C20666 +//#define CY8C20066 +//#define CY8C200661 + +// **** CY8C21x23 devices **** +//#define CY8C21123 +//#define CY8C21223 +//#define CY8C21323 +//#define CY8C21002 + +// **** CY8C21x34 devices **** +//#define CY8C21234 +//#define CY8C21334 +//#define CY8C21434 +//#define CY8C21534 +//#define CY8C21634 +//#define CY8C21001 + +// **** CY8C24x23A devices **** +//#define CY8C24123A +//#define CY8C24223A +//#define CY8C24423A +//#define CY8C24000A + +// **** CY8C24x94 devices **** +//#define CY8C24794 +//#define CY8C24894 +//#define CY8C24994 +//#define CY8C24094 + +// **** CY8C27x34 devices **** +//#define CY8C27143 +//#define CY8C27243 +//#define CY8C27443 +//#define CY8C27543 +//#define CY8C27643 +//#define CY8C27002 + +// **** CY8C29x66 devices **** +//#define CY8C29466 +//#define CY8C29566 +//#define CY8C29666 +//#define CY8C29866 +//#define CY8C29002 + +//----------------------------------------------------------------------------- +// This section sets the Family that has been selected. These are used to +// simplify other conditional compilation blocks. +//----------------------------------------------------------------------------- + +/*************** CY8CTMA30x, CY8CTMG30x, CY8CTST30x series by KIMC, 2009.08.11 ***********************************/ +#ifdef CY8CTST300_36 // CY8CTST300_36LQXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTST300_48 // CY8CTST300_48LTXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTST300_49 // CY8CTST300_49FNXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA300_36 // CY8CTMA300_36LQXI // 2009.08.11, test OK +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA300_48 // CY8CTMA300_48LTXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA300_49 // CY8CTMA300_49FNXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMG300_36 // CY8CTMG300_36LQXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMG300_48 // CY8CTMG300_48LTXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMG300_49 // CY8CTMG300_49FNXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMG300B_36 // CY8CTMG300B_36LQXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA300B_36 // CY8CTMA300B_36LQXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTST300B_36 // CY8CTST300B_36LQXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA301_36 // CY8CTMA301_36LQXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA301_48 // CY8CTMA301_48LTXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA301D_36 // CY8CTMA301D_36LQXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA301D_48 // CY8CTMA301D_48LTXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA300D_36 // CY8CTMA300D_36LQXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA300D_48 // CY8CTMA300D_48LTXI // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +#ifdef CY8CTMA300D_49 // CY8CTMA300D_49FNXIT // 2009.08.11, not tested. +#define CY8CTMx30x +#define CY8C20x66 +#endif +/**************************************************/ + +/*************** CY8CTMG/TST series modified by KJHW, 2009.08.14 *********************************************/ + +#ifdef CY8CTMG110 +#define CY8C21x34 +#endif +#ifdef CY8CTST200_24PIN +#define CY8C20x66 +#endif +#ifdef CY8CTST200_32PIN +#define CY8C20x66 +#endif +#ifdef CY8CTMG200_24PIN +#define CY8C20x66 +#endif +#ifdef CY8CTMG200_32PIN +#define CY8C20x66 +#endif + +/***************************************************************************************************/ +#ifdef CY8C20236 +#define CY8C20x66 +#endif +#ifdef CY8C20246 /// 2009.03.26. kimc +#define CY8C20x66 +#endif +#ifdef CY8C20266 +#define CY8C20x66 +#endif +#ifdef CY8C20366 +#define CY8C20x66 +#endif +#ifdef CY8C20466 +#define CY8C20x66 +#endif +#ifdef CY8C20566 +#define CY8C20x66 +#endif +#ifdef CY8C20666 +#define CY8C20x66 +#endif +#ifdef CY8C20066 +#define CY8C20x66 +#endif +#ifdef CY8C200661 +#define CY8C20x66 +#endif + +#ifdef CY8C21123 +#define CY8C21x23 +#endif +#ifdef CY8C21223 +#define CY8C21x23 +#endif +#ifdef CY8C21323 +#define CY8C21x23 +#endif +#ifdef CY8C21002 +#define CY8C21x23 +#endif +#ifdef CY8C21234 +#define CY8C21x34 +#endif +#ifdef CY8C21334 +#define CY8C21x34 +#endif +#ifdef CY8C21434 +#define CY8C21x34 +#endif +#ifdef CY8C21534 +#define CY8C21x34 +#endif +#ifdef CY8C21634 +#define CY8C21x34 +#endif +#ifdef CY8C21001 +#define CY8C21x34 +#endif +#ifdef CY8C24123A +#define CY8C24x23A +#endif +#ifdef CY8C24223A +#define CY8C24x23A +#endif +#ifdef CY8C24423A +#define CY8C24x23A +#endif +#ifdef CY8C24000A +#define CY8C24x23A +#endif +#ifdef CY8C24794 +#define CY8C24x94 +#endif +#ifdef CY8C24894 +#define CY8C24x94 +#endif +#ifdef CY8C24994 +#define CY8C24x94 +#endif +#ifdef CY8C24094 +#define CY8C24x94 +#endif +#ifdef CY8C27143 +#define CY8C27x43 +#endif +#ifdef CY8C27243 +#define CY8C27x43 +#endif +#ifdef CY8C27443 +#define CY8C27x43 +#endif +#ifdef CY8C27543 +#define CY8C27x43 +#endif +#ifdef CY8C27643 +#define CY8C27x43 +#endif +#ifdef CY8C27002 +#define CY8C27x43 +#endif +#ifdef CY8C29466 +#define CY8C29x66 +#endif +#ifdef CY8C29566 +#define CY8C29x66 +#endif +#ifdef CY8C29666 +#define CY8C29x66 +#endif +#ifdef CY8C29866 +#define CY8C29x66 +#endif +#ifdef CY8C29002 +#define CY8C29x66 +#endif + +//----------------------------------------------------------------------------- +// The directives below are used for Krypton. +// See the Krypton programming spec 001-15870 rev *A for more details. (The +// spec uses "mnemonics" instead of "directives" +//----------------------------------------------------------------------------- +#ifdef CY8C20x66 +#define TSYNC + +#define ID_SETUP_1 //PTJ: ID_SETUP_1 is similar to init1_v +#define ID_SETUP_2 //PTJ: ID_SETUP_2 is similar to init2_v +#define SET_BLOCK_NUM +#define CHECKSUM_SETUP //PTJ: CHECKSUM_SETUP_20x66 is the same as CHECKSUM-SETUP in 001-15870 +#define READ_CHECKSUM +#define PROGRAM_AND_VERIFY //PTJ: PROGRAM_BLOCK_20x66 is the same as PROGRAM-AND-VERIFY in 001-15870 +#define ERASE +#define SECURE +#define READ_SECURITY +#define READ_WRITE_SETUP +#define WRITE_BYTE +#define VERIFY_SETUP +#define READ_STATUS +#define READ_BYTE + //READ_ID_WORD //PTJ: 3rd Party Progrmmer will have to write code to handle this directive, we do it out own way in this code, see read_id_v +#endif +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// The directives below are used to define various sets of vectors that differ +// for more than one set of PSoC parts. +//----------------------------------------------------------------------------- +// **** Select a Checksum Setup Vector **** +#ifdef CY8C21x23 +#define CHECKSUM_SETUP_21_27 +#endif +#ifdef CY8C21x34 +#define CHECKSUM_SETUP_21_27 +#endif +#ifdef CY8C24x23A +#define CHECKSUM_SETUP_24_24A +#endif +#ifdef CY8C24x94 +#define CHECKSUM_SETUP_24_29 +#endif +#ifdef CY8C27x43 +#define CHECKSUM_SETUP_21_27 +#endif +#ifdef CY8C29x66 +#define CHECKSUM_SETUP_24_29 +#endif + +// **** Select a Program Block Vector **** + +#ifdef CY8C21x23 +#define PROGRAM_BLOCK_21_24_29 +#endif +#ifdef CY8C21x34 +#define PROGRAM_BLOCK_21_24_29 +#endif +#ifdef CY8C24x23A +#define PROGRAM_BLOCK_21_24_29 +#endif +#ifdef CY8C24x94 +#define PROGRAM_BLOCK_21_24_29 +#endif +#ifdef CY8C27x43 +#define PROGRAM_BLOCK_27 +#endif +#ifdef CY8C29x66 +#define PROGRAM_BLOCK_21_24_29 +#endif + +//----------------------------------------------------------------------------- +// The directives below are used to control switching banks if the device is +// has multiple banks of Flash. +//----------------------------------------------------------------------------- +// **** Select a Checksum Setup Vector **** +#ifdef CY8C24x94 +#define MULTI_BANK +#endif +#ifdef CY8C29x66 +#define MULTI_BANK +#endif + +// ---------------------------------------------------------------------------- +#endif //(INC_ISSP_DIRECTIVES) +#endif //(PROJECT_REV_) +//end of file ISSP_Directives.h diff --git a/drivers/input/keyboard/cypressbln/issp_driver_routines.c b/drivers/input/keyboard/cypressbln/issp_driver_routines.c new file mode 100644 index 0000000..a3b4fcf --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_driver_routines.c @@ -0,0 +1,498 @@ +// filename: ISSP_Driver_Routines.c +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress� product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +--------------------------------------------------------------------------*/ + +#include <linux/module.h> + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/sysctl.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <mach/regs-gpio.h> +#include <plat/gpio-cfg.h> +#include <asm/gpio.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> +#include <linux/earlysuspend.h> +#include <asm/io.h> +#include <linux/hrtimer.h> + +//mhsong #include <m8c.h> // part specific constants and macros +//mhsong #include "PSoCAPI.h" // PSoC API definitions for all User Modules +#include "issp_defs.h" +#include "issp_errors.h" +#include "issp_directives.h" +#include "u1-cypress-gpio.h" + +extern unsigned char bTargetDataPtr; +extern unsigned char abTargetDataOUT[TARGET_DATABUFF_LEN]; + +/* enable ldo11 */ +extern int touchkey_ldo_on(bool on); + +// ****************************** PORT BIT MASKS ****************************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +#define SDATA_PIN 0x80 // P1.0 -> P1.4 +#define SCLK_PIN 0x40 // P1.1 -> P1.3 +#define XRES_PIN 0x40 // P2.0 -> P1.6 +#define TARGET_VDD 0x08 // P2.1 + +unsigned int nBlockCount = 1; // test, KIMC + +extern unsigned char firmware_data[]; + +// ((((((((((((((((((((((( DEMO ISSP SUBROUTINE SECTION ))))))))))))))))))))))) +// ((((( Demo Routines can be deleted in final ISSP project if not used ))))) +// ((((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))) + +// ============================================================================ +// InitTargetTestData() +// !!!!!!!!!!!!!!!!!!FOR TEST!!!!!!!!!!!!!!!!!!!!!!!!!! +// PROCESSOR_SPECIFIC +// Loads a 64-Byte array to use as test data to program target. Ultimately, +// this data should be fed to the Host by some other means, ie: I2C, RS232, +// etc. Data should be derived from hex file. +// Global variables affected: +// bTargetDataPtr +// abTargetDataOUT +// ============================================================================ +void InitTargetTestData(unsigned char bBlockNum, unsigned char bBankNum) +{ + // create unique data for each block + for (bTargetDataPtr = 0; bTargetDataPtr < TARGET_DATABUFF_LEN; + bTargetDataPtr++) { + abTargetDataOUT[bTargetDataPtr] = nBlockCount; + // abTargetDataOUT[bTargetDataPtr] = bTargetDataPtr + bBlockNum + bBankNum; + } + nBlockCount++; +} + +// ============================================================================ +// LoadArrayWithSecurityData() +// !!!!!!!!!!!!!!!!!!FOR TEST!!!!!!!!!!!!!!!!!!!!!!!!!! +// PROCESSOR_SPECIFIC +// Most likely this data will be fed to the Host by some other means, ie: I2C, +// RS232, etc., or will be fixed in the host. The security data should come +// from the hex file. +// bStart - the starting byte in the array for loading data +// bLength - the number of byte to write into the array +// bType - the security data to write over the range defined by bStart and +// bLength +// ============================================================================ +void LoadArrayWithSecurityData(unsigned char bStart, unsigned char bLength, + unsigned char bType) +{ + // Now, write the desired security-bytes for the range specified + for (bTargetDataPtr = bStart; bTargetDataPtr < bLength; + bTargetDataPtr++) { + abTargetDataOUT[bTargetDataPtr] = bType; + } +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// Delay() +// This delay uses a simple "nop" loop. With the CPU running at 24MHz, each +// pass of the loop is about 1 usec plus an overhead of about 3 usec. +// total delay = (n + 3) * 1 usec +// To adjust delays and to adapt delays when porting this application, see the +// ISSP_Delays.h file. +// **************************************************************************** +void Delay(unsigned char n) // by KIMC +{ + udelay(n); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// LoadProgramData() +// The final application should load program data from HEX file generated by +// PSoC Designer into a 64 byte host ram buffer. +// 1. Read data from next line in hex file into ram buffer. One record +// (line) is 64 bytes of data. +// 2. Check host ram buffer + record data (Address, # of bytes) against hex +// record checksum at end of record line +// 3. If error reread data from file or abort +// 4. Exit this Function and Program block or verify the block. +// This demo program will, instead, load predetermined data into each block. +// The demo does it this way because there is no comm link to get data. +// **************************************************************************** +void LoadProgramData(unsigned char bBlockNum, unsigned char bBankNum) +{ + // >>> The following call is for demo use only. <<< + // Function InitTargetTestData fills buffer for demo + // InitTargetTestData(bBlockNum, bBankNum); + // create unique data for each block + int dataNum = 0; + for (dataNum = 0; dataNum < TARGET_DATABUFF_LEN; dataNum++) { + abTargetDataOUT[dataNum] = + firmware_data[bBlockNum * TARGET_DATABUFF_LEN + dataNum]; + // abTargetDataOUT[bTargetDataPtr] = bTargetDataPtr + bBlockNum + bBankNum; + } + + // Note: + // Error checking should be added for the final version as noted above. + // For demo use this function just returns VOID. +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// fLoadSecurityData() +// Load security data from hex file into 64 byte host ram buffer. In a fully +// functional program (not a demo) this routine should do the following: +// 1. Read data from security record in hex file into ram buffer. +// 2. Check host ram buffer + record data (Address, # of bytes) against hex +// record checksum at end of record line +// 3. If error reread security data from file or abort +// 4. Exit this Function and Program block +// In this demo routine, all of the security data is set to unprotected (0x00) +// and it returns. +// This function always returns PASS. The flag return is reserving +// functionality for non-demo versions. +// **************************************************************************** +signed char fLoadSecurityData(unsigned char bBankNum) +{ + // >>> The following call is for demo use only. <<< + // Function LoadArrayWithSecurityData fills buffer for demo +// LoadArrayWithSecurityData(0,SECURITY_BYTES_PER_BANK, 0x00); + LoadArrayWithSecurityData(0, SECURITY_BYTES_PER_BANK, 0xFF); //PTJ: 0x1B (00 01 10 11) is more interesting security data than 0x00 for testing purposes + + // Note: + // Error checking should be added for the final version as noted above. + // For demo use this function just returns PASS. + return (PASS); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// fSDATACheck() +// Check SDATA pin for high or low logic level and return value to calling +// routine. +// Returns: +// 0 if the pin was low. +// 1 if the pin was high. +// **************************************************************************** +unsigned char fSDATACheck(void) +{ + gpio_direction_input(_3_TOUCH_SDA_28V); + if (gpio_get_value(_3_TOUCH_SDA_28V)) + return (1); + else + return (0); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SCLKHigh() +// Set the SCLK pin High +// **************************************************************************** +void SCLKHigh(void) +{ + gpio_direction_output(_3_TOUCH_SCL_28V, 1); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SCLKLow() +// Make Clock pin Low +// **************************************************************************** +void SCLKLow(void) +{ + gpio_direction_output(_3_TOUCH_SCL_28V, 0); +} + +#ifndef RESET_MODE // Only needed for power cycle mode +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SetSCLKHiZ() +// Set SCLK pin to HighZ drive mode. +// **************************************************************************** +void SetSCLKHiZ(void) +{ + gpio_direction_input(_3_TOUCH_SCL_28V); +} +#endif + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SetSCLKStrong() +// Set SCLK to an output (Strong drive mode) +// **************************************************************************** +void SetSCLKStrong(void) +{ + //gpio_direction_output(_3_TOUCH_SCL_28V, 1); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SetSDATAHigh() +// Make SDATA pin High +// **************************************************************************** +void SetSDATAHigh(void) +{ + gpio_direction_output(_3_TOUCH_SDA_28V, 1); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SetSDATALow() +// Make SDATA pin Low +// **************************************************************************** +void SetSDATALow(void) +{ + gpio_direction_output(_3_TOUCH_SDA_28V, 0); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SetSDATAHiZ() +// Set SDATA pin to an input (HighZ drive mode). +// **************************************************************************** +void SetSDATAHiZ(void) +{ + gpio_direction_input(_3_TOUCH_SDA_28V); // ENA-> DIS +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SetSDATAStrong() +// Set SDATA for transmission (Strong drive mode) -- as opposed to being set to +// High Z for receiving data. +// **************************************************************************** +void SetSDATAStrong(void) +{ + //gpio_direction_output(_3_TOUCH_SDA_28V, 1); +} + +#ifdef RESET_MODE +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SetXRESStrong() +// Set external reset (XRES) to an output (Strong drive mode). +// **************************************************************************** +void SetXRESStrong(void) +{ + //gpio_tlmm_config(EXT_TSP_RST); + //gpio_out(EXT_TSP_RST, GPIO_HIGH_VALUE); + //clk_busy_wait(1000); + //clk_busy_wait(1000); + //clk_busy_wait(1000); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// AssertXRES() +// Set XRES pin High +// **************************************************************************** +void AssertXRES(void) +{ +#if 0 + gpio_tlmm_config(EXT_TSP_RST); + gpio_out(EXT_TSP_RST, GPIO_HIGH_VALUE); + clk_busy_wait(1000); + clk_busy_wait(1000); + clk_busy_wait(1000); +#endif +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// DeassertXRES() +// Set XRES pin low. +// **************************************************************************** +void DeassertXRES(void) +{ + //gpio_out(EXT_TSP_RST, GPIO_LOW_VALUE); +} +#else +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// SetTargetVDDStrong() +// Set VDD pin (PWR) to an output (Strong drive mode). +// **************************************************************************** +void SetTargetVDDStrong(void) +{ +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// ApplyTargetVDD() +// Provide power to the target PSoC's Vdd pin through a GPIO. +// **************************************************************************** +void ApplyTargetVDD(void) +{ + int ret; + + gpio_direction_input(_3_TOUCH_SDA_28V); + gpio_direction_input(_3_TOUCH_SCL_28V); + gpio_direction_output(_3_GPIO_TOUCH_EN, 1); + + /* enable ldo */ + ret = touchkey_ldo_on(1); + if (ret == 0) + printk(KERN_ERR "[Touchkey]regulator get fail!!!\n"); + + mdelay(1); +} + +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// RemoveTargetVDD() +// Remove power from the target PSoC's Vdd pin. +// **************************************************************************** +void RemoveTargetVDD(void) +{ + gpio_direction_output(_3_GPIO_TOUCH_EN, 0); + + touchkey_ldo_on(0); +} +#endif + +#ifdef USE_TP +// ********************* LOW-LEVEL ISSP SUBROUTINE SECTION ******************** +// **************************************************************************** +// **** PROCESSOR SPECIFIC **** +// **************************************************************************** +// **** USER ATTENTION REQUIRED **** +// **************************************************************************** +// A "Test Point" sets a GPIO pin of the host processor high or low. +// This GPIO pin can be observed with an oscilloscope to verify the timing of +// key programming steps. TPs have been added in main() that set Port 0, pin 1 +// high during bulk erase, during each block write and during security write. +// The timing of these programming steps should be verified as correct as part +// of the validation process of the final program. +// **************************************************************************** +void InitTP(void) +{ +} + +void SetTPHigh(void) +{ +} + +void SetTPLow(void) +{ +} + +void ToggleTP(void) +{ +} +#endif +#endif //(PROJECT_REV_) +//end of file ISSP_Drive_Routines.c diff --git a/drivers/input/keyboard/cypressbln/issp_errors.h b/drivers/input/keyboard/cypressbln/issp_errors.h new file mode 100644 index 0000000..e6f0673 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_errors.h @@ -0,0 +1,65 @@ +// filename: ISSP_Errors.h +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress� product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +--------------------------------------------------------------------------*/ +#ifndef INC_ISSP_ERRORS +#define INC_ISSP_ERRORS + +// The following are defines for error messages from the ISSP program. +#define PASS 0 +// PASS is used to indicate that a function completed successfully. +#define ERROR -1 +// ERROR is a generic failure used within lower level functions before the +// error is reported. This should not be seen as an error that is reported +// from main. +#define INIT_ERROR 1 +// INIT_ERROR means a step in chip initialization failed. +#define SiID_ERROR 2 +// SiID_ERROR means that the Silicon ID check failed. This happens if the +// target part does not match the device type that the ISSP program is +// configured for. +#define ERASE_ERROR 3 +// ERASE_ERROR means that the bulk erase step failed. +#define BLOCK_ERROR 4 +// BLOCK_ERROR means that a step in programming a Flash block or the verify +// of the block failed. +#define VERIFY_ERROR 5 +// VERIFY_ERROR means that the checksum verification failed. +#define SECURITY_ERROR 6 +// SECURITY_ERROR means that the write of the security information failed. +#define STATUS_ERROR 7 + +#endif //(INC_ISSP_ERRORS) +#endif //(PROJECT_REV_) +//end of file ISSP_Errors.h diff --git a/drivers/input/keyboard/cypressbln/issp_extern.h b/drivers/input/keyboard/cypressbln/issp_extern.h new file mode 100644 index 0000000..fad9122 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_extern.h @@ -0,0 +1,99 @@ +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress� product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. +*/ + +#ifndef INC_ISSP_EXTERN +#define INC_ISSP_EXTERN + +#include "issp_directives.h" + +extern signed char fXRESInitializeTargetForISSP(void); +extern signed char fPowerCycleInitializeTargetForISSP(void); +extern signed char fEraseTarget(void); +extern unsigned int iLoadTarget(void); +extern void ReStartTarget(void); +extern signed char fVerifySiliconID(void); +extern signed char fAccTargetBankChecksum(unsigned int *); +extern void SetBankNumber(unsigned char); +extern signed char fProgramTargetBlock(unsigned char, unsigned char); +extern signed char fVerifyTargetBlock(unsigned char, unsigned char); +extern signed char fVerifySetup(unsigned char, unsigned char); +extern signed char fReadByteLoop(void); /*PTJ: read bytes after VERIFY-SETUP*/ +extern signed char fSecureTargetFlash(void); + +extern signed char fReadStatus(void); /*PTJ: READ-STATUS*/ +extern signed char fReadCalRegisters(void); +extern signed char fReadWriteSetup(void); /*PTJ: READ-WRITE-SETUP*/ +extern signed char fReadSecurity(void); /*PTJ: READ-SECURITY*/ + +extern signed char fSyncDisable(void); /*PTJ: SYNC-DISABLE rev 307*/ +extern signed char fSyncEnable(void); /*PTJ: SYNC-ENABLE rev 307*/ + +extern void InitTargetTestData(void); +extern void LoadArrayWithSecurityData(unsigned char, unsigned char, + unsigned char); + +extern void LoadProgramData(unsigned char, unsigned char); +extern signed char fLoadSecurityData(unsigned char); +extern void Delay(unsigned char); +extern unsigned char fSDATACheck(void); +extern void SCLKHigh(void); +extern void SCLKLow(void); +#ifndef RESET_MODE /*only needed when power cycle mode*/ +extern void SetSCLKHiZ(void); +#endif +extern void SetSCLKStrong(void); +extern void SetSDATAHigh(void); +extern void SetSDATALow(void); +extern void SetSDATAHiZ(void); +extern void SetSDATAStrong(void); +extern void AssertXRES(void); +extern void DeassertXRES(void); +extern void SetXRESStrong(void); +extern void ApplyTargetVDD(void); +extern void RemoveTargetVDD(void); +extern void SetTargetVDDStrong(void); + +extern unsigned char fIsError; + +#ifdef USE_TP +extern void InitTP(void); +extern void SetTPHigh(void); +extern void SetTPLow(void); +extern void ToggleTP(void); +#endif + +extern int ISSP_main(void); + +#endif /*(INC_ISSP_EXTERN)*/ +#endif /*(PROJECT_REV_)*/ diff --git a/drivers/input/keyboard/cypressbln/issp_main.c b/drivers/input/keyboard/cypressbln/issp_main.c new file mode 100644 index 0000000..a799e3b --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_main.c @@ -0,0 +1,931 @@ +// filename: main.c +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress��?product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +---------------------------------------------------------------------------*/ + +/* ############################################################################ + ################### CRITICAL PROJECT CONSTRAINTS ######################## + ############################################################################ + + ISSP programming can only occur within a temperature range of 5C to 50C. + - This project is written without temperature compensation and using + programming pulse-widths that match those used by programmers such as the + Mini-Prog and the ISSP Programmer. + This means that the die temperature of the PSoC device cannot be outside + of the above temperature range. + If a wider temperature range is required, contact your Cypress Semi- + conductor FAE or sales person for assistance. + + The project can be configured to program devices at 5V or at 3.3V. + - Initialization of the device is different for different voltages. The + initialization is hardcoded and can only be set for one voltage range. + The supported voltages ranges are 3.3V (3.0V to 3.6V) and 5V (4.75V to + 5.25V). See the device datasheet for more details. If varying voltage + ranges must be supported, contact your Cypress Semiconductor FAE or sales + person for assistance. + - ISSP programming for the 2.7V range (2.7V to 3.0V) is not supported. + + This program does not support programming all PSoC Devices + - It does not support obsoleted PSoC devices. A list of devices that are + not supported is shown here: + CY8C22x13 - not supported + CY8C24x23 - not supported (CY8C24x23A is supported) + CY8C25x43 - not supported + CY8C26x43 - not supported + - It does not suport devices that have not been released for sale at the + time this version was created. If you need to ISSP program a newly released + device, please contact Cypress Semiconductor Applications, your FAE or + sales person for assistance. + The CY8C20x23 devices are not supported at the time of this release. + + ############################################################################ + ##########################################################################*/ + +/* This program uses information found in Cypress Semiconductor application +// notes "Programming - In-System Serial Programming Protocol", AN2026. The +// version of this application note that applies to the specific PSoC that is +// being In-System Serial Programmed should be read and and understood when +// using this program. (http://www.cypress.com) + +// This project is included with releases of PSoC Programmer software. It is +// important to confirm that the latest revision of this software is used when +// it is used. The revision of this copy can be found in the Project History +// table below. +*/ + +/*///////////////////////////////////////////////////////////////////////////// +// PROJECT HISTORY +// date revision author description +// -------- -------- ------ ----------------------------------------------- +// 7/23/08 3.04 ptj 1. CPU clock speed set to to 12MHz (default) after +// TSYNC is disabled. Previously, it was being set +// to 3MHz on accident. This affects the following +// mnemonics: +// ID_SETUP_1, +// VERIFY_SETUP, +// ERASE, +// SECURE, +// CHECKSUM_SETUP, +// PROGRAM_AND_VERIFY, +// ID_SETUP_2, +// SYNC_DISABLE +// +// 6/06/08 3.03 ptj 1. The Verify_Setup section can tell when flash +// is fully protected. bTargetStatus[0] shows a +// 01h when flash is "W" Full Protection +// 7/23/08 2. READ-ID-WORD updated to read Revision ID from +// Accumulator A and X, registers T,F0h and T,F3h +// +// 5/30/08 3.02 ptj 1. All vectors work. +// 2. Main function will execute the +// following programming sequence: +// . id setup 1 +// . id setup 2 +// . erase +// . program and verify +// . verify (although not necessary) +// . secure flash +// . read security +// . checksum +// +// 05/28/08 3.01 ptj TEST CODE - NOT COMPLETE +// 1. The sequence surrounding PROGRAM-AND-VERIFY was +// improved and works according to spec. +// 2. The sequence surroudning VERIFY-SETUP was devel- +// oped and improved. +// 3. TSYNC Enable is used to in a limited way +// 4. Working Vectors: ID-SETUP-1, ID-SETUP-2, ERASE, +// PROGRAM-AND-VERIFY, SECURE, VERIFY-SETUP, +// CHECKSUM-SETUP +// 5. Un-tested Vectors: READ-SECURITY +// +// 05/23/08 3.00 ptj TEST CODE - NOT COMPLETE +// 1. This code is a test platform for the development +// of the Krypton (cy8c20x66) Programming Sequence. +// See 001-15870 rev *A. This code works on "rev B" +// silicon. +// 2. Host is Hydra 29000, Target is Krypton "rev B" +// 3. Added Krypton device support +// 4. TYSNC Enable/Disable is not used. +// 5. Working Vectors: ID-SETUP-1, ID-SETUP-2, ERASE, +// PROGRAM-AND-VERIFY, SECURE +// 6. Non-working Vectors: CHECKSUM-SETUP +// 7. Un-tested Vectors: READ-SECURITY, VERIFY-SETUP +// 8. Other minor (non-SROM) vectors not listed. +// +// 09/23/07 2.11 dkn 1. Added searchable comments for the HSSP app note. +// 2. Added new device vectors. +// 3. Verified write and erase pulsewidths. +// 4. Modified some functions for easier porting to +// other processors. +// +// 09/23/06 2.10 mwl 1. Added #define SECURITY_BYTES_PER_BANK to +// file issp_defs.h. Modified function +// fSecureTargetFlashMain() in issp_routines.c +// to use new #define. Modified function +// fLoadSecurityData() in issp_driver_routines.c +// to accept a bank number. Modified the secure +// data loop in main.c to program multiple banks. +// +// 2. Created function fAccTargetBankChecksum to +// read and add the target bank checksum to the +// referenced accumulator. This allows the +// checksum loop in main.c to function at the +// same level of abstraction as the other +// programming steps. Accordingly, modified the +// checksum loop in main.c. Deleted previous +// function fVerifyTargetChecksum(). +// +// 09/08/06 2.00 mwl 1. Array variable abTargetDataOUT was not +// getting intialized anywhere and compiled as a +// one-byte array. Modified issp_driver_routines.c +// line 44 to initialize with TARGET_DATABUFF_LEN. +// +// 2. Function void LoadProgramData(unsigned char +// bBlockNum) in issp_driver_routines.c had only +// one parameter bBlockNum but was being called +// from function main() with two parameters, +// LoadProgramData(bBankCounter, (unsigned char) +// iBlockCounter). Modified function +// LoadProgramData() to accept both parameters, +// and in turn modified InitTargetTestData() to +// accept and use both as well. +// +// 3. Corrected byte set_bank_number[1] +// inissp_vectors.h. Was 0xF2, correct value is +// 0xE2. +// +// 4. Corrected the logic to send the SET_BANK_NUM +// vectors per the AN2026B flow chart.The previous +// code version was sending once per block, but +// should have been once per bank. Removed the +// conditionally-compiled bank setting code blocks +// from the top of fProgramTargetBlock() and +// fVerifyTargetBlock() int issp_routines.c and +// created a conditionally-compiled subroutine in +// that same file called SetBankNumber(). Two +// conditionally-compiled calls to SetBankNumber() +// were added to main.c(). +// +// 5. Corrected CY8C29x66 NUM_BANKS and +// BLOCKS_PER_BANK definitions in ISSP_Defs.h. +// Was 2 and 256 respectively, correct values are +// 4 and 128. +// +// 6. Modified function fVerifyTargetChecksum() +// in issp_routines.c to read and accumulate multiple +// banks of checksums as required for targets +// CY8C24x94 and CY8C29x66. Would have kept same +// level of abstraction as other multi-bank functions +// in main.c, but this implementation impacted the +// code the least. +// +// 7. Corrected byte checksum_v[26] of +// CHECKSUM_SETUP_24_29 in issp_vectors.h. Was 0x02, +// correct value is 0x04. +// +// 06/30/06 1.10 jvy Added support for 24x94 and 29x66 devices. +// 06/09/06 1.00 jvy Changed CPU Clk to 12MHz (from 24MHz) so the +// host can run from 3.3V. +// Simplified init of security data. +// 06/05/06 0.06 jvy Version #ifdef added to each file to make sure +// all of the file are from the same revision. +// Added flags to prevent multiple includes of H +// files. +// Changed pre-determined data for demo to be +// unique for each block. +// Changed block verify to check all blocks after +// block programming has been completed. +// Added SetSCLKHiZ to explicitly set the Clk to +// HighZ before power cycle acquire. +// Fixed wrong vectors in setting Security. +// Fixed wrong vectors in Block program. +// Added support for pods +// 06/05/06 0.05 jvy Comments from code review. First copy checked +// into perforce. Code has been updated enough to +// compile, by implementing some comments and +// fixing others. +// 06/04/06 0.04 jvy made code more efficient in bReceiveByte(), and +// SendVector() by re-arranging so that local vars +// could be eliminated. +// added defines for the delays used in the code. +// 06/02/06 0.03 jvy added number of Flash block adjustment to +// programming. added power cycle programming +// mode support. This is the version initially +// sent out for peer review. +// 06/02/06 0.02 jvy added framework for multiple chip support from +// one source code set using compiler directives. +// added timeout to high-low trasition detection. +// added multiple error message to allow tracking +// of failures. +// 05/30/06 0.01 jvy initial version, +// created from DBD's issp_27xxx_v3 program. +/////////////////////////////////////////////////////////////////////////////*/ + +/* (((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))) + PSoC In-System Serial Programming (ISSP) Template + This PSoC Project is designed to be used as a template for designs that + require PSoC ISSP Functions. + + This project is based on the AN2026 series of Application Notes. That app + note should be referenced before any modifications to this project are made. + + The subroutines and files were created in such a way as to allow easy cut & + paste as needed. There are no customer-specific functions in this project. + This demo of the code utilizes a PSoC as the Host. + + Some of the subroutines could be merged, or otherwise reduced, but they have + been written as independently as possible so that the specific steps involved + within each function can easily be seen. By merging things, some code-space + savings could be realized. + + As is, and with all features enabled, the project consumes approximately 3500 + bytes of code space, and 19-Bytes of RAM (not including stack usage). The + Block-Verify requires a 64-Byte buffer for read-back verification. This same + buffer could be used to hold the (actual) incoming program data. + + Please refer to the compiler-directives file "directives.h" to see the various + features. + + The pin used in this project are assigned as shown below. The HOST pins are + arbitrary and any 3 pins could be used (the masks used to control the pins + must be changed). The TARGET pins cannot be changed, these are fixed function + pins on the PSoC. + The PWR pin is used to provide power to the target device if power cycle + programming mode is used. The compiler directive RESET_MODE in ISSP_directives.h + is used to select the programming mode. This pin could control the enable on + a voltage regulator, or could control the gate of a FET that is used to turn + the power to the PSoC on. + The TP pin is a Test Point pin that can be used signal from the host processor + that the program has completed certain tasks. Predefined test points are + included that can be used to observe the timing for bulk erasing, block + programming and security programming. + + SIGNAL HOST TARGET + --------------------- + SDATA P1.7 P1.0 + SCLK P1.6 P1.1 + XRES P2.0 XRES + PWR P2.3 Vdd + TP P0.7 n/a + + For test & demonstration, this project generates the program data internally. + It does not take-in the data from an external source such as I2C, UART, SPI, + etc. However, the program was written in such a way to be portable into such + designs. The spirit of this project was to keep it stripped to the minimum + functions required to do the ISSP functions only, thereby making a portable + framework for integration with other projects. + + The high-level functions have been written in C in order to be portable to + other processors. The low-level functions that are processor dependent, such + as toggling pins and implementing specific delays, are all found in the file + ISSP_Drive_Routines.c. These functions must be converted to equivalent + functions for the HOST processor. Care must be taken to meet the timing + requirements when converting to a new processor. ISSP timing information can + be found in Application Note AN2026. All of the sections of this program + that need to be modified for the host processor have "PROCESSOR_SPECIFIC" in + the comments. By performing a "Find in files" using "PROCESSOR_SPECIFIC" these + sections can easily be identified. + + The variables in this project use Hungarian notation. Hungarian prepends a + lower case letter to each variable that identifies the variable type. The + prefixes used in this program are defined below: + b = byte length variable, signed char and unsigned char + i = 2-byte length variable, signed int and unsigned int + f = byte length variable used as a flag (TRUE = 0, FALSE != 0) + ab = an array of byte length variables + + After this program has been ported to the desired host processor the timing + of the signals must be confirmed. The maximum SCLK frequency must be checked + as well as the timing of the bulk erase, block write and security write + pulses. + + The maximum SCLK frequency for the target device can be found in the device + datasheet under AC Programming Specifications with a Symbol of "Fsclk". + An oscilloscope should be used to make sure that no half-cycles (the high + time or the low time) are shorter than the half-period of the maximum + freqency. In other words, if the maximum SCLK frequency is 8MHz, there can be + no high or low pulses shorter than 1/(2*8MHz), or 62.5 nsec. + + The test point (TP) functions, enabled by the define USE_TP, provide an output + from the host processor that brackets the timing of the internal bulk erase, + block write and security write programming pulses. An oscilloscope, along with + break points in the PSoC ICE Debugger should be used to verify the timing of + the programming. The Application Note, "Host-Sourced Serial Programming" + explains how to do these measurements and should be consulted for the expected + timing of the erase and program pulses. + + ############################################################################ + ############################################################################ + +(((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))) */ + +/*---------------------------------------------------------------------------- +// C main line +//---------------------------------------------------------------------------- +*/ +#include <linux/module.h> + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/sysctl.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> +#include <linux/input.h> +#include <mach/regs-gpio.h> +#include <plat/gpio-cfg.h> +#include <asm/gpio.h> +#include <asm/uaccess.h> +#include <asm/io.h> +//#include <m8c.h> // part specific constants and macros +//#include "PSoCAPI.h" // PSoC API definitions for all User Modules +// ------ Declarations Associated with ISSP Files & Routines ------- +// Add these to your project as needed. +#include "issp_extern.h" +#include "issp_directives.h" +#include "issp_defs.h" +#include "issp_errors.h" +#include "u1-cypress-gpio.h" +/* ------------------------------------------------------------------------- */ + +/* enable ldo11 */ +extern int touchkey_ldo_on(bool on); + +unsigned char bBankCounter; +unsigned int iBlockCounter; +unsigned int iChecksumData; +unsigned int iChecksumTarget; + +//update version "eclair/vendor/samsung/apps/Lcdtest/src/com/sec/android/app/lcdtest/touch_firmware.java" +#if defined(CONFIG_MACH_Q1_BD) +#include "touchkey_fw_Q1.h" +#elif defined(CONFIG_ARIES_NTT) +#include "touchkey_fw_NTT.h" +#elif defined(CONFIG_TARGET_LOCALE_NA) +#include "touchkey_fw_NA.h" +#elif defined(CONFIG_TARGET_LOCALE_NAATT) +#include "touchkey_fw_NAATT.h" +#else +#include "touchkey_fw_U1.h" +#endif + +//////I2C + +#define EXT_I2C_SCL_HIGH \ + do { \ + int delay_count; \ + gpio_direction_output(_3_TOUCH_SCL_28V, 1); \ + gpio_direction_input(_3_TOUCH_SCL_28V); \ + delay_count = 100000; \ + while(delay_count--) \ + { \ + if(gpio_get_value(_3_TOUCH_SCL_28V)) \ + break; \ + udelay(1); \ + } \ + } while(0); +#define EXT_I2C_SCL_LOW gpio_direction_output(_3_TOUCH_SCL_28V, 0); +#define EXT_I2C_SDA_HIGH gpio_direction_output(_3_TOUCH_SDA_28V, 1); +#define EXT_I2C_SDA_LOW gpio_direction_output(_3_TOUCH_SDA_28V, 0); +#define TRUE 1 +#define FALSE 0 + +static void EXT_I2C_LOW(u32 delay) +{ + EXT_I2C_SDA_LOW; + //udelay(delay); + EXT_I2C_SCL_HIGH; + //udelay(delay); + EXT_I2C_SCL_LOW; + //udelay(delay); +} + +static void EXT_I2C_HIGH(u32 delay) +{ + EXT_I2C_SDA_HIGH; + //udelay(delay); + EXT_I2C_SCL_HIGH; + //udelay(delay); + EXT_I2C_SCL_LOW; + //udelay(delay); +} + +static void EXT_I2C_START(u32 delay) +{ + EXT_I2C_SDA_HIGH; + EXT_I2C_SCL_HIGH; + //udelay(delay); + EXT_I2C_SDA_LOW; + //udelay(delay); + EXT_I2C_SCL_LOW; + //udelay(delay); + +} + +static void EXT_I2C_END(u32 delay) +{ + EXT_I2C_SDA_LOW; + EXT_I2C_SCL_HIGH; + //udelay(delay); + EXT_I2C_SDA_HIGH; +} + +static int EXT_I2C_ACK(u32 delay) +{ + u32 ack; + + /* SDA -> Input */ + gpio_direction_input(_3_TOUCH_SDA_28V); + + udelay(delay); + EXT_I2C_SCL_HIGH; + //udelay(delay); + ack = gpio_get_value(_3_TOUCH_SDA_28V); + EXT_I2C_SCL_LOW; + //udelay(delay); + if (ack) + printk("EXT_I2C No ACK\n"); + + return ack; +} + +static void EXT_I2C_NACK(u32 delay) +{ + EXT_I2C_SDA_HIGH; + EXT_I2C_SCL_HIGH; + //udelay(delay); + EXT_I2C_SCL_LOW; + //udelay(delay); +} + +static void EXT_I2C_SEND_ACK(u32 delay) +{ + gpio_direction_output(_3_TOUCH_SDA_28V, 0); + EXT_I2C_SCL_HIGH; + //udelay(delay); + EXT_I2C_SCL_LOW; + //udelay(delay); + +} + +#define EXT_I2C_DELAY 1 +//============================================================ +// +// Porting section 6. I2C function calling +// +// Connect baseband i2c function +// +// Warning 1. !!!! Burst mode is not supported. Transfer 1 byte Only. +// +// Every i2c packet has to +// " START > Slave address > One byte > STOP " at download mode. +// +// Warning 2. !!!! Check return value of i2c function. +// +// _i2c_read_(), _i2c_write_() must return +// TRUE (1) if success, +// FALSE(0) if failed. +// +// If baseband i2c function returns different value, convert return value. +// ex> baseband_return = baseband_i2c_read( slave_addr, pData, cLength ); +// return ( baseband_return == BASEBAND_RETURN_VALUE_SUCCESS ); +// +// +// Warning 3. !!!! Check Slave address +// +// Slave address is '0x7F' at download mode. ( Diffrent with Normal touch working mode ) +// '0x7F' is original address, +// If shift << 1 bit, It becomes '0xFE' +// +//============================================================ + +static int +_i2c_read_(unsigned char SlaveAddr, unsigned char *pData, unsigned char cLength) +{ + unsigned int i; + int delay_count = 10000; + + EXT_I2C_START(EXT_I2C_DELAY); + + SlaveAddr = SlaveAddr << 1; + for (i = 8; i > 1; i--) { + if ((SlaveAddr >> (i - 1)) & 0x1) + EXT_I2C_HIGH(EXT_I2C_DELAY); + else + EXT_I2C_LOW(EXT_I2C_DELAY); + } + + EXT_I2C_HIGH(EXT_I2C_DELAY); //readwrite + + if (EXT_I2C_ACK(EXT_I2C_DELAY)) { + EXT_I2C_END(EXT_I2C_DELAY); + return FALSE; + } + + udelay(10); + gpio_direction_input(_3_TOUCH_SCL_28V); + delay_count = 100000; + while (delay_count--) { + if (gpio_get_value(_3_TOUCH_SCL_28V)) + break; + udelay(1); + } + while (cLength--) { + *pData = 0; + for (i = 8; i > 0; i--) { + //udelay(EXT_I2C_DELAY); + EXT_I2C_SCL_HIGH; + //udelay(EXT_I2C_DELAY); + *pData |= + (!!(gpio_get_value(_3_TOUCH_SDA_28V)) << (i - 1)); + //udelay(EXT_I2C_DELAY); + EXT_I2C_SCL_LOW; + //udelay(EXT_I2C_DELAY); + } + + if (cLength) { + EXT_I2C_SEND_ACK(EXT_I2C_DELAY); + udelay(10); + pData++; + gpio_direction_input(_3_TOUCH_SDA_28V); + gpio_direction_input(_3_TOUCH_SCL_28V); + delay_count = 100000; + while (delay_count--) { + if (gpio_get_value(_3_TOUCH_SCL_28V)) + break; + udelay(1); + } + } else + EXT_I2C_NACK(EXT_I2C_DELAY); + } + + EXT_I2C_END(EXT_I2C_DELAY); + + return (TRUE); + +} + +#define TOUCHKEY_ADDRESS 0x20 + +int get_touchkey_firmware(char *version) +{ + int retry = 3; + while (retry--) { + if (_i2c_read_(TOUCHKEY_ADDRESS, version, 3)) + return 0; + + } + return (-1); + //printk("%s F/W version: 0x%x, Module version:0x%x\n",__FUNCTION__, version[1],version[2]); +} + +/* ========================================================================= */ +// ErrorTrap() +// Return is not valid from main for PSOC, so this ErrorTrap routine is used. +// For some systems returning an error code will work best. For those, the +// calls to ErrorTrap() should be replaced with a return(bErrorNumber). For +// other systems another method of reporting an error could be added to this +// function -- such as reporting over a communcations port. +/* ========================================================================= */ +void ErrorTrap(unsigned char bErrorNumber) +{ +#ifndef RESET_MODE + // Set all pins to highZ to avoid back powering the PSoC through the GPIO + // protection diodes. + SetSCLKHiZ(); + SetSDATAHiZ(); + // If Power Cycle programming, turn off the target + RemoveTargetVDD(); +#endif + printk("\r\nErrorTrap: errorNumber: %d\n", bErrorNumber); + + // TODO: write retry code or some processing. + return; +// while (1); +} + +/* ========================================================================= */ +/* MAIN LOOP */ +/* Based on the diagram in the AN2026 */ +/* ========================================================================= */ + +int ISSP_main(void) +{ + unsigned long flags; + + // -- This example section of commands show the high-level calls to ------- + // -- perform Target Initialization, SilcionID Test, Bulk-Erase, Target --- + // -- RAM Load, FLASH-Block Program, and Target Checksum Verification. ---- + + // >>>> ISSP Programming Starts Here <<<< + // Acquire the device through reset or power cycle + s3c_gpio_setpull(_3_TOUCH_SCL_28V, S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(_3_TOUCH_SDA_28V, S3C_GPIO_PULL_NONE); + gpio_direction_output(_3_GPIO_TOUCH_EN, 0); + /* disable ldo11 */ + touchkey_ldo_on(0); + msleep(1); +#ifdef RESET_MODE + gpio_tlmm_config(LED_26V_EN); + gpio_tlmm_config(EXT_TSP_SCL); + gpio_tlmm_config(EXT_TSP_SDA); + gpio_tlmm_config(LED_RST); + + gpio_out(LED_RST, GPIO_LOW_VALUE); + clk_busy_wait(10); + + gpio_out(LED_26V_EN, GPIO_HIGH_VALUE); + for (temp = 0; temp < 16; temp++) { + clk_busy_wait(1000); + dog_kick(); + } + + // Initialize the Host & Target for ISSP operations + printk("fXRESInitializeTargetForISSP Start\n"); + + //INTLOCK(); + local_save_flags(flags); + local_irq_disable(); + if (fIsError = fXRESInitializeTargetForISSP()) { + ErrorTrap(fIsError); + return fIsError; + } + //INTFREE(); +#else + //INTLOCK(); + local_irq_save(flags); + // Initialize the Host & Target for ISSP operations + if ((fIsError = fPowerCycleInitializeTargetForISSP())) { + ErrorTrap(fIsError); + return fIsError; + } + //INTFREE(); +#endif /* RESET_MODE */ + +#if 0 // issp_test_2010 block + printk("fXRESInitializeTargetForISSP END\n"); + + // Run the SiliconID Verification, and proceed according to result. + printk("fVerifySiliconID START\n"); +#endif + + //INTLOCK(); + fVerifySiliconID(); // .. error // issp_test_20100709 unblock +#if 0 + if (fIsError = fVerifySiliconID()) { + ErrorTrap(fIsError); + return fIsError; + } +#endif + + //INTFREE(); + local_irq_restore(flags); + //printk("fVerifySiliconID END\n"); // issp_test_2010 block + + // Bulk-Erase the Device. + //printk("fEraseTarget START\n"); // issp_test_2010 block + //INTLOCK(); + local_irq_save(flags); + if ((fIsError = fEraseTarget())) { + ErrorTrap(fIsError); + return fIsError; + } + //INTFREE(); + local_irq_restore(flags); + //printk("fEraseTarget END\n"); // issp_test_2010 block + + //==============================================================// + // Program Flash blocks with predetermined data. In the final application + // this data should come from the HEX output of PSoC Designer. + //printk("Program Flash Blocks Start\n"); + + iChecksumData = 0; // Calculte the device checksum as you go + for (bBankCounter = 0; bBankCounter < NUM_BANKS; bBankCounter++) //PTJ: NUM_BANKS should be 1 for Krypton + { + local_irq_save(flags); + for (iBlockCounter = 0; iBlockCounter < BLOCKS_PER_BANK; + iBlockCounter++) { + //printk("Program Loop : iBlockCounter %d \n",iBlockCounter); + //INTLOCK(); + // local_irq_save(flags); + + //PTJ: READ-WRITE-SETUP used here to select SRAM Bank 1, and TSYNC Enable +#ifdef CY8C20x66 + if ((fIsError = fSyncEnable())) { + ErrorTrap(fIsError); + return fIsError; + } + if ((fIsError = fReadWriteSetup())) { // send write command - swanhan + ErrorTrap(fIsError); + return fIsError; + } +#endif + //firmware read. + //LoadProgramData(bBankCounter, (unsigned char)iBlockCounter); //PTJ: this loads the Hydra with test data, not the krypton + LoadProgramData((unsigned char)iBlockCounter, bBankCounter); //PTJ: this loads the Hydra with test data, not the krypton + iChecksumData += iLoadTarget(); //PTJ: this loads the Krypton + + //dog_kick(); + if ((fIsError = + fProgramTargetBlock(bBankCounter, + (unsigned char)iBlockCounter))) { + ErrorTrap(fIsError); + return fIsError; + } +#ifdef CY8C20x66 //PTJ: READ-STATUS after PROGRAM-AND-VERIFY + if ((fIsError = fReadStatus())) { + ErrorTrap(fIsError); + return fIsError; + } +#endif + //INTFREE(); + //local_irq_restore(flags); + } + local_irq_restore(flags); + } + + //printk("\r\n Program Flash Blocks End\n"); + +#if 0 // verify check pass or check. + printk("\r\n Verify Start", 0, 0, 0); + //=======================================================// + //PTJ: Doing Verify + //PTJ: this code isnt needed in the program flow because we use PROGRAM-AND-VERIFY (ProgramAndVerify SROM Func) + //PTJ: which has Verify built into it. + // Verify included for completeness in case host desires to do a stand-alone verify at a later date. + for (bBankCounter = 0; bBankCounter < NUM_BANKS; bBankCounter++) { + for (iBlockCounter = 0; iBlockCounter < BLOCKS_PER_BANK; + iBlockCounter++) { + printk("Verify Loop: iBlockCounter %d", iBlockCounter, + 0, 0); + INTLOCK(); + LoadProgramData(bBankCounter, + (unsigned char)iBlockCounter); + + //PTJ: READ-WRITE-SETUP used here to select SRAM Bank 1, and TSYNC Enable +#ifdef CY8C20x66 + if (fIsError = fReadWriteSetup()) { + ErrorTrap(fIsError); + } +#endif + + dog_kick(); + + if (fIsError = + fVerifySetup(bBankCounter, + (unsigned char)iBlockCounter)) { + ErrorTrap(fIsError); + } +#ifdef CY8C20x66 //PTJ: READ-STATUS after VERIFY-SETUP + if (fIsError = fSyncEnable()) { //PTJ: 307, added for tsync enable testing + ErrorTrap(fIsError); + } + if (fIsError = fReadStatus()) { + ErrorTrap(fIsError); + } + //PTJ: READ-WRITE-SETUP used here to select SRAM Bank 1, and TSYNC Enable + if (fIsError = fReadWriteSetup()) { + ErrorTrap(fIsError); + } + if (fIsError = fSyncDisable()) { //PTJ: 307, added for tsync enable testing + ErrorTrap(fIsError); + } +#endif + INTFREE(); + } + } + printk("Verify End", 0, 0, 0); +#endif /* #if 1 */ +#if 1 /* security start */ + //=======================================================// + // Program security data into target PSoC. In the final application this + // data should come from the HEX output of PSoC Designer. + //printk("Program security data START\n"); + //INTLOCK(); + local_irq_save(flags); + for (bBankCounter = 0; bBankCounter < NUM_BANKS; bBankCounter++) { + //PTJ: READ-WRITE-SETUP used here to select SRAM Bank 1 +#ifdef CY8C20x66 + if ((fIsError = fSyncEnable())) { //PTJ: 307, added for tsync enable testing. + ErrorTrap(fIsError); + return fIsError; + } + if ((fIsError = fReadWriteSetup())) { + ErrorTrap(fIsError); + return fIsError; + } +#endif + // Load one bank of security data from hex file into buffer + if ((fIsError = fLoadSecurityData(bBankCounter))) { + ErrorTrap(fIsError); + return fIsError; + } + // Secure one bank of the target flash + if ((fIsError = fSecureTargetFlash())) { + ErrorTrap(fIsError); + return fIsError; + } + } + //INTFREE(); + local_irq_restore(flags); + + //printk("Program security data END\n"); + + //==============================================================// + //PTJ: Do READ-SECURITY after SECURE + + //Load one bank of security data from hex file into buffer + //loads abTargetDataOUT[] with security data that was used in secure bit stream + //INTLOCK(); + local_irq_save(flags); + if ((fIsError = fLoadSecurityData(bBankCounter))) { + ErrorTrap(fIsError); + return fIsError; + } +#ifdef CY8C20x66 + if ((fIsError = fReadSecurity())) { + ErrorTrap(fIsError); + return fIsError; + } +#endif + //INTFREE(); + local_irq_restore(flags); + //printk("Load security data END\n"); +#endif /* security end */ + + //=======================================================// + //PTJ: Doing Checksum after READ-SECURITY + //INTLOCK(); + local_irq_save(flags); + iChecksumTarget = 0; + for (bBankCounter = 0; bBankCounter < NUM_BANKS; bBankCounter++) { + if ((fIsError = fAccTargetBankChecksum(&iChecksumTarget))) { + ErrorTrap(fIsError); + return fIsError; + } + } + + //INTFREE(); + local_irq_restore(flags); + + //printk("Checksum : iChecksumTarget (0x%X)\n", (unsigned char)iChecksumTarget); + //printk ("Checksum : iChecksumData (0x%X)\n", (unsigned char)iChecksumData); + + if ((unsigned short)(iChecksumTarget & 0xffff) != + (unsigned short)(iChecksumData & 0xffff)) { + ErrorTrap(VERIFY_ERROR); + return fIsError; + } + //printk("Doing Checksum END\n"); + + // *** SUCCESS *** + // At this point, the Target has been successfully Initialize, ID-Checked, + // Bulk-Erased, Block-Loaded, Block-Programmed, Block-Verified, and Device- + // Checksum Verified. + + // You may want to restart Your Target PSoC Here. + ReStartTarget(); //Touch IC Reset. + + //printk("ReStartTarget\n"); + + return 0; +} + +// end of main() + +#endif //(PROJECT_REV_) end of file main.c diff --git a/drivers/input/keyboard/cypressbln/issp_revision.h b/drivers/input/keyboard/cypressbln/issp_revision.h new file mode 100644 index 0000000..ca1990c --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_revision.h @@ -0,0 +1,65 @@ +/* filename: ISSP_Revision.h + Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress� product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +--------------------------------------------------------------------------*/ +#ifndef INC_ISSP_REVISION +#define INC_ISSP_REVISION +// The PROJECT_REV_xyz is used to make sure that the files in the project +// are all from the same revision of the program. Each file starts with an +// ifdef that will prevent the file from being compiled if it is not the +// correct revision +// Set the revision to 3.04 +#define PROJECT_REV_304 + +#endif //(INC_ISSP_REVISION) +#include <linux/module.h> + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/sysctl.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <mach/regs-gpio.h> +#include <plat/gpio-cfg.h> +#include <asm/gpio.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> +#include <linux/earlysuspend.h> +#include <asm/io.h> +//end of file ISSP_Revision.h diff --git a/drivers/input/keyboard/cypressbln/issp_routines.c b/drivers/input/keyboard/cypressbln/issp_routines.c new file mode 100644 index 0000000..0186e2b --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_routines.c @@ -0,0 +1,1044 @@ +// filename: ISSP_Routines.c +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypressï¿?product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +--------------------------------------------------------------------------*/ +#include <linux/module.h> + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/pm.h> +#include <linux/sysctl.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <mach/regs-gpio.h> +#include <plat/gpio-cfg.h> +#include <asm/gpio.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> +#include <linux/earlysuspend.h> +#include <asm/io.h> +#include <linux/hrtimer.h> +//mhsong #include <m8c.h> // part specific constants and macros +//mhsong #include "PSoCAPI.h" // PSoC API definitions for all User Modules +#include "issp_defs.h" +#include "issp_vectors.h" +#include "issp_extern.h" +#include "issp_errors.h" +#include "issp_directives.h" +#include "issp_delays.h" + +unsigned char bTargetDataIN; +unsigned char abTargetDataOUT[TARGET_DATABUFF_LEN]; + +unsigned char bTargetAddress; +unsigned char bTargetDataPtr = 0; +unsigned char bTargetID[10]; +unsigned char bTargetStatus[10]; //PTJ: created to support READ-STATUS in fReadStatus() + +unsigned char fIsError; + +/* ((((((((((((((((((((( LOW-LEVEL ISSP SUBROUTINE SECTION )))))))))))))))))))) + (( The subroutines in this section use functions from the C file )) + (( ISSP_Drive_Routines.c. The functions in that file interface to the )) + (( processor specific hardware. So, these functions should work as is, if )) + (( the routines in ISSP_Drive_Routines.c are correctly converted. )) + (((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))))*/ + +// ============================================================================ +// RunClock() +// Description: +// Run Clock without sending/receiving bits. Use this when transitioning from +// write to read and read to write "num_cycles" is number of SCLK cycles, not +// number of counter cycles. +// +// SCLK cannot run faster than the specified maximum frequency of 8MHz. Some +// processors may need to have delays added after setting SCLK low and setting +// SCLK high in order to not exceed this specification. The maximum frequency +// of SCLK should be measured as part of validation of the final program +// +// ============================================================================ +void RunClock(unsigned int iNumCycles) +{ + int i; + + for (i = 0; i < iNumCycles; i++) { + SCLKLow(); + SCLKHigh(); + } + // function exits with CLK high. +} + +// ============================================================================ +// bReceiveBit() +// Clocks the SCLK pin (high-low-high) and reads the status of the SDATA pin +// after the rising edge. +// +// SCLK cannot run faster than the specified maximum frequency of 8MHz. Some +// processors may need to have delays added after setting SCLK low and setting +// SCLK high in order to not exceed this specification. The maximum frequency +// of SCLK should be measured as part of validation of the final program +// +// Returns: +// 0 if SDATA was low +// 1 if SDATA was high +// ============================================================================ +unsigned char bReceiveBit(void) +{ + SCLKLow(); + SCLKHigh(); + if (fSDATACheck()) { + return (1); + } else { + return (0); + } +} + +// ============================================================================ +// bReceiveByte() +// Calls ReceiveBit 8 times to receive one byte. +// Returns: +// The 8-bit values recieved. +// ============================================================================ +unsigned char bReceiveByte(void) +{ + unsigned char b; + unsigned char bCurrByte = 0x00; + + for (b = 0; b < 8; b++) { + bCurrByte = (bCurrByte << 1) + bReceiveBit(); + } + return (bCurrByte); +} + +// ============================================================================ +// SendByte() +// This routine sends up to one byte of a vector, one bit at a time. +// bCurrByte the byte that contains the bits to be sent. +// bSize the number of bits to be sent. Valid values are 1 to 8. +// +// SCLK cannot run faster than the specified maximum frequency of 8MHz. Some +// processors may need to have delays added after setting SCLK low and setting +// SCLK high in order to not exceed this specification. The maximum frequency +// of SCLK should be measured as part of validation of the final program +// +// There is no returned value. +// ============================================================================ +void SendByte(unsigned char bCurrByte, unsigned char bSize) +{ + unsigned char b = 0; + + for (b = 0; b < bSize; b++) { + if (bCurrByte & 0x80) { + // Send a '1' + SetSDATAHigh(); + SCLKHigh(); + SCLKLow(); + } else { + // Send a '0' + SetSDATALow(); + SCLKHigh(); + SCLKLow(); + } + bCurrByte = bCurrByte << 1; + } +} + +// ============================================================================ +// SendVector() +// This routine sends the vector specifed. All vectors constant strings found +// in ISSP_Vectors.h. The data line is returned to HiZ after the vector is +// sent. +// bVect a pointer to the vector to be sent. +// nNumBits the number of bits to be sent. +// bCurrByte scratch var to keep the byte to be sent. +// +// There is no returned value. +// ============================================================================ +void SendVector(const unsigned char *bVect, unsigned int iNumBits) +{ + SetSDATAStrong(); + while (iNumBits > 0) { + if (iNumBits >= 8) { + SendByte(*(bVect), 8); + iNumBits -= 8; + bVect++; + } else { + SendByte(*(bVect), iNumBits); + iNumBits = 0; + } + } + SetSDATALow(); // issp_test_20100709 add + SetSDATAHiZ(); +} + +// ============================================================================ +// fDetectHiLoTransition() +// Waits for transition from SDATA = 1 to SDATA = 0. Has a 100 msec timeout. +// TRANSITION_TIMEOUT is a loop counter for a 100msec timeout when waiting for +// a high-to-low transition. This is used in the polling loop of +// fDetectHiLoTransition(). The timing of the while(1) loops can be calculated +// and the number of loops is counted, using iTimer, to determine when 100 +// msec has passed. +// +//// SCLK cannot run faster than the specified maximum frequency of 8MHz. Some +// processors may need to have delays added after setting SCLK low and setting +// SCLK high in order to not exceed this specification. The maximum frequency +// of SCLK should be measured as part of validation of the final program +// +// Returns: +// 0 if successful +// -1 if timed out. +// ============================================================================ +signed char fDetectHiLoTransition(void) +{ + // nTimer breaks out of the while loops if the wait in the two loops totals + // more than 100 msec. Making this static makes the loop run a faster. + // This is really a processor/compiler dependency and it not needed. + static unsigned int iTimer; + + // NOTE: + // These loops look unconventional, but it is necessary to check SDATA_PIN + // as shown because the transition can be missed otherwise, due to the + // length of the SDATA Low-High-Low after certain commands. + + // Generate clocks for the target to pull SDATA High + //dog_kick(); + iTimer = TRANSITION_TIMEOUT; + printk(KERN_DEBUG + "Generate clocks for the target to pull SDATA High\n"); + while (1) { + SCLKLow(); + if (fSDATACheck()) // exit once SDATA goes HI + break; + SCLKHigh(); + // If the wait is too long then timeout + if (iTimer-- == 0) { + return (ERROR); + } + } + //dog_kick(); + // Generate Clocks and wait for Target to pull SDATA Low again + iTimer = TRANSITION_TIMEOUT; // reset the timeout counter + printk(KERN_DEBUG + "Generate Clocks and wait for Target to pull SDATA Low again\n"); + while (1) { + SCLKLow(); //issp_test_20100709 unblock + if (!fSDATACheck()) { // exit once SDATA returns LOW + break; + } + SCLKHigh(); //issp_test_20100709 unblock + // If the wait is too long then timeout + if (iTimer-- == 0) { + return (ERROR); + } + } + printk("fDetectHiLoTransition OUT!!!!\n"); + return (PASS); +} + +/* ((((((((((((((((((((( HIGH-LEVEL ISSP ROUTINE SECTION )))))))))))))))))))))) + (( These functions are mostly made of calls to the low level routines )) + (( above. This should isolate the processor-specific changes so that )) + (( these routines do not need to be modified. )) + (((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))))*/ + +#ifdef RESET_MODE +// ============================================================================ +// fXRESInitializeTargetForISSP() +// Implements the intialization vectors for the device. +// Returns: +// 0 if successful +// INIT_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fXRESInitializeTargetForISSP(void) +{ + // Configure the pins for initialization + SetSDATAHiZ(); + SetSCLKStrong(); + SCLKLow(); + // Cycle reset and put the device in programming mode when it exits reset + AssertXRES(); + DeassertXRES(); + // !!! NOTE: + // The timing spec that requires that the first Init-Vector happen within + // 1 msec after the reset/power up. For this reason, it is not advisable + // to separate the above RESET_MODE or POWER_CYCLE_MODE code from the + // Init-Vector instructions below. Doing so could introduce excess delay + // and cause the target device to exit ISSP Mode. + + //PTJ: Send id_setup_1 instead of init1_v + //PTJ: both send CA Test Key and do a Calibrate1 SROM function + SendVector(id_setup_1, num_bits_id_setup_1); + if (fIsError = fDetectHiLoTransition()) { +// TX8SW_CPutString("\r\n fDetectHiLoTransition Error"); + printk("\r\n fDetectHiLoTransition Error\n"); + return (INIT_ERROR); + } + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + // NOTE: DO NOT not wait for HiLo on SDATA after vector Init-3 + // it does not occur (per spec). + return (PASS); +} +#else //else = the part is power cycle programmed + +// ============================================================================ +// fPowerCycleInitializeTargetForISSP() +// Implements the intialization vectors for the device. +// The first time fDetectHiLoTransition is called the Clk pin is highZ because +// the clock is not needed during acquire. +// Returns: +// 0 if successful +// INIT_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fPowerCycleInitializeTargetForISSP(void) +{ + // unsigned char n; + + // Set all pins to highZ to avoid back powering the PSoC through the GPIO + // protection diodes. + SetSCLKHiZ(); + SetSDATAHiZ(); + + // Turn on power to the target device before other signals + SetTargetVDDStrong(); + ApplyTargetVDD(); + // wait 1msec for the power to stabilize +#if 0 + for (n = 0; n < 10; n++) { + Delay(DELAY100us); + } +#endif + // Set SCLK to high Z so there is no clock and wait for a high to low + // transition on SDAT. SCLK is not needed this time. + SetSCLKHiZ(); +// printk(KERN_DEBUG "fDetectHiLoTransition\n"); + if ((fIsError = fDetectHiLoTransition())) { + return (INIT_ERROR); + } + // Configure the pins for initialization +// SetSDATAHiZ(); // issp_test_20100709 block + SetSCLKStrong(); + SCLKLow(); //PTJ: DO NOT SET A BREAKPOINT HERE AND EXPECT SILICON ID TO PASS! + + // !!! NOTE: + // The timing spec that requires that the first Init-Vector happen within + // 1 msec after the reset/power up. For this reason, it is not advisable + // to separate the above RESET_MODE or POWER_CYCLE_MODE code from the + // Init-Vector instructions below. Doing so could introduce excess delay + // and cause the target device to exit ISSP Mode. + + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); //PTJ: rev308, added to match spec +// printk("SendVector(id_setup_1)\n",0,0,0); + SendVector(id_setup_1, num_bits_id_setup_1); + if ((fIsError = fDetectHiLoTransition())) { + return (INIT_ERROR); + } + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + // NOTE: DO NOT not wait for HiLo on SDATA after vector Init-3 + // it does not occur (per spec). + return (PASS); +} +#endif + +// ============================================================================ +// fVerifySiliconID() +// Returns: +// 0 if successful +// Si_ID_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fVerifySiliconID(void) +{ + SendVector(id_setup_2, num_bits_id_setup_2); + printk("fVerifySiliconID: SendVector id_stup2 END\n"); + + if ((fIsError = fDetectHiLoTransition())) { + printk("fVerifySiliconID(): fDetectHiLoTransition Error\n"); + return (SiID_ERROR); + } + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + SendVector(tsync_enable, num_bits_tsync_enable); + printk + ("fVerifySiliconID: SendVector(wait_and_poll_end) (tsync_enable) END\n"); + + //Send Read ID vector and get Target ID + SendVector(read_id_v, 11); // Read-MSB Vector is the first 11-Bits + RunClock(2); // Two SCLK cycles between write & read + bTargetID[0] = bReceiveByte(); + RunClock(1); + SendVector(read_id_v + 2, 12); // 1+11 bits starting from the 3rd byte + + RunClock(2); // Read-LSB Command + bTargetID[1] = bReceiveByte(); + + RunClock(1); + SendVector(read_id_v + 4, 1); // 1 bit starting from the 5th byte + + //read Revision ID from Accumulator A and Accumulator X + SendVector(read_id_v + 5, 11); //11 bits starting from the 6th byte + RunClock(2); + bTargetID[2] = bReceiveByte(); //Read from Acc.X + RunClock(1); + SendVector(read_id_v + 7, 12); //1+11 bits starting from the 8th byte + + RunClock(2); + bTargetID[3] = bReceiveByte(); //Read from Acc.A + + RunClock(1); + SendVector(read_id_v + 4, 1); //1bit starting from the 5th byte, + + SendVector(tsync_disable, num_bits_tsync_disable); + + // Print READ-ID + /* + TX8SW_CPutString("\r\n Silicon-ID : "); + TX8SW_PutChar(' '); + TX8SW_PutSHexByte(bTargetID[0]); + TX8SW_PutChar(' '); + TX8SW_PutSHexByte(bTargetID[1]); + TX8SW_PutChar(' '); + TX8SW_PutSHexByte(bTargetID[2]); + TX8SW_PutChar(' '); + TX8SW_PutSHexByte(bTargetID[3]); + TX8SW_PutChar(' '); + */ +#if 0 // issp_test_20100709 block + printk("issp_routines.c: ID0:0x%X, ID1:0x%X, ID2: 0x%X, ID2: 0x%X\n", + bTargetID[0], bTargetID[1], bTargetID[2], bTargetID[3]); + + if ((bTargetID[0] != target_id_v[0]) || (bTargetID[1] != target_id_v[1]) + || (bTargetID[2] != target_id_v[2]) + || (bTargetID[3] != target_id_v[3])) { + return (SiID_ERROR); + } else { + return (PASS); + } +#else + return (PASS); + +#endif +} + +// PTJ: ======================================================================= +// fReadStatus() +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// ============================================================================ +signed char fReadStatus(void) +{ + SendVector(tsync_enable, num_bits_tsync_enable); //PTJ: + + //Send Read ID vector and get Target ID + SendVector(read_id_v, 11); // Read-MSB Vector is the first 11-Bits + RunClock(2); // Two SCLK cycles between write & read + bTargetStatus[0] = bReceiveByte(); + RunClock(1); + //SendVector(read_id_v+2, 12); // 12 bits starting from the 3rd character + + //RunClock(2); // Read-LSB Command + //bTargetStatus[1] = bReceiveByte(); + + //RunClock(1); + SendVector(read_id_v + 4, 1); // 1 bit starting from the 5th character + + SendVector(tsync_disable, num_bits_tsync_disable); + + if (bTargetStatus[0] == target_status00_v) { + return (PASS); //PTJ: Status = 00 means Success, the SROM function did what it was supposed to + } + if (bTargetStatus[0] == target_status01_v) { + return (STATUS_ERROR); //PTJ: Status = 01 means that function is not allowed because of block level protection, for test with verify_setup (VERIFY-SETUP) + } + if (bTargetStatus[0] == target_status03_v) { + return (STATUS_ERROR); //PTJ: Status = 03 is fatal error, SROM halted + } + if (bTargetStatus[0] == target_status04_v) { + return (STATUS_ERROR); //PTJ: Status = 04 means there was a checksum faliure with either the smart write code checksum, or the smart write paramters checksum, for test with PROGRAM-AND-VERIFY + } + if (bTargetStatus[0] == target_status06_v) { + return (STATUS_ERROR); //PTJ: Status = 06 means that Calibrate1 failed, for test with id_setup_1 (ID-SETUP-1) + } else { + return (STATUS_ERROR); + } +} + +// PTJ: ======================================================================= +// fReadCalRegisters() +// PTJ: use this to read some cal registers that should be loaded by Calibrate1 in id_setup_1 +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// ============================================================================ +signed char fReadCalRegisters(void) +{ + SendVector(tsync_enable, num_bits_tsync_enable); + + SendVector(Switch_Bank1, 22); + + SendVector(read_IMOtrim, 11); // Read-MSB Vector is the first 11-Bits + RunClock(2); // Two SCLK cycles between write & read + bTargetStatus[0] = bReceiveByte(); + RunClock(1); + // Set SDATA to Strong Drive here because SendByte() does not + SetSDATAStrong(); + SendByte(read_reg_end, 1); + + SendVector(read_SPCtrim, 11); // Read-MSB Vector is the first 11-Bits + RunClock(2); // Two SCLK cycles between write & read + bTargetStatus[1] = bReceiveByte(); + RunClock(1); + // Set SDATA to Strong Drive here because SendByte() does not + SetSDATAStrong(); + SendByte(read_reg_end, 1); + + SendVector(read_VBGfinetrim, 11); // Read-MSB Vector is the first 11-Bits + RunClock(2); // Two SCLK cycles between write & read + bTargetStatus[2] = bReceiveByte(); + RunClock(1); + // Set SDATA to Strong Drive here because SendByte() does not + SetSDATAStrong(); + SendByte(read_reg_end, 1); + + SendVector(Switch_Bank0, 22); + + SendVector(tsync_disable, num_bits_tsync_disable); + + if (bTargetStatus[0] == target_status00_v) { + return (PASS); //PTJ: Status = 00 means Success, the SROM function did what it was supposed to + } + return PASS; +} + +// PTJ: ======================================================================= +// fReadWriteSetup() +// PTJ: The READ-WRITE-SETUP vector will enable TSYNC and switches the device +// to SRAM bank1 for PROGRAM-AND-VERIFY, SECURE and VERIFY-SETUP. +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// ============================================================================ +signed char fReadWriteSetup(void) +{ + SendVector(read_write_setup, num_bits_read_write_setup); + return (PASS); //PTJ: is there anything else that should be done? +} + +// PTJ: ======================================================================= +// fSyncEnable() +// PTJ: The SYNC-ENABLE vector will enable TSYNC +// +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// ============================================================================ +signed char fSyncEnable(void) +{ + SendVector(tsync_enable, num_bits_tsync_enable); //PTJ: 307 for tsync enable testing + return (PASS); //PTJ: is there anything else that should be done? +} + +// PTJ: ======================================================================= +// fSyncDisable() +// PTJ: The SYNC-ENABLE vector will enable TSYNC +// +// Returns: +// 0 if successful +// _____ if timed out on handshake to the device. +// ============================================================================ +signed char fSyncDisable(void) +{ + SendVector(tsync_disable, num_bits_tsync_disable); //PTJ: 307 for tsync enable testing + return (PASS); +} + +// ============================================================================ +// fEraseTarget() +// Perform a bulk erase of the target device. +// Returns: +// 0 if successful +// ERASE_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fEraseTarget(void) +{ + SendVector(erase, num_bits_erase); + if ((fIsError = fDetectHiLoTransition())) { +// TX8SW_CPutString("\r\n fDetectHiLoTransition"); + //printk("\r\n fDetectHiLoTransition\n"); // issp_test_2010 block + return (ERASE_ERROR); + } + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + return (PASS); +} + +extern unsigned int iBlockCounter; +// ============================================================================ +// LoadTarget() +// Transfers data from array in Host to RAM buffer in the target. +// Returns the checksum of the data. +// ============================================================================ +unsigned int iLoadTarget(void) +{ + unsigned char bTemp; + unsigned int iChecksumData = 0; + + // Set SDATA to Strong Drive here because SendByte() does not + SetSDATAStrong(); + + // Transfer the temporary RAM array into the target. + // In this section, a 128-Byte array was specified by #define, so the entire + // 128-Bytes are written in this loop. + bTargetAddress = 0x00; + bTargetDataPtr = 0x00; + + while (bTargetDataPtr < TARGET_DATABUFF_LEN) { + bTemp = abTargetDataOUT[bTargetDataPtr]; + iChecksumData += bTemp; + + SendByte(write_byte_start, 4); //PTJ: we need to be able to write 128 bytes from address 0x80 to 0xFF + SendByte(bTargetAddress, 7); //PTJ: we need to be able to write 128 bytes from address 0x80 to 0xFF + SendByte(bTemp, 8); + SendByte(write_byte_end, 3); + + // !!!NOTE: + // SendByte() uses MSbits, so inc by '2' to put the 0..128 address into + // the seven MSBit locations. + // + // This can be confusing, but check the logic: + // The address is only 7-Bits long. The SendByte() subroutine will + // send however-many bits, BUT...always reads them bits from left-to- + // right. So in order to pass a value of 0..128 as the address using + // SendByte(), we have to left justify the address by 1-Bit. + // This can be done easily by incrementing the address each time by + // '2' rather than by '1'. + + bTargetAddress += 2; //PTJ: inc by 2 in order to support a 128 byte address space, MSB~1 for address + bTargetDataPtr++; + } + + return (iChecksumData); +} + +#ifdef MULTI_BANK +// ============================================================================ +// SetBankNumber() +// Set the bank number in the target device. +// Returns: +// none +// ============================================================================ +void SetBankNumber(unsigned char bBankNumber) +{ + // Send the bank-select vector. + SendVector(set_bank_number, 33); + + // Set the drive here because SendByte() does not. + SetSDATAStrong(); + SendByte(bBankNumber, 8); + SendVector(set_bank_number_end, 25); +} +#endif + +// ============================================================================ +// fProgramTargetBlock() +// Program one block with data that has been loaded into a RAM buffer in the +// target device. +// Returns: +// 0 if successful +// BLOCK_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fProgramTargetBlock(unsigned char bBankNumber, + unsigned char bBlockNumber) +{ + + SendVector(tsync_enable, num_bits_tsync_enable); + + SendVector(set_block_num, num_bits_set_block_num); + + // Set the drive here because SendByte() does not. + SetSDATAStrong(); + SendByte(bBlockNumber, 8); + SendByte(set_block_num_end, 3); + + SendVector(tsync_disable, num_bits_tsync_disable); //PTJ: + + // Send the program-block vector. + SendVector(program_and_verify, num_bits_program_and_verify); //PTJ: PROGRAM-AND-VERIFY + // wait for acknowledge from target. + if ((fIsError = fDetectHiLoTransition())) { + return (BLOCK_ERROR); + } + // Send the Wait-For-Poll-End vector + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + return (PASS); + + //PTJ: Don't do READ-STATUS here because that will + //PTJ: require that we return multiple error values, if error occurs +} + +// ============================================================================ +// fAddTargetBankChecksum() +// Reads and adds the target bank checksum to the referenced accumulator. +// Returns: +// 0 if successful +// VERIFY_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fAccTargetBankChecksum(unsigned int *pAcc) +{ + unsigned int wCheckSumData; + + SendVector(checksum_setup, num_bits_checksum_setup); //PTJ:CHECKSUM-SETUP, it is taking 100ms > time > 200ms to complete the checksum + if ((fIsError = fDetectHiLoTransition())) { //100ms is default + return (VERIFY_ERROR); + } + + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + SendVector(tsync_enable, num_bits_tsync_enable); + + //Send Read Checksum vector and get Target Checksum + SendVector(read_checksum_v, 11); // first 11-bits is ReadCKSum-MSB + RunClock(2); // Two SCLKs between write & read + bTargetDataIN = bReceiveByte(); + wCheckSumData = bTargetDataIN << 8; + + RunClock(1); // See Fig. 6 + SendVector(read_checksum_v + 2, 12); // 12 bits starting from 3rd character + RunClock(2); // Read-LSB Command + bTargetDataIN = bReceiveByte(); + wCheckSumData |= (bTargetDataIN & 0xFF); + RunClock(1); + SendVector(read_checksum_v + 3, 1); // Send the final bit of the command //PTJ: read_checksum_v may have to change if TSYNC needs to be enabled + + SendVector(tsync_disable, num_bits_tsync_disable); + + *pAcc = wCheckSumData; + + return (PASS); +} + +// ============================================================================ +// ReStartTarget() +// After programming, the target PSoC must be reset to take it out of +// programming mode. This routine performs a reset. +// ============================================================================ +void ReStartTarget(void) +{ +#ifdef RESET_MODE + // Assert XRES, then release, then disable XRES-Enable + AssertXRES(); + Delay(XRES_CLK_DELAY); + DeassertXRES(); +#else + // Set all pins to highZ to avoid back powering the PSoC through the GPIO + // protection diodes. + SetSCLKHiZ(); + SetSDATAHiZ(); + // Cycle power on the target to cause a reset + RemoveTargetVDD(); + mdelay(300); + ApplyTargetVDD(); +#endif +} + +// ============================================================================ +// fVerifySetup() +// Verify the block just written to. This can be done byte-by-byte before the +// protection bits are set. +// Returns: +// 0 if successful +// BLOCK_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fVerifySetup(unsigned char bBankNumber, unsigned char bBlockNumber) +{ + SendVector(tsync_enable, num_bits_tsync_enable); + + SendVector(set_block_num, num_bits_set_block_num); + + //Set the drive here because SendByte() does not + SetSDATAStrong(); + SendByte(bBlockNumber, 8); + SendByte(set_block_num_end, 3); //PTJ: + + SendVector(tsync_disable, num_bits_tsync_disable); //PTJ: + + SendVector(verify_setup, num_bits_my_verify_setup); //PTJ: + if ((fIsError = fDetectHiLoTransition())) { + return (BLOCK_ERROR); + } + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + return (PASS); +} + +// ============================================================================ +// fReadByteLoop() +// Reads the data back from Target SRAM and compares it to expected data in +// Host SRAM +// Returns: +// 0 if successful +// BLOCK_ERROR if timed out on handshake to the device. +// ============================================================================ + +signed char fReadByteLoop(void) +{ + bTargetAddress = 0; + bTargetDataPtr = 0; + + while (bTargetDataPtr < TARGET_DATABUFF_LEN) { + //Send Read Byte vector and then get a byte from Target + SendVector(read_byte_v, 4); + // Set the drive here because SendByte() does not + SetSDATAStrong(); + SendByte(bTargetAddress, 7); + + RunClock(2); // Run two SCLK cycles between writing and reading + SetSDATAHiZ(); // Set to HiZ so Target can drive SDATA + bTargetDataIN = bReceiveByte(); + + RunClock(1); + SendVector(read_byte_v + 1, 1); // Send the ReadByte Vector End + + // Test the Byte that was read from the Target against the original + // value (already in the 128-Byte array "abTargetDataOUT[]"). If it + // matches, then bump the address & pointer,loop-back and continue. + // If it does NOT match abort the loop and return and error. + if (bTargetDataIN != abTargetDataOUT[bTargetDataPtr]) { +#ifdef TX_ON + UART_PutCRLF(); + UART_CPutString("bTargetDataIN : "); + UART_PutHexByte(bTargetDataIN); + UART_CPutString(" abTargetDataOUT : "); + UART_PutHexByte(abTargetDataOUT[bTargetDataPtr]); +#endif + return (BLOCK_ERROR); + } + + bTargetDataPtr++; + // Increment the address by 2 to accomodate 7-Bit addressing + // (puts the 7-bit address into MSBit locations for "SendByte()"). + bTargetAddress += 2; + + } + + return (PASS); +} + +// ============================================================================ +// fVerifyTargetBlock() +// Verify the block just written to. This can be done byte-by-byte before the +// protection bits are set. +// Returns: +// 0 if successful +// BLOCK_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fVerifyTargetBlock(unsigned char bBankNumber, + unsigned char bBlockNumber) +{ + SendVector(set_block_number, 11); + + //Set the drive here because SendByte() does not + SetSDATAStrong(); + SendByte(bBlockNumber, 8); + SendByte(set_block_number_end, 3); + + SendVector(verify_setup_v, num_bits_verify_setup); + if ((fIsError = fDetectHiLoTransition())) { + return (BLOCK_ERROR); + } + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + bTargetAddress = 0; + bTargetDataPtr = 0; + + while (bTargetDataPtr < TARGET_DATABUFF_LEN) { + //Send Read Byte vector and then get a byte from Target + SendVector(read_byte_v, 4); //PTJ 308: this was changed from sending the first 5 bits to sending the first 4 + // Set the drive here because SendByte() does not + SetSDATAStrong(); + SendByte(bTargetAddress, 6); + + RunClock(2); // Run two SCLK cycles between writing and reading + SetSDATAHiZ(); // Set to HiZ so Target can drive SDATA + bTargetDataIN = bReceiveByte(); + + RunClock(1); + SendVector(read_byte_v + 1, 1); // Send the ReadByte Vector End + + // Test the Byte that was read from the Target against the original + // value (already in the 128-Byte array "abTargetDataOUT[]"). If it + // matches, then bump the address & pointer,loop-back and continue. + // If it does NOT match abort the loop and return an error. + if (bTargetDataIN != abTargetDataOUT[bTargetDataPtr]) + return (BLOCK_ERROR); + + bTargetDataPtr++; + // Increment the address by four to accomodate 6-Bit addressing + // (puts the 6-bit address into MSBit locations for "SendByte()"). + bTargetAddress += 4; + } + return (PASS); +} + +// ============================================================================ +// fSecureTargetFlash() +// Before calling, load the array, abTargetDataOUT, with the desired security +// settings using LoadArrayWithSecurityData(StartAddress,Length,SecurityType). +// The can be called multiple times with different SecurityTypes as needed for +// particular Flash Blocks. Or set them all the same using the call below: +// LoadArrayWithSecurityData(0,SECURITY_BYTES_PER_BANK, 0); +// Returns: +// 0 if successful +// SECURITY_ERROR if timed out on handshake to the device. +// ============================================================================ +signed char fSecureTargetFlash(void) +{ + unsigned char bTemp; + + // Transfer the temporary RAM array into the target + bTargetAddress = 0x00; + bTargetDataPtr = 0x00; + + SetSDATAStrong(); + while (bTargetDataPtr < SECURITY_BYTES_PER_BANK) { + bTemp = abTargetDataOUT[bTargetDataPtr]; + SendByte(write_byte_start, 4); + SendByte(bTargetAddress, 7); + SendByte(bTemp, 8); + SendByte(write_byte_end, 3); + + // SendBytes() uses MSBits, so increment the address by '2' to put + // the 0..n address into the seven MSBit locations + bTargetAddress += 2; //PTJ: inc by 2 in order to support a 128 byte address space + bTargetDataPtr++; + } + + SendVector(secure, num_bits_secure); //PTJ: + if ((fIsError = fDetectHiLoTransition())) { + return (SECURITY_ERROR); + } + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + return (PASS); +} + +// ============================================================================ +// PTJ: fReadSecurity() +// This reads from SM0 with Read Supervisory SPC command. +// Need to have SPC Test Mode enabled before using these commands? +// Returns: +// 0 if successful +// __________ if timed out on handshake to the device. +// ============================================================================ +signed char fReadSecurity(void) +{ + SendVector(ReadSecuritySetup, num_bits_ReadSecuritySetup); +// SendVector(SPCTestMode_enable, num_bits_SPCTestMode_enable); + + bTargetAddress = 0x00; + while (bTargetAddress < (SECURITY_BYTES_PER_BANK * 2)) { //PTJ: we do SECURITY_BYTES_PER_BANK * 2 because we bTargetAddress += 2 + + //PTJ: TSYNC Enable + SendVector(tsync_enable, num_bits_tsync_enable); + + SendVector(read_security_pt1, num_bits_read_security_pt1); //PTJ: + // Set the drive here because SendByte() does not. + SetSDATAStrong(); + SendByte(bTargetAddress, 7); //PTJ: hardcode MSb of address as 0 in bit stream + SendVector(read_security_pt1_end, + num_bits_read_security_pt1_end); + + //PTJ: TSYNC Disable + SendVector(tsync_disable, num_bits_tsync_disable); + + SendVector(read_security_pt2, num_bits_read_security_pt2); + + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + SendVector(read_security_pt3, num_bits_read_security_pt3); + + SetSDATAStrong(); + SendByte(bTargetAddress, 7); + + SendVector(read_security_pt3_end, + num_bits_read_security_pt3_end); + + SendVector(wait_and_poll_end, num_bits_wait_and_poll_end); + + bTargetAddress += 2; + } + + bTargetAddress = 0x00; + bTargetDataPtr = 0x00; + + SendVector(tsync_enable, num_bits_tsync_enable); //PTJ: 307, added for tsync testing + while (bTargetAddress < (SECURITY_BYTES_PER_BANK * 2)) { //PTJ: we do SECURITY_BYTES_PER_BANK * 2 because we bTargetAddress += 2 + + //Send Read Byte vector and then get a byte from Target + SendVector(read_byte_v, 4); + // Set the drive here because SendByte() does not + SetSDATAStrong(); + SendByte(bTargetAddress, 7); + + RunClock(2); // Run two SCLK cycles between writing and reading + SetSDATAHiZ(); // Set to HiZ so Target can drive SDATA + bTargetDataIN = bReceiveByte(); + + RunClock(1); + SendVector(read_byte_v + 1, 1); // Send the ReadByte Vector End + + // Test the Byte that was read from the Target against the original + // value (already in the 128-Byte array "abTargetDataOUT[]"). If it + // matches, then bump the address & pointer,loop-back and continue. + // If it does NOT match abort the loop and return and error. + if (bTargetDataIN != abTargetDataOUT[bTargetDataPtr]) +// return(BLOCK_ERROR); + + // Increment the address by two to accomodate 7-Bit addressing + // (puts the 7-bit address into MSBit locations for "SendByte()"). + bTargetDataPtr++; + bTargetAddress += 2; + } + + SendVector(tsync_disable, num_bits_tsync_disable); //PTJ: 307, added for tsync testing + return (PASS); +} + +#endif //(PROJECT_REV_) +// end of file ISSP_Routines.c diff --git a/drivers/input/keyboard/cypressbln/issp_vectors.h b/drivers/input/keyboard/cypressbln/issp_vectors.h new file mode 100644 index 0000000..35d5ef1 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/issp_vectors.h @@ -0,0 +1,1146 @@ +// filename: ISSP_Vectors.h +#include "issp_revision.h" +#ifdef PROJECT_REV_304 +/* Copyright 2006-2007, Cypress Semiconductor Corporation. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONRTACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, + WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + Cypress reserves the right to make changes without further notice to the + materials described herein. Cypress does not assume any liability arising + out of the application or use of any product or circuit described herein. + Cypress does not authorize its products for use as critical components in + life-support systems where a malfunction or failure may reasonably be + expected to result in significant injury to the user. The inclusion of + Cypress� product in a life-support systems application implies that the + manufacturer assumes all risk of such use and in doing so indemnifies + Cypress against all charges. + + Use may be limited by and subject to the applicable Cypress software + license agreement. + +-----------------------------------------------------------------------------*/ +#ifndef INC_ISSP_VECTORS +#define INC_ISSP_VECTORS + +#include "issp_directives.h" + +#define HEX_DEFINE +// ------------------------- PSoC CY8C20x66 Devices --------------------------- + +#ifdef CY8C20236 /// 2009.03.26. kimc +unsigned char target_id_v[] = { 0x00, 0xb3, 0x52, 0x21 }; //ID for CY8C20236 +#endif +#ifdef CY8C20246 /// 2009.03.26. kimc +unsigned char target_id_v[] = { 0x00, 0xAA, 0x52, 0x21 }; //ID for CY8C20246 +#endif +#ifdef CY8C20266 +unsigned char target_id_v[] = { 0x00, 0x96, 0x52, 0x21 }; //ID for CY8C20266 +#endif +#ifdef CY8C20366 +unsigned char target_id_v[] = { 0x00, 0x97, 0x52, 0x21 }; //ID for CY8C20366 +#endif +#ifdef CY8C20466 +unsigned char target_id_v[] = { 0x00, 0x98, 0x52, 0x21 }; //ID for CY8C20466 +#endif +#ifdef CY8C20566 +unsigned char target_id_v[] = { 0x00, 0x99, 0x52, 0x21 }; //ID for CY8C20566 +#endif +#ifdef CY8C20666 +unsigned char target_id_v[] = { 0x00, 0x9c, 0x52, 0x21 }; //ID for CY8C20666 +#endif +#ifdef CY8C20066 +unsigned char target_id_v[] = { 0x00, 0x9a, 0x52, 0x21 }; //ID for CY8C20066 +#endif +#ifdef CY8C200661 +unsigned char target_id_v[] = { 0x00, 0x9b, 0x52, 0x21 }; //ID for CY8C200661 +#endif + +#ifdef CY8C20x66 +unsigned char target_status00_v = 0x00; //PTJ: Status = 00 means Success, the SROM function did what it was supposed to +unsigned char target_status01_v = 0x01; //PTJ: Status = 01 means that function is not allowed because of block level protection, for test with verify_setup (VERIFY-SETUP) +unsigned char target_status03_v = 0x03; //PTJ: Status = 03 is fatal error, SROM halted +unsigned char target_status04_v = 0x04; //PTJ: Status = 04 means that ___ for test with ___ (PROGRAM-AND-VERIFY) +unsigned char target_status06_v = 0x06; //PTJ: Status = 06 means that Calibrate1 failed, for test with id_setup_1 (ID-SETUP-1) +#endif + +/*************** CY8CTMA30x, CY8CTMG30x, CY8CTST30x series by KIMC, 2009.08.11 ***********************************/ +// ------------------------- PSoC CY8CTMA30x, CY8CTMG30x, CY8CTST30x Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CY8CTST300_36 // CY8CTST300_36LQXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x06, 0x71, 0x70, 0x11 }; +#endif +#ifdef CY8CTST300_48 // CY8CTST300_48LTXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x06, 0x72, 0x70, 0x11 }; +#endif +#ifdef CY8CTST300_49 // CY8CTST300_49FNXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x06, 0x73, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA300_36 // CY8CTMA300_36LQXI // 2009.08.11, Test OK. +unsigned char target_id_v[] = { 0x05, 0x71, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA300_48 // CY8CTMA300_48LTXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x72, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA300_49 // CY8CTMA300_49FNXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x73, 0x70, 0x11 }; +#endif +#ifdef CY8CTMG300_36 // CY8CTMG300_36LQXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x07, 0x71, 0x70, 0x11 }; +#endif +#ifdef CY8CTMG300_48 // CY8CTMG300_48LTXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x07, 0x72, 0x70, 0x11 }; +#endif +#ifdef CY8CTMG300_49 // CY8CTMG300_49FNXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x07, 0x73, 0x70, 0x11 }; +#endif +#ifdef CY8CTMG300B_36 // CY8CTMG300B_36LQXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x07, 0x75, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA300B_36 // CY8CTMA300B_36LQXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x74, 0x70, 0x11 }; +#endif +#ifdef CY8CTST300B_36 // CY8CTST300B_36LQXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x06, 0x74, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA301_36 // CY8CTMA301_36LQXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x75, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA301_48 // CY8CTMA301_48LTXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x76, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA301D_36 // CY8CTMA301D_36LQXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x77, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA301D_48 // CY8CTMA301D_48LTXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x78, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA300D_36 // CY8CTMA300D_36LQXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x79, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA300D_48 // CY8CTMA300D_48LTXI // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x80, 0x70, 0x11 }; +#endif +#ifdef CY8CTMA300D_49 // CY8CTMA300D_49FNXIT // 2009.08.11, not tested. +unsigned char target_id_v[] = { 0x05, 0x81, 0x70, 0x11 }; +#endif +/********************************************************************************************************/ + +/*************** CY8CTMG/TST series modified by KJHW, 2009.08.14 ***********************************/ +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CY8CTMG110 +unsigned char target_id_v[] = { 0x07, 0x38 }; //ID for CY8CTMG110 + +unsigned char target_status00_v = 0x00; //PTJ: Status = 00 means Success, the SROM function did what it was supposed to +unsigned char target_status01_v = 0x01; //PTJ: Status = 01 means that function is not allowed because of block level protection, for test with verify_setup (VERIFY-SETUP) +unsigned char target_status03_v = 0x03; //PTJ: Status = 03 is fatal error, SROM halted +unsigned char target_status04_v = 0x04; //PTJ: Status = 04 means that ___ for test with ___ (PROGRAM-AND-VERIFY) +unsigned char target_status06_v = 0x06; //PTJ: Status = 06 means that Calibrate1 failed, for test with id_setup_1 (ID-SETUP-1) +#endif + +#ifdef CY8CTST200_24PIN +unsigned char target_id_v[] = { 0x06, 0x6D, 0x52, 0x21 }; //ID for CY8CTST200 +#endif +#ifdef CY8CTST200_32PIN +unsigned char target_id_v[] = { 0x06, 0x6E, 0x52, 0x21 }; //ID for CY8CTST200 +#endif +#ifdef CY8CTMG200_24PIN +unsigned char target_id_v[] = { 0x07, 0x6D, 0x52, 0x21 }; //ID for CY8CTMG200 +#endif +#ifdef CY8CTMG200_32PIN +unsigned char target_id_v[] = { 0x07, 0x6E, 0x52, 0x21 }; //ID for CY8CTMG200 +#endif + +/********************************************************************************************************/ + +// ------------------------- PSoC CY8C21x23 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CY8C21123 +unsigned char target_id_v[] = { 0x00, 0x17 }; //ID for CY8C21123 +#endif +#ifdef CY8C21223 +unsigned char target_id_v[] = { 0x00, 0x18 }; //ID for CY8C21223 +#endif +#ifdef CY8C21323 +unsigned char target_id_v[] = { 0x00, 0x19 }; //ID for CY8C2132 +#endif +#ifdef CY8C21002 +unsigned char target_id_v[] = { 0x00, 0x3F }; //ID for CY8C21x23 ICE pod +#endif + +// ------------------------- PSoC CY8C21x34 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CY8C21234 +unsigned char target_id_v[] = { 0x00, 0x36 }; //ID for CY8C21234 +#endif +#ifdef CY8C21334 +unsigned char target_id_v[] = { 0x00, 0x37 }; //ID for CY8C21334 +#endif +#ifdef CY8C21434 +unsigned char target_id_v[] = { 0x00, 0x38 }; //ID for CY8C21434 +#endif +#ifdef CY8C21534 +unsigned char target_id_v[] = { 0x00, 0x40 }; //ID for CY8C21534 +#endif +#ifdef CY8C21634 +unsigned char target_id_v[] = { 0x00, 0x49 }; //ID for CY8C21634 +#endif +#ifdef CY8C21001 +unsigned char target_id_v[] = { 0x00, 0x39 }; //ID for CY8C21x34 ICE pod +#endif + +// ------------------------- PSoC CY8C24x23A Devices -------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CY8C24123A +unsigned char target_id_v[] = { 0x00, 0x32 }; //ID for CY8C24123A +#endif +#ifdef CY8C24223A +unsigned char target_id_v[] = { 0x00, 0x33 }; //ID for CY8C24223A +#endif +#ifdef CY8C24423A +unsigned char target_id_v[] = { 0x00, 0x34 }; //ID for CY8C24423A +#endif +#ifdef CY8C24000A +unsigned char target_id_v[] = { 0x00, 0x35 }; //ID for CY8C24x23A ICE pod +#endif + +// ------------------------- PSoC CY8C24x94 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CY8C24794 +unsigned char target_id_v[] = { 0x00, 0x1D }; //ID for CY8C24794 +#endif +#ifdef CY8C24894 +unsigned char target_id_v[] = { 0x00, 0x1F }; //ID for CY8C24894 +#endif +#ifdef CY8C24994 +unsigned char target_id_v[] = { 0x00, 0x59 }; //ID for CY8C24994 +#endif +#ifdef CY8C24094 +unsigned char target_id_v[] = { 0x00, 0x1B }; //ID for CY8C24094 +#endif + +// ------------------------- PSoC CY8C27x43 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CY8C27143 +unsigned char target_id_v[] = { 0x00, 0x09 }; //ID for CY8C27143 +#endif +#ifdef CY8C27243 +unsigned char target_id_v[] = { 0x00, 0x0A }; //ID for CY8C27243 +#endif +#ifdef CY8C27443 +unsigned char target_id_v[] = { 0x00, 0x0B }; //ID for CY8C27443 +#endif +#ifdef CY8C27543 +unsigned char target_id_v[] = { 0x00, 0x0C }; //ID for CY8C27543 +#endif +#ifdef CY8C27643 +unsigned char target_id_v[] = { 0x00, 0x0D }; //ID for CY8C27643 +#endif +#ifdef CY8C27002 +unsigned char target_id_v[] = { 0x00, 0x0E }; //ID for CY8C27x43 ICE pod +#endif + +// ------------------------- PSoC CY8C29x66 Devices --------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CY8C29466 +unsigned char target_id_v[] = { 0x00, 0x2A }; //ID for CY8C29466 +#endif +#ifdef CY8C29566 +unsigned char target_id_v[] = { 0x00, 0x2B }; //ID for CY8C29566 +#endif +#ifdef CY8C29666 +unsigned char target_id_v[] = { 0x00, 0x2C }; //ID for CY8C29666 +#endif +#ifdef CY8C29866 +unsigned char target_id_v[] = { 0x00, 0x2D }; //ID for CY8C29866 +#endif +#ifdef CY8C29002 +unsigned char target_id_v[] = { 0x00, 0x2E }; //ID for CY8C29002 +#endif + +// --------- CY8C20x66 Vectors ------------------------------------------------ +// ---------------------------------------------------------------------------- +#ifdef TSYNC +const unsigned int num_bits_tsync_enable = 110; +const unsigned char tsync_enable[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE2, 0x1F, 0x7F, 0x02, 0x7D, 0xC4, 0x09, + 0xF7, 0x00, 0x1F, 0xDE, 0xE0, 0x1C +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01111111, 0 b00000010, + 0 b01111101, 0 b11000100, 0 b00001001, + 0 b11110111, 0 b00000000, 0 b00011111, 0 b11011110, 0 b11100000, + 0 b00011100 +#endif +}; + +const unsigned int num_bits_tsync_disable = 110; +const unsigned char tsync_disable[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE2, 0x1F, 0x71, 0x00, 0x7D, 0xFC, 0x01, + 0xF7, 0x00, 0x1F, 0xDE, 0xE0, 0x1C +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01110001, 0 b00000000, + 0 b01111101, 0 b11111100, 0 b00000001, + 0 b11110111, 0 b00000000, 0 b00011111, 0 b11011110, 0 b11100000, + 0 b00011100 +#endif +}; +#endif + +#ifdef CY8CTMx30x +#ifdef ID_SETUP_1 +const unsigned int num_bits_id_setup_1 = 616; //KIMC, 2009.08.11, PTJ: id_setup_1 with TSYNC enabled for MW and disabled for IOW +const unsigned char id_setup_1[] = { + 0 b11001010, 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00001101, 0 b11101110, 0 b00100001, 0 b11110111, 0 b11110000, + 0 b00100111, 0 b11011100, 0 b01000000, + 0 b10011111, 0 b01110000, 0 b00000001, 0 b11111101, 0 b11101110, + 0 b00000001, 0 b11100111, 0 b11000001, + 0 b11010111, 0 b10011111, 0 b00100000, 0 b01111110, 0 b00111111, + 0 b10011101, 0 b01111000, 0 b11110110, + 0 b00100001, 0 b11110111, 0 b10111000, 0 b10000111, 0 b11011111, + 0 b11000000, 0 b00011111, 0 b01110001, + 0 b00000000, 0 b01111101, 0 b11000000, 0 b00000111, 0 b11110111, + 0 b10111000, 0 b00000111, 0 b11011110, + 0 b10000000, 0 b01111111, 0 b01111010, 0 b10000000, 0 b01111101, + 0 b11101100, 0 b00000001, 0 b11110111, + 0 b10000000, 0 b01001111, 0 b11011111, 0 b00000000, 0 b00011111, + 0 b01111100, 0 b10100000, 0 b01111101, + 0 b11110100, 0 b01100001, 0 b11110111, 0 b11111000, 0 b10010111 +}; +#endif +#else +#ifdef ID_SETUP_1 +const unsigned int num_bits_id_setup_1 = 594; //PTJ: id_setup_1 with TSYNC enabled for MW and disabled for IOW +const unsigned char id_setup_1[] = { +#ifdef HEX_DEFINE + 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0D, 0xEE, 0x21, 0xF7, 0xF0, 0x27, 0xDC, 0x40, + 0x9F, 0x70, 0x01, 0xFD, 0xEE, 0x01, /*0x21, */ 0xE7, 0xC1, + 0xD7, 0x9F, 0x20, 0x7E, 0x7D, 0x88, 0x7D, 0xEE, + 0x21, 0xF7, 0xF0, 0x07, 0xDC, 0x40, 0x1F, 0x70, + 0x01, 0xFD, 0xEE, 0x01, 0xF7, 0xA0, 0x1F, 0xDE, + 0xA0, 0x1F, 0x7B, 0x00, 0x7D, 0xE0, 0x13, 0xF7, + 0xC0, 0x07, 0xDF, 0x28, 0x1F, 0x7D, 0x18, 0x7D, + 0xFE, 0x25, 0xC0 +#else + 0 b11001010, 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00001101, 0 b11101110, 0 b00100001, 0 b11110111, 0 b11110000, + 0 b00100111, 0 b11011100, 0 b01000000, + 0 b10011111, 0 b01110000, 0 b00000001, 0 b11111101, 0 b11101110, + 0 b00100001, 0 b11100111, 0 b11000001, + 0 b11010111, 0 b10011111, 0 b00100000, 0 b01111110, 0 b01111101, + 0 b10001000, 0 b01111101, 0 b11101110, + 0 b00100001, 0 b11110111, 0 b11110000, 0 b00000111, 0 b11011100, + 0 b01000000, 0 b00011111, 0 b01110000, + 0 b00000001, 0 b11111101, 0 b11101110, 0 b00000001, 0 b11110111, + 0 b10100000, 0 b00011111, 0 b11011110, + 0 b10100000, 0 b00011111, 0 b01111011, 0 b00000000, 0 b01111101, + 0 b11100000, 0 b00010011, 0 b11110111, + 0 b11000000, 0 b00000111, 0 b11011111, 0 b00101000, 0 b00011111, + 0 b01111101, 0 b00011000, 0 b01111101, + 0 b11111110, 0 b00100101, 0 b11000000 +#endif +}; +#endif +#endif + +#ifdef SET_BLOCK_NUM +const unsigned int num_bits_set_block_num = 11; //PTJ: +const unsigned char set_block_num[] = { +#ifdef HEX_DEFINE + 0x9f, 0x40, 0x1c +#else + 0 b11011110, 0 b11100000, 0 b00011110, 0 b01111101, 0 b00000000, + 0 b01110000 +#endif +}; + +const unsigned int num_bits_set_block_num_end = 3; //PTJ: this selects the first three bits of set_block_num_end +const unsigned char set_block_num_end = 0xE0; +#endif + +#ifdef READ_WRITE_SETUP +const unsigned int num_bits_read_write_setup = 66; //PTJ: +const unsigned char read_write_setup[] = { +#ifdef HEX_DEFINE + 0xde, 0xf0, 0x1f, 0x78, 0x00, 0x7d, 0xa0, 0x03, + 0xc0 +#else + 0 b11011110, 0 b11110000, 0 b00011111, 0 b01111000, 0 b00000000, + 0 b01111101, 0 b10100000, 0 b00000011, + 0 b11000000 +#endif +}; +#endif + +#ifdef VERIFY_SETUP +const unsigned int num_bits_my_verify_setup = 440; +const unsigned char verify_setup[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0xfc, 0x81, + 0xf9, 0xf7, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf6, 0xa8, + 0x0f, 0xde, 0x80, 0x7f, 0x7a, 0x80, 0x7d, 0xec, + 0x01, 0xf7, 0x80, 0x0f, 0xdf, 0x00, 0x1f, 0x7c, + 0xa0, 0xfd, 0xf4, 0x61, 0xf7, 0xf8, 0x97 +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01111111, 0 b00000010, + 0 b01111101, 0 b11000100, 0 b00001001, + 0 b11110111, 0 b00000000, 0 b00011111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111001, 0 b11110111, 0 b00000001, 0 b11110111, 0 b11110000, + 0 b00000111, 0 b11011100, 0 b01000000, + 0 b00011111, 0 b01110000, 0 b00000001, 0 b11111101, 0 b11101110, + 0 b00000001, 0 b11110110, 0 b10101000, + 0 b00001111, 0 b11011110, 0 b10000000, 0 b01111111, 0 b01111010, + 0 b10000000, 0 b01111101, 0 b11101100, + 0 b00000001, 0 b11110111, 0 b10000000, 0 b00001111, 0 b11011111, + 0 b00000000, 0 b00011111, 0 b01111100, + 0 b10100000, 0 b01111101, 0 b11110100, 0 b01100001, 0 b11110111, + 0 b11111000, 0 b10010111 +#endif +}; +#endif + +#ifdef ERASE +const unsigned int num_bits_erase = 396; //PTJ: erase with TSYNC Enable and Disable +const unsigned char erase[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x85, + 0xfd, 0xfc, 0x01, 0xf7, 0x10, 0x07, 0xdc, 0x00, + 0x7f, 0x7b, 0x80, 0x7d, 0xe0, 0x0b, 0xf7, 0xa0, + 0x1f, 0xd7, 0xa0, 0x1f, 0x7b, 0x04, 0x7d, 0xf0, + 0x01, 0xf7, 0xc9, 0x87, 0xdf, 0x48, 0x1f, 0x7f, + 0x89, 0x70 +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01111111, 0 b00000010, + 0 b01111101, 0 b11000100, 0 b00001001, + 0 b11110111, 0 b00000000, 0 b00011111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000101, + 0 b11111101, 0 b11111100, 0 b00000001, 0 b11110111, 0 b00010000, + 0 b00000111, 0 b11011100, 0 b00000000, + 0 b01111111, 0 b01111011, 0 b10000000, 0 b01111101, 0 b11100000, + 0 b00001011, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b11011110, 0 b10100000, 0 b00011111, 0 b01111011, + 0 b00000100, 0 b01111101, 0 b11110000, + 0 b00000001, 0 b11110111, 0 b11001001, 0 b10000111, 0 b11011111, + 0 b01001000, 0 b00011111, 0 b01111111, + 0 b10001001, 0 b01110000 +#endif +}; +#endif + +#ifdef SECURE +const unsigned int num_bits_secure = 440; //PTJ: secure with TSYNC Enable and Disable +const unsigned char secure[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x81, + 0xf9, 0xf7, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf6, 0xa0, + 0x0f, 0xde, 0x80, 0x7f, 0x7a, 0x80, 0x7d, 0xec, + 0x01, 0xf7, 0x80, 0x27, 0xdf, 0x00, 0x1f, 0x7c, + 0xa0, 0x7d, 0xf4, 0x61, 0xf7, 0xf8, 0x97 +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01111111, 0 b00000010, + 0 b01111101, 0 b11000100, 0 b00001001, + 0 b11110111, 0 b00000000, 0 b00011111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111001, 0 b11110111, 0 b00000001, 0 b11110111, 0 b11110000, + 0 b00000111, 0 b11011100, 0 b01000000, + 0 b00011111, 0 b01110000, 0 b00000001, 0 b11111101, 0 b11101110, + 0 b00000001, 0 b11110110, 0 b10100000, + 0 b00001111, 0 b11011110, 0 b10000000, 0 b01111111, 0 b01111010, + 0 b10000000, 0 b01111101, 0 b11101100, + 0 b00000001, 0 b11110111, 0 b10000000, 0 b00100111, 0 b11011111, + 0 b00000000, 0 b00011111, 0 b01111100, + 0 b10100000, 0 b01111101, 0 b11110100, 0 b01100001, 0 b11110111, + 0 b11111000, 0 b10010111 +#endif +}; +#endif + +#ifdef READ_SECURITY +const unsigned int num_bits_ReadSecuritySetup = 88; //PTJ: READ-SECURITY-SETUP +const unsigned char ReadSecuritySetup[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x60, 0x88, 0x7d, 0x84, 0x21, + 0xf7, 0xb8, 0x07 +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01100000, 0 b10001000, + 0 b01111101, 0 b10000100, 0 b00100001, + 0 b11110111, 0 b10111000, 0 b00000111 +#endif +}; + +const unsigned int num_bits_read_security_pt1 = 78; //PTJ: This sends the beginning of the Read Supervisory command +const unsigned char read_security_pt1[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x72, 0x87, 0x7d, 0xca, 0x01, + 0xf7, 0x28 +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01110010, 0 b10000111, + 0 b01111101, 0 b11001010, 0 b00000001, + 0 b11110111, 0 b00101000 +#endif +}; + +const unsigned int num_bits_read_security_pt1_end = 25; //PTJ: this finishes the Address Low command and sends the Address High command +const unsigned char read_security_pt1_end[] = { +#ifdef HEX_DEFINE + 0xfb, 0x94, 0x03, 0x80 +#else + 0 b11111011, 0 b10010100, 0 b00000011, 0 b10000000 +#endif +}; + +const unsigned int num_bits_read_security_pt2 = 198; //PTJ: load the test queue with the op code for MOV 1,E5h register into Accumulator A +const unsigned char read_security_pt2[] = { +#ifdef HEX_DEFINE + 0xde, 0xe0, 0x1f, 0x7a, 0x01, 0xfd, 0xea, 0x01, + 0xf7, 0xb0, 0x07, 0xdf, 0x0b, 0xbf, 0x7c, 0xf2, + 0xfd, 0xf4, 0x61, 0xf7, 0xb8, 0x87, 0xdf, 0xe2, + 0x5c +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111101, 0 b11101010, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b00000111, 0 b11011111, 0 b00001011, + 0 b10111111, 0 b01111100, 0 b11110010, + 0 b11111101, 0 b11110100, 0 b01100001, 0 b11110111, 0 b10111000, + 0 b10000111, 0 b11011111, 0 b11100010, + 0 b01011100 +#endif +}; + +const unsigned int num_bits_read_security_pt3 = 122; //PTJ: +const unsigned char read_security_pt3[] = { +#ifdef HEX_DEFINE + 0xde, 0xe0, 0x1f, 0x7a, 0x01, 0xfd, 0xea, 0x01, + 0xf7, 0xb0, 0x07, 0xdf, 0x0a, 0x7f, 0x7c, 0xc0 +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111101, 0 b11101010, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b00000111, 0 b11011111, 0 b00001010, + 0 b01111111, 0 b01111100, 0 b11000000 +#endif +}; + +const unsigned int num_bits_read_security_pt3_end = 47; //PTJ: +const unsigned char read_security_pt3_end[] = { +#ifdef HEX_DEFINE + 0xfb, 0xe8, 0xc3, 0xef, 0xf1, 0x2e +#else + 0 b11111011, 0 b11101000, 0 b11000011, 0 b11101111, 0 b11110001, + 0 b00101110 +#endif +}; + +#endif + +// --------- CY8C20x66 Checksum Setup Vector ---------------------------------- +// ---------------------------------------------------------------------------- +#ifdef CHECKSUM_SETUP +const unsigned int num_bits_checksum_setup = 418; //PTJ: Checksum with TSYNC Enable and Disable +const unsigned char checksum_setup[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x81, + 0xf9, 0xf4, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf7, 0xa0, + 0x1f, 0xde, 0xa0, 0x1f, 0x7b, 0x00, 0x7d, 0xe0, + 0x0f, 0xf7, 0xc0, 0x07, 0xdf, 0x28, 0x1f, 0x7d, + 0x18, 0x7d, 0xfe, 0x25, 0xc0 +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01111111, 0 b00000010, + 0 b01111101, 0 b11000100, 0 b00001001, + 0 b11110111, 0 b00000000, 0 b00011111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111001, 0 b11110100, 0 b00000001, 0 b11110111, 0 b11110000, + 0 b00000111, 0 b11011100, 0 b01000000, + 0 b00011111, 0 b01110000, 0 b00000001, 0 b11111101, 0 b11101110, + 0 b00000001, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b11011110, 0 b10100000, 0 b00011111, 0 b01111011, + 0 b00000000, 0 b01111101, 0 b11100000, + 0 b00001111, 0 b11110111, 0 b11000000, 0 b00000111, 0 b11011111, + 0 b00101000, 0 b00011111, 0 b01111101, + 0 b00011000, 0 b01111101, 0 b11111110, 0 b00100101, 0 b11000000 +#endif +}; +#endif + +// --------- CY8C21x23, CY8C21x34 & CY8C27x43 Checksum Setup Vectors ---------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CHECKSUM_SETUP_21_27 +const unsigned int num_bits_checksum = 286; +const unsigned char checksum_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF7, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1E, 0x7D, 0x00, 0x7D, 0xE0, 0x0F, 0xF7, 0xC0, + 0x07, 0xDF, 0xE2, 0x5C +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111011, 0 b00000000, + 0 b01111001, 0 b11110000, 0 b01110101, + 0 b11100111, 0 b11001000, 0 b00011111, 0 b11011110, 0 b10100000, + 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111001, 0 b11110111, 0 b00000001, 0 b11110111, 0 b11001001, + 0 b10000111, 0 b11011111, 0 b01001000, + 0 b00011110, 0 b01111101, 0 b00000000, 0 b01111101, 0 b11100000, + 0 b00001111, 0 b11110111, 0 b11000000, + 0 b00000111, 0 b11011111, 0 b11100010, 0 b01011100 +#endif +}; +#endif + +// -------------- CY8C24x23 & CY8C24x23A Checksum Setup Vectors --------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CHECKSUM_SETUP_24_24A +const unsigned int num_bits_checksum = 286; +const unsigned char checksum_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF7, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1E, 0x7D, 0x20, 0x7D, 0xE0, 0x0F, 0xF7, 0xC0, + 0x07, 0xDF, 0xE2, 0x5C +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111011, 0 b00000000, + 0 b01111001, 0 b11110000, 0 b01110101, + 0 b11100111, 0 b11001000, 0 b00011111, 0 b11011110, 0 b10100000, + 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111001, 0 b11110111, 0 b00000001, 0 b11110111, 0 b11001001, + 0 b10000111, 0 b11011111, 0 b01001000, + 0 b00011110, 0 b01111101, 0 b00100000, 0 b01111101, 0 b11100000, + 0 b00001111, 0 b11110111, 0 b11000000, + 0 b00000111, 0 b11011111, 0 b11100010, 0 b01011100 +#endif +}; +#endif + +// -------------- CY8C24x94 & CY8C29x66 Checksum Setup Vectors ---------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef CHECKSUM_SETUP_24_29 +const unsigned int num_bits_checksum = 286; +const unsigned char checksum_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF6, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1E, 0x7D, 0x40, 0x7D, 0xE0, 0x0F, 0xF7, 0xC0, + 0x07, 0xDF, 0xE2, 0x5C +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111011, 0 b00000000, + 0 b01111001, 0 b11110000, 0 b01110101, + 0 b11100111, 0 b11001000, 0 b00011111, 0 b11011110, 0 b10100000, + 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111001, 0 b11110110, 0 b00000001, 0 b11110111, 0 b11001001, + 0 b10000111, 0 b11011111, 0 b01001000, + 0 b00011110, 0 b01111101, 0 b00100000, 0 b01111101, 0 b11100000, + 0 b00001111, 0 b11110111, 0 b11000000, + 0 b00000111, 0 b11011111, 0 b11100010, 0 b01011100 +#endif +}; +#endif + +// ---- CY8C20x66 Program Block Vector ---------------------------------------- +// +// ---------------------------------------------------------------------------- +#ifdef PROGRAM_AND_VERIFY +const unsigned int num_bits_program_and_verify = 440; //KIMC, PTJ: length of program_block[], not including zero padding at end +const unsigned char program_and_verify[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x81, + 0xf9, 0xf7, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf6, 0xa0, + 0x0f, 0xde, 0x80, 0x7f, 0x7a, 0x80, 0x7d, 0xec, + 0x01, 0xf7, 0x80, 0x57, 0xdf, 0x00, 0x1f, 0x7c, + 0xa0, 0x7d, 0xf4, 0x61, 0xf7, 0xf8, 0x97 +#else + 0 b00011011110, 0 b11100010, 0 b00011111, 0 b01111111, 0 b00000010, + 0 b01111101, 0 b11000100, 0 b00001001, + 0 b00011110111, 0 b00000000, 0 b00011111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b00011111001, 0 b11110111, 0 b00000001, 0 b11110111, 0 b11110000, + 0 b00000111, 0 b11011100, 0 b01000000, + 0 b00000011111, 0 b01110000, 0 b00000001, 0 b11111101, 0 b11101110, + 0 b00000001, 0 b11110110, 0 b10100000, + 0 b00000001111, 0 b11011110, 0 b10000000, 0 b01111111, 0 b01111010, + 0 b10000000, 0 b01111101, 0 b11101100, + 0 b00000000001, 0 b11110111, 0 b10000000, 0 b01010111, 0 b11011111, + 0 b00000000, 0 b00011111, 0 b01111100, + 0 b00010100000, 0 b01111101, 0 b11110100, 0 b01100001, 0 b11110111, + 0 b11111000, 0 b10010111 +#endif +}; +#endif + +// ---- CY8C21xxx, CY8C24x23A, CY8C24x94 & CY8C29x66 Program Block Vectors ---- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef PROGRAM_BLOCK_21_24_29 +const unsigned int num_bits_program_block = 308; +const unsigned char program_block[] = { +#ifdef HEX_DEFINE + 0x9F, 0x8A, 0x9E, 0x7F, 0x2B, 0x7D, 0xEE, 0x01, + 0xF7, 0xB0, 0x07, 0x9F, 0x07, 0x5E, 0x7C, 0x81, + 0xFD, 0xEA, 0x01, 0xF7, 0xA0, 0x1F, 0x9F, 0x70, + 0x1F, 0x7C, 0x98, 0x7D, 0xF4, 0x81, 0xF7, 0x80, + 0x17, 0xDF, 0x00, 0x1F, 0x7F, 0x89, 0x70 +#else + 0 b10011111, 0 b10001010, 0 b10011110, 0 b01111111, 0 b00101011, + 0 b01111101, 0 b11101110, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b00000111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111101, 0 b11101010, 0 b00000001, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b10011111, 0 b01110000, + 0 b00011111, 0 b01111100, 0 b10011000, 0 b01111101, 0 b11110100, + 0 b10000001, 0 b11110111, 0 b10000000, + 0 b00010111, 0 b11011111, 0 b00000000, 0 b00011111, 0 b01111111, + 0 b10001001, 0 b01110000 +#endif +}; +#endif + +// --------------------- CY8C27x43 Program Block Vectors----------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +#ifdef PROGRAM_BLOCK_27 +const unsigned int num_bits_program_block = 308; + +const unsigned char program_block[] = { +#ifdef HEX_DEFINE + 0x9F, 0x82, 0xBE, 0x7F, 0x2B, 0x7D, 0xEE, 0x01, + 0xF7, 0xB0, 0x07, 0x9F, 0x07, 0x5E, 0x7C, 0x81, + 0xFD, 0xEA, 0x01, 0xF7, 0xA0, 0x1F, 0x9F, 0x70, + 0x1F, 0x7C, 0x98, 0x7D, 0xF4, 0x81, 0xF7, 0x80, + 0x17, 0xDF, 0x00, 0x1F, 0x7F, 0x89, 0x70 +#else + 0 b10011111, 0 b10000010, 0 b10111110, 0 b01111111, 0 b00101011, + 0 b01111101, 0 b11101110, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b00000111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111101, 0 b11101010, 0 b00000001, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b10011111, 0 b01110000, + 0 b00011111, 0 b01111100, 0 b10011000, 0 b01111101, 0 b11110100, + 0 b10000001, 0 b11110111, 0 b10000000, + 0 b00010111, 0 b11011111, 0 b00000000, 0 b00011111, 0 b01111111, + 0 b10001001, 0 b01110000 +#endif +}; +#endif + +// ----------------------------- General PSoC Vectors-------------------------- +// Modifying these tables is NOT recommendended. Doing so will all but +// guarantee an ISSP error, unless updated vectors have been recommended or +// provided by Cypress Semiconductor. +// ---------------------------------------------------------------------------- +const unsigned int num_bits_init1 = 396; +const unsigned char init1_v[] = { +#ifdef HEX_DEFINE + 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0D, 0xEE, 0x01, 0xF7, 0xB0, 0x07, 0x9F, 0x07, + 0x5E, 0x7C, 0x81, 0xFD, 0xEA, 0x01, 0xF7, 0xA0, + 0x1F, 0x9F, 0x70, 0x1F, 0x7C, 0x98, 0x7D, 0xF4, + 0x81, 0xF7, 0x80, 0x4F, 0xDF, 0x00, 0x1F, 0x7F, + 0x89, 0x70 +#else + 0 b11001010, 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00000000, 0 b00000000, 0 b00000000, + 0 b00001101, 0 b11101110, 0 b00000001, 0 b11110111, 0 b10110000, + 0 b00000111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, 0 b11111101, 0 b11101010, + 0 b00000001, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b10011111, 0 b01110000, 0 b00011111, 0 b01111100, + 0 b10011000, 0 b01111101, 0 b11110100, + 0 b10000001, 0 b11110111, 0 b10000000, 0 b01001111, 0 b11011111, + 0 b00000000, 0 b00011111, 0 b01111111, + 0 b10001001, 0 b01110000 +#endif +}; + +const unsigned int num_bits_init2 = 286; +const unsigned char init2_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF7, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1E, 0x7D, 0x00, 0xFD, 0xE0, 0x0D, 0xF7, 0xC0, + 0x07, 0xDF, 0xE2, 0x5C +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111011, 0 b00000000, + 0 b01111001, 0 b11110000, 0 b01110101, + 0 b11100111, 0 b11001000, 0 b00011111, 0 b11011110, 0 b10100000, + 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111001, 0 b11110111, 0 b00000001, 0 b11110111, 0 b11001001, + 0 b10000111, 0 b11011111, 0 b01001000, + 0 b00011110, 0 b01111101, 0 b00000000, 0 b11111101, 0 b11100000, + 0 b00001101, 0 b11110111, 0 b11000000, + 0 b00000111, 0 b11011111, 0 b11100010, 0 b01011100 +#endif +}; + +const unsigned int num_bits_init3_5v = 836; +const unsigned char init3_5v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7A, 0x01, 0xFD, 0xEA, 0x01, + 0xF7, 0xB0, 0x47, 0xDF, 0x0A, 0x3F, 0x7C, 0xFE, + 0x7D, 0xF4, 0x61, 0xF7, 0xF8, 0x97, 0x00, 0x00, + 0x03, 0x7B, 0x80, 0x7D, 0xE8, 0x07, 0xF7, 0xA8, + 0x07, 0xDE, 0xC1, 0x1F, 0x7C, 0x30, 0x7D, 0xF3, + 0xD5, 0xF7, 0xD1, 0x87, 0xDE, 0xE2, 0x1F, 0x7F, + 0x89, 0x70, 0x00, 0x00, 0x37, 0xB8, 0x07, 0xDE, + 0x80, 0x7F, 0x7A, 0x80, 0x7D, 0xEC, 0x11, 0xF7, + 0xC2, 0x8F, 0xDF, 0x3F, 0xBF, 0x7D, 0x18, 0x7D, + 0xFE, 0x25, 0xC0, 0x00, 0x00, 0xDE, 0xE0, 0x1F, + 0x7A, 0x01, 0xFD, 0xEA, 0x01, 0xF7, 0xB0, 0x47, + 0xDF, 0x0C, 0x1F, 0x7C, 0xF4, 0x7D, 0xF4, 0x61, + 0xF7, 0xB8, 0x87, 0xDF, 0xE2, 0x5C, 0x00, 0x00, + 0x00 +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111101, 0 b11101010, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b01000111, 0 b11011111, 0 b00001010, + 0 b00111111, 0 b01111100, 0 b11111110, + 0 b01111101, 0 b11110100, 0 b01100001, 0 b11110111, 0 b11111000, + 0 b10010111, 0 b00000000, 0 b00000000, + 0 b00000011, 0 b01111011, 0 b10000000, 0 b01111101, 0 b11101000, + 0 b00000111, 0 b11110111, 0 b10101000, + 0 b00000111, 0 b11011110, 0 b11000001, 0 b00011111, 0 b01111100, + 0 b00110000, 0 b01111101, 0 b11110011, + 0 b11010101, 0 b11110111, 0 b11010001, 0 b10000111, 0 b11011110, + 0 b11100010, 0 b00011111, 0 b01111111, + 0 b10001001, 0 b01110000, 0 b00000000, 0 b00000000, 0 b00110111, + 0 b10111000, 0 b00000111, 0 b11011110, + 0 b10000000, 0 b01111111, 0 b01111010, 0 b10000000, 0 b01111101, + 0 b11101100, 0 b00010001, 0 b11110111, + 0 b11000010, 0 b10001111, 0 b11011111, 0 b00111111, 0 b10111111, + 0 b01111101, 0 b00011000, 0 b01111101, + 0 b11111110, 0 b00100101, 0 b11000000, 0 b00000000, 0 b00000000, + 0 b11011110, 0 b11100000, 0 b00011111, + 0 b01111010, 0 b00000001, 0 b11111101, 0 b11101010, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b01000111, + 0 b11011111, 0 b00001100, 0 b00011111, 0 b01111100, 0 b11110100, + 0 b01111101, 0 b11110100, 0 b01100001, + 0 b11110111, 0 b10111000, 0 b10000111, 0 b11011111, 0 b11100010, + 0 b01011100, 0 b00000000, 0 b00000000, + 0 b00000000 +#endif +}; + +const unsigned int num_bits_init3_3v = 836; +const unsigned char init3_3v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7A, 0x01, 0xFD, 0xEA, 0x01, + 0xF7, 0xB0, 0x47, 0xDF, 0x0A, 0x3F, 0x7C, 0xFC, + 0x7D, 0xF4, 0x61, 0xF7, 0xF8, 0x97, 0x00, 0x00, + 0x03, 0x7B, 0x80, 0x7D, 0xE8, 0x07, 0xF7, 0xA8, + 0x07, 0xDE, 0xC1, 0x1F, 0x7C, 0x30, 0x7D, 0xF3, + 0xD5, 0xF7, 0xD1, 0x87, 0xDE, 0xE2, 0x1F, 0x7F, + 0x89, 0x70, 0x00, 0x00, 0x37, 0xB8, 0x07, 0xDE, + 0x80, 0x7F, 0x7A, 0x80, 0x7D, 0xEC, 0x11, 0xF7, + 0xC2, 0x8F, 0xDF, 0x3F, 0x3F, 0x7D, 0x18, 0x7D, + 0xFE, 0x25, 0xC0, 0x00, 0x00, 0xDE, 0xE0, 0x1F, + 0x7A, 0x01, 0xFD, 0xEA, 0x01, 0xF7, 0xB0, 0x47, + 0xDF, 0x0C, 0x1F, 0x7C, 0xF4, 0x7D, 0xF4, 0x61, + 0xF7, 0xB8, 0x87, 0xDF, 0xE2, 0x5C, 0x00, 0x00, + 0x00 +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111101, 0 b11101010, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b01000111, 0 b11011111, 0 b00001010, + 0 b00111111, 0 b01111100, 0 b11111100, + 0 b01111101, 0 b11110100, 0 b01100001, 0 b11110111, 0 b11111000, + 0 b10010111, 0 b00000000, 0 b00000000, + 0 b00000011, 0 b01111011, 0 b10000000, 0 b01111101, 0 b11101000, + 0 b00000111, 0 b11110111, 0 b10101000, + 0 b00000111, 0 b11011110, 0 b11000001, 0 b00011111, 0 b01111100, + 0 b00110000, 0 b01111101, 0 b11110011, + 0 b11010101, 0 b11110111, 0 b11010001, 0 b10000111, 0 b11011110, + 0 b11100010, 0 b00011111, 0 b01111111, + 0 b10001001, 0 b01110000, 0 b00000000, 0 b00000000, 0 b00110111, + 0 b10111000, 0 b00000111, 0 b11011110, + 0 b10000000, 0 b01111111, 0 b01111010, 0 b10000000, 0 b01111101, + 0 b11101100, 0 b00010001, 0 b11110111, + 0 b11000010, 0 b10001111, 0 b11011111, 0 b00111111, 0 b00111111, + 0 b01111101, 0 b00011000, 0 b01111101, + 0 b11111110, 0 b00100101, 0 b11000000, 0 b00000000, 0 b00000000, + 0 b11011110, 0 b11100000, 0 b00011111, + 0 b01111010, 0 b00000001, 0 b11111101, 0 b11101010, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b01000111, + 0 b11011111, 0 b00001100, 0 b00011111, 0 b01111100, 0 b11110100, + 0 b01111101, 0 b11110100, 0 b01100001, + 0 b11110111, 0 b10111000, 0 b10000111, 0 b11011111, 0 b11100010, + 0 b01011100, 0 b00000000, 0 b00000000, + 0 b00000000 +#endif +}; + +#if 0 // +const unsigned int num_bits_id_setup = 330; +const unsigned char id_setup_v[] = { + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01110000, 0 b00000001, + 0 b01111101, 0 b11101110, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b00000111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111101, 0 b11101010, 0 b00000001, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b10011111, 0 b01110000, + 0 b00011111, 0 b01111100, 0 b10011000, 0 b01111101, 0 b11110100, + 0 b10000001, 0 b11100111, 0 b11010000, + 0 b00000111, 0 b11011110, 0 b00000000, 0 b11011111, 0 b01111100, + 0 b00000000, 0 b01111101, 0 b11111110, + 0 b00100101, 0 b11000000 +}; +#endif +#ifdef ID_SETUP_2 +const unsigned int num_bits_id_setup_2 = 418; //PTJ: id_setup_2 with TSYNC Disable (TSYNC enabled before with SendVector(tsync_enable....) +const unsigned char id_setup_2[] = { +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1f, 0x7f, 0x02, 0x7d, 0xc4, 0x09, + 0xf7, 0x00, 0x1f, 0x9f, 0x07, 0x5e, 0x7c, 0x81, + 0xf9, 0xf4, 0x01, 0xf7, 0xf0, 0x07, 0xdc, 0x40, + 0x1f, 0x70, 0x01, 0xfd, 0xee, 0x01, 0xf7, 0xa0, + 0x1f, 0xde, 0xa0, 0x1f, 0x7b, 0x00, 0x7d, 0xe0, + 0x0d, 0xf7, 0xc0, 0x07, 0xdf, 0x28, 0x1f, 0x7d, + 0x18, 0x7d, 0xfe, 0x25, 0xc0 +#else + 0 b11011110, 0 b11100010, 0 b00011111, 0 b01111111, 0 b00000010, + 0 b01111101, 0 b11000100, 0 b00001001, + 0 b11110111, 0 b00000000, 0 b00011111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111001, 0 b11110100, 0 b00000001, 0 b11110111, 0 b11110000, + 0 b00000111, 0 b11011100, 0 b01000000, + 0 b00011111, 0 b01110000, 0 b00000001, 0 b11111101, 0 b11101110, + 0 b00000001, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b11011110, 0 b10100000, 0 b00011111, 0 b01111011, + 0 b00000000, 0 b01111101, 0 b11100000, + 0 b00001101, 0 b11110111, 0 b11000000, 0 b00000111, 0 b11011111, + 0 b00101000, 0 b00011111, 0 b01111101, + 0 b00011000, 0 b01111101, 0 b11111110, 0 b00100101, 0 b11000000 +#endif +}; +#endif + +const unsigned int num_bits_erase_all = 308; +const unsigned char erase_all_v[] = { +#ifdef HEX_DEFINE + 0x9F, 0x82, 0xBE, 0x7F, 0x2B, 0x7D, 0xEE, 0x01, + 0xF7, 0xB0, 0x07, 0x9F, 0x07, 0x5E, 0x7C, 0x81, + 0xFD, 0xEA, 0x01, 0xF7, 0xA0, 0x1F, 0x9F, 0x70, + 0x1F, 0x7C, 0x98, 0x7D, 0xF4, 0x81, 0xF7, 0x80, + 0x2F, 0xDF, 0x00, 0x1F, 0x7F, 0x89, 0x70 +#else + 0 b10011111, 0 b10000010, 0 b10111110, 0 b01111111, 0 b00101011, + 0 b01111101, 0 b11101110, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b00000111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111101, 0 b11101010, 0 b00000001, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b10011111, 0 b01110000, + 0 b00011111, 0 b01111100, 0 b10011000, 0 b01111101, 0 b11110100, + 0 b10000001, 0 b11110111, 0 b10000000, + 0 b00101111, 0 b11011111, 0 b00000000, 0 b00011111, 0 b01111111, + 0 b10001001, 0 b01110000 +#endif +}; + +const unsigned char read_id_v[] = { +#ifdef HEX_DEFINE + 0xBF, 0x00, 0xDF, 0x90, 0x00, 0xFE, 0x60, 0xFF, 0x00 +#else + 0 b10111111, 0 b00000000, 0 b11011111, 0 b10010000, 0 b00000000, + 0 b11111110, 0 b0110000, 0 b11111111, 0 b00000000 +#endif +}; + +const unsigned char Switch_Bank1[] = //PTJ: use this to switch between register banks +{ +#ifdef HEX_DEFINE + 0xde, 0xe2, 0x1c +#else + 0 b11011110, 0 b11100010, 0 b00011100 +#endif +}; + +const unsigned char Switch_Bank0[] = //PTJ: use this to switch between register banks +{ +#ifdef HEX_DEFINE + 0xde, 0xe0, 0x1c +#else + 0 b11011110, 0 b11100000, 0 b00011100 +#endif +}; + +const unsigned char read_IMOtrim[] = //PTJ: read the 1,E8h register after id__setup_1 to see if the cal data was loaded properly. +{ +#ifdef HEX_DEFINE + 0xfd, 0x00, 0x10 +#else + 0 b11111101, 0 b00000000, 0 b00010000 +#endif +}; + +const unsigned char read_SPCtrim[] = //PTJ: read the 1,E7h register after id__setup_1 to see if the cal data was loaded properly. +{ +#ifdef HEX_DEFINE + 0xfc, 0xe0, 0x10 +#else + 0 b11111100, 0 b11100000, 0 b00010000 +#endif +}; + +const unsigned char read_VBGfinetrim[] = //PTJ: read the 1,D7h register after id__setup_1 to see if the cal data was loaded properly. +{ +#ifdef HEX_DEFINE + 0xfa, 0xe0, 0x08 +#else + 0 b11111010, 0 b11100000, 0 b0001000 +#endif +}; + +const unsigned char read_reg_end = 0x80; //PTJ: this is the final '1' after a MR command + +const unsigned char write_byte_start = 0x90; //PTJ: this is set to SRAM 0x80 +const unsigned char write_byte_end = 0xE0; + +const unsigned char set_block_number[] = { 0x9F, 0x40, 0xE0 }; + +const unsigned char set_block_number_end = 0xE0; +#ifdef MULTI_BANK +const unsigned char set_bank_number[] = { 0xDE, 0xE2, 0x1F, 0x7D, 0x00 }; +const unsigned char set_bank_number_end[] = { 0xFB, 0xDC, 0x03, 0x80 }; +#endif + +// const unsigned char num_bits_wait_and_poll_end = 40; //PTJ 308: commented out +const unsigned char num_bits_wait_and_poll_end = 30; //PTJ 308: added to match spec +const unsigned char wait_and_poll_end[] = { +// 0x00, 0x00, 0x00, 0x00, 0x00 //PTJ 308: commented out + 0x00, 0x00, 0x00, 0x00 //PTJ 308: added to match spec +}; // forty '0's per the spec + +const unsigned char read_checksum_v[] = { +#ifdef HEX_DEFINE + 0xBF, 0x20, 0xDF, 0x80, 0x80 +#else + 0 b10111111, 0 b00100000, 0 b11011111, 0 b10000000, 0 b10000000 +#endif +}; + +const unsigned char read_byte_v[] = { +#ifdef HEX_DEFINE + 0xB0, 0x80 +#else + 0 b10110000, 0 b10000000 +#endif +}; + +const unsigned int num_bits_verify_setup = 264; +const unsigned char verify_setup_v[] = { +#ifdef HEX_DEFINE + 0xDE, 0xE0, 0x1F, 0x7B, 0x00, 0x79, 0xF0, 0x75, + 0xE7, 0xC8, 0x1F, 0xDE, 0xA0, 0x1F, 0x7A, 0x01, + 0xF9, 0xF7, 0x01, 0xF7, 0xC9, 0x87, 0xDF, 0x48, + 0x1F, 0x78, 0x00, 0xFD, 0xF0, 0x01, 0xF7, 0xF8, + 0x97 +#else + 0 b11011110, 0 b11100000, 0 b00011111, 0 b01111011, 0 b00000000, + 0 b01111001, 0 b11110000, 0 b01110101, + 0 b11100111, 0 b11001000, 0 b00011111, 0 b11011110, 0 b10100000, + 0 b00011111, 0 b01111010, 0 b00000001, + 0 b11111001, 0 b11110111, 0 b00000001, 0 b11110111, 0 b11001001, + 0 b10000111, 0 b11011111, 0 b01001000, + 0 b00011111, 0 b01111000, 0 b00000000, 0 b11111101, 0 b11110000, + 0 b00000001, 0 b11110111, 0 b11111000, + 0 b10010111 +#endif +}; + +const unsigned int num_bits_security = 308; +const unsigned char security_v[] = { +#ifdef HEX_DEFINE + 0x9F, 0x8A, 0x9E, 0x7F, 0x2B, 0x7D, 0xEE, 0x01, + 0xF7, 0xB0, 0x07, 0x9F, 0x07, 0x5E, 0x7C, 0x81, + 0xFD, 0xEA, 0x01, 0xF7, 0xA0, 0x1F, 0x9F, 0x70, + 0x1F, 0x7C, 0x98, 0x7D, 0xF4, 0x81, 0xF7, 0x80, + 0x27, 0xDF, 0x00, 0x1F, 0x7F, 0x89, 0x70 +#else + 0 b10011111, 0 b10001010, 0 b10011110, 0 b01111111, 0 b00101011, + 0 b01111101, 0 b11101110, 0 b00000001, + 0 b11110111, 0 b10110000, 0 b00000111, 0 b10011111, 0 b00000111, + 0 b01011110, 0 b01111100, 0 b10000001, + 0 b11111101, 0 b11101010, 0 b00000001, 0 b11110111, 0 b10100000, + 0 b00011111, 0 b10011111, 0 b01110000, + 0 b00011111, 0 b01111100, 0 b10011000, 0 b01111101, 0 b11110100, + 0 b10000001, 0 b11110111, 0 b10000000, + 0 b00100111, 0 b11011111, 0 b00000000, 0 b00011111, 0 b01111111, + 0 b10001001, 0 b01110000 +#endif +}; + +#endif //(INC_ISSP_VECTORS) +#endif //(PROJECT_REV_) +//end of file ISSP_Vectors.h diff --git a/drivers/input/keyboard/cypressbln/touchkey_fw_M0.h b/drivers/input/keyboard/cypressbln/touchkey_fw_M0.h new file mode 100644 index 0000000..c712b5e --- /dev/null +++ b/drivers/input/keyboard/cypressbln/touchkey_fw_M0.h @@ -0,0 +1,747 @@ +unsigned char firmware_data[] = { + 0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, + 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x04, 0xce, 0x7e, 0x7e, 0x30, + 0x30, 0x30, 0x7d, 0x06, 0x1b, 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, + 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, + 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x40, 0x71, 0x10, 0x62, 0xe3, 0x06, 0x70, + 0xef, 0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, 0x38, 0x5d, + 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, 0xfa, 0x01, 0x40, 0x4f, 0x5b, + 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, + 0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, 0xef, 0x18, 0x60, + 0xd5, 0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, + 0x1a, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, 0xfe, + 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, 0x03, 0x50, 0x80, 0x4e, + 0x62, 0xd3, 0x03, 0x62, 0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, + 0x00, 0x71, 0xc0, 0x7c, 0x03, 0x3b, 0x62, 0xd0, 0x00, 0x50, 0x01, + 0x57, 0xe2, 0x08, 0x28, 0x53, 0x58, 0x18, 0x75, 0x09, 0x00, 0x28, + 0x4b, 0x51, 0x58, 0x80, 0x04, 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, + 0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, 0x75, 0x09, 0x00, + 0x08, 0x28, 0x53, 0x58, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0xa0, + 0x1c, 0x53, 0x57, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, 0x58, + 0x47, 0x58, 0xff, 0xb0, 0x06, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x18, + 0x7a, 0x57, 0xbf, 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, + 0x28, 0x53, 0x57, 0x50, 0x00, 0x3f, 0x58, 0x47, 0x58, 0xff, 0xb0, + 0x08, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x57, 0xbf, + 0xef, 0x18, 0x8f, 0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, + 0x10, 0x62, 0xe0, 0x1a, 0x70, 0xef, 0x62, 0xe2, 0x00, 0x7c, 0x18, + 0x88, 0x8f, 0xff, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x01, 0x99, 0x03, 0x33, 0x06, + 0x66, 0x0c, 0xcc, 0x19, 0x99, 0x33, 0x33, 0x66, 0x66, 0xcc, 0xcc, + 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0b, 0xff, 0x18, 0x00, 0x2f, + 0xff, 0x5f, 0xff, 0xbf, 0xff, 0x01, 0x66, 0x02, 0xcc, 0x05, 0x99, + 0x0b, 0x32, 0x16, 0x66, 0x2c, 0xcc, 0x59, 0x98, 0xb3, 0x32, 0x01, + 0x4d, 0x02, 0x9a, 0x05, 0x33, 0x0a, 0x66, 0x14, 0xcd, 0x29, 0x99, + 0x53, 0x33, 0xa6, 0x66, 0x01, 0x33, 0x02, 0x66, 0x04, 0xcc, 0x09, + 0x99, 0x13, 0x33, 0x26, 0x65, 0x4c, 0xcc, 0x99, 0x99, 0x01, 0x19, + 0x02, 0x33, 0x04, 0x66, 0x08, 0xcc, 0x11, 0x99, 0x25, 0x26, 0x46, + 0x65, 0x8c, 0xcc, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x0f, 0xff, 0x20, 0x00, 0x3f, 0xff, 0x7f, 0xff, 0x1a, 0xf5, 0x70, + 0xef, 0x62, 0x61, 0x00, 0x62, 0xfd, 0x00, 0x62, 0xcd, 0x00, 0x62, + 0xce, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x62, 0xa0, 0x00, + 0x62, 0xa1, 0x80, 0x62, 0xa2, 0xc0, 0x62, 0xa3, 0x0c, 0x62, 0xa8, + 0x00, 0x62, 0xa6, 0x00, 0x62, 0xa7, 0x00, 0x62, 0x7c, 0x33, 0x62, + 0x7a, 0x00, 0x62, 0x7b, 0x00, 0x62, 0x79, 0x00, 0x62, 0x36, 0x00, + 0x62, 0x37, 0x00, 0x62, 0x38, 0x00, 0x62, 0x39, 0x00, 0x62, 0x3a, + 0x00, 0x62, 0x3b, 0x00, 0x62, 0x3c, 0x00, 0x62, 0x3d, 0x00, 0x62, + 0x3e, 0x00, 0x62, 0x3f, 0x00, 0x62, 0x40, 0x00, 0x62, 0x41, 0x00, + 0x62, 0x42, 0x00, 0x62, 0x43, 0x00, 0x62, 0x44, 0x00, 0x62, 0x45, + 0x00, 0x62, 0x46, 0x00, 0x62, 0x47, 0x00, 0x62, 0x48, 0x00, 0x62, + 0x49, 0x00, 0x62, 0x4a, 0x00, 0x62, 0x4b, 0x00, 0x62, 0x4c, 0x00, + 0x62, 0x4d, 0x00, 0x62, 0x4e, 0x00, 0x62, 0x4f, 0x00, 0x62, 0xca, + 0x20, 0x62, 0xd6, 0x44, 0x62, 0xcf, 0x00, 0x62, 0xcb, 0x00, 0x62, + 0xc8, 0x00, 0x62, 0xcc, 0x00, 0x62, 0xc9, 0x00, 0x62, 0xd7, 0x00, + 0x62, 0xa9, 0x00, 0x62, 0x2b, 0x00, 0x62, 0xb0, 0x00, 0x62, 0xb3, + 0x02, 0x62, 0xb6, 0x00, 0x62, 0xb2, 0x00, 0x62, 0xb5, 0x00, 0x62, + 0xb8, 0x00, 0x62, 0xb1, 0x00, 0x62, 0xb4, 0x00, 0x62, 0xb7, 0x00, + 0x62, 0x33, 0x00, 0x62, 0x34, 0x00, 0x62, 0x35, 0x00, 0x71, 0x10, + 0x62, 0x54, 0x00, 0x62, 0x55, 0x00, 0x62, 0x56, 0x00, 0x62, 0x57, + 0x00, 0x62, 0x58, 0x00, 0x62, 0x59, 0x00, 0x62, 0x5a, 0x00, 0x62, + 0x5b, 0x00, 0x62, 0xdc, 0x00, 0x62, 0xe2, 0x00, 0x62, 0xdd, 0x00, + 0x62, 0xd8, 0x02, 0x62, 0xd9, 0x00, 0x62, 0xda, 0x00, 0x62, 0xdb, + 0x00, 0x62, 0xdf, 0x00, 0x62, 0x29, 0x00, 0x62, 0x30, 0x00, 0x62, + 0xbd, 0x00, 0x70, 0xef, 0x70, 0xef, 0x62, 0x00, 0x08, 0x71, 0x10, + 0x62, 0x00, 0x08, 0x62, 0x01, 0x92, 0x70, 0xef, 0x62, 0x04, 0x17, + 0x71, 0x10, 0x62, 0x04, 0x14, 0x62, 0x05, 0xbc, 0x70, 0xef, 0x62, + 0x08, 0x00, 0x71, 0x10, 0x62, 0x08, 0x00, 0x62, 0x09, 0x28, 0x70, + 0xef, 0x62, 0x0c, 0x00, 0x71, 0x10, 0x62, 0x0c, 0x00, 0x62, 0x0d, + 0x00, 0x70, 0xef, 0x62, 0x10, 0x00, 0x71, 0x10, 0x62, 0x10, 0x00, + 0x62, 0x11, 0x00, 0x70, 0xef, 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, + 0x62, 0x09, 0x00, 0x62, 0x0d, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, + 0x7f, 0x55, 0x02, 0x08, 0x55, 0x03, 0x17, 0x55, 0x04, 0x00, 0x7c, + 0x03, 0x48, 0x7f, 0x7c, 0x01, 0xe4, 0x70, 0xef, 0x7f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x62, 0xd0, 0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, + 0xe0, 0x08, 0x21, 0xf8, 0x29, 0x00, 0x70, 0xfe, 0x60, 0xe0, 0x70, + 0xef, 0x4b, 0x4b, 0x4b, 0x4b, 0x51, 0x02, 0x21, 0xf7, 0x60, 0x00, + 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, + 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, + 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, + 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, + 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, + 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, + 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, + 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, + 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, + 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, + 0x60, 0x00, 0x47, 0x00, 0x00, 0x49, 0x01, 0x00, 0x29, 0x08, 0x60, + 0x00, 0x57, 0x01, 0x79, 0xbf, 0xfe, 0x18, 0x71, 0x10, 0x60, 0xe0, + 0x70, 0xef, 0x71, 0x01, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x67, 0x21, + 0x0f, 0xff, 0x40, 0x9f, 0x4e, 0x18, 0x21, 0x0f, 0xff, 0x39, 0x9f, + 0x47, 0x7f, 0x08, 0x10, 0x28, 0xa0, 0x0b, 0x9f, 0x3f, 0x20, 0x18, + 0x75, 0xdf, 0xf5, 0x74, 0x8f, 0xf2, 0x38, 0xfe, 0x7f, 0x52, 0x00, + 0xa0, 0x08, 0x10, 0x9f, 0x2d, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x50, 0x0d, 0x9f, 0x20, 0x50, 0x0a, 0x9f, 0x1c, + 0x7f, 0x70, 0xbf, 0x62, 0xd3, 0x03, 0x4f, 0x52, 0xfb, 0xa0, 0x15, + 0x7b, 0xfb, 0x52, 0xfc, 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, + 0x05, 0x4f, 0x62, 0xd3, 0x03, 0x77, 0xfd, 0x8f, 0xe9, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x3d, 0xfa, 0x00, 0xb0, 0x06, 0x3d, 0xfb, 0x00, + 0xa0, 0x18, 0x10, 0x52, 0xfc, 0x59, 0xfd, 0x28, 0x9e, 0xe6, 0x20, + 0x07, 0xfd, 0x01, 0x0f, 0xfc, 0x00, 0x17, 0xfb, 0x01, 0x1f, 0xfa, + 0x00, 0x8f, 0xe0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, + 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xfb, 0x80, 0x04, + 0x2e, 0x03, 0x04, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, 0xc0, + 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, + 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xef, + 0x80, 0x04, 0x2e, 0x03, 0x10, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, 0x70, + 0x3f, 0x71, 0x80, 0x5d, 0xd3, 0x08, 0x5d, 0xd0, 0x08, 0x62, 0xd0, + 0x00, 0x51, 0x08, 0x60, 0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, + 0xa0, 0x09, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, 0x80, 0x08, 0x49, + 0xd7, 0x20, 0xa0, 0x03, 0x80, 0xa6, 0x51, 0x05, 0x21, 0x0e, 0xe0, + 0x01, 0x80, 0x11, 0x80, 0x67, 0x80, 0x79, 0x80, 0x47, 0x80, 0x96, + 0x80, 0x94, 0x80, 0x92, 0x80, 0x90, 0x80, 0x97, 0x5d, 0xd8, 0x21, + 0xfe, 0x39, 0x40, 0xa0, 0x06, 0x62, 0xd7, 0x00, 0x80, 0x8a, 0x49, + 0xd8, 0x01, 0xb0, 0x0f, 0x55, 0x0c, 0x02, 0x26, 0x05, 0xf0, 0x2e, + 0x05, 0x02, 0x62, 0xd7, 0x10, 0x80, 0x77, 0x55, 0x0c, 0x01, 0x26, + 0x05, 0xf0, 0x2e, 0x05, 0x06, 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, + 0x07, 0x5c, 0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x62, 0xd7, 0x14, + 0x80, 0x5b, 0x51, 0x0a, 0x78, 0x3a, 0x07, 0xc0, 0x0f, 0x51, 0x09, + 0x02, 0x07, 0x5c, 0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x2e, 0x05, + 0x20, 0x60, 0xd8, 0x62, 0xd7, 0x04, 0x80, 0x3f, 0x5d, 0xd8, 0x3a, + 0x0a, 0xd0, 0x2b, 0xa0, 0x29, 0x53, 0x07, 0x53, 0x06, 0x26, 0x05, + 0xf0, 0x2e, 0x05, 0x04, 0x80, 0x18, 0x51, 0x0b, 0x78, 0x3a, 0x07, + 0xc0, 0x16, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x5d, 0xd8, 0x54, 0x00, + 0x2e, 0x05, 0x10, 0x76, 0x07, 0x80, 0x01, 0x62, 0xd7, 0x10, 0x80, + 0x0f, 0x62, 0xd7, 0x00, 0x80, 0x0a, 0x26, 0x05, 0xf0, 0x2e, 0x05, + 0x00, 0x55, 0x0c, 0x00, 0x18, 0x60, 0xd0, 0x18, 0x60, 0xd3, 0x20, + 0x18, 0x7e, 0x62, 0xd0, 0x00, 0x71, 0x10, 0x41, 0x04, 0xfc, 0x43, + 0x05, 0x03, 0x70, 0xef, 0x26, 0x03, 0xfc, 0x51, 0x03, 0x60, 0x04, + 0x55, 0x0c, 0x00, 0x90, 0x28, 0x90, 0x2d, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x50, 0x00, 0x53, 0x06, 0x71, 0x10, 0x43, 0x04, 0x03, 0x43, + 0x05, 0x03, 0x70, 0xef, 0x2e, 0x03, 0x03, 0x51, 0x03, 0x60, 0x04, + 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x05, 0x21, 0xb0, 0x26, 0x05, 0x4f, + 0x7f, 0x41, 0xe0, 0x7f, 0x43, 0xe0, 0x80, 0x7f, 0x43, 0xd6, 0x31, + 0x7f, 0x41, 0xe0, 0x7f, 0x41, 0xd6, 0xfe, 0x7f, 0x62, 0xd0, 0x00, + 0x4f, 0x52, 0xfd, 0x53, 0x0a, 0x52, 0xfc, 0x53, 0x0b, 0x52, 0xfb, + 0x53, 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x08, 0x5d, 0xa4, 0x04, 0x1b, 0x5d, 0xa5, 0x0c, 0x1a, 0x55, 0x1c, + 0x01, 0x18, 0x7e, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x53, + 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x8c, 0x62, 0xd3, 0x00, + 0x13, 0x7a, 0x62, 0xd3, 0x00, 0x54, 0x7e, 0x62, 0xd3, 0x00, 0x52, + 0x8b, 0x62, 0xd3, 0x00, 0x1b, 0x79, 0x62, 0xd3, 0x00, 0x54, 0x7d, + 0x48, 0x7d, 0x80, 0xb0, 0x33, 0x3d, 0x7d, 0x00, 0xb0, 0x7b, 0x51, + 0x0d, 0x3b, 0x7e, 0xc0, 0x75, 0x52, 0x7e, 0x58, 0x1e, 0x01, 0x00, + 0x6d, 0x62, 0xd3, 0x00, 0x05, 0x40, 0xc0, 0x09, 0x51, 0x0f, 0x3b, + 0x40, 0xd0, 0x12, 0xa0, 0x10, 0x56, 0x40, 0x00, 0x5b, 0x64, 0x5c, + 0x62, 0xd3, 0x00, 0x07, 0x7a, 0x01, 0x0f, 0x79, 0x00, 0x80, 0x41, + 0x3d, 0x7d, 0xff, 0xb0, 0x09, 0x50, 0xff, 0x12, 0x0e, 0x3b, 0x7e, + 0xc0, 0x20, 0x62, 0xd3, 0x00, 0x56, 0x7e, 0x00, 0x56, 0x7d, 0x00, + 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x47, 0x78, 0xd0, 0x03, + 0x50, 0x00, 0x54, 0x47, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x2c, + 0x62, 0xd3, 0x00, 0x52, 0x8c, 0x62, 0xd3, 0x00, 0x54, 0x7a, 0x62, + 0xd3, 0x00, 0x52, 0x8b, 0x62, 0xd3, 0x00, 0x54, 0x79, 0x51, 0x1e, + 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x56, 0x7e, 0x00, 0x56, 0x7d, 0x00, + 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x12, 0x54, 0x47, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, + 0x08, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x42, 0x53, 0x19, 0x55, 0x18, + 0x00, 0x18, 0x08, 0x90, 0x7e, 0x62, 0xd3, 0x00, 0x23, 0x44, 0xb0, + 0x2c, 0x51, 0x10, 0x04, 0x19, 0x0e, 0x18, 0x00, 0x18, 0x64, 0x5c, + 0x62, 0xd3, 0x00, 0x52, 0x7e, 0x12, 0x19, 0x52, 0x7d, 0x1a, 0x18, + 0xc0, 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x45, 0x78, + 0x54, 0x45, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, + 0x51, 0x10, 0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, + 0xd3, 0x00, 0x52, 0x7e, 0x12, 0x19, 0x52, 0x7d, 0x1a, 0x18, 0xc0, + 0x0e, 0x5b, 0x67, 0x90, 0x31, 0x62, 0xd3, 0x00, 0x2d, 0x44, 0x50, + 0x01, 0x80, 0x24, 0x5b, 0x67, 0x08, 0x90, 0x23, 0x73, 0x62, 0xd3, + 0x00, 0x25, 0x44, 0x62, 0xd3, 0x00, 0x20, 0x51, 0x11, 0x54, 0x45, + 0x50, 0x00, 0x80, 0x0d, 0x5b, 0x67, 0x90, 0x0d, 0x73, 0x62, 0xd3, + 0x00, 0x25, 0x44, 0x50, 0x00, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, + 0x67, 0x67, 0x67, 0x5c, 0x18, 0x21, 0x07, 0xf0, 0x01, 0x7f, 0x01, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x70, 0xbf, 0x70, 0xbf, + 0x62, 0xd3, 0x00, 0x50, 0x02, 0x78, 0x08, 0x5c, 0x56, 0x42, 0x19, + 0x18, 0x78, 0xdf, 0xf8, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x91, + 0xb2, 0x70, 0xbf, 0x18, 0x08, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, + 0x8c, 0x62, 0xd3, 0x00, 0x54, 0x7a, 0x62, 0xd3, 0x00, 0x52, 0x8b, + 0x62, 0xd3, 0x00, 0x54, 0x79, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x14, 0x00, 0x50, 0x02, + 0x78, 0x08, 0x9f, 0x0e, 0x39, 0x01, 0xb0, 0x04, 0x55, 0x14, 0x01, + 0x18, 0x78, 0xdf, 0xf3, 0x51, 0x14, 0x7f, 0x50, 0x02, 0x78, 0x08, + 0x9e, 0x3e, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x98, 0x90, 0x91, 0x92, + 0x93, 0x94, 0x95, 0x96, 0x97, 0xd8, 0xd9, 0xda, 0xdb, 0xdf, 0x00, + 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x70, 0xbf, 0x62, + 0xd0, 0x00, 0x62, 0xd3, 0x00, 0x57, 0x00, 0x56, 0x44, 0x00, 0x79, + 0xdf, 0xfb, 0x62, 0xd3, 0x00, 0x57, 0x01, 0x50, 0x03, 0x54, 0x45, + 0x79, 0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x14, 0x57, 0x01, 0x54, + 0x47, 0x79, 0xdf, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x55, 0x0d, 0x14, + 0x55, 0x0e, 0x05, 0x55, 0x0f, 0x14, 0x55, 0x10, 0x01, 0x55, 0x11, + 0x03, 0x55, 0x12, 0x14, 0x55, 0x22, 0x04, 0x55, 0x1f, 0x14, 0x43, + 0x61, 0x0d, 0x57, 0x00, 0x50, 0x02, 0x90, 0xae, 0x50, 0x04, 0xff, + 0x98, 0x29, 0x00, 0x60, 0xa9, 0x62, 0xa0, 0x08, 0x43, 0xa2, 0x04, + 0x62, 0xa3, 0x70, 0x43, 0x7a, 0x01, 0x43, 0xaa, 0x02, 0x43, 0xdf, + 0x01, 0x50, 0x01, 0x57, 0x09, 0x90, 0x20, 0x90, 0x55, 0x57, 0x01, + 0x50, 0xb3, 0x91, 0x5d, 0x50, 0x01, 0x57, 0x0e, 0x90, 0x12, 0x90, + 0x47, 0x7f, 0x53, 0x22, 0xff, 0x67, 0x29, 0x00, 0x60, 0xa9, 0x51, + 0x21, 0x58, 0x20, 0x90, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, 0x03, + 0x53, 0x21, 0x64, 0x64, 0x64, 0x64, 0x64, 0x29, 0x80, 0x60, 0xa1, + 0x5b, 0x78, 0x21, 0x0f, 0x29, 0x08, 0x74, 0x53, 0x20, 0x12, 0x22, + 0x02, 0x21, 0x5c, 0x50, 0x00, 0x53, 0x1d, 0x53, 0x23, 0x29, 0x01, + 0x79, 0xa0, 0x08, 0x64, 0x6b, 0x1d, 0x6b, 0x23, 0x8f, 0xf5, 0x60, + 0xb5, 0x51, 0x1d, 0x60, 0xb4, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x90, + 0x28, 0x90, 0x5a, 0x18, 0x78, 0xdf, 0xf8, 0x7f, 0x41, 0xdf, 0xfe, + 0x71, 0x10, 0x41, 0xd8, 0xfd, 0x70, 0xef, 0x41, 0x61, 0xf3, 0x41, + 0xa2, 0xfb, 0x41, 0xa0, 0xf7, 0x62, 0xa3, 0x00, 0x62, 0xa9, 0x00, + 0x41, 0xaa, 0xfd, 0x7f, 0x02, 0x20, 0x02, 0x08, 0x64, 0x5c, 0xff, + 0xf8, 0x4b, 0x74, 0xff, 0xf4, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1d, + 0x10, 0x5b, 0x64, 0x64, 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x2a, 0x1d, + 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, + 0x36, 0x1d, 0xff, 0x18, 0xfe, 0xd6, 0x5c, 0x5e, 0x00, 0x2a, 0x1d, + 0x61, 0x00, 0x70, 0xef, 0x7f, 0x62, 0xd0, 0x00, 0x10, 0x73, 0x53, + 0x1d, 0x71, 0x10, 0x5b, 0xfe, 0xc0, 0x5c, 0x5e, 0x00, 0x22, 0x1d, + 0x61, 0x00, 0x70, 0xef, 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, 0x5e, + 0x01, 0x22, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, 0x00, 0x2a, + 0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, + 0x53, 0x1e, 0x50, 0x00, 0x53, 0x1a, 0x53, 0x1b, 0x51, 0x1e, 0x5c, + 0x62, 0xd3, 0x00, 0x52, 0x24, 0x53, 0x1f, 0x43, 0xa0, 0x01, 0x51, + 0x1f, 0x60, 0xfd, 0x41, 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x7a, 0x9f, + 0x81, 0x58, 0x23, 0x55, 0x1c, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, + 0x00, 0x43, 0xb3, 0x01, 0x51, 0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, + 0x51, 0x1e, 0x9f, 0x5f, 0x9f, 0x91, 0x43, 0xa3, 0x20, 0x41, 0xa0, + 0xfe, 0x62, 0xfd, 0x00, 0x50, 0xff, 0x4c, 0x1b, 0x14, 0x1b, 0x51, + 0x20, 0x11, 0x08, 0xfe, 0x4d, 0x4c, 0x1a, 0x1c, 0x1a, 0xd0, 0x07, + 0x55, 0x1a, 0x00, 0x55, 0x1b, 0x00, 0x51, 0x1e, 0x64, 0x5c, 0x62, + 0xd3, 0x00, 0x51, 0x1b, 0x54, 0x8c, 0x51, 0x1a, 0x54, 0x8b, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x9f, 0x86, 0x18, 0x78, 0xdf, 0xfa, + 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x27, 0x5a, 0x26, 0x55, + 0x1e, 0x01, 0x62, 0xd3, 0x00, 0x58, 0x1e, 0x56, 0x24, 0x80, 0x55, + 0x29, 0x08, 0x55, 0x28, 0x80, 0x51, 0x1e, 0x9f, 0x63, 0x51, 0x1e, + 0x9f, 0x5f, 0x70, 0xbf, 0x58, 0x1e, 0x62, 0xd3, 0x00, 0x51, 0x1b, + 0x3a, 0x27, 0x51, 0x1a, 0x1a, 0x26, 0xd0, 0x06, 0x51, 0x28, 0x73, + 0x25, 0x24, 0x68, 0x28, 0x26, 0x28, 0x7f, 0x51, 0x28, 0x2d, 0x24, + 0x7a, 0x29, 0xbf, 0xd6, 0x7a, 0x1e, 0xdf, 0xc4, 0x70, 0x3f, 0x71, + 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0xa0, 0x11, 0x10, 0x51, 0x9f, + 0x19, 0x0e, 0xd0, 0x12, 0x7c, 0x14, 0x1d, 0x39, 0x0f, 0xa0, 0x16, + 0x62, 0xd0, 0x00, 0x76, 0xa0, 0x0e, 0x9f, 0x00, 0x80, 0x0c, 0x62, + 0xd0, 0x00, 0x55, 0xa0, 0x00, 0x55, 0x9f, 0x00, 0x90, 0xa9, 0x7f, + 0x62, 0xd0, 0x00, 0x3c, 0xa7, 0xf0, 0xd0, 0x03, 0x76, 0xa7, 0x62, + 0xd0, 0x00, 0x51, 0x2f, 0x21, 0x7f, 0x53, 0x58, 0x51, 0xa7, 0x3a, + 0x58, 0xb0, 0x50, 0x7c, 0x14, 0x1d, 0x62, 0xd0, 0x00, 0x53, 0xad, + 0x3c, 0xad, 0x0f, 0xa0, 0x3d, 0x3c, 0xa9, 0x00, 0xb0, 0x1c, 0x55, + 0x93, 0x00, 0x55, 0x94, 0x00, 0x51, 0xad, 0x53, 0x57, 0x55, 0x58, + 0x00, 0x06, 0x57, 0x93, 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd5, + 0x50, 0x08, 0x3f, 0x57, 0x62, 0xd0, 0x00, 0x55, 0xa5, 0x00, 0x3c, + 0xac, 0x00, 0xb0, 0x0a, 0x7c, 0x14, 0xb2, 0x62, 0xd0, 0x00, 0x55, + 0xac, 0x01, 0x62, 0xd0, 0x00, 0x55, 0xb0, 0x03, 0x80, 0x07, 0x62, + 0xd0, 0x00, 0x55, 0xa7, 0x00, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0xa0, + 0x00, 0x55, 0x9f, 0x00, 0x3c, 0xac, 0x01, 0xb0, 0x31, 0x7a, 0xb0, + 0x3c, 0xb0, 0x00, 0xb0, 0x2a, 0x3c, 0xac, 0x01, 0xb0, 0x0a, 0x7c, + 0x15, 0x45, 0x62, 0xd0, 0x00, 0x55, 0xac, 0x00, 0x62, 0xd0, 0x00, + 0x3c, 0xa9, 0x00, 0xb0, 0x0e, 0x51, 0xad, 0x53, 0x57, 0x55, 0x58, + 0x00, 0x06, 0x57, 0x93, 0x7c, 0x1a, 0xcf, 0x62, 0xd0, 0x00, 0x55, + 0xa7, 0x00, 0x7f, 0x10, 0x4f, 0x38, 0x16, 0x62, 0xd0, 0x00, 0x3c, + 0xa8, 0x00, 0xb0, 0x05, 0x51, 0x9b, 0x53, 0x24, 0x56, 0x0d, 0x00, + 0x80, 0x67, 0x56, 0x00, 0x00, 0x80, 0x5b, 0x62, 0xd0, 0x00, 0x3c, + 0xa8, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, + 0x06, 0x57, 0x9b, 0x7c, 0x19, 0xf9, 0x52, 0x00, 0x53, 0x55, 0x55, + 0x56, 0x00, 0x06, 0x55, 0x24, 0x7c, 0x1a, 0xc3, 0x10, 0x52, 0x00, + 0x7c, 0x09, 0x5a, 0x20, 0x10, 0x7c, 0x05, 0xe5, 0x62, 0xd0, 0x00, + 0x20, 0x39, 0x00, 0xbf, 0xee, 0x7c, 0x19, 0x52, 0x52, 0x0d, 0x7c, + 0x1a, 0xb7, 0x02, 0x57, 0x53, 0x57, 0x51, 0x56, 0x0a, 0x58, 0x53, + 0x58, 0x7c, 0x1a, 0x85, 0x06, 0x55, 0x8b, 0x0e, 0x56, 0x00, 0x51, + 0x56, 0x7c, 0x19, 0xe3, 0x7c, 0x1a, 0x05, 0x77, 0x00, 0x3d, 0x00, + 0x02, 0xcf, 0xa2, 0x77, 0x0d, 0x3d, 0x0d, 0x03, 0xcf, 0x96, 0x56, + 0x00, 0x00, 0x81, 0x06, 0x7c, 0x19, 0x47, 0x7c, 0x19, 0x9e, 0x51, + 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x0e, 0x3e, 0x57, 0x54, 0x0f, + 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x55, 0x55, 0x06, 0x55, + 0x56, 0x00, 0x55, 0x52, 0x00, 0x55, 0x51, 0x00, 0x3c, 0x56, 0x00, + 0xb0, 0x06, 0x3c, 0x55, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x56, + 0x6e, 0x55, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x57, 0x04, 0x52, + 0x51, 0x58, 0x0c, 0x51, 0x65, 0x57, 0x6b, 0x58, 0x8f, 0xde, 0x5f, + 0x57, 0x52, 0x5f, 0x58, 0x51, 0x62, 0xd0, 0x00, 0x5a, 0x55, 0x06, + 0x55, 0x03, 0x51, 0x55, 0x04, 0x57, 0x0e, 0x58, 0x03, 0x51, 0x58, + 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x10, 0x3e, 0x57, 0x54, 0x11, 0x52, + 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x55, 0x55, 0x06, 0x55, 0x56, + 0x00, 0x55, 0x52, 0x00, 0x55, 0x51, 0x00, 0x3c, 0x56, 0x00, 0xb0, + 0x06, 0x3c, 0x55, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x56, 0x6e, + 0x55, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x57, 0x04, 0x52, 0x51, + 0x58, 0x0c, 0x51, 0x65, 0x57, 0x6b, 0x58, 0x8f, 0xde, 0x5f, 0x57, + 0x52, 0x5f, 0x58, 0x51, 0x62, 0xd0, 0x00, 0x5a, 0x55, 0x06, 0x55, + 0x05, 0x51, 0x55, 0x04, 0x57, 0x0e, 0x58, 0x03, 0x51, 0x58, 0x60, + 0xd4, 0x3e, 0x57, 0x54, 0x12, 0x3e, 0x57, 0x54, 0x13, 0x50, 0x03, + 0x08, 0x5a, 0x57, 0x06, 0x57, 0x0e, 0x08, 0x51, 0x57, 0x08, 0x7c, + 0x17, 0xdc, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x57, 0x54, 0x15, + 0x51, 0x58, 0x54, 0x14, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x8b, + 0x7c, 0x1a, 0x33, 0x06, 0x57, 0x79, 0x7c, 0x1a, 0x6a, 0x7c, 0x19, + 0x2a, 0x51, 0x57, 0x01, 0x61, 0x7c, 0x1a, 0x33, 0x51, 0x57, 0x01, + 0x69, 0x7c, 0x1a, 0x33, 0x06, 0x57, 0x71, 0x7c, 0x1a, 0x6a, 0x77, + 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf7, 0x38, 0xea, 0x20, 0x7f, 0x10, + 0x4f, 0x38, 0x16, 0x10, 0x57, 0x09, 0x50, 0x01, 0x7c, 0x08, 0x94, + 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x10, 0x08, 0x57, 0xc2, 0x28, + 0x53, 0x58, 0x18, 0x75, 0x09, 0x00, 0x28, 0x53, 0x57, 0x20, 0x10, + 0x51, 0x58, 0x08, 0x51, 0x57, 0x20, 0x7c, 0x09, 0xd9, 0x20, 0x10, + 0x57, 0x0e, 0x50, 0x01, 0x7c, 0x08, 0x94, 0x20, 0x62, 0xd0, 0x00, + 0x3c, 0xa8, 0x01, 0xb0, 0x0b, 0x51, 0x24, 0x53, 0x30, 0x51, 0x25, + 0x53, 0x31, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x9b, 0x53, 0x24, + 0x51, 0x9c, 0x53, 0x25, 0x10, 0x50, 0x00, 0x7c, 0x09, 0x5a, 0x20, + 0x56, 0x0d, 0x00, 0x80, 0x67, 0x56, 0x00, 0x00, 0x80, 0x5b, 0x62, + 0xd0, 0x00, 0x3c, 0xa8, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x57, + 0x55, 0x58, 0x00, 0x06, 0x57, 0x9b, 0x7c, 0x19, 0xf9, 0x52, 0x00, + 0x53, 0x55, 0x55, 0x56, 0x00, 0x06, 0x55, 0x24, 0x7c, 0x1a, 0xc3, + 0x10, 0x52, 0x00, 0x7c, 0x09, 0x5a, 0x20, 0x10, 0x7c, 0x05, 0xe5, + 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, 0x7c, 0x19, 0x52, + 0x52, 0x0d, 0x7c, 0x1a, 0xb7, 0x02, 0x57, 0x53, 0x57, 0x51, 0x56, + 0x0a, 0x58, 0x53, 0x58, 0x7c, 0x1a, 0x85, 0x06, 0x55, 0x8b, 0x0e, + 0x56, 0x00, 0x51, 0x56, 0x7c, 0x19, 0xe3, 0x7c, 0x1a, 0x05, 0x77, + 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xa2, 0x77, 0x0d, 0x3d, 0x0d, 0x03, + 0xcf, 0x96, 0x56, 0x00, 0x00, 0x81, 0x06, 0x7c, 0x19, 0x47, 0x7c, + 0x19, 0x9e, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x0e, 0x3e, + 0x57, 0x54, 0x0f, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x55, + 0x55, 0x06, 0x55, 0x56, 0x00, 0x55, 0x52, 0x00, 0x55, 0x51, 0x00, + 0x3c, 0x56, 0x00, 0xb0, 0x06, 0x3c, 0x55, 0x00, 0xa0, 0x1a, 0x70, + 0xfb, 0x6e, 0x56, 0x6e, 0x55, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, + 0x57, 0x04, 0x52, 0x51, 0x58, 0x0c, 0x51, 0x65, 0x57, 0x6b, 0x58, + 0x8f, 0xde, 0x5f, 0x57, 0x52, 0x5f, 0x58, 0x51, 0x62, 0xd0, 0x00, + 0x5a, 0x55, 0x06, 0x55, 0x03, 0x51, 0x55, 0x04, 0x57, 0x0e, 0x58, + 0x03, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x10, 0x3e, 0x57, + 0x54, 0x11, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x55, 0x55, + 0x06, 0x55, 0x56, 0x00, 0x55, 0x52, 0x00, 0x55, 0x51, 0x00, 0x3c, + 0x56, 0x00, 0xb0, 0x06, 0x3c, 0x55, 0x00, 0xa0, 0x1a, 0x70, 0xfb, + 0x6e, 0x56, 0x6e, 0x55, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x57, + 0x04, 0x52, 0x51, 0x58, 0x0c, 0x51, 0x65, 0x57, 0x6b, 0x58, 0x8f, + 0xde, 0x5f, 0x57, 0x52, 0x5f, 0x58, 0x51, 0x62, 0xd0, 0x00, 0x5a, + 0x55, 0x06, 0x55, 0x05, 0x51, 0x55, 0x04, 0x57, 0x0e, 0x58, 0x03, + 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x12, 0x3e, 0x57, 0x54, + 0x13, 0x50, 0x03, 0x08, 0x5a, 0x57, 0x06, 0x57, 0x0e, 0x08, 0x51, + 0x57, 0x08, 0x7c, 0x17, 0xdc, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, + 0x57, 0x54, 0x15, 0x51, 0x58, 0x54, 0x14, 0x7c, 0x19, 0x2a, 0x51, + 0x57, 0x01, 0x8b, 0x7c, 0x1a, 0x33, 0x06, 0x57, 0x79, 0x7c, 0x1a, + 0x6a, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x61, 0x7c, 0x1a, 0x33, + 0x51, 0x57, 0x01, 0x69, 0x7c, 0x1a, 0x33, 0x06, 0x57, 0x71, 0x7c, + 0x1a, 0x6a, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf7, 0x56, 0x00, + 0x00, 0x80, 0x19, 0x7c, 0x19, 0x47, 0x06, 0x57, 0x24, 0x7c, 0x19, + 0xf9, 0x52, 0x00, 0x53, 0x55, 0x55, 0x56, 0x00, 0x06, 0x55, 0x30, + 0x7c, 0x1a, 0xc3, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xe4, 0x38, + 0xea, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x62, 0xd0, 0x00, 0x52, + 0xfc, 0x01, 0x02, 0x53, 0x57, 0x52, 0xfb, 0x09, 0x00, 0x7c, 0x1a, + 0x12, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x55, 0x52, 0xfb, 0x7c, 0x19, + 0xee, 0x12, 0x57, 0x51, 0x56, 0x1a, 0x58, 0xc0, 0x6f, 0x52, 0xfc, + 0x53, 0x57, 0x52, 0xfb, 0x7c, 0x1a, 0x12, 0x52, 0xfc, 0x01, 0x02, + 0x53, 0x55, 0x52, 0xfb, 0x7c, 0x19, 0xee, 0x12, 0x57, 0x51, 0x56, + 0x1a, 0x58, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, 0x1a, 0x51, + 0x54, 0x00, 0x3e, 0x57, 0x54, 0x01, 0x80, 0xb3, 0x62, 0xd0, 0x00, + 0x52, 0xfc, 0x01, 0x04, 0x53, 0x57, 0x52, 0xfb, 0x09, 0x00, 0x7c, + 0x1a, 0x12, 0x52, 0xfc, 0x53, 0x55, 0x52, 0xfb, 0x60, 0xd4, 0x3e, + 0x55, 0x53, 0x56, 0x3e, 0x55, 0x12, 0x57, 0x51, 0x56, 0x1a, 0x58, + 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x04, 0x7c, 0x1a, 0x51, 0x54, 0x00, + 0x3e, 0x57, 0x54, 0x01, 0x80, 0x7e, 0x62, 0xd0, 0x00, 0x52, 0xfc, + 0x53, 0x57, 0x52, 0xfb, 0x7c, 0x1a, 0x7a, 0x80, 0x70, 0x62, 0xd0, + 0x00, 0x52, 0xfc, 0x53, 0x57, 0x52, 0xfb, 0x7c, 0x1a, 0x12, 0x52, + 0xfc, 0x01, 0x04, 0x53, 0x55, 0x52, 0xfb, 0x7c, 0x19, 0xee, 0x12, + 0x57, 0x51, 0x56, 0x1a, 0x58, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x04, + 0x7c, 0x1a, 0x51, 0x54, 0x00, 0x3e, 0x57, 0x54, 0x01, 0x80, 0x42, + 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x01, 0x02, 0x53, 0x57, 0x52, 0xfb, + 0x09, 0x00, 0x7c, 0x1a, 0x12, 0x52, 0xfc, 0x53, 0x55, 0x52, 0xfb, + 0x60, 0xd4, 0x3e, 0x55, 0x53, 0x56, 0x3e, 0x55, 0x12, 0x57, 0x51, + 0x56, 0x1a, 0x58, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, 0x1a, + 0x51, 0x54, 0x00, 0x3e, 0x57, 0x54, 0x01, 0x80, 0x0d, 0x62, 0xd0, + 0x00, 0x52, 0xfc, 0x53, 0x57, 0x52, 0xfb, 0x7c, 0x1a, 0x7a, 0x62, + 0xd0, 0x00, 0x52, 0x01, 0x53, 0x57, 0x52, 0x00, 0x53, 0x58, 0x38, + 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x05, 0x62, 0xd0, 0x00, 0x55, + 0xaf, 0x00, 0x56, 0x00, 0x00, 0x80, 0x38, 0x62, 0xd0, 0x00, 0x3c, + 0xa8, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, + 0x06, 0x57, 0x9b, 0x7c, 0x19, 0xf9, 0x52, 0x00, 0x53, 0x55, 0x55, + 0x56, 0x00, 0x06, 0x55, 0x24, 0x7c, 0x1a, 0xc3, 0x10, 0x52, 0x00, + 0x7c, 0x09, 0x5a, 0x20, 0x10, 0x7c, 0x05, 0xe5, 0x62, 0xd0, 0x00, + 0x20, 0x39, 0x00, 0xbf, 0xee, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, + 0xc5, 0x56, 0x00, 0x00, 0x82, 0x86, 0x62, 0xd0, 0x00, 0x3c, 0xae, + 0x02, 0xa0, 0x9f, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x79, 0x7c, + 0x19, 0x36, 0x06, 0x57, 0x8b, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, 0x44, + 0xd0, 0x16, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x79, 0x7c, 0x19, + 0x36, 0x06, 0x57, 0x8b, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, 0xdb, 0x80, + 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x8b, + 0x7c, 0x19, 0x36, 0x06, 0x57, 0x79, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, + 0xdb, 0x50, 0x5e, 0x13, 0x02, 0x50, 0x01, 0x1b, 0x01, 0xc0, 0x4e, + 0x62, 0xd0, 0x00, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x71, 0x7c, + 0x19, 0x36, 0x06, 0x57, 0x8b, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, 0x44, + 0xd0, 0x16, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x71, 0x7c, 0x19, + 0x36, 0x06, 0x57, 0x8b, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, 0xe8, 0x80, + 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x8b, + 0x7c, 0x19, 0x36, 0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, + 0xe8, 0x50, 0x5e, 0x13, 0x04, 0x50, 0x01, 0x1b, 0x03, 0xd0, 0x08, + 0x62, 0xd0, 0x00, 0x76, 0xaf, 0x81, 0xde, 0x62, 0xd0, 0x00, 0x7c, + 0x19, 0x2a, 0x51, 0x57, 0x01, 0x8b, 0x7c, 0x19, 0x36, 0x06, 0x57, + 0x71, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, 0x44, 0xd0, 0x5a, 0x7c, 0x19, + 0x2a, 0x7c, 0x1a, 0x1d, 0x06, 0x55, 0x01, 0x0e, 0x56, 0x00, 0x7c, + 0x1a, 0x05, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x8b, 0x7c, 0x19, + 0x36, 0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, 0x7c, 0x1a, 0x44, 0xd0, + 0xb4, 0x7c, 0x19, 0x2a, 0x7c, 0x1a, 0x1d, 0x06, 0x55, 0x01, 0x0e, + 0x56, 0x00, 0x7c, 0x1a, 0x05, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, + 0x8b, 0x7c, 0x19, 0x36, 0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, 0x7c, + 0x1a, 0x44, 0xd0, 0x90, 0x7c, 0x19, 0x2a, 0x7c, 0x1a, 0x1d, 0x06, + 0x55, 0x01, 0x0e, 0x56, 0x00, 0x7c, 0x1a, 0x05, 0x80, 0x7f, 0x62, + 0xd0, 0x00, 0x7c, 0x19, 0x2a, 0x51, 0x57, 0x01, 0x8b, 0x7c, 0x19, + 0x36, 0x06, 0x57, 0x71, 0x7c, 0x19, 0xf9, 0x3e, 0x57, 0x12, 0x55, + 0x51, 0x58, 0x1a, 0x56, 0xd0, 0x62, 0x7c, 0x19, 0x2a, 0x7c, 0x1a, + 0x1d, 0x16, 0x55, 0x01, 0x1e, 0x56, 0x00, 0x7c, 0x1a, 0x05, 0x97, + 0xf8, 0x40, 0x51, 0x57, 0x01, 0x8b, 0x97, 0xfd, 0x40, 0x06, 0x57, + 0x71, 0x7c, 0x19, 0xf9, 0x3e, 0x57, 0x12, 0x55, 0x51, 0x58, 0x1a, + 0x56, 0xd0, 0x39, 0x97, 0xde, 0x40, 0x7c, 0x1a, 0x1d, 0x16, 0x55, + 0x01, 0x1e, 0x56, 0x00, 0x7c, 0x1a, 0x05, 0x97, 0xcf, 0x40, 0x51, + 0x57, 0x01, 0x8b, 0x97, 0xd4, 0x40, 0x06, 0x57, 0x71, 0x7c, 0x19, + 0xf9, 0x3e, 0x57, 0x12, 0x55, 0x51, 0x58, 0x1a, 0x56, 0xd0, 0x10, + 0x97, 0xb5, 0x40, 0x7c, 0x1a, 0x1d, 0x16, 0x55, 0x01, 0x1e, 0x56, + 0x00, 0x7c, 0x1a, 0x05, 0x62, 0xd0, 0x00, 0x97, 0xa3, 0x40, 0x51, + 0x57, 0x01, 0x69, 0x97, 0xa8, 0x40, 0x06, 0x57, 0x61, 0x0e, 0x58, + 0x00, 0x7c, 0x1a, 0x05, 0x97, 0x90, 0x40, 0x51, 0x57, 0x01, 0x71, + 0x97, 0x95, 0x40, 0x06, 0x57, 0x69, 0x0e, 0x58, 0x00, 0x7c, 0x1a, + 0x05, 0x97, 0x7d, 0x40, 0x51, 0x57, 0x01, 0x8b, 0x97, 0x82, 0x40, + 0x06, 0x57, 0x71, 0x0e, 0x58, 0x00, 0x7c, 0x1a, 0x05, 0x10, 0x52, + 0x00, 0x7c, 0x06, 0x29, 0x20, 0x62, 0xd0, 0x00, 0x97, 0x60, 0x40, + 0x51, 0x57, 0x01, 0x8b, 0x97, 0x65, 0x40, 0x06, 0x57, 0x79, 0x7c, + 0x19, 0xf9, 0x7c, 0x1a, 0x44, 0xd0, 0x25, 0x52, 0x00, 0x53, 0x57, + 0x55, 0x58, 0x00, 0x06, 0x57, 0x97, 0x0e, 0x58, 0x00, 0x51, 0x58, + 0x60, 0xd4, 0x3e, 0x57, 0x7a, 0x57, 0x53, 0x56, 0x06, 0x56, 0x01, + 0x51, 0x58, 0x60, 0xd5, 0x51, 0x56, 0x3f, 0x57, 0x80, 0x0a, 0x97, + 0x44, 0x40, 0x06, 0x57, 0x97, 0x7c, 0x1a, 0xcf, 0x97, 0x3b, 0x40, + 0x06, 0x57, 0x97, 0x97, 0xe7, 0x40, 0x50, 0x05, 0x3a, 0x58, 0xd0, + 0x58, 0x97, 0x0f, 0x40, 0x51, 0x57, 0x01, 0x79, 0x53, 0x55, 0x51, + 0x58, 0x09, 0x00, 0x53, 0x56, 0x06, 0x57, 0x8b, 0x97, 0xcc, 0x40, + 0x3e, 0x57, 0x53, 0x57, 0x51, 0x56, 0x60, 0xd4, 0x3e, 0x55, 0x53, + 0x54, 0x3e, 0x55, 0x16, 0x55, 0x02, 0x02, 0x57, 0x53, 0x57, 0x51, + 0x54, 0x0a, 0x58, 0x53, 0x58, 0x70, 0xfb, 0x6e, 0x58, 0x6e, 0x57, + 0x51, 0x56, 0x60, 0xd5, 0x51, 0x58, 0x3f, 0x55, 0x51, 0x57, 0x3f, + 0x55, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x06, 0x57, 0x97, + 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x57, + 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcd, 0x77, 0x62, 0xd0, 0x00, 0x3c, + 0xae, 0x02, 0xb1, 0x10, 0x56, 0x00, 0x00, 0x81, 0x06, 0x62, 0xd0, + 0x00, 0x96, 0xa1, 0x40, 0x51, 0x57, 0x01, 0x8b, 0x96, 0xa6, 0x40, + 0x06, 0x57, 0x38, 0x0e, 0x58, 0x00, 0x97, 0x6c, 0x40, 0x96, 0x8e, + 0x40, 0x51, 0x57, 0x01, 0x79, 0x96, 0x93, 0x40, 0x06, 0x57, 0x3c, + 0x0e, 0x58, 0x00, 0x97, 0x59, 0x40, 0x96, 0x7b, 0x40, 0x51, 0x57, + 0x01, 0x79, 0x96, 0x80, 0x40, 0x51, 0x57, 0x01, 0x8b, 0x53, 0x53, + 0x51, 0x58, 0x97, 0xe9, 0x40, 0x51, 0x55, 0x12, 0x53, 0x51, 0x56, + 0x1a, 0x54, 0xd0, 0x21, 0x97, 0xb7, 0x40, 0x51, 0x55, 0x01, 0x79, + 0x53, 0x53, 0x51, 0x56, 0x97, 0xd1, 0x40, 0x06, 0x55, 0x8b, 0x97, + 0x7d, 0x40, 0x12, 0x53, 0x54, 0x02, 0x51, 0x56, 0x1a, 0x54, 0x54, + 0x01, 0x80, 0x07, 0x56, 0x02, 0x00, 0x56, 0x01, 0x00, 0x62, 0xd0, + 0x00, 0x06, 0x57, 0x34, 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd5, + 0x52, 0x01, 0x3f, 0x57, 0x52, 0x02, 0x3f, 0x57, 0x96, 0x21, 0x40, + 0x51, 0x57, 0x01, 0x8b, 0x96, 0x26, 0x40, 0x06, 0x57, 0x38, 0x0e, + 0x58, 0x00, 0x96, 0xec, 0x40, 0x96, 0x0e, 0x40, 0x51, 0x57, 0x01, + 0x79, 0x96, 0x13, 0x40, 0x06, 0x57, 0x3c, 0x0e, 0x58, 0x00, 0x96, + 0xd9, 0x40, 0x95, 0xfb, 0x40, 0x51, 0x57, 0x01, 0x79, 0x96, 0x00, + 0x40, 0x51, 0x57, 0x01, 0x8b, 0x53, 0x53, 0x51, 0x58, 0x97, 0x69, + 0x40, 0x51, 0x55, 0x12, 0x53, 0x51, 0x56, 0x1a, 0x54, 0xd0, 0x21, + 0x97, 0x37, 0x40, 0x51, 0x55, 0x01, 0x79, 0x53, 0x53, 0x51, 0x56, + 0x97, 0x51, 0x40, 0x06, 0x55, 0x8b, 0x96, 0xfd, 0x40, 0x12, 0x53, + 0x54, 0x04, 0x51, 0x56, 0x1a, 0x54, 0x54, 0x03, 0x80, 0x07, 0x56, + 0x04, 0x00, 0x56, 0x03, 0x00, 0x62, 0xd0, 0x00, 0x06, 0x57, 0x34, + 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd5, 0x52, 0x03, 0x3f, 0x57, + 0x52, 0x04, 0x3f, 0x57, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf7, + 0x62, 0xd0, 0x00, 0x3c, 0xae, 0x02, 0xa0, 0x18, 0x3c, 0xaf, 0x00, + 0xa0, 0x13, 0x50, 0x01, 0x08, 0x50, 0x2c, 0x08, 0x90, 0x0e, 0x38, + 0xfe, 0x7c, 0x0a, 0xf9, 0x10, 0x7c, 0x07, 0xe5, 0x20, 0x38, 0xfb, + 0x20, 0x7f, 0x10, 0x4f, 0x80, 0x02, 0x40, 0x62, 0xd0, 0x00, 0x52, + 0xfc, 0x53, 0x57, 0x52, 0xfb, 0x53, 0x58, 0x51, 0x57, 0x11, 0x01, + 0x54, 0xfc, 0x51, 0x58, 0x19, 0x00, 0x54, 0xfb, 0x3c, 0x58, 0x00, + 0xbf, 0xe4, 0x3c, 0x57, 0x00, 0xbf, 0xdf, 0x20, 0x7f, 0x10, 0x7c, + 0x04, 0xaf, 0x7c, 0x04, 0x8c, 0x20, 0x7f, 0x10, 0x7c, 0x04, 0xab, + 0x7c, 0x04, 0x88, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x42, 0x12, + 0x7e, 0x50, 0x00, 0x1a, 0x7d, 0xd0, 0x0f, 0x51, 0x43, 0x12, 0x80, + 0x50, 0x00, 0x1a, 0x7f, 0xd0, 0x05, 0x50, 0x0f, 0x80, 0x17, 0x62, + 0xd0, 0x00, 0x51, 0x80, 0x12, 0x7e, 0x51, 0x7f, 0x1a, 0x7d, 0xd0, + 0x05, 0x50, 0x00, 0x80, 0x06, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x7f, + 0x10, 0x4f, 0x38, 0x05, 0x62, 0xd0, 0x00, 0x51, 0x7e, 0x54, 0x02, + 0x51, 0x7d, 0x54, 0x01, 0x56, 0x04, 0x00, 0x56, 0x00, 0x00, 0x56, + 0x03, 0x00, 0x80, 0x61, 0x95, 0x0e, 0x40, 0x06, 0x57, 0x42, 0x0e, + 0x58, 0x00, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x53, 0x57, 0x96, + 0x3b, 0x40, 0x06, 0x55, 0x7d, 0x0e, 0x56, 0x00, 0x51, 0x56, 0x95, + 0x8e, 0x40, 0x51, 0x57, 0x12, 0x55, 0x50, 0x00, 0x1a, 0x56, 0xd0, + 0x03, 0x77, 0x03, 0x62, 0xd0, 0x00, 0x94, 0xc3, 0x40, 0x06, 0x57, + 0x7d, 0x95, 0x8c, 0x40, 0x3e, 0x57, 0x53, 0x57, 0x52, 0x02, 0x12, + 0x57, 0x52, 0x01, 0x1a, 0x58, 0xd0, 0x1a, 0x94, 0xac, 0x40, 0x06, + 0x57, 0x7d, 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, + 0x54, 0x01, 0x3e, 0x57, 0x54, 0x02, 0x52, 0x00, 0x54, 0x04, 0x77, + 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x9c, 0x50, 0x01, 0x3b, 0x03, 0xd0, + 0x08, 0x62, 0xd0, 0x00, 0x50, 0x0f, 0x80, 0x06, 0x52, 0x04, 0x62, + 0xd0, 0x00, 0x38, 0xfb, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x70, + 0xfe, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0xf0, 0x51, 0xad, 0x01, 0x01, + 0x53, 0x58, 0x51, 0x2a, 0x2a, 0x58, 0x53, 0x2a, 0x71, 0x01, 0x62, + 0xe3, 0x38, 0x10, 0x7c, 0x05, 0xe5, 0x62, 0xd0, 0x00, 0x20, 0x41, + 0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, + 0x7c, 0x05, 0xe5, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x58, 0x47, 0x58, + 0x20, 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x01, 0x08, + 0x9e, 0xb6, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, + 0x11, 0x0a, 0x52, 0x00, 0x19, 0x04, 0xcf, 0xd7, 0x56, 0x01, 0x00, + 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xe5, 0x62, 0xd0, + 0x00, 0x20, 0x53, 0x58, 0x47, 0x58, 0x20, 0xb0, 0x03, 0x80, 0x1a, + 0x50, 0x00, 0x08, 0x50, 0x01, 0x08, 0x9e, 0x84, 0x38, 0xfe, 0x77, + 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, 0xce, 0x52, 0x00, 0x19, + 0x00, 0xcf, 0xd7, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, + 0x4f, 0x38, 0x02, 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0xf0, + 0x51, 0xad, 0x01, 0x09, 0x53, 0x58, 0x51, 0x2a, 0x2a, 0x58, 0x53, + 0x2a, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x05, 0xe5, 0x62, + 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, 0x00, + 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xe5, 0x62, 0xd0, 0x00, 0x20, + 0x53, 0x58, 0x47, 0x58, 0x20, 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, + 0x08, 0x50, 0x01, 0x08, 0x9e, 0x23, 0x38, 0xfe, 0x77, 0x01, 0x0f, + 0x00, 0x00, 0x52, 0x01, 0x11, 0x0a, 0x52, 0x00, 0x19, 0x04, 0xcf, + 0xd7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, + 0x05, 0xe5, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x58, 0x47, 0x58, 0x20, + 0xb0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x01, 0x08, 0x9d, + 0xf1, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, + 0xce, 0x52, 0x00, 0x19, 0x00, 0xcf, 0xd7, 0x43, 0x00, 0x08, 0x38, + 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x04, 0x62, 0xd0, 0x00, 0x51, + 0x2a, 0x21, 0xf0, 0x54, 0x00, 0x51, 0x2d, 0x54, 0x01, 0x3d, 0x00, + 0x10, 0xb0, 0x2a, 0x55, 0xa5, 0x00, 0x3c, 0xa9, 0x01, 0xb0, 0x09, + 0x55, 0x93, 0x00, 0x55, 0x94, 0x00, 0x80, 0x0f, 0x62, 0xd0, 0x00, + 0x3c, 0xac, 0x01, 0xa0, 0x07, 0x55, 0x93, 0x00, 0x55, 0x94, 0x00, + 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x81, 0x7d, + 0x3d, 0x00, 0x20, 0xb0, 0x18, 0x62, 0xd0, 0x00, 0x55, 0xa5, 0x01, + 0x55, 0xa6, 0x00, 0x55, 0x93, 0x08, 0x55, 0x94, 0x08, 0x56, 0x00, + 0x00, 0x26, 0x2a, 0x0f, 0x81, 0x61, 0x3d, 0x00, 0x30, 0xb0, 0x0f, + 0x62, 0xd0, 0x00, 0x55, 0xae, 0x00, 0x56, 0x00, 0x00, 0x26, 0x2a, + 0x0f, 0x81, 0x4e, 0x3d, 0x00, 0x40, 0xb0, 0x0f, 0x62, 0xd0, 0x00, + 0x55, 0xae, 0x02, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x81, 0x3b, + 0x3d, 0x00, 0x50, 0xb0, 0xa7, 0x52, 0x01, 0x54, 0x03, 0x56, 0x02, + 0x00, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x01, 0xa0, 0x21, + 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x02, 0xa0, 0x28, 0x3d, + 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x04, 0xa0, 0x36, 0x3d, 0x02, + 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x08, 0xa0, 0x48, 0x80, 0x62, 0x62, + 0xd0, 0x00, 0x55, 0xa8, 0x01, 0x51, 0x2f, 0x29, 0x80, 0x53, 0x2f, + 0x7c, 0x0c, 0x8c, 0x80, 0x51, 0x62, 0xd0, 0x00, 0x51, 0x2b, 0x53, + 0x42, 0x51, 0x2b, 0x53, 0x43, 0x51, 0x2b, 0x53, 0x2e, 0x51, 0x2c, + 0x53, 0x0e, 0x55, 0x0d, 0x00, 0x80, 0x39, 0x62, 0xd0, 0x00, 0x51, + 0x2b, 0x53, 0x2f, 0x3c, 0xa8, 0x00, 0xa0, 0x09, 0x51, 0x2f, 0x29, + 0x80, 0x53, 0x2f, 0x80, 0x25, 0x62, 0xd0, 0x00, 0x26, 0x2f, 0x7f, + 0x80, 0x1d, 0x62, 0xd0, 0x00, 0x55, 0xa8, 0x00, 0x26, 0x2f, 0x7f, + 0x51, 0x9b, 0x53, 0x24, 0x51, 0x24, 0x53, 0x30, 0x51, 0x9c, 0x53, + 0x25, 0x51, 0x25, 0x53, 0x31, 0x7c, 0x0c, 0x8c, 0x56, 0x00, 0x00, + 0x62, 0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x55, 0x2b, 0x06, 0x55, 0x2c, + 0x05, 0x55, 0x2d, 0x00, 0x80, 0x90, 0x3d, 0x00, 0x60, 0xb0, 0x0f, + 0x62, 0xd0, 0x00, 0x55, 0xa9, 0x01, 0x56, 0x00, 0x00, 0x26, 0x2a, + 0x0f, 0x80, 0x7d, 0x3d, 0x00, 0x70, 0xb0, 0x0f, 0x62, 0xd0, 0x00, + 0x55, 0xa9, 0x00, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x80, 0x6a, + 0x3d, 0x00, 0x80, 0xb0, 0x65, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, + 0x26, 0x2a, 0x0f, 0x9c, 0x9f, 0x10, 0x7c, 0x08, 0xd8, 0x7c, 0x05, + 0xfb, 0x20, 0x70, 0xfe, 0x71, 0x10, 0x41, 0x00, 0xf7, 0x41, 0x01, + 0xf7, 0x70, 0xcf, 0x62, 0xda, 0x00, 0x71, 0x10, 0x41, 0xdc, 0xfe, + 0x70, 0xcf, 0x43, 0x01, 0x08, 0x43, 0x00, 0x08, 0x50, 0x00, 0x08, + 0x50, 0x1e, 0x08, 0x9c, 0x4b, 0x38, 0xfe, 0x71, 0x01, 0x43, 0xe0, + 0x10, 0x43, 0xff, 0x08, 0x70, 0xfe, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x10, 0x7c, 0x08, 0x07, 0x7c, 0x05, 0xaf, 0x7c, 0x05, + 0xf0, 0x20, 0x93, 0x0b, 0x40, 0x62, 0xe3, 0x38, 0x56, 0x00, 0x00, + 0x62, 0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x38, 0xfc, 0x20, 0x7f, 0x62, + 0xd0, 0x00, 0x3c, 0xa5, 0x00, 0xa0, 0x13, 0x9c, 0x38, 0x62, 0xd0, + 0x00, 0x3c, 0xa6, 0x00, 0xb0, 0x33, 0x55, 0xa6, 0x01, 0x7c, 0x0a, + 0xf9, 0x80, 0x2b, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x93, 0xd0, + 0x08, 0x10, 0x7c, 0x04, 0xaf, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, + 0xab, 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x94, 0xd0, 0x08, + 0x10, 0x7c, 0x04, 0x8c, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0x88, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x03, 0x56, 0x02, 0x00, 0x56, 0x01, + 0x00, 0x56, 0x00, 0x00, 0x80, 0x3e, 0x62, 0xd0, 0x00, 0x91, 0x3a, + 0x40, 0x52, 0xfc, 0x04, 0x57, 0x52, 0xfb, 0x0c, 0x58, 0x51, 0x58, + 0x60, 0xd4, 0x3e, 0x57, 0x53, 0x58, 0x3e, 0x57, 0x53, 0x57, 0x52, + 0x02, 0x12, 0x57, 0x52, 0x01, 0x1a, 0x58, 0xd0, 0x18, 0x91, 0x19, + 0x40, 0x52, 0xfc, 0x04, 0x57, 0x52, 0xfb, 0x0c, 0x58, 0x51, 0x58, + 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x01, 0x3e, 0x57, 0x54, 0x02, 0x77, + 0x00, 0x52, 0x00, 0x3b, 0xfa, 0xcf, 0xbe, 0x62, 0xd0, 0x00, 0x52, + 0x02, 0x53, 0x57, 0x52, 0x01, 0x53, 0x58, 0x38, 0xfd, 0x20, 0x7f, + 0x10, 0x7c, 0x04, 0x3a, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x8b, 0x08, 0x7c, 0x04, 0x43, 0x38, 0xfd, 0x20, 0x10, + 0x50, 0x04, 0x08, 0x50, 0x00, 0x08, 0x50, 0x79, 0x08, 0x7c, 0x04, + 0x43, 0x38, 0xfd, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, 0x08, + 0x50, 0x7d, 0x08, 0x7c, 0x04, 0x43, 0x38, 0xfd, 0x20, 0x10, 0x50, + 0x00, 0x7c, 0x03, 0x5e, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x5e, + 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x5e, 0x20, 0x7f, 0x62, 0xd0, + 0x00, 0x55, 0xa8, 0x00, 0x55, 0xa9, 0x01, 0x10, 0x7c, 0x04, 0xaf, + 0x7c, 0x04, 0x8c, 0x20, 0x9b, 0x3e, 0x62, 0xe3, 0x38, 0x71, 0x10, + 0x43, 0x00, 0x08, 0x41, 0x01, 0xf7, 0x70, 0xcf, 0x43, 0x00, 0x08, + 0x62, 0xd0, 0x00, 0x55, 0x2a, 0x08, 0x55, 0x2b, 0x06, 0x55, 0x2c, + 0x05, 0x55, 0x2e, 0x19, 0x55, 0x2f, 0x03, 0x55, 0x30, 0x56, 0x55, + 0x31, 0x45, 0x55, 0x32, 0x00, 0x55, 0x33, 0x00, 0x3c, 0xa8, 0x00, + 0xa0, 0x09, 0x51, 0x2f, 0x29, 0x80, 0x53, 0x2f, 0x80, 0x07, 0x62, + 0xd0, 0x00, 0x26, 0x2f, 0x7f, 0x10, 0x50, 0x00, 0x08, 0x50, 0x2a, + 0x08, 0x50, 0x06, 0x08, 0x50, 0x16, 0x08, 0x7c, 0x06, 0x02, 0x38, + 0xfc, 0x7c, 0x05, 0xaf, 0x7c, 0x05, 0xf0, 0x20, 0x91, 0x9a, 0x40, + 0x10, 0x7c, 0x08, 0x07, 0x7c, 0x07, 0x8d, 0x20, 0x7c, 0x0c, 0x8c, + 0x80, 0x22, 0x62, 0xe3, 0x38, 0x7c, 0x0f, 0x9d, 0x10, 0x7c, 0x07, + 0xcb, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xa0, 0x09, 0x7c, 0x0a, + 0x27, 0x7c, 0x0a, 0x51, 0x80, 0x04, 0x7c, 0x0a, 0xba, 0x9c, 0xb4, + 0x9e, 0x71, 0x8f, 0xde, 0x8f, 0xff, 0x52, 0x00, 0x53, 0x57, 0x55, + 0x58, 0x00, 0x65, 0x57, 0x6b, 0x58, 0x7f, 0x53, 0x55, 0x51, 0x58, + 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x55, 0x53, 0x56, 0x3e, 0x55, 0x53, + 0x55, 0x7f, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, + 0x00, 0x7f, 0x52, 0x00, 0x53, 0x57, 0x55, 0x58, 0x00, 0x55, 0x55, + 0x06, 0x55, 0x56, 0x00, 0x55, 0x52, 0x00, 0x55, 0x51, 0x00, 0x3c, + 0x56, 0x00, 0xb0, 0x06, 0x3c, 0x55, 0x00, 0xa0, 0x1a, 0x70, 0xfb, + 0x6e, 0x56, 0x6e, 0x55, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x57, + 0x04, 0x52, 0x51, 0x58, 0x0c, 0x51, 0x65, 0x57, 0x6b, 0x58, 0x8f, + 0xde, 0x5f, 0x57, 0x52, 0x5f, 0x58, 0x51, 0x62, 0xd0, 0x00, 0x5a, + 0x55, 0x06, 0x55, 0x01, 0x51, 0x55, 0x04, 0x57, 0x0e, 0x58, 0x03, + 0x7f, 0x55, 0x55, 0x06, 0x55, 0x56, 0x00, 0x55, 0x52, 0x00, 0x55, + 0x51, 0x00, 0x3c, 0x56, 0x00, 0xb0, 0x06, 0x3c, 0x55, 0x00, 0xa0, + 0x1a, 0x70, 0xfb, 0x6e, 0x56, 0x6e, 0x55, 0xd0, 0x0c, 0x62, 0xd0, + 0x00, 0x51, 0x57, 0x04, 0x52, 0x51, 0x58, 0x0c, 0x51, 0x65, 0x57, + 0x6b, 0x58, 0x8f, 0xde, 0x5f, 0x57, 0x52, 0x5f, 0x58, 0x51, 0x62, + 0xd0, 0x00, 0x5a, 0x55, 0x06, 0x55, 0x01, 0x51, 0x55, 0x04, 0x57, + 0x0e, 0x58, 0x03, 0x7f, 0x60, 0xd4, 0x3e, 0x55, 0x53, 0x56, 0x3e, + 0x55, 0x53, 0x55, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x55, 0x53, + 0x56, 0x3e, 0x55, 0x7f, 0x0e, 0x58, 0x00, 0x51, 0x58, 0x60, 0xd4, + 0x3e, 0x57, 0x53, 0x58, 0x7f, 0x51, 0x58, 0x60, 0xd5, 0x51, 0x56, + 0x3f, 0x57, 0x51, 0x55, 0x3f, 0x57, 0x7f, 0x60, 0xd4, 0x3e, 0x57, + 0x53, 0x58, 0x3e, 0x57, 0x53, 0x57, 0x7f, 0x06, 0x57, 0x8b, 0x0e, + 0x58, 0x00, 0x51, 0x58, 0x60, 0xd4, 0x3e, 0x57, 0x53, 0x56, 0x3e, + 0x57, 0x16, 0x57, 0x02, 0x53, 0x55, 0x7f, 0x53, 0x55, 0x51, 0x58, + 0x09, 0x00, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x55, 0x52, 0x15, 0x3f, + 0x55, 0x7f, 0x3e, 0x57, 0x53, 0x57, 0x51, 0x55, 0x12, 0x57, 0x51, + 0x56, 0x1a, 0x58, 0x7f, 0x53, 0x57, 0x52, 0xfb, 0x09, 0x00, 0x60, + 0xd4, 0x3e, 0x57, 0x7f, 0x0e, 0x56, 0x00, 0x51, 0x56, 0x60, 0xd4, + 0x3e, 0x55, 0x53, 0x56, 0x3e, 0x55, 0x7f, 0x0e, 0x58, 0x00, 0x51, + 0x58, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x57, 0x52, 0x15, 0x3f, 0x57, + 0x7f, 0x60, 0xd4, 0x3e, 0x57, 0x54, 0x00, 0x3e, 0x57, 0x54, 0x01, + 0x7f, 0x52, 0x00, 0x53, 0x55, 0x55, 0x56, 0x00, 0x65, 0x55, 0x6b, + 0x56, 0x7f, 0x71, 0x10, 0x41, 0x04, 0xfe, 0x41, 0x05, 0xfe, 0x41, + 0x04, 0xfd, 0x41, 0x05, 0xfd, 0x70, 0xcf, 0x43, 0x04, 0x01, 0x43, + 0x04, 0x02, 0x71, 0x01, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x53, + 0x53, 0x54, 0x3e, 0x53, 0x53, 0x53, 0x7f, 0x53, 0x55, 0x55, 0x56, + 0x00, 0x65, 0x55, 0x6b, 0x56, 0x51, 0x55, 0x7f, 0x0e, 0x56, 0x00, + 0x51, 0x56, 0x60, 0xd5, 0x51, 0x58, 0x3f, 0x55, 0x7f, 0x0e, 0x58, + 0x00, 0x51, 0x58, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x57, 0x7f, 0x3e, + 0x57, 0x12, 0x55, 0x54, 0x02, 0x51, 0x58, 0x1a, 0x56, 0x54, 0x01, + 0x7f, 0x3e, 0x57, 0x12, 0x55, 0x54, 0x04, 0x51, 0x58, 0x1a, 0x56, + 0x54, 0x03, 0x7f, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x49, 0x00, 0x08, + 0x00, 0x59, 0x00, 0x20, 0x00, 0x81, 0x00, 0x0a, 0x00, 0x8f, 0x00, + 0x04, 0x00, 0x93, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, 0x97, 0x00, + 0x04, 0x00, 0x9b, 0x02, 0x56, 0x45, 0x00, 0x9d, 0x00, 0x08, 0x00, + 0xa5, 0x06, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0xab, 0x00, + 0x05, 0x00, 0xb0, 0x01, 0x03, 0xff, 0x00, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypressbln/touchkey_fw_NA.h b/drivers/input/keyboard/cypressbln/touchkey_fw_NA.h new file mode 100644 index 0000000..2667cf6 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/touchkey_fw_NA.h @@ -0,0 +1,747 @@ +unsigned char firmware_data[] = { + 0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, + 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x05, 0x47, 0x7e, 0x7e, 0x30, + 0x30, 0x30, 0x7d, 0x06, 0x93, 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, + 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, + 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x40, 0x71, 0x10, 0x62, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, 0x38, 0x5d, + 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, 0xfa, 0x01, 0x40, 0x4f, 0x5b, + 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, + 0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, 0xef, 0x18, 0x60, + 0xd5, 0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, + 0x02, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, 0xfe, + 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, 0x03, 0x50, 0x00, 0x4e, + 0x62, 0xd3, 0x03, 0x62, 0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, + 0x00, 0x71, 0xc0, 0x7c, 0x03, 0x01, 0x62, 0xd0, 0x00, 0x50, 0x02, + 0x57, 0xff, 0x08, 0x28, 0x53, 0x79, 0x18, 0x75, 0x09, 0x00, 0x28, + 0x4b, 0x51, 0x79, 0x80, 0x04, 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, + 0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, 0x75, 0x09, 0x00, + 0x08, 0x28, 0x53, 0x79, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0xa0, + 0x1c, 0x53, 0x78, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, 0x79, + 0x47, 0x79, 0xff, 0xb0, 0x06, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x18, + 0x7a, 0x78, 0xbf, 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, + 0x28, 0x53, 0x78, 0x50, 0x00, 0x3f, 0x79, 0x47, 0x79, 0xff, 0xb0, + 0x08, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x78, 0xbf, + 0xef, 0x18, 0x8f, 0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, + 0x10, 0x62, 0xe0, 0x03, 0x70, 0xef, 0x62, 0xe2, 0x00, 0x7c, 0x0a, + 0x86, 0x8f, 0xff, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x61, 0x00, 0xfd, 0x00, 0xcd, 0x00, + 0xce, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa0, 0x00, 0xa1, 0x80, 0xa2, + 0xc0, 0xa3, 0x0c, 0xa8, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x7c, 0x33, + 0x7a, 0x00, 0x7b, 0x00, 0x79, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, + 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, + 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, + 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, + 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, + 0x00, 0x4f, 0x00, 0xca, 0x20, 0xd6, 0x44, 0xcf, 0x00, 0xcb, 0x00, + 0xc8, 0x00, 0xcc, 0x00, 0xc9, 0x00, 0xd7, 0x00, 0xa9, 0x00, 0x2b, + 0x00, 0xb0, 0x00, 0xb3, 0x02, 0xb6, 0x00, 0xb2, 0x00, 0xb5, 0x00, + 0xb8, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0x33, 0x00, 0x34, + 0x00, 0x35, 0x00, 0xff, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, + 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0xdc, 0x00, + 0xe2, 0x00, 0xdd, 0x00, 0xd8, 0x02, 0xd9, 0xb4, 0xda, 0x00, 0xdb, + 0x00, 0xdf, 0x00, 0x29, 0x00, 0x30, 0x00, 0xbd, 0x00, 0xff, 0x70, + 0xef, 0x62, 0x00, 0x08, 0x71, 0x10, 0x62, 0x00, 0x98, 0x62, 0x01, + 0x02, 0x70, 0xef, 0x62, 0x04, 0x03, 0x71, 0x10, 0x62, 0x04, 0x00, + 0x62, 0x05, 0xbc, 0x70, 0xef, 0x62, 0x08, 0x00, 0x71, 0x10, 0x62, + 0x08, 0x28, 0x62, 0x09, 0x00, 0x70, 0xef, 0x62, 0x0c, 0x00, 0x71, + 0x10, 0x62, 0x0c, 0x00, 0x62, 0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, + 0x00, 0x71, 0x10, 0x62, 0x10, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, + 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, 0x62, 0x09, 0x00, 0x62, 0x0d, + 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, 0x7f, 0x1d, 0x3e, 0x55, 0x02, + 0x08, 0x55, 0x03, 0x03, 0x55, 0x04, 0x00, 0x7c, 0x03, 0x11, 0x7c, + 0x02, 0xaa, 0x7f, 0x10, 0x70, 0xef, 0x50, 0x00, 0x67, 0x50, 0x02, + 0x57, 0x00, 0x7c, 0x03, 0x2c, 0x50, 0x01, 0x67, 0x50, 0x02, 0x57, + 0x83, 0x7c, 0x03, 0x2c, 0x70, 0xef, 0x20, 0x7f, 0x38, 0x02, 0x10, + 0x08, 0x4f, 0x56, 0xfc, 0x00, 0xd0, 0x04, 0x56, 0xfc, 0x01, 0x18, + 0x20, 0x70, 0xef, 0x62, 0xe3, 0x00, 0x10, 0x08, 0x28, 0x39, 0xff, + 0xa0, 0x1f, 0x4f, 0x48, 0xfc, 0x01, 0xa0, 0x03, 0x71, 0x10, 0x54, + 0xfd, 0x18, 0x20, 0x75, 0x09, 0x00, 0x10, 0x08, 0x28, 0x4f, 0x59, + 0xfd, 0x61, 0x00, 0x18, 0x20, 0x75, 0x09, 0x00, 0x8f, 0xd7, 0x38, + 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x62, 0xd0, 0x00, 0x2e, 0x02, 0x08, 0x51, 0x02, 0x60, 0x00, 0x71, + 0x10, 0x41, 0x01, 0xf7, 0x43, 0x00, 0x08, 0x70, 0xef, 0x7f, 0x62, + 0xd0, 0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, 0x21, 0xf8, + 0x29, 0x00, 0x70, 0xfe, 0x60, 0xe0, 0x70, 0xef, 0x4b, 0x4b, 0x4b, + 0x4b, 0x51, 0x02, 0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, + 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, + 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, + 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, + 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, + 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, + 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, + 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, + 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, + 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, + 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x47, 0x00, + 0x00, 0x49, 0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, 0x01, 0x79, + 0xbf, 0xfe, 0x18, 0x71, 0x10, 0x60, 0xe0, 0x70, 0xef, 0x71, 0x01, + 0x7f, 0x08, 0x67, 0x67, 0x67, 0x67, 0x21, 0x0f, 0xff, 0x2b, 0x9f, + 0x4e, 0x18, 0x21, 0x0f, 0xff, 0x24, 0x9f, 0x47, 0x7f, 0x08, 0x10, + 0x28, 0xa0, 0x0b, 0x9f, 0x3f, 0x20, 0x18, 0x75, 0xdf, 0xf5, 0x74, + 0x8f, 0xf2, 0x38, 0xfe, 0x7f, 0x52, 0x00, 0xa0, 0x08, 0x10, 0x9f, + 0x2d, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, + 0x0d, 0x9f, 0x20, 0x50, 0x0a, 0x9f, 0x1c, 0x7f, 0x70, 0xbf, 0x62, + 0xd3, 0x03, 0x4f, 0x52, 0xfb, 0xa0, 0x15, 0x7b, 0xfb, 0x52, 0xfc, + 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, 0x05, 0x4f, 0x62, 0xd3, + 0x03, 0x77, 0xfd, 0x8f, 0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x3d, + 0xfa, 0x00, 0xb0, 0x06, 0x3d, 0xfb, 0x00, 0xa0, 0x18, 0x10, 0x52, + 0xfc, 0x59, 0xfd, 0x28, 0x9e, 0xe6, 0x20, 0x07, 0xfd, 0x01, 0x0f, + 0xfc, 0x00, 0x17, 0xfb, 0x01, 0x1f, 0xfa, 0x00, 0x8f, 0xe0, 0x7f, + 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, + 0xa0, 0x06, 0x26, 0x04, 0xdf, 0x80, 0x04, 0x2e, 0x04, 0x20, 0x51, + 0x04, 0x60, 0x08, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, + 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, + 0x29, 0x00, 0xa0, 0x06, 0x26, 0x04, 0xf7, 0x80, 0x04, 0x2e, 0x04, + 0x08, 0x51, 0x04, 0x60, 0x08, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, + 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x02, 0xef, 0x80, 0x04, + 0x2e, 0x02, 0x10, 0x51, 0x02, 0x60, 0x00, 0x70, 0x3f, 0x71, 0xc0, + 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, + 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x02, 0x7f, + 0x80, 0x04, 0x2e, 0x02, 0x80, 0x51, 0x02, 0x60, 0x00, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, 0x70, + 0x3f, 0x71, 0x80, 0x5d, 0xd3, 0x08, 0x5d, 0xd0, 0x08, 0x62, 0xd0, + 0x00, 0x51, 0x08, 0x60, 0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, + 0xa0, 0x09, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, 0x80, 0x08, 0x49, + 0xd7, 0x20, 0xa0, 0x03, 0x80, 0xac, 0x51, 0x05, 0x21, 0x0e, 0xe0, + 0x01, 0x80, 0x11, 0x80, 0x6d, 0x80, 0x7f, 0x80, 0x4d, 0x80, 0x9c, + 0x80, 0x9a, 0x80, 0x98, 0x80, 0x96, 0x80, 0x9d, 0x5d, 0xd8, 0x21, + 0xfe, 0x39, 0x40, 0xa0, 0x06, 0x62, 0xd7, 0x00, 0x80, 0x90, 0x49, + 0xd8, 0x01, 0xb0, 0x15, 0x55, 0x0c, 0x02, 0x26, 0x07, 0x00, 0x26, + 0x06, 0x00, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x62, 0xd7, 0x10, + 0x80, 0x77, 0x55, 0x0c, 0x01, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x06, + 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, 0x60, + 0xd8, 0x76, 0x07, 0x62, 0xd7, 0x14, 0x80, 0x5b, 0x51, 0x0a, 0x78, + 0x3a, 0x07, 0xc0, 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, + 0x60, 0xd8, 0x76, 0x07, 0x2e, 0x05, 0x20, 0x60, 0xd8, 0x62, 0xd7, + 0x04, 0x80, 0x3f, 0x5d, 0xd8, 0x3a, 0x0a, 0xd0, 0x2b, 0xa0, 0x29, + 0x53, 0x07, 0x53, 0x06, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x80, + 0x18, 0x51, 0x0b, 0x78, 0x3a, 0x07, 0xc0, 0x16, 0x51, 0x09, 0x02, + 0x07, 0x5c, 0x5d, 0xd8, 0x54, 0x00, 0x2e, 0x05, 0x10, 0x76, 0x07, + 0x80, 0x01, 0x62, 0xd7, 0x10, 0x80, 0x0f, 0x62, 0xd7, 0x00, 0x80, + 0x0a, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, 0x55, 0x0c, 0x00, 0x18, + 0x60, 0xd0, 0x18, 0x60, 0xd3, 0x20, 0x18, 0x7e, 0x62, 0xd0, 0x00, + 0x71, 0x10, 0x41, 0x04, 0xfc, 0x43, 0x05, 0x03, 0x70, 0xef, 0x26, + 0x03, 0xfc, 0x51, 0x03, 0x60, 0x04, 0x55, 0x0c, 0x00, 0x90, 0x28, + 0x90, 0x2d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x50, 0x00, 0x53, 0x06, + 0x71, 0x10, 0x43, 0x04, 0x03, 0x43, 0x05, 0x03, 0x70, 0xef, 0x2e, + 0x03, 0x03, 0x51, 0x03, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, 0x51, + 0x05, 0x21, 0xb0, 0x26, 0x05, 0x4f, 0x7f, 0x41, 0xe0, 0x7f, 0x43, + 0xe0, 0x80, 0x7f, 0x43, 0xd6, 0x31, 0x7f, 0x62, 0xd0, 0x00, 0x4f, + 0x52, 0xfd, 0x53, 0x0a, 0x52, 0xfc, 0x53, 0x0b, 0x52, 0xfb, 0x53, + 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, + 0x5d, 0xa4, 0x04, 0x1b, 0x5d, 0xa5, 0x0c, 0x1a, 0x55, 0x1c, 0x01, + 0x18, 0x7e, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x53, 0x1e, + 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x7b, 0x62, 0xd3, 0x00, 0x13, + 0x60, 0x62, 0xd3, 0x00, 0x54, 0x68, 0x62, 0xd3, 0x00, 0x52, 0x7a, + 0x62, 0xd3, 0x00, 0x1b, 0x5f, 0x62, 0xd3, 0x00, 0x54, 0x67, 0x48, + 0x67, 0x80, 0xb0, 0x33, 0x3d, 0x67, 0x00, 0xb0, 0x7b, 0x51, 0x0d, + 0x3b, 0x68, 0xc0, 0x75, 0x52, 0x68, 0x58, 0x1e, 0x01, 0x00, 0x6d, + 0x62, 0xd3, 0x00, 0x05, 0x4e, 0xc0, 0x09, 0x51, 0x0f, 0x3b, 0x4e, + 0xd0, 0x12, 0xa0, 0x10, 0x56, 0x4e, 0x00, 0x5b, 0x64, 0x5c, 0x62, + 0xd3, 0x00, 0x07, 0x60, 0x01, 0x0f, 0x5f, 0x00, 0x80, 0x41, 0x3d, + 0x67, 0xff, 0xb0, 0x09, 0x50, 0xff, 0x12, 0x0e, 0x3b, 0x68, 0xc0, + 0x20, 0x62, 0xd3, 0x00, 0x56, 0x68, 0x00, 0x56, 0x67, 0x00, 0x5b, + 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x5b, 0x78, 0xd0, 0x03, 0x50, + 0x00, 0x54, 0x5b, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, + 0xd3, 0x00, 0x52, 0x7b, 0x62, 0xd3, 0x00, 0x54, 0x60, 0x62, 0xd3, + 0x00, 0x52, 0x7a, 0x62, 0xd3, 0x00, 0x54, 0x5f, 0x51, 0x1e, 0x64, + 0x5c, 0x62, 0xd3, 0x00, 0x56, 0x68, 0x00, 0x56, 0x67, 0x00, 0x5b, + 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x12, 0x54, 0x5b, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x08, + 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x52, 0x53, 0x19, 0x55, 0x18, 0x00, + 0x18, 0x08, 0x90, 0x7e, 0x62, 0xd3, 0x00, 0x23, 0x56, 0xb0, 0x2c, + 0x51, 0x10, 0x04, 0x19, 0x0e, 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, + 0xd3, 0x00, 0x52, 0x68, 0x12, 0x19, 0x52, 0x67, 0x1a, 0x18, 0xc0, + 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x57, 0x78, 0x54, + 0x57, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, 0x51, + 0x10, 0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, + 0x00, 0x52, 0x68, 0x12, 0x19, 0x52, 0x67, 0x1a, 0x18, 0xc0, 0x0e, + 0x5b, 0x67, 0x90, 0x31, 0x62, 0xd3, 0x00, 0x2d, 0x56, 0x50, 0x01, + 0x80, 0x24, 0x5b, 0x67, 0x08, 0x90, 0x23, 0x73, 0x62, 0xd3, 0x00, + 0x25, 0x56, 0x62, 0xd3, 0x00, 0x20, 0x51, 0x11, 0x54, 0x57, 0x50, + 0x00, 0x80, 0x0d, 0x5b, 0x67, 0x90, 0x0d, 0x73, 0x62, 0xd3, 0x00, + 0x25, 0x56, 0x50, 0x00, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x67, + 0x67, 0x67, 0x5c, 0x18, 0x21, 0x07, 0xf0, 0x01, 0x7f, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x70, 0xbf, 0x70, 0xbf, 0x62, + 0xd3, 0x00, 0x50, 0x04, 0x78, 0x08, 0x5c, 0x56, 0x52, 0x32, 0x18, + 0x78, 0xdf, 0xf8, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x91, 0x99, + 0x70, 0xbf, 0x18, 0x08, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x7b, + 0x62, 0xd3, 0x00, 0x54, 0x60, 0x62, 0xd3, 0x00, 0x52, 0x7a, 0x62, + 0xd3, 0x00, 0x54, 0x5f, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, 0x71, + 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x14, 0x00, 0x50, 0x04, 0x78, + 0x08, 0x9f, 0x0e, 0x39, 0x01, 0xb0, 0x04, 0x55, 0x14, 0x01, 0x18, + 0x78, 0xdf, 0xf3, 0x51, 0x14, 0x7f, 0x50, 0x04, 0x78, 0x08, 0x9e, + 0x3e, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x98, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0xd8, 0xd9, 0xda, 0xdb, 0xdf, 0x00, 0x01, + 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x70, 0xbf, 0x62, 0xd0, + 0x00, 0x62, 0xd3, 0x00, 0x57, 0x00, 0x56, 0x56, 0x00, 0x79, 0xdf, + 0xfb, 0x62, 0xd3, 0x00, 0x57, 0x03, 0x50, 0x02, 0x54, 0x57, 0x79, + 0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x0a, 0x57, 0x03, 0x54, 0x5b, + 0x79, 0xdf, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x55, 0x0d, 0x28, 0x55, + 0x0e, 0x05, 0x55, 0x0f, 0x0f, 0x55, 0x10, 0x01, 0x55, 0x11, 0x02, + 0x55, 0x12, 0x0a, 0x55, 0x22, 0x05, 0x55, 0x1f, 0x64, 0x43, 0x61, + 0x0d, 0x57, 0x00, 0x50, 0x02, 0x90, 0x95, 0x50, 0x05, 0xff, 0x98, + 0x29, 0x00, 0x60, 0xa9, 0x62, 0xa0, 0x08, 0x43, 0xa2, 0x04, 0x62, + 0xa3, 0x70, 0x43, 0x7a, 0x01, 0x43, 0xaa, 0x02, 0x43, 0xdf, 0x01, + 0x50, 0x01, 0x57, 0x09, 0x90, 0x20, 0x90, 0x55, 0x57, 0x01, 0x50, + 0xb3, 0x91, 0x44, 0x50, 0x01, 0x57, 0x0e, 0x90, 0x12, 0x90, 0x47, + 0x7f, 0x53, 0x22, 0xff, 0x67, 0x29, 0x00, 0x60, 0xa9, 0x51, 0x21, + 0x58, 0x20, 0x90, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, 0x03, 0x53, + 0x21, 0x64, 0x64, 0x64, 0x64, 0x64, 0x29, 0x80, 0x60, 0xa1, 0x5b, + 0x78, 0x21, 0x0f, 0x29, 0x08, 0x74, 0x53, 0x20, 0x12, 0x22, 0x02, + 0x21, 0x5c, 0x50, 0x00, 0x53, 0x1d, 0x53, 0x23, 0x29, 0x01, 0x79, + 0xa0, 0x08, 0x64, 0x6b, 0x1d, 0x6b, 0x23, 0x8f, 0xf5, 0x60, 0xb5, + 0x51, 0x1d, 0x60, 0xb4, 0x7f, 0x50, 0x04, 0x78, 0x08, 0x90, 0x0f, + 0x90, 0x41, 0x18, 0x78, 0xdf, 0xf8, 0x7f, 0x01, 0x04, 0x01, 0x10, + 0x01, 0x20, 0x01, 0x80, 0x64, 0x5c, 0xff, 0xf4, 0x4b, 0x74, 0xff, + 0xf0, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, 0x5b, 0x64, 0x64, + 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, + 0xff, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, 0x18, + 0xfe, 0xef, 0x5c, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, + 0x7f, 0x62, 0xd0, 0x00, 0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, + 0xfe, 0xd9, 0x5c, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, 0x70, 0xef, + 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x22, 0x1d, 0x61, + 0x01, 0x36, 0x1d, 0xff, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, + 0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x1e, 0x50, 0x00, + 0x53, 0x1a, 0x53, 0x1b, 0x51, 0x1e, 0x5c, 0x62, 0xd3, 0x00, 0x52, + 0x24, 0x53, 0x1f, 0x43, 0xa0, 0x01, 0x51, 0x1f, 0x60, 0xfd, 0x41, + 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x7a, 0x9f, 0x81, 0x58, 0x23, 0x55, + 0x1c, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x43, 0xb3, 0x01, + 0x51, 0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, 0x9f, 0x5f, + 0x9f, 0x91, 0x43, 0xa3, 0x20, 0x41, 0xa0, 0xfe, 0x62, 0xfd, 0x00, + 0x50, 0xff, 0x4c, 0x1b, 0x14, 0x1b, 0x51, 0x20, 0x11, 0x08, 0xfe, + 0x66, 0x4c, 0x1a, 0x1c, 0x1a, 0xd0, 0x07, 0x55, 0x1a, 0x00, 0x55, + 0x1b, 0x00, 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x1b, + 0x54, 0x7b, 0x51, 0x1a, 0x54, 0x7a, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x08, 0x9f, 0x86, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x70, 0xbf, 0x62, + 0xd0, 0x00, 0x53, 0x29, 0x5a, 0x28, 0x55, 0x1e, 0x03, 0x62, 0xd3, + 0x00, 0x58, 0x1e, 0x56, 0x24, 0x80, 0x55, 0x2b, 0x08, 0x55, 0x2a, + 0x80, 0x51, 0x1e, 0x9f, 0x63, 0x51, 0x1e, 0x9f, 0x5f, 0x70, 0xbf, + 0x58, 0x1e, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x3a, 0x29, 0x51, 0x1a, + 0x1a, 0x28, 0xd0, 0x06, 0x51, 0x2a, 0x73, 0x25, 0x24, 0x68, 0x2a, + 0x26, 0x2a, 0x7f, 0x51, 0x2a, 0x2d, 0x24, 0x7a, 0x2b, 0xbf, 0xd6, + 0x7a, 0x1e, 0xdf, 0xc4, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x10, 0x4f, + 0x38, 0x02, 0x62, 0xd0, 0x00, 0x55, 0xb9, 0x00, 0x10, 0x7c, 0x05, + 0x28, 0x7c, 0x05, 0x05, 0x7c, 0x04, 0xe2, 0x7c, 0x04, 0xbf, 0x20, + 0x7c, 0x16, 0x44, 0x10, 0x7c, 0x03, 0x7c, 0x20, 0x43, 0x00, 0x08, + 0x62, 0xd0, 0x00, 0x55, 0x2c, 0x08, 0x55, 0x2d, 0x0e, 0x55, 0x2e, + 0x08, 0x55, 0x30, 0x32, 0x55, 0x31, 0x04, 0x10, 0x50, 0x00, 0x08, + 0x50, 0x2c, 0x08, 0x50, 0x05, 0x08, 0x50, 0x22, 0x08, 0x7c, 0x06, + 0x7a, 0x38, 0xfc, 0x7c, 0x06, 0x2e, 0x7c, 0x06, 0x6f, 0x20, 0x71, + 0x10, 0x41, 0x04, 0xfc, 0x41, 0x05, 0xfc, 0x71, 0x01, 0x10, 0x70, + 0xcf, 0x7c, 0x08, 0x7f, 0x20, 0x62, 0xd0, 0x00, 0x55, 0xb4, 0x00, + 0x93, 0x17, 0x10, 0x7c, 0x08, 0x05, 0x20, 0x80, 0xc7, 0x7c, 0x17, + 0xfe, 0x95, 0xa1, 0x62, 0xd0, 0x00, 0x3c, 0xbd, 0x01, 0xb0, 0x09, + 0x50, 0x00, 0x08, 0x7c, 0x1a, 0xb0, 0x38, 0xff, 0x10, 0x7c, 0x08, + 0x43, 0x20, 0x39, 0x00, 0xa0, 0x7c, 0x62, 0xd0, 0x00, 0x3c, 0xb1, + 0x00, 0xb0, 0x74, 0x51, 0xaf, 0x11, 0x4a, 0x51, 0xae, 0x19, 0x01, + 0xd0, 0x12, 0x7c, 0x16, 0x62, 0x39, 0xe1, 0xa0, 0x16, 0x62, 0xd0, + 0x00, 0x76, 0xaf, 0x0e, 0xae, 0x00, 0x80, 0x0c, 0x62, 0xd0, 0x00, + 0x55, 0xaf, 0x00, 0x55, 0xae, 0x00, 0x90, 0x81, 0x62, 0xd0, 0x00, + 0x3c, 0xbb, 0xf0, 0xd0, 0x03, 0x76, 0xbb, 0x62, 0xd0, 0x00, 0x51, + 0x31, 0x21, 0x0f, 0x53, 0x79, 0x51, 0xbb, 0x3a, 0x79, 0xb0, 0x5f, + 0x7c, 0x16, 0x62, 0x62, 0xd0, 0x00, 0x53, 0xbc, 0x3c, 0xbc, 0xe1, + 0xa0, 0x20, 0x3c, 0xb5, 0x01, 0xb0, 0x04, 0x55, 0xb0, 0x01, 0x62, + 0xd0, 0x00, 0x55, 0xb5, 0x00, 0x55, 0xb8, 0x01, 0x7c, 0x16, 0xf7, + 0x62, 0xd0, 0x00, 0x55, 0xb2, 0x01, 0x55, 0xb3, 0x03, 0x80, 0x33, + 0x62, 0xd0, 0x00, 0x55, 0xbb, 0x00, 0x80, 0x2b, 0x62, 0xd0, 0x00, + 0x55, 0xaf, 0x00, 0x55, 0xae, 0x00, 0x55, 0xb0, 0x00, 0x55, 0xb7, + 0x00, 0x55, 0xb8, 0x00, 0x3c, 0xb2, 0x01, 0xb0, 0x14, 0x7a, 0xb3, + 0x3c, 0xb3, 0x00, 0xb0, 0x0d, 0x7c, 0x17, 0x7f, 0x62, 0xd0, 0x00, + 0x55, 0xb2, 0x00, 0x55, 0xbb, 0x00, 0x7c, 0x18, 0xe4, 0x8f, 0x39, + 0x38, 0xfe, 0x20, 0x8f, 0xff, 0x10, 0x4f, 0x38, 0x24, 0x62, 0xd0, + 0x00, 0x3c, 0xb9, 0x00, 0xb0, 0x05, 0x51, 0xaa, 0x53, 0x24, 0x56, + 0x19, 0x00, 0x81, 0x5d, 0x56, 0x00, 0x00, 0x81, 0x51, 0x62, 0xd0, + 0x00, 0x3c, 0xb9, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x78, 0x55, + 0x79, 0x00, 0x06, 0x78, 0xaa, 0x7c, 0x1c, 0x33, 0x52, 0x00, 0x53, + 0x76, 0x55, 0x77, 0x00, 0x06, 0x76, 0x24, 0x7c, 0x1c, 0xc9, 0x10, + 0x52, 0x00, 0x7c, 0x09, 0xb9, 0x20, 0x10, 0x7c, 0x06, 0x64, 0x20, + 0x39, 0x00, 0xbf, 0xf1, 0x62, 0xd0, 0x00, 0x3c, 0xb9, 0x01, 0xb0, + 0xcf, 0x52, 0x00, 0x54, 0x23, 0x56, 0x22, 0x00, 0x3d, 0x22, 0x00, + 0xb0, 0x06, 0x3d, 0x23, 0x00, 0xa0, 0x21, 0x3d, 0x22, 0x00, 0xb0, + 0x06, 0x3d, 0x23, 0x01, 0xa0, 0x38, 0x3d, 0x22, 0x00, 0xb0, 0x06, + 0x3d, 0x23, 0x02, 0xa0, 0x66, 0x3d, 0x22, 0x00, 0xb0, 0x06, 0x3d, + 0x23, 0x03, 0xa0, 0x89, 0x80, 0x9e, 0x62, 0xd0, 0x00, 0x51, 0x7a, + 0x08, 0x51, 0x7b, 0x08, 0x50, 0x00, 0x08, 0x50, 0x01, 0x08, 0x7c, + 0x1b, 0xd0, 0x38, 0xfc, 0x51, 0x71, 0x62, 0xd0, 0x00, 0x53, 0x7b, + 0x51, 0x70, 0x53, 0x7a, 0x80, 0x7d, 0x62, 0xd0, 0x00, 0x51, 0x7c, + 0x08, 0x51, 0x7d, 0x08, 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x7c, + 0x1b, 0xd0, 0x38, 0xfc, 0x51, 0x71, 0x53, 0x78, 0x51, 0x70, 0x53, + 0x79, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x79, 0x08, 0x51, + 0x78, 0x08, 0x7c, 0x1b, 0x8c, 0x18, 0x62, 0xd0, 0x00, 0x53, 0x7d, + 0x18, 0x53, 0x7c, 0x38, 0xfe, 0x80, 0x45, 0x62, 0xd0, 0x00, 0x51, + 0x7f, 0x08, 0x51, 0x7e, 0x53, 0x79, 0x18, 0x53, 0x78, 0x65, 0x78, + 0x6b, 0x79, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x79, 0x08, + 0x51, 0x78, 0x08, 0x7c, 0x1b, 0x8c, 0x18, 0x62, 0xd0, 0x00, 0x53, + 0x7f, 0x18, 0x53, 0x7e, 0x38, 0xfe, 0x80, 0x18, 0x62, 0xd0, 0x00, + 0x51, 0x80, 0x08, 0x51, 0x81, 0x08, 0x50, 0x00, 0x08, 0x50, 0x01, + 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x7c, 0x1c, 0x86, 0x62, 0xd0, + 0x00, 0x55, 0x79, 0x03, 0x5a, 0x78, 0x06, 0x78, 0x01, 0x52, 0x00, + 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, + 0x50, 0x06, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x7c, 0x1c, 0x3f, + 0x53, 0x79, 0x52, 0x19, 0x53, 0x76, 0x55, 0x77, 0x00, 0x65, 0x76, + 0x6b, 0x77, 0x7c, 0x1c, 0x6a, 0x53, 0x79, 0x7c, 0x1c, 0xbd, 0x06, + 0x76, 0x7a, 0x0e, 0x77, 0x00, 0x51, 0x77, 0x7c, 0x1c, 0x28, 0x7c, + 0x1c, 0x52, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xce, 0xac, 0x77, 0x19, + 0x3d, 0x19, 0x03, 0xce, 0xa0, 0x56, 0x00, 0x00, 0x80, 0xc0, 0x62, + 0xd0, 0x00, 0x55, 0x79, 0x03, 0x5a, 0x78, 0x06, 0x78, 0x01, 0x52, + 0x00, 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x06, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x7c, 0x1c, + 0x3f, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x1a, 0x3e, 0x78, 0x54, 0x1b, + 0x5a, 0x78, 0x06, 0x78, 0x03, 0x52, 0x00, 0x53, 0x76, 0x50, 0x00, + 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, + 0x1b, 0xd0, 0x38, 0xfc, 0x7c, 0x1c, 0x3f, 0x60, 0xd4, 0x3e, 0x78, + 0x54, 0x1c, 0x3e, 0x78, 0x54, 0x1d, 0x5a, 0x78, 0x06, 0x78, 0x05, + 0x52, 0x00, 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x7c, + 0x1c, 0x3f, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x1e, 0x3e, 0x78, 0x54, + 0x1f, 0x50, 0x03, 0x08, 0x5a, 0x78, 0x06, 0x78, 0x1a, 0x08, 0x51, + 0x78, 0x08, 0x7c, 0x19, 0xe5, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, + 0x78, 0x54, 0x21, 0x51, 0x79, 0x54, 0x20, 0x7c, 0x1c, 0x00, 0x7c, + 0x1c, 0x5f, 0x7c, 0x1c, 0xa2, 0x06, 0x78, 0x5f, 0x7c, 0x1c, 0xad, + 0x7c, 0x1c, 0x00, 0x51, 0x78, 0x01, 0x82, 0x7c, 0x1c, 0x75, 0x51, + 0x78, 0x01, 0x8a, 0x7c, 0x1c, 0x75, 0x06, 0x78, 0x92, 0x7c, 0x1c, + 0xad, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xcf, 0x3d, 0x38, 0xdc, 0x20, + 0x7f, 0x10, 0x4f, 0x38, 0x24, 0x10, 0x57, 0x30, 0x50, 0x00, 0x7c, + 0x0a, 0x38, 0x20, 0x62, 0xd0, 0x00, 0x3c, 0xb9, 0x01, 0xb0, 0x13, + 0x51, 0x24, 0x53, 0x32, 0x51, 0x25, 0x53, 0x33, 0x51, 0x26, 0x53, + 0x34, 0x51, 0x27, 0x53, 0x35, 0x80, 0x14, 0x62, 0xd0, 0x00, 0x51, + 0xaa, 0x53, 0x24, 0x51, 0xab, 0x53, 0x25, 0x51, 0xac, 0x53, 0x26, + 0x51, 0xad, 0x53, 0x27, 0x10, 0x50, 0x00, 0x7c, 0x09, 0xb9, 0x20, + 0x56, 0x19, 0x00, 0x81, 0x5d, 0x56, 0x00, 0x00, 0x81, 0x51, 0x62, + 0xd0, 0x00, 0x3c, 0xb9, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x78, + 0x55, 0x79, 0x00, 0x06, 0x78, 0xaa, 0x7c, 0x1c, 0x33, 0x52, 0x00, + 0x53, 0x76, 0x55, 0x77, 0x00, 0x06, 0x76, 0x24, 0x7c, 0x1c, 0xc9, + 0x10, 0x52, 0x00, 0x7c, 0x09, 0xb9, 0x20, 0x10, 0x7c, 0x06, 0x64, + 0x20, 0x39, 0x00, 0xbf, 0xf1, 0x62, 0xd0, 0x00, 0x3c, 0xb9, 0x01, + 0xb0, 0xcf, 0x52, 0x00, 0x54, 0x23, 0x56, 0x22, 0x00, 0x3d, 0x22, + 0x00, 0xb0, 0x06, 0x3d, 0x23, 0x00, 0xa0, 0x21, 0x3d, 0x22, 0x00, + 0xb0, 0x06, 0x3d, 0x23, 0x01, 0xa0, 0x38, 0x3d, 0x22, 0x00, 0xb0, + 0x06, 0x3d, 0x23, 0x02, 0xa0, 0x66, 0x3d, 0x22, 0x00, 0xb0, 0x06, + 0x3d, 0x23, 0x03, 0xa0, 0x89, 0x80, 0x9e, 0x62, 0xd0, 0x00, 0x51, + 0x7a, 0x08, 0x51, 0x7b, 0x08, 0x50, 0x00, 0x08, 0x50, 0x01, 0x08, + 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x51, 0x71, 0x62, 0xd0, 0x00, 0x53, + 0x7b, 0x51, 0x70, 0x53, 0x7a, 0x80, 0x7d, 0x62, 0xd0, 0x00, 0x51, + 0x7c, 0x08, 0x51, 0x7d, 0x08, 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, + 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x51, 0x71, 0x53, 0x78, 0x51, 0x70, + 0x53, 0x79, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x79, 0x08, + 0x51, 0x78, 0x08, 0x7c, 0x1b, 0x8c, 0x18, 0x62, 0xd0, 0x00, 0x53, + 0x7d, 0x18, 0x53, 0x7c, 0x38, 0xfe, 0x80, 0x45, 0x62, 0xd0, 0x00, + 0x51, 0x7f, 0x08, 0x51, 0x7e, 0x53, 0x79, 0x18, 0x53, 0x78, 0x65, + 0x78, 0x6b, 0x79, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x79, + 0x08, 0x51, 0x78, 0x08, 0x7c, 0x1b, 0x8c, 0x18, 0x62, 0xd0, 0x00, + 0x53, 0x7f, 0x18, 0x53, 0x7e, 0x38, 0xfe, 0x80, 0x18, 0x62, 0xd0, + 0x00, 0x51, 0x80, 0x08, 0x51, 0x81, 0x08, 0x50, 0x00, 0x08, 0x50, + 0x01, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x7c, 0x1c, 0x86, 0x62, + 0xd0, 0x00, 0x55, 0x79, 0x03, 0x5a, 0x78, 0x06, 0x78, 0x01, 0x52, + 0x00, 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x06, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x7c, 0x1c, + 0x3f, 0x53, 0x79, 0x52, 0x19, 0x53, 0x76, 0x55, 0x77, 0x00, 0x65, + 0x76, 0x6b, 0x77, 0x7c, 0x1c, 0x6a, 0x53, 0x79, 0x7c, 0x1c, 0xbd, + 0x06, 0x76, 0x7a, 0x0e, 0x77, 0x00, 0x51, 0x77, 0x7c, 0x1c, 0x28, + 0x7c, 0x1c, 0x52, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xce, 0xac, 0x77, + 0x19, 0x3d, 0x19, 0x03, 0xce, 0xa0, 0x56, 0x00, 0x00, 0x80, 0xc0, + 0x62, 0xd0, 0x00, 0x55, 0x79, 0x03, 0x5a, 0x78, 0x06, 0x78, 0x01, + 0x52, 0x00, 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x7c, + 0x1c, 0x3f, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x1a, 0x3e, 0x78, 0x54, + 0x1b, 0x5a, 0x78, 0x06, 0x78, 0x03, 0x52, 0x00, 0x53, 0x76, 0x50, + 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, + 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x7c, 0x1c, 0x3f, 0x60, 0xd4, 0x3e, + 0x78, 0x54, 0x1c, 0x3e, 0x78, 0x54, 0x1d, 0x5a, 0x78, 0x06, 0x78, + 0x05, 0x52, 0x00, 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, + 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, + 0x7c, 0x1c, 0x3f, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x1e, 0x3e, 0x78, + 0x54, 0x1f, 0x50, 0x03, 0x08, 0x5a, 0x78, 0x06, 0x78, 0x1a, 0x08, + 0x51, 0x78, 0x08, 0x7c, 0x19, 0xe5, 0x38, 0xfd, 0x62, 0xd0, 0x00, + 0x51, 0x78, 0x54, 0x21, 0x51, 0x79, 0x54, 0x20, 0x7c, 0x1c, 0x00, + 0x7c, 0x1c, 0x5f, 0x7c, 0x1c, 0xa2, 0x06, 0x78, 0x5f, 0x7c, 0x1c, + 0xad, 0x7c, 0x1c, 0x00, 0x51, 0x78, 0x01, 0x82, 0x7c, 0x1c, 0x75, + 0x51, 0x78, 0x01, 0x8a, 0x7c, 0x1c, 0x75, 0x06, 0x78, 0x92, 0x7c, + 0x1c, 0xad, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xcf, 0x3d, 0x56, 0x00, + 0x00, 0x80, 0x19, 0x7c, 0x1c, 0x0c, 0x06, 0x78, 0x24, 0x7c, 0x1c, + 0x33, 0x52, 0x00, 0x53, 0x76, 0x55, 0x77, 0x00, 0x06, 0x76, 0x32, + 0x7c, 0x1c, 0xc9, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xcf, 0xe4, 0x38, + 0xdc, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x07, 0x56, 0x02, 0x00, 0x62, + 0xd0, 0x00, 0x55, 0xb1, 0x00, 0x3c, 0xb9, 0x00, 0xb0, 0x05, 0x51, + 0xaa, 0x53, 0x24, 0x10, 0x50, 0x00, 0x7c, 0x09, 0xb9, 0x20, 0x56, + 0x00, 0x00, 0x81, 0x0b, 0x62, 0xd0, 0x00, 0x3c, 0xb9, 0x00, 0xb0, + 0x1b, 0x52, 0x00, 0x53, 0x78, 0x55, 0x79, 0x00, 0x06, 0x78, 0xaa, + 0x7c, 0x1c, 0x33, 0x52, 0x00, 0x53, 0x76, 0x55, 0x77, 0x00, 0x06, + 0x76, 0x24, 0x7c, 0x1c, 0xc9, 0x10, 0x52, 0x00, 0x7c, 0x09, 0xb9, + 0x20, 0x10, 0x7c, 0x06, 0x64, 0x20, 0x39, 0x00, 0xbf, 0xf1, 0x62, + 0xd0, 0x00, 0x3c, 0xb9, 0x01, 0xb0, 0xcf, 0x52, 0x00, 0x54, 0x04, + 0x56, 0x03, 0x00, 0x3d, 0x03, 0x00, 0xb0, 0x06, 0x3d, 0x04, 0x00, + 0xa0, 0x21, 0x3d, 0x03, 0x00, 0xb0, 0x06, 0x3d, 0x04, 0x01, 0xa0, + 0x38, 0x3d, 0x03, 0x00, 0xb0, 0x06, 0x3d, 0x04, 0x02, 0xa0, 0x66, + 0x3d, 0x03, 0x00, 0xb0, 0x06, 0x3d, 0x04, 0x03, 0xa0, 0x89, 0x80, + 0x9e, 0x62, 0xd0, 0x00, 0x51, 0x7a, 0x08, 0x51, 0x7b, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x01, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x51, + 0x71, 0x62, 0xd0, 0x00, 0x53, 0x7b, 0x51, 0x70, 0x53, 0x7a, 0x80, + 0x7d, 0x62, 0xd0, 0x00, 0x51, 0x7c, 0x08, 0x51, 0x7d, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x03, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x51, + 0x71, 0x53, 0x78, 0x51, 0x70, 0x53, 0x79, 0x50, 0x00, 0x08, 0x50, + 0x05, 0x08, 0x51, 0x79, 0x08, 0x51, 0x78, 0x08, 0x7c, 0x1b, 0x8c, + 0x18, 0x62, 0xd0, 0x00, 0x53, 0x7d, 0x18, 0x53, 0x7c, 0x38, 0xfe, + 0x80, 0x45, 0x62, 0xd0, 0x00, 0x51, 0x7f, 0x08, 0x51, 0x7e, 0x53, + 0x79, 0x18, 0x53, 0x78, 0x65, 0x78, 0x6b, 0x79, 0x50, 0x00, 0x08, + 0x50, 0x05, 0x08, 0x51, 0x79, 0x08, 0x51, 0x78, 0x08, 0x7c, 0x1b, + 0x8c, 0x18, 0x62, 0xd0, 0x00, 0x53, 0x7f, 0x18, 0x53, 0x7e, 0x38, + 0xfe, 0x80, 0x18, 0x62, 0xd0, 0x00, 0x51, 0x80, 0x08, 0x51, 0x81, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x01, 0x08, 0x7c, 0x1b, 0xd0, 0x38, + 0xfc, 0x7c, 0x1c, 0x86, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xce, 0xf2, + 0x56, 0x00, 0x00, 0x82, 0xa6, 0x62, 0xd0, 0x00, 0x3c, 0xbd, 0x02, + 0xa0, 0xb1, 0x7c, 0x1c, 0x00, 0x51, 0x78, 0x01, 0x5f, 0x7c, 0x1c, + 0x17, 0x06, 0x78, 0x7a, 0x7c, 0x1c, 0x33, 0x3e, 0x78, 0x53, 0x78, + 0x51, 0x76, 0x12, 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x16, 0x7c, + 0x1c, 0x00, 0x51, 0x78, 0x01, 0x5f, 0x7c, 0x1c, 0x17, 0x06, 0x78, + 0x7a, 0x7c, 0x1c, 0x33, 0x7c, 0x1d, 0x0b, 0x80, 0x17, 0x62, 0xd0, + 0x00, 0x7c, 0x1c, 0x00, 0x51, 0x78, 0x01, 0x7a, 0x7c, 0x1c, 0x17, + 0x06, 0x78, 0x5f, 0x7c, 0x1c, 0x33, 0x7c, 0x1d, 0x0b, 0x50, 0x2c, + 0x13, 0x04, 0x50, 0x01, 0x1b, 0x03, 0xc0, 0x57, 0x62, 0xd0, 0x00, + 0x7c, 0x1c, 0x00, 0x51, 0x78, 0x01, 0x92, 0x7c, 0x1c, 0x17, 0x06, + 0x78, 0x7a, 0x7c, 0x1c, 0x33, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x76, + 0x12, 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x16, 0x7c, 0x1c, 0x00, + 0x51, 0x78, 0x01, 0x92, 0x7c, 0x1c, 0x17, 0x06, 0x78, 0x7a, 0x7c, + 0x1c, 0x33, 0x7c, 0x1c, 0xfe, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x7c, + 0x1c, 0x00, 0x51, 0x78, 0x01, 0x7a, 0x7c, 0x1c, 0x17, 0x06, 0x78, + 0x92, 0x7c, 0x1c, 0x33, 0x7c, 0x1c, 0xfe, 0x50, 0x2c, 0x13, 0x06, + 0x50, 0x01, 0x1b, 0x05, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x76, 0xb1, + 0x81, 0xec, 0x56, 0x01, 0x00, 0x80, 0x61, 0x62, 0xd0, 0x00, 0x7c, + 0x1c, 0x00, 0x51, 0x78, 0x01, 0x7a, 0x7c, 0x1c, 0x17, 0x06, 0x78, + 0x8a, 0x7c, 0x1c, 0x33, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x76, 0x12, + 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x12, 0x7c, 0x1c, 0x00, 0x7c, + 0x1c, 0xd5, 0x06, 0x76, 0x01, 0x0e, 0x77, 0x00, 0x7c, 0x1c, 0x52, + 0x80, 0x2d, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x00, 0x51, 0x78, 0x01, + 0x7a, 0x7c, 0x1c, 0x17, 0x06, 0x78, 0x8a, 0x7c, 0x1c, 0x33, 0x3e, + 0x78, 0x12, 0x76, 0x51, 0x79, 0x1a, 0x77, 0xd0, 0x10, 0x7c, 0x1c, + 0x00, 0x7c, 0x1c, 0xd5, 0x16, 0x76, 0x01, 0x1e, 0x77, 0x00, 0x7c, + 0x1c, 0x52, 0x77, 0x01, 0x3d, 0x01, 0x06, 0xcf, 0x9c, 0x62, 0xd0, + 0x00, 0x7c, 0x1c, 0x00, 0x51, 0x78, 0x01, 0x8a, 0x7c, 0x1c, 0x17, + 0x06, 0x78, 0x82, 0x0e, 0x79, 0x00, 0x7c, 0x1c, 0x52, 0x7c, 0x1c, + 0x00, 0x51, 0x78, 0x01, 0x92, 0x7c, 0x1c, 0x17, 0x06, 0x78, 0x8a, + 0x0e, 0x79, 0x00, 0x7c, 0x1c, 0x52, 0x7c, 0x1c, 0x00, 0x51, 0x78, + 0x01, 0x7a, 0x7c, 0x1c, 0x17, 0x06, 0x78, 0x92, 0x0e, 0x79, 0x00, + 0x7c, 0x1c, 0x52, 0x7c, 0x1c, 0x00, 0x7c, 0x1c, 0x5f, 0x53, 0x77, + 0x7c, 0x1d, 0x32, 0x53, 0x74, 0x08, 0x51, 0x75, 0x53, 0x73, 0x18, + 0x53, 0x72, 0x65, 0x72, 0x6b, 0x73, 0x06, 0x78, 0x8a, 0x7c, 0x1c, + 0x33, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x72, 0x04, 0x78, 0x51, 0x73, + 0x0c, 0x79, 0x51, 0x74, 0x04, 0x78, 0x51, 0x75, 0x0c, 0x79, 0x70, + 0xfb, 0x6e, 0x79, 0x6e, 0x78, 0x7c, 0x1c, 0xeb, 0x10, 0x52, 0x00, + 0x7c, 0x06, 0xa1, 0x20, 0x7c, 0x1c, 0x0c, 0x06, 0x78, 0x52, 0x0e, + 0x79, 0x00, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x53, 0x78, 0x7c, + 0x1c, 0xbd, 0x06, 0x76, 0x67, 0x0e, 0x77, 0x00, 0x51, 0x77, 0x7c, + 0x1c, 0x28, 0x51, 0x78, 0x12, 0x76, 0x50, 0x00, 0x1a, 0x77, 0xd0, + 0x1b, 0x55, 0x79, 0x01, 0x52, 0x00, 0xa0, 0x09, 0x62, 0xd0, 0x00, + 0x65, 0x79, 0x78, 0xbf, 0xf9, 0x62, 0xd0, 0x00, 0x51, 0xb4, 0x2a, + 0x79, 0x53, 0xb4, 0x80, 0x1b, 0x62, 0xd0, 0x00, 0x55, 0x79, 0x01, + 0x52, 0x00, 0xa0, 0x09, 0x62, 0xd0, 0x00, 0x65, 0x79, 0x78, 0xbf, + 0xf9, 0x62, 0xd0, 0x00, 0x51, 0x79, 0x73, 0x24, 0xb4, 0x62, 0xd0, + 0x00, 0x7c, 0x1c, 0x00, 0x51, 0x78, 0x01, 0x7a, 0x7c, 0x1c, 0x17, + 0x06, 0x78, 0x5f, 0x7c, 0x1c, 0x33, 0x3e, 0x78, 0x53, 0x78, 0x51, + 0x76, 0x12, 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x25, 0x52, 0x00, + 0x53, 0x78, 0x55, 0x79, 0x00, 0x06, 0x78, 0xa2, 0x0e, 0x79, 0x00, + 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x7a, 0x78, 0x53, 0x77, 0x06, + 0x77, 0x01, 0x51, 0x79, 0x60, 0xd5, 0x51, 0x77, 0x3f, 0x78, 0x80, + 0x12, 0x97, 0xf7, 0x40, 0x06, 0x78, 0xa2, 0x0e, 0x79, 0x00, 0x51, + 0x79, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x78, 0x97, 0xe6, 0x40, 0x06, + 0x78, 0xa2, 0x7c, 0x1c, 0x33, 0x50, 0x05, 0x3a, 0x79, 0xd0, 0x41, + 0x97, 0xcb, 0x40, 0x51, 0x78, 0x01, 0x5f, 0x53, 0x76, 0x51, 0x79, + 0x09, 0x00, 0x53, 0x77, 0x06, 0x78, 0x7a, 0x97, 0xec, 0x40, 0x3e, + 0x78, 0x53, 0x78, 0x51, 0x77, 0x7c, 0x1d, 0x32, 0x02, 0x78, 0x53, + 0x78, 0x51, 0x75, 0x0a, 0x79, 0x53, 0x79, 0x7c, 0x1c, 0xeb, 0x52, + 0x00, 0x53, 0x78, 0x55, 0x79, 0x00, 0x06, 0x78, 0xa2, 0x0e, 0x79, + 0x00, 0x51, 0x79, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x78, 0x77, 0x00, + 0x3d, 0x00, 0x04, 0xcd, 0x57, 0x56, 0x00, 0x00, 0x81, 0x73, 0x62, + 0xd0, 0x00, 0x3c, 0xb9, 0x01, 0xb0, 0xd9, 0x52, 0x00, 0x54, 0x04, + 0x56, 0x03, 0x00, 0x3d, 0x03, 0x00, 0xb0, 0x06, 0x3d, 0x04, 0x00, + 0xa0, 0x21, 0x3d, 0x03, 0x00, 0xb0, 0x06, 0x3d, 0x04, 0x01, 0xa0, + 0x38, 0x3d, 0x03, 0x00, 0xb0, 0x06, 0x3d, 0x04, 0x02, 0xa0, 0x66, + 0x3d, 0x03, 0x00, 0xb0, 0x06, 0x3d, 0x04, 0x03, 0xa0, 0x8d, 0x80, + 0xbe, 0x62, 0xd0, 0x00, 0x51, 0x7a, 0x08, 0x51, 0x7b, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x01, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x51, + 0x71, 0x62, 0xd0, 0x00, 0x53, 0x3f, 0x51, 0x70, 0x53, 0x3e, 0x80, + 0x9d, 0x62, 0xd0, 0x00, 0x51, 0x7c, 0x08, 0x51, 0x7d, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x05, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, 0x51, + 0x71, 0x53, 0x78, 0x51, 0x70, 0x53, 0x79, 0x50, 0x00, 0x08, 0x50, + 0x03, 0x08, 0x51, 0x79, 0x08, 0x51, 0x78, 0x08, 0x7c, 0x1b, 0x8c, + 0x18, 0x62, 0xd0, 0x00, 0x53, 0x41, 0x18, 0x53, 0x40, 0x38, 0xfe, + 0x80, 0x65, 0x62, 0xd0, 0x00, 0x51, 0x7e, 0x08, 0x51, 0x7f, 0x08, + 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x7c, 0x1b, 0xd0, 0x38, 0xfc, + 0x51, 0x71, 0x53, 0x78, 0x51, 0x70, 0x53, 0x79, 0x70, 0xfb, 0x6e, + 0x79, 0x6e, 0x78, 0x51, 0x78, 0x08, 0x51, 0x79, 0x62, 0xd0, 0x00, + 0x53, 0x42, 0x18, 0x53, 0x43, 0x80, 0x34, 0x62, 0xd0, 0x00, 0x51, + 0x81, 0x08, 0x51, 0x80, 0x53, 0x79, 0x18, 0x53, 0x78, 0x65, 0x78, + 0x6b, 0x79, 0x51, 0x78, 0x08, 0x51, 0x79, 0x53, 0x44, 0x18, 0x53, + 0x45, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x96, 0x9c, 0x40, 0x51, 0x78, + 0x01, 0x7a, 0x96, 0xac, 0x40, 0x06, 0x78, 0x3e, 0x0e, 0x79, 0x00, + 0x96, 0xde, 0x40, 0x62, 0xd0, 0x00, 0x96, 0x86, 0x40, 0x51, 0x78, + 0x01, 0x5f, 0x96, 0x96, 0x40, 0x51, 0x78, 0x01, 0x7a, 0x53, 0x74, + 0x51, 0x79, 0x97, 0x99, 0x40, 0x51, 0x76, 0x12, 0x74, 0x51, 0x77, + 0x1a, 0x75, 0xd0, 0x2b, 0x97, 0x24, 0x40, 0x51, 0x76, 0x01, 0x5f, + 0x53, 0x74, 0x51, 0x77, 0x97, 0x81, 0x40, 0x06, 0x76, 0x7a, 0x0e, + 0x77, 0x00, 0x51, 0x77, 0x60, 0xd4, 0x3e, 0x76, 0x53, 0x77, 0x3e, + 0x76, 0x12, 0x74, 0x54, 0x04, 0x51, 0x77, 0x1a, 0x75, 0x54, 0x03, + 0x80, 0x07, 0x56, 0x04, 0x00, 0x56, 0x03, 0x00, 0x62, 0xd0, 0x00, + 0x06, 0x78, 0x36, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd5, 0x52, + 0x03, 0x3f, 0x78, 0x52, 0x04, 0x3f, 0x78, 0x96, 0x22, 0x40, 0x51, + 0x78, 0x01, 0x5f, 0x96, 0x32, 0x40, 0x06, 0x78, 0x46, 0x0e, 0x79, + 0x00, 0x96, 0x64, 0x40, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xce, 0x8a, + 0x62, 0xd0, 0x00, 0x3c, 0xbd, 0x02, 0xa0, 0x1b, 0x3c, 0xb1, 0x00, + 0xa0, 0x16, 0x55, 0xbb, 0x00, 0x50, 0x75, 0x08, 0x50, 0x30, 0x08, + 0x90, 0x0e, 0x38, 0xfe, 0x7c, 0x0b, 0xc1, 0x10, 0x7c, 0x08, 0x5d, + 0x20, 0x38, 0xf9, 0x20, 0x7f, 0x10, 0x4f, 0x80, 0x02, 0x40, 0x62, + 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x78, 0x52, 0xfb, 0x53, 0x79, 0x51, + 0x78, 0x11, 0x01, 0x54, 0xfc, 0x51, 0x79, 0x19, 0x00, 0x54, 0xfb, + 0x3c, 0x79, 0x00, 0xbf, 0xe4, 0x3c, 0x78, 0x00, 0xbf, 0xdf, 0x20, + 0x7f, 0x10, 0x7c, 0x05, 0x28, 0x7c, 0x05, 0x05, 0x7c, 0x04, 0xe2, + 0x7c, 0x04, 0xbf, 0x20, 0x7f, 0x10, 0x7c, 0x05, 0x24, 0x7c, 0x05, + 0x01, 0x7c, 0x04, 0xde, 0x7c, 0x04, 0xbb, 0x20, 0x7f, 0x10, 0x4f, + 0x38, 0x05, 0x62, 0xd0, 0x00, 0x51, 0x68, 0x54, 0x02, 0x51, 0x67, + 0x54, 0x01, 0x56, 0x04, 0x00, 0x56, 0x00, 0x00, 0x56, 0x03, 0x00, + 0x80, 0x61, 0x95, 0x8e, 0x40, 0x06, 0x78, 0x52, 0x0e, 0x79, 0x00, + 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x53, 0x78, 0x96, 0x2e, 0x40, + 0x06, 0x76, 0x67, 0x0e, 0x77, 0x00, 0x51, 0x77, 0x95, 0x8e, 0x40, + 0x51, 0x78, 0x12, 0x76, 0x50, 0x00, 0x1a, 0x77, 0xd0, 0x03, 0x77, + 0x03, 0x62, 0xd0, 0x00, 0x95, 0x54, 0x40, 0x06, 0x78, 0x67, 0x95, + 0x81, 0x40, 0x3e, 0x78, 0x53, 0x78, 0x52, 0x02, 0x12, 0x78, 0x52, + 0x01, 0x1a, 0x79, 0xd0, 0x1a, 0x95, 0x3d, 0x40, 0x06, 0x78, 0x67, + 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x01, + 0x3e, 0x78, 0x54, 0x02, 0x52, 0x00, 0x54, 0x04, 0x77, 0x00, 0x3d, + 0x00, 0x04, 0xcf, 0x9c, 0x50, 0x01, 0x3b, 0x03, 0xd0, 0x08, 0x62, + 0xd0, 0x00, 0x50, 0xe1, 0x80, 0x06, 0x52, 0x04, 0x62, 0xd0, 0x00, + 0x38, 0xfb, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x62, 0xd0, 0x00, + 0x3c, 0xb2, 0x00, 0xb0, 0x79, 0x70, 0xfe, 0x26, 0x2c, 0xf0, 0x51, + 0xbc, 0x01, 0x01, 0x53, 0x79, 0x51, 0x2c, 0x2a, 0x79, 0x53, 0x2c, + 0x71, 0x01, 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x41, + 0x00, 0xf7, 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x06, 0x64, + 0x62, 0xd0, 0x00, 0x20, 0x53, 0x79, 0x47, 0x79, 0x20, 0xa0, 0x03, + 0x80, 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, 0xdd, 0x38, + 0xfe, 0x77, 0x00, 0x3d, 0x00, 0xc8, 0xcf, 0xdf, 0x56, 0x00, 0x00, + 0x80, 0x1e, 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x53, + 0x79, 0x47, 0x79, 0x20, 0xb0, 0x03, 0x80, 0x12, 0x50, 0x00, 0x08, + 0x50, 0x14, 0x08, 0x9e, 0xb6, 0x38, 0xfe, 0x77, 0x00, 0x3d, 0x00, + 0x1e, 0xcf, 0xdf, 0x62, 0xd0, 0x00, 0x51, 0x2c, 0x29, 0x08, 0x53, + 0x2c, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, + 0x02, 0x62, 0xd0, 0x00, 0x3c, 0xb2, 0x01, 0xb0, 0x70, 0x70, 0xfe, + 0x26, 0x2c, 0xf0, 0x51, 0xbc, 0x01, 0x09, 0x53, 0x79, 0x51, 0x2c, + 0x2a, 0x79, 0x53, 0x2c, 0x71, 0x01, 0x10, 0x7c, 0x06, 0x64, 0x62, + 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, 0x00, 0x00, 0x80, 0x1e, + 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x79, 0x47, + 0x79, 0x20, 0xa0, 0x03, 0x80, 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, + 0x08, 0x9e, 0x55, 0x38, 0xfe, 0x77, 0x00, 0x3d, 0x00, 0xc8, 0xcf, + 0xdf, 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x06, 0x64, 0x62, + 0xd0, 0x00, 0x20, 0x53, 0x79, 0x47, 0x79, 0x20, 0xb0, 0x03, 0x80, + 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, 0x2e, 0x38, 0xfe, + 0x77, 0x00, 0x3d, 0x00, 0x1e, 0xcf, 0xdf, 0x43, 0x00, 0x08, 0x38, + 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x04, 0x62, 0xd0, 0x00, 0x51, + 0x2c, 0x21, 0xf0, 0x54, 0x00, 0x51, 0x2f, 0x54, 0x01, 0x3d, 0x00, + 0x10, 0xb0, 0x18, 0x55, 0xb5, 0x00, 0x55, 0x9b, 0x00, 0x55, 0x9a, + 0x00, 0x55, 0x9d, 0x00, 0x55, 0x9c, 0x00, 0x56, 0x00, 0x00, 0x26, + 0x2c, 0x0f, 0x80, 0xb6, 0x3d, 0x00, 0x20, 0xb0, 0x1e, 0x62, 0xd0, + 0x00, 0x55, 0xb5, 0x01, 0x55, 0xb6, 0x00, 0x55, 0x9b, 0x08, 0x55, + 0x9a, 0x08, 0x55, 0x9d, 0x08, 0x55, 0x9c, 0x08, 0x56, 0x00, 0x00, + 0x26, 0x2c, 0x0f, 0x80, 0x94, 0x3d, 0x00, 0x40, 0xb0, 0x0f, 0x62, + 0xd0, 0x00, 0x55, 0xbd, 0x02, 0x56, 0x00, 0x00, 0x26, 0x2c, 0x0f, + 0x80, 0x81, 0x3d, 0x00, 0x50, 0xb0, 0x7c, 0x52, 0x01, 0x54, 0x03, + 0x56, 0x02, 0x00, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x01, + 0xa0, 0x17, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x02, 0xa0, + 0x27, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x04, 0xa0, 0x38, + 0x80, 0x46, 0x62, 0xd0, 0x00, 0x55, 0xb9, 0x01, 0x7c, 0x0e, 0x04, + 0x62, 0xd0, 0x00, 0x51, 0x31, 0x29, 0x80, 0x53, 0x31, 0x56, 0x00, + 0x00, 0x26, 0x2c, 0x0f, 0x80, 0x2c, 0x62, 0xd0, 0x00, 0x51, 0x30, + 0x53, 0x52, 0x51, 0x30, 0x53, 0x53, 0x51, 0x30, 0x53, 0x54, 0x51, + 0x30, 0x53, 0x55, 0x56, 0x00, 0x00, 0x26, 0x2c, 0x0f, 0x80, 0x11, + 0x62, 0xd0, 0x00, 0x51, 0x30, 0x53, 0x0e, 0x55, 0x0d, 0x00, 0x56, + 0x00, 0x00, 0x26, 0x2c, 0x0f, 0x56, 0x01, 0x00, 0x62, 0xd0, 0x00, + 0x55, 0x2d, 0x0e, 0x55, 0x2e, 0x08, 0x55, 0x2f, 0x00, 0x38, 0xfc, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x04, 0x62, 0xd0, 0x00, 0x3c, 0xb5, + 0x00, 0xa0, 0x13, 0x9d, 0x52, 0x62, 0xd0, 0x00, 0x3c, 0xb6, 0x00, + 0xb0, 0xe8, 0x55, 0xb6, 0x01, 0x7c, 0x0b, 0xc1, 0x80, 0xe0, 0x62, + 0xd0, 0x00, 0x3c, 0xb7, 0x00, 0xb0, 0x27, 0x3c, 0xb0, 0x01, 0xb0, + 0x22, 0x51, 0xbc, 0x53, 0x78, 0x55, 0x79, 0x00, 0x65, 0x78, 0x6b, + 0x79, 0x06, 0x78, 0x67, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd4, + 0x3e, 0x78, 0x54, 0x01, 0x3e, 0x78, 0x54, 0x02, 0x51, 0xbc, 0x54, + 0x00, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x9a, 0xd0, 0x08, 0x10, + 0x7c, 0x05, 0x28, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x05, 0x24, 0x20, + 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x9b, 0xd0, 0x08, 0x10, 0x7c, + 0x05, 0x05, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x05, 0x01, 0x20, 0x62, + 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x9c, 0xd0, 0x08, 0x10, 0x7c, 0x04, + 0xe2, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0xde, 0x20, 0x62, 0xd0, + 0x00, 0x50, 0x01, 0x3a, 0x9d, 0xd0, 0x08, 0x10, 0x7c, 0x04, 0xbf, + 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0xbb, 0x20, 0x7c, 0x10, 0x9a, + 0x62, 0xd0, 0x00, 0x3c, 0xb7, 0x00, 0xb0, 0x53, 0x3c, 0xb0, 0x01, + 0xb0, 0x4e, 0x3c, 0xb1, 0x00, 0xb0, 0x40, 0x92, 0x65, 0x40, 0x51, + 0x78, 0x01, 0x5f, 0x92, 0x75, 0x40, 0x06, 0x76, 0x37, 0x0e, 0x77, + 0x00, 0x06, 0x78, 0x7a, 0x92, 0x85, 0x40, 0x3e, 0x78, 0x53, 0x78, + 0x51, 0x76, 0x12, 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x1c, 0x92, + 0x41, 0x40, 0x51, 0x78, 0x01, 0x7a, 0x92, 0x51, 0x40, 0x52, 0x02, + 0x14, 0x76, 0x52, 0x01, 0x1c, 0x77, 0x06, 0x78, 0x5f, 0x0e, 0x79, + 0x00, 0x92, 0x7b, 0x40, 0x62, 0xd0, 0x00, 0x55, 0xb7, 0x01, 0x55, + 0xb0, 0x00, 0x38, 0xfc, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x03, 0x56, + 0x02, 0x00, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x3e, 0x62, + 0xd0, 0x00, 0x92, 0x07, 0x40, 0x52, 0xfc, 0x04, 0x78, 0x52, 0xfb, + 0x0c, 0x79, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x53, 0x79, 0x3e, + 0x78, 0x53, 0x78, 0x52, 0x02, 0x12, 0x78, 0x52, 0x01, 0x1a, 0x79, + 0xd0, 0x18, 0x91, 0xe6, 0x40, 0x52, 0xfc, 0x04, 0x78, 0x52, 0xfb, + 0x0c, 0x79, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x01, 0x3e, + 0x78, 0x54, 0x02, 0x77, 0x00, 0x52, 0x00, 0x3b, 0xfa, 0xcf, 0xbe, + 0x62, 0xd0, 0x00, 0x52, 0x02, 0x53, 0x78, 0x52, 0x01, 0x53, 0x79, + 0x38, 0xfd, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x71, 0x10, 0x41, + 0x01, 0xf7, 0x43, 0x00, 0x08, 0x70, 0xcf, 0x43, 0x00, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x64, 0x08, 0x9b, 0xbd, 0x71, 0x10, 0x41, 0x01, + 0xf7, 0x41, 0x00, 0xf7, 0x70, 0xcf, 0x43, 0x00, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x64, 0x08, 0x9b, 0xa8, 0x38, 0xfc, 0x5d, 0x00, 0x62, + 0xd0, 0x00, 0x53, 0x79, 0x26, 0x79, 0x08, 0x3c, 0x79, 0x08, 0xb0, + 0x09, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x07, 0x56, 0x01, + 0x01, 0x56, 0x00, 0x00, 0x52, 0x01, 0x62, 0xd0, 0x00, 0x53, 0xbd, + 0x71, 0x10, 0x43, 0x00, 0x08, 0x41, 0x01, 0xf7, 0x70, 0xcf, 0x3c, + 0xbd, 0x00, 0xb0, 0x04, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, + 0x10, 0x4f, 0x38, 0x01, 0x10, 0x50, 0x02, 0x7c, 0x03, 0x91, 0x20, + 0x10, 0x50, 0xff, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, 0xff, 0x7c, + 0x03, 0x91, 0x20, 0x10, 0x50, 0x08, 0x08, 0x50, 0x00, 0x08, 0x50, + 0x7a, 0x08, 0x7c, 0x04, 0x76, 0x38, 0xfd, 0x20, 0x56, 0x00, 0x00, + 0x80, 0x6e, 0x62, 0xd0, 0x00, 0x91, 0x1d, 0x40, 0x51, 0x78, 0x01, + 0x5f, 0x91, 0x2d, 0x40, 0x06, 0x78, 0x7a, 0x91, 0x43, 0x40, 0x3e, + 0x78, 0x53, 0x78, 0x51, 0x76, 0x12, 0x78, 0x51, 0x77, 0x1a, 0x79, + 0xd0, 0x3d, 0x90, 0xff, 0x40, 0x51, 0x78, 0x01, 0x5f, 0x91, 0x0f, + 0x40, 0x06, 0x78, 0x7a, 0x91, 0x25, 0x40, 0x92, 0x07, 0x40, 0x51, + 0x79, 0x10, 0x7c, 0x03, 0x91, 0x20, 0x62, 0xd0, 0x00, 0x90, 0xe2, + 0x40, 0x51, 0x78, 0x01, 0x5f, 0x90, 0xf2, 0x40, 0x06, 0x78, 0x7a, + 0x91, 0x08, 0x40, 0x91, 0xea, 0x40, 0x26, 0x79, 0x00, 0x51, 0x78, + 0x10, 0x7c, 0x03, 0x91, 0x20, 0x80, 0x0f, 0x10, 0x50, 0x00, 0x7c, + 0x03, 0x91, 0x20, 0x10, 0x50, 0x00, 0x7c, 0x03, 0x91, 0x20, 0x77, + 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x8f, 0x10, 0x50, 0x00, 0x7c, 0x03, + 0x91, 0x20, 0x10, 0x50, 0x01, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, + 0x00, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, 0x01, 0x7c, 0x03, 0x91, + 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, 0xff, + 0x7c, 0x03, 0x91, 0x7c, 0x04, 0x6d, 0x20, 0x50, 0x13, 0x08, 0x50, + 0x88, 0x08, 0x9a, 0x97, 0x38, 0xfe, 0x38, 0xff, 0x20, 0x7f, 0x7f, + 0x10, 0x4f, 0x7c, 0x1b, 0x97, 0x20, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x00, 0x53, 0x70, 0x53, + 0x71, 0x55, 0x6f, 0x10, 0x66, 0xfc, 0x6c, 0xfb, 0x6b, 0x70, 0x6b, + 0x71, 0x51, 0x70, 0x1b, 0xfa, 0x51, 0x71, 0x1b, 0xf9, 0xc0, 0x09, + 0x53, 0x71, 0x52, 0xfa, 0x1c, 0x70, 0x77, 0xfc, 0x7a, 0x6f, 0xbf, + 0xe3, 0x51, 0x70, 0x54, 0xfa, 0x51, 0x71, 0x54, 0xf9, 0x18, 0x60, + 0xd0, 0x7f, 0x10, 0x4f, 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, + 0x00, 0x53, 0x71, 0x53, 0x70, 0x55, 0x6f, 0x10, 0x6f, 0xf9, 0x6f, + 0xfa, 0xd0, 0x09, 0x52, 0xfc, 0x04, 0x71, 0x52, 0xfb, 0x0c, 0x70, + 0x66, 0xfc, 0x6c, 0xfb, 0x7a, 0x6f, 0xbf, 0xeb, 0x18, 0x60, 0xd0, + 0x20, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x52, 0x00, 0x53, 0x78, 0x55, + 0x79, 0x00, 0x65, 0x78, 0x6b, 0x79, 0x7f, 0x62, 0xd0, 0x00, 0x52, + 0x00, 0x53, 0x78, 0x55, 0x79, 0x00, 0x7f, 0x53, 0x76, 0x51, 0x79, + 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x76, 0x53, 0x77, 0x3e, 0x76, 0x53, + 0x76, 0x7f, 0x60, 0xd4, 0x3e, 0x76, 0x53, 0x77, 0x3e, 0x76, 0x53, + 0x76, 0x7f, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, + 0x53, 0x79, 0x7f, 0x51, 0x71, 0x53, 0x76, 0x51, 0x70, 0x53, 0x77, + 0x51, 0x76, 0x02, 0x78, 0x53, 0x78, 0x51, 0x77, 0x0a, 0x79, 0x7f, + 0x51, 0x79, 0x60, 0xd5, 0x51, 0x77, 0x3f, 0x78, 0x51, 0x76, 0x3f, + 0x78, 0x7f, 0x51, 0x78, 0x01, 0x7a, 0x53, 0x76, 0x51, 0x79, 0x09, + 0x00, 0x7f, 0x51, 0x76, 0x02, 0x78, 0x53, 0x78, 0x51, 0x77, 0x0a, + 0x79, 0x7f, 0x53, 0x76, 0x51, 0x79, 0x09, 0x00, 0x60, 0xd5, 0x52, + 0x20, 0x3f, 0x76, 0x52, 0x21, 0x3f, 0x76, 0x7f, 0x51, 0x71, 0x53, + 0x78, 0x51, 0x70, 0x53, 0x79, 0x70, 0xfb, 0x6e, 0x79, 0x6e, 0x78, + 0x51, 0x78, 0x08, 0x51, 0x79, 0x62, 0xd0, 0x00, 0x53, 0x80, 0x18, + 0x53, 0x81, 0x7f, 0x60, 0xd5, 0x52, 0x20, 0x3f, 0x76, 0x52, 0x21, + 0x3f, 0x76, 0x7f, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd5, 0x52, + 0x20, 0x3f, 0x78, 0x52, 0x21, 0x3f, 0x78, 0x7f, 0x52, 0x00, 0x53, + 0x76, 0x55, 0x77, 0x00, 0x65, 0x76, 0x6b, 0x77, 0x7f, 0x0e, 0x77, + 0x00, 0x51, 0x77, 0x60, 0xd5, 0x51, 0x79, 0x3f, 0x76, 0x7f, 0x06, + 0x78, 0x7a, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, + 0x53, 0x77, 0x3e, 0x78, 0x16, 0x78, 0x02, 0x53, 0x76, 0x7f, 0x70, + 0xfb, 0x6e, 0x79, 0x6e, 0x78, 0x51, 0x77, 0x60, 0xd5, 0x51, 0x79, + 0x3f, 0x76, 0x51, 0x78, 0x3f, 0x76, 0x7f, 0x3e, 0x78, 0x12, 0x76, + 0x54, 0x06, 0x51, 0x79, 0x1a, 0x77, 0x54, 0x05, 0x7f, 0x3e, 0x78, + 0x12, 0x76, 0x54, 0x04, 0x51, 0x79, 0x1a, 0x77, 0x54, 0x03, 0x7f, + 0x3e, 0x78, 0x53, 0x78, 0x51, 0x76, 0x14, 0x78, 0x51, 0x77, 0x1c, + 0x79, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x74, 0x53, 0x75, 0x3e, + 0x74, 0x53, 0x74, 0x7f, 0x60, 0xd4, 0x3e, 0x76, 0x53, 0x75, 0x3e, + 0x76, 0x16, 0x76, 0x02, 0x7f, 0x00, 0x2c, 0x00, 0x22, 0x00, 0x82, + 0x00, 0x18, 0x00, 0x9a, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00, 0x9e, + 0x00, 0x09, 0x00, 0xa7, 0x07, 0x01, 0x02, 0x03, 0x10, 0x17, 0x1c, + 0x15, 0x00, 0xae, 0x00, 0x05, 0x00, 0xb3, 0x04, 0x03, 0x00, 0x01, + 0x01, 0x00, 0xb7, 0x00, 0x07, 0xff, 0x00, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypressbln/touchkey_fw_NAATT.h b/drivers/input/keyboard/cypressbln/touchkey_fw_NAATT.h new file mode 100644 index 0000000..9a966b1 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/touchkey_fw_NAATT.h @@ -0,0 +1,747 @@ +unsigned char firmware_data[] = { + 0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, + 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x05, 0x47, 0x7e, 0x7e, 0x30, + 0x30, 0x30, 0x7d, 0x06, 0x93, 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, + 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, + 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x40, 0x71, 0x10, 0x62, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, 0x38, 0x5d, + 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, 0xfa, 0x01, 0x40, 0x4f, 0x5b, + 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, + 0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, 0xef, 0x18, 0x60, + 0xd5, 0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, + 0x02, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, 0xfe, + 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, 0x03, 0x50, 0x00, 0x4e, + 0x62, 0xd3, 0x03, 0x62, 0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, + 0x00, 0x71, 0xc0, 0x7c, 0x03, 0x01, 0x62, 0xd0, 0x00, 0x50, 0x02, + 0x57, 0xff, 0x08, 0x28, 0x53, 0x79, 0x18, 0x75, 0x09, 0x00, 0x28, + 0x4b, 0x51, 0x79, 0x80, 0x04, 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, + 0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, 0x75, 0x09, 0x00, + 0x08, 0x28, 0x53, 0x79, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0xa0, + 0x1c, 0x53, 0x78, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, 0x79, + 0x47, 0x79, 0xff, 0xb0, 0x06, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x18, + 0x7a, 0x78, 0xbf, 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, + 0x28, 0x53, 0x78, 0x50, 0x00, 0x3f, 0x79, 0x47, 0x79, 0xff, 0xb0, + 0x08, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x78, 0xbf, + 0xef, 0x18, 0x8f, 0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, + 0x10, 0x62, 0xe0, 0x02, 0x70, 0xef, 0x62, 0xe2, 0x00, 0x7c, 0x0a, + 0x86, 0x8f, 0xff, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x61, 0x00, 0xfd, 0x00, 0xcd, 0x00, + 0xce, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa0, 0x00, 0xa1, 0x80, 0xa2, + 0xc0, 0xa3, 0x0c, 0xa8, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x7c, 0x33, + 0x7a, 0x00, 0x7b, 0x00, 0x79, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, + 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, + 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, + 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, + 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, + 0x00, 0x4f, 0x00, 0xca, 0x20, 0xd6, 0x44, 0xcf, 0x00, 0xcb, 0x00, + 0xc8, 0x00, 0xcc, 0x00, 0xc9, 0x00, 0xd7, 0x00, 0xa9, 0x00, 0x2b, + 0x00, 0xb0, 0x00, 0xb3, 0x02, 0xb6, 0x00, 0xb2, 0x00, 0xb5, 0x00, + 0xb8, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0x33, 0x00, 0x34, + 0x00, 0x35, 0x00, 0xff, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, + 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0xdc, 0x00, + 0xe2, 0x00, 0xdd, 0x00, 0xd8, 0x02, 0xd9, 0xa0, 0xda, 0x28, 0xdb, + 0x00, 0xdf, 0x00, 0x29, 0x00, 0x30, 0x00, 0xbd, 0x00, 0xff, 0x70, + 0xef, 0x62, 0x00, 0x08, 0x71, 0x10, 0x62, 0x00, 0x98, 0x62, 0x01, + 0x02, 0x70, 0xef, 0x62, 0x04, 0x03, 0x71, 0x10, 0x62, 0x04, 0x17, + 0x62, 0x05, 0xab, 0x70, 0xef, 0x62, 0x08, 0x00, 0x71, 0x10, 0x62, + 0x08, 0x00, 0x62, 0x09, 0x28, 0x70, 0xef, 0x62, 0x0c, 0x00, 0x71, + 0x10, 0x62, 0x0c, 0x00, 0x62, 0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, + 0x00, 0x71, 0x10, 0x62, 0x10, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, + 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, 0x62, 0x09, 0x00, 0x62, 0x0d, + 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, 0x7f, 0x1d, 0x8c, 0x55, 0x02, + 0x08, 0x55, 0x03, 0x03, 0x55, 0x04, 0x00, 0x7c, 0x03, 0x11, 0x7c, + 0x02, 0xaa, 0x7f, 0x10, 0x70, 0xef, 0x50, 0x00, 0x67, 0x50, 0x02, + 0x57, 0x00, 0x7c, 0x03, 0x2c, 0x50, 0x01, 0x67, 0x50, 0x02, 0x57, + 0x83, 0x7c, 0x03, 0x2c, 0x70, 0xef, 0x20, 0x7f, 0x38, 0x02, 0x10, + 0x08, 0x4f, 0x56, 0xfc, 0x00, 0xd0, 0x04, 0x56, 0xfc, 0x01, 0x18, + 0x20, 0x70, 0xef, 0x62, 0xe3, 0x00, 0x10, 0x08, 0x28, 0x39, 0xff, + 0xa0, 0x1f, 0x4f, 0x48, 0xfc, 0x01, 0xa0, 0x03, 0x71, 0x10, 0x54, + 0xfd, 0x18, 0x20, 0x75, 0x09, 0x00, 0x10, 0x08, 0x28, 0x4f, 0x59, + 0xfd, 0x61, 0x00, 0x18, 0x20, 0x75, 0x09, 0x00, 0x8f, 0xd7, 0x38, + 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x62, 0xd0, 0x00, 0x2e, 0x02, 0x08, 0x51, 0x02, 0x60, 0x00, 0x71, + 0x10, 0x41, 0x01, 0xf7, 0x43, 0x00, 0x08, 0x70, 0xef, 0x7f, 0x62, + 0xd0, 0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, 0x21, 0xf8, + 0x29, 0x00, 0x70, 0xfe, 0x60, 0xe0, 0x70, 0xef, 0x4b, 0x4b, 0x4b, + 0x4b, 0x51, 0x02, 0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, + 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, + 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, + 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, + 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, + 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, + 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, + 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, + 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, + 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, + 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x47, 0x00, + 0x00, 0x49, 0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, 0x01, 0x79, + 0xbf, 0xfe, 0x18, 0x71, 0x10, 0x60, 0xe0, 0x70, 0xef, 0x71, 0x01, + 0x7f, 0x08, 0x67, 0x67, 0x67, 0x67, 0x21, 0x0f, 0xff, 0x2b, 0x9f, + 0x4e, 0x18, 0x21, 0x0f, 0xff, 0x24, 0x9f, 0x47, 0x7f, 0x08, 0x10, + 0x28, 0xa0, 0x0b, 0x9f, 0x3f, 0x20, 0x18, 0x75, 0xdf, 0xf5, 0x74, + 0x8f, 0xf2, 0x38, 0xfe, 0x7f, 0x52, 0x00, 0xa0, 0x08, 0x10, 0x9f, + 0x2d, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, + 0x0d, 0x9f, 0x20, 0x50, 0x0a, 0x9f, 0x1c, 0x7f, 0x70, 0xbf, 0x62, + 0xd3, 0x03, 0x4f, 0x52, 0xfb, 0xa0, 0x15, 0x7b, 0xfb, 0x52, 0xfc, + 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, 0x05, 0x4f, 0x62, 0xd3, + 0x03, 0x77, 0xfd, 0x8f, 0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x3d, + 0xfa, 0x00, 0xb0, 0x06, 0x3d, 0xfb, 0x00, 0xa0, 0x18, 0x10, 0x52, + 0xfc, 0x59, 0xfd, 0x28, 0x9e, 0xe6, 0x20, 0x07, 0xfd, 0x01, 0x0f, + 0xfc, 0x00, 0x17, 0xfb, 0x01, 0x1f, 0xfa, 0x00, 0x8f, 0xe0, 0x7f, + 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, + 0xa0, 0x06, 0x26, 0x02, 0x7f, 0x80, 0x04, 0x2e, 0x02, 0x80, 0x51, + 0x02, 0x60, 0x00, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, + 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, + 0x29, 0x00, 0xa0, 0x06, 0x26, 0x02, 0xef, 0x80, 0x04, 0x2e, 0x02, + 0x10, 0x51, 0x02, 0x60, 0x00, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, + 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xef, 0x80, 0x04, + 0x2e, 0x03, 0x10, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, 0xc0, + 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, + 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xfb, + 0x80, 0x04, 0x2e, 0x03, 0x04, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, 0x70, + 0x3f, 0x71, 0x80, 0x5d, 0xd3, 0x08, 0x5d, 0xd0, 0x08, 0x62, 0xd0, + 0x00, 0x51, 0x08, 0x60, 0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, + 0xa0, 0x09, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, 0x80, 0x08, 0x49, + 0xd7, 0x20, 0xa0, 0x03, 0x80, 0xac, 0x51, 0x05, 0x21, 0x0e, 0xe0, + 0x01, 0x80, 0x11, 0x80, 0x6d, 0x80, 0x7f, 0x80, 0x4d, 0x80, 0x9c, + 0x80, 0x9a, 0x80, 0x98, 0x80, 0x96, 0x80, 0x9d, 0x5d, 0xd8, 0x21, + 0xfe, 0x39, 0x40, 0xa0, 0x06, 0x62, 0xd7, 0x00, 0x80, 0x90, 0x49, + 0xd8, 0x01, 0xb0, 0x15, 0x55, 0x0c, 0x02, 0x26, 0x07, 0x00, 0x26, + 0x06, 0x00, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x62, 0xd7, 0x10, + 0x80, 0x77, 0x55, 0x0c, 0x01, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x06, + 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, 0x60, + 0xd8, 0x76, 0x07, 0x62, 0xd7, 0x14, 0x80, 0x5b, 0x51, 0x0a, 0x78, + 0x3a, 0x07, 0xc0, 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, + 0x60, 0xd8, 0x76, 0x07, 0x2e, 0x05, 0x20, 0x60, 0xd8, 0x62, 0xd7, + 0x04, 0x80, 0x3f, 0x5d, 0xd8, 0x3a, 0x0a, 0xd0, 0x2b, 0xa0, 0x29, + 0x53, 0x07, 0x53, 0x06, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x80, + 0x18, 0x51, 0x0b, 0x78, 0x3a, 0x07, 0xc0, 0x16, 0x51, 0x09, 0x02, + 0x07, 0x5c, 0x5d, 0xd8, 0x54, 0x00, 0x2e, 0x05, 0x10, 0x76, 0x07, + 0x80, 0x01, 0x62, 0xd7, 0x10, 0x80, 0x0f, 0x62, 0xd7, 0x00, 0x80, + 0x0a, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x00, 0x55, 0x0c, 0x00, 0x18, + 0x60, 0xd0, 0x18, 0x60, 0xd3, 0x20, 0x18, 0x7e, 0x62, 0xd0, 0x00, + 0x71, 0x10, 0x41, 0x04, 0xfc, 0x43, 0x05, 0x03, 0x70, 0xef, 0x26, + 0x03, 0xfc, 0x51, 0x03, 0x60, 0x04, 0x55, 0x0c, 0x00, 0x90, 0x28, + 0x90, 0x2d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x50, 0x00, 0x53, 0x06, + 0x71, 0x10, 0x43, 0x04, 0x03, 0x43, 0x05, 0x03, 0x70, 0xef, 0x2e, + 0x03, 0x03, 0x51, 0x03, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, 0x51, + 0x05, 0x21, 0xb0, 0x26, 0x05, 0x4f, 0x7f, 0x41, 0xe0, 0x7f, 0x43, + 0xe0, 0x80, 0x7f, 0x43, 0xd6, 0x31, 0x7f, 0x62, 0xd0, 0x00, 0x4f, + 0x52, 0xfd, 0x53, 0x0a, 0x52, 0xfc, 0x53, 0x0b, 0x52, 0xfb, 0x53, + 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, + 0x5d, 0xa4, 0x04, 0x1b, 0x5d, 0xa5, 0x0c, 0x1a, 0x55, 0x1c, 0x01, + 0x18, 0x7e, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x53, 0x1e, + 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0xa3, 0x62, 0xd3, 0x00, 0x13, + 0x60, 0x62, 0xd3, 0x00, 0x54, 0x68, 0x62, 0xd3, 0x00, 0x52, 0xa2, + 0x62, 0xd3, 0x00, 0x1b, 0x5f, 0x62, 0xd3, 0x00, 0x54, 0x67, 0x48, + 0x67, 0x80, 0xb0, 0x33, 0x3d, 0x67, 0x00, 0xb0, 0x7b, 0x51, 0x0d, + 0x3b, 0x68, 0xc0, 0x75, 0x52, 0x68, 0x58, 0x1e, 0x01, 0x00, 0x6d, + 0x62, 0xd3, 0x00, 0x05, 0x4e, 0xc0, 0x09, 0x51, 0x0f, 0x3b, 0x4e, + 0xd0, 0x12, 0xa0, 0x10, 0x56, 0x4e, 0x00, 0x5b, 0x64, 0x5c, 0x62, + 0xd3, 0x00, 0x07, 0x60, 0x01, 0x0f, 0x5f, 0x00, 0x80, 0x41, 0x3d, + 0x67, 0xff, 0xb0, 0x09, 0x50, 0xff, 0x12, 0x0e, 0x3b, 0x68, 0xc0, + 0x20, 0x62, 0xd3, 0x00, 0x56, 0x68, 0x00, 0x56, 0x67, 0x00, 0x5b, + 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x5b, 0x78, 0xd0, 0x03, 0x50, + 0x00, 0x54, 0x5b, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, + 0xd3, 0x00, 0x52, 0xa3, 0x62, 0xd3, 0x00, 0x54, 0x60, 0x62, 0xd3, + 0x00, 0x52, 0xa2, 0x62, 0xd3, 0x00, 0x54, 0x5f, 0x51, 0x1e, 0x64, + 0x5c, 0x62, 0xd3, 0x00, 0x56, 0x68, 0x00, 0x56, 0x67, 0x00, 0x5b, + 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x12, 0x54, 0x5b, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x08, + 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x52, 0x53, 0x19, 0x55, 0x18, 0x00, + 0x18, 0x08, 0x90, 0x7e, 0x62, 0xd3, 0x00, 0x23, 0x56, 0xb0, 0x2c, + 0x51, 0x10, 0x04, 0x19, 0x0e, 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, + 0xd3, 0x00, 0x52, 0x68, 0x12, 0x19, 0x52, 0x67, 0x1a, 0x18, 0xc0, + 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x57, 0x78, 0x54, + 0x57, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, 0x51, + 0x10, 0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, + 0x00, 0x52, 0x68, 0x12, 0x19, 0x52, 0x67, 0x1a, 0x18, 0xc0, 0x0e, + 0x5b, 0x67, 0x90, 0x31, 0x62, 0xd3, 0x00, 0x2d, 0x56, 0x50, 0x01, + 0x80, 0x24, 0x5b, 0x67, 0x08, 0x90, 0x23, 0x73, 0x62, 0xd3, 0x00, + 0x25, 0x56, 0x62, 0xd3, 0x00, 0x20, 0x51, 0x11, 0x54, 0x57, 0x50, + 0x00, 0x80, 0x0d, 0x5b, 0x67, 0x90, 0x0d, 0x73, 0x62, 0xd3, 0x00, + 0x25, 0x56, 0x50, 0x00, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x67, + 0x67, 0x67, 0x5c, 0x18, 0x21, 0x07, 0xf0, 0x01, 0x7f, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x70, 0xbf, 0x70, 0xbf, 0x62, + 0xd3, 0x00, 0x50, 0x04, 0x78, 0x08, 0x5c, 0x56, 0x52, 0x32, 0x18, + 0x78, 0xdf, 0xf8, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x91, 0x99, + 0x70, 0xbf, 0x18, 0x08, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0xa3, + 0x62, 0xd3, 0x00, 0x54, 0x60, 0x62, 0xd3, 0x00, 0x52, 0xa2, 0x62, + 0xd3, 0x00, 0x54, 0x5f, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, 0x71, + 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x14, 0x00, 0x50, 0x04, 0x78, + 0x08, 0x9f, 0x0e, 0x39, 0x01, 0xb0, 0x04, 0x55, 0x14, 0x01, 0x18, + 0x78, 0xdf, 0xf3, 0x51, 0x14, 0x7f, 0x50, 0x04, 0x78, 0x08, 0x9e, + 0x3e, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x98, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0xd8, 0xd9, 0xda, 0xdb, 0xdf, 0x00, 0x01, + 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x70, 0xbf, 0x62, 0xd0, + 0x00, 0x62, 0xd3, 0x00, 0x57, 0x00, 0x56, 0x56, 0x00, 0x79, 0xdf, + 0xfb, 0x62, 0xd3, 0x00, 0x57, 0x03, 0x50, 0x03, 0x54, 0x57, 0x79, + 0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x32, 0x57, 0x03, 0x54, 0x5b, + 0x79, 0xdf, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x55, 0x0d, 0x19, 0x55, + 0x0e, 0x0a, 0x55, 0x0f, 0x0f, 0x55, 0x10, 0x0a, 0x55, 0x11, 0x03, + 0x55, 0x12, 0x32, 0x55, 0x22, 0x01, 0x55, 0x1f, 0x14, 0x43, 0x61, + 0x0d, 0x57, 0x00, 0x50, 0x02, 0x90, 0x95, 0x50, 0x01, 0xff, 0x98, + 0x29, 0x00, 0x60, 0xa9, 0x62, 0xa0, 0x28, 0x43, 0xa2, 0x04, 0x62, + 0xa3, 0x70, 0x43, 0x7a, 0x01, 0x43, 0xaa, 0x02, 0x43, 0xdf, 0x01, + 0x50, 0x01, 0x57, 0x09, 0x90, 0x20, 0x90, 0x55, 0x57, 0x01, 0x50, + 0xb3, 0x91, 0x44, 0x50, 0x01, 0x57, 0x0e, 0x90, 0x12, 0x90, 0x47, + 0x7f, 0x53, 0x22, 0xff, 0x67, 0x29, 0x00, 0x60, 0xa9, 0x51, 0x21, + 0x58, 0x20, 0x90, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, 0x03, 0x53, + 0x21, 0x64, 0x64, 0x64, 0x64, 0x64, 0x29, 0x80, 0x60, 0xa1, 0x5b, + 0x78, 0x21, 0x0f, 0x29, 0x08, 0x74, 0x53, 0x20, 0x12, 0x22, 0x02, + 0x21, 0x5c, 0x50, 0x00, 0x53, 0x1d, 0x53, 0x23, 0x29, 0x01, 0x79, + 0xa0, 0x08, 0x64, 0x6b, 0x1d, 0x6b, 0x23, 0x8f, 0xf5, 0x60, 0xb5, + 0x51, 0x1d, 0x60, 0xb4, 0x7f, 0x50, 0x04, 0x78, 0x08, 0x90, 0x0f, + 0x90, 0x41, 0x18, 0x78, 0xdf, 0xf8, 0x7f, 0x02, 0x20, 0x02, 0x08, + 0x01, 0x80, 0x01, 0x20, 0x64, 0x5c, 0xff, 0xf4, 0x4b, 0x74, 0xff, + 0xf0, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, 0x5b, 0x64, 0x64, + 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, + 0xff, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, 0x18, + 0xfe, 0xef, 0x5c, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, + 0x7f, 0x62, 0xd0, 0x00, 0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, + 0xfe, 0xd9, 0x5c, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, 0x70, 0xef, + 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x22, 0x1d, 0x61, + 0x01, 0x36, 0x1d, 0xff, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, + 0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x1e, 0x50, 0x00, + 0x53, 0x1a, 0x53, 0x1b, 0x51, 0x1e, 0x5c, 0x62, 0xd3, 0x00, 0x52, + 0x24, 0x53, 0x1f, 0x43, 0xa0, 0x01, 0x51, 0x1f, 0x60, 0xfd, 0x41, + 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x7a, 0x9f, 0x81, 0x58, 0x23, 0x55, + 0x1c, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x43, 0xb3, 0x01, + 0x51, 0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, 0x9f, 0x5f, + 0x9f, 0x91, 0x43, 0xa3, 0x20, 0x41, 0xa0, 0xfe, 0x62, 0xfd, 0x00, + 0x50, 0xff, 0x4c, 0x1b, 0x14, 0x1b, 0x51, 0x20, 0x11, 0x08, 0xfe, + 0x66, 0x4c, 0x1a, 0x1c, 0x1a, 0xd0, 0x07, 0x55, 0x1a, 0x00, 0x55, + 0x1b, 0x00, 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x1b, + 0x54, 0xa3, 0x51, 0x1a, 0x54, 0xa2, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x08, 0x9f, 0x86, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x70, 0xbf, 0x62, + 0xd0, 0x00, 0x53, 0x29, 0x5a, 0x28, 0x55, 0x1e, 0x03, 0x62, 0xd3, + 0x00, 0x58, 0x1e, 0x56, 0x24, 0x80, 0x55, 0x2b, 0x08, 0x55, 0x2a, + 0x80, 0x51, 0x1e, 0x9f, 0x63, 0x51, 0x1e, 0x9f, 0x5f, 0x70, 0xbf, + 0x58, 0x1e, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x3a, 0x29, 0x51, 0x1a, + 0x1a, 0x28, 0xd0, 0x06, 0x51, 0x2a, 0x73, 0x25, 0x24, 0x68, 0x2a, + 0x26, 0x2a, 0x7f, 0x51, 0x2a, 0x2d, 0x24, 0x7a, 0x2b, 0xbf, 0xd6, + 0x7a, 0x1e, 0xdf, 0xc4, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x10, 0x7c, + 0x05, 0x28, 0x7c, 0x05, 0x05, 0x7c, 0x04, 0xe2, 0x7c, 0x04, 0xbf, + 0x20, 0x7c, 0x16, 0xb6, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x03, 0x7c, + 0x20, 0x43, 0x00, 0x08, 0x62, 0xd0, 0x00, 0x55, 0x2c, 0x08, 0x55, + 0x2d, 0x0b, 0x55, 0x2e, 0x03, 0x55, 0x30, 0x32, 0x55, 0x31, 0x02, + 0x10, 0x50, 0x00, 0x08, 0x50, 0x2c, 0x08, 0x50, 0x06, 0x08, 0x50, + 0x22, 0x08, 0x7c, 0x06, 0x7a, 0x38, 0xfc, 0x7c, 0x06, 0x2e, 0x7c, + 0x06, 0x6f, 0x20, 0x71, 0x10, 0x41, 0x04, 0xfc, 0x41, 0x05, 0xfc, + 0x71, 0x01, 0x10, 0x70, 0xcf, 0x7c, 0x08, 0x7f, 0x20, 0x62, 0xd0, + 0x00, 0x55, 0xc5, 0x00, 0x91, 0x23, 0x10, 0x7c, 0x08, 0x05, 0x20, + 0x93, 0xcb, 0x81, 0x17, 0x7c, 0x18, 0x71, 0x62, 0xe3, 0x38, 0x7c, + 0x11, 0x2d, 0x62, 0xd0, 0x00, 0x3c, 0xc0, 0x01, 0xb0, 0x09, 0x50, + 0x00, 0x08, 0x7c, 0x1a, 0xfe, 0x38, 0xff, 0x62, 0xe3, 0x38, 0x10, + 0x7c, 0x08, 0x43, 0x20, 0x39, 0x00, 0xa0, 0xa8, 0x62, 0xd0, 0x00, + 0x51, 0xbf, 0x11, 0x4a, 0x51, 0xbe, 0x19, 0x01, 0xd0, 0x12, 0x7c, + 0x16, 0xd4, 0x39, 0xe1, 0xa0, 0x16, 0x62, 0xd0, 0x00, 0x76, 0xbf, + 0x0e, 0xbe, 0x00, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x55, 0xbf, 0x00, + 0x55, 0xbe, 0x00, 0x90, 0xcc, 0x62, 0xd0, 0x00, 0x3c, 0xcd, 0xf0, + 0xd0, 0x03, 0x76, 0xcd, 0x62, 0xd0, 0x00, 0x51, 0x31, 0x21, 0x7f, + 0x53, 0x79, 0x51, 0xcd, 0x3a, 0x79, 0xb0, 0xad, 0x7c, 0x16, 0xd4, + 0x62, 0xd0, 0x00, 0x53, 0xce, 0x3c, 0xce, 0xe1, 0xa0, 0x51, 0x3c, + 0xca, 0x00, 0xb0, 0x06, 0x7c, 0x1d, 0x14, 0x80, 0x25, 0x62, 0xd0, + 0x00, 0x55, 0xb7, 0x00, 0x55, 0xb6, 0x00, 0x55, 0xb9, 0x00, 0x55, + 0xb8, 0x00, 0x51, 0xce, 0x53, 0x78, 0x55, 0x79, 0x00, 0x06, 0x78, + 0xb6, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd5, 0x50, 0x08, 0x3f, + 0x78, 0x62, 0xd0, 0x00, 0x3c, 0xc6, 0x01, 0xb0, 0x04, 0x55, 0xc8, + 0x01, 0x62, 0xd0, 0x00, 0x55, 0xc6, 0x00, 0x55, 0xc1, 0x01, 0x7c, + 0x17, 0x5a, 0x62, 0xd0, 0x00, 0x55, 0xc3, 0x01, 0x55, 0xc4, 0x03, + 0x80, 0x50, 0x62, 0xd0, 0x00, 0x55, 0xcd, 0x00, 0x80, 0x48, 0x62, + 0xd0, 0x00, 0x55, 0xbf, 0x00, 0x55, 0xbe, 0x00, 0x55, 0xc8, 0x00, + 0x55, 0xc9, 0x00, 0x55, 0xc1, 0x00, 0x3c, 0xc3, 0x01, 0xb0, 0x31, + 0x7a, 0xc4, 0x3c, 0xc4, 0x00, 0xb0, 0x2a, 0x7c, 0x17, 0xea, 0x62, + 0xd0, 0x00, 0x55, 0xc3, 0x00, 0x3c, 0xca, 0x00, 0xb0, 0x06, 0x7c, + 0x1d, 0x14, 0x80, 0x11, 0x62, 0xd0, 0x00, 0x51, 0xce, 0x53, 0x78, + 0x55, 0x79, 0x00, 0x06, 0x78, 0xb6, 0x7c, 0x1d, 0x4c, 0x62, 0xd0, + 0x00, 0x55, 0xcd, 0x00, 0x7c, 0x19, 0x32, 0x8e, 0xe9, 0x8f, 0xff, + 0x10, 0x4f, 0x38, 0x24, 0x62, 0xd0, 0x00, 0x3c, 0xcb, 0x00, 0xb0, + 0x05, 0x51, 0xaa, 0x53, 0x24, 0x10, 0x50, 0x00, 0x7c, 0x09, 0xb9, + 0x20, 0x56, 0x19, 0x00, 0x81, 0x2c, 0x56, 0x00, 0x00, 0x81, 0x20, + 0x62, 0xd0, 0x00, 0x3c, 0xcb, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, + 0x78, 0x55, 0x79, 0x00, 0x06, 0x78, 0xaa, 0x7c, 0x1c, 0x86, 0x52, + 0x00, 0x53, 0x76, 0x55, 0x77, 0x00, 0x06, 0x76, 0x24, 0x7c, 0x1d, + 0x08, 0x10, 0x52, 0x00, 0x7c, 0x09, 0xb9, 0x20, 0x10, 0x7c, 0x06, + 0x64, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, + 0x00, 0xb0, 0x3c, 0x7c, 0x1c, 0x51, 0x7c, 0x1c, 0x9d, 0x51, 0x77, + 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x7c, + 0x1c, 0x21, 0x38, 0xfc, 0x51, 0x71, 0x53, 0x76, 0x51, 0x70, 0x53, + 0x77, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x77, 0x08, 0x51, + 0x76, 0x08, 0x7c, 0x1b, 0xdd, 0x18, 0x53, 0x76, 0x18, 0x53, 0x77, + 0x38, 0xfe, 0x7c, 0x1c, 0x79, 0x80, 0x63, 0x3d, 0x00, 0x01, 0xb0, + 0x2e, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x51, 0x7c, 0x1c, 0x9d, 0x65, + 0x76, 0x6b, 0x77, 0x65, 0x76, 0x6b, 0x77, 0x50, 0x00, 0x08, 0x50, + 0x05, 0x08, 0x51, 0x77, 0x08, 0x51, 0x76, 0x08, 0x7c, 0x1b, 0xdd, + 0x18, 0x53, 0x76, 0x18, 0x53, 0x77, 0x38, 0xfe, 0x7c, 0x1c, 0x79, + 0x80, 0x31, 0x3d, 0x00, 0x02, 0xb0, 0x2c, 0x62, 0xd0, 0x00, 0x7c, + 0x1c, 0x51, 0x7c, 0x1c, 0x9d, 0x65, 0x76, 0x6b, 0x77, 0x65, 0x76, + 0x6b, 0x77, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x77, 0x08, + 0x51, 0x76, 0x08, 0x7c, 0x1b, 0xdd, 0x18, 0x53, 0x76, 0x18, 0x53, + 0x77, 0x38, 0xfe, 0x7c, 0x1c, 0x79, 0x62, 0xd0, 0x00, 0x55, 0x79, + 0x03, 0x5a, 0x78, 0x06, 0x78, 0x01, 0x52, 0x00, 0x53, 0x76, 0x50, + 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, + 0x7c, 0x1c, 0x21, 0x38, 0xfc, 0x7c, 0x1c, 0xbe, 0x53, 0x79, 0x52, + 0x19, 0x53, 0x76, 0x55, 0x77, 0x00, 0x65, 0x76, 0x6b, 0x77, 0x7c, + 0x1c, 0xe2, 0x53, 0x79, 0x7c, 0x1d, 0x34, 0x06, 0x76, 0xa2, 0x0e, + 0x77, 0x00, 0x51, 0x77, 0x7c, 0x1c, 0x92, 0x7c, 0x1c, 0x79, 0x77, + 0x00, 0x3d, 0x00, 0x04, 0xce, 0xdd, 0x77, 0x19, 0x3d, 0x19, 0x03, + 0xce, 0xd1, 0x56, 0x00, 0x00, 0x80, 0xd0, 0x62, 0xd0, 0x00, 0x55, + 0x79, 0x03, 0x5a, 0x78, 0x06, 0x78, 0x01, 0x52, 0x00, 0x53, 0x76, + 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, + 0x08, 0x7c, 0x1c, 0x21, 0x38, 0xfc, 0x7c, 0x1c, 0xbe, 0x60, 0xd4, + 0x3e, 0x78, 0x54, 0x1a, 0x3e, 0x78, 0x54, 0x1b, 0x5a, 0x78, 0x06, + 0x78, 0x03, 0x52, 0x00, 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x1c, 0x21, 0x38, + 0xfc, 0x7c, 0x1c, 0xbe, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x1c, 0x3e, + 0x78, 0x54, 0x1d, 0x5a, 0x78, 0x06, 0x78, 0x05, 0x52, 0x00, 0x53, + 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, 0x50, + 0x06, 0x08, 0x7c, 0x1c, 0x21, 0x38, 0xfc, 0x7c, 0x1c, 0xbe, 0x60, + 0xd4, 0x3e, 0x78, 0x54, 0x1e, 0x3e, 0x78, 0x54, 0x1f, 0x50, 0x03, + 0x08, 0x5a, 0x78, 0x06, 0x78, 0x1a, 0x08, 0x51, 0x78, 0x08, 0x7c, + 0x1a, 0x33, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x78, 0x54, 0x21, + 0x51, 0x79, 0x54, 0x20, 0x7c, 0x1c, 0x51, 0x7c, 0x1c, 0xb3, 0x7c, + 0x1c, 0xfd, 0x06, 0x78, 0x5f, 0x7c, 0x1c, 0xed, 0x7c, 0x1c, 0x51, + 0x51, 0x78, 0x01, 0x8a, 0x7c, 0x1c, 0xd1, 0x51, 0x78, 0x01, 0x92, + 0x7c, 0x1c, 0xd1, 0x06, 0x78, 0x9a, 0x7c, 0x1c, 0xed, 0x7c, 0x1c, + 0x51, 0x51, 0x78, 0x01, 0x7a, 0x7c, 0x1c, 0xd1, 0x06, 0x78, 0x82, + 0x7c, 0x1c, 0xed, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xcf, 0x2d, 0x3d, + 0x00, 0x00, 0xb0, 0x09, 0x62, 0xd0, 0x00, 0x47, 0xc5, 0x0e, 0xa0, + 0x0e, 0x3d, 0x00, 0x03, 0xb0, 0x75, 0x62, 0xd0, 0x00, 0x47, 0xc5, + 0x07, 0xb0, 0x6d, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x51, 0x7c, 0x1c, + 0xb3, 0x53, 0x77, 0x7c, 0x1d, 0x40, 0x53, 0x74, 0x06, 0x78, 0x5f, + 0x7c, 0x1c, 0x86, 0x3e, 0x78, 0x12, 0x74, 0x51, 0x79, 0x1a, 0x75, + 0xd0, 0x2c, 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0x5f, 0x53, 0x72, + 0x51, 0x79, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x72, 0x53, 0x73, 0x3e, + 0x72, 0x53, 0x72, 0x06, 0x78, 0xa2, 0x7c, 0x1c, 0x86, 0x3e, 0x78, + 0x12, 0x72, 0x54, 0x23, 0x51, 0x79, 0x1a, 0x73, 0x54, 0x22, 0x80, + 0x07, 0x56, 0x23, 0x00, 0x56, 0x22, 0x00, 0x62, 0xd0, 0x00, 0x51, + 0x74, 0x03, 0x23, 0x53, 0x78, 0x51, 0x75, 0x0b, 0x22, 0x53, 0x79, + 0x51, 0x77, 0x60, 0xd5, 0x51, 0x79, 0x3f, 0x76, 0x51, 0x78, 0x3f, + 0x76, 0x38, 0xdc, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x22, 0x10, 0x57, + 0x30, 0x50, 0x00, 0x7c, 0x0a, 0x38, 0x20, 0x62, 0xd0, 0x00, 0x3c, + 0xcb, 0x01, 0xb0, 0x13, 0x51, 0x24, 0x53, 0x32, 0x51, 0x25, 0x53, + 0x33, 0x51, 0x26, 0x53, 0x34, 0x51, 0x27, 0x53, 0x35, 0x80, 0x14, + 0x62, 0xd0, 0x00, 0x51, 0xaa, 0x53, 0x24, 0x51, 0xab, 0x53, 0x25, + 0x51, 0xac, 0x53, 0x26, 0x51, 0xad, 0x53, 0x27, 0x10, 0x50, 0x00, + 0x7c, 0x09, 0xb9, 0x20, 0x56, 0x19, 0x00, 0x81, 0x2c, 0x56, 0x00, + 0x00, 0x81, 0x20, 0x62, 0xd0, 0x00, 0x3c, 0xcb, 0x00, 0xb0, 0x1b, + 0x52, 0x00, 0x53, 0x78, 0x55, 0x79, 0x00, 0x06, 0x78, 0xaa, 0x7c, + 0x1c, 0x86, 0x52, 0x00, 0x53, 0x76, 0x55, 0x77, 0x00, 0x06, 0x76, + 0x24, 0x7c, 0x1d, 0x08, 0x10, 0x52, 0x00, 0x7c, 0x09, 0xb9, 0x20, + 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, + 0xee, 0x3d, 0x00, 0x00, 0xb0, 0x3c, 0x7c, 0x1c, 0x51, 0x7c, 0x1c, + 0x9d, 0x51, 0x77, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, 0x50, + 0x03, 0x08, 0x7c, 0x1c, 0x21, 0x38, 0xfc, 0x51, 0x71, 0x53, 0x76, + 0x51, 0x70, 0x53, 0x77, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, + 0x77, 0x08, 0x51, 0x76, 0x08, 0x7c, 0x1b, 0xdd, 0x18, 0x53, 0x76, + 0x18, 0x53, 0x77, 0x38, 0xfe, 0x7c, 0x1c, 0x79, 0x80, 0x63, 0x3d, + 0x00, 0x01, 0xb0, 0x2e, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x51, 0x7c, + 0x1c, 0x9d, 0x65, 0x76, 0x6b, 0x77, 0x65, 0x76, 0x6b, 0x77, 0x50, + 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x77, 0x08, 0x51, 0x76, 0x08, + 0x7c, 0x1b, 0xdd, 0x18, 0x53, 0x76, 0x18, 0x53, 0x77, 0x38, 0xfe, + 0x7c, 0x1c, 0x79, 0x80, 0x31, 0x3d, 0x00, 0x02, 0xb0, 0x2c, 0x62, + 0xd0, 0x00, 0x7c, 0x1c, 0x51, 0x7c, 0x1c, 0x9d, 0x65, 0x76, 0x6b, + 0x77, 0x65, 0x76, 0x6b, 0x77, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, + 0x51, 0x77, 0x08, 0x51, 0x76, 0x08, 0x7c, 0x1b, 0xdd, 0x18, 0x53, + 0x76, 0x18, 0x53, 0x77, 0x38, 0xfe, 0x7c, 0x1c, 0x79, 0x62, 0xd0, + 0x00, 0x55, 0x79, 0x03, 0x5a, 0x78, 0x06, 0x78, 0x01, 0x52, 0x00, + 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, + 0x50, 0x06, 0x08, 0x7c, 0x1c, 0x21, 0x38, 0xfc, 0x7c, 0x1c, 0xbe, + 0x53, 0x79, 0x52, 0x19, 0x53, 0x76, 0x55, 0x77, 0x00, 0x65, 0x76, + 0x6b, 0x77, 0x7c, 0x1c, 0xe2, 0x53, 0x79, 0x7c, 0x1d, 0x34, 0x06, + 0x76, 0xa2, 0x0e, 0x77, 0x00, 0x51, 0x77, 0x7c, 0x1c, 0x92, 0x7c, + 0x1c, 0x79, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xce, 0xdd, 0x77, 0x19, + 0x3d, 0x19, 0x03, 0xce, 0xd1, 0x56, 0x00, 0x00, 0x80, 0xd0, 0x62, + 0xd0, 0x00, 0x55, 0x79, 0x03, 0x5a, 0x78, 0x06, 0x78, 0x01, 0x52, + 0x00, 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x06, 0x08, 0x7c, 0x1c, 0x21, 0x38, 0xfc, 0x7c, 0x1c, + 0xbe, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x1a, 0x3e, 0x78, 0x54, 0x1b, + 0x5a, 0x78, 0x06, 0x78, 0x03, 0x52, 0x00, 0x53, 0x76, 0x50, 0x00, + 0x08, 0x51, 0x76, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, + 0x1c, 0x21, 0x38, 0xfc, 0x7c, 0x1c, 0xbe, 0x60, 0xd4, 0x3e, 0x78, + 0x54, 0x1c, 0x3e, 0x78, 0x54, 0x1d, 0x5a, 0x78, 0x06, 0x78, 0x05, + 0x52, 0x00, 0x53, 0x76, 0x50, 0x00, 0x08, 0x51, 0x76, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x1c, 0x21, 0x38, 0xfc, 0x7c, + 0x1c, 0xbe, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x1e, 0x3e, 0x78, 0x54, + 0x1f, 0x50, 0x03, 0x08, 0x5a, 0x78, 0x06, 0x78, 0x1a, 0x08, 0x51, + 0x78, 0x08, 0x7c, 0x1a, 0x33, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, + 0x78, 0x54, 0x21, 0x51, 0x79, 0x54, 0x20, 0x7c, 0x1c, 0x51, 0x7c, + 0x1c, 0xb3, 0x7c, 0x1c, 0xfd, 0x06, 0x78, 0x5f, 0x7c, 0x1c, 0xed, + 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0x8a, 0x7c, 0x1c, 0xd1, 0x51, + 0x78, 0x01, 0x92, 0x7c, 0x1c, 0xd1, 0x06, 0x78, 0x9a, 0x7c, 0x1c, + 0xed, 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0x7a, 0x7c, 0x1c, 0xd1, + 0x06, 0x78, 0x82, 0x7c, 0x1c, 0xed, 0x77, 0x00, 0x3d, 0x00, 0x04, + 0xcf, 0x2d, 0x56, 0x00, 0x00, 0x80, 0x19, 0x7c, 0x1c, 0x5d, 0x06, + 0x78, 0x24, 0x7c, 0x1c, 0x86, 0x52, 0x00, 0x53, 0x76, 0x55, 0x77, + 0x00, 0x06, 0x76, 0x32, 0x7c, 0x1d, 0x08, 0x77, 0x00, 0x3d, 0x00, + 0x04, 0xcf, 0xe4, 0x38, 0xde, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x07, + 0x56, 0x02, 0x00, 0x62, 0xd0, 0x00, 0x55, 0xc2, 0x00, 0x3c, 0xcb, + 0x00, 0xb0, 0x05, 0x51, 0xaa, 0x53, 0x24, 0x10, 0x50, 0x00, 0x7c, + 0x09, 0xb9, 0x20, 0x56, 0x00, 0x00, 0x80, 0xda, 0x62, 0xd0, 0x00, + 0x3c, 0xcb, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x78, 0x55, 0x79, + 0x00, 0x06, 0x78, 0xaa, 0x7c, 0x1c, 0x86, 0x52, 0x00, 0x53, 0x76, + 0x55, 0x77, 0x00, 0x06, 0x76, 0x24, 0x7c, 0x1d, 0x08, 0x10, 0x52, + 0x00, 0x7c, 0x09, 0xb9, 0x20, 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, + 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, 0x00, 0xb0, 0x3c, + 0x7c, 0x1c, 0x51, 0x7c, 0x1c, 0x9d, 0x51, 0x77, 0x08, 0x51, 0x76, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x7c, 0x1c, 0x21, 0x38, + 0xfc, 0x51, 0x71, 0x53, 0x76, 0x51, 0x70, 0x53, 0x77, 0x50, 0x00, + 0x08, 0x50, 0x05, 0x08, 0x51, 0x77, 0x08, 0x51, 0x76, 0x08, 0x7c, + 0x1b, 0xdd, 0x18, 0x53, 0x76, 0x18, 0x53, 0x77, 0x38, 0xfe, 0x7c, + 0x1c, 0x79, 0x80, 0x63, 0x3d, 0x00, 0x01, 0xb0, 0x2e, 0x62, 0xd0, + 0x00, 0x7c, 0x1c, 0x51, 0x7c, 0x1c, 0x9d, 0x65, 0x76, 0x6b, 0x77, + 0x65, 0x76, 0x6b, 0x77, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, + 0x77, 0x08, 0x51, 0x76, 0x08, 0x7c, 0x1b, 0xdd, 0x18, 0x53, 0x76, + 0x18, 0x53, 0x77, 0x38, 0xfe, 0x7c, 0x1c, 0x79, 0x80, 0x31, 0x3d, + 0x00, 0x02, 0xb0, 0x2c, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x51, 0x7c, + 0x1c, 0x9d, 0x65, 0x76, 0x6b, 0x77, 0x65, 0x76, 0x6b, 0x77, 0x50, + 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x77, 0x08, 0x51, 0x76, 0x08, + 0x7c, 0x1b, 0xdd, 0x18, 0x53, 0x76, 0x18, 0x53, 0x77, 0x38, 0xfe, + 0x7c, 0x1c, 0x79, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xcf, 0x23, 0x56, + 0x00, 0x00, 0x82, 0xb5, 0x62, 0xd0, 0x00, 0x3c, 0xc0, 0x02, 0xa0, + 0xb1, 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0x5f, 0x7c, 0x1c, 0x68, + 0x06, 0x78, 0xa2, 0x7c, 0x1c, 0x86, 0x3e, 0x78, 0x53, 0x78, 0x51, + 0x76, 0x12, 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x16, 0x7c, 0x1c, + 0x51, 0x51, 0x78, 0x01, 0x5f, 0x7c, 0x1c, 0x68, 0x06, 0x78, 0xa2, + 0x7c, 0x1c, 0x86, 0x7c, 0x1d, 0x65, 0x80, 0x17, 0x62, 0xd0, 0x00, + 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0xa2, 0x7c, 0x1c, 0x68, 0x06, + 0x78, 0x5f, 0x7c, 0x1c, 0x86, 0x7c, 0x1d, 0x65, 0x50, 0x90, 0x13, + 0x04, 0x50, 0x01, 0x1b, 0x03, 0xc0, 0x57, 0x62, 0xd0, 0x00, 0x7c, + 0x1c, 0x51, 0x51, 0x78, 0x01, 0x9a, 0x7c, 0x1c, 0x68, 0x06, 0x78, + 0xa2, 0x7c, 0x1c, 0x86, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x76, 0x12, + 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x16, 0x7c, 0x1c, 0x51, 0x51, + 0x78, 0x01, 0x9a, 0x7c, 0x1c, 0x68, 0x06, 0x78, 0xa2, 0x7c, 0x1c, + 0x86, 0x7c, 0x1d, 0x58, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x1c, + 0x51, 0x51, 0x78, 0x01, 0xa2, 0x7c, 0x1c, 0x68, 0x06, 0x78, 0x9a, + 0x7c, 0x1c, 0x86, 0x7c, 0x1d, 0x58, 0x50, 0x90, 0x13, 0x06, 0x50, + 0x01, 0x1b, 0x05, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x76, 0xc2, 0x81, + 0xfb, 0x56, 0x01, 0x00, 0x80, 0x61, 0x62, 0xd0, 0x00, 0x7c, 0x1c, + 0x51, 0x51, 0x78, 0x01, 0xa2, 0x7c, 0x1c, 0x68, 0x06, 0x78, 0x92, + 0x7c, 0x1c, 0x86, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x76, 0x12, 0x78, + 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x12, 0x7c, 0x1c, 0x51, 0x7c, 0x1c, + 0x9d, 0x06, 0x76, 0x01, 0x0e, 0x77, 0x00, 0x7c, 0x1c, 0x79, 0x80, + 0x2d, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0xa2, + 0x7c, 0x1c, 0x68, 0x06, 0x78, 0x92, 0x7c, 0x1c, 0x86, 0x3e, 0x78, + 0x12, 0x76, 0x51, 0x79, 0x1a, 0x77, 0xd0, 0x10, 0x7c, 0x1c, 0x51, + 0x7c, 0x1c, 0x9d, 0x16, 0x76, 0x01, 0x1e, 0x77, 0x00, 0x7c, 0x1c, + 0x79, 0x77, 0x01, 0x3d, 0x01, 0x04, 0xcf, 0x9c, 0x62, 0xd0, 0x00, + 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0x82, 0x7c, 0x1c, 0x68, 0x06, + 0x78, 0x7a, 0x0e, 0x79, 0x00, 0x7c, 0x1c, 0x79, 0x7c, 0x1c, 0x51, + 0x51, 0x78, 0x01, 0x8a, 0x7c, 0x1c, 0x68, 0x06, 0x78, 0x82, 0x0e, + 0x79, 0x00, 0x7c, 0x1c, 0x79, 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, + 0x92, 0x7c, 0x1c, 0x68, 0x06, 0x78, 0x8a, 0x0e, 0x79, 0x00, 0x7c, + 0x1c, 0x79, 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0x9a, 0x7c, 0x1c, + 0x68, 0x06, 0x78, 0x92, 0x0e, 0x79, 0x00, 0x7c, 0x1c, 0x79, 0x7c, + 0x1c, 0x51, 0x51, 0x78, 0x01, 0xa2, 0x7c, 0x1c, 0x68, 0x06, 0x78, + 0x9a, 0x0e, 0x79, 0x00, 0x7c, 0x1c, 0x79, 0x7c, 0x1c, 0x51, 0x7c, + 0x1c, 0xb3, 0x53, 0x77, 0x7c, 0x1d, 0x40, 0x53, 0x74, 0x08, 0x51, + 0x75, 0x53, 0x73, 0x18, 0x53, 0x72, 0x65, 0x72, 0x6b, 0x73, 0x06, + 0x78, 0x92, 0x7c, 0x1c, 0x86, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x72, + 0x04, 0x78, 0x51, 0x73, 0x0c, 0x79, 0x51, 0x74, 0x04, 0x78, 0x51, + 0x75, 0x0c, 0x79, 0x70, 0xfb, 0x6e, 0x79, 0x6e, 0x78, 0x7c, 0x1d, + 0x21, 0x10, 0x52, 0x00, 0x7c, 0x06, 0xa1, 0x20, 0x62, 0xd0, 0x00, + 0x7c, 0x1c, 0x51, 0x06, 0x78, 0x67, 0x7c, 0x1c, 0x86, 0x3e, 0x78, + 0x53, 0x78, 0x50, 0x32, 0x12, 0x78, 0x50, 0x00, 0x1a, 0x79, 0xd0, + 0x1b, 0x55, 0x79, 0x01, 0x52, 0x00, 0xa0, 0x09, 0x62, 0xd0, 0x00, + 0x65, 0x79, 0x78, 0xbf, 0xf9, 0x62, 0xd0, 0x00, 0x51, 0xc5, 0x2a, + 0x79, 0x53, 0xc5, 0x80, 0x1b, 0x62, 0xd0, 0x00, 0x55, 0x79, 0x01, + 0x52, 0x00, 0xa0, 0x09, 0x62, 0xd0, 0x00, 0x65, 0x79, 0x78, 0xbf, + 0xf9, 0x62, 0xd0, 0x00, 0x51, 0x79, 0x73, 0x24, 0xc5, 0x62, 0xd0, + 0x00, 0x7c, 0x1c, 0x51, 0x51, 0x78, 0x01, 0xa2, 0x7c, 0x1c, 0x68, + 0x06, 0x78, 0x5f, 0x7c, 0x1c, 0x86, 0x3e, 0x78, 0x53, 0x78, 0x51, + 0x76, 0x12, 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x25, 0x52, 0x00, + 0x53, 0x78, 0x55, 0x79, 0x00, 0x06, 0x78, 0xba, 0x0e, 0x79, 0x00, + 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x7a, 0x78, 0x53, 0x77, 0x06, + 0x77, 0x01, 0x51, 0x79, 0x60, 0xd5, 0x51, 0x77, 0x3f, 0x78, 0x80, + 0x0a, 0x97, 0xcf, 0x40, 0x06, 0x78, 0xba, 0x7c, 0x1d, 0x4c, 0x97, + 0xc6, 0x40, 0x06, 0x78, 0xba, 0x97, 0xe9, 0x40, 0x50, 0x05, 0x3a, + 0x79, 0xd0, 0x41, 0x97, 0xab, 0x40, 0x51, 0x78, 0x01, 0x5f, 0x53, + 0x76, 0x51, 0x79, 0x09, 0x00, 0x53, 0x77, 0x06, 0x78, 0xa2, 0x97, + 0xce, 0x40, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x77, 0x7c, 0x1d, 0x40, + 0x02, 0x78, 0x53, 0x78, 0x51, 0x75, 0x0a, 0x79, 0x53, 0x79, 0x7c, + 0x1d, 0x21, 0x52, 0x00, 0x53, 0x78, 0x55, 0x79, 0x00, 0x06, 0x78, + 0xba, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd5, 0x50, 0x00, 0x3f, + 0x78, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xcd, 0x48, 0x62, 0xd0, 0x00, + 0x3c, 0xc0, 0x02, 0xb1, 0x73, 0x56, 0x00, 0x00, 0x81, 0x69, 0x3d, + 0x00, 0x00, 0xb0, 0x49, 0x62, 0xd0, 0x00, 0x97, 0x4f, 0x40, 0x51, + 0x78, 0x01, 0xa2, 0x97, 0x5f, 0x40, 0x51, 0x77, 0x08, 0x51, 0x76, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x7c, 0x1c, 0x21, 0x38, + 0xfc, 0x51, 0x71, 0x53, 0x76, 0x51, 0x70, 0x53, 0x77, 0x50, 0x00, + 0x08, 0x50, 0x03, 0x08, 0x51, 0x77, 0x08, 0x51, 0x76, 0x08, 0x7c, + 0x1b, 0xdd, 0x18, 0x53, 0x76, 0x18, 0x53, 0x77, 0x38, 0xfe, 0x06, + 0x78, 0x3e, 0x0e, 0x79, 0x00, 0x97, 0x37, 0x40, 0x80, 0xa0, 0x3d, + 0x00, 0x01, 0xb0, 0x3e, 0x62, 0xd0, 0x00, 0x97, 0x02, 0x40, 0x51, + 0x78, 0x01, 0xa2, 0x97, 0x12, 0x40, 0x51, 0x77, 0x08, 0x51, 0x76, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x7c, 0x1c, 0x21, 0x38, + 0xfc, 0x51, 0x71, 0x53, 0x76, 0x51, 0x70, 0x53, 0x77, 0x70, 0xfb, + 0x6e, 0x77, 0x6e, 0x76, 0x70, 0xfb, 0x6e, 0x77, 0x6e, 0x76, 0x06, + 0x78, 0x3e, 0x0e, 0x79, 0x00, 0x96, 0xf5, 0x40, 0x80, 0x5e, 0x3d, + 0x00, 0x02, 0xb0, 0x3e, 0x62, 0xd0, 0x00, 0x96, 0xc0, 0x40, 0x51, + 0x78, 0x01, 0xa2, 0x96, 0xd0, 0x40, 0x51, 0x77, 0x08, 0x51, 0x76, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x7c, 0x1c, 0x21, 0x38, + 0xfc, 0x51, 0x71, 0x53, 0x76, 0x51, 0x70, 0x53, 0x77, 0x70, 0xfb, + 0x6e, 0x77, 0x6e, 0x76, 0x70, 0xfb, 0x6e, 0x77, 0x6e, 0x76, 0x06, + 0x78, 0x3e, 0x0e, 0x79, 0x00, 0x96, 0xb3, 0x40, 0x80, 0x1c, 0x3d, + 0x00, 0x03, 0xb0, 0x17, 0x62, 0xd0, 0x00, 0x96, 0x7e, 0x40, 0x51, + 0x78, 0x01, 0xa2, 0x96, 0x8e, 0x40, 0x06, 0x78, 0x3e, 0x0e, 0x79, + 0x00, 0x96, 0x96, 0x40, 0x62, 0xd0, 0x00, 0x96, 0x68, 0x40, 0x51, + 0x78, 0x01, 0x5f, 0x96, 0x78, 0x40, 0x06, 0x78, 0x46, 0x0e, 0x79, + 0x00, 0x96, 0x80, 0x40, 0x96, 0x55, 0x40, 0x51, 0x78, 0x01, 0x5f, + 0x96, 0x65, 0x40, 0x51, 0x78, 0x01, 0xa2, 0x53, 0x74, 0x51, 0x79, + 0x97, 0x71, 0x40, 0x51, 0x76, 0x12, 0x74, 0x51, 0x77, 0x1a, 0x75, + 0xd0, 0x2b, 0x97, 0x19, 0x40, 0x51, 0x76, 0x01, 0x5f, 0x53, 0x74, + 0x51, 0x77, 0x97, 0x59, 0x40, 0x06, 0x76, 0xa2, 0x0e, 0x77, 0x00, + 0x51, 0x77, 0x60, 0xd4, 0x3e, 0x76, 0x53, 0x77, 0x3e, 0x76, 0x12, + 0x74, 0x54, 0x04, 0x51, 0x77, 0x1a, 0x75, 0x54, 0x03, 0x80, 0x07, + 0x56, 0x04, 0x00, 0x56, 0x03, 0x00, 0x62, 0xd0, 0x00, 0x06, 0x78, + 0x36, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd5, 0x52, 0x03, 0x3f, + 0x78, 0x52, 0x04, 0x3f, 0x78, 0x77, 0x00, 0x3d, 0x00, 0x04, 0xce, + 0x94, 0x62, 0xd0, 0x00, 0x3c, 0xc0, 0x02, 0xa0, 0x1e, 0x3c, 0xc2, + 0x00, 0xa0, 0x19, 0x55, 0xc2, 0x00, 0x55, 0xcd, 0x00, 0x50, 0x75, + 0x08, 0x50, 0x30, 0x08, 0x90, 0x0e, 0x38, 0xfe, 0x7c, 0x0c, 0x09, + 0x10, 0x7c, 0x08, 0x5d, 0x20, 0x38, 0xf9, 0x20, 0x7f, 0x10, 0x4f, + 0x80, 0x02, 0x40, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x78, 0x52, + 0xfb, 0x53, 0x79, 0x51, 0x78, 0x11, 0x01, 0x54, 0xfc, 0x51, 0x79, + 0x19, 0x00, 0x54, 0xfb, 0x3c, 0x79, 0x00, 0xbf, 0xe4, 0x3c, 0x78, + 0x00, 0xbf, 0xdf, 0x20, 0x7f, 0x10, 0x7c, 0x05, 0x28, 0x7c, 0x05, + 0x05, 0x7c, 0x04, 0xe2, 0x7c, 0x04, 0xbf, 0x20, 0x7f, 0x10, 0x7c, + 0x05, 0x24, 0x7c, 0x05, 0x01, 0x7c, 0x04, 0xde, 0x7c, 0x04, 0xbb, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x05, 0x62, 0xd0, 0x00, 0x51, 0x68, + 0x54, 0x02, 0x51, 0x67, 0x54, 0x01, 0x56, 0x04, 0x00, 0x56, 0x00, + 0x00, 0x56, 0x03, 0x00, 0x80, 0x52, 0x62, 0xd0, 0x00, 0x95, 0x5e, + 0x40, 0x06, 0x78, 0x67, 0x95, 0x8d, 0x40, 0x3e, 0x78, 0x53, 0x78, + 0x50, 0x32, 0x12, 0x78, 0x50, 0x00, 0x1a, 0x79, 0xd0, 0x03, 0x77, + 0x03, 0x62, 0xd0, 0x00, 0x95, 0x42, 0x40, 0x06, 0x78, 0x67, 0x95, + 0x71, 0x40, 0x3e, 0x78, 0x53, 0x78, 0x52, 0x02, 0x12, 0x78, 0x52, + 0x01, 0x1a, 0x79, 0xd0, 0x1a, 0x95, 0x2b, 0x40, 0x06, 0x78, 0x67, + 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x01, + 0x3e, 0x78, 0x54, 0x02, 0x52, 0x00, 0x54, 0x04, 0x77, 0x00, 0x3d, + 0x00, 0x04, 0xcf, 0xab, 0x50, 0x01, 0x3b, 0x03, 0xd0, 0x08, 0x62, + 0xd0, 0x00, 0x50, 0xe1, 0x80, 0x06, 0x52, 0x04, 0x62, 0xd0, 0x00, + 0x38, 0xfb, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x62, 0xd0, 0x00, + 0x3c, 0xc2, 0x00, 0xa0, 0x07, 0x51, 0x2c, 0x29, 0x10, 0x53, 0x2c, + 0x62, 0xd0, 0x00, 0x3c, 0xc3, 0x00, 0xb0, 0x73, 0x70, 0xfe, 0x51, + 0xce, 0x01, 0x01, 0x53, 0x2c, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, + 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, + 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, + 0x20, 0x53, 0x79, 0x47, 0x79, 0x20, 0xa0, 0x03, 0x80, 0x12, 0x50, + 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, 0xe4, 0x38, 0xfe, 0x77, 0x00, + 0x3d, 0x00, 0xc8, 0xcf, 0xdf, 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, + 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x79, 0x47, 0x79, + 0x20, 0xb0, 0x03, 0x80, 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, + 0x9e, 0xbd, 0x38, 0xfe, 0x77, 0x00, 0x3d, 0x00, 0x1e, 0xcf, 0xdf, + 0x62, 0xd0, 0x00, 0x51, 0x2c, 0x29, 0x08, 0x53, 0x2c, 0x43, 0x00, + 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x62, 0xd0, + 0x00, 0x3c, 0xc2, 0x00, 0xa0, 0x07, 0x51, 0x2c, 0x29, 0x10, 0x53, + 0x2c, 0x62, 0xd0, 0x00, 0x3c, 0xc3, 0x01, 0xb0, 0x6a, 0x70, 0xfe, + 0x51, 0xce, 0x01, 0x09, 0x53, 0x2c, 0x71, 0x01, 0x62, 0xe3, 0x38, + 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, + 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, + 0x00, 0x20, 0x53, 0x79, 0x47, 0x79, 0x20, 0xa0, 0x03, 0x80, 0x12, + 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, 0x54, 0x38, 0xfe, 0x77, + 0x00, 0x3d, 0x00, 0xc8, 0xcf, 0xdf, 0x56, 0x00, 0x00, 0x80, 0x1e, + 0x10, 0x7c, 0x06, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x79, 0x47, + 0x79, 0x20, 0xb0, 0x03, 0x80, 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, + 0x08, 0x9e, 0x2d, 0x38, 0xfe, 0x77, 0x00, 0x3d, 0x00, 0x1e, 0xcf, + 0xdf, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, + 0x02, 0x62, 0xd0, 0x00, 0x51, 0x2c, 0x54, 0x00, 0x51, 0x2f, 0x54, + 0x01, 0x3d, 0x00, 0x01, 0xb0, 0x1d, 0x3c, 0xca, 0x00, 0xb0, 0x18, + 0x55, 0xc6, 0x00, 0x55, 0xb7, 0x00, 0x55, 0xb6, 0x00, 0x55, 0xb9, + 0x00, 0x55, 0xb8, 0x00, 0x55, 0x2c, 0x00, 0x55, 0xca, 0x01, 0x80, + 0x8e, 0x3d, 0x00, 0x02, 0xb0, 0x1a, 0x62, 0xd0, 0x00, 0x3c, 0xca, + 0x01, 0xb0, 0x12, 0x55, 0xc6, 0x01, 0x55, 0xc7, 0x00, 0x94, 0x5e, + 0x40, 0x55, 0x2c, 0x00, 0x55, 0xca, 0x00, 0x80, 0x70, 0x52, 0x00, + 0x21, 0xf0, 0x39, 0x40, 0xb0, 0x0c, 0x62, 0xd0, 0x00, 0x55, 0xc0, + 0x02, 0x55, 0x2c, 0x00, 0x80, 0x5d, 0x52, 0x00, 0x21, 0xf0, 0x39, + 0x50, 0xb0, 0x55, 0x3d, 0x01, 0x01, 0xb0, 0x15, 0x62, 0xd0, 0x00, + 0x55, 0xcb, 0x01, 0x7c, 0x0e, 0xb8, 0x62, 0xd0, 0x00, 0x51, 0x31, + 0x29, 0x80, 0x53, 0x31, 0x80, 0x27, 0x3d, 0x01, 0x02, 0xb0, 0x16, + 0x62, 0xd0, 0x00, 0x51, 0x30, 0x53, 0x52, 0x51, 0x30, 0x53, 0x53, + 0x51, 0x30, 0x53, 0x54, 0x51, 0x30, 0x53, 0x55, 0x80, 0x0d, 0x3d, + 0x01, 0x04, 0xb0, 0x08, 0x62, 0xd0, 0x00, 0x51, 0x30, 0x53, 0x0d, + 0x62, 0xd0, 0x00, 0x55, 0x2d, 0x0b, 0x55, 0x2e, 0x03, 0x56, 0x00, + 0x00, 0x56, 0x01, 0x00, 0x55, 0x2f, 0x00, 0x55, 0x2c, 0x00, 0x38, + 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x04, 0x62, 0xd0, 0x00, 0x3c, + 0xc6, 0x00, 0xa0, 0x13, 0x9d, 0x76, 0x62, 0xd0, 0x00, 0x3c, 0xc7, + 0x00, 0xb0, 0xe8, 0x55, 0xc7, 0x01, 0x7c, 0x0c, 0x09, 0x80, 0xe0, + 0x62, 0xd0, 0x00, 0x3c, 0xc9, 0x00, 0xb0, 0x27, 0x3c, 0xc8, 0x01, + 0xb0, 0x22, 0x51, 0xce, 0x53, 0x78, 0x55, 0x79, 0x00, 0x65, 0x78, + 0x6b, 0x79, 0x06, 0x78, 0x67, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, + 0xd4, 0x3e, 0x78, 0x54, 0x01, 0x3e, 0x78, 0x54, 0x02, 0x51, 0xce, + 0x54, 0x00, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0xb6, 0xd0, 0x08, + 0x10, 0x7c, 0x05, 0x28, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x05, 0x24, + 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0xb7, 0xd0, 0x08, 0x10, + 0x7c, 0x05, 0x05, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x05, 0x01, 0x20, + 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0xb8, 0xd0, 0x08, 0x10, 0x7c, + 0x04, 0xe2, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0xde, 0x20, 0x62, + 0xd0, 0x00, 0x50, 0x01, 0x3a, 0xb9, 0xd0, 0x08, 0x10, 0x7c, 0x04, + 0xbf, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0xbb, 0x20, 0x7c, 0x11, + 0x2d, 0x62, 0xd0, 0x00, 0x3c, 0xc9, 0x00, 0xb0, 0x53, 0x3c, 0xc8, + 0x01, 0xb0, 0x4e, 0x3c, 0xc2, 0x00, 0xb0, 0x40, 0x92, 0x68, 0x40, + 0x51, 0x78, 0x01, 0x5f, 0x92, 0x78, 0x40, 0x06, 0x76, 0x32, 0x0e, + 0x77, 0x00, 0x06, 0x78, 0xa2, 0x92, 0x8a, 0x40, 0x3e, 0x78, 0x53, + 0x78, 0x51, 0x76, 0x12, 0x78, 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x1c, + 0x92, 0x44, 0x40, 0x51, 0x78, 0x01, 0xa2, 0x92, 0x54, 0x40, 0x52, + 0x02, 0x14, 0x76, 0x52, 0x01, 0x1c, 0x77, 0x06, 0x78, 0x5f, 0x0e, + 0x79, 0x00, 0x92, 0x54, 0x40, 0x62, 0xd0, 0x00, 0x55, 0xc9, 0x01, + 0x55, 0xc8, 0x00, 0x38, 0xfc, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x03, + 0x56, 0x02, 0x00, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x3e, + 0x62, 0xd0, 0x00, 0x92, 0x0a, 0x40, 0x52, 0xfc, 0x04, 0x78, 0x52, + 0xfb, 0x0c, 0x79, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x53, 0x79, + 0x3e, 0x78, 0x53, 0x78, 0x52, 0x02, 0x12, 0x78, 0x52, 0x01, 0x1a, + 0x79, 0xd0, 0x18, 0x91, 0xe9, 0x40, 0x52, 0xfc, 0x04, 0x78, 0x52, + 0xfb, 0x0c, 0x79, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x54, 0x01, + 0x3e, 0x78, 0x54, 0x02, 0x77, 0x00, 0x52, 0x00, 0x3b, 0xfa, 0xcf, + 0xbe, 0x62, 0xd0, 0x00, 0x52, 0x02, 0x53, 0x78, 0x52, 0x01, 0x53, + 0x79, 0x38, 0xfd, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x71, 0x10, + 0x41, 0x01, 0xf7, 0x43, 0x00, 0x08, 0x70, 0xcf, 0x43, 0x00, 0x08, + 0x50, 0x00, 0x08, 0x50, 0x64, 0x08, 0x9b, 0xe1, 0x71, 0x10, 0x41, + 0x01, 0xf7, 0x41, 0x00, 0xf7, 0x70, 0xcf, 0x43, 0x00, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x64, 0x08, 0x9b, 0xcc, 0x38, 0xfc, 0x5d, 0x00, + 0x62, 0xd0, 0x00, 0x53, 0x79, 0x26, 0x79, 0x08, 0x3c, 0x79, 0x08, + 0xb0, 0x09, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x07, 0x56, + 0x01, 0x01, 0x56, 0x00, 0x00, 0x52, 0x01, 0x62, 0xd0, 0x00, 0x53, + 0xc0, 0x71, 0x10, 0x43, 0x00, 0x08, 0x41, 0x01, 0xf7, 0x70, 0xcf, + 0x3c, 0xc0, 0x00, 0xb0, 0x04, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, + 0x7f, 0x10, 0x4f, 0x38, 0x01, 0x62, 0xe3, 0x38, 0x10, 0x50, 0x02, + 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x91, 0x20, + 0x10, 0x50, 0xff, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, 0x08, 0x08, + 0x50, 0x00, 0x08, 0x50, 0xa2, 0x08, 0x7c, 0x04, 0x76, 0x38, 0xfd, + 0x20, 0x56, 0x00, 0x00, 0x80, 0x6e, 0x62, 0xd0, 0x00, 0x91, 0x1d, + 0x40, 0x51, 0x78, 0x01, 0x5f, 0x91, 0x2d, 0x40, 0x06, 0x78, 0xa2, + 0x91, 0x45, 0x40, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x76, 0x12, 0x78, + 0x51, 0x77, 0x1a, 0x79, 0xd0, 0x3d, 0x90, 0xff, 0x40, 0x51, 0x78, + 0x01, 0x5f, 0x91, 0x0f, 0x40, 0x06, 0x78, 0xa2, 0x91, 0x27, 0x40, + 0x92, 0x10, 0x40, 0x51, 0x79, 0x10, 0x7c, 0x03, 0x91, 0x20, 0x62, + 0xd0, 0x00, 0x90, 0xe2, 0x40, 0x51, 0x78, 0x01, 0x5f, 0x90, 0xf2, + 0x40, 0x06, 0x78, 0xa2, 0x91, 0x0a, 0x40, 0x91, 0xf3, 0x40, 0x26, + 0x79, 0x00, 0x51, 0x78, 0x10, 0x7c, 0x03, 0x91, 0x20, 0x80, 0x0f, + 0x10, 0x50, 0x00, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, 0x00, 0x7c, + 0x03, 0x91, 0x20, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x8f, 0x10, + 0x50, 0x00, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, 0x01, 0x7c, 0x03, + 0x91, 0x20, 0x10, 0x50, 0x00, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, + 0x01, 0x7c, 0x03, 0x91, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x91, + 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x91, 0x7c, 0x04, 0x6d, 0x20, + 0x50, 0x13, 0x08, 0x50, 0x88, 0x08, 0x9a, 0xb8, 0x38, 0xfe, 0x38, + 0xff, 0x20, 0x7f, 0x7f, 0x10, 0x4f, 0x7c, 0x1b, 0xe8, 0x20, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, + 0x00, 0x53, 0x70, 0x53, 0x71, 0x55, 0x6f, 0x10, 0x66, 0xfc, 0x6c, + 0xfb, 0x6b, 0x70, 0x6b, 0x71, 0x51, 0x70, 0x1b, 0xfa, 0x51, 0x71, + 0x1b, 0xf9, 0xc0, 0x09, 0x53, 0x71, 0x52, 0xfa, 0x1c, 0x70, 0x77, + 0xfc, 0x7a, 0x6f, 0xbf, 0xe3, 0x51, 0x70, 0x54, 0xfa, 0x51, 0x71, + 0x54, 0xf9, 0x18, 0x60, 0xd0, 0x7f, 0x10, 0x4f, 0x5d, 0xd0, 0x08, + 0x62, 0xd0, 0x00, 0x50, 0x00, 0x53, 0x71, 0x53, 0x70, 0x55, 0x6f, + 0x10, 0x6f, 0xf9, 0x6f, 0xfa, 0xd0, 0x09, 0x52, 0xfc, 0x04, 0x71, + 0x52, 0xfb, 0x0c, 0x70, 0x66, 0xfc, 0x6c, 0xfb, 0x7a, 0x6f, 0xbf, + 0xeb, 0x18, 0x60, 0xd0, 0x20, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x52, + 0x00, 0x53, 0x78, 0x55, 0x79, 0x00, 0x65, 0x78, 0x6b, 0x79, 0x7f, + 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x78, 0x55, 0x79, 0x00, 0x7f, + 0x53, 0x76, 0x51, 0x79, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x76, 0x53, + 0x77, 0x3e, 0x76, 0x53, 0x76, 0x7f, 0x51, 0x79, 0x60, 0xd5, 0x51, + 0x77, 0x3f, 0x78, 0x51, 0x76, 0x3f, 0x78, 0x7f, 0x0e, 0x79, 0x00, + 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x53, 0x79, 0x7f, 0x60, 0xd4, + 0x3e, 0x76, 0x53, 0x77, 0x3e, 0x76, 0x53, 0x76, 0x7f, 0x06, 0x78, + 0xa2, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd4, 0x3e, 0x78, 0x53, + 0x77, 0x3e, 0x78, 0x16, 0x78, 0x02, 0x53, 0x76, 0x7f, 0x51, 0x78, + 0x01, 0xa2, 0x53, 0x76, 0x51, 0x79, 0x09, 0x00, 0x7f, 0x51, 0x71, + 0x53, 0x76, 0x51, 0x70, 0x53, 0x77, 0x51, 0x76, 0x02, 0x78, 0x53, + 0x78, 0x51, 0x77, 0x0a, 0x79, 0x7f, 0x53, 0x76, 0x51, 0x79, 0x09, + 0x00, 0x60, 0xd5, 0x52, 0x20, 0x3f, 0x76, 0x52, 0x21, 0x3f, 0x76, + 0x7f, 0x51, 0x76, 0x02, 0x78, 0x53, 0x78, 0x51, 0x77, 0x0a, 0x79, + 0x7f, 0x0e, 0x79, 0x00, 0x51, 0x79, 0x60, 0xd5, 0x52, 0x20, 0x3f, + 0x78, 0x52, 0x21, 0x3f, 0x78, 0x7f, 0x60, 0xd5, 0x52, 0x20, 0x3f, + 0x76, 0x52, 0x21, 0x3f, 0x76, 0x7f, 0x0e, 0x77, 0x00, 0x51, 0x77, + 0x60, 0xd5, 0x51, 0x79, 0x3f, 0x76, 0x7f, 0x55, 0xb7, 0x08, 0x55, + 0xb6, 0x08, 0x55, 0xb9, 0x08, 0x55, 0xb8, 0x08, 0x7f, 0x70, 0xfb, + 0x6e, 0x79, 0x6e, 0x78, 0x51, 0x77, 0x60, 0xd5, 0x51, 0x79, 0x3f, + 0x76, 0x51, 0x78, 0x3f, 0x76, 0x7f, 0x52, 0x00, 0x53, 0x76, 0x55, + 0x77, 0x00, 0x65, 0x76, 0x6b, 0x77, 0x7f, 0x60, 0xd4, 0x3e, 0x76, + 0x53, 0x75, 0x3e, 0x76, 0x16, 0x76, 0x02, 0x7f, 0x0e, 0x79, 0x00, + 0x51, 0x79, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x78, 0x7f, 0x3e, 0x78, + 0x12, 0x76, 0x54, 0x06, 0x51, 0x79, 0x1a, 0x77, 0x54, 0x05, 0x7f, + 0x3e, 0x78, 0x12, 0x76, 0x54, 0x04, 0x51, 0x79, 0x1a, 0x77, 0x54, + 0x03, 0x7f, 0x3e, 0x78, 0x53, 0x78, 0x51, 0x76, 0x14, 0x78, 0x51, + 0x77, 0x1c, 0x79, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x74, 0x53, + 0x75, 0x3e, 0x74, 0x53, 0x74, 0x7f, 0x00, 0x2c, 0x00, 0x22, 0x00, + 0x7a, 0x00, 0x28, 0x00, 0xaa, 0x04, 0x2a, 0x31, 0x33, 0x39, 0x00, + 0xae, 0x00, 0x05, 0x00, 0xb3, 0x07, 0x01, 0x02, 0x03, 0x08, 0x08, + 0x08, 0x08, 0x00, 0xba, 0x00, 0x0a, 0x00, 0xc4, 0x04, 0x03, 0x00, + 0x01, 0x01, 0x00, 0xc8, 0x00, 0x07, 0xff, 0x00, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypressbln/touchkey_fw_NTT.h b/drivers/input/keyboard/cypressbln/touchkey_fw_NTT.h new file mode 100644 index 0000000..b5b5564 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/touchkey_fw_NTT.h @@ -0,0 +1,685 @@ +unsigned char firmware_data[] = { + 0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x04, 0x6f, 0x7e, 0x7e, 0x30, 0x30, 0x30, + 0x7d, 0x05, 0xa4, 0x7e, 0x7d, 0x04, 0x28, 0x7e, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x71, 0x10, 0x41, 0xd7, + 0x9f, 0x70, 0xef, 0x40, 0x71, 0x10, 0x62, 0xe3, 0x00, 0x70, 0xef, 0x50, + 0x80, 0x4e, 0x5d, 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, 0xfa, 0x01, 0x40, + 0x4f, 0x5b, 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, + 0x40, 0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, 0xef, 0x18, 0x60, + 0xd5, 0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, 0x71, 0x10, 0x41, 0xe1, 0xfe, + 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, 0x03, 0x50, 0x00, 0x4e, 0x62, + 0xd3, 0x03, 0x62, 0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, 0x00, 0x71, + 0xc0, 0x7c, 0x02, 0x71, 0x62, 0xd0, 0x00, 0x50, 0x02, 0x57, 0x6f, 0x08, + 0x28, 0x53, 0x40, 0x18, 0x75, 0x09, 0x00, 0x28, 0x4b, 0x51, 0x40, 0x80, + 0x04, 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, 0x08, 0x28, 0x60, 0xd5, 0x74, + 0xa0, 0x4b, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x53, 0x40, 0x18, 0x75, + 0x09, 0x00, 0x08, 0x28, 0xa0, 0x1c, 0x53, 0x3f, 0x18, 0x75, 0x09, 0x00, + 0x08, 0x28, 0x3f, 0x40, 0x47, 0x40, 0xff, 0xb0, 0x06, 0x5d, 0xd5, 0x74, + 0x60, 0xd5, 0x18, 0x7a, 0x3f, 0xbf, 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, + 0x00, 0x08, 0x28, 0x53, 0x3f, 0x50, 0x00, 0x3f, 0x40, 0x47, 0x40, 0xff, + 0xb0, 0x08, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x3f, 0xbf, + 0xef, 0x18, 0x8f, 0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, 0xef, + 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, 0x10, 0x62, + 0xe0, 0x12, 0x70, 0xef, 0x62, 0xe2, 0x00, 0x7c, 0x09, 0x1c, 0x8f, 0xff, + 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x61, 0x00, + 0xfd, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa0, 0x00, + 0xa1, 0x80, 0xa2, 0x80, 0xa3, 0x0c, 0xa8, 0x00, 0xa6, 0x00, 0xa7, 0x00, + 0x7c, 0x33, 0x7a, 0x00, 0x7b, 0x04, 0x79, 0x00, 0x36, 0x00, 0x37, 0x00, + 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, + 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, + 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, + 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, + 0xd6, 0x44, 0xcf, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xc8, 0x00, 0xcc, 0x00, + 0xc9, 0x00, 0xd7, 0x00, 0x2b, 0x00, 0xb0, 0x00, 0xb3, 0x02, 0xb6, 0x00, + 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0xff, 0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x7f, + 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0xff, 0x54, 0x00, 0x55, 0x00, 0x56, + 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0xdc, + 0x00, 0xe2, 0x00, 0xdd, 0x00, 0xd8, 0x02, 0xd9, 0x00, 0xda, 0x00, 0xdb, + 0x00, 0xdf, 0x00, 0x29, 0x00, 0x30, 0x00, 0xbd, 0x00, 0xff, 0x70, 0xef, + 0x62, 0x00, 0x00, 0x71, 0x10, 0x62, 0x00, 0x08, 0x62, 0x01, 0x92, 0x70, + 0xef, 0x62, 0x04, 0x17, 0x71, 0x10, 0x62, 0x04, 0x14, 0x62, 0x05, 0xa8, + 0x70, 0xef, 0x62, 0x08, 0x00, 0x71, 0x10, 0x62, 0x08, 0x00, 0x62, 0x09, + 0x28, 0x70, 0xef, 0x62, 0x0c, 0x00, 0x71, 0x10, 0x62, 0x0c, 0x00, 0x62, + 0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, 0x00, 0x71, 0x10, 0x62, 0x10, 0x00, + 0x62, 0x11, 0x00, 0x70, 0xef, 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, 0x62, + 0x09, 0x00, 0x62, 0x0d, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, 0x7f, 0x13, + 0xba, 0x55, 0x02, 0x00, 0x55, 0x03, 0x17, 0x55, 0x04, 0x00, 0x7c, 0x02, + 0x81, 0x7c, 0x02, 0x1a, 0x7f, 0x10, 0x70, 0xef, 0x50, 0x00, 0x67, 0x50, + 0x01, 0x57, 0x72, 0x7c, 0x02, 0x9c, 0x50, 0x01, 0x67, 0x50, 0x01, 0x57, + 0xf3, 0x7c, 0x02, 0x9c, 0x70, 0xef, 0x20, 0x7f, 0x38, 0x02, 0x10, 0x08, + 0x4f, 0x56, 0xfc, 0x00, 0xd0, 0x04, 0x56, 0xfc, 0x01, 0x18, 0x20, 0x70, + 0xef, 0x62, 0xe3, 0x00, 0x10, 0x08, 0x28, 0x39, 0xff, 0xa0, 0x1f, 0x4f, + 0x48, 0xfc, 0x01, 0xa0, 0x03, 0x71, 0x10, 0x54, 0xfd, 0x18, 0x20, 0x75, + 0x09, 0x00, 0x10, 0x08, 0x28, 0x4f, 0x59, 0xfd, 0x61, 0x00, 0x18, 0x20, + 0x75, 0x09, 0x00, 0x8f, 0xd7, 0x38, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x2e, 0x02, 0x08, 0x51, 0x02, 0x60, 0x00, 0x71, + 0x10, 0x41, 0x01, 0xf7, 0x43, 0x00, 0x08, 0x70, 0xef, 0x7f, 0x62, 0xd0, + 0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, 0x21, 0xf8, 0x29, 0x00, + 0x70, 0xfe, 0x60, 0xe0, 0x70, 0xef, 0x4b, 0x4b, 0x4b, 0x4b, 0x51, 0x02, + 0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, + 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, + 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, + 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, + 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, + 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, + 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, + 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, + 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, + 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x47, 0x00, 0x00, 0x49, + 0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, 0x01, 0x79, 0xbf, 0xfe, 0x18, + 0x71, 0x10, 0x60, 0xe0, 0x70, 0xef, 0x71, 0x01, 0x7f, 0x08, 0x67, 0x67, + 0x67, 0x67, 0x21, 0x0f, 0xff, 0x2e, 0x9f, 0x4e, 0x18, 0x21, 0x0f, 0xff, + 0x27, 0x9f, 0x47, 0x7f, 0x08, 0x10, 0x28, 0xa0, 0x0b, 0x9f, 0x3f, 0x20, + 0x18, 0x75, 0xdf, 0xf5, 0x74, 0x8f, 0xf2, 0x38, 0xfe, 0x7f, 0x52, 0x00, + 0xa0, 0x08, 0x10, 0x9f, 0x2d, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, 0x71, + 0xc0, 0x7f, 0x50, 0x0d, 0x9f, 0x20, 0x50, 0x0a, 0x9f, 0x1c, 0x7f, 0x70, + 0xbf, 0x62, 0xd3, 0x03, 0x4f, 0x52, 0xfb, 0xa0, 0x15, 0x7b, 0xfb, 0x52, + 0xfc, 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, 0x05, 0x4f, 0x62, 0xd3, + 0x03, 0x77, 0xfd, 0x8f, 0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x3d, 0xfa, + 0x00, 0xb0, 0x06, 0x3d, 0xfb, 0x00, 0xa0, 0x18, 0x10, 0x52, 0xfc, 0x59, + 0xfd, 0x28, 0x9e, 0xe6, 0x20, 0x07, 0xfd, 0x01, 0x0f, 0xfc, 0x00, 0x17, + 0xfb, 0x01, 0x1f, 0xfa, 0x00, 0x8f, 0xe0, 0x7f, 0x7e, 0x50, 0x01, 0x80, + 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, + 0xef, 0x80, 0x04, 0x2e, 0x03, 0x10, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, + 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xfb, + 0x80, 0x04, 0x2e, 0x03, 0x04, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, + 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, 0x70, 0x3f, 0x71, + 0x80, 0x5d, 0xd3, 0x08, 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x51, 0x08, + 0x60, 0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, 0xa0, 0x09, 0x26, 0x05, + 0xf0, 0x2e, 0x05, 0x00, 0x80, 0x0b, 0x49, 0xd7, 0x20, 0xa0, 0x06, 0x41, + 0xd7, 0xdf, 0x80, 0xac, 0x51, 0x05, 0x21, 0x0e, 0xe0, 0x01, 0x80, 0x11, + 0x80, 0x6d, 0x80, 0x7f, 0x80, 0x4d, 0x80, 0x9c, 0x80, 0x9a, 0x80, 0x98, + 0x80, 0x96, 0x80, 0x9d, 0x5d, 0xd8, 0x21, 0xfe, 0x39, 0x40, 0xa0, 0x06, + 0x62, 0xd7, 0x00, 0x80, 0x90, 0x49, 0xd8, 0x01, 0xb0, 0x15, 0x55, 0x0c, + 0x02, 0x26, 0x07, 0x00, 0x26, 0x06, 0x00, 0x26, 0x05, 0xf0, 0x2e, 0x05, + 0x04, 0x62, 0xd7, 0x10, 0x80, 0x77, 0x55, 0x0c, 0x01, 0x26, 0x05, 0xf0, + 0x2e, 0x05, 0x06, 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, + 0x00, 0x60, 0xd8, 0x76, 0x07, 0x62, 0xd7, 0x14, 0x80, 0x5b, 0x51, 0x0a, + 0x78, 0x3a, 0x07, 0xc0, 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, + 0x60, 0xd8, 0x76, 0x07, 0x2e, 0x05, 0x20, 0x60, 0xd8, 0x62, 0xd7, 0x04, + 0x80, 0x3f, 0x5d, 0xd8, 0x3a, 0x0a, 0xd0, 0x2b, 0xa0, 0x29, 0x53, 0x07, + 0x53, 0x06, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x80, 0x18, 0x51, 0x0b, + 0x78, 0x3a, 0x07, 0xc0, 0x16, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x5d, 0xd8, + 0x54, 0x00, 0x2e, 0x05, 0x10, 0x76, 0x07, 0x80, 0x01, 0x62, 0xd7, 0x10, + 0x80, 0x0f, 0x62, 0xd7, 0x00, 0x80, 0x0a, 0x26, 0x05, 0xf0, 0x2e, 0x05, + 0x00, 0x55, 0x0c, 0x00, 0x18, 0x60, 0xd0, 0x18, 0x60, 0xd3, 0x20, 0x18, + 0x7e, 0x62, 0xc8, 0x00, 0x55, 0x0c, 0x00, 0x90, 0x0e, 0x90, 0x18, 0x7f, + 0x62, 0xd0, 0x00, 0x51, 0x05, 0x21, 0xb0, 0x26, 0x05, 0x4f, 0x7f, 0x08, + 0x5d, 0xe0, 0x21, 0x7f, 0x60, 0xe0, 0x43, 0xe0, 0x80, 0x18, 0x7f, 0x43, + 0xd6, 0x31, 0x7f, 0x62, 0xd0, 0x00, 0x4f, 0x52, 0xfd, 0x53, 0x0a, 0x52, + 0xfc, 0x53, 0x0b, 0x52, 0xfb, 0x53, 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x02, 0x08, 0x02, 0x20, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x05, 0x08, 0x5d, 0xa4, 0x04, 0x1b, 0x5d, 0xa5, 0x0c, + 0x1a, 0x55, 0x1c, 0x01, 0x18, 0x7e, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, + 0xbf, 0x53, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x5b, 0x62, 0xd3, + 0x00, 0x13, 0x4b, 0x62, 0xd3, 0x00, 0x54, 0x4f, 0x62, 0xd3, 0x00, 0x52, + 0x5a, 0x62, 0xd3, 0x00, 0x1b, 0x4a, 0x62, 0xd3, 0x00, 0x54, 0x4e, 0x48, + 0x4e, 0x80, 0xb0, 0x33, 0x3d, 0x4e, 0x00, 0xb0, 0x77, 0x51, 0x0d, 0x3b, + 0x4f, 0xc0, 0x71, 0x52, 0x4f, 0x58, 0x1e, 0x01, 0x00, 0x6d, 0x62, 0xd3, + 0x00, 0x05, 0x41, 0xc0, 0x09, 0x51, 0x0f, 0x3b, 0x41, 0xd0, 0x12, 0xa0, + 0x10, 0x56, 0x41, 0x00, 0x5b, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x07, 0x4b, + 0x01, 0x0f, 0x4a, 0x00, 0x80, 0x3d, 0x3d, 0x4e, 0xff, 0xb0, 0x09, 0x50, + 0xff, 0x12, 0x0e, 0x3b, 0x4f, 0xc0, 0x1c, 0x62, 0xd3, 0x00, 0x56, 0x4f, + 0x00, 0x56, 0x4e, 0x00, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x48, + 0x78, 0x54, 0x48, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, 0xd3, + 0x00, 0x52, 0x5b, 0x62, 0xd3, 0x00, 0x54, 0x4b, 0x62, 0xd3, 0x00, 0x52, + 0x5a, 0x62, 0xd3, 0x00, 0x54, 0x4a, 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, + 0x00, 0x56, 0x4f, 0x00, 0x56, 0x4e, 0x00, 0x5b, 0x67, 0x5c, 0x62, 0xd3, + 0x00, 0x51, 0x12, 0x54, 0x48, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0xbf, + 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x08, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x43, + 0x53, 0x19, 0x55, 0x18, 0x00, 0x18, 0x08, 0x90, 0x7e, 0x62, 0xd3, 0x00, + 0x23, 0x45, 0xb0, 0x2c, 0x51, 0x10, 0x04, 0x19, 0x0e, 0x18, 0x00, 0x18, + 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x4f, 0x12, 0x19, 0x52, 0x4e, 0x1a, + 0x18, 0xc0, 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x46, 0x78, + 0x54, 0x46, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, 0x51, + 0x10, 0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, + 0x52, 0x4f, 0x12, 0x19, 0x52, 0x4e, 0x1a, 0x18, 0xc0, 0x0e, 0x5b, 0x67, + 0x90, 0x31, 0x62, 0xd3, 0x00, 0x2d, 0x45, 0x50, 0x01, 0x80, 0x24, 0x5b, + 0x67, 0x08, 0x90, 0x23, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x45, 0x62, 0xd3, + 0x00, 0x20, 0x51, 0x11, 0x54, 0x46, 0x50, 0x00, 0x80, 0x0d, 0x5b, 0x67, + 0x90, 0x0d, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x45, 0x50, 0x00, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x5c, 0x18, 0x21, 0x07, 0xf0, + 0x01, 0x7f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x70, 0xbf, + 0x70, 0xbf, 0x62, 0xd3, 0x00, 0x50, 0x02, 0x78, 0x08, 0x5c, 0x56, 0x43, + 0x28, 0x18, 0x78, 0xdf, 0xf8, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x91, + 0x7a, 0x70, 0xbf, 0x18, 0x08, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x5b, + 0x62, 0xd3, 0x00, 0x54, 0x4b, 0x62, 0xd3, 0x00, 0x52, 0x5a, 0x62, 0xd3, + 0x00, 0x54, 0x4a, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x62, 0xd0, 0x00, 0x55, 0x14, 0x00, 0x50, 0x02, 0x78, 0x08, 0x9f, 0x0e, + 0x39, 0x01, 0xb0, 0x04, 0x55, 0x14, 0x01, 0x18, 0x78, 0xdf, 0xf3, 0x51, + 0x14, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x9e, 0x42, 0x18, 0x78, 0xdf, 0xfa, + 0x7f, 0x98, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0xd8, 0xd9, + 0xda, 0xdb, 0xdf, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, + 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x62, 0xd3, 0x00, 0x57, 0x00, 0x56, 0x45, + 0x00, 0x79, 0xdf, 0xfb, 0x62, 0xd3, 0x00, 0x50, 0x32, 0x57, 0x01, 0x54, + 0x48, 0x79, 0xdf, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x55, 0x0d, 0x1e, 0x55, + 0x0e, 0x05, 0x55, 0x0f, 0x32, 0x55, 0x10, 0x01, 0x55, 0x11, 0x01, 0x55, + 0x12, 0x32, 0x55, 0x22, 0x04, 0x55, 0x1f, 0x32, 0x43, 0x61, 0x0d, 0x57, + 0x00, 0x50, 0x02, 0x90, 0x82, 0x50, 0x04, 0xff, 0xa4, 0x29, 0x00, 0x60, + 0xa9, 0x62, 0xa0, 0x08, 0x43, 0xa2, 0x04, 0x62, 0xa3, 0x70, 0x43, 0x7a, + 0x01, 0x43, 0xdf, 0x01, 0x50, 0x01, 0x57, 0x0d, 0x90, 0x12, 0x90, 0x4d, + 0x7f, 0x53, 0x22, 0xff, 0x84, 0x29, 0x00, 0x60, 0xa9, 0x51, 0x21, 0x58, + 0x20, 0x90, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, 0x03, 0x53, 0x21, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x29, 0x80, 0x60, 0xa1, 0x5b, 0x78, 0x21, 0x0f, + 0x29, 0x08, 0x74, 0x53, 0x20, 0x12, 0x22, 0x02, 0x21, 0x5c, 0x50, 0x00, + 0x53, 0x1d, 0x53, 0x23, 0x29, 0x01, 0x79, 0xa0, 0x08, 0x64, 0x6b, 0x1d, + 0x6b, 0x23, 0x8f, 0xf5, 0x60, 0xb5, 0x51, 0x1d, 0x60, 0xb4, 0x7f, 0x62, + 0xd0, 0x00, 0x53, 0x1f, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x90, 0x07, 0x90, + 0x39, 0x18, 0x78, 0xdf, 0xf8, 0x7f, 0x64, 0x5c, 0xfd, 0x4e, 0x4b, 0x74, + 0xfd, 0x4a, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, 0x5b, 0x64, 0x64, + 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, + 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, 0x18, 0xff, 0x0e, + 0x5c, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, 0x62, 0xd0, + 0x00, 0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, 0xfe, 0xf8, 0x5c, 0x5e, + 0x00, 0x22, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x18, 0x64, 0x64, 0x5c, 0x71, + 0x10, 0x5e, 0x01, 0x22, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, 0x00, + 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, + 0x53, 0x1e, 0x50, 0x00, 0x53, 0x1a, 0x53, 0x1b, 0x43, 0xa0, 0x01, 0x51, + 0x1f, 0x60, 0xfd, 0x41, 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x84, 0x9f, 0x8b, + 0x58, 0x23, 0x55, 0x1c, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x43, + 0xb3, 0x01, 0x51, 0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, 0x9f, + 0x69, 0x9f, 0x9b, 0x43, 0xa3, 0x20, 0x41, 0xa0, 0xfe, 0x62, 0xfd, 0x00, + 0x50, 0xff, 0x4c, 0x1b, 0x14, 0x1b, 0x51, 0x20, 0x11, 0x08, 0xfe, 0x8f, + 0x4c, 0x1a, 0x1c, 0x1a, 0xd0, 0x07, 0x55, 0x1a, 0x00, 0x55, 0x1b, 0x00, + 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x54, 0x5b, 0x51, + 0x1a, 0x54, 0x5a, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x9f, 0x90, 0x18, + 0x78, 0xdf, 0xfa, 0x7f, 0x10, 0x7c, 0x04, 0x50, 0x7c, 0x04, 0x2d, 0x20, + 0x7c, 0x0e, 0xdd, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x02, 0xec, 0x20, 0x43, + 0x00, 0x08, 0x62, 0xd0, 0x00, 0x55, 0x24, 0x08, 0x55, 0x25, 0x04, 0x55, + 0x26, 0x03, 0x55, 0x28, 0x55, 0x55, 0x29, 0x02, 0x10, 0x50, 0x00, 0x08, + 0x50, 0x24, 0x08, 0x50, 0x05, 0x08, 0x50, 0x12, 0x08, 0x7c, 0x05, 0x7f, + 0x38, 0xfc, 0x7c, 0x05, 0x59, 0x7c, 0x05, 0x6f, 0x20, 0x71, 0x01, 0x10, + 0x7c, 0x07, 0x8c, 0x7c, 0x07, 0x12, 0x20, 0x90, 0xea, 0x80, 0xe5, 0x7c, + 0x10, 0x2e, 0x62, 0xe3, 0x38, 0x92, 0x61, 0x62, 0xd0, 0x00, 0x3c, 0x6f, + 0x01, 0xb0, 0x09, 0x50, 0x00, 0x08, 0x7c, 0x11, 0xae, 0x38, 0xff, 0x62, + 0xe3, 0x38, 0x10, 0x7c, 0x07, 0x50, 0x20, 0x39, 0x00, 0xa0, 0x86, 0x62, + 0xd0, 0x00, 0x51, 0x63, 0x11, 0x94, 0x51, 0x62, 0x19, 0x02, 0xd0, 0x12, + 0x7c, 0x0e, 0xef, 0x39, 0xe1, 0xa0, 0x10, 0x62, 0xd0, 0x00, 0x76, 0x63, + 0x0e, 0x62, 0x00, 0x80, 0x06, 0x7c, 0x13, 0x92, 0x90, 0xa1, 0x62, 0xd0, + 0x00, 0x3c, 0x72, 0xf0, 0xd0, 0x06, 0x62, 0xd0, 0x00, 0x76, 0x72, 0x62, + 0xd0, 0x00, 0x51, 0x72, 0x62, 0xd0, 0x00, 0x3a, 0x29, 0xb0, 0x82, 0x7c, + 0x0e, 0xef, 0x62, 0xd0, 0x00, 0x53, 0x73, 0x3c, 0x73, 0xe1, 0xa0, 0x35, + 0x62, 0xd0, 0x00, 0x55, 0x67, 0x00, 0x55, 0x66, 0x00, 0x62, 0xd0, 0x00, + 0x51, 0x73, 0x62, 0xd0, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x06, 0x3f, + 0x66, 0x7c, 0x13, 0x05, 0x50, 0x08, 0x3f, 0x3f, 0x7c, 0x13, 0xb3, 0x7c, + 0x0f, 0x2a, 0x62, 0xd0, 0x00, 0x55, 0x71, 0x01, 0x62, 0xd0, 0x00, 0x55, + 0x6e, 0x03, 0x80, 0x41, 0x62, 0xd0, 0x00, 0x55, 0x72, 0x00, 0x80, 0x39, + 0x7c, 0x13, 0x92, 0x7c, 0x13, 0xa3, 0xb0, 0x31, 0x62, 0xd0, 0x00, 0x7a, + 0x6e, 0x3c, 0x6e, 0x00, 0xb0, 0x27, 0x7c, 0x0f, 0xb2, 0x62, 0xd0, 0x00, + 0x55, 0x71, 0x00, 0x62, 0xd0, 0x00, 0x51, 0x73, 0x62, 0xd0, 0x00, 0x53, + 0x3f, 0x55, 0x40, 0x00, 0x06, 0x3f, 0x66, 0x7c, 0x13, 0x05, 0x50, 0x00, + 0x3f, 0x3f, 0x62, 0xd0, 0x00, 0x55, 0x72, 0x00, 0x7c, 0x10, 0x9b, 0x8f, + 0x1b, 0x8f, 0xff, 0x10, 0x4f, 0x38, 0x16, 0x10, 0x62, 0xd0, 0x00, 0x51, + 0x68, 0x7c, 0x08, 0x33, 0x20, 0x10, 0x50, 0x00, 0x7c, 0x08, 0xa7, 0x20, + 0x56, 0x0d, 0x00, 0x80, 0x86, 0x56, 0x00, 0x00, 0x80, 0x7a, 0x7c, 0x12, + 0xdb, 0x06, 0x3f, 0x68, 0x7c, 0x12, 0xf4, 0x10, 0x7c, 0x08, 0x33, 0x20, + 0x10, 0x52, 0x00, 0x7c, 0x08, 0xa7, 0x20, 0x10, 0x7c, 0x05, 0x64, 0x62, + 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, 0x55, 0x40, 0x03, 0x5a, 0x3f, + 0x06, 0x3f, 0x01, 0x52, 0x00, 0x53, 0x3d, 0x50, 0x00, 0x08, 0x51, 0x3d, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x12, 0x8e, 0x38, 0xfc, + 0x7c, 0x13, 0x0d, 0x53, 0x40, 0x52, 0x0d, 0x7c, 0x13, 0x47, 0x51, 0x3d, + 0x02, 0x3f, 0x53, 0x3f, 0x51, 0x3e, 0x0a, 0x40, 0x53, 0x40, 0x52, 0x00, + 0x7c, 0x13, 0x47, 0x06, 0x3d, 0x5a, 0x0e, 0x3e, 0x00, 0x51, 0x3e, 0x60, + 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x51, 0x40, 0x60, + 0xd5, 0x51, 0x3e, 0x3f, 0x3f, 0x51, 0x3d, 0x3f, 0x3f, 0x77, 0x00, 0x3d, + 0x00, 0x02, 0xcf, 0x83, 0x77, 0x0d, 0x3d, 0x0d, 0x03, 0xcf, 0x77, 0x56, + 0x00, 0x00, 0x80, 0xd0, 0x62, 0xd0, 0x00, 0x55, 0x40, 0x03, 0x5a, 0x3f, + 0x06, 0x3f, 0x01, 0x52, 0x00, 0x53, 0x3d, 0x50, 0x00, 0x08, 0x51, 0x3d, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x12, 0x8e, 0x38, 0xfc, + 0x97, 0xef, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x54, 0x0e, 0x3e, 0x3f, 0x54, + 0x0f, 0x5a, 0x3f, 0x06, 0x3f, 0x03, 0x52, 0x00, 0x53, 0x3d, 0x50, 0x00, + 0x08, 0x51, 0x3d, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x12, + 0x8e, 0x38, 0xfc, 0x97, 0xc8, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x54, 0x10, + 0x3e, 0x3f, 0x54, 0x11, 0x5a, 0x3f, 0x06, 0x3f, 0x05, 0x52, 0x00, 0x53, + 0x3d, 0x50, 0x00, 0x08, 0x51, 0x3d, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, + 0x08, 0x7c, 0x12, 0x8e, 0x38, 0xfc, 0x97, 0xa1, 0x40, 0x60, 0xd4, 0x3e, + 0x3f, 0x54, 0x12, 0x3e, 0x3f, 0x54, 0x13, 0x50, 0x03, 0x08, 0x5a, 0x3f, + 0x06, 0x3f, 0x0e, 0x08, 0x51, 0x3f, 0x08, 0x7c, 0x10, 0xe0, 0x38, 0xfd, + 0x62, 0xd0, 0x00, 0x51, 0x3f, 0x54, 0x15, 0x51, 0x40, 0x54, 0x14, 0x97, + 0x3a, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x97, 0x62, 0x40, 0x97, 0x9d, 0x40, + 0x06, 0x3f, 0x4a, 0x97, 0x60, 0x40, 0x7c, 0x13, 0xaa, 0x97, 0x24, 0x40, + 0x51, 0x3f, 0x01, 0x52, 0x97, 0x4c, 0x40, 0x97, 0x87, 0x40, 0x51, 0x3f, + 0x01, 0x56, 0x97, 0x42, 0x40, 0x97, 0x7d, 0x40, 0x06, 0x3f, 0x5e, 0x97, + 0x40, 0x40, 0x97, 0xe2, 0x40, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x2d, + 0x38, 0xea, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x06, 0x62, 0xd0, 0x00, 0x55, + 0x70, 0x00, 0x10, 0x62, 0xd0, 0x00, 0x51, 0x68, 0x7c, 0x08, 0x33, 0x20, + 0x10, 0x50, 0x00, 0x7c, 0x08, 0xa7, 0x20, 0x56, 0x00, 0x00, 0x80, 0x24, + 0x96, 0xe5, 0x40, 0x06, 0x3f, 0x68, 0x96, 0xf8, 0x40, 0x10, 0x7c, 0x08, + 0x33, 0x20, 0x10, 0x52, 0x00, 0x7c, 0x08, 0xa7, 0x20, 0x10, 0x7c, 0x05, + 0x64, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, 0x77, 0x00, 0x3d, + 0x00, 0x02, 0xcf, 0xd9, 0x56, 0x00, 0x00, 0x81, 0xcf, 0x97, 0x79, 0x40, + 0xa0, 0xb6, 0x62, 0xd0, 0x00, 0x96, 0xa4, 0x40, 0x51, 0x3f, 0x01, 0x4a, + 0x96, 0x8c, 0x40, 0x06, 0x3f, 0x5a, 0x96, 0xae, 0x40, 0x53, 0x3f, 0x51, + 0x3d, 0x12, 0x3f, 0x51, 0x3e, 0x1a, 0x40, 0xd0, 0x19, 0x62, 0xd0, 0x00, + 0x96, 0x85, 0x40, 0x51, 0x3f, 0x01, 0x4a, 0x96, 0x6d, 0x40, 0x06, 0x3f, + 0x5a, 0x96, 0x8f, 0x40, 0x97, 0x22, 0x40, 0x80, 0x17, 0x62, 0xd0, 0x00, + 0x96, 0x6d, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x96, 0x55, 0x40, 0x06, 0x3f, + 0x4a, 0x96, 0x77, 0x40, 0x97, 0x0a, 0x40, 0x50, 0x90, 0x13, 0x03, 0x50, + 0x01, 0x1b, 0x02, 0xc0, 0x58, 0x62, 0xd0, 0x00, 0x96, 0x4d, 0x40, 0x51, + 0x3f, 0x01, 0x5e, 0x96, 0x35, 0x40, 0x06, 0x3f, 0x5a, 0x96, 0x57, 0x40, + 0x53, 0x3f, 0x51, 0x3d, 0x12, 0x3f, 0x51, 0x3e, 0x1a, 0x40, 0xd0, 0x19, + 0x62, 0xd0, 0x00, 0x96, 0x2e, 0x40, 0x51, 0x3f, 0x01, 0x5e, 0x96, 0x16, + 0x40, 0x06, 0x3f, 0x5a, 0x96, 0x38, 0x40, 0x96, 0xc0, 0x40, 0x80, 0x17, + 0x62, 0xd0, 0x00, 0x96, 0x16, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x95, 0xfe, + 0x40, 0x06, 0x3f, 0x5e, 0x96, 0x20, 0x40, 0x96, 0xa8, 0x40, 0x50, 0x90, + 0x13, 0x05, 0x50, 0x01, 0x1b, 0x04, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x76, + 0x70, 0x81, 0x13, 0x62, 0xd0, 0x00, 0x95, 0xef, 0x40, 0x51, 0x3f, 0x01, + 0x56, 0x95, 0xd7, 0x40, 0x06, 0x3f, 0x52, 0x96, 0x18, 0x40, 0x96, 0x30, + 0x40, 0x95, 0xdc, 0x40, 0x51, 0x3f, 0x01, 0x5e, 0x95, 0xc4, 0x40, 0x06, + 0x3f, 0x56, 0x96, 0x05, 0x40, 0x96, 0x1d, 0x40, 0x95, 0xc9, 0x40, 0x51, + 0x3f, 0x01, 0x5a, 0x95, 0xb1, 0x40, 0x06, 0x3f, 0x5e, 0x95, 0xf2, 0x40, + 0x96, 0x0a, 0x40, 0x95, 0xb6, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x95, 0xde, + 0x40, 0x53, 0x3e, 0x96, 0x40, 0x40, 0x53, 0x3b, 0x08, 0x51, 0x3c, 0x53, + 0x3a, 0x18, 0x53, 0x39, 0x65, 0x39, 0x6b, 0x3a, 0x06, 0x3f, 0x56, 0x95, + 0xad, 0x40, 0x53, 0x3f, 0x51, 0x39, 0x04, 0x3f, 0x51, 0x3a, 0x0c, 0x40, + 0x51, 0x3b, 0x04, 0x3f, 0x51, 0x3c, 0x0c, 0x40, 0x70, 0xfb, 0x6e, 0x40, + 0x6e, 0x3f, 0x95, 0xd5, 0x40, 0x10, 0x52, 0x00, 0x7c, 0x05, 0xb2, 0x20, + 0x62, 0xd0, 0x00, 0x95, 0x6e, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x95, 0x56, + 0x40, 0x06, 0x3f, 0x4a, 0x95, 0x78, 0x40, 0x53, 0x3f, 0x51, 0x3d, 0x12, + 0x3f, 0x51, 0x3e, 0x1a, 0x40, 0xd0, 0x1b, 0x95, 0x5e, 0x40, 0x06, 0x3f, + 0x6c, 0x95, 0x71, 0x40, 0x7a, 0x3f, 0x53, 0x3e, 0x06, 0x3e, 0x01, 0x51, + 0x40, 0x60, 0xd5, 0x51, 0x3e, 0x3f, 0x3f, 0x80, 0x0e, 0x95, 0x44, 0x40, + 0x06, 0x3f, 0x6c, 0x95, 0x68, 0x40, 0x50, 0x00, 0x3f, 0x3f, 0x95, 0x37, + 0x40, 0x06, 0x3f, 0x6c, 0x95, 0x4a, 0x40, 0x53, 0x40, 0x50, 0x05, 0x3a, + 0x40, 0xd0, 0x3b, 0x62, 0xd0, 0x00, 0x95, 0x17, 0x40, 0x51, 0x3f, 0x01, + 0x4a, 0x95, 0x3f, 0x40, 0x53, 0x3e, 0x06, 0x3f, 0x5a, 0x95, 0x1f, 0x40, + 0x53, 0x3f, 0x51, 0x3e, 0x95, 0x97, 0x40, 0x02, 0x3f, 0x53, 0x3f, 0x51, + 0x3c, 0x0a, 0x40, 0x53, 0x40, 0x95, 0x4e, 0x40, 0x52, 0x00, 0x53, 0x3f, + 0x55, 0x40, 0x00, 0x06, 0x3f, 0x6c, 0x95, 0x1d, 0x40, 0x50, 0x00, 0x3f, + 0x3f, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0x2e, 0x95, 0xa6, 0x40, 0xb0, + 0x9b, 0x56, 0x00, 0x00, 0x80, 0x91, 0x62, 0xd0, 0x00, 0x94, 0xcc, 0x40, + 0x51, 0x3f, 0x01, 0x5a, 0x94, 0xb4, 0x40, 0x06, 0x3f, 0x2e, 0x94, 0xf5, + 0x40, 0x95, 0x0d, 0x40, 0x94, 0xb9, 0x40, 0x51, 0x3f, 0x01, 0x4a, 0x94, + 0xa1, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x53, 0x3b, 0x51, 0x40, 0x95, 0x29, + 0x40, 0x51, 0x3d, 0x12, 0x3b, 0x51, 0x3e, 0x1a, 0x3c, 0xd0, 0x30, 0x62, + 0xd0, 0x00, 0x52, 0x00, 0x95, 0x0d, 0x40, 0x51, 0x3d, 0x01, 0x4a, 0x53, + 0x3b, 0x51, 0x3e, 0x95, 0x0c, 0x40, 0x06, 0x3d, 0x5a, 0x0e, 0x3e, 0x00, + 0x51, 0x3e, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x12, 0x3b, + 0x54, 0x03, 0x51, 0x3e, 0x1a, 0x3c, 0x54, 0x02, 0x80, 0x07, 0x56, 0x03, + 0x00, 0x56, 0x02, 0x00, 0x62, 0xd0, 0x00, 0x06, 0x3f, 0x2a, 0x94, 0x95, + 0x40, 0x52, 0x02, 0x3f, 0x3f, 0x52, 0x03, 0x3f, 0x3f, 0x94, 0x54, 0x40, + 0x51, 0x3f, 0x01, 0x4a, 0x94, 0x3c, 0x40, 0x06, 0x3f, 0x32, 0x94, 0x7d, + 0x40, 0x94, 0x95, 0x40, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x6c, 0x95, + 0x07, 0x40, 0xa0, 0x1a, 0x62, 0xd0, 0x00, 0x3c, 0x70, 0x00, 0xa0, 0x12, + 0x50, 0x75, 0x08, 0x50, 0x30, 0x08, 0x90, 0x0d, 0x38, 0xfe, 0x9b, 0xa7, + 0x10, 0x7c, 0x07, 0x6a, 0x20, 0x38, 0xfa, 0x20, 0x7f, 0x10, 0x4f, 0x80, + 0x02, 0x40, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x3f, 0x52, 0xfb, 0x53, + 0x40, 0x51, 0x3f, 0x11, 0x01, 0x54, 0xfc, 0x51, 0x40, 0x19, 0x00, 0x54, + 0xfb, 0x3c, 0x40, 0x00, 0xbf, 0xe4, 0x3c, 0x3f, 0x00, 0xbf, 0xdf, 0x20, + 0x7f, 0x10, 0x7c, 0x04, 0x50, 0x7c, 0x04, 0x2d, 0x20, 0x7f, 0x10, 0x7c, + 0x04, 0x4c, 0x7c, 0x04, 0x29, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x50, 0x28, + 0x12, 0x4f, 0x50, 0x00, 0x1a, 0x4e, 0xd0, 0x15, 0x62, 0xd0, 0x00, 0x50, + 0x28, 0x12, 0x51, 0x50, 0x00, 0x1a, 0x50, 0xd0, 0x08, 0x62, 0xd0, 0x00, + 0x50, 0xe1, 0x80, 0x1a, 0x62, 0xd0, 0x00, 0x51, 0x51, 0x12, 0x4f, 0x51, + 0x50, 0x1a, 0x4e, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x00, 0x80, 0x06, + 0x62, 0xd0, 0x00, 0x50, 0x01, 0x7f, 0x10, 0x4f, 0x38, 0x01, 0x70, 0xfe, + 0x62, 0xd0, 0x00, 0x51, 0x73, 0x01, 0x01, 0x62, 0xd0, 0x00, 0x53, 0x24, + 0x71, 0x01, 0x62, 0xd0, 0x00, 0x3c, 0x71, 0x00, 0xb0, 0x69, 0x62, 0xe3, + 0x38, 0x10, 0x7c, 0x05, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, + 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x05, 0x64, 0x62, 0xd0, 0x00, + 0x20, 0x53, 0x40, 0x47, 0x40, 0x20, 0xa0, 0x03, 0x80, 0x12, 0x50, 0x00, + 0x08, 0x50, 0x14, 0x08, 0x9f, 0x43, 0x38, 0xfe, 0x77, 0x00, 0x3d, 0x00, + 0xc8, 0xcf, 0xdf, 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x05, 0x64, + 0x62, 0xd0, 0x00, 0x20, 0x53, 0x40, 0x47, 0x40, 0x20, 0xb0, 0x03, 0x80, + 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9f, 0x1c, 0x38, 0xfe, 0x77, + 0x00, 0x3d, 0x00, 0x1e, 0xcf, 0xdf, 0x62, 0xd0, 0x00, 0x51, 0x24, 0x29, + 0x08, 0x53, 0x24, 0x43, 0x00, 0x08, 0x38, 0xff, 0x20, 0x7f, 0x10, 0x4f, + 0x38, 0x01, 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x51, 0x73, 0x01, 0x09, 0x62, + 0xd0, 0x00, 0x53, 0x24, 0x71, 0x01, 0x93, 0xdb, 0x40, 0xb0, 0x60, 0x62, + 0xe3, 0x38, 0x10, 0x7c, 0x05, 0x64, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, + 0xf7, 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x05, 0x64, 0x62, 0xd0, + 0x00, 0x20, 0x53, 0x40, 0x47, 0x40, 0x20, 0xa0, 0x03, 0x80, 0x12, 0x50, + 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, 0xbe, 0x38, 0xfe, 0x77, 0x00, 0x3d, + 0x00, 0xc8, 0xcf, 0xdf, 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x05, + 0x64, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x40, 0x47, 0x40, 0x20, 0xb0, 0x03, + 0x80, 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, 0x97, 0x38, 0xfe, + 0x77, 0x00, 0x3d, 0x00, 0x1e, 0xcf, 0xdf, 0x43, 0x00, 0x08, 0x38, 0xff, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x01, 0x62, 0xd0, 0x00, 0x51, 0x24, 0x54, + 0x00, 0x3d, 0x00, 0x01, 0xb0, 0x17, 0x93, 0x73, 0x40, 0x93, 0x60, 0x40, + 0xa0, 0x0a, 0x62, 0xd0, 0x00, 0x55, 0x67, 0x00, 0x55, 0x66, 0x00, 0x93, + 0x0d, 0x40, 0x80, 0x44, 0x3d, 0x00, 0x02, 0xb0, 0x1b, 0x62, 0xd0, 0x00, + 0x55, 0x75, 0x01, 0x62, 0xd0, 0x00, 0x55, 0x74, 0x00, 0x62, 0xd0, 0x00, + 0x55, 0x67, 0x08, 0x55, 0x66, 0x08, 0x92, 0xee, 0x40, 0x80, 0x25, 0x52, + 0x00, 0x21, 0xf0, 0x39, 0x40, 0xb0, 0x0c, 0x62, 0xd0, 0x00, 0x55, 0x6f, + 0x02, 0x92, 0xdb, 0x40, 0x80, 0x12, 0x52, 0x00, 0x21, 0xf0, 0x39, 0x50, + 0xb0, 0x0a, 0x62, 0xd0, 0x00, 0x55, 0x6f, 0x01, 0x92, 0xc8, 0x40, 0x38, + 0xff, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x3c, 0x75, 0x00, 0xa0, 0x13, 0x9e, + 0x38, 0x62, 0xd0, 0x00, 0x3c, 0x74, 0x00, 0xb0, 0x33, 0x55, 0x74, 0x01, + 0x7c, 0x0a, 0x53, 0x80, 0x2b, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x66, + 0xd0, 0x08, 0x10, 0x7c, 0x04, 0x50, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, + 0x4c, 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x67, 0xd0, 0x08, 0x10, + 0x7c, 0x04, 0x2d, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0x29, 0x20, 0x7f, + 0x10, 0x4f, 0x38, 0x03, 0x56, 0x02, 0x00, 0x56, 0x01, 0x00, 0x56, 0x00, + 0x00, 0x80, 0x41, 0x62, 0xd0, 0x00, 0x91, 0xdb, 0x40, 0x52, 0xfc, 0x04, + 0x3f, 0x52, 0xfb, 0x0c, 0x40, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, + 0x40, 0x3e, 0x3f, 0x53, 0x3f, 0x52, 0x02, 0x12, 0x3f, 0x52, 0x01, 0x1a, + 0x40, 0xd0, 0x1b, 0x62, 0xd0, 0x00, 0x91, 0xb7, 0x40, 0x52, 0xfc, 0x04, + 0x3f, 0x52, 0xfb, 0x0c, 0x40, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x54, + 0x01, 0x3e, 0x3f, 0x54, 0x02, 0x77, 0x00, 0x52, 0x00, 0x3b, 0xfa, 0xcf, + 0xbb, 0x62, 0xd0, 0x00, 0x52, 0x02, 0x53, 0x3f, 0x52, 0x01, 0x53, 0x40, + 0x38, 0xfd, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x71, 0x10, 0x41, 0x01, + 0xf7, 0x43, 0x00, 0x08, 0x70, 0xcf, 0x43, 0x00, 0x08, 0x50, 0x00, 0x08, + 0x50, 0x64, 0x08, 0x9d, 0x58, 0x71, 0x10, 0x41, 0x01, 0xf7, 0x41, 0x00, + 0xf7, 0x70, 0xcf, 0x43, 0x00, 0x08, 0x50, 0x00, 0x08, 0x50, 0x64, 0x08, + 0x9d, 0x43, 0x38, 0xfc, 0x5d, 0x00, 0x62, 0xd0, 0x00, 0x53, 0x40, 0x26, + 0x40, 0x08, 0x3c, 0x40, 0x08, 0xb0, 0x09, 0x56, 0x01, 0x00, 0x56, 0x00, + 0x00, 0x80, 0x07, 0x56, 0x01, 0x01, 0x56, 0x00, 0x00, 0x52, 0x01, 0x62, + 0xd0, 0x00, 0x53, 0x6f, 0x71, 0x10, 0x43, 0x00, 0x08, 0x41, 0x01, 0xf7, + 0x70, 0xcf, 0x3c, 0x6f, 0x00, 0xb0, 0x04, 0x43, 0x00, 0x08, 0x38, 0xfe, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x01, 0x62, 0xe3, 0x38, 0x10, 0x50, 0x02, + 0x7c, 0x02, 0xfe, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x02, 0xfe, 0x20, 0x10, + 0x50, 0xff, 0x7c, 0x02, 0xfe, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x5a, 0x08, 0x7c, 0x03, 0xe3, 0x38, 0xfd, 0x20, 0x56, 0x00, + 0x00, 0x80, 0x6f, 0x62, 0xd0, 0x00, 0x90, 0xeb, 0x40, 0x51, 0x3f, 0x01, + 0x4a, 0x90, 0xd3, 0x40, 0x06, 0x3f, 0x5a, 0x90, 0xf5, 0x40, 0x53, 0x3f, + 0x51, 0x3d, 0x12, 0x3f, 0x51, 0x3e, 0x1a, 0x40, 0xd0, 0x40, 0x62, 0xd0, + 0x00, 0x90, 0xcc, 0x40, 0x51, 0x3f, 0x01, 0x4a, 0x90, 0xb4, 0x40, 0x06, + 0x3f, 0x5a, 0x90, 0xd6, 0x40, 0x91, 0x74, 0x40, 0x51, 0x40, 0x10, 0x7c, + 0x02, 0xfe, 0x20, 0x62, 0xd0, 0x00, 0x90, 0xaf, 0x40, 0x51, 0x3f, 0x01, + 0x4a, 0x90, 0x97, 0x40, 0x06, 0x3f, 0x5a, 0x90, 0xb9, 0x40, 0x91, 0x57, + 0x40, 0x26, 0x40, 0x00, 0x51, 0x3f, 0x10, 0x7c, 0x02, 0xfe, 0x20, 0x80, + 0x0f, 0x10, 0x50, 0x00, 0x7c, 0x02, 0xfe, 0x20, 0x10, 0x50, 0x00, 0x7c, + 0x02, 0xfe, 0x20, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x8e, 0x10, 0x50, + 0x00, 0x7c, 0x02, 0xfe, 0x20, 0x10, 0x50, 0x01, 0x7c, 0x02, 0xfe, 0x20, + 0x10, 0x50, 0x00, 0x7c, 0x02, 0xfe, 0x20, 0x10, 0x50, 0x01, 0x7c, 0x02, + 0xfe, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x02, 0xfe, 0x20, 0x10, 0x50, 0xff, + 0x7c, 0x02, 0xfe, 0x7c, 0x03, 0xda, 0x20, 0x50, 0x13, 0x08, 0x50, 0x88, + 0x08, 0x9c, 0x2e, 0x38, 0xfe, 0x38, 0xff, 0x20, 0x7f, 0x7f, 0x10, 0x4f, + 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x00, 0x53, 0x38, 0x53, 0x37, + 0x55, 0x36, 0x10, 0x6f, 0xf9, 0x6f, 0xfa, 0xd0, 0x09, 0x52, 0xfc, 0x04, + 0x38, 0x52, 0xfb, 0x0c, 0x37, 0x66, 0xfc, 0x6c, 0xfb, 0x7a, 0x36, 0xbf, + 0xeb, 0x18, 0x60, 0xd0, 0x20, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x53, 0x3d, + 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, + 0x53, 0x3d, 0x7f, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, + 0x6b, 0x40, 0x7f, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, + 0x00, 0x7f, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, + 0x40, 0x3e, 0x3f, 0x7f, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, + 0x3f, 0x7f, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x7f, 0x0e, 0x40, 0x00, + 0x51, 0x40, 0x60, 0xd5, 0x7f, 0x51, 0x38, 0x53, 0x3d, 0x51, 0x37, 0x53, + 0x3e, 0x51, 0x3d, 0x02, 0x3f, 0x53, 0x3f, 0x51, 0x3e, 0x0a, 0x40, 0x7f, + 0x51, 0x3e, 0x3f, 0x3f, 0x51, 0x3d, 0x3f, 0x3f, 0x7f, 0x70, 0xfb, 0x6e, + 0x40, 0x6e, 0x3f, 0x51, 0x3e, 0x60, 0xd5, 0x51, 0x40, 0x3f, 0x3d, 0x51, + 0x3f, 0x3f, 0x3d, 0x7f, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x3d, 0x52, 0x15, + 0x3f, 0x3d, 0x7f, 0x53, 0x3d, 0x55, 0x3e, 0x00, 0x65, 0x3d, 0x6b, 0x3e, + 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3b, 0x53, 0x3c, 0x3e, 0x3b, 0x53, + 0x3b, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x24, 0x00, 0x7f, 0x60, 0xd4, 0x3e, + 0x3d, 0x53, 0x3c, 0x3e, 0x3d, 0x16, 0x3d, 0x02, 0x7f, 0x12, 0x3d, 0x54, + 0x05, 0x51, 0x40, 0x1a, 0x3e, 0x54, 0x04, 0x7f, 0x12, 0x3d, 0x54, 0x03, + 0x51, 0x40, 0x1a, 0x3e, 0x54, 0x02, 0x7f, 0x53, 0x3f, 0x51, 0x3d, 0x14, + 0x3f, 0x51, 0x3e, 0x1c, 0x40, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x63, 0x00, + 0x55, 0x62, 0x00, 0x7f, 0x62, 0xd0, 0x00, 0x3c, 0x6f, 0x02, 0x7f, 0x62, + 0xd0, 0x00, 0x3c, 0x71, 0x01, 0x7f, 0x52, 0x14, 0x3f, 0x3f, 0x52, 0x15, + 0x3f, 0x3f, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x75, 0x00, 0x7f, 0x00, 0x24, + 0x00, 0x12, 0x00, 0x52, 0x00, 0x08, 0x00, 0x5e, 0x00, 0x07, 0x00, 0x65, + 0x05, 0x01, 0x08, 0x08, 0x64, 0x5a, 0x00, 0x6a, 0x00, 0x04, 0x00, 0x6e, + 0x01, 0x03, 0x00, 0x6f, 0x00, 0x05, 0x00, 0x74, 0x02, 0x01, 0x01, 0xff, + 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypressbln/touchkey_fw_Q1.h b/drivers/input/keyboard/cypressbln/touchkey_fw_Q1.h new file mode 100644 index 0000000..3c882b8 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/touchkey_fw_Q1.h @@ -0,0 +1,747 @@ +unsigned char firmware_data[] = { + 0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, + 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x03, 0x64, 0x7e, 0x7e, 0x30, + 0x30, 0x30, 0x7d, 0x04, 0xb7, 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, + 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, + 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x40, 0x71, 0x10, 0x62, 0xe3, 0x06, 0x70, + 0xef, 0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, 0x38, 0x5d, + 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, 0xfa, 0x01, 0x40, 0x4f, 0x5b, + 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, + 0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, 0xef, 0x18, 0x60, + 0xd5, 0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, + 0x1a, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, 0xfe, + 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, 0x03, 0x50, 0x80, 0x4e, + 0x62, 0xd3, 0x03, 0x62, 0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, + 0x00, 0x71, 0xc0, 0x7c, 0x02, 0xb3, 0x62, 0xd0, 0x00, 0x50, 0x02, + 0x57, 0x5c, 0x08, 0x28, 0x53, 0x48, 0x18, 0x75, 0x09, 0x00, 0x28, + 0x4b, 0x51, 0x48, 0x80, 0x04, 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, + 0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, 0x75, 0x09, 0x00, + 0x08, 0x28, 0x53, 0x48, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0xa0, + 0x1c, 0x53, 0x47, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, 0x48, + 0x47, 0x48, 0xff, 0xb0, 0x06, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x18, + 0x7a, 0x47, 0xbf, 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, + 0x28, 0x53, 0x47, 0x50, 0x00, 0x3f, 0x48, 0x47, 0x48, 0xff, 0xb0, + 0x08, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x47, 0xbf, + 0xef, 0x18, 0x8f, 0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, + 0x10, 0x62, 0xe0, 0x1a, 0x70, 0xef, 0x62, 0xe2, 0x00, 0x7c, 0x17, + 0x9a, 0x8f, 0xff, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x01, 0x80, 0x03, 0x00, 0x06, + 0x00, 0x0b, 0xff, 0x1b, 0x33, 0x2f, 0xff, 0x5f, 0xff, 0xbf, 0xff, + 0x01, 0x66, 0x02, 0xcc, 0x05, 0x99, 0x0b, 0x32, 0x16, 0x66, 0x2c, + 0xcc, 0x59, 0x98, 0xb3, 0x32, 0x01, 0x4c, 0x02, 0x99, 0x05, 0x33, + 0x0a, 0x65, 0x14, 0xcc, 0x29, 0x98, 0x53, 0x32, 0xa6, 0x65, 0x01, + 0x33, 0x02, 0x66, 0x04, 0xcc, 0x09, 0x99, 0x13, 0x33, 0x26, 0x65, + 0x4c, 0xcc, 0x99, 0x99, 0x61, 0x00, 0xfd, 0x00, 0xcd, 0x00, 0xce, + 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa0, 0x00, 0xa1, 0x80, 0xa2, 0xc0, + 0xa3, 0x0c, 0xa8, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x7c, 0x33, 0x7a, + 0x00, 0x7b, 0x00, 0x79, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, + 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, + 0x00, 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, + 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, + 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, + 0x4f, 0x00, 0xca, 0x20, 0xd6, 0x44, 0xcf, 0x00, 0xcb, 0x00, 0xc8, + 0x00, 0xcc, 0x00, 0xc9, 0x00, 0xd7, 0x00, 0xa9, 0x00, 0x2b, 0x00, + 0xb0, 0x00, 0xb3, 0x02, 0xb6, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, + 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0x33, 0x00, 0x34, 0x00, + 0x35, 0x00, 0xff, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, + 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0xdc, 0x00, 0xe2, + 0x00, 0xdd, 0x00, 0xd8, 0x02, 0xd9, 0x00, 0xda, 0x28, 0xdb, 0x00, + 0xdf, 0x00, 0x29, 0x00, 0x30, 0x00, 0xbd, 0x00, 0xff, 0x1a, 0x69, + 0x70, 0xef, 0x62, 0x00, 0x08, 0x71, 0x10, 0x62, 0x00, 0x00, 0x62, + 0x01, 0x92, 0x70, 0xef, 0x62, 0x04, 0x03, 0x71, 0x10, 0x62, 0x04, + 0x17, 0x62, 0x05, 0xab, 0x70, 0xef, 0x62, 0x08, 0x00, 0x71, 0x10, + 0x62, 0x08, 0x00, 0x62, 0x09, 0x28, 0x70, 0xef, 0x62, 0x0c, 0x00, + 0x71, 0x10, 0x62, 0x0c, 0x00, 0x62, 0x0d, 0x00, 0x70, 0xef, 0x62, + 0x10, 0x00, 0x71, 0x10, 0x62, 0x10, 0x00, 0x62, 0x11, 0x00, 0x70, + 0xef, 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, 0x62, 0x09, 0x00, 0x62, + 0x0d, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, 0x7f, 0x55, 0x00, 0x08, + 0x55, 0x01, 0x03, 0x55, 0x02, 0x00, 0x7c, 0x02, 0xc3, 0x7c, 0x02, + 0x5e, 0x7f, 0x10, 0x70, 0xef, 0x50, 0x00, 0x67, 0x50, 0x01, 0x57, + 0xb2, 0x7c, 0x02, 0xde, 0x50, 0x01, 0x67, 0x50, 0x02, 0x57, 0x35, + 0x7c, 0x02, 0xde, 0x70, 0xef, 0x20, 0x7f, 0x38, 0x02, 0x10, 0x08, + 0x4f, 0x56, 0xfc, 0x00, 0xd0, 0x04, 0x56, 0xfc, 0x01, 0x18, 0x20, + 0x70, 0xef, 0x62, 0xe3, 0x00, 0x10, 0x08, 0x28, 0x39, 0xff, 0xa0, + 0x1f, 0x4f, 0x48, 0xfc, 0x01, 0xa0, 0x03, 0x71, 0x10, 0x54, 0xfd, + 0x18, 0x20, 0x75, 0x09, 0x00, 0x10, 0x08, 0x28, 0x4f, 0x59, 0xfd, + 0x61, 0x00, 0x18, 0x20, 0x75, 0x09, 0x00, 0x8f, 0xd7, 0x38, 0xfc, + 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, + 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x01, 0xef, 0x80, + 0x04, 0x2e, 0x01, 0x10, 0x51, 0x01, 0x60, 0x04, 0x70, 0x3f, 0x71, + 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, 0x80, 0x03, + 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x01, + 0xfb, 0x80, 0x04, 0x2e, 0x01, 0x04, 0x51, 0x01, 0x60, 0x04, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, + 0x70, 0x3f, 0x71, 0x80, 0x5d, 0xd3, 0x08, 0x5d, 0xd0, 0x08, 0x62, + 0xd0, 0x00, 0x51, 0x06, 0x60, 0xd3, 0x2e, 0x03, 0x80, 0x49, 0xd7, + 0x08, 0xa0, 0x09, 0x26, 0x03, 0xf0, 0x2e, 0x03, 0x00, 0x80, 0x08, + 0x49, 0xd7, 0x20, 0xa0, 0x03, 0x80, 0xac, 0x51, 0x03, 0x21, 0x0e, + 0xe0, 0x01, 0x80, 0x11, 0x80, 0x6d, 0x80, 0x7f, 0x80, 0x4d, 0x80, + 0x9c, 0x80, 0x9a, 0x80, 0x98, 0x80, 0x96, 0x80, 0x9d, 0x5d, 0xd8, + 0x21, 0xfe, 0x39, 0x40, 0xa0, 0x06, 0x62, 0xd7, 0x00, 0x80, 0x90, + 0x49, 0xd8, 0x01, 0xb0, 0x15, 0x55, 0x0a, 0x02, 0x26, 0x05, 0x00, + 0x26, 0x04, 0x00, 0x26, 0x03, 0xf0, 0x2e, 0x03, 0x04, 0x62, 0xd7, + 0x10, 0x80, 0x77, 0x55, 0x0a, 0x01, 0x26, 0x03, 0xf0, 0x2e, 0x03, + 0x06, 0x5f, 0x05, 0x04, 0x51, 0x07, 0x02, 0x05, 0x5c, 0x52, 0x00, + 0x60, 0xd8, 0x76, 0x05, 0x62, 0xd7, 0x14, 0x80, 0x5b, 0x51, 0x08, + 0x78, 0x3a, 0x05, 0xc0, 0x0f, 0x51, 0x07, 0x02, 0x05, 0x5c, 0x52, + 0x00, 0x60, 0xd8, 0x76, 0x05, 0x2e, 0x03, 0x20, 0x60, 0xd8, 0x62, + 0xd7, 0x04, 0x80, 0x3f, 0x5d, 0xd8, 0x3a, 0x08, 0xd0, 0x2b, 0xa0, + 0x29, 0x53, 0x05, 0x53, 0x04, 0x26, 0x03, 0xf0, 0x2e, 0x03, 0x04, + 0x80, 0x18, 0x51, 0x09, 0x78, 0x3a, 0x05, 0xc0, 0x16, 0x51, 0x07, + 0x02, 0x05, 0x5c, 0x5d, 0xd8, 0x54, 0x00, 0x2e, 0x03, 0x10, 0x76, + 0x05, 0x80, 0x01, 0x62, 0xd7, 0x10, 0x80, 0x0f, 0x62, 0xd7, 0x00, + 0x80, 0x0a, 0x26, 0x03, 0xf0, 0x2e, 0x03, 0x00, 0x55, 0x0a, 0x00, + 0x18, 0x60, 0xd0, 0x18, 0x60, 0xd3, 0x20, 0x18, 0x7e, 0x62, 0xd0, + 0x00, 0x71, 0x10, 0x41, 0x04, 0xfc, 0x43, 0x05, 0x03, 0x70, 0xef, + 0x26, 0x01, 0xfc, 0x51, 0x01, 0x60, 0x04, 0x55, 0x0a, 0x00, 0x90, + 0x28, 0x90, 0x2d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x50, 0x00, 0x53, + 0x04, 0x71, 0x10, 0x43, 0x04, 0x03, 0x43, 0x05, 0x03, 0x70, 0xef, + 0x2e, 0x01, 0x03, 0x51, 0x01, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, + 0x51, 0x03, 0x21, 0xb0, 0x26, 0x03, 0x4f, 0x7f, 0x41, 0xe0, 0x7f, + 0x43, 0xe0, 0x80, 0x7f, 0x43, 0xd6, 0x31, 0x7f, 0x41, 0xe0, 0x7f, + 0x41, 0xd6, 0xfe, 0x7f, 0x62, 0xd0, 0x00, 0x4f, 0x52, 0xfd, 0x53, + 0x08, 0x52, 0xfc, 0x53, 0x09, 0x52, 0xfb, 0x53, 0x07, 0x52, 0xfa, + 0x53, 0x06, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x5d, 0xa4, 0x04, + 0x19, 0x5d, 0xa5, 0x0c, 0x18, 0x55, 0x1a, 0x01, 0x18, 0x7e, 0x70, + 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x53, 0x1c, 0x64, 0x5c, 0x62, + 0xd3, 0x00, 0x52, 0x87, 0x62, 0xd3, 0x00, 0x13, 0x6b, 0x62, 0xd3, + 0x00, 0x54, 0x6f, 0x62, 0xd3, 0x00, 0x52, 0x86, 0x62, 0xd3, 0x00, + 0x1b, 0x6a, 0x62, 0xd3, 0x00, 0x54, 0x6e, 0x48, 0x6e, 0x80, 0xb0, + 0x33, 0x3d, 0x6e, 0x00, 0xb0, 0x7b, 0x51, 0x0b, 0x3b, 0x6f, 0xc0, + 0x75, 0x52, 0x6f, 0x58, 0x1c, 0x01, 0x00, 0x6d, 0x62, 0xd3, 0x00, + 0x05, 0x49, 0xc0, 0x09, 0x51, 0x0d, 0x3b, 0x49, 0xd0, 0x12, 0xa0, + 0x10, 0x56, 0x49, 0x00, 0x5b, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x07, + 0x6b, 0x01, 0x0f, 0x6a, 0x00, 0x80, 0x41, 0x3d, 0x6e, 0xff, 0xb0, + 0x09, 0x50, 0xff, 0x12, 0x0c, 0x3b, 0x6f, 0xc0, 0x20, 0x62, 0xd3, + 0x00, 0x56, 0x6f, 0x00, 0x56, 0x6e, 0x00, 0x5b, 0x67, 0x5c, 0x62, + 0xd3, 0x00, 0x52, 0x50, 0x78, 0xd0, 0x03, 0x50, 0x00, 0x54, 0x50, + 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, 0xd3, 0x00, 0x52, + 0x87, 0x62, 0xd3, 0x00, 0x54, 0x6b, 0x62, 0xd3, 0x00, 0x52, 0x86, + 0x62, 0xd3, 0x00, 0x54, 0x6a, 0x51, 0x1c, 0x64, 0x5c, 0x62, 0xd3, + 0x00, 0x56, 0x6f, 0x00, 0x56, 0x6e, 0x00, 0x5b, 0x67, 0x5c, 0x62, + 0xd3, 0x00, 0x51, 0x10, 0x54, 0x50, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x08, 0x5c, 0x62, 0xd3, + 0x00, 0x52, 0x4b, 0x53, 0x17, 0x55, 0x16, 0x00, 0x18, 0x08, 0x90, + 0x7e, 0x62, 0xd3, 0x00, 0x23, 0x4d, 0xb0, 0x2c, 0x51, 0x0e, 0x04, + 0x17, 0x0e, 0x16, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, + 0x6f, 0x12, 0x17, 0x52, 0x6e, 0x1a, 0x16, 0xc0, 0x39, 0x5b, 0x67, + 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x4e, 0x78, 0x54, 0x4e, 0x08, 0x5b, + 0x64, 0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, 0x51, 0x0e, 0x14, 0x17, + 0x1e, 0x16, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x6f, + 0x12, 0x17, 0x52, 0x6e, 0x1a, 0x16, 0xc0, 0x0e, 0x5b, 0x67, 0x90, + 0x31, 0x62, 0xd3, 0x00, 0x2d, 0x4d, 0x50, 0x01, 0x80, 0x24, 0x5b, + 0x67, 0x08, 0x90, 0x23, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x4d, 0x62, + 0xd3, 0x00, 0x20, 0x51, 0x0f, 0x54, 0x4e, 0x50, 0x00, 0x80, 0x0d, + 0x5b, 0x67, 0x90, 0x0d, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x4d, 0x50, + 0x00, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x5c, + 0x18, 0x21, 0x07, 0xf0, 0x01, 0x7f, 0x01, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0x70, 0xbf, 0x70, 0xbf, 0x62, 0xd3, 0x00, 0x50, + 0x02, 0x78, 0x08, 0x5c, 0x56, 0x4b, 0x1e, 0x18, 0x78, 0xdf, 0xf8, + 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x91, 0xb2, 0x70, 0xbf, 0x18, + 0x08, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x87, 0x62, 0xd3, 0x00, + 0x54, 0x6b, 0x62, 0xd3, 0x00, 0x52, 0x86, 0x62, 0xd3, 0x00, 0x54, + 0x6a, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, + 0xd0, 0x00, 0x55, 0x12, 0x00, 0x50, 0x02, 0x78, 0x08, 0x9f, 0x0e, + 0x39, 0x01, 0xb0, 0x04, 0x55, 0x12, 0x01, 0x18, 0x78, 0xdf, 0xf3, + 0x51, 0x12, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x9e, 0x3e, 0x18, 0x78, + 0xdf, 0xfa, 0x7f, 0x98, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0xd8, 0xd9, 0xda, 0xdb, 0xdf, 0x00, 0x01, 0x03, 0x07, 0x0f, + 0x1f, 0x3f, 0x7f, 0xff, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x62, 0xd3, + 0x00, 0x57, 0x00, 0x56, 0x4d, 0x00, 0x79, 0xdf, 0xfb, 0x62, 0xd3, + 0x00, 0x57, 0x01, 0x50, 0x03, 0x54, 0x4e, 0x79, 0xdf, 0xfc, 0x62, + 0xd3, 0x00, 0x50, 0x32, 0x57, 0x01, 0x54, 0x50, 0x79, 0xdf, 0xfc, + 0x70, 0x3f, 0x71, 0xc0, 0x55, 0x0b, 0x19, 0x55, 0x0c, 0x05, 0x55, + 0x0d, 0x14, 0x55, 0x0e, 0x01, 0x55, 0x0f, 0x03, 0x55, 0x10, 0x32, + 0x55, 0x20, 0x04, 0x55, 0x1d, 0x14, 0x43, 0x61, 0x0d, 0x57, 0x00, + 0x50, 0x02, 0x90, 0xae, 0x50, 0x04, 0xff, 0x98, 0x29, 0x00, 0x60, + 0xa9, 0x62, 0xa0, 0x08, 0x43, 0xa2, 0x04, 0x62, 0xa3, 0x70, 0x43, + 0x7a, 0x01, 0x43, 0xaa, 0x02, 0x43, 0xdf, 0x01, 0x50, 0x01, 0x57, + 0x09, 0x90, 0x20, 0x90, 0x55, 0x57, 0x01, 0x50, 0xb3, 0x91, 0x5d, + 0x50, 0x00, 0x57, 0x0d, 0x90, 0x12, 0x90, 0x47, 0x7f, 0x53, 0x20, + 0xff, 0x67, 0x29, 0x00, 0x60, 0xa9, 0x51, 0x1f, 0x58, 0x1e, 0x90, + 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, 0x03, 0x53, 0x1f, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x29, 0x80, 0x60, 0xa1, 0x5b, 0x78, 0x21, 0x0f, + 0x29, 0x08, 0x74, 0x53, 0x1e, 0x12, 0x20, 0x02, 0x1f, 0x5c, 0x50, + 0x00, 0x53, 0x1b, 0x53, 0x21, 0x29, 0x01, 0x79, 0xa0, 0x08, 0x64, + 0x6b, 0x1b, 0x6b, 0x21, 0x8f, 0xf5, 0x60, 0xb5, 0x51, 0x1b, 0x60, + 0xb4, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x90, 0x28, 0x90, 0x5a, 0x18, + 0x78, 0xdf, 0xf8, 0x7f, 0x41, 0xdf, 0xfe, 0x71, 0x10, 0x41, 0xd8, + 0xfd, 0x70, 0xef, 0x41, 0x61, 0xf3, 0x41, 0xa2, 0xfb, 0x41, 0xa0, + 0xf7, 0x62, 0xa3, 0x00, 0x62, 0xa9, 0x00, 0x41, 0xaa, 0xfd, 0x7f, + 0x02, 0x20, 0x02, 0x08, 0x64, 0x5c, 0xff, 0xf8, 0x4b, 0x74, 0xff, + 0xf4, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1b, 0x10, 0x5b, 0x64, 0x64, + 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x2a, 0x1b, 0x61, 0x01, 0x36, 0x1b, + 0xff, 0x5e, 0x00, 0x22, 0x1b, 0x61, 0x00, 0x36, 0x1b, 0xff, 0x18, + 0xfe, 0xd6, 0x5c, 0x5e, 0x00, 0x2a, 0x1b, 0x61, 0x00, 0x70, 0xef, + 0x7f, 0x62, 0xd0, 0x00, 0x10, 0x73, 0x53, 0x1b, 0x71, 0x10, 0x5b, + 0xfe, 0xc0, 0x5c, 0x5e, 0x00, 0x22, 0x1b, 0x61, 0x00, 0x70, 0xef, + 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x22, 0x1b, 0x61, + 0x01, 0x36, 0x1b, 0xff, 0x5e, 0x00, 0x2a, 0x1b, 0x61, 0x00, 0x70, + 0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x1c, 0x50, 0x00, + 0x53, 0x18, 0x53, 0x19, 0x51, 0x1c, 0x5c, 0x62, 0xd3, 0x00, 0x52, + 0x22, 0x53, 0x1d, 0x43, 0xa0, 0x01, 0x51, 0x1d, 0x60, 0xfd, 0x41, + 0xa3, 0xdf, 0x51, 0x1c, 0x9f, 0x7a, 0x9f, 0x81, 0x58, 0x21, 0x55, + 0x1a, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x43, 0xb3, 0x01, + 0x51, 0x1a, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1c, 0x9f, 0x5f, + 0x9f, 0x91, 0x43, 0xa3, 0x20, 0x41, 0xa0, 0xfe, 0x62, 0xfd, 0x00, + 0x50, 0xff, 0x4c, 0x19, 0x14, 0x19, 0x51, 0x1e, 0x11, 0x08, 0xfe, + 0x4d, 0x4c, 0x18, 0x1c, 0x18, 0xd0, 0x07, 0x55, 0x18, 0x00, 0x55, + 0x19, 0x00, 0x51, 0x1c, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x19, + 0x54, 0x87, 0x51, 0x18, 0x54, 0x86, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x08, 0x9f, 0x86, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x70, 0xbf, 0x62, + 0xd0, 0x00, 0x53, 0x25, 0x5a, 0x24, 0x55, 0x1c, 0x01, 0x62, 0xd3, + 0x00, 0x58, 0x1c, 0x56, 0x22, 0x80, 0x55, 0x27, 0x08, 0x55, 0x26, + 0x80, 0x51, 0x1c, 0x9f, 0x63, 0x51, 0x1c, 0x9f, 0x5f, 0x70, 0xbf, + 0x58, 0x1c, 0x62, 0xd3, 0x00, 0x51, 0x19, 0x3a, 0x25, 0x51, 0x18, + 0x1a, 0x24, 0xd0, 0x06, 0x51, 0x26, 0x73, 0x25, 0x22, 0x68, 0x26, + 0x26, 0x26, 0x7f, 0x51, 0x26, 0x2d, 0x22, 0x7a, 0x27, 0xbf, 0xd6, + 0x7a, 0x1c, 0xdf, 0xc4, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, 0xd0, + 0x00, 0x51, 0x8b, 0x11, 0xb0, 0x51, 0x8a, 0x19, 0x04, 0xd0, 0x12, + 0x7c, 0x13, 0x75, 0x39, 0x0f, 0xa0, 0x16, 0x62, 0xd0, 0x00, 0x76, + 0x8b, 0x0e, 0x8a, 0x00, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x55, 0x8b, + 0x00, 0x55, 0x8a, 0x00, 0x90, 0xa1, 0x7f, 0x62, 0xd0, 0x00, 0x3c, + 0x94, 0xf0, 0xd0, 0x03, 0x76, 0x94, 0x62, 0xd0, 0x00, 0x51, 0x2d, + 0x21, 0x7f, 0x53, 0x48, 0x51, 0x94, 0x3a, 0x48, 0xb0, 0x50, 0x7c, + 0x13, 0x75, 0x62, 0xd0, 0x00, 0x53, 0x95, 0x3c, 0x95, 0x0f, 0xa0, + 0x3d, 0x3c, 0x8c, 0x00, 0xb0, 0x1c, 0x55, 0x82, 0x00, 0x55, 0x83, + 0x00, 0x51, 0x95, 0x53, 0x47, 0x55, 0x48, 0x00, 0x06, 0x47, 0x82, + 0x0e, 0x48, 0x00, 0x51, 0x48, 0x60, 0xd5, 0x50, 0x08, 0x3f, 0x47, + 0x62, 0xd0, 0x00, 0x55, 0x8f, 0x00, 0x3c, 0x93, 0x00, 0xb0, 0x0a, + 0x7c, 0x14, 0x06, 0x62, 0xd0, 0x00, 0x55, 0x93, 0x01, 0x62, 0xd0, + 0x00, 0x55, 0x8e, 0x03, 0x80, 0x07, 0x62, 0xd0, 0x00, 0x55, 0x94, + 0x00, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x8b, 0x00, 0x55, 0x8a, 0x00, + 0x3c, 0x93, 0x01, 0xb0, 0x29, 0x7a, 0x8e, 0x3c, 0x8e, 0x00, 0xb0, + 0x22, 0x7c, 0x14, 0xa2, 0x62, 0xd0, 0x00, 0x55, 0x93, 0x00, 0x3c, + 0x8c, 0x00, 0xb0, 0x0e, 0x51, 0x95, 0x53, 0x47, 0x55, 0x48, 0x00, + 0x06, 0x47, 0x82, 0x7c, 0x1a, 0x37, 0x62, 0xd0, 0x00, 0x55, 0x94, + 0x00, 0x7f, 0x10, 0x4f, 0x38, 0x16, 0x62, 0xd0, 0x00, 0x3c, 0x91, + 0x00, 0xb0, 0x05, 0x51, 0x7a, 0x53, 0x22, 0x56, 0x0d, 0x00, 0x81, + 0x09, 0x56, 0x00, 0x00, 0x80, 0xfd, 0x62, 0xd0, 0x00, 0x3c, 0x91, + 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x47, 0x55, 0x48, 0x00, 0x06, + 0x47, 0x7a, 0x7c, 0x19, 0x0f, 0x52, 0x00, 0x53, 0x45, 0x55, 0x46, + 0x00, 0x06, 0x45, 0x22, 0x7c, 0x1a, 0x01, 0x10, 0x52, 0x00, 0x7c, + 0x07, 0xf6, 0x20, 0x10, 0x7c, 0x04, 0x81, 0x62, 0xd0, 0x00, 0x20, + 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, 0x00, 0xb0, 0x3a, 0x7c, 0x18, + 0xb9, 0x7c, 0x18, 0xe1, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x51, + 0x40, 0x53, 0x45, 0x51, 0x3f, 0x53, 0x46, 0x50, 0x00, 0x08, 0x50, + 0x07, 0x08, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, 0x7c, 0x18, 0x45, + 0x18, 0x53, 0x45, 0x18, 0x53, 0x46, 0x38, 0xfe, 0x7c, 0x18, 0xf7, + 0x3d, 0x00, 0x01, 0xb0, 0x3d, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb9, + 0x7c, 0x18, 0xe1, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x03, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x51, 0x40, + 0x53, 0x45, 0x51, 0x3f, 0x53, 0x46, 0x50, 0x00, 0x08, 0x50, 0x07, + 0x08, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, 0x7c, 0x18, 0x45, 0x18, + 0x53, 0x45, 0x18, 0x53, 0x46, 0x38, 0xfe, 0x7c, 0x18, 0xf7, 0x62, + 0xd0, 0x00, 0x55, 0x48, 0x03, 0x5a, 0x47, 0x06, 0x47, 0x01, 0x52, + 0x00, 0x53, 0x45, 0x50, 0x00, 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x06, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x7c, 0x19, + 0x9e, 0x53, 0x48, 0x52, 0x0d, 0x53, 0x45, 0x55, 0x46, 0x00, 0x65, + 0x45, 0x6b, 0x46, 0x7c, 0x19, 0xb1, 0x53, 0x48, 0x7c, 0x19, 0xf5, + 0x06, 0x45, 0x86, 0x0e, 0x46, 0x00, 0x51, 0x46, 0x7c, 0x19, 0x04, + 0x7c, 0x18, 0xf7, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x00, 0x77, + 0x0d, 0x3d, 0x0d, 0x03, 0xce, 0xf4, 0x56, 0x00, 0x00, 0x80, 0xc0, + 0x62, 0xd0, 0x00, 0x55, 0x48, 0x03, 0x5a, 0x47, 0x06, 0x47, 0x01, + 0x52, 0x00, 0x53, 0x45, 0x50, 0x00, 0x08, 0x51, 0x45, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x7c, + 0x19, 0x9e, 0x60, 0xd4, 0x3e, 0x47, 0x54, 0x0e, 0x3e, 0x47, 0x54, + 0x0f, 0x5a, 0x47, 0x06, 0x47, 0x03, 0x52, 0x00, 0x53, 0x45, 0x50, + 0x00, 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, + 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x7c, 0x19, 0x9e, 0x60, 0xd4, 0x3e, + 0x47, 0x54, 0x10, 0x3e, 0x47, 0x54, 0x11, 0x5a, 0x47, 0x06, 0x47, + 0x05, 0x52, 0x00, 0x53, 0x45, 0x50, 0x00, 0x08, 0x51, 0x45, 0x08, + 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, + 0x7c, 0x19, 0x9e, 0x60, 0xd4, 0x3e, 0x47, 0x54, 0x12, 0x3e, 0x47, + 0x54, 0x13, 0x50, 0x03, 0x08, 0x5a, 0x47, 0x06, 0x47, 0x0e, 0x08, + 0x51, 0x47, 0x08, 0x7c, 0x17, 0x38, 0x38, 0xfd, 0x62, 0xd0, 0x00, + 0x51, 0x47, 0x54, 0x15, 0x51, 0x48, 0x54, 0x14, 0x7c, 0x18, 0xb9, + 0x7c, 0x19, 0x93, 0x7c, 0x19, 0xda, 0x06, 0x47, 0x6a, 0x7c, 0x19, + 0xe5, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x62, 0x7c, 0x19, 0xbc, + 0x51, 0x47, 0x01, 0x52, 0x7c, 0x19, 0xbc, 0x06, 0x47, 0x5a, 0x7c, + 0x19, 0xe5, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x3d, 0x38, 0xea, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x16, 0x62, 0xd0, 0x00, 0x50, 0x01, + 0x10, 0x08, 0x57, 0x8a, 0x28, 0x53, 0x48, 0x18, 0x75, 0x09, 0x00, + 0x28, 0x53, 0x47, 0x20, 0x10, 0x51, 0x48, 0x08, 0x51, 0x47, 0x20, + 0x7c, 0x08, 0x75, 0x20, 0x62, 0xd0, 0x00, 0x3c, 0x91, 0x01, 0xb0, + 0x0b, 0x51, 0x22, 0x53, 0x2e, 0x51, 0x23, 0x53, 0x2f, 0x80, 0x0c, + 0x62, 0xd0, 0x00, 0x51, 0x7a, 0x53, 0x22, 0x51, 0x7b, 0x53, 0x23, + 0x10, 0x50, 0x00, 0x7c, 0x07, 0xf6, 0x20, 0x56, 0x0d, 0x00, 0x81, + 0x09, 0x56, 0x00, 0x00, 0x80, 0xfd, 0x62, 0xd0, 0x00, 0x3c, 0x91, + 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x47, 0x55, 0x48, 0x00, 0x06, + 0x47, 0x7a, 0x7c, 0x19, 0x0f, 0x52, 0x00, 0x53, 0x45, 0x55, 0x46, + 0x00, 0x06, 0x45, 0x22, 0x7c, 0x1a, 0x01, 0x10, 0x52, 0x00, 0x7c, + 0x07, 0xf6, 0x20, 0x10, 0x7c, 0x04, 0x81, 0x62, 0xd0, 0x00, 0x20, + 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, 0x00, 0xb0, 0x3a, 0x7c, 0x18, + 0xb9, 0x7c, 0x18, 0xe1, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x51, + 0x40, 0x53, 0x45, 0x51, 0x3f, 0x53, 0x46, 0x50, 0x00, 0x08, 0x50, + 0x07, 0x08, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, 0x7c, 0x18, 0x45, + 0x18, 0x53, 0x45, 0x18, 0x53, 0x46, 0x38, 0xfe, 0x7c, 0x18, 0xf7, + 0x3d, 0x00, 0x01, 0xb0, 0x3d, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb9, + 0x7c, 0x18, 0xe1, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x03, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x51, 0x40, + 0x53, 0x45, 0x51, 0x3f, 0x53, 0x46, 0x50, 0x00, 0x08, 0x50, 0x07, + 0x08, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, 0x7c, 0x18, 0x45, 0x18, + 0x53, 0x45, 0x18, 0x53, 0x46, 0x38, 0xfe, 0x7c, 0x18, 0xf7, 0x62, + 0xd0, 0x00, 0x55, 0x48, 0x03, 0x5a, 0x47, 0x06, 0x47, 0x01, 0x52, + 0x00, 0x53, 0x45, 0x50, 0x00, 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x06, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x7c, 0x19, + 0x9e, 0x53, 0x48, 0x52, 0x0d, 0x53, 0x45, 0x55, 0x46, 0x00, 0x65, + 0x45, 0x6b, 0x46, 0x7c, 0x19, 0xb1, 0x53, 0x48, 0x7c, 0x19, 0xf5, + 0x06, 0x45, 0x86, 0x0e, 0x46, 0x00, 0x51, 0x46, 0x7c, 0x19, 0x04, + 0x7c, 0x18, 0xf7, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x00, 0x77, + 0x0d, 0x3d, 0x0d, 0x03, 0xce, 0xf4, 0x56, 0x00, 0x00, 0x80, 0xc0, + 0x62, 0xd0, 0x00, 0x55, 0x48, 0x03, 0x5a, 0x47, 0x06, 0x47, 0x01, + 0x52, 0x00, 0x53, 0x45, 0x50, 0x00, 0x08, 0x51, 0x45, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x7c, + 0x19, 0x9e, 0x60, 0xd4, 0x3e, 0x47, 0x54, 0x0e, 0x3e, 0x47, 0x54, + 0x0f, 0x5a, 0x47, 0x06, 0x47, 0x03, 0x52, 0x00, 0x53, 0x45, 0x50, + 0x00, 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, + 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x7c, 0x19, 0x9e, 0x60, 0xd4, 0x3e, + 0x47, 0x54, 0x10, 0x3e, 0x47, 0x54, 0x11, 0x5a, 0x47, 0x06, 0x47, + 0x05, 0x52, 0x00, 0x53, 0x45, 0x50, 0x00, 0x08, 0x51, 0x45, 0x08, + 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x18, 0x89, 0x38, 0xfc, + 0x7c, 0x19, 0x9e, 0x60, 0xd4, 0x3e, 0x47, 0x54, 0x12, 0x3e, 0x47, + 0x54, 0x13, 0x50, 0x03, 0x08, 0x5a, 0x47, 0x06, 0x47, 0x0e, 0x08, + 0x51, 0x47, 0x08, 0x7c, 0x17, 0x38, 0x38, 0xfd, 0x62, 0xd0, 0x00, + 0x51, 0x47, 0x54, 0x15, 0x51, 0x48, 0x54, 0x14, 0x7c, 0x18, 0xb9, + 0x7c, 0x19, 0x93, 0x7c, 0x19, 0xda, 0x06, 0x47, 0x6a, 0x7c, 0x19, + 0xe5, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x62, 0x7c, 0x19, 0xbc, + 0x51, 0x47, 0x01, 0x52, 0x7c, 0x19, 0xbc, 0x06, 0x47, 0x5a, 0x7c, + 0x19, 0xe5, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x3d, 0x56, 0x00, + 0x00, 0x80, 0x19, 0x7c, 0x18, 0xd6, 0x06, 0x47, 0x22, 0x7c, 0x19, + 0x0f, 0x52, 0x00, 0x53, 0x45, 0x55, 0x46, 0x00, 0x06, 0x45, 0x2e, + 0x7c, 0x1a, 0x01, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xe4, 0x38, + 0xea, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x0a, 0x62, 0xd0, 0x00, 0x55, + 0x8d, 0x00, 0x3c, 0x91, 0x00, 0xb0, 0x05, 0x51, 0x7a, 0x53, 0x22, + 0x10, 0x50, 0x00, 0x7c, 0x07, 0xf6, 0x20, 0x56, 0x00, 0x00, 0x80, + 0xb7, 0x62, 0xd0, 0x00, 0x3c, 0x91, 0x00, 0xb0, 0x1b, 0x52, 0x00, + 0x53, 0x47, 0x55, 0x48, 0x00, 0x06, 0x47, 0x7a, 0x7c, 0x19, 0x0f, + 0x52, 0x00, 0x53, 0x45, 0x55, 0x46, 0x00, 0x06, 0x45, 0x22, 0x7c, + 0x1a, 0x01, 0x10, 0x52, 0x00, 0x7c, 0x07, 0xf6, 0x20, 0x10, 0x7c, + 0x04, 0x81, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, 0x3d, + 0x00, 0x00, 0xb0, 0x3a, 0x7c, 0x18, 0xb9, 0x7c, 0x18, 0xe1, 0x51, + 0x46, 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, + 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x51, 0x40, 0x53, 0x45, 0x51, 0x3f, + 0x53, 0x46, 0x50, 0x00, 0x08, 0x50, 0x07, 0x08, 0x51, 0x46, 0x08, + 0x51, 0x45, 0x08, 0x7c, 0x18, 0x45, 0x18, 0x53, 0x45, 0x18, 0x53, + 0x46, 0x38, 0xfe, 0x7c, 0x18, 0xf7, 0x3d, 0x00, 0x01, 0xb0, 0x3d, + 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb9, 0x7c, 0x18, 0xe1, 0x51, 0x46, + 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x7c, + 0x18, 0x89, 0x38, 0xfc, 0x51, 0x40, 0x53, 0x45, 0x51, 0x3f, 0x53, + 0x46, 0x50, 0x00, 0x08, 0x50, 0x07, 0x08, 0x51, 0x46, 0x08, 0x51, + 0x45, 0x08, 0x7c, 0x18, 0x45, 0x18, 0x53, 0x45, 0x18, 0x53, 0x46, + 0x38, 0xfe, 0x7c, 0x18, 0xf7, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, + 0x46, 0x56, 0x00, 0x00, 0x82, 0xf8, 0x62, 0xd0, 0x00, 0x3c, 0x96, + 0x02, 0xa0, 0x9f, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x6a, 0x7c, + 0x18, 0xc5, 0x06, 0x47, 0x86, 0x7c, 0x19, 0x0f, 0x7c, 0x19, 0xcd, + 0xd0, 0x16, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x6a, 0x7c, 0x18, + 0xc5, 0x06, 0x47, 0x86, 0x7c, 0x19, 0x0f, 0x7c, 0x1a, 0x50, 0x80, + 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x86, + 0x7c, 0x18, 0xc5, 0x06, 0x47, 0x6a, 0x7c, 0x19, 0x0f, 0x7c, 0x1a, + 0x50, 0x50, 0x90, 0x13, 0x07, 0x50, 0x01, 0x1b, 0x06, 0xc0, 0x4e, + 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x5a, 0x7c, + 0x18, 0xc5, 0x06, 0x47, 0x86, 0x7c, 0x19, 0x0f, 0x7c, 0x19, 0xcd, + 0xd0, 0x16, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x5a, 0x7c, 0x18, + 0xc5, 0x06, 0x47, 0x86, 0x7c, 0x19, 0x0f, 0x7c, 0x1a, 0x43, 0x80, + 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x86, + 0x7c, 0x18, 0xc5, 0x06, 0x47, 0x5a, 0x7c, 0x19, 0x0f, 0x7c, 0x1a, + 0x43, 0x50, 0x90, 0x13, 0x09, 0x50, 0x01, 0x1b, 0x08, 0xd0, 0x08, + 0x62, 0xd0, 0x00, 0x76, 0x8d, 0x82, 0x50, 0x62, 0xd0, 0x00, 0x7c, + 0x18, 0xb9, 0x51, 0x47, 0x01, 0x86, 0x7c, 0x18, 0xc5, 0x06, 0x47, + 0x5a, 0x7c, 0x19, 0x0f, 0x7c, 0x19, 0xcd, 0xd0, 0x7e, 0x7c, 0x18, + 0xb9, 0x7c, 0x18, 0xe1, 0x06, 0x45, 0x01, 0x0e, 0x46, 0x00, 0x7c, + 0x18, 0xf7, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x86, 0x7c, 0x18, + 0xc5, 0x06, 0x47, 0x5a, 0x7c, 0x19, 0x0f, 0x7c, 0x19, 0xcd, 0xd1, + 0x01, 0x7c, 0x18, 0xb9, 0x7c, 0x18, 0xe1, 0x06, 0x45, 0x01, 0x0e, + 0x46, 0x00, 0x7c, 0x18, 0xf7, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, + 0x86, 0x7c, 0x18, 0xc5, 0x06, 0x47, 0x5a, 0x7c, 0x19, 0x0f, 0x7c, + 0x19, 0xcd, 0xd0, 0xdd, 0x7c, 0x18, 0xb9, 0x7c, 0x18, 0xe1, 0x06, + 0x45, 0x01, 0x0e, 0x46, 0x00, 0x7c, 0x18, 0xf7, 0x7c, 0x18, 0xb9, + 0x51, 0x47, 0x01, 0x86, 0x7c, 0x18, 0xc5, 0x06, 0x47, 0x5a, 0x7c, + 0x19, 0x0f, 0x7c, 0x19, 0xcd, 0xd0, 0xb9, 0x7c, 0x18, 0xb9, 0x7c, + 0x18, 0xe1, 0x06, 0x45, 0x01, 0x0e, 0x46, 0x00, 0x7c, 0x18, 0xf7, + 0x80, 0xa8, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, + 0x86, 0x7c, 0x18, 0xc5, 0x06, 0x47, 0x5a, 0x7c, 0x19, 0x0f, 0x3e, + 0x47, 0x12, 0x45, 0x51, 0x48, 0x1a, 0x46, 0xd0, 0x8b, 0x7c, 0x18, + 0xb9, 0x7c, 0x18, 0xe1, 0x16, 0x45, 0x01, 0x1e, 0x46, 0x00, 0x7c, + 0x18, 0xf7, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x86, 0x7c, 0x18, + 0xc5, 0x06, 0x47, 0x5a, 0x7c, 0x19, 0x0f, 0x3e, 0x47, 0x12, 0x45, + 0x51, 0x48, 0x1a, 0x46, 0xd0, 0x62, 0x7c, 0x18, 0xb9, 0x7c, 0x18, + 0xe1, 0x16, 0x45, 0x01, 0x1e, 0x46, 0x00, 0x7c, 0x18, 0xf7, 0x7c, + 0x18, 0xb9, 0x51, 0x47, 0x01, 0x86, 0x7c, 0x18, 0xc5, 0x06, 0x47, + 0x5a, 0x7c, 0x19, 0x0f, 0x3e, 0x47, 0x12, 0x45, 0x51, 0x48, 0x1a, + 0x46, 0xd0, 0x39, 0x7c, 0x18, 0xb9, 0x7c, 0x18, 0xe1, 0x16, 0x45, + 0x01, 0x1e, 0x46, 0x00, 0x7c, 0x18, 0xf7, 0x7c, 0x18, 0xb9, 0x51, + 0x47, 0x01, 0x86, 0x7c, 0x18, 0xc5, 0x06, 0x47, 0x5a, 0x7c, 0x19, + 0x0f, 0x3e, 0x47, 0x12, 0x45, 0x51, 0x48, 0x1a, 0x46, 0xd0, 0x10, + 0x7c, 0x18, 0xb9, 0x7c, 0x18, 0xe1, 0x16, 0x45, 0x01, 0x1e, 0x46, + 0x00, 0x7c, 0x18, 0xf7, 0x62, 0xd0, 0x00, 0x7c, 0x18, 0xb9, 0x51, + 0x47, 0x01, 0x52, 0x7c, 0x18, 0xc5, 0x06, 0x47, 0x62, 0x0e, 0x48, + 0x00, 0x7c, 0x18, 0xf7, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x5a, + 0x7c, 0x18, 0xc5, 0x06, 0x47, 0x52, 0x0e, 0x48, 0x00, 0x7c, 0x18, + 0xf7, 0x7c, 0x18, 0xb9, 0x51, 0x47, 0x01, 0x86, 0x7c, 0x18, 0xc5, + 0x06, 0x47, 0x5a, 0x0e, 0x48, 0x00, 0x7c, 0x18, 0xf7, 0x97, 0xf6, + 0x40, 0x7c, 0x19, 0x93, 0x53, 0x46, 0x7c, 0x1a, 0x5d, 0x53, 0x43, + 0x08, 0x51, 0x44, 0x53, 0x42, 0x18, 0x53, 0x41, 0x65, 0x41, 0x6b, + 0x42, 0x06, 0x47, 0x52, 0x7c, 0x19, 0x0f, 0x3e, 0x47, 0x53, 0x47, + 0x51, 0x41, 0x04, 0x47, 0x51, 0x42, 0x0c, 0x48, 0x51, 0x43, 0x04, + 0x47, 0x51, 0x44, 0x0c, 0x48, 0x70, 0xfb, 0x6e, 0x48, 0x6e, 0x47, + 0x7c, 0x1a, 0x24, 0x10, 0x52, 0x00, 0x7c, 0x04, 0xc5, 0x20, 0x62, + 0xd0, 0x00, 0x97, 0xb0, 0x40, 0x51, 0x47, 0x01, 0x86, 0x97, 0xb5, + 0x40, 0x06, 0x47, 0x6a, 0x97, 0xf9, 0x40, 0x7c, 0x19, 0xcd, 0xd0, + 0x25, 0x52, 0x00, 0x53, 0x47, 0x55, 0x48, 0x00, 0x06, 0x47, 0x76, + 0x0e, 0x48, 0x00, 0x51, 0x48, 0x60, 0xd4, 0x3e, 0x47, 0x7a, 0x47, + 0x53, 0x46, 0x06, 0x46, 0x01, 0x51, 0x48, 0x60, 0xd5, 0x51, 0x46, + 0x3f, 0x47, 0x80, 0x0a, 0x97, 0x94, 0x40, 0x06, 0x47, 0x76, 0x7c, + 0x1a, 0x37, 0x97, 0x8b, 0x40, 0x06, 0x47, 0x76, 0x97, 0xbe, 0x40, + 0x50, 0x05, 0x3a, 0x48, 0xd0, 0x41, 0x97, 0x5f, 0x40, 0x51, 0x47, + 0x01, 0x6a, 0x53, 0x45, 0x51, 0x48, 0x09, 0x00, 0x53, 0x46, 0x06, + 0x47, 0x86, 0x97, 0xa3, 0x40, 0x3e, 0x47, 0x53, 0x47, 0x51, 0x46, + 0x7c, 0x1a, 0x5d, 0x02, 0x47, 0x53, 0x47, 0x51, 0x44, 0x0a, 0x48, + 0x53, 0x48, 0x7c, 0x1a, 0x24, 0x52, 0x00, 0x53, 0x47, 0x55, 0x48, + 0x00, 0x06, 0x47, 0x76, 0x0e, 0x48, 0x00, 0x51, 0x48, 0x60, 0xd5, + 0x50, 0x00, 0x3f, 0x47, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcd, 0x05, + 0x62, 0xd0, 0x00, 0x3c, 0x96, 0x02, 0xb1, 0x40, 0x56, 0x00, 0x00, + 0x81, 0x36, 0x3d, 0x00, 0x00, 0xb0, 0x99, 0x62, 0xd0, 0x00, 0x97, + 0x03, 0x40, 0x51, 0x47, 0x01, 0x86, 0x97, 0x08, 0x40, 0x51, 0x46, + 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, 0x08, 0x50, 0x07, 0x08, 0x7c, + 0x18, 0x89, 0x38, 0xfc, 0x51, 0x40, 0x53, 0x45, 0x51, 0x3f, 0x53, + 0x46, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x51, 0x46, 0x08, 0x51, + 0x45, 0x08, 0x7c, 0x18, 0x45, 0x18, 0x53, 0x45, 0x18, 0x53, 0x46, + 0x38, 0xfe, 0x06, 0x47, 0x36, 0x0e, 0x48, 0x00, 0x97, 0x01, 0x40, + 0x96, 0xc0, 0x40, 0x51, 0x47, 0x01, 0x6a, 0x96, 0xc5, 0x40, 0x51, + 0x46, 0x08, 0x51, 0x45, 0x08, 0x50, 0x00, 0x08, 0x50, 0x07, 0x08, + 0x7c, 0x18, 0x89, 0x38, 0xfc, 0x51, 0x40, 0x53, 0x45, 0x51, 0x3f, + 0x53, 0x46, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x51, 0x46, 0x08, + 0x51, 0x45, 0x08, 0x7c, 0x18, 0x45, 0x18, 0x53, 0x45, 0x18, 0x53, + 0x46, 0x38, 0xfe, 0x06, 0x47, 0x3a, 0x0e, 0x48, 0x00, 0x96, 0xbe, + 0x40, 0x96, 0x7d, 0x40, 0x51, 0x47, 0x01, 0x6a, 0x96, 0x82, 0x40, + 0x96, 0xd5, 0x40, 0x80, 0x97, 0x62, 0xd0, 0x00, 0x96, 0x6b, 0x40, + 0x51, 0x47, 0x01, 0x86, 0x96, 0x70, 0x40, 0x51, 0x46, 0x08, 0x51, + 0x45, 0x08, 0x50, 0x00, 0x08, 0x50, 0x07, 0x08, 0x7c, 0x18, 0x89, + 0x38, 0xfc, 0x51, 0x40, 0x53, 0x45, 0x51, 0x3f, 0x53, 0x46, 0x50, + 0x00, 0x08, 0x50, 0x03, 0x08, 0x51, 0x46, 0x08, 0x51, 0x45, 0x08, + 0x7c, 0x18, 0x45, 0x18, 0x53, 0x45, 0x18, 0x53, 0x46, 0x38, 0xfe, + 0x06, 0x47, 0x36, 0x0e, 0x48, 0x00, 0x96, 0x69, 0x40, 0x96, 0x28, + 0x40, 0x51, 0x47, 0x01, 0x6a, 0x96, 0x2d, 0x40, 0x51, 0x46, 0x08, + 0x51, 0x45, 0x08, 0x50, 0x00, 0x08, 0x50, 0x07, 0x08, 0x7c, 0x18, + 0x89, 0x38, 0xfc, 0x51, 0x40, 0x53, 0x45, 0x51, 0x3f, 0x53, 0x46, + 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x51, 0x46, 0x08, 0x51, 0x45, + 0x08, 0x7c, 0x18, 0x45, 0x18, 0x53, 0x45, 0x18, 0x53, 0x46, 0x38, + 0xfe, 0x06, 0x47, 0x3a, 0x0e, 0x48, 0x00, 0x96, 0x26, 0x40, 0x95, + 0xe5, 0x40, 0x51, 0x47, 0x01, 0x6a, 0x95, 0xea, 0x40, 0x96, 0x3d, + 0x40, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xc7, 0x62, 0xd0, 0x00, + 0x3c, 0x96, 0x02, 0xa0, 0x18, 0x3c, 0x8d, 0x00, 0xa0, 0x13, 0x50, + 0x75, 0x08, 0x50, 0x30, 0x08, 0x90, 0x0e, 0x38, 0xfe, 0x7c, 0x09, + 0x8d, 0x10, 0x7c, 0x06, 0x81, 0x20, 0x38, 0xf6, 0x20, 0x7f, 0x10, + 0x4f, 0x80, 0x02, 0x40, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x47, + 0x52, 0xfb, 0x53, 0x48, 0x51, 0x47, 0x11, 0x01, 0x54, 0xfc, 0x51, + 0x48, 0x19, 0x00, 0x54, 0xfb, 0x3c, 0x48, 0x00, 0xbf, 0xe4, 0x3c, + 0x47, 0x00, 0xbf, 0xdf, 0x20, 0x7f, 0x10, 0x7c, 0x03, 0x45, 0x7c, + 0x03, 0x22, 0x20, 0x7f, 0x10, 0x7c, 0x03, 0x41, 0x7c, 0x03, 0x1e, + 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x4b, 0x12, 0x6f, 0x50, 0x00, + 0x1a, 0x6e, 0xd0, 0x0f, 0x51, 0x4c, 0x12, 0x71, 0x50, 0x00, 0x1a, + 0x70, 0xd0, 0x05, 0x50, 0x0f, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x51, + 0x6f, 0x12, 0x71, 0x51, 0x6e, 0x1a, 0x70, 0xd0, 0x05, 0x50, 0x00, + 0x80, 0x06, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x7f, 0x10, 0x4f, 0x38, + 0x05, 0x62, 0xd0, 0x00, 0x51, 0x6f, 0x54, 0x02, 0x51, 0x6e, 0x54, + 0x01, 0x56, 0x04, 0x00, 0x56, 0x00, 0x00, 0x56, 0x03, 0x00, 0x80, + 0x5d, 0x95, 0x45, 0x40, 0x06, 0x47, 0x4b, 0x0e, 0x48, 0x00, 0x51, + 0x48, 0x60, 0xd4, 0x3e, 0x47, 0x53, 0x47, 0x96, 0x53, 0x40, 0x06, + 0x45, 0x6e, 0x0e, 0x46, 0x00, 0x51, 0x46, 0x95, 0x57, 0x40, 0x51, + 0x47, 0x12, 0x45, 0x50, 0x00, 0x1a, 0x46, 0xd0, 0x03, 0x77, 0x03, + 0x62, 0xd0, 0x00, 0x94, 0xfa, 0x40, 0x06, 0x47, 0x6e, 0x95, 0x4a, + 0x40, 0x3e, 0x47, 0x13, 0x02, 0x51, 0x48, 0x1b, 0x01, 0xd0, 0x1a, + 0x94, 0xe7, 0x40, 0x06, 0x47, 0x6e, 0x0e, 0x48, 0x00, 0x51, 0x48, + 0x60, 0xd4, 0x3e, 0x47, 0x54, 0x01, 0x3e, 0x47, 0x54, 0x02, 0x52, + 0x00, 0x54, 0x04, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xa0, 0x50, + 0x01, 0x3b, 0x03, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x0f, 0x80, + 0x06, 0x52, 0x04, 0x62, 0xd0, 0x00, 0x38, 0xfb, 0x20, 0x7f, 0x10, + 0x4f, 0x38, 0x02, 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x26, 0x28, 0xf0, + 0x51, 0x95, 0x01, 0x01, 0x53, 0x48, 0x51, 0x28, 0x2a, 0x48, 0x53, + 0x28, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x04, 0x81, 0x62, + 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, 0x00, + 0x00, 0x80, 0x21, 0x10, 0x7c, 0x04, 0x81, 0x62, 0xd0, 0x00, 0x20, + 0x53, 0x48, 0x47, 0x48, 0x20, 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, + 0x08, 0x50, 0x14, 0x08, 0x9e, 0xba, 0x38, 0xfe, 0x77, 0x01, 0x0f, + 0x00, 0x00, 0x52, 0x01, 0x11, 0x2c, 0x52, 0x00, 0x19, 0x01, 0xcf, + 0xd7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, + 0x04, 0x81, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x48, 0x47, 0x48, 0x20, + 0xb0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, + 0x88, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, + 0x3c, 0x52, 0x00, 0x19, 0x00, 0xcf, 0xd7, 0x62, 0xd0, 0x00, 0x51, + 0x28, 0x29, 0x08, 0x53, 0x28, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, + 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x26, + 0x28, 0xf0, 0x51, 0x95, 0x01, 0x09, 0x53, 0x48, 0x51, 0x28, 0x2a, + 0x48, 0x53, 0x28, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x04, + 0x81, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, 0x01, 0x00, + 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x04, 0x81, 0x62, 0xd0, + 0x00, 0x20, 0x53, 0x48, 0x47, 0x48, 0x20, 0xa0, 0x03, 0x80, 0x1a, + 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, 0x1e, 0x38, 0xfe, 0x77, + 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, 0x2c, 0x52, 0x00, 0x19, + 0x01, 0xcf, 0xd7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, + 0x10, 0x7c, 0x04, 0x81, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x48, 0x47, + 0x48, 0x20, 0xb0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x14, + 0x08, 0x9d, 0xec, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, + 0x01, 0x11, 0x3c, 0x52, 0x00, 0x19, 0x00, 0xcf, 0xd7, 0x43, 0x00, + 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x04, 0x62, 0xd0, + 0x00, 0x51, 0x28, 0x21, 0xf0, 0x54, 0x00, 0x51, 0x2b, 0x54, 0x01, + 0x3d, 0x00, 0x10, 0xb0, 0x12, 0x55, 0x8f, 0x00, 0x55, 0x82, 0x00, + 0x55, 0x83, 0x00, 0x56, 0x00, 0x00, 0x26, 0x28, 0x0f, 0x81, 0x94, + 0x3d, 0x00, 0x20, 0xb0, 0x18, 0x62, 0xd0, 0x00, 0x55, 0x8f, 0x01, + 0x55, 0x90, 0x00, 0x55, 0x82, 0x08, 0x55, 0x83, 0x08, 0x56, 0x00, + 0x00, 0x26, 0x28, 0x0f, 0x81, 0x78, 0x3d, 0x00, 0x40, 0xb0, 0x0f, + 0x62, 0xd0, 0x00, 0x55, 0x96, 0x02, 0x56, 0x00, 0x00, 0x26, 0x28, + 0x0f, 0x81, 0x65, 0x3d, 0x00, 0x50, 0xb0, 0xa7, 0x52, 0x01, 0x54, + 0x03, 0x56, 0x02, 0x00, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, + 0x01, 0xa0, 0x21, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x02, + 0xa0, 0x28, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x04, 0xa0, + 0x36, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x08, 0xa0, 0x48, + 0x80, 0x62, 0x62, 0xd0, 0x00, 0x55, 0x91, 0x01, 0x51, 0x2d, 0x29, + 0x80, 0x53, 0x2d, 0x7c, 0x0b, 0x7c, 0x80, 0x51, 0x62, 0xd0, 0x00, + 0x51, 0x29, 0x53, 0x4b, 0x51, 0x29, 0x53, 0x4c, 0x51, 0x29, 0x53, + 0x2c, 0x51, 0x2a, 0x53, 0x0c, 0x55, 0x0b, 0x00, 0x80, 0x39, 0x62, + 0xd0, 0x00, 0x51, 0x29, 0x53, 0x2d, 0x3c, 0x91, 0x00, 0xa0, 0x09, + 0x51, 0x2d, 0x29, 0x80, 0x53, 0x2d, 0x80, 0x25, 0x62, 0xd0, 0x00, + 0x26, 0x2d, 0x7f, 0x80, 0x1d, 0x62, 0xd0, 0x00, 0x55, 0x91, 0x00, + 0x26, 0x2d, 0x7f, 0x51, 0x7a, 0x53, 0x22, 0x51, 0x22, 0x53, 0x2e, + 0x51, 0x7b, 0x53, 0x23, 0x51, 0x23, 0x53, 0x2f, 0x7c, 0x0b, 0x7c, + 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x28, 0x0f, 0x55, 0x29, + 0x12, 0x55, 0x2a, 0x11, 0x55, 0x2b, 0x00, 0x80, 0xba, 0x3d, 0x00, + 0x60, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0x8c, 0x01, 0x56, 0x00, + 0x00, 0x26, 0x28, 0x0f, 0x80, 0xa7, 0x3d, 0x00, 0x70, 0xb0, 0x0f, + 0x62, 0xd0, 0x00, 0x55, 0x8c, 0x00, 0x56, 0x00, 0x00, 0x26, 0x28, + 0x0f, 0x80, 0x94, 0x3d, 0x00, 0x80, 0xb0, 0x8f, 0x56, 0x00, 0x00, + 0x62, 0xd0, 0x00, 0x26, 0x28, 0x0f, 0x9c, 0xc5, 0x10, 0x7c, 0x03, + 0x45, 0x7c, 0x03, 0x22, 0x7c, 0x07, 0x74, 0x7c, 0x04, 0x97, 0x20, + 0x93, 0x91, 0x40, 0x70, 0xfe, 0x71, 0x10, 0x43, 0x00, 0x08, 0x43, + 0x01, 0x08, 0x70, 0xcf, 0x43, 0x00, 0x08, 0x62, 0xda, 0x00, 0x71, + 0x10, 0x41, 0xdc, 0xfe, 0x70, 0xcf, 0x43, 0x01, 0x08, 0x43, 0x00, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x1e, 0x08, 0x9c, 0x65, 0x38, 0xfe, + 0x71, 0x01, 0x43, 0xe0, 0x10, 0x41, 0x7a, 0xef, 0x41, 0x7a, 0xfe, + 0x71, 0x10, 0x41, 0xdc, 0xfd, 0x41, 0xec, 0xfd, 0x43, 0xe0, 0x40, + 0x41, 0xe0, 0xdf, 0x70, 0xcf, 0x43, 0xff, 0x08, 0x43, 0x7a, 0x10, + 0x43, 0x7a, 0x01, 0x70, 0xfe, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x10, 0x7c, 0x06, 0xa3, 0x7c, 0x04, 0x4b, 0x7c, 0x04, 0x8c, + 0x20, 0x93, 0x2d, 0x40, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x56, 0x00, + 0x00, 0x62, 0xd0, 0x00, 0x26, 0x28, 0x0f, 0x38, 0xfc, 0x20, 0x7f, + 0x62, 0xd0, 0x00, 0x3c, 0x8f, 0x00, 0xa0, 0x13, 0x9c, 0x34, 0x62, + 0xd0, 0x00, 0x3c, 0x90, 0x00, 0xb0, 0x33, 0x55, 0x90, 0x01, 0x7c, + 0x09, 0x8d, 0x80, 0x2b, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x82, + 0xd0, 0x08, 0x10, 0x7c, 0x03, 0x45, 0x20, 0x80, 0x06, 0x10, 0x7c, + 0x03, 0x41, 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x83, 0xd0, + 0x08, 0x10, 0x7c, 0x03, 0x22, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x03, + 0x1e, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x03, 0x56, 0x02, 0x00, 0x56, + 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x3e, 0x62, 0xd0, 0x00, 0x91, + 0x6d, 0x40, 0x52, 0xfc, 0x04, 0x47, 0x52, 0xfb, 0x0c, 0x48, 0x51, + 0x48, 0x60, 0xd4, 0x3e, 0x47, 0x53, 0x48, 0x3e, 0x47, 0x53, 0x47, + 0x52, 0x02, 0x12, 0x47, 0x52, 0x01, 0x1a, 0x48, 0xd0, 0x18, 0x91, + 0x4c, 0x40, 0x52, 0xfc, 0x04, 0x47, 0x52, 0xfb, 0x0c, 0x48, 0x51, + 0x48, 0x60, 0xd4, 0x3e, 0x47, 0x54, 0x01, 0x3e, 0x47, 0x54, 0x02, + 0x77, 0x00, 0x52, 0x00, 0x3b, 0xfa, 0xcf, 0xbe, 0x62, 0xd0, 0x00, + 0x52, 0x02, 0x53, 0x47, 0x52, 0x01, 0x53, 0x48, 0x38, 0xfd, 0x20, + 0x7f, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x91, 0x00, 0x55, 0x8c, 0x01, + 0x10, 0x7c, 0x03, 0x45, 0x7c, 0x03, 0x22, 0x20, 0x9b, 0x84, 0x71, + 0x10, 0x41, 0x00, 0xf7, 0x41, 0x01, 0xf7, 0x70, 0xcf, 0x43, 0x00, + 0x08, 0x43, 0x00, 0x08, 0x62, 0xd0, 0x00, 0x55, 0x28, 0x08, 0x55, + 0x29, 0x12, 0x55, 0x2a, 0x11, 0x55, 0x2c, 0x1e, 0x55, 0x2d, 0x02, + 0x3c, 0x91, 0x00, 0xa0, 0x09, 0x51, 0x2d, 0x29, 0x80, 0x53, 0x2d, + 0x80, 0x07, 0x62, 0xd0, 0x00, 0x26, 0x2d, 0x7f, 0x10, 0x50, 0x00, + 0x08, 0x50, 0x28, 0x08, 0x50, 0x06, 0x08, 0x50, 0x16, 0x08, 0x7c, + 0x04, 0x9e, 0x38, 0xfc, 0x7c, 0x04, 0x4b, 0x7c, 0x04, 0x8c, 0x20, + 0x71, 0x10, 0x41, 0x04, 0xfe, 0x41, 0x05, 0xfe, 0x41, 0x04, 0xfd, + 0x41, 0x05, 0xfd, 0x70, 0xcf, 0x43, 0x04, 0x01, 0x43, 0x04, 0x02, + 0x71, 0x01, 0x10, 0x7c, 0x06, 0xa3, 0x7c, 0x06, 0x29, 0x20, 0x7c, + 0x0b, 0x7c, 0x80, 0x22, 0x62, 0xe3, 0x38, 0x7c, 0x0d, 0xc4, 0x10, + 0x7c, 0x06, 0x67, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xa0, 0x09, + 0x7c, 0x08, 0xc3, 0x7c, 0x08, 0xed, 0x80, 0x04, 0x7c, 0x09, 0x56, + 0x9c, 0xf6, 0x9e, 0xb2, 0x8f, 0xde, 0x8f, 0xff, 0x10, 0x4f, 0x7c, + 0x18, 0x50, 0x20, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x5d, 0xd0, 0x08, + 0x62, 0xd0, 0x00, 0x50, 0x00, 0x53, 0x3f, 0x53, 0x40, 0x55, 0x3e, + 0x10, 0x66, 0xfc, 0x6c, 0xfb, 0x6b, 0x3f, 0x6b, 0x40, 0x51, 0x3f, + 0x1b, 0xfa, 0x51, 0x40, 0x1b, 0xf9, 0xc0, 0x09, 0x53, 0x40, 0x52, + 0xfa, 0x1c, 0x3f, 0x77, 0xfc, 0x7a, 0x3e, 0xbf, 0xe3, 0x51, 0x3f, + 0x54, 0xfa, 0x51, 0x40, 0x54, 0xf9, 0x18, 0x60, 0xd0, 0x7f, 0x10, + 0x4f, 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x00, 0x53, 0x40, + 0x53, 0x3f, 0x55, 0x3e, 0x10, 0x6f, 0xf9, 0x6f, 0xfa, 0xd0, 0x09, + 0x52, 0xfc, 0x04, 0x40, 0x52, 0xfb, 0x0c, 0x3f, 0x66, 0xfc, 0x6c, + 0xfb, 0x7a, 0x3e, 0xbf, 0xeb, 0x18, 0x60, 0xd0, 0x20, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x52, 0x00, 0x53, 0x47, 0x55, 0x48, 0x00, 0x65, + 0x47, 0x6b, 0x48, 0x7f, 0x53, 0x45, 0x51, 0x48, 0x09, 0x00, 0x60, + 0xd4, 0x3e, 0x45, 0x53, 0x46, 0x3e, 0x45, 0x53, 0x45, 0x7f, 0x62, + 0xd0, 0x00, 0x52, 0x00, 0x53, 0x47, 0x55, 0x48, 0x00, 0x7f, 0x06, + 0x47, 0x86, 0x0e, 0x48, 0x00, 0x51, 0x48, 0x60, 0xd4, 0x3e, 0x47, + 0x53, 0x46, 0x3e, 0x47, 0x16, 0x47, 0x02, 0x53, 0x45, 0x7f, 0x51, + 0x48, 0x60, 0xd5, 0x51, 0x46, 0x3f, 0x47, 0x51, 0x45, 0x3f, 0x47, + 0x7f, 0x60, 0xd4, 0x3e, 0x45, 0x53, 0x46, 0x3e, 0x45, 0x53, 0x45, + 0x7f, 0x0e, 0x48, 0x00, 0x51, 0x48, 0x60, 0xd4, 0x3e, 0x47, 0x53, + 0x48, 0x7f, 0x51, 0x47, 0x01, 0x86, 0x53, 0x43, 0x51, 0x48, 0x09, + 0x00, 0x60, 0xd4, 0x3e, 0x43, 0x53, 0x44, 0x3e, 0x43, 0x53, 0x43, + 0x51, 0x45, 0x12, 0x43, 0x51, 0x46, 0x1a, 0x44, 0xd0, 0x3f, 0x62, + 0xd0, 0x00, 0x52, 0x00, 0x53, 0x45, 0x55, 0x46, 0x00, 0x65, 0x45, + 0x6b, 0x46, 0x51, 0x45, 0x01, 0x6a, 0x53, 0x43, 0x51, 0x46, 0x09, + 0x00, 0x60, 0xd4, 0x3e, 0x43, 0x53, 0x44, 0x3e, 0x43, 0x53, 0x43, + 0x06, 0x45, 0x86, 0x0e, 0x46, 0x00, 0x51, 0x46, 0x60, 0xd4, 0x3e, + 0x45, 0x53, 0x46, 0x3e, 0x45, 0x12, 0x43, 0x54, 0x07, 0x51, 0x46, + 0x1a, 0x44, 0x54, 0x06, 0x80, 0x07, 0x56, 0x07, 0x00, 0x56, 0x06, + 0x00, 0x62, 0xd0, 0x00, 0x06, 0x47, 0x32, 0x0e, 0x48, 0x00, 0x51, + 0x48, 0x60, 0xd5, 0x52, 0x06, 0x3f, 0x47, 0x52, 0x07, 0x3f, 0x47, + 0x7f, 0x51, 0x47, 0x01, 0x86, 0x53, 0x45, 0x51, 0x48, 0x09, 0x00, + 0x7f, 0x51, 0x40, 0x53, 0x45, 0x51, 0x3f, 0x53, 0x46, 0x51, 0x45, + 0x02, 0x47, 0x53, 0x47, 0x51, 0x46, 0x0a, 0x48, 0x7f, 0x51, 0x45, + 0x02, 0x47, 0x53, 0x47, 0x51, 0x46, 0x0a, 0x48, 0x7f, 0x53, 0x45, + 0x51, 0x48, 0x09, 0x00, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x45, 0x52, + 0x15, 0x3f, 0x45, 0x7f, 0x3e, 0x47, 0x53, 0x47, 0x51, 0x45, 0x12, + 0x47, 0x51, 0x46, 0x1a, 0x48, 0x7f, 0x60, 0xd5, 0x52, 0x14, 0x3f, + 0x45, 0x52, 0x15, 0x3f, 0x45, 0x7f, 0x0e, 0x48, 0x00, 0x51, 0x48, + 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x47, 0x52, 0x15, 0x3f, 0x47, 0x7f, + 0x52, 0x00, 0x53, 0x45, 0x55, 0x46, 0x00, 0x65, 0x45, 0x6b, 0x46, + 0x7f, 0x0e, 0x46, 0x00, 0x51, 0x46, 0x60, 0xd5, 0x51, 0x48, 0x3f, + 0x45, 0x7f, 0x71, 0x10, 0x43, 0x04, 0x01, 0x43, 0x05, 0x01, 0x43, + 0x04, 0x02, 0x43, 0x05, 0x02, 0x70, 0xcf, 0x43, 0x04, 0x01, 0x43, + 0x04, 0x02, 0x7f, 0x70, 0xfb, 0x6e, 0x48, 0x6e, 0x47, 0x51, 0x46, + 0x60, 0xd5, 0x51, 0x48, 0x3f, 0x45, 0x51, 0x47, 0x3f, 0x45, 0x7f, + 0x0e, 0x48, 0x00, 0x51, 0x48, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x47, + 0x7f, 0x3e, 0x47, 0x12, 0x45, 0x54, 0x09, 0x51, 0x48, 0x1a, 0x46, + 0x54, 0x08, 0x7f, 0x3e, 0x47, 0x12, 0x45, 0x54, 0x07, 0x51, 0x48, + 0x1a, 0x46, 0x54, 0x06, 0x7f, 0x60, 0xd4, 0x3e, 0x45, 0x53, 0x44, + 0x3e, 0x45, 0x16, 0x45, 0x02, 0x7f, 0x00, 0x28, 0x00, 0x16, 0x00, + 0x52, 0x00, 0x18, 0x00, 0x72, 0x00, 0x08, 0x00, 0x7a, 0x04, 0x2e, + 0x18, 0x0d, 0x0f, 0x00, 0x7e, 0x00, 0x04, 0x00, 0x82, 0x04, 0x08, + 0x08, 0x08, 0x08, 0x00, 0x8a, 0x09, 0x00, 0x00, 0x01, 0x00, 0x03, + 0x01, 0x01, 0x00, 0x02, 0x00, 0x93, 0x00, 0x04, 0xff, 0x00, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypressbln/touchkey_fw_T0.h b/drivers/input/keyboard/cypressbln/touchkey_fw_T0.h new file mode 100644 index 0000000..671d265 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/touchkey_fw_T0.h @@ -0,0 +1,770 @@ +unsigned char firmware_data[] = { + 0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x00, 0x68, + 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x04, 0xae, 0x7e, 0x7e, 0x30, + 0x30, 0x30, 0x7d, 0x05, 0xfb, 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, + 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x40, 0x71, 0x10, 0x62, 0xe3, + 0x06, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, + 0x38, 0x5d, 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, + 0xfa, 0x01, 0x40, 0x4f, 0x5b, 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, + 0x50, 0x06, 0x00, 0x40, 0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, + 0x70, 0xef, 0x18, 0x60, 0xd5, 0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, + 0x71, 0x10, 0x62, 0xe0, 0x1a, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x71, + 0x10, 0x41, 0xe1, 0xfe, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, + 0x03, 0x50, 0x80, 0x4e, 0x62, 0xd3, 0x03, 0x62, + 0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, 0x00, 0x71, 0xc0, 0x7c, 0x03, + 0x1b, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x57, 0xc2, 0x08, 0x28, 0x53, + 0x51, 0x18, 0x75, 0x09, 0x00, 0x28, 0x4b, 0x51, 0x51, 0x80, 0x04, + 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, 0x08, 0x28, 0x60, 0xd5, 0x74, + 0xa0, 0x4b, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x53, 0x51, 0x18, + 0x75, 0x09, 0x00, 0x08, 0x28, 0xa0, 0x1c, 0x53, + 0x50, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, 0x51, 0x47, 0x51, 0xff, + 0xb0, 0x06, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x18, 0x7a, 0x50, 0xbf, + 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x53, 0x50, + 0x50, 0x00, 0x3f, 0x51, 0x47, 0x51, 0xff, 0xb0, 0x08, 0x5d, 0xd5, + 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x50, 0xbf, 0xef, 0x18, 0x8f, + 0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, 0x10, + 0x62, 0xe0, 0x1a, 0x70, 0xef, 0x62, 0xe2, 0x00, 0x7c, 0x1b, 0x4b, + 0x8f, 0xff, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x01, 0x99, 0x03, 0x33, 0x06, 0x66, + 0x0c, 0xcc, 0x19, 0x99, 0x33, 0x33, 0x66, 0x66, + 0xcc, 0xcc, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0b, 0xff, 0x18, 0x00, + 0x2f, 0xff, 0x5f, 0xff, 0xbf, 0xff, 0x01, 0x66, 0x02, 0xcc, 0x05, + 0x99, 0x0b, 0x32, 0x16, 0x66, 0x2c, 0xcc, 0x59, 0x98, 0xb3, 0x32, + 0x01, 0x4c, 0x02, 0x99, 0x05, 0x33, 0x0a, 0x65, 0x14, 0xcc, 0x29, + 0x98, 0x53, 0x32, 0xa6, 0x65, 0x01, 0x33, 0x02, 0x66, 0x04, 0xcc, + 0x09, 0x99, 0x13, 0x33, 0x26, 0x65, 0x4c, 0xcc, + 0x99, 0x99, 0x1d, 0xea, 0x70, 0xef, 0x62, 0x61, 0x00, 0x62, 0xfd, 0x00, + 0x62, 0xcd, 0x00, 0x62, 0xce, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, + 0x00, 0x62, 0xa0, 0x00, 0x62, 0xa1, 0x80, 0x62, 0xa2, 0xc0, 0x62, + 0xa3, 0x0c, 0x62, 0xa8, 0x00, 0x62, 0xa6, 0x00, 0x62, 0xa7, 0x00, + 0x62, 0x7c, 0x33, 0x62, 0x7a, 0x00, 0x62, 0x7b, 0x00, 0x62, 0x79, + 0x00, 0x62, 0x36, 0x00, 0x62, 0x37, 0x00, 0x62, + 0x38, 0x00, 0x62, 0x39, 0x00, 0x62, 0x3a, 0x00, 0x62, 0x3b, 0x00, 0x62, + 0x3c, 0x00, 0x62, 0x3d, 0x00, 0x62, 0x3e, 0x00, 0x62, 0x3f, 0x00, + 0x62, 0x40, 0x00, 0x62, 0x41, 0x00, 0x62, 0x42, 0x00, 0x62, 0x43, + 0x00, 0x62, 0x44, 0x00, 0x62, 0x45, 0x00, 0x62, 0x46, 0x00, 0x62, + 0x47, 0x00, 0x62, 0x48, 0x00, 0x62, 0x49, 0x00, 0x62, 0x4a, 0x00, + 0x62, 0x4b, 0x00, 0x62, 0x4c, 0x00, 0x62, 0x4d, + 0x00, 0x62, 0x4e, 0x00, 0x62, 0x4f, 0x00, 0x62, 0xca, 0x20, 0x62, 0xd6, + 0x44, 0x62, 0xcf, 0x00, 0x62, 0xcb, 0x00, 0x62, 0xc8, 0x00, 0x62, + 0xcc, 0x00, 0x62, 0xc9, 0x00, 0x62, 0xd7, 0x00, 0x62, 0xa9, 0x00, + 0x62, 0x2b, 0x00, 0x62, 0xb0, 0x00, 0x62, 0xb3, 0x02, 0x62, 0xb6, + 0x00, 0x62, 0xb2, 0x00, 0x62, 0xb5, 0x00, 0x62, 0xb8, 0x00, 0x62, + 0xb1, 0x00, 0x62, 0xb4, 0x00, 0x62, 0xb7, 0x00, + 0x62, 0x33, 0x00, 0x62, 0x34, 0x00, 0x62, 0x35, 0x00, 0x71, 0x10, 0x62, + 0x54, 0x00, 0x62, 0x55, 0x00, 0x62, 0x56, 0x00, 0x62, 0x57, 0x00, + 0x62, 0x58, 0x00, 0x62, 0x59, 0x00, 0x62, 0x5a, 0x00, 0x62, 0x5b, + 0x00, 0x62, 0xdc, 0x00, 0x62, 0xe2, 0x00, 0x62, 0xdd, 0x00, 0x62, + 0xd8, 0x02, 0x62, 0xd9, 0x00, 0x62, 0xda, 0x28, 0x62, 0xdb, 0x00, + 0x62, 0xdf, 0x00, 0x62, 0x29, 0x00, 0x62, 0x30, + 0x00, 0x62, 0xbd, 0x00, 0x70, 0xef, 0x70, 0xef, 0x62, 0x00, 0x08, 0x71, + 0x10, 0x62, 0x00, 0x08, 0x62, 0x01, 0x92, 0x70, 0xef, 0x62, 0x04, + 0x17, 0x71, 0x10, 0x62, 0x04, 0x17, 0x62, 0x05, 0xab, 0x70, 0xef, + 0x62, 0x08, 0x00, 0x71, 0x10, 0x62, 0x08, 0x00, 0x62, 0x09, 0x28, + 0x70, 0xef, 0x62, 0x0c, 0x00, 0x71, 0x10, 0x62, 0x0c, 0x00, 0x62, + 0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, 0x00, 0x71, + 0x10, 0x62, 0x10, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, 0x62, 0x01, 0x00, + 0x62, 0x05, 0x00, 0x62, 0x09, 0x00, 0x62, 0x0d, 0x00, 0x62, 0x11, + 0x00, 0x70, 0xef, 0x7f, 0x55, 0x02, 0x08, 0x55, 0x03, 0x17, 0x55, + 0x04, 0x00, 0x7c, 0x03, 0x28, 0x7f, 0x7c, 0x01, 0xc4, 0x70, 0xef, + 0x7f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x62, 0xd0, + 0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, 0x21, 0xf8, 0x29, 0x00, + 0x70, 0xfe, 0x60, 0xe0, 0x70, 0xef, 0x4b, 0x4b, 0x4b, 0x4b, 0x51, + 0x02, 0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, + 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, + 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, + 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, + 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, + 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, + 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, + 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, + 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, + 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, + 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, + 0x47, 0x00, 0x00, 0x49, 0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, + 0x01, 0x79, 0xbf, 0xfe, 0x18, 0x71, 0x10, 0x60, 0xe0, 0x70, 0xef, + 0x71, 0x01, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x67, 0x21, 0x0f, 0xff, + 0x40, 0x9f, 0x4e, 0x18, 0x21, 0x0f, 0xff, 0x39, 0x9f, 0x47, 0x7f, + 0x08, 0x10, 0x28, 0xa0, 0x0b, 0x9f, 0x3f, 0x20, + 0x18, 0x75, 0xdf, 0xf5, 0x74, 0x8f, 0xf2, 0x38, 0xfe, 0x7f, 0x52, 0x00, + 0xa0, 0x08, 0x10, 0x9f, 0x2d, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x50, 0x0d, 0x9f, 0x20, 0x50, 0x0a, 0x9f, 0x1c, + 0x7f, 0x70, 0xbf, 0x62, 0xd3, 0x03, 0x4f, 0x52, 0xfb, 0xa0, 0x15, + 0x7b, 0xfb, 0x52, 0xfc, 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9f, + 0x05, 0x4f, 0x62, 0xd3, 0x03, 0x77, 0xfd, 0x8f, + 0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x3d, 0xfa, 0x00, 0xb0, 0x06, 0x3d, + 0xfb, 0x00, 0xa0, 0x18, 0x10, 0x52, 0xfc, 0x59, 0xfd, 0x28, 0x9e, + 0xe6, 0x20, 0x07, 0xfd, 0x01, 0x0f, 0xfc, 0x00, 0x17, 0xfb, 0x01, + 0x1f, 0xfa, 0x00, 0x8f, 0xe0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, + 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xef, + 0x80, 0x04, 0x2e, 0x03, 0x10, 0x51, 0x03, 0x60, + 0x04, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, + 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, + 0x06, 0x26, 0x03, 0xfb, 0x80, 0x04, 0x2e, 0x03, 0x04, 0x51, 0x03, + 0x60, 0x04, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0x3f, 0x71, 0xc0, + 0x7f, 0x08, 0x10, 0x70, 0x3f, 0x71, 0x80, 0x5d, 0xd3, 0x08, 0x5d, + 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x51, 0x08, 0x60, + 0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, 0xa0, 0x09, 0x26, 0x05, 0xf0, + 0x2e, 0x05, 0x00, 0x80, 0x08, 0x49, 0xd7, 0x20, 0xa0, 0x03, 0x80, + 0xa6, 0x51, 0x05, 0x21, 0x0e, 0xe0, 0x01, 0x80, 0x11, 0x80, 0x67, + 0x80, 0x79, 0x80, 0x47, 0x80, 0x96, 0x80, 0x94, 0x80, 0x92, 0x80, + 0x90, 0x80, 0x97, 0x5d, 0xd8, 0x21, 0xfe, 0x39, 0x40, 0xa0, 0x06, + 0x62, 0xd7, 0x00, 0x80, 0x8a, 0x49, 0xd8, 0x01, + 0xb0, 0x0f, 0x55, 0x0c, 0x02, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x02, 0x62, + 0xd7, 0x10, 0x80, 0x77, 0x55, 0x0c, 0x01, 0x26, 0x05, 0xf0, 0x2e, + 0x05, 0x06, 0x5f, 0x07, 0x06, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, + 0x00, 0x60, 0xd8, 0x76, 0x07, 0x62, 0xd7, 0x14, 0x80, 0x5b, 0x51, + 0x0a, 0x78, 0x3a, 0x07, 0xc0, 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, + 0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, 0x2e, 0x05, + 0x20, 0x60, 0xd8, 0x62, 0xd7, 0x04, 0x80, 0x3f, 0x5d, 0xd8, 0x3a, 0x0a, + 0xd0, 0x2b, 0xa0, 0x29, 0x53, 0x07, 0x53, 0x06, 0x26, 0x05, 0xf0, + 0x2e, 0x05, 0x04, 0x80, 0x18, 0x51, 0x0b, 0x78, 0x3a, 0x07, 0xc0, + 0x16, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x5d, 0xd8, 0x54, 0x00, 0x2e, + 0x05, 0x10, 0x76, 0x07, 0x80, 0x01, 0x62, 0xd7, 0x10, 0x80, 0x0f, + 0x62, 0xd7, 0x00, 0x80, 0x0a, 0x26, 0x05, 0xf0, + 0x2e, 0x05, 0x00, 0x55, 0x0c, 0x00, 0x18, 0x60, 0xd0, 0x18, 0x60, 0xd3, + 0x20, 0x18, 0x7e, 0x62, 0xd0, 0x00, 0x71, 0x10, 0x41, 0x04, 0xfc, + 0x43, 0x05, 0x03, 0x70, 0xef, 0x26, 0x03, 0xfc, 0x51, 0x03, 0x60, + 0x04, 0x55, 0x0c, 0x00, 0x90, 0x28, 0x90, 0x2d, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x50, 0x00, 0x53, 0x06, 0x71, 0x10, 0x43, 0x04, 0x03, + 0x43, 0x05, 0x03, 0x70, 0xef, 0x2e, 0x03, 0x03, + 0x51, 0x03, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x05, 0x21, 0xb0, + 0x26, 0x05, 0x4f, 0x7f, 0x41, 0xe0, 0x7f, 0x43, 0xe0, 0x80, 0x7f, + 0x43, 0xd6, 0x31, 0x7f, 0x41, 0xe0, 0x7f, 0x41, 0xd6, 0xfe, 0x7f, + 0x62, 0xd0, 0x00, 0x4f, 0x52, 0xfd, 0x53, 0x0a, 0x52, 0xfc, 0x53, + 0x0b, 0x52, 0xfb, 0x53, 0x09, 0x52, 0xfa, 0x53, 0x08, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x08, 0x5d, 0xa4, 0x04, 0x1b, + 0x5d, 0xa5, 0x0c, 0x1a, 0x55, 0x1c, 0x01, 0x18, 0x7e, 0x70, 0xbf, 0x62, + 0xd0, 0x00, 0x70, 0xbf, 0x53, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, + 0x52, 0x8d, 0x62, 0xd3, 0x00, 0x13, 0x63, 0x62, 0xd3, 0x00, 0x54, + 0x67, 0x62, 0xd3, 0x00, 0x52, 0x8c, 0x62, 0xd3, 0x00, 0x1b, 0x62, + 0x62, 0xd3, 0x00, 0x54, 0x66, 0x48, 0x66, 0x80, 0xb0, 0x33, 0x3d, + 0x66, 0x00, 0xb0, 0x7b, 0x51, 0x0d, 0x3b, 0x67, + 0xc0, 0x75, 0x52, 0x67, 0x58, 0x1e, 0x01, 0x00, 0x6d, 0x62, 0xd3, 0x00, + 0x05, 0x40, 0xc0, 0x09, 0x51, 0x0f, 0x3b, 0x40, 0xd0, 0x12, 0xa0, + 0x10, 0x56, 0x40, 0x00, 0x5b, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x07, + 0x63, 0x01, 0x0f, 0x62, 0x00, 0x80, 0x41, 0x3d, 0x66, 0xff, 0xb0, + 0x09, 0x50, 0xff, 0x12, 0x0e, 0x3b, 0x67, 0xc0, 0x20, 0x62, 0xd3, + 0x00, 0x56, 0x67, 0x00, 0x56, 0x66, 0x00, 0x5b, + 0x67, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x47, 0x78, 0xd0, 0x03, 0x50, 0x00, + 0x54, 0x47, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, 0xd3, + 0x00, 0x52, 0x8d, 0x62, 0xd3, 0x00, 0x54, 0x63, 0x62, 0xd3, 0x00, + 0x52, 0x8c, 0x62, 0xd3, 0x00, 0x54, 0x62, 0x51, 0x1e, 0x64, 0x5c, + 0x62, 0xd3, 0x00, 0x56, 0x67, 0x00, 0x56, 0x66, 0x00, 0x5b, 0x67, + 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x12, 0x54, 0x47, + 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, + 0x08, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x42, 0x53, 0x19, 0x55, 0x18, + 0x00, 0x18, 0x08, 0x90, 0x7e, 0x62, 0xd3, 0x00, 0x23, 0x44, 0xb0, + 0x2c, 0x51, 0x10, 0x04, 0x19, 0x0e, 0x18, 0x00, 0x18, 0x64, 0x5c, + 0x62, 0xd3, 0x00, 0x52, 0x67, 0x12, 0x19, 0x52, 0x66, 0x1a, 0x18, + 0xc0, 0x39, 0x5b, 0x67, 0x5c, 0x62, 0xd3, 0x00, + 0x52, 0x45, 0x78, 0x54, 0x45, 0x08, 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x3e, + 0x80, 0x18, 0x51, 0x10, 0x14, 0x19, 0x1e, 0x18, 0x00, 0x18, 0x64, + 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x67, 0x12, 0x19, 0x52, 0x66, 0x1a, + 0x18, 0xc0, 0x0e, 0x5b, 0x67, 0x90, 0x31, 0x62, 0xd3, 0x00, 0x2d, + 0x44, 0x50, 0x01, 0x80, 0x24, 0x5b, 0x67, 0x08, 0x90, 0x23, 0x73, + 0x62, 0xd3, 0x00, 0x25, 0x44, 0x62, 0xd3, 0x00, + 0x20, 0x51, 0x11, 0x54, 0x45, 0x50, 0x00, 0x80, 0x0d, 0x5b, 0x67, 0x90, + 0x0d, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x44, 0x50, 0x00, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x5c, 0x18, 0x21, 0x07, + 0xf0, 0x01, 0x7f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x70, 0xbf, 0x70, 0xbf, 0x62, 0xd3, 0x00, 0x50, 0x02, 0x78, 0x08, + 0x5c, 0x56, 0x42, 0x1e, 0x18, 0x78, 0xdf, 0xf8, + 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x91, 0xb2, 0x70, 0xbf, 0x18, 0x08, + 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x8d, 0x62, 0xd3, 0x00, 0x54, + 0x63, 0x62, 0xd3, 0x00, 0x52, 0x8c, 0x62, 0xd3, 0x00, 0x54, 0x62, + 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, 0xd0, + 0x00, 0x55, 0x14, 0x00, 0x50, 0x02, 0x78, 0x08, 0x9f, 0x0e, 0x39, + 0x01, 0xb0, 0x04, 0x55, 0x14, 0x01, 0x18, 0x78, + 0xdf, 0xf3, 0x51, 0x14, 0x7f, 0x50, 0x02, 0x78, 0x08, 0x9e, 0x3e, 0x18, + 0x78, 0xdf, 0xfa, 0x7f, 0x98, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0xd8, 0xd9, 0xda, 0xdb, 0xdf, 0x00, 0x01, 0x03, 0x07, + 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x62, + 0xd3, 0x00, 0x57, 0x00, 0x56, 0x44, 0x00, 0x79, 0xdf, 0xfb, 0x62, + 0xd3, 0x00, 0x57, 0x01, 0x50, 0x03, 0x54, 0x45, + 0x79, 0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x14, 0x57, 0x01, 0x54, 0x47, + 0x79, 0xdf, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x55, 0x0d, 0x19, 0x55, + 0x0e, 0x05, 0x55, 0x0f, 0x14, 0x55, 0x10, 0x01, 0x55, 0x11, 0x03, + 0x55, 0x12, 0x14, 0x55, 0x22, 0x04, 0x55, 0x1f, 0x14, 0x43, 0x61, + 0x0d, 0x57, 0x00, 0x50, 0x02, 0x90, 0xae, 0x50, 0x04, 0xff, 0x98, + 0x29, 0x00, 0x60, 0xa9, 0x62, 0xa0, 0x08, 0x43, + 0xa2, 0x04, 0x62, 0xa3, 0x70, 0x43, 0x7a, 0x01, 0x43, 0xaa, 0x02, 0x43, + 0xdf, 0x01, 0x50, 0x01, 0x57, 0x09, 0x90, 0x20, 0x90, 0x55, 0x57, + 0x01, 0x50, 0xb3, 0x91, 0x5d, 0x50, 0x01, 0x57, 0x0e, 0x90, 0x12, + 0x90, 0x47, 0x7f, 0x53, 0x22, 0xff, 0x67, 0x29, 0x00, 0x60, 0xa9, + 0x51, 0x21, 0x58, 0x20, 0x90, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, + 0x03, 0x53, 0x21, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x29, 0x80, 0x60, 0xa1, 0x5b, 0x78, 0x21, 0x0f, 0x29, 0x08, 0x74, 0x53, + 0x20, 0x12, 0x22, 0x02, 0x21, 0x5c, 0x50, 0x00, 0x53, 0x1d, 0x53, + 0x23, 0x29, 0x01, 0x79, 0xa0, 0x08, 0x64, 0x6b, 0x1d, 0x6b, 0x23, + 0x8f, 0xf5, 0x60, 0xb5, 0x51, 0x1d, 0x60, 0xb4, 0x7f, 0x50, 0x02, + 0x78, 0x08, 0x90, 0x28, 0x90, 0x5a, 0x18, 0x78, 0xdf, 0xf8, 0x7f, + 0x41, 0xdf, 0xfe, 0x71, 0x10, 0x41, 0xd8, 0xfd, + 0x70, 0xef, 0x41, 0x61, 0xf3, 0x41, 0xa2, 0xfb, 0x41, 0xa0, 0xf7, 0x62, + 0xa3, 0x00, 0x62, 0xa9, 0x00, 0x41, 0xaa, 0xfd, 0x7f, 0x02, 0x08, + 0x02, 0x20, 0x64, 0x5c, 0xff, 0xf8, 0x4b, 0x74, 0xff, 0xf4, 0x7f, + 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, 0x5b, 0x64, 0x64, 0x5c, 0x71, + 0x10, 0x5e, 0x01, 0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, + 0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, + 0x18, 0xfe, 0xd6, 0x5c, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, + 0x7f, 0x62, 0xd0, 0x00, 0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, + 0xfe, 0xc0, 0x5c, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, 0x70, 0xef, + 0x18, 0x64, 0x64, 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x22, 0x1d, 0x61, + 0x01, 0x36, 0x1d, 0xff, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, + 0xef, 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, + 0x1e, 0x50, 0x00, 0x53, 0x1a, 0x53, 0x1b, 0x51, 0x1e, 0x5c, 0x62, 0xd3, + 0x00, 0x52, 0x24, 0x53, 0x1f, 0x43, 0xa0, 0x01, 0x51, 0x1f, 0x60, + 0xfd, 0x41, 0xa3, 0xdf, 0x51, 0x1e, 0x9f, 0x7a, 0x9f, 0x81, 0x58, + 0x23, 0x55, 0x1c, 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x43, + 0xb3, 0x01, 0x51, 0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, + 0x9f, 0x5f, 0x9f, 0x91, 0x43, 0xa3, 0x20, 0x41, + 0xa0, 0xfe, 0x62, 0xfd, 0x00, 0x50, 0xff, 0x4c, 0x1b, 0x14, 0x1b, 0x51, + 0x20, 0x11, 0x08, 0xfe, 0x4d, 0x4c, 0x1a, 0x1c, 0x1a, 0xd0, 0x07, + 0x55, 0x1a, 0x00, 0x55, 0x1b, 0x00, 0x51, 0x1e, 0x64, 0x5c, 0x62, + 0xd3, 0x00, 0x51, 0x1b, 0x54, 0x8d, 0x51, 0x1a, 0x54, 0x8c, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x9f, 0x86, 0x18, 0x78, 0xdf, 0xfa, + 0x7f, 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x27, + 0x5a, 0x26, 0x55, 0x1e, 0x01, 0x62, 0xd3, 0x00, 0x58, 0x1e, 0x56, 0x24, + 0x80, 0x55, 0x29, 0x08, 0x55, 0x28, 0x80, 0x51, 0x1e, 0x9f, 0x63, + 0x51, 0x1e, 0x9f, 0x5f, 0x70, 0xbf, 0x58, 0x1e, 0x62, 0xd3, 0x00, + 0x51, 0x1b, 0x3a, 0x27, 0x51, 0x1a, 0x1a, 0x26, 0xd0, 0x06, 0x51, + 0x28, 0x73, 0x25, 0x24, 0x68, 0x28, 0x26, 0x28, 0x7f, 0x51, 0x28, + 0x2d, 0x24, 0x7a, 0x29, 0xbf, 0xd6, 0x7a, 0x1e, + 0xdf, 0xc4, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0xa5, + 0x11, 0xdc, 0x51, 0xa4, 0x19, 0x05, 0xd0, 0x12, 0x7c, 0x16, 0xe7, + 0x39, 0x0f, 0xa0, 0x16, 0x62, 0xd0, 0x00, 0x76, 0xa5, 0x0e, 0xa4, + 0x00, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x55, 0xa5, 0x00, 0x55, 0xa4, + 0x00, 0x90, 0xbe, 0x7f, 0x62, 0xd0, 0x00, 0x3c, 0xaf, 0xf0, 0xd0, + 0x03, 0x76, 0xaf, 0x62, 0xd0, 0x00, 0x51, 0x2f, + 0x21, 0x7f, 0x53, 0x51, 0x51, 0xaf, 0x3a, 0x51, 0xb0, 0x55, 0x7c, 0x16, + 0xe7, 0x62, 0xd0, 0x00, 0x53, 0xb0, 0x3c, 0xb0, 0x0f, 0xa0, 0x3d, + 0x3c, 0xab, 0x00, 0xb0, 0x1c, 0x55, 0x94, 0x00, 0x55, 0x95, 0x00, + 0x51, 0xb0, 0x53, 0x50, 0x55, 0x51, 0x00, 0x06, 0x50, 0x94, 0x0e, + 0x51, 0x00, 0x51, 0x51, 0x60, 0xd5, 0x50, 0x08, 0x3f, 0x50, 0x62, + 0xd0, 0x00, 0x55, 0xa7, 0x00, 0x3c, 0xae, 0x00, + 0xb0, 0x0a, 0x7c, 0x17, 0x7c, 0x62, 0xd0, 0x00, 0x55, 0xae, 0x01, 0x62, + 0xd0, 0x00, 0x55, 0xa6, 0x03, 0x80, 0x0c, 0x62, 0xd0, 0x00, 0x3c, + 0xa9, 0x00, 0xb0, 0x04, 0x55, 0xa9, 0x01, 0x7f, 0x62, 0xd0, 0x00, + 0x55, 0xa5, 0x00, 0x55, 0xa4, 0x00, 0x3c, 0xae, 0x01, 0xb0, 0x33, + 0x7a, 0xa6, 0x3c, 0xa6, 0x00, 0xb0, 0x3a, 0x3c, 0xae, 0x01, 0xb0, + 0x0a, 0x7c, 0x18, 0x0f, 0x62, 0xd0, 0x00, 0x55, + 0xae, 0x00, 0x62, 0xd0, 0x00, 0x3c, 0xab, 0x00, 0xb0, 0x0e, 0x51, 0xb0, + 0x53, 0x50, 0x55, 0x51, 0x00, 0x06, 0x50, 0x94, 0x7c, 0x1d, 0xb9, + 0x62, 0xd0, 0x00, 0x55, 0xaf, 0x00, 0x80, 0x0f, 0x62, 0xd0, 0x00, + 0x3c, 0xa9, 0x01, 0xb0, 0x07, 0x55, 0xa9, 0x00, 0x55, 0xaf, 0x00, + 0x7f, 0x10, 0x4f, 0x38, 0x16, 0x62, 0xd0, 0x00, 0x3c, 0xaa, 0x00, + 0xb0, 0x05, 0x51, 0x9c, 0x53, 0x24, 0x56, 0x0d, + 0x00, 0x80, 0xff, 0x56, 0x00, 0x00, 0x80, 0xf3, 0x62, 0xd0, 0x00, 0x3c, + 0xaa, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x50, 0x55, 0x51, 0x00, + 0x06, 0x50, 0x9c, 0x7c, 0x1d, 0x06, 0x52, 0x00, 0x53, 0x4e, 0x55, + 0x4f, 0x00, 0x06, 0x4e, 0x24, 0x7c, 0x1d, 0xa1, 0x10, 0x52, 0x00, + 0x7c, 0x09, 0x3a, 0x20, 0x10, 0x7c, 0x05, 0xc5, 0x62, 0xd0, 0x00, + 0x20, 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, 0x00, + 0xb0, 0x12, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x55, 0x4c, 0x01, 0x7c, + 0x1c, 0x2a, 0x7c, 0x1c, 0x88, 0x80, 0x80, 0x3d, 0x00, 0x01, 0xb0, + 0x2a, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x65, + 0x4e, 0x6b, 0x4f, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x4f, + 0x08, 0x51, 0x4e, 0x08, 0x7c, 0x1b, 0xe6, 0x18, 0x53, 0x4e, 0x18, + 0x53, 0x4f, 0x38, 0xfe, 0x7c, 0x1c, 0x88, 0x80, + 0x52, 0x3d, 0x00, 0x02, 0xb0, 0x21, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, + 0x7c, 0x1c, 0x95, 0x55, 0x4c, 0x03, 0x7c, 0x1c, 0x2a, 0x70, 0xfb, + 0x6e, 0x4f, 0x6e, 0x4e, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, 0x7c, + 0x1c, 0x88, 0x80, 0x2d, 0x3d, 0x00, 0x03, 0xb0, 0x28, 0x62, 0xd0, + 0x00, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x65, 0x4e, 0x6b, 0x4f, + 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x4f, + 0x08, 0x51, 0x4e, 0x08, 0x7c, 0x1b, 0xe6, 0x18, 0x53, 0x4e, 0x18, 0x53, + 0x4f, 0x38, 0xfe, 0x7c, 0x1c, 0x88, 0x7c, 0x1c, 0x6c, 0x7c, 0x1c, + 0xc1, 0x52, 0x0d, 0x7c, 0x1d, 0xad, 0x02, 0x50, 0x53, 0x50, 0x51, + 0x4f, 0x0a, 0x51, 0x53, 0x51, 0x7c, 0x1d, 0x6f, 0x06, 0x4e, 0x8c, + 0x0e, 0x4f, 0x00, 0x51, 0x4f, 0x7c, 0x1c, 0xab, 0x7c, 0x1c, 0x88, + 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x0a, 0x77, + 0x0d, 0x3d, 0x0d, 0x03, 0xce, 0xfe, 0x56, 0x00, 0x00, 0x81, 0x06, 0x7c, + 0x1c, 0x6c, 0x7c, 0x1c, 0xc1, 0x51, 0x51, 0x60, 0xd4, 0x3e, 0x50, + 0x54, 0x0e, 0x3e, 0x50, 0x54, 0x0f, 0x52, 0x00, 0x53, 0x50, 0x55, + 0x51, 0x00, 0x55, 0x4e, 0x06, 0x55, 0x4f, 0x00, 0x55, 0x4b, 0x00, + 0x55, 0x4a, 0x00, 0x3c, 0x4f, 0x00, 0xb0, 0x06, 0x3c, 0x4e, 0x00, + 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, + 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x50, 0x04, 0x4b, 0x51, 0x51, 0x0c, + 0x4a, 0x65, 0x50, 0x6b, 0x51, 0x8f, 0xde, 0x5f, 0x50, 0x4b, 0x5f, + 0x51, 0x4a, 0x62, 0xd0, 0x00, 0x5a, 0x4e, 0x06, 0x4e, 0x03, 0x51, + 0x4e, 0x04, 0x50, 0x0e, 0x51, 0x03, 0x51, 0x51, 0x60, 0xd4, 0x3e, + 0x50, 0x54, 0x10, 0x3e, 0x50, 0x54, 0x11, 0x52, 0x00, 0x53, 0x50, + 0x55, 0x51, 0x00, 0x55, 0x4e, 0x06, 0x55, 0x4f, + 0x00, 0x55, 0x4b, 0x00, 0x55, 0x4a, 0x00, 0x3c, 0x4f, 0x00, 0xb0, 0x06, + 0x3c, 0x4e, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, + 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x50, 0x04, 0x4b, 0x51, 0x51, + 0x0c, 0x4a, 0x65, 0x50, 0x6b, 0x51, 0x8f, 0xde, 0x5f, 0x50, 0x4b, + 0x5f, 0x51, 0x4a, 0x62, 0xd0, 0x00, 0x5a, 0x4e, 0x06, 0x4e, 0x05, + 0x51, 0x4e, 0x04, 0x50, 0x0e, 0x51, 0x03, 0x51, + 0x51, 0x60, 0xd4, 0x3e, 0x50, 0x54, 0x12, 0x3e, 0x50, 0x54, 0x13, 0x50, + 0x03, 0x08, 0x5a, 0x50, 0x06, 0x50, 0x0e, 0x08, 0x51, 0x50, 0x08, + 0x7c, 0x1a, 0x9f, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x50, 0x54, + 0x15, 0x51, 0x51, 0x54, 0x14, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, + 0x8c, 0x7c, 0x1d, 0x1d, 0x06, 0x50, 0x62, 0x7c, 0x1d, 0x5f, 0x7c, + 0x1c, 0x60, 0x51, 0x50, 0x01, 0x6a, 0x7c, 0x1d, + 0x1d, 0x51, 0x50, 0x01, 0x72, 0x7c, 0x1d, 0x1d, 0x06, 0x50, 0x7a, 0x7c, + 0x1d, 0x5f, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf7, 0x38, 0xea, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x16, 0x10, 0x57, 0x09, 0x50, 0x01, + 0x7c, 0x08, 0x74, 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x10, 0x08, + 0x57, 0x92, 0x28, 0x53, 0x51, 0x18, 0x75, 0x09, 0x00, 0x28, 0x53, + 0x50, 0x20, 0x10, 0x51, 0x51, 0x08, 0x51, 0x50, + 0x20, 0x7c, 0x09, 0xb9, 0x20, 0x10, 0x57, 0x0e, 0x50, 0x01, 0x7c, 0x08, + 0x74, 0x20, 0x62, 0xd0, 0x00, 0x3c, 0xaa, 0x01, 0xb0, 0x0b, 0x51, + 0x24, 0x53, 0x30, 0x51, 0x25, 0x53, 0x31, 0x80, 0x0c, 0x62, 0xd0, + 0x00, 0x51, 0x9c, 0x53, 0x24, 0x51, 0x9d, 0x53, 0x25, 0x10, 0x50, + 0x00, 0x7c, 0x09, 0x3a, 0x20, 0x56, 0x0d, 0x00, 0x80, 0xff, 0x56, + 0x00, 0x00, 0x80, 0xf3, 0x62, 0xd0, 0x00, 0x3c, + 0xaa, 0x00, 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x50, 0x55, 0x51, 0x00, 0x06, + 0x50, 0x9c, 0x7c, 0x1d, 0x06, 0x52, 0x00, 0x53, 0x4e, 0x55, 0x4f, + 0x00, 0x06, 0x4e, 0x24, 0x7c, 0x1d, 0xa1, 0x10, 0x52, 0x00, 0x7c, + 0x09, 0x3a, 0x20, 0x10, 0x7c, 0x05, 0xc5, 0x62, 0xd0, 0x00, 0x20, + 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, 0x00, 0xb0, 0x12, 0x7c, 0x1c, + 0x60, 0x7c, 0x1c, 0x95, 0x55, 0x4c, 0x01, 0x7c, + 0x1c, 0x2a, 0x7c, 0x1c, 0x88, 0x80, 0x80, 0x3d, 0x00, 0x01, 0xb0, 0x2a, + 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x65, 0x4e, + 0x6b, 0x4f, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x4f, 0x08, + 0x51, 0x4e, 0x08, 0x7c, 0x1b, 0xe6, 0x18, 0x53, 0x4e, 0x18, 0x53, + 0x4f, 0x38, 0xfe, 0x7c, 0x1c, 0x88, 0x80, 0x52, 0x3d, 0x00, 0x02, + 0xb0, 0x21, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, + 0x7c, 0x1c, 0x95, 0x55, 0x4c, 0x03, 0x7c, 0x1c, 0x2a, 0x70, 0xfb, 0x6e, + 0x4f, 0x6e, 0x4e, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, 0x7c, 0x1c, + 0x88, 0x80, 0x2d, 0x3d, 0x00, 0x03, 0xb0, 0x28, 0x62, 0xd0, 0x00, + 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x65, 0x4e, 0x6b, 0x4f, 0x50, + 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x4f, 0x08, 0x51, 0x4e, 0x08, + 0x7c, 0x1b, 0xe6, 0x18, 0x53, 0x4e, 0x18, 0x53, + 0x4f, 0x38, 0xfe, 0x7c, 0x1c, 0x88, 0x7c, 0x1c, 0x6c, 0x7c, 0x1c, 0xc1, + 0x52, 0x0d, 0x7c, 0x1d, 0xad, 0x02, 0x50, 0x53, 0x50, 0x51, 0x4f, + 0x0a, 0x51, 0x53, 0x51, 0x7c, 0x1d, 0x6f, 0x06, 0x4e, 0x8c, 0x0e, + 0x4f, 0x00, 0x51, 0x4f, 0x7c, 0x1c, 0xab, 0x7c, 0x1c, 0x88, 0x77, + 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x0a, 0x77, 0x0d, 0x3d, 0x0d, 0x03, + 0xce, 0xfe, 0x56, 0x00, 0x00, 0x81, 0x06, 0x7c, + 0x1c, 0x6c, 0x7c, 0x1c, 0xc1, 0x51, 0x51, 0x60, 0xd4, 0x3e, 0x50, 0x54, + 0x0e, 0x3e, 0x50, 0x54, 0x0f, 0x52, 0x00, 0x53, 0x50, 0x55, 0x51, + 0x00, 0x55, 0x4e, 0x06, 0x55, 0x4f, 0x00, 0x55, 0x4b, 0x00, 0x55, + 0x4a, 0x00, 0x3c, 0x4f, 0x00, 0xb0, 0x06, 0x3c, 0x4e, 0x00, 0xa0, + 0x1a, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, 0xd0, 0x0c, 0x62, 0xd0, + 0x00, 0x51, 0x50, 0x04, 0x4b, 0x51, 0x51, 0x0c, + 0x4a, 0x65, 0x50, 0x6b, 0x51, 0x8f, 0xde, 0x5f, 0x50, 0x4b, 0x5f, 0x51, + 0x4a, 0x62, 0xd0, 0x00, 0x5a, 0x4e, 0x06, 0x4e, 0x03, 0x51, 0x4e, + 0x04, 0x50, 0x0e, 0x51, 0x03, 0x51, 0x51, 0x60, 0xd4, 0x3e, 0x50, + 0x54, 0x10, 0x3e, 0x50, 0x54, 0x11, 0x52, 0x00, 0x53, 0x50, 0x55, + 0x51, 0x00, 0x55, 0x4e, 0x06, 0x55, 0x4f, 0x00, 0x55, 0x4b, 0x00, + 0x55, 0x4a, 0x00, 0x3c, 0x4f, 0x00, 0xb0, 0x06, + 0x3c, 0x4e, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, 0xd0, + 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x50, 0x04, 0x4b, 0x51, 0x51, 0x0c, + 0x4a, 0x65, 0x50, 0x6b, 0x51, 0x8f, 0xde, 0x5f, 0x50, 0x4b, 0x5f, + 0x51, 0x4a, 0x62, 0xd0, 0x00, 0x5a, 0x4e, 0x06, 0x4e, 0x05, 0x51, + 0x4e, 0x04, 0x50, 0x0e, 0x51, 0x03, 0x51, 0x51, 0x60, 0xd4, 0x3e, + 0x50, 0x54, 0x12, 0x3e, 0x50, 0x54, 0x13, 0x50, + 0x03, 0x08, 0x5a, 0x50, 0x06, 0x50, 0x0e, 0x08, 0x51, 0x50, 0x08, 0x7c, + 0x1a, 0x9f, 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x50, 0x54, 0x15, + 0x51, 0x51, 0x54, 0x14, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x8c, + 0x7c, 0x1d, 0x1d, 0x06, 0x50, 0x62, 0x7c, 0x1d, 0x5f, 0x7c, 0x1c, + 0x60, 0x51, 0x50, 0x01, 0x6a, 0x7c, 0x1d, 0x1d, 0x51, 0x50, 0x01, + 0x72, 0x7c, 0x1d, 0x1d, 0x06, 0x50, 0x7a, 0x7c, + 0x1d, 0x5f, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xf7, 0x56, 0x00, 0x00, + 0x80, 0x19, 0x7c, 0x1c, 0x6c, 0x06, 0x50, 0x24, 0x7c, 0x1d, 0x06, + 0x52, 0x00, 0x53, 0x4e, 0x55, 0x4f, 0x00, 0x06, 0x4e, 0x30, 0x7c, + 0x1d, 0xa1, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xe4, 0x38, 0xea, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x62, 0xd0, 0x00, 0x52, 0xfc, + 0x01, 0x02, 0x53, 0x50, 0x52, 0xfb, 0x09, 0x00, + 0x7c, 0x1d, 0x12, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x4e, 0x52, 0xfb, 0x7c, + 0x1c, 0xb6, 0x12, 0x50, 0x51, 0x4f, 0x1a, 0x51, 0xc0, 0x6f, 0x52, + 0xfc, 0x53, 0x50, 0x52, 0xfb, 0x7c, 0x1d, 0x12, 0x52, 0xfc, 0x01, + 0x02, 0x53, 0x4e, 0x52, 0xfb, 0x7c, 0x1c, 0xb6, 0x12, 0x50, 0x51, + 0x4f, 0x1a, 0x51, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, 0x1d, + 0x3b, 0x54, 0x00, 0x3e, 0x50, 0x54, 0x01, 0x80, + 0xb3, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x50, 0x52, 0xfb, + 0x09, 0x00, 0x7c, 0x1d, 0x12, 0x52, 0xfc, 0x53, 0x4e, 0x52, 0xfb, + 0x60, 0xd4, 0x3e, 0x4e, 0x53, 0x4f, 0x3e, 0x4e, 0x12, 0x50, 0x51, + 0x4f, 0x1a, 0x51, 0xc0, 0x10, 0x52, 0xfc, 0x01, 0x04, 0x7c, 0x1d, + 0x3b, 0x54, 0x00, 0x3e, 0x50, 0x54, 0x01, 0x80, 0x7e, 0x62, 0xd0, + 0x00, 0x52, 0xfc, 0x53, 0x50, 0x52, 0xfb, 0x7c, + 0x1d, 0x54, 0x80, 0x70, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x50, 0x52, + 0xfb, 0x7c, 0x1d, 0x12, 0x52, 0xfc, 0x01, 0x04, 0x53, 0x4e, 0x52, + 0xfb, 0x7c, 0x1c, 0xb6, 0x12, 0x50, 0x51, 0x4f, 0x1a, 0x51, 0xc0, + 0x10, 0x52, 0xfc, 0x01, 0x04, 0x7c, 0x1d, 0x3b, 0x54, 0x00, 0x3e, + 0x50, 0x54, 0x01, 0x80, 0x42, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x01, + 0x02, 0x53, 0x50, 0x52, 0xfb, 0x09, 0x00, 0x7c, + 0x1d, 0x12, 0x52, 0xfc, 0x53, 0x4e, 0x52, 0xfb, 0x60, 0xd4, 0x3e, 0x4e, + 0x53, 0x4f, 0x3e, 0x4e, 0x12, 0x50, 0x51, 0x4f, 0x1a, 0x51, 0xc0, + 0x10, 0x52, 0xfc, 0x01, 0x02, 0x7c, 0x1d, 0x3b, 0x54, 0x00, 0x3e, + 0x50, 0x54, 0x01, 0x80, 0x0d, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, + 0x50, 0x52, 0xfb, 0x7c, 0x1d, 0x54, 0x62, 0xd0, 0x00, 0x52, 0x01, + 0x53, 0x50, 0x52, 0x00, 0x53, 0x51, 0x38, 0xfe, + 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x05, 0x62, 0xd0, 0x00, 0x55, 0xb2, 0x00, + 0x56, 0x00, 0x00, 0x80, 0xcd, 0x62, 0xd0, 0x00, 0x3c, 0xaa, 0x00, + 0xb0, 0x1b, 0x52, 0x00, 0x53, 0x50, 0x55, 0x51, 0x00, 0x06, 0x50, + 0x9c, 0x7c, 0x1d, 0x06, 0x52, 0x00, 0x53, 0x4e, 0x55, 0x4f, 0x00, + 0x06, 0x4e, 0x24, 0x7c, 0x1d, 0xa1, 0x10, 0x52, 0x00, 0x7c, 0x09, + 0x3a, 0x20, 0x10, 0x7c, 0x05, 0xc5, 0x62, 0xd0, + 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, 0x3d, 0x00, 0x00, 0xb0, 0x12, 0x7c, + 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x55, 0x4c, 0x01, 0x7c, 0x1c, 0x2a, + 0x7c, 0x1c, 0x88, 0x80, 0x80, 0x3d, 0x00, 0x01, 0xb0, 0x2a, 0x62, + 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x65, 0x4e, 0x6b, + 0x4f, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x4f, 0x08, 0x51, + 0x4e, 0x08, 0x7c, 0x1b, 0xe6, 0x18, 0x53, 0x4e, + 0x18, 0x53, 0x4f, 0x38, 0xfe, 0x7c, 0x1c, 0x88, 0x80, 0x52, 0x3d, 0x00, + 0x02, 0xb0, 0x21, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, + 0x95, 0x55, 0x4c, 0x03, 0x7c, 0x1c, 0x2a, 0x70, 0xfb, 0x6e, 0x4f, + 0x6e, 0x4e, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, 0x7c, 0x1c, 0x88, + 0x80, 0x2d, 0x3d, 0x00, 0x03, 0xb0, 0x28, 0x62, 0xd0, 0x00, 0x7c, + 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x65, 0x4e, 0x6b, + 0x4f, 0x50, 0x00, 0x08, 0x50, 0x05, 0x08, 0x51, 0x4f, 0x08, 0x51, 0x4e, + 0x08, 0x7c, 0x1b, 0xe6, 0x18, 0x53, 0x4e, 0x18, 0x53, 0x4f, 0x38, + 0xfe, 0x7c, 0x1c, 0x88, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0x30, + 0x56, 0x00, 0x00, 0x82, 0x86, 0x62, 0xd0, 0x00, 0x3c, 0xb1, 0x02, + 0xa0, 0x9f, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x62, 0x7c, 0x1c, + 0x77, 0x06, 0x50, 0x8c, 0x7c, 0x1d, 0x06, 0x7c, + 0x1d, 0x2e, 0xd0, 0x16, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x62, 0x7c, + 0x1c, 0x77, 0x06, 0x50, 0x8c, 0x7c, 0x1d, 0x06, 0x7c, 0x1d, 0xd2, + 0x80, 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, + 0x8c, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x62, 0x7c, 0x1d, 0x06, 0x7c, + 0x1d, 0xd2, 0x50, 0x90, 0x13, 0x02, 0x50, 0x01, 0x1b, 0x01, 0xc0, + 0x4e, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x51, + 0x50, 0x01, 0x7a, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x8c, 0x7c, 0x1d, 0x06, + 0x7c, 0x1d, 0x2e, 0xd0, 0x16, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, + 0x7a, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x8c, 0x7c, 0x1d, 0x06, 0x7c, + 0x1d, 0xc5, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x51, + 0x50, 0x01, 0x8c, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x7a, 0x7c, 0x1d, + 0x06, 0x7c, 0x1d, 0xc5, 0x50, 0x90, 0x13, 0x04, + 0x50, 0x01, 0x1b, 0x03, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x76, 0xb2, 0x81, + 0xde, 0x62, 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x8c, + 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x7a, 0x7c, 0x1d, 0x06, 0x7c, 0x1d, + 0x2e, 0xd0, 0x5a, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x06, 0x4e, + 0x01, 0x0e, 0x4f, 0x00, 0x7c, 0x1c, 0x88, 0x7c, 0x1c, 0x60, 0x51, + 0x50, 0x01, 0x8c, 0x7c, 0x1c, 0x77, 0x06, 0x50, + 0x7a, 0x7c, 0x1d, 0x06, 0x7c, 0x1d, 0x2e, 0xd0, 0xb4, 0x7c, 0x1c, 0x60, + 0x7c, 0x1c, 0x95, 0x06, 0x4e, 0x01, 0x0e, 0x4f, 0x00, 0x7c, 0x1c, + 0x88, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x8c, 0x7c, 0x1c, 0x77, + 0x06, 0x50, 0x7a, 0x7c, 0x1d, 0x06, 0x7c, 0x1d, 0x2e, 0xd0, 0x90, + 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x06, 0x4e, 0x01, 0x0e, 0x4f, + 0x00, 0x7c, 0x1c, 0x88, 0x80, 0x7f, 0x62, 0xd0, + 0x00, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x8c, 0x7c, 0x1c, 0x77, 0x06, + 0x50, 0x7a, 0x7c, 0x1d, 0x06, 0x3e, 0x50, 0x12, 0x4e, 0x51, 0x51, + 0x1a, 0x4f, 0xd0, 0x62, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x16, + 0x4e, 0x01, 0x1e, 0x4f, 0x00, 0x7c, 0x1c, 0x88, 0x7c, 0x1c, 0x60, + 0x51, 0x50, 0x01, 0x8c, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x7a, 0x7c, + 0x1d, 0x06, 0x3e, 0x50, 0x12, 0x4e, 0x51, 0x51, + 0x1a, 0x4f, 0xd0, 0x39, 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x16, 0x4e, + 0x01, 0x1e, 0x4f, 0x00, 0x7c, 0x1c, 0x88, 0x7c, 0x1c, 0x60, 0x51, + 0x50, 0x01, 0x8c, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x7a, 0x7c, 0x1d, + 0x06, 0x3e, 0x50, 0x12, 0x4e, 0x51, 0x51, 0x1a, 0x4f, 0xd0, 0x10, + 0x7c, 0x1c, 0x60, 0x7c, 0x1c, 0x95, 0x16, 0x4e, 0x01, 0x1e, 0x4f, + 0x00, 0x7c, 0x1c, 0x88, 0x62, 0xd0, 0x00, 0x7c, + 0x1c, 0x60, 0x51, 0x50, 0x01, 0x72, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x6a, + 0x0e, 0x51, 0x00, 0x7c, 0x1c, 0x88, 0x7c, 0x1c, 0x60, 0x51, 0x50, + 0x01, 0x7a, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x72, 0x0e, 0x51, 0x00, + 0x7c, 0x1c, 0x88, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x8c, 0x7c, + 0x1c, 0x77, 0x06, 0x50, 0x7a, 0x0e, 0x51, 0x00, 0x7c, 0x1c, 0x88, + 0x10, 0x52, 0x00, 0x7c, 0x06, 0x09, 0x20, 0x62, + 0xd0, 0x00, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x8c, 0x7c, 0x1c, 0x77, + 0x06, 0x50, 0x62, 0x7c, 0x1d, 0x06, 0x7c, 0x1d, 0x2e, 0xd0, 0x25, + 0x52, 0x00, 0x53, 0x50, 0x55, 0x51, 0x00, 0x06, 0x50, 0x98, 0x0e, + 0x51, 0x00, 0x51, 0x51, 0x60, 0xd4, 0x3e, 0x50, 0x7a, 0x50, 0x53, + 0x4f, 0x06, 0x4f, 0x01, 0x51, 0x51, 0x60, 0xd5, 0x51, 0x4f, 0x3f, + 0x50, 0x80, 0x0a, 0x7c, 0x1c, 0x6c, 0x06, 0x50, + 0x98, 0x7c, 0x1d, 0xb9, 0x7c, 0x1c, 0x6c, 0x06, 0x50, 0x98, 0x7c, 0x1d, + 0x06, 0x50, 0x05, 0x3a, 0x51, 0xd0, 0x58, 0x7c, 0x1c, 0x60, 0x51, + 0x50, 0x01, 0x62, 0x53, 0x4e, 0x51, 0x51, 0x09, 0x00, 0x53, 0x4f, + 0x06, 0x50, 0x8c, 0x7c, 0x1d, 0x06, 0x3e, 0x50, 0x53, 0x50, 0x51, + 0x4f, 0x60, 0xd4, 0x3e, 0x4e, 0x53, 0x4d, 0x3e, 0x4e, 0x16, 0x4e, + 0x02, 0x02, 0x50, 0x53, 0x50, 0x51, 0x4d, 0x0a, + 0x51, 0x53, 0x51, 0x70, 0xfb, 0x6e, 0x51, 0x6e, 0x50, 0x51, 0x4f, 0x60, + 0xd5, 0x51, 0x51, 0x3f, 0x4e, 0x51, 0x50, 0x3f, 0x4e, 0x52, 0x00, + 0x53, 0x50, 0x55, 0x51, 0x00, 0x06, 0x50, 0x98, 0x0e, 0x51, 0x00, + 0x51, 0x51, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x50, 0x77, 0x00, 0x3d, + 0x00, 0x02, 0xcd, 0x77, 0x62, 0xd0, 0x00, 0x3c, 0xb1, 0x02, 0xb2, + 0x20, 0x56, 0x00, 0x00, 0x82, 0x16, 0x62, 0xd0, + 0x00, 0x7c, 0x1c, 0x60, 0x51, 0x50, 0x01, 0x8c, 0x7c, 0x1c, 0x77, 0x06, + 0x50, 0x38, 0x0e, 0x51, 0x00, 0x7c, 0x1c, 0x88, 0x7c, 0x1c, 0x60, + 0x51, 0x50, 0x01, 0x62, 0x7c, 0x1c, 0x77, 0x06, 0x50, 0x3c, 0x0e, + 0x51, 0x00, 0x7c, 0x1c, 0x88, 0x97, 0xf7, 0x40, 0x51, 0x50, 0x01, + 0x62, 0x7c, 0x1c, 0x77, 0x51, 0x50, 0x01, 0x8c, 0x53, 0x4c, 0x51, + 0x51, 0x7c, 0x1d, 0x7b, 0x51, 0x4e, 0x12, 0x4c, + 0x51, 0x4f, 0x1a, 0x4d, 0xd0, 0x21, 0x7c, 0x1d, 0x6f, 0x51, 0x4e, 0x01, + 0x62, 0x53, 0x4c, 0x51, 0x4f, 0x7c, 0x1d, 0x7b, 0x06, 0x4e, 0x8c, + 0x7c, 0x1d, 0x46, 0x12, 0x4c, 0x54, 0x02, 0x51, 0x4f, 0x1a, 0x4d, + 0x54, 0x01, 0x80, 0x07, 0x56, 0x02, 0x00, 0x56, 0x01, 0x00, 0x62, + 0xd0, 0x00, 0x06, 0x50, 0x34, 0x0e, 0x51, 0x00, 0x51, 0x51, 0x60, + 0xd5, 0x52, 0x01, 0x3f, 0x50, 0x52, 0x02, 0x3f, + 0x50, 0x3d, 0x00, 0x00, 0xb0, 0x35, 0x97, 0x98, 0x40, 0x51, 0x50, 0x01, + 0x8c, 0x97, 0xa8, 0x40, 0x55, 0x4c, 0x01, 0x97, 0x55, 0x40, 0x06, + 0x50, 0x38, 0x0e, 0x51, 0x00, 0x97, 0xaa, 0x40, 0x97, 0x7f, 0x40, + 0x51, 0x50, 0x01, 0x62, 0x97, 0x8f, 0x40, 0x55, 0x4c, 0x01, 0x97, + 0x3c, 0x40, 0x06, 0x50, 0x3c, 0x0e, 0x51, 0x00, 0x97, 0x91, 0x40, + 0x80, 0xfb, 0x3d, 0x00, 0x01, 0xb0, 0x44, 0x62, + 0xd0, 0x00, 0x97, 0x5c, 0x40, 0x51, 0x50, 0x01, 0x8c, 0x97, 0x6c, 0x40, + 0x55, 0x4c, 0x05, 0x97, 0x19, 0x40, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, + 0x4e, 0x06, 0x50, 0x38, 0x0e, 0x51, 0x00, 0x97, 0x68, 0x40, 0x97, + 0x3d, 0x40, 0x51, 0x50, 0x01, 0x62, 0x97, 0x4d, 0x40, 0x55, 0x4c, + 0x05, 0x96, 0xfa, 0x40, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, 0x06, + 0x50, 0x3c, 0x0e, 0x51, 0x00, 0x97, 0x49, 0x40, + 0x80, 0xb3, 0x3d, 0x00, 0x02, 0xb0, 0x68, 0x62, 0xd0, 0x00, 0x97, 0x14, + 0x40, 0x51, 0x50, 0x01, 0x8c, 0x97, 0x24, 0x40, 0x55, 0x4c, 0x03, + 0x96, 0xd1, 0x40, 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x51, 0x4f, + 0x08, 0x51, 0x4e, 0x08, 0x7c, 0x1b, 0xe6, 0x18, 0x53, 0x4e, 0x18, + 0x53, 0x4f, 0x38, 0xfe, 0x06, 0x50, 0x38, 0x0e, 0x51, 0x00, 0x97, + 0x0f, 0x40, 0x96, 0xe4, 0x40, 0x51, 0x50, 0x01, + 0x62, 0x96, 0xf4, 0x40, 0x65, 0x4e, 0x6b, 0x4f, 0x65, 0x4e, 0x6b, 0x4f, + 0x50, 0x00, 0x08, 0x50, 0x03, 0x08, 0x51, 0x4f, 0x08, 0x51, 0x4e, + 0x08, 0x7c, 0x1b, 0xe6, 0x18, 0x53, 0x4e, 0x18, 0x53, 0x4f, 0x38, + 0xfe, 0x06, 0x50, 0x3c, 0x0e, 0x51, 0x00, 0x96, 0xdd, 0x40, 0x80, + 0x47, 0x3d, 0x00, 0x03, 0xb0, 0x42, 0x62, 0xd0, 0x00, 0x96, 0xa8, + 0x40, 0x51, 0x50, 0x01, 0x8c, 0x96, 0xb8, 0x40, + 0x55, 0x4c, 0x05, 0x96, 0x65, 0x40, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, + 0x06, 0x50, 0x38, 0x0e, 0x51, 0x00, 0x96, 0xb4, 0x40, 0x96, 0x89, + 0x40, 0x51, 0x50, 0x01, 0x62, 0x96, 0x99, 0x40, 0x55, 0x4c, 0x05, + 0x96, 0x46, 0x40, 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, 0x06, 0x50, + 0x3c, 0x0e, 0x51, 0x00, 0x96, 0x95, 0x40, 0x62, 0xd0, 0x00, 0x96, + 0x67, 0x40, 0x51, 0x50, 0x01, 0x62, 0x96, 0x77, + 0x40, 0x51, 0x50, 0x01, 0x8c, 0x53, 0x4c, 0x51, 0x51, 0x97, 0x70, 0x40, + 0x51, 0x4e, 0x12, 0x4c, 0x51, 0x4f, 0x1a, 0x4d, 0xd0, 0x21, 0x97, + 0x57, 0x40, 0x51, 0x4e, 0x01, 0x62, 0x53, 0x4c, 0x51, 0x4f, 0x97, + 0x58, 0x40, 0x06, 0x4e, 0x8c, 0x97, 0x1d, 0x40, 0x12, 0x4c, 0x54, + 0x04, 0x51, 0x4f, 0x1a, 0x4d, 0x54, 0x03, 0x80, 0x07, 0x56, 0x04, + 0x00, 0x56, 0x03, 0x00, 0x62, 0xd0, 0x00, 0x06, + 0x50, 0x34, 0x0e, 0x51, 0x00, 0x51, 0x51, 0x60, 0xd5, 0x52, 0x03, 0x3f, + 0x50, 0x52, 0x04, 0x3f, 0x50, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcd, + 0xe7, 0x62, 0xd0, 0x00, 0x3c, 0xb1, 0x02, 0xa0, 0x18, 0x3c, 0xb2, + 0x00, 0xa0, 0x13, 0x50, 0x01, 0x08, 0x50, 0x2c, 0x08, 0x90, 0x0e, + 0x38, 0xfe, 0x7c, 0x0a, 0xee, 0x10, 0x7c, 0x07, 0xc5, 0x20, 0x38, + 0xfb, 0x20, 0x7f, 0x10, 0x4f, 0x80, 0x02, 0x40, + 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, 0x50, 0x52, 0xfb, 0x53, 0x51, 0x51, + 0x50, 0x11, 0x01, 0x54, 0xfc, 0x51, 0x51, 0x19, 0x00, 0x54, 0xfb, + 0x3c, 0x51, 0x00, 0xbf, 0xe4, 0x3c, 0x50, 0x00, 0xbf, 0xdf, 0x20, + 0x7f, 0x10, 0x7c, 0x04, 0x8f, 0x7c, 0x04, 0x6c, 0x20, 0x7f, 0x10, + 0x7c, 0x04, 0x8b, 0x7c, 0x04, 0x68, 0x20, 0x7f, 0x62, 0xd0, 0x00, + 0x51, 0x42, 0x12, 0x67, 0x50, 0x00, 0x1a, 0x66, + 0xd0, 0x0f, 0x51, 0x43, 0x12, 0x69, 0x50, 0x00, 0x1a, 0x68, 0xd0, 0x05, + 0x50, 0x0f, 0x80, 0x17, 0x62, 0xd0, 0x00, 0x51, 0x69, 0x12, 0x67, + 0x51, 0x68, 0x1a, 0x66, 0xd0, 0x05, 0x50, 0x00, 0x80, 0x06, 0x62, + 0xd0, 0x00, 0x50, 0x01, 0x7f, 0x10, 0x4f, 0x38, 0x05, 0x62, 0xd0, + 0x00, 0x51, 0x67, 0x54, 0x02, 0x51, 0x66, 0x54, 0x01, 0x56, 0x04, + 0x00, 0x56, 0x00, 0x00, 0x56, 0x03, 0x00, 0x80, + 0x61, 0x95, 0x69, 0x40, 0x06, 0x50, 0x42, 0x0e, 0x51, 0x00, 0x51, 0x51, + 0x60, 0xd4, 0x3e, 0x50, 0x53, 0x50, 0x96, 0x5b, 0x40, 0x06, 0x4e, + 0x66, 0x0e, 0x4f, 0x00, 0x51, 0x4f, 0x95, 0x8c, 0x40, 0x51, 0x50, + 0x12, 0x4e, 0x50, 0x00, 0x1a, 0x4f, 0xd0, 0x03, 0x77, 0x03, 0x62, + 0xd0, 0x00, 0x95, 0x2f, 0x40, 0x06, 0x50, 0x66, 0x95, 0xcf, 0x40, + 0x3e, 0x50, 0x53, 0x50, 0x52, 0x02, 0x12, 0x50, + 0x52, 0x01, 0x1a, 0x51, 0xd0, 0x1a, 0x95, 0x18, 0x40, 0x06, 0x50, 0x66, + 0x0e, 0x51, 0x00, 0x51, 0x51, 0x60, 0xd4, 0x3e, 0x50, 0x54, 0x01, + 0x3e, 0x50, 0x54, 0x02, 0x52, 0x00, 0x54, 0x04, 0x77, 0x00, 0x3d, + 0x00, 0x02, 0xcf, 0x9c, 0x50, 0x01, 0x3b, 0x03, 0xd0, 0x08, 0x62, + 0xd0, 0x00, 0x50, 0x0f, 0x80, 0x06, 0x52, 0x04, 0x62, 0xd0, 0x00, + 0x38, 0xfb, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, + 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0xf0, 0x51, 0xb0, 0x01, 0x01, + 0x53, 0x51, 0x51, 0x2a, 0x2a, 0x51, 0x53, 0x2a, 0x71, 0x01, 0x62, + 0xe3, 0x38, 0x10, 0x7c, 0x05, 0xc5, 0x62, 0xd0, 0x00, 0x20, 0x41, + 0x00, 0xf7, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, + 0x7c, 0x05, 0xc5, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x51, 0x47, 0x51, + 0x20, 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, + 0x50, 0x04, 0x08, 0x9e, 0xb6, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, + 0x52, 0x01, 0x11, 0xdc, 0x52, 0x00, 0x19, 0x05, 0xcf, 0xd7, 0x56, + 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xc5, + 0x62, 0xd0, 0x00, 0x20, 0x53, 0x51, 0x47, 0x51, 0x20, 0xb0, 0x03, + 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x04, 0x08, 0x9e, 0x84, 0x38, + 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, + 0x11, 0x2c, 0x52, 0x00, 0x19, 0x01, 0xcf, 0xd7, 0x43, 0x00, 0x08, 0x38, + 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x02, 0x70, 0xfe, 0x62, 0xd0, + 0x00, 0x26, 0x2a, 0xf0, 0x51, 0xb0, 0x01, 0x09, 0x53, 0x51, 0x51, + 0x2a, 0x2a, 0x51, 0x53, 0x2a, 0x71, 0x01, 0x62, 0xe3, 0x38, 0x10, + 0x7c, 0x05, 0xc5, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, + 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x21, 0x10, + 0x7c, 0x05, 0xc5, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x51, 0x47, 0x51, 0x20, + 0xa0, 0x03, 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x04, 0x08, 0x9e, + 0x23, 0x38, 0xfe, 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, + 0xdc, 0x52, 0x00, 0x19, 0x05, 0xcf, 0xd7, 0x56, 0x01, 0x00, 0x56, + 0x00, 0x00, 0x80, 0x21, 0x10, 0x7c, 0x05, 0xc5, 0x62, 0xd0, 0x00, + 0x20, 0x53, 0x51, 0x47, 0x51, 0x20, 0xb0, 0x03, + 0x80, 0x1a, 0x50, 0x00, 0x08, 0x50, 0x04, 0x08, 0x9d, 0xf1, 0x38, 0xfe, + 0x77, 0x01, 0x0f, 0x00, 0x00, 0x52, 0x01, 0x11, 0x2c, 0x52, 0x00, + 0x19, 0x01, 0xcf, 0xd7, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, + 0x10, 0x4f, 0x38, 0x04, 0x62, 0xd0, 0x00, 0x51, 0x2a, 0x21, 0xf0, + 0x54, 0x00, 0x51, 0x2d, 0x54, 0x01, 0x3d, 0x00, 0x10, 0xb0, 0x2a, + 0x55, 0xa7, 0x00, 0x3c, 0xab, 0x01, 0xb0, 0x09, + 0x55, 0x94, 0x00, 0x55, 0x95, 0x00, 0x80, 0x0f, 0x62, 0xd0, 0x00, 0x3c, + 0xae, 0x01, 0xa0, 0x07, 0x55, 0x94, 0x00, 0x55, 0x95, 0x00, 0x56, + 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x81, 0x76, 0x3d, + 0x00, 0x20, 0xb0, 0x18, 0x62, 0xd0, 0x00, 0x55, 0xa7, 0x01, 0x55, + 0xa8, 0x00, 0x55, 0x94, 0x08, 0x55, 0x95, 0x08, 0x56, 0x00, 0x00, + 0x26, 0x2a, 0x0f, 0x81, 0x5a, 0x3d, 0x00, 0x30, + 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0xb1, 0x00, 0x56, 0x00, 0x00, 0x26, + 0x2a, 0x0f, 0x81, 0x47, 0x3d, 0x00, 0x40, 0xb0, 0x0f, 0x62, 0xd0, + 0x00, 0x55, 0xb1, 0x02, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x81, + 0x34, 0x3d, 0x00, 0x50, 0xb0, 0xa7, 0x52, 0x01, 0x54, 0x03, 0x56, + 0x02, 0x00, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x01, 0xa0, + 0x21, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, + 0x02, 0xa0, 0x28, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x04, 0xa0, + 0x36, 0x3d, 0x02, 0x00, 0xb0, 0x06, 0x3d, 0x03, 0x08, 0xa0, 0x48, + 0x80, 0x62, 0x62, 0xd0, 0x00, 0x55, 0xaa, 0x01, 0x51, 0x2f, 0x29, + 0x80, 0x53, 0x2f, 0x7c, 0x0d, 0x19, 0x80, 0x51, 0x62, 0xd0, 0x00, + 0x51, 0x2b, 0x53, 0x42, 0x51, 0x2b, 0x53, 0x43, 0x51, 0x2b, 0x53, + 0x2e, 0x51, 0x2c, 0x53, 0x0e, 0x55, 0x0d, 0x00, + 0x80, 0x39, 0x62, 0xd0, 0x00, 0x51, 0x2b, 0x53, 0x2f, 0x3c, 0xaa, 0x00, + 0xa0, 0x09, 0x51, 0x2f, 0x29, 0x80, 0x53, 0x2f, 0x80, 0x25, 0x62, + 0xd0, 0x00, 0x26, 0x2f, 0x7f, 0x80, 0x1d, 0x62, 0xd0, 0x00, 0x55, + 0xaa, 0x00, 0x26, 0x2f, 0x7f, 0x51, 0x9c, 0x53, 0x24, 0x51, 0x24, + 0x53, 0x30, 0x51, 0x9d, 0x53, 0x25, 0x51, 0x25, 0x53, 0x31, 0x7c, + 0x0d, 0x19, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, + 0x26, 0x2a, 0x0f, 0x55, 0x2b, 0x11, 0x55, 0x2c, 0x08, 0x55, 0x2d, 0x00, + 0x80, 0x89, 0x3d, 0x00, 0x60, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, + 0xab, 0x01, 0x56, 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x80, 0x76, 0x3d, + 0x00, 0x70, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0xab, 0x00, 0x56, + 0x00, 0x00, 0x26, 0x2a, 0x0f, 0x80, 0x63, 0x3d, 0x00, 0x80, 0xb0, + 0x5e, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, + 0x2a, 0x0f, 0x9c, 0x9f, 0x10, 0x7c, 0x08, 0xb8, 0x7c, 0x05, 0xdb, 0x20, + 0x70, 0xfe, 0x93, 0xcf, 0x40, 0x62, 0xda, 0x00, 0x71, 0x10, 0x41, + 0xdc, 0xfe, 0x70, 0xcf, 0x43, 0x01, 0x08, 0x43, 0x00, 0x08, 0x50, + 0x00, 0x08, 0x50, 0x1e, 0x08, 0x9c, 0x52, 0x38, 0xfe, 0x71, 0x01, + 0x43, 0xe0, 0x10, 0x43, 0xff, 0x08, 0x70, 0xfe, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x10, 0x7c, 0x07, 0xe7, + 0x7c, 0x05, 0x8f, 0x7c, 0x05, 0xd0, 0x20, 0x93, 0x3f, 0x40, 0x62, 0xe3, + 0x38, 0x56, 0x00, 0x00, 0x62, 0xd0, 0x00, 0x26, 0x2a, 0x0f, 0x38, + 0xfc, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x3c, 0xa7, 0x00, 0xa0, 0x13, + 0x9c, 0x3f, 0x62, 0xd0, 0x00, 0x3c, 0xa8, 0x00, 0xb0, 0x33, 0x55, + 0xa8, 0x01, 0x7c, 0x0a, 0xee, 0x80, 0x2b, 0x62, 0xd0, 0x00, 0x50, + 0x01, 0x3a, 0x94, 0xd0, 0x08, 0x10, 0x7c, 0x04, + 0x8f, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0x8b, 0x20, 0x62, 0xd0, 0x00, + 0x50, 0x01, 0x3a, 0x95, 0xd0, 0x08, 0x10, 0x7c, 0x04, 0x6c, 0x20, + 0x80, 0x06, 0x10, 0x7c, 0x04, 0x68, 0x20, 0x7f, 0x10, 0x4f, 0x38, + 0x03, 0x56, 0x02, 0x00, 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, + 0x3e, 0x62, 0xd0, 0x00, 0x91, 0xad, 0x40, 0x52, 0xfc, 0x04, 0x50, + 0x52, 0xfb, 0x0c, 0x51, 0x51, 0x51, 0x60, 0xd4, + 0x3e, 0x50, 0x53, 0x51, 0x3e, 0x50, 0x53, 0x50, 0x52, 0x02, 0x12, 0x50, + 0x52, 0x01, 0x1a, 0x51, 0xd0, 0x18, 0x91, 0x8c, 0x40, 0x52, 0xfc, + 0x04, 0x50, 0x52, 0xfb, 0x0c, 0x51, 0x51, 0x51, 0x60, 0xd4, 0x3e, + 0x50, 0x54, 0x01, 0x3e, 0x50, 0x54, 0x02, 0x77, 0x00, 0x52, 0x00, + 0x3b, 0xfa, 0xcf, 0xbe, 0x62, 0xd0, 0x00, 0x52, 0x02, 0x53, 0x50, + 0x52, 0x01, 0x53, 0x51, 0x38, 0xfd, 0x20, 0x7f, + 0x10, 0x7c, 0x04, 0x1a, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, 0x08, + 0x50, 0x8c, 0x08, 0x7c, 0x04, 0x23, 0x38, 0xfd, 0x20, 0x10, 0x50, + 0x04, 0x08, 0x50, 0x00, 0x08, 0x50, 0x62, 0x08, 0x7c, 0x04, 0x23, + 0x38, 0xfd, 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, 0x08, 0x50, + 0x66, 0x08, 0x7c, 0x04, 0x23, 0x38, 0xfd, 0x20, 0x10, 0x50, 0x00, + 0x7c, 0x03, 0x3e, 0x20, 0x10, 0x50, 0xff, 0x7c, + 0x03, 0x3e, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x3e, 0x20, 0x7f, 0x62, + 0xd0, 0x00, 0x55, 0xaa, 0x00, 0x55, 0xab, 0x01, 0x10, 0x7c, 0x04, + 0x8f, 0x7c, 0x04, 0x6c, 0x20, 0x9b, 0x45, 0x62, 0xe3, 0x38, 0x92, + 0x7c, 0x40, 0x43, 0x00, 0x08, 0x62, 0xd0, 0x00, 0x55, 0x2a, 0x08, + 0x55, 0x2b, 0x11, 0x55, 0x2c, 0x08, 0x55, 0x2e, 0x1e, 0x55, 0x2f, + 0x03, 0x55, 0x30, 0x5f, 0x55, 0x31, 0x28, 0x55, + 0x32, 0x00, 0x55, 0x33, 0x00, 0x3c, 0xaa, 0x00, 0xa0, 0x09, 0x51, 0x2f, + 0x29, 0x80, 0x53, 0x2f, 0x80, 0x07, 0x62, 0xd0, 0x00, 0x26, 0x2f, + 0x7f, 0x10, 0x50, 0x00, 0x08, 0x50, 0x2a, 0x08, 0x50, 0x06, 0x08, + 0x50, 0x16, 0x08, 0x7c, 0x05, 0xe2, 0x38, 0xfc, 0x7c, 0x05, 0x8f, + 0x7c, 0x05, 0xd0, 0x20, 0x91, 0xd5, 0x40, 0x10, 0x7c, 0x07, 0xe7, + 0x7c, 0x07, 0x6d, 0x20, 0x7c, 0x0d, 0x19, 0x80, + 0x22, 0x62, 0xe3, 0x38, 0x7c, 0x10, 0xc2, 0x10, 0x7c, 0x07, 0xab, 0x62, + 0xd0, 0x00, 0x20, 0x39, 0x00, 0xa0, 0x09, 0x7c, 0x0a, 0x07, 0x7c, + 0x0a, 0x31, 0x80, 0x04, 0x7c, 0x0a, 0x9f, 0x9c, 0xc2, 0x9e, 0x78, + 0x8f, 0xde, 0x8f, 0xff, 0x10, 0x4f, 0x7c, 0x1b, 0xf1, 0x20, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, + 0x00, 0x53, 0x4a, 0x53, 0x4b, 0x55, 0x49, 0x10, + 0x66, 0xfc, 0x6c, 0xfb, 0x6b, 0x4a, 0x6b, 0x4b, 0x51, 0x4a, 0x1b, 0xfa, + 0x51, 0x4b, 0x1b, 0xf9, 0xc0, 0x09, 0x53, 0x4b, 0x52, 0xfa, 0x1c, + 0x4a, 0x77, 0xfc, 0x7a, 0x49, 0xbf, 0xe3, 0x51, 0x4a, 0x54, 0xfa, + 0x51, 0x4b, 0x54, 0xf9, 0x18, 0x60, 0xd0, 0x7f, 0x55, 0x4d, 0x00, + 0x55, 0x4b, 0x00, 0x55, 0x4a, 0x00, 0x3c, 0x4d, 0x00, 0xb0, 0x06, + 0x3c, 0x4c, 0x00, 0xa0, 0x1a, 0x70, 0xfb, 0x6e, + 0x4d, 0x6e, 0x4c, 0xd0, 0x0c, 0x62, 0xd0, 0x00, 0x51, 0x4e, 0x04, 0x4b, + 0x51, 0x4f, 0x0c, 0x4a, 0x65, 0x4e, 0x6b, 0x4f, 0x8f, 0xde, 0x5f, + 0x4e, 0x4b, 0x5f, 0x4f, 0x4a, 0x62, 0xd0, 0x00, 0x7f, 0x52, 0x00, + 0x53, 0x50, 0x55, 0x51, 0x00, 0x65, 0x50, 0x6b, 0x51, 0x7f, 0x62, + 0xd0, 0x00, 0x52, 0x00, 0x53, 0x50, 0x55, 0x51, 0x00, 0x7f, 0x53, + 0x4e, 0x51, 0x51, 0x09, 0x00, 0x60, 0xd4, 0x3e, + 0x4e, 0x53, 0x4f, 0x3e, 0x4e, 0x53, 0x4e, 0x7f, 0x51, 0x51, 0x60, 0xd5, + 0x51, 0x4f, 0x3f, 0x50, 0x51, 0x4e, 0x3f, 0x50, 0x7f, 0x06, 0x50, + 0x8c, 0x0e, 0x51, 0x00, 0x51, 0x51, 0x60, 0xd4, 0x3e, 0x50, 0x53, + 0x4f, 0x3e, 0x50, 0x16, 0x50, 0x02, 0x53, 0x4e, 0x7f, 0x60, 0xd4, + 0x3e, 0x4e, 0x53, 0x4f, 0x3e, 0x4e, 0x53, 0x4e, 0x7f, 0x09, 0x00, + 0x60, 0xd4, 0x3e, 0x4e, 0x53, 0x4f, 0x3e, 0x4e, + 0x7f, 0x55, 0x4e, 0x06, 0x55, 0x4f, 0x00, 0x55, 0x4b, 0x00, 0x55, 0x4a, + 0x00, 0x3c, 0x4f, 0x00, 0xb0, 0x06, 0x3c, 0x4e, 0x00, 0xa0, 0x1a, + 0x70, 0xfb, 0x6e, 0x4f, 0x6e, 0x4e, 0xd0, 0x0c, 0x62, 0xd0, 0x00, + 0x51, 0x50, 0x04, 0x4b, 0x51, 0x51, 0x0c, 0x4a, 0x65, 0x50, 0x6b, + 0x51, 0x8f, 0xde, 0x5f, 0x50, 0x4b, 0x5f, 0x51, 0x4a, 0x62, 0xd0, + 0x00, 0x5a, 0x4e, 0x06, 0x4e, 0x01, 0x51, 0x4e, + 0x04, 0x50, 0x0e, 0x51, 0x03, 0x7f, 0x0e, 0x51, 0x00, 0x51, 0x51, 0x60, + 0xd4, 0x3e, 0x50, 0x53, 0x51, 0x7f, 0x60, 0xd4, 0x3e, 0x50, 0x53, + 0x51, 0x3e, 0x50, 0x53, 0x50, 0x7f, 0x53, 0x4e, 0x51, 0x51, 0x09, + 0x00, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x4e, 0x52, 0x15, 0x3f, 0x4e, + 0x7f, 0x3e, 0x50, 0x53, 0x50, 0x51, 0x4e, 0x12, 0x50, 0x51, 0x4f, + 0x1a, 0x51, 0x7f, 0x53, 0x50, 0x52, 0xfb, 0x09, + 0x00, 0x60, 0xd4, 0x3e, 0x50, 0x7f, 0x0e, 0x4f, 0x00, 0x51, 0x4f, 0x60, + 0xd4, 0x3e, 0x4e, 0x53, 0x4f, 0x3e, 0x4e, 0x7f, 0x60, 0xd4, 0x3e, + 0x50, 0x54, 0x00, 0x3e, 0x50, 0x54, 0x01, 0x7f, 0x0e, 0x51, 0x00, + 0x51, 0x51, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x50, 0x52, 0x15, 0x3f, + 0x50, 0x7f, 0x52, 0x00, 0x53, 0x4e, 0x55, 0x4f, 0x00, 0x65, 0x4e, + 0x6b, 0x4f, 0x7f, 0x09, 0x00, 0x60, 0xd4, 0x3e, + 0x4c, 0x53, 0x4d, 0x3e, 0x4c, 0x53, 0x4c, 0x7f, 0x71, 0x10, 0x41, 0x04, + 0xfe, 0x41, 0x05, 0xfe, 0x41, 0x04, 0xfd, 0x41, 0x05, 0xfd, 0x70, + 0xcf, 0x43, 0x04, 0x01, 0x43, 0x04, 0x02, 0x71, 0x01, 0x7f, 0x0e, + 0x4f, 0x00, 0x51, 0x4f, 0x60, 0xd5, 0x51, 0x51, 0x3f, 0x4e, 0x7f, + 0x53, 0x4e, 0x55, 0x4f, 0x00, 0x65, 0x4e, 0x6b, 0x4f, 0x51, 0x4e, + 0x7f, 0x0e, 0x51, 0x00, 0x51, 0x51, 0x60, 0xd5, + 0x50, 0x00, 0x3f, 0x50, 0x7f, 0x3e, 0x50, 0x12, 0x4e, 0x54, 0x04, 0x51, + 0x51, 0x1a, 0x4f, 0x54, 0x03, 0x7f, 0x3e, 0x50, 0x12, 0x4e, 0x54, + 0x02, 0x51, 0x51, 0x1a, 0x4f, 0x54, 0x01, 0x7f, 0x71, 0x10, 0x41, + 0x00, 0xf7, 0x41, 0x01, 0xf7, 0x70, 0xcf, 0x7f, 0x00, 0x2a, 0x00, + 0x16, 0x00, 0x52, 0x00, 0x10, 0x00, 0x6a, 0x00, 0x22, 0x00, 0x90, + 0x00, 0x04, 0x00, 0x94, 0x04, 0x08, 0x08, 0x08, + 0x08, 0x00, 0x98, 0x00, 0x04, 0x00, 0x9c, 0x02, 0x5f, 0x28, 0x00, 0x9e, + 0x00, 0x08, 0x00, 0xa6, 0x07, 0x03, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x02, 0x00, 0xad, 0x00, 0x06, 0xff, 0x00, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypressbln/touchkey_fw_U1.h b/drivers/input/keyboard/cypressbln/touchkey_fw_U1.h new file mode 100644 index 0000000..a625b41 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/touchkey_fw_U1.h @@ -0,0 +1,747 @@ +unsigned char firmware_data[] = { + 0x40, 0x7d, 0x00, 0x68, 0x30, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, + 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7d, 0x05, 0x4f, 0x7e, 0x7e, 0x30, + 0x30, 0x30, 0x7d, 0x06, 0xbb, 0x7e, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, + 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, + 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, + 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x7e, + 0x30, 0x30, 0x30, 0x7e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x40, 0x71, 0x10, 0x62, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe3, 0x38, 0x50, 0x80, 0x4e, 0x62, 0xe3, 0x38, 0x5d, + 0xd5, 0x08, 0x62, 0xd5, 0x00, 0x55, 0xfa, 0x01, 0x40, 0x4f, 0x5b, + 0x01, 0x03, 0x53, 0xf9, 0x55, 0xf8, 0x3a, 0x50, 0x06, 0x00, 0x40, + 0x40, 0x71, 0x10, 0x51, 0xfa, 0x60, 0xe8, 0x70, 0xef, 0x18, 0x60, + 0xd5, 0x55, 0xf8, 0x00, 0x55, 0xf9, 0x00, 0x71, 0x10, 0x62, 0xe0, + 0x02, 0x70, 0xef, 0x62, 0xe3, 0x38, 0x71, 0x10, 0x41, 0xe1, 0xfe, + 0x70, 0xef, 0x62, 0xe3, 0x38, 0x62, 0xd1, 0x03, 0x50, 0x00, 0x4e, + 0x62, 0xd3, 0x03, 0x62, 0xd0, 0x00, 0x62, 0xd5, 0x00, 0x62, 0xd4, + 0x00, 0x71, 0xc0, 0x7c, 0x03, 0x01, 0x62, 0xd0, 0x00, 0x50, 0x02, + 0x57, 0xff, 0x08, 0x28, 0x53, 0x40, 0x18, 0x75, 0x09, 0x00, 0x28, + 0x4b, 0x51, 0x40, 0x80, 0x04, 0x75, 0x09, 0x00, 0x62, 0xe3, 0x00, + 0x08, 0x28, 0x60, 0xd5, 0x74, 0xa0, 0x4b, 0x18, 0x75, 0x09, 0x00, + 0x08, 0x28, 0x53, 0x40, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0xa0, + 0x1c, 0x53, 0x3f, 0x18, 0x75, 0x09, 0x00, 0x08, 0x28, 0x3f, 0x40, + 0x47, 0x40, 0xff, 0xb0, 0x06, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x18, + 0x7a, 0x3f, 0xbf, 0xeb, 0x8f, 0xc9, 0x18, 0x75, 0x09, 0x00, 0x08, + 0x28, 0x53, 0x3f, 0x50, 0x00, 0x3f, 0x40, 0x47, 0x40, 0xff, 0xb0, + 0x08, 0x5d, 0xd5, 0x74, 0x60, 0xd5, 0x50, 0x00, 0x7a, 0x3f, 0xbf, + 0xef, 0x18, 0x8f, 0xaa, 0x18, 0x71, 0x10, 0x43, 0xe3, 0x00, 0x70, + 0xef, 0x62, 0xe0, 0x00, 0x41, 0xfe, 0xe7, 0x43, 0xfe, 0x10, 0x71, + 0x10, 0x62, 0xe0, 0x02, 0x70, 0xef, 0x62, 0xe2, 0x00, 0x7c, 0x0a, + 0xce, 0x8f, 0xff, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x61, 0x00, 0xfd, 0x00, 0xcd, 0x00, + 0xce, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa0, 0x00, 0xa1, 0x80, 0xa2, + 0x80, 0xa3, 0x0c, 0xa8, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x7c, 0x33, + 0x7a, 0x00, 0x7b, 0x00, 0x79, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, + 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, + 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, + 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, + 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, + 0x00, 0x4f, 0x00, 0xca, 0x20, 0xd6, 0x44, 0xcf, 0x00, 0xcb, 0x00, + 0xc8, 0x00, 0xcc, 0x00, 0xc9, 0x00, 0xd7, 0x00, 0xa9, 0x00, 0x2b, + 0x00, 0xb0, 0x00, 0xb3, 0x02, 0xb6, 0x00, 0xb2, 0x00, 0xb5, 0x00, + 0xb8, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0x33, 0x00, 0x34, + 0x00, 0x35, 0x00, 0xff, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, + 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0xdc, 0x00, + 0xe2, 0x00, 0xdd, 0x00, 0xd8, 0x02, 0xd9, 0x00, 0xda, 0x28, 0xdb, + 0x00, 0xdf, 0x00, 0x29, 0x00, 0x30, 0x00, 0xbd, 0x00, 0xff, 0x70, + 0xef, 0x62, 0x00, 0x08, 0x71, 0x10, 0x62, 0x00, 0x08, 0x62, 0x01, + 0x92, 0x70, 0xef, 0x62, 0x04, 0x03, 0x71, 0x10, 0x62, 0x04, 0x14, + 0x62, 0x05, 0xa8, 0x70, 0xef, 0x62, 0x08, 0x00, 0x71, 0x10, 0x62, + 0x08, 0x00, 0x62, 0x09, 0x28, 0x70, 0xef, 0x62, 0x0c, 0x00, 0x71, + 0x10, 0x62, 0x0c, 0x00, 0x62, 0x0d, 0x00, 0x70, 0xef, 0x62, 0x10, + 0x00, 0x71, 0x10, 0x62, 0x10, 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, + 0x62, 0x01, 0x00, 0x62, 0x05, 0x00, 0x62, 0x09, 0x00, 0x62, 0x0d, + 0x00, 0x62, 0x11, 0x00, 0x70, 0xef, 0x7f, 0x17, 0xc4, 0x55, 0x02, + 0x08, 0x55, 0x03, 0x03, 0x55, 0x04, 0x00, 0x7c, 0x03, 0x11, 0x7c, + 0x02, 0xaa, 0x7f, 0x10, 0x70, 0xef, 0x50, 0x00, 0x67, 0x50, 0x02, + 0x57, 0x00, 0x7c, 0x03, 0x2c, 0x50, 0x01, 0x67, 0x50, 0x02, 0x57, + 0x83, 0x7c, 0x03, 0x2c, 0x70, 0xef, 0x20, 0x7f, 0x38, 0x02, 0x10, + 0x08, 0x4f, 0x56, 0xfc, 0x00, 0xd0, 0x04, 0x56, 0xfc, 0x01, 0x18, + 0x20, 0x70, 0xef, 0x62, 0xe3, 0x00, 0x10, 0x08, 0x28, 0x39, 0xff, + 0xa0, 0x1f, 0x4f, 0x48, 0xfc, 0x01, 0xa0, 0x03, 0x71, 0x10, 0x54, + 0xfd, 0x18, 0x20, 0x75, 0x09, 0x00, 0x10, 0x08, 0x28, 0x4f, 0x59, + 0xfd, 0x61, 0x00, 0x18, 0x20, 0x75, 0x09, 0x00, 0x8f, 0xd7, 0x38, + 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x62, 0xd0, 0x00, 0x2e, 0x02, 0x08, 0x51, 0x02, 0x60, 0x00, 0x71, + 0x10, 0x41, 0x01, 0xf7, 0x43, 0x00, 0x08, 0x70, 0xef, 0x7f, 0x71, + 0x10, 0x43, 0x01, 0x08, 0x41, 0x00, 0xf7, 0x70, 0xef, 0x7f, 0x62, + 0xd0, 0x00, 0x53, 0x00, 0x71, 0x10, 0x5d, 0xe0, 0x08, 0x21, 0xf8, + 0x29, 0x00, 0x70, 0xfe, 0x60, 0xe0, 0x70, 0xef, 0x4b, 0x4b, 0x4b, + 0x4b, 0x51, 0x02, 0x21, 0xf7, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, + 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, + 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, + 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, + 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, + 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, + 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, + 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, + 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, 0xf7, 0x80, 0x05, + 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x6e, 0x00, 0xc0, 0x05, 0x21, + 0xf7, 0x80, 0x05, 0x29, 0x08, 0x80, 0x01, 0x60, 0x00, 0x47, 0x00, + 0x00, 0x49, 0x01, 0x00, 0x29, 0x08, 0x60, 0x00, 0x57, 0x01, 0x79, + 0xbf, 0xfe, 0x18, 0x71, 0x10, 0x60, 0xe0, 0x70, 0xef, 0x71, 0x01, + 0x7f, 0x08, 0x67, 0x67, 0x67, 0x67, 0x21, 0x0f, 0xff, 0x20, 0x9f, + 0x4e, 0x18, 0x21, 0x0f, 0xff, 0x19, 0x9f, 0x47, 0x7f, 0x08, 0x5b, + 0x9f, 0xe9, 0x18, 0x9f, 0xe6, 0x7f, 0x08, 0x10, 0x28, 0xa0, 0x0b, + 0x9f, 0x37, 0x20, 0x18, 0x75, 0xdf, 0xf5, 0x74, 0x8f, 0xf2, 0x38, + 0xfe, 0x7f, 0x70, 0xbf, 0x60, 0xd3, 0x52, 0x00, 0xa0, 0x08, 0x10, + 0x9f, 0x21, 0x20, 0x75, 0x8f, 0xf6, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x50, 0x0d, 0x9f, 0x14, 0x50, 0x0a, 0x9f, 0x10, 0x7f, 0x70, 0xbf, + 0x62, 0xd3, 0x03, 0x4f, 0x52, 0xfb, 0xa0, 0x15, 0x7b, 0xfb, 0x52, + 0xfc, 0x59, 0xfd, 0x60, 0xd3, 0x52, 0x00, 0x9e, 0xf9, 0x4f, 0x62, + 0xd3, 0x03, 0x77, 0xfd, 0x8f, 0xe9, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x4f, 0x3d, 0xfa, 0x00, 0xb0, 0x06, 0x3d, 0xfb, 0x00, 0xa0, 0x18, + 0x10, 0x52, 0xfc, 0x59, 0xfd, 0x28, 0x9e, 0xd9, 0x20, 0x07, 0xfd, + 0x01, 0x0f, 0xfc, 0x00, 0x17, 0xfb, 0x01, 0x1f, 0xfa, 0x00, 0x8f, + 0xe0, 0x7f, 0x50, 0x01, 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, + 0x29, 0x00, 0xa0, 0x06, 0x26, 0x03, 0xfb, 0x80, 0x04, 0x2e, 0x03, + 0x04, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, + 0xd0, 0x00, 0x36, 0x03, 0x04, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x03, 0x73, 0x21, 0x04, + 0xa0, 0x03, 0x50, 0x01, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, 0x01, + 0x80, 0x03, 0x50, 0x00, 0x62, 0xd0, 0x00, 0x29, 0x00, 0xa0, 0x06, + 0x26, 0x03, 0xef, 0x80, 0x04, 0x2e, 0x03, 0x10, 0x51, 0x03, 0x60, + 0x04, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x36, 0x03, + 0x10, 0x51, 0x03, 0x60, 0x04, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, + 0xd0, 0x00, 0x51, 0x03, 0x73, 0x21, 0x10, 0xa0, 0x03, 0x50, 0x01, + 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x10, 0x70, 0x3f, 0x71, 0x80, + 0x5d, 0xd3, 0x08, 0x5d, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x51, 0x08, + 0x60, 0xd3, 0x2e, 0x05, 0x80, 0x49, 0xd7, 0x08, 0xa0, 0x09, 0x26, + 0x05, 0xf0, 0x2e, 0x05, 0x00, 0x80, 0x08, 0x49, 0xd7, 0x20, 0xa0, + 0x03, 0x80, 0xac, 0x51, 0x05, 0x21, 0x0e, 0xe0, 0x01, 0x80, 0x11, + 0x80, 0x6d, 0x80, 0x7f, 0x80, 0x4d, 0x80, 0x9c, 0x80, 0x9a, 0x80, + 0x98, 0x80, 0x96, 0x80, 0x9d, 0x5d, 0xd8, 0x21, 0xfe, 0x39, 0x40, + 0xa0, 0x06, 0x62, 0xd7, 0x00, 0x80, 0x90, 0x49, 0xd8, 0x01, 0xb0, + 0x15, 0x55, 0x0c, 0x02, 0x26, 0x07, 0x00, 0x26, 0x06, 0x00, 0x26, + 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x62, 0xd7, 0x10, 0x80, 0x77, 0x55, + 0x0c, 0x01, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x06, 0x5f, 0x07, 0x06, + 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, 0x60, 0xd8, 0x76, 0x07, + 0x62, 0xd7, 0x14, 0x80, 0x5b, 0x51, 0x0a, 0x78, 0x3a, 0x07, 0xc0, + 0x0f, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x52, 0x00, 0x60, 0xd8, 0x76, + 0x07, 0x2e, 0x05, 0x20, 0x60, 0xd8, 0x62, 0xd7, 0x04, 0x80, 0x3f, + 0x5d, 0xd8, 0x3a, 0x0a, 0xd0, 0x2b, 0xa0, 0x29, 0x53, 0x07, 0x53, + 0x06, 0x26, 0x05, 0xf0, 0x2e, 0x05, 0x04, 0x80, 0x18, 0x51, 0x0b, + 0x78, 0x3a, 0x07, 0xc0, 0x16, 0x51, 0x09, 0x02, 0x07, 0x5c, 0x5d, + 0xd8, 0x54, 0x00, 0x2e, 0x05, 0x10, 0x76, 0x07, 0x80, 0x01, 0x62, + 0xd7, 0x10, 0x80, 0x0f, 0x62, 0xd7, 0x00, 0x80, 0x0a, 0x26, 0x05, + 0xf0, 0x2e, 0x05, 0x00, 0x55, 0x0c, 0x00, 0x18, 0x60, 0xd0, 0x18, + 0x60, 0xd3, 0x20, 0x18, 0x7e, 0x62, 0xd0, 0x00, 0x71, 0x10, 0x41, + 0x04, 0xfc, 0x43, 0x05, 0x03, 0x70, 0xef, 0x26, 0x03, 0xfc, 0x51, + 0x03, 0x60, 0x04, 0x55, 0x0c, 0x00, 0x90, 0x2d, 0x90, 0x32, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x50, 0x00, 0x53, 0x06, 0x71, 0x10, 0x43, + 0x04, 0x03, 0x43, 0x05, 0x03, 0x70, 0xef, 0x2e, 0x03, 0x03, 0x51, + 0x03, 0x60, 0x04, 0x7f, 0x62, 0xd0, 0x00, 0x51, 0x05, 0x21, 0xb0, + 0x26, 0x05, 0x4f, 0x7f, 0x50, 0x20, 0x7f, 0x80, 0x04, 0x41, 0xe0, + 0x7f, 0x43, 0xe0, 0x80, 0x7f, 0x43, 0xd6, 0x31, 0x7f, 0x41, 0xe0, + 0x7f, 0x41, 0xd6, 0xfe, 0x7f, 0x41, 0xe0, 0x7f, 0x7f, 0x41, 0xd6, + 0xfe, 0x7f, 0x62, 0xd0, 0x00, 0x4f, 0x52, 0xfd, 0x53, 0x0a, 0x52, + 0xfc, 0x53, 0x0b, 0x52, 0xfb, 0x53, 0x09, 0x52, 0xfa, 0x53, 0x08, + 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x02, 0x20, 0x02, 0x08, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x06, 0xb9, 0x08, 0x5d, 0xa4, 0x04, 0x1b, + 0x5d, 0xa5, 0x0c, 0x1a, 0x55, 0x1c, 0x01, 0x18, 0x7e, 0x70, 0xbf, + 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x53, 0x1e, 0x64, 0x5c, 0x62, 0xd3, + 0x00, 0x52, 0x5b, 0x62, 0xd3, 0x00, 0x13, 0x4b, 0x62, 0xd3, 0x00, + 0x54, 0x4f, 0x62, 0xd3, 0x00, 0x52, 0x5a, 0x62, 0xd3, 0x00, 0x1b, + 0x4a, 0x62, 0xd3, 0x00, 0x54, 0x4e, 0x48, 0x4e, 0x80, 0xb0, 0x33, + 0x3d, 0x4e, 0x00, 0xb0, 0x7b, 0x51, 0x0d, 0x3b, 0x4f, 0xc0, 0x75, + 0x52, 0x4f, 0x58, 0x1e, 0x01, 0x00, 0x6d, 0x62, 0xd3, 0x00, 0x05, + 0x41, 0xc0, 0x09, 0x51, 0x0f, 0x3b, 0x41, 0xd0, 0x12, 0xa0, 0x10, + 0x56, 0x41, 0x00, 0x5b, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x07, 0x4b, + 0x01, 0x0f, 0x4a, 0x00, 0x80, 0x41, 0x3d, 0x4e, 0xff, 0xb0, 0x09, + 0x50, 0xff, 0x12, 0x0e, 0x3b, 0x4f, 0xc0, 0x20, 0x62, 0xd3, 0x00, + 0x56, 0x4f, 0x00, 0x56, 0x4e, 0x00, 0x5b, 0x67, 0x5c, 0x62, 0xd3, + 0x00, 0x52, 0x48, 0x78, 0xd0, 0x03, 0x50, 0x00, 0x54, 0x48, 0x08, + 0x5b, 0x64, 0x5c, 0x18, 0xb0, 0x2c, 0x62, 0xd3, 0x00, 0x52, 0x5b, + 0x62, 0xd3, 0x00, 0x54, 0x4b, 0x62, 0xd3, 0x00, 0x52, 0x5a, 0x62, + 0xd3, 0x00, 0x54, 0x4a, 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, + 0x56, 0x4f, 0x00, 0x56, 0x4e, 0x00, 0x5b, 0x67, 0x5c, 0x62, 0xd3, + 0x00, 0x51, 0x12, 0x54, 0x48, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x70, + 0xbf, 0x62, 0xd0, 0x00, 0x70, 0xbf, 0x08, 0x5c, 0x62, 0xd3, 0x00, + 0x52, 0x43, 0x53, 0x19, 0x55, 0x18, 0x00, 0x18, 0x08, 0x90, 0x7e, + 0x62, 0xd3, 0x00, 0x23, 0x45, 0xb0, 0x2c, 0x51, 0x10, 0x04, 0x19, + 0x0e, 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x4f, + 0x12, 0x19, 0x52, 0x4e, 0x1a, 0x18, 0xc0, 0x39, 0x5b, 0x67, 0x5c, + 0x62, 0xd3, 0x00, 0x52, 0x46, 0x78, 0x54, 0x46, 0x08, 0x5b, 0x64, + 0x5c, 0x18, 0xb0, 0x3e, 0x80, 0x18, 0x51, 0x10, 0x14, 0x19, 0x1e, + 0x18, 0x00, 0x18, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x4f, 0x12, + 0x19, 0x52, 0x4e, 0x1a, 0x18, 0xc0, 0x0e, 0x5b, 0x67, 0x90, 0x31, + 0x62, 0xd3, 0x00, 0x2d, 0x45, 0x50, 0x01, 0x80, 0x24, 0x5b, 0x67, + 0x08, 0x90, 0x23, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x45, 0x62, 0xd3, + 0x00, 0x20, 0x51, 0x11, 0x54, 0x46, 0x50, 0x00, 0x80, 0x0d, 0x5b, + 0x67, 0x90, 0x0d, 0x73, 0x62, 0xd3, 0x00, 0x25, 0x45, 0x50, 0x00, + 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x08, 0x67, 0x67, 0x67, 0x5c, 0x18, + 0x21, 0x07, 0xf0, 0x01, 0x7f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, + 0x40, 0x80, 0x70, 0xbf, 0x70, 0xbf, 0x62, 0xd3, 0x00, 0x50, 0x02, + 0x78, 0x08, 0x5c, 0x56, 0x43, 0x28, 0x18, 0x78, 0xdf, 0xf8, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x50, 0x02, 0x78, 0x08, 0x91, + 0xf9, 0x70, 0xbf, 0x18, 0x08, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, + 0x5b, 0x62, 0xd3, 0x00, 0x54, 0x4b, 0x62, 0xd3, 0x00, 0x52, 0x5a, + 0x62, 0xd3, 0x00, 0x54, 0x4a, 0x18, 0x78, 0xdf, 0xe0, 0x70, 0x3f, + 0x71, 0xc0, 0x7f, 0x70, 0xbf, 0x08, 0x91, 0xd1, 0x70, 0xbf, 0x18, + 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x52, 0x5b, 0x62, 0xd3, 0x00, 0x54, + 0x4b, 0x62, 0xd3, 0x00, 0x52, 0x5a, 0x62, 0xd3, 0x00, 0x54, 0x4a, + 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x62, 0xd0, 0x00, 0x55, 0x14, 0x00, + 0x50, 0x02, 0x78, 0x08, 0x9e, 0xe6, 0x39, 0x01, 0xb0, 0x04, 0x55, + 0x14, 0x01, 0x18, 0x78, 0xdf, 0xf3, 0x51, 0x14, 0x7f, 0x50, 0x02, + 0x78, 0x08, 0x9e, 0x16, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x98, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0xd8, 0xd9, 0xda, 0xdb, + 0xdf, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x70, + 0xbf, 0x62, 0xd0, 0x00, 0x62, 0xd3, 0x00, 0x57, 0x00, 0x56, 0x45, + 0x00, 0x79, 0xdf, 0xfb, 0x62, 0xd3, 0x00, 0x57, 0x01, 0x50, 0x03, + 0x54, 0x46, 0x79, 0xdf, 0xfc, 0x62, 0xd3, 0x00, 0x50, 0x32, 0x57, + 0x01, 0x54, 0x48, 0x79, 0xdf, 0xfc, 0x70, 0x3f, 0x71, 0xc0, 0x55, + 0x0d, 0x14, 0x55, 0x0e, 0x05, 0x55, 0x0f, 0x19, 0x55, 0x10, 0x01, + 0x55, 0x11, 0x03, 0x55, 0x12, 0x32, 0x55, 0x22, 0x04, 0x55, 0x1f, + 0x14, 0x43, 0x61, 0x0d, 0x57, 0x00, 0x50, 0x02, 0x90, 0xd2, 0x50, + 0x04, 0xff, 0x98, 0x29, 0x00, 0x60, 0xa9, 0x62, 0xa0, 0x08, 0x43, + 0xa2, 0x04, 0x62, 0xa3, 0x70, 0x43, 0x7a, 0x01, 0x43, 0xaa, 0x02, + 0x43, 0xdf, 0x01, 0x50, 0x01, 0x57, 0x0d, 0x90, 0x1b, 0x90, 0x56, + 0x7f, 0x62, 0xd0, 0x00, 0x39, 0x09, 0xc0, 0x03, 0x50, 0x08, 0x53, + 0x22, 0xff, 0x6c, 0x29, 0x00, 0x60, 0xa9, 0x51, 0x21, 0x58, 0x20, + 0x90, 0x01, 0x7f, 0x62, 0xd0, 0x00, 0x21, 0x03, 0x53, 0x21, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x29, 0x80, 0x60, 0xa1, 0x5b, 0x78, 0x21, + 0x0f, 0x29, 0x08, 0x74, 0x53, 0x20, 0x12, 0x22, 0x02, 0x21, 0x5c, + 0x50, 0x00, 0x53, 0x1d, 0x53, 0x23, 0x29, 0x01, 0x79, 0xa0, 0x08, + 0x64, 0x6b, 0x1d, 0x6b, 0x23, 0x8f, 0xf5, 0x60, 0xb5, 0x51, 0x1d, + 0x60, 0xb4, 0x7f, 0x62, 0xd0, 0x00, 0x53, 0x1f, 0x7f, 0x50, 0x02, + 0x78, 0x08, 0x90, 0x4b, 0x90, 0x7d, 0x18, 0x78, 0xdf, 0xf8, 0x7f, + 0x41, 0xdf, 0xfe, 0x71, 0x10, 0x41, 0xd8, 0xfd, 0x70, 0xef, 0x41, + 0x61, 0xf3, 0x41, 0xa2, 0xfb, 0x41, 0xa0, 0xf7, 0x62, 0xa3, 0x00, + 0x62, 0xa9, 0x00, 0x41, 0xaa, 0xfd, 0x7f, 0x62, 0xd0, 0x00, 0x62, + 0xa3, 0x50, 0x51, 0x22, 0xfe, 0xf0, 0x29, 0x00, 0x60, 0xa9, 0x43, + 0x61, 0x0d, 0x57, 0x00, 0x50, 0x02, 0x90, 0x19, 0x43, 0xa3, 0x20, + 0x43, 0xa2, 0x04, 0x43, 0xa0, 0x08, 0x43, 0xaa, 0x02, 0x43, 0xdf, + 0x01, 0x7f, 0x64, 0x5c, 0xfc, 0xc6, 0x4b, 0x74, 0xfc, 0xc2, 0x7f, + 0x62, 0xd0, 0x00, 0x53, 0x1d, 0x10, 0x5b, 0x64, 0x64, 0x5c, 0x71, + 0x10, 0x5e, 0x01, 0x2a, 0x1d, 0x61, 0x01, 0x36, 0x1d, 0xff, 0x5e, + 0x00, 0x22, 0x1d, 0x61, 0x00, 0x36, 0x1d, 0xff, 0x18, 0xfe, 0xb2, + 0x5c, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, 0x62, + 0xd0, 0x00, 0x10, 0x73, 0x53, 0x1d, 0x71, 0x10, 0x5b, 0xfe, 0x9c, + 0x5c, 0x5e, 0x00, 0x22, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x18, 0x64, + 0x64, 0x5c, 0x71, 0x10, 0x5e, 0x01, 0x22, 0x1d, 0x61, 0x01, 0x36, + 0x1d, 0xff, 0x5e, 0x00, 0x2a, 0x1d, 0x61, 0x00, 0x70, 0xef, 0x7f, + 0x70, 0xbf, 0x62, 0xd0, 0x00, 0x53, 0x1e, 0x50, 0x00, 0x53, 0x1a, + 0x53, 0x1b, 0x43, 0xa0, 0x01, 0x51, 0x1f, 0x60, 0xfd, 0x41, 0xa3, + 0xdf, 0x51, 0x1e, 0x9f, 0x84, 0x9f, 0x8b, 0x58, 0x23, 0x55, 0x1c, + 0x00, 0x62, 0xa5, 0x00, 0x62, 0xa4, 0x00, 0x43, 0xb3, 0x01, 0x51, + 0x1c, 0xaf, 0xfd, 0x79, 0xdf, 0xee, 0x51, 0x1e, 0x9f, 0x69, 0x9f, + 0x9b, 0x43, 0xa3, 0x20, 0x41, 0xa0, 0xfe, 0x62, 0xfd, 0x00, 0x50, + 0xff, 0x4c, 0x1b, 0x14, 0x1b, 0x51, 0x20, 0x11, 0x08, 0xfe, 0x33, + 0x4c, 0x1a, 0x1c, 0x1a, 0xd0, 0x07, 0x55, 0x1a, 0x00, 0x55, 0x1b, + 0x00, 0x51, 0x1e, 0x64, 0x5c, 0x62, 0xd3, 0x00, 0x51, 0x1b, 0x54, + 0x5b, 0x51, 0x1a, 0x54, 0x5a, 0x70, 0x3f, 0x71, 0xc0, 0x7f, 0x50, + 0x02, 0x78, 0x08, 0x9f, 0x8d, 0x18, 0x78, 0xdf, 0xfa, 0x7f, 0x70, + 0xbf, 0x62, 0xd3, 0x00, 0x64, 0x5c, 0x52, 0x5b, 0x59, 0x5a, 0x70, + 0x3f, 0x71, 0xc0, 0x7f, 0x10, 0x7c, 0x05, 0x15, 0x7c, 0x04, 0xd7, + 0x20, 0x7c, 0x13, 0x53, 0x43, 0x00, 0x08, 0x62, 0xd0, 0x00, 0x55, + 0x24, 0x08, 0x55, 0x25, 0x04, 0x55, 0x26, 0x0c, 0x55, 0x28, 0x55, + 0x55, 0x29, 0x02, 0x10, 0x50, 0x00, 0x08, 0x50, 0x24, 0x08, 0x50, + 0x06, 0x08, 0x50, 0x12, 0x08, 0x7c, 0x06, 0x96, 0x38, 0xfc, 0x7c, + 0x06, 0x36, 0x7c, 0x06, 0x7c, 0x20, 0x71, 0x10, 0x41, 0x04, 0xfc, + 0x41, 0x05, 0xfc, 0x71, 0x01, 0x10, 0x70, 0xcf, 0x7c, 0x08, 0xcf, + 0x7c, 0x08, 0x2d, 0x20, 0x90, 0xc4, 0x80, 0xbf, 0x7c, 0x14, 0xa7, + 0x62, 0xe3, 0x38, 0x92, 0xd0, 0x62, 0xd0, 0x00, 0x3c, 0x6f, 0x01, + 0xb0, 0x09, 0x50, 0x00, 0x08, 0x7c, 0x16, 0x49, 0x38, 0xff, 0x62, + 0xe3, 0x38, 0x10, 0x7c, 0x08, 0x93, 0x20, 0x39, 0x00, 0xa0, 0x6e, + 0x62, 0xd0, 0x00, 0x51, 0x63, 0x11, 0xd0, 0x51, 0x62, 0x19, 0x07, + 0xd0, 0x12, 0x7c, 0x13, 0x65, 0x39, 0xe1, 0xa0, 0x16, 0x62, 0xd0, + 0x00, 0x76, 0x63, 0x0e, 0x62, 0x00, 0x80, 0x0c, 0x62, 0xd0, 0x00, + 0x55, 0x63, 0x00, 0x55, 0x62, 0x00, 0x90, 0x75, 0x62, 0xd0, 0x00, + 0x3c, 0x72, 0xf0, 0xd0, 0x06, 0x62, 0xd0, 0x00, 0x76, 0x72, 0x62, + 0xd0, 0x00, 0x51, 0x72, 0x62, 0xd0, 0x00, 0x3a, 0x29, 0xb0, 0x56, + 0x97, 0xde, 0x62, 0xd0, 0x00, 0x53, 0x73, 0x3c, 0x73, 0xe1, 0xa0, + 0x18, 0x62, 0xd0, 0x00, 0x55, 0x75, 0x00, 0x7c, 0x13, 0xa0, 0x62, + 0xd0, 0x00, 0x55, 0x71, 0x01, 0x62, 0xd0, 0x00, 0x55, 0x6e, 0x03, + 0x80, 0x33, 0x62, 0xd0, 0x00, 0x55, 0x72, 0x00, 0x80, 0x2b, 0x62, + 0xd0, 0x00, 0x55, 0x63, 0x00, 0x55, 0x62, 0x00, 0x62, 0xd0, 0x00, + 0x3c, 0x71, 0x01, 0xb0, 0x1a, 0x62, 0xd0, 0x00, 0x7a, 0x6e, 0x3c, + 0x6e, 0x00, 0xb0, 0x10, 0x7c, 0x14, 0x28, 0x62, 0xd0, 0x00, 0x55, + 0x71, 0x00, 0x62, 0xd0, 0x00, 0x55, 0x72, 0x00, 0x7c, 0x15, 0x24, + 0x8f, 0x41, 0x8f, 0xff, 0x10, 0x4f, 0x38, 0x16, 0x10, 0x62, 0xd0, + 0x00, 0x51, 0x68, 0x7c, 0x09, 0x8e, 0x20, 0x10, 0x50, 0x00, 0x7c, + 0x0a, 0x46, 0x20, 0x56, 0x0d, 0x00, 0x80, 0xae, 0x56, 0x00, 0x00, + 0x80, 0xa2, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, + 0x00, 0x06, 0x3f, 0x68, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, + 0x3e, 0x3f, 0x10, 0x7c, 0x09, 0x8e, 0x20, 0x10, 0x52, 0x00, 0x7c, + 0x0a, 0x46, 0x20, 0x10, 0x7c, 0x06, 0x6c, 0x62, 0xd0, 0x00, 0x20, + 0x39, 0x00, 0xbf, 0xee, 0x55, 0x40, 0x03, 0x5a, 0x3f, 0x06, 0x3f, + 0x01, 0x52, 0x00, 0x53, 0x3d, 0x50, 0x00, 0x08, 0x51, 0x3d, 0x08, + 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x17, 0x94, 0x38, 0xfc, + 0x51, 0x38, 0x53, 0x3d, 0x51, 0x37, 0x53, 0x3e, 0x51, 0x3d, 0x02, + 0x3f, 0x53, 0x3f, 0x51, 0x3e, 0x0a, 0x40, 0x53, 0x40, 0x52, 0x0d, + 0x53, 0x3d, 0x55, 0x3e, 0x00, 0x65, 0x3d, 0x6b, 0x3e, 0x51, 0x3d, + 0x02, 0x3f, 0x53, 0x3f, 0x51, 0x3e, 0x0a, 0x40, 0x53, 0x40, 0x52, + 0x00, 0x53, 0x3d, 0x55, 0x3e, 0x00, 0x65, 0x3d, 0x6b, 0x3e, 0x06, + 0x3d, 0x5a, 0x0e, 0x3e, 0x00, 0x51, 0x3e, 0x60, 0xd4, 0x3e, 0x3d, + 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x51, 0x40, 0x60, 0xd5, 0x51, + 0x3e, 0x3f, 0x3f, 0x51, 0x3d, 0x3f, 0x3f, 0x77, 0x00, 0x3d, 0x00, + 0x02, 0xcf, 0x5b, 0x77, 0x0d, 0x3d, 0x0d, 0x03, 0xcf, 0x4f, 0x56, + 0x00, 0x00, 0x81, 0x3d, 0x62, 0xd0, 0x00, 0x55, 0x40, 0x03, 0x5a, + 0x3f, 0x06, 0x3f, 0x01, 0x52, 0x00, 0x53, 0x3d, 0x50, 0x00, 0x08, + 0x51, 0x3d, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x17, + 0x94, 0x38, 0xfc, 0x51, 0x38, 0x53, 0x3d, 0x51, 0x37, 0x53, 0x3e, + 0x51, 0x3d, 0x02, 0x3f, 0x53, 0x3f, 0x51, 0x3e, 0x0a, 0x40, 0x60, + 0xd4, 0x3e, 0x3f, 0x54, 0x0e, 0x3e, 0x3f, 0x54, 0x0f, 0x5a, 0x3f, + 0x06, 0x3f, 0x03, 0x52, 0x00, 0x53, 0x3d, 0x50, 0x00, 0x08, 0x51, + 0x3d, 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x17, 0x94, + 0x38, 0xfc, 0x51, 0x38, 0x53, 0x3d, 0x51, 0x37, 0x53, 0x3e, 0x51, + 0x3d, 0x02, 0x3f, 0x53, 0x3f, 0x51, 0x3e, 0x0a, 0x40, 0x60, 0xd4, + 0x3e, 0x3f, 0x54, 0x10, 0x3e, 0x3f, 0x54, 0x11, 0x5a, 0x3f, 0x06, + 0x3f, 0x05, 0x52, 0x00, 0x53, 0x3d, 0x50, 0x00, 0x08, 0x51, 0x3d, + 0x08, 0x50, 0x00, 0x08, 0x50, 0x06, 0x08, 0x7c, 0x17, 0x94, 0x38, + 0xfc, 0x51, 0x38, 0x53, 0x3d, 0x51, 0x37, 0x53, 0x3e, 0x51, 0x3d, + 0x02, 0x3f, 0x53, 0x3f, 0x51, 0x3e, 0x0a, 0x40, 0x60, 0xd4, 0x3e, + 0x3f, 0x54, 0x12, 0x3e, 0x3f, 0x54, 0x13, 0x50, 0x03, 0x08, 0x5a, + 0x3f, 0x06, 0x3f, 0x0e, 0x08, 0x51, 0x3f, 0x08, 0x7c, 0x15, 0x6b, + 0x38, 0xfd, 0x62, 0xd0, 0x00, 0x51, 0x3f, 0x54, 0x15, 0x51, 0x40, + 0x54, 0x14, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, + 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x53, 0x3d, 0x51, 0x40, 0x09, + 0x00, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x3d, 0x52, 0x15, 0x3f, 0x3d, + 0x06, 0x3f, 0x4a, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd5, 0x52, + 0x14, 0x3f, 0x3f, 0x52, 0x15, 0x3f, 0x3f, 0x52, 0x00, 0x53, 0x3f, + 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x52, + 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd5, 0x52, 0x14, 0x3f, + 0x3d, 0x52, 0x15, 0x3f, 0x3d, 0x51, 0x3f, 0x01, 0x56, 0x53, 0x3d, + 0x51, 0x40, 0x09, 0x00, 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x3d, 0x52, + 0x15, 0x3f, 0x3d, 0x06, 0x3f, 0x5e, 0x0e, 0x40, 0x00, 0x51, 0x40, + 0x60, 0xd5, 0x52, 0x14, 0x3f, 0x3f, 0x52, 0x15, 0x3f, 0x3f, 0x77, + 0x00, 0x3d, 0x00, 0x02, 0xce, 0xc0, 0x38, 0xea, 0x20, 0x7f, 0x10, + 0x4f, 0x38, 0x06, 0x62, 0xd0, 0x00, 0x55, 0x70, 0x00, 0x10, 0x62, + 0xd0, 0x00, 0x51, 0x68, 0x7c, 0x09, 0x8e, 0x20, 0x10, 0x50, 0x00, + 0x7c, 0x0a, 0x46, 0x20, 0x56, 0x00, 0x00, 0x80, 0x31, 0x62, 0xd0, + 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x06, 0x3f, 0x68, + 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x10, 0x7c, + 0x09, 0x8e, 0x20, 0x10, 0x52, 0x00, 0x7c, 0x0a, 0x46, 0x20, 0x10, + 0x7c, 0x06, 0x6c, 0x62, 0xd0, 0x00, 0x20, 0x39, 0x00, 0xbf, 0xee, + 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcf, 0xcc, 0x56, 0x00, 0x00, 0x83, + 0xa2, 0x62, 0xd0, 0x00, 0x3c, 0x6f, 0x02, 0xa1, 0x8c, 0x62, 0xd0, + 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, + 0x40, 0x51, 0x3f, 0x01, 0x4a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, + 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, + 0x3f, 0x5a, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, + 0x53, 0x40, 0x3e, 0x3f, 0x53, 0x3f, 0x51, 0x3d, 0x12, 0x3f, 0x51, + 0x3e, 0x1a, 0x40, 0xd0, 0x3f, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, + 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, + 0x4a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, + 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, 0x5a, 0x0e, 0x40, + 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, 0x40, 0x3e, 0x3f, + 0x12, 0x3d, 0x54, 0x03, 0x51, 0x40, 0x1a, 0x3e, 0x54, 0x02, 0x80, + 0x3d, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, + 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x53, 0x3d, 0x51, + 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, + 0x53, 0x3d, 0x06, 0x3f, 0x4a, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, + 0xd4, 0x3e, 0x3f, 0x53, 0x40, 0x3e, 0x3f, 0x12, 0x3d, 0x54, 0x03, + 0x51, 0x40, 0x1a, 0x3e, 0x54, 0x02, 0x50, 0x90, 0x13, 0x03, 0x50, + 0x01, 0x1b, 0x02, 0xc0, 0xc3, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, + 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, + 0x5e, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, + 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, 0x5a, 0x0e, 0x40, + 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, 0x40, 0x3e, 0x3f, + 0x53, 0x3f, 0x51, 0x3d, 0x12, 0x3f, 0x51, 0x3e, 0x1a, 0x40, 0xd0, + 0x3f, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, + 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x5e, 0x53, 0x3d, 0x51, + 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, + 0x53, 0x3d, 0x06, 0x3f, 0x5a, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, + 0xd4, 0x3e, 0x3f, 0x53, 0x40, 0x3e, 0x3f, 0x12, 0x3d, 0x54, 0x05, + 0x51, 0x40, 0x1a, 0x3e, 0x54, 0x04, 0x80, 0x3d, 0x62, 0xd0, 0x00, + 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, + 0x51, 0x3f, 0x01, 0x5a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, + 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, + 0x5e, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, + 0x40, 0x3e, 0x3f, 0x12, 0x3d, 0x54, 0x05, 0x51, 0x40, 0x1a, 0x3e, + 0x54, 0x04, 0x50, 0x90, 0x13, 0x05, 0x50, 0x01, 0x1b, 0x04, 0xd0, + 0x08, 0x62, 0xd0, 0x00, 0x76, 0x70, 0x82, 0x0d, 0x62, 0xd0, 0x00, + 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, + 0x51, 0x3f, 0x01, 0x56, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, + 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, + 0x52, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd5, 0x51, 0x3e, 0x3f, + 0x3f, 0x51, 0x3d, 0x3f, 0x3f, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, + 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x5e, 0x53, 0x3d, + 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, + 0x3d, 0x53, 0x3d, 0x06, 0x3f, 0x56, 0x0e, 0x40, 0x00, 0x51, 0x40, + 0x60, 0xd5, 0x51, 0x3e, 0x3f, 0x3f, 0x51, 0x3d, 0x3f, 0x3f, 0x52, + 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, + 0x3f, 0x01, 0x5a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, + 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, 0x5e, + 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd5, 0x51, 0x3e, 0x3f, 0x3f, + 0x51, 0x3d, 0x3f, 0x3f, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, + 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x53, 0x3d, 0x51, + 0x40, 0x09, 0x00, 0x53, 0x3e, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3c, + 0x3e, 0x3d, 0x16, 0x3d, 0x02, 0x53, 0x3b, 0x08, 0x51, 0x3c, 0x53, + 0x3a, 0x18, 0x53, 0x39, 0x65, 0x39, 0x6b, 0x3a, 0x06, 0x3f, 0x56, + 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, 0x40, + 0x3e, 0x3f, 0x53, 0x3f, 0x51, 0x39, 0x04, 0x3f, 0x51, 0x3a, 0x0c, + 0x40, 0x51, 0x3b, 0x04, 0x3f, 0x51, 0x3c, 0x0c, 0x40, 0x70, 0xfb, + 0x6e, 0x40, 0x6e, 0x3f, 0x70, 0xfb, 0x6e, 0x40, 0x6e, 0x3f, 0x51, + 0x3e, 0x60, 0xd5, 0x51, 0x40, 0x3f, 0x3d, 0x51, 0x3f, 0x3f, 0x3d, + 0x10, 0x52, 0x00, 0x7c, 0x06, 0xc9, 0x20, 0x62, 0xd0, 0x00, 0x52, + 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, + 0x3f, 0x01, 0x5a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, + 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, 0x4a, + 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, 0x40, + 0x3e, 0x3f, 0x53, 0x3f, 0x51, 0x3d, 0x12, 0x3f, 0x51, 0x3e, 0x1a, + 0x40, 0xd0, 0x28, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, + 0x40, 0x00, 0x06, 0x3f, 0x6c, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, + 0xd4, 0x3e, 0x3f, 0x7a, 0x3f, 0x53, 0x3e, 0x06, 0x3e, 0x01, 0x51, + 0x40, 0x60, 0xd5, 0x51, 0x3e, 0x3f, 0x3f, 0x80, 0x19, 0x62, 0xd0, + 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x06, 0x3f, 0x6c, + 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd5, 0x50, 0x00, 0x3f, 0x3f, + 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x06, + 0x3f, 0x6c, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, + 0x53, 0x40, 0x50, 0x05, 0x3a, 0x40, 0xd0, 0x6b, 0x62, 0xd0, 0x00, + 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, + 0x51, 0x3f, 0x01, 0x4a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x53, + 0x3e, 0x06, 0x3f, 0x5a, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, + 0x3e, 0x3f, 0x53, 0x40, 0x3e, 0x3f, 0x53, 0x3f, 0x51, 0x3e, 0x60, + 0xd4, 0x3e, 0x3d, 0x53, 0x3c, 0x3e, 0x3d, 0x16, 0x3d, 0x02, 0x02, + 0x3f, 0x53, 0x3f, 0x51, 0x3c, 0x0a, 0x40, 0x53, 0x40, 0x70, 0xfb, + 0x6e, 0x40, 0x6e, 0x3f, 0x51, 0x3e, 0x60, 0xd5, 0x51, 0x40, 0x3f, + 0x3d, 0x51, 0x3f, 0x3f, 0x3d, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, + 0x00, 0x06, 0x3f, 0x6c, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd5, + 0x50, 0x00, 0x3f, 0x3f, 0x77, 0x00, 0x3d, 0x00, 0x02, 0xcc, 0x5b, + 0x62, 0xd0, 0x00, 0x3c, 0x6f, 0x02, 0xb1, 0x08, 0x56, 0x00, 0x00, + 0x80, 0xfe, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, + 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x5a, 0x53, 0x3d, + 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, + 0x3d, 0x53, 0x3d, 0x06, 0x3f, 0x2e, 0x0e, 0x40, 0x00, 0x51, 0x40, + 0x60, 0xd5, 0x51, 0x3e, 0x3f, 0x3f, 0x51, 0x3d, 0x3f, 0x3f, 0x52, + 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, + 0x3f, 0x01, 0x4a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, + 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x51, 0x3f, 0x01, + 0x5a, 0x53, 0x3b, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3b, + 0x53, 0x3c, 0x3e, 0x3b, 0x53, 0x3b, 0x51, 0x3d, 0x12, 0x3b, 0x51, + 0x3e, 0x1a, 0x3c, 0xd0, 0x3f, 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, + 0x3d, 0x55, 0x3e, 0x00, 0x65, 0x3d, 0x6b, 0x3e, 0x51, 0x3d, 0x01, + 0x4a, 0x53, 0x3b, 0x51, 0x3e, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3b, + 0x53, 0x3c, 0x3e, 0x3b, 0x53, 0x3b, 0x06, 0x3d, 0x5a, 0x0e, 0x3e, + 0x00, 0x51, 0x3e, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, + 0x12, 0x3b, 0x54, 0x03, 0x51, 0x3e, 0x1a, 0x3c, 0x54, 0x02, 0x80, + 0x07, 0x56, 0x03, 0x00, 0x56, 0x02, 0x00, 0x62, 0xd0, 0x00, 0x06, + 0x3f, 0x2a, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd5, 0x52, 0x02, + 0x3f, 0x3f, 0x52, 0x03, 0x3f, 0x3f, 0x52, 0x00, 0x53, 0x3f, 0x55, + 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x4a, 0x53, + 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, + 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, 0x32, 0x0e, 0x40, 0x00, 0x51, + 0x40, 0x60, 0xd5, 0x51, 0x3e, 0x3f, 0x3f, 0x51, 0x3d, 0x3f, 0x3f, + 0x77, 0x00, 0x3d, 0x00, 0x02, 0xce, 0xff, 0x62, 0xd0, 0x00, 0x3c, + 0x6f, 0x02, 0xa0, 0x1a, 0x62, 0xd0, 0x00, 0x3c, 0x70, 0x00, 0xa0, + 0x12, 0x50, 0x75, 0x08, 0x50, 0x30, 0x08, 0x90, 0x0d, 0x38, 0xfe, + 0x98, 0xbf, 0x10, 0x7c, 0x08, 0xad, 0x20, 0x38, 0xfa, 0x20, 0x7f, + 0x10, 0x4f, 0x80, 0x02, 0x40, 0x62, 0xd0, 0x00, 0x52, 0xfc, 0x53, + 0x3f, 0x52, 0xfb, 0x53, 0x40, 0x51, 0x3f, 0x11, 0x01, 0x54, 0xfc, + 0x51, 0x40, 0x19, 0x00, 0x54, 0xfb, 0x3c, 0x40, 0x00, 0xbf, 0xe4, + 0x3c, 0x3f, 0x00, 0xbf, 0xdf, 0x20, 0x7f, 0x10, 0x7c, 0x05, 0x15, + 0x7c, 0x04, 0xd7, 0x20, 0x7f, 0x10, 0x7c, 0x05, 0x11, 0x7c, 0x04, + 0xd3, 0x20, 0x7f, 0x62, 0xd0, 0x00, 0x50, 0x28, 0x12, 0x4f, 0x50, + 0x00, 0x1a, 0x4e, 0xd0, 0x15, 0x62, 0xd0, 0x00, 0x50, 0x28, 0x12, + 0x51, 0x50, 0x00, 0x1a, 0x50, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, + 0xe1, 0x80, 0x1a, 0x62, 0xd0, 0x00, 0x51, 0x51, 0x12, 0x4f, 0x51, + 0x50, 0x1a, 0x4e, 0xd0, 0x08, 0x62, 0xd0, 0x00, 0x50, 0x00, 0x80, + 0x06, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x7f, 0x10, 0x4f, 0x38, 0x02, + 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x51, 0x73, 0x01, 0x01, 0x62, 0xd0, + 0x00, 0x53, 0x24, 0x71, 0x01, 0x62, 0xd0, 0x00, 0x3c, 0x71, 0x00, + 0xb0, 0x69, 0x62, 0xe3, 0x38, 0x10, 0x7c, 0x06, 0x6c, 0x62, 0xd0, + 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, + 0x7c, 0x06, 0x6c, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x40, 0x47, 0x40, + 0x20, 0xa0, 0x03, 0x80, 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, + 0x9f, 0x43, 0x38, 0xfe, 0x77, 0x00, 0x3d, 0x00, 0xc8, 0xcf, 0xdf, + 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x06, 0x6c, 0x62, 0xd0, + 0x00, 0x20, 0x53, 0x40, 0x47, 0x40, 0x20, 0xb0, 0x03, 0x80, 0x12, + 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9f, 0x1c, 0x38, 0xfe, 0x77, + 0x00, 0x3d, 0x00, 0x1e, 0xcf, 0xdf, 0x62, 0xd0, 0x00, 0x51, 0x24, + 0x29, 0x08, 0x53, 0x24, 0x43, 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, + 0x10, 0x4f, 0x38, 0x02, 0x70, 0xfe, 0x62, 0xd0, 0x00, 0x51, 0x73, + 0x01, 0x09, 0x62, 0xd0, 0x00, 0x53, 0x24, 0x71, 0x01, 0x62, 0xd0, + 0x00, 0x3c, 0x71, 0x01, 0xb0, 0x60, 0x62, 0xe3, 0x38, 0x10, 0x7c, + 0x06, 0x6c, 0x62, 0xd0, 0x00, 0x20, 0x41, 0x00, 0xf7, 0x56, 0x00, + 0x00, 0x80, 0x1e, 0x10, 0x7c, 0x06, 0x6c, 0x62, 0xd0, 0x00, 0x20, + 0x53, 0x40, 0x47, 0x40, 0x20, 0xa0, 0x03, 0x80, 0x12, 0x50, 0x00, + 0x08, 0x50, 0x14, 0x08, 0x9e, 0xbb, 0x38, 0xfe, 0x77, 0x00, 0x3d, + 0x00, 0xc8, 0xcf, 0xdf, 0x56, 0x00, 0x00, 0x80, 0x1e, 0x10, 0x7c, + 0x06, 0x6c, 0x62, 0xd0, 0x00, 0x20, 0x53, 0x40, 0x47, 0x40, 0x20, + 0xb0, 0x03, 0x80, 0x12, 0x50, 0x00, 0x08, 0x50, 0x14, 0x08, 0x9e, + 0x94, 0x38, 0xfe, 0x77, 0x00, 0x3d, 0x00, 0x1e, 0xcf, 0xdf, 0x43, + 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x01, 0x62, + 0xd0, 0x00, 0x51, 0x24, 0x54, 0x00, 0x52, 0x00, 0x21, 0x0f, 0x39, + 0x01, 0xb0, 0x18, 0x62, 0xd0, 0x00, 0x55, 0x75, 0x00, 0x62, 0xd0, + 0x00, 0x55, 0x67, 0x00, 0x55, 0x66, 0x00, 0x62, 0xd0, 0x00, 0x55, + 0x24, 0x00, 0x80, 0x50, 0x52, 0x00, 0x21, 0x0f, 0x39, 0x02, 0xb0, + 0x1e, 0x62, 0xd0, 0x00, 0x55, 0x75, 0x01, 0x62, 0xd0, 0x00, 0x55, + 0x74, 0x00, 0x62, 0xd0, 0x00, 0x55, 0x67, 0x08, 0x55, 0x66, 0x08, + 0x62, 0xd0, 0x00, 0x55, 0x24, 0x00, 0x80, 0x2b, 0x52, 0x00, 0x21, + 0xf0, 0x39, 0x40, 0xb0, 0x0f, 0x62, 0xd0, 0x00, 0x55, 0x6f, 0x02, + 0x62, 0xd0, 0x00, 0x55, 0x24, 0x00, 0x80, 0x15, 0x52, 0x00, 0x21, + 0xf0, 0x39, 0x50, 0xb0, 0x0d, 0x62, 0xd0, 0x00, 0x55, 0x6f, 0x01, + 0x62, 0xd0, 0x00, 0x55, 0x24, 0x00, 0x38, 0xff, 0x20, 0x7f, 0x62, + 0xd0, 0x00, 0x3c, 0x75, 0x00, 0xa0, 0x13, 0x9e, 0x25, 0x62, 0xd0, + 0x00, 0x3c, 0x74, 0x00, 0xb0, 0x35, 0x55, 0x74, 0x01, 0x7c, 0x0b, + 0xe1, 0x80, 0x2d, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x66, 0xd0, + 0x08, 0x10, 0x7c, 0x05, 0x15, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x05, + 0x11, 0x20, 0x62, 0xd0, 0x00, 0x50, 0x01, 0x3a, 0x67, 0xd0, 0x08, + 0x10, 0x7c, 0x04, 0xd7, 0x20, 0x80, 0x06, 0x10, 0x7c, 0x04, 0xd3, + 0x20, 0x98, 0x8d, 0x7f, 0x10, 0x4f, 0x38, 0x03, 0x56, 0x02, 0x00, + 0x56, 0x01, 0x00, 0x56, 0x00, 0x00, 0x80, 0x51, 0x62, 0xd0, 0x00, + 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, + 0x52, 0xfc, 0x04, 0x3f, 0x52, 0xfb, 0x0c, 0x40, 0x51, 0x40, 0x60, + 0xd4, 0x3e, 0x3f, 0x53, 0x40, 0x3e, 0x3f, 0x53, 0x3f, 0x52, 0x02, + 0x12, 0x3f, 0x52, 0x01, 0x1a, 0x40, 0xd0, 0x23, 0x62, 0xd0, 0x00, + 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, + 0x52, 0xfc, 0x04, 0x3f, 0x52, 0xfb, 0x0c, 0x40, 0x51, 0x40, 0x60, + 0xd4, 0x3e, 0x3f, 0x54, 0x01, 0x3e, 0x3f, 0x54, 0x02, 0x77, 0x00, + 0x52, 0x00, 0x3b, 0xfa, 0xcf, 0xab, 0x62, 0xd0, 0x00, 0x52, 0x02, + 0x53, 0x3f, 0x52, 0x01, 0x53, 0x40, 0x38, 0xfd, 0x20, 0x7f, 0x10, + 0x4f, 0x38, 0x02, 0x71, 0x10, 0x41, 0x01, 0xf7, 0x43, 0x00, 0x08, + 0x70, 0xcf, 0x43, 0x00, 0x08, 0x50, 0x00, 0x08, 0x50, 0x64, 0x08, + 0x9d, 0x33, 0x71, 0x10, 0x41, 0x01, 0xf7, 0x41, 0x00, 0xf7, 0x70, + 0xcf, 0x43, 0x00, 0x08, 0x50, 0x00, 0x08, 0x50, 0x64, 0x08, 0x9d, + 0x1e, 0x38, 0xfc, 0x5d, 0x00, 0x62, 0xd0, 0x00, 0x53, 0x40, 0x26, + 0x40, 0x08, 0x3c, 0x40, 0x08, 0xb0, 0x09, 0x56, 0x01, 0x00, 0x56, + 0x00, 0x00, 0x80, 0x07, 0x56, 0x01, 0x01, 0x56, 0x00, 0x00, 0x52, + 0x01, 0x62, 0xd0, 0x00, 0x53, 0x6f, 0x71, 0x10, 0x43, 0x00, 0x08, + 0x41, 0x01, 0xf7, 0x70, 0xcf, 0x3c, 0x6f, 0x00, 0xb0, 0x04, 0x43, + 0x00, 0x08, 0x38, 0xfe, 0x20, 0x7f, 0x10, 0x4f, 0x38, 0x01, 0x62, + 0xe3, 0x38, 0x10, 0x50, 0x02, 0x7c, 0x03, 0x9c, 0x20, 0x10, 0x50, + 0xff, 0x7c, 0x03, 0x9c, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x9c, + 0x20, 0x10, 0x50, 0x04, 0x08, 0x50, 0x00, 0x08, 0x50, 0x5a, 0x08, + 0x7c, 0x04, 0x8d, 0x38, 0xfd, 0x20, 0x56, 0x00, 0x00, 0x80, 0xda, + 0x62, 0xd0, 0x00, 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, + 0x3f, 0x6b, 0x40, 0x51, 0x3f, 0x01, 0x4a, 0x53, 0x3d, 0x51, 0x40, + 0x09, 0x00, 0x60, 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, + 0x3d, 0x06, 0x3f, 0x5a, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, + 0x3e, 0x3f, 0x53, 0x40, 0x3e, 0x3f, 0x53, 0x3f, 0x51, 0x3d, 0x12, + 0x3f, 0x51, 0x3e, 0x1a, 0x40, 0xd0, 0x8c, 0x62, 0xd0, 0x00, 0x52, + 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, 0x51, + 0x3f, 0x01, 0x4a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, 0xd4, + 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, 0x5a, + 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, 0x40, + 0x3e, 0x3f, 0x53, 0x3f, 0x51, 0x3d, 0x14, 0x3f, 0x51, 0x3e, 0x1c, + 0x40, 0x51, 0x40, 0x10, 0x7c, 0x03, 0x9c, 0x20, 0x62, 0xd0, 0x00, + 0x52, 0x00, 0x53, 0x3f, 0x55, 0x40, 0x00, 0x65, 0x3f, 0x6b, 0x40, + 0x51, 0x3f, 0x01, 0x4a, 0x53, 0x3d, 0x51, 0x40, 0x09, 0x00, 0x60, + 0xd4, 0x3e, 0x3d, 0x53, 0x3e, 0x3e, 0x3d, 0x53, 0x3d, 0x06, 0x3f, + 0x5a, 0x0e, 0x40, 0x00, 0x51, 0x40, 0x60, 0xd4, 0x3e, 0x3f, 0x53, + 0x40, 0x3e, 0x3f, 0x53, 0x3f, 0x51, 0x3d, 0x14, 0x3f, 0x51, 0x3e, + 0x1c, 0x40, 0x26, 0x40, 0x00, 0x51, 0x3f, 0x10, 0x7c, 0x03, 0x9c, + 0x20, 0x80, 0x0f, 0x10, 0x50, 0x00, 0x7c, 0x03, 0x9c, 0x20, 0x10, + 0x50, 0x00, 0x7c, 0x03, 0x9c, 0x20, 0x77, 0x00, 0x3d, 0x00, 0x02, + 0xcf, 0x23, 0x10, 0x50, 0x00, 0x7c, 0x03, 0x9c, 0x20, 0x10, 0x50, + 0x01, 0x7c, 0x03, 0x9c, 0x20, 0x10, 0x50, 0x00, 0x7c, 0x03, 0x9c, + 0x20, 0x10, 0x50, 0x01, 0x7c, 0x03, 0x9c, 0x20, 0x10, 0x50, 0xff, + 0x7c, 0x03, 0x9c, 0x20, 0x10, 0x50, 0xff, 0x7c, 0x03, 0x9c, 0x7c, + 0x04, 0x84, 0x20, 0x50, 0x13, 0x08, 0x50, 0x88, 0x08, 0x9b, 0x9e, + 0x38, 0xfe, 0x38, 0xff, 0x20, 0x7f, 0x7f, 0x10, 0x4f, 0x5d, 0xd0, + 0x08, 0x62, 0xd0, 0x00, 0x50, 0x00, 0x53, 0x38, 0x53, 0x37, 0x55, + 0x36, 0x10, 0x6f, 0xf9, 0x6f, 0xfa, 0xd0, 0x09, 0x52, 0xfc, 0x04, + 0x38, 0x52, 0xfb, 0x0c, 0x37, 0x66, 0xfc, 0x6c, 0xfb, 0x7a, 0x36, + 0xbf, 0xeb, 0x18, 0x60, 0xd0, 0x20, 0x70, 0x3f, 0x71, 0xc0, 0x7f, + 0x00, 0x24, 0x00, 0x12, 0x00, 0x52, 0x00, 0x08, 0x00, 0x5e, 0x00, + 0x07, 0x00, 0x65, 0x05, 0x01, 0x08, 0x08, 0x78, 0x64, 0x00, 0x6a, + 0x00, 0x04, 0x00, 0x6e, 0x01, 0x03, 0x00, 0x6f, 0x00, 0x05, 0x00, + 0x74, 0x02, 0x01, 0x01, 0xff, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 +}; diff --git a/drivers/input/keyboard/cypressbln/u1-cypress-gpio.h b/drivers/input/keyboard/cypressbln/u1-cypress-gpio.h new file mode 100644 index 0000000..36296e1 --- /dev/null +++ b/drivers/input/keyboard/cypressbln/u1-cypress-gpio.h @@ -0,0 +1,28 @@ +#ifndef __U1_CYPRESS_GPIO_H__ +#define __U1_CYPRESS_GPIO_H__ + +extern unsigned int system_rev; + +#if defined (CONFIG_MACH_U1_REV00PRE) || defined (CONFIG_MACH_U1_REV01PRE) \ + || defined (CONFIG_MACH_U1_REV00) +#define _3_GPIO_TOUCH_EN S5PV310_GPE3(3) +#define _3_GPIO_TOUCH_INT S5PV310_GPE3(7) +#define _3_GPIO_TOUCH_INT_AF S3C_GPIO_SFN(0xf) +#define _3_TOUCH_SDA_28V S5PV310_GPE4(0) +#define _3_TOUCH_SCL_28V S5PV310_GPE4(1) + +#define IRQ_TOUCH_INT gpio_to_irq(_3_GPIO_TOUCH_INT) + +#else + +#define _3_GPIO_TOUCH_EN -1 +#define _3_GPIO_TOUCH_INT GPIO_3_TOUCH_INT +#define _3_GPIO_TOUCH_INT_AF S3C_GPIO_SFN(0xf) +#define _3_TOUCH_SDA_28V GPIO_3_TOUCH_SDA +#define _3_TOUCH_SCL_28V GPIO_3_TOUCH_SCL + +#define IRQ_TOUCH_INT gpio_to_irq(_3_GPIO_TOUCH_INT) +#endif + + +#endif diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 0a619c5..c0531c2 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1811,6 +1811,14 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); + /* Verify that a device really has an endpoint */ + if (intf->altsetting[0].desc.bNumEndpoints < 1) { + dev_err(&intf->dev, + "interface has %d endpoints, but must have minimum 1\n", + intf->altsetting[0].desc.bNumEndpoints); + err = -EINVAL; + goto fail3; + } endpoint = &intf->altsetting[0].endpoint[0].desc; /* Go set up our URB, which is called when the tablet receives @@ -1853,7 +1861,8 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) if (i == ARRAY_SIZE(speeds)) { dev_info(&intf->dev, "Aiptek tried all speeds, no sane response\n"); - goto fail2; + err = -EINVAL; + goto fail3; } /* Associate this driver's struct with the usb interface. diff --git a/drivers/input/touchscreen/mxt224_u1.c b/drivers/input/touchscreen/mxt224_u1.c index 5a243fb..8b81017 100644 --- a/drivers/input/touchscreen/mxt224_u1.c +++ b/drivers/input/touchscreen/mxt224_u1.c @@ -1210,6 +1210,10 @@ static int __devinit mxt224_init_touch_driver(struct mxt224_data *data) return ret; } +#if defined(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN) && defined(CONFIG_TOUCHKEY_BLN) +void (*mxt224_touch_cb)(void) = NULL; +#endif + static void report_input_data(struct mxt224_data *data) { int i; @@ -1336,6 +1340,9 @@ static void report_input_data(struct mxt224_data *data) level); copy_data->lock_status = 1; } + #if defined(CONFIG_KEYBOARD_CYPRESS_TOUCH_BLN) && defined(CONFIG_TOUCHKEY_BLN) + if(mxt224_touch_cb!=NULL) (*mxt224_touch_cb)(); + #endif } } diff --git a/drivers/media/video/s5c73m3.c b/drivers/media/video/s5c73m3.c index bd08605..3d24612 100644 --- a/drivers/media/video/s5c73m3.c +++ b/drivers/media/video/s5c73m3.c @@ -579,6 +579,7 @@ static int s5c73m3_get_sensor_fw_binary(struct v4l2_subdev *sd) u16 read_val; int i, rxSize; int err = 0; + struct file *fp = NULL; mm_segment_t old_fs; long ret = 0; char fw_path[25] = {0,}; @@ -729,6 +730,17 @@ retry: set_fs(KERNEL_DS); if (IntOriginalCRC == DataCRC) { + fp = filp_open(fw_path, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (IS_ERR(fp) || fp == NULL) { + cam_err("failed to open %s, err %ld\n", + fw_path, PTR_ERR(fp)); + err = -EINVAL; + goto out; + } + + ret = vfs_write(fp, (char __user *)data_memory, + state->sensor_size, &fp->f_pos); + if (camfw_info[S5C73M3_SD_CARD].opened == 0) { memcpy(state->phone_fw, state->sensor_fw, @@ -749,6 +761,9 @@ retry: } } + if (fp != NULL) + filp_close(fp, current->files); + out: set_fs(old_fs); return err; @@ -1049,14 +1064,17 @@ request_fw: state->fw_index = S5C73M3_IN_DATA; } } else { + cam_dbg("can't open %s Ver. Firmware. so, download from F-ROM\n", + state->sensor_fw); if (fw != NULL) release_firmware(fw); - memcpy(state->phone_fw, state->sensor_fw, S5C73M3_FW_VER_LEN); - fw_requested = 0; - err = 0; - goto out; - + retVal = s5c73m3_reset_module(sd, true); + CHECK_ERR(retVal); + retVal = s5c73m3_get_sensor_fw_binary(sd); + CHECK_ERR(retVal); + copied_fw_binary = 1; + goto request_fw; } } @@ -1232,7 +1250,7 @@ static int s5c73m3_check_fw(struct v4l2_subdev *sd, int download) /* retVal = 0 : Same Version retVal < 0 : Phone Version is latest Version than sensorFW. retVal > 0 : Sensor Version is latest version than phoenFW. */ - if (retVal < 0 || download) { + if (retVal <= 0 || download) { cam_dbg("Loading From PhoneFW......\n"); /* In case that there is no FW in phone and FW needs to be @@ -1252,10 +1270,10 @@ static int s5c73m3_check_fw(struct v4l2_subdev *sd, int download) CHECK_ERR(err); } } else { - cam_dbg("Loading From FROM......\n"); - err = s5c73m3_reset_module(sd, false); + cam_dbg("Loading From SensorFW......\n"); + err = s5c73m3_reset_module(sd, true); CHECK_ERR(err); - err = s5c73m3_SPI_booting_by_ISP(sd); + err = s5c73m3_get_sensor_fw_binary(sd); CHECK_ERR(err); } @@ -2663,6 +2681,7 @@ static int s5c73m3_load_fw(struct v4l2_subdev *sd) const struct firmware *fw; char fw_path[20] = {0,}; char fw_path_in_data[25] = {0,}; + u8 *buf = NULL; int err = 0; int txSize = 0; @@ -2732,25 +2751,30 @@ static int s5c73m3_load_fw(struct v4l2_subdev *sd) } /*cam_dbg("start, size %d Bytes\n", fw->size);*/ - memcpy((void *) &data_memory, (void *) fw->data, fw->size); + buf = (u8 *)fw->data; fsize = fw->size; } txSize = 60*1024; /*60KB*/ - err = s5c73m3_spi_write((char *)&data_memory, - fsize, txSize); - if (err < 0) { - cam_err("s5c73m3_spi_write falied\n"); - goto out; + if (state->fw_index != S5C73M3_IN_SYSTEM) { + err = s5c73m3_spi_write((char *)&data_memory, + fsize, txSize); + if (err < 0) { + cam_err("s5c73m3_spi_write falied\n"); + goto out; + } + } else { + err = s5c73m3_spi_write((char *)buf, fsize, txSize); } - out: if (state->fw_index == S5C73M3_SD_CARD || state->fw_index == S5C73M3_IN_DATA) { if (!IS_ERR(fp) && fp != NULL) filp_close(fp, current->files); + vfree(buf); + set_fs(old_fs); } else { release_firmware(fw); @@ -3488,14 +3512,25 @@ static int s5c73m3_init(struct v4l2_subdev *sd, u32 val) err = s5c73m3_i2c_check_status_with_CRC(sd); if (err < 0) { cam_err("ISP is not ready. retry loading fw!!\n"); - - err = s5c73m3_check_fw(sd, 0); - if (err < 0) { - cam_dbg("isp.bad_fw is true\n"); - state->isp.bad_fw = 1; + /* retry */ + retVal = s5c73m3_check_fw_date(sd); + + /* retVal = 0 : Same Version + retVal < 0 : Phone Version is latest Version than sensorFW. + retVal > 0 : Sensor Version is latest version than phoenFW. */ + if (retVal <= 0) { + cam_dbg("Loading From PhoneFW......\n"); + err = s5c73m3_reset_module(sd, false); + CHECK_ERR(err); + err = s5c73m3_SPI_booting(sd); + CHECK_ERR(err); + } else { + cam_dbg("Loading From SensorFW......\n"); + err = s5c73m3_reset_module(sd, true); + CHECK_ERR(err); + err = s5c73m3_get_sensor_fw_binary(sd); + CHECK_ERR(err); } - - CHECK_ERR(err); } state->isp.bad_fw = 0; diff --git a/drivers/media/video/samsung/mfc5x/SsbSipMfcApi.h b/drivers/media/video/samsung/mfc5x/SsbSipMfcApi.h index cbf6cab..c68980d 100644 --- a/drivers/media/video/samsung/mfc5x/SsbSipMfcApi.h +++ b/drivers/media/video/samsung/mfc5x/SsbSipMfcApi.h @@ -41,7 +41,7 @@ #define SAMSUNG_MFC_DEV_NAME "/dev/s3c-mfc" #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) -#define SUPPORT_SLICE_ENCODING 0 // originaly 1, but we're missing matching userspace +#define SUPPORT_SLICE_ENCODING 0 // originally 1, but we're missing matching userspace #else #define SUPPORT_SLICE_ENCODING 0 #endif @@ -136,7 +136,7 @@ typedef enum { /* C210 specific feature */ MFC_ENC_SETCONF_VUI_INFO, MFC_ENC_SETCONF_I_PERIOD, - MFC_ENC_SETCONF_SPS_PPS_GEN, + MFC_ENC_SETCONF_SPS_PPS_GEN, MFC_ENC_SETCONF_HIER_P, MFC_ENC_SETCONF_SEI_GEN, diff --git a/drivers/media/video/samsung/mfc5x/mfc_buf.h b/drivers/media/video/samsung/mfc5x/mfc_buf.h index 28ef0d6..f93ed26 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_buf.h +++ b/drivers/media/video/samsung/mfc5x/mfc_buf.h @@ -34,8 +34,13 @@ #define ALIGN_H_L_L 16 /* Linear, Vertical, Luma */ #define ALIGN_H_L_C 8 /* Linear, Vertical, Chroma */ +#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_GC1) +/* System */ /* Size, Port, Align */ +#define MFC_FW_SYSTEM_SIZE (0x100000) /* 1MB, A, N(4KB for VMEM) */ +#else /* System */ /* Size, Port, Align */ #define MFC_FW_SYSTEM_SIZE (0x80000) /* 512KB, A, N(4KB for VMEM) */ +#endif /* Instance */ #define MFC_CTX_SIZE_L (0x96000) /* 600KB, N, 2KB, H.264 Decoding only */ diff --git a/drivers/media/video/samsung/mfc5x/mfc_cmd.c b/drivers/media/video/samsung/mfc5x/mfc_cmd.c index 38b4757..ba4faf9 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_cmd.c +++ b/drivers/media/video/samsung/mfc5x/mfc_cmd.c @@ -310,7 +310,7 @@ int mfc_cmd_inst_open(struct mfc_inst_ctx *ctx) } memset(&h2r_args, 0, sizeof(struct mfc_cmd_args)); - h2r_args.arg[0] = ctx->codecid; + h2r_args.arg[0] = (1 << 29) | ctx->codecid; h2r_args.arg[1] = crc << 31 | pixelcache; h2r_args.arg[2] = ctx->ctxbufofs; h2r_args.arg[3] = ctx->ctxbufsize; diff --git a/drivers/media/video/samsung/mfc5x/mfc_dec.c b/drivers/media/video/samsung/mfc5x/mfc_dec.c index d3d336a..f0a7c4d 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_dec.c +++ b/drivers/media/video/samsung/mfc5x/mfc_dec.c @@ -155,10 +155,6 @@ static void dump_stream(unsigned long address, unsigned int size) ctx->ctxbufofs = mfc_mem_base_ofs(alloc->real) >> 11; ctx->ctxbufsize = alloc->size; - memset((void *)alloc->addr, 0, alloc->size); - - mfc_mem_cache_clean((void *)alloc->addr, alloc->size); - return 0; } @@ -176,10 +172,6 @@ static int h264_alloc_ctx_buf(struct mfc_inst_ctx *ctx) ctx->ctxbufofs = mfc_mem_base_ofs(alloc->real) >> 11; ctx->ctxbufsize = alloc->size; - memset((void *)alloc->addr, 0, alloc->size); - - mfc_mem_cache_clean((void *)alloc->addr, alloc->size); - return 0; } @@ -1591,56 +1583,6 @@ static int CheckMPEG4StartCode(unsigned char *src_mem, unsigned int remainSize) return -1; } -static int CheckDecStartCode(unsigned char *src_mem, - unsigned int nstreamSize, - SSBSIP_MFC_CODEC_TYPE nCodecType) -{ - unsigned int index = 0; - /* Check Start Code within "isearchSize" bytes */ - unsigned int isearchSize = 20; - unsigned int nShift = 0; - unsigned char nFlag = 0xFF; - - if (nCodecType == H263_DEC) { - nFlag = 0x08; - nShift = 4; - } else if (nCodecType == MPEG4_DEC) { - nFlag = 0x01; - nShift = 0; - } else if (nCodecType == H264_DEC) { - nFlag = 0x01; - nShift = 0; - } else - nFlag = 0xFF; - - /* Last frame detection from user */ - if (nstreamSize == 0) - nFlag = 0xFF; - - if (nFlag == 0xFF) - return 0; - - if (nstreamSize > 3) { - if (nstreamSize > isearchSize) { - for (index = 0; index < isearchSize-3; index++) { - if ((src_mem[index] == 0x00) && - (src_mem[index+1] == 0x00) && - ((src_mem[index+2] >> nShift) == nFlag)) - return index; - } - } else { - for (index = 0; index < nstreamSize - 3; index++) { - if ((src_mem[index] == 0x00) && - (src_mem[index+1] == 0x00) && - ((src_mem[index+2] >> nShift) == nFlag)) - return index; - } - } - } - - return -1; -} - void mfc_init_decoders(void) { list_add_tail(&unknown_dec.list, &mfc_decoders); @@ -1904,6 +1846,20 @@ int mfc_init_decoding(struct mfc_inst_ctx *ctx, union mfc_args *args) } #endif +#if defined(CONFIG_MACH_GC1) && defined(CONFIG_EXYNOS4_CPUFREQ) + if ((ctx->width >= 1280 && ctx->height >= 720) + || (ctx->width >= 720 && ctx->height >= 1280)) { + if (atomic_read(&ctx->dev->cpufreq_lock_cnt) == 0) { + if (0 == ctx->dev->cpufreq_level) /* 800MHz */ + exynos_cpufreq_get_level(800000, &ctx->dev->cpufreq_level); + exynos_cpufreq_lock(DVFS_LOCK_ID_MFC, ctx->dev->cpufreq_level); + mfc_dbg("[%s] CPU Freq Locked 800MHz!\n", __func__); + } + atomic_inc(&ctx->dev->cpufreq_lock_cnt); + ctx->cpufreq_flag = true; + } +#endif + #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_EXYNOS4_CPUFREQ) if ((ctx->width >= 1280 && ctx->height >= 720) || (ctx->width >= 720 && ctx->height >= 1280)) { @@ -1919,27 +1875,27 @@ int mfc_init_decoding(struct mfc_inst_ctx *ctx, union mfc_args *args) #endif #ifdef CONFIG_BUSFREQ_OPP - if (HD_MOVIE_SIZE_MULTIPLY_WIDTH_HEIGHT > (ctx->width * ctx->height)) { - if (atomic_read(&ctx->dev->dmcthreshold_lock_cnt) == 0) { - mfc_info("Implement set dmc_max_threshold\n"); - if (soc_is_exynos4212()) { +if (HD_MOVIE_SIZE_MULTIPLY_WIDTH_HEIGHT > (ctx->width * ctx->height)) { + if (atomic_read(&ctx->dev->dmcthreshold_lock_cnt) == 0) { + mfc_info("Implement set dmc_max_threshold\n"); + if (soc_is_exynos4212()) { + dmc_max_threshold = + EXYNOS4212_DMC_MAX_THRESHOLD + DECODING_LOAD; + } else if (soc_is_exynos4412()) { + if (samsung_rev() >= EXYNOS4412_REV_2_0) dmc_max_threshold = - EXYNOS4212_DMC_MAX_THRESHOLD + 5; - } else if (soc_is_exynos4412()) { - if (samsung_rev() >= EXYNOS4412_REV_2_0) - dmc_max_threshold = - PRIME_DMC_MAX_THRESHOLD + 5; - else - dmc_max_threshold = - EXYNOS4412_DMC_MAX_THRESHOLD + 5; - } else { - pr_err("Unsupported model.\n"); - return -EINVAL; - } + PRIME_DMC_MAX_THRESHOLD + DECODING_LOAD; + else + dmc_max_threshold = + EXYNOS4412_DMC_MAX_THRESHOLD + DECODING_LOAD; + } else { + pr_err("Unsupported model.\n"); + return -EINVAL; } - atomic_inc(&ctx->dev->dmcthreshold_lock_cnt); - ctx->dmcthreshold_flag = true; } + atomic_inc(&ctx->dev->dmcthreshold_lock_cnt); + ctx->dmcthreshold_flag = true; +} #endif /* * allocate & set codec buffers @@ -2146,7 +2102,6 @@ static int mfc_decoding_frame(struct mfc_inst_ctx *ctx, struct mfc_dec_exe_arg * int display_chroma_addr; int display_frame_type; int display_frame_tag; - unsigned char *stream_vir; int ret; struct mfc_dec_ctx *dec_ctx = (struct mfc_dec_ctx *)ctx->c_priv; long mem_ofs; @@ -2154,22 +2109,6 @@ static int mfc_decoding_frame(struct mfc_inst_ctx *ctx, struct mfc_dec_exe_arg * void *ump_handle; #endif -#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION - if (!ctx->drm_flag) { -#endif - /* Check Frame Start code */ - stream_vir = phys_to_virt(exe_arg->in_strm_buf + start_ofs); - ret = CheckDecStartCode(stream_vir, exe_arg->in_strm_size, - exe_arg->in_codec_type); - if (ret < 0) { - mfc_err("Frame Check start Code Failed\n"); - /* FIXME: Need to define proper error */ - return MFC_FRM_BUF_SIZE_FAIL; - } -#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION - } -#endif - /* Set Frame Tag */ write_shm(ctx, dec_ctx->frametag, SET_FRAME_TAG); @@ -2405,7 +2344,9 @@ int mfc_exec_decoding(struct mfc_inst_ctx *ctx, union mfc_args *args) if (ctx->resolution_status == RES_SET_CHANGE) { ret = mfc_decoding_frame(ctx, exe_arg, &consumed); #ifndef CONFIG_SLP - } else if ((ctx->resolution_status == RES_WAIT_FRAME_DONE) && + } + + if ((ctx->resolution_status == RES_WAIT_FRAME_DONE) && (exe_arg->out_display_status == DISP_S_FINISH)) { exe_arg->out_display_status = DISP_S_RES_CHANGE; ret = mfc_change_resolution(ctx, exe_arg); diff --git a/drivers/media/video/samsung/mfc5x/mfc_dev.c b/drivers/media/video/samsung/mfc5x/mfc_dev.c index 23bc10d..43ea79d 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_dev.c +++ b/drivers/media/video/samsung/mfc5x/mfc_dev.c @@ -213,7 +213,7 @@ static int mfc_open(struct inode *inode, struct file *file) mutex_lock(&mfcdev->lock); -#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_M0) +#ifdef CONFIG_USE_MFC_CMA if (atomic_read(&mfcdev->inst_cnt) == 0) { size_t size = 0x02800000; mfcdev->cma_vaddr = dma_alloc_coherent(mfcdev->device, size, @@ -368,8 +368,6 @@ static int mfc_open(struct inode *inode, struct file *file) mfc_ctx->ctxbufofs = mfc_mem_base_ofs(alloc->real) >> 11; mfc_ctx->ctxbufsize = alloc->size; - memset((void *)alloc->addr, 0, alloc->size); - mfc_mem_cache_clean((void *)alloc->addr, alloc->size); } #endif @@ -392,7 +390,7 @@ static int mfc_open(struct inode *inode, struct file *file) ret = mfc_queue_alloc(mfc_ctx); if (ret < 0) { mfc_err("mfc_queue_alloc failed\n"); - goto err_inst_ctx; + goto err_queue_alloc; } #endif @@ -403,9 +401,17 @@ static int mfc_open(struct inode *inode, struct file *file) return 0; +#ifdef CONFIG_SLP_DMABUF +err_queue_alloc: +#endif #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION err_drm_ctx: #endif + mfcdev->inst_ctx[inst_id] = NULL; + atomic_dec(&mfcdev->inst_cnt); + + mfc_destroy_inst(mfc_ctx); + err_inst_ctx: err_inst_id: err_inst_cnt: @@ -423,7 +429,16 @@ err_pwr_enable: #endif err_fw_state: -#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION +#ifdef CONFIG_USE_MFC_CMA + if (atomic_read(&mfcdev->inst_cnt) == 0) { + size_t size = 0x02800000; + dma_free_coherent(mfcdev->device, size, mfcdev->cma_vaddr, + mfcdev->cma_dma_addr); + printk(KERN_INFO "%s[%d] size 0x%x, vaddr 0x%x, base 0x0%x\n", + __func__, __LINE__, (int)size, + (int) mfcdev->cma_vaddr, + (int)mfcdev->cma_dma_addr); + } #endif mutex_unlock(&mfcdev->lock); @@ -476,6 +491,19 @@ static int mfc_release(struct inode *inode, struct file *file) } #endif +#if defined(CONFIG_MACH_GC1) && defined(CONFIG_EXYNOS4_CPUFREQ) + /* Release MFC & CPU Frequency lock for High resolution */ + if (mfc_ctx->cpufreq_flag == true) { + atomic_dec(&dev->cpufreq_lock_cnt); + mfc_ctx->cpufreq_flag = false; + if (atomic_read(&dev->cpufreq_lock_cnt) == 0) { + /* release Freq lock back to normal */ + exynos_cpufreq_lock_free(DVFS_LOCK_ID_MFC); + mfc_dbg("[%s] CPU Freq lock Released Normal!\n", __func__); + } + } +#endif + #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_EXYNOS4_CPUFREQ) /* Release MFC & CPU Frequency lock for High resolution */ if (mfc_ctx->cpufreq_flag == true) { @@ -565,7 +593,7 @@ static int mfc_release(struct inode *inode, struct file *file) err_pwr_disable: -#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_M0) +#ifdef CONFIG_USE_MFC_CMA if (atomic_read(&mfcdev->inst_cnt) == 0) { size_t size = 0x02800000; dma_free_coherent(mfcdev->device, size, mfcdev->cma_vaddr, @@ -977,6 +1005,16 @@ static long mfc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* RMVME: need locking ? */ mutex_lock(&dev->lock); + if (mfc_ctx->state < INST_STATE_SETUP) { + mfc_err("IOCTL_MFC_GET_CONFIG invalid state: 0x%08x\n", + mfc_ctx->state); + in_param.ret_code = MFC_STATE_INVALID; + ret = -EINVAL; + + mutex_unlock(&dev->lock); + break; + } + cfg_arg = (struct mfc_config_arg *)&in_param.args; in_param.ret_code = mfc_get_inst_cfg(mfc_ctx, cfg_arg->type, @@ -1083,9 +1121,13 @@ static int mfc_mmap(struct file *file, struct vm_area_struct *vma) unsigned long start, size; #endif #endif + mfc_info("%s line : %d IN\n", __func__, __LINE__); mfc_ctx = (struct mfc_inst_ctx *)file->private_data; - if (!mfc_ctx) + if (!mfc_ctx) { + mfc_err("%s line : %d mfc_ctx is NULL\n", + __func__, __LINE__); return -EINVAL; + } #if !(defined(CONFIG_VIDEO_MFC_VCM_UMP) || defined(CONFIG_S5P_VMEM)) dev = mfc_ctx->dev; @@ -1325,9 +1367,30 @@ static int mfc_mmap(struct file *file, struct vm_area_struct *vma) return 0; } +#ifdef CONFIG_USE_MFC_CMA +/* FIXME: workaround for CMA migration fail due to page lock */ +static int mfc_open_with_retry(struct inode *inode, struct file *file) +{ + int ret; + int i = 0; + + ret = mfc_open(inode, file); + + while (ret == -ENOMEM && i++ < 10) { + msleep(1000); + ret = mfc_open(inode, file); + } + + return ret; +} +#define MFC_OPEN mfc_open_with_retry +#else +#define MFC_OPEN mfc_open +#endif + static const struct file_operations mfc_fops = { .owner = THIS_MODULE, - .open = mfc_open, + .open = MFC_OPEN, .release = mfc_release, .unlocked_ioctl = mfc_ioctl, .mmap = mfc_mmap, diff --git a/drivers/media/video/samsung/mfc5x/mfc_dev.h b/drivers/media/video/samsung/mfc5x/mfc_dev.h index bb2095c..16bd027 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_dev.h +++ b/drivers/media/video/samsung/mfc5x/mfc_dev.h @@ -114,6 +114,10 @@ struct mfc_dev { #if defined(CONFIG_BUSFREQ) atomic_t busfreq_lock_cnt; /* Bus frequency Lock count */ #endif +#if defined(CONFIG_MACH_GC1) && defined(CONFIG_EXYNOS4_CPUFREQ) + atomic_t cpufreq_lock_cnt; /* CPU frequency Lock count */ + int cpufreq_level; /* CPU frequency leve */ +#endif #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_EXYNOS4_CPUFREQ) atomic_t cpufreq_lock_cnt; /* CPU frequency Lock count */ int cpufreq_level; /* CPU frequency leve */ diff --git a/drivers/media/video/samsung/mfc5x/mfc_enc.c b/drivers/media/video/samsung/mfc5x/mfc_enc.c index 65d7b6b..f2dc039 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_enc.c +++ b/drivers/media/video/samsung/mfc5x/mfc_enc.c @@ -55,10 +55,6 @@ static LIST_HEAD(mfc_encoders); ctx->ctxbufofs = mfc_mem_base_ofs(alloc->real) >> 11; ctx->ctxbufsize = alloc->size; - memset((void *)alloc->addr, 0, alloc->size); - - mfc_mem_cache_clean((void *)alloc->addr, alloc->size); - return 0; } @@ -101,7 +97,7 @@ int get_init_arg(struct mfc_inst_ctx *ctx, void *arg) write_reg((1 << 1) | 0x1, MFC_ENC_MSLICE_CTRL); if (init_arg->cmn.in_ms_arg < 1900) init_arg->cmn.in_ms_arg = 1900; - write_reg(init_arg->cmn.in_ms_arg, MFC_ENC_MSLICE_BIT); + write_reg(init_arg->cmn.in_ms_arg * 8, MFC_ENC_MSLICE_BIT); } else { write_reg(0, MFC_ENC_MSLICE_CTRL); write_reg(0, MFC_ENC_MSLICE_MB); @@ -586,8 +582,7 @@ static int h264_pre_seq_start(struct mfc_inst_ctx *ctx) if (h264->sps_pps_gen == 1) { write_shm(ctx, - ((h264->sps_pps_gen << 8) | - read_shm(ctx, EXT_ENC_CONTROL)), + ((h264->sps_pps_gen << 8) | read_shm(ctx, EXT_ENC_CONTROL)), EXT_ENC_CONTROL); } @@ -1066,10 +1061,8 @@ static int h264_set_codec_cfg(struct mfc_inst_ctx *ctx, int type, void *arg) case MFC_ENC_SETCONF_SPS_PPS_GEN: mfc_dbg("MFC_ENC_SETCONF_SPS_PPS_GEN : %d\n", ctx->state); - if ((ctx->state < INST_STATE_CREATE) || - (ctx->state > INST_STATE_EXE)) { - mfc_err("MFC_ENC_SETCONF_SPS_PPS_GEN : " - " state is invalid\n"); + if ((ctx->state < INST_STATE_CREATE) || (ctx->state > INST_STATE_EXE)) { + mfc_err("MFC_ENC_SETCONF_SPS_PPS_GEN : state is invalid\n"); return MFC_STATE_INVALID; } @@ -1079,6 +1072,7 @@ static int h264_set_codec_cfg(struct mfc_inst_ctx *ctx, int type, void *arg) h264->sps_pps_gen = 0; break; + default: mfc_dbg("invalid set cfg type: 0x%08x\n", type); ret = -2; @@ -1548,6 +1542,22 @@ int mfc_init_encoding(struct mfc_inst_ctx *ctx, union mfc_args *args) } #endif +#if defined(CONFIG_MACH_GC1) && defined(CONFIG_EXYNOS4_CPUFREQ) + if ((ctx->width >= 1280 && ctx->height >= 720) + || (ctx->width >= 720 && ctx->height >= 1280)) { + if (atomic_read(&ctx->dev->cpufreq_lock_cnt) == 0) { + if (0 == ctx->dev->cpufreq_level) /* 800MHz */ + exynos_cpufreq_get_level(800000, + &ctx->dev->cpufreq_level); + exynos_cpufreq_lock(DVFS_LOCK_ID_MFC, + ctx->dev->cpufreq_level); + mfc_dbg("[%s] CPU Freq Locked 800MHz!\n", __func__); + } + atomic_inc(&ctx->dev->cpufreq_lock_cnt); + ctx->cpufreq_flag = true; + } +#endif + #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_EXYNOS4_CPUFREQ) if ((ctx->width >= 320 && ctx->height >= 240) || (ctx->width >= 240 && ctx->height >= 320)) { diff --git a/drivers/media/video/samsung/mfc5x/mfc_inst.c b/drivers/media/video/samsung/mfc5x/mfc_inst.c index ef0d0e0..33736c9 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_inst.c +++ b/drivers/media/video/samsung/mfc5x/mfc_inst.c @@ -55,6 +55,9 @@ struct mfc_inst_ctx *mfc_create_inst(void) #ifdef CONFIG_BUSFREQ ctx->busfreq_flag = false; #endif +#if defined(CONFIG_MACH_GC1) && defined(CONFIG_EXYNOS4_CPUFREQ) + ctx->cpufreq_flag = false; +#endif #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_EXYNOS4_CPUFREQ) ctx->cpufreq_flag = false; #endif @@ -193,34 +196,34 @@ int mfc_set_inst_cfg(struct mfc_inst_ctx *ctx, int type, void *arg) } switch (type) { - case MFC_DEC_SETCONF_POST_ENABLE: - case MFC_DEC_SETCONF_EXTRA_BUFFER_NUM: - case MFC_DEC_SETCONF_DISPLAY_DELAY: - case MFC_DEC_SETCONF_IS_LAST_FRAME: - case MFC_DEC_SETCONF_SLICE_ENABLE: - case MFC_DEC_SETCONF_CRC_ENABLE: - case MFC_DEC_SETCONF_FIMV1_WIDTH_HEIGHT: - case MFC_DEC_SETCONF_FRAME_TAG: - case MFC_DEC_SETCONF_IMMEDIATELY_DISPLAY: - case MFC_DEC_SETCONF_DPB_FLUSH: - case MFC_DEC_SETCONF_SEI_PARSE: - case MFC_DEC_SETCONF_PIXEL_CACHE: - case MFC_ENC_SETCONF_FRAME_TYPE: - case MFC_ENC_SETCONF_CHANGE_FRAME_RATE: - case MFC_ENC_SETCONF_CHANGE_BIT_RATE: - case MFC_ENC_SETCONF_FRAME_TAG: - case MFC_ENC_SETCONF_ALLOW_FRAME_SKIP: - case MFC_ENC_SETCONF_VUI_INFO: - case MFC_ENC_SETCONF_I_PERIOD: - case MFC_ENC_SETCONF_HIER_P: - case MFC_ENC_SETCONF_SEI_GEN: - case MFC_ENC_SETCONF_FRAME_PACKING: - case MFC_ENC_SETCONF_SPS_PPS_GEN: - if (ctx->c_ops->set_codec_cfg) { - if ((ctx->c_ops->set_codec_cfg(ctx, type, arg)) < 0) - return MFC_SET_CONF_FAIL; - } - break; + case MFC_DEC_SETCONF_POST_ENABLE: + case MFC_DEC_SETCONF_EXTRA_BUFFER_NUM: + case MFC_DEC_SETCONF_DISPLAY_DELAY: + case MFC_DEC_SETCONF_IS_LAST_FRAME: + case MFC_DEC_SETCONF_SLICE_ENABLE: + case MFC_DEC_SETCONF_CRC_ENABLE: + case MFC_DEC_SETCONF_FIMV1_WIDTH_HEIGHT: + case MFC_DEC_SETCONF_FRAME_TAG: + case MFC_DEC_SETCONF_IMMEDIATELY_DISPLAY: + case MFC_DEC_SETCONF_DPB_FLUSH: + case MFC_DEC_SETCONF_SEI_PARSE: + case MFC_DEC_SETCONF_PIXEL_CACHE: + case MFC_ENC_SETCONF_FRAME_TYPE: + case MFC_ENC_SETCONF_CHANGE_FRAME_RATE: + case MFC_ENC_SETCONF_CHANGE_BIT_RATE: + case MFC_ENC_SETCONF_FRAME_TAG: + case MFC_ENC_SETCONF_ALLOW_FRAME_SKIP: + case MFC_ENC_SETCONF_VUI_INFO: + case MFC_ENC_SETCONF_I_PERIOD: + case MFC_ENC_SETCONF_HIER_P: + case MFC_ENC_SETCONF_SEI_GEN: + case MFC_ENC_SETCONF_FRAME_PACKING: + case MFC_ENC_SETCONF_SPS_PPS_GEN: + if (ctx->c_ops->set_codec_cfg) { + if ((ctx->c_ops->set_codec_cfg(ctx, type, arg)) < 0) + return MFC_SET_CONF_FAIL; + } + break; default: mfc_err("invalid set config type: 0x%08x\n", type); diff --git a/drivers/media/video/samsung/mfc5x/mfc_inst.h b/drivers/media/video/samsung/mfc5x/mfc_inst.h index b78dd91..eedd6f1 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_inst.h +++ b/drivers/media/video/samsung/mfc5x/mfc_inst.h @@ -158,6 +158,10 @@ struct mfc_inst_ctx { int busfreq_flag; /* context bus frequency flag */ #endif +#if defined(CONFIG_MACH_GC1) && defined(CONFIG_EXYNOS4_CPUFREQ) + int cpufreq_flag; /* context CPU frequency flag*/ +#endif + #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_EXYNOS4_CPUFREQ) int cpufreq_flag; /* context CPU frequency flag*/ #endif diff --git a/drivers/media/video/samsung/mfc5x/mfc_mem.c b/drivers/media/video/samsung/mfc5x/mfc_mem.c index 051e4c0..a4f5345 100644 --- a/drivers/media/video/samsung/mfc5x/mfc_mem.c +++ b/drivers/media/video/samsung/mfc5x/mfc_mem.c @@ -551,12 +551,26 @@ int mfc_init_mem_mgr(struct mfc_dev *dev) /* early allocator */ #if defined(CONFIG_S5P_MEM_CMA) #ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION -#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_M0) +#ifdef CONFIG_USE_MFC_CMA +#if defined(CONFIG_MACH_M0) cma_infos[0].lower_bound = 0x5C100000; cma_infos[0].upper_bound = 0x5F200000; cma_infos[0].total_size = 0x03100000; cma_infos[0].free_size = 0x03100000; cma_infos[0].count = 1; +#elif defined(CONFIG_MACH_GC1) || defined(CONFIG_MACH_GC2PD) + cma_infos[0].lower_bound = 0x50200000; + cma_infos[0].upper_bound = 0x53300000; + cma_infos[0].total_size = 0x03100000; + cma_infos[0].free_size = 0x03100000; + cma_infos[0].count = 1; +#elif defined(CONFIG_MACH_TAB3) || defined(CONFIG_MACH_ZEST) + cma_infos[0].lower_bound = 0x58100000; + cma_infos[0].upper_bound = 0x5B200000; + cma_infos[0].total_size = 0x03100000; + cma_infos[0].free_size = 0x03100000; + cma_infos[0].count = 1; +#endif #else if (cma_info(&cma_infos[0], dev->device, "A")) { mfc_info("failed to get CMA info of 'mfc-secure'\n"); @@ -611,8 +625,14 @@ int mfc_init_mem_mgr(struct mfc_dev *dev) return -ENOMEM; } -#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_M0) +#ifdef CONFIG_USE_MFC_CMA +#if defined(CONFIG_MACH_GC1) || defined(CONFIG_MACH_GC2PD) + base[0] = 0x50200000; +#elif defined(CONFIG_MACH_TAB3) || defined(CONFIG_MACH_ZEST) + base[0] = 0x58100000; +#else base[0] = 0x5c100000; +#endif dev->mem_infos[0].base = base[0]; dev->mem_infos[0].size = size; dev->mem_infos[0].addr = phys_to_virt(base[0]); @@ -707,6 +727,20 @@ int mfc_init_mem_mgr(struct mfc_dev *dev) dev->mem_infos[0].size = size; dev->mem_infos[0].addr = cma_get_virt(base[0], size, 0); } else if (dev->mem_ports == 2) { +#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_Q1_BD) + /* for MFC0:A */ + cma_infos[0].lower_bound = 0x67200000; + cma_infos[0].upper_bound = 0x68400000; + cma_infos[0].total_size = 0x01200000; + cma_infos[0].free_size = 0x01200000; + cma_infos[0].count = 1; + /* for MFC1:B */ + cma_infos[1].lower_bound = 0x68400000; + cma_infos[1].upper_bound = 0x6A000000; + cma_infos[1].total_size = 0x01C00000; + cma_infos[1].free_size = 0x01C00000; + cma_infos[1].count = 1; +#else if (cma_info(&cma_infos[0], dev->device, "A")) { mfc_info("failed to get CMA info of 'mfc0'\n"); return -ENOMEM; @@ -716,7 +750,7 @@ int mfc_init_mem_mgr(struct mfc_dev *dev) mfc_info("failed to get CMA info of 'mfc1'\n"); return -ENOMEM; } - +#endif if (cma_infos[0].lower_bound > cma_infos[1].lower_bound) cma_index = 1; @@ -733,8 +767,12 @@ int mfc_init_mem_mgr(struct mfc_dev *dev) base[0] = cma_alloc(dev->device, cma_index ? "B" : "A", MFC_FW_SYSTEM_SIZE, ALIGN_128KB); #else +#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_Q1_BD) + base[0] = cma_index ? 0x68400000 : 0x67200000; +#else base[0] = cma_alloc(dev->device, cma_index ? "B" : "A", size, ALIGN_128KB); #endif +#endif if (IS_ERR_VALUE(base[0])) { mfc_err("failed to get rsv. memory from CMA on port #0"); return -ENOMEM; @@ -742,7 +780,11 @@ int mfc_init_mem_mgr(struct mfc_dev *dev) dev->mem_infos[0].base = base[0]; dev->mem_infos[0].size = size; +#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_Q1_BD) + dev->mem_infos[0].addr = phys_to_virt(base[0]); +#else dev->mem_infos[0].addr = cma_get_virt(base[0], size, 0); +#endif /* swap CMA index */ cma_index = !cma_index; @@ -760,8 +802,12 @@ int mfc_init_mem_mgr(struct mfc_dev *dev) base[1] = cma_index ? cma_infos[1].lower_bound : cma_infos[0].lower_bound; #else +#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_Q1_BD) + base[1] = cma_index ? 0x68400000 : 0x67200000; +#else base[1] = cma_alloc(dev->device, cma_index ? "B" : "A", size, ALIGN_128KB); #endif +#endif if (IS_ERR_VALUE(base[1])) { mfc_err("failed to get rsv. memory from CMA on port #1"); cma_free(base[0]); @@ -770,7 +816,11 @@ int mfc_init_mem_mgr(struct mfc_dev *dev) dev->mem_infos[1].base = base[1]; dev->mem_infos[1].size = size; +#if defined(CONFIG_USE_MFC_CMA) && defined(CONFIG_MACH_Q1_BD) + dev->mem_infos[1].addr = phys_to_virt(base[1]); +#else dev->mem_infos[1].addr = cma_get_virt(base[1], size, 0); +#endif } else { mfc_err("failed to get reserved memory from CMA"); return -EPERM; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0559caa..1daa392 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -61,27 +61,6 @@ config AD525X_DPOT_SPI To compile this driver as a module, choose M here: the module will be called ad525x_dpot-spi. -config ANDROID_PMEM - bool "Android pmem allocator" - depends on MACH_U1 || MACH_PX || MACH_TRATS - default n - -if ANDROID_PMEM - comment "Reserved memory configurations" - -config ANDROID_PMEM_MEMSIZE_PMEM - int "Memory size in kbytes for android surface using pmem" - default "4096" - -config ANDROID_PMEM_MEMSIZE_PMEM_GPU1 - int "Memory size in kbytes for android surface using pmem_gpu1" - default "10240" - -config ANDROID_PMEM_MEMSIZE_PMEM_CAM - int "Memory size in kbytes for android camera using pmem_camera" - default "4096" -endif - config ATMEL_PWM tristate "Atmel AT32/AT91 PWM support" depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 44e4884..8d3b193 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o -obj-$(CONFIG_ANDROID_PMEM) += pmem.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o diff --git a/drivers/misc/modem_if/Kconfig b/drivers/misc/modem_if/Kconfig index 6a6eeab..a425439 100644 --- a/drivers/misc/modem_if/Kconfig +++ b/drivers/misc/modem_if/Kconfig @@ -24,11 +24,21 @@ config CDMA_MODEM_CBP72 depends on SEC_MODEM default n +config CDMA_MODEM_CBP82 + bool "modem chip : VIA CBP8.2" + depends on SEC_MODEM + default n + config LTE_MODEM_CMC221 bool "modem chip : SEC CMC221" depends on SEC_MODEM default n +config UMTS_MODEM_SS222 + bool "modem chip : SEC SS222" + depends on SEC_MODEM + default n + config CDMA_MODEM_MDM6600 bool "modem chip : QC MDM6600" depends on SEC_MODEM @@ -44,6 +54,11 @@ config GSM_MODEM_ESC6270 depends on SEC_MODEM default n +config CDMA_MODEM_QSC6085 + bool "modem chip : Qualcomm QSC6085" + depends on SEC_MODEM + default n + config LINK_DEVICE_MIPI bool "modem driver link device MIPI-HSI" depends on SEC_MODEM @@ -58,6 +73,7 @@ config LINK_DEVICE_PLD bool "modem driver link device PLD" depends on SEC_MODEM default n + config LINK_DEVICE_USB bool "modem driver link device USB" depends on SEC_MODEM @@ -78,6 +94,11 @@ config LINK_DEVICE_SPI depends on SEC_MODEM default n +config BOOT_DEVICE_SPI + bool "modem driver boot device SPI" + depends on SEC_MODEM + default n + config WORKQUEUE_FRONT bool "IPC: SPI workqueue front" depends on SEC_MODEM diff --git a/drivers/misc/modem_if/Makefile b/drivers/misc/modem_if/Makefile index 5bd62ea..fbb00af 100644 --- a/drivers/misc/modem_if/Makefile +++ b/drivers/misc/modem_if/Makefile @@ -2,7 +2,7 @@ EXTRA_CFLAGS += -Idrivers/misc/modem_if -obj-y += sipc5_modem.o sipc5_io_device.o +obj-y += sipc5_modem.o sipc5_io_device.o sipc5_common.o obj-y += sipc4_modem.o sipc4_io_device.o obj-y += modem_net_flowcontrol_device.o modem_utils.o @@ -10,17 +10,43 @@ obj-$(CONFIG_UMTS_MODEM_XMM6260) += modem_modemctl_device_xmm6260.o obj-$(CONFIG_UMTS_MODEM_XMM6262) += modem_modemctl_device_xmm6262.o obj-$(CONFIG_CDMA_MODEM_CBP71) += modem_modemctl_device_cbp71.o obj-$(CONFIG_CDMA_MODEM_CBP72) += modem_modemctl_device_cbp72.o +obj-$(CONFIG_CDMA_MODEM_CBP82) += modem_modemctl_device_cbp82.o obj-$(CONFIG_LTE_MODEM_CMC221) += modem_modemctl_device_cmc221.o lte_modem_bootloader.o +obj-$(CONFIG_UMTS_MODEM_SS222) += modem_modemctl_device_ss222.o obj-$(CONFIG_CDMA_MODEM_MDM6600) += modem_modemctl_device_mdm6600.o obj-$(CONFIG_GSM_MODEM_ESC6270) += modem_modemctl_device_esc6270.o +obj-$(CONFIG_CDMA_MODEM_QSC6085) += modem_modemctl_device_qsc6085.o obj-$(CONFIG_TDSCDMA_MODEM_SPRD8803) += modem_modemctl_device_sprd8803.o obj-$(CONFIG_LINK_DEVICE_MIPI) += modem_link_device_mipi.o -obj-$(CONFIG_LINK_DEVICE_DPRAM) += modem_link_device_dpram.o modem_link_device_dpram_ext_op.o -obj-$(CONFIG_LINK_DEVICE_PLD) += modem_link_device_pld.o modem_link_device_pld_ext_op.o obj-$(CONFIG_LINK_DEVICE_USB) += modem_link_device_usb.o modem_link_pm_usb.o obj-$(CONFIG_LINK_DEVICE_HSIC) += modem_link_device_hsic.o +obj-$(CONFIG_LINK_DEVICE_DPRAM) += modem_link_device_dpram.o modem_link_device_dpram_ext_op.o +obj-$(CONFIG_LINK_DEVICE_PLD) += modem_link_device_pld.o modem_link_device_pld_ext_op.o obj-$(CONFIG_LINK_DEVICE_C2C) += modem_link_device_c2c.o obj-$(CONFIG_LINK_DEVICE_SPI) += modem_link_device_spi.o +obj-$(CONFIG_BOOT_DEVICE_SPI) += modem_boot_device_spi.o + obj-$(CONFIG_SIM_SLOT_SWITCH) += modem_sim_slot_switch.o + +# Check whether or not memory-type interface +ifeq ($(CONFIG_LINK_DEVICE_DPRAM),y) +LINK_DEVICE_MEMORY_INTERFACE=y +endif + +ifeq ($(CONFIG_LINK_DEVICE_PLD),y) +LINK_DEVICE_MEMORY_INTERFACE=y +endif + +ifeq ($(CONFIG_LINK_DEVICE_C2C),y) +LINK_DEVICE_MEMORY_INTERFACE=y +endif + +ifeq ($(CONFIG_LINK_DEVICE_SHMEM),y) +LINK_DEVICE_MEMORY_INTERFACE=y +endif + +ifdef LINK_DEVICE_MEMORY_INTERFACE +obj-y += modem_link_device_memory.o +endif diff --git a/drivers/misc/modem_if/lte_modem_bootloader.c b/drivers/misc/modem_if/lte_modem_bootloader.c index f259aae..0bc8894 100644 --- a/drivers/misc/modem_if/lte_modem_bootloader.c +++ b/drivers/misc/modem_if/lte_modem_bootloader.c @@ -31,7 +31,7 @@ #include <linux/delay.h> #include <linux/spi/spi.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include <linux/platform_data/lte_modem_bootloader.h> #define LEN_XMIT_DELEY 100 diff --git a/drivers/misc/modem_if/modem.h b/drivers/misc/modem_if/modem.h new file mode 100644 index 0000000..bc4433e --- /dev/null +++ b/drivers/misc/modem_if/modem.h @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2010 Samsung Electronics. + * + * 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 __MODEM_IF_H__ +#define __MODEM_IF_H__ + +#include <linux/platform_device.h> +#include <linux/miscdevice.h> + +enum modem_t { + IMC_XMM6260, + IMC_XMM6262, + VIA_CBP71, + VIA_CBP72, + VIA_CBP82, + SEC_CMC220, + SEC_CMC221, + SEC_SS222, + QC_MDM6600, + QC_ESC6270, + QC_QSC6085, + SPRD_SC8803, + DUMMY, + MAX_MODEM_TYPE +}; + +enum dev_format { + IPC_FMT, + IPC_RAW, + IPC_RFS, + IPC_MULTI_RAW, + IPC_CMD, + IPC_BOOT, + IPC_RAMDUMP, + IPC_DEBUG, + MAX_DEV_FORMAT, +}; +#define MAX_IPC_DEV (IPC_RFS + 1) /* FMT, RAW, RFS */ +#define MAX_SIPC5_DEV (IPC_RAW + 1) /* FMT, RAW */ + +enum modem_io { + IODEV_MISC, + IODEV_NET, + IODEV_DUMMY, +}; + +enum modem_link { + LINKDEV_UNDEFINED, + LINKDEV_MIPI, + LINKDEV_USB, + LINKDEV_HSIC, + LINKDEV_DPRAM, + LINKDEV_PLD, + LINKDEV_C2C, + LINKDEV_SHMEM, + LINKDEV_SPI, + LINKDEV_MAX +}; +#define LINKTYPE(modem_link) (1u << (modem_link)) + +enum modem_network { + UMTS_NETWORK, + CDMA_NETWORK, + TDSCDMA_NETWORK, + LTE_NETWORK, + MAX_MODEM_NETWORK +}; + +enum ap_type { + S5P, + MAX_AP_TYPE +}; + +enum sipc_ver { + NO_SIPC_VER = 0, + SIPC_VER_40 = 40, + SIPC_VER_41 = 41, + SIPC_VER_42 = 42, + SIPC_VER_50 = 50, + MAX_SIPC_VER +}; + +/** + * struct modem_io_t - declaration for io_device + * @name: device name + * @id: for SIPC4, contains format & channel information + * (id & 11100000b)>>5 = format (eg, 0=FMT, 1=RAW, 2=RFS) + * (id & 00011111b) = channel (valid only if format is RAW) + * for SIPC5, contains only 8-bit channel ID + * @format: device format + * @io_type: type of this io_device + * @links: list of link_devices to use this io_device + * for example, if you want to use DPRAM and USB in an io_device. + * .links = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB) + * @tx_link: when you use 2+ link_devices, set the link for TX. + * If define multiple link_devices in @links, + * you can receive data from them. But, cannot send data to all. + * TX is only one link_device. + * @app: the name of the application that will use this IO device + * + * This structure is used in board-*-modems.c + */ +struct modem_io_t { + char *name; + int id; + enum dev_format format; + enum modem_io io_type; + enum modem_link links; + enum modem_link tx_link; + char *app; +}; + +struct modemlink_pm_data { + char *name; + /* link power contol 2 types : pin & regulator control */ + int (*link_ldo_enable)(bool); + unsigned gpio_link_enable; + unsigned gpio_link_active; + unsigned gpio_link_hostwake; + unsigned gpio_link_slavewake; + int (*link_reconnect)(void); + + /* usb hub only */ + int (*port_enable)(int, int); + int (*hub_standby)(void *); + void *hub_pm_data; + bool has_usbhub; + +#ifdef CONFIG_EXYNOS4_CPUFREQ + /* cpu/bus frequency lock */ + atomic_t freqlock; + atomic_t freq_dpramlock; + int (*freq_lock)(struct device *dev); + int (*freq_unlock)(struct device *dev); + unsigned gpio_cpufreq_lock; +#endif + + int autosuspend_delay_ms; /* if zero, the default value is used */ + void (*ehci_reg_dump)(struct device *); +}; + +struct modemlink_pm_link_activectl { + int gpio_initialized; + int gpio_request_host_active; +}; + +#define RES_DPRAM_MEM_ID 0 +#define RES_DPRAM_SFR_ID 1 + +#define STR_DPRAM_BASE "dpram_base" +#define STR_DPRAM_SFR_BASE "dpram_sfr_base" + +enum dpram_type { + EXT_DPRAM, + AP_IDPRAM, + CP_IDPRAM, + PLD_DPRAM, + MAX_DPRAM_TYPE +}; + +#define DPRAM_SIZE_8KB (8 << 10) +#define DPRAM_SIZE_16KB (16 << 10) +#define DPRAM_SIZE_32KB (32 << 10) +#define DPRAM_SIZE_64KB (64 << 10) +#define DPRAM_SIZE_128KB (128 << 10) + +enum dpram_speed { + DPRAM_SPEED_LOW, + DPRAM_SPEED_MID, + DPRAM_SPEED_HIGH, + MAX_DPRAM_SPEED +}; + +struct dpram_circ { + u16 __iomem *head; + u16 __iomem *tail; + u8 __iomem *buff; + u32 size; +}; + +struct dpram_ipc_device { + char name[16]; + int id; + + struct dpram_circ txq; + struct dpram_circ rxq; + + u16 mask_req_ack; + u16 mask_res_ack; + u16 mask_send; +}; + +struct dpram_ipc_map { + u16 __iomem *magic; + u16 __iomem *access; + + struct dpram_ipc_device dev[MAX_IPC_DEV]; + + u16 __iomem *mbx_cp2ap; + u16 __iomem *mbx_ap2cp; +}; + +struct pld_ipc_map { + u16 __iomem *mbx_ap2cp; + u16 __iomem *magic_ap2cp; + u16 __iomem *access_ap2cp; + + u16 __iomem *mbx_cp2ap; + u16 __iomem *magic_cp2ap; + u16 __iomem *access_cp2ap; + + struct dpram_ipc_device dev[MAX_IPC_DEV]; + + u16 __iomem *address_buffer; +}; + +struct modemlink_dpram_data { + enum dpram_type type; /* DPRAM type */ + enum ap_type ap; /* AP type for AP_IDPRAM */ + + /* Stirct I/O access (e.g. ioread16(), etc.) is required */ + bool strict_io_access; + + /* Aligned access is required */ + int aligned; + + /* Disabled during phone booting */ + bool disabled; + + /* Virtual base address and size */ + u8 __iomem *base; + u32 size; + + /* Pointer to an IPC map (DPRAM or PLD) */ + void *ipc_map; + + /* Timeout of waiting for RES_ACK from CP (in msec) */ + unsigned long res_ack_wait_timeout; + + unsigned boot_size_offset; + unsigned boot_tag_offset; + unsigned boot_count_offset; + unsigned max_boot_frame_size; + + void (*setup_speed)(enum dpram_speed); + void (*clear_int2ap)(void); +}; + +enum shmem_type { + REAL_SHMEM, + C2C_SHMEM, + MAX_SHMEM_TYPE +}; + +#define STR_SHMEM_BASE "shmem_base" + +#define SHMEM_SIZE_1MB (1 << 20) /* 1 MB */ +#define SHMEM_SIZE_2MB (2 << 20) /* 2 MB */ +#define SHMEM_SIZE_4MB (4 << 20) /* 4 MB */ + +/* platform data */ +struct modem_data { + char *name; + + unsigned gpio_cp_on; + unsigned gpio_cp_off; + unsigned gpio_reset_req_n; + unsigned gpio_cp_reset; + + /* for broadcasting AP's PM state (active or sleep) */ + unsigned gpio_pda_active; + + /* for checking aliveness of CP */ + unsigned gpio_phone_active; + int irq_phone_active; + + /* for AP-CP IPC interrupt */ + unsigned gpio_ipc_int2ap; + int irq_ipc_int2ap; + unsigned long irqf_ipc_int2ap; /* IRQ flags */ + unsigned gpio_ipc_int2cp; + + /* for AP-CP power management (PM) handshaking */ + unsigned gpio_ap_wakeup; + int irq_ap_wakeup; + unsigned gpio_ap_status; + unsigned gpio_cp_wakeup; + unsigned gpio_cp_status; + int irq_cp_status; + + /* for USB/HSIC PM */ + unsigned gpio_host_wakeup; + int irq_host_wakeup; + unsigned gpio_host_active; + unsigned gpio_slave_wakeup; + unsigned gpio_hub_suspend; + + unsigned gpio_cp_dump_int; + unsigned gpio_ap_dump_int; + unsigned gpio_flm_uart_sel; + unsigned gpio_cp_warm_reset; +#if defined(CONFIG_MACH_M0_CTC) + unsigned gpio_flm_uart_sel_rev06; +#endif + + unsigned gpio_sim_detect; + int irq_sim_detect; + +#ifdef CONFIG_LINK_DEVICE_PLD + unsigned gpio_fpga1_creset; + unsigned gpio_fpga1_cdone; + unsigned gpio_fpga1_rst_n; + unsigned gpio_fpga1_cs_n; + + unsigned gpio_fpga2_creset; + unsigned gpio_fpga2_cdone; + unsigned gpio_fpga2_rst_n; + unsigned gpio_fpga2_cs_n; +#endif + +#ifdef CONFIG_MACH_U1_KOR_LGT + unsigned gpio_cp_reset_msm; + unsigned gpio_boot_sw_sel; + void (*vbus_on)(void); + void (*vbus_off)(void); + struct regulator *cp_vbus; +#endif + +#ifdef CONFIG_TDSCDMA_MODEM_SPRD8803 + unsigned gpio_ipc_mrdy; + unsigned gpio_ipc_srdy; + unsigned gpio_ipc_sub_mrdy; + unsigned gpio_ipc_sub_srdy; + unsigned gpio_ap_cp_int1; + unsigned gpio_ap_cp_int2; +#endif + +#ifdef CONFIG_SEC_DUAL_MODEM_MODE + unsigned gpio_sim_io_sel; + unsigned gpio_cp_ctrl1; + unsigned gpio_cp_ctrl2; +#endif + + /* Switch with 2 links in a modem */ + unsigned gpio_link_switch; + +#ifdef CONFIG_EXYNOS4_CPUFREQ + /* cpu/bus frequency lock */ + unsigned gpio_cpufreq_lock; +#endif + + /* Modem component */ + enum modem_network modem_net; + enum modem_t modem_type; + enum modem_link link_types; + char *link_name; + + /* Link to DPRAM control functions dependent on each platform */ + struct modemlink_dpram_data *dpram; + + /* SIPC version */ + enum sipc_ver ipc_version; + + /* the number of real IPC devices -> (IPC_RAW + 1) or (IPC_RFS + 1) */ + int max_ipc_dev; + + /* Information of IO devices */ + unsigned num_iodevs; + struct modem_io_t *iodevs; + + /* Modem link PM support */ + struct modemlink_pm_data *link_pm_data; + + /* Handover with 2+ modems */ + bool use_handover; + + /* SIM Detect polarity */ + bool sim_polarity; + + void (*gpio_revers_bias_clear)(void); + void (*gpio_revers_bias_restore)(void); +}; + +#define MODEM_BOOT_DEV_SPI "modem_boot_spi" + +struct modem_boot_spi_platform_data { + const char *name; + unsigned int gpio_cp_status; +}; + +struct modem_boot_spi { + struct miscdevice dev; + struct spi_device *spi_dev; + struct mutex lock; + unsigned gpio_cp_status; +}; +#define to_modem_boot_spi(misc) container_of(misc, struct modem_boot_spi, dev); + +struct utc_time { + u16 year; + u8 mon:4, + day:4; + u8 hour; + u8 min; + u8 sec; + u16 msec; +} __packed; + +extern void get_utc_time(struct utc_time *utc); + +#define LOG_TAG "mif: " +#define CALLER (__builtin_return_address(0)) + +#define mif_err(fmt, ...) \ + pr_err(LOG_TAG "%s: " pr_fmt(fmt), __func__, ##__VA_ARGS__) +#define mif_debug(fmt, ...) \ + pr_debug(LOG_TAG "%s: " pr_fmt(fmt), __func__, ##__VA_ARGS__) +#define mif_info(fmt, ...) \ + pr_info(LOG_TAG "%s: " pr_fmt(fmt), __func__, ##__VA_ARGS__) +#define mif_trace(fmt, ...) \ + printk(KERN_DEBUG "mif: %s: %d: called(%pF): " fmt, \ + __func__, __LINE__, __builtin_return_address(0), ##__VA_ARGS__) + +#endif diff --git a/drivers/misc/modem_if/modem_boot_device_spi.c b/drivers/misc/modem_if/modem_boot_device_spi.c new file mode 100644 index 0000000..369e473 --- /dev/null +++ b/drivers/misc/modem_if/modem_boot_device_spi.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2011 Samsung Electronics. + * + * 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/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/miscdevice.h> + +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/wakelock.h> +#include <linux/delay.h> +#include <linux/spi/spi.h> + +#include "modem.h" +#include "modem_prj.h" + +#define SPI_XMIT_DELEY 100 + +static int check_cp_status(unsigned int gpio_cp_status, unsigned int count) +{ + int ret = 0; + int cnt = 0; + + while (1) { + if (gpio_get_value(gpio_cp_status) != 0) { + ret = 0; + break; + } + + cnt++; + if (cnt >= count) { + mif_err("ERR! gpio_cp_status == 0 (cnt %d)\n", cnt); + ret = -EFAULT; + break; + } + + msleep(20); + } + + return ret; +} + +static inline int spi_send(struct modem_boot_spi *loader, const char val) +{ + char buff[1]; + int ret; + struct spi_message msg; + struct spi_transfer xfer = { + .len = 1, + .tx_buf = buff, + }; + + buff[0] = val; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(loader->spi_dev, &msg); + if (ret < 0) + mif_err("ERR! spi_sync fail (err %d)\n", ret); + + return ret; +} + +static int spi_boot_write(struct modem_boot_spi *loader, const char *addr, + const long len) +{ + int i; + int ret = 0; + char *buff = NULL; + mif_err("+++\n"); + + buff = kzalloc(len, GFP_KERNEL); + if (!buff) { + mif_err("ERR! kzalloc(%ld) fail\n", len); + ret = -ENOMEM; + goto exit; + } + + ret = copy_from_user(buff, (const void __user *)addr, len); + if (ret) { + mif_err("ERR! copy_from_user fail (err %d)\n", ret); + ret = -EFAULT; + goto exit; + } + + for (i = 0 ; i < len ; i++) { + ret = spi_send(loader, buff[i]); + if (ret < 0) { + mif_err("ERR! spi_send fail (err %d)\n", ret); + goto exit; + } + } + +exit: + if (buff) + kfree(buff); + + mif_err("---\n"); + return ret; +} + +static int spi_boot_open(struct inode *inode, struct file *filp) +{ + struct modem_boot_spi *loader = to_modem_boot_spi(filp->private_data); + filp->private_data = loader; + return 0; +} + +static long spi_boot_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + struct modem_firmware img; + struct modem_boot_spi *loader = filp->private_data; + + mutex_lock(&loader->lock); + switch (cmd) { + case IOCTL_MODEM_XMIT_BOOT: + ret = copy_from_user(&img, (const void __user *)arg, + sizeof(struct modem_firmware)); + if (ret) { + mif_err("ERR! copy_from_user fail (err %d)\n", ret); + ret = -EFAULT; + goto exit_err; + } + mif_info("IOCTL_MODEM_XMIT_BOOT (size %d)\n", img.size); + + ret = spi_boot_write(loader, img.binary, img.size); + if (ret < 0) { + mif_err("ERR! spi_boot_write fail (err %d)\n", ret); + break; + } + + if (!loader->gpio_cp_status) + break; + + ret = check_cp_status(loader->gpio_cp_status, 100); + if (ret < 0) + mif_err("ERR! check_cp_status fail (err %d)\n", ret); + + break; + + default: + mif_err("ioctl cmd error\n"); + ret = -ENOIOCTLCMD; + + break; + } + mutex_unlock(&loader->lock); + +exit_err: + return ret; +} + +static const struct file_operations modem_spi_boot_fops = { + .owner = THIS_MODULE, + .open = spi_boot_open, + .unlocked_ioctl = spi_boot_ioctl, +}; + +static int __devinit modem_spi_boot_probe(struct spi_device *spi) +{ + int ret; + struct modem_boot_spi *loader; + struct modem_boot_spi_platform_data *pdata; + mif_debug("+++\n"); + + loader = kzalloc(sizeof(*loader), GFP_KERNEL); + if (!loader) { + mif_err("failed to allocate for modem_boot_spi\n"); + ret = -ENOMEM; + goto err_alloc; + } + mutex_init(&loader->lock); + + spi->bits_per_word = 8; + + if (spi_setup(spi)) { + mif_err("ERR! spi_setup fail\n"); + ret = -EINVAL; + goto err_setup; + } + loader->spi_dev = spi; + + if (!spi->dev.platform_data) { + mif_err("ERR! no platform_data\n"); + ret = -EINVAL; + goto err_setup; + } + pdata = (struct modem_boot_spi_platform_data *)spi->dev.platform_data; + + loader->gpio_cp_status = pdata->gpio_cp_status; + + spi_set_drvdata(spi, loader); + + loader->dev.minor = MISC_DYNAMIC_MINOR; + loader->dev.name = MODEM_BOOT_DEV_SPI; + loader->dev.fops = &modem_spi_boot_fops; + ret = misc_register(&loader->dev); + if (ret) { + mif_err("ERR! misc_register fail (err %d)\n", ret); + goto err_setup; + } + + mif_debug("---\n"); + return 0; + +err_setup: + mutex_destroy(&loader->lock); + kfree(loader); + +err_alloc: + mif_err("xxx\n"); + return ret; +} + +static int __devexit modem_spi_boot_remove(struct spi_device *spi) +{ + struct modem_boot_spi *loader = spi_get_drvdata(spi); + + misc_deregister(&loader->dev); + mutex_destroy(&loader->lock); + kfree(loader); + + return 0; +} + +static struct spi_driver modem_boot_device_spi_driver = { + .driver = { + .name = MODEM_BOOT_DEV_SPI, + .owner = THIS_MODULE, + }, + .probe = modem_spi_boot_probe, + .remove = __devexit_p(modem_spi_boot_remove), +}; + +static int __init modem_boot_device_spi_init(void) +{ + int err; + + err = spi_register_driver(&modem_boot_device_spi_driver); + if (err) { + mif_err("spi_register_driver fail (err %d)\n", err); + return err; + } + + return 0; +} + +static void __exit modem_boot_device_spi_exit(void) +{ + spi_unregister_driver(&modem_boot_device_spi_driver); +} + +module_init(modem_boot_device_spi_init); +module_exit(modem_boot_device_spi_exit); + +MODULE_DESCRIPTION("SPI Driver for Downloading Modem Bootloader"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/misc/modem_if/modem_link_device_c2c.c b/drivers/misc/modem_if/modem_link_device_c2c.c index acbaadf..b51cf9e 100644 --- a/drivers/misc/modem_if/modem_link_device_c2c.c +++ b/drivers/misc/modem_if/modem_link_device_c2c.c @@ -1,6 +1,4 @@ -/* /linux/drivers/new_modem_if/link_dev_c2c.c - * - * Copyright (C) 2010 Google, Inc. +/* * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -14,9 +12,9 @@ * */ -#include <linux/init.h> #include <linux/irq.h> #include <linux/gpio.h> +#include <linux/time.h> #include <linux/interrupt.h> #include <linux/timer.h> #include <linux/wakelock.h> @@ -24,38 +22,2279 @@ #include <linux/wait.h> #include <linux/sched.h> #include <linux/vmalloc.h> -#include <linux/proc_fs.h> #include <linux/if_arp.h> #include <linux/platform_device.h> +#include <linux/kallsyms.h> +#include <linux/suspend.h> +#ifdef CONFIG_FB +#include <linux/fb.h> +#endif +#include <plat/gpio-cfg.h> +#include <mach/gpio.h> +#include <mach/regs-gpio.h> +#include <linux/notifier.h> -#include <linux/platform_data/modem.h> -#include <linux/platform_data/c2c.h> +#include "modem.h" #include "modem_prj.h" +#include "modem_utils.h" #include "modem_link_device_c2c.h" +static void trigger_forced_cp_crash(struct shmem_link_device *shmd); + +#ifdef DEBUG_MODEM_IF +static void save_mem_dump(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + char *path = shmd->dump_path; + struct file *fp; + struct utc_time t; + + get_utc_time(&t); + snprintf(path, MIF_MAX_PATH_LEN, "%s/%s_%d%02d%02d_%02d%02d%02d.dump", + MIF_LOG_DIR, ld->name, t.year, t.mon, t.day, t.hour, t.min, + t.sec); + + fp = mif_open_file(path); + if (!fp) { + mif_err("%s: ERR! %s open fail\n", ld->name, path); + return; + } + mif_err("%s: %s opened\n", ld->name, path); + + mif_save_file(fp, shmd->base, shmd->size); + + mif_close_file(fp); +} + +/** + * mem_dump_work + * @ws: pointer to an instance of work_struct structure + * + * Performs actual file operation for saving a DPRAM dump. + */ +static void mem_dump_work(struct work_struct *ws) +{ + struct shmem_link_device *shmd; + + shmd = container_of(ws, struct shmem_link_device, dump_dwork.work); + if (!shmd) { + mif_err("ERR! no shmd\n"); + return; + } + + save_mem_dump(shmd); +} +#endif + +static void print_pm_status(struct shmem_link_device *shmd, int level) +{ +#ifdef DEBUG_MODEM_IF + struct utc_time t; + u32 magic; + int ap_wakeup; + int ap_status; + int cp_wakeup; + int cp_status; + + if (level < 0) + return; + + get_utc_time(&t); + magic = get_magic(shmd); + ap_wakeup = gpio_get_value(shmd->gpio_ap_wakeup); + ap_status = gpio_get_value(shmd->gpio_ap_status); + cp_wakeup = gpio_get_value(shmd->gpio_cp_wakeup); + cp_status = gpio_get_value(shmd->gpio_cp_status); + + /* + ** PM {ap_wakeup:cp_wakeup:cp_status:ap_status:magic:state} CALLER + */ + if (level > 0) { + pr_err(LOG_TAG "[%02d:%02d:%02d.%03d] C2C PM {%d:%d:%d:%d:%X} " + "%pf\n", t.hour, t.min, t.sec, t.msec, ap_wakeup, + cp_wakeup, cp_status, ap_status, magic, CALLER); + } else { + pr_info(LOG_TAG "[%02d:%02d:%02d.%03d] C2C PM {%d:%d:%d:%d:%X} " + "%pf\n", t.hour, t.min, t.sec, t.msec, ap_wakeup, + cp_wakeup, cp_status, ap_status, magic, CALLER); + } +#endif +} + +static inline void s5p_change_irq_type(int irq, int value) +{ + irq_set_irq_type(irq, value ? IRQ_TYPE_LEVEL_LOW : IRQ_TYPE_LEVEL_HIGH); + /** + * Exynos BSP has a problem when using level-triggering interrupt. + * If the irq type is changed in an interrupt handler, the handler will + * be called again. + * Below is a temporary solution until SYS.LSI resolves this problem. + */ + __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq))); +} + +/** + * recv_int2ap + * @shmd: pointer to an instance of shmem_link_device structure + * + * Returns the value of the CP-to-AP interrupt register. + */ +static inline u16 recv_int2ap(struct shmem_link_device *shmd) +{ + if (shmd->type == C2C_SHMEM) + return (u16)c2c_read_interrupt(); + + if (shmd->mbx2ap) + return *shmd->mbx2ap; + + return 0; +} + +/** + * send_int2cp + * @shmd: pointer to an instance of shmem_link_device structure + * @mask: value to be written to the AP-to-CP interrupt register + */ +static inline void send_int2cp(struct shmem_link_device *shmd, u16 mask) +{ + struct link_device *ld = &shmd->ld; + + if (ld->mode != LINK_MODE_IPC) + mif_info("%s: <by %pf> mask = 0x%04X\n", ld->name, CALLER, mask); + + if (shmd->type == C2C_SHMEM) + c2c_send_interrupt(mask); + + if (shmd->mbx2cp) + *shmd->mbx2cp = mask; +} + +/** + * get_shmem_status + * @shmd: pointer to an instance of shmem_link_device structure + * @dir: direction of communication (TX or RX) + * @mst: pointer to an instance of mem_status structure + * + * Takes a snapshot of the current status of a SHMEM. + */ +static void get_shmem_status(struct shmem_link_device *shmd, + enum circ_dir_type dir, struct mem_status *mst) +{ +#ifdef DEBUG_MODEM_IF + getnstimeofday(&mst->ts); +#endif + + mst->dir = dir; + mst->magic = get_magic(shmd); + mst->access = get_access(shmd); + mst->head[IPC_FMT][TX] = get_txq_head(shmd, IPC_FMT); + mst->tail[IPC_FMT][TX] = get_txq_tail(shmd, IPC_FMT); + mst->head[IPC_FMT][RX] = get_rxq_head(shmd, IPC_FMT); + mst->tail[IPC_FMT][RX] = get_rxq_tail(shmd, IPC_FMT); + mst->head[IPC_RAW][TX] = get_txq_head(shmd, IPC_RAW); + mst->tail[IPC_RAW][TX] = get_txq_tail(shmd, IPC_RAW); + mst->head[IPC_RAW][RX] = get_rxq_head(shmd, IPC_RAW); + mst->tail[IPC_RAW][RX] = get_rxq_tail(shmd, IPC_RAW); +} + +static inline int check_link_status(struct shmem_link_device *shmd) +{ + u32 magic = get_magic(shmd); + int cnt; + + if (gpio_get_value(shmd->gpio_cp_status) != 0 && magic == SHM_IPC_MAGIC) + return 0; + + cnt = 0; + while (gpio_get_value(shmd->gpio_cp_status) == 0) { + if (gpio_get_value(shmd->gpio_ap_status) == 0) { + print_pm_status(shmd, 1); + gpio_set_value(shmd->gpio_ap_status, 1); + } + + cnt++; + if (cnt >= 100) { + mif_err("ERR! cp_status != 1 (cnt %d)\n", cnt); + return -EACCES; + } + + if (in_interrupt()) + udelay(100); + else + usleep_range(100, 200); + } + + cnt = 0; + while (1) { + magic = get_magic(shmd); + if (magic == SHM_IPC_MAGIC) + break; + + cnt++; + if (cnt >= 100) { + mif_err("ERR! magic 0x%X != SHM_IPC_MAGIC (cnt %d)\n", + magic, cnt); + return -EACCES; + } + + if (in_interrupt()) + udelay(100); + else + usleep_range(100, 200); + } + + return 0; +} + +static void release_cp_wakeup(struct work_struct *ws) +{ + struct shmem_link_device *shmd; + struct link_device *ld; + int i; + unsigned long flags; + + shmd = container_of(ws, struct shmem_link_device, cp_sleep_dwork.work); + + spin_lock_irqsave(&shmd->pm_lock, flags); + i = atomic_read(&shmd->ref_cnt); + spin_unlock_irqrestore(&shmd->pm_lock, flags); + if (i > 0) + goto reschedule; + + /* + * If there is any IPC message remained in a TXQ, AP must prevent CP + * from going to sleep. + */ + ld = &shmd->ld; + for (i = 0; i < ld->max_ipc_dev; i++) { + if (ld->skb_txq[i]->qlen > 0) + goto reschedule; + } + + if (gpio_get_value(shmd->gpio_ap_wakeup)) + goto reschedule; + + gpio_set_value(shmd->gpio_cp_wakeup, 0); + print_pm_status(shmd, 1); + return; + +reschedule: + if (!work_pending(&shmd->cp_sleep_dwork.work)) { + queue_delayed_work(system_nrt_wq, &shmd->cp_sleep_dwork, + msecs_to_jiffies(CP_WAKEUP_HOLD_TIME)); + } +} + +static void release_ap_status(struct work_struct *ws) +{ + struct shmem_link_device *shmd; + struct link_device *ld; + int i; + unsigned long flags; + + shmd = container_of(ws, struct shmem_link_device, link_off_dwork.work); + + spin_lock_irqsave(&shmd->pm_lock, flags); + i = atomic_read(&shmd->ref_cnt); + spin_unlock_irqrestore(&shmd->pm_lock, flags); + if (i > 0) + goto reschedule; + + if (gpio_get_value(shmd->gpio_cp_status)) + goto reschedule; + + gpio_set_value(shmd->gpio_ap_status, 0); + print_pm_status(shmd, 1); + + if (wake_lock_active(&shmd->cp_wlock)) + wake_unlock(&shmd->cp_wlock); + + return; + +reschedule: + if (!work_pending(&shmd->link_off_dwork.work)) { + queue_delayed_work(system_nrt_wq, &shmd->link_off_dwork, + msecs_to_jiffies(100)); + } +} + +/** + * forbid_cp_sleep + * @shmd: pointer to an instance of shmem_link_device structure + * + * Wakes up a CP if it can sleep and increases the "ref_cnt" counter in the + * shmem_link_device instance. + * + * CAUTION!!! permit_cp_sleep() MUST be invoked after forbid_cp_sleep() success + * to decrease the "ref_cnt" counter. + */ +static int forbid_cp_sleep(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + int err = 0; + unsigned long flags; + + spin_lock_irqsave(&shmd->pm_lock, flags); + atomic_inc(&shmd->ref_cnt); + if (gpio_get_value(shmd->gpio_ap_status) == 0) { + gpio_set_value(shmd->gpio_ap_status, 1); + print_pm_status(shmd, 1); + } + spin_unlock_irqrestore(&shmd->pm_lock, flags); + + if (work_pending(&shmd->cp_sleep_dwork.work)) + cancel_delayed_work(&shmd->cp_sleep_dwork); + + if (work_pending(&shmd->link_off_dwork.work)) + cancel_delayed_work(&shmd->link_off_dwork); + + if (gpio_get_value(shmd->gpio_cp_wakeup) == 0) { + gpio_set_value(shmd->gpio_cp_wakeup, 1); + print_pm_status(shmd, 1); + } + + if (check_link_status(shmd) < 0) { + print_pm_status(shmd, 1); + mif_err("%s: ERR! check_link_status fail\n", ld->name); + err = -EACCES; + goto exit; + } + +exit: + return err; +} + +/** + * permit_cp_sleep + * @shmd: pointer to an instance of shmem_link_device structure + * + * Decreases the "ref_cnt" counter in the shmem_link_device instance if it can + * sleep and allows a CP to sleep only if the value of "ref_cnt" counter is + * less than or equal to 0. + * + * MUST be invoked after forbid_cp_sleep() success to decrease the "ref_cnt" + * counter. + */ +static void permit_cp_sleep(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + unsigned long flags; + + spin_lock_irqsave(&shmd->pm_lock, flags); + + if (atomic_dec_return(&shmd->ref_cnt) > 0) { + spin_unlock_irqrestore(&shmd->pm_lock, flags); + return; + } + + atomic_set(&shmd->ref_cnt, 0); + spin_unlock_irqrestore(&shmd->pm_lock, flags); + + /* Hold gpio_cp_wakeup for CP_WAKEUP_HOLD_TIME until CP finishes RX */ + if (!work_pending(&shmd->cp_sleep_dwork.work)) { + queue_delayed_work(system_nrt_wq, &shmd->cp_sleep_dwork, + msecs_to_jiffies(CP_WAKEUP_HOLD_TIME)); + } +} + +/** + * ap_wakeup_handler: interrupt handler for a wakeup interrupt + * @irq: IRQ number + * @data: pointer to a data + * + * 1) Reads the interrupt value + * 2) Performs interrupt handling + */ +static irqreturn_t ap_wakeup_handler(int irq, void *data) +{ + struct shmem_link_device *shmd = (struct shmem_link_device *)data; + struct link_device *ld = (struct link_device *)&shmd->ld; + int ap_wakeup = gpio_get_value(shmd->gpio_ap_wakeup); + int ap_status = gpio_get_value(shmd->gpio_ap_status); + + s5p_change_irq_type(irq, ap_wakeup); + + if (ld->mode != LINK_MODE_IPC) + goto exit; + + if (work_pending(&shmd->cp_sleep_dwork.work)) + __cancel_delayed_work(&shmd->cp_sleep_dwork); + + print_pm_status(shmd, 1); + + if (ap_wakeup) { + if (work_pending(&shmd->link_off_dwork.work)) + __cancel_delayed_work(&shmd->link_off_dwork); + + if (!wake_lock_active(&shmd->ap_wlock)) + wake_lock(&shmd->ap_wlock); + + if (!c2c_suspended() && !ap_status) + gpio_set_value(shmd->gpio_ap_status, 1); + } else { + if (wake_lock_active(&shmd->ap_wlock)) + wake_unlock(&shmd->ap_wlock); + + queue_delayed_work(system_nrt_wq, &shmd->cp_sleep_dwork, + msecs_to_jiffies(CP_WAKEUP_HOLD_TIME)); + } + +exit: + return IRQ_HANDLED; +} + +static irqreturn_t cp_status_handler(int irq, void *data) +{ + struct shmem_link_device *shmd = (struct shmem_link_device *)data; + struct link_device *ld = (struct link_device *)&shmd->ld; + int cp_status = gpio_get_value(shmd->gpio_cp_status); + unsigned long flags; + + spin_lock_irqsave(&shmd->pm_lock, flags); + + s5p_change_irq_type(irq, cp_status); + + if (ld->mode != LINK_MODE_IPC) + goto exit; + + if (work_pending(&shmd->link_off_dwork.work)) + __cancel_delayed_work(&shmd->link_off_dwork); + + print_pm_status(shmd, 1); + + if (cp_status) { + if (!wake_lock_active(&shmd->cp_wlock)) + wake_lock(&shmd->cp_wlock); + } else { + if (atomic_read(&shmd->ref_cnt) > 0) { + queue_delayed_work(system_nrt_wq, &shmd->link_off_dwork, + msecs_to_jiffies(10)); + } else { + gpio_set_value(shmd->gpio_ap_status, 0); + if (wake_lock_active(&shmd->cp_wlock)) + wake_unlock(&shmd->cp_wlock); + } + } + +exit: + spin_unlock_irqrestore(&shmd->pm_lock, flags); + return IRQ_HANDLED; +} + +#if 1 +/* Functions for IPC/BOOT/DUMP RX */ +#endif + +/** + * handle_cp_crash + * @shmd: pointer to an instance of shmem_link_device structure + * + * Actual handler for the CRASH_EXIT command from a CP. + */ +static void handle_cp_crash(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + struct io_device *iod; + int i; + + if (shmd->forced_cp_crash) + shmd->forced_cp_crash = false; + + /* Stop network interfaces */ + mif_netif_stop(ld); + + /* Purge the skb_txq in every IPC device (IPC_FMT, IPC_RAW, etc.) */ + for (i = 0; i < MAX_SIPC5_DEV; i++) + skb_queue_purge(ld->skb_txq[i]); + + /* Change the modem state to STATE_CRASH_EXIT for the FMT IO device */ + iod = link_get_iod_with_format(ld, IPC_FMT); + if (iod) + iod->modem_state_changed(iod, STATE_CRASH_EXIT); + + /* time margin for taking state changes by rild */ + mdelay(100); + + /* Change the modem state to STATE_CRASH_EXIT for the BOOT IO device */ + iod = link_get_iod_with_format(ld, IPC_BOOT); + if (iod) + iod->modem_state_changed(iod, STATE_CRASH_EXIT); +} + +/** + * handle_no_cp_crash_ack + * @arg: pointer to an instance of shmem_link_device structure + * + * Invokes handle_cp_crash() to enter the CRASH_EXIT state if there was no + * CRASH_ACK from a CP in FORCE_CRASH_ACK_TIMEOUT. + */ +static void handle_no_cp_crash_ack(unsigned long arg) +{ + struct shmem_link_device *shmd = (struct shmem_link_device *)arg; + struct link_device *ld = &shmd->ld; + + mif_err("%s: ERR! No CRASH_EXIT ACK from CP\n", ld->name); + + handle_cp_crash(shmd); +} + +/** + * trigger_forced_cp_crash + * @shmd: pointer to an instance of shmem_link_device structure + * + * Triggers an enforced CP crash. + */ +static void trigger_forced_cp_crash(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + struct utc_time t; + + if (ld->mode == LINK_MODE_ULOAD) { + mif_err("%s: <by %pf> ALREADY in progress\n", ld->name, CALLER); + return; + } + ld->mode = LINK_MODE_ULOAD; + shmd->forced_cp_crash = true; + + get_utc_time(&t); + mif_err("%s: [%02d:%02d:%02d.%03d] <by %pf>\n", + ld->name, t.hour, t.min, t.sec, t.msec, CALLER); + + if (!wake_lock_active(&shmd->wlock)) + wake_lock(&shmd->wlock); + +#ifdef DEBUG_MODEM_IF + if (in_interrupt()) + queue_delayed_work(system_nrt_wq, &shmd->dump_dwork, 0); + else + save_mem_dump(shmd); +#endif + + /* Send CRASH_EXIT command to a CP */ + send_int2cp(shmd, INT_CMD(INT_CMD_CRASH_EXIT)); + get_shmem_status(shmd, TX, msq_get_free_slot(&shmd->stat_list)); + + /* If there is no CRASH_ACK from a CP in FORCE_CRASH_ACK_TIMEOUT, + handle_no_cp_crash_ack() will be executed. */ + mif_add_timer(&shmd->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, + handle_no_cp_crash_ack, (unsigned long)shmd); + + return; +} + +/** + * cmd_crash_reset_handler + * @shmd: pointer to an instance of shmem_link_device structure + * + * Handles the CRASH_RESET command from a CP. + */ +static void cmd_crash_reset_handler(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + struct io_device *iod = NULL; + int i; + struct utc_time t; + + ld->mode = LINK_MODE_ULOAD; + + if (!wake_lock_active(&shmd->wlock)) + wake_lock(&shmd->wlock); + + get_utc_time(&t); + mif_err("%s: ERR! [%02d:%02d:%02d.%03d] Recv 0xC7 (CRASH_RESET)\n", + ld->name, t.hour, t.min, t.sec, t.msec); +#ifdef DEBUG_MODEM_IF + queue_delayed_work(system_nrt_wq, &shmd->dump_dwork, 0); +#endif + + /* Stop network interfaces */ + mif_netif_stop(ld); + + /* Purge the skb_txq in every IPC device (IPC_FMT, IPC_RAW, etc.) */ + for (i = 0; i < MAX_SIPC5_DEV; i++) + skb_queue_purge(ld->skb_txq[i]); + + /* Change the modem state to STATE_CRASH_RESET for the FMT IO device */ + iod = link_get_iod_with_format(ld, IPC_FMT); + if (iod) + iod->modem_state_changed(iod, STATE_CRASH_RESET); + + /* time margin for taking state changes by rild */ + mdelay(100); + + /* Change the modem state to STATE_CRASH_RESET for the BOOT IO device */ + iod = link_get_iod_with_format(ld, IPC_BOOT); + if (iod) + iod->modem_state_changed(iod, STATE_CRASH_RESET); +} + +/** + * cmd_crash_exit_handler + * @shmd: pointer to an instance of shmem_link_device structure + * + * Handles the CRASH_EXIT command from a CP. + */ +static void cmd_crash_exit_handler(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + struct utc_time t; + + ld->mode = LINK_MODE_ULOAD; + + del_timer(&shmd->crash_ack_timer); + + if (!wake_lock_active(&shmd->wlock)) + wake_lock(&shmd->wlock); + + get_utc_time(&t); + mif_err("%s: ERR! [%02d:%02d:%02d.%03d] Recv 0xC9 (CRASH_EXIT)\n", + ld->name, t.hour, t.min, t.sec, t.msec); +#ifdef DEBUG_MODEM_IF + queue_delayed_work(system_nrt_wq, &shmd->dump_dwork, 0); +#endif + + handle_cp_crash(shmd); +} + +/** + * cmd_phone_start_handler + * @shmd: pointer to an instance of shmem_link_device structure + * + * Handles the PHONE_START command from a CP. + */ +static void cmd_phone_start_handler(struct shmem_link_device *shmd) +{ + int err; + struct link_device *ld = &shmd->ld; + struct io_device *iod; + int ap_wakeup = gpio_get_value(shmd->gpio_ap_wakeup); + int cp_status = gpio_get_value(shmd->gpio_cp_status); + + mif_err("%s: Recv 0xC8 (CP_START)\n", ld->name); + + iod = link_get_iod_with_format(ld, IPC_FMT); + if (!iod) { + mif_err("%s: ERR! no iod\n", ld->name); + return; + } + + err = init_shmem_ipc(shmd); + if (err) + return; + + if (wake_lock_active(&shmd->wlock)) + wake_unlock(&shmd->wlock); + + s5p_change_irq_type(shmd->irq_ap_wakeup, ap_wakeup); + if (ap_wakeup && !wake_lock_active(&shmd->ap_wlock)) + wake_lock(&shmd->ap_wlock); + + s5p_change_irq_type(shmd->irq_cp_status, cp_status); + if (cp_status && !wake_lock_active(&shmd->ap_wlock)) + wake_lock(&shmd->cp_wlock); + + ld->mode = LINK_MODE_IPC; + iod->modem_state_changed(iod, STATE_ONLINE); +} + +/** + * cmd_handler: processes a SHMEM command from a CP + * @shmd: pointer to an instance of shmem_link_device structure + * @cmd: SHMEM command from a CP + */ +static void cmd_handler(struct shmem_link_device *shmd, u16 cmd) +{ + struct link_device *ld = &shmd->ld; + + switch (INT_CMD_MASK(cmd)) { + case INT_CMD_CRASH_RESET: + cmd_crash_reset_handler(shmd); + break; + + case INT_CMD_CRASH_EXIT: + cmd_crash_exit_handler(shmd); + break; + + case INT_CMD_PHONE_START: + cmd_phone_start_handler(shmd); + complete_all(&ld->init_cmpl); + break; + + default: + mif_err("%s: unknown command 0x%04X\n", ld->name, cmd); + break; + } +} + +/** + * ipc_rx_work + * @ws: pointer to an instance of work_struct structure + * + * Invokes the recv method in the io_device instance to perform receiving IPC + * messages from each skb. + */ +static void ipc_rx_work(struct work_struct *ws) +{ + struct shmem_link_device *shmd; + struct link_device *ld; + struct io_device *iod; + struct sk_buff *skb; + int i; + + shmd = container_of(ws, struct shmem_link_device, ipc_rx_dwork.work); + ld = &shmd->ld; + + for (i = 0; i < MAX_SIPC5_DEV; i++) { + iod = shmd->iod[i]; + while (1) { + skb = skb_dequeue(ld->skb_rxq[i]); + if (!skb) + break; + iod->recv_skb(iod, ld, skb); + } + } +} + +/** + * rx_ipc_frames + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @mst: pointer to an instance of mem_status structure + * + * Returns + * ret < 0 : error + * ret == 0 : ILLEGAL status + * ret > 0 : valid data + * + * Must be invoked only when there is data in the corresponding RXQ. + * + * Requires a recv_skb method in the io_device instance, so this function must + * be used for only SIPC5. + */ +static int rx_ipc_frames(struct shmem_link_device *shmd, int dev, + struct circ_status *circ) +{ + struct link_device *ld = &shmd->ld; + struct sk_buff_head *rxq = ld->skb_rxq[dev]; + struct sk_buff *skb; + int ret; + /** + * variables for the status of the circular queue + */ + u8 *src; + u8 hdr[SIPC5_MIN_HEADER_SIZE]; + /** + * variables for RX processing + */ + int qsize; /* size of the queue */ + int rcvd; /* size of data in the RXQ or error */ + int rest; /* size of the rest data */ + int out; /* index to the start of current frame */ + u8 *dst; /* pointer to the destination buffer */ + int tot; /* total length including padding data */ + + src = circ->buff; + qsize = circ->qsize; + out = circ->out; + rcvd = circ->size; + + rest = rcvd; + tot = 0; + while (rest > 0) { + /* Copy the header in the frame to the header buffer */ + circ_read(hdr, src, qsize, out, SIPC5_MIN_HEADER_SIZE); + + /* Check the config field in the header */ + if (unlikely(!sipc5_start_valid(hdr))) { + mif_err("%s: ERR! %s INVALID config 0x%02X " + "(rcvd %d, rest %d)\n", ld->name, + get_dev_name(dev), hdr[0], rcvd, rest); + ret = -EBADMSG; + goto exit; + } + + /* Verify the total length of the frame (data + padding) */ + tot = sipc5_get_total_len(hdr); + if (unlikely(tot > rest)) { + mif_err("%s: ERR! %s tot %d > rest %d (rcvd %d)\n", + ld->name, get_dev_name(dev), tot, rest, rcvd); + ret = -EBADMSG; + goto exit; + } + + /* Allocate an skb */ + skb = dev_alloc_skb(tot); + if (!skb) { + mif_err("%s: ERR! %s dev_alloc_skb fail\n", + ld->name, get_dev_name(dev)); + ret = -ENOMEM; + goto exit; + } + + /* Set the attribute of the skb as "single frame" */ + skbpriv(skb)->single_frame = true; + + /* Read the frame from the RXQ */ + dst = skb_put(skb, tot); + circ_read(dst, src, qsize, out, tot); + + /* Store the skb to the corresponding skb_rxq */ + skb_queue_tail(rxq, skb); + + /* Calculate new out value */ + rest -= tot; + out += tot; + if (unlikely(out >= qsize)) + out -= qsize; + } + + /* Update tail (out) pointer to empty out the RXQ */ + set_rxq_tail(shmd, dev, circ->in); + + return rcvd; + +exit: +#ifdef DEBUG_MODEM_IF + mif_err("%s: ERR! rcvd:%d tot:%d rest:%d\n", ld->name, rcvd, tot, rest); + pr_ipc(1, "c2c: ERR! CP2MIF", (src + out), (rest > 20) ? 20 : rest); +#endif + + return ret; +} + +/** + * msg_handler: receives IPC messages from every RXQ + * @shmd: pointer to an instance of shmem_link_device structure + * @mst: pointer to an instance of mem_status structure + * + * 1) Receives all IPC message frames currently in every IPC RXQ. + * 2) Sends RES_ACK responses if there are REQ_ACK requests from a CP. + * 3) Completes all threads waiting for the corresponding RES_ACK from a CP if + * there is any RES_ACK response. + */ +static void msg_handler(struct shmem_link_device *shmd, struct mem_status *mst) +{ + struct link_device *ld = &shmd->ld; + struct circ_status circ; + int i = 0; + int ret = 0; + + if (!ipc_active(shmd)) + return; + + /* Read data from every RXQ */ + for (i = 0; i < MAX_SIPC5_DEV; i++) { + /* Invoke an RX function only when there is data in the RXQ */ + if (likely(mst->head[i][RX] != mst->tail[i][RX])) { + ret = get_rxq_rcvd(shmd, i, mst, &circ); + if (unlikely(ret < 0)) { + mif_err("%s: ERR! get_rxq_rcvd fail (err %d)\n", + ld->name, ret); +#ifdef DEBUG_MODEM_IF + trigger_forced_cp_crash(shmd); +#endif + return; + } + + ret = rx_ipc_frames(shmd, i, &circ); + if (ret < 0) { +#ifdef DEBUG_MODEM_IF + trigger_forced_cp_crash(shmd); +#endif + reset_rxq_circ(shmd, i); + } + } + } + + /* Schedule soft IRQ for RX */ + queue_delayed_work(system_nrt_wq, &shmd->ipc_rx_dwork, 0); +} + +static void msg_rx_task(unsigned long data) +{ + struct shmem_link_device *shmd = (struct shmem_link_device *)data; + struct link_device *ld = &shmd->ld; + struct mem_status mst; + u16 mask = 0; + + get_shmem_status(shmd, RX, &mst); + + if ((mst.head[IPC_FMT][RX] != mst.tail[IPC_FMT][RX]) + || (mst.head[IPC_RAW][RX] != mst.tail[IPC_RAW][RX])) { +#if 0 + print_mem_status(ld, &mst); +#endif + msg_handler(shmd, &mst); + } + + /* + ** Check and process REQ_ACK (at this time, in == out) + */ + if (unlikely(shmd->dev[IPC_FMT]->req_ack_rcvd)) { + mask |= get_mask_res_ack(shmd, IPC_FMT); + shmd->dev[IPC_FMT]->req_ack_rcvd = 0; + } + + if (unlikely(shmd->dev[IPC_RAW]->req_ack_rcvd)) { + mask |= get_mask_res_ack(shmd, IPC_RAW); + shmd->dev[IPC_RAW]->req_ack_rcvd = 0; + } + + if (unlikely(mask)) { +#ifdef DEBUG_MODEM_IF + mif_info("%s: send RES_ACK 0x%04X\n", ld->name, mask); +#endif + send_int2cp(shmd, INT_NON_CMD(mask)); + } +} + +/** + * ipc_handler: processes a SHMEM command or receives IPC messages + * @shmd: pointer to an instance of shmem_link_device structure + * @mst: pointer to an instance of mem_status structure + * + * Invokes cmd_handler for a SHMEM command or msg_handler for IPC messages. + */ +static void ipc_handler(struct shmem_link_device *shmd, struct mem_status *mst) +{ +#ifdef DEBUG_MODEM_IF + struct link_device *ld = &shmd->ld; +#endif + u16 intr = mst->int2ap; + + if (unlikely(INT_CMD_VALID(intr))) { + cmd_handler(shmd, intr); + return; + } + + /* + ** Check REQ_ACK from CP -> REQ_ACK will be processed in the RX tasklet + */ + if (unlikely(intr & get_mask_req_ack(shmd, IPC_FMT))) + shmd->dev[IPC_FMT]->req_ack_rcvd = 1; + + if (unlikely(intr & get_mask_req_ack(shmd, IPC_RAW))) + shmd->dev[IPC_RAW]->req_ack_rcvd = 1; + + /* + ** Check and process RES_ACK from CP + */ + if (unlikely(intr & get_mask_res_ack(shmd, IPC_FMT))) { +#ifdef DEBUG_MODEM_IF + mif_info("%s: recv FMT RES_ACK\n", ld->name); +#endif + complete(&shmd->req_ack_cmpl[IPC_FMT]); + } + + if (unlikely(intr & get_mask_res_ack(shmd, IPC_RAW))) { +#ifdef DEBUG_MODEM_IF + mif_info("%s: recv RAW RES_ACK\n", ld->name); +#endif + complete(&shmd->req_ack_cmpl[IPC_RAW]); + } + + /* + ** Schedule RX tasklet + */ + tasklet_hi_schedule(&shmd->rx_tsk); +} + +/** + * rx_udl_frames + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @mst: pointer to an instance of mem_status structure + * + * Returns + * ret < 0 : error + * ret == 0 : ILLEGAL status + * ret > 0 : valid data + * + * Must be invoked only when there is data in the corresponding RXQ. + * + * Requires a recv_skb method in the io_device instance, so this function must + * be used for only SIPC5. + */ +static int rx_udl_frames(struct shmem_link_device *shmd, int dev, + struct circ_status *circ) +{ + struct link_device *ld = &shmd->ld; + struct io_device *iod; + struct sk_buff *skb; + int ret; + /** + * variables for the status of the circular queue + */ + u8 *src; + u8 hdr[SIPC5_MIN_HEADER_SIZE]; + /** + * variables for RX processing + */ + int qsize; /* size of the queue */ + int rcvd; /* size of data in the RXQ or error */ + int rest; /* size of the rest data */ + int out; /* index to the start of current frame */ + u8 *dst; /* pointer to the destination buffer */ + int tot; /* total length including padding data */ + + src = circ->buff; + qsize = circ->qsize; + out = circ->out; + rcvd = circ->size; + + rest = rcvd; + tot = 0; + while (rest > 0) { + /* Copy the header in the frame to the header buffer */ + circ_read(hdr, src, qsize, out, SIPC5_MIN_HEADER_SIZE); + + /* Check the config field in the header */ + if (unlikely(!sipc5_start_valid(hdr))) { + mif_err("%s: ERR! %s INVALID config 0x%02X " + "(rest %d, rcvd %d)\n", ld->name, + get_dev_name(dev), hdr[0], rest, rcvd); + pr_ipc(1, "UDL", (src + out), (rest > 20) ? 20 : rest); + ret = -EBADMSG; + goto exit; + } + + /* Verify the total length of the frame (data + padding) */ + tot = sipc5_get_total_len(hdr); + if (unlikely(tot > rest)) { + mif_err("%s: ERR! %s tot %d > rest %d (rcvd %d)\n", + ld->name, get_dev_name(dev), tot, rest, rcvd); + ret = -ENODATA; + goto exit; + } + + /* Allocate an skb */ + skb = alloc_skb(tot + NET_SKB_PAD, GFP_KERNEL); + if (!skb) { + mif_err("%s: ERR! %s alloc_skb fail\n", + ld->name, get_dev_name(dev)); + ret = -ENOMEM; + goto exit; + } + skb_reserve(skb, NET_SKB_PAD); + + /* Set the attribute of the skb as "single frame" */ + skbpriv(skb)->single_frame = true; + + /* Read the frame from the RXQ */ + dst = skb_put(skb, tot); + circ_read(dst, src, qsize, out, tot); + + /* Pass the skb to an iod */ + iod = link_get_iod_with_channel(ld, sipc5_get_ch_id(skb->data)); + if (!iod) { + mif_err("%s: ERR! no IPC_BOOT iod\n", ld->name); + break; + } + +#ifdef DEBUG_MODEM_IF + if (!std_udl_with_payload(std_udl_get_cmd(skb->data))) { + if (ld->mode == LINK_MODE_DLOAD) { + pr_ipc(0, "[CP->AP] DL CMD", skb->data, + (skb->len > 20 ? 20 : skb->len)); + } else { + pr_ipc(0, "[CP->AP] UL CMD", skb->data, + (skb->len > 20 ? 20 : skb->len)); + } + } +#endif + + iod->recv_skb(iod, ld, skb); + + /* Calculate new out value */ + rest -= tot; + out += tot; + if (unlikely(out >= qsize)) + out -= qsize; + } + + /* Update tail (out) pointer to empty out the RXQ */ + set_rxq_tail(shmd, dev, circ->in); + + return rcvd; + +exit: + return ret; +} + +/** + * udl_rx_work + * @ws: pointer to an instance of the work_struct structure + * + * Invokes the recv method in the io_device instance to perform receiving IPC + * messages from each skb. + */ +static void udl_rx_work(struct work_struct *ws) +{ + struct shmem_link_device *shmd; + struct link_device *ld; + struct sk_buff_head *rxq; + struct mem_status mst; + struct circ_status circ; + int dev = IPC_RAW; + + shmd = container_of(ws, struct shmem_link_device, udl_rx_dwork.work); + ld = &shmd->ld; + rxq = ld->skb_rxq[dev]; + + while (1) { + get_shmem_status(shmd, RX, &mst); + if (mst.head[dev][RX] == mst.tail[dev][RX]) + break; + + /* Invoke an RX function only when there is data in the RXQ */ + if (get_rxq_rcvd(shmd, dev, &mst, &circ) < 0) { + mif_err("%s: ERR! get_rxq_rcvd fail\n", ld->name); +#ifdef DEBUG_MODEM_IF + trigger_forced_cp_crash(shmd); +#endif + break; + } + + if (rx_udl_frames(shmd, dev, &circ) < 0) { + skb_queue_purge(rxq); + break; + } + } +} + +/** + * udl_handler: receives BOOT/DUMP IPC messages from every RXQ + * @shmd: pointer to an instance of shmem_link_device structure + * @mst: pointer to an instance of mem_status structure + * + * 1) Receives all IPC message frames currently in every IPC RXQ. + * 2) Sends RES_ACK responses if there are REQ_ACK requests from a CP. + * 3) Completes all threads waiting for the corresponding RES_ACK from a CP if + * there is any RES_ACK response. + */ +static void udl_handler(struct shmem_link_device *shmd, struct mem_status *mst) +{ + u16 intr = mst->int2ap; + + /* Schedule soft IRQ for RX */ + queue_delayed_work(system_nrt_wq, &shmd->udl_rx_dwork, 0); + + /* Check and process RES_ACK */ + if (intr & INT_MASK_RES_ACK_SET) { + if (intr & get_mask_res_ack(shmd, IPC_RAW)) { +#ifdef DEBUG_MODEM_IF + struct link_device *ld = &shmd->ld; + mif_info("%s: recv RAW RES_ACK\n", ld->name); + print_circ_status(ld, IPC_RAW, mst); +#endif + complete(&shmd->req_ack_cmpl[IPC_RAW]); + } + } +} + +/** + * c2c_irq_handler: interrupt handler for a C2C interrupt + * @data: pointer to a data + * + * 1) Reads the interrupt value + * 2) Performs interrupt handling + * + * Flow for normal interrupt handling: + * c2c_irq_handler -> udl_handler + * c2c_irq_handler -> ipc_handler -> cmd_handler -> cmd_xxx_handler + * c2c_irq_handler -> ipc_handler -> msg_handler -> rx_ipc_frames -> ... + */ +static void c2c_irq_handler(void *data, u32 intr) +{ + struct shmem_link_device *shmd = (struct shmem_link_device *)data; + struct link_device *ld = (struct link_device *)&shmd->ld; + struct mem_status *mst = msq_get_free_slot(&shmd->stat_list); + + get_shmem_status(shmd, RX, mst); + + if (unlikely(ld->mode == LINK_MODE_OFFLINE)) { + mif_info("%s: ld->mode == LINK_MODE_OFFLINE\n", ld->name); + return; + } + + if (unlikely(!INT_VALID(intr))) { + mif_info("%s: ERR! invalid intr 0x%X\n", ld->name, intr); + return; + } + + mst->int2ap = intr; + + if (ld->mode == LINK_MODE_DLOAD || ld->mode == LINK_MODE_ULOAD) + udl_handler(shmd, mst); + else + ipc_handler(shmd, mst); +} + +#if 1 +/* Functions for IPC/BOOT/DUMP TX */ +#endif + +/** + * write_ipc_to_txq + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @circ: pointer to an instance of circ_status structure + * @skb: pointer to an instance of sk_buff structure + * + * Must be invoked only when there is enough space in the TXQ. + */ +static void write_ipc_to_txq(struct shmem_link_device *shmd, int dev, + struct circ_status *circ, struct sk_buff *skb) +{ + u32 qsize = circ->qsize; + u32 in = circ->in; + u8 *buff = circ->buff; + u8 *src = skb->data; + u32 len = skb->len; +#ifdef DEBUG_MODEM_IF + struct io_device *iod = skbpriv(skb)->iod; + struct modem_ctl *mc = shmd->ld.mc; + char tag[MIF_MAX_STR_LEN]; + + snprintf(tag, MIF_MAX_STR_LEN, "LNK: %s->%s", iod->name, mc->name); + + if (dev == IPC_FMT) + pr_ipc(1, tag, src, (len > 20 ? 20 : len)); +#if 0 + if (dev == IPC_RAW) + pr_ipc(0, tag, src, (len > 20 ? 20 : len)); +#endif +#endif + + /* Write data to the TXQ */ + circ_write(buff, src, qsize, in, len); + + /* Update new head (in) pointer */ + set_txq_head(shmd, dev, circ_new_pointer(qsize, in, len)); +} + +/** + * xmit_ipc_msg + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Tries to transmit IPC messages in the skb_txq of @dev as many as possible. + * + * Returns total length of IPC messages transmitted or an error code. + */ +static int xmit_ipc_msg(struct shmem_link_device *shmd, int dev) +{ + struct link_device *ld = &shmd->ld; + struct sk_buff_head *txq = ld->skb_txq[dev]; + struct sk_buff *skb; + unsigned long flags; + struct circ_status circ; + int space; + int copied = 0; + + /* Acquire the spin lock for a TXQ */ + spin_lock_irqsave(&shmd->tx_lock[dev], flags); + + while (1) { + /* Get the size of free space in the TXQ */ + space = get_txq_space(shmd, dev, &circ); + if (unlikely(space < 0)) { +#ifdef DEBUG_MODEM_IF + /* Trigger a enforced CP crash */ + trigger_forced_cp_crash(shmd); +#endif + /* Empty out the TXQ */ + reset_txq_circ(shmd, dev); + copied = -EIO; + break; + } + + skb = skb_dequeue(txq); + if (unlikely(!skb)) + break; + + /* Check the free space size comparing with skb->len */ + if (unlikely(space < skb->len)) { +#ifdef DEBUG_MODEM_IF + struct mem_status mst; +#endif + /* Set res_required flag for the "dev" */ + atomic_set(&shmd->res_required[dev], 1); + + /* Take the skb back to the skb_txq */ + skb_queue_head(txq, skb); + + mif_err("%s: <by %pf> NOSPC in %s_TXQ" + "{qsize:%u in:%u out:%u} free:%u < len:%u\n", + ld->name, CALLER, get_dev_name(dev), + circ.qsize, circ.in, circ.out, space, skb->len); +#ifdef DEBUG_MODEM_IF + get_shmem_status(shmd, TX, &mst); + print_circ_status(ld, dev, &mst); +#endif + copied = -ENOSPC; + break; + } + +#ifdef DEBUG_MODEM_IF + if (!ipc_active(shmd)) { + if (get_magic(shmd) == SHM_PM_MAGIC) { + mif_err("%s: Going to SLEEP\n", ld->name); + copied = -EBUSY; + } else { + mif_err("%s: IPC is NOT active\n", ld->name); + copied = -EIO; + } + break; + } +#endif + + /* TX only when there is enough space in the TXQ */ + write_ipc_to_txq(shmd, dev, &circ, skb); + copied += skb->len; + dev_kfree_skb_any(skb); + } + + /* Release the spin lock */ + spin_unlock_irqrestore(&shmd->tx_lock[dev], flags); + + return copied; +} + +/** + * wait_for_res_ack + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * 1) Sends an REQ_ACK interrupt for @dev to CP. + * 2) Waits for the corresponding RES_ACK for @dev from CP. + * + * Returns the return value from wait_for_completion_interruptible_timeout(). + */ +static int wait_for_res_ack(struct shmem_link_device *shmd, int dev) +{ + struct link_device *ld = &shmd->ld; + struct completion *cmpl = &shmd->req_ack_cmpl[dev]; + unsigned long timeout = msecs_to_jiffies(RES_ACK_WAIT_TIMEOUT); + int ret; + u16 mask; + +#ifdef DEBUG_MODEM_IF + mif_info("%s: send %s REQ_ACK\n", ld->name, get_dev_name(dev)); +#endif + + mask = get_mask_req_ack(shmd, dev); + send_int2cp(shmd, INT_NON_CMD(mask)); + + /* ret < 0 if interrupted, ret == 0 on timeout */ + ret = wait_for_completion_interruptible_timeout(cmpl, timeout); + if (ret < 0) { + mif_err("%s: %s: wait_for_completion interrupted! (ret %d)\n", + ld->name, get_dev_name(dev), ret); + goto exit; + } + + if (ret == 0) { + struct mem_status mst; + get_shmem_status(shmd, TX, &mst); + + mif_err("%s: wait_for_completion TIMEOUT! (no %s_RES_ACK)\n", + ld->name, get_dev_name(dev)); + + /* + ** The TXQ must be checked whether or not it is empty, because + ** an interrupt mask can be overwritten by the next interrupt. + */ + if (mst.head[dev][TX] == mst.tail[dev][TX]) { + ret = get_txq_buff_size(shmd, dev); +#ifdef DEBUG_MODEM_IF + mif_err("%s: %s_TXQ has been emptied\n", + ld->name, get_dev_name(dev)); + print_circ_status(ld, dev, &mst); +#endif + } + } + +exit: + return ret; +} + +/** + * process_res_ack + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * 1) Tries to transmit IPC messages in the skb_txq with xmit_ipc_msg(). + * 2) Sends an interrupt to CP if there is no error from xmit_ipc_msg(). + * 3) Restarts SHMEM flow control if xmit_ipc_msg() returns -ENOSPC. + * + * Returns the return value from xmit_ipc_msg(). + */ +static int process_res_ack(struct shmem_link_device *shmd, int dev) +{ + int ret; + u16 mask; + + ret = xmit_ipc_msg(shmd, dev); + if (ret > 0) { + mask = get_mask_send(shmd, dev); + send_int2cp(shmd, INT_NON_CMD(mask)); + get_shmem_status(shmd, TX, msq_get_free_slot(&shmd->stat_list)); + } + + if (ret >= 0) + atomic_set(&shmd->res_required[dev], 0); + + return ret; +} + +/** + * fmt_tx_work: performs TX for FMT IPC device under SHMEM flow control + * @ws: pointer to an instance of the work_struct structure + * + * 1) Starts waiting for RES_ACK of FMT IPC device. + * 2) Returns immediately if the wait is interrupted. + * 3) Restarts SHMEM flow control if there is a timeout from the wait. + * 4) Otherwise, it performs processing RES_ACK for FMT IPC device. + */ +static void fmt_tx_work(struct work_struct *ws) +{ + struct link_device *ld; + struct shmem_link_device *shmd; + int ret; + + ld = container_of(ws, struct link_device, fmt_tx_dwork.work); + shmd = to_shmem_link_device(ld); + + ret = wait_for_res_ack(shmd, IPC_FMT); + /* ret < 0 if interrupted */ + if (ret < 0) + return; + + /* ret == 0 on timeout */ + if (ret == 0) { + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_FMT], 0); + return; + } + + ret = process_res_ack(shmd, IPC_FMT); + if (ret >= 0) { + permit_cp_sleep(shmd); + return; + } + + /* At this point, ret < 0 */ + if (ret == -ENOSPC || ret == -EBUSY) { + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_FMT], + msecs_to_jiffies(1)); + } +} + +/** + * raw_tx_work: performs TX for RAW IPC device under SHMEM flow control. + * @ws: pointer to an instance of the work_struct structure + * + * 1) Starts waiting for RES_ACK of RAW IPC device. + * 2) Returns immediately if the wait is interrupted. + * 3) Restarts SHMEM flow control if there is a timeout from the wait. + * 4) Otherwise, it performs processing RES_ACK for RAW IPC device. + */ +static void raw_tx_work(struct work_struct *ws) +{ + struct link_device *ld; + struct shmem_link_device *shmd; + int ret; + + ld = container_of(ws, struct link_device, raw_tx_dwork.work); + shmd = to_shmem_link_device(ld); + + ret = wait_for_res_ack(shmd, IPC_RAW); + /* ret < 0 if interrupted */ + if (ret < 0) + return; + + /* ret == 0 on timeout */ + if (ret == 0) { + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_RAW], 0); + return; + } + + ret = process_res_ack(shmd, IPC_RAW); + if (ret >= 0) { + permit_cp_sleep(shmd); + mif_netif_wake(ld); + return; + } + + /* At this point, ret < 0 */ + if (ret == -ENOSPC || ret == -EBUSY) { + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_RAW], + msecs_to_jiffies(1)); + } +} + +/** + * c2c_send_ipc + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @skb: pointer to an skb that will be transmitted + * + * 1) Tries to transmit IPC messages in the skb_txq with xmit_ipc_msg(). + * 2) Sends an interrupt to CP if there is no error from xmit_ipc_msg(). + * 3) Starts SHMEM flow control if xmit_ipc_msg() returns -ENOSPC. + */ +static int c2c_send_ipc(struct shmem_link_device *shmd, int dev) +{ + struct link_device *ld = &shmd->ld; + int ret; + u16 mask; + + if (atomic_read(&shmd->res_required[dev]) > 0) { + mif_info("%s: %s_TXQ is full\n", ld->name, get_dev_name(dev)); + return 0; + } + + ret = xmit_ipc_msg(shmd, dev); + if (likely(ret > 0)) { + mask = get_mask_send(shmd, dev); + send_int2cp(shmd, INT_NON_CMD(mask)); + get_shmem_status(shmd, TX, msq_get_free_slot(&shmd->stat_list)); + goto exit; + } + + /* If there was no TX, just exit */ + if (ret == 0) + goto exit; + + /* At this point, ret < 0 */ + if (ret == -ENOSPC || ret == -EBUSY) { + /* Prohibit CP from sleeping until the TXQ buffer is empty */ + if (forbid_cp_sleep(shmd) < 0) { + trigger_forced_cp_crash(shmd); + goto exit; + } + + /*----------------------------------------------------*/ + /* shmd->res_required[dev] was set in xmit_ipc_msg(). */ + /*----------------------------------------------------*/ + + if (dev == IPC_RAW) + mif_netif_stop(ld); + + queue_delayed_work(ld->tx_wq, ld->tx_dwork[dev], + msecs_to_jiffies(1)); + } + +exit: + return ret; +} + +/** + * c2c_try_send_ipc + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @iod: pointer to an instance of the io_device structure + * @skb: pointer to an skb that will be transmitted + * + * 1) Enqueues an skb to the skb_txq for @dev in the link device instance. + * 2) Tries to transmit IPC messages with c2c_send_ipc(). + */ +static void c2c_try_send_ipc(struct shmem_link_device *shmd, int dev, + struct io_device *iod, struct sk_buff *skb) +{ + struct link_device *ld = &shmd->ld; + struct sk_buff_head *txq = ld->skb_txq[dev]; + int ret; + + if (forbid_cp_sleep(shmd) < 0) { + trigger_forced_cp_crash(shmd); + goto exit; + } + + if (unlikely(txq->qlen >= MAX_SKB_TXQ_DEPTH)) { + mif_err("%s: %s txq->qlen %d >= %d\n", ld->name, + get_dev_name(dev), txq->qlen, MAX_SKB_TXQ_DEPTH); + dev_kfree_skb_any(skb); + goto exit; + } + + skb_queue_tail(txq, skb); + + ret = c2c_send_ipc(shmd, dev); + if (ret < 0) { + mif_err("%s->%s: ERR! c2c_send_ipc fail (err %d)\n", + iod->name, ld->name, ret); + } + +exit: + permit_cp_sleep(shmd); +} + +static int c2c_send_udl_cmd(struct shmem_link_device *shmd, int dev, + struct io_device *iod, struct sk_buff *skb) +{ + struct link_device *ld = &shmd->ld; + u8 *buff; + u8 *src; + u32 qsize; + u32 in; + int space; + int tx_bytes; + struct circ_status circ; + + if (iod->format == IPC_BOOT) { + pr_ipc(0, "[AP->CP] DL CMD", skb->data, + (skb->len > 20 ? 20 : skb->len)); + } else { + pr_ipc(0, "[AP->CP] UL CMD", skb->data, + (skb->len > 20 ? 20 : skb->len)); + } + + /* Get the size of free space in the TXQ */ + space = get_txq_space(shmd, dev, &circ); + if (space < 0) { + reset_txq_circ(shmd, dev); + tx_bytes = -EIO; + goto exit; + } + + /* Get the size of data to be sent */ + tx_bytes = skb->len; + + /* Check the size of free space */ + if (space < tx_bytes) { + mif_err("%s: NOSPC in %s_TXQ {qsize:%u in:%u out:%u}, " + "free:%u < tx_bytes:%u\n", ld->name, get_dev_name(dev), + circ.qsize, circ.in, circ.out, space, tx_bytes); + tx_bytes = -ENOSPC; + goto exit; + } + + /* Write data to the TXQ */ + buff = circ.buff; + src = skb->data; + qsize = circ.qsize; + in = circ.in; + circ_write(buff, src, qsize, in, tx_bytes); + + /* Update new head (in) pointer */ + set_txq_head(shmd, dev, circ_new_pointer(qsize, circ.in, tx_bytes)); + +exit: + dev_kfree_skb_any(skb); + return tx_bytes; +} + +static int c2c_send_udl_data(struct shmem_link_device *shmd, int dev) +{ + struct link_device *ld = &shmd->ld; + struct sk_buff_head *txq = ld->skb_txq[dev]; + struct sk_buff *skb; + u8 *src; + int tx_bytes; + int copied; + u8 *buff; + u32 qsize; + u32 in; + u32 out; + int space; + struct circ_status circ; + + /* Get the size of free space in the TXQ */ + space = get_txq_space(shmd, dev, &circ); + if (space < 0) { +#ifdef DEBUG_MODEM_IF + /* Trigger a enforced CP crash */ + trigger_forced_cp_crash(shmd); +#endif + /* Empty out the TXQ */ + reset_txq_circ(shmd, dev); + return -EFAULT; + } + + buff = circ.buff; + qsize = circ.qsize; + in = circ.in; + out = circ.out; + space = circ.size; + + copied = 0; + while (1) { + skb = skb_dequeue(txq); + if (!skb) + break; + + /* Get the size of data to be sent */ + src = skb->data; + tx_bytes = skb->len; + + /* Check the free space size comparing with skb->len */ + if (space < tx_bytes) { + /* Set res_required flag for the "dev" */ + atomic_set(&shmd->res_required[dev], 1); + + /* Take the skb back to the skb_txq */ + skb_queue_head(txq, skb); + + mif_info("NOSPC in RAW_TXQ {qsize:%u in:%u out:%u}, " + "space:%u < tx_bytes:%u\n", + qsize, in, out, space, tx_bytes); + break; + } + + /* + ** TX only when there is enough space in the TXQ + */ + circ_write(buff, src, qsize, in, tx_bytes); + + copied += tx_bytes; + in = circ_new_pointer(qsize, in, tx_bytes); + space -= tx_bytes; + + dev_kfree_skb_any(skb); + } + + /* Update new head (in) pointer */ + if (copied > 0) { + in = circ_new_pointer(qsize, circ.in, copied); + set_txq_head(shmd, dev, in); + } + + return copied; +} + +/** + * c2c_send_udl + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @iod: pointer to an instance of the io_device structure + * @skb: pointer to an skb that will be transmitted + * + * 1) Enqueues an skb to the skb_txq for @dev in the link device instance. + * 2) Tries to transmit IPC messages in the skb_txq by invoking xmit_ipc_msg() + * function. + * 3) Sends an interrupt to CP if there is no error from xmit_ipc_msg(). + * 4) Starts SHMEM flow control if xmit_ipc_msg() returns -ENOSPC. + */ +static void c2c_send_udl(struct shmem_link_device *shmd, int dev, + struct io_device *iod, struct sk_buff *skb) +{ + struct link_device *ld = &shmd->ld; + struct sk_buff_head *txq = ld->skb_txq[dev]; + struct completion *cmpl = &shmd->req_ack_cmpl[dev]; + struct std_dload_info *dl_info = &shmd->dl_info; + struct mem_status mst; + u32 timeout = msecs_to_jiffies(RES_ACK_WAIT_TIMEOUT); + u32 udl_cmd; + int ret; + u16 mask = get_mask_send(shmd, dev); + + udl_cmd = std_udl_get_cmd(skb->data); + if (iod->format == IPC_RAMDUMP || !std_udl_with_payload(udl_cmd)) { + ret = c2c_send_udl_cmd(shmd, dev, iod, skb); + if (ret > 0) + send_int2cp(shmd, INT_NON_CMD(mask)); + else + mif_err("ERR! c2c_send_udl_cmd fail (err %d)\n", ret); + goto exit; + } + + skb_queue_tail(txq, skb); + if (txq->qlen < dl_info->num_frames) + goto exit; + + mask |= get_mask_req_ack(shmd, dev); + while (1) { + ret = c2c_send_udl_data(shmd, dev); + if (ret < 0) { + mif_err("ERR! c2c_send_udl_data fail (err %d)\n", ret); + skb_queue_purge(txq); + break; + } + + if (skb_queue_empty(txq)) { + send_int2cp(shmd, INT_NON_CMD(mask)); + break; + } + + send_int2cp(shmd, INT_NON_CMD(mask)); + + do { + ret = wait_for_completion_timeout(cmpl, timeout); + get_shmem_status(shmd, TX, &mst); + } while (mst.head[dev][TX] != mst.tail[dev][TX]); + } + +exit: + return; +} + +/** + * c2c_send + * @ld: pointer to an instance of the link_device structure + * @iod: pointer to an instance of the io_device structure + * @skb: pointer to an skb that will be transmitted + * + * Returns the length of data transmitted or an error code. + * + * Normal call flow for an IPC message: + * c2c_try_send_ipc -> c2c_send_ipc -> xmit_ipc_msg -> write_ipc_to_txq + * + * Call flow on congestion in a IPC TXQ: + * c2c_try_send_ipc -> c2c_send_ipc -> xmit_ipc_msg ,,, queue_delayed_work + * => xxx_tx_work -> wait_for_res_ack + * => msg_handler + * => process_res_ack -> xmit_ipc_msg (,,, queue_delayed_work ...) + */ +static int c2c_send(struct link_device *ld, struct io_device *iod, + struct sk_buff *skb) +{ + struct shmem_link_device *shmd = to_shmem_link_device(ld); + int dev = iod->format; + int len = skb->len; + + switch (dev) { + case IPC_FMT: + case IPC_RAW: + if (likely(ld->mode == LINK_MODE_IPC)) { + c2c_try_send_ipc(shmd, dev, iod, skb); + } else { + mif_err("%s->%s: ERR! ld->mode != LINK_MODE_IPC\n", + iod->name, ld->name); + dev_kfree_skb_any(skb); + } + return len; + + case IPC_BOOT: + case IPC_RAMDUMP: + c2c_send_udl(shmd, IPC_RAW, iod, skb); + return len; + + default: + mif_err("%s: ERR! no TXQ for %s\n", ld->name, iod->name); + dev_kfree_skb_any(skb); + return -ENODEV; + } +} + +#if 1 +/* Functions for BOOT/DUMP and INIT */ +#endif + +static int c2c_dload_start(struct link_device *ld, struct io_device *iod) +{ + struct shmem_link_device *shmd = to_shmem_link_device(ld); + u32 magic; + + ld->mode = LINK_MODE_DLOAD; + + clear_shmem_map(shmd); + + set_magic(shmd, SHM_BOOT_MAGIC); + magic = get_magic(shmd); + if (magic != SHM_BOOT_MAGIC) { + mif_err("%s: ERR! magic 0x%08X != SHM_BOOT_MAGIC 0x%08X\n", + ld->name, magic, SHM_BOOT_MAGIC); + return -EFAULT; + } + + return 0; +} + +/** + * c2c_set_dload_info + * @ld: pointer to an instance of link_device structure + * @iod: pointer to an instance of io_device structure + * @arg: pointer to an instance of std_dload_info structure in "user" memory + * + */ +static int c2c_set_dload_info(struct link_device *ld, struct io_device *iod, + unsigned long arg) +{ + struct shmem_link_device *shmd = to_shmem_link_device(ld); + struct std_dload_info *dl_info = &shmd->dl_info; + int ret; + + ret = copy_from_user(dl_info, (void __user *)arg, + sizeof(struct std_dload_info)); + if (ret) { + mif_err("ERR! copy_from_user fail!\n"); + return -EFAULT; + } + + return 0; +} + +static int c2c_force_dump(struct link_device *ld, struct io_device *iod) +{ + struct shmem_link_device *shmd = to_shmem_link_device(ld); + mif_err("+++\n"); + trigger_forced_cp_crash(shmd); + mif_err("---\n"); + return 0; +} + +static int c2c_dump_start(struct link_device *ld, struct io_device *iod) +{ + struct shmem_link_device *shmd = to_shmem_link_device(ld); + + ld->mode = LINK_MODE_ULOAD; + + clear_shmem_map(shmd); + + mif_err("%s: magic = 0x%08X\n", ld->name, SHM_DUMP_MAGIC); + set_magic(shmd, SHM_DUMP_MAGIC); + + return 0; +} + +static void c2c_remap_4mb_ipc_region(struct shmem_link_device *shmd) +{ + struct shmem_4mb_phys_map *map; + struct shmem_ipc_device *dev; + + map = (struct shmem_4mb_phys_map *)shmd->base; + + /* Magic code and access enable fields */ + shmd->ipc_map.magic = (u32 __iomem *)&map->magic; + shmd->ipc_map.access = (u32 __iomem *)&map->access; + + /* FMT */ + dev = &shmd->ipc_map.dev[IPC_FMT]; + + strcpy(dev->name, "FMT"); + dev->id = IPC_FMT; + + dev->txq.head = (u32 __iomem *)&map->fmt_tx_head; + dev->txq.tail = (u32 __iomem *)&map->fmt_tx_tail; + dev->txq.buff = (u8 __iomem *)&map->fmt_tx_buff[0]; + dev->txq.size = SHM_4M_FMT_TX_BUFF_SZ; + + dev->rxq.head = (u32 __iomem *)&map->fmt_rx_head; + dev->rxq.tail = (u32 __iomem *)&map->fmt_rx_tail; + dev->rxq.buff = (u8 __iomem *)&map->fmt_rx_buff[0]; + dev->rxq.size = SHM_4M_FMT_RX_BUFF_SZ; + + dev->mask_req_ack = INT_MASK_REQ_ACK_F; + dev->mask_res_ack = INT_MASK_RES_ACK_F; + dev->mask_send = INT_MASK_SEND_F; + + /* RAW */ + dev = &shmd->ipc_map.dev[IPC_RAW]; + + strcpy(dev->name, "RAW"); + dev->id = IPC_RAW; + + dev->txq.head = (u32 __iomem *)&map->raw_tx_head; + dev->txq.tail = (u32 __iomem *)&map->raw_tx_tail; + dev->txq.buff = (u8 __iomem *)&map->raw_tx_buff[0]; + dev->txq.size = SHM_4M_RAW_TX_BUFF_SZ; + + dev->rxq.head = (u32 __iomem *)&map->raw_rx_head; + dev->rxq.tail = (u32 __iomem *)&map->raw_rx_tail; + dev->rxq.buff = (u8 __iomem *)&map->raw_rx_buff[0]; + dev->rxq.size = SHM_4M_RAW_RX_BUFF_SZ; + + dev->mask_req_ack = INT_MASK_REQ_ACK_R; + dev->mask_res_ack = INT_MASK_RES_ACK_R; + dev->mask_send = INT_MASK_SEND_R; + + /* interrupt ports */ + shmd->ipc_map.mbx2ap = NULL; + shmd->ipc_map.mbx2cp = NULL; +} + +static int c2c_init_ipc_map(struct shmem_link_device *shmd) +{ + if (shmd->size >= SHMEM_SIZE_4MB) + c2c_remap_4mb_ipc_region(shmd); + else + return -EINVAL; + + memset(shmd->base, 0, shmd->size); + + shmd->magic = shmd->ipc_map.magic; + shmd->access = shmd->ipc_map.access; + + shmd->dev[IPC_FMT] = &shmd->ipc_map.dev[IPC_FMT]; + shmd->dev[IPC_RAW] = &shmd->ipc_map.dev[IPC_RAW]; + + shmd->mbx2ap = shmd->ipc_map.mbx2ap; + shmd->mbx2cp = shmd->ipc_map.mbx2cp; + + return 0; +} +static int c2c_init_communication(struct link_device *ld, struct io_device *iod) +{ + struct shmem_link_device *shmd = to_shmem_link_device(ld); + struct io_device *check_iod; + + if (iod->format == IPC_BOOT) + return 0; + + /* send 0xC2 */ + switch(iod->format) { + case IPC_FMT: + check_iod = link_get_iod_with_format(ld, IPC_RFS); + if (check_iod ? atomic_read(&check_iod->opened) : true) { + mif_err("%s: Send 0xC2 (INIT_END)\n", ld->name); + send_int2cp(shmd, INT_CMD(INT_CMD_INIT_END)); + } else + mif_err("%s defined but not opened\n", check_iod->name); + break; + case IPC_RFS: + check_iod = link_get_iod_with_format(ld, IPC_FMT); + if (check_iod && atomic_read(&check_iod->opened)) { + mif_err("%s: Send 0xC2 (INIT_END)\n", ld->name); + send_int2cp(shmd, INT_CMD(INT_CMD_INIT_END)); + } else + mif_err("not opened\n"); + break; + default: + break; + } + return 0; +} + +#if 0 +static void c2c_link_terminate(struct link_device *ld, struct io_device *iod) +{ + if (iod->format == IPC_FMT && ld->mode == LINK_MODE_IPC) { + if (!atomic_read(&iod->opened)) { + ld->mode = LINK_MODE_OFFLINE; + mif_err("%s: %s: link mode changed: IPC -> OFFLINE\n", + iod->name, ld->name); + } + } + + return; +} +#endif + struct link_device *c2c_create_link_device(struct platform_device *pdev) { - struct c2c_link_device *dpld; + struct modem_data *modem; + struct shmem_link_device *shmd; struct link_device *ld; - struct modem_data *pdata; + int err; + int i; + u32 phys_base; + u32 offset; + u32 size; + int irq; + unsigned long irq_flags; + char name[MIF_MAX_NAME_LEN]; - pdata = pdev->dev.platform_data; + /* + ** Get the modem (platform) data + */ + modem = (struct modem_data *)pdev->dev.platform_data; + if (!modem) { + mif_err("ERR! modem == NULL\n"); + return NULL; + } + mif_err("%s: %s\n", modem->link_name, modem->name); - dpld = kzalloc(sizeof(struct c2c_link_device), GFP_KERNEL); - if (!dpld) { - mif_err("dpld == NULL\n"); + if (modem->ipc_version < SIPC_VER_50) { + mif_err("%s: %s: ERR! IPC version %d < SIPC_VER_50\n", + modem->link_name, modem->name, modem->ipc_version); return NULL; } - wake_lock_init(&dpld->c2c_wake_lock, WAKE_LOCK_SUSPEND, "c2c_wakelock"); - wake_lock(&dpld->c2c_wake_lock); + /* + ** Alloc an instance of shmem_link_device structure + */ + shmd = kzalloc(sizeof(struct shmem_link_device), GFP_KERNEL); + if (!shmd) { + mif_err("%s: ERR! shmd kzalloc fail\n", modem->link_name); + goto error; + } + ld = &shmd->ld; + + /* + ** Retrieve modem data and SHMEM control data from the modem data + */ + ld->mdm_data = modem; + ld->name = modem->link_name; + ld->aligned = 1; + ld->ipc_version = modem->ipc_version; + ld->max_ipc_dev = MAX_SIPC5_DEV; + + /* + ** Set attributes as a link device + */ + ld->init_comm = c2c_init_communication; +#if 0 + ld->terminate_comm = c2c_link_terminate; +#endif + ld->send = c2c_send; + ld->dload_start = c2c_dload_start; + ld->firm_update = c2c_set_dload_info; + ld->force_dump = c2c_force_dump; + ld->dump_start = c2c_dump_start; + + INIT_LIST_HEAD(&ld->list); - ld = &dpld->ld; - dpld->pdata = pdata; + skb_queue_head_init(&ld->sk_fmt_tx_q); + skb_queue_head_init(&ld->sk_raw_tx_q); + ld->skb_txq[IPC_FMT] = &ld->sk_fmt_tx_q; + ld->skb_txq[IPC_RAW] = &ld->sk_raw_tx_q; - ld->name = "c2c"; + skb_queue_head_init(&ld->sk_fmt_rx_q); + skb_queue_head_init(&ld->sk_raw_rx_q); + ld->skb_rxq[IPC_FMT] = &ld->sk_fmt_rx_q; + ld->skb_rxq[IPC_RAW] = &ld->sk_raw_rx_q; - mif_info("%s is created!!!\n", dpld->ld.name); + init_completion(&ld->init_cmpl); + + /* + ** Retrieve SHMEM resource + */ + if (modem->link_types & LINKTYPE(LINKDEV_C2C)) { + shmd->type = C2C_SHMEM; + mif_debug("%s: shmd->type = C2C_SHMEM\n", ld->name); + } else if (modem->link_types & LINKTYPE(LINKDEV_SHMEM)) { + shmd->type = REAL_SHMEM; + mif_debug("%s: shmd->type = REAL_SHMEM\n", ld->name); + } else { + mif_err("%s: ERR! invalid type\n", ld->name); + goto error; + } + + phys_base = c2c_get_phys_base(); + offset = c2c_get_sh_rgn_offset(); + size = c2c_get_sh_rgn_size(); + mif_debug("%s: phys_base:0x%08X offset:0x%08X size:%d\n", + ld->name, phys_base, offset, size); + + shmd->start = phys_base + offset; + shmd->size = size; + shmd->base = c2c_request_sh_region(shmd->start, shmd->size); + if (!shmd->base) { + mif_err("%s: ERR! c2c_request_sh_region fail\n", ld->name); + goto error; + } + + mif_debug("%s: phys_addr:0x%08X virt_addr:0x%08X size:%d\n", + ld->name, shmd->start, (int)shmd->base, shmd->size); + + /* + ** Initialize SHMEM maps (physical map -> logical map) + */ + err = c2c_init_ipc_map(shmd); + if (err < 0) { + mif_err("%s: ERR! c2c_init_ipc_map fail (err %d)\n", + ld->name, err); + goto error; + } + + /* + ** Initialize locks, completions, and bottom halves + */ + sprintf(shmd->wlock_name, "%s_wlock", ld->name); + wake_lock_init(&shmd->wlock, WAKE_LOCK_SUSPEND, shmd->wlock_name); + + sprintf(shmd->ap_wlock_name, "%s_ap_wlock", ld->name); + wake_lock_init(&shmd->ap_wlock, WAKE_LOCK_SUSPEND, shmd->ap_wlock_name); + + sprintf(shmd->cp_wlock_name, "%s_cp_wlock", ld->name); + wake_lock_init(&shmd->cp_wlock, WAKE_LOCK_SUSPEND, shmd->cp_wlock_name); + + init_completion(&shmd->udl_cmpl); + for (i = 0; i < MAX_SIPC5_DEV; i++) + init_completion(&shmd->req_ack_cmpl[i]); + + tasklet_init(&shmd->rx_tsk, msg_rx_task, (unsigned long)shmd); + INIT_DELAYED_WORK(&shmd->ipc_rx_dwork, ipc_rx_work); + INIT_DELAYED_WORK(&shmd->udl_rx_dwork, udl_rx_work); + + for (i = 0; i < MAX_SIPC5_DEV; i++) { + spin_lock_init(&shmd->tx_lock[i]); + atomic_set(&shmd->res_required[i], 0); + } + + ld->tx_wq = create_singlethread_workqueue("shmem_tx_wq"); + if (!ld->tx_wq) { + mif_err("%s: ERR! fail to create tx_wq\n", ld->name); + goto error; + } + INIT_DELAYED_WORK(&ld->fmt_tx_dwork, fmt_tx_work); + INIT_DELAYED_WORK(&ld->raw_tx_dwork, raw_tx_work); + ld->tx_dwork[IPC_FMT] = &ld->fmt_tx_dwork; + ld->tx_dwork[IPC_RAW] = &ld->raw_tx_dwork; + + spin_lock_init(&shmd->stat_list.lock); + spin_lock_init(&shmd->trace_list.lock); +#ifdef DEBUG_MODEM_IF + INIT_DELAYED_WORK(&shmd->dump_dwork, mem_dump_work); +#endif + + INIT_DELAYED_WORK(&shmd->cp_sleep_dwork, release_cp_wakeup); + INIT_DELAYED_WORK(&shmd->link_off_dwork, release_ap_status); + spin_lock_init(&shmd->pm_lock); + + /* + ** Retrieve SHMEM IRQ GPIO#, IRQ#, and IRQ flags + */ + shmd->gpio_pda_active = modem->gpio_pda_active; + mif_err("PDA_ACTIVE gpio# = %d (value %d)\n", + shmd->gpio_pda_active, gpio_get_value(shmd->gpio_pda_active)); + + shmd->gpio_ap_status = modem->gpio_ap_status; + shmd->gpio_ap_wakeup = modem->gpio_ap_wakeup; + shmd->irq_ap_wakeup = modem->irq_ap_wakeup; + if (!shmd->irq_ap_wakeup) { + mif_err("ERR! no irq_ap_wakeup\n"); + goto error; + } + mif_debug("CP2AP_WAKEUP IRQ# = %d\n", shmd->irq_ap_wakeup); + + shmd->gpio_cp_wakeup = modem->gpio_cp_wakeup; + shmd->gpio_cp_status = modem->gpio_cp_status; + shmd->irq_cp_status = modem->irq_cp_status; + if (!shmd->irq_cp_status) { + mif_err("ERR! no irq_cp_status\n"); + goto error; + } + mif_debug("CP2AP_STATUS IRQ# = %d\n", shmd->irq_cp_status); + + c2c_assign_gpio_ap_wakeup(shmd->gpio_ap_wakeup); + c2c_assign_gpio_ap_status(shmd->gpio_ap_status); + c2c_assign_gpio_cp_wakeup(shmd->gpio_cp_wakeup); + c2c_assign_gpio_cp_status(shmd->gpio_cp_status); + + gpio_set_value(shmd->gpio_pda_active, 1); + gpio_set_value(shmd->gpio_ap_status, 1); + + /* + ** Register interrupt handlers + */ + err = c2c_register_handler(c2c_irq_handler, shmd); + if (err) { + mif_err("%s: ERR! c2c_register_handler fail (err %d)\n", + ld->name, err); + goto error; + } + + snprintf(name, MIF_MAX_NAME_LEN, "%s_ap_wakeup", ld->name); + irq = shmd->irq_ap_wakeup; + irq_flags = (IRQF_NO_THREAD | IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH); + err = mif_register_isr(irq, ap_wakeup_handler, irq_flags, name, shmd); + if (err) + goto error; + + snprintf(name, MIF_MAX_NAME_LEN, "%s_cp_status", ld->name); + irq = shmd->irq_cp_status; + irq_flags = (IRQF_NO_THREAD | IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH); + err = mif_register_isr(irq, cp_status_handler, irq_flags, name, shmd); + if (err) + goto error; return ld; + +error: + mif_err("xxx\n"); + kfree(shmd); + return NULL; } + diff --git a/drivers/misc/modem_if/modem_link_device_c2c.h b/drivers/misc/modem_if/modem_link_device_c2c.h index 7ec9aa6..9dba90b 100644 --- a/drivers/misc/modem_if/modem_link_device_c2c.h +++ b/drivers/misc/modem_if/modem_link_device_c2c.h @@ -1,5 +1,4 @@ /* - * Copyright (C) 2010 Google, Inc. * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -8,209 +7,18 @@ * * 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ -#include <linux/wakelock.h> #ifndef __MODEM_LINK_DEVICE_C2C_H__ #define __MODEM_LINK_DEVICE_C2C_H__ -#define DPRAM_ERR_MSG_LEN 128 -#define DPRAM_ERR_DEVICE "c2cerr" +#include <mach/c2c.h> +#include "modem_link_device_shmem.h" -#define MAX_IDX 2 - -#define DPRAM_BASE_PTR 0x4000000 - -#define DPRAM_START_ADDRESS 0 -#define DPRAM_MAGIC_CODE_ADDRESS DPRAM_START_ADDRESS -#define DPRAM_GOTA_MAGIC_CODE_SIZE 0x4 -#define DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS \ - (DPRAM_START_ADDRESS + DPRAM_GOTA_MAGIC_CODE_SIZE) -#define BSP_DPRAM_BASE_SIZE 0x1ff8 -#define DPRAM_END_OF_ADDRESS (BSP_DPRAM_BASE_SIZE - 1) -#define DPRAM_INTERRUPT_SIZE 0x2 -#define DPRAM_PDA2PHONE_INTERRUPT_ADDRESS \ - (DPRAM_START_ADDRESS + BSP_DPRAM_BASE_SIZE - DPRAM_INTERRUPT_SIZE*2) -#define DPRAM_PHONE2PDA_INTERRUPT_ADDRESS \ - (DPRAM_START_ADDRESS + BSP_DPRAM_BASE_SIZE) -#define DPRAM_BUFFER_SIZE \ - (DPRAM_PHONE2PDA_INTERRUPT_ADDRESS -\ - DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS) -#define DPRAM_INDEX_SIZE 0x2 - -#define MAGIC_DMDL 0x4445444C -#define MAGIC_UMDL 0x4445444D - -#define DPRAM_PACKET_DATA_SIZE 0x3f00 -#define DPRAM_PACKET_HEADER_SIZE 0x7 - -#define INT_GOTA_MASK_VALID 0xA000 -#define INT_DPRAM_DUMP_MASK_VALID 0xA000 -#define MASK_CMD_RECEIVE_READY_NOTIFICATION 0xA100 -#define MASK_CMD_DOWNLOAD_START_REQUEST 0xA200 -#define MASK_CMD_DOWNLOAD_START_RESPONSE 0xA301 -#define MASK_CMD_IMAGE_SEND_REQUEST 0xA400 -#define MASK_CMD_IMAGE_SEND_RESPONSE 0xA500 -#define MASK_CMD_SEND_DONE_REQUEST 0xA600 -#define MASK_CMD_SEND_DONE_RESPONSE 0xA701 -#define MASK_CMD_STATUS_UPDATE_NOTIFICATION 0xA800 -#define MASK_CMD_UPDATE_DONE_NOTIFICATION 0xA900 -#define MASK_CMD_EFS_CLEAR_RESPONSE 0xAB00 -#define MASK_CMD_ALARM_BOOT_OK 0xAC00 -#define MASK_CMD_ALARM_BOOT_FAIL 0xAD00 - -#define WRITEIMG_HEADER_SIZE 8 -#define WRITEIMG_TAIL_SIZE 4 -#define WRITEIMG_BODY_SIZE \ - (DPRAM_BUFFER_SIZE - WRITEIMG_HEADER_SIZE - WRITEIMG_TAIL_SIZE) - -#define DPDN_DEFAULT_WRITE_LEN WRITEIMG_BODY_SIZE -#define CMD_DL_START_REQ 0x9200 -#define CMD_IMG_SEND_REQ 0x9400 -#define CMD_DL_SEND_DONE_REQ 0x9600 - -#define CMD_UL_START_REQ 0x9200 -#define CMD_UL_START_READY 0x9400 -#define CMD_UL_SEND_RESP 0x9601 -#define CMD_UL_SEND_DONE_RESP 0x9801 -#define CMD_UL_SEND_REQ 0xA500 -#define CMD_UL_START_RESPONSE 0xA301 -#define CMD_UL_SEND_DONE_REQ 0xA700 -#define CMD_RECEIVE_READY_NOTIFICATION 0xA100 - -#define MASK_CMD_RESULT_FAIL 0x0002 -#define MASK_CMD_RESULT_SUCCESS 0x0001 - -#define START_INDEX 0x007F -#define END_INDEX 0x007E - -#define CMD_IMG_SEND_REQ 0x9400 - -#define CRC_TAB_SIZE 256 -#define CRC_16_L_SEED 0xFFFF - -struct c2c_device { - /* DPRAM memory addresses */ - u16 *in_head_addr; - u16 *in_tail_addr; - u8 *in_buff_addr; - unsigned long in_buff_size; - - u16 *out_head_addr; - u16 *out_tail_addr; - u8 *out_buff_addr; - unsigned long out_buff_size; - - unsigned long in_head_saved; - unsigned long in_tail_saved; - unsigned long out_head_saved; - unsigned long out_tail_saved; - - u16 mask_req_ack; - u16 mask_res_ack; - u16 mask_send; -}; - -struct memory_region { - u8 *control; - u8 *fmt_out; - u8 *raw_out; - u8 *fmt_in; - u8 *raw_in; - u8 *mbx; -}; - -struct UldDataHeader { - u8 bop; - u16 total_frame; - u16 curr_frame; - u16 len; -}; - -struct c2c_link_device { - struct link_device ld; - - struct modem_data *pdata; - - /*only c2c*/ - struct wake_lock c2c_wake_lock; - atomic_t raw_txq_req_ack_rcvd; - atomic_t fmt_txq_req_ack_rcvd; - u8 net_stop_flag; - int phone_sync; - u8 phone_status; - - struct work_struct xmit_work_struct; - - struct workqueue_struct *gota_wq; - struct work_struct gota_cmd_work; - - struct c2c_device dev_map[MAX_IDX]; - - struct wake_lock dumplock; - - u8 c2c_read_data[131072]; - - int c2c_init_cmd_wait_condition; - wait_queue_head_t c2c_init_cmd_wait_q; - - int modem_pif_init_wait_condition; - wait_queue_head_t modem_pif_init_done_wait_q; - - struct completion gota_download_start_complete; - - int gota_send_done_cmd_wait_condition; - wait_queue_head_t gota_send_done_cmd_wait_q; - - int gota_update_done_cmd_wait_condition; - wait_queue_head_t gota_update_done_cmd_wait_q; - - int upload_send_req_wait_condition; - wait_queue_head_t upload_send_req_wait_q; - - int upload_send_done_wait_condition; - wait_queue_head_t upload_send_done_wait_q; - - int upload_start_req_wait_condition; - wait_queue_head_t upload_start_req_wait_q; - - int upload_packet_start_condition; - wait_queue_head_t upload_packet_start_wait_q; - - u16 gota_irq_handler_cmd; - - u16 c2c_dump_handler_cmd; - - int dump_region_number; - - unsigned int is_c2c_err ; - - int c2c_dump_start; - int gota_start; - - char c2c_err_buf[DPRAM_ERR_MSG_LEN]; - - struct fasync_struct *c2c_err_async_q; - - void (*clear_interrupt)(struct c2c_link_device *); - - struct memory_region m_region; - - unsigned long fmt_out_buff_size; - unsigned long raw_out_buff_size; - unsigned long fmt_in_buff_size; - unsigned long raw_in_buff_size; - - struct delayed_work delayed_tx; - struct sk_buff *delayed_skb; - u8 delayed_count; -}; - -/* converts from struct link_device* to struct xxx_link_device* */ -#define to_c2c_link_device(linkdev) \ - container_of(linkdev, struct c2c_link_device, ld) +#define CP_WAKEUP_HOLD_TIME 500 /* 500 ms */ #endif + diff --git a/drivers/misc/modem_if/modem_link_device_dpram.c b/drivers/misc/modem_if/modem_link_device_dpram.c index a650ed9..a87aff2 100644 --- a/drivers/misc/modem_if/modem_link_device_dpram.c +++ b/drivers/misc/modem_if/modem_link_device_dpram.c @@ -25,560 +25,385 @@ #include <linux/if_arp.h> #include <linux/platform_device.h> #include <linux/kallsyms.h> -#include <linux/platform_data/modem.h> +#include <linux/suspend.h> +#include <plat/gpio-cfg.h> +#include <mach/gpio.h> +#include "modem.h" #include "modem_prj.h" -#include "modem_link_device_dpram.h" #include "modem_utils.h" +#include "modem_link_device_dpram.h" -/* -** Function prototypes for basic DPRAM operations -*/ -static inline void clear_intr(struct dpram_link_device *dpld); -static inline u16 recv_intr(struct dpram_link_device *dpld); -static inline void send_intr(struct dpram_link_device *dpld, u16 mask); - -static inline u16 get_magic(struct dpram_link_device *dpld); -static inline void set_magic(struct dpram_link_device *dpld, u16 val); -static inline u16 get_access(struct dpram_link_device *dpld); -static inline void set_access(struct dpram_link_device *dpld, u16 val); - -static inline u32 get_tx_head(struct dpram_link_device *dpld, int id); -static inline u32 get_tx_tail(struct dpram_link_device *dpld, int id); -static inline void set_tx_head(struct dpram_link_device *dpld, int id, u32 in); -static inline void set_tx_tail(struct dpram_link_device *dpld, int id, u32 out); -static inline u8 *get_tx_buff(struct dpram_link_device *dpld, int id); -static inline u32 get_tx_buff_size(struct dpram_link_device *dpld, int id); - -static inline u32 get_rx_head(struct dpram_link_device *dpld, int id); -static inline u32 get_rx_tail(struct dpram_link_device *dpld, int id); -static inline void set_rx_head(struct dpram_link_device *dpld, int id, u32 in); -static inline void set_rx_tail(struct dpram_link_device *dpld, int id, u32 out); -static inline u8 *get_rx_buff(struct dpram_link_device *dpld, int id); -static inline u32 get_rx_buff_size(struct dpram_link_device *dpld, int id); - -static inline u16 get_mask_req_ack(struct dpram_link_device *dpld, int id); -static inline u16 get_mask_res_ack(struct dpram_link_device *dpld, int id); -static inline u16 get_mask_send(struct dpram_link_device *dpld, int id); - -static inline bool dpram_circ_valid(u32 size, u32 in, u32 out); - -static void handle_cp_crash(struct dpram_link_device *dpld); -static int trigger_force_cp_crash(struct dpram_link_device *dpld); -static void dpram_dump_memory(struct link_device *ld, char *buff); - -/* -** Functions for debugging -*/ -static inline void log_dpram_status(struct dpram_link_device *dpld) -{ - pr_info("mif: %s: {M:0x%X A:%d} {FMT TI:%u TO:%u RI:%u RO:%u} " - "{RAW TI:%u TO:%u RI:%u RO:%u} {INT:0x%X}\n", - dpld->ld.mc->name, - get_magic(dpld), get_access(dpld), - get_tx_head(dpld, IPC_FMT), get_tx_tail(dpld, IPC_FMT), - get_rx_head(dpld, IPC_FMT), get_rx_tail(dpld, IPC_FMT), - get_tx_head(dpld, IPC_RAW), get_tx_tail(dpld, IPC_RAW), - get_rx_head(dpld, IPC_RAW), get_rx_tail(dpld, IPC_RAW), - recv_intr(dpld)); -} - -static void set_dpram_map(struct dpram_link_device *dpld, - struct mif_irq_map *map) -{ - map->magic = get_magic(dpld); - map->access = get_access(dpld); - - map->fmt_tx_in = get_tx_head(dpld, IPC_FMT); - map->fmt_tx_out = get_tx_tail(dpld, IPC_FMT); - map->fmt_rx_in = get_rx_head(dpld, IPC_FMT); - map->fmt_rx_out = get_rx_tail(dpld, IPC_FMT); - map->raw_tx_in = get_tx_head(dpld, IPC_RAW); - map->raw_tx_out = get_tx_tail(dpld, IPC_RAW); - map->raw_rx_in = get_rx_head(dpld, IPC_RAW); - map->raw_rx_out = get_rx_tail(dpld, IPC_RAW); - - map->cp2ap = recv_intr(dpld); -} - -/* -** RXB (DPRAM RX buffer) functions -*/ -static struct dpram_rxb *rxbq_create_pool(unsigned size, int count) -{ - struct dpram_rxb *rxb; - u8 *buff; - int i; - - rxb = kzalloc(sizeof(struct dpram_rxb) * count, GFP_KERNEL); - if (!rxb) { - mif_info("ERR! kzalloc rxb fail\n"); - return NULL; - } - - buff = kzalloc((size * count), GFP_KERNEL|GFP_DMA); - if (!buff) { - mif_info("ERR! kzalloc buff fail\n"); - kfree(rxb); - return NULL; - } - - for (i = 0; i < count; i++) { - rxb[i].buff = buff; - rxb[i].size = size; - buff += size; - } - - return rxb; -} - -static inline unsigned rxbq_get_page_size(unsigned len) -{ - return ((len + PAGE_SIZE - 1) >> PAGE_SHIFT) << PAGE_SHIFT; -} - -static inline bool rxbq_empty(struct dpram_rxb_queue *rxbq) -{ - return (rxbq->in == rxbq->out) ? true : false; -} - -static inline int rxbq_free_size(struct dpram_rxb_queue *rxbq) -{ - int in = rxbq->in; - int out = rxbq->out; - int qsize = rxbq->size; - return (in < out) ? (out - in - 1) : (qsize + out - in - 1); -} +static void trigger_forced_cp_crash(struct dpram_link_device *dpld); -static inline struct dpram_rxb *rxbq_get_free_rxb(struct dpram_rxb_queue *rxbq) +/** + * set_circ_pointer + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @dir: direction of communication (TX or RX) + * @ptr: type of the queue pointer (HEAD or TAIL) + * @addr: address of the queue pointer + * @val: value to be written to the queue pointer + * + * Writes a value to a pointer in a circular queue with verification. + */ +static inline void set_circ_pointer(struct dpram_link_device *dpld, int id, + int dir, int ptr, void __iomem *addr, u16 val) { - struct dpram_rxb *rxb = NULL; + struct link_device *ld = &dpld->ld; + int cnt = 0; + u16 saved = 0; - if (likely(rxbq_free_size(rxbq) > 0)) { - rxb = &rxbq->rxb[rxbq->in]; - rxbq->in++; - if (rxbq->in >= rxbq->size) - rxbq->in -= rxbq->size; - rxb->data = rxb->buff; - } + iowrite16(val, addr); - return rxb; -} + while (1) { + /* Check the value written to the address */ + saved = ioread16(addr); + if (likely(saved == val)) + break; -static inline int rxbq_size(struct dpram_rxb_queue *rxbq) -{ - int in = rxbq->in; - int out = rxbq->out; - int qsize = rxbq->size; - return (in >= out) ? (in - out) : (qsize - out + in); -} + cnt++; + mif_err("%s: ERR! %s_%s.%s saved(%d) != val(%d), count %d\n", + ld->name, get_dev_name(id), circ_dir(dir), + circ_ptr(ptr), saved, val, cnt); + if (cnt >= MAX_RETRY_CNT) { + trigger_forced_cp_crash(dpld); + break; + } -static inline struct dpram_rxb *rxbq_get_data_rxb(struct dpram_rxb_queue *rxbq) -{ - struct dpram_rxb *rxb = NULL; + udelay(100); - if (likely(!rxbq_empty(rxbq))) { - rxb = &rxbq->rxb[rxbq->out]; - rxbq->out++; - if (rxbq->out >= rxbq->size) - rxbq->out -= rxbq->size; + /* Write the value again */ + iowrite16(val, addr); } - - return rxb; -} - -static inline u8 *rxb_put(struct dpram_rxb *rxb, unsigned len) -{ - rxb->len = len; - return rxb->data; } -static inline void rxb_clear(struct dpram_rxb *rxb) +/** + * recv_int2ap + * @dpld: pointer to an instance of dpram_link_device structure + * + * Returns the value of the CP-to-AP interrupt register in a DPRAM. + */ +static inline u16 recv_int2ap(struct dpram_link_device *dpld) { - rxb->data = NULL; - rxb->len = 0; + return ioread16(dpld->mbx2ap); } -/* -** DPRAM operations -*/ -static int dpram_register_isr(unsigned irq, irqreturn_t (*isr)(int, void*), - unsigned long flag, const char *name, - struct dpram_link_device *dpld) +/** + * send_int2cp + * @dpld: pointer to an instance of dpram_link_device structure + * @mask: value to be written to the AP-to-CP interrupt register in a DPRAM + */ +static inline void send_int2cp(struct dpram_link_device *dpld, u16 mask) { - int ret; + struct idpram_pm_op *pm_op = dpld->pm_op; - ret = request_irq(irq, isr, flag, name, dpld); - if (ret) { - mif_info("%s: ERR! request_irq fail (err %d)\n", name, ret); - return ret; + if (pm_op && pm_op->int2cp_possible) { + if (!pm_op->int2cp_possible(dpld)) + return; } - ret = enable_irq_wake(irq); - if (ret) - mif_info("%s: ERR! enable_irq_wake fail (err %d)\n", name, ret); - - mif_info("%s (#%d) handler registered\n", name, irq); - - return 0; -} - -static inline void clear_intr(struct dpram_link_device *dpld) -{ - if (likely(dpld->dpctl->clear_intr)) - dpld->dpctl->clear_intr(); + iowrite16(mask, dpld->mbx2cp); } -static inline u16 recv_intr(struct dpram_link_device *dpld) -{ - if (likely(dpld->dpctl->recv_intr)) - return dpld->dpctl->recv_intr(); - else - return ioread16(dpld->mbx2ap); -} - -static inline void send_intr(struct dpram_link_device *dpld, u16 mask) +/** + * read_int2cp + * @dpld: pointer to an instance of dpram_link_device structure + * + * Returns the value of the AP-to-CP interrupt register in a DPRAM. + */ +static inline u16 read_int2cp(struct dpram_link_device *dpld) { - if (likely(dpld->dpctl->send_intr)) - dpld->dpctl->send_intr(mask); - else - iowrite16(mask, dpld->mbx2cp); + return ioread16(dpld->mbx2cp); } +/** + * get_magic + * @dpld: pointer to an instance of dpram_link_device structure + * + * Returns the value of the "magic code" field in a DPRAM. + */ static inline u16 get_magic(struct dpram_link_device *dpld) { return ioread16(dpld->magic); } +/** + * set_magic + * @dpld: pointer to an instance of dpram_link_device structure + * @val: value to be written to the "magic code" field in a DPRAM + */ static inline void set_magic(struct dpram_link_device *dpld, u16 val) { iowrite16(val, dpld->magic); } +/** + * get_access + * @dpld: pointer to an instance of dpram_link_device structure + * + * Returns the value of the "access enable" field in a DPRAM. + */ static inline u16 get_access(struct dpram_link_device *dpld) { return ioread16(dpld->access); } +/** + * set_access + * @dpld: pointer to an instance of dpram_link_device structure + * @val: value to be written to the "access enable" field in a DPRAM + */ static inline void set_access(struct dpram_link_device *dpld, u16 val) { iowrite16(val, dpld->access); } -static inline u32 get_tx_head(struct dpram_link_device *dpld, int id) +/** + * get_txq_head + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the value of a head (in) pointer in a TX queue. + */ +static inline u32 get_txq_head(struct dpram_link_device *dpld, int id) { return ioread16(dpld->dev[id]->txq.head); } -static inline u32 get_tx_tail(struct dpram_link_device *dpld, int id) +/** + * get_txq_tail + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the value of a tail (out) pointer in a TX queue. + * + * It is useless for an AP to read a tail pointer in a TX queue twice to verify + * whether or not the value in the pointer is valid, because it can already have + * been updated by a CP after the first access from the AP. + */ +static inline u32 get_txq_tail(struct dpram_link_device *dpld, int id) { return ioread16(dpld->dev[id]->txq.tail); } -static inline void set_tx_head(struct dpram_link_device *dpld, int id, u32 in) -{ - int cnt = 3; - u32 val = 0; - - iowrite16((u16)in, dpld->dev[id]->txq.head); - - do { - /* Check head value written */ - val = ioread16(dpld->dev[id]->txq.head); - if (likely(val == in)) - return; - - mif_err("ERR: %s txq.head(%d) != in(%d)\n", - get_dev_name(id), val, in); - udelay(100); - - /* Write head value again */ - iowrite16((u16)in, dpld->dev[id]->txq.head); - } while (cnt--); - - trigger_force_cp_crash(dpld); -} - -static inline void set_tx_tail(struct dpram_link_device *dpld, int id, u32 out) -{ - int cnt = 3; - u32 val = 0; - - iowrite16((u16)out, dpld->dev[id]->txq.tail); - - do { - /* Check tail value written */ - val = ioread16(dpld->dev[id]->txq.tail); - if (likely(val == out)) - return; - - mif_err("ERR: %s txq.tail(%d) != out(%d)\n", - get_dev_name(id), val, out); - udelay(100); - - /* Write tail value again */ - iowrite16((u16)out, dpld->dev[id]->txq.tail); - } while (cnt--); - - trigger_force_cp_crash(dpld); -} - -static inline u8 *get_tx_buff(struct dpram_link_device *dpld, int id) +/** + * get_txq_buff + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the start address of the buffer in a TXQ. + */ +static inline u8 *get_txq_buff(struct dpram_link_device *dpld, int id) { return dpld->dev[id]->txq.buff; } -static inline u32 get_tx_buff_size(struct dpram_link_device *dpld, int id) +/** + * get_txq_buff_size + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the size of the buffer in a TXQ. + */ +static inline u32 get_txq_buff_size(struct dpram_link_device *dpld, int id) { return dpld->dev[id]->txq.size; } -static inline u32 get_rx_head(struct dpram_link_device *dpld, int id) +/** + * get_rxq_head + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the value of a head (in) pointer in an RX queue. + * + * It is useless for an AP to read a head pointer in an RX queue twice to verify + * whether or not the value in the pointer is valid, because it can already have + * been updated by a CP after the first access from the AP. + */ +static inline u32 get_rxq_head(struct dpram_link_device *dpld, int id) { return ioread16(dpld->dev[id]->rxq.head); } -static inline u32 get_rx_tail(struct dpram_link_device *dpld, int id) +/** + * get_rxq_tail + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the value of a tail (in) pointer in an RX queue. + */ +static inline u32 get_rxq_tail(struct dpram_link_device *dpld, int id) { return ioread16(dpld->dev[id]->rxq.tail); } -static inline void set_rx_head(struct dpram_link_device *dpld, int id, u32 in) -{ - int cnt = 3; - u32 val = 0; - - iowrite16((u16)in, dpld->dev[id]->rxq.head); - - do { - /* Check head value written */ - val = ioread16(dpld->dev[id]->rxq.head); - if (val == in) - return; - - mif_err("ERR: %s rxq.head(%d) != in(%d)\n", - get_dev_name(id), val, in); - udelay(100); - - /* Write head value again */ - iowrite16((u16)in, dpld->dev[id]->rxq.head); - } while (cnt--); - - trigger_force_cp_crash(dpld); -} - -static inline void set_rx_tail(struct dpram_link_device *dpld, int id, u32 out) -{ - int cnt = 3; - u32 val = 0; - - iowrite16((u16)out, dpld->dev[id]->rxq.tail); - - do { - /* Check tail value written */ - val = ioread16(dpld->dev[id]->rxq.tail); - if (val == out) - return; - - mif_err("ERR: %s rxq.tail(%d) != out(%d)\n", - get_dev_name(id), val, out); - udelay(100); - - /* Write tail value again */ - iowrite16((u16)out, dpld->dev[id]->rxq.tail); - } while (cnt--); - - trigger_force_cp_crash(dpld); -} - -static inline u8 *get_rx_buff(struct dpram_link_device *dpld, int id) +/** + * get_rxq_buff + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the start address of the buffer in an RXQ. + */ +static inline u8 *get_rxq_buff(struct dpram_link_device *dpld, int id) { return dpld->dev[id]->rxq.buff; } -static inline u32 get_rx_buff_size(struct dpram_link_device *dpld, int id) +/** + * get_rxq_buff_size + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the size of the buffer in an RXQ. + */ +static inline u32 get_rxq_buff_size(struct dpram_link_device *dpld, int id) { return dpld->dev[id]->rxq.size; } -static inline u16 get_mask_req_ack(struct dpram_link_device *dpld, int id) +/** + * set_txq_head + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @in: value to be written to the head pointer in a TXQ + */ +static inline void set_txq_head(struct dpram_link_device *dpld, int id, u32 in) { - return dpld->dev[id]->mask_req_ack; + set_circ_pointer(dpld, id, TX, HEAD, dpld->dev[id]->txq.head, in); } -static inline u16 get_mask_res_ack(struct dpram_link_device *dpld, int id) +/** + * set_txq_tail + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @out: value to be written to the tail pointer in a TXQ + */ +static inline void set_txq_tail(struct dpram_link_device *dpld, int id, u32 out) { - return dpld->dev[id]->mask_res_ack; + set_circ_pointer(dpld, id, TX, TAIL, dpld->dev[id]->txq.tail, out); } -static inline u16 get_mask_send(struct dpram_link_device *dpld, int id) +/** + * set_rxq_head + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @in: value to be written to the head pointer in an RXQ + */ +static inline void set_rxq_head(struct dpram_link_device *dpld, int id, u32 in) { - return dpld->dev[id]->mask_send; + set_circ_pointer(dpld, id, RX, HEAD, dpld->dev[id]->rxq.head, in); } -static inline bool dpram_circ_valid(u32 size, u32 in, u32 out) +/** + * set_rxq_tail + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @out: value to be written to the tail pointer in an RXQ + */ +static inline void set_rxq_tail(struct dpram_link_device *dpld, int id, u32 out) { - if (in >= size) - return false; - - if (out >= size) - return false; - - return true; + set_circ_pointer(dpld, id, RX, TAIL, dpld->dev[id]->rxq.tail, out); } -/* Get free space in the TXQ as well as in & out pointers */ -static inline int dpram_get_txq_space(struct dpram_link_device *dpld, int dev, - u32 qsize, u32 *in, u32 *out) -{ - struct link_device *ld = &dpld->ld; - int cnt = 3; - u32 head; - u32 tail; - int space; - - do { - head = get_tx_head(dpld, dev); - tail = get_tx_tail(dpld, dev); - - space = (head < tail) ? (tail - head - 1) : - (qsize + tail - head - 1); - mif_debug("%s: %s_TXQ qsize[%u] in[%u] out[%u] space[%u]\n", - ld->name, get_dev_name(dev), qsize, head, tail, space); - - if (dpram_circ_valid(qsize, head, tail)) { - *in = head; - *out = tail; - return space; - } - - mif_info("%s: CAUTION! <%pf> " - "%s_TXQ invalid (size:%d in:%d out:%d)\n", - ld->name, __builtin_return_address(0), - get_dev_name(dev), qsize, head, tail); - - udelay(100); - } while (cnt--); - - *in = 0; - *out = 0; - return -EINVAL; -} - -static void dpram_reset_tx_circ(struct dpram_link_device *dpld, int dev) +/** + * get_mask_req_ack + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the REQ_ACK mask value for the IPC device. + */ +static inline u16 get_mask_req_ack(struct dpram_link_device *dpld, int id) { - set_tx_head(dpld, dev, 0); - set_tx_tail(dpld, dev, 0); - if (dev == IPC_FMT) - trigger_force_cp_crash(dpld); + return dpld->dev[id]->mask_req_ack; } -/* Get data size in the RXQ as well as in & out pointers */ -static inline int dpram_get_rxq_rcvd(struct dpram_link_device *dpld, int dev, - u32 qsize, u32 *in, u32 *out) +/** + * get_mask_res_ack + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the RES_ACK mask value for the IPC device. + */ +static inline u16 get_mask_res_ack(struct dpram_link_device *dpld, int id) { - struct link_device *ld = &dpld->ld; - int cnt = 3; - u32 head; - u32 tail; - u32 rcvd; - - do { - head = get_rx_head(dpld, dev); - tail = get_rx_tail(dpld, dev); - if (head == tail) { - *in = head; - *out = tail; - return 0; - } - - rcvd = (head > tail) ? (head - tail) : (qsize - tail + head); - mif_debug("%s: %s_RXQ qsize[%u] in[%u] out[%u] rcvd[%u]\n", - ld->name, get_dev_name(dev), qsize, head, tail, rcvd); - - if (dpram_circ_valid(qsize, head, tail)) { - *in = head; - *out = tail; - return rcvd; - } - - mif_info("%s: CAUTION! <%pf> " - "%s_RXQ invalid (size:%d in:%d out:%d)\n", - ld->name, __builtin_return_address(0), - get_dev_name(dev), qsize, head, tail); - - udelay(100); - } while (cnt--); - - *in = 0; - *out = 0; - return -EINVAL; + return dpld->dev[id]->mask_res_ack; } -static void dpram_reset_rx_circ(struct dpram_link_device *dpld, int dev) +/** + * get_mask_send + * @dpld: pointer to an instance of dpram_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the SEND mask value for the IPC device. + */ +static inline u16 get_mask_send(struct dpram_link_device *dpld, int id) { - set_rx_head(dpld, dev, 0); - set_rx_tail(dpld, dev, 0); - if (dev == IPC_FMT) - trigger_force_cp_crash(dpld); + return dpld->dev[id]->mask_send; } -/* -** CAUTION : dpram_allow_sleep() MUST be invoked after dpram_wake_up() success -*/ -static int dpram_wake_up(struct dpram_link_device *dpld) +/** + * reset_txq_circ + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Empties a TXQ by resetting the head (in) pointer with the value in the tail + * (out) pointer. + */ +static inline void reset_txq_circ(struct dpram_link_device *dpld, int dev) { struct link_device *ld = &dpld->ld; + u32 head = get_txq_head(dpld, dev); + u32 tail = get_txq_tail(dpld, dev); - if (!dpld->dpctl->wakeup) - return 0; - - if (dpld->dpctl->wakeup() < 0) { - mif_err("%s: ERR! <%pf> DPRAM wakeup fail once\n", - ld->name, __builtin_return_address(0)); - - if (dpld->dpctl->sleep) - dpld->dpctl->sleep(); + mif_info("%s: %s_TXQ: HEAD[%u] <== TAIL[%u]\n", + ld->name, get_dev_name(dev), head, tail); - udelay(10); - - if (dpld->dpctl->wakeup() < 0) { - mif_err("%s: ERR! <%pf> DPRAM wakeup fail twice\n", - ld->name, __builtin_return_address(0)); - return -EACCES; - } - } - - atomic_inc(&dpld->accessing); - return 0; + set_txq_head(dpld, dev, tail); } -static void dpram_allow_sleep(struct dpram_link_device *dpld) +/** + * reset_rxq_circ + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Empties an RXQ by resetting the tail (out) pointer with the value in the head + * (in) pointer. + */ +static inline void reset_rxq_circ(struct dpram_link_device *dpld, int dev) { struct link_device *ld = &dpld->ld; + u32 head = get_rxq_head(dpld, dev); + u32 tail = get_rxq_tail(dpld, dev); - if (!dpld->dpctl->sleep) - return; + mif_info("%s: %s_RXQ: TAIL[%u] <== HEAD[%u]\n", + ld->name, get_dev_name(dev), tail, head); - if (atomic_dec_return(&dpld->accessing) <= 0) { - dpld->dpctl->sleep(); - atomic_set(&dpld->accessing, 0); - mif_debug("%s: DPRAM sleep possible\n", ld->name); - } + set_rxq_tail(dpld, dev, head); } -static int dpram_check_access(struct dpram_link_device *dpld) +/** + * check_magic_access + * @dpld: pointer to an instance of dpram_link_device structure + * + * Returns 0 if the "magic code" and "access enable" values are valid, otherwise + * returns -EACCES. + */ +static int check_magic_access(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; int i; u16 magic = get_magic(dpld); u16 access = get_access(dpld); + /* Returns 0 if the "magic code" and "access enable" are valid */ if (likely(magic == DPRAM_MAGIC_CODE && access == 1)) return 0; + /* Retry up to 100 times with 100 us delay per each retry */ for (i = 1; i <= 100; i++) { - mif_info("%s: ERR! magic:%X access:%X -> retry:%d\n", + mif_info("%s: magic:%X access:%X -> retry:%d\n", ld->name, magic, access, i); udelay(100); @@ -592,357 +417,313 @@ static int dpram_check_access(struct dpram_link_device *dpld) return -EACCES; } -static bool dpram_ipc_active(struct dpram_link_device *dpld) +/** + * ipc_active + * @dpld: pointer to an instance of dpram_link_device structure + * + * Returns whether or not IPC via the dpram_link_device instance is possible. + */ +static bool ipc_active(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; /* Check DPRAM mode */ if (ld->mode != LINK_MODE_IPC) { - mif_info("%s: <%pf> ld->mode != LINK_MODE_IPC\n", - ld->name, __builtin_return_address(0)); + mif_err("%s: <called by %pf> ERR! ld->mode != LINK_MODE_IPC\n", + ld->name, CALLER); return false; } - if (dpram_check_access(dpld) < 0) { - mif_info("%s: ERR! <%pf> dpram_check_access fail\n", - ld->name, __builtin_return_address(0)); + /* Check "magic code" and "access enable" values */ + if (check_magic_access(dpld) < 0) { + mif_err("%s: <called by %pf> ERR! check_magic_access fail\n", + ld->name, CALLER); return false; } return true; } -static void dpram_ipc_write(struct dpram_link_device *dpld, int dev, - u32 qsize, u32 in, u32 out, struct sk_buff *skb) -{ - struct link_device *ld = &dpld->ld; - u8 __iomem *buff = get_tx_buff(dpld, dev); - u8 *src = skb->data; - u32 len = skb->len; - u32 inp; - struct mif_irq_map map; - - if (in < out) { - /* +++++++++ in ---------- out ++++++++++ */ - memcpy((buff + in), src, len); - } else { - /* ------ out +++++++++++ in ------------ */ - u32 space = qsize - in; - - /* 1) in -> buffer end */ - memcpy((buff + in), src, ((len > space) ? space : len)); - - /* 2) buffer start -> out */ - if (len > space) - memcpy(buff, (src + space), (len - space)); - } - - /* update new in pointer */ - inp = in + len; - if (inp >= qsize) - inp -= qsize; - set_tx_head(dpld, dev, inp); +/** + * get_dpram_status + * @dpld: pointer to an instance of dpram_link_device structure + * @dir: direction of communication (TX or RX) + * @stat: pointer to an instance of mem_status structure + * + * Takes a snapshot of the current status of a DPRAM. + */ +static void get_dpram_status(struct dpram_link_device *dpld, + enum circ_dir_type dir, struct mem_status *stat) +{ +#ifdef DEBUG_MODEM_IF + getnstimeofday(&stat->ts); +#endif + + stat->dir = dir; + stat->magic = get_magic(dpld); + stat->access = get_access(dpld); + stat->head[IPC_FMT][TX] = get_txq_head(dpld, IPC_FMT); + stat->tail[IPC_FMT][TX] = get_txq_tail(dpld, IPC_FMT); + stat->head[IPC_FMT][RX] = get_rxq_head(dpld, IPC_FMT); + stat->tail[IPC_FMT][RX] = get_rxq_tail(dpld, IPC_FMT); + stat->head[IPC_RAW][TX] = get_txq_head(dpld, IPC_RAW); + stat->tail[IPC_RAW][TX] = get_txq_tail(dpld, IPC_RAW); + stat->head[IPC_RAW][RX] = get_rxq_head(dpld, IPC_RAW); + stat->tail[IPC_RAW][RX] = get_rxq_tail(dpld, IPC_RAW); + stat->int2ap = recv_int2ap(dpld); + stat->int2cp = read_int2cp(dpld); +} + +#if 0 +/** + * save_ipc_trace_work + * @work: pointer to an instance of work_struct structure + * + * Performs actual file operation for saving RX IPC trace. + */ +static void save_ipc_trace_work(struct work_struct *work) +{ + struct dpram_link_device *dpld; + struct link_device *ld; + struct trace_data_queue *trq; + struct trace_data *trd; + struct circ_status *stat; + struct file *fp; + struct timespec *ts; + int dev; + u8 *dump; + int rcvd; + u8 *buff; + char *path; + struct utc_time utc; - if (dev == IPC_FMT) { - set_dpram_map(dpld, &map); - mif_irq_log(ld->mc->msd, map, "ipc_write", sizeof("ipc_write")); - mif_ipc_log(MIF_IPC_AP2CP, ld->mc->msd, skb->data, skb->len); - } + dpld = container_of(work, struct dpram_link_device, trace_dwork.work); + ld = &dpld->ld; + trq = &dpld->trace_list; + path = dpld->trace_path; - if (ld->aligned && memcmp16_to_io((buff + in), src, 4)) { - mif_err("%s: memcmp16_to_io fail\n", ld->name); - trigger_force_cp_crash(dpld); + buff = kzalloc(dpld->size << 3, GFP_KERNEL); + if (!buff) { + while (1) { + trd = trq_get_data_slot(trq); + if (!trd) + break; + + ts = &trd->ts; + dev = trd->dev; + stat = &trd->circ_stat; + dump = trd->data; + rcvd = trd->size; + print_ipc_trace(ld, dev, stat, ts, dump, rcvd); + + kfree(dump); + } + return; } -} - -static int dpram_try_ipc_tx(struct dpram_link_device *dpld, int dev) -{ - struct link_device *ld = &dpld->ld; - struct sk_buff_head *txq = ld->skb_txq[dev]; - struct sk_buff *skb; - unsigned long int flags; - u32 qsize = get_tx_buff_size(dpld, dev); - u32 in; - u32 out; - int space; - int copied = 0; - - spin_lock_irqsave(&dpld->tx_lock[dev], flags); while (1) { - space = dpram_get_txq_space(dpld, dev, qsize, &in, &out); - if (unlikely(space < 0)) { - spin_unlock_irqrestore(&dpld->tx_lock[dev], flags); - dpram_reset_tx_circ(dpld, dev); - return space; - } - - skb = skb_dequeue(txq); - if (unlikely(!skb)) + trd = trq_get_data_slot(trq); + if (!trd) break; - if (unlikely(space < skb->len)) { - atomic_set(&dpld->res_required[dev], 1); - skb_queue_head(txq, skb); - spin_unlock_irqrestore(&dpld->tx_lock[dev], flags); - mif_info("%s: %s " - "qsize[%u] in[%u] out[%u] free[%u] < len[%u]\n", - ld->name, get_dev_name(dev), - qsize, in, out, space, skb->len); - return -ENOSPC; + ts = &trd->ts; + dev = trd->dev; + stat = &trd->circ_stat; + dump = trd->data; + rcvd = trd->size; + + ts2utc(ts, &utc); + snprintf(path, MIF_MAX_PATH_LEN, + "%s/%s_%s_%d%02d%02d-%02d%02d%02d.lst", + MIF_LOG_DIR, ld->name, get_dev_name(dev), + utc.year, utc.mon, utc.day, utc.hour, utc.min, utc.sec); + + fp = mif_open_file(path); + if (fp) { + int len; + + snprintf(buff, MIF_MAX_PATH_LEN, + "[%d-%02d-%02d %02d:%02d:%02d.%03d] " + "%s %s_RXQ {IN:%u OUT:%u LEN:%d}\n", + utc.year, utc.mon, utc.day, utc.hour, utc.min, + utc.sec, utc.msec, ld->name, get_dev_name(dev), + stat->in, stat->out, stat->size); + len = strlen(buff); + mif_dump2format4(dump, rcvd, (buff + len), NULL); + strcat(buff, "\n"); + len = strlen(buff); + + mif_save_file(fp, buff, len); + + memset(buff, 0, len); + mif_close_file(fp); + } else { + mif_err("%s: %s open fail\n", ld->name, path); + print_ipc_trace(ld, dev, stat, ts, dump, rcvd); } - /* TX if there is enough room in the queue */ - dpram_ipc_write(dpld, dev, qsize, in, out, skb); - copied += skb->len; - dev_kfree_skb_any(skb); + kfree(dump); } - spin_unlock_irqrestore(&dpld->tx_lock[dev], flags); - - return copied; -} - -static void dpram_ipc_rx_task(unsigned long data) -{ - struct dpram_link_device *dpld = (struct dpram_link_device *)data; - struct link_device *ld = &dpld->ld; - struct io_device *iod; - struct dpram_rxb *rxb; - unsigned qlen; - int i; - - for (i = 0; i < dpld->max_ipc_dev; i++) { - iod = dpld->iod[i]; - qlen = rxbq_size(&dpld->rxbq[i]); - while (qlen > 0) { - rxb = rxbq_get_data_rxb(&dpld->rxbq[i]); - iod->recv(iod, ld, rxb->data, rxb->len); - rxb_clear(rxb); - qlen--; - } - } + kfree(buff); } +#endif -static void dpram_ipc_read(struct dpram_link_device *dpld, int dev, u8 *dst, - u8 __iomem *src, u32 out, u32 len, u32 qsize) +/** + * set_dpram_map + * @dpld: pointer to an instance of dpram_link_device structure + * @map: pointer to an instance of mif_irq_map structure + * + * Sets variables in an mif_irq_map instance as current DPRAM status for IPC + * logging. + */ +static void set_dpram_map(struct dpram_link_device *dpld, + struct mif_irq_map *map) { - if ((out + len) <= qsize) { - /* ----- (out) (in) ----- */ - /* ----- 7f 00 00 7e ----- */ - memcpy(dst, (src + out), len); - } else { - /* (in) ----------- (out) */ - /* 00 7e ----------- 7f 00 */ - unsigned len1 = qsize - out; + map->magic = get_magic(dpld); + map->access = get_access(dpld); - /* 1) out -> buffer end */ - memcpy(dst, (src + out), len1); + map->fmt_tx_in = get_txq_head(dpld, IPC_FMT); + map->fmt_tx_out = get_txq_tail(dpld, IPC_FMT); + map->fmt_rx_in = get_rxq_head(dpld, IPC_FMT); + map->fmt_rx_out = get_rxq_tail(dpld, IPC_FMT); + map->raw_tx_in = get_txq_head(dpld, IPC_RAW); + map->raw_tx_out = get_txq_tail(dpld, IPC_RAW); + map->raw_rx_in = get_rxq_head(dpld, IPC_RAW); + map->raw_rx_out = get_rxq_tail(dpld, IPC_RAW); - /* 2) buffer start -> in */ - dst += len1; - memcpy(dst, src, (len - len1)); - } + map->cp2ap = recv_int2ap(dpld); } -/* - ret < 0 : error - ret == 0 : no data - ret > 0 : valid data -*/ -static int dpram_ipc_recv_data_with_rxb(struct dpram_link_device *dpld, int dev) +/** + * dpram_wake_up + * @dpld: pointer to an instance of dpram_link_device structure + * + * Wakes up a DPRAM if it can sleep and increases the "accessing" counter in the + * dpram_link_device instance. + * + * CAUTION!!! dpram_allow_sleep() MUST be invoked after dpram_wake_up() success + * to decrease the "accessing" counter. + */ +static int dpram_wake_up(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; - struct dpram_rxb *rxb; - u8 __iomem *src = get_rx_buff(dpld, dev); - u32 qsize = get_rx_buff_size(dpld, dev); - u32 in; - u32 out; - u32 rcvd; - struct mif_irq_map map; - - rcvd = dpram_get_rxq_rcvd(dpld, dev, qsize, &in, &out); - if (rcvd <= 0) - return rcvd; - if (dev == IPC_FMT) { - set_dpram_map(dpld, &map); - mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv")); - } + if (unlikely(!dpld->need_wake_up)) + return 0; - /* Allocate an rxb */ - rxb = rxbq_get_free_rxb(&dpld->rxbq[dev]); - if (!rxb) { - mif_info("%s: ERR! %s rxbq_get_free_rxb fail\n", - ld->name, get_dev_name(dev)); - return -ENOMEM; + if (dpld->ext_op->wakeup(dpld) < 0) { + mif_err("%s: <called by %pf> ERR! wakeup fail\n", + ld->name, CALLER); + return -EACCES; } - /* Read data from each DPRAM buffer */ - dpram_ipc_read(dpld, dev, rxb_put(rxb, rcvd), src, out, rcvd, qsize); - - /* Calculate and set new out */ - out += rcvd; - if (out >= qsize) - out -= qsize; - set_rx_tail(dpld, dev, out); + atomic_inc(&dpld->accessing); - return rcvd; + return 0; } -/* - ret < 0 : error - ret == 0 : no data - ret > 0 : valid data -*/ -static int dpram_ipc_recv_data_with_skb(struct dpram_link_device *dpld, int dev) +/** + * dpram_allow_sleep + * @dpld: pointer to an instance of dpram_link_device structure + * + * Decreases the "accessing" counter in the dpram_link_device instance if it can + * sleep and allows the DPRAM to sleep only if the value of "accessing" counter + * is less than or equal to 0. + * + * MUST be invoked after dpram_wake_up() success to decrease the "accessing" + * counter. + */ +static void dpram_allow_sleep(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; - struct io_device *iod = dpld->iod[dev]; - struct sk_buff *skb; - u8 __iomem *src = get_rx_buff(dpld, dev); - u32 qsize = get_rx_buff_size(dpld, dev); - u32 in; - u32 out; - u32 rcvd; - int rest; - u8 *frm; - u8 *dst; - unsigned int len; - unsigned int pad; - unsigned int tot; - struct mif_irq_map map; - - rcvd = dpram_get_rxq_rcvd(dpld, dev, qsize, &in, &out); - if (rcvd <= 0) - return rcvd; - - if (dev == IPC_FMT) { - set_dpram_map(dpld, &map); - mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv")); - } - - rest = rcvd; - while (rest > 0) { - frm = src + out; - if (unlikely(!sipc5_start_valid(frm[0]))) { - mif_err("%s: ERR! %s invalid start 0x%02X\n", - ld->name, get_dev_name(dev), frm[0]); - skb_queue_purge(&dpld->skb_rxq[dev]); - return -EBADMSG; - } - - len = sipc5_get_frame_sz16(frm); - if (unlikely(len > rest)) { - mif_err("%s: ERR! %s len %d > rest %d\n", - ld->name, get_dev_name(dev), len, rest); - skb_queue_purge(&dpld->skb_rxq[dev]); - return -EBADMSG; - } - - pad = sipc5_calc_padding_size(len); - tot = len + pad; - - /* Allocate an skb */ - skb = dev_alloc_skb(tot); - if (!skb) { - mif_err("%s: ERR! %s dev_alloc_skb fail\n", - ld->name, get_dev_name(dev)); - return -ENOMEM; - } - /* Read data from each DPRAM buffer */ - dst = skb_put(skb, tot); - dpram_ipc_read(dpld, dev, dst, src, out, tot, qsize); - skb_trim(skb, len); - iod->recv_skb(iod, ld, skb); + if (unlikely(!dpld->need_wake_up)) + return; - /* Calculate and set new out */ - rest -= tot; - out += tot; - if (out >= qsize) - out -= qsize; + if (atomic_dec_return(&dpld->accessing) <= 0) { + dpld->ext_op->sleep(dpld); + atomic_set(&dpld->accessing, 0); + mif_debug("%s: DPRAM sleep possible\n", ld->name); } - - set_rx_tail(dpld, dev, out); - - return rcvd; } -static void non_command_handler(struct dpram_link_device *dpld, u16 intr) +static int capture_dpram_snapshot(struct link_device *ld, struct io_device *iod) { - struct link_device *ld = &dpld->ld; - int i = 0; - int ret = 0; - u16 tx_mask = 0; + struct dpram_link_device *dpld = to_dpram_link_device(ld); + struct sk_buff *skb; + u32 size = dpld->size; + u32 copied = 0; + u8 *dump; - if (!dpram_ipc_active(dpld)) - return; + dpram_wake_up(dpld); + dump = capture_mem_dump(ld, dpld->base, dpld->size); + dpram_allow_sleep(dpld); - /* Read data from DPRAM */ - for (i = 0; i < dpld->max_ipc_dev; i++) { - if (dpld->use_skb) - ret = dpram_ipc_recv_data_with_skb(dpld, i); - else - ret = dpram_ipc_recv_data_with_rxb(dpld, i); - if (ret < 0) - dpram_reset_rx_circ(dpld, i); + if (!dump) + return -ENOMEM; - /* Check and process REQ_ACK (at this time, in == out) */ - if (intr & get_mask_req_ack(dpld, i)) { - mif_debug("%s: send %s_RES_ACK\n", - ld->name, get_dev_name(i)); - tx_mask |= get_mask_res_ack(dpld, i); + while (copied < size) { + skb = alloc_skb(MAX_DUMP_SKB_SIZE, GFP_ATOMIC); + if (!skb) { + mif_err("ERR! alloc_skb fail\n"); + kfree(dump); + return -ENOMEM; } - } - if (!dpld->use_skb) { - /* Schedule soft IRQ for RX */ - tasklet_hi_schedule(&dpld->rx_tsk); - } + skb_put(skb, MAX_DUMP_SKB_SIZE); + memcpy(skb->data, (dump + copied), MAX_DUMP_SKB_SIZE); + copied += MAX_DUMP_SKB_SIZE; - /* Try TX via DPRAM */ - for (i = 0; i < dpld->max_ipc_dev; i++) { - if (atomic_read(&dpld->res_required[i]) > 0) { - ret = dpram_try_ipc_tx(dpld, i); - if (ret > 0) { - atomic_set(&dpld->res_required[i], 0); - tx_mask |= get_mask_send(dpld, i); - } else if (ret == -ENOSPC) { - tx_mask |= get_mask_req_ack(dpld, i); - } - } + skb_queue_tail(&iod->sk_rx_q, skb); + wake_up(&iod->wq); } - if (tx_mask) { - send_intr(dpld, INT_NON_CMD(tx_mask)); - mif_debug("%s: send intr 0x%04X\n", ld->name, tx_mask); - } + kfree(dump); + return 0; } +/** + * handle_cp_crash + * @dpld: pointer to an instance of dpram_link_device structure + * + * Actual handler for the CRASH_EXIT command from a CP. + */ static void handle_cp_crash(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod; int i; - for (i = 0; i < dpld->max_ipc_dev; i++) { - mif_info("%s: purging %s_skb_txq\b", ld->name, get_dev_name(i)); + if (dpld->forced_cp_crash) + dpld->forced_cp_crash = false; + + /* Stop network interfaces */ + mif_netif_stop(ld); + + /* Purge the skb_txq in every IPC device (IPC_FMT, IPC_RAW, etc.) */ + for (i = 0; i < ld->max_ipc_dev; i++) skb_queue_purge(ld->skb_txq[i]); - } + /* Change the modem state to STATE_CRASH_EXIT for the FMT IO device */ iod = link_get_iod_with_format(ld, IPC_FMT); - iod->modem_state_changed(iod, STATE_CRASH_EXIT); + if (iod) + iod->modem_state_changed(iod, STATE_CRASH_EXIT); + /* Change the modem state to STATE_CRASH_EXIT for the BOOT IO device */ iod = link_get_iod_with_format(ld, IPC_BOOT); - iod->modem_state_changed(iod, STATE_CRASH_EXIT); - - iod = link_get_iod_with_channel(ld, PS_DATA_CH_0); if (iod) - iodevs_for_each(iod->msd, iodev_netif_stop, 0); + iod->modem_state_changed(iod, STATE_CRASH_EXIT); } -static void handle_no_crash_ack(unsigned long arg) +/** + * handle_no_cp_crash_ack + * @arg: pointer to an instance of dpram_link_device structure + * + * Invokes handle_cp_crash() to enter the CRASH_EXIT state if there was no + * CRASH_ACK from a CP in FORCE_CRASH_ACK_TIMEOUT. + */ +static void handle_no_cp_crash_ack(unsigned long arg) { struct dpram_link_device *dpld = (struct dpram_link_device *)arg; struct link_device *ld = &dpld->ld; @@ -955,165 +736,341 @@ static void handle_no_crash_ack(unsigned long arg) handle_cp_crash(dpld); } -static int trigger_force_cp_crash(struct dpram_link_device *dpld) +/** + * trigger_forced_cp_crash + * @dpld: pointer to an instance of dpram_link_device structure + * + * Triggers an enforced CP crash. + */ +static void trigger_forced_cp_crash(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; +#ifdef DEBUG_MODEM_IF + struct trace_data *trd; + u8 *dump; + struct timespec ts; + getnstimeofday(&ts); +#endif if (ld->mode == LINK_MODE_ULOAD) { - mif_err("%s: CP crash is already in progress\n", ld->mc->name); - return 0; + mif_err("%s: <called by %pf> ALREADY in progress\n", + ld->name, CALLER); + return; } ld->mode = LINK_MODE_ULOAD; - mif_err("%s: called by %pf\n", ld->name, __builtin_return_address(0)); + dpld->forced_cp_crash = true; + + disable_irq_nosync(dpld->irq); + + dpram_wake_up(dpld); + +#ifdef DEBUG_MODEM_IF + dump = capture_mem_dump(ld, dpld->base, dpld->size); + if (dump) { + trd = trq_get_free_slot(&dpld->trace_list); + memcpy(&trd->ts, &ts, sizeof(struct timespec)); + trd->dev = IPC_DEBUG; + trd->data = dump; + trd->size = dpld->size; + } +#endif - if (dpld->dp_type == CP_IDPRAM) - dpram_wake_up(dpld); + enable_irq(dpld->irq); - send_intr(dpld, INT_CMD(INT_CMD_CRASH_EXIT)); + mif_err("%s: <called by %pf>\n", ld->name, CALLER); + /* Send CRASH_EXIT command to a CP */ + send_int2cp(dpld, INT_CMD(INT_CMD_CRASH_EXIT)); + get_dpram_status(dpld, TX, msq_get_free_slot(&dpld->stat_list)); + + /* If there is no CRASH_ACK from a CP in FORCE_CRASH_ACK_TIMEOUT, + handle_no_cp_crash_ack() will be executed. */ mif_add_timer(&dpld->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, - handle_no_crash_ack, (unsigned long)dpld); + handle_no_cp_crash_ack, (unsigned long)dpld); - return 0; + return; } -static int dpram_init_ipc(struct dpram_link_device *dpld) +/** + * ext_command_handler + * @dpld: pointer to an instance of dpram_link_device structure + * @cmd: extended DPRAM command from a CP + * + * Processes an extended command from a CP. + */ +static void ext_command_handler(struct dpram_link_device *dpld, u16 cmd) { struct link_device *ld = &dpld->ld; - int i; - - if (ld->mode == LINK_MODE_IPC && - get_magic(dpld) == DPRAM_MAGIC_CODE && - get_access(dpld) == 1) - mif_info("%s: IPC already initialized\n", ld->name); + u16 resp; - /* Clear pointers in every circular queue */ - for (i = 0; i < dpld->max_ipc_dev; i++) { - set_tx_head(dpld, i, 0); - set_tx_tail(dpld, i, 0); - set_rx_head(dpld, i, 0); - set_rx_tail(dpld, i, 0); - } + switch (EXT_CMD_MASK(cmd)) { + case EXT_CMD_SET_SPEED_LOW: + if (dpld->dpram->setup_speed) { + dpld->dpram->setup_speed(DPRAM_SPEED_LOW); + resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_LOW); + send_int2cp(dpld, resp); + } + break; - /* Initialize variables for efficient TX/RX processing */ - for (i = 0; i < dpld->max_ipc_dev; i++) - dpld->iod[i] = link_get_iod_with_format(ld, i); - dpld->iod[IPC_RAW] = link_get_iod_with_format(ld, IPC_MULTI_RAW); + case EXT_CMD_SET_SPEED_MID: + if (dpld->dpram->setup_speed) { + dpld->dpram->setup_speed(DPRAM_SPEED_MID); + resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_MID); + send_int2cp(dpld, resp); + } + break; - if (dpld->iod[IPC_RAW]->recv_skb) - dpld->use_skb = true; + case EXT_CMD_SET_SPEED_HIGH: + if (dpld->dpram->setup_speed) { + dpld->dpram->setup_speed(DPRAM_SPEED_HIGH); + resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_HIGH); + send_int2cp(dpld, resp); + } + break; - for (i = 0; i < dpld->max_ipc_dev; i++) { - spin_lock_init(&dpld->tx_lock[i]); - atomic_set(&dpld->res_required[i], 0); - skb_queue_purge(&dpld->skb_rxq[i]); + default: + mif_info("%s: unknown command 0x%04X\n", ld->name, cmd); + break; } +} - /* Enable IPC */ - atomic_set(&dpld->accessing, 0); - - set_magic(dpld, DPRAM_MAGIC_CODE); - set_access(dpld, 1); - if (get_magic(dpld) != DPRAM_MAGIC_CODE || get_access(dpld) != 1) - return -EACCES; +/** + * udl_command_handler + * @dpld: pointer to an instance of dpram_link_device structure + * @cmd: DPRAM upload/download command from a CP + * + * Processes a command for upload/download from a CP. + */ +static void udl_command_handler(struct dpram_link_device *dpld, u16 cmd) +{ + struct link_device *ld = &dpld->ld; - ld->mode = LINK_MODE_IPC; + if (cmd & UDL_RESULT_FAIL) { + mif_err("%s: ERR! command fail (0x%04X)\n", ld->name, cmd); + return; + } - if (wake_lock_active(&dpld->wlock)) - wake_unlock(&dpld->wlock); + switch (UDL_CMD_MASK(cmd)) { + case UDL_CMD_RECV_READY: + mif_err("%s: [CP->AP] CMD_DL_READY (0x%04X)\n", ld->name, cmd); +#ifdef CONFIG_CDMA_MODEM_CBP72 + mif_err("%s: [AP->CP] CMD_DL_START_REQ (0x%04X)\n", + ld->name, CMD_DL_START_REQ); + send_int2cp(dpld, CMD_DL_START_REQ); +#else + complete(&dpld->udl_cmpl); +#endif + break; - return 0; + default: + complete(&dpld->udl_cmpl); + } } +/** + * cmd_req_active_handler + * @dpld: pointer to an instance of dpram_link_device structure + * + * Handles the REQ_ACTIVE command from a CP. + */ static void cmd_req_active_handler(struct dpram_link_device *dpld) { - send_intr(dpld, INT_CMD(INT_CMD_RES_ACTIVE)); + send_int2cp(dpld, INT_CMD(INT_CMD_RES_ACTIVE)); } +/** + * cmd_crash_reset_handler + * @dpld: pointer to an instance of dpram_link_device structure + * + * Handles the CRASH_RESET command from a CP. + */ static void cmd_crash_reset_handler(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod = NULL; + int i; ld->mode = LINK_MODE_ULOAD; if (!wake_lock_active(&dpld->wlock)) wake_lock(&dpld->wlock); + /* Stop network interfaces */ + mif_netif_stop(ld); + + /* Purge the skb_txq in every IPC device (IPC_FMT, IPC_RAW, etc.) */ + for (i = 0; i < ld->max_ipc_dev; i++) + skb_queue_purge(ld->skb_txq[i]); + mif_err("%s: Recv 0xC7 (CRASH_RESET)\n", ld->name); + /* Change the modem state to STATE_CRASH_RESET for the FMT IO device */ iod = link_get_iod_with_format(ld, IPC_FMT); iod->modem_state_changed(iod, STATE_CRASH_RESET); + /* Change the modem state to STATE_CRASH_RESET for the BOOT IO device */ iod = link_get_iod_with_format(ld, IPC_BOOT); iod->modem_state_changed(iod, STATE_CRASH_RESET); } +/** + * cmd_crash_exit_handler + * @dpld: pointer to an instance of dpram_link_device structure + * + * Handles the CRASH_EXIT command from a CP. + */ static void cmd_crash_exit_handler(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; - u32 size = dpld->dpctl->dp_size; - char *dpram_buff = NULL; +#ifdef DEBUG_MODEM_IF + struct trace_data *trd; + u8 *dump; + struct timespec ts; + getnstimeofday(&ts); +#endif ld->mode = LINK_MODE_ULOAD; if (!wake_lock_active(&dpld->wlock)) wake_lock(&dpld->wlock); - mif_err("%s: Recv 0xC9 (CRASH_EXIT)\n", ld->name); - - if (dpld->dp_type == CP_IDPRAM) - dpram_wake_up(dpld); + del_timer(&dpld->crash_ack_timer); - dpram_buff = kzalloc(size + (MAX_MIF_SEPA_SIZE * 2), GFP_ATOMIC); - if (!dpram_buff) { - mif_err("DPRAM dump failed!!\n"); - } else { - memset(dpram_buff, 0, size + (MAX_MIF_SEPA_SIZE * 2)); - memcpy(dpram_buff, MIF_SEPARATOR_DPRAM, MAX_MIF_SEPA_SIZE); - memcpy(dpram_buff + MAX_MIF_SEPA_SIZE, &size, sizeof(u32)); - dpram_buff += (MAX_MIF_SEPA_SIZE * 2); - dpram_dump_memory(ld, dpram_buff); + dpram_wake_up(dpld); + +#ifdef DEBUG_MODEM_IF + if (!dpld->forced_cp_crash) { + dump = capture_mem_dump(ld, dpld->base, dpld->size); + if (dump) { + trd = trq_get_free_slot(&dpld->trace_list); + memcpy(&trd->ts, &ts, sizeof(struct timespec)); + trd->dev = IPC_DEBUG; + trd->data = dump; + trd->size = dpld->size; + } } - - del_timer(&dpld->crash_ack_timer); +#endif if (dpld->ext_op && dpld->ext_op->crash_log) dpld->ext_op->crash_log(dpld); + mif_err("%s: Recv 0xC9 (CRASH_EXIT)\n", ld->name); + handle_cp_crash(dpld); } -static void cmd_phone_start_handler(struct dpram_link_device *dpld) +/** + * init_dpram_ipc + * @dpld: pointer to an instance of dpram_link_device structure + * + * Initializes IPC via DPRAM. + */ +static int init_dpram_ipc(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; - struct io_device *iod = NULL; + int i; + + if (ld->mode == LINK_MODE_IPC && + get_magic(dpld) == DPRAM_MAGIC_CODE && + get_access(dpld) == 1) + mif_info("%s: IPC already initialized\n", ld->name); + + /* Clear pointers in every circular queue */ + for (i = 0; i < ld->max_ipc_dev; i++) { + set_txq_head(dpld, i, 0); + set_txq_tail(dpld, i, 0); + set_rxq_head(dpld, i, 0); + set_rxq_tail(dpld, i, 0); + } + + /* Initialize variables for efficient TX/RX processing */ + for (i = 0; i < ld->max_ipc_dev; i++) + dpld->iod[i] = link_get_iod_with_format(ld, i); + dpld->iod[IPC_RAW] = link_get_iod_with_format(ld, IPC_MULTI_RAW); + + /* Initialize variables for TX flow control */ + for (i = 0; i < ld->max_ipc_dev; i++) + atomic_set(&dpld->res_required[i], 0); + + /* Enable IPC */ + if (wake_lock_active(&dpld->wlock)) + wake_unlock(&dpld->wlock); + + atomic_set(&dpld->accessing, 0); + + set_magic(dpld, DPRAM_MAGIC_CODE); + set_access(dpld, 1); + if (get_magic(dpld) != DPRAM_MAGIC_CODE || get_access(dpld) != 1) + return -EACCES; + + ld->mode = LINK_MODE_IPC; + + return 0; +} + +/** + * reset_dpram_ipc + * @dpld: pointer to an instance of dpram_link_device structure + * + * Reset DPRAM with IPC map. + */ +static void reset_dpram_ipc(struct dpram_link_device *dpld) +{ + int i; + struct link_device *ld = &dpld->ld; + + dpld->set_access(dpld, 0); + + /* Clear pointers in every circular queue */ + for (i = 0; i < ld->max_ipc_dev; i++) { + dpld->set_txq_head(dpld, i, 0); + dpld->set_txq_tail(dpld, i, 0); + dpld->set_rxq_head(dpld, i, 0); + dpld->set_rxq_tail(dpld, i, 0); + } - mif_info("%s: Recv 0xC8 (CP_START)\n", ld->name); + dpld->set_magic(dpld, DPRAM_MAGIC_CODE); + dpld->set_access(dpld, 1); +} + +/** + * cmd_phone_start_handler + * @dpld: pointer to an instance of dpram_link_device structure + * + * Handles the PHONE_START command from a CP. + */ +static void cmd_phone_start_handler(struct dpram_link_device *dpld) +{ + struct link_device *ld = &dpld->ld; + struct io_device *iod; - dpram_init_ipc(dpld); + mif_err("%s: Recv 0xC8 (CP_START)\n", ld->name); iod = link_get_iod_with_format(ld, IPC_FMT); if (!iod) { - mif_info("%s: ERR! no iod\n", ld->name); + mif_err("%s: ERR! no iod\n", ld->name); return; } - if (dpld->ext_op && dpld->ext_op->cp_start_handler) - dpld->ext_op->cp_start_handler(dpld); + init_dpram_ipc(dpld); - if (ld->mc->phone_state != STATE_ONLINE) { - mif_info("%s: phone_state: %d -> ONLINE\n", - ld->name, ld->mc->phone_state); - iod->modem_state_changed(iod, STATE_ONLINE); - } + iod->modem_state_changed(iod, STATE_ONLINE); - mif_info("%s: Send 0xC2 (INIT_END)\n", ld->name); - send_intr(dpld, INT_CMD(INT_CMD_INIT_END)); + if (dpld->ext_op && dpld->ext_op->cp_start_handler) { + dpld->ext_op->cp_start_handler(dpld); + } else { + mif_err("%s: Send 0xC2 (INIT_END)\n", ld->name); + send_int2cp(dpld, INT_CMD(INT_CMD_INIT_END)); + } } -static void command_handler(struct dpram_link_device *dpld, u16 cmd) +/** + * cmd_handler: processes a DPRAM command from a CP + * @dpld: pointer to an instance of dpram_link_device structure + * @cmd: DPRAM command from a CP + */ +static void cmd_handler(struct dpram_link_device *dpld, u16 cmd) { struct link_device *ld = &dpld->ld; @@ -1123,19 +1080,19 @@ static void command_handler(struct dpram_link_device *dpld, u16 cmd) break; case INT_CMD_CRASH_RESET: - dpld->dpram_init_status = DPRAM_INIT_STATE_NONE; + dpld->init_status = DPRAM_INIT_STATE_NONE; cmd_crash_reset_handler(dpld); break; case INT_CMD_CRASH_EXIT: - dpld->dpram_init_status = DPRAM_INIT_STATE_NONE; + dpld->init_status = DPRAM_INIT_STATE_NONE; cmd_crash_exit_handler(dpld); break; case INT_CMD_PHONE_START: - dpld->dpram_init_status = DPRAM_INIT_STATE_READY; + dpld->init_status = DPRAM_INIT_STATE_READY; cmd_phone_start_handler(dpld); - complete_all(&dpld->dpram_init_cmd); + complete_all(&ld->init_cmpl); break; case INT_CMD_NV_REBUILDING: @@ -1143,14 +1100,14 @@ static void command_handler(struct dpram_link_device *dpld, u16 cmd) break; case INT_CMD_PIF_INIT_DONE: - complete_all(&dpld->modem_pif_init_done); + complete_all(&ld->pif_cmpl); break; case INT_CMD_SILENT_NV_REBUILDING: mif_info("%s: SILENT_NV_REBUILDING\n", ld->name); break; - case INT_CMD_NORMAL_PWR_OFF: + case INT_CMD_NORMAL_POWER_OFF: /*ToDo:*/ /*kernel_sec_set_cp_ack()*/; break; @@ -1165,72 +1122,437 @@ static void command_handler(struct dpram_link_device *dpld, u16 cmd) } } -static void ext_command_handler(struct dpram_link_device *dpld, u16 cmd) +/** + * ipc_rx_work + * @work: pointer to an instance of the work_struct structure + * + * Invokes the recv method in the io_device instance to perform receiving IPC + * messages from each skb. + */ +static void ipc_rx_work(struct work_struct *work) +{ + struct dpram_link_device *dpld; + struct link_device *ld; + struct io_device *iod; + struct sk_buff *skb; + int i; + + dpld = container_of(work, struct dpram_link_device, rx_dwork.work); + ld = &dpld->ld; + + for (i = 0; i < ld->max_ipc_dev; i++) { + iod = dpld->iod[i]; + while (1) { + skb = skb_dequeue(ld->skb_rxq[i]); + if (!skb) + break; + + if (iod->recv_skb) { + iod->recv_skb(iod, ld, skb); + } else { + iod->recv(iod, ld, skb->data, skb->len); + dev_kfree_skb_any(skb); + } + } + } +} + +/** + * get_rxq_rcvd + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @mst: pointer to an instance of mem_status structure + * OUT @dcst: pointer to an instance of circ_status structure + * + * Stores {start address of the buffer in a RXQ, size of the buffer, in & out + * pointer values, size of received data} into the 'stat' instance. + * + * Returns an error code. + */ +static int get_rxq_rcvd(struct dpram_link_device *dpld, int dev, + struct mem_status *mst, struct circ_status *dcst) { struct link_device *ld = &dpld->ld; - u16 resp; - switch (EXT_CMD_MASK(cmd)) { - case EXT_CMD_SET_SPEED_LOW: - if (dpld->dpctl->setup_speed) { - dpld->dpctl->setup_speed(DPRAM_SPEED_LOW); - resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_LOW); - send_intr(dpld, resp); + dcst->buff = get_rxq_buff(dpld, dev); + dcst->qsize = get_rxq_buff_size(dpld, dev); + dcst->in = mst->head[dev][RX]; + dcst->out = mst->tail[dev][RX]; + dcst->size = circ_get_usage(dcst->qsize, dcst->in, dcst->out); + + if (circ_valid(dcst->qsize, dcst->in, dcst->out)) { + mif_debug("%s: %s_RXQ qsize[%u] in[%u] out[%u] rcvd[%u]\n", + ld->name, get_dev_name(dev), dcst->qsize, dcst->in, + dcst->out, dcst->size); + return 0; + } else { + mif_err("%s: ERR! %s_RXQ invalid (qsize[%d] in[%d] out[%d])\n", + ld->name, get_dev_name(dev), dcst->qsize, dcst->in, + dcst->out); + return -EIO; + } +} + +/** + * rx_sipc4_frames + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @mst: pointer to an instance of mem_status structure + * + * Returns + * ret < 0 : error + * ret == 0 : ILLEGAL status + * ret > 0 : valid data + * + * Must be invoked only when there is data in the corresponding RXQ. + * + * Requires a bottom half (e.g. ipc_rx_task) that will invoke the recv method in + * the io_device instance. + */ +static int rx_sipc4_frames(struct dpram_link_device *dpld, int dev, + struct mem_status *mst) +{ + struct link_device *ld = &dpld->ld; + struct sk_buff *skb; + u8 *dst; + struct circ_status dcst; + int rcvd; + + rcvd = get_rxq_rcvd(dpld, dev, mst, &dcst); + if (unlikely(rcvd < 0)) { +#ifdef DEBUG_MODEM_IF + trigger_forced_cp_crash(dpld); +#endif + goto exit; + } + rcvd = dcst.size; + + /* Allocate an skb */ + skb = dev_alloc_skb(rcvd); + if (!skb) { + mif_info("%s: ERR! %s dev_alloc_skb fail\n", + ld->name, get_dev_name(dev)); + rcvd = -ENOMEM; + goto exit; + } + + /* Read data from the RXQ */ + dst = skb_put(skb, rcvd); + circ_read16_from_io(dst, dcst.buff, dcst.qsize, dcst.out, rcvd); + + /* Store the skb to the corresponding skb_rxq */ + skb_queue_tail(ld->skb_rxq[dev], skb); + +exit: + /* Update tail (out) pointer to empty out the RXQ */ + set_rxq_tail(dpld, dev, dcst.in); + + return rcvd; +} + +/** + * rx_sipc5_frames + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @mst: pointer to an instance of mem_status structure + * + * Returns + * ret < 0 : error + * ret == 0 : ILLEGAL status + * ret > 0 : valid data + * + * Must be invoked only when there is data in the corresponding RXQ. + * + * Requires a recv_skb method in the io_device instance, so this function must + * be used for only SIPC5. + */ +static int rx_sipc5_frames(struct dpram_link_device *dpld, int dev, + struct mem_status *mst) +{ + struct link_device *ld = &dpld->ld; + struct sk_buff *skb; + /** + * variables for the status of the circular queue + */ + u8 __iomem *src; + u8 hdr[SIPC5_MIN_HEADER_SIZE]; + struct circ_status dcst; + /** + * variables for RX processing + */ + int qsize; /* size of the queue */ + int rcvd; /* size of data in the RXQ or error */ + int rest; /* size of the rest data */ + int idx; /* index to the start of current frame */ + u8 *frm; /* pointer to current frame */ + u8 *dst; /* pointer to the destination buffer */ + int tot; /* total length including padding data */ + /** + * variables for debug logging + */ + struct mif_irq_map map; + + /* Get data size in the RXQ and in/out pointer values */ + rcvd = get_rxq_rcvd(dpld, dev, mst, &dcst); + if (unlikely(rcvd < 0)) { + mif_err("%s: ERR! rcvd %d < 0\n", ld->name, rcvd); + goto exit; + } + + rcvd = dcst.size; + src = dcst.buff; + qsize = dcst.qsize; + idx = dcst.out; + + if (dev == IPC_FMT) { + set_dpram_map(dpld, &map); + mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv")); + } + +#if 0 + skb = dev_alloc_skb(rcvd); + + /* + ** If there is enough free space for an skb to store received + ** data at once, + */ + if (skb) { + /* Read all data from the RXQ to the skb */ + dst = skb_put(skb, rcvd); + if (unlikely(dpld->strict_io_access)) + circ_read16_from_io(dst, src, qsize, idx, rcvd); + else + circ_read(dst, src, qsize, idx, rcvd); + +#ifdef DEBUG_MODEM_IF + /* Verify data copied to the skb */ + if (ld->aligned && memcmp16_to_io((src + idx), dst, 4)) { + mif_err("%s: memcmp16_to_io fail\n", ld->name); + rcvd = -EIO; + goto exit; } - break; +#endif - case EXT_CMD_SET_SPEED_MID: - if (dpld->dpctl->setup_speed) { - dpld->dpctl->setup_speed(DPRAM_SPEED_MID); - resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_MID); - send_intr(dpld, resp); + /* Store the skb to the corresponding skb_rxq */ + skb_queue_tail(ld->skb_rxq[dev], skb); + + goto exit; + } + + /* + ** If there was no enough space to store received data at once, + */ +#endif + + rest = rcvd; + while (rest > 0) { + /* Calculate the start of an SIPC5 frame */ + frm = src + idx; + + /* Copy the header in the frame to the header buffer */ + if (unlikely(dpld->strict_io_access)) + memcpy16_from_io(hdr, frm, SIPC5_MIN_HEADER_SIZE); + else + memcpy(hdr, frm, SIPC5_MIN_HEADER_SIZE); + + /* Check the config field in the header */ + if (unlikely(!sipc5_start_valid(hdr))) { + char str[MIF_MAX_STR_LEN]; + snprintf(str, MIF_MAX_STR_LEN, "%s: BAD CONFIG", + ld->mc->name); + mif_err("%s: ERR! %s INVALID config 0x%02X\n", + ld->name, get_dev_name(dev), hdr[0]); + pr_ipc(1, str, hdr, 4); + rcvd = -EBADMSG; + goto exit; } - break; - case EXT_CMD_SET_SPEED_HIGH: - if (dpld->dpctl->setup_speed) { - dpld->dpctl->setup_speed(DPRAM_SPEED_HIGH); - resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_HIGH); - send_intr(dpld, resp); + /* Verify the total length of the frame (data + padding) */ + tot = sipc5_get_total_len(hdr); + if (unlikely(tot > rest)) { + char str[MIF_MAX_STR_LEN]; + snprintf(str, MIF_MAX_STR_LEN, "%s: BAD LENGTH", + ld->mc->name); + mif_err("%s: ERR! %s tot %d > rest %d\n", + ld->name, get_dev_name(dev), tot, rest); + pr_ipc(1, str, hdr, 4); + rcvd = -EBADMSG; +#if defined(CONFIG_MACH_C1_KOR_SKT) || defined(CONFIG_MACH_C1_KOR_KT) || defined(CONFIG_MACH_C1_KOR_LGT) + return rcvd; +#else + goto exit; +#endif } - break; - default: - mif_info("%s: unknown command 0x%04X\n", ld->name, cmd); - break; + /* Allocate an skb */ + skb = dev_alloc_skb(tot); + if (!skb) { + mif_err("%s: ERR! %s dev_alloc_skb fail\n", + ld->name, get_dev_name(dev)); + rcvd = -ENOMEM; + goto exit; + } + + /* Set the attribute of the skb as "single frame" */ + skbpriv(skb)->single_frame = true; + + /* Read the frame from the RXQ */ + dst = skb_put(skb, tot); + if (unlikely(dpld->strict_io_access)) + circ_read16_from_io(dst, src, qsize, idx, tot); + else + circ_read(dst, src, qsize, idx, tot); + +#ifdef DEBUG_MODEM_IF + /* Take a log for debugging */ + if (unlikely(dev == IPC_FMT)) { + size_t len = (skb->len > 32) ? 32 : skb->len; + char str[MIF_MAX_STR_LEN]; + snprintf(str, MIF_MAX_STR_LEN, "%s: CP2MIF", + ld->mc->name); + pr_ipc(0, str, skb->data, len); + } +#endif + +#ifdef DEBUG_MODEM_IF + /* Verify data copied to the skb */ + if (ld->aligned && memcmp16_to_io((src + idx), dst, 4)) { + mif_err("%s: memcmp16_to_io fail\n", ld->name); + rcvd = -EIO; + goto exit; + } +#endif + + /* Store the skb to the corresponding skb_rxq */ + skb_queue_tail(ld->skb_rxq[dev], skb); + + /* Calculate new idx value */ + rest -= tot; + idx += tot; + if (unlikely(idx >= qsize)) + idx -= qsize; } + +exit: +#ifdef DEBUG_MODEM_IF + if (rcvd < 0) + trigger_forced_cp_crash(dpld); +#endif + + /* Update tail (out) pointer to empty out the RXQ */ + set_rxq_tail(dpld, dev, dcst.in); + + return rcvd; } -static void udl_command_handler(struct dpram_link_device *dpld, u16 cmd) +/** + * msg_handler: receives IPC messages from every RXQ + * @dpld: pointer to an instance of dpram_link_device structure + * @stat: pointer to an instance of mem_status structure + * + * 1) Receives all IPC message frames currently in every DPRAM RXQ. + * 2) Sends RES_ACK responses if there are REQ_ACK requests from a CP. + * 3) Completes all threads waiting for the corresponding RES_ACK from a CP if + * there is any RES_ACK response. + */ +static void msg_handler(struct dpram_link_device *dpld, struct mem_status *stat) { struct link_device *ld = &dpld->ld; + int i = 0; + int ret = 0; + u16 mask = 0; + u16 intr = stat->int2ap; - if (cmd & UDL_RESULT_FAIL) { - mif_info("%s: ERR! Command failed: %04x\n", ld->name, cmd); + if (!ipc_active(dpld)) return; + + /* Read data from DPRAM */ + for (i = 0; i < ld->max_ipc_dev; i++) { + /* Invoke an RX function only when there is data in the RXQ */ + if (unlikely(stat->head[i][RX] == stat->tail[i][RX])) { + mif_debug("%s: %s_RXQ is empty\n", + ld->name, get_dev_name(i)); + } else { + if (unlikely(ld->ipc_version < SIPC_VER_50)) + ret = rx_sipc4_frames(dpld, i, stat); + else + ret = rx_sipc5_frames(dpld, i, stat); + if (ret < 0) + reset_rxq_circ(dpld, i); + } } - switch (UDL_CMD_MASK(cmd)) { - case UDL_CMD_RECV_READY: - mif_debug("%s: Send CP-->AP RECEIVE_READY\n", ld->name); - send_intr(dpld, CMD_IMG_START_REQ); - break; - default: - complete_all(&dpld->udl_cmd_complete); + /* Schedule soft IRQ for RX */ + queue_delayed_work(system_nrt_wq, &dpld->rx_dwork, 0); + + /* Check and process REQ_ACK (at this time, in == out) */ + if (unlikely(intr & INT_MASK_REQ_ACK_SET)) { + for (i = 0; i < ld->max_ipc_dev; i++) { + if (intr & get_mask_req_ack(dpld, i)) { + mif_debug("%s: set %s_RES_ACK\n", + ld->name, get_dev_name(i)); + mask |= get_mask_res_ack(dpld, i); + } + } + + send_int2cp(dpld, INT_NON_CMD(mask)); + } + + /* Check and process RES_ACK */ + if (unlikely(intr & INT_MASK_RES_ACK_SET)) { + for (i = 0; i < ld->max_ipc_dev; i++) { + if (intr & get_mask_res_ack(dpld, i)) { +#ifdef DEBUG_MODEM_IF + mif_info("%s: recv %s_RES_ACK\n", + ld->name, get_dev_name(i)); + print_circ_status(ld, i, stat); +#endif + complete(&dpld->req_ack_cmpl[i]); + } + } } } -static inline void dpram_ipc_rx(struct dpram_link_device *dpld, u16 intr) +/** + * cmd_msg_handler: processes a DPRAM command or receives IPC messages + * @dpld: pointer to an instance of dpram_link_device structure + * @stat: pointer to an instance of mem_status structure + * + * Invokes cmd_handler for a DPRAM command or msg_handler for IPC messages. + */ +static inline void cmd_msg_handler(struct dpram_link_device *dpld, + struct mem_status *stat) { - if (unlikely(INT_CMD_VALID(intr))) - command_handler(dpld, intr); - else - non_command_handler(dpld, intr); + struct dpram_ext_op *ext_op = dpld->ext_op; + struct mem_status *mst = msq_get_free_slot(&dpld->stat_list); + u16 intr = stat->int2ap; + + memcpy(mst, stat, sizeof(struct mem_status)); + + if (unlikely(INT_CMD_VALID(intr))) { + if (ext_op && ext_op->cmd_handler) + ext_op->cmd_handler(dpld, intr); + else + cmd_handler(dpld, intr); + } else { + msg_handler(dpld, stat); + } } -static inline void dpram_intr_handler(struct dpram_link_device *dpld, u16 intr) +/** + * intr_handler: processes an interrupt from a CP + * @dpld: pointer to an instance of dpram_link_device structure + * @stat: pointer to an instance of mem_status structure + * + * Call flow for normal interrupt handling: + * cmd_msg_handler -> cmd_handler -> cmd_xxx_handler + * cmd_msg_handler -> msg_handler -> rx_sipc5_frames -> ... + */ +static inline void intr_handler(struct dpram_link_device *dpld, + struct mem_status *stat) { char *name = dpld->ld.name; + u16 intr = stat->int2ap; if (unlikely(intr == INT_POWERSAFE_FAIL)) { mif_info("%s: intr == INT_POWERSAFE_FAIL\n", name); @@ -1247,131 +1569,696 @@ static inline void dpram_intr_handler(struct dpram_link_device *dpld, u16 intr) mif_info("%s: ERR! invalid intr 0x%04X\n", name, intr); } else { - mif_info("%s: ERR! invalid intr 0x%04X\n", name, intr); + mif_err("%s: ERR! invalid intr 0x%04X\n", name, intr); } + return; } if (likely(INT_VALID(intr))) - dpram_ipc_rx(dpld, intr); + cmd_msg_handler(dpld, stat); else - mif_info("%s: ERR! invalid intr 0x%04X\n", name, intr); + mif_err("%s: ERR! invalid intr 0x%04X\n", name, intr); } +/** + * ap_idpram_irq_handler: interrupt handler for an internal DPRAM in an AP + * @irq: IRQ number + * @data: pointer to a data + * + * 1) Reads the interrupt value + * 2) Performs interrupt handling + */ static irqreturn_t ap_idpram_irq_handler(int irq, void *data) { struct dpram_link_device *dpld = (struct dpram_link_device *)data; struct link_device *ld = (struct link_device *)&dpld->ld; - u16 int2ap = recv_intr(dpld); + struct modemlink_dpram_data *dpram = dpld->dpram; + struct mem_status stat; if (unlikely(ld->mode == LINK_MODE_OFFLINE)) return IRQ_HANDLED; - dpram_intr_handler(dpld, int2ap); + get_dpram_status(dpld, RX, &stat); + + intr_handler(dpld, &stat); + + if (likely(dpram->clear_int2ap)) + dpram->clear_int2ap(); return IRQ_HANDLED; } +/** + * cp_idpram_irq_handler: interrupt handler for an internal DPRAM in a CP + * @irq: IRQ number + * @data: pointer to a data + * + * 1) Wakes up the DPRAM + * 2) Reads the interrupt value + * 3) Performs interrupt handling + * 4) Clears the interrupt port (port = memory or register) + * 5) Allows the DPRAM to sleep + */ static irqreturn_t cp_idpram_irq_handler(int irq, void *data) { struct dpram_link_device *dpld = (struct dpram_link_device *)data; struct link_device *ld = (struct link_device *)&dpld->ld; - u16 int2ap; - - if (unlikely(ld->mode == LINK_MODE_OFFLINE)) + struct dpram_ext_op *ext_op = dpld->ext_op; + struct mem_status stat; + + if (unlikely(ld->mode == LINK_MODE_OFFLINE)) { + mif_err("%s: ERR! ld->mode == LINK_MODE_OFFLINE\n", ld->name); + get_dpram_status(dpld, RX, &stat); +#ifdef DEBUG_MODEM_IF + print_mem_status(ld, &stat); +#endif return IRQ_HANDLED; + } if (dpram_wake_up(dpld) < 0) { - log_dpram_status(dpld); - trigger_force_cp_crash(dpld); + trigger_forced_cp_crash(dpld); return IRQ_HANDLED; } - int2ap = recv_intr(dpld); + get_dpram_status(dpld, RX, &stat); - dpram_intr_handler(dpld, int2ap); + intr_handler(dpld, &stat); - clear_intr(dpld); + if (likely(ext_op && ext_op->clear_int2ap)) + ext_op->clear_int2ap(dpld); dpram_allow_sleep(dpld); return IRQ_HANDLED; } +/** + * ext_dpram_irq_handler: interrupt handler for a normal external DPRAM + * @irq: IRQ number + * @data: pointer to a data + * + * 1) Reads the interrupt value + * 2) Performs interrupt handling + */ static irqreturn_t ext_dpram_irq_handler(int irq, void *data) { struct dpram_link_device *dpld = (struct dpram_link_device *)data; struct link_device *ld = (struct link_device *)&dpld->ld; - u16 int2ap = recv_intr(dpld); + struct mem_status stat; if (unlikely(ld->mode == LINK_MODE_OFFLINE)) return IRQ_HANDLED; - dpram_intr_handler(dpld, int2ap); + get_dpram_status(dpld, RX, &stat); + + intr_handler(dpld, &stat); return IRQ_HANDLED; } -static void dpram_send_ipc(struct link_device *ld, int dev, - struct io_device *iod, struct sk_buff *skb) +/** + * get_txq_space + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * OUT @stat: pointer to an instance of circ_status structure + * + * Stores {start address of the buffer in a TXQ, size of the buffer, in & out + * pointer values, size of free space} into the 'stat' instance. + * + * Returns the size of free space in the buffer or an error code. + */ +static int get_txq_space(struct dpram_link_device *dpld, int dev, + struct circ_status *stat) { - struct dpram_link_device *dpld = to_dpram_link_device(ld); + struct link_device *ld = &dpld->ld; + int cnt = 0; + u32 qsize; + u32 head; + u32 tail; + int space; + + while (1) { + qsize = get_txq_buff_size(dpld, dev); + head = get_txq_head(dpld, dev); + tail = get_txq_tail(dpld, dev); + space = circ_get_space(qsize, head, tail); + + mif_debug("%s: %s_TXQ{qsize:%u in:%u out:%u space:%u}\n", + ld->name, get_dev_name(dev), qsize, head, tail, space); + + if (circ_valid(qsize, head, tail)) + break; + + cnt++; + mif_err("%s: ERR! invalid %s_TXQ{qsize:%d in:%d out:%d " + "space:%d}, count %d\n", + ld->name, get_dev_name(dev), qsize, head, tail, + space, cnt); + if (cnt >= MAX_RETRY_CNT) { + space = -EIO; + break; + } + + udelay(100); + } + + stat->buff = get_txq_buff(dpld, dev); + stat->qsize = qsize; + stat->in = head; + stat->out = tail; + stat->size = space; + + return space; +} + +/** + * write_ipc_to_txq + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @stat: pointer to an instance of circ_status structure + * @skb: pointer to an instance of sk_buff structure + * + * Must be invoked only when there is enough space in the TXQ. + */ +static void write_ipc_to_txq(struct dpram_link_device *dpld, int dev, + struct circ_status *stat, struct sk_buff *skb) +{ + struct link_device *ld = &dpld->ld; + u8 __iomem *buff = stat->buff; + u32 qsize = stat->qsize; + u32 in = stat->in; + u8 *src = skb->data; + u32 len = skb->len; + struct mif_irq_map map; + + /* Write data to the TXQ */ + if (unlikely(dpld->strict_io_access)) + circ_write16_to_io(buff, src, qsize, in, len); + else + circ_write(buff, src, qsize, in, len); + + /* Update new head (in) pointer */ + set_txq_head(dpld, dev, circ_new_pointer(qsize, in, len)); + + /* Take a log for debugging */ + if (dev == IPC_FMT) { +#ifdef DEBUG_MODEM_IF + char tag[MIF_MAX_STR_LEN]; + snprintf(tag, MIF_MAX_STR_LEN, "%s: MIF2CP", ld->mc->name); + pr_ipc(0, tag, src, (len > 32 ? 32 : len)); +#endif + set_dpram_map(dpld, &map); + mif_irq_log(ld->mc->msd, map, "ipc_write", sizeof("ipc_write")); + mif_ipc_log(MIF_IPC_AP2CP, ld->mc->msd, skb->data, skb->len); + } + +#ifdef DEBUG_MODEM_IF + /* Verify data written to the TXQ */ + if (ld->aligned && memcmp16_to_io((buff + in), src, 4)) { + mif_err("%s: memcmp16_to_io fail\n", ld->name); + trigger_forced_cp_crash(dpld); + } +#endif +} + +/** + * xmit_ipc_msg + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Tries to transmit IPC messages in the skb_txq of @dev as many as possible. + * + * Returns total length of IPC messages transmitted or an error code. + */ +static int xmit_ipc_msg(struct dpram_link_device *dpld, int dev) +{ + struct link_device *ld = &dpld->ld; struct sk_buff_head *txq = ld->skb_txq[dev]; + struct sk_buff *skb; + unsigned long flags; + struct circ_status stat; + int space; + int copied = 0; + + /* Acquire the spin lock for a TXQ */ + spin_lock_irqsave(&dpld->tx_lock[dev], flags); + + while (1) { + /* Get the size of free space in the TXQ */ + space = get_txq_space(dpld, dev, &stat); + if (unlikely(space < 0)) { +#ifdef DEBUG_MODEM_IF + /* Trigger a enforced CP crash */ + trigger_forced_cp_crash(dpld); +#endif + /* Empty out the TXQ */ + reset_txq_circ(dpld, dev); + copied = -EIO; + break; + } + + skb = skb_dequeue(txq); + if (unlikely(!skb)) + break; + + /* Check the free space size comparing with skb->len */ + if (unlikely(space < skb->len)) { +#ifdef DEBUG_MODEM_IF + struct mem_status mst; +#endif + /* Set res_required flag for the "dev" */ + atomic_set(&dpld->res_required[dev], 1); + + /* Take the skb back to the skb_txq */ + skb_queue_head(txq, skb); + + mif_info("%s: <called by %pf> NOSPC in %s_TXQ" + "{qsize:%u in:%u out:%u}, free:%u < len:%u\n", + ld->name, CALLER, get_dev_name(dev), + stat.qsize, stat.in, stat.out, space, skb->len); +#ifdef DEBUG_MODEM_IF + get_dpram_status(dpld, TX, &mst); + print_circ_status(ld, dev, &mst); +#endif + copied = -ENOSPC; + break; + } + + /* TX only when there is enough space in the TXQ */ + write_ipc_to_txq(dpld, dev, &stat, skb); + copied += skb->len; + dev_kfree_skb_any(skb); + } + + /* Release the spin lock */ + spin_unlock_irqrestore(&dpld->tx_lock[dev], flags); + + return copied; +} + +/** + * wait_for_res_ack + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * 1) Sends an REQ_ACK interrupt for @dev to CP. + * 2) Waits for the corresponding RES_ACK for @dev from CP. + * + * Returns the return value from wait_for_completion_interruptible_timeout(). + */ +static int wait_for_res_ack(struct dpram_link_device *dpld, int dev) +{ + struct link_device *ld = &dpld->ld; + struct completion *cmpl = &dpld->req_ack_cmpl[dev]; + unsigned long timeout = msecs_to_jiffies(dpld->res_ack_wait_timeout); int ret; u16 mask; - skb_queue_tail(txq, skb); - if (txq->qlen > 1024) { - mif_debug("%s: %s txq->qlen %d > 1024\n", - ld->name, get_dev_name(dev), txq->qlen); +#ifdef DEBUG_MODEM_IF + mif_info("%s: send %s_REQ_ACK\n", ld->name, get_dev_name(dev)); +#endif + + mask = get_mask_req_ack(dpld, dev); + send_int2cp(dpld, INT_NON_CMD(mask)); + + ret = wait_for_completion_interruptible_timeout(cmpl, timeout); + /* ret == 0 on timeout, ret < 0 if interrupted */ + if (ret < 0) { + mif_info("%s: %s: wait_for_completion interrupted! (ret %d)\n", + ld->name, get_dev_name(dev), ret); + goto exit; } - if (dpld->dp_type == CP_IDPRAM) { - if (dpram_wake_up(dpld) < 0) { - trigger_force_cp_crash(dpld); - return; + if (ret == 0) { + struct mem_status mst; + get_dpram_status(dpld, TX, &mst); + + mif_info("%s: wait_for_completion TIMEOUT! (no %s_RES_ACK)\n", + ld->name, get_dev_name(dev)); + + /* + ** The TXQ must be checked whether or not it is empty, because + ** an interrupt mask can be overwritten by the next interrupt. + */ + if (mst.head[dev][TX] == mst.tail[dev][TX]) { + ret = get_txq_buff_size(dpld, dev); +#ifdef DEBUG_MODEM_IF + mif_info("%s: %s_TXQ has been emptied\n", + ld->name, get_dev_name(dev)); + print_circ_status(ld, dev, &mst); +#endif } } - if (!dpram_ipc_active(dpld)) - goto exit; +exit: + return ret; +} + +/** + * process_res_ack + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * 1) Tries to transmit IPC messages in the skb_txq by invoking xmit_ipc_msg() + * function. + * 2) Sends an interrupt to CP if there is no error from xmit_ipc_msg(). + * 3) Restarts DPRAM flow control if xmit_ipc_msg() returns -ENOSPC. + * + * Returns the return value from xmit_ipc_msg(). + */ +static int process_res_ack(struct dpram_link_device *dpld, int dev) +{ + int ret; + u16 mask; + + ret = xmit_ipc_msg(dpld, dev); + if (ret > 0) { + mask = get_mask_send(dpld, dev); + send_int2cp(dpld, INT_NON_CMD(mask)); + get_dpram_status(dpld, TX, msq_get_free_slot(&dpld->stat_list)); + } + + if (ret >= 0) + atomic_set(&dpld->res_required[dev], 0); + + return ret; +} + +/** + * fmt_tx_work: performs TX for FMT IPC device under DPRAM flow control + * @work: pointer to an instance of the work_struct structure + * + * 1) Starts waiting for RES_ACK of FMT IPC device. + * 2) Returns immediately if the wait is interrupted. + * 3) Restarts DPRAM flow control if there is a timeout from the wait. + * 4) Otherwise, it performs processing RES_ACK for FMT IPC device. + */ +static void fmt_tx_work(struct work_struct *work) +{ + struct link_device *ld; + struct dpram_link_device *dpld; + unsigned long delay = 0; + int ret; + + ld = container_of(work, struct link_device, fmt_tx_dwork.work); + dpld = to_dpram_link_device(ld); + + ret = wait_for_res_ack(dpld, IPC_FMT); + /* ret < 0 if interrupted */ + if (ret < 0) + return; + + /* ret == 0 on timeout */ + if (ret == 0) { + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_FMT], 0); + return; + } + + ret = process_res_ack(dpld, IPC_FMT); + if (ret >= 0) { + dpram_allow_sleep(dpld); + return; + } + + /* At this point, ret < 0 */ + if (ret == -ENOSPC) + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_FMT], delay); +} + +/** + * raw_tx_work: performs TX for RAW IPC device under DPRAM flow control. + * @work: pointer to an instance of the work_struct structure + * + * 1) Starts waiting for RES_ACK of RAW IPC device. + * 2) Returns immediately if the wait is interrupted. + * 3) Restarts DPRAM flow control if there is a timeout from the wait. + * 4) Otherwise, it performs processing RES_ACK for RAW IPC device. + */ +static void raw_tx_work(struct work_struct *work) +{ + struct link_device *ld; + struct dpram_link_device *dpld; + unsigned long delay = 0; + int ret; + + ld = container_of(work, struct link_device, raw_tx_dwork.work); + dpld = to_dpram_link_device(ld); + + ret = wait_for_res_ack(dpld, IPC_RAW); + /* ret < 0 if interrupted */ + if (ret < 0) + return; + + /* ret == 0 on timeout */ + if (ret == 0) { + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_RAW], 0); + return; + } + + ret = process_res_ack(dpld, IPC_RAW); + if (ret >= 0) { + dpram_allow_sleep(dpld); + mif_netif_wake(ld); + return; + } + + /* At this point, ret < 0 */ + if (ret == -ENOSPC) + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_RAW], delay); +} + +/** + * rfs_tx_work: performs TX for RFS IPC device under DPRAM flow control + * @work: pointer to an instance of the work_struct structure + * + * 1) Starts waiting for RES_ACK of RFS IPC device. + * 2) Returns immediately if the wait is interrupted. + * 3) Restarts DPRAM flow control if there is a timeout from the wait. + * 4) Otherwise, it performs processing RES_ACK for RFS IPC device. + */ +static void rfs_tx_work(struct work_struct *work) +{ + struct link_device *ld; + struct dpram_link_device *dpld; + unsigned long delay = 0; + int ret; + + ld = container_of(work, struct link_device, rfs_tx_dwork.work); + dpld = to_dpram_link_device(ld); + + ret = wait_for_res_ack(dpld, IPC_RFS); + /* ret < 0 if interrupted */ + if (ret < 0) + return; + + /* ret == 0 on timeout */ + if (ret == 0) { + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_RFS], 0); + return; + } + + ret = process_res_ack(dpld, IPC_RFS); + if (ret >= 0) { + dpram_allow_sleep(dpld); + return; + } + + /* At this point, ret < 0 */ + if (ret == -ENOSPC) + queue_delayed_work(ld->tx_wq, ld->tx_dwork[IPC_RFS], delay); +} + +/** + * dpram_send_ipc + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * 1) Tries to transmit IPC messages in the skb_txq by invoking xmit_ipc_msg() + * function. + * 2) Sends an interrupt to CP if there is no error from xmit_ipc_msg(). + * 3) Starts DPRAM flow control if xmit_ipc_msg() returns -ENOSPC. + */ +static int dpram_send_ipc(struct dpram_link_device *dpld, int dev) +{ + struct link_device *ld = &dpld->ld; + int ret; + u16 mask; if (atomic_read(&dpld->res_required[dev]) > 0) { - mif_debug("%s: %s_TXQ is full\n", ld->name, get_dev_name(dev)); + mif_info("%s: %s_TXQ is full\n", ld->name, get_dev_name(dev)); + return 0; + } + + if (dpram_wake_up(dpld) < 0) { + trigger_forced_cp_crash(dpld); + return -EIO; + } + + if (!ipc_active(dpld)) { + mif_info("%s: IPC is NOT active\n", ld->name); + ret = -EIO; goto exit; } - ret = dpram_try_ipc_tx(dpld, dev); - if (ret > 0) { + ret = xmit_ipc_msg(dpld, dev); + if (likely(ret > 0)) { mask = get_mask_send(dpld, dev); - send_intr(dpld, INT_NON_CMD(mask)); - } else if (ret == -ENOSPC) { - mask = get_mask_req_ack(dpld, dev); - send_intr(dpld, INT_NON_CMD(mask)); - mif_info("%s: Send REQ_ACK 0x%04X\n", ld->name, mask); - } else { - mif_info("%s: dpram_try_ipc_tx fail (err %d)\n", ld->name, ret); + send_int2cp(dpld, INT_NON_CMD(mask)); + get_dpram_status(dpld, TX, msq_get_free_slot(&dpld->stat_list)); + goto exit; + } + + /* If there was no TX, just exit */ + if (ret == 0) + goto exit; + + /* At this point, ret < 0 */ + if (ret == -ENOSPC) { + /* Prohibit DPRAM from sleeping until the TXQ buffer is empty */ + if (dpram_wake_up(dpld) < 0) { + trigger_forced_cp_crash(dpld); + goto exit; + } + + /*----------------------------------------------------*/ + /* dpld->res_required[dev] was set in xmit_ipc_msg(). */ + /*----------------------------------------------------*/ + + if (dev == IPC_RAW) + mif_netif_stop(ld); + + queue_delayed_work(ld->tx_wq, ld->tx_dwork[dev], 0); } exit: - if (dpld->dp_type == CP_IDPRAM) - dpram_allow_sleep(dpld); + dpram_allow_sleep(dpld); + return ret; +} + +/** + * pm_tx_work: performs TX while DPRAM PM is locked + * @work: pointer to an instance of the work_struct structure + */ +static void pm_tx_work(struct work_struct *work) +{ + struct idpram_pm_data *pm_data; + struct idpram_pm_op *pm_op; + struct dpram_link_device *dpld; + struct link_device *ld; + struct workqueue_struct *pm_wq = system_nrt_wq; + int i; + int ret; + unsigned long delay = 0; + + pm_data = container_of(work, struct idpram_pm_data, tx_dwork.work); + dpld = container_of(pm_data, struct dpram_link_device, pm_data); + ld = &dpld->ld; + pm_op = dpld->pm_op; + + if (pm_op->locked(dpld)) { + queue_delayed_work(pm_wq, &pm_data->tx_dwork, delay); + return; + } + + /* Here, PM is not locked. */ + for (i = 0; i < ld->max_ipc_dev; i++) { + ret = dpram_send_ipc(dpld, i); + if (ret < 0) { + struct io_device *iod = dpld->iod[i]; + mif_err("%s->%s: ERR! dpram_send_ipc fail (err %d)\n", + iod->name, ld->name, ret); + } + } +} + +/** + * dpram_try_send_ipc + * @dpld: pointer to an instance of dpram_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @iod: pointer to an instance of the io_device structure + * @skb: pointer to an skb that will be transmitted + * + * 1) Enqueues an skb to the skb_txq for @dev in the link device instance. + * 2) Tries to transmit IPC messages in the skb_txq by invoking xmit_ipc_msg() + * function. + * 3) Sends an interrupt to CP if there is no error from xmit_ipc_msg(). + * 4) Starts DPRAM flow control if xmit_ipc_msg() returns -ENOSPC. + */ +static void dpram_try_send_ipc(struct dpram_link_device *dpld, int dev, + struct io_device *iod, struct sk_buff *skb) +{ + struct link_device *ld = &dpld->ld; + struct idpram_pm_data *pm_data = &dpld->pm_data; + struct idpram_pm_op *pm_op = dpld->pm_op; + struct workqueue_struct *pm_wq = system_nrt_wq; + unsigned long delay = msecs_to_jiffies(10); + struct sk_buff_head *txq = ld->skb_txq[dev]; + int ret; + + if (unlikely(txq->qlen >= MAX_SKB_TXQ_DEPTH)) { + mif_info("%s: %s txq->qlen %d >= %d\n", ld->name, + get_dev_name(dev), txq->qlen, MAX_SKB_TXQ_DEPTH); + dev_kfree_skb_any(skb); + return; + } + + skb_queue_tail(txq, skb); + + if (pm_op && pm_op->locked) { + if (pm_op->locked(dpld)) { + queue_delayed_work(pm_wq, &pm_data->tx_dwork, delay); + return; + } + + /* Here, PM is not locked. */ + if (work_pending(&pm_data->tx_dwork.work)) + cancel_delayed_work_sync(&pm_data->tx_dwork); + } + + ret = dpram_send_ipc(dpld, dev); + if (ret < 0) { + mif_err("%s->%s: ERR! dpram_send_ipc fail (err %d)\n", + iod->name, ld->name, ret); + } } static int dpram_send_cp_binary(struct link_device *ld, struct sk_buff *skb) { struct dpram_link_device *dpld = to_dpram_link_device(ld); - if (dpld->ext_op && dpld->ext_op->download_binary) - return dpld->ext_op->download_binary(dpld, skb); + if (dpld->ext_op && dpld->ext_op->xmit_binary) + return dpld->ext_op->xmit_binary(dpld, skb); else return -ENODEV; } +/** + * dpram_send + * @ld: pointer to an instance of the link_device structure + * @iod: pointer to an instance of the io_device structure + * @skb: pointer to an skb that will be transmitted + * + * Returns the length of data transmitted or an error code. + * + * Normal call flow for an IPC message: + * dpram_try_send_ipc -> dpram_send_ipc -> xmit_ipc_msg -> write_ipc_to_txq + * + * Call flow on PM lock in a DPRAM IPC TXQ: + * dpram_try_send_ipc ,,, queue_delayed_work + * => pm_tx_work -> dpram_send_ipc -> xmit_ipc_msg -> write_ipc_to_txq + * + * Call flow on congestion in a DPRAM IPC TXQ: + * dpram_try_send_ipc -> xmit_ipc_msg ,,, queue_delayed_work + * => xxx_tx_work -> wait_for_res_ack + * => msg_handler + * => process_res_ack -> xmit_ipc_msg (,,, queue_delayed_work ...) + */ static int dpram_send(struct link_device *ld, struct io_device *iod, - struct sk_buff *skb) + struct sk_buff *skb) { - enum dev_format dev = iod->format; + struct dpram_link_device *dpld = to_dpram_link_device(ld); + int dev = iod->format; int len = skb->len; switch (dev) { @@ -1379,7 +2266,7 @@ static int dpram_send(struct link_device *ld, struct io_device *iod, case IPC_RAW: case IPC_RFS: if (likely(ld->mode == LINK_MODE_IPC)) { - dpram_send_ipc(ld, dev, iod, skb); + dpram_try_send_ipc(dpld, dev, iod, skb); } else { mif_info("%s: ld->mode != LINK_MODE_IPC\n", ld->name); dev_kfree_skb_any(skb); @@ -1396,23 +2283,45 @@ static int dpram_send(struct link_device *ld, struct io_device *iod, } } -static int dpram_force_dump(struct link_device *ld, struct io_device *iod) +static int dpram_xmit_boot(struct link_device *ld, struct io_device *iod, + unsigned long arg) +{ + struct dpram_link_device *dpld = to_dpram_link_device(ld); + + if (dpld->ext_op && dpld->ext_op->xmit_boot) + return dpld->ext_op->xmit_boot(dpld, arg); + else + return -ENODEV; +} + +static int dpram_set_dload_magic(struct link_device *ld, struct io_device *iod) { struct dpram_link_device *dpld = to_dpram_link_device(ld); - trigger_force_cp_crash(dpld); + + ld->mode = LINK_MODE_DLOAD; + + mif_err("%s: magic = 0x%08X\n", ld->name, DP_MAGIC_DMDL); + iowrite32(DP_MAGIC_DMDL, dpld->dl_map.magic); + return 0; } -static void dpram_dump_memory(struct link_device *ld, char *buff) +static int dpram_dload_firmware(struct link_device *ld, struct io_device *iod, + unsigned long arg) { struct dpram_link_device *dpld = to_dpram_link_device(ld); - u8 __iomem *base = dpld->dpctl->dp_base; - u32 size = dpld->dpctl->dp_size; - if (dpld->dp_type == CP_IDPRAM) - dpram_wake_up(dpld); + if (dpld->ext_op && dpld->ext_op->firm_update) + return dpld->ext_op->firm_update(dpld, arg); + else + return -ENODEV; +} - memcpy(buff, base, size); +static int dpram_force_dump(struct link_device *ld, struct io_device *iod) +{ + struct dpram_link_device *dpld = to_dpram_link_device(ld); + trigger_forced_cp_crash(dpld); + return 0; } static int dpram_dump_start(struct link_device *ld, struct io_device *iod) @@ -1431,13 +2340,24 @@ static int dpram_dump_update(struct link_device *ld, struct io_device *iod, struct dpram_link_device *dpld = to_dpram_link_device(ld); if (dpld->ext_op && dpld->ext_op->dump_update) - return dpld->ext_op->dump_update(dpld, (void *)arg); + return dpld->ext_op->dump_update(dpld, arg); + else + return -ENODEV; +} + +static int dpram_dump_finish(struct link_device *ld, struct io_device *iod, + unsigned long arg) +{ + struct dpram_link_device *dpld = to_dpram_link_device(ld); + + if (dpld->ext_op && dpld->ext_op->dump_finish) + return dpld->ext_op->dump_finish(dpld, arg); else return -ENODEV; } static int dpram_ioctl(struct link_device *ld, struct io_device *iod, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { struct dpram_link_device *dpld = to_dpram_link_device(ld); int err = 0; @@ -1447,17 +2367,21 @@ static int dpram_ioctl(struct link_device *ld, struct io_device *iod, switch (cmd) { case IOCTL_DPRAM_INIT_STATUS: mif_debug("%s: get dpram init status\n", ld->name); - return dpld->dpram_init_status; + return dpld->init_status; - default: - if (dpld->ext_ioctl) { - err = dpld->ext_ioctl(dpld, iod, cmd, arg); - } else { - mif_err("%s: ERR! invalid cmd 0x%08X\n", ld->name, cmd); - err = -EINVAL; - } + case IOCTL_MIF_DPRAM_DUMP: + if (copy_to_user((void __user *)arg, &dpld->size, sizeof(u32))) + return -EFAULT; + capture_dpram_snapshot(ld, iod); break; + + default: + if (dpld->ext_ioctl) + return dpld->ext_ioctl(dpld, iod, cmd, arg); + + mif_err("%s: ERR! invalid cmd 0x%08X\n", ld->name, cmd); + return -EINVAL; } return err; @@ -1468,9 +2392,9 @@ static void dpram_remap_std_16k_region(struct dpram_link_device *dpld) struct dpram_ipc_16k_map *dpram_map; struct dpram_ipc_device *dev; - dpram_map = (struct dpram_ipc_16k_map *)dpld->dp_base; + dpram_map = (struct dpram_ipc_16k_map *)dpld->base; - /* magic code and access enable fields */ + /* "magic code" and "access enable" fields */ dpld->ipc_map.magic = (u16 __iomem *)&dpram_map->magic; dpld->ipc_map.access = (u16 __iomem *)&dpram_map->access; @@ -1519,167 +2443,201 @@ static void dpram_remap_std_16k_region(struct dpram_link_device *dpld) dpld->ipc_map.mbx_ap2cp = (u16 __iomem *)&dpram_map->mbx_ap2cp; } -static int dpram_table_init(struct dpram_link_device *dpld) +static int dpram_init_boot_map(struct dpram_link_device *dpld) { - struct link_device *ld = &dpld->ld; - u8 __iomem *dp_base; - int i; + u8 __iomem *dp_base = dpld->base; + u32 magic_size = DP_DLOAD_MAGIC_SIZE; + u32 mbx_size = DP_MBX_SET_SIZE; - if (!dpld->dp_base) { - mif_info("%s: ERR! dpld->dp_base == NULL\n", ld->name); - return -EINVAL; - } - dp_base = dpld->dp_base; - - /* Map for IPC */ - if (dpld->dpctl->ipc_map) { - memcpy(&dpld->ipc_map, dpld->dpctl->ipc_map, - sizeof(struct dpram_ipc_map)); - } else { - if (dpld->dp_size == DPRAM_SIZE_16KB) - dpram_remap_std_16k_region(dpld); - else - return -EINVAL; - } - - dpld->magic = dpld->ipc_map.magic; - dpld->access = dpld->ipc_map.access; - for (i = 0; i < dpld->max_ipc_dev; i++) - dpld->dev[i] = &dpld->ipc_map.dev[i]; - dpld->mbx2ap = dpld->ipc_map.mbx_cp2ap; - dpld->mbx2cp = dpld->ipc_map.mbx_ap2cp; - - /* Map for booting */ if (dpld->ext_op && dpld->ext_op->init_boot_map) { dpld->ext_op->init_boot_map(dpld); } else { dpld->bt_map.magic = (u32 *)(dp_base); - dpld->bt_map.buff = (u8 *)(dp_base + DP_BOOT_BUFF_OFFSET); - dpld->bt_map.size = dpld->dp_size - 8; + dpld->bt_map.buff = (u8 *)(dp_base + magic_size); + dpld->bt_map.space = dpld->size - (magic_size + mbx_size); } - /* Map for download (FOTA, UDL, etc.) */ + return 0; +} + +static int dpram_init_dload_map(struct dpram_link_device *dpld) +{ + u8 __iomem *dp_base = dpld->base; + u32 magic_size = DP_DLOAD_MAGIC_SIZE; + u32 mbx_size = DP_MBX_SET_SIZE; + if (dpld->ext_op && dpld->ext_op->init_dl_map) { dpld->ext_op->init_dl_map(dpld); } else { dpld->dl_map.magic = (u32 *)(dp_base); - dpld->dl_map.buff = (u8 *)(dp_base + DP_DLOAD_BUFF_OFFSET); + dpld->dl_map.buff = (u8 *)(dp_base + magic_size); + dpld->dl_map.space = dpld->size - (magic_size + mbx_size); } - /* Map for upload mode */ + return 0; +} + +static int dpram_init_uload_map(struct dpram_link_device *dpld) +{ + u8 __iomem *dp_base = dpld->base; + u32 magic_size = DP_DLOAD_MAGIC_SIZE; + u32 mbx_size = DP_MBX_SET_SIZE; + if (dpld->ext_op && dpld->ext_op->init_ul_map) { dpld->ext_op->init_ul_map(dpld); } else { dpld->ul_map.magic = (u32 *)(dp_base); dpld->ul_map.buff = (u8 *)(dp_base + DP_ULOAD_BUFF_OFFSET); + dpld->ul_map.space = dpld->size - (magic_size + mbx_size); } return 0; } +static int dpram_init_ipc_map(struct dpram_link_device *dpld) +{ + int i; + struct link_device *ld = &dpld->ld; + + if (dpld->ext_op && dpld->ext_op->init_ipc_map) { + dpld->ext_op->init_ipc_map(dpld); + } else if (dpld->dpram->ipc_map) { + memcpy(&dpld->ipc_map, dpld->dpram->ipc_map, + sizeof(struct dpram_ipc_map)); + } else { + if (dpld->size == DPRAM_SIZE_16KB) + dpram_remap_std_16k_region(dpld); + else + return -EINVAL; + } + + dpld->magic = dpld->ipc_map.magic; + dpld->access = dpld->ipc_map.access; + for (i = 0; i < ld->max_ipc_dev; i++) + dpld->dev[i] = &dpld->ipc_map.dev[i]; + dpld->mbx2ap = dpld->ipc_map.mbx_cp2ap; + dpld->mbx2cp = dpld->ipc_map.mbx_ap2cp; + + return 0; +} + static void dpram_setup_common_op(struct dpram_link_device *dpld) { - dpld->clear_intr = clear_intr; - dpld->recv_intr = recv_intr; - dpld->send_intr = send_intr; + dpld->recv_intr = recv_int2ap; + dpld->send_intr = send_int2cp; dpld->get_magic = get_magic; dpld->set_magic = set_magic; dpld->get_access = get_access; dpld->set_access = set_access; - dpld->get_tx_head = get_tx_head; - dpld->get_tx_tail = get_tx_tail; - dpld->set_tx_head = set_tx_head; - dpld->set_tx_tail = set_tx_tail; - dpld->get_tx_buff = get_tx_buff; - dpld->get_tx_buff_size = get_tx_buff_size; - dpld->get_rx_head = get_rx_head; - dpld->get_rx_tail = get_rx_tail; - dpld->set_rx_head = set_rx_head; - dpld->set_rx_tail = set_rx_tail; - dpld->get_rx_buff = get_rx_buff; - dpld->get_rx_buff_size = get_rx_buff_size; + dpld->get_txq_head = get_txq_head; + dpld->get_txq_tail = get_txq_tail; + dpld->set_txq_head = set_txq_head; + dpld->set_txq_tail = set_txq_tail; + dpld->get_txq_buff = get_txq_buff; + dpld->get_txq_buff_size = get_txq_buff_size; + dpld->get_rxq_head = get_rxq_head; + dpld->get_rxq_tail = get_rxq_tail; + dpld->set_rxq_head = set_rxq_head; + dpld->set_rxq_tail = set_rxq_tail; + dpld->get_rxq_buff = get_rxq_buff; + dpld->get_rxq_buff_size = get_rxq_buff_size; dpld->get_mask_req_ack = get_mask_req_ack; dpld->get_mask_res_ack = get_mask_res_ack; dpld->get_mask_send = get_mask_send; - dpld->ipc_rx_handler = dpram_ipc_rx; -} - -static int dpram_link_init(struct link_device *ld, struct io_device *iod) -{ - return 0; + dpld->get_dpram_status = get_dpram_status; + dpld->ipc_rx_handler = cmd_msg_handler; + dpld->reset_dpram_ipc = reset_dpram_ipc; } static void dpram_link_terminate(struct link_device *ld, struct io_device *iod) { + if (iod->format == IPC_FMT && ld->mode == LINK_MODE_IPC) { + if (!atomic_read(&iod->opened)) { + ld->mode = LINK_MODE_OFFLINE; + mif_err("%s: %s: link mode is changed: IPC->OFFLINE\n", + iod->name, ld->name); + } + } + return; } struct link_device *dpram_create_link_device(struct platform_device *pdev) { - struct modem_data *mdm_data = NULL; struct dpram_link_device *dpld = NULL; struct link_device *ld = NULL; + struct modem_data *modem = NULL; + struct modemlink_dpram_data *dpram = NULL; struct resource *res = NULL; resource_size_t res_size; - struct modemlink_dpram_control *dpctl = NULL; - unsigned long task_data; int ret = 0; int i = 0; - int bsize; - int qsize; - /* Get the platform data */ - mdm_data = (struct modem_data *)pdev->dev.platform_data; - if (!mdm_data) { - mif_info("ERR! mdm_data == NULL\n"); + /* + ** Alloc an instance of dpram_link_device structure + */ + dpld = kzalloc(sizeof(struct dpram_link_device), GFP_KERNEL); + if (!dpld) { + mif_err("ERR! kzalloc dpld fail\n"); goto err; } - mif_info("modem = %s\n", mdm_data->name); - mif_info("link device = %s\n", mdm_data->link_name); + ld = &dpld->ld; - if (!mdm_data->dpram_ctl) { - mif_info("ERR! mdm_data->dpram_ctl == NULL\n"); + /* + ** Get the modem (platform) data + */ + modem = (struct modem_data *)pdev->dev.platform_data; + if (!modem) { + mif_err("ERR! modem == NULL\n"); goto err; } - dpctl = mdm_data->dpram_ctl; - - /* Alloc DPRAM link device structure */ - dpld = kzalloc(sizeof(struct dpram_link_device), GFP_KERNEL); - if (!dpld) { - mif_info("ERR! kzalloc dpld fail\n"); + mif_info("modem = %s\n", modem->name); + mif_info("link device = %s\n", modem->link_name); + + /* + ** Retrieve modem data and DPRAM control data from the modem data + */ + ld->mdm_data = modem; + ld->name = modem->link_name; + ld->ipc_version = modem->ipc_version; + + if (!modem->dpram) { + mif_err("ERR! no modem->dpram\n"); goto err; } - ld = &dpld->ld; + dpram = modem->dpram; - /* Retrieve modem data and DPRAM control data from the modem data */ - ld->mdm_data = mdm_data; - ld->name = mdm_data->link_name; - ld->ipc_version = mdm_data->ipc_version; + dpld->dpram = dpram; + dpld->type = dpram->type; + dpld->ap = dpram->ap; + dpld->strict_io_access = dpram->strict_io_access; - /* Retrieve the most basic data for IPC from the modem data */ - dpld->dpctl = dpctl; - dpld->dp_type = dpctl->dp_type; - - if (mdm_data->ipc_version < SIPC_VER_50) { - if (!dpctl->max_ipc_dev) { - mif_info("ERR! no max_ipc_dev\n"); + if (ld->ipc_version < SIPC_VER_50) { + if (!modem->max_ipc_dev) { + mif_err("%s: ERR! no max_ipc_dev\n", ld->name); goto err; } - ld->aligned = dpctl->aligned; - dpld->max_ipc_dev = dpctl->max_ipc_dev; + ld->aligned = dpram->aligned; + ld->max_ipc_dev = modem->max_ipc_dev; } else { ld->aligned = 1; - dpld->max_ipc_dev = MAX_SIPC5_DEV; + ld->max_ipc_dev = MAX_SIPC5_DEV; } - /* Set attributes as a link device */ - ld->init_comm = dpram_link_init; + /* + ** Set attributes as a link device + */ ld->terminate_comm = dpram_link_terminate; ld->send = dpram_send; + ld->xmit_boot = dpram_xmit_boot; + ld->dload_start = dpram_set_dload_magic; + ld->firm_update = dpram_dload_firmware; ld->force_dump = dpram_force_dump; ld->dump_start = dpram_dump_start; ld->dump_update = dpram_dump_update; + ld->dump_finish = dpram_dump_finish; + /* IOCTL extension */ ld->ioctl = dpram_ioctl; INIT_LIST_HEAD(&ld->list); @@ -1691,129 +2649,217 @@ struct link_device *dpram_create_link_device(struct platform_device *pdev) ld->skb_txq[IPC_RAW] = &ld->sk_raw_tx_q; ld->skb_txq[IPC_RFS] = &ld->sk_rfs_tx_q; - /* Set up function pointers */ + skb_queue_head_init(&ld->sk_fmt_rx_q); + skb_queue_head_init(&ld->sk_raw_rx_q); + skb_queue_head_init(&ld->sk_rfs_rx_q); + ld->skb_rxq[IPC_FMT] = &ld->sk_fmt_rx_q; + ld->skb_rxq[IPC_RAW] = &ld->sk_raw_rx_q; + ld->skb_rxq[IPC_RFS] = &ld->sk_rfs_rx_q; + + init_completion(&ld->init_cmpl); + init_completion(&ld->pif_cmpl); + + /* + ** Set up function pointers + */ dpram_setup_common_op(dpld); - dpld->dpram_dump = dpram_dump_memory; - dpld->ext_op = dpram_get_ext_op(mdm_data->modem_type); - if (dpld->ext_op && dpld->ext_op->ioctl) - dpld->ext_ioctl = dpld->ext_op->ioctl; - - /* Retrieve DPRAM resource */ - if (!dpctl->dp_base) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dpld->ext_op = dpram_get_ext_op(modem->modem_type); + if (dpld->ext_op) { + if (dpld->ext_op->ioctl) + dpld->ext_ioctl = dpld->ext_op->ioctl; + + if (dpld->ext_op->wakeup && dpld->ext_op->sleep) + dpld->need_wake_up = true; + } + + /* + ** Retrieve DPRAM resource + */ + if (!dpram->base) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + STR_DPRAM_BASE); if (!res) { - mif_info("%s: ERR! platform_get_resource fail\n", + mif_err("%s: ERR! no DPRAM resource\n", ld->name); + goto err; + } + res_size = resource_size(res); + + dpram->base = ioremap_nocache(res->start, res_size); + if (!dpram->base) { + mif_err("%s: ERR! ioremap_nocache for BASE fail\n", ld->name); goto err; } + dpram->size = res_size; + } + dpld->base = dpram->base; + dpld->size = dpram->size; + + mif_info("%s: type %d, aligned %d, base 0x%08X, size %d\n", + ld->name, dpld->type, ld->aligned, (int)dpld->base, dpld->size); + + /* + ** Retrieve DPRAM SFR resource if exists + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + STR_DPRAM_SFR_BASE); + if (res) { res_size = resource_size(res); + dpld->sfr_base = ioremap_nocache(res->start, res_size); + if (!dpld->sfr_base) { + mif_err("%s: ERR! ioremap_nocache for SFR fail\n", + ld->name); + goto err; + } + } + + /* + ** Initialize DPRAM maps (physical map -> logical map) + */ + ret = dpram_init_boot_map(dpld); + if (ret < 0) { + mif_err("%s: ERR! dpram_init_boot_map fail (err %d)\n", + ld->name, ret); + goto err; + } - dpctl->dp_base = ioremap_nocache(res->start, res_size); - dpctl->dp_size = res_size; + ret = dpram_init_dload_map(dpld); + if (ret < 0) { + mif_err("%s: ERR! dpram_init_dload_map fail (err %d)\n", + ld->name, ret); + goto err; } - dpld->dp_base = dpctl->dp_base; - dpld->dp_size = dpctl->dp_size; - mif_info("%s: dp_type %d, aligned %d, dp_base 0x%08X, dp_size %d\n", - ld->name, dpld->dp_type, ld->aligned, (int)dpld->dp_base, - dpld->dp_size); + ret = dpram_init_uload_map(dpld); + if (ret < 0) { + mif_err("%s: ERR! dpram_init_uload_map fail (err %d)\n", + ld->name, ret); + goto err; + } - /* Initialize DPRAM map (physical map -> logical map) */ - ret = dpram_table_init(dpld); + ret = dpram_init_ipc_map(dpld); if (ret < 0) { - mif_info("%s: ERR! dpram_table_init fail (err %d)\n", + mif_err("%s: ERR! dpram_init_ipc_map fail (err %d)\n", ld->name, ret); goto err; } + if (dpram->res_ack_wait_timeout > 0) + dpld->res_ack_wait_timeout = dpram->res_ack_wait_timeout; + else + dpld->res_ack_wait_timeout = RES_ACK_WAIT_TIMEOUT; + /* Disable IPC */ - set_magic(dpld, 0); - set_access(dpld, 0); - dpld->dpram_init_status = DPRAM_INIT_STATE_NONE; + if (!dpram->disabled) { + set_magic(dpld, 0); + set_access(dpld, 0); + } + dpld->init_status = DPRAM_INIT_STATE_NONE; - /* Initialize locks, completions, and bottom halves */ - snprintf(dpld->wlock_name, DP_MAX_NAME_LEN, "%s_wlock", ld->name); + /* + ** Initialize locks, completions, and bottom halves + */ + snprintf(dpld->wlock_name, MIF_MAX_NAME_LEN, "%s_wlock", ld->name); wake_lock_init(&dpld->wlock, WAKE_LOCK_SUSPEND, dpld->wlock_name); - init_completion(&dpld->dpram_init_cmd); - init_completion(&dpld->modem_pif_init_done); - init_completion(&dpld->udl_start_complete); - init_completion(&dpld->udl_cmd_complete); - init_completion(&dpld->dump_start_complete); - init_completion(&dpld->dump_recv_done); - - task_data = (unsigned long)dpld; - tasklet_init(&dpld->rx_tsk, dpram_ipc_rx_task, task_data); - - /* Prepare SKB queue head for RX processing */ - for (i = 0; i < dpld->max_ipc_dev; i++) - skb_queue_head_init(&dpld->skb_rxq[i]); - - /* Prepare RXB queue */ - qsize = DPRAM_MAX_RXBQ_SIZE; - for (i = 0; i < dpld->max_ipc_dev; i++) { - bsize = rxbq_get_page_size(get_rx_buff_size(dpld, i)); - dpld->rxbq[i].size = qsize; - dpld->rxbq[i].in = 0; - dpld->rxbq[i].out = 0; - dpld->rxbq[i].rxb = rxbq_create_pool(bsize, qsize); - if (!dpld->rxbq[i].rxb) { - mif_info("%s: ERR! %s rxbq_create_pool fail\n", - ld->name, get_dev_name(i)); - goto err; - } - mif_info("%s: %s rxbq_pool created (bsize:%d, qsize:%d)\n", - ld->name, get_dev_name(i), bsize, qsize); + init_completion(&dpld->udl_cmpl); + init_completion(&dpld->crash_cmpl); + + for (i = 0; i < ld->max_ipc_dev; i++) + init_completion(&dpld->req_ack_cmpl[i]); + + INIT_DELAYED_WORK(&dpld->rx_dwork, ipc_rx_work); + + for (i = 0; i < ld->max_ipc_dev; i++) { + spin_lock_init(&dpld->tx_lock[i]); + atomic_set(&dpld->res_required[i], 0); + } + + ld->tx_wq = create_singlethread_workqueue("dpram_tx_wq"); + if (!ld->tx_wq) { + mif_err("%s: ERR! fail to create tx_wq\n", ld->name); + goto err; } + INIT_DELAYED_WORK(&ld->fmt_tx_dwork, fmt_tx_work); + INIT_DELAYED_WORK(&ld->raw_tx_dwork, raw_tx_work); + INIT_DELAYED_WORK(&ld->rfs_tx_dwork, rfs_tx_work); + ld->tx_dwork[IPC_FMT] = &ld->fmt_tx_dwork; + ld->tx_dwork[IPC_RAW] = &ld->raw_tx_dwork; + ld->tx_dwork[IPC_RFS] = &ld->rfs_tx_dwork; + +#ifdef DEBUG_MODEM_IF + spin_lock_init(&dpld->stat_list.lock); + spin_lock_init(&dpld->trace_list.lock); +#endif /* Prepare a multi-purpose miscellaneous buffer */ - dpld->buff = kzalloc(dpld->dp_size, GFP_KERNEL); + dpld->buff = kzalloc(dpld->size, GFP_KERNEL); if (!dpld->buff) { - mif_info("%s: ERR! kzalloc dpld->buff fail\n", ld->name); + mif_err("%s: ERR! kzalloc dpld->buff fail\n", ld->name); goto err; } - /* Retrieve DPRAM IRQ GPIO# */ - dpld->gpio_dpram_int = mdm_data->gpio_dpram_int; - - /* Retrieve DPRAM IRQ# */ - if (!dpctl->dpram_irq) { - dpctl->dpram_irq = platform_get_irq_byname(pdev, "dpram_irq"); - if (dpctl->dpram_irq < 0) { - mif_info("%s: ERR! platform_get_irq_byname fail\n", - ld->name); + /* + ** Retrieve DPRAM IRQ GPIO#, IRQ#, and IRQ flags + */ + dpld->gpio_int2ap = modem->gpio_ipc_int2ap; + dpld->gpio_cp_status = modem->gpio_cp_status; + dpld->gpio_cp_wakeup = modem->gpio_cp_wakeup; + if (dpram->type == AP_IDPRAM) { + if (!modem->gpio_ipc_int2cp) { + mif_err("%s: ERR! no gpio_ipc_int2cp\n", ld->name); goto err; } + dpld->gpio_int2cp = modem->gpio_ipc_int2cp; } - dpld->irq = dpctl->dpram_irq; - /* Retrieve DPRAM IRQ flags */ - if (!dpctl->dpram_irq_flags) - dpctl->dpram_irq_flags = (IRQF_NO_SUSPEND | IRQF_TRIGGER_LOW); - dpld->irq_flags = dpctl->dpram_irq_flags; + dpld->irq = modem->irq_ipc_int2ap; + + if (modem->irqf_ipc_int2ap) + dpld->irq_flags = modem->irqf_ipc_int2ap; + else + dpld->irq_flags = (IRQF_NO_SUSPEND | IRQF_TRIGGER_LOW); + + /* + ** Initialize power management (PM) for AP_IDPRAM + */ + if (dpld->type == AP_IDPRAM) { + dpld->pm_op = idpram_get_pm_op(dpld->ap); + if (!dpld->pm_op) { + mif_err("%s: no pm_op for AP_IDPRAM\n", ld->name); + goto err; + } + + ret = dpld->pm_op->pm_init(dpld, modem, pm_tx_work); + if (ret) { + mif_err("%s: pm_init fail (err %d)\n", ld->name, ret); + goto err; + } + } - /* Register DPRAM interrupt handler */ - snprintf(dpld->irq_name, DP_MAX_NAME_LEN, "%s_irq", ld->name); + /* + ** Register DPRAM interrupt handler + */ + snprintf(dpld->irq_name, MIF_MAX_NAME_LEN, "%s_irq", ld->name); if (dpld->ext_op && dpld->ext_op->irq_handler) dpld->irq_handler = dpld->ext_op->irq_handler; - else if (dpld->dp_type == CP_IDPRAM) + else if (dpld->type == CP_IDPRAM) dpld->irq_handler = cp_idpram_irq_handler; - else if (dpld->dp_type == AP_IDPRAM) + else if (dpld->type == AP_IDPRAM) dpld->irq_handler = ap_idpram_irq_handler; else dpld->irq_handler = ext_dpram_irq_handler; - ret = dpram_register_isr(dpld->irq, dpld->irq_handler, dpld->irq_flags, + ret = mif_register_isr(dpld->irq, dpld->irq_handler, dpld->irq_flags, dpld->irq_name, dpld); if (ret) goto err; - else - return ld; + + return ld; err: if (dpld) { - if (dpld->buff) - kfree(dpld->buff); + kfree(dpld->buff); kfree(dpld); } diff --git a/drivers/misc/modem_if/modem_link_device_dpram.h b/drivers/misc/modem_if/modem_link_device_dpram.h index c651e51..d9ef251 100644 --- a/drivers/misc/modem_if/modem_link_device_dpram.h +++ b/drivers/misc/modem_if/modem_link_device_dpram.h @@ -1,5 +1,4 @@ /* - * Copyright (C) 2011 Google, Inc. * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -12,227 +11,11 @@ * GNU General Public License for more details. * */ + #ifndef __MODEM_LINK_DEVICE_DPRAM_H__ #define __MODEM_LINK_DEVICE_DPRAM_H__ -#include <linux/spinlock.h> -#include <linux/wakelock.h> -#include <linux/workqueue.h> -#include <linux/timer.h> -#include <linux/platform_data/modem.h> - -#include "modem_prj.h" - -#define DPRAM_MAGIC_CODE 0xAA - -/* interrupt masks.*/ -#define INT_MASK_VALID 0x0080 -#define INT_MASK_CMD 0x0040 -#define INT_VALID(x) ((x) & INT_MASK_VALID) -#define INT_CMD_VALID(x) ((x) & INT_MASK_CMD) -#define INT_NON_CMD(x) (INT_MASK_VALID | (x)) -#define INT_CMD(x) (INT_MASK_VALID | INT_MASK_CMD | (x)) - -#define EXT_UDL_MASK 0xF000 -#define EXT_UDL_CMD(x) ((x) & EXT_UDL_MASK) -#define EXT_INT_VALID_MASK 0x8000 -#define EXT_CMD_VALID_MASK 0x4000 -#define UDL_CMD_VALID_MASK 0x2000 -#define EXT_INT_VALID(x) ((x) & EXT_INT_VALID_MASK) -#define EXT_CMD_VALID(x) ((x) & EXT_CMD_VALID_MASK) -#define UDL_CMD_VALID(x) ((x) & UDL_CMD_VALID_MASK) -#define INT_EXT_CMD(x) (EXT_INT_VALID_MASK | EXT_CMD_VALID_MASK | (x)) - -#define EXT_CMD_MASK(x) ((x) & 0x0FFF) -#define EXT_CMD_SET_SPEED_LOW 0x0011 -#define EXT_CMD_SET_SPEED_MID 0x0012 -#define EXT_CMD_SET_SPEED_HIGH 0x0013 - -#define UDL_RESULT_SUCCESS 0x1 -#define UDL_RESULT_FAIL 0x2 - -#define UDL_CMD_MASK(x) (((x) >> 8) & 0xF) -#define UDL_CMD_RECV_READY 0x1 -#define UDL_CMD_DL_START_REQ 0x2 -#define UDL_CMD_DL_START_RESP 0x3 -#define UDL_CMD_IMAGE_SEND_REQ 0x4 -#define UDL_CMD_SEND_DONE_RESP 0x5 -#define UDL_CMD_SEND_DONE_REQ 0x6 -#define UDL_CMD_UPDATE_DONE 0x7 -#define UDL_CMD_STATUS_UPDATE 0x8 -#define UDL_CMD_IMAGE_SEND_RESP 0x9 -#define UDL_CMD_EFS_CLEAR_RESP 0xB -#define UDL_CMD_ALARM_BOOT_OK 0xC -#define UDL_CMD_ALARM_BOOT_FAIL 0xD - -#define CMD_IMG_START_REQ 0x9200 -#define CMD_IMG_SEND_REQ 0x9400 -#define CMD_DL_SEND_DONE_REQ 0x9600 -#define CMD_UL_RECV_RESP 0x9601 -#define CMD_UL_RECV_DONE_RESP 0x9801 - -/* special interrupt cmd indicating modem boot failure. */ -#define INT_POWERSAFE_FAIL 0xDEAD - -#define INT_MASK_REQ_ACK_RFS 0x0400 /* Request RES_ACK_RFS */ -#define INT_MASK_RES_ACK_RFS 0x0200 /* Response of REQ_ACK_RFS */ -#define INT_MASK_SEND_RFS 0x0100 /* Indicate sending RFS data */ - -#define INT_MASK_REQ_ACK_F 0x0020 -#define INT_MASK_REQ_ACK_R 0x0010 -#define INT_MASK_RES_ACK_F 0x0008 -#define INT_MASK_RES_ACK_R 0x0004 -#define INT_MASK_SEND_F 0x0002 -#define INT_MASK_SEND_R 0x0001 - -#define INT_MASK_RES_ACK_SET \ - (INT_MASK_RES_ACK_F | INT_MASK_RES_ACK_R | INT_MASK_RES_ACK_RFS) - -#define INT_MASK_SEND_SET \ - (INT_MASK_SEND_F | INT_MASK_SEND_R | INT_MASK_SEND_RFS) - -#define INT_CMD_MASK(x) ((x) & 0xF) -#define INT_CMD_INIT_START 0x1 -#define INT_CMD_INIT_END 0x2 -#define INT_CMD_REQ_ACTIVE 0x3 -#define INT_CMD_RES_ACTIVE 0x4 -#define INT_CMD_REQ_TIME_SYNC 0x5 -#define INT_CMD_CRASH_RESET 0x7 -#define INT_CMD_PHONE_START 0x8 -#define INT_CMD_ERR_DISPLAY 0x9 -#define INT_CMD_CRASH_EXIT 0x9 -#define INT_CMD_CP_DEEP_SLEEP 0xA -#define INT_CMD_NV_REBUILDING 0xB -#define INT_CMD_EMER_DOWN 0xC -#define INT_CMD_PIF_INIT_DONE 0xD -#define INT_CMD_SILENT_NV_REBUILDING 0xE -#define INT_CMD_NORMAL_PWR_OFF 0xF - -#define START_FLAG 0x7F -#define END_FLAG 0x7E - -#define DP_MAGIC_DMDL 0x4445444C -#define DP_MAGIC_UMDL 0x4445444D -#define DP_DPRAM_SIZE 0x4000 -#define DP_DEFAULT_WRITE_LEN 8168 -#define DP_DEFAULT_DUMP_LEN 16128 -#define DP_DUMP_HEADER_SIZE 7 - -#define UDL_TIMEOUT (50 * HZ) -#define UDL_SEND_TIMEOUT (200 * HZ) -#define FORCE_CRASH_ACK_TIMEOUT (5 * HZ) -#define DUMP_TIMEOUT (30 * HZ) -#define DUMP_START_TIMEOUT (100 * HZ) -#define DUMP_WAIT_TIMEOUT (HZ >> 10) /* 1/1024 second */ - -enum host_boot_mode { - HOST_BOOT_MODE_NORMAL, - HOST_BOOT_MODE_DUMP, -}; - -enum dpram_init_status { - DPRAM_INIT_STATE_NONE, - DPRAM_INIT_STATE_READY, -}; - -struct dpram_boot_img { - char *addr; - int size; - enum host_boot_mode mode; - unsigned req; - unsigned resp; -}; - -#define MAX_PAYLOAD_SIZE 0x2000 -struct dpram_boot_frame { - unsigned req; /* AP->CP request */ - unsigned resp; /* response expected by AP */ - ssize_t len; /* data size in the buffer */ - unsigned offset; /* offset to write into DPRAM */ - char data[MAX_PAYLOAD_SIZE]; -}; - -/* buffer type for modem image */ -struct dpram_dump_arg { - char *buff; /* pointer to the buffer */ - int buff_size; /* buffer size */ - unsigned req; /* AP->CP request */ - unsigned resp; /* CP->AP response */ - bool cmd; /* AP->CP command */ -}; - -struct dpram_boot_map { - u32 __iomem *magic; - u8 __iomem *buff; - u32 __iomem *req; - u32 __iomem *resp; - u32 size; -}; - -struct qc_dpram_boot_map { - u8 __iomem *buff; - u16 __iomem *frame_size; - u16 __iomem *tag; - u16 __iomem *count; -}; - -struct dpram_dload_map { - u32 __iomem *magic; - u8 __iomem *buff; -}; - -struct dpram_uload_map { - u32 __iomem *magic; - u8 __iomem *buff; -}; - -struct ul_header { - u8 bop; - u16 total_frame; - u16 curr_frame; - u16 len; -} __packed; - -struct dpram_udl_param { - unsigned char *addr; - unsigned int size; - unsigned int count; - unsigned int tag; -}; - -struct dpram_udl_check { - unsigned int total_size; - unsigned int rest_size; - unsigned int send_size; - unsigned int copy_start; - unsigned int copy_complete; - unsigned int boot_complete; -}; - -#define DP_BOOT_BUFF_OFFSET 4 -#define DP_DLOAD_BUFF_OFFSET 4 -#define DP_ULOAD_BUFF_OFFSET 4 -#define DP_BOOT_REQ_OFFSET 0 -#define DP_BOOT_RESP_OFFSET 8 - -#define MAX_WQ_NAME_LENGTH 64 - -#define DPRAM_MAX_RXBQ_SIZE 256 - -struct dpram_rxb { - u8 *buff; - unsigned size; - - u8 *data; - unsigned len; -}; - -struct dpram_rxb_queue { - int size; - int in; - int out; - struct dpram_rxb *rxb; -}; +#include "modem_link_device_memory.h" /* magic_code + @@ -282,38 +65,110 @@ struct dpram_ipc_16k_map { u16 mbx_ap2cp; }; -#define DP_MAX_NAME_LEN 32 +enum dpram_init_status { + DPRAM_INIT_STATE_NONE, + DPRAM_INIT_STATE_READY, +}; + +struct dpram_boot_frame { + unsigned req; /* AP->CP request */ + unsigned resp; /* response expected by AP */ + ssize_t len; /* data size in the buffer */ + unsigned offset; /* offset to write into DPRAM */ + char data[DP_MAX_PAYLOAD_SIZE]; +}; + +struct dpram_dump_arg { + char *buff; /* pointer to the buffer */ + int buff_size; /* buffer size */ + unsigned req; /* AP->CP request */ + unsigned resp; /* CP->AP response */ + int cmd; /* AP->CP command */ +}; + +/* DPRAM upload/download header */ +struct dpram_udl_header { + u8 bop; + u16 num_frames; + u16 curr_frame; + u16 len; +#ifdef CONFIG_CDMA_MODEM_CBP82 + u8 pad; +#endif +} __packed; + +#define MAX_DUMP_SKB_SIZE 4096 + +enum idpram_link_pm_states { + IDPRAM_PM_SUSPEND_PREPARE, + IDPRAM_PM_DPRAM_POWER_DOWN, + IDPRAM_PM_SUSPEND_START, + IDPRAM_PM_RESUME_START, + IDPRAM_PM_ACTIVE, +}; + +struct idpram_pm_data { + atomic_t pm_lock; + + enum idpram_link_pm_states pm_state; + + struct completion down_cmpl; + + struct wake_lock ap_wlock; + struct wake_lock hold_wlock; + struct delayed_work tx_dwork; + struct delayed_work resume_dwork; + + struct notifier_block pm_noti; + + unsigned resume_try_cnt; + + /* the last value in the mbx_cp2ap */ + unsigned last_msg; +}; + +struct dpram_link_device; struct dpram_ext_op; +struct idpram_pm_op; struct dpram_link_device { struct link_device ld; + enum dpram_type type; /* DPRAM type */ + enum ap_type ap; /* AP type for AP_IDPRAM */ + + /* Stirct I/O access (e.g. ioread16(), etc.) is required */ + bool strict_io_access; + /* DPRAM address and size */ - u8 __iomem *dp_base; /* DPRAM base virtual address */ - u32 dp_size; /* DPRAM size */ - enum dpram_type dp_type; /* DPRAM type */ + u8 __iomem *base; /* Virtual address of DPRAM */ + u32 size; /* DPRAM size */ + + /* DPRAM SFR */ + u8 __iomem *sfr_base; /* Virtual address of SFR */ + + /* Whether or not this DPRAM can go asleep */ + bool need_wake_up; /* DPRAM IRQ GPIO# */ - unsigned gpio_dpram_int; + unsigned gpio_int2ap; + unsigned gpio_cp_status; + unsigned gpio_cp_wakeup; + unsigned gpio_int2cp; /* DPRAM IRQ from CP */ int irq; unsigned long irq_flags; - char irq_name[DP_MAX_NAME_LEN]; + char irq_name[MIF_MAX_NAME_LEN]; /* Link to DPRAM control functions dependent on each platform */ - int max_ipc_dev; - struct modemlink_dpram_control *dpctl; + struct modemlink_dpram_data *dpram; /* Physical configuration -> logical configuration */ - union { - struct dpram_boot_map bt_map; - struct qc_dpram_boot_map qc_bt_map; - }; - - struct dpram_dload_map dl_map; - struct dpram_uload_map ul_map; + struct memif_boot_map bt_map; + struct memif_dload_map dl_map; + struct memif_uload_map ul_map; /* IPC device map */ struct dpram_ipc_map ipc_map; @@ -327,40 +182,40 @@ struct dpram_link_device { /* Wakelock for DPRAM device */ struct wake_lock wlock; - char wlock_name[DP_MAX_NAME_LEN]; + char wlock_name[MIF_MAX_NAME_LEN]; /* For booting */ unsigned boot_start_complete; - struct completion dpram_init_cmd; - struct completion modem_pif_init_done; /* For UDL */ - struct tasklet_struct ul_tsk; struct tasklet_struct dl_tsk; - struct completion udl_start_complete; - struct completion udl_cmd_complete; - struct dpram_udl_check udl_check; - struct dpram_udl_param udl_param; + struct completion udl_cmpl; - /* For CP RAM dump */ + /* + ** For CP crash dump + */ + bool forced_cp_crash; struct timer_list crash_ack_timer; - struct completion dump_start_complete; - struct completion dump_recv_done; - struct timer_list dump_timer; - int dump_rcvd; /* Count of dump packets received */ + struct timer_list crash_timer; + struct completion crash_cmpl; + /* If this field is wanted to be used, it must be initialized only in + * the "ld->dump_start" method. + */ + struct delayed_work crash_dwork; + /* Count of CP crash dump packets received */ + int crash_rcvd; /* For locking TX process */ spinlock_t tx_lock[MAX_IPC_DEV]; + /* For retransmission under DPRAM flow control after TXQ full state */ + unsigned long res_ack_wait_timeout; + atomic_t res_required[MAX_IPC_DEV]; + struct completion req_ack_cmpl[MAX_IPC_DEV]; + /* For efficient RX process */ - struct tasklet_struct rx_tsk; - struct dpram_rxb_queue rxbq[MAX_IPC_DEV]; + struct delayed_work rx_dwork; struct io_device *iod[MAX_IPC_DEV]; - bool use_skb; - struct sk_buff_head skb_rxq[MAX_IPC_DEV]; - - /* For retransmission after buffer full state */ - atomic_t res_required[MAX_IPC_DEV]; /* For wake-up/sleep control */ atomic_t accessing; @@ -369,45 +224,53 @@ struct dpram_link_device { u8 *buff; /* DPRAM IPC initialization status */ - int dpram_init_status; + int init_status; /* Alias to device-specific IOCTL function */ int (*ext_ioctl)(struct dpram_link_device *dpld, struct io_device *iod, unsigned int cmd, unsigned long arg); /* Alias to DPRAM IRQ handler */ - irqreturn_t (*irq_handler)(int irq, void *data); + irq_handler_t irq_handler; - /* For DPRAM dump */ - void (*dpram_dump)(struct link_device *ld, char *buff); + /* For DPRAM logging */ + struct mem_status_queue stat_list; + struct trace_data_queue trace_list; /* Common operations for each DPRAM */ - void (*clear_intr)(struct dpram_link_device *dpld); u16 (*recv_intr)(struct dpram_link_device *dpld); void (*send_intr)(struct dpram_link_device *dpld, u16 mask); u16 (*get_magic)(struct dpram_link_device *dpld); void (*set_magic)(struct dpram_link_device *dpld, u16 value); u16 (*get_access)(struct dpram_link_device *dpld); void (*set_access)(struct dpram_link_device *dpld, u16 value); - u32 (*get_tx_head)(struct dpram_link_device *dpld, int id); - u32 (*get_tx_tail)(struct dpram_link_device *dpld, int id); - void (*set_tx_head)(struct dpram_link_device *dpld, int id, u32 head); - void (*set_tx_tail)(struct dpram_link_device *dpld, int id, u32 tail); - u8 *(*get_tx_buff)(struct dpram_link_device *dpld, int id); - u32 (*get_tx_buff_size)(struct dpram_link_device *dpld, int id); - u32 (*get_rx_head)(struct dpram_link_device *dpld, int id); - u32 (*get_rx_tail)(struct dpram_link_device *dpld, int id); - void (*set_rx_head)(struct dpram_link_device *dpld, int id, u32 head); - void (*set_rx_tail)(struct dpram_link_device *dpld, int id, u32 tail); - u8 *(*get_rx_buff)(struct dpram_link_device *dpld, int id); - u32 (*get_rx_buff_size)(struct dpram_link_device *dpld, int id); + u32 (*get_txq_head)(struct dpram_link_device *dpld, int id); + u32 (*get_txq_tail)(struct dpram_link_device *dpld, int id); + void (*set_txq_head)(struct dpram_link_device *dpld, int id, u32 in); + void (*set_txq_tail)(struct dpram_link_device *dpld, int id, u32 out); + u8 *(*get_txq_buff)(struct dpram_link_device *dpld, int id); + u32 (*get_txq_buff_size)(struct dpram_link_device *dpld, int id); + u32 (*get_rxq_head)(struct dpram_link_device *dpld, int id); + u32 (*get_rxq_tail)(struct dpram_link_device *dpld, int id); + void (*set_rxq_head)(struct dpram_link_device *dpld, int id, u32 in); + void (*set_rxq_tail)(struct dpram_link_device *dpld, int id, u32 out); + u8 *(*get_rxq_buff)(struct dpram_link_device *dpld, int id); + u32 (*get_rxq_buff_size)(struct dpram_link_device *dpld, int id); u16 (*get_mask_req_ack)(struct dpram_link_device *dpld, int id); u16 (*get_mask_res_ack)(struct dpram_link_device *dpld, int id); u16 (*get_mask_send)(struct dpram_link_device *dpld, int id); - void (*ipc_rx_handler)(struct dpram_link_device *dpld, u16 int2ap); + void (*get_dpram_status)(struct dpram_link_device *dpld, + enum circ_dir_type, struct mem_status *stat); + void (*ipc_rx_handler)(struct dpram_link_device *dpld, + struct mem_status *stat); + void (*reset_dpram_ipc)(struct dpram_link_device *dpld); /* Extended operations for various modems */ struct dpram_ext_op *ext_op; + + /* Power management (PM) for AP_IDPRAM */ + struct idpram_pm_data pm_data; + struct idpram_pm_op *pm_op; }; /* converts from struct link_device* to struct xxx_link_device* */ @@ -415,27 +278,65 @@ struct dpram_link_device { container_of(linkdev, struct dpram_link_device, ld) struct dpram_ext_op { + /* flag for checking whether or not a dpram_ext_op instance exists */ int exist; + /* methods for setting up DPRAM maps */ void (*init_boot_map)(struct dpram_link_device *dpld); void (*init_dl_map)(struct dpram_link_device *dpld); void (*init_ul_map)(struct dpram_link_device *dpld); + void (*init_ipc_map)(struct dpram_link_device *dpld); - int (*download_binary)(struct dpram_link_device *dpld, - struct sk_buff *skb); + /* methods for CP booting */ + int (*xmit_boot)(struct dpram_link_device *dpld, unsigned long arg); + int (*xmit_binary)(struct dpram_link_device *dpld, struct sk_buff *skb); + /* methods for DPRAM command handling */ + void (*cmd_handler)(struct dpram_link_device *dpld, u16 cmd); void (*cp_start_handler)(struct dpram_link_device *dpld); + /* method for CP firmware upgrade */ + int (*firm_update)(struct dpram_link_device *dpld, unsigned long arg); + + /* methods for CP crash dump */ void (*crash_log)(struct dpram_link_device *dpld); int (*dump_start)(struct dpram_link_device *dpld); - int (*dump_update)(struct dpram_link_device *dpld, void *arg); + int (*dump_update)(struct dpram_link_device *dpld, unsigned long arg); + int (*dump_finish)(struct dpram_link_device *dpld, unsigned long arg); + /* IOCTL extension */ int (*ioctl)(struct dpram_link_device *dpld, struct io_device *iod, - unsigned int cmd, unsigned long arg); + unsigned int cmd, unsigned long arg); - irqreturn_t (*irq_handler)(int irq, void *data); + /* methods for interrupt handling */ + irq_handler_t irq_handler; + void (*clear_int2ap)(struct dpram_link_device *dpld); + + /* methods for power management */ + int (*wakeup)(struct dpram_link_device *dpld); + void (*sleep)(struct dpram_link_device *dpld); }; struct dpram_ext_op *dpram_get_ext_op(enum modem_t modem); +struct idpram_pm_op { + /* flag for checking whether or not a idpram_pm_op instance exists */ + int exist; + int (*pm_init)(struct dpram_link_device *dpld, struct modem_data *modem, + void (*pm_tx_func)(struct work_struct *work)); + void (*power_down)(struct dpram_link_device *dpld); + void (*power_up)(struct dpram_link_device *dpld); + void (*halt_suspend)(struct dpram_link_device *dpld); + bool (*locked)(struct dpram_link_device *dpld); + bool (*int2cp_possible)(struct dpram_link_device *dpld); +}; + +struct idpram_pm_op *idpram_get_pm_op(enum ap_type id); + +#if 1 +#endif + +extern void set_sromc_access(bool access); + #endif + diff --git a/drivers/misc/modem_if/modem_link_device_dpram_ext_op.c b/drivers/misc/modem_if/modem_link_device_dpram_ext_op.c index 1475a46..edaf6e5 100644 --- a/drivers/misc/modem_if/modem_link_device_dpram_ext_op.c +++ b/drivers/misc/modem_if/modem_link_device_dpram_ext_op.c @@ -25,103 +25,82 @@ #include <linux/if_arp.h> #include <linux/platform_device.h> #include <linux/kallsyms.h> -#include <linux/platform_data/modem.h> +#include <linux/suspend.h> +#include <plat/gpio-cfg.h> +#include <mach/gpio.h> +#include "modem.h" #include "modem_prj.h" -#include "modem_link_device_dpram.h" #include "modem_utils.h" +#include "modem_link_device_dpram.h" -#if defined(CONFIG_LTE_MODEM_CMC221) -/* -** For host (flashless) booting via DPRAM -*/ -#define CMC22x_AP_BOOT_DOWN_DONE 0x54329876 -#define CMC22x_CP_REQ_MAIN_BIN 0xA5A5A5A5 -#define CMC22x_CP_REQ_NV_DATA 0x5A5A5A5A -#define CMC22x_CP_DUMP_MAGIC 0xDEADDEAD - -#define CMC22x_HOST_DOWN_START 0x1234 -#define CMC22x_HOST_DOWN_END 0x4321 -#define CMC22x_REG_NV_DOWN_END 0xABCD -#define CMC22x_CAL_NV_DOWN_END 0xDCBA - -#define CMC22x_1ST_BUFF_READY 0xAAAA -#define CMC22x_2ND_BUFF_READY 0xBBBB -#define CMC22x_1ST_BUFF_FULL 0x1111 -#define CMC22x_2ND_BUFF_FULL 0x2222 - -#define CMC22x_CP_RECV_NV_END 0x8888 -#define CMC22x_CP_CAL_OK 0x4F4B -#define CMC22x_CP_CAL_BAD 0x4552 -#define CMC22x_CP_DUMP_END 0xFADE - -#define CMC22x_DUMP_BUFF_SIZE 8192 /* 8 KB */ -#endif - -#if defined(CONFIG_CDMA_MODEM_CBP72) -static void cbp72_init_boot_map(struct dpram_link_device *dpld) +#if defined(CONFIG_CDMA_MODEM_CBP72) || defined(CONFIG_CDMA_MODEM_CBP82) +static void cbp_init_boot_map(struct dpram_link_device *dpld) { - struct dpram_boot_map *bt_map = &dpld->bt_map; + struct memif_boot_map *bt_map = &dpld->bt_map; - bt_map->magic = (u32 *)dpld->dp_base; - bt_map->buff = (u8 *)(dpld->dp_base + DP_BOOT_BUFF_OFFSET); - bt_map->size = dpld->dp_size - 4; + bt_map->magic = (u32 *)dpld->base; + bt_map->buff = (u8 *)(dpld->base + DP_BOOT_BUFF_OFFSET); + bt_map->space = dpld->size - 4; } -static void cbp72_init_dl_map(struct dpram_link_device *dpld) +static void cbp_init_dl_map(struct dpram_link_device *dpld) { - dpld->dl_map.magic = (u32 *)dpld->dp_base; - dpld->dl_map.buff = (u8 *)(dpld->dp_base + DP_DLOAD_BUFF_OFFSET); + dpld->dl_map.magic = (u32 *)dpld->base; + dpld->dl_map.buff = (u8 *)(dpld->base + DP_DLOAD_BUFF_OFFSET); } -static int _cbp72_edpram_wait_resp(struct dpram_link_device *dpld, u32 resp) +static int cbp_udl_wait_resp(struct dpram_link_device *dpld, u32 resp) { - struct link_device *ld = &dpld->ld; int ret; - int int2cp; + int int2ap; - ret = wait_for_completion_interruptible_timeout( - &dpld->udl_cmd_complete, UDL_TIMEOUT); + mif_debug("wait for 0x%04X\n", resp); + ret = wait_for_completion_timeout(&dpld->udl_cmpl, UDL_TIMEOUT); if (!ret) { - mif_info("%s: ERR! No UDL_CMD_RESP!!!\n", ld->name); - return -ENXIO; + mif_info("ERR! No UDL_CMD_RESP!!!\n"); + return -EIO; } - int2cp = dpld->recv_intr(dpld); - mif_debug("%s: int2cp = 0x%x\n", ld->name, int2cp); - if (resp == int2cp || int2cp == 0xA700) - return int2cp; - else + int2ap = dpld->recv_intr(dpld); + if (resp == int2ap || int2ap == CMD_UL_RECV_DONE_REQ) { + mif_debug("int2ap = 0x%04X\n", int2ap); + return int2ap; + } else { + mif_err("ERR! int2ap 0x%04X != resp 0x%04X\n", int2ap, resp); return -EINVAL; + } } -static int _cbp72_edpram_download_bin(struct dpram_link_device *dpld, +static int cbp_xmit_binary(struct dpram_link_device *dpld, struct sk_buff *skb) { - struct link_device *ld = &dpld->ld; struct dpram_boot_frame *bf = (struct dpram_boot_frame *)skb->data; u8 __iomem *buff = dpld->bt_map.buff; int err = 0; - if (bf->len > dpld->bt_map.size) { - mif_info("%s: ERR! Out of DPRAM boundary\n", ld->name); - err = -EINVAL; + if (bf->len > dpld->bt_map.space) { + mif_info("ERR! Out of DPRAM boundary\n"); + err = -ERANGE; goto exit; } if (bf->len) - memcpy(buff, bf->data, bf->len); + memcpy16_to_io(buff, bf->data, bf->len); - init_completion(&dpld->udl_cmd_complete); +#ifdef CONFIG_CDMA_MODEM_CBP72 + init_completion(&dpld->udl_cmpl); +#endif - if (bf->req) + if (bf->req) { dpld->send_intr(dpld, (u16)bf->req); + mif_debug("send intr 0x%04X\n", (u16)bf->req); + } if (bf->resp) { - err = _cbp72_edpram_wait_resp(dpld, bf->resp); + err = cbp_udl_wait_resp(dpld, bf->resp); if (err < 0) { - mif_info("%s: ERR! wait_response fail (%d)\n", - ld->name, err); + mif_err("ERR! cbp_udl_wait_resp fail (err %d)\n", err); goto exit; } else if (err == bf->resp) { err = skb->len; @@ -133,24 +112,14 @@ exit: return err; } -static int cbp72_download_binary(struct dpram_link_device *dpld, - struct sk_buff *skb) -{ - if (dpld->dp_type == EXT_DPRAM) - return _cbp72_edpram_download_bin(dpld, skb); - else - return -ENODEV; -} - -static int cbp72_dump_start(struct dpram_link_device *dpld) +static int cbp_dump_start(struct dpram_link_device *dpld) { - struct link_device *ld = &dpld->ld; u8 *dest = dpld->ul_map.buff; int ret; - ld->mode = LINK_MODE_ULOAD; + dpld->ld.mode = LINK_MODE_ULOAD; - ret = del_timer(&dpld->dump_timer); + ret = del_timer(&dpld->crash_timer); wake_lock(&dpld->wlock); iowrite32(DP_MAGIC_UMDL, dpld->ul_map.magic); @@ -161,53 +130,65 @@ static int cbp72_dump_start(struct dpram_link_device *dpld) iowrite8((u8)0x0, dest + 3); iowrite8((u8)END_FLAG, dest + 4); - init_completion(&dpld->dump_start_complete); + init_completion(&dpld->crash_cmpl); return 0; } -static int _cbp72_edpram_upload(struct dpram_link_device *dpld, - struct dpram_dump_arg *dump, unsigned char __user *target) +static int cbp_dump_update(struct dpram_link_device *dpld, unsigned long arg) { - struct link_device *ld = &dpld->ld; - struct ul_header header; + struct dpram_dump_arg dump; + struct dpram_udl_header header; + unsigned char __user *target = (unsigned char __user *)arg; + int err = 0; + int resp = 0; u8 *dest = NULL; u8 *buff = NULL; - u16 plen = 0; - int err = 0; - int ret = 0; + u8 *header_buff = NULL; int buff_size = 0; + u16 plen = 0; - mif_debug("\n"); - - init_completion(&dpld->udl_cmd_complete); - - mif_debug("%s: req %x, resp %x", ld->name, dump->req, dump->resp); + err = copy_from_user(&dump, (void __user *)arg, sizeof(dump)); + if (err < 0) { + mif_err("ERR! ARG copy_from_user fail (err %d)\n", err); + goto exit; + } + mif_debug("req %x, resp %x", dump.req, dump.resp); - if (dump->req) - dpld->send_intr(dpld, (u16)dump->req); + if (dump.req) + dpld->send_intr(dpld, (u16)dump.req); - if (dump->resp) { - err = _cbp72_edpram_wait_resp(dpld, dump->resp); + if (dump.resp) { + resp = err = cbp_udl_wait_resp(dpld, dump.resp); if (err < 0) { - mif_info("%s: ERR! wait_response fail (%d)\n", - ld->name, err); + mif_info("ERR! wait_response fail (err %d)\n", err); goto exit; } } - if (dump->cmd) - return err; + if (dump.cmd) + goto exit; dest = (u8 *)dpld->ul_map.buff; - header.bop = *(u8 *)(dest); - header.total_frame = *(u16 *)(dest + 1); - header.curr_frame = *(u16 *)(dest + 3); - header.len = *(u16 *)(dest + 5); + header_buff = vmalloc(sizeof(struct dpram_udl_header)); + if (!header_buff) { + err = -ENOMEM; + goto exit; + } + + memcpy16_from_io(header_buff, dest, sizeof(struct dpram_udl_header)); + + header.bop = *(u8 *)(header_buff); + header.num_frames = *(u16 *)(header_buff + 1); + header.curr_frame = *(u16 *)(header_buff + 3); + header.len = *(u16 *)(header_buff + 5); +#ifdef CONFIG_CDMA_MODEM_CBP82 + header.pad = *(u8 *)(header_buff + 7); +#endif - mif_debug("%s: total frame:%d, current frame:%d, data len:%d\n", - ld->name, header.total_frame, header.curr_frame, header.len); + mif_debug("total frames:%d, current frame:%d, data len:%d\n", + header.num_frames, header.curr_frame, header.len); plen = min_t(u16, header.len, DP_DEFAULT_DUMP_LEN); @@ -217,22 +198,26 @@ static int _cbp72_edpram_upload(struct dpram_link_device *dpld, goto exit; } - memcpy(buff, dest + sizeof(struct ul_header), plen); - ret = copy_to_user(dump->buff, buff, plen); - if (ret < 0) { - mif_info("%s: ERR! dump copy_to_user fail\n", ld->name); + memcpy16_from_io(buff, dest + sizeof(struct dpram_udl_header), plen); + err = copy_to_user(dump.buff, buff, plen); + if (err) { + mif_info("ERR! DUMP copy_to_user fail\n"); err = -EIO; goto exit; } - buff_size = plen; - ret = copy_to_user(target + 4, &buff_size, sizeof(int)); - if (ret < 0) { - mif_info("%s: ERR! size copy_to_user fail\n", ld->name); + buff_size = plen; + err = copy_to_user(target + 4, &buff_size, sizeof(int)); + if (err) { + mif_info("ERR! SIZE copy_to_user fail\n"); err = -EIO; goto exit; } + /* Return response value */ + if (err == 0) + err = resp; + vfree(buff); return err; @@ -243,82 +228,169 @@ exit: wake_unlock(&dpld->wlock); return err; } +#endif -static int cbp72_dump_update(struct dpram_link_device *dpld, void *arg) -{ - struct link_device *ld = &dpld->ld; - struct dpram_dump_arg dump; - int ret; +#if defined(CONFIG_LTE_MODEM_CMC221) +/* +** For CMC221 SFR for IDPRAM +*/ +#define CMC_INT2CP_REG 0x10 /* Interrupt to CP */ +#define CMC_INT2AP_REG 0x50 +#define CMC_CLR_INT_REG 0x28 /* Clear Interrupt to AP */ +#define CMC_RESET_REG 0x3C +#define CMC_PUT_REG 0x40 /* AP->CP reg for hostbooting */ +#define CMC_GET_REG 0x50 /* CP->AP reg for hostbooting */ - ret = copy_from_user(&dump, (void __user *)arg, sizeof(dump)); - if (ret < 0) { - mif_info("%s: ERR! copy_from_user fail\n", ld->name); - return ret; - } +/* +** For host (flashless) booting via DPRAM +*/ +#define CMC22x_AP_BOOT_DOWN_DONE 0x54329876 +#define CMC22x_CP_REQ_MAIN_BIN 0xA5A5A5A5 +#define CMC22x_CP_REQ_NV_DATA 0x5A5A5A5A +#define CMC22x_CP_DUMP_MAGIC 0xDEADDEAD - return _cbp72_edpram_upload(dpld, &dump, (unsigned char __user *)arg); -} +#define CMC22x_HOST_DOWN_START 0x1234 +#define CMC22x_HOST_DOWN_END 0x4321 +#define CMC22x_REG_NV_DOWN_END 0xABCD +#define CMC22x_CAL_NV_DOWN_END 0xDCBA -static int cbp72_set_dl_magic(struct link_device *ld, struct io_device *iod) -{ - struct dpram_link_device *dpld = to_dpram_link_device(ld); +#define CMC22x_1ST_BUFF_READY 0xAAAA +#define CMC22x_2ND_BUFF_READY 0xBBBB +#define CMC22x_1ST_BUFF_FULL 0x1111 +#define CMC22x_2ND_BUFF_FULL 0x2222 + +#define CMC22x_CP_RECV_NV_END 0x8888 +#define CMC22x_CP_CAL_OK 0x4F4B +#define CMC22x_CP_CAL_BAD 0x4552 +#define CMC22x_CP_DUMP_END 0xFADE - ld->mode = LINK_MODE_DLOAD; +#define CMC22x_DUMP_BUFF_SIZE 8192 - iowrite32(DP_MAGIC_DMDL, dpld->dl_map.magic); +/* CMC221 IDPRAM SFR */ +struct cmc221_idpram_sfr { + u16 __iomem *int2cp; + u16 __iomem *int2ap; + u16 __iomem *clr_int2ap; + u16 __iomem *reset; + u16 __iomem *msg2cp; + u16 __iomem *msg2ap; +}; - return 0; -} +struct cmc221_boot_img { + char *addr; + int size; + enum cp_boot_mode mode; + unsigned req; + unsigned resp; +}; -static int cbp72_ioctl(struct dpram_link_device *dpld, struct io_device *iod, - unsigned int cmd, unsigned long arg) +static struct cmc221_idpram_sfr cmc_sfr; + +static void cmc221_init_boot_map(struct dpram_link_device *dpld) { - struct link_device *ld = &dpld->ld; - int err = 0; + struct memif_boot_map *bt_map = &dpld->bt_map; - switch (cmd) { - case IOCTL_MODEM_DL_START: - err = cbp72_set_dl_magic(ld, iod); - if (err < 0) - mif_err("%s: ERR! set_dl_magic fail\n", ld->name); - break; + bt_map->buff = dpld->base; + bt_map->space = dpld->size; + bt_map->req = (u32 *)(dpld->base + DP_BOOT_REQ_OFFSET); + bt_map->resp = (u32 *)(dpld->base + DP_BOOT_RESP_OFFSET); +} - default: - mif_err("%s: ERR! invalid cmd 0x%08X\n", ld->name, cmd); - err = -EINVAL; - break; - } +static void cmc221_init_dl_map(struct dpram_link_device *dpld) +{ + dpld->dl_map.magic = (u32 *)dpld->base; + dpld->dl_map.buff = (u8 *)dpld->base; +} - return err; +static void cmc221_init_ul_map(struct dpram_link_device *dpld) +{ + dpld->ul_map.magic = (u32 *)dpld->base; + dpld->ul_map.buff = (u8 *)dpld->base; } -#endif -#if defined(CONFIG_LTE_MODEM_CMC221) -static void cmc221_init_boot_map(struct dpram_link_device *dpld) +static void cmc221_init_ipc_map(struct dpram_link_device *dpld) { - struct dpram_boot_map *bt_map = &dpld->bt_map; + struct dpram_ipc_16k_map *dpram_map; + struct dpram_ipc_device *dev; + u8 __iomem *sfr_base = dpld->sfr_base; + + dpram_map = (struct dpram_ipc_16k_map *)dpld->base; + + /* Magic code and access enable fields */ + dpld->ipc_map.magic = (u16 __iomem *)&dpram_map->magic; + dpld->ipc_map.access = (u16 __iomem *)&dpram_map->access; + + /* FMT */ + dev = &dpld->ipc_map.dev[IPC_FMT]; + + strcpy(dev->name, "FMT"); + dev->id = IPC_FMT; + + dev->txq.head = (u16 __iomem *)&dpram_map->fmt_tx_head; + dev->txq.tail = (u16 __iomem *)&dpram_map->fmt_tx_tail; + dev->txq.buff = (u8 __iomem *)&dpram_map->fmt_tx_buff[0]; + dev->txq.size = DP_16K_FMT_TX_BUFF_SZ; + + dev->rxq.head = (u16 __iomem *)&dpram_map->fmt_rx_head; + dev->rxq.tail = (u16 __iomem *)&dpram_map->fmt_rx_tail; + dev->rxq.buff = (u8 __iomem *)&dpram_map->fmt_rx_buff[0]; + dev->rxq.size = DP_16K_FMT_RX_BUFF_SZ; + + dev->mask_req_ack = INT_MASK_REQ_ACK_F; + dev->mask_res_ack = INT_MASK_RES_ACK_F; + dev->mask_send = INT_MASK_SEND_F; + + /* RAW */ + dev = &dpld->ipc_map.dev[IPC_RAW]; + + strcpy(dev->name, "RAW"); + dev->id = IPC_RAW; + + dev->txq.head = (u16 __iomem *)&dpram_map->raw_tx_head; + dev->txq.tail = (u16 __iomem *)&dpram_map->raw_tx_tail; + dev->txq.buff = (u8 __iomem *)&dpram_map->raw_tx_buff[0]; + dev->txq.size = DP_16K_RAW_TX_BUFF_SZ; + + dev->rxq.head = (u16 __iomem *)&dpram_map->raw_rx_head; + dev->rxq.tail = (u16 __iomem *)&dpram_map->raw_rx_tail; + dev->rxq.buff = (u8 __iomem *)&dpram_map->raw_rx_buff[0]; + dev->rxq.size = DP_16K_RAW_RX_BUFF_SZ; + + dev->mask_req_ack = INT_MASK_REQ_ACK_R; + dev->mask_res_ack = INT_MASK_RES_ACK_R; + dev->mask_send = INT_MASK_SEND_R; + + /* SFR */ + cmc_sfr.int2cp = (u16 __iomem *)(sfr_base + CMC_INT2CP_REG); + cmc_sfr.int2ap = (u16 __iomem *)(sfr_base + CMC_INT2AP_REG); + cmc_sfr.clr_int2ap = (u16 __iomem *)(sfr_base + CMC_CLR_INT_REG); + cmc_sfr.reset = (u16 __iomem *)(sfr_base + CMC_RESET_REG); + cmc_sfr.msg2cp = (u16 __iomem *)(sfr_base + CMC_PUT_REG); + cmc_sfr.msg2ap = (u16 __iomem *)(sfr_base + CMC_GET_REG); + + /* Interrupt ports */ + dpld->ipc_map.mbx_cp2ap = cmc_sfr.int2ap; + dpld->ipc_map.mbx_ap2cp = cmc_sfr.int2cp; +} - bt_map->buff = dpld->dp_base; - bt_map->size = dpld->dp_size; - bt_map->req = (u32 *)(dpld->dp_base + DP_BOOT_REQ_OFFSET); - bt_map->resp = (u32 *)(dpld->dp_base + DP_BOOT_RESP_OFFSET); +static inline void cmc221_idpram_reset(struct dpram_link_device *dpld) +{ + iowrite16(1, cmc_sfr.reset); } -static void cmc221_init_dl_map(struct dpram_link_device *dpld) +static inline u16 cmc221_idpram_recv_msg(struct dpram_link_device *dpld) { - dpld->dl_map.magic = (u32 *)dpld->dp_base; - dpld->dl_map.buff = (u8 *)dpld->dp_base; + return ioread16(cmc_sfr.msg2ap); } -static void cmc221_init_ul_map(struct dpram_link_device *dpld) +static inline void cmc221_idpram_send_msg(struct dpram_link_device *dpld, + u16 msg) { - dpld->ul_map.magic = (u32 *)dpld->dp_base; - dpld->ul_map.buff = (u8 *)dpld->dp_base; + iowrite16(msg, cmc_sfr.msg2cp); } -static int _cmc221_idpram_wait_resp(struct dpram_link_device *dpld, u32 resp) +static int cmc221_idpram_wait_resp(struct dpram_link_device *dpld, u32 resp) { - struct link_device *ld = &dpld->ld; int count = 50000; u32 rcvd = 0; @@ -328,16 +400,14 @@ static int _cmc221_idpram_wait_resp(struct dpram_link_device *dpld, u32 resp) if (rcvd == resp) break; - rcvd = dpld->dpctl->recv_msg(); + rcvd = cmc221_idpram_recv_msg(dpld); if (rcvd == 0x9999) { - mif_info("%s: Invalid resp 0x%04X\n", - ld->name, rcvd); + mif_info("invalid resp 0x%04X\n", rcvd); panic("CP Crash ... BAD CRC in CP"); } if (count-- < 0) { - mif_info("%s: Invalid resp 0x%08X\n", - ld->name, rcvd); + mif_info("invalid resp 0x%08X\n", rcvd); return -EAGAIN; } @@ -345,20 +415,19 @@ static int _cmc221_idpram_wait_resp(struct dpram_link_device *dpld, u32 resp) } } else { while (1) { - rcvd = dpld->dpctl->recv_msg(); + rcvd = cmc221_idpram_recv_msg(dpld); if (rcvd == resp) break; if (resp == CMC22x_CP_RECV_NV_END && rcvd == CMC22x_CP_CAL_BAD) { - mif_info("%s: CMC22x_CP_CAL_BAD\n", ld->name); + mif_info("invalid resp CMC22x_CP_CAL_BAD\n"); break; } if (count-- < 0) { - mif_info("%s: Invalid resp 0x%04X\n", - ld->name, rcvd); + mif_info("invalid resp 0x%04X\n", rcvd); return -EAGAIN; } @@ -369,110 +438,104 @@ static int _cmc221_idpram_wait_resp(struct dpram_link_device *dpld, u32 resp) return rcvd; } -static int _cmc221_idpram_send_boot(struct dpram_link_device *dpld, void *arg) +static int cmc221_xmit_boot(struct dpram_link_device *dpld, unsigned long arg) { struct link_device *ld = &dpld->ld; u8 __iomem *bt_buff = dpld->bt_map.buff; - struct dpram_boot_img cp_img; + struct cmc221_boot_img cp_img; u8 *img_buff = NULL; int err = 0; int cnt = 0; + mif_info("+++\n"); ld->mode = LINK_MODE_BOOT; - dpld->dpctl->setup_speed(DPRAM_SPEED_LOW); + dpld->dpram->setup_speed(DPRAM_SPEED_LOW); /* Test memory... After testing, memory is cleared. */ - if (mif_test_dpram(ld->name, bt_buff, dpld->bt_map.size) < 0) { - mif_info("%s: ERR! mif_test_dpram fail!\n", ld->name); + if (mif_test_dpram(ld->name, bt_buff, dpld->bt_map.space) < 0) { + mif_info("ERR! mif_test_dpram fail!\n"); ld->mode = LINK_MODE_OFFLINE; return -EIO; } - memset(&cp_img, 0, sizeof(struct dpram_boot_img)); + memset(&cp_img, 0, sizeof(struct cmc221_boot_img)); /* Get information about the boot image */ - err = copy_from_user(&cp_img, arg, sizeof(cp_img)); - mif_info("%s: CP image addr = 0x%08X, size = %d\n", - ld->name, (int)cp_img.addr, cp_img.size); + err = copy_from_user(&cp_img, (void __user *)arg, sizeof(cp_img)); + mif_info("CP image addr = 0x%08X, size = %d\n", + (int)cp_img.addr, cp_img.size); /* Alloc a buffer for the boot image */ - img_buff = kzalloc(dpld->bt_map.size, GFP_KERNEL); + img_buff = kzalloc(dpld->bt_map.space, GFP_KERNEL); if (!img_buff) { - mif_info("%s: ERR! kzalloc fail\n", ld->name); + mif_info("ERR! kzalloc fail\n"); ld->mode = LINK_MODE_OFFLINE; return -ENOMEM; } /* Copy boot image from the user space to the image buffer */ - err = copy_from_user(img_buff, cp_img.addr, cp_img.size); + err = copy_from_user(img_buff, (void __user *)cp_img.addr, cp_img.size); /* Copy boot image to DPRAM and verify it */ memcpy(bt_buff, img_buff, cp_img.size); if (memcmp16_to_io(bt_buff, img_buff, cp_img.size)) { - mif_info("%s: ERR! Boot may be broken!!!\n", ld->name); + mif_info("ERR! Boot may be broken!!!\n"); goto err; } - dpld->dpctl->reset(); + cmc221_idpram_reset(dpld); usleep_range(1000, 2000); - if (cp_img.mode == HOST_BOOT_MODE_NORMAL) { - mif_info("%s: HOST_BOOT_MODE_NORMAL\n", ld->name); - mif_info("%s: Send req 0x%08X\n", ld->name, cp_img.req); + if (cp_img.mode == CP_BOOT_MODE_NORMAL) { + mif_info("CP_BOOT_MODE_NORMAL\n"); + mif_info("send req 0x%08X\n", cp_img.req); iowrite32(cp_img.req, dpld->bt_map.req); /* Wait for cp_img.resp for up to 2 seconds */ - mif_info("%s: Wait resp 0x%08X\n", ld->name, cp_img.resp); + mif_info("wait resp 0x%08X\n", cp_img.resp); while (ioread32(dpld->bt_map.resp) != cp_img.resp) { cnt++; usleep_range(1000, 2000); if (cnt > 1000) { - mif_info("%s: ERR! Invalid resp 0x%08X\n", - ld->name, ioread32(dpld->bt_map.resp)); + mif_info("ERR! invalid resp 0x%08X\n", + ioread32(dpld->bt_map.resp)); goto err; } } } else { - mif_info("%s: HOST_BOOT_MODE_DUMP\n", ld->name); + mif_info("CP_BOOT_MODE_DUMP\n"); } kfree(img_buff); - mif_info("%s: Send BOOT done\n", ld->name); + mif_info("send BOOT done\n"); - dpld->dpctl->setup_speed(DPRAM_SPEED_HIGH); + dpld->dpram->setup_speed(DPRAM_SPEED_HIGH); + mif_info("---\n"); return 0; err: ld->mode = LINK_MODE_OFFLINE; kfree(img_buff); - mif_info("%s: ERR! Boot send fail!!!\n", ld->name); + mif_err("FAIL!!!\n"); + mif_info("---\n"); return -EIO; } -static int cmc221_download_boot(struct dpram_link_device *dpld, void *arg) -{ - if (dpld->dp_type == CP_IDPRAM) - return _cmc221_idpram_send_boot(dpld, arg); - else - return -ENODEV; -} - -static int _cmc221_idpram_download_bin(struct dpram_link_device *dpld, +static int cmc221_idpram_download_bin(struct dpram_link_device *dpld, struct sk_buff *skb) { int err = 0; int ret = 0; - struct link_device *ld = &dpld->ld; struct dpram_boot_frame *bf = (struct dpram_boot_frame *)skb->data; u8 __iomem *buff = (dpld->bt_map.buff + bf->offset); - if ((bf->offset + bf->len) > dpld->bt_map.size) { - mif_info("%s: ERR! Out of DPRAM boundary\n", ld->name); + if ((bf->offset + bf->len) > dpld->bt_map.space) { + mif_info("ERR! out of DPRAM boundary\n"); err = -EINVAL; goto exit; } @@ -481,17 +544,16 @@ static int _cmc221_idpram_download_bin(struct dpram_link_device *dpld, memcpy(buff, bf->data, bf->len); if (bf->req) - dpld->dpctl->send_msg((u16)bf->req); + cmc221_idpram_send_msg(dpld, (u16)bf->req); if (bf->resp) { - err = _cmc221_idpram_wait_resp(dpld, bf->resp); + err = cmc221_idpram_wait_resp(dpld, bf->resp); if (err < 0) - mif_info("%s: ERR! wait_response fail (err %d)\n", - ld->name, err); + mif_info("ERR! wait_resp fail (err %d)\n", err); } if (bf->req == CMC22x_CAL_NV_DOWN_END) - mif_info("%s: CMC22x_CAL_NV_DOWN_END\n", ld->name); + mif_info("request CMC22x_CAL_NV_DOWN_END\n"); exit: if (err < 0) @@ -504,89 +566,84 @@ exit: return ret; } -static int cmc221_download_binary(struct dpram_link_device *dpld, +static int cmc221_xmit_binary(struct dpram_link_device *dpld, struct sk_buff *skb) { - if (dpld->dp_type == CP_IDPRAM) - return _cmc221_idpram_download_bin(dpld, skb); + if (dpld->type == CP_IDPRAM) + return cmc221_idpram_download_bin(dpld, skb); else return -ENODEV; } static int cmc221_dump_start(struct dpram_link_device *dpld) { - struct link_device *ld = &dpld->ld; - int ret; - - ld->mode = LINK_MODE_ULOAD; + dpld->ld.mode = LINK_MODE_ULOAD; - ret = del_timer(&dpld->dump_timer); + del_timer(&dpld->crash_timer); wake_lock(&dpld->wlock); - dpld->dump_rcvd = 0; + dpld->crash_rcvd = 0; iowrite32(CMC22x_CP_DUMP_MAGIC, dpld->ul_map.magic); - init_completion(&dpld->dump_start_complete); + init_completion(&dpld->crash_cmpl); return 0; } -static void _cmc221_idpram_wait_dump(unsigned long arg) +static void cmc221_idpram_wait_dump(unsigned long arg) { struct dpram_link_device *dpld = (struct dpram_link_device *)arg; u16 msg; - msg = dpld->dpctl->recv_msg(); + msg = cmc221_idpram_recv_msg(dpld); if (msg == CMC22x_CP_DUMP_END) { - complete_all(&dpld->dump_recv_done); + complete_all(&dpld->crash_cmpl); return; } - if (((dpld->dump_rcvd & 0x1) == 0) && (msg == CMC22x_1ST_BUFF_FULL)) { - complete_all(&dpld->dump_recv_done); + if (((dpld->crash_rcvd & 0x1) == 0) && (msg == CMC22x_1ST_BUFF_FULL)) { + complete_all(&dpld->crash_cmpl); return; } - if (((dpld->dump_rcvd & 0x1) == 1) && (msg == CMC22x_2ND_BUFF_FULL)) { - complete_all(&dpld->dump_recv_done); + if (((dpld->crash_rcvd & 0x1) == 1) && (msg == CMC22x_2ND_BUFF_FULL)) { + complete_all(&dpld->crash_cmpl); return; } - mif_add_timer(&dpld->dump_timer, DUMP_WAIT_TIMEOUT, - _cmc221_idpram_wait_dump, (unsigned long)dpld); + mif_add_timer(&dpld->crash_timer, DUMP_WAIT_TIMEOUT, + cmc221_idpram_wait_dump, (unsigned long)dpld); } -static int _cmc221_idpram_upload(struct dpram_link_device *dpld, - struct dpram_dump_arg *dumparg) +static int cmc221_idpram_upload(struct dpram_link_device *dpld, + struct dpram_dump_arg *dumparg) { - struct link_device *ld = &dpld->ld; int ret; u8 __iomem *src; int buff_size = CMC22x_DUMP_BUFF_SIZE; - if ((dpld->dump_rcvd & 0x1) == 0) - dpld->dpctl->send_msg(CMC22x_1ST_BUFF_READY); + if ((dpld->crash_rcvd & 0x1) == 0) + cmc221_idpram_send_msg(dpld, CMC22x_1ST_BUFF_READY); else - dpld->dpctl->send_msg(CMC22x_2ND_BUFF_READY); + cmc221_idpram_send_msg(dpld, CMC22x_2ND_BUFF_READY); - init_completion(&dpld->dump_recv_done); + init_completion(&dpld->crash_cmpl); - mif_add_timer(&dpld->dump_timer, DUMP_WAIT_TIMEOUT, - _cmc221_idpram_wait_dump, (unsigned long)dpld); + mif_add_timer(&dpld->crash_timer, DUMP_WAIT_TIMEOUT, + cmc221_idpram_wait_dump, (unsigned long)dpld); - ret = wait_for_completion_interruptible_timeout( - &dpld->dump_recv_done, DUMP_TIMEOUT); + ret = wait_for_completion_timeout(&dpld->crash_cmpl, DUMP_TIMEOUT); if (!ret) { - mif_info("%s: ERR! CP didn't send dump data!!!\n", ld->name); + mif_info("ERR! no dump from CP!!!\n"); goto err_out; } - if (dpld->dpctl->recv_msg() == CMC22x_CP_DUMP_END) { - mif_info("%s: CMC22x_CP_DUMP_END\n", ld->name); + if (cmc221_idpram_recv_msg(dpld) == CMC22x_CP_DUMP_END) { + mif_info("recv CMC22x_CP_DUMP_END\n"); return 0; } - if ((dpld->dump_rcvd & 0x1) == 0) + if ((dpld->crash_rcvd & 0x1) == 0) src = dpld->ul_map.buff; else src = dpld->ul_map.buff + CMC22x_DUMP_BUFF_SIZE; @@ -595,52 +652,64 @@ static int _cmc221_idpram_upload(struct dpram_link_device *dpld, ret = copy_to_user(dumparg->buff, dpld->buff, buff_size); if (ret < 0) { - mif_info("%s: ERR! copy_to_user fail\n", ld->name); + mif_info("ERR! copy_to_user fail\n"); goto err_out; } - dpld->dump_rcvd++; + dpld->crash_rcvd++; return buff_size; err_out: return -EIO; } -static int cmc221_dump_update(struct dpram_link_device *dpld, void *arg) +static int cmc221_dump_update(struct dpram_link_device *dpld, unsigned long arg) { - struct link_device *ld = &dpld->ld; struct dpram_dump_arg dump; int ret; ret = copy_from_user(&dump, (void __user *)arg, sizeof(dump)); if (ret < 0) { - mif_info("%s: ERR! copy_from_user fail\n", ld->name); + mif_info("ERR! copy_from_user fail\n"); return ret; } - return _cmc221_idpram_upload(dpld, &dump); + return cmc221_idpram_upload(dpld, &dump); } -static int cmc221_ioctl(struct dpram_link_device *dpld, struct io_device *iod, - unsigned int cmd, unsigned long arg) +static void cmc221_idpram_clr_int2ap(struct dpram_link_device *dpld) { - struct link_device *ld = &dpld->ld; - int err = 0; + iowrite16(0xFFFF, cmc_sfr.clr_int2ap); +} - switch (cmd) { - case IOCTL_DPRAM_SEND_BOOT: - err = cmc221_download_boot(dpld, (void *)arg); - if (err < 0) - mif_info("%s: ERR! download_boot fail\n", ld->name); - break; +static int cmc221_idpram_wakeup(struct dpram_link_device *dpld) +{ + int cnt = 0; - default: - mif_err("%s: ERR! invalid cmd 0x%08X\n", ld->name, cmd); - err = -EINVAL; - break; + gpio_set_value(dpld->gpio_cp_wakeup, 1); + + while (!gpio_get_value(dpld->gpio_cp_status)) { + if (cnt++ > 10) { + if (in_irq()) + mif_err("ERR! gpio_cp_status == 0 in IRQ\n"); + else + mif_err("ERR! gpio_cp_status == 0\n"); + return -EACCES; + } + + mif_info("gpio_cp_status == 0 (cnt %d)\n", cnt); + if (in_interrupt()) + udelay(1000); + else + usleep_range(1000, 2000); } - return err; + return 0; +} + +static void cmc221_idpram_sleep(struct dpram_link_device *dpld) +{ + gpio_set_value(dpld->gpio_cp_wakeup, 0); } #endif @@ -652,17 +721,44 @@ enum qc_dload_tag { QC_DLOAD_TAG_MAX }; +struct qc_dpram_boot_map { + u8 __iomem *buff; + u16 __iomem *frame_size; + u16 __iomem *tag; + u16 __iomem *count; +}; + +struct qc_dpram_udl_param { + unsigned char *addr; + unsigned int size; + unsigned int count; + unsigned int tag; +}; + +struct qc_dpram_udl_check { + unsigned int total_size; + unsigned int rest_size; + unsigned int send_size; + unsigned int copy_start; + unsigned int copy_complete; + unsigned int boot_complete; +}; + +static struct qc_dpram_boot_map qc_bt_map; +static struct qc_dpram_udl_param qc_udl_param; +static struct qc_dpram_udl_check qc_udl_check; + static void qc_dload_task(unsigned long data); static void qc_init_boot_map(struct dpram_link_device *dpld) { - struct qc_dpram_boot_map *bt_map = &dpld->qc_bt_map; - struct modemlink_dpram_control *dpctl = dpld->dpctl; + struct qc_dpram_boot_map *qbt_map = &qc_bt_map; + struct modemlink_dpram_data *dpram = dpld->dpram; - bt_map->buff = dpld->dp_base; - bt_map->frame_size = (u16 *)(dpld->dp_base + dpctl->boot_size_offset); - bt_map->tag = (u16 *)(dpld->dp_base + dpctl->boot_tag_offset); - bt_map->count = (u16 *)(dpld->dp_base + dpctl->boot_count_offset); + qbt_map->buff = dpld->base; + qbt_map->frame_size = (u16 *)(dpld->base + dpram->boot_size_offset); + qbt_map->tag = (u16 *)(dpld->base + dpram->boot_tag_offset); + qbt_map->count = (u16 *)(dpld->base + dpram->boot_count_offset); tasklet_init(&dpld->dl_tsk, qc_dload_task, (unsigned long)dpld); } @@ -673,15 +769,15 @@ static int qc_prepare_download(struct dpram_link_device *dpld) int count = 0; while (1) { - if (dpld->udl_check.copy_start) { - dpld->udl_check.copy_start = 0; + if (qc_udl_check.copy_start) { + qc_udl_check.copy_start = 0; break; } - msleep_interruptible(10); + usleep_range(10000, 11000); count++; - if (count > 200) { + if (count > 300) { mif_err("ERR! count %d\n", count); return -1; } @@ -690,32 +786,33 @@ static int qc_prepare_download(struct dpram_link_device *dpld) return retval; } -static void _qc_do_download(struct dpram_link_device *dpld, - struct dpram_udl_param *param) +static void qc_do_download(struct dpram_link_device *dpld, + struct qc_dpram_udl_param *param) { - struct qc_dpram_boot_map *bt_map = &dpld->qc_bt_map; + struct qc_dpram_boot_map *qbt_map = &qc_bt_map; - if (param->size <= dpld->dpctl->max_boot_frame_size) { - memcpy(bt_map->buff, param->addr, param->size); - iowrite16(param->size, bt_map->frame_size); - iowrite16(param->tag, bt_map->tag); - iowrite16(param->count, bt_map->count); + if (param->size <= dpld->dpram->max_boot_frame_size) { + memcpy(qbt_map->buff, param->addr, param->size); + iowrite16(param->size, qbt_map->frame_size); + iowrite16(param->tag, qbt_map->tag); + iowrite16(param->count, qbt_map->count); dpld->send_intr(dpld, 0xDB12); } else { mif_info("param->size %d\n", param->size); } } -static int _qc_download(struct dpram_link_device *dpld, void *arg, +static int qc_download(struct dpram_link_device *dpld, void *arg, enum qc_dload_tag tag) { int retval = 0; int count = 0; int cnt_limit; unsigned char *img; - struct dpram_udl_param param; + struct qc_dpram_udl_param param; - retval = copy_from_user((void *)¶m, (void *)arg, sizeof(param)); + retval = copy_from_user((void *)¶m, (void __user *)arg, + sizeof(param)); if (retval < 0) { mif_err("ERR! copy_from_user fail\n"); return -1; @@ -729,24 +826,24 @@ static int _qc_download(struct dpram_link_device *dpld, void *arg, memset(img, 0, param.size); memcpy(img, param.addr, param.size); - dpld->udl_check.total_size = param.size; - dpld->udl_check.rest_size = param.size; - dpld->udl_check.send_size = 0; - dpld->udl_check.copy_complete = 0; + qc_udl_check.total_size = param.size; + qc_udl_check.rest_size = param.size; + qc_udl_check.send_size = 0; + qc_udl_check.copy_complete = 0; - dpld->udl_param.addr = img; - dpld->udl_param.size = dpld->dpctl->max_boot_frame_size; + qc_udl_param.addr = img; + qc_udl_param.size = dpld->dpram->max_boot_frame_size; if (tag == QC_DLOAD_TAG_NV) - dpld->udl_param.count = 1; + qc_udl_param.count = 1; else - dpld->udl_param.count = param.count; - dpld->udl_param.tag = tag; + qc_udl_param.count = param.count; + qc_udl_param.tag = tag; - if (dpld->udl_check.rest_size < dpld->dpctl->max_boot_frame_size) - dpld->udl_param.size = dpld->udl_check.rest_size; + if (qc_udl_check.rest_size < dpld->dpram->max_boot_frame_size) + qc_udl_param.size = qc_udl_check.rest_size; /* Download image (binary or NV) */ - _qc_do_download(dpld, &dpld->udl_param); + qc_do_download(dpld, &qc_udl_param); /* Wait for completion */ @@ -756,18 +853,18 @@ static int _qc_download(struct dpram_link_device *dpld, void *arg, cnt_limit = 1000; while (1) { - if (dpld->udl_check.copy_complete) { - dpld->udl_check.copy_complete = 0; + if (qc_udl_check.copy_complete) { + qc_udl_check.copy_complete = 0; retval = 0; break; } - msleep(10); + usleep_range(10000, 11000); count++; if (count > cnt_limit) { - dpld->udl_check.total_size = 0; - dpld->udl_check.rest_size = 0; + qc_udl_check.total_size = 0; + qc_udl_check.rest_size = 0; mif_err("ERR! count %d\n", count); retval = -1; break; @@ -781,51 +878,51 @@ static int _qc_download(struct dpram_link_device *dpld, void *arg, static int qc_download_binary(struct dpram_link_device *dpld, void *arg) { - return _qc_download(dpld, arg, QC_DLOAD_TAG_BIN); + return qc_download(dpld, arg, QC_DLOAD_TAG_BIN); } static int qc_download_nv(struct dpram_link_device *dpld, void *arg) { - return _qc_download(dpld, arg, QC_DLOAD_TAG_NV); + return qc_download(dpld, arg, QC_DLOAD_TAG_NV); } static void qc_dload_task(unsigned long data) { struct dpram_link_device *dpld = (struct dpram_link_device *)data; - dpld->udl_check.send_size += dpld->udl_param.size; - dpld->udl_check.rest_size -= dpld->udl_param.size; + qc_udl_check.send_size += qc_udl_param.size; + qc_udl_check.rest_size -= qc_udl_param.size; - dpld->udl_param.addr += dpld->udl_param.size; + qc_udl_param.addr += qc_udl_param.size; - if (dpld->udl_check.send_size >= dpld->udl_check.total_size) { - dpld->udl_check.copy_complete = 1; - dpld->udl_param.tag = 0; + if (qc_udl_check.send_size >= qc_udl_check.total_size) { + qc_udl_check.copy_complete = 1; + qc_udl_param.tag = 0; return; } - if (dpld->udl_check.rest_size < dpld->dpctl->max_boot_frame_size) - dpld->udl_param.size = dpld->udl_check.rest_size; + if (qc_udl_check.rest_size < dpld->dpram->max_boot_frame_size) + qc_udl_param.size = qc_udl_check.rest_size; - dpld->udl_param.count += 1; + qc_udl_param.count += 1; - _qc_do_download(dpld, &dpld->udl_param); + qc_do_download(dpld, &qc_udl_param); } static void qc_dload_cmd_handler(struct dpram_link_device *dpld, u16 cmd) { switch (cmd) { case 0x1234: - dpld->udl_check.copy_start = 1; + qc_udl_check.copy_start = 1; break; case 0xDBAB: - if (dpld->udl_check.total_size) + if (qc_udl_check.total_size) tasklet_schedule(&dpld->dl_tsk); break; case 0xABCD: - dpld->udl_check.boot_complete = 1; + qc_udl_check.boot_complete = 1; break; default: @@ -843,12 +940,12 @@ static int qc_boot_start(struct dpram_link_device *dpld) dpld->send_intr(dpld, mask); while (1) { - if (dpld->udl_check.boot_complete) { - dpld->udl_check.boot_complete = 0; + if (qc_udl_check.boot_complete) { + qc_udl_check.boot_complete = 0; break; } - msleep_interruptible(10); + usleep_range(10000, 11000); count++; if (count > 200) { @@ -870,7 +967,7 @@ static int qc_boot_post_process(struct dpram_link_device *dpld) break; } - msleep_interruptible(10); + usleep_range(10000, 11000); count++; if (count > 200) { @@ -900,27 +997,26 @@ static void qc_start_handler(struct dpram_link_device *dpld) static void qc_crash_log(struct dpram_link_device *dpld) { - struct link_device *ld = &dpld->ld; static unsigned char buf[151]; u8 __iomem *data = NULL; - data = dpld->get_rx_buff(dpld, IPC_FMT); + data = dpld->get_rxq_buff(dpld, IPC_FMT); memcpy(buf, data, (sizeof(buf) - 1)); - mif_info("PHONE ERR MSG\t| %s Crash\n", ld->mdm_data->name); + mif_info("PHONE ERR MSG\t| %s Crash\n", dpld->ld.mc->name); mif_info("PHONE ERR MSG\t| %s\n", buf); } -static int _qc_data_upload(struct dpram_link_device *dpld, - struct dpram_udl_param *param) +static int qc_data_upload(struct dpram_link_device *dpld, + struct qc_dpram_udl_param *param) { - struct qc_dpram_boot_map *bt_map = &dpld->qc_bt_map; + struct qc_dpram_boot_map *qbt_map = &qc_bt_map; int retval = 0; u16 intval = 0; int count = 0; while (1) { - if (!gpio_get_value(dpld->gpio_dpram_int)) { + if (!gpio_get_value(dpld->gpio_int2ap)) { intval = dpld->recv_intr(dpld); if (intval == 0xDBAB) { break; @@ -930,7 +1026,7 @@ static int _qc_data_upload(struct dpram_link_device *dpld, } } - msleep_interruptible(1); + usleep_range(1000, 2000); count++; if (count > 200) { @@ -939,10 +1035,10 @@ static int _qc_data_upload(struct dpram_link_device *dpld, } } - param->size = ioread16(bt_map->frame_size); - memcpy(param->addr, bt_map->buff, param->size); - param->tag = ioread16(bt_map->tag); - param->count = ioread16(bt_map->count); + param->size = ioread16(qbt_map->frame_size); + memcpy(param->addr, qbt_map->buff, param->size); + param->tag = ioread16(qbt_map->tag); + param->count = ioread16(qbt_map->count); dpld->send_intr(dpld, 0xDB12); @@ -961,7 +1057,7 @@ static int qc_uload_step1(struct dpram_link_device *dpld) mif_info("+---------------------------------------------+\n"); while (1) { - if (!gpio_get_value(dpld->gpio_dpram_int)) { + if (!gpio_get_value(dpld->gpio_int2ap)) { intval = dpld->recv_intr(dpld); mif_info("intr 0x%04x\n", intval); if (intval == 0x1234) { @@ -972,7 +1068,7 @@ static int qc_uload_step1(struct dpram_link_device *dpld) } } - msleep_interruptible(1); + usleep_range(1000, 2000); count++; if (count > 200) { @@ -993,17 +1089,18 @@ static int qc_uload_step1(struct dpram_link_device *dpld) static int qc_uload_step2(struct dpram_link_device *dpld, void *arg) { int retval = 0; - struct dpram_udl_param param; + struct qc_dpram_udl_param param; - retval = copy_from_user((void *)¶m, (void *)arg, sizeof(param)); + retval = copy_from_user((void *)¶m, (void __user *)arg, + sizeof(param)); if (retval < 0) { mif_err("ERR! copy_from_user fail (err %d)\n", retval); return -1; } - retval = _qc_data_upload(dpld, ¶m); + retval = qc_data_upload(dpld, ¶m); if (retval < 0) { - mif_err("ERR! _qc_data_upload fail (err %d)\n", retval); + mif_err("ERR! qc_data_upload fail (err %d)\n", retval); return -1; } @@ -1025,40 +1122,39 @@ static int qc_uload_step2(struct dpram_link_device *dpld, void *arg) } static int qc_ioctl(struct dpram_link_device *dpld, struct io_device *iod, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - struct link_device *ld = &dpld->ld; int err = 0; switch (cmd) { case IOCTL_DPRAM_PHONE_POWON: err = qc_prepare_download(dpld); if (err < 0) - mif_info("%s: ERR! prepare_download fail\n", ld->name); + mif_info("ERR! prepare_download fail\n"); break; case IOCTL_DPRAM_PHONEIMG_LOAD: err = qc_download_binary(dpld, (void *)arg); if (err < 0) - mif_info("%s: ERR! download_binary fail\n", ld->name); + mif_info("ERR! download_binary fail\n"); break; case IOCTL_DPRAM_NVDATA_LOAD: err = qc_download_nv(dpld, (void *)arg); if (err < 0) - mif_info("%s: ERR! download_nv fail\n", ld->name); + mif_info("ERR! download_nv fail\n"); break; case IOCTL_DPRAM_PHONE_BOOTSTART: err = qc_boot_start(dpld); if (err < 0) { - mif_info("%s: ERR! boot_start fail\n", ld->name); + mif_info("ERR! boot_start fail\n"); break; } err = qc_boot_post_process(dpld); if (err < 0) - mif_info("%s: ERR! boot_post_process fail\n", ld->name); + mif_info("ERR! boot_post_process fail\n"); break; @@ -1067,7 +1163,7 @@ static int qc_ioctl(struct dpram_link_device *dpld, struct io_device *iod, err = qc_uload_step1(dpld); if (err < 0) { enable_irq(dpld->irq); - mif_info("%s: ERR! upload_step1 fail\n", ld->name); + mif_info("ERR! upload_step1 fail\n"); } break; @@ -1075,12 +1171,12 @@ static int qc_ioctl(struct dpram_link_device *dpld, struct io_device *iod, err = qc_uload_step2(dpld, (void *)arg); if (err < 0) { enable_irq(dpld->irq); - mif_info("%s: ERR! upload_step2 fail\n", ld->name); + mif_info("ERR! upload_step2 fail\n"); } break; default: - mif_err("%s: ERR! invalid cmd 0x%08X\n", ld->name, cmd); + mif_err("ERR! invalid cmd 0x%08X\n", cmd); err = -EINVAL; break; } @@ -1091,44 +1187,402 @@ static int qc_ioctl(struct dpram_link_device *dpld, struct io_device *iod, static irqreturn_t qc_dpram_irq_handler(int irq, void *data) { struct dpram_link_device *dpld = (struct dpram_link_device *)data; - struct link_device *ld = (struct link_device *)&dpld->ld; + struct link_device *ld = &dpld->ld; + struct mem_status stat; u16 int2ap = 0; - if (unlikely(ld->mode == LINK_MODE_OFFLINE)) + if (ld->mode == LINK_MODE_OFFLINE) { + int2ap = dpld->recv_intr(dpld); return IRQ_HANDLED; + } - int2ap = dpld->recv_intr(dpld); + dpld->get_dpram_status(dpld, RX, &stat); + int2ap = stat.int2ap; if (int2ap == INT_POWERSAFE_FAIL) { - mif_info("%s: int2ap == INT_POWERSAFE_FAIL\n", ld->name); + mif_info("int2ap == INT_POWERSAFE_FAIL\n"); goto exit; } if (int2ap == 0x1234 || int2ap == 0xDBAB || int2ap == 0xABCD) { qc_dload_cmd_handler(dpld, int2ap); goto exit; + } else if (int2ap == 0x4321 || int2ap == 0x5432) { + mif_err("ERR! CP error command (0x%04X)\n", int2ap); + goto exit; } if (likely(INT_VALID(int2ap))) - dpld->ipc_rx_handler(dpld, int2ap); + dpld->ipc_rx_handler(dpld, &stat); else - mif_info("%s: ERR! invalid intr 0x%04X\n", ld->name, int2ap); + mif_info("ERR! invalid intr 0x%04X\n", int2ap); exit: return IRQ_HANDLED; } #endif -static struct dpram_ext_op ext_op_set[] = { +#if defined(CONFIG_CDMA_MODEM_QSC6085) +#define CMD_CP_RAMDUMP_START_REQ 0x9200 +#define CMD_CP_RAMDUMP_SEND_REQ 0x9400 +#define CMD_CP_RAMDUMP_SEND_DONE_REQ 0x9600 + +#define CMD_CP_RAMDUMP_START_RESP 0x0300 +#define CMD_CP_RAMDUMP_SEND_RESP 0x0500 +#define CMD_CP_RAMDUMP_SEND_DONE_RESP 0x0700 + +#define QSC_UPLOAD_MODE (0x444D554C) +#define QSC_UPLOAD_MODE_COMPLETE (0xABCDEF90) + +#define RAMDUMP_CMD_TIMEOUT (5 * HZ) +#define QSC6085_RAM_SIZE (32 * 1024 * 1024) /* 32MB */ + +struct qsc6085_dump_command { + u32 addr; + u32 size; + u32 copyto_offset; +}; + +struct qsc6085_dump_status { + u32 dump_size; + u32 addr; + u32 rcvd; + u32 rest; +}; + +static struct qsc6085_dump_status qsc_dump_stat; + +static void qsc6085_dump_work(struct work_struct *work); + +static void qsc6085_init_dl_map(struct dpram_link_device *dpld) +{ + dpld->dl_map.magic = (u32 *)dpld->base; + dpld->dl_map.buff = (u8 *)(dpld->base + DP_DLOAD_BUFF_OFFSET); +} + +static void qsc6085_init_ul_map(struct dpram_link_device *dpld) +{ + int magic_size = DP_ULOAD_MAGIC_SIZE; + int cmd_size = sizeof(struct qsc6085_dump_command); + int mbx_size = DP_MBX_SET_SIZE; + + dpld->ul_map.magic = (u32 *)dpld->base; + dpld->ul_map.cmd = dpld->base + magic_size; + dpld->ul_map.cmd_size = cmd_size; + dpld->ul_map.buff = dpld->base + magic_size + cmd_size; + dpld->ul_map.space = dpld->size - (magic_size + cmd_size + mbx_size); +} + +static void qsc6085_req_active_handler(struct dpram_link_device *dpld) +{ + struct modem_ctl *mc = dpld->ld.mc; + mif_info("pda_active = %d\n", gpio_get_value(mc->gpio_pda_active)); + dpld->send_intr(dpld, INT_CMD(INT_CMD_RES_ACTIVE)); +} + +static void qsc6085_error_display_handler(struct dpram_link_device *dpld) +{ + struct link_device *ld = &dpld->ld; + struct io_device *iod; + + mif_err("recv 0xC9 (CRASH_EXIT)\n"); + mif_err("CP Crash: %s\n", dpld->get_rxq_buff(dpld, IPC_FMT)); + + iod = link_get_iod_with_format(ld, IPC_FMT); + if (iod) + iod->modem_state_changed(iod, STATE_CRASH_EXIT); +} + +static void qsc6085_start_handler(struct dpram_link_device *dpld) +{ + struct link_device *ld = &dpld->ld; + struct io_device *iod; + + mif_info("recv 0xC8 (CP_START)\n"); + + mif_info("send 0xC1 (INIT_START)\n"); + dpld->send_intr(dpld, INT_CMD(INT_CMD_INIT_START)); + + dpld->reset_dpram_ipc(dpld); + + iod = link_get_iod_with_format(ld, IPC_FMT); + if (!iod) { + mif_err("ERR! no iod\n"); + return; + } + iod->modem_state_changed(iod, STATE_ONLINE); + + mif_info("send 0xC2 (INIT_END)\n"); + dpld->send_intr(dpld, INT_CMD(INT_CMD_INIT_END)); +} + +static void qsc6085_command_handler(struct dpram_link_device *dpld, u16 cmd) +{ + switch (INT_CMD_MASK(cmd)) { + case INT_CMD_REQ_ACTIVE: + qsc6085_req_active_handler(dpld); + break; + + case INT_CMD_ERR_DISPLAY: +#ifdef CONFIG_LINK_DEVICE_S5P_IDPRAM + /* If modem crashes while PDA_SLEEP is in progres */ + dpld->pm_op->halt_suspend(dpld); +#endif + qsc6085_error_display_handler(dpld); + break; + + case INT_CMD_PHONE_START: + qsc6085_start_handler(dpld); + complete_all(&ld->init_cmpl); + break; + +#ifdef CONFIG_LINK_DEVICE_S5P_IDPRAM + case INT_CMD_IDPRAM_SUSPEND_ACK: + dpld->pm_op->power_down(dpld); + break; + + case INT_CMD_IDPRAM_WAKEUP_START: + dpld->pm_op->power_up(dpld); + break; +#endif + + case INT_CMD_NORMAL_POWER_OFF: + complete(&dpld->crash_cmpl); + qsc6085_error_display_handler(dpld); + break; + + default: + mif_err("unknown command 0x%04X\n", cmd); + break; + } +} + +static int qsc6085_download_firmware(struct dpram_link_device *dpld, + struct modem_firmware *fw) +{ + int ret = 0; + char __user *src = fw->binary; + int rest = fw->size; + char __iomem *dst = NULL; + unsigned long timeout; + u16 curr_frame = 0; + u16 len = 0; + struct dpram_udl_header header; + + header.bop = START_FLAG; + header.num_frames = DIV_ROUND_UP(len, DP_DEFAULT_WRITE_LEN); + mif_err("FW %d bytes = %d frames\n", fw->size, header.num_frames); + + while (rest > 0) { + curr_frame++; + len = min(rest, DP_DEFAULT_WRITE_LEN); + + header.curr_frame = curr_frame; + header.len = len; + mif_info(">>> frame# %u, len %u\n", curr_frame, len); + + dst = dpld->dl_map.buff; + memcpy(dst, &header, sizeof(header)); + + dst += sizeof(header); + ret = copy_from_user(dst, (void __user *)src, len); + if (ret < 0) { + mif_err("copy_from_user fail\n"); + return -EIO; + } + + dst += len; + src += len; + rest -= len; + + iowrite8(END_FLAG, (dst+3)); + + if (curr_frame == 1) { + dpld->send_intr(dpld, 0); + timeout = UDL_TIMEOUT; + } else { + dpld->send_intr(dpld, CMD_DL_SEND_REQ); + timeout = UDL_SEND_TIMEOUT; + } + + ret = wait_for_completion_timeout(&dpld->udl_cmpl, timeout); + if (!ret) { + mif_err("ERR! no response from CP\n"); + return -EIO; + } + } + + mif_err("send CMD_DL_DONE_REQ to CP\n"); + dpld->send_intr(dpld, CMD_DL_DONE_REQ); + + ret = wait_for_completion_timeout(&dpld->udl_cmpl, UDL_TIMEOUT); + if (!ret) { + mif_err("ERR! no response from CP\n"); + return -EIO; + } + + return 0; +} + +static int qsc6085_dload_firmware(struct dpram_link_device *dpld, + unsigned long arg) +{ + int ret; + struct modem_firmware fw; + mif_err("+++\n"); + + ret = copy_from_user(&fw, (void __user *)arg, sizeof(fw)); + if (ret < 0) { + mif_err("ERR! copy_from_user fail!\n"); + return ret; + } + + ret = qsc6085_download_firmware(dpld, &fw); + + mif_err("---\n"); + return ret; +} + +static int qsc6085_dump_start(struct dpram_link_device *dpld) +{ + int ret; + struct link_device *ld = &dpld->ld; + struct modem_ctl *mc = ld->mc; + struct qsc6085_dump_status *dump_stat = &qsc_dump_stat; + mif_err("+++\n"); + + init_completion(&dpld->crash_cmpl); + INIT_DELAYED_WORK(&dpld->crash_dwork, qsc6085_dump_work); + + iowrite32(QSC_UPLOAD_MODE, &dpld->ul_map.magic); + + /* reset modem so that it goes to upload mode */ + /* ap does not need to reset cp during CRASH_EXIT case */ + if (gpio_get_value(mc->gpio_phone_active)) + mc->ops.modem_reset(mc); + + dpld->send_intr(dpld, CMD_CP_RAMDUMP_START_REQ); + ret = wait_for_completion_timeout(&dpld->crash_cmpl, + RAMDUMP_CMD_TIMEOUT); + if (!ret) { + mif_err("ERR! no response to CP_RAMDUMP_START_REQ\n"); + dump_stat->dump_size = 0; + } else { + dump_stat->dump_size = QSC6085_RAM_SIZE; + dump_stat->addr = 0; + dump_stat->rcvd = 0; + dump_stat->rest = dump_stat->dump_size; + } + + queue_delayed_work(system_nrt_wq, &dpld->crash_dwork, 0); + + mif_err("---\n"); + return 0; +} + +static int qsc6085_dump_update(struct dpram_link_device *dpld, + unsigned long arg) +{ + int ret; + struct link_device *ld = &dpld->ld; + struct io_device *iod = link_get_iod_with_format(ld, IPC_RAMDUMP); + struct memif_uload_map *ul_map = &dpld->ul_map; + struct qsc6085_dump_status *dump_stat = &qsc_dump_stat; + struct qsc6085_dump_command dump_cmd; + + while (iod->sk_rx_q.qlen > 0) + usleep_range(1000, 1100); + + memset(&dump_cmd, 0, sizeof(dump_cmd)); + dump_cmd.addr = dump_stat->addr; + dump_cmd.size = min(dump_stat->rest, ul_map->space); + dump_cmd.copyto_offset = 0x38000010; + + memcpy_toio(ul_map->cmd, &dump_cmd, ul_map->cmd_size); + + dpld->send_intr(dpld, CMD_CP_RAMDUMP_SEND_REQ); + ret = wait_for_completion_timeout(&dpld->crash_cmpl, + RAMDUMP_CMD_TIMEOUT); + if (!ret) { + dump_stat->dump_size = 0; + mif_err("ERR! no response to CP_RAMDUMP_SEND_REQ\n"); + ret = -EIO; + goto exit; + } + + memcpy_fromio(dpld->buff, ul_map->buff, dump_cmd.size); + + ret = iod->recv(iod, ld, dpld->buff, dump_cmd.size); + if (ret < 0) + goto exit; + + dump_stat->addr += dump_cmd.size; + dump_stat->rcvd += dump_cmd.size; + dump_stat->rest -= dump_cmd.size; + mif_info("rest = %u bytes\n", dump_stat->rest); + + ret = dump_cmd.size; + +exit: + return ret; +} + +static void qsc6085_dump_work(struct work_struct *work) +{ + struct dpram_link_device *dpld; + struct link_device *ld; + struct qsc6085_dump_status *dump_stat = &qsc_dump_stat; + int ret; + + dpld = container_of(work, struct dpram_link_device, crash_dwork.work); + ld = &dpld->ld; + + ret = qsc6085_dump_update(dpld, 0); + if (ret > 0 && dump_stat->rest > 0) + queue_delayed_work(system_nrt_wq, &dpld->crash_dwork, 0); +} + +static int qsc6085_dump_finish(struct dpram_link_device *dpld, + unsigned long arg) +{ + int ret; + struct completion *cmpl = &dpld->crash_cmpl; + mif_err("+++\n"); + + init_completion(cmpl); + + dpld->send_intr(dpld, CMD_CP_RAMDUMP_SEND_DONE_REQ); + + ret = wait_for_completion_timeout(cmpl, RAMDUMP_CMD_TIMEOUT); + if (!ret) { + mif_err("ERR! no response to CP_RAMDUMP_SEND_DONE_REQ\n"); + ret = -EIO; + } + + mif_err("---\n"); + return ret; +} +#endif + +static struct dpram_ext_op ext_op_set[MAX_MODEM_TYPE] = { #ifdef CONFIG_CDMA_MODEM_CBP72 [VIA_CBP72] = { .exist = 1, - .init_boot_map = cbp72_init_boot_map, - .init_dl_map = cbp72_init_dl_map, - .download_binary = cbp72_download_binary, - .dump_start = cbp72_dump_start, - .dump_update = cbp72_dump_update, - .ioctl = cbp72_ioctl, + .init_boot_map = cbp_init_boot_map, + .init_dl_map = cbp_init_dl_map, + .xmit_binary = cbp_xmit_binary, + .dump_start = cbp_dump_start, + .dump_update = cbp_dump_update, + }, +#endif +#ifdef CONFIG_CDMA_MODEM_CBP82 + [VIA_CBP82] = { + .exist = 1, + .init_boot_map = cbp_init_boot_map, + .init_dl_map = cbp_init_dl_map, + .xmit_binary = cbp_xmit_binary, + .dump_start = cbp_dump_start, + .dump_update = cbp_dump_update, }, #endif #ifdef CONFIG_LTE_MODEM_CMC221 @@ -1137,10 +1591,14 @@ static struct dpram_ext_op ext_op_set[] = { .init_boot_map = cmc221_init_boot_map, .init_dl_map = cmc221_init_dl_map, .init_ul_map = cmc221_init_ul_map, - .download_binary = cmc221_download_binary, + .init_ipc_map = cmc221_init_ipc_map, + .xmit_boot = cmc221_xmit_boot, + .xmit_binary = cmc221_xmit_binary, .dump_start = cmc221_dump_start, .dump_update = cmc221_dump_update, - .ioctl = cmc221_ioctl, + .clear_int2ap = cmc221_idpram_clr_int2ap, + .wakeup = cmc221_idpram_wakeup, + .sleep = cmc221_idpram_sleep, }, #endif #if defined(CONFIG_CDMA_MODEM_MDM6600) @@ -1163,6 +1621,18 @@ static struct dpram_ext_op ext_op_set[] = { .irq_handler = qc_dpram_irq_handler, }, #endif +#if defined(CONFIG_CDMA_MODEM_QSC6085) + [QC_QSC6085] = { + .exist = 1, + .init_dl_map = qsc6085_init_dl_map, + .init_ul_map = qsc6085_init_ul_map, + .cmd_handler = qsc6085_command_handler, + .firm_update = qsc6085_dload_firmware, + .dump_start = qsc6085_dump_start, + .dump_update = qsc6085_dump_update, + .dump_finish = qsc6085_dump_finish, + }, +#endif }; struct dpram_ext_op *dpram_get_ext_op(enum modem_t modem) @@ -1173,3 +1643,422 @@ struct dpram_ext_op *dpram_get_ext_op(enum modem_t modem) return NULL; } +#ifdef CONFIG_LINK_DEVICE_S5P_IDPRAM +#define GPIO_IDPRAM_SFN S3C_GPIO_SFN(2) + +#define MAX_CHECK_RETRY_CNT 5 +#define MAX_RESUME_TRY_CNT 5 + +static bool s5p_idpram_is_pm_locked(struct dpram_link_device *dpld) +{ + struct modem_ctl *mc = dpld->ld.mc; + struct idpram_pm_data *pm_data = &dpld->pm_data; + + /* If PM is in SUSPEND */ + if (atomic_read(&pm_data->pm_lock) > 0) { + mif_info("in SUSPEND\n"); + return true; + } + + /* If AP is in or into LPA */ + if (!gpio_get_value(mc->gpio_pda_active)) { + mif_info("in LPA\n"); + return true; + } + + return false; +} + +static void s5p_idpram_set_pm_lock(struct dpram_link_device *dpld, int lock) +{ + struct idpram_pm_data *pm_data = &dpld->pm_data; + + /* 0 = unlock, 1 = lock */ + switch (lock) { + case 0: + if (atomic_read(&pm_data->pm_lock)) + atomic_set(&pm_data->pm_lock, lock); + break; + + case 1: + if (!atomic_read(&pm_data->pm_lock)) + atomic_set(&pm_data->pm_lock, lock); + break; + + default: + break; + } +} + +static void s5p_idpram_try_resume(struct work_struct *work) +{ + struct idpram_pm_data *pm_data; + struct dpram_link_device *dpld; + struct link_device *ld; + unsigned long delay; + u16 cmd; + mif_info("+++\n"); + + pm_data = container_of(work, struct idpram_pm_data, resume_dwork.work); + dpld = container_of(pm_data, struct dpram_link_device, pm_data); + ld = &dpld->ld; + + if (pm_data->last_msg == INT_CMD(INT_CMD_IDPRAM_RESUME_REQ)) { + pm_data->last_msg = 0; + + s5p_idpram_set_pm_lock(dpld, 0); + wake_unlock(&pm_data->hold_wlock); + + delay = msecs_to_jiffies(10); + schedule_delayed_work(&pm_data->tx_dwork, delay); + + mif_info("%s resumed\n", ld->name); + goto exit; + } + + if (pm_data->resume_try_cnt++ < MAX_RESUME_TRY_CNT) { + mif_info("%s not resumed yet\n", ld->name); + + cmd = INT_CMD(INT_CMD_IDPRAM_RESUME_REQ); + mif_info("send IDPRAM_RESUME_REQ (0x%X)\n", cmd); + dpld->send_intr(dpld, cmd); + + delay = msecs_to_jiffies(200); + schedule_delayed_work(&pm_data->resume_dwork, delay); + } else { + struct io_device *iod; + mif_err("ERR! %s resume T-I-M-E-O-U-T\n", ld->name); + + iod = link_get_iod_with_format(ld, IPC_FMT); + if (iod) + iod->modem_state_changed(iod, STATE_CRASH_EXIT); + + wake_unlock(&pm_data->hold_wlock); + + /* hold wakelock until uevnet sent to rild */ + wake_lock_timeout(&pm_data->hold_wlock, HZ*7); + s5p_idpram_set_pm_lock(dpld, 0); + } + +exit: + mif_info("---\n"); +} + +static irqreturn_t s5p_cp_dump_irq_handler(int irq, void *data) +{ + return IRQ_HANDLED; +} + +static irqreturn_t s5p_ap_wakeup_irq_handler(int irq, void *data) +{ + struct idpram_pm_data *pm_data = data; + wake_lock_timeout(&pm_data->ap_wlock, HZ*5); + return IRQ_HANDLED; +} + +static void s5p_idpram_power_down(struct dpram_link_device *dpld) +{ + struct idpram_pm_data *pm_data = &dpld->pm_data; + mif_info("+++\n"); + + pm_data->last_msg = INT_CMD(INT_CMD_IDPRAM_SUSPEND_ACK); + complete(&pm_data->down_cmpl); + + mif_info("---\n"); +} + +static void s5p_idpram_power_up(struct dpram_link_device *dpld) +{ + struct idpram_pm_data *pm_data = &dpld->pm_data; + mif_info("+++\n"); + + pm_data->last_msg = INT_CMD(INT_CMD_IDPRAM_RESUME_REQ); + pm_data->pm_state = IDPRAM_PM_ACTIVE; + + mif_info("---\n"); +} + +static void s5p_idpram_halt_suspend(struct dpram_link_device *dpld) +{ + struct idpram_pm_data *pm_data = &dpld->pm_data; + mif_info("+++\n"); + + complete(&pm_data->down_cmpl); + + mif_info("---\n"); +} + +static int s5p_idpram_prepare_suspend(struct dpram_link_device *dpld) +{ + struct link_device *ld = &dpld->ld; + struct idpram_pm_data *pm_data = &dpld->pm_data; + struct modem_ctl *mc = dpld->ld.mc; + struct completion *cmpl; + unsigned long timeout; + unsigned long rest; + int cnt = 0; + u16 cmd = INT_CMD(INT_CMD_IDPRAM_SUSPEND_REQ); + mif_info("+++\n"); + + pm_data->pm_state = IDPRAM_PM_SUSPEND_PREPARE; + pm_data->last_msg = 0; + s5p_idpram_set_pm_lock(dpld, 1); + + /* + * Because, if dpram was powered down, cp dpram random intr was + * ocurred. so, fixed by muxing cp dpram intr pin to GPIO output + * high,.. + */ + gpio_set_value(dpld->gpio_int2cp, 1); + s3c_gpio_cfgpin(dpld->gpio_int2cp, S3C_GPIO_OUTPUT); + + /* prevent PDA_ACTIVE status is low */ + gpio_set_value(mc->gpio_pda_active, 1); + + cmpl = &pm_data->down_cmpl; + timeout = IDPRAM_SUSPEND_REQ_TIMEOUT; + cnt = 0; + do { + init_completion(cmpl); + + mif_info("send IDPRAM_SUSPEND_REQ (0x%X)\n", cmd); + dpld->send_intr(dpld, cmd); + + rest = wait_for_completion_timeout(cmpl, timeout); + if (rest == 0) { + cnt++; + mif_err("timeout!!! (count = %d)\n", cnt); + if (cnt >= 3) { + mif_err("ERR! no response from CP\n"); + break; + } + } + } while (rest == 0); + + switch (pm_data->last_msg) { + case INT_CMD(INT_CMD_IDPRAM_SUSPEND_ACK): + mif_info("recv IDPRAM_SUSPEND_ACK (0x%X)\n", pm_data->last_msg); + pm_data->pm_state = IDPRAM_PM_DPRAM_POWER_DOWN; + break; + + default: + mif_err("ERR! %s down or not ready!!! (intr 0x%04X)\n", + ld->name, dpld->recv_intr(dpld)); + timeout = msecs_to_jiffies(500); + wake_lock_timeout(&pm_data->hold_wlock, timeout); + s5p_idpram_set_pm_lock(dpld, 0); + break; + } + + mif_info("---\n"); + return 0; +} + +static int s5p_idpram_resume_init(struct dpram_link_device *dpld) +{ + struct idpram_pm_data *pm_data = &dpld->pm_data; + mif_info("+++\n"); + + pm_data->pm_state = IDPRAM_PM_RESUME_START; + pm_data->last_msg = 0; + + dpld->reset_dpram_ipc(dpld); + + /* re-initialize internal dpram gpios */ + s3c_gpio_cfgpin(dpld->gpio_int2cp, GPIO_IDPRAM_SFN); + + mif_info("---\n"); + return 0; +} + +static int s5p_idpram_start_resume(struct dpram_link_device *dpld) +{ + struct idpram_pm_data *pm_data = &dpld->pm_data; + struct modem_ctl *mc = dpld->ld.mc; + unsigned long delay; + mif_info("+++ (pm_state = %d)\n", pm_data->pm_state); + + switch (pm_data->pm_state) { + /* schedule_work */ + case IDPRAM_PM_DPRAM_POWER_DOWN: + gpio_set_value(mc->gpio_pda_active, 0); + msleep(50); + + s5p_idpram_resume_init(dpld); + msleep(50); + + gpio_set_value(mc->gpio_pda_active, 1); + msleep(20); + + pm_data->resume_try_cnt = 0; + wake_lock(&pm_data->hold_wlock); + + delay = msecs_to_jiffies(20); + schedule_delayed_work(&pm_data->resume_dwork, delay); + break; + + case IDPRAM_PM_RESUME_START: + case IDPRAM_PM_SUSPEND_PREPARE: + default: + break; + } + + mif_info("---\n"); + return 0; +} + +static int s5p_idpram_notify_pm_event(struct notifier_block *this, + unsigned long event, void *v) +{ + struct idpram_pm_data *pm_data; + struct dpram_link_device *dpld; + int err; + mif_info("+++ (event 0x%08X)\n", (int)event); + + pm_data = container_of(this, struct idpram_pm_data, pm_noti); + dpld = container_of(pm_data, struct dpram_link_device, pm_data); + + switch (event) { + case PM_SUSPEND_PREPARE: + err = s5p_idpram_prepare_suspend(dpld); + break; + + case PM_POST_SUSPEND: + err = s5p_idpram_start_resume(dpld); + break; + + default: + break; + } + + mif_info("---\n"); + return NOTIFY_DONE; +} + +static int s5p_idpram_pm_init(struct dpram_link_device *dpld, + struct modem_data *modem, void (*pm_tx_func)(struct work_struct *work)) +{ + struct idpram_pm_data *pm_data = &dpld->pm_data; + int err; + unsigned gpio; + unsigned irq; + mif_info("+++\n"); + + atomic_set(&pm_data->pm_lock, 0); + + init_completion(&pm_data->down_cmpl); + + wake_lock_init(&pm_data->ap_wlock, WAKE_LOCK_SUSPEND, "ap_wakeup"); + wake_lock_init(&pm_data->hold_wlock, WAKE_LOCK_SUSPEND, "dpram_hold"); + + INIT_DELAYED_WORK(&pm_data->tx_dwork, pm_tx_func); + INIT_DELAYED_WORK(&pm_data->resume_dwork, s5p_idpram_try_resume); + + pm_data->resume_try_cnt = 0; + + /* register PM notifier */ + pm_data->pm_noti.notifier_call = s5p_idpram_notify_pm_event; + register_pm_notifier(&pm_data->pm_noti); + + /* + ** Register gpio_ap_wakeup interrupt handler + */ + gpio = modem->gpio_ap_wakeup; + irq = gpio_to_irq(gpio); + mif_info("gpio_ap_wakeup: GPIO# %d, IRQ# %d\n", gpio, irq); + + err = request_irq(irq, s5p_ap_wakeup_irq_handler, IRQF_TRIGGER_RISING, + "idpram_ap_wakeup", (void *)pm_data); + if (err) { + mif_err("ERR! request_irq(#%d) fail (err %d)\n", irq, err); + goto exit; + } + + err = enable_irq_wake(irq); + if (err) { + mif_err("ERR! enable_irq_wake(#%d) fail (err %d)\n", irq, err); + free_irq(irq, (void *)pm_data); + goto exit; + } + + /* + ** Register gpio_cp_dump_int interrupt handler for LPA mode + */ + gpio = modem->gpio_cp_dump_int; + irq = gpio_to_irq(gpio); + mif_info("gpio_cp_dump_int: GPIO# %d, IRQ# %d\n", gpio, irq); + + err = request_irq(irq, s5p_cp_dump_irq_handler, IRQF_TRIGGER_RISING, + "idpram_cp_dump", (void *)pm_data); + if (err) { + mif_err("ERR! request_irq(#%d) fail (err %d)\n", irq, err); + free_irq(gpio_to_irq(modem->gpio_ap_wakeup), (void *)pm_data); + goto exit; + } + + err = enable_irq_wake(irq); + if (err) { + mif_err("ERR! enable_irq_wake(#%d) fail (err %d)\n", irq, err); + free_irq(gpio_to_irq(modem->gpio_cp_dump_int), (void *)pm_data); + free_irq(gpio_to_irq(modem->gpio_ap_wakeup), (void *)pm_data); + goto exit; + } + +exit: + mif_err("---\n"); + return err; +} + +static bool s5p_idpram_int2cp_possible(struct dpram_link_device *dpld) +{ + struct modem_ctl *mc = dpld->ld.mc; + int i; + int level; + + for (i = 1; i <= MAX_CHECK_RETRY_CNT; i++) { + level = gpio_get_value(dpld->gpio_int2cp); + if (level) + break; + + /* CP has not yet received previous command. */ + mif_info("gpio_ipc_int2cp == 0 (count %d)\n", i); + + usleep_range(1000, 1100); + } + + for (i = 1; i <= MAX_CHECK_RETRY_CNT; i++) { + level = gpio_get_value(mc->gpio_pda_active); + if (level) + break; + + /* AP is in transition to LPA mode. */ + mif_info("gpio_pda_active == 0 (count %d)\n", i); + + usleep_range(1000, 1100); + } + + return true; +} +#endif + +static struct idpram_pm_op idpram_pm_op_set[MAX_AP_TYPE] = { +#ifdef CONFIG_LINK_DEVICE_S5P_IDPRAM + [S5P] = { + .pm_init = s5p_idpram_pm_init, + .power_down = s5p_idpram_power_down, + .power_up = s5p_idpram_power_up, + .halt_suspend = s5p_idpram_halt_suspend, + .locked = s5p_idpram_is_pm_locked, + .int2cp_possible = s5p_idpram_int2cp_possible, + }, +#endif +}; + +struct idpram_pm_op *idpram_get_pm_op(enum ap_type ap) +{ + if (idpram_pm_op_set[ap].exist) + return &idpram_pm_op_set[ap]; + else + return NULL; +} + diff --git a/drivers/misc/modem_if/modem_link_device_hsic.c b/drivers/misc/modem_if/modem_link_device_hsic.c index eb5dfc6..e50e4a8 100644 --- a/drivers/misc/modem_if/modem_link_device_hsic.c +++ b/drivers/misc/modem_if/modem_link_device_hsic.c @@ -31,7 +31,7 @@ #include <linux/suspend.h> #include <linux/version.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_hsic.h" #include "modem_utils.h" @@ -269,7 +269,7 @@ static void usb_rx_complete(struct urb *urb) switch (pipe_data->format) { case IF_USB_FMT_EP: if (usb_ld->if_usb_is_main) { -// pr_urb("IPC-RX", urb); + pr_urb("IPC-RX", urb); iod_format = IPC_FMT; } else { iod_format = IPC_BOOT; @@ -477,13 +477,13 @@ static int _usb_tx_work(struct sk_buff *skb) if (!pipe_data) return -ENOENT; -/* + if (iod->format == IPC_FMT && usb_ld->if_usb_is_main) pr_skb("IPC-TX", skb); if (iod->format == IPC_RAW) mif_debug("TX[RAW]\n"); -*/ + return usb_tx_urb_with_skb(usb_ld->usbdev, skb, pipe_data); } @@ -741,11 +741,11 @@ static inline int link_pm_slave_wake(struct link_pm_data *pm_data) != HOSTWAKE_TRIGLEVEL) { if (gpio_get_value(pm_data->gpio_link_slavewake)) { gpio_set_value(pm_data->gpio_link_slavewake, 0); - mif_debug("gpio [SWK] set [0]\n"); + mif_info("gpio [SWK] set [0]\n"); mdelay(5); } gpio_set_value(pm_data->gpio_link_slavewake, 1); - mif_debug("gpio [SWK] set [1]\n"); + mif_info("gpio [SWK] set [1]\n"); mdelay(5); /* wait host wake signal*/ @@ -860,7 +860,7 @@ static irqreturn_t link_pm_irq_handler(int irq, void *data) runtime pm status changes to ACTIVE */ value = gpio_get_value(pm_data->gpio_link_hostwake); - mif_debug("gpio [HWK] get [%d]\n", value); + mif_info("gpio [HWK] get [%d]\n", value); /* * igonore host wakeup interrupt at suspending kernel @@ -975,9 +975,7 @@ static int link_pm_notifier_event(struct notifier_block *this, { struct link_pm_data *pm_data = container_of(this, struct link_pm_data, pm_notifier); -#ifdef CONFIG_UMTS_MODEM_XMM6262 struct modem_ctl *mc = if_usb_get_modemctl(pm_data); -#endif switch (event) { case PM_SUSPEND_PREPARE: @@ -986,13 +984,11 @@ static int link_pm_notifier_event(struct notifier_block *this, case PM_RESTORE_PREPARE: #endif pm_data->dpm_suspending = true; -#ifdef CONFIG_UMTS_MODEM_XMM6262 /* set PDA Active High if previous state was LPA */ if (!gpio_get_value(pm_data->gpio_link_active)) { mif_info("PDA active High to LPA suspend spot\n"); gpio_set_value(mc->gpio_pda_active, 1); } -#endif mif_debug("dpm suspending set to true\n"); return NOTIFY_OK; case PM_POST_SUSPEND: @@ -1006,15 +1002,14 @@ static int link_pm_notifier_event(struct notifier_block *this, queue_delayed_work(pm_data->wq, &pm_data->link_pm_work, 0); mif_info("post resume\n"); - } -#ifdef CONFIG_UMTS_MODEM_XMM6262 + } else { /* LPA to Kernel suspend and User Freezing task fail resume, restore to LPA GPIO states. */ - if (!gpio_get_value(pm_data->gpio_link_active)) { - mif_info("PDA active low to LPA GPIO state\n"); - gpio_set_value(mc->gpio_pda_active, 0); + if (!gpio_get_value(pm_data->gpio_link_active)) { + mif_info("PDA active low to LPA GPIO state\n"); + gpio_set_value(mc->gpio_pda_active, 0); + } } -#endif mif_debug("dpm suspending set to false\n"); return NOTIFY_OK; } @@ -1458,8 +1453,7 @@ static int usb_link_pm_init(struct usb_link_device *usb_ld, void *data) struct modem_data *pdata = (struct modem_data *)pdev->dev.platform_data; struct modemlink_pm_data *pm_pdata; - struct link_pm_data *pm_data = - kzalloc(sizeof(struct link_pm_data), GFP_KERNEL); + struct link_pm_data *pm_data; if (!pdata || !pdata->link_pm_data) { mif_err("platform data is NULL\n"); @@ -1467,6 +1461,7 @@ static int usb_link_pm_init(struct usb_link_device *usb_ld, void *data) } pm_pdata = pdata->link_pm_data; + pm_data = kzalloc(sizeof(struct link_pm_data), GFP_KERNEL); if (!pm_data) { mif_err("link_pm_data is NULL\n"); return -ENOMEM; diff --git a/drivers/misc/modem_if/modem_link_device_memory.c b/drivers/misc/modem_if/modem_link_device_memory.c new file mode 100644 index 0000000..9e49e50 --- /dev/null +++ b/drivers/misc/modem_if/modem_link_device_memory.c @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2011 Samsung Electronics. + * + * 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/irq.h> +#include <linux/gpio.h> +#include <linux/time.h> +#include <linux/interrupt.h> +#include <linux/timer.h> +#include <linux/wakelock.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/vmalloc.h> +#include <linux/if_arp.h> +#include <linux/platform_device.h> +#include <linux/kallsyms.h> +#include <linux/suspend.h> +#include <plat/gpio-cfg.h> +#include <mach/gpio.h> + +#include "modem.h" +#include "modem_prj.h" +#include "modem_utils.h" +#include "modem_link_device_memory.h" +#ifdef CONFIG_LINK_DEVICE_DPRAM +#include "modem_link_device_dpram.h" +#endif + +/** + * msq_get_free_slot + * @trq : pointer to an instance of mem_status_queue structure + * + * Succeeds always by dropping the oldest slot if a "msq" is full. + */ +struct mem_status *msq_get_free_slot(struct mem_status_queue *msq) +{ + int qsize = MAX_MEM_LOG_CNT; + int in; + int out; + unsigned long flags; + struct mem_status *stat; + + spin_lock_irqsave(&msq->lock, flags); + + in = msq->in; + out = msq->out; + + if (circ_get_space(qsize, in, out) < 1) { + /* Make the oldest slot empty */ + out++; + msq->out = (out == qsize) ? 0 : out; + } + + /* Get a free slot */ + stat = &msq->stat[in]; + + /* Make it as "data" slot */ + in++; + msq->in = (in == qsize) ? 0 : in; + + spin_unlock_irqrestore(&msq->lock, flags); + + memset(stat, 0, sizeof(struct mem_status)); + + return stat; +} + +struct mem_status *msq_get_data_slot(struct mem_status_queue *msq) +{ + int qsize = MAX_MEM_LOG_CNT; + int in; + int out; + unsigned long flags; + struct mem_status *stat; + + spin_lock_irqsave(&msq->lock, flags); + + in = msq->in; + out = msq->out; + + if (in == out) { + stat = NULL; + goto exit; + } + + /* Get a data slot */ + stat = &msq->stat[out]; + + /* Make it "free" slot */ + out++; + msq->out = (out == qsize) ? 0 : out; + +exit: + spin_unlock_irqrestore(&msq->lock, flags); + return stat; +} + +/** + * memcpy16_from_io + * @to: pointer to "real" memory + * @from: pointer to IO memory + * @count: data length in bytes to be copied + * + * Copies data from IO memory space to "real" memory space. + */ +void memcpy16_from_io(const void *to, const void __iomem *from, u32 count) +{ + u16 *d = (u16 *)to; + u16 *s = (u16 *)from; + u32 words = count >> 1; + while (words--) + *d++ = ioread16(s++); +} + +/** + * memcpy16_to_io + * @to: pointer to IO memory + * @from: pointer to "real" memory + * @count: data length in bytes to be copied + * + * Copies data from "real" memory space to IO memory space. + */ +void memcpy16_to_io(const void __iomem *to, const void *from, u32 count) +{ + u16 *d = (u16 *)to; + u16 *s = (u16 *)from; + u32 words = count >> 1; + while (words--) + iowrite16(*s++, d++); +} + +/** + * memcmp16_to_io + * @to: pointer to IO memory + * @from: pointer to "real" memory + * @count: data length in bytes to be compared + * + * Compares data from "real" memory space to IO memory space. + */ +int memcmp16_to_io(const void __iomem *to, const void *from, u32 count) +{ + u16 *d = (u16 *)to; + u16 *s = (u16 *)from; + int words = count >> 1; + int diff = 0; + int i; + u16 d1; + u16 s1; + + for (i = 0; i < words; i++) { + d1 = ioread16(d); + s1 = *s; + if (d1 != s1) { + diff++; + mif_err("ERR! [%d] d:0x%04X != s:0x%04X\n", i, d1, s1); + } + d++; + s++; + } + + return diff; +} + +/** + * circ_read16_from_io + * @dst: start address of the destination buffer + * @src: start address of the buffer in a circular queue + * @qsize: size of the circular queue + * @out: offset to read + * @len: length of data to be read + * + * Should be invoked after checking data length + */ +void circ_read16_from_io(void *dst, void *src, u32 qsize, u32 out, u32 len) +{ + if ((out + len) <= qsize) { + /* ----- (out) (in) ----- */ + /* ----- 7f 00 00 7e ----- */ + memcpy16_from_io(dst, (src + out), len); + } else { + /* (in) ----------- (out) */ + /* 00 7e ----------- 7f 00 */ + unsigned len1 = qsize - out; + + /* 1) data start (out) ~ buffer end */ + memcpy16_from_io(dst, (src + out), len1); + + /* 2) buffer start ~ data end (in - 1) */ + memcpy16_from_io((dst + len1), src, (len - len1)); + } +} + +/** + * circ_write16_to_io + * @dst: pointer to the start of the circular queue + * @src: pointer to the source + * @qsize: size of the circular queue + * @in: offset to write + * @len: length of data to be written + * + * Should be invoked after checking free space + */ +void circ_write16_to_io(void *dst, void *src, u32 qsize, u32 in, u32 len) +{ + u32 space; + + if ((in + len) < qsize) { + /* (in) ----------- (out) */ + /* 00 7e ----------- 7f 00 */ + memcpy16_to_io((dst + in), src, len); + } else { + /* ----- (out) (in) ----- */ + /* ----- 7f 00 00 7e ----- */ + + /* 1) space start (in) ~ buffer end */ + space = qsize - in; + memcpy16_to_io((dst + in), src, ((len > space) ? space : len)); + + /* 2) buffer start ~ data end */ + if (len > space) + memcpy16_to_io(dst, (src + space), (len - space)); + } +} + +/** + * copy_circ_to_user + * @dst: start address of the destination buffer + * @src: start address of the buffer in a circular queue + * @qsize: size of the circular queue + * @out: offset to read + * @len: length of data to be read + * + * Should be invoked after checking data length + */ +int copy_circ_to_user(void __user *dst, void *src, u32 qsize, u32 out, u32 len) +{ + if ((out + len) <= qsize) { + /* ----- (out) (in) ----- */ + /* ----- 7f 00 00 7e ----- */ + if (copy_to_user(dst, (src + out), len)) { + mif_err("ERR! <called by %pf> copy_to_user fail\n", + CALLER); + return -EFAULT; + } + } else { + /* (in) ----------- (out) */ + /* 00 7e ----------- 7f 00 */ + unsigned len1 = qsize - out; + + /* 1) data start (out) ~ buffer end */ + if (copy_to_user(dst, (src + out), len1)) { + mif_err("ERR! <called by %pf> copy_to_user fail\n", + CALLER); + return -EFAULT; + } + + /* 2) buffer start ~ data end (in?) */ + if (copy_to_user((dst + len1), src, (len - len1))) { + mif_err("ERR! <called by %pf> copy_to_user fail\n", + CALLER); + return -EFAULT; + } + } + + return 0; +} + +/** + * copy_user_to_circ + * @dst: pointer to the start of the circular queue + * @src: pointer to the source + * @qsize: size of the circular queue + * @in: offset to write + * @len: length of data to be written + * + * Should be invoked after checking free space + */ +int copy_user_to_circ(void *dst, void __user *src, u32 qsize, u32 in, u32 len) +{ + u32 space; + u32 len1; + + if ((in + len) < qsize) { + /* (in) ----------- (out) */ + /* 00 7e ----------- 7f 00 */ + if (copy_from_user((dst + in), src, len)) { + mif_err("ERR! <called by %pf> copy_from_user fail\n", + CALLER); + return -EFAULT; + } + } else { + /* ----- (out) (in) ----- */ + /* ----- 7f 00 00 7e ----- */ + + /* 1) space start (in) ~ buffer end */ + space = qsize - in; + len1 = (len > space) ? space : len; + if (copy_from_user((dst + in), src, len1)) { + mif_err("ERR! <called by %pf> copy_from_user fail\n", + CALLER); + return -EFAULT; + } + + /* 2) buffer start ~ data end */ + if (len > len1) { + if (copy_from_user(dst, (src + space), (len - len1))) { + mif_err("ERR! <called by %pf> copy_from_user " + "fail\n", CALLER); + return -EFAULT; + } + } + } + + return 0; +} + +/** + * print_mem_status + * @ld: pointer to an instance of link_device structure + * @mst: pointer to an instance of mem_status structure + * + * Prints a snapshot of the status of a SHM. + */ +void print_mem_status(struct link_device *ld, struct mem_status *mst) +{ + struct utc_time utc; + int us = ns2us(mst->ts.tv_nsec); + + ts2utc(&mst->ts, &utc); + pr_info("%s: %s: [%02d:%02d:%02d.%06d] " + "[%s] ACC{%X %d} " + "FMT{TI:%u TO:%u RI:%u RO:%u} " + "RAW{TI:%u TO:%u RI:%u RO:%u} " + "INTR{RX:0x%X TX:0x%X}\n", + MIF_TAG, ld->name, utc.hour, utc.min, utc.sec, us, + get_dir_str(mst->dir), mst->magic, mst->access, + mst->head[IPC_FMT][TX], mst->tail[IPC_FMT][TX], + mst->head[IPC_FMT][RX], mst->tail[IPC_FMT][RX], + mst->head[IPC_RAW][TX], mst->tail[IPC_RAW][TX], + mst->head[IPC_RAW][RX], mst->tail[IPC_RAW][RX], + mst->int2ap, mst->int2cp); +} + +/** + * print_circ_status + * @ld: pointer to an instance of link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @mst: pointer to an instance of mem_status structure + * + * Prints a snapshot of the status of a memory + */ +void print_circ_status(struct link_device *ld, int dev, struct mem_status *mst) +{ + struct utc_time utc; + int us = ns2us(mst->ts.tv_nsec); + + if (dev > IPC_RAW) + return; + + ts2utc(&mst->ts, &utc); + pr_info("%s: %s: [%02d:%02d:%02d.%06d] " + "[%s] %s | TXQ{in:%u out:%u} RXQ{in:%u out:%u}\n", + MIF_TAG, ld->name, utc.hour, utc.min, utc.sec, us, + get_dir_str(mst->dir), get_dev_name(dev), + mst->head[dev][TX], mst->tail[dev][TX], + mst->head[dev][RX], mst->tail[dev][RX]); +} + +/** + * print_ipc_trace + * @ld: pointer to an instance of link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @stat: pointer to an instance of circ_status structure + * @ts: pointer to an instance of timespec structure + * @buff: start address of a buffer into which RX IPC messages were copied + * @rcvd: size of data in the buffer + * + * Prints IPC messages in a local memory buffer to a kernel log. + */ +void print_ipc_trace(struct link_device *ld, int dev, struct circ_status *stat, + struct timespec *ts, u8 *buff, u32 rcvd) +{ + struct utc_time utc; + + ts2utc(ts, &utc); + + pr_info("%s: [%d-%02d-%02d %02d:%02d:%02d.%03d] " + "%s %s_RXQ {IN:%u OUT:%u LEN:%d}\n", + MIF_TAG, utc.year, utc.mon, utc.day, utc.hour, utc.min, utc.sec, + utc.msec, ld->name, get_dev_name(dev), stat->in, stat->out, + stat->size); + + mif_print_dump(buff, rcvd, 4); +} + +/** + * capture_mem_dump + * @ld: pointer to an instance of link_device structure + * @base: base virtual address to a memory interface medium + * @size: size of the memory interface medium + * + * Captures a dump for a memory interface medium. + * + * Returns the pointer to a memory dump buffer. + */ +u8 *capture_mem_dump(struct link_device *ld, u8 *base, u32 size) +{ + u8 *buff = kzalloc(size, GFP_ATOMIC); + if (!buff) { + mif_err("%s: ERR! kzalloc(%d) fail\n", ld->name, size); + return NULL; + } else { + memcpy16_from_io(buff, base, size); + return buff; + } +} + +/** + * trq_get_free_slot + * @trq : pointer to an instance of trace_data_queue structure + * + * Succeeds always by dropping the oldest slot if a "trq" is full. + */ +struct trace_data *trq_get_free_slot(struct trace_data_queue *trq) +{ + int qsize = MAX_TRACE_SIZE; + int in; + int out; + unsigned long flags; + struct trace_data *trd; + + spin_lock_irqsave(&trq->lock, flags); + + in = trq->in; + out = trq->out; + + /* The oldest slot can be dropped. */ + if (circ_get_space(qsize, in, out) < 1) { + /* Free the data buffer in the oldest slot */ + trd = &trq->trd[out]; + kfree(trd->data); + + /* Make the oldest slot empty */ + out++; + trq->out = (out == qsize) ? 0 : out; + } + + /* Get a free slot and make it occupied */ + trd = &trq->trd[in++]; + trq->in = (in == qsize) ? 0 : in; + + spin_unlock_irqrestore(&trq->lock, flags); + + memset(trd, 0, sizeof(struct trace_data)); + + return trd; +} + +struct trace_data *trq_get_data_slot(struct trace_data_queue *trq) +{ + int qsize = MAX_TRACE_SIZE; + int in; + int out; + unsigned long flags; + struct trace_data *trd; + + spin_lock_irqsave(&trq->lock, flags); + + in = trq->in; + out = trq->out; + + if (circ_get_usage(qsize, in, out) < 1) { + spin_unlock_irqrestore(&trq->lock, flags); + return NULL; + } + + /* Get a data slot and make it empty */ + trd = &trq->trd[out++]; + trq->out = (out == qsize) ? 0 : out; + + spin_unlock_irqrestore(&trq->lock, flags); + + return trd; +} + diff --git a/drivers/misc/modem_if/modem_link_device_memory.h b/drivers/misc/modem_if/modem_link_device_memory.h new file mode 100644 index 0000000..29a84ac --- /dev/null +++ b/drivers/misc/modem_if/modem_link_device_memory.h @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2010 Samsung Electronics. + * + * 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 __MODEM_LINK_DEVICE_MEMORY_H__ +#define __MODEM_LINK_DEVICE_MEMORY_H__ + +#include <linux/spinlock.h> +#include <linux/wakelock.h> +#include <linux/workqueue.h> +#include <linux/timer.h> +#include <linux/notifier.h> +#if defined(CONFIG_HAS_EARLYSUSPEND) +#include <linux/earlysuspend.h> +#elif defined(CONFIG_FB) +#include <linux/fb.h> +#endif + +#include "modem.h" +#include "modem_prj.h" + +#define DPRAM_MAGIC_CODE 0xAA + +/* interrupt masks.*/ +#define INT_MASK_VALID 0x0080 +#define INT_MASK_CMD 0x0040 +#define INT_VALID(x) ((x) & INT_MASK_VALID) +#define INT_CMD_VALID(x) ((x) & INT_MASK_CMD) +#define INT_NON_CMD(x) (INT_MASK_VALID | (x)) +#define INT_CMD(x) (INT_MASK_VALID | INT_MASK_CMD | (x)) + +#define EXT_UDL_MASK 0xF000 +#define EXT_UDL_CMD(x) ((x) & EXT_UDL_MASK) +#define EXT_INT_VALID_MASK 0x8000 +#define EXT_CMD_VALID_MASK 0x4000 +#define UDL_CMD_VALID_MASK 0x2000 +#define EXT_INT_VALID(x) ((x) & EXT_INT_VALID_MASK) +#define EXT_CMD_VALID(x) ((x) & EXT_CMD_VALID_MASK) +#define UDL_CMD_VALID(x) ((x) & UDL_CMD_VALID_MASK) +#define INT_EXT_CMD(x) (EXT_INT_VALID_MASK | EXT_CMD_VALID_MASK | (x)) + +#define EXT_CMD_MASK(x) ((x) & 0x0FFF) +#define EXT_CMD_SET_SPEED_LOW 0x0011 +#define EXT_CMD_SET_SPEED_MID 0x0012 +#define EXT_CMD_SET_SPEED_HIGH 0x0013 + +#define UDL_RESULT_SUCCESS 0x1 +#define UDL_RESULT_FAIL 0x2 + +#define UDL_CMD_MASK(x) (((x) >> 8) & 0xF) +#define UDL_CMD_RECV_READY 0x1 +#define UDL_CMD_DL_START_REQ 0x2 +#define UDL_CMD_DL_START_RESP 0x3 +#define UDL_CMD_IMAGE_SEND_REQ 0x4 +#define UDL_CMD_SEND_DONE_RESP 0x5 +#define UDL_CMD_SEND_DONE_REQ 0x6 +#define UDL_CMD_UPDATE_DONE 0x7 +#define UDL_CMD_STATUS_UPDATE 0x8 +#define UDL_CMD_IMAGE_SEND_RESP 0x9 +#define UDL_CMD_EFS_CLEAR_RESP 0xB +#define UDL_CMD_ALARM_BOOT_OK 0xC +#define UDL_CMD_ALARM_BOOT_FAIL 0xD + +#define CMD_DL_READY 0xA100 +#define CMD_DL_START_REQ 0x9200 +#define CMD_DL_START_RESP 0xA301 +#define CMD_DL_SEND_REQ 0x9400 +#define CMD_DL_SEND_RESP 0xA501 +#define CMD_DL_DONE_REQ 0x9600 +#define CMD_DL_DONE_RESP 0xA701 + +#define CMD_UL_RECV_RESP 0x9601 +#define CMD_UL_RECV_DONE_REQ 0xA700 +#define CMD_UL_RECV_DONE_RESP 0x9801 + +/* special interrupt cmd indicating modem boot failure. */ +#define INT_POWERSAFE_FAIL 0xDEAD + +#define INT_MASK_REQ_ACK_F 0x0020 +#define INT_MASK_REQ_ACK_R 0x0010 +#define INT_MASK_RES_ACK_F 0x0008 +#define INT_MASK_RES_ACK_R 0x0004 +#define INT_MASK_SEND_F 0x0002 +#define INT_MASK_SEND_R 0x0001 + +#define INT_MASK_REQ_ACK_RFS 0x0400 /* Request RES_ACK_RFS */ +#define INT_MASK_RES_ACK_RFS 0x0200 /* Response of REQ_ACK_RFS */ +#define INT_MASK_SEND_RFS 0x0100 /* Indicate sending RFS data */ + +#define INT_MASK_REQ_ACK_SET \ + (INT_MASK_REQ_ACK_F | INT_MASK_REQ_ACK_R | INT_MASK_REQ_ACK_RFS) + +#define INT_MASK_RES_ACK_SET \ + (INT_MASK_RES_ACK_F | INT_MASK_RES_ACK_R | INT_MASK_RES_ACK_RFS) + +#define INT_CMD_MASK(x) ((x) & 0xF) +#define INT_CMD_INIT_START 0x1 +#define INT_CMD_INIT_END 0x2 +#define INT_CMD_REQ_ACTIVE 0x3 +#define INT_CMD_RES_ACTIVE 0x4 +#define INT_CMD_REQ_TIME_SYNC 0x5 +#define INT_CMD_CRASH_RESET 0x7 +#define INT_CMD_PHONE_START 0x8 +#define INT_CMD_ERR_DISPLAY 0x9 +#define INT_CMD_CRASH_EXIT 0x9 +#define INT_CMD_CP_DEEP_SLEEP 0xA +#define INT_CMD_NV_REBUILDING 0xB +#define INT_CMD_EMER_DOWN 0xC +#define INT_CMD_PIF_INIT_DONE 0xD +#define INT_CMD_SILENT_NV_REBUILDING 0xE +#define INT_CMD_NORMAL_POWER_OFF 0xF + +/* AP_IDPRAM PM control command with QSC6085 */ +#define INT_CMD_IDPRAM_SUSPEND_REQ 0xD +#define INT_CMD_IDPRAM_SUSPEND_ACK 0xB +#define INT_CMD_IDPRAM_WAKEUP_START 0xE +#define INT_CMD_IDPRAM_RESUME_REQ 0xC + +#define START_FLAG 0x7F +#define END_FLAG 0x7E + +#define DP_MAGIC_DMDL 0x4445444C +#define DP_MAGIC_UMDL 0x4445444D +#define DP_DPRAM_SIZE 0x4000 +#define DP_DEFAULT_WRITE_LEN 8168 +#define DP_DEFAULT_DUMP_LEN 16128 +#define DP_DUMP_HEADER_SIZE 7 + +#define UDL_TIMEOUT (50 * HZ) +#define UDL_SEND_TIMEOUT (200 * HZ) +#define FORCE_CRASH_ACK_TIMEOUT (5 * HZ) +#define DUMP_TIMEOUT (30 * HZ) +#define DUMP_START_TIMEOUT (100 * HZ) +#define DUMP_WAIT_TIMEOUT (HZ >> 10) /* 1/1024 second */ + +#define IDPRAM_SUSPEND_REQ_TIMEOUT (50 * HZ) + +#define RES_ACK_WAIT_TIMEOUT 10 /* 10 ms */ +#define REQ_ACK_DELAY 10 /* 10 ms */ + +#ifdef DEBUG_MODEM_IF +#define MAX_RETRY_CNT 1 +#else +#define MAX_RETRY_CNT 3 +#endif + +#define MAX_SKB_TXQ_DEPTH 1024 + +struct memif_boot_map { + u32 __iomem *magic; + u8 __iomem *buff; + u32 __iomem *req; + u32 __iomem *resp; + u32 space; +}; + +struct memif_dload_map { + u32 __iomem *magic; + u8 __iomem *buff; + u32 space; +}; + +struct memif_uload_map { + u32 __iomem *magic; + u8 __iomem *cmd; + u32 cmd_size; + u8 __iomem *buff; + u32 space; +}; + +#define DP_BOOT_BUFF_OFFSET 4 +#define DP_DLOAD_MAGIC_SIZE 4 +#define DP_DLOAD_BUFF_OFFSET 4 +#define DP_ULOAD_MAGIC_SIZE 4 +#define DP_ULOAD_BUFF_OFFSET 4 +#define DP_BOOT_REQ_OFFSET 0 +#define DP_BOOT_RESP_OFFSET 8 +#define DP_MBX_SET_SIZE 4 +#define DP_MAX_PAYLOAD_SIZE 0x2000 + +enum circ_dir_type { + TX, + RX, + MAX_DIR, +}; + +enum circ_ptr_type { + HEAD, + TAIL, +}; + +static inline bool circ_valid(u32 qsize, u32 in, u32 out) +{ + if (in >= qsize) + return false; + + if (out >= qsize) + return false; + + return true; +} + +static inline u32 circ_get_space(u32 qsize, u32 in, u32 out) +{ + return (in < out) ? (out - in - 1) : (qsize + out - in - 1); +} + +static inline u32 circ_get_usage(u32 qsize, u32 in, u32 out) +{ + return (in >= out) ? (in - out) : (qsize - out + in); +} + +static inline u32 circ_new_pointer(u32 qsize, u32 p, u32 len) +{ + p += len; + return (p < qsize) ? p : (p - qsize); +} + +/** + * circ_read + * @dst: start address of the destination buffer + * @src: start address of the buffer in a circular queue + * @qsize: size of the circular queue + * @out: offset to read + * @len: length of data to be read + * + * Should be invoked after checking data length + */ +static inline void circ_read(void *dst, void *src, u32 qsize, u32 out, u32 len) +{ + unsigned len1; + + if ((out + len) <= qsize) { + /* ----- (out) (in) ----- */ + /* ----- 7f 00 00 7e ----- */ + memcpy(dst, (src + out), len); + } else { + /* (in) ----------- (out) */ + /* 00 7e ----------- 7f 00 */ + + /* 1) data start (out) ~ buffer end */ + len1 = qsize - out; + memcpy(dst, (src + out), len1); + + /* 2) buffer start ~ data end (in?) */ + memcpy((dst + len1), src, (len - len1)); + } +} + +/** + * circ_write + * @dst: pointer to the start of the circular queue + * @src: pointer to the source + * @qsize: size of the circular queue + * @in: offset to write + * @len: length of data to be written + * + * Should be invoked after checking free space + */ +static inline void circ_write(void *dst, void *src, u32 qsize, u32 in, u32 len) +{ + u32 space; + + if ((in + len) < qsize) { + /* (in) ----------- (out) */ + /* 00 7e ----------- 7f 00 */ + memcpy((dst + in), src, len); + } else { + /* ----- (out) (in) ----- */ + /* ----- 7f 00 00 7e ----- */ + + /* 1) space start (in) ~ buffer end */ + space = qsize - in; + memcpy((dst + in), src, ((len > space) ? space : len)); + + /* 2) buffer start ~ data end */ + if (len > space) + memcpy(dst, (src + space), (len - space)); + } +} + +/** + * circ_dir + * @dir: communication direction (enum circ_dir_type) + * + * Returns the direction of a circular queue + * + */ +static const inline char *circ_dir(enum circ_dir_type dir) +{ + if (dir == TX) + return "TXQ"; + else + return "RXQ"; +} + +/** + * circ_ptr + * @ptr: circular queue pointer (enum circ_ptr_type) + * + * Returns the name of a circular queue pointer + * + */ +static const inline char *circ_ptr(enum circ_ptr_type ptr) +{ + if (ptr == HEAD) + return "head"; + else + return "tail"; +} + +/** + * get_dir_str + * @dir: communication direction (enum circ_dir_type) + * + * Returns the direction of a circular queue + * + */ +static const inline char *get_dir_str(enum circ_dir_type dir) +{ + if (dir == TX) + return "AP->CP"; + else + return "CP->AP"; +} + +void memcpy16_from_io(const void *to, const void __iomem *from, u32 count); +void memcpy16_to_io(const void __iomem *to, const void *from, u32 count); +int memcmp16_to_io(const void __iomem *to, const void *from, u32 count); +void circ_read16_from_io(void *dst, void *src, u32 qsize, u32 out, u32 len); +void circ_write16_to_io(void *dst, void *src, u32 qsize, u32 in, u32 len); +int copy_circ_to_user(void __user *dst, void *src, u32 qsize, u32 out, u32 len); +int copy_user_to_circ(void *dst, void __user *src, u32 qsize, u32 in, u32 len); + +#define MAX_MEM_LOG_CNT 8192 +#define MAX_TRACE_SIZE 1024 + +struct mem_status { + /* Timestamp */ + struct timespec ts; + + /* Direction (TX or RX) */ + enum circ_dir_type dir; + + /* The status of memory interface at the time */ + u32 magic; + u32 access; + + u32 head[MAX_IPC_DEV][MAX_DIR]; + u32 tail[MAX_IPC_DEV][MAX_DIR]; + + u16 int2ap; + u16 int2cp; +}; + +struct mem_status_queue { + spinlock_t lock; + u32 in; + u32 out; + struct mem_status stat[MAX_MEM_LOG_CNT]; +}; + +struct circ_status { + u8 *buff; + u32 qsize; /* the size of a circular buffer */ + u32 in; + u32 out; + u32 size; /* the size of free space or received data */ +}; + +struct trace_data { + struct timespec ts; + enum dev_format dev; + struct circ_status circ_stat; + u8 *data; + u32 size; +}; + +struct trace_data_queue { + spinlock_t lock; + u32 in; + u32 out; + struct trace_data trd[MAX_TRACE_SIZE]; +}; + +struct mem_status *msq_get_free_slot(struct mem_status_queue *msq); +struct mem_status *msq_get_data_slot(struct mem_status_queue *msq); + +void print_mem_status(struct link_device *ld, struct mem_status *mst); +void print_circ_status(struct link_device *ld, int dev, struct mem_status *mst); +void print_ipc_trace(struct link_device *ld, int dev, struct circ_status *stat, + struct timespec *ts, u8 *buff, u32 rcvd); + +u8 *capture_mem_dump(struct link_device *ld, u8 *base, u32 size); +struct trace_data *trq_get_free_slot(struct trace_data_queue *trq); +struct trace_data *trq_get_data_slot(struct trace_data_queue *trq); + +#endif + diff --git a/drivers/misc/modem_if/modem_link_device_mipi.c b/drivers/misc/modem_if/modem_link_device_mipi.c index f2804e9..948a61c 100644 --- a/drivers/misc/modem_if/modem_link_device_mipi.c +++ b/drivers/misc/modem_if/modem_link_device_mipi.c @@ -26,7 +26,7 @@ #include <linux/semaphore.h> #include <linux/hsi_driver_if.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_mipi.h" #include "modem_utils.h" diff --git a/drivers/misc/modem_if/modem_link_device_pld.c b/drivers/misc/modem_if/modem_link_device_pld.c index b68040e..c0769ff 100644 --- a/drivers/misc/modem_if/modem_link_device_pld.c +++ b/drivers/misc/modem_if/modem_link_device_pld.c @@ -25,190 +25,76 @@ #include <linux/if_arp.h> #include <linux/platform_device.h> #include <linux/kallsyms.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_pld.h" #include "modem_utils.h" - /* ** Function prototypes for basic DPRAM operations */ -static inline void clear_intr(struct dpram_link_device *dpld); -static inline u16 recv_intr(struct dpram_link_device *dpld); -static inline void send_intr(struct dpram_link_device *dpld, u16 mask); - -static inline u16 get_magic(struct dpram_link_device *dpld); -static inline void set_magic(struct dpram_link_device *dpld, u16 val); -static inline u16 get_access(struct dpram_link_device *dpld); -static inline void set_access(struct dpram_link_device *dpld, u16 val); - -static inline u32 get_tx_head(struct dpram_link_device *dpld, int id); -static inline u32 get_tx_tail(struct dpram_link_device *dpld, int id); -static inline void set_tx_head(struct dpram_link_device *dpld, int id, u32 in); -static inline void set_tx_tail(struct dpram_link_device *dpld, int id, u32 out); -static inline u8 *get_tx_buff(struct dpram_link_device *dpld, int id); -static inline u32 get_tx_buff_size(struct dpram_link_device *dpld, int id); - -static inline u32 get_rx_head(struct dpram_link_device *dpld, int id); -static inline u32 get_rx_tail(struct dpram_link_device *dpld, int id); -static inline void set_rx_head(struct dpram_link_device *dpld, int id, u32 in); -static inline void set_rx_tail(struct dpram_link_device *dpld, int id, u32 out); -static inline u8 *get_rx_buff(struct dpram_link_device *dpld, int id); -static inline u32 get_rx_buff_size(struct dpram_link_device *dpld, int id); - -static inline u16 get_mask_req_ack(struct dpram_link_device *dpld, int id); -static inline u16 get_mask_res_ack(struct dpram_link_device *dpld, int id); -static inline u16 get_mask_send(struct dpram_link_device *dpld, int id); - -static inline bool dpram_circ_valid(u32 size, u32 in, u32 out); - -static void handle_cp_crash(struct dpram_link_device *dpld); -static int trigger_force_cp_crash(struct dpram_link_device *dpld); +static inline void clear_intr(struct pld_link_device *pld); +static inline u16 recv_intr(struct pld_link_device *pld); +static inline void send_intr(struct pld_link_device *pld, u16 mask); + +static inline u16 get_magic(struct pld_link_device *pld); +static inline void set_magic(struct pld_link_device *pld, u16 val); +static inline u16 get_access(struct pld_link_device *pld); +static inline void set_access(struct pld_link_device *pld, u16 val); + +static inline u32 get_tx_head(struct pld_link_device *pld, int id); +static inline u32 get_tx_tail(struct pld_link_device *pld, int id); +static inline void set_tx_head(struct pld_link_device *pld, int id, u32 in); +static inline void set_tx_tail(struct pld_link_device *pld, int id, u32 out); +static inline u8 *get_tx_buff(struct pld_link_device *pld, int id); +static inline u32 get_tx_buff_size(struct pld_link_device *pld, int id); + +static inline u32 get_rx_head(struct pld_link_device *pld, int id); +static inline u32 get_rx_tail(struct pld_link_device *pld, int id); +static inline void set_rx_head(struct pld_link_device *pld, int id, u32 in); +static inline void set_rx_tail(struct pld_link_device *pld, int id, u32 out); +static inline u8 *get_rx_buff(struct pld_link_device *pld, int id); +static inline u32 get_rx_buff_size(struct pld_link_device *pld, int id); + +static inline u16 get_mask_req_ack(struct pld_link_device *pld, int id); +static inline u16 get_mask_res_ack(struct pld_link_device *pld, int id); +static inline u16 get_mask_send(struct pld_link_device *pld, int id); + +static void handle_cp_crash(struct pld_link_device *pld); +static int trigger_force_cp_crash(struct pld_link_device *pld); /* ** Functions for debugging */ -static inline void log_dpram_status(struct dpram_link_device *dpld) -{ - pr_info("mif: %s: {M:0x%X A:%d} {FMT TI:%u TO:%u RI:%u RO:%u} " - "{RAW TI:%u TO:%u RI:%u RO:%u} {INT:0x%X}\n", - dpld->ld.mc->name, - get_magic(dpld), get_access(dpld), - get_tx_head(dpld, IPC_FMT), get_tx_tail(dpld, IPC_FMT), - get_rx_head(dpld, IPC_FMT), get_rx_tail(dpld, IPC_FMT), - get_tx_head(dpld, IPC_RAW), get_tx_tail(dpld, IPC_RAW), - get_rx_head(dpld, IPC_RAW), get_rx_tail(dpld, IPC_RAW), - recv_intr(dpld)); -} - -static void set_dpram_map(struct dpram_link_device *dpld, +static void set_dpram_map(struct pld_link_device *pld, struct mif_irq_map *map) { - map->magic = get_magic(dpld); - map->access = get_access(dpld); - - map->fmt_tx_in = get_tx_head(dpld, IPC_FMT); - map->fmt_tx_out = get_tx_tail(dpld, IPC_FMT); - map->fmt_rx_in = get_rx_head(dpld, IPC_FMT); - map->fmt_rx_out = get_rx_tail(dpld, IPC_FMT); - map->raw_tx_in = get_tx_head(dpld, IPC_RAW); - map->raw_tx_out = get_tx_tail(dpld, IPC_RAW); - map->raw_rx_in = get_rx_head(dpld, IPC_RAW); - map->raw_rx_out = get_rx_tail(dpld, IPC_RAW); - - map->cp2ap = recv_intr(dpld); -} - -/* -** RXB (DPRAM RX buffer) functions -*/ -static struct dpram_rxb *rxbq_create_pool(unsigned size, int count) -{ - struct dpram_rxb *rxb; - u8 *buff; - int i; - - rxb = kzalloc(sizeof(struct dpram_rxb) * count, GFP_KERNEL); - if (!rxb) { - mif_info("ERR! kzalloc rxb fail\n"); - return NULL; - } - - buff = kzalloc((size * count), GFP_KERNEL|GFP_DMA); - if (!buff) { - mif_info("ERR! kzalloc buff fail\n"); - kfree(rxb); - return NULL; - } - - for (i = 0; i < count; i++) { - rxb[i].buff = buff; - rxb[i].size = size; - buff += size; - } - - return rxb; -} - -static inline unsigned rxbq_get_page_size(unsigned len) -{ - return ((len + PAGE_SIZE - 1) >> PAGE_SHIFT) << PAGE_SHIFT; -} + map->magic = get_magic(pld); + map->access = get_access(pld); -static inline bool rxbq_empty(struct dpram_rxb_queue *rxbq) -{ - return (rxbq->in == rxbq->out) ? true : false; -} - -static inline int rxbq_free_size(struct dpram_rxb_queue *rxbq) -{ - int in = rxbq->in; - int out = rxbq->out; - int qsize = rxbq->size; - return (in < out) ? (out - in - 1) : (qsize + out - in - 1); -} - -static inline struct dpram_rxb *rxbq_get_free_rxb(struct dpram_rxb_queue *rxbq) -{ - struct dpram_rxb *rxb = NULL; - - if (likely(rxbq_free_size(rxbq) > 0)) { - rxb = &rxbq->rxb[rxbq->in]; - rxbq->in++; - if (rxbq->in >= rxbq->size) - rxbq->in -= rxbq->size; - rxb->data = rxb->buff; - } - - return rxb; -} - -static inline int rxbq_size(struct dpram_rxb_queue *rxbq) -{ - int in = rxbq->in; - int out = rxbq->out; - int qsize = rxbq->size; - return (in >= out) ? (in - out) : (qsize - out + in); -} - -static inline struct dpram_rxb *rxbq_get_data_rxb(struct dpram_rxb_queue *rxbq) -{ - struct dpram_rxb *rxb = NULL; - - if (likely(!rxbq_empty(rxbq))) { - rxb = &rxbq->rxb[rxbq->out]; - rxbq->out++; - if (rxbq->out >= rxbq->size) - rxbq->out -= rxbq->size; - } - - return rxb; -} - -static inline u8 *rxb_put(struct dpram_rxb *rxb, unsigned len) -{ - rxb->len = len; - return rxb->data; -} + map->fmt_tx_in = get_tx_head(pld, IPC_FMT); + map->fmt_tx_out = get_tx_tail(pld, IPC_FMT); + map->fmt_rx_in = get_rx_head(pld, IPC_FMT); + map->fmt_rx_out = get_rx_tail(pld, IPC_FMT); + map->raw_tx_in = get_tx_head(pld, IPC_RAW); + map->raw_tx_out = get_tx_tail(pld, IPC_RAW); + map->raw_rx_in = get_rx_head(pld, IPC_RAW); + map->raw_rx_out = get_rx_tail(pld, IPC_RAW); -static inline void rxb_clear(struct dpram_rxb *rxb) -{ - rxb->data = NULL; - rxb->len = 0; + map->cp2ap = recv_intr(pld); } /* ** DPRAM operations */ -static int dpram_register_isr(unsigned irq, irqreturn_t (*isr)(int, void*), +static int pld_register_isr(unsigned irq, irqreturn_t (*isr)(int, void*), unsigned long flag, const char *name, - struct dpram_link_device *dpld) + struct pld_link_device *pld) { int ret = 0; - ret = request_irq(irq, isr, flag, name, dpld); + ret = request_irq(irq, isr, flag, name, pld); if (ret) { mif_info("%s: ERR! request_irq fail (err %d)\n", name, ret); return ret; @@ -223,31 +109,31 @@ static int dpram_register_isr(unsigned irq, irqreturn_t (*isr)(int, void*), return 0; } -static inline void clear_intr(struct dpram_link_device *dpld) +static inline void clear_intr(struct pld_link_device *pld) { - if (dpld->dpctl->clear_intr) - dpld->dpctl->clear_intr(); + if (pld->ext_op && pld->ext_op->clear_intr) + pld->ext_op->clear_intr(pld); } -static inline u16 recv_intr(struct dpram_link_device *dpld) +static inline u16 recv_intr(struct pld_link_device *pld) { u16 val1 = 0, val2 = 0, cnt = 3; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&dpld->mbx2ap[0]), - dpld->address_buffer); - val1 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->mbx2ap[0]), + pld->address_buffer); + val1 = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&dpld->mbx2ap[0]), - dpld->address_buffer); - val2 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->mbx2ap[0]), + pld->address_buffer); + val2 = ioread16(pld->base); if (likely(val1 == val2)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } @@ -255,31 +141,31 @@ static inline u16 recv_intr(struct dpram_link_device *dpld) } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } -static inline void send_intr(struct dpram_link_device *dpld, u16 mask) +static inline void send_intr(struct pld_link_device *pld, u16 mask) { int cnt = 3; u32 val = 0; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); - iowrite16(PLD_ADDR_MASK(&dpld->mbx2cp[0]), - dpld->address_buffer); - iowrite16((u16)mask, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->mbx2cp[0]), + pld->address_buffer); + iowrite16((u16)mask, pld->base); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&dpld->mbx2cp[0]), - dpld->address_buffer); - val = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->mbx2cp[0]), + pld->address_buffer); + val = ioread16(pld->base); if (likely(val == mask)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } @@ -287,35 +173,35 @@ static inline void send_intr(struct dpram_link_device *dpld, u16 mask) udelay(100); /* Write head value again */ - iowrite16(PLD_ADDR_MASK(&dpld->mbx2cp[0]), - dpld->address_buffer); - iowrite16((u16)mask, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->mbx2cp[0]), + pld->address_buffer); + iowrite16((u16)mask, pld->base); } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } -static inline u16 get_magic(struct dpram_link_device *dpld) +static inline u16 get_magic(struct pld_link_device *pld) { u16 val1 = 0, val2 = 0, cnt = 3; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&dpld->magic_ap2cp[0]), - dpld->address_buffer); - val1 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->magic_ap2cp[0]), + pld->address_buffer); + val1 = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&dpld->magic_ap2cp[0]), - dpld->address_buffer); - val2 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->magic_ap2cp[0]), + pld->address_buffer); + val2 = ioread16(pld->base); if (likely(val1 == val2)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } @@ -324,31 +210,31 @@ static inline u16 get_magic(struct dpram_link_device *dpld) } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } -static inline void set_magic(struct dpram_link_device *dpld, u16 in) +static inline void set_magic(struct pld_link_device *pld, u16 in) { int cnt = 3; u32 val = 0; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); - iowrite16(PLD_ADDR_MASK(&dpld->magic_ap2cp[0]), - dpld->address_buffer); - iowrite16((u16)in, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->magic_ap2cp[0]), + pld->address_buffer); + iowrite16((u16)in, pld->base); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&dpld->magic_ap2cp[0]), - dpld->address_buffer); - val = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->magic_ap2cp[0]), + pld->address_buffer); + val = ioread16(pld->base); if (likely(val == in)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } @@ -356,34 +242,34 @@ static inline void set_magic(struct dpram_link_device *dpld, u16 in) udelay(100); /* Write head value again */ - iowrite16(PLD_ADDR_MASK(&dpld->magic_ap2cp[0]), - dpld->address_buffer); - iowrite16((u16)in, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->magic_ap2cp[0]), + pld->address_buffer); + iowrite16((u16)in, pld->base); } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } -static inline u16 get_access(struct dpram_link_device *dpld) +static inline u16 get_access(struct pld_link_device *pld) { u16 val1 = 0, val2 = 0, cnt = 3; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&dpld->access_ap2cp[0]), - dpld->address_buffer); - val1 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->access_ap2cp[0]), + pld->address_buffer); + val1 = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&dpld->access_ap2cp[0]), - dpld->address_buffer); - val2 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->access_ap2cp[0]), + pld->address_buffer); + val2 = ioread16(pld->base); if (likely(val1 == val2)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } @@ -392,31 +278,31 @@ static inline u16 get_access(struct dpram_link_device *dpld) } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } -static inline void set_access(struct dpram_link_device *dpld, u16 in) +static inline void set_access(struct pld_link_device *pld, u16 in) { int cnt = 3; u32 val = 0; unsigned long int flags; - iowrite16(PLD_ADDR_MASK(&dpld->access_ap2cp[0]), - dpld->address_buffer); - iowrite16((u16)in, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->access_ap2cp[0]), + pld->address_buffer); + iowrite16((u16)in, pld->base); - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&dpld->access_ap2cp[0]), - dpld->address_buffer); - val = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->access_ap2cp[0]), + pld->address_buffer); + val = ioread16(pld->base); if (likely(val == in)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } @@ -424,34 +310,34 @@ static inline void set_access(struct dpram_link_device *dpld, u16 in) udelay(100); /* Write head value again */ - iowrite16(PLD_ADDR_MASK(&dpld->access_ap2cp[0]), - dpld->address_buffer); - iowrite16((u16)in, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&pld->access_ap2cp[0]), + pld->address_buffer); + iowrite16((u16)in, pld->base); } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } -static inline u32 get_tx_head(struct dpram_link_device *dpld, int id) +static inline u32 get_tx_head(struct pld_link_device *pld, int id) { u16 val1 = 0, val2 = 0, cnt = 3; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->txq.head)[0]), - dpld->address_buffer); - val1 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->txq.head)[0]), + pld->address_buffer); + val1 = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->txq.head)[0]), - dpld->address_buffer); - val2 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->txq.head)[0]), + pld->address_buffer); + val2 = ioread16(pld->base); if (likely(val1 == val2)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } @@ -461,29 +347,29 @@ static inline u32 get_tx_head(struct dpram_link_device *dpld, int id) } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } -static inline u32 get_tx_tail(struct dpram_link_device *dpld, int id) +static inline u32 get_tx_tail(struct pld_link_device *pld, int id) { u16 val1 = 0, val2 = 0, cnt = 3; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->txq.tail)[0]), - dpld->address_buffer); - val1 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->txq.tail)[0]), + pld->address_buffer); + val1 = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->txq.tail)[0]), - dpld->address_buffer); - val2 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->txq.tail)[0]), + pld->address_buffer); + val2 = ioread16(pld->base); if (likely(val1 == val2)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } @@ -493,30 +379,30 @@ static inline u32 get_tx_tail(struct dpram_link_device *dpld, int id) } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } -static inline void set_tx_head(struct dpram_link_device *dpld, int id, u32 in) +static inline void set_tx_head(struct pld_link_device *pld, int id, u32 in) { int cnt = 3; u32 val = 0; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->txq.head)[0]), - dpld->address_buffer); - iowrite16((u16)in, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->txq.head)[0]), + pld->address_buffer); + iowrite16((u16)in, pld->base); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->txq.head)[0]), - dpld->address_buffer); - val = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->txq.head)[0]), + pld->address_buffer); + val = ioread16(pld->base); if (likely(val == in)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } @@ -525,49 +411,49 @@ static inline void set_tx_head(struct dpram_link_device *dpld, int id, u32 in) udelay(100); /* Write head value again */ - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->txq.head)[0]), - dpld->address_buffer); - iowrite16((u16)in, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->txq.head)[0]), + pld->address_buffer); + iowrite16((u16)in, pld->base); } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } -static inline void set_tx_tail(struct dpram_link_device *dpld, int id, u32 out) +static inline void set_tx_tail(struct pld_link_device *pld, int id, u32 out) { return; } -static inline u8 *get_tx_buff(struct dpram_link_device *dpld, int id) +static inline u8 *get_tx_buff(struct pld_link_device *pld, int id) { - return dpld->dev[id]->txq.buff; + return pld->dev[id]->txq.buff; } -static inline u32 get_tx_buff_size(struct dpram_link_device *dpld, int id) +static inline u32 get_tx_buff_size(struct pld_link_device *pld, int id) { - return dpld->dev[id]->txq.size; + return pld->dev[id]->txq.size; } -static inline u32 get_rx_head(struct dpram_link_device *dpld, int id) +static inline u32 get_rx_head(struct pld_link_device *pld, int id) { u16 val1 = 0, val2 = 0, cnt = 3; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->rxq.head)[0]), - dpld->address_buffer); - val1 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->rxq.head)[0]), + pld->address_buffer); + val1 = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->rxq.head)[0]), - dpld->address_buffer); - val2 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->rxq.head)[0]), + pld->address_buffer); + val2 = ioread16(pld->base); if (likely(val1 == val2)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } @@ -577,29 +463,29 @@ static inline u32 get_rx_head(struct dpram_link_device *dpld, int id) } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } -static inline u32 get_rx_tail(struct dpram_link_device *dpld, int id) +static inline u32 get_rx_tail(struct pld_link_device *pld, int id) { u16 val1 = 0, val2 = 0, cnt = 3; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); do { /* Check head value written */ - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->rxq.tail)[0]), - dpld->address_buffer); - val1 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->rxq.tail)[0]), + pld->address_buffer); + val1 = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->rxq.tail)[0]), - dpld->address_buffer); - val2 = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->rxq.tail)[0]), + pld->address_buffer); + val2 = ioread16(pld->base); if (likely(val1 == val2)) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } @@ -609,35 +495,35 @@ static inline u32 get_rx_tail(struct dpram_link_device *dpld, int id) } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return val1; } -static inline void set_rx_head(struct dpram_link_device *dpld, int id, u32 in) +static inline void set_rx_head(struct pld_link_device *pld, int id, u32 in) { return; } -static inline void set_rx_tail(struct dpram_link_device *dpld, int id, u32 out) +static inline void set_rx_tail(struct pld_link_device *pld, int id, u32 out) { int cnt = 3; u32 val = 0; unsigned long int flags; - spin_lock_irqsave(&dpld->pld_lock, flags); + spin_lock_irqsave(&pld->pld_lock, flags); - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->rxq.tail)[0]), - dpld->address_buffer); - iowrite16((u16)out, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->rxq.tail)[0]), + pld->address_buffer); + iowrite16((u16)out, pld->base); do { /* Check tail value written */ - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->rxq.tail)[0]), - dpld->address_buffer); - val = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->rxq.tail)[0]), + pld->address_buffer); + val = ioread16(pld->base); if (val == out) { - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } @@ -646,71 +532,60 @@ static inline void set_rx_tail(struct dpram_link_device *dpld, int id, u32 out) udelay(100); /* Write tail value again */ - iowrite16(PLD_ADDR_MASK(&(dpld->dev[id]->rxq.tail)[0]), - dpld->address_buffer); - iowrite16((u16)out, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&(pld->dev[id]->rxq.tail)[0]), + pld->address_buffer); + iowrite16((u16)out, pld->base); } while (cnt--); - spin_unlock_irqrestore(&dpld->pld_lock, flags); + spin_unlock_irqrestore(&pld->pld_lock, flags); return; } -static inline u8 *get_rx_buff(struct dpram_link_device *dpld, int id) +static inline u8 *get_rx_buff(struct pld_link_device *pld, int id) { - return dpld->dev[id]->rxq.buff; + return pld->dev[id]->rxq.buff; } -static inline u32 get_rx_buff_size(struct dpram_link_device *dpld, int id) +static inline u32 get_rx_buff_size(struct pld_link_device *pld, int id) { - return dpld->dev[id]->rxq.size; + return pld->dev[id]->rxq.size; } -static inline u16 get_mask_req_ack(struct dpram_link_device *dpld, int id) +static inline u16 get_mask_req_ack(struct pld_link_device *pld, int id) { - return dpld->dev[id]->mask_req_ack; + return pld->dev[id]->mask_req_ack; } -static inline u16 get_mask_res_ack(struct dpram_link_device *dpld, int id) +static inline u16 get_mask_res_ack(struct pld_link_device *pld, int id) { - return dpld->dev[id]->mask_res_ack; + return pld->dev[id]->mask_res_ack; } -static inline u16 get_mask_send(struct dpram_link_device *dpld, int id) +static inline u16 get_mask_send(struct pld_link_device *pld, int id) { - return dpld->dev[id]->mask_send; -} - -static inline bool dpram_circ_valid(u32 size, u32 in, u32 out) -{ - if (in >= size) - return false; - - if (out >= size) - return false; - - return true; + return pld->dev[id]->mask_send; } /* Get free space in the TXQ as well as in & out pointers */ -static inline int dpram_get_txq_space(struct dpram_link_device *dpld, int dev, - u32 qsize, u32 *in, u32 *out) +static inline int get_txq_space(struct pld_link_device *pld, int dev, u32 qsize, + u32 *in, u32 *out) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; int cnt = 3; u32 head; u32 tail; int space; do { - head = get_tx_head(dpld, dev); - tail = get_tx_tail(dpld, dev); + head = get_tx_head(pld, dev); + tail = get_tx_tail(pld, dev); space = (head < tail) ? (tail - head - 1) : (qsize + tail - head - 1); mif_debug("%s: %s_TXQ qsize[%u] in[%u] out[%u] space[%u]\n", ld->name, get_dev_name(dev), qsize, head, tail, space); - if (dpram_circ_valid(qsize, head, tail)) { + if (circ_valid(qsize, head, tail)) { *in = head; *out = tail; return space; @@ -729,27 +604,27 @@ static inline int dpram_get_txq_space(struct dpram_link_device *dpld, int dev, return -EINVAL; } -static void dpram_reset_tx_circ(struct dpram_link_device *dpld, int dev) +static void reset_tx_circ(struct pld_link_device *pld, int dev) { - set_tx_head(dpld, dev, 0); - set_tx_tail(dpld, dev, 0); + set_tx_head(pld, dev, 0); + set_tx_tail(pld, dev, 0); if (dev == IPC_FMT) - trigger_force_cp_crash(dpld); + trigger_force_cp_crash(pld); } /* Get data size in the RXQ as well as in & out pointers */ -static inline int dpram_get_rxq_rcvd(struct dpram_link_device *dpld, int dev, - u32 qsize, u32 *in, u32 *out) +static inline int get_rxq_rcvd(struct pld_link_device *pld, int dev, u32 qsize, + u32 *in, u32 *out) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; int cnt = 3; u32 head; u32 tail; u32 rcvd; do { - head = get_rx_head(dpld, dev); - tail = get_rx_tail(dpld, dev); + head = get_rx_head(pld, dev); + tail = get_rx_tail(pld, dev); if (head == tail) { *in = head; *out = tail; @@ -760,7 +635,7 @@ static inline int dpram_get_rxq_rcvd(struct dpram_link_device *dpld, int dev, mif_info("%s: %s_RXQ qsize[%u] in[%u] out[%u] rcvd[%u]\n", ld->name, get_dev_name(dev), qsize, head, tail, rcvd); - if (dpram_circ_valid(qsize, head, tail)) { + if (circ_valid(qsize, head, tail)) { *in = head; *out = tail; return rcvd; @@ -779,54 +654,20 @@ static inline int dpram_get_rxq_rcvd(struct dpram_link_device *dpld, int dev, return -EINVAL; } -static void dpram_reset_rx_circ(struct dpram_link_device *dpld, int dev) +static void reset_rx_circ(struct pld_link_device *pld, int dev) { - set_rx_head(dpld, dev, 0); - set_rx_tail(dpld, dev, 0); + set_rx_head(pld, dev, 0); + set_rx_tail(pld, dev, 0); if (dev == IPC_FMT) - trigger_force_cp_crash(dpld); + trigger_force_cp_crash(pld); } -/* -** CAUTION : dpram_allow_sleep() MUST be invoked after dpram_wake_up() success -*/ -static int dpram_wake_up(struct dpram_link_device *dpld) +static int check_access(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; - - if (!dpld->dpctl->wakeup) - return 0; - - if (dpld->dpctl->wakeup() < 0) { - mif_err("%s: ERR! <%pf> DPRAM wakeup fail\n", - ld->name, __builtin_return_address(0)); - return -EACCES; - } - - atomic_inc(&dpld->accessing); - return 0; -} - -static void dpram_allow_sleep(struct dpram_link_device *dpld) -{ - struct link_device *ld = &dpld->ld; - - if (!dpld->dpctl->sleep) - return; - - if (atomic_dec_return(&dpld->accessing) <= 0) { - dpld->dpctl->sleep(); - atomic_set(&dpld->accessing, 0); - mif_debug("%s: DPRAM sleep possible\n", ld->name); - } -} - -static int dpram_check_access(struct dpram_link_device *dpld) -{ - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; int i; - u16 magic = get_magic(dpld); - u16 access = get_access(dpld); + u16 magic = get_magic(pld); + u16 access = get_access(pld); if (likely(magic == DPRAM_MAGIC_CODE && access == 1)) return 0; @@ -836,8 +677,8 @@ static int dpram_check_access(struct dpram_link_device *dpld) ld->name, magic, access, i); udelay(100); - magic = get_magic(dpld); - access = get_access(dpld); + magic = get_magic(pld); + access = get_access(pld); if (likely(magic == DPRAM_MAGIC_CODE && access == 1)) return 0; } @@ -846,9 +687,9 @@ static int dpram_check_access(struct dpram_link_device *dpld) return -EACCES; } -static bool dpram_ipc_active(struct dpram_link_device *dpld) +static bool ipc_active(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; /* Check DPRAM mode */ if (ld->mode != LINK_MODE_IPC) { @@ -857,8 +698,8 @@ static bool dpram_ipc_active(struct dpram_link_device *dpld) return false; } - if (dpram_check_access(dpld) < 0) { - mif_info("%s: ERR! <%pf> dpram_check_access fail\n", + if (check_access(pld) < 0) { + mif_info("%s: ERR! <%pf> check_access fail\n", ld->name, __builtin_return_address(0)); return false; } @@ -866,67 +707,72 @@ static bool dpram_ipc_active(struct dpram_link_device *dpld) return true; } -static void dpram_ipc_write(struct dpram_link_device *dpld, int dev, +static void pld_ipc_write(struct pld_link_device *pld, int dev, u32 qsize, u32 in, u32 out, struct sk_buff *skb) { - struct link_device *ld = &dpld->ld; - u8 __iomem *buff = get_tx_buff(dpld, dev); + struct link_device *ld = &pld->ld; + u8 __iomem *buff = get_tx_buff(pld, dev); u8 *src = skb->data; u32 len = skb->len; u32 inp; struct mif_irq_map map; + unsigned long int flags; + + spin_lock_irqsave(&pld->pld_lock, flags); if (in < out) { /* +++++++++ in ---------- out ++++++++++ */ - iowrite16(PLD_ADDR_MASK(&(buff+in)[0]), dpld->address_buffer); - memcpy(dpld->dp_base, src, len); + iowrite16(PLD_ADDR_MASK(&(buff+in)[0]), pld->address_buffer); + memcpy(pld->base, src, len); } else { /* ------ out +++++++++++ in ------------ */ u32 space = qsize - in; /* 1) in -> buffer end */ - iowrite16(PLD_ADDR_MASK(&(buff+in)[0]), dpld->address_buffer); - memcpy(dpld->dp_base, src, ((len > space) ? space : len)); + iowrite16(PLD_ADDR_MASK(&(buff+in)[0]), pld->address_buffer); + memcpy(pld->base, src, ((len > space) ? space : len)); if (len > space) { iowrite16(PLD_ADDR_MASK(&buff[0]), - dpld->address_buffer); - memcpy(dpld->dp_base, (src+space), (len-space)); + pld->address_buffer); + memcpy(pld->base, (src+space), (len-space)); } } + spin_unlock_irqrestore(&pld->pld_lock, flags); + /* update new in pointer */ inp = in + len; if (inp >= qsize) inp -= qsize; - set_tx_head(dpld, dev, inp); + set_tx_head(pld, dev, inp); if (dev == IPC_FMT) { - set_dpram_map(dpld, &map); + set_dpram_map(pld, &map); mif_irq_log(ld->mc->msd, map, "ipc_write", sizeof("ipc_write")); mif_ipc_log(MIF_IPC_AP2CP, ld->mc->msd, skb->data, skb->len); } } -static int dpram_try_ipc_tx(struct dpram_link_device *dpld, int dev) +static int pld_try_ipc_tx(struct pld_link_device *pld, int dev) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; struct sk_buff_head *txq = ld->skb_txq[dev]; struct sk_buff *skb; unsigned long int flags; - u32 qsize = get_tx_buff_size(dpld, dev); + u32 qsize = get_tx_buff_size(pld, dev); u32 in; u32 out; int space; int copied = 0; - spin_lock_irqsave(&dpld->tx_rx_lock, flags); + spin_lock_irqsave(&pld->tx_rx_lock, flags); while (1) { - space = dpram_get_txq_space(dpld, dev, qsize, &in, &out); + space = get_txq_space(pld, dev, qsize, &in, &out); if (unlikely(space < 0)) { - spin_unlock_irqrestore(&dpld->tx_rx_lock, flags); - dpram_reset_tx_circ(dpld, dev); + spin_unlock_irqrestore(&pld->tx_rx_lock, flags); + reset_tx_circ(pld, dev); return space; } @@ -935,9 +781,9 @@ static int dpram_try_ipc_tx(struct dpram_link_device *dpld, int dev) break; if (unlikely(space < skb->len)) { - atomic_set(&dpld->res_required[dev], 1); + atomic_set(&pld->res_required[dev], 1); skb_queue_head(txq, skb); - spin_unlock_irqrestore(&dpld->tx_rx_lock, flags); + spin_unlock_irqrestore(&pld->tx_rx_lock, flags); mif_info("%s: %s " "qsize[%u] in[%u] out[%u] free[%u] < len[%u]\n", ld->name, get_dev_name(dev), @@ -946,30 +792,30 @@ static int dpram_try_ipc_tx(struct dpram_link_device *dpld, int dev) } /* TX if there is enough room in the queue */ - dpram_ipc_write(dpld, dev, qsize, in, out, skb); + pld_ipc_write(pld, dev, qsize, in, out, skb); copied += skb->len; dev_kfree_skb_any(skb); } - spin_unlock_irqrestore(&dpld->tx_rx_lock, flags); + spin_unlock_irqrestore(&pld->tx_rx_lock, flags); return copied; } -static void dpram_ipc_rx_task(unsigned long data) +static void pld_ipc_rx_task(unsigned long data) { - struct dpram_link_device *dpld = (struct dpram_link_device *)data; - struct link_device *ld = &dpld->ld; + struct pld_link_device *pld = (struct pld_link_device *)data; + struct link_device *ld = &pld->ld; struct io_device *iod; - struct dpram_rxb *rxb; + struct mif_rxb *rxb; unsigned qlen; int i; - for (i = 0; i < dpld->max_ipc_dev; i++) { - iod = dpld->iod[i]; - qlen = rxbq_size(&dpld->rxbq[i]); + for (i = 0; i < ld->max_ipc_dev; i++) { + iod = pld->iod[i]; + qlen = rxbq_size(&pld->rxbq[i]); while (qlen > 0) { - rxb = rxbq_get_data_rxb(&dpld->rxbq[i]); + rxb = rxbq_get_data_rxb(&pld->rxbq[i]); iod->recv(iod, ld, rxb->data, rxb->len); rxb_clear(rxb); qlen--; @@ -977,36 +823,39 @@ static void dpram_ipc_rx_task(unsigned long data) } } -static void dpram_ipc_read(struct dpram_link_device *dpld, int dev, u8 *dst, +static void pld_ipc_read(struct pld_link_device *pld, int dev, u8 *dst, u8 __iomem *src, u32 out, u32 len, u32 qsize) { u8 *ori_det = dst; unsigned long flags; + spin_lock_irqsave(&pld->pld_lock, flags); + if ((out + len) <= qsize) { /* ----- (out) (in) ----- */ /* ----- 7f 00 00 7e ----- */ - iowrite16(PLD_ADDR_MASK(&(src+out)[0]), dpld->address_buffer); - memcpy(dst, dpld->dp_base, len); + iowrite16(PLD_ADDR_MASK(&(src+out)[0]), pld->address_buffer); + memcpy(dst, pld->base, len); } else { /* (in) ----------- (out) */ /* 00 7e ----------- 7f 00 */ unsigned len1 = qsize - out; /* 1) out -> buffer end */ - iowrite16(PLD_ADDR_MASK(&(src+out)[0]), dpld->address_buffer); - memcpy(dst, dpld->dp_base, len1); + iowrite16(PLD_ADDR_MASK(&(src+out)[0]), pld->address_buffer); + memcpy(dst, pld->base, len1); /* 2) buffer start -> in */ dst += len1; - iowrite16(PLD_ADDR_MASK(&src[0]), dpld->address_buffer); - memcpy(dst, dpld->dp_base, (len - len1)); + iowrite16(PLD_ADDR_MASK(&src[0]), pld->address_buffer); + memcpy(dst, pld->base, (len - len1)); } - if (dpld->ld.mode == LINK_MODE_IPC && ori_det[0] != 0x7F) { + spin_unlock_irqrestore(&pld->pld_lock, flags); + if (pld->ld.mode == LINK_MODE_IPC && ori_det[0] != 0x7F) { mif_info("ipc read error!! in[%d], out[%d]\n", - get_rx_head(dpld, dev), - get_rx_tail(dpld, dev)); + get_rx_head(pld, dev), + get_rx_tail(pld, dev)); } } @@ -1016,190 +865,106 @@ static void dpram_ipc_read(struct dpram_link_device *dpld, int dev, u8 *dst, ret == 0 : no data ret > 0 : valid data */ -static int dpram_ipc_recv_data_with_rxb(struct dpram_link_device *dpld, int dev) +static int pld_ipc_recv_data_with_rxb(struct pld_link_device *pld, int dev) { - struct link_device *ld = &dpld->ld; - struct dpram_rxb *rxb; - u8 __iomem *src = get_rx_buff(dpld, dev); - u32 qsize = get_rx_buff_size(dpld, dev); + struct link_device *ld = &pld->ld; + struct mif_rxb *rxb; + u8 __iomem *src = get_rx_buff(pld, dev); + u32 qsize = get_rx_buff_size(pld, dev); u32 in; u32 out; u32 rcvd; struct mif_irq_map map; unsigned long int flags; - spin_lock_irqsave(&dpld->tx_rx_lock, flags); + spin_lock_irqsave(&pld->tx_rx_lock, flags); - rcvd = dpram_get_rxq_rcvd(dpld, dev, qsize, &in, &out); + rcvd = get_rxq_rcvd(pld, dev, qsize, &in, &out); if (rcvd <= 0) { - spin_unlock_irqrestore(&dpld->tx_rx_lock, flags); + spin_unlock_irqrestore(&pld->tx_rx_lock, flags); return rcvd; } if (dev == IPC_FMT) { - set_dpram_map(dpld, &map); + set_dpram_map(pld, &map); mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv")); } /* Allocate an rxb */ - rxb = rxbq_get_free_rxb(&dpld->rxbq[dev]); + rxb = rxbq_get_free_rxb(&pld->rxbq[dev]); if (!rxb) { mif_info("%s: ERR! %s rxbq_get_free_rxb fail\n", ld->name, get_dev_name(dev)); - spin_unlock_irqrestore(&dpld->tx_rx_lock, flags); + spin_unlock_irqrestore(&pld->tx_rx_lock, flags); return -ENOMEM; } /* Read data from each DPRAM buffer */ - dpram_ipc_read(dpld, dev, rxb_put(rxb, rcvd), src, out, rcvd, qsize); + pld_ipc_read(pld, dev, rxb_put(rxb, rcvd), src, out, rcvd, qsize); /* Calculate and set new out */ out += rcvd; if (out >= qsize) out -= qsize; - set_rx_tail(dpld, dev, out); - - spin_unlock_irqrestore(&dpld->tx_rx_lock, flags); - return rcvd; -} - -/* - ret < 0 : error - ret == 0 : no data - ret > 0 : valid data -*/ -static int dpram_ipc_recv_data_with_skb(struct dpram_link_device *dpld, int dev) -{ - struct link_device *ld = &dpld->ld; - struct io_device *iod = dpld->iod[dev]; - struct sk_buff *skb; - u8 __iomem *src = get_rx_buff(dpld, dev); - u32 qsize = get_rx_buff_size(dpld, dev); - u32 in; - u32 out; - u32 rcvd; - int rest; - u8 *frm; - u8 *dst; - unsigned int len; - unsigned int pad; - unsigned int tot; - struct mif_irq_map map; - - rcvd = dpram_get_rxq_rcvd(dpld, dev, qsize, &in, &out); - if (rcvd <= 0) - return rcvd; - - if (dev == IPC_FMT) { - set_dpram_map(dpld, &map); - mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv")); - } - - rest = rcvd; - while (rest > 0) { - frm = src + out; - if (unlikely(!sipc5_start_valid(frm[0]))) { - mif_err("%s: ERR! %s invalid start 0x%02X\n", - ld->name, get_dev_name(dev), frm[0]); - skb_queue_purge(&dpld->skb_rxq[dev]); - return -EBADMSG; - } - - len = sipc5_get_frame_sz16(frm); - if (unlikely(len > rest)) { - mif_err("%s: ERR! %s len %d > rest %d\n", - ld->name, get_dev_name(dev), len, rest); - skb_queue_purge(&dpld->skb_rxq[dev]); - return -EBADMSG; - } - - pad = sipc5_calc_padding_size(len); - tot = len + pad; - - /* Allocate an skb */ - skb = dev_alloc_skb(tot); - if (!skb) { - mif_err("%s: ERR! %s dev_alloc_skb fail\n", - ld->name, get_dev_name(dev)); - return -ENOMEM; - } - - /* Read data from each DPRAM buffer */ - dst = skb_put(skb, tot); - dpram_ipc_read(dpld, dev, dst, src, out, tot, qsize); - skb_trim(skb, len); - iod->recv_skb(iod, ld, skb); - - /* Calculate and set new out */ - rest -= tot; - out += tot; - if (out >= qsize) - out -= qsize; - } - - set_rx_tail(dpld, dev, out); + set_rx_tail(pld, dev, out); + spin_unlock_irqrestore(&pld->tx_rx_lock, flags); return rcvd; } -static void non_command_handler(struct dpram_link_device *dpld, u16 non_cmd) +static void non_command_handler(struct pld_link_device *pld, u16 non_cmd) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; int i = 0; int ret = 0; - u16 tx_mask = 0; + u16 mask = 0; - if (!dpram_ipc_active(dpld)) + if (!ipc_active(pld)) return; /* Read data from DPRAM */ - for (i = 0; i < dpld->max_ipc_dev; i++) { - if (dpld->use_skb) - ret = dpram_ipc_recv_data_with_skb(dpld, i); - else - ret = dpram_ipc_recv_data_with_rxb(dpld, i); + for (i = 0; i < ld->max_ipc_dev; i++) { + ret = pld_ipc_recv_data_with_rxb(pld, i); if (ret < 0) - dpram_reset_rx_circ(dpld, i); + reset_rx_circ(pld, i); /* Check and process REQ_ACK (at this time, in == out) */ - if (non_cmd & get_mask_req_ack(dpld, i)) { + if (non_cmd & get_mask_req_ack(pld, i)) { mif_debug("%s: send %s_RES_ACK\n", ld->name, get_dev_name(i)); - tx_mask |= get_mask_res_ack(dpld, i); + mask |= get_mask_res_ack(pld, i); } } - if (!dpld->use_skb) { - /* Schedule soft IRQ for RX */ - tasklet_hi_schedule(&dpld->rx_tsk); - } + /* Schedule soft IRQ for RX */ + tasklet_hi_schedule(&pld->rx_tsk); /* Try TX via DPRAM */ - for (i = 0; i < dpld->max_ipc_dev; i++) { - if (atomic_read(&dpld->res_required[i]) > 0) { - ret = dpram_try_ipc_tx(dpld, i); + for (i = 0; i < ld->max_ipc_dev; i++) { + if (atomic_read(&pld->res_required[i]) > 0) { + ret = pld_try_ipc_tx(pld, i); if (ret > 0) { - atomic_set(&dpld->res_required[i], 0); - tx_mask |= get_mask_send(dpld, i); + atomic_set(&pld->res_required[i], 0); + mask |= get_mask_send(pld, i); } else if (ret == -ENOSPC) { - tx_mask |= get_mask_req_ack(dpld, i); + mask |= get_mask_req_ack(pld, i); } } } - if (tx_mask) { - send_intr(dpld, INT_NON_CMD(tx_mask)); - mif_debug("%s: send intr 0x%04X\n", ld->name, tx_mask); + if (mask) { + send_intr(pld, INT_NON_CMD(mask)); + mif_debug("%s: send intr 0x%04X\n", ld->name, mask); } } -static void handle_cp_crash(struct dpram_link_device *dpld) +static void handle_cp_crash(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; struct io_device *iod; int i; - for (i = 0; i < dpld->max_ipc_dev; i++) { + for (i = 0; i < ld->max_ipc_dev; i++) { mif_info("%s: purging %s_skb_txq\b", ld->name, get_dev_name(i)); skb_queue_purge(ld->skb_txq[i]); } @@ -1210,27 +975,27 @@ static void handle_cp_crash(struct dpram_link_device *dpld) iod = link_get_iod_with_format(ld, IPC_BOOT); iod->modem_state_changed(iod, STATE_CRASH_EXIT); - iod = link_get_iod_with_channel(ld, PS_DATA_CH_0); + iod = link_get_iod_with_channel(ld, RMNET0_CH_ID); if (iod) iodevs_for_each(iod->msd, iodev_netif_stop, 0); } static void handle_no_crash_ack(unsigned long arg) { - struct dpram_link_device *dpld = (struct dpram_link_device *)arg; - struct link_device *ld = &dpld->ld; + struct pld_link_device *pld = (struct pld_link_device *)arg; + struct link_device *ld = &pld->ld; mif_err("%s: ERR! No CRASH_EXIT ACK from CP\n", ld->mc->name); - if (!wake_lock_active(&dpld->wlock)) - wake_lock(&dpld->wlock); + if (!wake_lock_active(&pld->wlock)) + wake_lock(&pld->wlock); - handle_cp_crash(dpld); + handle_cp_crash(pld); } -static int trigger_force_cp_crash(struct dpram_link_device *dpld) +static int trigger_force_cp_crash(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; if (ld->mode == LINK_MODE_ULOAD) { mif_err("%s: CP crash is already in progress\n", ld->mc->name); @@ -1240,79 +1005,72 @@ static int trigger_force_cp_crash(struct dpram_link_device *dpld) ld->mode = LINK_MODE_ULOAD; mif_err("%s: called by %pf\n", ld->name, __builtin_return_address(0)); - dpram_wake_up(dpld); - - send_intr(dpld, INT_CMD(INT_CMD_CRASH_EXIT)); + send_intr(pld, INT_CMD(INT_CMD_CRASH_EXIT)); - mif_add_timer(&dpld->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, - handle_no_crash_ack, (unsigned long)dpld); + mif_add_timer(&pld->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, + handle_no_crash_ack, (unsigned long)pld); return 0; } -static int dpram_init_ipc(struct dpram_link_device *dpld) +static int pld_init_ipc(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; int i; if (ld->mode == LINK_MODE_IPC && - get_magic(dpld) == DPRAM_MAGIC_CODE && - get_access(dpld) == 1) + get_magic(pld) == DPRAM_MAGIC_CODE && + get_access(pld) == 1) mif_info("%s: IPC already initialized\n", ld->name); /* Clear pointers in every circular queue */ - for (i = 0; i < dpld->max_ipc_dev; i++) { - set_tx_head(dpld, i, 0); - set_tx_tail(dpld, i, 0); - set_rx_head(dpld, i, 0); - set_rx_tail(dpld, i, 0); + for (i = 0; i < ld->max_ipc_dev; i++) { + set_tx_head(pld, i, 0); + set_tx_tail(pld, i, 0); + set_rx_head(pld, i, 0); + set_rx_tail(pld, i, 0); } /* Initialize variables for efficient TX/RX processing */ - for (i = 0; i < dpld->max_ipc_dev; i++) - dpld->iod[i] = link_get_iod_with_format(ld, i); - dpld->iod[IPC_RAW] = link_get_iod_with_format(ld, IPC_MULTI_RAW); + for (i = 0; i < ld->max_ipc_dev; i++) + pld->iod[i] = link_get_iod_with_format(ld, i); + pld->iod[IPC_RAW] = link_get_iod_with_format(ld, IPC_MULTI_RAW); - if (dpld->iod[IPC_RAW]->recv_skb) - dpld->use_skb = true; + for (i = 0; i < ld->max_ipc_dev; i++) + atomic_set(&pld->res_required[i], 0); - for (i = 0; i < dpld->max_ipc_dev; i++) { - atomic_set(&dpld->res_required[i], 0); - skb_queue_purge(&dpld->skb_rxq[i]); - } - - spin_lock_init(&dpld->tx_rx_lock); + spin_lock_init(&pld->tx_rx_lock); /* Enable IPC */ - atomic_set(&dpld->accessing, 0); + atomic_set(&pld->accessing, 0); - set_magic(dpld, DPRAM_MAGIC_CODE); - set_access(dpld, 1); - if (get_magic(dpld) != DPRAM_MAGIC_CODE || get_access(dpld) != 1) + set_magic(pld, DPRAM_MAGIC_CODE); + set_access(pld, 1); + if (get_magic(pld) != DPRAM_MAGIC_CODE || get_access(pld) != 1) return -EACCES; ld->mode = LINK_MODE_IPC; - if (wake_lock_active(&dpld->wlock)) - wake_unlock(&dpld->wlock); + if (wake_lock_active(&pld->wlock)) + wake_unlock(&pld->wlock); return 0; } -static void cmd_req_active_handler(struct dpram_link_device *dpld) +static void cmd_req_active_handler(struct pld_link_device *pld) { - send_intr(dpld, INT_CMD(INT_CMD_RES_ACTIVE)); + send_intr(pld, INT_CMD(INT_CMD_RES_ACTIVE)); } -static void cmd_crash_reset_handler(struct dpram_link_device *dpld) +static void cmd_crash_reset_handler(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; struct io_device *iod = NULL; ld->mode = LINK_MODE_ULOAD; - if (!wake_lock_active(&dpld->wlock)) - wake_lock(&dpld->wlock); + if (!wake_lock_active(&pld->wlock)) + wake_lock(&pld->wlock); mif_err("%s: Recv 0xC7 (CRASH_RESET)\n", ld->name); @@ -1323,35 +1081,33 @@ static void cmd_crash_reset_handler(struct dpram_link_device *dpld) iod->modem_state_changed(iod, STATE_CRASH_RESET); } -static void cmd_crash_exit_handler(struct dpram_link_device *dpld) +static void cmd_crash_exit_handler(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; ld->mode = LINK_MODE_ULOAD; - if (!wake_lock_active(&dpld->wlock)) - wake_lock(&dpld->wlock); + if (!wake_lock_active(&pld->wlock)) + wake_lock(&pld->wlock); mif_err("%s: Recv 0xC9 (CRASH_EXIT)\n", ld->name); - dpram_wake_up(dpld); - - del_timer(&dpld->crash_ack_timer); + del_timer(&pld->crash_ack_timer); - if (dpld->ext_op && dpld->ext_op->crash_log) - dpld->ext_op->crash_log(dpld); + if (pld->ext_op && pld->ext_op->crash_log) + pld->ext_op->crash_log(pld); - handle_cp_crash(dpld); + handle_cp_crash(pld); } -static void cmd_phone_start_handler(struct dpram_link_device *dpld) +static void cmd_phone_start_handler(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; struct io_device *iod = NULL; mif_info("%s: Recv 0xC8 (CP_START)\n", ld->name); - dpram_init_ipc(dpld); + pld_init_ipc(pld); iod = link_get_iod_with_format(ld, IPC_FMT); if (!iod) { @@ -1359,8 +1115,8 @@ static void cmd_phone_start_handler(struct dpram_link_device *dpld) return; } - if (dpld->ext_op && dpld->ext_op->cp_start_handler) - dpld->ext_op->cp_start_handler(dpld); + if (pld->ext_op && pld->ext_op->cp_start_handler) + pld->ext_op->cp_start_handler(pld); if (ld->mc->phone_state != STATE_ONLINE) { mif_info("%s: phone_state: %d -> ONLINE\n", @@ -1369,32 +1125,32 @@ static void cmd_phone_start_handler(struct dpram_link_device *dpld) } mif_info("%s: Send 0xC2 (INIT_END)\n", ld->name); - send_intr(dpld, INT_CMD(INT_CMD_INIT_END)); + send_intr(pld, INT_CMD(INT_CMD_INIT_END)); } -static void command_handler(struct dpram_link_device *dpld, u16 cmd) +static void command_handler(struct pld_link_device *pld, u16 cmd) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; switch (INT_CMD_MASK(cmd)) { case INT_CMD_REQ_ACTIVE: - cmd_req_active_handler(dpld); + cmd_req_active_handler(pld); break; case INT_CMD_CRASH_RESET: - dpld->dpram_init_status = DPRAM_INIT_STATE_NONE; - cmd_crash_reset_handler(dpld); + pld->init_status = PLD_INIT_STATE_NONE; + cmd_crash_reset_handler(pld); break; case INT_CMD_CRASH_EXIT: - dpld->dpram_init_status = DPRAM_INIT_STATE_NONE; - cmd_crash_exit_handler(dpld); + pld->init_status = PLD_INIT_STATE_NONE; + cmd_crash_exit_handler(pld); break; case INT_CMD_PHONE_START: - dpld->dpram_init_status = DPRAM_INIT_STATE_READY; - cmd_phone_start_handler(dpld); - complete_all(&dpld->dpram_init_cmd); + pld->init_status = PLD_INIT_STATE_READY; + cmd_phone_start_handler(pld); + complete_all(&pld->dpram_init_cmd); break; case INT_CMD_NV_REBUILDING: @@ -1402,14 +1158,14 @@ static void command_handler(struct dpram_link_device *dpld, u16 cmd) break; case INT_CMD_PIF_INIT_DONE: - complete_all(&dpld->modem_pif_init_done); + complete_all(&pld->modem_pif_init_done); break; case INT_CMD_SILENT_NV_REBUILDING: mif_info("%s: SILENT_NV_REBUILDING\n", ld->name); break; - case INT_CMD_NORMAL_PWR_OFF: + case INT_CMD_NORMAL_POWER_OFF: /*ToDo:*/ /*kernel_sec_set_cp_ack()*/; break; @@ -1424,123 +1180,46 @@ static void command_handler(struct dpram_link_device *dpld, u16 cmd) } } -static void ext_command_handler(struct dpram_link_device *dpld, u16 cmd) -{ - struct link_device *ld = &dpld->ld; - u16 resp; - - switch (EXT_CMD_MASK(cmd)) { - case EXT_CMD_SET_SPEED_LOW: - if (dpld->dpctl->setup_speed) { - dpld->dpctl->setup_speed(DPRAM_SPEED_LOW); - resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_LOW); - send_intr(dpld, resp); - } - break; - - case EXT_CMD_SET_SPEED_MID: - if (dpld->dpctl->setup_speed) { - dpld->dpctl->setup_speed(DPRAM_SPEED_MID); - resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_MID); - send_intr(dpld, resp); - } - break; - - case EXT_CMD_SET_SPEED_HIGH: - if (dpld->dpctl->setup_speed) { - dpld->dpctl->setup_speed(DPRAM_SPEED_HIGH); - resp = INT_EXT_CMD(EXT_CMD_SET_SPEED_HIGH); - send_intr(dpld, resp); - } - break; - - default: - mif_info("%s: unknown command 0x%04X\n", ld->name, cmd); - break; - } -} - -static void udl_command_handler(struct dpram_link_device *dpld, u16 cmd) -{ - struct link_device *ld = &dpld->ld; - - if (cmd & UDL_RESULT_FAIL) { - mif_info("%s: ERR! Command failed: %04x\n", ld->name, cmd); - return; - } - - switch (UDL_CMD_MASK(cmd)) { - case UDL_CMD_RECV_READY: - mif_debug("%s: Send CP-->AP RECEIVE_READY\n", ld->name); - send_intr(dpld, CMD_IMG_START_REQ); - break; - default: - complete_all(&dpld->udl_cmd_complete); - } -} - -static irqreturn_t dpram_irq_handler(int irq, void *data) +static irqreturn_t pld_irq_handler(int irq, void *data) { - struct dpram_link_device *dpld = (struct dpram_link_device *)data; - struct link_device *ld = (struct link_device *)&dpld->ld; + struct pld_link_device *pld = (struct pld_link_device *)data; + struct link_device *ld = (struct link_device *)&pld->ld; u16 int2ap = 0; if (unlikely(ld->mode == LINK_MODE_OFFLINE)) return IRQ_HANDLED; - if (dpram_wake_up(dpld) < 0) { - log_dpram_status(dpld); - trigger_force_cp_crash(dpld); - return IRQ_HANDLED; - } - - int2ap = recv_intr(dpld); + int2ap = recv_intr(pld); if (unlikely(int2ap == INT_POWERSAFE_FAIL)) { mif_info("%s: int2ap == INT_POWERSAFE_FAIL\n", ld->name); goto exit; } else if (int2ap == 0x1234 || int2ap == 0xDBAB || int2ap == 0xABCD) { - if (dpld->ext_op && dpld->ext_op->dload_cmd_handler) { - dpld->ext_op->dload_cmd_handler(dpld, int2ap); + if (pld->ext_op && pld->ext_op->dload_cmd_handler) { + pld->ext_op->dload_cmd_handler(pld, int2ap); goto exit; } } - if (unlikely(EXT_UDL_CMD(int2ap))) { - if (likely(EXT_INT_VALID(int2ap))) { - if (UDL_CMD_VALID(int2ap)) - udl_command_handler(dpld, int2ap); - else if (EXT_CMD_VALID(int2ap)) - ext_command_handler(dpld, int2ap); - else - mif_info("%s: ERR! invalid intr 0x%04X\n", - ld->name, int2ap); - } else { - mif_info("%s: ERR! invalid intr 0x%04X\n", - ld->name, int2ap); - } + if (likely(INT_VALID(int2ap))) { + if (unlikely(INT_CMD_VALID(int2ap))) + command_handler(pld, int2ap); + else + non_command_handler(pld, int2ap); } else { - if (likely(INT_VALID(int2ap))) { - if (unlikely(INT_CMD_VALID(int2ap))) - command_handler(dpld, int2ap); - else - non_command_handler(dpld, int2ap); - } else { - mif_info("%s: ERR! invalid intr 0x%04X\n", - ld->name, int2ap); - } + mif_info("%s: ERR! invalid intr 0x%04X\n", + ld->name, int2ap); } exit: - clear_intr(dpld); - dpram_allow_sleep(dpld); + clear_intr(pld); return IRQ_HANDLED; } -static void dpram_send_ipc(struct link_device *ld, int dev, +static void pld_send_ipc(struct link_device *ld, int dev, struct io_device *iod, struct sk_buff *skb) { - struct dpram_link_device *dpld = to_dpram_link_device(ld); + struct pld_link_device *pld = to_pld_link_device(ld); struct sk_buff_head *txq = ld->skb_txq[dev]; int ret; u16 mask; @@ -1551,46 +1230,31 @@ static void dpram_send_ipc(struct link_device *ld, int dev, ld->name, get_dev_name(dev), txq->qlen); } - if (dpram_wake_up(dpld) < 0) { - trigger_force_cp_crash(dpld); - return; - } - - if (!dpram_ipc_active(dpld)) + if (!ipc_active(pld)) goto exit; - if (atomic_read(&dpld->res_required[dev]) > 0) { + if (atomic_read(&pld->res_required[dev]) > 0) { mif_debug("%s: %s_TXQ is full\n", ld->name, get_dev_name(dev)); goto exit; } - ret = dpram_try_ipc_tx(dpld, dev); + ret = pld_try_ipc_tx(pld, dev); if (ret > 0) { - mask = get_mask_send(dpld, dev); - send_intr(dpld, INT_NON_CMD(mask)); + mask = get_mask_send(pld, dev); + send_intr(pld, INT_NON_CMD(mask)); } else if (ret == -ENOSPC) { - mask = get_mask_req_ack(dpld, dev); - send_intr(dpld, INT_NON_CMD(mask)); + mask = get_mask_req_ack(pld, dev); + send_intr(pld, INT_NON_CMD(mask)); mif_info("%s: Send REQ_ACK 0x%04X\n", ld->name, mask); } else { - mif_info("%s: dpram_try_ipc_tx fail (err %d)\n", ld->name, ret); + mif_info("%s: pld_try_ipc_tx fail (err %d)\n", ld->name, ret); } exit: - dpram_allow_sleep(dpld); -} - -static int dpram_download_bin(struct link_device *ld, struct sk_buff *skb) -{ - struct dpram_link_device *dpld = to_dpram_link_device(ld); - - if (dpld->ext_op && dpld->ext_op->dload_bin) - return dpld->ext_op->dload_bin(dpld, skb); - else - return -ENODEV; + return; } -static int dpram_send(struct link_device *ld, struct io_device *iod, +static int pld_send(struct link_device *ld, struct io_device *iod, struct sk_buff *skb) { enum dev_format dev = iod->format; @@ -1601,16 +1265,13 @@ static int dpram_send(struct link_device *ld, struct io_device *iod, case IPC_RAW: case IPC_RFS: if (likely(ld->mode == LINK_MODE_IPC)) { - dpram_send_ipc(ld, dev, iod, skb); + pld_send_ipc(ld, dev, iod, skb); } else { mif_info("%s: ld->mode != LINK_MODE_IPC\n", ld->name); dev_kfree_skb_any(skb); } return len; - case IPC_BOOT: - return dpram_download_bin(ld, skb); - default: mif_info("%s: ERR! no TXQ for %s\n", ld->name, iod->name); dev_kfree_skb_any(skb); @@ -1618,48 +1279,38 @@ static int dpram_send(struct link_device *ld, struct io_device *iod, } } -static int dpram_force_dump(struct link_device *ld, struct io_device *iod) +static int pld_force_dump(struct link_device *ld, struct io_device *iod) { - struct dpram_link_device *dpld = to_dpram_link_device(ld); - trigger_force_cp_crash(dpld); + struct pld_link_device *pld = to_pld_link_device(ld); + trigger_force_cp_crash(pld); return 0; } -static void dpram_dump_memory(struct link_device *ld, char *buff) +static int pld_dump_start(struct link_device *ld, struct io_device *iod) { - struct dpram_link_device *dpld = to_dpram_link_device(ld); - u8 __iomem *base = dpld->dpctl->dp_base; - u32 size = dpld->dpctl->dp_size; + struct pld_link_device *pld = to_pld_link_device(ld); - dpram_wake_up(dpld); - memcpy(buff, base, size); -} - -static int dpram_dump_start(struct link_device *ld, struct io_device *iod) -{ - struct dpram_link_device *dpld = to_dpram_link_device(ld); - - if (dpld->ext_op && dpld->ext_op->dump_start) - return dpld->ext_op->dump_start(dpld); + if (pld->ext_op && pld->ext_op->dump_start) + return pld->ext_op->dump_start(pld); else return -ENODEV; } -static int dpram_dump_update(struct link_device *ld, struct io_device *iod, +static int pld_dump_update(struct link_device *ld, struct io_device *iod, unsigned long arg) { - struct dpram_link_device *dpld = to_dpram_link_device(ld); + struct pld_link_device *pld = to_pld_link_device(ld); - if (dpld->ext_op && dpld->ext_op->dump_update) - return dpld->ext_op->dump_update(dpld, (void *)arg); + if (pld->ext_op && pld->ext_op->dump_update) + return pld->ext_op->dump_update(pld, (void *)arg); else return -ENODEV; } -static int dpram_ioctl(struct link_device *ld, struct io_device *iod, +static int pld_ioctl(struct link_device *ld, struct io_device *iod, unsigned int cmd, unsigned long arg) { - struct dpram_link_device *dpld = to_dpram_link_device(ld); + struct pld_link_device *pld = to_pld_link_device(ld); int err = 0; /* @@ -1669,11 +1320,11 @@ static int dpram_ioctl(struct link_device *ld, struct io_device *iod, switch (cmd) { case IOCTL_DPRAM_INIT_STATUS: mif_debug("%s: get dpram init status\n", ld->name); - return dpld->dpram_init_status; + return pld->init_status; default: - if (dpld->ext_ioctl) { - err = dpld->ext_ioctl(dpld, iod, cmd, arg); + if (pld->ext_ioctl) { + err = pld->ext_ioctl(pld, iod, cmd, arg); } else { mif_err("%s: ERR! invalid cmd 0x%08X\n", ld->name, cmd); err = -EINVAL; @@ -1685,97 +1336,97 @@ static int dpram_ioctl(struct link_device *ld, struct io_device *iod, return err; } -static int dpram_table_init(struct dpram_link_device *dpld) +static int pld_table_init(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; u8 __iomem *dp_base; int i; - if (!dpld->dp_base) { - mif_info("%s: ERR! dpld->dp_base == NULL\n", ld->name); + if (!pld->base) { + mif_info("%s: ERR! pld->base == NULL\n", ld->name); return -EINVAL; } - dp_base = dpld->dp_base; + dp_base = pld->base; /* Map for IPC */ - if (dpld->dpctl->ipc_map) { - memcpy(&dpld->ipc_map, dpld->dpctl->ipc_map, - sizeof(struct dpram_ipc_map)); + if (pld->dpram->ipc_map) { + memcpy(&pld->ipc_map, pld->dpram->ipc_map, + sizeof(struct pld_ipc_map)); } - dpld->magic_ap2cp = dpld->ipc_map.magic_ap2cp; - dpld->access_ap2cp = dpld->ipc_map.access_ap2cp; + pld->magic_ap2cp = pld->ipc_map.magic_ap2cp; + pld->access_ap2cp = pld->ipc_map.access_ap2cp; - dpld->magic_cp2ap = dpld->ipc_map.magic_cp2ap; - dpld->access_cp2ap = dpld->ipc_map.access_cp2ap; + pld->magic_cp2ap = pld->ipc_map.magic_cp2ap; + pld->access_cp2ap = pld->ipc_map.access_cp2ap; - dpld->address_buffer = dpld->ipc_map.address_buffer; + pld->address_buffer = pld->ipc_map.address_buffer; - for (i = 0; i < dpld->max_ipc_dev; i++) - dpld->dev[i] = &dpld->ipc_map.dev[i]; - dpld->mbx2ap = dpld->ipc_map.mbx_cp2ap; - dpld->mbx2cp = dpld->ipc_map.mbx_ap2cp; + for (i = 0; i < ld->max_ipc_dev; i++) + pld->dev[i] = &pld->ipc_map.dev[i]; + pld->mbx2ap = pld->ipc_map.mbx_cp2ap; + pld->mbx2cp = pld->ipc_map.mbx_ap2cp; /* Map for booting */ - if (dpld->ext_op && dpld->ext_op->init_boot_map) { - dpld->ext_op->init_boot_map(dpld); + if (pld->ext_op && pld->ext_op->init_boot_map) { + pld->ext_op->init_boot_map(pld); } else { - dpld->bt_map.magic = (u32 *)(dp_base); - dpld->bt_map.buff = (u8 *)(dp_base + DP_BOOT_BUFF_OFFSET); - dpld->bt_map.size = dpld->dp_size - 8; + pld->bt_map.magic = (u32 *)(dp_base); + pld->bt_map.buff = (u8 *)(dp_base + DP_BOOT_BUFF_OFFSET); + pld->bt_map.space = pld->size - 8; } /* Map for download (FOTA, UDL, etc.) */ - if (dpld->ext_op && dpld->ext_op->init_dl_map) { - dpld->ext_op->init_dl_map(dpld); + if (pld->ext_op && pld->ext_op->init_dl_map) { + pld->ext_op->init_dl_map(pld); } else { - dpld->dl_map.magic = (u32 *)(dp_base); - dpld->dl_map.buff = (u8 *)(dp_base + DP_DLOAD_BUFF_OFFSET); + pld->dl_map.magic = (u32 *)(dp_base); + pld->dl_map.buff = (u8 *)(dp_base + DP_DLOAD_BUFF_OFFSET); } /* Map for upload mode */ - if (dpld->ext_op && dpld->ext_op->init_ul_map) { - dpld->ext_op->init_ul_map(dpld); + if (pld->ext_op && pld->ext_op->init_ul_map) { + pld->ext_op->init_ul_map(pld); } else { - dpld->ul_map.magic = (u32 *)(dp_base); - dpld->ul_map.buff = (u8 *)(dp_base + DP_ULOAD_BUFF_OFFSET); + pld->ul_map.magic = (u32 *)(dp_base); + pld->ul_map.buff = (u8 *)(dp_base + DP_ULOAD_BUFF_OFFSET); } return 0; } -static void dpram_setup_common_op(struct dpram_link_device *dpld) -{ - dpld->clear_intr = clear_intr; - dpld->recv_intr = recv_intr; - dpld->send_intr = send_intr; - dpld->get_magic = get_magic; - dpld->set_magic = set_magic; - dpld->get_access = get_access; - dpld->set_access = set_access; - dpld->get_tx_head = get_tx_head; - dpld->get_tx_tail = get_tx_tail; - dpld->set_tx_head = set_tx_head; - dpld->set_tx_tail = set_tx_tail; - dpld->get_tx_buff = get_tx_buff; - dpld->get_tx_buff_size = get_tx_buff_size; - dpld->get_rx_head = get_rx_head; - dpld->get_rx_tail = get_rx_tail; - dpld->set_rx_head = set_rx_head; - dpld->set_rx_tail = set_rx_tail; - dpld->get_rx_buff = get_rx_buff; - dpld->get_rx_buff_size = get_rx_buff_size; - dpld->get_mask_req_ack = get_mask_req_ack; - dpld->get_mask_res_ack = get_mask_res_ack; - dpld->get_mask_send = get_mask_send; -} - -static int dpram_link_init(struct link_device *ld, struct io_device *iod) +static void pld_setup_common_op(struct pld_link_device *pld) +{ + pld->clear_intr = clear_intr; + pld->recv_intr = recv_intr; + pld->send_intr = send_intr; + pld->get_magic = get_magic; + pld->set_magic = set_magic; + pld->get_access = get_access; + pld->set_access = set_access; + pld->get_tx_head = get_tx_head; + pld->get_tx_tail = get_tx_tail; + pld->set_tx_head = set_tx_head; + pld->set_tx_tail = set_tx_tail; + pld->get_tx_buff = get_tx_buff; + pld->get_tx_buff_size = get_tx_buff_size; + pld->get_rx_head = get_rx_head; + pld->get_rx_tail = get_rx_tail; + pld->set_rx_head = set_rx_head; + pld->set_rx_tail = set_rx_tail; + pld->get_rx_buff = get_rx_buff; + pld->get_rx_buff_size = get_rx_buff_size; + pld->get_mask_req_ack = get_mask_req_ack; + pld->get_mask_res_ack = get_mask_res_ack; + pld->get_mask_send = get_mask_send; +} + +static int pld_link_init(struct link_device *ld, struct io_device *iod) { return 0; } -static void dpram_link_terminate(struct link_device *ld, struct io_device *iod) +static void pld_link_terminate(struct link_device *ld, struct io_device *iod) { return; } @@ -1783,11 +1434,11 @@ static void dpram_link_terminate(struct link_device *ld, struct io_device *iod) struct link_device *pld_create_link_device(struct platform_device *pdev) { struct modem_data *mdm_data = NULL; - struct dpram_link_device *dpld = NULL; + struct pld_link_device *pld = NULL; struct link_device *ld = NULL; struct resource *res = NULL; resource_size_t res_size; - struct modemlink_dpram_control *dpctl = NULL; + struct modemlink_dpram_data *dpram = NULL; unsigned long task_data; int ret = 0; int i = 0; @@ -1803,19 +1454,19 @@ struct link_device *pld_create_link_device(struct platform_device *pdev) mif_info("modem = %s\n", mdm_data->name); mif_info("link device = %s\n", mdm_data->link_name); - if (!mdm_data->dpram_ctl) { - mif_info("ERR! mdm_data->dpram_ctl == NULL\n"); + if (!mdm_data->dpram) { + mif_info("ERR! no mdm_data->dpram\n"); goto err; } - dpctl = mdm_data->dpram_ctl; + dpram = mdm_data->dpram; /* Alloc DPRAM link device structure */ - dpld = kzalloc(sizeof(struct dpram_link_device), GFP_KERNEL); - if (!dpld) { - mif_info("ERR! kzalloc dpld fail\n"); + pld = kzalloc(sizeof(struct pld_link_device), GFP_KERNEL); + if (!pld) { + mif_info("ERR! kzalloc pld fail\n"); goto err; } - ld = &dpld->ld; + ld = &pld->ld; /* Retrieve modem data and DPRAM control data from the modem data */ ld->mdm_data = mdm_data; @@ -1823,30 +1474,30 @@ struct link_device *pld_create_link_device(struct platform_device *pdev) ld->ipc_version = mdm_data->ipc_version; /* Retrieve the most basic data for IPC from the modem data */ - dpld->dpctl = dpctl; - dpld->dp_type = dpctl->dp_type; + pld->dpram = dpram; + pld->type = dpram->type; if (mdm_data->ipc_version < SIPC_VER_50) { - if (!dpctl->max_ipc_dev) { + if (!mdm_data->max_ipc_dev) { mif_info("ERR! no max_ipc_dev\n"); goto err; } - ld->aligned = dpctl->aligned; - dpld->max_ipc_dev = dpctl->max_ipc_dev; + ld->aligned = dpram->aligned; + ld->max_ipc_dev = mdm_data->max_ipc_dev; } else { ld->aligned = 1; - dpld->max_ipc_dev = MAX_SIPC5_DEV; + ld->max_ipc_dev = MAX_SIPC5_DEV; } /* Set attributes as a link device */ - ld->init_comm = dpram_link_init; - ld->terminate_comm = dpram_link_terminate; - ld->send = dpram_send; - ld->force_dump = dpram_force_dump; - ld->dump_start = dpram_dump_start; - ld->dump_update = dpram_dump_update; - ld->ioctl = dpram_ioctl; + ld->init_comm = pld_link_init; + ld->terminate_comm = pld_link_terminate; + ld->send = pld_send; + ld->force_dump = pld_force_dump; + ld->dump_start = pld_dump_start; + ld->dump_update = pld_dump_update; + ld->ioctl = pld_ioctl; INIT_LIST_HEAD(&ld->list); @@ -1858,14 +1509,13 @@ struct link_device *pld_create_link_device(struct platform_device *pdev) ld->skb_txq[IPC_RFS] = &ld->sk_rfs_tx_q; /* Set up function pointers */ - dpram_setup_common_op(dpld); - dpld->dpram_dump = dpram_dump_memory; - dpld->ext_op = dpram_get_ext_op(mdm_data->modem_type); - if (dpld->ext_op && dpld->ext_op->ioctl) - dpld->ext_ioctl = dpld->ext_op->ioctl; + pld_setup_common_op(pld); + pld->ext_op = pld_get_ext_op(mdm_data->modem_type); + if (pld->ext_op && pld->ext_op->ioctl) + pld->ext_ioctl = pld->ext_op->ioctl; /* Retrieve DPRAM resource */ - if (!dpctl->dp_base) { + if (!dpram->base) { res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { mif_info("%s: ERR! platform_get_resource fail\n", @@ -1874,59 +1524,54 @@ struct link_device *pld_create_link_device(struct platform_device *pdev) } res_size = resource_size(res); - dpctl->dp_base = ioremap_nocache(res->start, res_size); - dpctl->dp_size = res_size; + dpram->base = ioremap_nocache(res->start, res_size); + dpram->size = res_size; } - dpld->dp_base = dpctl->dp_base; - dpld->dp_size = dpctl->dp_size; + pld->base = dpram->base; + pld->size = dpram->size; - mif_info("%s: dp_type %d, aligned %d, dp_base 0x%08X, dp_size %d\n", - ld->name, dpld->dp_type, ld->aligned, (int)dpld->dp_base, - dpld->dp_size); + mif_info("%s: type %d, aligned %d, base 0x%08X, size %d\n", + ld->name, pld->type, ld->aligned, (int)pld->base, pld->size); /* Initialize DPRAM map (physical map -> logical map) */ - ret = dpram_table_init(dpld); + ret = pld_table_init(pld); if (ret < 0) { - mif_info("%s: ERR! dpram_table_init fail (err %d)\n", + mif_info("%s: ERR! pld_table_init fail (err %d)\n", ld->name, ret); goto err; } - spin_lock_init(&dpld->pld_lock); + spin_lock_init(&pld->pld_lock); /* Disable IPC */ - set_magic(dpld, 0); - set_access(dpld, 0); + set_magic(pld, 0); + set_access(pld, 0); - dpld->dpram_init_status = DPRAM_INIT_STATE_NONE; + pld->init_status = PLD_INIT_STATE_NONE; /* Initialize locks, completions, and bottom halves */ - snprintf(dpld->wlock_name, DP_MAX_NAME_LEN, "%s_wlock", ld->name); - wake_lock_init(&dpld->wlock, WAKE_LOCK_SUSPEND, dpld->wlock_name); - - init_completion(&dpld->dpram_init_cmd); - init_completion(&dpld->modem_pif_init_done); - init_completion(&dpld->udl_start_complete); - init_completion(&dpld->udl_cmd_complete); - init_completion(&dpld->dump_start_complete); - init_completion(&dpld->dump_recv_done); + snprintf(pld->wlock_name, MIF_MAX_NAME_LEN, "%s_wlock", ld->name); + wake_lock_init(&pld->wlock, WAKE_LOCK_SUSPEND, pld->wlock_name); - task_data = (unsigned long)dpld; - tasklet_init(&dpld->rx_tsk, dpram_ipc_rx_task, task_data); + init_completion(&pld->dpram_init_cmd); + init_completion(&pld->modem_pif_init_done); + init_completion(&pld->udl_start_complete); + init_completion(&pld->udl_cmd_complete); + init_completion(&pld->crash_start_complete); + init_completion(&pld->crash_recv_done); - /* Prepare SKB queue head for RX processing */ - for (i = 0; i < dpld->max_ipc_dev; i++) - skb_queue_head_init(&dpld->skb_rxq[i]); + task_data = (unsigned long)pld; + tasklet_init(&pld->rx_tsk, pld_ipc_rx_task, task_data); /* Prepare RXB queue */ - qsize = DPRAM_MAX_RXBQ_SIZE; - for (i = 0; i < dpld->max_ipc_dev; i++) { - bsize = rxbq_get_page_size(get_rx_buff_size(dpld, i)); - dpld->rxbq[i].size = qsize; - dpld->rxbq[i].in = 0; - dpld->rxbq[i].out = 0; - dpld->rxbq[i].rxb = rxbq_create_pool(bsize, qsize); - if (!dpld->rxbq[i].rxb) { + qsize = MAX_RXBQ_SIZE; + for (i = 0; i < ld->max_ipc_dev; i++) { + bsize = rxbq_get_page_size(get_rx_buff_size(pld, i)); + pld->rxbq[i].size = qsize; + pld->rxbq[i].in = 0; + pld->rxbq[i].out = 0; + pld->rxbq[i].rxb = rxbq_create_pool(bsize, qsize); + if (!pld->rxbq[i].rxb) { mif_info("%s: ERR! %s rxbq_create_pool fail\n", ld->name, get_dev_name(i)); goto err; @@ -1936,44 +1581,37 @@ struct link_device *pld_create_link_device(struct platform_device *pdev) } /* Prepare a multi-purpose miscellaneous buffer */ - dpld->buff = kzalloc(dpld->dp_size, GFP_KERNEL); - if (!dpld->buff) { - mif_info("%s: ERR! kzalloc dpld->buff fail\n", ld->name); + pld->buff = kzalloc(pld->size, GFP_KERNEL); + if (!pld->buff) { + mif_info("%s: ERR! kzalloc pld->buff fail\n", ld->name); goto err; } /* Retrieve DPRAM IRQ GPIO# */ - dpld->gpio_dpram_int = mdm_data->gpio_dpram_int; + pld->gpio_ipc_int2ap = mdm_data->gpio_ipc_int2ap; /* Retrieve DPRAM IRQ# */ - if (!dpctl->dpram_irq) { - dpctl->dpram_irq = platform_get_irq_byname(pdev, "dpram_irq"); - if (dpctl->dpram_irq < 0) { - mif_info("%s: ERR! platform_get_irq_byname fail\n", - ld->name); - goto err; - } - } - dpld->irq = dpctl->dpram_irq; + pld->irq = mdm_data->irq_ipc_int2ap; /* Retrieve DPRAM IRQ flags */ - if (!dpctl->dpram_irq_flags) - dpctl->dpram_irq_flags = (IRQF_NO_SUSPEND | IRQF_TRIGGER_LOW); - dpld->irq_flags = dpctl->dpram_irq_flags; + if (mdm_data->irqf_ipc_int2ap) + pld->irq_flags = mdm_data->irqf_ipc_int2ap; + else + pld->irq_flags = (IRQF_NO_SUSPEND | IRQF_TRIGGER_LOW); /* Register DPRAM interrupt handler */ - snprintf(dpld->irq_name, DP_MAX_NAME_LEN, "%s_irq", ld->name); - ret = dpram_register_isr(dpld->irq, dpram_irq_handler, dpld->irq_flags, - dpld->irq_name, dpld); + snprintf(pld->irq_name, MIF_MAX_NAME_LEN, "%s_irq", ld->name); + ret = pld_register_isr(pld->irq, pld_irq_handler, pld->irq_flags, + pld->irq_name, pld); if (ret) goto err; return ld; err: - if (dpld) { - kfree(dpld->buff); - kfree(dpld); + if (pld) { + kfree(pld->buff); + kfree(pld); } return NULL; diff --git a/drivers/misc/modem_if/modem_link_device_pld.h b/drivers/misc/modem_if/modem_link_device_pld.h index 2656110..2690faa 100644 --- a/drivers/misc/modem_if/modem_link_device_pld.h +++ b/drivers/misc/modem_if/modem_link_device_pld.h @@ -1,5 +1,4 @@ /* - * Copyright (C) 2011 Google, Inc. * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -12,181 +11,134 @@ * GNU General Public License for more details. * */ -#ifndef __MODEM_LINK_DEVICE_DPRAM_H__ -#define __MODEM_LINK_DEVICE_DPRAM_H__ - -#include <linux/spinlock.h> -#include <linux/wakelock.h> -#include <linux/workqueue.h> -#include <linux/timer.h> -#include <linux/platform_data/modem.h> - -#include "modem_prj.h" - -#define DPRAM_MAGIC_CODE 0xAA - -/* interrupt masks.*/ -#define INT_MASK_VALID 0x0080 -#define INT_MASK_CMD 0x0040 -#define INT_VALID(x) ((x) & INT_MASK_VALID) -#define INT_CMD_VALID(x) ((x) & INT_MASK_CMD) -#define INT_NON_CMD(x) (INT_MASK_VALID | (x)) -#define INT_CMD(x) (INT_MASK_VALID | INT_MASK_CMD | (x)) - -#define EXT_UDL_MASK 0xF000 -#define EXT_UDL_CMD(x) ((x) & EXT_UDL_MASK) -#define EXT_INT_VALID_MASK 0x8000 -#define EXT_CMD_VALID_MASK 0x4000 -#define UDL_CMD_VALID_MASK 0x2000 -#define EXT_INT_VALID(x) ((x) & EXT_INT_VALID_MASK) -#define EXT_CMD_VALID(x) ((x) & EXT_CMD_VALID_MASK) -#define UDL_CMD_VALID(x) ((x) & UDL_CMD_VALID_MASK) -#define INT_EXT_CMD(x) (EXT_INT_VALID_MASK | EXT_CMD_VALID_MASK | (x)) - -#define EXT_CMD_MASK(x) ((x) & 0x0FFF) -#define EXT_CMD_SET_SPEED_LOW 0x0011 -#define EXT_CMD_SET_SPEED_MID 0x0012 -#define EXT_CMD_SET_SPEED_HIGH 0x0013 - -#define UDL_RESULT_SUCCESS 0x1 -#define UDL_RESULT_FAIL 0x2 - -#define UDL_CMD_MASK(x) (((x) >> 8) & 0xF) -#define UDL_CMD_RECV_READY 0x1 -#define UDL_CMD_DL_START_REQ 0x2 -#define UDL_CMD_DL_START_RESP 0x3 -#define UDL_CMD_IMAGE_SEND_REQ 0x4 -#define UDL_CMD_SEND_DONE_RESP 0x5 -#define UDL_CMD_SEND_DONE_REQ 0x6 -#define UDL_CMD_UPDATE_DONE 0x7 -#define UDL_CMD_STATUS_UPDATE 0x8 -#define UDL_CMD_IMAGE_SEND_RESP 0x9 -#define UDL_CMD_EFS_CLEAR_RESP 0xB -#define UDL_CMD_ALARM_BOOT_OK 0xC -#define UDL_CMD_ALARM_BOOT_FAIL 0xD - -#define CMD_IMG_START_REQ 0x9200 -#define CMD_IMG_SEND_REQ 0x9400 -#define CMD_DL_SEND_DONE_REQ 0x9600 -#define CMD_UL_RECV_RESP 0x9601 -#define CMD_UL_RECV_DONE_RESP 0x9801 - -/* special interrupt cmd indicating modem boot failure. */ -#define INT_POWERSAFE_FAIL 0xDEAD - -#define INT_MASK_REQ_ACK_RFS 0x0400 /* Request RES_ACK_RFS */ -#define INT_MASK_RES_ACK_RFS 0x0200 /* Response of REQ_ACK_RFS */ -#define INT_MASK_SEND_RFS 0x0100 /* Indicate sending RFS data */ - -#define INT_MASK_REQ_ACK_F 0x0020 -#define INT_MASK_REQ_ACK_R 0x0010 -#define INT_MASK_RES_ACK_F 0x0008 -#define INT_MASK_RES_ACK_R 0x0004 -#define INT_MASK_SEND_F 0x0002 -#define INT_MASK_SEND_R 0x0001 - -#define INT_MASK_REQ_ACK_RFS 0x0400 /* Request RES_ACK_RFS */ -#define INT_MASK_RES_ACK_RFS 0x0200 /* Response of REQ_ACK_RFS */ -#define INT_MASK_SEND_RFS 0x0100 /* Indicate sending RFS data */ - -#define INT_MASK_RES_ACK_SET \ - (INT_MASK_RES_ACK_F | INT_MASK_RES_ACK_R | INT_MASK_RES_ACK_RFS) - -#define INT_MASK_SEND_SET \ - (INT_MASK_SEND_F | INT_MASK_SEND_R | INT_MASK_SEND_RFS) - -#define INT_CMD_MASK(x) ((x) & 0xF) -#define INT_CMD_INIT_START 0x1 -#define INT_CMD_INIT_END 0x2 -#define INT_CMD_REQ_ACTIVE 0x3 -#define INT_CMD_RES_ACTIVE 0x4 -#define INT_CMD_REQ_TIME_SYNC 0x5 -#define INT_CMD_CRASH_RESET 0x7 -#define INT_CMD_PHONE_START 0x8 -#define INT_CMD_ERR_DISPLAY 0x9 -#define INT_CMD_CRASH_EXIT 0x9 -#define INT_CMD_CP_DEEP_SLEEP 0xA -#define INT_CMD_NV_REBUILDING 0xB -#define INT_CMD_EMER_DOWN 0xC -#define INT_CMD_PIF_INIT_DONE 0xD -#define INT_CMD_SILENT_NV_REBUILDING 0xE -#define INT_CMD_NORMAL_PWR_OFF 0xF - -#define START_FLAG 0x7F -#define END_FLAG 0x7E - -#define DP_MAGIC_DMDL 0x4445444C -#define DP_MAGIC_UMDL 0x4445444D -#define DP_DPRAM_SIZE 0x4000 -#define DP_DEFAULT_WRITE_LEN 8168 -#define DP_DEFAULT_DUMP_LEN 16128 -#define DP_DUMP_HEADER_SIZE 7 - -#define UDL_TIMEOUT (50 * HZ) -#define UDL_SEND_TIMEOUT (200 * HZ) -#define FORCE_CRASH_ACK_TIMEOUT (5 * HZ) -#define DUMP_TIMEOUT (30 * HZ) -#define DUMP_START_TIMEOUT (100 * HZ) -#define DUMP_WAIT_TIMEOUT (HZ >> 10) /* 1/1024 second */ +#ifndef __MODEM_LINK_DEVICE_PLD_H__ +#define __MODEM_LINK_DEVICE_PLD_H__ -#define PLD_ADDR_MASK(x) (0x00003FFF & (unsigned long)(x)) +#include "modem_link_device_memory.h" -enum host_boot_mode { - HOST_BOOT_MODE_NORMAL, - HOST_BOOT_MODE_DUMP, -}; +#define PLD_ADDR_MASK(x) (0x00003FFF & (unsigned long)(x)) -enum dpram_init_status { - DPRAM_INIT_STATE_NONE, - DPRAM_INIT_STATE_READY, +enum pld_init_status { + PLD_INIT_STATE_NONE, + PLD_INIT_STATE_READY, }; -struct dpram_boot_img { - char *addr; - int size; - enum host_boot_mode mode; - unsigned req; - unsigned resp; -}; +#if 1 +#define MAX_RXBQ_SIZE 256 -#define MAX_PAYLOAD_SIZE 0x2000 -struct dpram_boot_frame { - unsigned req; /* AP->CP request */ - unsigned resp; /* response expected by AP */ - ssize_t len; /* data size in the buffer */ - unsigned offset; /* offset to write into DPRAM */ - char data[MAX_PAYLOAD_SIZE]; -}; +struct mif_rxb { + u8 *buff; + unsigned size; -/* buffer type for modem image */ -struct dpram_dump_arg { - char *buff; /* pointer to the buffer */ - int buff_size; /* buffer size */ - unsigned req; /* AP->CP request */ - unsigned resp; /* CP->AP response */ - bool cmd; /* AP->CP command */ + u8 *data; + unsigned len; }; -struct dpram_firmware { - char *firmware; +struct mif_rxb_queue { int size; - int is_delta; -}; -enum dpram_link_mode { - DPRAM_LINK_MODE_INVALID = 0, - DPRAM_LINK_MODE_IPC, - DPRAM_LINK_MODE_BOOT, - DPRAM_LINK_MODE_DLOAD, - DPRAM_LINK_MODE_ULOAD, + int in; + int out; + struct mif_rxb *rxb; }; -struct dpram_boot_map { - u32 __iomem *magic; - u8 __iomem *buff; - u32 __iomem *req; - u32 __iomem *resp; - u32 size; -}; +/* +** RXB (DPRAM RX buffer) functions +*/ +static inline struct mif_rxb *rxbq_create_pool(unsigned size, int count) +{ + struct mif_rxb *rxb; + u8 *buff; + int i; + + rxb = kzalloc(sizeof(struct mif_rxb) * count, GFP_KERNEL); + if (!rxb) { + mif_info("ERR! kzalloc rxb fail\n"); + return NULL; + } + + buff = kzalloc((size * count), GFP_KERNEL|GFP_DMA); + if (!buff) { + mif_info("ERR! kzalloc buff fail\n"); + kfree(rxb); + return NULL; + } + + for (i = 0; i < count; i++) { + rxb[i].buff = buff; + rxb[i].size = size; + buff += size; + } + + return rxb; +} + +static inline unsigned rxbq_get_page_size(unsigned len) +{ + return ((len + PAGE_SIZE - 1) >> PAGE_SHIFT) << PAGE_SHIFT; +} + +static inline bool rxbq_empty(struct mif_rxb_queue *rxbq) +{ + return (rxbq->in == rxbq->out) ? true : false; +} + +static inline int rxbq_free_size(struct mif_rxb_queue *rxbq) +{ + int in = rxbq->in; + int out = rxbq->out; + int qsize = rxbq->size; + return (in < out) ? (out - in - 1) : (qsize + out - in - 1); +} + +static inline struct mif_rxb *rxbq_get_free_rxb(struct mif_rxb_queue *rxbq) +{ + struct mif_rxb *rxb = NULL; + + if (likely(rxbq_free_size(rxbq) > 0)) { + rxb = &rxbq->rxb[rxbq->in]; + rxbq->in++; + if (rxbq->in >= rxbq->size) + rxbq->in -= rxbq->size; + rxb->data = rxb->buff; + } + + return rxb; +} + +static inline int rxbq_size(struct mif_rxb_queue *rxbq) +{ + int in = rxbq->in; + int out = rxbq->out; + int qsize = rxbq->size; + return (in >= out) ? (in - out) : (qsize - out + in); +} + +static inline struct mif_rxb *rxbq_get_data_rxb(struct mif_rxb_queue *rxbq) +{ + struct mif_rxb *rxb = NULL; + + if (likely(!rxbq_empty(rxbq))) { + rxb = &rxbq->rxb[rxbq->out]; + rxbq->out++; + if (rxbq->out >= rxbq->size) + rxbq->out -= rxbq->size; + } + + return rxb; +} + +static inline u8 *rxb_put(struct mif_rxb *rxb, unsigned len) +{ + rxb->len = len; + return rxb->data; +} + +static inline void rxb_clear(struct mif_rxb *rxb) +{ + rxb->data = NULL; + rxb->len = 0; +} +#endif struct qc_dpram_boot_map { u8 __iomem *buff; @@ -195,39 +147,14 @@ struct qc_dpram_boot_map { u16 __iomem *count; }; -struct dpram_dload_map { - u32 __iomem *magic; - u8 __iomem *buff; -}; - -struct dpram_uload_map { - u32 __iomem *magic; - u8 __iomem *buff; -}; - -struct dpram_ota_header { - u8 start_index; - u16 nframes; - u16 curframe; - u16 len; - -} __packed; - -struct ul_header { - u8 bop; - u16 total_frame; - u16 curr_frame; - u16 len; -} __packed; - -struct dpram_udl_param { +struct qc_dpram_udl_param { unsigned char *addr; unsigned int size; unsigned int count; unsigned int tag; }; -struct dpram_udl_check { +struct qc_dpram_udl_check { unsigned int total_size; unsigned int rest_size; unsigned int send_size; @@ -236,180 +163,38 @@ struct dpram_udl_check { unsigned int boot_complete; }; -#define DP_BOOT_BUFF_OFFSET 4 -#define DP_DLOAD_BUFF_OFFSET 4 -#define DP_ULOAD_BUFF_OFFSET 4 -#define DP_BOOT_REQ_OFFSET 0 -#define DP_BOOT_RESP_OFFSET 8 - -#define MAX_WQ_NAME_LENGTH 64 - -#define DPRAM_MAX_RXBQ_SIZE 256 - -struct dpram_rxb { - u8 *buff; - unsigned size; +struct pld_ext_op; - u8 *data; - unsigned len; -}; - -struct dpram_rxb_queue { - int size; - int in; - int out; - struct dpram_rxb *rxb; -}; - -/* - mbx_ap2cp + 0x0 - magic_code + - access_enable + - padding + - mbx_cp2ap + 0x1000 - magic_code + - access_enable + - padding + - fmt_tx_head + fmt_tx_tail + fmt_tx_buff + 0x2000 - raw_tx_head + raw_tx_tail + raw_tx_buff + - fmt_rx_head + fmt_rx_tail + fmt_rx_buff + 0x3000 - raw_rx_head + raw_rx_tail + raw_rx_buff + - = 2 + - 4094 + - 2 + - 4094 + - 2 + - 2 + - 2 + 2 + 1020 + - 2 + 2 + 3064 + - 2 + 2 + 1020 + - 2 + 2 + 3064 - */ - -#define DP_PLD_FMT_TX_BUFF_SZ 1024 -#define DP_PLD_RAW_TX_BUFF_SZ 3072 -#define DP_PLD_FMT_RX_BUFF_SZ 1024 -#define DP_PLD_RAW_RX_BUFF_SZ 3072 - -#define MAX_MSM_EDPRAM_IPC_DEV 2 /* FMT, RAW */ - -struct dpram_ipc_pld_map { - u16 mbx_ap2cp; - u16 magic_ap2cp; - u16 access_ap2cp; - u16 fmt_tx_head; - u16 raw_tx_head; - u16 fmt_rx_tail; - u16 raw_rx_tail; - u16 temp1; - u8 padding1[4080]; - - u16 mbx_cp2ap; - u16 magic_cp2ap; - u16 access_cp2ap; - u16 fmt_tx_tail; - u16 raw_tx_tail; - u16 fmt_rx_head; - u16 raw_rx_head; - u16 temp2; - u8 padding2[4080]; - - u8 fmt_tx_buff[DP_PLD_FMT_TX_BUFF_SZ]; - u8 raw_tx_buff[DP_PLD_RAW_TX_BUFF_SZ]; - u8 fmt_rx_buff[DP_PLD_RAW_TX_BUFF_SZ]; - u8 raw_rx_buff[DP_PLD_RAW_RX_BUFF_SZ]; - - u8 padding3[16384]; - - u16 address_buffer; -}; - -/* - magic_code + - access_enable + - fmt_tx_head + fmt_tx_tail + fmt_tx_buff + - raw_tx_head + raw_tx_tail + raw_tx_buff + - fmt_rx_head + fmt_rx_tail + fmt_rx_buff + - raw_rx_head + raw_rx_tail + raw_rx_buff + - mbx_cp2ap + - mbx_ap2cp - = 2 + - 2 + - 2 + 2 + 1336 + - 2 + 2 + 4564 + - 2 + 2 + 1336 + - 2 + 2 + 9124 + - 2 + - 2 - = 16384 -*/ -#define DP_16K_FMT_TX_BUFF_SZ 1336 -#define DP_16K_RAW_TX_BUFF_SZ 4564 -#define DP_16K_FMT_RX_BUFF_SZ 1336 -#define DP_16K_RAW_RX_BUFF_SZ 9124 - -struct dpram_ipc_16k_map { - u16 magic; - u16 access; - - u16 fmt_tx_head; - u16 fmt_tx_tail; - u8 fmt_tx_buff[DP_16K_FMT_TX_BUFF_SZ]; - - u16 raw_tx_head; - u16 raw_tx_tail; - u8 raw_tx_buff[DP_16K_RAW_TX_BUFF_SZ]; - - u16 fmt_rx_head; - u16 fmt_rx_tail; - u8 fmt_rx_buff[DP_16K_FMT_RX_BUFF_SZ]; - - u16 raw_rx_head; - u16 raw_rx_tail; - u8 raw_rx_buff[DP_16K_RAW_RX_BUFF_SZ]; - - u16 mbx_cp2ap; - u16 mbx_ap2cp; -}; - -#define DP_MAX_NAME_LEN 32 - -struct dpram_ext_op; - -struct dpram_link_device { +struct pld_link_device { struct link_device ld; - /* The mode of this DPRAM link device */ - enum dpram_link_mode mode; - /* DPRAM address and size */ - u8 __iomem *dp_base; /* DPRAM base virtual address */ - u32 dp_size; /* DPRAM size */ - enum dpram_type dp_type; /* DPRAM type */ + enum dpram_type type; /* DPRAM type */ + u8 __iomem *base; /* DPRAM base virtual address */ + u32 size; /* DPRAM size */ /* DPRAM IRQ GPIO# */ - unsigned gpio_dpram_int; + unsigned gpio_ipc_int2ap; /* DPRAM IRQ from CP */ int irq; unsigned long irq_flags; - char irq_name[DP_MAX_NAME_LEN]; + char irq_name[MIF_MAX_NAME_LEN]; /* Link to DPRAM control functions dependent on each platform */ - int max_ipc_dev; - struct modemlink_dpram_control *dpctl; + struct modemlink_dpram_data *dpram; /* Physical configuration -> logical configuration */ union { - struct dpram_boot_map bt_map; + struct memif_boot_map bt_map; struct qc_dpram_boot_map qc_bt_map; }; - struct dpram_dload_map dl_map; - struct dpram_uload_map ul_map; + struct memif_dload_map dl_map; + struct memif_uload_map ul_map; /* IPC device map */ - struct dpram_ipc_map ipc_map; + struct pld_ipc_map ipc_map; /* Pointers (aliases) to IPC device map */ u16 __iomem *magic_ap2cp; @@ -424,7 +209,7 @@ struct dpram_link_device { /* Wakelock for DPRAM device */ struct wake_lock wlock; - char wlock_name[DP_MAX_NAME_LEN]; + char wlock_name[MIF_MAX_NAME_LEN]; /* For booting */ unsigned boot_start_complete; @@ -432,19 +217,16 @@ struct dpram_link_device { struct completion modem_pif_init_done; /* For UDL */ - struct tasklet_struct ul_tsk; struct tasklet_struct dl_tsk; struct completion udl_start_complete; struct completion udl_cmd_complete; - struct dpram_udl_check udl_check; - struct dpram_udl_param udl_param; + struct qc_dpram_udl_check qc_udl_check; + struct qc_dpram_udl_param qc_udl_param; - /* For CP RAM dump */ + /* For CP crash dump */ struct timer_list crash_ack_timer; - struct completion dump_start_complete; - struct completion dump_recv_done; - struct timer_list dump_timer; - int dump_rcvd; /* Count of dump packets received */ + struct completion crash_start_complete; + struct completion crash_recv_done; /* For locking TX process */ spinlock_t tx_rx_lock; @@ -452,10 +234,8 @@ struct dpram_link_device { /* For efficient RX process */ struct tasklet_struct rx_tsk; - struct dpram_rxb_queue rxbq[MAX_IPC_DEV]; + struct mif_rxb_queue rxbq[MAX_IPC_DEV]; struct io_device *iod[MAX_IPC_DEV]; - bool use_skb; - struct sk_buff_head skb_rxq[MAX_IPC_DEV]; /* For retransmission after buffer full state */ atomic_t res_required[MAX_IPC_DEV]; @@ -466,67 +246,65 @@ struct dpram_link_device { /* Multi-purpose miscellaneous buffer */ u8 *buff; - /* DPRAM IPC initialization status */ - int dpram_init_status; + /* PLD IPC initialization status */ + int init_status; /* Alias to device-specific IOCTL function */ - int (*ext_ioctl)(struct dpram_link_device *dpld, struct io_device *iod, + int (*ext_ioctl)(struct pld_link_device *pld, struct io_device *iod, unsigned int cmd, unsigned long arg); - /* For DPRAM dump */ - void (*dpram_dump)(struct link_device *ld, char *buff); - /* Common operations for each DPRAM */ - void (*clear_intr)(struct dpram_link_device *dpld); - u16 (*recv_intr)(struct dpram_link_device *dpld); - void (*send_intr)(struct dpram_link_device *dpld, u16 mask); - u16 (*get_magic)(struct dpram_link_device *dpld); - void (*set_magic)(struct dpram_link_device *dpld, u16 value); - u16 (*get_access)(struct dpram_link_device *dpld); - void (*set_access)(struct dpram_link_device *dpld, u16 value); - u32 (*get_tx_head)(struct dpram_link_device *dpld, int id); - u32 (*get_tx_tail)(struct dpram_link_device *dpld, int id); - void (*set_tx_head)(struct dpram_link_device *dpld, int id, u32 head); - void (*set_tx_tail)(struct dpram_link_device *dpld, int id, u32 tail); - u8 *(*get_tx_buff)(struct dpram_link_device *dpld, int id); - u32 (*get_tx_buff_size)(struct dpram_link_device *dpld, int id); - u32 (*get_rx_head)(struct dpram_link_device *dpld, int id); - u32 (*get_rx_tail)(struct dpram_link_device *dpld, int id); - void (*set_rx_head)(struct dpram_link_device *dpld, int id, u32 head); - void (*set_rx_tail)(struct dpram_link_device *dpld, int id, u32 tail); - u8 *(*get_rx_buff)(struct dpram_link_device *dpld, int id); - u32 (*get_rx_buff_size)(struct dpram_link_device *dpld, int id); - u16 (*get_mask_req_ack)(struct dpram_link_device *dpld, int id); - u16 (*get_mask_res_ack)(struct dpram_link_device *dpld, int id); - u16 (*get_mask_send)(struct dpram_link_device *dpld, int id); + void (*clear_intr)(struct pld_link_device *pld); + u16 (*recv_intr)(struct pld_link_device *pld); + void (*send_intr)(struct pld_link_device *pld, u16 mask); + u16 (*get_magic)(struct pld_link_device *pld); + void (*set_magic)(struct pld_link_device *pld, u16 value); + u16 (*get_access)(struct pld_link_device *pld); + void (*set_access)(struct pld_link_device *pld, u16 value); + u32 (*get_tx_head)(struct pld_link_device *pld, int id); + u32 (*get_tx_tail)(struct pld_link_device *pld, int id); + void (*set_tx_head)(struct pld_link_device *pld, int id, u32 head); + void (*set_tx_tail)(struct pld_link_device *pld, int id, u32 tail); + u8 *(*get_tx_buff)(struct pld_link_device *pld, int id); + u32 (*get_tx_buff_size)(struct pld_link_device *pld, int id); + u32 (*get_rx_head)(struct pld_link_device *pld, int id); + u32 (*get_rx_tail)(struct pld_link_device *pld, int id); + void (*set_rx_head)(struct pld_link_device *pld, int id, u32 head); + void (*set_rx_tail)(struct pld_link_device *pld, int id, u32 tail); + u8 *(*get_rx_buff)(struct pld_link_device *pld, int id); + u32 (*get_rx_buff_size)(struct pld_link_device *pld, int id); + u16 (*get_mask_req_ack)(struct pld_link_device *pld, int id); + u16 (*get_mask_res_ack)(struct pld_link_device *pld, int id); + u16 (*get_mask_send)(struct pld_link_device *pld, int id); /* Extended operations for various modems */ - struct dpram_ext_op *ext_op; + struct pld_ext_op *ext_op; }; /* converts from struct link_device* to struct xxx_link_device* */ -#define to_dpram_link_device(linkdev) \ - container_of(linkdev, struct dpram_link_device, ld) +#define to_pld_link_device(linkdev) \ + container_of(linkdev, struct pld_link_device, ld) -struct dpram_ext_op { +struct pld_ext_op { int exist; - void (*init_boot_map)(struct dpram_link_device *dpld); - void (*init_dl_map)(struct dpram_link_device *dpld); - void (*init_ul_map)(struct dpram_link_device *dpld); + void (*init_boot_map)(struct pld_link_device *pld); + void (*init_dl_map)(struct pld_link_device *pld); + void (*init_ul_map)(struct pld_link_device *pld); - int (*dload_bin)(struct dpram_link_device *dpld, struct sk_buff *skb); - void (*dload_cmd_handler)(struct dpram_link_device *dpld, u16 cmd); + void (*dload_cmd_handler)(struct pld_link_device *pld, u16 cmd); - void (*cp_start_handler)(struct dpram_link_device *dpld); + void (*cp_start_handler)(struct pld_link_device *pld); - void (*crash_log)(struct dpram_link_device *dpld); - int (*dump_start)(struct dpram_link_device *dpld); - int (*dump_update)(struct dpram_link_device *dpld, void *arg); + void (*crash_log)(struct pld_link_device *pld); + int (*dump_start)(struct pld_link_device *pld); + int (*dump_update)(struct pld_link_device *pld, void *arg); - int (*ioctl)(struct dpram_link_device *dpld, struct io_device *iod, + int (*ioctl)(struct pld_link_device *pld, struct io_device *iod, unsigned int cmd, unsigned long arg); + + void (*clear_intr)(struct pld_link_device *pld); }; -struct dpram_ext_op *dpram_get_ext_op(enum modem_t modem); +struct pld_ext_op *pld_get_ext_op(enum modem_t modem); #endif diff --git a/drivers/misc/modem_if/modem_link_device_pld_ext_op.c b/drivers/misc/modem_if/modem_link_device_pld_ext_op.c index ae6578c..26b0e28 100644 --- a/drivers/misc/modem_if/modem_link_device_pld_ext_op.c +++ b/drivers/misc/modem_if/modem_link_device_pld_ext_op.c @@ -25,8 +25,8 @@ #include <linux/if_arp.h> #include <linux/platform_device.h> #include <linux/kallsyms.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_pld.h" #include "modem_utils.h" @@ -41,56 +41,55 @@ enum qc_dload_tag { static void qc_dload_task(unsigned long data); -static void qc_init_boot_map(struct dpram_link_device *dpld) +static void qc_init_boot_map(struct pld_link_device *pld) { - struct qc_dpram_boot_map *bt_map = &dpld->qc_bt_map; - struct modemlink_dpram_control *dpctl = dpld->dpctl; + struct qc_dpram_boot_map *qbt_map = &pld->qc_bt_map; + struct modemlink_dpram_data *dpram = pld->dpram; - bt_map->buff = dpld->dev[0]->txq.buff; - bt_map->frame_size = (u16 *)(dpld->dp_base + dpctl->boot_size_offset); - bt_map->tag = (u16 *)(dpld->dp_base + dpctl->boot_tag_offset); - bt_map->count = (u16 *)(dpld->dp_base + dpctl->boot_count_offset); + qbt_map->buff = pld->dev[0]->txq.buff; + qbt_map->frame_size = (u16 *)(pld->base + dpram->boot_size_offset); + qbt_map->tag = (u16 *)(pld->base + dpram->boot_tag_offset); + qbt_map->count = (u16 *)(pld->base + dpram->boot_count_offset); - tasklet_init(&dpld->dl_tsk, qc_dload_task, (unsigned long)dpld); + tasklet_init(&pld->dl_tsk, qc_dload_task, (unsigned long)pld); } -static void qc_dload_map(struct dpram_link_device *dpld, u8 is_upload) +static void qc_dload_map(struct pld_link_device *pld, u8 is_upload) { - struct qc_dpram_boot_map *bt_map = &dpld->qc_bt_map; - struct modemlink_dpram_control *dpctl = dpld->dpctl; + struct qc_dpram_boot_map *qbt_map = &pld->qc_bt_map; + struct modemlink_dpram_data *dpram = pld->dpram; unsigned int upload_offset = 0; if (is_upload == 1) { upload_offset = 0x1000; - bt_map->buff = dpld->dev[0]->rxq.buff; + qbt_map->buff = pld->dev[0]->rxq.buff; } else { upload_offset = 0; - bt_map->buff = dpld->dev[0]->txq.buff; + qbt_map->buff = pld->dev[0]->txq.buff; } - bt_map->frame_size = (u16 *)(dpld->dp_base + - dpctl->boot_size_offset + upload_offset); - bt_map->tag = (u16 *)(dpld->dp_base + - dpctl->boot_tag_offset + upload_offset); - bt_map->count = (u16 *)(dpld->dp_base + - dpctl->boot_count_offset + upload_offset); - + qbt_map->frame_size = (u16 *)(pld->base + + dpram->boot_size_offset + upload_offset); + qbt_map->tag = (u16 *)(pld->base + + dpram->boot_tag_offset + upload_offset); + qbt_map->count = (u16 *)(pld->base + + dpram->boot_count_offset + upload_offset); } -static int qc_prepare_download(struct dpram_link_device *dpld) +static int qc_prepare_download(struct pld_link_device *pld) { int retval = 0; int count = 0; - qc_dload_map(dpld, 0); + qc_dload_map(pld, 0); while (1) { - if (dpld->udl_check.copy_start) { - dpld->udl_check.copy_start = 0; + if (pld->qc_udl_check.copy_start) { + pld->qc_udl_check.copy_start = 0; break; } - msleep(20); + usleep_range(10000, 11000); count++; if (count > 1000) { @@ -102,42 +101,42 @@ static int qc_prepare_download(struct dpram_link_device *dpld) return retval; } -static void _qc_do_download(struct dpram_link_device *dpld, - struct dpram_udl_param *param) +static void _qc_do_download(struct pld_link_device *pld, + struct qc_dpram_udl_param *param) { - struct qc_dpram_boot_map *bt_map = &dpld->qc_bt_map; + struct qc_dpram_boot_map *qbt_map = &pld->qc_bt_map; - if (param->size <= dpld->dpctl->max_boot_frame_size) { - iowrite16(PLD_ADDR_MASK(&bt_map->buff[0]), - dpld->address_buffer); - memcpy(dpld->dp_base, param->addr, param->size); + if (param->size <= pld->dpram->max_boot_frame_size) { + iowrite16(PLD_ADDR_MASK(&qbt_map->buff[0]), + pld->address_buffer); + memcpy(pld->base, param->addr, param->size); - iowrite16(PLD_ADDR_MASK(&bt_map->frame_size[0]), - dpld->address_buffer); - iowrite16(param->size, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&qbt_map->frame_size[0]), + pld->address_buffer); + iowrite16(param->size, pld->base); - iowrite16(PLD_ADDR_MASK(&bt_map->tag[0]), - dpld->address_buffer); - iowrite16(param->tag, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&qbt_map->tag[0]), + pld->address_buffer); + iowrite16(param->tag, pld->base); - iowrite16(PLD_ADDR_MASK(&bt_map->count[0]), - dpld->address_buffer); - iowrite16(param->count, dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&qbt_map->count[0]), + pld->address_buffer); + iowrite16(param->count, pld->base); - dpld->send_intr(dpld, 0xDB12); + pld->send_intr(pld, 0xDB12); } else { mif_info("param->size %d\n", param->size); } } -static int _qc_download(struct dpram_link_device *dpld, void *arg, +static int _qc_download(struct pld_link_device *pld, void *arg, enum qc_dload_tag tag) { int retval = 0; int count = 0; int cnt_limit; unsigned char *img; - struct dpram_udl_param param; + struct qc_dpram_udl_param param; retval = copy_from_user((void *)¶m, (void *)arg, sizeof(param)); if (retval < 0) { @@ -153,24 +152,24 @@ static int _qc_download(struct dpram_link_device *dpld, void *arg, memset(img, 0, param.size); memcpy(img, param.addr, param.size); - dpld->udl_check.total_size = param.size; - dpld->udl_check.rest_size = param.size; - dpld->udl_check.send_size = 0; - dpld->udl_check.copy_complete = 0; + pld->qc_udl_check.total_size = param.size; + pld->qc_udl_check.rest_size = param.size; + pld->qc_udl_check.send_size = 0; + pld->qc_udl_check.copy_complete = 0; - dpld->udl_param.addr = img; - dpld->udl_param.size = dpld->dpctl->max_boot_frame_size; + pld->qc_udl_param.addr = img; + pld->qc_udl_param.size = pld->dpram->max_boot_frame_size; if (tag == QC_DLOAD_TAG_NV) - dpld->udl_param.count = 1; + pld->qc_udl_param.count = 1; else - dpld->udl_param.count = param.count; - dpld->udl_param.tag = tag; + pld->qc_udl_param.count = param.count; + pld->qc_udl_param.tag = tag; - if (dpld->udl_check.rest_size < dpld->dpctl->max_boot_frame_size) - dpld->udl_param.size = dpld->udl_check.rest_size; + if (pld->qc_udl_check.rest_size < pld->dpram->max_boot_frame_size) + pld->qc_udl_param.size = pld->qc_udl_check.rest_size; /* Download image (binary or NV) */ - _qc_do_download(dpld, &dpld->udl_param); + _qc_do_download(pld, &pld->qc_udl_param); /* Wait for completion */ @@ -180,13 +179,13 @@ static int _qc_download(struct dpram_link_device *dpld, void *arg, cnt_limit = 1000; while (1) { - if (dpld->udl_check.copy_complete) { - dpld->udl_check.copy_complete = 0; + if (pld->qc_udl_check.copy_complete) { + pld->qc_udl_check.copy_complete = 0; retval = 0; break; } - msleep(20); + usleep_range(10000, 11000); count++; if (count > cnt_limit) { @@ -201,53 +200,53 @@ static int _qc_download(struct dpram_link_device *dpld, void *arg, return retval; } -static int qc_download_bin(struct dpram_link_device *dpld, void *arg) +static int qc_download_bin(struct pld_link_device *pld, void *arg) { - return _qc_download(dpld, arg, QC_DLOAD_TAG_BIN); + return _qc_download(pld, arg, QC_DLOAD_TAG_BIN); } -static int qc_download_nv(struct dpram_link_device *dpld, void *arg) +static int qc_download_nv(struct pld_link_device *pld, void *arg) { - return _qc_download(dpld, arg, QC_DLOAD_TAG_NV); + return _qc_download(pld, arg, QC_DLOAD_TAG_NV); } static void qc_dload_task(unsigned long data) { - struct dpram_link_device *dpld = (struct dpram_link_device *)data; + struct pld_link_device *pld = (struct pld_link_device *)data; - dpld->udl_check.send_size += dpld->udl_param.size; - dpld->udl_check.rest_size -= dpld->udl_param.size; + pld->qc_udl_check.send_size += pld->qc_udl_param.size; + pld->qc_udl_check.rest_size -= pld->qc_udl_param.size; - dpld->udl_param.addr += dpld->udl_param.size; + pld->qc_udl_param.addr += pld->qc_udl_param.size; - if (dpld->udl_check.send_size >= dpld->udl_check.total_size) { - dpld->udl_check.copy_complete = 1; - dpld->udl_param.tag = 0; + if (pld->qc_udl_check.send_size >= pld->qc_udl_check.total_size) { + pld->qc_udl_check.copy_complete = 1; + pld->qc_udl_param.tag = 0; return; } - if (dpld->udl_check.rest_size < dpld->dpctl->max_boot_frame_size) - dpld->udl_param.size = dpld->udl_check.rest_size; + if (pld->qc_udl_check.rest_size < pld->dpram->max_boot_frame_size) + pld->qc_udl_param.size = pld->qc_udl_check.rest_size; - dpld->udl_param.count += 1; + pld->qc_udl_param.count += 1; - _qc_do_download(dpld, &dpld->udl_param); + _qc_do_download(pld, &pld->qc_udl_param); } -static void qc_dload_cmd_handler(struct dpram_link_device *dpld, u16 cmd) +static void qc_dload_cmd_handler(struct pld_link_device *pld, u16 cmd) { switch (cmd) { case 0x1234: - dpld->udl_check.copy_start = 1; + pld->qc_udl_check.copy_start = 1; break; case 0xDBAB: - tasklet_schedule(&dpld->dl_tsk); + tasklet_schedule(&pld->dl_tsk); break; case 0xABCD: - mif_info("[%s] booting Start\n", dpld->ld.name); - dpld->udl_check.boot_complete = 1; + mif_info("[%s] booting Start\n", pld->ld.name); + pld->qc_udl_check.boot_complete = 1; break; default: @@ -255,22 +254,22 @@ static void qc_dload_cmd_handler(struct dpram_link_device *dpld, u16 cmd) } } -static int qc_boot_start(struct dpram_link_device *dpld) +static int qc_boot_start(struct pld_link_device *pld) { u16 mask = 0; int count = 0; /* Send interrupt -> '0x4567' */ mask = 0x4567; - dpld->send_intr(dpld, mask); + pld->send_intr(pld, mask); while (1) { - if (dpld->udl_check.boot_complete) { - dpld->udl_check.boot_complete = 0; + if (pld->qc_udl_check.boot_complete) { + pld->qc_udl_check.boot_complete = 0; break; } - msleep(20); + usleep_range(10000, 11000); count++; if (count > 200) { @@ -282,17 +281,17 @@ static int qc_boot_start(struct dpram_link_device *dpld) return 0; } -static int qc_boot_post_process(struct dpram_link_device *dpld) +static int qc_boot_post_process(struct pld_link_device *pld) { int count = 0; while (1) { - if (dpld->boot_start_complete) { - dpld->boot_start_complete = 0; + if (pld->boot_start_complete) { + pld->boot_start_complete = 0; break; } - msleep(20); + usleep_range(10000, 11000); count++; if (count > 200) { @@ -304,7 +303,7 @@ static int qc_boot_post_process(struct dpram_link_device *dpld) return 0; } -static void qc_start_handler(struct dpram_link_device *dpld) +static void qc_start_handler(struct pld_link_device *pld) { /* * INT_MASK_VALID | INT_MASK_CMD | INT_MASK_CP_AIRPLANE_BOOT | @@ -312,38 +311,38 @@ static void qc_start_handler(struct dpram_link_device *dpld) */ u16 mask = (0x0080 | 0x0040 | 0x1000 | 0x0100 | 0x0002); - dpld->boot_start_complete = 1; + pld->boot_start_complete = 1; /* Send INIT_END code to CP */ mif_info("send 0x%04X (INIT_END)\n", mask); - dpld->send_intr(dpld, mask); + pld->send_intr(pld, mask); } -static void qc_crash_log(struct dpram_link_device *dpld) +static void qc_crash_log(struct pld_link_device *pld) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; static unsigned char buf[151]; u8 __iomem *data = NULL; - data = dpld->get_rx_buff(dpld, IPC_FMT); + data = pld->get_rx_buff(pld, IPC_FMT); memcpy(buf, data, (sizeof(buf) - 1)); mif_info("PHONE ERR MSG\t| %s Crash\n", ld->mdm_data->name); mif_info("PHONE ERR MSG\t| %s\n", buf); } -static int _qc_data_upload(struct dpram_link_device *dpld, - struct dpram_udl_param *param) +static int _qc_data_upload(struct pld_link_device *pld, + struct qc_dpram_udl_param *param) { - struct qc_dpram_boot_map *bt_map = &dpld->qc_bt_map; + struct qc_dpram_boot_map *qbt_map = &pld->qc_bt_map; int retval = 0; u16 intval = 0; int count = 0; while (1) { - if (!gpio_get_value(dpld->gpio_dpram_int)) { - intval = dpld->recv_intr(dpld); + if (!gpio_get_value(pld->gpio_ipc_int2ap)) { + intval = pld->recv_intr(pld); if (intval == 0xDBAB) { break; } else { @@ -352,7 +351,7 @@ static int _qc_data_upload(struct dpram_link_device *dpld, } } - msleep(20); + usleep_range(1000, 2000); count++; if (count > 200) { @@ -361,43 +360,43 @@ static int _qc_data_upload(struct dpram_link_device *dpld, } } - iowrite16(PLD_ADDR_MASK(&bt_map->frame_size[0]), - dpld->address_buffer); - param->size = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&qbt_map->frame_size[0]), + pld->address_buffer); + param->size = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&bt_map->tag[0]), - dpld->address_buffer); - param->tag = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&qbt_map->tag[0]), + pld->address_buffer); + param->tag = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&bt_map->count[0]), - dpld->address_buffer); - param->count = ioread16(dpld->dp_base); + iowrite16(PLD_ADDR_MASK(&qbt_map->count[0]), + pld->address_buffer); + param->count = ioread16(pld->base); - iowrite16(PLD_ADDR_MASK(&bt_map->buff[0]), - dpld->address_buffer); - memcpy(param->addr, dpld->dp_base, param->size); + iowrite16(PLD_ADDR_MASK(&qbt_map->buff[0]), + pld->address_buffer); + memcpy(param->addr, pld->base, param->size); - dpld->send_intr(dpld, 0xDB12); + pld->send_intr(pld, 0xDB12); return retval; } -static int qc_uload_step1(struct dpram_link_device *dpld) +static int qc_uload_step1(struct pld_link_device *pld) { int retval = 0; int count = 0; u16 intval = 0; u16 mask = 0; - qc_dload_map(dpld, 1); + qc_dload_map(pld, 1); mif_info("+---------------------------------------------+\n"); mif_info("| UPLOAD PHONE SDRAM |\n"); mif_info("+---------------------------------------------+\n"); while (1) { - if (!gpio_get_value(dpld->gpio_dpram_int)) { - intval = dpld->recv_intr(dpld); + if (!gpio_get_value(pld->gpio_ipc_int2ap)) { + intval = pld->recv_intr(pld); mif_info("intr 0x%04x\n", intval); if (intval == 0x1234) { break; @@ -407,11 +406,11 @@ static int qc_uload_step1(struct dpram_link_device *dpld) } } - msleep(20); + usleep_range(1000, 2000); count++; if (count > 200) { - intval = dpld->recv_intr(dpld); + intval = pld->recv_intr(pld); mif_info("count %d, intr 0x%04x\n", count, intval); if (intval == 0x1234) break; @@ -420,15 +419,15 @@ static int qc_uload_step1(struct dpram_link_device *dpld) } mask = 0xDEAD; - dpld->send_intr(dpld, mask); + pld->send_intr(pld, mask); return retval; } -static int qc_uload_step2(struct dpram_link_device *dpld, void *arg) +static int qc_uload_step2(struct pld_link_device *pld, void *arg) { int retval = 0; - struct dpram_udl_param param; + struct qc_dpram_udl_param param; retval = copy_from_user((void *)¶m, (void *)arg, sizeof(param)); if (retval < 0) { @@ -436,7 +435,7 @@ static int qc_uload_step2(struct dpram_link_device *dpld, void *arg) return -1; } - retval = _qc_data_upload(dpld, ¶m); + retval = _qc_data_upload(pld, ¶m); if (retval < 0) { mif_err("ERR! _qc_data_upload fail (err %d)\n", retval); return -1; @@ -446,7 +445,7 @@ static int qc_uload_step2(struct dpram_link_device *dpld, void *arg) mif_info("param->count = %d\n", param.count); if (param.tag == 4) { - enable_irq(dpld->irq); + enable_irq(pld->irq); mif_info("param->tag = %d\n", param.tag); } @@ -459,57 +458,57 @@ static int qc_uload_step2(struct dpram_link_device *dpld, void *arg) return retval; } -static int qc_ioctl(struct dpram_link_device *dpld, struct io_device *iod, +static int qc_ioctl(struct pld_link_device *pld, struct io_device *iod, unsigned int cmd, unsigned long arg) { - struct link_device *ld = &dpld->ld; + struct link_device *ld = &pld->ld; int err = 0; switch (cmd) { case IOCTL_DPRAM_PHONE_POWON: - err = qc_prepare_download(dpld); + err = qc_prepare_download(pld); if (err < 0) mif_info("%s: ERR! prepare_download fail\n", ld->name); break; case IOCTL_DPRAM_PHONEIMG_LOAD: - err = qc_download_bin(dpld, (void *)arg); + err = qc_download_bin(pld, (void *)arg); if (err < 0) mif_info("%s: ERR! download_bin fail\n", ld->name); break; case IOCTL_DPRAM_NVDATA_LOAD: - err = qc_download_nv(dpld, (void *)arg); + err = qc_download_nv(pld, (void *)arg); if (err < 0) mif_info("%s: ERR! download_nv fail\n", ld->name); break; case IOCTL_DPRAM_PHONE_BOOTSTART: - err = qc_boot_start(dpld); + err = qc_boot_start(pld); if (err < 0) { mif_info("%s: ERR! boot_start fail\n", ld->name); break; } - err = qc_boot_post_process(dpld); + err = qc_boot_post_process(pld); if (err < 0) mif_info("%s: ERR! boot_post_process fail\n", ld->name); break; case IOCTL_DPRAM_PHONE_UPLOAD_STEP1: - disable_irq_nosync(dpld->irq); - err = qc_uload_step1(dpld); + disable_irq_nosync(pld->irq); + err = qc_uload_step1(pld); if (err < 0) { - enable_irq(dpld->irq); + enable_irq(pld->irq); mif_info("%s: ERR! upload_step1 fail\n", ld->name); } break; case IOCTL_DPRAM_PHONE_UPLOAD_STEP2: - err = qc_uload_step2(dpld, (void *)arg); + err = qc_uload_step2(pld, (void *)arg); if (err < 0) { - enable_irq(dpld->irq); + enable_irq(pld->irq); mif_info("%s: ERR! upload_step2 fail\n", ld->name); } break; @@ -524,7 +523,7 @@ static int qc_ioctl(struct dpram_link_device *dpld, struct io_device *iod, } #endif -static struct dpram_ext_op ext_op_set[] = { +static struct pld_ext_op ext_op_set[] = { #if defined(CONFIG_CDMA_MODEM_MDM6600) [QC_MDM6600] = { .exist = 1, @@ -547,7 +546,7 @@ static struct dpram_ext_op ext_op_set[] = { #endif }; -struct dpram_ext_op *dpram_get_ext_op(enum modem_t modem) +struct pld_ext_op *pld_get_ext_op(enum modem_t modem) { if (ext_op_set[modem].exist) return &ext_op_set[modem]; diff --git a/drivers/misc/modem_if/modem_link_device_shmem.h b/drivers/misc/modem_if/modem_link_device_shmem.h new file mode 100644 index 0000000..1f33c2a --- /dev/null +++ b/drivers/misc/modem_if/modem_link_device_shmem.h @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2010 Samsung Electronics. + * + * 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 __MODEM_LINK_DEVICE_SHMEM_H__ +#define __MODEM_LINK_DEVICE_SHMEM_H__ + +#include "modem_utils.h" +#include "modem_link_device_memory.h" + +#define SHM_BOOT_MAGIC 0x424F4F54 +#define SHM_DUMP_MAGIC 0x44554D50 +#define SHM_IPC_MAGIC 0xAA +#define SHM_PM_MAGIC 0x5F + +#define SHM_4M_RESERVED_SZ 4056 +#define SHM_4M_FMT_TX_BUFF_SZ 4096 +#define SHM_4M_FMT_RX_BUFF_SZ 4096 +#define SHM_4M_RAW_TX_BUFF_SZ 2084864 +#define SHM_4M_RAW_RX_BUFF_SZ 2097152 + +struct shmem_4mb_phys_map { + u32 magic; + u32 access; + + u32 fmt_tx_head; + u32 fmt_tx_tail; + + u32 fmt_rx_head; + u32 fmt_rx_tail; + + u32 raw_tx_head; + u32 raw_tx_tail; + + u32 raw_rx_head; + u32 raw_rx_tail; + + u8 reserved[SHM_4M_RESERVED_SZ]; + + u8 fmt_tx_buff[SHM_4M_FMT_TX_BUFF_SZ]; + u8 fmt_rx_buff[SHM_4M_FMT_RX_BUFF_SZ]; + + u8 raw_tx_buff[SHM_4M_RAW_TX_BUFF_SZ]; + u8 raw_rx_buff[SHM_4M_RAW_RX_BUFF_SZ]; +} __packed; + +struct shmem_circ { + u32 __iomem *head; + u32 __iomem *tail; + u8 __iomem *buff; + u32 size; +}; + +struct shmem_ipc_device { + char name[16]; + int id; + + struct shmem_circ txq; + struct shmem_circ rxq; + + u16 mask_req_ack; + u16 mask_res_ack; + u16 mask_send; + + int req_ack_rcvd; +}; + +struct shmem_ipc_map { + u32 __iomem *magic; + u32 __iomem *access; + + struct shmem_ipc_device dev[MAX_SIPC5_DEV]; + + u32 __iomem *mbx2ap; + u32 __iomem *mbx2cp; +}; + +struct shmem_link_device { + struct link_device ld; + + enum shmem_type type; + + /* SHMEM (SHARED MEMORY) address and size */ + u32 start; /* physical "start" address of SHMEM */ + u32 size; /* size of SHMEM */ + u8 __iomem *base; /* virtual address of the "start" */ + + /* SHMEM GPIO & IRQ */ + unsigned gpio_pda_active; + + unsigned gpio_ap_wakeup; + int irq_ap_wakeup; + unsigned gpio_ap_status; + + unsigned gpio_cp_wakeup; + unsigned gpio_cp_status; + int irq_cp_status; + + /* IPC device map */ + struct shmem_ipc_map ipc_map; + + /* Pointers (aliases) to IPC device map */ + u32 __iomem *magic; + u32 __iomem *access; + struct shmem_ipc_device *dev[MAX_SIPC5_DEV]; + u32 __iomem *mbx2ap; + u32 __iomem *mbx2cp; + + /* Wakelock for SHMEM device */ + struct wake_lock wlock; + char wlock_name[MIF_MAX_NAME_LEN]; + struct wake_lock ap_wlock; + char ap_wlock_name[MIF_MAX_NAME_LEN]; + struct wake_lock cp_wlock; + char cp_wlock_name[MIF_MAX_NAME_LEN]; + + /* for UDL */ + struct completion udl_cmpl; + struct std_dload_info dl_info; + + /* for CP crash dump */ + bool forced_cp_crash; + struct timer_list crash_ack_timer; + + /* for locking TX process */ + spinlock_t tx_lock[MAX_SIPC5_DEV]; + + /* for retransmission under SHMEM flow control after TXQ full state */ + atomic_t res_required[MAX_SIPC5_DEV]; + struct completion req_ack_cmpl[MAX_SIPC5_DEV]; + + /* for efficient RX process */ + struct tasklet_struct rx_tsk; + struct delayed_work ipc_rx_dwork; + struct delayed_work udl_rx_dwork; + struct io_device *iod[MAX_SIPC5_DEV]; + + /* for logging SHMEM status */ + struct mem_status_queue stat_list; + + /* for logging SHMEM dump */ + struct trace_data_queue trace_list; +#ifdef DEBUG_MODEM_IF + struct delayed_work dump_dwork; + char dump_path[MIF_MAX_PATH_LEN]; +#endif + + /* to hold/release "cp_wakeup" for PM (power-management) */ + struct delayed_work cp_sleep_dwork; + struct delayed_work link_off_dwork; + atomic_t ref_cnt; + spinlock_t pm_lock; +}; + +/* converts from struct link_device* to struct xxx_link_device* */ +#define to_shmem_link_device(linkdev) \ + container_of(linkdev, struct shmem_link_device, ld) + +#if 1 +#endif + +/** + * get_magic + * @shmd: pointer to an instance of shmem_link_device structure + * + * Returns the value of the "magic code" field. + */ +static inline u32 get_magic(struct shmem_link_device *shmd) +{ + return ioread32(shmd->magic); +} + +/** + * get_access + * @shmd: pointer to an instance of shmem_link_device structure + * + * Returns the value of the "access enable" field. + */ +static inline u32 get_access(struct shmem_link_device *shmd) +{ + return ioread32(shmd->access); +} + +/** + * set_magic + * @shmd: pointer to an instance of shmem_link_device structure + * @val: value to be written to the "magic code" field + */ +static inline void set_magic(struct shmem_link_device *shmd, u32 val) +{ + iowrite32(val, shmd->magic); +} + +/** + * set_access + * @shmd: pointer to an instance of shmem_link_device structure + * @val: value to be written to the "access enable" field + */ +static inline void set_access(struct shmem_link_device *shmd, u32 val) +{ + iowrite32(val, shmd->access); +} + +/** + * get_txq_head + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the value of a head (in) pointer in a TX queue. + */ +static inline u32 get_txq_head(struct shmem_link_device *shmd, int id) +{ + return ioread32(shmd->dev[id]->txq.head); +} + +/** + * get_txq_tail + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the value of a tail (out) pointer in a TX queue. + * + * It is useless for an AP to read a tail pointer in a TX queue twice to verify + * whether or not the value in the pointer is valid, because it can already have + * been updated by a CP after the first access from the AP. + */ +static inline u32 get_txq_tail(struct shmem_link_device *shmd, int id) +{ + return ioread32(shmd->dev[id]->txq.tail); +} + +/** + * get_txq_buff + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the start address of the buffer in a TXQ. + */ +static inline u8 *get_txq_buff(struct shmem_link_device *shmd, int id) +{ + return shmd->dev[id]->txq.buff; +} + +/** + * get_txq_buff_size + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the size of the buffer in a TXQ. + */ +static inline u32 get_txq_buff_size(struct shmem_link_device *shmd, int id) +{ + return shmd->dev[id]->txq.size; +} + +/** + * get_rxq_head + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the value of a head (in) pointer in an RX queue. + * + * It is useless for an AP to read a head pointer in an RX queue twice to verify + * whether or not the value in the pointer is valid, because it can already have + * been updated by a CP after the first access from the AP. + */ +static inline u32 get_rxq_head(struct shmem_link_device *shmd, int id) +{ + return ioread32(shmd->dev[id]->rxq.head); +} + +/** + * get_rxq_tail + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the value of a tail (in) pointer in an RX queue. + */ +static inline u32 get_rxq_tail(struct shmem_link_device *shmd, int id) +{ + return ioread32(shmd->dev[id]->rxq.tail); +} + +/** + * get_rxq_buff + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the start address of the buffer in an RXQ. + */ +static inline u8 *get_rxq_buff(struct shmem_link_device *shmd, int id) +{ + return shmd->dev[id]->rxq.buff; +} + +/** + * get_rxq_buff_size + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the size of the buffer in an RXQ. + */ +static inline u32 get_rxq_buff_size(struct shmem_link_device *shmd, int id) +{ + return shmd->dev[id]->rxq.size; +} + +/** + * set_txq_head + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @in: value to be written to the head pointer in a TXQ + */ +static inline void set_txq_head(struct shmem_link_device *shmd, int id, u32 in) +{ + iowrite32(in, shmd->dev[id]->txq.head); +} + +/** + * set_txq_tail + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @out: value to be written to the tail pointer in a TXQ + */ +static inline void set_txq_tail(struct shmem_link_device *shmd, int id, u32 out) +{ + iowrite32(out, shmd->dev[id]->txq.tail); +} + +/** + * set_rxq_head + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @in: value to be written to the head pointer in an RXQ + */ +static inline void set_rxq_head(struct shmem_link_device *shmd, int id, u32 in) +{ + iowrite32(in, shmd->dev[id]->rxq.head); +} + +/** + * set_rxq_tail + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * @out: value to be written to the tail pointer in an RXQ + */ +static inline void set_rxq_tail(struct shmem_link_device *shmd, int id, u32 out) +{ + iowrite32(out, shmd->dev[id]->rxq.tail); +} + +/** + * get_mask_req_ack + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the REQ_ACK mask value for the IPC device. + */ +static inline u16 get_mask_req_ack(struct shmem_link_device *shmd, int id) +{ + return shmd->dev[id]->mask_req_ack; +} + +/** + * get_mask_res_ack + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the RES_ACK mask value for the IPC device. + */ +static inline u16 get_mask_res_ack(struct shmem_link_device *shmd, int id) +{ + return shmd->dev[id]->mask_res_ack; +} + +/** + * get_mask_send + * @shmd: pointer to an instance of shmem_link_device structure + * @id: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Returns the SEND mask value for the IPC device. + */ +static inline u16 get_mask_send(struct shmem_link_device *shmd, int id) +{ + return shmd->dev[id]->mask_send; +} + +#ifndef CONFIG_LINK_DEVICE_C2C +/** + * read_int2cp + * @shmd: pointer to an instance of shmem_link_device structure + * + * Returns the value of the AP-to-CP interrupt register. + */ +static inline u16 read_int2cp(struct shmem_link_device *shmd) +{ + if (shmd->mbx2cp) + return ioread16(shmd->mbx2cp); + else + return 0; +} +#endif + +/** + * reset_txq_circ + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Empties a TXQ by resetting the head (in) pointer with the value in the tail + * (out) pointer. + */ +static inline void reset_txq_circ(struct shmem_link_device *shmd, int dev) +{ + struct link_device *ld = &shmd->ld; + u32 head = get_txq_head(shmd, dev); + u32 tail = get_txq_tail(shmd, dev); + + mif_err("%s: %s_TXQ: HEAD[%u] <== TAIL[%u]\n", + ld->name, get_dev_name(dev), head, tail); + + set_txq_head(shmd, dev, tail); +} + +/** + * reset_rxq_circ + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * + * Empties an RXQ by resetting the tail (out) pointer with the value in the head + * (in) pointer. + */ +static inline void reset_rxq_circ(struct shmem_link_device *shmd, int dev) +{ + struct link_device *ld = &shmd->ld; + u32 head = get_rxq_head(shmd, dev); + u32 tail = get_rxq_tail(shmd, dev); + + mif_err("%s: %s_RXQ: TAIL[%u] <== HEAD[%u]\n", + ld->name, get_dev_name(dev), tail, head); + + set_rxq_tail(shmd, dev, head); +} + +/** + * ipc_active + * @shmd: pointer to an instance of shmem_link_device structure + * + * Returns whether or not IPC via the shmem_link_device instance is possible. + */ +static bool ipc_active(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + u32 magic = get_magic(shmd); + u32 access = get_access(shmd); + + /* Check link mode */ + if (unlikely(ld->mode != LINK_MODE_IPC)) { + mif_err("%s: <by %pf> ERR! ld->mode != LINK_MODE_IPC\n", + ld->name, CALLER); + return false; + } + + /* Check "magic code" and "access enable" values */ + if (unlikely(magic != SHM_IPC_MAGIC || access != 1)) { + mif_err("%s: <by %pf> ERR! magic:0x%X access:%d\n", + ld->name, CALLER, magic, access); + return false; + } + + return true; +} + +/** + * get_rxq_rcvd + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @mst: pointer to an instance of mem_status structure + * OUT @circ: pointer to an instance of circ_status structure + * + * Stores {start address of the buffer in a RXQ, size of the buffer, in & out + * pointer values, size of received data} into the 'circ' instance. + * + * Returns an error code. + */ +static int get_rxq_rcvd(struct shmem_link_device *shmd, int dev, + struct mem_status *mst, struct circ_status *circ) +{ + struct link_device *ld = &shmd->ld; + + circ->buff = get_rxq_buff(shmd, dev); + circ->qsize = get_rxq_buff_size(shmd, dev); + circ->in = mst->head[dev][RX]; + circ->out = mst->tail[dev][RX]; + circ->size = circ_get_usage(circ->qsize, circ->in, circ->out); + + if (circ_valid(circ->qsize, circ->in, circ->out)) { + mif_debug("%s: %s_RXQ qsize[%u] in[%u] out[%u] rcvd[%u]\n", + ld->name, get_dev_name(dev), circ->qsize, circ->in, + circ->out, circ->size); + return 0; + } else { + mif_err("%s: ERR! %s_RXQ invalid (qsize[%d] in[%d] out[%d])\n", + ld->name, get_dev_name(dev), circ->qsize, circ->in, + circ->out); + return -EIO; + } +} + +/** + * get_txq_space + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * OUT @circ: pointer to an instance of circ_status structure + * + * Stores {start address of the buffer in a TXQ, size of the buffer, in & out + * pointer values, size of free space} into the 'circ' instance. + * + * Returns the size of free space in the buffer or an error code. + */ +static int get_txq_space(struct shmem_link_device *shmd, int dev, + struct circ_status *circ) +{ + struct link_device *ld = &shmd->ld; + int cnt = 0; + u32 qsize; + u32 head; + u32 tail; + int space; + + while (1) { + qsize = get_txq_buff_size(shmd, dev); + head = get_txq_head(shmd, dev); + tail = get_txq_tail(shmd, dev); + space = circ_get_space(qsize, head, tail); + + mif_debug("%s: %s_TXQ{qsize:%u in:%u out:%u space:%u}\n", + ld->name, get_dev_name(dev), qsize, head, tail, space); + + if (circ_valid(qsize, head, tail)) + break; + + cnt++; + mif_err("%s: ERR! invalid %s_TXQ{qsize:%d in:%d out:%d " + "space:%d}, count %d\n", + ld->name, get_dev_name(dev), qsize, head, tail, + space, cnt); + if (cnt >= MAX_RETRY_CNT) { + space = -EIO; + break; + } + + udelay(100); + } + + circ->buff = get_txq_buff(shmd, dev); + circ->qsize = qsize; + circ->in = head; + circ->out = tail; + circ->size = space; + + return space; +} + +/** + * get_txq_saved + * @shmd: pointer to an instance of shmem_link_device structure + * @dev: IPC device (IPC_FMT, IPC_RAW, etc.) + * @mst: pointer to an instance of mem_status structure + * OUT @circ: pointer to an instance of circ_status structure + * + * Stores {start address of the buffer in a TXQ, size of the buffer, in & out + * pointer values, size of stored data} into the 'circ' instance. + * + * Returns an error code. + */ +static int get_txq_saved(struct shmem_link_device *shmd, int dev, + struct circ_status *circ) +{ + struct link_device *ld = &shmd->ld; + int cnt = 0; + u32 qsize; + u32 head; + u32 tail; + int saved; + + while (1) { + qsize = get_txq_buff_size(shmd, dev); + head = get_txq_head(shmd, dev); + tail = get_txq_tail(shmd, dev); + saved = circ_get_usage(qsize, head, tail); + + mif_debug("%s: %s_TXQ{qsize:%u in:%u out:%u saved:%u}\n", + ld->name, get_dev_name(dev), qsize, head, tail, saved); + + if (circ_valid(qsize, head, tail)) + break; + + cnt++; + mif_err("%s: ERR! invalid %s_TXQ{qsize:%d in:%d out:%d " + "saved:%d}, count %d\n", + ld->name, get_dev_name(dev), qsize, head, tail, + saved, cnt); + if (cnt >= MAX_RETRY_CNT) { + saved = -EIO; + break; + } + + udelay(100); + } + + circ->buff = get_txq_buff(shmd, dev); + circ->qsize = qsize; + circ->in = head; + circ->out = tail; + circ->size = saved; + + return saved; +} + +/** + * clear_shmem_map + * @shmd: pointer to an instance of shmem_link_device structure + * + * Clears all pointers in every circular queue. + */ +static void clear_shmem_map(struct shmem_link_device *shmd) +{ + set_txq_head(shmd, IPC_FMT, 0); + set_txq_tail(shmd, IPC_FMT, 0); + set_rxq_head(shmd, IPC_FMT, 0); + set_rxq_tail(shmd, IPC_FMT, 0); + + set_txq_head(shmd, IPC_RAW, 0); + set_txq_tail(shmd, IPC_RAW, 0); + set_rxq_head(shmd, IPC_RAW, 0); + set_rxq_tail(shmd, IPC_RAW, 0); +} + +/** + * reset_shmem_ipc + * @shmd: pointer to an instance of shmem_link_device structure + * + * Reset SHMEM with IPC map. + */ +static void reset_shmem_ipc(struct shmem_link_device *shmd) +{ + set_access(shmd, 0); + + clear_shmem_map(shmd); + + atomic_set(&shmd->res_required[IPC_FMT], 0); + atomic_set(&shmd->res_required[IPC_RAW], 0); + + atomic_set(&shmd->ref_cnt, 0); + + set_magic(shmd, SHM_IPC_MAGIC); + set_access(shmd, 1); +} + +/** + * init_shmem_ipc + * @shmd: pointer to an instance of shmem_link_device structure + * + * Initializes IPC via SHMEM. + */ +static int init_shmem_ipc(struct shmem_link_device *shmd) +{ + struct link_device *ld = &shmd->ld; + + if (ld->mode == LINK_MODE_IPC && + get_magic(shmd) == SHM_IPC_MAGIC && + get_access(shmd) == 1) { + mif_err("%s: IPC already initialized\n", ld->name); + return 0; + } + + /* Initialize variables for efficient TX/RX processing */ + shmd->iod[IPC_FMT] = link_get_iod_with_format(ld, IPC_FMT); + shmd->iod[IPC_RAW] = link_get_iod_with_format(ld, IPC_MULTI_RAW); + + reset_shmem_ipc(shmd); + + if (get_magic(shmd) != SHM_IPC_MAGIC || get_access(shmd) != 1) + return -EACCES; + + return 0; +} + +#endif + diff --git a/drivers/misc/modem_if/modem_link_device_spi.c b/drivers/misc/modem_if/modem_link_device_spi.c index c4715e0..ece6b65 100644 --- a/drivers/misc/modem_if/modem_link_device_spi.c +++ b/drivers/misc/modem_if/modem_link_device_spi.c @@ -26,9 +26,10 @@ #include <linux/if_arp.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> +#include <linux/suspend.h> #include <linux/kthread.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_spi.h" #include "modem_utils.h" @@ -66,8 +67,7 @@ static irqreturn_t spi_srdy_irq_handler(int irq, void *p_ld) if (!spild->boot_done) return result; - if (!wake_lock_active(&spild->spi_wake_lock) - && spild->send_modem_spi != 1) { + if (!wake_lock_active(&spild->spi_wake_lock)) { wake_lock(&spild->spi_wake_lock); pr_debug("[SPI] [%s](%d) spi_wakelock locked . spild->spi_state[%d]\n", __func__, __LINE__, (int)spild->spi_state); @@ -311,7 +311,7 @@ static void spi_prepare_tx_packet(void) ld = &p_spild->ld; - for (i = 0; i < p_spild->max_ipc_dev; i++) { + for (i = 0; i < ld->max_ipc_dev; i++) { while ((skb = skb_dequeue(ld->skb_txq[i]))) { ret = spi_buff_write(p_spild, i, skb->data, skb->len); if (!ret) { @@ -331,7 +331,7 @@ static void spi_start_data_send(void) ld = &p_spild->ld; - for (i = 0; i < p_spild->max_ipc_dev; i++) { + for (i = 0; i < ld->max_ipc_dev; i++) { if (skb_queue_len(ld->skb_txq[i]) > 0) spi_send_work(SPI_WORK_SEND, SPI_WORK); } @@ -345,6 +345,14 @@ static void spi_tx_work(void) char *spi_sync_buf; spild = p_spild; + iod = link_get_iod_with_format(&spild->ld, IPC_FMT); + if (!iod) { + mif_err("no iodevice for modem control\n"); + return; + } + + if (iod->mc->phone_state == STATE_CRASH_EXIT) + return; /* check SUB SRDY, SRDY state */ if (gpio_get_value(spild->gpio_ipc_sub_srdy) == @@ -420,8 +428,6 @@ static void spi_tx_work(void) pr_err("[SPI] spi_dev_send fail\n"); /* add cp reset when spi sync fail */ - iod = link_get_iod_with_format(&spild->ld, IPC_FMT); - if (iod) iod->modem_state_changed(iod, STATE_CRASH_RESET); @@ -553,6 +559,15 @@ static void spi_rx_work(void) if (!spild) pr_err("[LNK/E] <%s> dpld == NULL\n", __func__); + iod = link_get_iod_with_format(&spild->ld, IPC_FMT); + if (!iod) { + mif_err("no iodevice for modem control\n"); + return; + } + + if (iod->mc->phone_state == STATE_CRASH_EXIT) + return; + if (!wake_lock_active(&spild->spi_wake_lock) || gpio_get_value(spild->gpio_ipc_srdy) == SPI_GPIOLEVEL_LOW || get_console_suspended() || @@ -606,7 +621,7 @@ static void spi_rx_work(void) /* parsing SPI packet */ if (spi_buff_read(spild) > 0) { /* call function for send data to IPC, RAW, RFS */ - for (i = 0; i < spild->max_ipc_dev; i++) { + for (i = 0; i < ld->max_ipc_dev; i++) { iod = spild->iod[i]; while ((skb = skb_dequeue(&spild->skb_rxq[i])) != NULL) { @@ -623,8 +638,6 @@ static void spi_rx_work(void) "spi sync failed"); /* add cp reset when spi sync fail */ - iod = link_get_iod_with_format(&spild->ld, IPC_FMT); - if (iod) iod->modem_state_changed(iod, STATE_CRASH_RESET); @@ -639,6 +652,34 @@ static void spi_rx_work(void) spi_start_data_send(); } + +static int spi_init_ipc(struct spi_link_device *spild) +{ + struct link_device *ld = &spild->ld; + + int i; + + /* Make aliases to each IO device */ + for (i = 0; i < MAX_DEV_FORMAT; i++) + spild->iod[i] = link_get_iod_with_format(ld, i); + + spild->iod[IPC_RAW] = spild->iod[IPC_MULTI_RAW]; + + /* List up the IO devices connected to each IPC channel */ + for (i = 0; i < MAX_DEV_FORMAT; i++) { + if (spild->iod[i]) + pr_err("[LNK] <%s:%s> spild->iod[%d]->name = %s\n", + __func__, ld->name, i, spild->iod[i]->name); + else + pr_err("[LNK] <%s:%s> No spild->iod[%d]\n", + __func__, ld->name, i); + } + + ld->mode = LINK_MODE_IPC; + + return 0; +} + unsigned int sprd_crc_calc(char *buf_ptr, unsigned int len) { unsigned int i; @@ -1239,10 +1280,19 @@ err3: static void spi_send_modem_bin(struct work_struct *send_modem_w) { + struct spi_link_device *spild; + struct io_device *iod; int retval; struct image_buf img; unsigned long tick1, tick2 = 0; + spild = p_spild; + iod = link_get_iod_with_format(&spild->ld, IPC_FMT); + if (!iod) { + mif_err("no iodevice for modem control\n"); + return; + } + tick1 = jiffies_to_msecs(jiffies); retval = spi_send_modem_bin_xmit_img(MODEM_MAIN, &img); @@ -1285,16 +1335,25 @@ static void spi_send_modem_bin(struct work_struct *send_modem_w) tick2 = jiffies_to_msecs(jiffies); pr_info("Downloading takes %lu msec\n", (tick2-tick1)); - complete_all(&p_spild->ril_init); + spi_init_ipc(p_spild); + sprd_boot_done = 1; p_spild->ril_send_cnt = 0; + p_spild->spi_state = SPI_STATE_IDLE; + if (iod) + iod->modem_state_changed(iod, + STATE_ONLINE); + return; err: + if (iod) + iod->modem_state_changed(iod, + STATE_OFFLINE); return; } -static inline int _request_mem(struct ipc_spi *od) +static inline int _request_mem(struct spi_v_buff *od) { if (!p_spild->p_virtual_buff) { od->mmio = vmalloc(od->size); @@ -1320,7 +1379,7 @@ void spi_tx_timer_callback(unsigned long param) { if (p_spild->spi_state == SPI_STATE_TX_WAIT) { p_spild->spi_timer_tx_state = SPI_STATE_TIME_OVER; - pr_err("[SPI] spi_tx_timer_callback -timer expires\n"); + pr_debug("[SPI] spi_tx_timer_callback -timer expires\n"); } } @@ -1328,7 +1387,7 @@ void spi_rx_timer_callback(unsigned long param) { if (p_spild->spi_state == SPI_STATE_RX_WAIT) { p_spild->spi_timer_rx_state = SPI_STATE_TIME_OVER; - pr_err("[SPI] spi_rx_timer_callback -timer expires\n"); + pr_debug("[SPI] spi_rx_timer_callback -timer expires\n"); } } @@ -1381,96 +1440,37 @@ static void spi_work(struct work_struct *work) } } -static int spi_init_ipc(struct spi_link_device *spild) +static int link_pm_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) { - struct link_device *ld = &spild->ld; - - int i; - - /* Make aliases to each IO device */ - for (i = 0; i < MAX_DEV_FORMAT; i++) - spild->iod[i] = link_get_iod_with_format(ld, i); - - spild->iod[IPC_RAW] = spild->iod[IPC_MULTI_RAW]; - - /* List up the IO devices connected to each IPC channel */ - for (i = 0; i < MAX_DEV_FORMAT; i++) { - if (spild->iod[i]) - pr_err("[LNK] <%s:%s> spild->iod[%d]->name = %s\n", - __func__, ld->name, i, spild->iod[i]->name); - else - pr_err("[LNK] <%s:%s> No spild->iod[%d]\n", - __func__, ld->name, i); - } - - ld->mode = LINK_MODE_IPC; - - return 0; -} - -static int spi_thread(void *data) -{ - struct spi_link_device *spild = (struct spi_link_device *)data; + struct io_device *iod; + struct link_pm_data *pm_data = + container_of(this, struct link_pm_data, pm_notifier); - if (lpcharge == 1) { - pr_err("[LPM MODE] spi_thread_exit!\n"); - return 0; + iod = link_get_iod_with_format(&pm_data->spild->ld, IPC_FMT); + if (!iod) { + pr_err("no iodevice for modem control\n"); + return NOTIFY_BAD; } - daemonize("spi_thread"); - - pr_info("[%s] spi_thread start.\n", __func__); - p_spild->boot_done = 1; - - wait_for_completion(&p_spild->ril_init); - - pr_info("[%s] ril_init completed.\n", __func__); + if (!gpio_get_value(iod->mc->gpio_phone_active)) + return NOTIFY_DONE; - pr_info("<%s> wait 2 sec... srdy : %d\n", - __func__, gpio_get_value(spild->gpio_ipc_srdy)); - msleep_interruptible(1700); + switch (event) { + case PM_SUSPEND_PREPARE: + /* set TD PDA Active High if previous state was LPA */ + mif_info("TD PDA active low to LPA suspend spot\n"); + gpio_set_value(iod->mc->gpio_pda_active, 0); - while (gpio_get_value(spild->gpio_ipc_srdy)) - ; - pr_info("(%s) cp booting... Done.\n", __func__); - - spi_init_ipc(spild); - - pr_info("[spi_thread] Start IPC Communication. SRDY : %d\n", - gpio_get_value(spild->gpio_ipc_srdy)); - - /* CP booting is already completed, just set submrdy to high */ - if (gpio_get_value(spild->gpio_ipc_sub_srdy) == SPI_GPIOLEVEL_HIGH) { - gpio_set_value(spild->gpio_ipc_sub_mrdy, SPI_GPIOLEVEL_HIGH); - pr_err("[spi_thread] CP booting is already completed\n"); + return NOTIFY_OK; + case PM_POST_SUSPEND: + /* LPA to Kernel suspend and User Freezing task fail resume, + restore to LPA GPIO states. */ + mif_info("TD PDA active High to LPA GPIO state\n"); + gpio_set_value(iod->mc->gpio_pda_active, 1); + return NOTIFY_OK; } - /* CP booting is not completed. - set submrdy to high and wait until subsrdy is high */ - else { - pr_err("[spi_thread] CP booting is not completed. wait...\n"); - - gpio_set_value(spild->gpio_ipc_sub_mrdy, SPI_GPIOLEVEL_HIGH); - do { - msleep_interruptible(5); - } while (gpio_get_value(spild->gpio_ipc_sub_srdy) == - SPI_GPIOLEVEL_LOW); - - pr_err("[spi_thread] CP booting is done...\n"); - } - - if (p_spild->spi_is_restart) - msleep_interruptible(100); - else - msleep_interruptible(30); - - gpio_set_value(spild->gpio_ipc_sub_mrdy, SPI_GPIOLEVEL_LOW); - - pr_info("(%s) spi sync done.\n", __func__); - - spild->spi_state = SPI_STATE_IDLE; - p_spild->spi_is_restart = 0; - - return 0; + return NOTIFY_DONE; } static int spi_probe(struct spi_device *spi) @@ -1512,8 +1512,7 @@ static struct spi_driver spi_driver = { static int spi_link_init(void) { int ret; - struct ipc_spi *od; - struct task_struct *th; + struct spi_v_buff *od; struct link_device *ld = &p_spild->ld; p_spild->gpio_modem_bin_srdy = p_spild->gpio_ipc_srdy; @@ -1522,7 +1521,7 @@ static int spi_link_init(void) p_spild->gpio_ipc_mrdy, p_spild->gpio_modem_bin_srdy, gpio_get_value(p_spild->gpio_ipc_srdy)); - od = kzalloc(sizeof(struct ipc_spi), GFP_KERNEL); + od = kzalloc(sizeof(struct spi_v_buff), GFP_KERNEL); if (!od) { pr_err("(%d) failed to allocate device\n", __LINE__); ret = -ENOMEM; @@ -1537,7 +1536,6 @@ static int spi_link_init(void) if (ret) goto err; - init_completion(&p_spild->ril_init); sema_init(&p_spild->srdy_sem, 0); INIT_WORK(&p_spild->send_modem_w, @@ -1563,12 +1561,7 @@ static int spi_link_init(void) if (ret) goto err; - th = kthread_create(spi_thread, (void *)p_spild, "spi_thread"); - if (IS_ERR(th)) { - pr_err("kernel_thread() failed\n"); - goto err; - } - wake_up_process(th); + p_spild->boot_done = 1; pr_info("[%s] Done\n", __func__); return 0; @@ -1591,7 +1584,6 @@ void spi_set_restart(void) gpio_set_value(p_spild->gpio_ipc_sub_mrdy, SPI_GPIOLEVEL_LOW); p_spild->spi_state = SPI_STATE_END; - p_spild->spi_is_restart = 1; /* Flush SPI work queue */ flush_workqueue(p_spild->spi_wq); @@ -1635,6 +1627,35 @@ exit: } EXPORT_SYMBOL(spi_thread_restart); +static int spi_link_pm_init(struct spi_link_device *spild, + struct platform_device *pdev) +{ + struct modem_data *pdata = + (struct modem_data *)pdev->dev.platform_data; + struct modemlink_pm_data *pm_pdata; + struct link_pm_data *pm_data = + kzalloc(sizeof(struct link_pm_data), GFP_KERNEL); + + if (!pdata || !pdata->link_pm_data) { + mif_err("platform data is NULL\n"); + return -EINVAL; + } + pm_pdata = pdata->link_pm_data; + + if (!pm_data) { + mif_err("link_pm_data is NULL\n"); + return -ENOMEM; + } + + pm_data->spild = spild; + spild->link_pm_data = pm_data; + + pm_data->pm_notifier.notifier_call = link_pm_notifier_event; + register_pm_notifier(&pm_data->pm_notifier); + + return 0; +} + struct link_device *spi_create_link_device(struct platform_device *pdev) { struct spi_link_device *spild = NULL; @@ -1689,9 +1710,9 @@ struct link_device *spi_create_link_device(struct platform_device *pdev) } spild->spi_state = SPI_STATE_END; - spild->max_ipc_dev = IPC_RFS+1; /* FMT, RAW, RFS */ + ld->max_ipc_dev = (IPC_RFS + 1); /* FMT, RAW, RFS */ - for (i = 0; i < spild->max_ipc_dev; i++) + for (i = 0; i < ld->max_ipc_dev; i++) skb_queue_head_init(&spild->skb_rxq[i]); /* Prepare a clean buffer for SPI access */ @@ -1738,6 +1759,11 @@ struct link_device *spi_create_link_device(struct platform_device *pdev) goto err; } + /* create link pm device */ + ret = spi_link_pm_init(spild, pdev); + if (ret) + goto err; + /* Create SPI device */ ret = spi_link_init(); if (ret) diff --git a/drivers/misc/modem_if/modem_link_device_spi.h b/drivers/misc/modem_if/modem_link_device_spi.h index 210d815..b1b334f 100644 --- a/drivers/misc/modem_if/modem_link_device_spi.h +++ b/drivers/misc/modem_if/modem_link_device_spi.h @@ -18,7 +18,7 @@ #include <linux/wakelock.h> #include <linux/workqueue.h> #include <linux/timer.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #define SPI_TIMER_TX_WAIT_TIME 60 /* ms */ @@ -135,20 +135,24 @@ struct spi_data_packet_header { unsigned long more:1; }; +struct link_pm_data { + struct miscdevice miscdev; + struct spi_link_device *spild; + + struct notifier_block pm_notifier; +}; + struct spi_link_device { struct link_device ld; - /* Link to SPI control functions dependent on each platform */ - int max_ipc_dev; - /* Wakelock for SPI device */ struct wake_lock spi_wake_lock; + /* Workqueue for modem bin transfers */ struct workqueue_struct *ipc_spi_wq; /* SPI state */ int spi_state; - int spi_is_restart; /* SPI Timer state */ int spi_timer_tx_state; @@ -182,11 +186,13 @@ struct spi_link_device { struct io_device *iod[MAX_DEV_FORMAT]; struct sk_buff_head skb_rxq[MAX_DEV_FORMAT]; + /* LINK PM DEVICE DATA */ + struct link_pm_data *link_pm_data; + /* Multi-purpose miscellaneous buffer */ u8 *buff; u8 *sync_buff; - struct completion ril_init; struct semaphore srdy_sem; int send_modem_spi; @@ -202,6 +208,12 @@ struct spi_link_device { #define to_spi_link_device(linkdev) \ container_of(linkdev, struct spi_link_device, ld) +struct spi_v_buff { + unsigned long base; + unsigned long size; + void __iomem *mmio; +}; + extern unsigned int lpcharge; extern int get_console_suspended(void); static void spi_work(struct work_struct *work); diff --git a/drivers/misc/modem_if/modem_link_device_usb.c b/drivers/misc/modem_if/modem_link_device_usb.c index 14aee9f..9e6cbea 100644 --- a/drivers/misc/modem_if/modem_link_device_usb.c +++ b/drivers/misc/modem_if/modem_link_device_usb.c @@ -13,7 +13,7 @@ * */ -/* #define DEBUG */ +#define DEBUG #include <linux/init.h> #include <linux/module.h> @@ -26,7 +26,7 @@ #include <linux/platform_device.h> #include <linux/suspend.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_usb.h" #include "modem_utils.h" @@ -297,10 +297,15 @@ static void usb_change_modem_state(struct usb_link_device *usb_ld, enum modem_state state) { struct io_device *iod; + struct io_device *bootd; iod = link_get_iod_with_format(&usb_ld->ld, IPC_FMT); if (iod) iod->modem_state_changed(iod, state); + + bootd = usb_ld->ld.mc->bootd; + if (bootd) + bootd->modem_state_changed(bootd, state); } static int usb_tx_urb_with_skb(struct usb_link_device *usb_ld, @@ -624,7 +629,12 @@ static void if_usb_disconnect(struct usb_interface *intf) cancel_delayed_work_sync(&usb_ld->ld.tx_delayed_work); usb_put_dev(usbdev); usb_ld->usbdev = NULL; - pm_runtime_forbid(pm_data->root_hub); + if (!has_hub(usb_ld)) { + if (pm_data->root_hub) + pm_runtime_forbid(pm_data->root_hub); + schedule_delayed_work(&usb_ld->wait_enumeration, + WAIT_ENUMURATION_TIMEOUT_JIFFIES); + } } } diff --git a/drivers/misc/modem_if/modem_link_pm_usb.c b/drivers/misc/modem_if/modem_link_pm_usb.c index 75ad970..c63f08e 100644 --- a/drivers/misc/modem_if/modem_link_pm_usb.c +++ b/drivers/misc/modem_if/modem_link_pm_usb.c @@ -12,7 +12,7 @@ * */ -/* #define DEBUG */ +#define DEBUG #include <linux/init.h> #include <linux/module.h> @@ -27,12 +27,15 @@ #include "modem_link_pm_usb.h" +int during_hub_resume; + static inline void start_hub_work(struct link_pm_data *pm_data, int delay) { if (pm_data->hub_work_running == false) { pm_data->hub_work_running = true; wake_lock(&pm_data->hub_lock); mif_debug("link_pm_hub_work is started\n"); + during_hub_resume = 1; } schedule_delayed_work(&pm_data->link_pm_hub, msecs_to_jiffies(delay)); @@ -81,12 +84,13 @@ void link_pm_preactive(struct link_pm_data *pm_data) static void link_pm_hub_work(struct work_struct *work) { - int err; + int err, cnt; struct link_pm_data *pm_data = container_of(work, struct link_pm_data, link_pm_hub.work); if (pm_data->hub_status == HUB_STATE_ACTIVE) { end_hub_work(pm_data); + during_hub_resume = 0; return; } @@ -111,7 +115,16 @@ static void link_pm_hub_work(struct work_struct *work) /* skip 1st time before first probe */ if (pm_data->root_hub) pm_runtime_get_sync(pm_data->root_hub); - err = pm_data->port_enable(2, 1); + + for (cnt=0;cnt<5;cnt++) { + err = pm_data->port_enable(2, 1); + if (err >= 0) { + mif_err("hub on success\n"); + break; + } + mif_err("hub on fail %d th\n", cnt); + msleep(100); + } if (err < 0) { mif_err("hub on fail err=%d\n", err); err = pm_data->port_enable(2, 0); @@ -132,6 +145,8 @@ static void link_pm_hub_work(struct work_struct *work) pm_data->hub_status = HUB_STATE_OFF; if (pm_data->root_hub) pm_runtime_put_sync(pm_data->root_hub); + + mif_err("USB Hub resume fail !!!\n"); end_hub_work(pm_data); } else { mif_info("hub resumming: %d\n", @@ -164,9 +179,6 @@ static int link_pm_hub_standby(void *args) /* this function is atomic. * make force disconnect in workqueue.. */ - if (pm_data->usb_ld->if_usb_connected) - schedule_work(&usb_ld->disconnect_work); - return err; } @@ -210,6 +222,7 @@ static long link_pm_ioctl(struct file *file, unsigned int cmd, sizeof(int))) return -EFAULT; gpio_set_value(pm_data->gpio_link_active, value); + mif_info("> H-ACT %d\n", value); break; case IOCTL_LINK_GET_HOSTWAKE: return !gpio_get_value(pm_data->gpio_link_hostwake); @@ -233,7 +246,7 @@ static long link_pm_ioctl(struct file *file, unsigned int cmd, case IOCTL_LINK_PORT_OFF: err = link_pm_hub_standby(pm_data); if (err < 0) { - mif_err("usb3503 active fail\n"); + mif_err("usb3503 standby fail\n"); goto exit; } pm_data->hub_init_lock = 1; @@ -363,6 +376,8 @@ int link_pm_init(struct usb_link_device *usb_ld, void *data) pm_data->miscdev.name = "link_pm"; pm_data->miscdev.fops = &link_pm_fops; + during_hub_resume = 0; + err = misc_register(&pm_data->miscdev); if (err < 0) { mif_err("fail to register pm device(%d)\n", err); diff --git a/drivers/misc/modem_if/modem_link_pm_usb.h b/drivers/misc/modem_if/modem_link_pm_usb.h index d26af76..5fc762d 100644 --- a/drivers/misc/modem_if/modem_link_pm_usb.h +++ b/drivers/misc/modem_if/modem_link_pm_usb.h @@ -15,7 +15,7 @@ #ifndef __MODEM_LINK_PM_USB_H__ #define __MODEM_LINK_PM_USB_H__ -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_usb.h" diff --git a/drivers/misc/modem_if/modem_modemctl_device_cbp71.c b/drivers/misc/modem_if/modem_modemctl_device_cbp71.c index 28f2ce7..5a4db56 100644 --- a/drivers/misc/modem_if/modem_modemctl_device_cbp71.c +++ b/drivers/misc/modem_if/modem_modemctl_device_cbp71.c @@ -23,7 +23,7 @@ #include <linux/wait.h> #include <linux/sched.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_dpram.h" diff --git a/drivers/misc/modem_if/modem_modemctl_device_cbp72.c b/drivers/misc/modem_if/modem_modemctl_device_cbp72.c index 2617be8..d8f2af9 100644 --- a/drivers/misc/modem_if/modem_modemctl_device_cbp72.c +++ b/drivers/misc/modem_if/modem_modemctl_device_cbp72.c @@ -1,6 +1,4 @@ -/* /linux/drivers/misc/modem_if/modem_modemctl_device_cbp7.1.c - * - * Copyright (C) 2010 Google, Inc. +/* * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -24,14 +22,13 @@ #include <linux/sched.h> #include <linux/platform_device.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_link_device_dpram.h" #define PIF_TIMEOUT (180 * HZ) #define DPRAM_INIT_TIMEOUT (30 * HZ) - static irqreturn_t phone_active_handler(int irq, void *arg) { struct modem_ctl *mc = (struct modem_ctl *)arg; @@ -163,13 +160,13 @@ static int cbp72_boot_off(struct modem_ctl *mc) { int ret; struct link_device *ld = get_current_link(mc->bootd); - struct dpram_link_device *dpld = to_dpram_link_device(ld); + mif_debug("\n"); /* Wait here until the PHONE is up. * Waiting as the this called from IOCTL->UM thread */ mif_info("Waiting for INT_CMD_PHONE_START\n"); - ret = wait_for_completion_interruptible_timeout( - &dpld->dpram_init_cmd, DPRAM_INIT_TIMEOUT); + ret = wait_for_completion_interruptible_timeout(&ld->init_cmpl, + DPRAM_INIT_TIMEOUT); if (!ret) { /* ret == 0 on timeout, ret < 0 if interrupted */ mif_err("Timeout!!! (PHONE_START was not arrived.)\n"); @@ -177,8 +174,8 @@ static int cbp72_boot_off(struct modem_ctl *mc) } mif_info("Waiting for INT_CMD_PIF_INIT_DONE\n"); - ret = wait_for_completion_interruptible_timeout( - &dpld->modem_pif_init_done, PIF_TIMEOUT); + ret = wait_for_completion_interruptible_timeout(&ld->pif_cmpl, + PIF_TIMEOUT); if (!ret) { mif_err("Timeout!!! (PIF_INIT_DONE was not arrived.)\n"); return -ENXIO; @@ -199,10 +196,6 @@ static int cbp72_force_crash_exit(struct modem_ctl *mc) /* Make DUMP start */ ld->force_dump(ld, mc->bootd); - msleep_interruptible(1000); - - mc->bootd->modem_state_changed(mc->bootd, STATE_CRASH_EXIT); - return 0; } @@ -221,16 +214,15 @@ int cbp72_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) int ret = 0; int irq = 0; unsigned long flag = 0; - struct platform_device *pdev = NULL; - - mc->gpio_cp_on = pdata->gpio_cp_on; - mc->gpio_cp_off = pdata->gpio_cp_off; - mc->gpio_reset_req_n = pdata->gpio_reset_req_n; - mc->gpio_cp_reset = pdata->gpio_cp_reset; - mc->gpio_pda_active = pdata->gpio_pda_active; - mc->gpio_phone_active = pdata->gpio_phone_active; - mc->gpio_cp_dump_int = pdata->gpio_cp_dump_int; - mc->gpio_flm_uart_sel = pdata->gpio_flm_uart_sel; + + mc->gpio_cp_on = pdata->gpio_cp_on; + mc->gpio_cp_off = pdata->gpio_cp_off; + mc->gpio_reset_req_n = pdata->gpio_reset_req_n; + mc->gpio_cp_reset = pdata->gpio_cp_reset; + mc->gpio_pda_active = pdata->gpio_pda_active; + mc->gpio_phone_active = pdata->gpio_phone_active; + mc->gpio_cp_dump_int = pdata->gpio_cp_dump_int; + mc->gpio_flm_uart_sel = pdata->gpio_flm_uart_sel; mc->gpio_cp_warm_reset = pdata->gpio_cp_warm_reset; if (!mc->gpio_cp_on || !mc->gpio_cp_reset || !mc->gpio_phone_active) { @@ -245,10 +237,9 @@ int cbp72_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) cbp72_get_ops(mc); - pdev = to_platform_device(mc->dev); - mc->irq_phone_active = platform_get_irq_byname(pdev, "cp_active_irq"); + mc->irq_phone_active = pdata->irq_phone_active; if (!mc->irq_phone_active) { - mif_err("get irq fail\n"); + mif_err("get irq_phone_active fail\n"); return -1; } diff --git a/drivers/misc/modem_if/modem_modemctl_device_cbp82.c b/drivers/misc/modem_if/modem_modemctl_device_cbp82.c new file mode 100644 index 0000000..dc5799e --- /dev/null +++ b/drivers/misc/modem_if/modem_modemctl_device_cbp82.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2010 Samsung Electronics. + * + * 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/init.h> + +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/platform_device.h> + +#include "modem.h" +#include "modem_prj.h" +#include "modem_utils.h" + +#define DPRAM_INIT_TIMEOUT (30 * HZ) +#define PIF_TIMEOUT (180 * HZ) + +static irqreturn_t phone_active_handler(int irq, void *arg) +{ + struct modem_ctl *mc = (struct modem_ctl *)arg; + int cp_on = gpio_get_value(mc->gpio_cp_on); + int cp_reset = gpio_get_value(mc->gpio_cp_reset); + int cp_active = gpio_get_value(mc->gpio_phone_active); + int old_state = mc->phone_state; + int new_state = mc->phone_state; + + mif_info("old_state:%s cp_on:%d cp_reset:%d cp_active:%d\n", + get_cp_state_str(old_state), cp_on, cp_reset, cp_active); + + if (cp_reset && cp_active) { + if (mc->phone_state == STATE_BOOTING) { + new_state = STATE_ONLINE; + mc->bootd->modem_state_changed(mc->bootd, new_state); + } + } else if (cp_reset && !cp_active) { + if (mc->phone_state == STATE_ONLINE) { + new_state = STATE_CRASH_EXIT; + mc->bootd->modem_state_changed(mc->bootd, new_state); + } + } else { + new_state = STATE_OFFLINE; + if (mc->bootd && mc->bootd->modem_state_changed) + mc->bootd->modem_state_changed(mc->bootd, new_state); + } + + if (new_state != old_state) { + mif_err("%s: phone_state changed (%s -> %s\n)", + mc->name, get_cp_state_str(old_state), + get_cp_state_str(new_state)); + } + + return IRQ_HANDLED; +} + +static int cbp82_on(struct modem_ctl *mc) +{ + int cp_on = gpio_get_value(mc->gpio_cp_on); + int cp_off = gpio_get_value(mc->gpio_cp_off); + int cp_reset = gpio_get_value(mc->gpio_cp_reset); + int cp_active = gpio_get_value(mc->gpio_phone_active); + mif_err("+++\n"); + + mif_err("phone_state:%s cp_on:%d cp_off:%d cp_reset:%d cp_active:%d\n", + get_cp_state_str(mc->phone_state), cp_on, cp_off, cp_reset, + cp_active); + + /* prevent sleep during bootloader downloading */ + if (!wake_lock_active(&mc->mc_wake_lock)) + wake_lock(&mc->mc_wake_lock); + + gpio_set_value(mc->gpio_cp_on, 0); + gpio_set_value(mc->gpio_cp_off, 1); + gpio_set_value(mc->gpio_cp_reset, 0); + + msleep(500); + + cp_on = gpio_get_value(mc->gpio_cp_on); + cp_off = gpio_get_value(mc->gpio_cp_off); + cp_reset = gpio_get_value(mc->gpio_cp_reset); + cp_active = gpio_get_value(mc->gpio_phone_active); + mif_err("phone_state:%s cp_on:%d cp_off:%d cp_reset:%d cp_active:%d\n", + get_cp_state_str(mc->phone_state), cp_on, cp_off, cp_reset, + cp_active); + + gpio_set_value(mc->gpio_cp_off, 0); + gpio_set_value(mc->gpio_cp_on, 1); + + msleep(100); + + gpio_set_value(mc->gpio_cp_reset, 1); + + msleep(300); + + cp_on = gpio_get_value(mc->gpio_cp_on); + cp_off = gpio_get_value(mc->gpio_cp_off); + cp_reset = gpio_get_value(mc->gpio_cp_reset); + cp_active = gpio_get_value(mc->gpio_phone_active); + mif_err("phone_state:%s cp_on:%d cp_off:%d cp_reset:%d cp_active:%d\n", + get_cp_state_str(mc->phone_state), cp_on, cp_off, cp_reset, + cp_active); + + if (mc->gpio_pda_active) + gpio_set_value(mc->gpio_pda_active, 1); + + if (mc->bootd) + mc->bootd->modem_state_changed(mc->bootd, STATE_BOOTING); + else + mif_err("no mc->bootd\n"); + + mif_err("---\n"); + return 0; +} + +static int cbp82_off(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->bootd); + mif_err("+++\n"); + + gpio_set_value(mc->gpio_cp_reset, 0); + gpio_set_value(mc->gpio_cp_on, 0); + gpio_set_value(mc->gpio_cp_off, 1); + + mc->bootd->modem_state_changed(mc->bootd, STATE_OFFLINE); + ld->mode = LINK_MODE_OFFLINE; + + mif_err("---\n"); + return 0; +} + +static int cbp82_reset(struct modem_ctl *mc) +{ + int ret = 0; + + mif_debug("cbp82_reset()\n"); + + ret = cbp82_off(mc); + if (ret) + return -ENXIO; + + msleep(100); + + ret = cbp82_on(mc); + if (ret) + return -ENXIO; + + return 0; +} + +static int cbp82_boot_on(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->bootd); + mif_info("+++\n"); + + ld->mode = LINK_MODE_BOOT; + + mif_info("---\n"); + return 0; +} + +static int cbp82_boot_off(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->bootd); + int ret; + mif_err("+++\n"); + + /* Wait here until the PHONE is up. + * Waiting as the this called from IOCTL->UM thread */ + mif_err("Waiting for PHONE_START\n"); + ret = wait_for_completion_timeout(&ld->init_cmpl, DPRAM_INIT_TIMEOUT); + if (!ret) { + /* ret == 0 on timeout */ + mif_err("T-I-M-E-O-U-T (PHONE_START)\n"); + cbp82_off(mc); + ret = -EIO; + goto exit; + } + mif_err("recv PHONE_START\n"); + + mif_err("Waiting for PIF_INIT_DONE\n"); + ret = wait_for_completion_timeout(&ld->pif_cmpl, PIF_TIMEOUT); + if (!ret) { + /* ret == 0 on timeout */ + mif_err("T-I-M-E-O-U-T (PIF_INIT_DONE)!!!\n"); + cbp82_off(mc); + ret = -EIO; + goto exit; + } + mif_err("recv PIF_INIT_DONE\n"); + + mc->bootd->modem_state_changed(mc->bootd, STATE_ONLINE); + ret = 0; + +exit: + wake_unlock(&mc->mc_wake_lock); + mif_err("---\n"); + return ret; +} + +static int cbp82_force_crash_exit(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->bootd); + + mif_err("device = %s\n", mc->bootd->name); + + /* Make DUMP start */ + ld->force_dump(ld, mc->bootd); + + return 0; +} + +static void cbp82_get_ops(struct modem_ctl *mc) +{ + mc->ops.modem_on = cbp82_on; + mc->ops.modem_off = cbp82_off; + mc->ops.modem_reset = cbp82_reset; + mc->ops.modem_boot_on = cbp82_boot_on; + mc->ops.modem_boot_off = cbp82_boot_off; + mc->ops.modem_force_crash_exit = cbp82_force_crash_exit; +} + +int cbp82_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) +{ + int ret = 0; + int irq = 0; + unsigned long flag = 0; + mif_err("+++\n"); + + mc->gpio_cp_on = pdata->gpio_cp_on; + mc->gpio_cp_off = pdata->gpio_cp_off; + mc->gpio_cp_reset = pdata->gpio_cp_reset; + mc->gpio_phone_active = pdata->gpio_phone_active; + + if (!mc->gpio_cp_on || !mc->gpio_cp_off || !mc->gpio_cp_reset + || !mc->gpio_phone_active) { + mif_err("no GPIO data\n"); + mif_err("---\n"); + return -ENXIO; + } + + mc->gpio_pda_active = pdata->gpio_pda_active; + + gpio_set_value(mc->gpio_cp_reset, 0); + gpio_set_value(mc->gpio_cp_off, 1); + gpio_set_value(mc->gpio_cp_on, 0); + + cbp82_get_ops(mc); + + wake_lock_init(&mc->mc_wake_lock, WAKE_LOCK_SUSPEND, "cbp82_wake_lock"); + + mc->irq_phone_active = pdata->irq_phone_active; + if (!mc->irq_phone_active) { + mif_err("get irq fail\n"); + mif_err("---\n"); + return -1; + } + mif_info("PHONE_ACTIVE IRQ# = %d\n", mc->irq_phone_active); + + irq = mc->irq_phone_active; + flag = IRQF_NO_SUSPEND | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + ret = request_irq(irq, phone_active_handler, flag, "cdma_active", mc); + if (ret) { + mif_err("request_irq fail (%d)\n", ret); + mif_err("---\n"); + return ret; + } + + ret = enable_irq_wake(irq); + if (ret) + mif_err("enable_irq_wake fail (%d)\n", ret); + + mif_err("---\n"); + return 0; +} + diff --git a/drivers/misc/modem_if/modem_modemctl_device_cmc221.c b/drivers/misc/modem_if/modem_modemctl_device_cmc221.c index fe8ce69..a960edb 100644 --- a/drivers/misc/modem_if/modem_modemctl_device_cmc221.c +++ b/drivers/misc/modem_if/modem_modemctl_device_cmc221.c @@ -1,6 +1,4 @@ -/* /linux/drivers/misc/modem_if/modem_modemctl_device_cmc221.c - * - * Copyright (C) 2010 Google, Inc. +/* * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -13,15 +11,15 @@ * GNU General Public License for more details. * */ -#include <linux/init.h> +#include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/gpio.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include "modem.h" -#include <linux/platform_data/modem.h> #include "modem_prj.h" #include "modem_link_device_usb.h" #include "modem_link_device_dpram.h" @@ -77,7 +75,7 @@ static irqreturn_t phone_active_handler(int irq, void *arg) static irqreturn_t dynamic_switching_handler(int irq, void *arg) { struct modem_ctl *mc = (struct modem_ctl *)arg; - int txpath = gpio_get_value(mc->gpio_dynamic_switching); + int txpath = gpio_get_value(mc->gpio_link_switch); bool enumerated = usb_is_enumerated(mc->msd); mif_err("txpath=%d, enumeration=%d\n", txpath, enumerated); @@ -94,6 +92,52 @@ static irqreturn_t dynamic_switching_handler(int irq, void *arg) return IRQ_HANDLED; } +#ifdef CONFIG_EXYNOS4_CPUFREQ /* Set cpu clock to 800MHz for high TP */ +static void cmc221_cpufreq_lock(struct work_struct *work) +{ + struct modem_ctl *mc; + + mc = container_of(work, struct modem_ctl, work_cpu_lock.work); + if (mc->mdm_data->link_pm_data->freq_lock) { + mif_debug("Call freq lock func.\n"); + mc->mdm_data->link_pm_data->freq_lock(mc->dev); + + cancel_delayed_work(&mc->work_cpu_unlock); + schedule_delayed_work(&mc->work_cpu_unlock, + msecs_to_jiffies(5000)); + } +} + +static void cmc221_cpufreq_unlock(struct work_struct *work) +{ + struct modem_ctl *mc; + int tp_level; + + mc = container_of(work, struct modem_ctl, work_cpu_unlock.work); + tp_level = gpio_get_value(mc->gpio_cpufreq_lock); + + mif_debug("TP Level is (%d)\n", tp_level); + if (tp_level) { + mif_debug("maintain cpufreq lock !!!\n"); + schedule_delayed_work(&mc->work_cpu_unlock, + msecs_to_jiffies(5000)); + } else { + if (mc->mdm_data->link_pm_data->freq_unlock) { + mif_debug("Call freq unlock func.\n"); + mc->mdm_data->link_pm_data->freq_unlock(mc->dev); + } + } +} + +static irqreturn_t cpufreq_lock_handler(int irq, void *arg) +{ + struct modem_ctl *mc = (struct modem_ctl *)arg; + + schedule_delayed_work(&mc->work_cpu_lock, 0); + return IRQ_HANDLED; +} +#endif + static int cmc221_on(struct modem_ctl *mc) { struct link_device *ld = get_current_link(mc->iod); @@ -204,11 +248,10 @@ static int cmc221_boot_off(struct modem_ctl *mc) { int ret; struct link_device *ld = get_current_link(mc->bootd); - struct dpram_link_device *dpld = to_dpram_link_device(ld); mif_err("%s\n", mc->name); - ret = wait_for_completion_interruptible_timeout(&dpld->dpram_init_cmd, + ret = wait_for_completion_interruptible_timeout(&ld->init_cmpl, DPRAM_INIT_TIMEOUT); if (!ret) { /* ret == 0 on timeout, ret < 0 if interrupted */ @@ -249,22 +292,23 @@ int cmc221_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) int ret = 0; int irq = 0; unsigned long flag = 0; - struct platform_device *pdev = NULL; - mc->gpio_cp_on = pdata->gpio_cp_on; - mc->gpio_cp_reset = pdata->gpio_cp_reset; + mc->gpio_cp_on = pdata->gpio_cp_on; + mc->gpio_cp_reset = pdata->gpio_cp_reset; mc->gpio_phone_active = pdata->gpio_phone_active; - mc->gpio_pda_active = pdata->gpio_pda_active; + mc->gpio_pda_active = pdata->gpio_pda_active; #if 0 /*TODO: check the GPIO map*/ - mc->gpio_cp_dump_int = pdata->gpio_cp_dump_int; + mc->gpio_cp_dump_int = pdata->gpio_cp_dump_int; mc->gpio_flm_uart_sel = pdata->gpio_flm_uart_sel; mc->gpio_slave_wakeup = pdata->gpio_slave_wakeup; - mc->gpio_host_active = pdata->gpio_host_active; - mc->gpio_host_wakeup = pdata->gpio_host_wakeup; + mc->gpio_host_active = pdata->gpio_host_active; + mc->gpio_host_wakeup = pdata->gpio_host_wakeup; #endif - mc->gpio_dynamic_switching = pdata->gpio_dynamic_switching; + mc->gpio_link_switch = pdata->gpio_link_switch; mc->need_switch_to_usb = false; - +#ifdef CONFIG_EXYNOS4_CPUFREQ + mc->gpio_cpufreq_lock = pdata->gpio_cpufreq_lock; +#endif if (!mc->gpio_cp_on || !mc->gpio_cp_reset || !mc->gpio_phone_active) { mif_err("%s: ERR! no GPIO data\n", mc->name); return -ENXIO; @@ -276,10 +320,9 @@ int cmc221_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) cmc221_get_ops(mc); dev_set_drvdata(mc->dev, mc); - pdev = to_platform_device(mc->dev); - mc->irq_phone_active = platform_get_irq_byname(pdev, "cp_active_irq"); + mc->irq_phone_active = pdata->irq_phone_active; if (!mc->irq_phone_active) { - mif_err("%s: ERR! get cp_active_irq fail\n", mc->name); + mif_err("%s: ERR! get irq_phone_active fail\n", mc->name); return -1; } mif_err("%s: PHONE_ACTIVE IRQ# = %d\n", mc->name, mc->irq_phone_active); @@ -301,8 +344,8 @@ int cmc221_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) } flag = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND; - if (mc->gpio_dynamic_switching) { - irq = gpio_to_irq(mc->gpio_dynamic_switching); + if (mc->gpio_link_switch) { + irq = gpio_to_irq(mc->gpio_link_switch); mif_err("%s: DYNAMIC_SWITCH IRQ# = %d\n", mc->name, irq); ret = request_irq(irq, dynamic_switching_handler, flag, "dynamic_switching", mc); @@ -313,5 +356,23 @@ int cmc221_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) } } +#ifdef CONFIG_EXYNOS4_CPUFREQ + INIT_DELAYED_WORK(&mc->work_cpu_lock, cmc221_cpufreq_lock); + INIT_DELAYED_WORK(&mc->work_cpu_unlock, cmc221_cpufreq_unlock); + + flag = IRQF_TRIGGER_RISING; + if (mc->gpio_cpufreq_lock) { + irq = gpio_to_irq(mc->gpio_cpufreq_lock); + mif_err("%s: CPUFREQ_LOCK_CNT IRQ# = %d\n", mc->name, irq); + ret = request_irq(irq, cpufreq_lock_handler, flag, + "cpufreq_lock", mc); + if (ret) { + mif_err("%s: ERR! request_irq(#%d) fail (err %d)\n", + mc->name, irq, ret); + return ret; + } + } +#endif + return 0; } diff --git a/drivers/misc/modem_if/modem_modemctl_device_esc6270.c b/drivers/misc/modem_if/modem_modemctl_device_esc6270.c index 5a42755..79cdd95 100644 --- a/drivers/misc/modem_if/modem_modemctl_device_esc6270.c +++ b/drivers/misc/modem_if/modem_modemctl_device_esc6270.c @@ -24,7 +24,7 @@ #include <linux/sched.h> #include <linux/platform_device.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include <linux/regulator/consumer.h> @@ -115,6 +115,13 @@ static int esc6270_reset(struct modem_ctl *mc) int esc6270_boot_on(struct modem_ctl *mc) { struct link_device *ld = get_current_link(mc->iod); +#if defined(CONFIG_LINK_DEVICE_DPRAM) + /* clear intr */ + struct dpram_link_device *dpld = to_dpram_link_device(ld); + u16 recv_msg = dpld->recv_intr(dpld); + + pr_info("[MODEM_IF:ESC] dpram intr: %x\n", recv_msg); +#endif pr_info("[MODEM_IF:ESC] <%s>\n", __func__); @@ -273,8 +280,11 @@ int esc6270_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) gpio_set_value(mc->gpio_cp_reset, 0); gpio_set_value(mc->gpio_cp_on, 0); - pdev = to_platform_device(mc->dev); - mc->irq_phone_active = platform_get_irq_byname(pdev, "cp_active_irq"); + mc->irq_phone_active = pdata->irq_phone_active; + if (!mc->irq_phone_active) { + mif_err("%s: ERR! get irq_phone_active fail\n", mc->name); + return -1; + } pr_info("[MODEM_IF:ESC] <%s> PHONE_ACTIVE IRQ# = %d\n", __func__, mc->irq_phone_active); @@ -302,7 +312,7 @@ int esc6270_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) } #if defined(CONFIG_SIM_DETECT) - mc->irq_sim_detect = platform_get_irq_byname(pdev, "sim_irq"); + mc->irq_sim_detect = pdata->irq_sim_detect; pr_info("[MODEM_IF:ESC] <%s> SIM_DECTCT IRQ# = %d\n", __func__, mc->irq_sim_detect); diff --git a/drivers/misc/modem_if/modem_modemctl_device_mdm6600.c b/drivers/misc/modem_if/modem_modemctl_device_mdm6600.c index ad44579..38bef9a 100644 --- a/drivers/misc/modem_if/modem_modemctl_device_mdm6600.c +++ b/drivers/misc/modem_if/modem_modemctl_device_mdm6600.c @@ -24,12 +24,14 @@ #include <linux/sched.h> #include <linux/platform_device.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include <linux/regulator/consumer.h> #include <plat/gpio-cfg.h> +#include "modem_link_device_pld.h" + #if defined(CONFIG_MACH_M0_CTC) #include <linux/mfd/max77693.h> #endif @@ -39,6 +41,8 @@ static int mdm6600_on(struct modem_ctl *mc) { + struct link_device *ld = get_current_link(mc->iod); + pr_info("[MODEM_IF] mdm6600_on()\n"); if (!mc->gpio_cp_reset || !mc->gpio_cp_reset_msm || !mc->gpio_cp_on) { @@ -58,6 +62,7 @@ static int mdm6600_on(struct modem_ctl *mc) gpio_set_value(mc->gpio_pda_active, 1); mc->iod->modem_state_changed(mc->iod, STATE_BOOTING); + ld->mode = LINK_MODE_BOOT; return 0; } @@ -82,7 +87,8 @@ static int mdm6600_off(struct modem_ctl *mc) static int mdm6600_reset(struct modem_ctl *mc) { - int ret; + struct link_device *ld = get_current_link(mc->iod); + /* int ret; */ pr_info("[MODEM_IF] mdm6600_reset()\n"); @@ -109,6 +115,9 @@ static int mdm6600_reset(struct modem_ctl *mc) msleep(40); /* > 37.2 + 2 msec */ } + mc->iod->modem_state_changed(mc->iod, STATE_BOOTING); + ld->mode = LINK_MODE_BOOT; + return 0; } @@ -159,6 +168,7 @@ static irqreturn_t phone_active_irq_handler(int irq, void *_mc) int cp_dump_value = 0; int phone_state = 0; struct modem_ctl *mc = (struct modem_ctl *)_mc; + struct link_device *ld; if (!mc->gpio_cp_reset || !mc->gpio_phone_active /*|| !mc->gpio_cp_dump_int */) { @@ -179,11 +189,6 @@ static irqreturn_t phone_active_irq_handler(int irq, void *_mc) } else if (phone_reset && !phone_active_value) { if (count == 1) { phone_state = STATE_CRASH_EXIT; - if (mc->iod) { - ld = get_current_link(mc->iod); - if (ld->terminate_comm) - ld->terminate_comm(ld, mc->iod); - } if (mc->iod && mc->iod->modem_state_changed) mc->iod->modem_state_changed (mc->iod, phone_state); @@ -226,8 +231,11 @@ int mdm6600_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) mc->vbus_on = pdata->vbus_on; mc->vbus_off = pdata->vbus_off; - pdev = to_platform_device(mc->dev); - mc->irq_phone_active = platform_get_irq_byname(pdev, "cp_active_irq"); + mc->irq_phone_active = pdata->irq_phone_active; + if (!mc->irq_phone_active) { + mif_err("%s: ERR! get irq_phone_active fail\n", mc->name); + return -1; + } pr_info("[MODEM_IF] <%s> PHONE_ACTIVE IRQ# = %d\n", __func__, mc->irq_phone_active); @@ -332,7 +340,7 @@ static int mdm6600_on(struct modem_ctl *mc) return -ENXIO; } - gpio_set_value(mc->gpio_pda_active, 0); + gpio_set_value(mc->gpio_pda_active, 1); gpio_set_value(mc->gpio_cp_on, 1); msleep(500); @@ -346,8 +354,6 @@ static int mdm6600_on(struct modem_ctl *mc) gpio_set_value(mc->gpio_cp_on, 0); msleep(500); - gpio_set_value(mc->gpio_pda_active, 1); - #if defined(CONFIG_LINK_DEVICE_PLD) gpio_set_value(mc->gpio_fpga_cs_n, 1); #endif @@ -420,9 +426,13 @@ static int mdm6600_reset(struct modem_ctl *mc) static int mdm6600_boot_on(struct modem_ctl *mc) { struct regulator *regulator; + struct link_device *ld = get_current_link(mc->iod); + struct pld_link_device *dpld = to_pld_link_device(ld); pr_info("[MSM] <%s>\n", __func__); + dpld->recv_intr(dpld); + if (!mc->gpio_flm_uart_sel) { pr_err("[MSM] no gpio data\n"); return -ENXIO; @@ -729,8 +739,11 @@ int mdm6600_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) gpio_set_value(mc->gpio_cp_reset, 0); gpio_set_value(mc->gpio_cp_on, 0); - pdev = to_platform_device(mc->dev); - mc->irq_phone_active = platform_get_irq_byname(pdev, "cp_active_irq"); + mc->irq_phone_active = pdata->irq_phone_active; + if (!mc->irq_phone_active) { + mif_err("%s: ERR! get irq_phone_active fail\n", mc->name); + return -1; + } pr_info("[MSM] <%s> PHONE_ACTIVE IRQ# = %d\n", __func__, mc->irq_phone_active); @@ -754,7 +767,7 @@ int mdm6600_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) } #if defined(CONFIG_SIM_DETECT) - mc->irq_sim_detect = platform_get_irq_byname(pdev, "sim_irq"); + mc->irq_sim_detect = pdata->irq_sim_detect; pr_info("[MSM] <%s> SIM_DECTCT IRQ# = %d\n", __func__, mc->irq_sim_detect); diff --git a/drivers/misc/modem_if/modem_modemctl_device_qsc6085.c b/drivers/misc/modem_if/modem_modemctl_device_qsc6085.c new file mode 100644 index 0000000..25d3cfe --- /dev/null +++ b/drivers/misc/modem_if/modem_modemctl_device_qsc6085.c @@ -0,0 +1,218 @@ +/* /linux/drivers/misc/modem_if/modem_modemctl_device_qsc6085.c + * + * Copyright (C) 2010 Samsung Electronics. + * + * 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/init.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/platform_device.h> +#include "modem.h" + +#include "modem_prj.h" +#include "modem_link_device_dpram.h" +#include "modem_utils.h" + +#define IDPRAM_NORMAL_BOOT_MAGIC 0x4D4E + +static irqreturn_t phone_active_irq_handler(int irq, void *arg) +{ + struct modem_ctl *mc = (struct modem_ctl *)arg; + int phone_reset = gpio_get_value(mc->gpio_cp_reset); + int phone_active = gpio_get_value(mc->gpio_phone_active); + int phone_state = mc->phone_state; + + pr_info("MIF: <%s> state = %d, phone_reset = %d, phone_active = %d\n", + __func__, phone_state, phone_reset, phone_active); + + if (phone_reset && phone_active) { + phone_state = STATE_ONLINE; + if (mc->phone_state != STATE_BOOTING) + mc->iod->modem_state_changed(mc->iod, phone_state); + } else if (phone_reset && !phone_active) { + if (mc->phone_state == STATE_ONLINE) { + phone_state = STATE_CRASH_EXIT; + mc->iod->modem_state_changed(mc->iod, phone_state); + } + } else { + phone_state = STATE_OFFLINE; + if (mc->iod && mc->iod->modem_state_changed) + mc->iod->modem_state_changed(mc->iod, phone_state); + } + + if (phone_active) + irq_set_irq_type(mc->irq_phone_active, IRQ_TYPE_LEVEL_LOW); + else + irq_set_irq_type(mc->irq_phone_active, IRQ_TYPE_LEVEL_HIGH); + + pr_info("MIF: <%s> phone_state = %d\n", __func__, phone_state); + + return IRQ_HANDLED; +} + +static void set_idpram_boot_magic(struct dpram_link_device *dpld) +{ + dpld->set_access(dpld, 0); + dpld->set_magic(dpld, IDPRAM_NORMAL_BOOT_MAGIC); + dpld->set_access(dpld, 1); +} + +static int qsc6085_on(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->iod); + struct dpram_link_device *dpld = to_dpram_link_device(ld); + + mif_err("+++\n"); + + if (!mc->gpio_cp_on || !mc->gpio_cp_reset) { + mif_err("no gpio_cp_on or no gpio_cp_reset\n"); + return -ENXIO; + } + + set_idpram_boot_magic(dpld); + + mc->iod->modem_state_changed(mc->iod, STATE_BOOTING); + + gpio_set_value(mc->gpio_cp_reset, 1); + gpio_set_value(mc->gpio_cp_on, 0); + + msleep(100); + + gpio_set_value(mc->gpio_cp_on, 1); + + msleep(400); + msleep(400); + msleep(200); + + gpio_set_value(mc->gpio_cp_on, 0); + + mif_err("---\n"); + return 0; +} + +static int qsc6085_off(struct modem_ctl *mc) +{ + int phone_wait_cnt = 0; + + pr_info("MIF: <%s+>\n", __func__); + + if (!mc->gpio_cp_on || !mc->gpio_cp_reset || + !mc->gpio_phone_active) { + pr_err("MIF: <%s> no gpio data\n", __func__); + return -ENXIO; + } + + gpio_set_value(mc->gpio_cp_on, 0); + + /* confirm phone off */ + while (1) { + if (gpio_get_value(mc->gpio_phone_active)) { + pr_err("MIF: <%s> Try to Turn Phone Off by CP_RST\n", + __func__); + gpio_set_value(mc->gpio_cp_reset, 0); + if (phone_wait_cnt > 10) { + pr_emerg("MIF: <%s> OFF Failed\n", __func__); + break; + } + phone_wait_cnt++; + mdelay(100); + } else { + pr_emerg("MIF: <%s> OFF Success\n", __func__); + break; + } + } + + mc->iod->modem_state_changed(mc->iod, STATE_OFFLINE); + + pr_info("MIF: <%s->\n", __func__); + + return 0; +} + +static int qsc6085_reset(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->iod); + struct dpram_link_device *dpld = to_dpram_link_device(ld); + + mif_err("+++\n"); + + set_idpram_boot_magic(dpld); + + gpio_set_value(mc->gpio_cp_reset, 0); + msleep(100); + gpio_set_value(mc->gpio_cp_reset, 1); + + mif_err("---\n"); + return 0; +} + +static int qsc6085_modem_dump_reset(struct modem_ctl *mc) +{ + pr_info("MIF: <%s>\n", __func__); + panic("CP Crashed"); +} + +static void qsc6085_get_ops(struct modem_ctl *mc) +{ + mc->ops.modem_on = qsc6085_on; + mc->ops.modem_off = qsc6085_off; + mc->ops.modem_reset = qsc6085_reset; + mc->ops.modem_dump_reset = qsc6085_modem_dump_reset; +} + +int qsc6085_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) +{ + int ret = 0; + unsigned long flag = 0; + + mc->gpio_cp_on = pdata->gpio_cp_on; + mc->gpio_cp_reset = pdata->gpio_cp_reset; + mc->gpio_pda_active = pdata->gpio_pda_active; + mc->gpio_phone_active = pdata->gpio_phone_active; + mc->gpio_cp_dump_int = pdata->gpio_cp_dump_int; + + if (!mc->gpio_cp_on || !mc->gpio_cp_reset || !mc->gpio_phone_active) { + mif_err("no GPIO data\n"); + return -ENXIO; + } + + mc->irq_phone_active = gpio_to_irq(mc->gpio_phone_active); + pr_err("MIF: <%s> PHONE_ACTIVE IRQ# = %d\n", + __func__, mc->irq_phone_active); + + qsc6085_get_ops(mc); + + /*register phone_active_handler*/ + flag = IRQF_TRIGGER_HIGH; + + ret = request_irq(mc->irq_phone_active, + phone_active_irq_handler, + flag, "phone_active", mc); + if (ret) { + pr_err("MIF: failed to irq_phone_active request_irq: %d\n" + , ret); + return ret; + } + + ret = enable_irq_wake(mc->irq_phone_active); + if (ret) { + pr_err("MIF: <%s> failed to enable_irq_wake:%d\n", + __func__, ret); + free_irq(mc->irq_phone_active, mc); + return ret; + } + return ret; +} diff --git a/drivers/misc/modem_if/modem_modemctl_device_sprd8803.c b/drivers/misc/modem_if/modem_modemctl_device_sprd8803.c index cfa2896..7a6e6fc 100644 --- a/drivers/misc/modem_if/modem_modemctl_device_sprd8803.c +++ b/drivers/misc/modem_if/modem_modemctl_device_sprd8803.c @@ -22,10 +22,13 @@ #include <linux/platform_device.h> #include <linux/cma.h> #include <plat/devs.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include <plat/gpio-cfg.h> +spinlock_t irq_lock; +int irq_lock_flag; + int sprd_boot_done; extern int spi_thread_restart(void); @@ -45,10 +48,20 @@ static int sprd8803_on(struct modem_ctl *mc) gpio_set_value(mc->gpio_cp_ctrl2, 1); #endif msleep(100); -// pr_info("[MODEM_IF] %s\n", __func__); // Kill spam + pr_info("[MODEM_IF] %s\n", __func__); gpio_set_value(mc->gpio_cp_on, 1); gpio_set_value(mc->gpio_pda_active, 1); + spin_lock(&irq_lock); + if (!irq_lock_flag) { + enable_irq(mc->irq_phone_active); + enable_irq(gpio_to_irq(mc->gpio_cp_dump_int)); + enable_irq_wake(mc->irq_phone_active); + enable_irq_wake(gpio_to_irq(mc->gpio_cp_dump_int)); + irq_lock_flag = 1; + } + spin_unlock(&irq_lock); + mc->phone_state = STATE_BOOTING; return 0; @@ -56,7 +69,7 @@ static int sprd8803_on(struct modem_ctl *mc) static int sprd8803_off(struct modem_ctl *mc) { - pr_debug("[MODEM_IF] %s\n", __func__); + pr_info("[MODEM_IF] %s\n", __func__); if (!mc->gpio_cp_on) { mif_err("no gpio data\n"); @@ -64,6 +77,17 @@ static int sprd8803_off(struct modem_ctl *mc) } gpio_set_value(mc->gpio_cp_on, 0); + gpio_set_value(mc->gpio_pda_active, 0); + + spin_lock(&irq_lock); + if (irq_lock_flag) { + disable_irq(mc->irq_phone_active); + disable_irq(gpio_to_irq(mc->gpio_cp_dump_int)); + disable_irq_wake(mc->irq_phone_active); + disable_irq_wake(gpio_to_irq(mc->gpio_cp_dump_int)); + irq_lock_flag = 0; + } + spin_unlock(&irq_lock); mc->phone_state = STATE_OFFLINE; @@ -72,7 +96,7 @@ static int sprd8803_off(struct modem_ctl *mc) static int sprd8803_reset(struct modem_ctl *mc) { - pr_debug("[MODEM_IF] %s\n", __func__); + pr_info("[MODEM_IF] %s\n", __func__); spi_thread_restart(); @@ -81,20 +105,20 @@ static int sprd8803_reset(struct modem_ctl *mc) static int sprd8803_boot_on(struct modem_ctl *mc) { - pr_debug("[MODEM_IF] %s %d\n", __func__, sprd_boot_done); - return sprd_boot_done; + pr_info("[MODEM_IF] %s %d\n", __func__, mc->phone_state); + return mc->phone_state; } static int sprd8803_boot_off(struct modem_ctl *mc) { - pr_debug("[MODEM_IF] %s\n", __func__); + pr_info("[MODEM_IF] %s\n", __func__); spi_sema_init(); return 0; } static int sprd8803_dump_reset(struct modem_ctl *mc) { - pr_debug("[MODEM_IF] %s\n", __func__); + pr_info("[MODEM_IF] %s\n", __func__); if (!mc->gpio_ap_cp_int2) return -ENXIO; @@ -115,6 +139,8 @@ static irqreturn_t phone_active_irq_handler(int irq, void *_mc) int phone_state = 0; struct modem_ctl *mc = (struct modem_ctl *)_mc; + disable_irq_nosync(mc->irq_phone_active); + if (!mc->gpio_phone_active || !mc->gpio_cp_dump_int) { pr_err("[MODEM_IF] no gpio data\n"); @@ -135,7 +161,7 @@ static irqreturn_t phone_active_irq_handler(int irq, void *_mc) else phone_state = STATE_OFFLINE; - if (cp_dump_value) + if (phone_active_value && cp_dump_value) phone_state = STATE_CRASH_EXIT; if (mc->iod && mc->iod->modem_state_changed) @@ -145,6 +171,8 @@ static irqreturn_t phone_active_irq_handler(int irq, void *_mc) mc->bootd->modem_state_changed(mc->bootd, phone_state); exit: + enable_irq(mc->irq_phone_active); + return IRQ_HANDLED; } @@ -217,5 +245,19 @@ int sprd8803_init_modemctl_device(struct modem_ctl *mc, __func__, ret); free_irq(irq_cp_dump_int, mc); } + + irq_lock_flag = 1; + spin_lock_init(&irq_lock); + + spin_lock(&irq_lock); + if (irq_lock_flag) { + disable_irq(mc->irq_phone_active); + disable_irq(gpio_to_irq(mc->gpio_cp_dump_int)); + disable_irq_wake(mc->irq_phone_active); + disable_irq_wake(gpio_to_irq(mc->gpio_cp_dump_int)); + irq_lock_flag = 0; + } + spin_unlock(&irq_lock); + return ret; } diff --git a/drivers/misc/modem_if/modem_modemctl_device_ss222.c b/drivers/misc/modem_if/modem_modemctl_device_ss222.c new file mode 100644 index 0000000..5dbda45 --- /dev/null +++ b/drivers/misc/modem_if/modem_modemctl_device_ss222.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2010 Samsung Electronics. + * + * 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/init.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/platform_device.h> + +#include <mach/c2c.h> +#include "modem.h" +#include "modem_prj.h" +#include "modem_utils.h" + +#define MIF_INIT_TIMEOUT (30 * HZ) + +static void ss222_mc_state_fsm(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->iod); + int cp_on = gpio_get_value(mc->gpio_cp_on); + int cp_reset = gpio_get_value(mc->gpio_cp_reset); + int cp_active = gpio_get_value(mc->gpio_phone_active); + int old_state = mc->phone_state; + int new_state = mc->phone_state; + + mif_err("old_state:%s cp_on:%d cp_reset:%d cp_active:%d\n", + get_cp_state_str(old_state), cp_on, cp_reset, cp_active); + + if (cp_active) { + if (!cp_on) { + new_state = STATE_OFFLINE; + ld->mode = LINK_MODE_OFFLINE; + } else if (old_state == STATE_ONLINE) { + new_state = STATE_CRASH_EXIT; + ld->mode = LINK_MODE_ULOAD; + } else { + mif_err("don't care!!!\n"); + } + } + + if (old_state != new_state) { + mif_err("new_state = %s\n", get_cp_state_str(new_state)); + mc->bootd->modem_state_changed(mc->bootd, new_state); + mc->iod->modem_state_changed(mc->iod, new_state); + } +} + +static irqreturn_t phone_active_handler(int irq, void *arg) +{ + struct modem_ctl *mc = (struct modem_ctl *)arg; + int cp_reset = gpio_get_value(mc->gpio_cp_reset); + + if (cp_reset) + ss222_mc_state_fsm(mc); + + return IRQ_HANDLED; +} + +static inline void make_gpio_floating(int gpio, bool floating) +{ + if (floating) + gpio_direction_input(gpio); + else + gpio_direction_output(gpio, 0); +} + +static int ss222_on(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->iod); + int cp_on = gpio_get_value(mc->gpio_cp_on); + int cp_off = gpio_get_value(mc->gpio_cp_off); + int cp_reset = gpio_get_value(mc->gpio_cp_reset); + int cp_active = gpio_get_value(mc->gpio_phone_active); + int cp_status = gpio_get_value(mc->gpio_cp_status); + mif_err("+++\n"); + mif_err("cp_on:%d cp_reset:%d ps_hold:%d cp_active:%d cp_status:%d\n", + cp_on, cp_reset, cp_off, cp_active, cp_status); + + gpio_set_value(mc->gpio_pda_active, 1); + + if (!wake_lock_active(&mc->mc_wake_lock)) + wake_lock(&mc->mc_wake_lock); + + mc->phone_state = STATE_OFFLINE; + ld->mode = LINK_MODE_OFFLINE; + + /* Make PS_HOLD floating (Hi-Z) for CP ON */ + make_gpio_floating(mc->gpio_cp_off, true); + + gpio_set_value(mc->gpio_cp_on, 0); + msleep(100); + + gpio_set_value(mc->gpio_cp_reset, 0); + msleep(500); + + gpio_set_value(mc->gpio_cp_on, 1); + msleep(100); + + c2c_reload(); + gpio_set_value(mc->gpio_cp_reset, 1); + msleep(300); + + mif_err("---\n"); + return 0; +} + +static int ss222_off(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->iod); + int cp_on = gpio_get_value(mc->gpio_cp_on); + mif_err("+++\n"); + + if (mc->phone_state == STATE_OFFLINE || cp_on == 0) + return 0; + + mc->phone_state = STATE_OFFLINE; + ld->mode = LINK_MODE_OFFLINE; + + gpio_set_value(mc->gpio_cp_reset, 0); + + /* Make PS_HOLD LOW for CP OFF */ + make_gpio_floating(mc->gpio_cp_off, false); + gpio_set_value(mc->gpio_cp_on, 0); + + mif_err("---\n"); + return 0; +} + +static int ss222_reset(struct modem_ctl *mc) +{ + mif_err("+++\n"); + + if (ss222_off(mc)) + return -EIO; + + msleep(100); + + if (ss222_on(mc)) + return -EIO; + + mif_err("---\n"); + return 0; +} + +static int ss222_force_crash_exit(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->bootd); + mif_err("+++\n"); + + /* Make DUMP start */ + ld->force_dump(ld, mc->bootd); + + mif_err("---\n"); + return 0; +} + +static int ss222_dump_reset(struct modem_ctl *mc) +{ + unsigned int gpio_cp_reset = mc->gpio_cp_reset; + mif_err("+++\n"); + + if (!wake_lock_active(&mc->mc_wake_lock)) + wake_lock(&mc->mc_wake_lock); + + gpio_set_value(gpio_cp_reset, 0); + udelay(200); + + c2c_reload(); + gpio_set_value(gpio_cp_reset, 1); + msleep(300); + + gpio_set_value(mc->gpio_ap_status, 1); + + mif_err("---\n"); + return 0; +} + +static int ss222_boot_on(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->bootd); + mif_debug("+++\n"); + + disable_irq_nosync(mc->irq_phone_active); + + gpio_set_value(mc->gpio_ap_status, 1); + + ld->mode = LINK_MODE_BOOT; + + mc->bootd->modem_state_changed(mc->bootd, STATE_BOOTING); + mc->iod->modem_state_changed(mc->iod, STATE_BOOTING); + + INIT_COMPLETION(ld->init_cmpl); + + mif_debug("---\n"); + return 0; +} + +static int ss222_boot_off(struct modem_ctl *mc) +{ + struct link_device *ld = get_current_link(mc->bootd); + unsigned long remain; + mif_debug("+++\n"); + + ld->mode = LINK_MODE_IPC; + + remain = wait_for_completion_timeout(&ld->init_cmpl, MIF_INIT_TIMEOUT); + if (remain == 0) { + mif_err("T-I-M-E-O-U-T\n"); + mif_err("xxx\n"); + return -EAGAIN; + } + + mif_debug("---\n"); + return 0; +} + +static int ss222_boot_done(struct modem_ctl *mc) +{ + mif_debug("+++\n"); + + if (wake_lock_active(&mc->mc_wake_lock)) + wake_unlock(&mc->mc_wake_lock); + + enable_irq(mc->irq_phone_active); + + mif_debug("---\n"); + return 0; +} + +static void ss222_get_ops(struct modem_ctl *mc) +{ + mc->ops.modem_on = ss222_on; + mc->ops.modem_off = ss222_off; + mc->ops.modem_reset = ss222_reset; + mc->ops.modem_boot_on = ss222_boot_on; + mc->ops.modem_boot_off = ss222_boot_off; + mc->ops.modem_boot_done = ss222_boot_done; + mc->ops.modem_force_crash_exit = ss222_force_crash_exit; + mc->ops.modem_dump_reset = ss222_dump_reset; +} + +int ss222_init_modemctl_device(struct modem_ctl *mc, struct modem_data *pdata) +{ + int ret = 0; + int irq = 0; + unsigned long flag = 0; + mif_debug("+++\n"); + + if (!pdata->gpio_cp_on || !pdata->gpio_cp_off || !pdata->gpio_cp_reset + || !pdata->gpio_pda_active || !pdata->gpio_phone_active + || !pdata->gpio_ap_wakeup || !pdata->gpio_ap_status + || !pdata->gpio_cp_wakeup || !pdata->gpio_cp_status) { + mif_err("ERR! no GPIO data\n"); + mif_err("xxx\n"); + return -ENXIO; + } + + mc->gpio_cp_on = pdata->gpio_cp_on; + mc->gpio_cp_off = pdata->gpio_cp_off; + mc->gpio_cp_reset = pdata->gpio_cp_reset; + mc->gpio_pda_active = pdata->gpio_pda_active; + mc->gpio_phone_active = pdata->gpio_phone_active; + mc->gpio_ap_wakeup = pdata->gpio_ap_wakeup; + mc->gpio_ap_status = pdata->gpio_ap_status; + mc->gpio_cp_wakeup = pdata->gpio_cp_wakeup; + mc->gpio_cp_status = pdata->gpio_cp_status; + + gpio_set_value(mc->gpio_cp_reset, 0); + + gpio_set_value(mc->gpio_cp_on, 0); + + ss222_get_ops(mc); + dev_set_drvdata(mc->dev, mc); + + wake_lock_init(&mc->mc_wake_lock, WAKE_LOCK_SUSPEND, "umts_wake_lock"); + + mc->irq_phone_active = pdata->irq_phone_active; + if (!mc->irq_phone_active) { + mif_err("ERR! no irq_phone_active\n"); + mif_err("xxx\n"); + return -1; + } + mif_err("PHONE_ACTIVE IRQ# = %d\n", mc->irq_phone_active); + + irq = mc->irq_phone_active; + flag = IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND; + ret = request_irq(irq, phone_active_handler, flag, "umts_active", mc); + if (ret) { + mif_err("ERR! request_irq(#%d) fail (err %d)\n", irq, ret); + mif_err("xxx\n"); + return ret; + } + ret = enable_irq_wake(irq); + if (ret) + mif_err("enable_irq_wake(#%d) fail (err %d)\n", irq, ret); + + mif_debug("---\n"); + return 0; +} + diff --git a/drivers/misc/modem_if/modem_modemctl_device_xmm6260.c b/drivers/misc/modem_if/modem_modemctl_device_xmm6260.c index d2fcf5b..9741f59 100644 --- a/drivers/misc/modem_if/modem_modemctl_device_xmm6260.c +++ b/drivers/misc/modem_if/modem_modemctl_device_xmm6260.c @@ -22,12 +22,12 @@ #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" static int xmm6260_on(struct modem_ctl *mc) { - mif_debug("xmm6260_on()\n"); + mif_info("xmm6260_on()\n"); if (!mc->gpio_cp_reset || !mc->gpio_cp_on || !mc->gpio_reset_req_n) { mif_err("no gpio data\n"); @@ -66,7 +66,7 @@ static int xmm6260_on(struct modem_ctl *mc) static int xmm6260_off(struct modem_ctl *mc) { - mif_debug("xmm6260_off()\n"); + mif_info("xmm6260_off()\n"); if (!mc->gpio_cp_reset || !mc->gpio_cp_on) { mif_err("no gpio data\n"); @@ -85,7 +85,7 @@ static int xmm6260_off(struct modem_ctl *mc) static int xmm6260_reset(struct modem_ctl *mc) { - mif_debug("xmm6260_reset()\n"); + mif_info("xmm6260_reset()\n"); if (!mc->gpio_cp_reset || !mc->gpio_reset_req_n) return -ENXIO; @@ -122,7 +122,7 @@ static int xmm6260_reset(struct modem_ctl *mc) static int xmm6260_boot_on(struct modem_ctl *mc) { - mif_debug("xmm6260_boot_on()\n"); + mif_info("xmm6260_boot_on()\n"); if (!mc->gpio_flm_uart_sel) { mif_err("no gpio data\n"); @@ -136,7 +136,7 @@ static int xmm6260_boot_on(struct modem_ctl *mc) static int xmm6260_boot_off(struct modem_ctl *mc) { - mif_debug("xmm6260_boot_off()\n"); + mif_info("xmm6260_boot_off()\n"); if (!mc->gpio_flm_uart_sel) { mif_err("no gpio data\n"); diff --git a/drivers/misc/modem_if/modem_modemctl_device_xmm6262.c b/drivers/misc/modem_if/modem_modemctl_device_xmm6262.c index 4d0b69c..5473aad 100644 --- a/drivers/misc/modem_if/modem_modemctl_device_xmm6262.c +++ b/drivers/misc/modem_if/modem_modemctl_device_xmm6262.c @@ -24,9 +24,11 @@ #include <linux/platform_device.h> #include <linux/cma.h> #include <plat/devs.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" - +#ifdef CONFIG_FAST_BOOT +#include <linux/fake_shut_down.h> +#endif static int xmm6262_on(struct modem_ctl *mc) { mif_info("\n"); @@ -59,11 +61,13 @@ static int xmm6262_on(struct modem_ctl *mc) udelay(60); gpio_set_value(mc->gpio_cp_on, 0); msleep(20); + + mc->phone_state = STATE_BOOTING; + if (mc->gpio_revers_bias_restore) mc->gpio_revers_bias_restore(); gpio_set_value(mc->gpio_pda_active, 1); - mc->phone_state = STATE_BOOTING; return 0; } @@ -120,6 +124,20 @@ static int xmm6262_reset(struct modem_ctl *mc) return 0; } +static int xmm6262_force_crash_exit(struct modem_ctl *mc) +{ + mif_info("\n"); + + if (!mc->gpio_ap_dump_int) + return -ENXIO; + + gpio_set_value(mc->gpio_ap_dump_int, 1); + mif_info("set ap_dump_int(%d) to high=%d\n", + mc->gpio_ap_dump_int, gpio_get_value(mc->gpio_ap_dump_int)); + return 0; +} + + static irqreturn_t phone_active_irq_handler(int irq, void *_mc) { int phone_reset = 0; @@ -172,14 +190,72 @@ static irqreturn_t phone_active_irq_handler(int irq, void *_mc) return IRQ_HANDLED; } +#ifdef CONFIG_FAST_BOOT +#include <linux/reboot.h> + +static void mif_sim_detect_complete(struct modem_ctl *mc) +{ + if (mc->sim_shutdown_req) { + mif_info("fake shutdown sim changed shutdown\n"); + kernel_power_off(); + /*kernel_restart(NULL);*/ + mc->sim_shutdown_req = false; + } +} + +static int mif_init_sim_shutdown(struct modem_ctl *mc) +{ + mc->sim_shutdown_req = false; + mc->modem_complete = mif_sim_detect_complete; + + return 0; +} + +static void mif_check_fake_shutdown(struct modem_ctl *mc, bool online) +{ + if (fake_shut_down && mc->sim_state.online != online) + mc->sim_shutdown_req = true; +} + +#else +static inline int mif_init_sim_shutdown(struct modem_ctl *mc) { return 0; } +#define mif_check_fake_shutdown(a, b) do {} while (0) +#endif + + +#define SIM_DETECT_DEBUG static irqreturn_t sim_detect_irq_handler(int irq, void *_mc) { struct modem_ctl *mc = (struct modem_ctl *)_mc; +#ifdef SIM_DETECT_DEBUG + int val = gpio_get_value(mc->gpio_sim_detect); + static int unchange; + static int prev_val; + + if (mc->phone_state == STATE_BOOTING) { + mif_info("BOOTING, reset unchange\n"); + unchange = 0; + } - if (mc->iod && mc->iod->sim_state_changed) + if (prev_val == val) { + if (unchange++ > 50) { + mif_err("Abnormal SIM detect GPIO irqs"); + disable_irq_nosync(mc->gpio_sim_detect); + panic("SIM detect IRQ Error"); + } + } else { + unchange = 0; + } + prev_val = val; +#endif + if (mc->iod && mc->iod->sim_state_changed) { + mif_check_fake_shutdown(mc, + gpio_get_value(mc->gpio_sim_detect) == mc->sim_polarity + ); mc->iod->sim_state_changed(mc->iod, gpio_get_value(mc->gpio_sim_detect) == mc->sim_polarity ); + } return IRQ_HANDLED; } @@ -189,6 +265,7 @@ static void xmm6262_get_ops(struct modem_ctl *mc) mc->ops.modem_on = xmm6262_on; mc->ops.modem_off = xmm6262_off; mc->ops.modem_reset = xmm6262_reset; + mc->ops.modem_force_crash_exit = xmm6262_force_crash_exit; } int xmm6262_init_modemctl_device(struct modem_ctl *mc, @@ -218,6 +295,7 @@ int xmm6262_init_modemctl_device(struct modem_ctl *mc, mc->gpio_cp_ctrl2 = pdata->gpio_cp_ctrl2; #endif + pdev = to_platform_device(mc->dev); mc->irq_phone_active = gpio_to_irq(mc->gpio_phone_active); @@ -261,6 +339,12 @@ int xmm6262_init_modemctl_device(struct modem_ctl *mc, /* initialize sim_state => insert: gpio=0, remove: gpio=1 */ mc->sim_state.online = gpio_get_value(mc->gpio_sim_detect) == mc->sim_polarity; + + ret = mif_init_sim_shutdown(mc); + if (ret) { + mif_err("failed to sim fake shutdown init: %d\n", ret); + goto err_sim_detect_set_wake_irq; + } } return ret; diff --git a/drivers/misc/modem_if/modem_net_flowcontrol_device.c b/drivers/misc/modem_if/modem_net_flowcontrol_device.c index b3f055d..3aa340f 100644 --- a/drivers/misc/modem_if/modem_net_flowcontrol_device.c +++ b/drivers/misc/modem_if/modem_net_flowcontrol_device.c @@ -22,7 +22,7 @@ #include <linux/sched.h> #include <linux/netdevice.h> #include <linux/if_arp.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" diff --git a/drivers/misc/modem_if/modem_prj.h b/drivers/misc/modem_if/modem_prj.h index f85596f..ccff272 100644 --- a/drivers/misc/modem_if/modem_prj.h +++ b/drivers/misc/modem_if/modem_prj.h @@ -1,5 +1,4 @@ /* - * Copyright (C) 2010 Google, Inc. * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -19,12 +18,18 @@ #include <linux/wait.h> #include <linux/miscdevice.h> #include <linux/skbuff.h> +#include <linux/interrupt.h> #include <linux/completion.h> #include <linux/wakelock.h> #include <linux/rbtree.h> #include <linux/spinlock.h> #include <linux/cdev.h> #include <linux/types.h> +#include "modem.h" + +#ifndef CONFIG_SAMSUNG_PRODUCT_SHIP +#define DEBUG_MODEM_IF +#endif #define MAX_CPINFO_SIZE 512 @@ -33,7 +38,10 @@ #define MAX_FMT_DEVS 10 #define MAX_RAW_DEVS 32 #define MAX_RFS_DEVS 10 -#define MAX_NUM_IO_DEV (MAX_FMT_DEVS + MAX_RAW_DEVS + MAX_RFS_DEVS) +#define MAX_BOOT_DEVS 10 +#define MAX_DUMP_DEVS 10 + +#define MAX_IOD_RXQ_LEN 2048 #define IOCTL_MODEM_ON _IO('o', 0x19) #define IOCTL_MODEM_OFF _IO('o', 0x20) @@ -62,22 +70,40 @@ #define IOCTL_MODEM_SWITCH_MODEM _IO('o', 0x37) #endif -#define IOCTL_DPRAM_SEND_BOOT _IO('o', 0x40) -#define IOCTL_DPRAM_INIT_STATUS _IO('o', 0x43) - -/* ioctl command definitions. */ -#define IOCTL_DPRAM_PHONE_POWON _IO('o', 0xd0) -#define IOCTL_DPRAM_PHONEIMG_LOAD _IO('o', 0xd1) -#define IOCTL_DPRAM_NVDATA_LOAD _IO('o', 0xd2) -#define IOCTL_DPRAM_PHONE_BOOTSTART _IO('o', 0xd3) +#define IOCTL_MODEM_RAMDUMP_START _IO('o', 0xCE) +#define IOCTL_MODEM_RAMDUMP_STOP _IO('o', 0xCF) -#define IOCTL_DPRAM_PHONE_UPLOAD_STEP1 _IO('o', 0xde) -#define IOCTL_DPRAM_PHONE_UPLOAD_STEP2 _IO('o', 0xdf) +#define IOCTL_MODEM_XMIT_BOOT _IO('o', 0x40) +#define IOCTL_DPRAM_INIT_STATUS _IO('o', 0x43) /* ioctl command for IPC Logger */ #define IOCTL_MIF_LOG_DUMP _IO('o', 0x51) #define IOCTL_MIF_DPRAM_DUMP _IO('o', 0x52) +/* ioctl command definitions. */ +#define IOCTL_DPRAM_PHONE_POWON _IO('o', 0xD0) +#define IOCTL_DPRAM_PHONEIMG_LOAD _IO('o', 0xD1) +#define IOCTL_DPRAM_NVDATA_LOAD _IO('o', 0xD2) +#define IOCTL_DPRAM_PHONE_BOOTSTART _IO('o', 0xD3) + +#define IOCTL_DPRAM_PHONE_UPLOAD_STEP1 _IO('o', 0xDE) +#define IOCTL_DPRAM_PHONE_UPLOAD_STEP2 _IO('o', 0xDF) + +#define CPBOOT_DIR_MASK 0xF000 +#define CPBOOT_STAGE_MASK 0x0F00 +#define CPBOOT_CMD_MASK 0x000F +#define CPBOOT_REQ_RESP_MASK 0x0FFF + +#define CPBOOT_DIR_AP2CP 0x9000 +#define CPBOOT_DIR_CP2AP 0xA000 + +#define CPBOOT_STAGE_SHIFT 8 + +#define CPBOOT_STAGE_START 0x0000 +#define CPBOOT_CRC_SEND 0x000C +#define CPBOOT_STAGE_DONE 0x000D +#define CPBOOT_STAGE_FAIL 0x000F + /* modem status */ #define MODEM_OFF 0 #define MODEM_CRASHED 1 @@ -93,83 +119,50 @@ #define PSD_DATA_CHID_BEGIN 0x2A #define PSD_DATA_CHID_END 0x38 -#define PS_DATA_CH_0 10 -#define PS_DATA_CH_LAST 24 +#define PS_DATA_CH_0 10 +#define PS_DATA_CH_LAST 24 +#define RMNET0_CH_ID PS_DATA_CH_0 #define IP6VERSION 6 #define SOURCE_MAC_ADDR {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC} -/* loopback: CP -> AP -> CP */ -#define CP2AP_LOOPBACK_CHANNEL 30 - -/* ip loopback */ -#define RMNET0_CH_ID 10 +/* IP loopback */ +#define DATA_DRAIN_CHANNEL 30 /* Drain channel to drop RX packets */ #define DATA_LOOPBACK_CHANNEL 31 /* Debugging features */ -#define MAX_MIF_LOG_PATH_LEN 128 -#define MAX_MIF_LOG_FILE_SIZE 0x800000 /* 8 MB */ - -#define MAX_MIF_EVT_BUFF_SIZE 256 -#define MAX_MIF_TIME_LEN 32 -#define MAX_MIF_NAME_LEN 16 -#define MAX_MIF_STR_LEN 127 -#define MAX_MIF_LOG_LEN 128 - -enum mif_event_id { - MIF_IRQ_EVT = 0, - MIF_LNK_RX_EVT, - MIF_MUX_RX_EVT, - MIF_IOD_RX_EVT, - MIF_IOD_TX_EVT, - MIF_MUX_TX_EVT, - MIF_LNK_TX_EVT, - MAX_MIF_EVT -}; - -struct dpram_queue_status { - unsigned in; - unsigned out; -}; - -struct dpram_queue_status_pair { - struct dpram_queue_status txq; - struct dpram_queue_status rxq; -}; - -struct dpram_irq_buff { - unsigned magic; - unsigned access; - struct dpram_queue_status_pair qsp[MAX_IPC_DEV]; - unsigned int2ap; - unsigned int2cp; -}; - -/* Not use */ -struct mif_event_buff { - char time[MAX_MIF_TIME_LEN]; - - struct timeval tv; - enum mif_event_id evt; - - char mc[MAX_MIF_NAME_LEN]; - - char iod[MAX_MIF_NAME_LEN]; - - char ld[MAX_MIF_NAME_LEN]; - enum modem_link link_type; - - unsigned rcvd; - unsigned len; - union { - u8 data[MAX_MIF_LOG_LEN]; - struct dpram_irq_buff dpram_irqb; - }; +#define MIF_LOG_DIR "/sdcard/log" +#define MIF_MAX_PATH_LEN 256 +#define MIF_MAX_NAME_LEN 64 +#define MIF_MAX_STR_LEN 32 + +#define CP_CRASH_TAG "CP Crash " + +static const char const *dev_format_str[] = { + [IPC_FMT] = "FMT", + [IPC_RAW] = "RAW", + [IPC_RFS] = "RFS", + [IPC_MULTI_RAW] = "MULTI_RAW", + [IPC_CMD] = "CMD", + [IPC_BOOT] = "BOOT", + [IPC_RAMDUMP] = "RAMDUMP", + [IPC_DEBUG] = "DEBUG", }; -#define MIF_LOG_DIR "/sdcard" -#define MIF_LOG_LV_FILE "/data/.mif_log_level" +/** + * get_dev_name + * @dev: IPC device (enum dev_format) + * + * Returns IPC device name as a string. + */ +static const inline char *get_dev_name(unsigned int dev) +{ + if (unlikely(dev >= MAX_DEV_FORMAT)) + return "INVALID"; + else + return dev_format_str[dev]; +} /* Does modem ctl structure will use state ? or status defined below ?*/ enum modem_state { @@ -187,6 +180,26 @@ enum modem_state { #endif }; +static const char const *cp_state_str[] = { + [STATE_OFFLINE] = "OFFLINE", + [STATE_CRASH_RESET] = "CRASH_RESET", + [STATE_CRASH_EXIT] = "CRASH_EXIT", + [STATE_BOOTING] = "BOOTING", + [STATE_ONLINE] = "ONLINE", + [STATE_NV_REBUILDING] = "NV_REBUILDING", + [STATE_LOADER_DONE] = "LOADER_DONE", + [STATE_SIM_ATTACH] = "SIM_ATTACH", + [STATE_SIM_DETACH] = "SIM_DETACH", +#if defined(CONFIG_SEC_DUAL_MODEM_MODE) + [STATE_MODEM_SWITCH] = "MODEM_SWITCH", +#endif +}; + +static const inline char *get_cp_state_str(int state) +{ + return cp_state_str[state]; +} + enum com_state { COM_NONE, COM_ONLINE, @@ -208,6 +221,17 @@ struct sim_state { bool changed; /* online is changed? */ }; +enum cp_boot_mode { + CP_BOOT_MODE_NORMAL, + CP_BOOT_MODE_DUMP, + MAX_CP_BOOT_MODE +}; + +struct modem_firmware { + char *binary; + u32 size; +}; + #define HDLC_START 0x7F #define HDLC_END 0x7E #define SIZE_OF_HDLC_START 1 @@ -216,8 +240,8 @@ struct sim_state { struct header_data { char hdr[HDLC_HEADER_MAX_SIZE]; - unsigned len; - unsigned frag_len; + u32 len; + u32 frag_len; char start; /*hdlc start header 0x7F*/ }; @@ -255,10 +279,14 @@ struct sipc_fmt_hdr { #define SIPC5_EXT_FIELD_EXIST 0b00000010 #define SIPC5_CTL_FIELD_EXIST 0b00000001 -#define SIPC5_MAX_HEADER_SIZE 6 -#define SIPC5_HEADER_SIZE_WITH_EXT_LEN 6 +#define SIPC5_EXT_LENGTH_MASK SIPC5_EXT_FIELD_EXIST +#define SIPC5_CTL_FIELD_MASK (SIPC5_EXT_FIELD_EXIST | SIPC5_CTL_FIELD_EXIST) + +#define SIPC5_MIN_HEADER_SIZE 4 #define SIPC5_HEADER_SIZE_WITH_CTL_FLD 5 -#define SIPC5_MIN_HEADER_SIZE 4 +#define SIPC5_HEADER_SIZE_WITH_EXT_LEN 6 +#define SIPC5_MAX_HEADER_SIZE SIPC5_HEADER_SIZE_WITH_EXT_LEN + #define SIPC5_CONFIG_SIZE 1 #define SIPC5_CH_ID_SIZE 1 @@ -267,13 +295,18 @@ struct sipc_fmt_hdr { #define SIPC5_LEN_OFFSET 2 #define SIPC5_CTL_OFFSET 4 -#define SIPC5_CH_ID_RAW_0 0 #define SIPC5_CH_ID_PDP_0 10 #define SIPC5_CH_ID_PDP_LAST 24 +#define SIPC5_CH_ID_BOOT0 215 +#define SIPC5_CH_ID_DUMP0 225 #define SIPC5_CH_ID_FMT_0 235 #define SIPC5_CH_ID_RFS_0 245 #define SIPC5_CH_ID_MAX 255 +#define SIPC5_CH_ID_FLOW_CTRL 255 +#define FLOW_CTRL_SUSPEND ((u8)(0xCA)) +#define FLOW_CTRL_RESUME ((u8)(0xCB)) + /* If iod->id is 0, do not need to store to `iodevs_tree_fmt' in SIPC4 */ #define sipc4_is_not_reserved_channel(ch) ((ch) != 0) @@ -295,20 +328,6 @@ struct sipc5_link_hdr { } __packed; struct sipc5_frame_data { - /* Config octet */ - u8 config; - - /* Channel ID */ - u8 ch_id; - - /* Control for multiple FMT frame */ - u8 control; - - /* Frame configuration set by header analysis */ - bool padding; - bool ctl_fld; - bool ext_len; - /* Frame length calculated from the length fields */ unsigned len; @@ -318,11 +337,17 @@ struct sipc5_frame_data { /* The length of received header */ unsigned hdr_rcvd; - /* The length of data payload */ - unsigned data_len; + /* The length of link layer payload */ + unsigned pay_len; /* The length of received data */ - unsigned data_rcvd; + unsigned pay_rcvd; + + /* The length of link layer padding */ + unsigned pad_len; + + /* The length of received padding */ + unsigned pad_rcvd; /* Header buffer */ u8 hdr[SIPC5_MAX_HEADER_SIZE]; @@ -349,8 +374,9 @@ struct skbuff_private { struct io_device *iod; struct link_device *ld; struct io_device *real_iod; /* for rx multipdp */ - u8 ch_id; - u8 control; + + /* for indicating that thers is only one IPC frame in an skb */ + bool single_frame; } __packed; static inline struct skbuff_private *skbpriv(struct sk_buff *skb) @@ -359,6 +385,35 @@ static inline struct skbuff_private *skbpriv(struct sk_buff *skb) return (struct skbuff_private *)&skb->cb; } +enum iod_rx_state { + IOD_RX_ON_STANDBY = 0, + IOD_RX_HEADER, + IOD_RX_PAYLOAD, + IOD_RX_PADDING, + MAX_IOD_RX_STATE +}; + +static const char const *rx_state_str[] = { + [IOD_RX_ON_STANDBY] = "RX_ON_STANDBY", + [IOD_RX_HEADER] = "RX_HEADER", + [IOD_RX_PAYLOAD] = "RX_PAYLOAD", + [IOD_RX_PADDING] = "RX_PADDING", +}; + +/** + * get_dev_name + * @dev: IPC device (enum dev_format) + * + * Returns IPC device name as a string. + */ +static const inline char *get_rx_state_str(unsigned int state) +{ + if (unlikely(state >= MAX_IOD_RX_STATE)) + return "INVALID_STATE"; + else + return rx_state_str[state]; +} + struct io_device { /* rb_tree node for an io device */ struct rb_node node_chan; @@ -367,6 +422,7 @@ struct io_device { /* Name of the IO device */ char *name; + /* Reference count */ atomic_t opened; /* Wait queue for the IO device */ @@ -383,7 +439,11 @@ struct io_device { enum modem_io io_typ; enum modem_network net_typ; - bool use_handover; /* handover 2+ link devices */ + /* The name of the application that will use this IO device */ + char *app; + + /* Whether or not handover among 2+ link devices */ + bool use_handover; /* SIPC version */ enum sipc_ver ipc_version; @@ -391,6 +451,10 @@ struct io_device { /* Rx queue of sk_buff */ struct sk_buff_head sk_rx_q; + /* RX state used in RX FSM */ + enum iod_rx_state curr_rx_state; + enum iod_rx_state next_rx_state; + /* ** work for each io device, when delayed work needed ** use this for private io device rx action @@ -447,6 +511,9 @@ struct link_device { /* SIPC version */ enum sipc_ver ipc_version; + /* Maximum IPC device = the last IPC device (e.g. IPC_RFS) + 1 */ + int max_ipc_dev; + /* Modem data */ struct modem_data *mdm_data; @@ -459,6 +526,12 @@ struct link_device { /* Operation mode of the link device */ enum link_mode mode; + /* completion for waiting for link initialization */ + struct completion init_cmpl; + + /* completion for waiting for PIF initialization in a CP */ + struct completion pif_cmpl; + struct io_device *fmt_iods[4]; /* TX queue of socket buffers */ @@ -468,13 +541,30 @@ struct link_device { struct sk_buff_head *skb_txq[MAX_IPC_DEV]; + /* RX queue of socket buffers */ + struct sk_buff_head sk_fmt_rx_q; + struct sk_buff_head sk_raw_rx_q; + struct sk_buff_head sk_rfs_rx_q; + + struct sk_buff_head *skb_rxq[MAX_IPC_DEV]; + bool raw_tx_suspended; /* for misc dev */ struct completion raw_tx_resumed_by_cp; + /** + * This flag is for TX flow control on network interface. + * This must be set and clear only by a flow control command from CP. + */ + bool suspend_netif_tx; + struct workqueue_struct *tx_wq; struct work_struct tx_work; struct delayed_work tx_delayed_work; - struct delayed_work tx_dwork; + + struct delayed_work *tx_dwork[MAX_IPC_DEV]; + struct delayed_work fmt_tx_dwork; + struct delayed_work raw_tx_dwork; + struct delayed_work rfs_tx_dwork; struct workqueue_struct *rx_wq; struct work_struct rx_work; @@ -495,20 +585,26 @@ struct link_device { int (*send)(struct link_device *ld, struct io_device *iod, struct sk_buff *skb); - int (*udl_start)(struct link_device *ld, struct io_device *iod); - - int (*force_dump)(struct link_device *ld, struct io_device *iod); - - int (*dump_start)(struct link_device *ld, struct io_device *iod); + /* method for CP booting */ + int (*xmit_boot)(struct link_device *ld, struct io_device *iod, + unsigned long arg); - int (*modem_update)(struct link_device *ld, struct io_device *iod, + /* methods for CP firmware upgrade */ + int (*dload_start)(struct link_device *ld, struct io_device *iod); + int (*firm_update)(struct link_device *ld, struct io_device *iod, unsigned long arg); + /* methods for CP crash dump */ + int (*force_dump)(struct link_device *ld, struct io_device *iod); + int (*dump_start)(struct link_device *ld, struct io_device *iod); int (*dump_update)(struct link_device *ld, struct io_device *iod, unsigned long arg); + int (*dump_finish)(struct link_device *ld, struct io_device *iod, + unsigned long arg); + /* IOCTL extension */ int (*ioctl)(struct link_device *ld, struct io_device *iod, - unsigned cmd, unsigned long _arg); + unsigned cmd, unsigned long arg); }; /** rx_alloc_skb - allocate an skbuff and set skb's iod, ld @@ -567,6 +663,9 @@ struct modem_shared { struct mif_storage storage; spinlock_t lock; + /* CP crash information */ + char cp_crash_info[530]; + /* loopbacked IP address * default is 0.0.0.0 (disabled) * after you setted this, you can use IP packet loopback using this IP. @@ -586,35 +685,52 @@ struct modem_ctl { struct sim_state sim_state; unsigned gpio_cp_on; + unsigned gpio_cp_off; unsigned gpio_reset_req_n; unsigned gpio_cp_reset; + + /* for broadcasting AP's PM state (active or sleep) */ unsigned gpio_pda_active; + + /* for checking aliveness of CP */ unsigned gpio_phone_active; + int irq_phone_active; + + /* for AP-CP power management (PM) handshaking */ + unsigned gpio_ap_wakeup; + int irq_ap_wakeup; + unsigned gpio_ap_status; + unsigned gpio_cp_wakeup; + unsigned gpio_cp_status; + int irq_cp_status; + + /* for USB/HSIC PM */ + unsigned gpio_host_wakeup; + int irq_host_wakeup; + unsigned gpio_host_active; + unsigned gpio_slave_wakeup; + +#ifdef CONFIG_EXYNOS4_CPUFREQ + /* cpu/bus frequency lock */ + unsigned gpio_cpufreq_lock; + struct delayed_work work_cpu_lock; + struct delayed_work work_cpu_unlock; +#endif + unsigned gpio_cp_dump_int; unsigned gpio_ap_dump_int; unsigned gpio_flm_uart_sel; + unsigned gpio_cp_warm_reset; #if defined(CONFIG_MACH_M0_CTC) unsigned gpio_flm_uart_sel_rev06; #endif - unsigned gpio_cp_warm_reset; - unsigned gpio_cp_off; - unsigned gpio_sim_detect; - unsigned gpio_dynamic_switching; - int irq_phone_active; + unsigned gpio_sim_detect; int irq_sim_detect; -#ifdef CONFIG_LTE_MODEM_CMC221 - const struct attribute_group *group; - unsigned gpio_slave_wakeup; - unsigned gpio_host_wakeup; - unsigned gpio_host_active; - int irq_host_wakeup; - - struct delayed_work dwork; -#endif /*CONFIG_LTE_MODEM_CMC221*/ - - struct work_struct work; +#ifdef CONFIG_LINK_DEVICE_PLD + unsigned gpio_fpga_cs_n; +#endif #if defined(CONFIG_MACH_U1_KOR_LGT) unsigned gpio_cp_reset_msm; @@ -635,9 +751,13 @@ struct modem_ctl { unsigned gpio_cp_ctrl2; #endif -#ifdef CONFIG_LINK_DEVICE_PLD - unsigned gpio_fpga_cs_n; -#endif + /* Switch with 2 links in a modem */ + unsigned gpio_link_switch; + + const struct attribute_group *group; + + struct delayed_work dwork; + struct work_struct work; struct modemctl_ops ops; struct io_device *iod; @@ -651,119 +771,45 @@ struct modem_ctl { bool need_switch_to_usb; bool sim_polarity; + + bool sim_shutdown_req; + void (*modem_complete)(struct modem_ctl *mc); }; int sipc4_init_io_device(struct io_device *iod); int sipc5_init_io_device(struct io_device *iod); -/** - * sipc5_start_valid - * @cfg: configuration field of an SIPC5 link frame - * - * Returns TRUE if the start (configuration field) of an SIPC5 link frame - * is valid or returns FALSE if it is not valid. - * - */ -static inline int sipc5_start_valid(u8 cfg) -{ - return (cfg & SIPC5_START_MASK) == SIPC5_START_MASK; -} - -/** - * sipc5_get_hdr_len - * @cfg: configuration field of an SIPC5 link frame - * - * Returns the length of SIPC5 link layer header in an SIPC5 link frame - * - */ -static inline unsigned sipc5_get_hdr_len(u8 cfg) -{ - if (cfg & SIPC5_EXT_FIELD_EXIST) { - if (cfg & SIPC5_CTL_FIELD_EXIST) - return SIPC5_HEADER_SIZE_WITH_CTL_FLD; - else - return SIPC5_HEADER_SIZE_WITH_EXT_LEN; - } else { - return SIPC5_MIN_HEADER_SIZE; - } -} - -/** - * sipc5_get_ch_id - * @frm: pointer to an SIPC5 frame - * - * Returns the channel ID in an SIPC5 link frame - * - */ -static inline u8 sipc5_get_ch_id(u8 *frm) -{ - return *(frm + SIPC5_CH_ID_OFFSET); -} - -/** - * sipc5_get_frame_sz16 - * @frm: pointer to an SIPC5 link frame - * - * Returns the length of an SIPC5 link frame without the extended length field - * - */ -static inline unsigned sipc5_get_frame_sz16(u8 *frm) -{ - return *((u16 *)(frm + SIPC5_LEN_OFFSET)); -} - -/** - * sipc5_get_frame_sz32 - * @frm: pointer to an SIPC5 frame - * - * Returns the length of an SIPC5 link frame with the extended length field - * - */ -static inline unsigned sipc5_get_frame_sz32(u8 *frm) -{ - return *((u32 *)(frm + SIPC5_LEN_OFFSET)); -} - -/** - * sipc5_calc_padding_size - * @len: length of an SIPC5 link frame - * - * Returns the padding size for an SIPC5 link frame - * - */ -static inline unsigned sipc5_calc_padding_size(unsigned len) -{ - unsigned residue = len & 0x3; - return residue ? (4 - residue) : 0; -} - -extern void set_sromc_access(bool access); +bool sipc5_start_valid(u8 *frm); +bool sipc5_padding_exist(u8 *frm); +bool sipc5_multi_frame(u8 *frm); +bool sipc5_ext_len(u8 *frm); +int sipc5_get_hdr_len(u8 *frm); +u8 sipc5_get_ch_id(u8 *frm); +u8 sipc5_get_ctrl_field(u8 *frm); +int sipc5_get_frame_len(u8 *frm); +int sipc5_calc_padding_size(int len); +int sipc5_get_total_len(u8 *frm); + +u8 sipc5_build_config(struct io_device *iod, struct link_device *ld, u32 count); +void sipc5_build_header(struct io_device *iod, struct link_device *ld, + u8 *buff, u8 cfg, u8 ctrl, u32 count); #if defined(CONFIG_TDSCDMA_MODEM_SPRD8803) && defined(CONFIG_LINK_DEVICE_SPI) extern int spi_sema_init(void); extern int sprd_boot_done; -struct ipc_spi { - struct class *class; - struct device *dev; - struct cdev cdev; - dev_t devid; - - wait_queue_head_t waitq; - struct fasync_struct *async_queue; - u32 mailbox; - - unsigned long base; - unsigned long size; - void __iomem *mmio; +#endif - int irq; +#define STD_UDL_STEP_MASK 0x0000000F +#define STD_UDL_SEND 0x1 +#define STD_UDL_CRC 0xC - struct completion comp; - atomic_t ref_sem; - unsigned long flags; +struct std_dload_info { + u32 size; + u32 mtu; + u32 num_frames; +} __packed; - const struct attribute_group *group; -}; -#endif +u32 std_udl_get_cmd(u8 *frm); +bool std_udl_with_payload(u32 cmd); #endif diff --git a/drivers/misc/modem_if/modem_sim_slot_switch.c b/drivers/misc/modem_if/modem_sim_slot_switch.c index c8e83ed..366d0fa 100644 --- a/drivers/misc/modem_if/modem_sim_slot_switch.c +++ b/drivers/misc/modem_if/modem_sim_slot_switch.c @@ -17,7 +17,7 @@ static ssize_t get_slot_switch(struct device *dev, struct device_attribute *attr //return '0' slot path is '||', return '1' slot path is 'X' value = gpio_get_value(GPIO_UIM_SIM_SEL); #if defined(CONFIG_MACH_T0_CHN_CTC) - if (system_rev < 7) + if (system_rev <= 7) value = (~value & 0x1); #endif printk("Current Slot is %x\n", value); @@ -34,7 +34,7 @@ static ssize_t set_slot_switch(struct device *dev, struct device_attribute *attr switch(value) { case 0: #if defined(CONFIG_MACH_T0_CHN_CTC) - if (system_rev < 7) + if (system_rev <= 7) gpio_set_value(GPIO_UIM_SIM_SEL, 1); else #endif @@ -43,7 +43,7 @@ static ssize_t set_slot_switch(struct device *dev, struct device_attribute *attr break; case 1: #if defined(CONFIG_MACH_T0_CHN_CTC) - if (system_rev < 7) + if (system_rev <= 7) gpio_set_value(GPIO_UIM_SIM_SEL, 0); else #endif @@ -57,7 +57,8 @@ static ssize_t set_slot_switch(struct device *dev, struct device_attribute *attr return size; } -static DEVICE_ATTR(slot_sel, S_IRUGO |S_IWUGO | S_IRUSR | S_IWUSR, get_slot_switch, set_slot_switch); +static DEVICE_ATTR(slot_sel, S_IRUGO | S_IWUSR | S_IWGRP, + get_slot_switch, set_slot_switch); static int __init slot_switch_manager_init(void) { @@ -75,7 +76,7 @@ static int __init slot_switch_manager_init(void) gpio_direction_output(GPIO_UIM_SIM_SEL, 1); s3c_gpio_setpull(GPIO_UIM_SIM_SEL, S3C_GPIO_PULL_NONE); #if defined(CONFIG_MACH_T0_CHN_CTC) - if (system_rev < 7) + if (system_rev <= 7) gpio_set_value(GPIO_UIM_SIM_SEL, 1); else #endif diff --git a/drivers/misc/modem_if/modem_utils.c b/drivers/misc/modem_if/modem_utils.c index d62aaa6..e829324 100644 --- a/drivers/misc/modem_if/modem_utils.c +++ b/drivers/misc/modem_if/modem_utils.c @@ -12,18 +12,35 @@ * */ -#include <linux/netdevice.h> -#include <linux/platform_data/modem.h> +#include <linux/init.h> +#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/miscdevice.h> +#include <linux/netdevice.h> #include <linux/skbuff.h> #include <linux/ip.h> +#include <net/ip.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/rtc.h> #include <linux/time.h> -#include <net/ip.h> - +#include <linux/uaccess.h> +#include <linux/fs.h> +#include <linux/io.h> +#include <linux/wait.h> +#include <linux/time.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/wakelock.h> + +#include "modem.h" #include "modem_prj.h" +#include "modem_variation.h" #include "modem_utils.h" #define CMD_SUSPEND ((unsigned short)(0x00CA)) @@ -35,42 +52,29 @@ "mif: ------------------------------------------------------------" #define LINE_BUFF_SIZE 80 -#ifdef CONFIG_LINK_DEVICE_DPRAM -#include "modem_link_device_dpram.h" -int mif_dump_dpram(struct io_device *iod) -{ - struct link_device *ld = get_current_link(iod); - struct dpram_link_device *dpld = to_dpram_link_device(ld); - u32 size = dpld->dp_size; - unsigned long read_len = 0; - struct sk_buff *skb; - char *buff; +static const char *hex = "0123456789abcdef"; - buff = kzalloc(size, GFP_ATOMIC); - if (!buff) { - pr_err("[MIF] <%s> alloc dpram buff failed\n", __func__); - return -ENOMEM; - } else { - dpld->dpram_dump(ld, buff); - } +void ts2utc(struct timespec *ts, struct utc_time *utc) +{ + struct tm tm; + + time_to_tm((ts->tv_sec - (sys_tz.tz_minuteswest * 60)), 0, &tm); + utc->year = 1900 + tm.tm_year; + utc->mon = 1 + tm.tm_mon; + utc->day = tm.tm_mday; + utc->hour = tm.tm_hour; + utc->min = tm.tm_min; + utc->sec = tm.tm_sec; + utc->msec = ns2ms(ts->tv_nsec); +} - while (read_len < size) { - skb = alloc_skb(MAX_IPC_SKB_SIZE, GFP_ATOMIC); - if (!skb) { - pr_err("[MIF] <%s> alloc skb failed\n", __func__); - kfree(buff); - return -ENOMEM; - } - memcpy(skb_put(skb, MAX_IPC_SKB_SIZE), - buff + read_len, MAX_IPC_SKB_SIZE); - skb_queue_tail(&iod->sk_rx_q, skb); - read_len += MAX_IPC_SKB_SIZE; - wake_up(&iod->wq); - } - kfree(buff); - return 0; +void get_utc_time(struct utc_time *utc) +{ + struct timespec ts; + getnstimeofday(&ts); + ts2utc(&ts, utc); } -#endif +EXPORT_SYMBOL(get_utc_time); int mif_dump_log(struct modem_shared *msd, struct io_device *iod) { @@ -82,7 +86,7 @@ int mif_dump_log(struct modem_shared *msd, struct io_device *iod) while (read_len < MAX_MIF_BUFF_SIZE) { skb = alloc_skb(MAX_IPC_SKB_SIZE, GFP_ATOMIC); if (!skb) { - pr_err("[MIF] <%s> alloc skb failed\n", __func__); + mif_err("ERR! alloc_skb fail\n"); spin_unlock_irqrestore(&msd->lock, flags); return -ENOMEM; } @@ -164,7 +168,6 @@ void _mif_com_log(enum mif_log_id id, struct mif_common_block *block; unsigned long int flags; va_list args; - int ret; spin_lock_irqsave(&msd->lock, flags); @@ -179,7 +182,7 @@ void _mif_com_log(enum mif_log_id id, block->time = get_kernel_time(); va_start(args, format); - ret = vsnprintf(block->buff, MAX_COM_LOG_SIZE, format, args); + vsnprintf(block->buff, MAX_COM_LOG_SIZE, format, args); va_end(args); } @@ -209,13 +212,12 @@ void _mif_time_log(enum mif_log_id id, struct modem_shared *msd, /* dump2hex * dump data to hex as fast as possible. - * the length of @buf must be greater than "@len * 3" + * the length of @buff must be greater than "@len * 3" * it need 3 bytes per one data byte to print. */ -static inline int dump2hex(char *buf, const char *data, size_t len) +static inline int dump2hex(char *buff, const char *data, size_t len) { - static const char *hex = "0123456789abcdef"; - char *dest = buf; + char *dest = buff; int i; for (i = 0; i < len; i++) { @@ -228,24 +230,26 @@ static inline int dump2hex(char *buf, const char *data, size_t len) *dest = '\0'; - return dest - buf; + return dest - buff; } -int pr_ipc(const char *str, const char *data, size_t len) +void pr_ipc(int level, const char *tag, const char *data, size_t len) { - struct timeval tv; - struct tm date; - unsigned char hexstr[128]; + struct utc_time utc; + unsigned char str[128]; - do_gettimeofday(&tv); - time_to_tm((tv.tv_sec - sys_tz.tz_minuteswest * 60), 0, &date); - - dump2hex(hexstr, data, (len > 40 ? 40 : len)); + if (level < 0) + return; - return pr_info("mif: %s: [%02d-%02d %02d:%02d:%02d.%03ld] %s\n", - str, date.tm_mon + 1, date.tm_mday, - date.tm_hour, date.tm_min, date.tm_sec, - (tv.tv_usec > 0 ? tv.tv_usec / 1000 : 0), hexstr); + get_utc_time(&utc); + dump2hex(str, data, (len > 32 ? 32 : len)); + if (level > 0) { + pr_err("%s: [%02d:%02d:%02d.%03d] %s: %s\n", MIF_TAG, + utc.hour, utc.min, utc.sec, utc.msec, tag, str); + } else { + pr_info("%s: [%02d:%02d:%02d.%03d] %s: %s\n", MIF_TAG, + utc.hour, utc.min, utc.sec, utc.msec, tag, str); + } } /* print buffer as hex string */ @@ -253,12 +257,12 @@ int pr_buffer(const char *tag, const char *data, size_t data_len, size_t max_len) { size_t len = min(data_len, max_len); - unsigned char hexstr[len ? len * 3 : 1]; /* 1 <= sizeof <= max_len*3 */ - dump2hex(hexstr, data, len); + unsigned char str[len ? len * 3 : 1]; /* 1 <= sizeof <= max_len*3 */ + dump2hex(str, data, len); /* don't change this printk to mif_debug for print this as level7 */ - return printk(KERN_INFO "mif: %s(%u): %s%s\n", tag, data_len, hexstr, - len == data_len ? "" : " ..."); + return printk(KERN_INFO "%s: %s(%u): %s%s\n", MIF_TAG, tag, data_len, + str, (len == data_len) ? "" : " ..."); } /* flow control CM from CP, it use in serial devices */ @@ -285,7 +289,7 @@ int link_rx_flowctl_cmd(struct link_device *ld, const char *data, size_t len) break; default: - mif_err("flowctl BACMD: %04X\n", *cmd); + mif_err("flowctl BAD CMD: %04X\n", *cmd); break; } } @@ -411,6 +415,42 @@ void rawdevs_set_tx_link(struct modem_shared *msd, enum modem_link link_type) iodevs_for_each(msd, iodev_set_tx_link, ld); } +void mif_netif_stop(struct link_device *ld) +{ + struct io_device *iod; + + if (ld->ipc_version < SIPC_VER_50) + iod = link_get_iod_with_channel(ld, 0x20 | RMNET0_CH_ID); + else + iod = link_get_iod_with_channel(ld, RMNET0_CH_ID); + + if (iod) + iodevs_for_each(iod->msd, iodev_netif_stop, 0); +} + +void mif_netif_wake(struct link_device *ld) +{ + struct io_device *iod; + + /** + * If ld->suspend_netif_tx is true, this means that there was a SUSPEND + * flow control command from CP so MIF must wait for a RESUME command + * from CP. + */ + if (ld->suspend_netif_tx) { + mif_info("%s: waiting for FLOW_CTRL_RESUME\n", ld->name); + return; + } + + if (ld->ipc_version < SIPC_VER_50) + iod = link_get_iod_with_channel(ld, 0x20 | RMNET0_CH_ID); + else + iod = link_get_iod_with_channel(ld, RMNET0_CH_ID); + + if (iod) + iodevs_for_each(iod->msd, iodev_netif_wake, 0); +} + /** * ipv4str_to_be32 - ipv4 string to be32 (big endian 32bits integer) * @return: return zero when errors occurred @@ -447,7 +487,7 @@ void mif_add_timer(struct timer_list *timer, unsigned long expire, add_timer(timer); } -void mif_print_data(char *buf, int len) +void mif_print_data(const char *buff, int len) { int words = len >> 4; int residue = len - (words << 4); @@ -458,11 +498,8 @@ void mif_print_data(char *buf, int len) /* Make the last line, if ((len % 16) > 0) */ if (residue > 0) { - memset(last, 0, sizeof(last)); - memset(tb, 0, sizeof(tb)); - b = buf + (words << 4); - sprintf(last, "%04X: ", (words << 4)); + b = (char *)buff + (words << 4); for (i = 0; i < residue; i++) { sprintf(tb, "%02x ", b[i]); strcat(last, tb); @@ -474,7 +511,7 @@ void mif_print_data(char *buf, int len) } for (i = 0; i < words; i++) { - b = buf + (i << 4); + b = (char *)buff + (i << 4); mif_err("%04X: " "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n", @@ -488,13 +525,141 @@ void mif_print_data(char *buf, int len) mif_err("%s\n", last); } +void mif_dump2format16(const char *data, int len, char *buff, char *tag) +{ + char *d; + int i; + int words = len >> 4; + int residue = len - (words << 4); + char line[LINE_BUFF_SIZE]; + char tb[8]; + + for (i = 0; i < words; i++) { + memset(line, 0, LINE_BUFF_SIZE); + d = (char *)data + (i << 4); + + if (tag) + sprintf(line, "%s%04X| " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + tag, (i << 4), + d[0], d[1], d[2], d[3], + d[4], d[5], d[6], d[7], + d[8], d[9], d[10], d[11], + d[12], d[13], d[14], d[15]); + else + sprintf(line, "%04X| " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + (i << 4), + d[0], d[1], d[2], d[3], + d[4], d[5], d[6], d[7], + d[8], d[9], d[10], d[11], + d[12], d[13], d[14], d[15]); + + strcat(buff, line); + } + + /* Make the last line, if (len % 16) > 0 */ + if (residue > 0) { + memset(line, 0, LINE_BUFF_SIZE); + memset(tb, 0, sizeof(tb)); + d = (char *)data + (words << 4); + + if (tag) + sprintf(line, "%s%04X|", tag, (words << 4)); + else + sprintf(line, "%04X|", (words << 4)); + + for (i = 0; i < residue; i++) { + sprintf(tb, " %02x", d[i]); + strcat(line, tb); + if ((i & 0x3) == 0x3) { + sprintf(tb, " "); + strcat(line, tb); + } + } + strcat(line, "\n"); + + strcat(buff, line); + } +} + +void mif_dump2format4(const char *data, int len, char *buff, char *tag) +{ + char *d; + int i; + int words = len >> 2; + int residue = len - (words << 2); + char line[LINE_BUFF_SIZE]; + char tb[8]; + + for (i = 0; i < words; i++) { + memset(line, 0, LINE_BUFF_SIZE); + d = (char *)data + (i << 2); + + if (tag) + sprintf(line, "%s%04X| %02x %02x %02x %02x\n", + tag, (i << 2), d[0], d[1], d[2], d[3]); + else + sprintf(line, "%04X| %02x %02x %02x %02x\n", + (i << 2), d[0], d[1], d[2], d[3]); + + strcat(buff, line); + } + + /* Make the last line, if (len % 4) > 0 */ + if (residue > 0) { + memset(line, 0, LINE_BUFF_SIZE); + memset(tb, 0, sizeof(tb)); + d = (char *)data + (words << 2); + + if (tag) + sprintf(line, "%s%04X|", tag, (words << 2)); + else + sprintf(line, "%04X|", (words << 2)); + + for (i = 0; i < residue; i++) { + sprintf(tb, " %02x", d[i]); + strcat(line, tb); + } + strcat(line, "\n"); + + strcat(buff, line); + } +} + +void mif_print_dump(const char *data, int len, int width) +{ + char *buff; + + buff = kzalloc(len << 3, GFP_ATOMIC); + if (!buff) { + mif_err("ERR! kzalloc fail\n"); + return; + } + + if (width == 16) + mif_dump2format16(data, len, buff, LOG_TAG); + else + mif_dump2format4(data, len, buff, LOG_TAG); + + pr_info("%s", buff); + + kfree(buff); +} + void print_sipc4_hdlc_fmt_frame(const u8 *psrc) { u8 *frm; /* HDLC Frame */ struct fmt_hdr *hh; /* HDLC Header */ struct sipc_fmt_hdr *fh; /* IPC Header */ - u16 hh_len = sizeof(struct fmt_hdr); - u16 fh_len = sizeof(struct sipc_fmt_hdr); + int hh_len = sizeof(struct fmt_hdr); + int fh_len = sizeof(struct sipc_fmt_hdr); u8 *data; int dlen; @@ -531,7 +696,7 @@ void print_sipc4_hdlc_fmt_frame(const u8 *psrc) void print_sipc4_fmt_frame(const u8 *psrc) { struct sipc_fmt_hdr *fh = (struct sipc_fmt_hdr *)psrc; - u16 fh_len = sizeof(struct sipc_fmt_hdr); + int fh_len = sizeof(struct sipc_fmt_hdr); u8 *data; int dlen; @@ -558,8 +723,8 @@ void print_sipc5_link_fmt_frame(const u8 *psrc) u8 *lf; /* Link Frame */ struct sipc5_link_hdr *lh; /* Link Header */ struct sipc_fmt_hdr *fh; /* IPC Header */ - u16 lh_len; - u16 fh_len; + int lh_len; + int fh_len; u8 *data; int dlen; @@ -567,10 +732,7 @@ void print_sipc5_link_fmt_frame(const u8 *psrc) /* Point HDLC header and IPC header */ lh = (struct sipc5_link_hdr *)lf; - if (lh->cfg & SIPC5_CTL_FIELD_EXIST) - lh_len = SIPC5_HEADER_SIZE_WITH_CTL_FLD; - else - lh_len = SIPC5_MIN_HEADER_SIZE; + lh_len = (u16)sipc5_get_hdr_len((u8 *)lh); fh = (struct sipc_fmt_hdr *)(lf + lh_len); fh_len = sizeof(struct sipc_fmt_hdr); @@ -601,8 +763,8 @@ static void strcat_tcp_header(char *buff, u8 *pkt) { struct tcphdr *tcph = (struct tcphdr *)pkt; int eol; - char line[LINE_BUFF_SIZE]; - char flag_str[32]; + char line[LINE_BUFF_SIZE] = {0, }; + char flag_str[32] = {0, }; /*------------------------------------------------------------------------- @@ -630,21 +792,17 @@ static void strcat_tcp_header(char *buff, u8 *pkt) -------------------------------------------------------------------------*/ - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, - "mif: TCP:: Src.Port %u, Dst.Port %u\n", - ntohs(tcph->source), ntohs(tcph->dest)); + "%s: TCP:: Src.Port %u, Dst.Port %u\n", + MIF_TAG, ntohs(tcph->source), ntohs(tcph->dest)); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, - "mif: TCP:: SEQ 0x%08X(%u), ACK 0x%08X(%u)\n", - ntohs(tcph->seq), ntohs(tcph->seq), + "%s: TCP:: SEQ 0x%08X(%u), ACK 0x%08X(%u)\n", + MIF_TAG, ntohs(tcph->seq), ntohs(tcph->seq), ntohs(tcph->ack_seq), ntohs(tcph->ack_seq)); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); - memset(flag_str, 0, sizeof(flag_str)); if (tcph->cwr) strcat(flag_str, "CWR "); if (tcph->ece) @@ -664,12 +822,12 @@ static void strcat_tcp_header(char *buff, u8 *pkt) eol = strlen(flag_str) - 1; if (eol > 0) flag_str[eol] = 0; - snprintf(line, LINE_BUFF_SIZE, "mif: TCP:: Flags {%s}\n", flag_str); + snprintf(line, LINE_BUFF_SIZE, "%s: TCP:: Flags {%s}\n", + MIF_TAG, flag_str); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, - "mif: TCP:: Window %u, Checksum 0x%04X, Urg Pointer %u\n", + "%s: TCP:: Window %u, Checksum 0x%04X, Urgent %u\n", MIF_TAG, ntohs(tcph->window), ntohs(tcph->check), ntohs(tcph->urg_ptr)); strcat(buff, line); } @@ -677,7 +835,7 @@ static void strcat_tcp_header(char *buff, u8 *pkt) static void strcat_udp_header(char *buff, u8 *pkt) { struct udphdr *udph = (struct udphdr *)pkt; - char line[LINE_BUFF_SIZE]; + char line[LINE_BUFF_SIZE] = {0, }; /*------------------------------------------------------------------------- @@ -693,41 +851,39 @@ static void strcat_udp_header(char *buff, u8 *pkt) -------------------------------------------------------------------------*/ - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, - "mif: UDP:: Src.Port %u, Dst.Port %u\n", - ntohs(udph->source), ntohs(udph->dest)); + "%s: UDP:: Src.Port %u, Dst.Port %u\n", + MIF_TAG, ntohs(udph->source), ntohs(udph->dest)); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, - "mif: UDP:: Length %u, Checksum 0x%04X\n", - ntohs(udph->len), ntohs(udph->check)); + "%s: UDP:: Length %u, Checksum 0x%04X\n", + MIF_TAG, ntohs(udph->len), ntohs(udph->check)); strcat(buff, line); if (ntohs(udph->dest) == 53) { - memset(line, 0, LINE_BUFF_SIZE); - snprintf(line, LINE_BUFF_SIZE, "mif: UDP:: DNS query!!!\n"); + snprintf(line, LINE_BUFF_SIZE, "%s: UDP:: DNS query!!!\n", + MIF_TAG); strcat(buff, line); } if (ntohs(udph->source) == 53) { - memset(line, 0, LINE_BUFF_SIZE); - snprintf(line, LINE_BUFF_SIZE, "mif: UDP:: DNS response!!!\n"); + snprintf(line, LINE_BUFF_SIZE, "%s: UDP:: DNS response!!!\n", + MIF_TAG); strcat(buff, line); } } -void print_ip4_packet(u8 *ip_pkt, bool tx) +void print_ip4_packet(const u8 *ip_pkt, bool tx) { char *buff; struct iphdr *iph = (struct iphdr *)ip_pkt; - u8 *pkt = ip_pkt + (iph->ihl << 2); + u8 *pkt = (u8 *)ip_pkt + (iph->ihl << 2); u16 flags = (ntohs(iph->frag_off) & 0xE000); u16 frag_off = (ntohs(iph->frag_off) & 0x1FFF); int eol; - char line[LINE_BUFF_SIZE]; - char flag_str[16]; + char line[LINE_BUFF_SIZE] = {0, }; + char flag_str[16] = {0, }; /*--------------------------------------------------------------------------- IPv4 Header Format @@ -764,32 +920,25 @@ void print_ip4_packet(u8 *ip_pkt, bool tx) if (!buff) return; - - memset(line, 0, LINE_BUFF_SIZE); if (tx) snprintf(line, LINE_BUFF_SIZE, "\n%s\n", TX_SEPARATOR); else snprintf(line, LINE_BUFF_SIZE, "\n%s\n", RX_SEPARATOR); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, "%s\n", LINE_SEPARATOR); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, - "mif: IP4:: Version %u, Header Length %u, TOS %u, Length %u\n", - iph->version, (iph->ihl << 2), iph->tos, ntohs(iph->tot_len)); + "%s: IP4:: Version %u, Header Length %u, TOS %u, Length %u\n", + MIF_TAG, iph->version, (iph->ihl << 2), iph->tos, + ntohs(iph->tot_len)); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); - snprintf(line, LINE_BUFF_SIZE, - "mif: IP4:: ID %u, Fragment Offset %u\n", - ntohs(iph->id), frag_off); + snprintf(line, LINE_BUFF_SIZE, "%s: IP4:: ID %u, Fragment Offset %u\n", + MIF_TAG, ntohs(iph->id), frag_off); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); - memset(flag_str, 0, sizeof(flag_str)); if (flags & IP_CE) strcat(flag_str, "CE "); if (flags & IP_DF) @@ -799,19 +948,18 @@ void print_ip4_packet(u8 *ip_pkt, bool tx) eol = strlen(flag_str) - 1; if (eol > 0) flag_str[eol] = 0; - snprintf(line, LINE_BUFF_SIZE, "mif: IP4:: Flags {%s}\n", flag_str); + snprintf(line, LINE_BUFF_SIZE, "%s: IP4:: Flags {%s}\n", + MIF_TAG, flag_str); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, - "mif: IP4:: TTL %u, Protocol %u, Header Checksum 0x%04X\n", - iph->ttl, iph->protocol, ntohs(iph->check)); + "%s: IP4:: TTL %u, Protocol %u, Header Checksum 0x%04X\n", + MIF_TAG, iph->ttl, iph->protocol, ntohs(iph->check)); strcat(buff, line); - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, - "mif: IP4:: Src.IP %u.%u.%u.%u, Dst.IP %u.%u.%u.%u\n", - ip_pkt[12], ip_pkt[13], ip_pkt[14], ip_pkt[15], + "%s: IP4:: Src.IP %u.%u.%u.%u, Dst.IP %u.%u.%u.%u\n", + MIF_TAG, ip_pkt[12], ip_pkt[13], ip_pkt[14], ip_pkt[15], ip_pkt[16], ip_pkt[17], ip_pkt[18], ip_pkt[19]); strcat(buff, line); @@ -828,7 +976,6 @@ void print_ip4_packet(u8 *ip_pkt, bool tx) break; } - memset(line, 0, LINE_BUFF_SIZE); snprintf(line, LINE_BUFF_SIZE, "%s\n", LINE_SEPARATOR); strcat(buff, line); @@ -837,7 +984,7 @@ void print_ip4_packet(u8 *ip_pkt, bool tx) kfree(buff); } -bool is_dns_packet(u8 *ip_pkt) +bool is_dns_packet(const u8 *ip_pkt) { struct iphdr *iph = (struct iphdr *)ip_pkt; struct udphdr *udph = (struct udphdr *)(ip_pkt + (iph->ihl << 2)); @@ -852,7 +999,7 @@ bool is_dns_packet(u8 *ip_pkt) return false; } -bool is_syn_packet(u8 *ip_pkt) +bool is_syn_packet(const u8 *ip_pkt) { struct iphdr *iph = (struct iphdr *)ip_pkt; struct tcphdr *tcph = (struct tcphdr *)(ip_pkt + (iph->ihl << 2)); @@ -867,124 +1014,248 @@ bool is_syn_packet(u8 *ip_pkt) return false; } -int memcmp16_to_io(const void __iomem *to, void *from, int size) +/** + * mif_register_isr + * @irq: IRQ number for a DPRAM interrupt + * @isr: function pointer to an interrupt service routine + * @flags: set of interrupt flags + * @name: name of the interrupt + * @data: pointer to a data for @isr + * + * Registers the ISR for the IRQ number. + */ +int mif_register_isr(unsigned int irq, irq_handler_t isr, unsigned long flags, + const char *name, void *data) { - u16 *d = (u16 *)to; - u16 *s = (u16 *)from; - int count = size >> 1; - int diff = 0; - int i; - u16 d1; - u16 s1; - - for (i = 0; i < count; i++) { - d1 = ioread16(d); - s1 = *s; - if (d1 != s1) { - diff++; - mif_err("ERR! [%d] d:0x%04X != s:0x%04X\n", i, d1, s1); - } - d++; - s++; + int ret; + + ret = request_irq(irq, isr, flags, name, data); + if (ret) { + mif_err("%s: ERR! request_irq fail (err %d)\n", name, ret); + return ret; } - return diff; + ret = enable_irq_wake(irq); + if (ret) + mif_err("%s: ERR! enable_irq_wake fail (err %d)\n", name, ret); + + mif_err("%s (#%d) handler registered\n", name, irq); + + return 0; } -int mif_test_dpram(char *dp_name, u8 __iomem *start, u32 size) +int mif_test_dpram(char *dp_name, void __iomem *start, u16 bytes) { - u8 __iomem *dst; - int i; + u16 i; + u16 words = bytes >> 1; + u16 __iomem *dst = (u16 __iomem *)start; u16 val; + int err_cnt = 0; - mif_info("%s: start = 0x%p, size = %d\n", dp_name, start, size); + mif_err("%s: start 0x%p, bytes %d\n", dp_name, start, bytes); - dst = start; - for (i = 0; i < (size >> 1); i++) { - iowrite16((i & 0xFFFF), dst); - dst += 2; + mif_err("%s: 0/6 stage ...\n", dp_name); + for (i = 1; i <= 100; i++) { + iowrite16(0x1234, dst); + val = ioread16(dst); + if (val != 0x1234) { + mif_err("%s: [0x0000] read 0x%04X != written 0x1234 " + "(try# %d)\n", dp_name, val, i); + err_cnt++; + } + } + + if (err_cnt > 0) { + mif_err("%s: FAIL!!!\n", dp_name); + return -EINVAL; + } + + mif_err("%s: 1/6 stage ...\n", dp_name); + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { + iowrite16(0, dst); + dst++; } - dst = start; - for (i = 0; i < (size >> 1); i++) { + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { val = ioread16(dst); - if (val != (i & 0xFFFF)) { - mif_info("%s: ERR! dst[%d] 0x%04X != 0x%04X\n", - dp_name, i, val, (i & 0xFFFF)); - return -EINVAL; + if (val != 0x0000) { + mif_err("%s: ERR! [0x%04X] read 0x%04X != written " + "0x0000\n", dp_name, i, val); + err_cnt++; } - dst += 2; + dst++; + } + + if (err_cnt > 0) { + mif_err("%s: FAIL!!!\n", dp_name); + return -EINVAL; } - dst = start; - for (i = 0; i < (size >> 1); i++) { + mif_err("%s: 2/6 stage ...\n", dp_name); + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { + iowrite16(0xFFFF, dst); + dst++; + } + + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { + val = ioread16(dst); + if (val != 0xFFFF) { + mif_err("%s: ERR! [0x%04X] read 0x%04X != written " + "0xFFFF\n", dp_name, i, val); + err_cnt++; + } + dst++; + } + + if (err_cnt > 0) { + mif_err("%s: FAIL!!!\n", dp_name); + return -EINVAL; + } + + mif_err("%s: 3/6 stage ...\n", dp_name); + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { iowrite16(0x00FF, dst); - dst += 2; + dst++; } - dst = start; - for (i = 0; i < (size >> 1); i++) { + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { val = ioread16(dst); if (val != 0x00FF) { - mif_info("%s: ERR! dst[%d] 0x%04X != 0x00FF\n", - dp_name, i, val); - return -EINVAL; + mif_err("%s: ERR! [0x%04X] read 0x%04X != written " + "0x00FF\n", dp_name, i, val); + err_cnt++; } - dst += 2; + dst++; } - dst = start; - for (i = 0; i < (size >> 1); i++) { + if (err_cnt > 0) { + mif_err("%s: FAIL!!!\n", dp_name); + return -EINVAL; + } + + mif_err("%s: 4/6 stage ...\n", dp_name); + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { iowrite16(0x0FF0, dst); - dst += 2; + dst++; } - dst = start; - for (i = 0; i < (size >> 1); i++) { + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { val = ioread16(dst); if (val != 0x0FF0) { - mif_info("%s: ERR! dst[%d] 0x%04X != 0x0FF0\n", - dp_name, i, val); - return -EINVAL; + mif_err("%s: ERR! [0x%04X] read 0x%04X != written " + "0x0FF0\n", dp_name, i, val); + err_cnt++; } - dst += 2; + dst++; + } + + if (err_cnt > 0) { + mif_err("%s: FAIL!!!\n", dp_name); + return -EINVAL; } - dst = start; - for (i = 0; i < (size >> 1); i++) { + mif_err("%s: 5/6 stage ...\n", dp_name); + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { iowrite16(0xFF00, dst); - dst += 2; + dst++; } - dst = start; - for (i = 0; i < (size >> 1); i++) { + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { val = ioread16(dst); if (val != 0xFF00) { - mif_info("%s: ERR! dst[%d] 0x%04X != 0xFF00\n", - dp_name, i, val); - return -EINVAL; + mif_err("%s: ERR! [0x%04X] read 0x%04X != written " + "0xFF00\n", dp_name, i, val); + err_cnt++; } - dst += 2; + dst++; } - dst = start; - for (i = 0; i < (size >> 1); i++) { - iowrite16(0, dst); - dst += 2; + mif_err("%s: 6/6 stage ...\n", dp_name); + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { + iowrite16((i & 0xFFFF), dst); + dst++; } - dst = start; - for (i = 0; i < (size >> 1); i++) { + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { val = ioread16(dst); - if (val != 0) { - mif_info("%s: ERR! dst[%d] 0x%04X != 0\n", - dp_name, i, val); - return -EINVAL; + if (val != (i & 0xFFFF)) { + mif_err("%s: ERR! [0x%04X] read 0x%04X != written " + "0x%04X\n", dp_name, i, val, (i & 0xFFFF)); + err_cnt++; } - dst += 2; + dst++; + } + + if (err_cnt > 0) { + mif_err("%s: FAIL!!!\n", dp_name); + return -EINVAL; + } + + mif_err("%s: PASS!!!\n", dp_name); + + dst = (u16 __iomem *)start; + for (i = 0; i < words; i++) { + iowrite16(0, dst); + dst++; } - mif_info("%s: PASS!!!\n", dp_name); return 0; } +struct file *mif_open_file(const char *path) +{ + struct file *fp; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(get_ds()); + + fp = filp_open(path, O_RDWR|O_CREAT|O_APPEND, 0666); + + set_fs(old_fs); + + if (IS_ERR(fp)) + return NULL; + + return fp; +} + +void mif_save_file(struct file *fp, const char *buff, size_t size) +{ + int ret; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(get_ds()); + + ret = fp->f_op->write(fp, buff, size, &fp->f_pos); + if (ret < 0) + mif_err("ERR! write fail\n"); + + set_fs(old_fs); +} + +void mif_close_file(struct file *fp) +{ + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(get_ds()); + + filp_close(fp, NULL); + + set_fs(old_fs); +} + diff --git a/drivers/misc/modem_if/modem_utils.h b/drivers/misc/modem_if/modem_utils.h index 7225ec2..15edb43 100644 --- a/drivers/misc/modem_if/modem_utils.h +++ b/drivers/misc/modem_if/modem_utils.h @@ -16,6 +16,7 @@ #define __MODEM_UTILS_H__ #include <linux/rbtree.h> +#include "modem_prj.h" #define IS_CONNECTED(iod, ld) ((iod)->link_types & LINKTYPE((ld)->link_type)) @@ -26,6 +27,8 @@ #define MAX_IPC_SKB_SIZE 4096 #define MAX_LOG_SIZE 64 +#define MIF_TAG "mif" + #define MAX_LOG_CNT (MAX_MIF_BUFF_SIZE / MAX_LOG_SIZE) #define MIF_ID_SIZE sizeof(enum mif_log_id) @@ -96,7 +99,19 @@ struct mif_time_block { char buff[MAX_TIM_LOG_SIZE]; }; -int mif_dump_dpram(struct io_device *); +static inline int ns2us(long ns) +{ + return (ns > 0) ? (ns / 1000) : 0; +} + +static inline int ns2ms(long ns) +{ + return (ns > 0) ? (ns / 1000000) : 0; +} + +void ts2utc(struct timespec *ts, struct utc_time *utc); +void get_utc_time(struct utc_time *utc); + int mif_dump_log(struct modem_shared *, struct io_device *); #define mif_irq_log(msd, map, data, len) \ @@ -141,7 +156,7 @@ static inline unsigned int countbits(unsigned int n) } /* print IPC message as hex string with UTC time */ -int pr_ipc(const char *str, const char *data, size_t len); +void pr_ipc(int level, const char *tag, const char *data, size_t len); /* print buffer as hex string */ int pr_buffer(const char *tag, const char *data, size_t data_len, @@ -156,10 +171,13 @@ int pr_buffer(const char *tag, const char *data, size_t data_len, pr_buffer(tag, (char *)((urb)->transfer_buffer), \ (size_t)((urb)->actual_length), (size_t)16) +/* Stop/wake all TX queues in network interfaces */ +void mif_netif_stop(struct link_device *ld); +void mif_netif_wake(struct link_device *ld); + /* flow control CMD from CP, it use in serial devices */ int link_rx_flowctl_cmd(struct link_device *ld, const char *data, size_t len); - /* get iod from tree functions */ struct io_device *get_iod_with_format(struct modem_shared *msd, @@ -204,12 +222,14 @@ void mif_add_timer(struct timer_list *timer, unsigned long expire, void (*function)(unsigned long), unsigned long data); /* debug helper functions for sipc4, sipc5 */ -void mif_print_data(char *buf, int len); +void mif_print_data(const char *buff, int len); +void mif_dump2format16(const char *data, int len, char *buff, char *tag); +void mif_dump2format4(const char *data, int len, char *buff, char *tag); +void mif_print_dump(const char *data, int len, int width); void print_sipc4_hdlc_fmt_frame(const u8 *psrc); void print_sipc4_fmt_frame(const u8 *psrc); void print_sipc5_link_fmt_frame(const u8 *psrc); - /*--------------------------------------------------------------------------- IPv4 Header Format @@ -282,23 +302,17 @@ void print_sipc5_link_fmt_frame(const u8 *psrc); -------------------------------------------------------------------------*/ #define UDP_HDR_SIZE 8 -void print_ip4_packet(u8 *ip_pkt, bool tx); -bool is_dns_packet(u8 *ip_pkt); -bool is_syn_packet(u8 *ip_pkt); +void print_ip4_packet(const u8 *ip_pkt, bool tx); +bool is_dns_packet(const u8 *ip_pkt); +bool is_syn_packet(const u8 *ip_pkt); -int memcmp16_to_io(const void __iomem *to, void *from, int size); -int mif_test_dpram(char *dp_name, u8 __iomem *start, u32 size); +int mif_register_isr(unsigned int irq, irq_handler_t isr, unsigned long flags, + const char *name, void *data); +int mif_test_dpram(char *dp_name, void __iomem *start, u16 bytes); -static const inline char *get_dev_name(int dev) -{ - if (dev == IPC_FMT) - return "FMT"; - else if (dev == IPC_RAW) - return "RAW"; - else if (dev == IPC_RFS) - return "RFS"; - else - return "NONE"; -} +struct file *mif_open_file(const char *path); +void mif_save_file(struct file *fp, const char *buff, size_t size); +void mif_close_file(struct file *fp); #endif/*__MODEM_UTILS_H__*/ + diff --git a/drivers/misc/modem_if/modem_variation.h b/drivers/misc/modem_if/modem_variation.h index b5ec61b..b314bb2 100644 --- a/drivers/misc/modem_if/modem_variation.h +++ b/drivers/misc/modem_if/modem_variation.h @@ -1,5 +1,4 @@ /* - * Copyright (C) 2010 Google, Inc. * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -16,7 +15,7 @@ #ifndef __MODEM_VARIATION_H__ #define __MODEM_VARIATION_H__ -#include <linux/platform_data/modem.h> +#include "modem.h" #define DECLARE_MODEM_INIT(type) \ int type ## _init_modemctl_device(struct modem_ctl *mc, \ @@ -61,12 +60,30 @@ DECLARE_MODEM_INIT(cbp72); DECLARE_MODEM_INIT_DUMMY(cbp72) #endif +#ifdef CONFIG_CDMA_MODEM_CBP82 +DECLARE_MODEM_INIT(cbp82); +#else +DECLARE_MODEM_INIT_DUMMY(cbp82) +#endif + +#ifdef CONFIG_LTE_MODEM_CMC220 +DECLARE_MODEM_INIT(cmc220); +#else +DECLARE_MODEM_INIT_DUMMY(cmc220) +#endif + #ifdef CONFIG_LTE_MODEM_CMC221 DECLARE_MODEM_INIT(cmc221); #else DECLARE_MODEM_INIT_DUMMY(cmc221) #endif +#ifdef CONFIG_UMTS_MODEM_SS222 +DECLARE_MODEM_INIT(ss222); +#else +DECLARE_MODEM_INIT_DUMMY(ss222) +#endif + #ifdef CONFIG_CDMA_MODEM_MDM6600 DECLARE_MODEM_INIT(mdm6600); #else @@ -79,6 +96,12 @@ DECLARE_MODEM_INIT(esc6270); DECLARE_MODEM_INIT_DUMMY(esc6270) #endif +#ifdef CONFIG_CDMA_MODEM_QSC6085 +DECLARE_MODEM_INIT(qsc6085); +#else +DECLARE_MODEM_INIT_DUMMY(qsc6085) +#endif + #ifdef CONFIG_TDSCDMA_MODEM_SPRD8803 DECLARE_MODEM_INIT(sprd8803); #else @@ -94,6 +117,18 @@ DECLARE_LINK_INIT(mipi); DECLARE_LINK_INIT_DUMMY(mipi) #endif +#ifdef CONFIG_LINK_DEVICE_USB +DECLARE_LINK_INIT(usb); +#else +DECLARE_LINK_INIT_DUMMY(usb) +#endif + +#ifdef CONFIG_LINK_DEVICE_HSIC +DECLARE_LINK_INIT(hsic); +#else +DECLARE_LINK_INIT_DUMMY(hsic) +#endif + #ifdef CONFIG_LINK_DEVICE_DPRAM DECLARE_LINK_INIT(dpram); #else @@ -106,53 +141,52 @@ DECLARE_LINK_INIT(pld); DECLARE_LINK_INIT_DUMMY(pld) #endif -#ifdef CONFIG_LINK_DEVICE_SPI -DECLARE_LINK_INIT(spi); -#else -DECLARE_LINK_INIT_DUMMY(spi) -#endif - -#ifdef CONFIG_LINK_DEVICE_USB -DECLARE_LINK_INIT(usb); +#ifdef CONFIG_LINK_DEVICE_C2C +DECLARE_LINK_INIT(c2c); #else -DECLARE_LINK_INIT_DUMMY(usb) +DECLARE_LINK_INIT_DUMMY(c2c) #endif -#ifdef CONFIG_LINK_DEVICE_HSIC -DECLARE_LINK_INIT(hsic); +#ifdef CONFIG_LINK_DEVICE_SHMEM +DECLARE_LINK_INIT(shmem); #else -DECLARE_LINK_INIT_DUMMY(hsic) +DECLARE_LINK_INIT_DUMMY(shmem) #endif -#ifdef CONFIG_LINK_DEVICE_C2C -DECLARE_LINK_INIT(c2c); +#ifdef CONFIG_LINK_DEVICE_SPI +DECLARE_LINK_INIT(spi); #else -DECLARE_LINK_INIT_DUMMY(c2c) +DECLARE_LINK_INIT_DUMMY(spi) #endif typedef int (*modem_init_call)(struct modem_ctl *, struct modem_data *); -static modem_init_call modem_init_func[] = { - MODEM_INIT_CALL(xmm6260), - MODEM_INIT_CALL(xmm6262), - MODEM_INIT_CALL(cbp71), - MODEM_INIT_CALL(cbp72), - MODEM_INIT_CALL(cmc221), - MODEM_INIT_CALL(mdm6600), - MODEM_INIT_CALL(esc6270), - MODEM_INIT_CALL(sprd8803), - MODEM_INIT_CALL(dummy), +static modem_init_call modem_init_func[MAX_MODEM_TYPE] = { + [IMC_XMM6260] = MODEM_INIT_CALL(xmm6260), + [IMC_XMM6262] = MODEM_INIT_CALL(xmm6262), + [VIA_CBP71] = MODEM_INIT_CALL(cbp71), + [VIA_CBP72] = MODEM_INIT_CALL(cbp72), + [VIA_CBP82] = MODEM_INIT_CALL(cbp82), + [SEC_CMC220] = MODEM_INIT_CALL(cmc220), + [SEC_CMC221] = MODEM_INIT_CALL(cmc221), + [SEC_SS222] = MODEM_INIT_CALL(ss222), + [QC_MDM6600] = MODEM_INIT_CALL(mdm6600), + [QC_ESC6270] = MODEM_INIT_CALL(esc6270), + [QC_QSC6085] = MODEM_INIT_CALL(qsc6085), + [SPRD_SC8803] = MODEM_INIT_CALL(sprd8803), + [DUMMY] = MODEM_INIT_CALL(dummy), }; typedef struct link_device *(*link_init_call)(struct platform_device *); -static link_init_call link_init_func[] = { - LINK_INIT_CALL(undefined), - LINK_INIT_CALL(mipi), - LINK_INIT_CALL(dpram), - LINK_INIT_CALL(spi), - LINK_INIT_CALL(usb), - LINK_INIT_CALL(hsic), - LINK_INIT_CALL(c2c), - LINK_INIT_CALL(pld), +static link_init_call link_init_func[LINKDEV_MAX] = { + [LINKDEV_UNDEFINED] = LINK_INIT_CALL(undefined), + [LINKDEV_MIPI] = LINK_INIT_CALL(mipi), + [LINKDEV_USB] = LINK_INIT_CALL(usb), + [LINKDEV_HSIC] = LINK_INIT_CALL(hsic), + [LINKDEV_DPRAM] = LINK_INIT_CALL(dpram), + [LINKDEV_PLD] = LINK_INIT_CALL(pld), + [LINKDEV_C2C] = LINK_INIT_CALL(c2c), + [LINKDEV_SHMEM] = LINK_INIT_CALL(shmem), + [LINKDEV_SPI] = LINK_INIT_CALL(spi), }; static int call_modem_init_func(struct modem_ctl *mc, struct modem_data *pdata) diff --git a/drivers/misc/modem_if/sipc4_io_device.c b/drivers/misc/modem_if/sipc4_io_device.c index 28f95f7..da1ea04 100644 --- a/drivers/misc/modem_if/sipc4_io_device.c +++ b/drivers/misc/modem_if/sipc4_io_device.c @@ -1,6 +1,4 @@ -/* /linux/drivers/misc/modem_if/modem_io_device.c - * - * Copyright (C) 2010 Google, Inc. +/* * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -26,10 +24,7 @@ #include <linux/etherdevice.h> #include <linux/device.h> -#include <linux/platform_data/modem.h> -#ifdef CONFIG_LINK_DEVICE_C2C -#include <linux/platform_data/c2c.h> -#endif +#include "modem.h" #include "modem_prj.h" #include "modem_utils.h" @@ -40,7 +35,8 @@ * So, give restriction to allocation size below 1 page to prevent * big pages broken. */ -#define MAX_RXDATA_SIZE 0x0E00 /* 4 * 1024 - 512 */ +#define MAX_RXDATA_SIZE (4096 - 512) +#define MAX_BOOTDATA_SIZE 0x4008 /* EBL package format*/ #define MAX_MULTI_FMT_SIZE 0x4000 /* 16 * 1024 */ static const char hdlc_start[1] = { HDLC_START }; @@ -250,22 +246,6 @@ static int rx_hdlc_head_check(struct io_device *iod, struct link_device *ld, hdr->start = HDLC_START; hdr->len = 0; - /* debug print */ - switch (iod->format) { - case IPC_FMT: - case IPC_RAW: - case IPC_MULTI_RAW: - case IPC_RFS: - /* TODO: print buf... */ - break; - - case IPC_CMD: - case IPC_BOOT: - case IPC_RAMDUMP: - default: - break; - } - buf += len; done_len += len; rest -= len; /* rest, call by value */ @@ -409,12 +389,6 @@ static int rx_multi_fmt_frame(struct sk_buff *rx_skb) /* If there has been no multiple frame with this ID */ if (!(fh->control & 0x80)) { /* It is a single frame because the "more" bit is 0. */ -#if 0 - mif_err("\n<%s> Rx FMT frame (len %d)\n", - iod->name, rcvd); - print_sipc4_fmt_frame(data); - mif_err("\n"); -#endif skb_queue_tail(&iod->sk_rx_q, fragdata(iod, ld)->skb_recv); mif_debug("wake up wq of %s\n", iod->name); @@ -449,12 +423,6 @@ static int rx_multi_fmt_frame(struct sk_buff *rx_skb) /* It is the last frame because the "more" bit is 0. */ mif_info("The Last (ID %d, %d bytes received)\n", id, skb->len); -#if 0 - mif_err("\n<%s> Rx FMT frame (len %d)\n", - iod->name, skb->len); - print_sipc4_fmt_frame(skb->data); - mif_err("\n"); -#endif skb_queue_tail(&iod->sk_rx_q, skb); iod->skb[id] = NULL; mif_info("wake up wq of %s\n", iod->name); @@ -491,12 +459,6 @@ static int rx_multi_fmt_frame_sipc42(struct sk_buff *rx_skb) /* If there has been no multiple frame with this ID */ if (!(fh->control & 0x80)) { /* It is a single frame because the "more" bit is 0. */ -#if 0 - mif_err("\n<%s> Rx FMT frame (len %d)\n", - iod->name, rcvd); - print_sipc4_fmt_frame(data); - mif_err("\n"); -#endif skb_queue_tail(&real_iod->sk_rx_q, fragdata(iod, ld)->skb_recv); mif_debug("wake up wq of %s\n", iod->name); @@ -530,12 +492,6 @@ static int rx_multi_fmt_frame_sipc42(struct sk_buff *rx_skb) /* It is the last frame because the "more" bit is 0. */ mif_err("The Last (ID %d, %d bytes received)\n", id, skb->len); -#if 0 - mif_err("\n<%s> Rx FMT frame (len %d)\n", - iod->name, skb->len); - print_sipc4_fmt_frame(skb->data); - mif_err("\n"); -#endif skb_queue_tail(&real_iod->sk_rx_q, skb); real_iod->skb[id] = NULL; mif_info("wake up wq of %s\n", real_iod->name); @@ -819,55 +775,6 @@ exit: return err; } -static int rx_rfs_packet(struct io_device *iod, struct link_device *ld, - const char *data, unsigned size) -{ - int err = 0; - int pad = 0; - int rcvd = 0; - struct sk_buff *skb; - - if (data[0] != HDLC_START) { - mif_err("Dropping RFS packet ... " - "size = %d, start = %02X %02X %02X %02X\n", - size, - data[0], data[1], data[2], data[3]); - return -EINVAL; - } - - if (data[size-1] != HDLC_END) { - for (pad = 1; pad < 4; pad++) - if (data[(size-1)-pad] == HDLC_END) - break; - - if (pad >= 4) { - char *b = (char *)data; - unsigned sz = size; - mif_err("size %d, No END_FLAG!!!\n", size); - mif_err("end = %02X %02X %02X %02X\n", - b[sz-4], b[sz-3], b[sz-2], b[sz-1]); - return -EINVAL; - } else { - mif_info("padding = %d\n", pad); - } - } - - skb = rx_alloc_skb(size, iod, ld); - if (unlikely(!skb)) { - mif_err("alloc_skb fail\n"); - return -ENOMEM; - } - - /* copy the RFS haeder to skb->data */ - rcvd = size - sizeof(hdlc_start) - sizeof(hdlc_end) - pad; - memcpy(skb_put(skb, rcvd), ((char *)data + sizeof(hdlc_start)), rcvd); - - fragdata(iod, ld)->skb_recv = skb; - err = rx_iodev_skb(fragdata(iod, ld)->skb_recv); - - return err; -} - /* called from link device when a packet arrives for this io device */ static int io_dev_recv_data_from_link_dev(struct io_device *iod, struct link_device *ld, const char *data, unsigned int len) @@ -891,14 +798,9 @@ static int io_dev_recv_data_from_link_dev(struct io_device *iod, */ switch (iod->format) { - case IPC_RFS: -#ifdef CONFIG_IPC_CMC22x_OLD_RFS - err = rx_rfs_packet(iod, ld, data, len); - return err; -#endif - case IPC_FMT: case IPC_RAW: + case IPC_RFS: case IPC_MULTI_RAW: if (iod->waketime) wake_lock_timeout(&iod->wakelock, iod->waketime); @@ -961,12 +863,17 @@ static int io_dev_recv_data_from_link_dev(struct io_device *iod, static void io_dev_modem_state_changed(struct io_device *iod, enum modem_state state) { - iod->mc->phone_state = state; - mif_err("modem state changed. (iod: %s, state: %d)\n", - iod->name, state); + struct modem_ctl *mc = iod->mc; + int old_state = mc->phone_state; - if ((state == STATE_CRASH_RESET) || (state == STATE_CRASH_EXIT) - || (state == STATE_NV_REBUILDING)) + if (old_state != state) { + mc->phone_state = state; + mif_err("%s state changed (%s -> %s)\n", mc->name, + get_cp_state_str(old_state), get_cp_state_str(state)); + } + + if (state == STATE_CRASH_RESET || state == STATE_CRASH_EXIT || + state == STATE_NV_REBUILDING) wake_up(&iod->wq); } @@ -977,10 +884,24 @@ static void io_dev_modem_state_changed(struct io_device *iod, */ static void io_dev_sim_state_changed(struct io_device *iod, bool sim_online) { + +#if defined(CONFIG_MACH_KONA) && defined(CONFIG_UMTS_MODEM_XMM6262) + mif_err("modem_current_state is %d\n", iod->mc->phone_state); +#endif + if (atomic_read(&iod->opened) == 0) { - mif_err("iod is not opened: %s\n", - iod->name); - } else if (iod->mc->sim_state.online == sim_online) { + mif_err("iod is not opened: %s\n", iod->name); + /* update latest sim status */ + iod->mc->sim_state.online = sim_online; + } +#if defined(CONFIG_LINK_DEVICE_HSIC) && defined(CONFIG_UMTS_MODEM_XMM6262) // fixed modem unknown issue (kina 3G) + else if (iod->mc->phone_state == STATE_BOOTING) { + mif_err("modem_current_state is STATE_BOOTING\n"); + /* update latest sim status */ + iod->mc->sim_state.online = sim_online; + } +#endif + else if (iod->mc->sim_state.online == sim_online) { mif_err("sim state not changed.\n"); } else { iod->mc->sim_state.online = sim_online; @@ -995,6 +916,7 @@ static void io_dev_sim_state_changed(struct io_device *iod, bool sim_online) } } + static int misc_open(struct inode *inode, struct file *filp) { struct io_device *iod = to_io_device(filp->private_data); @@ -1078,32 +1000,32 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case IOCTL_MODEM_ON: - mif_debug("misc_ioctl : IOCTL_MODEM_ON\n"); + mif_debug("%s: IOCTL_MODEM_ON\n", iod->name); return iod->mc->ops.modem_on(iod->mc); case IOCTL_MODEM_OFF: - mif_debug("misc_ioctl : IOCTL_MODEM_OFF\n"); + mif_debug("%s: IOCTL_MODEM_OFF\n", iod->name); return iod->mc->ops.modem_off(iod->mc); case IOCTL_MODEM_RESET: - mif_debug("misc_ioctl : IOCTL_MODEM_RESET\n"); + mif_debug("%s: IOCTL_MODEM_RESET\n", iod->name); return iod->mc->ops.modem_reset(iod->mc); case IOCTL_MODEM_BOOT_ON: - mif_debug("misc_ioctl : IOCTL_MODEM_BOOT_ON\n"); + mif_debug("%s: IOCTL_MODEM_BOOT_ON\n", iod->name); return iod->mc->ops.modem_boot_on(iod->mc); case IOCTL_MODEM_BOOT_OFF: - mif_debug("misc_ioctl : IOCTL_MODEM_BOOT_OFF\n"); + mif_debug("%s: IOCTL_MODEM_BOOT_OFF\n", iod->name); return iod->mc->ops.modem_boot_off(iod->mc); /* TODO - will remove this command after ril updated */ case IOCTL_MODEM_BOOT_DONE: - mif_debug("misc_ioctl : IOCTL_MODEM_BOOT_DONE\n"); + mif_debug("%s: IOCTL_MODEM_BOOT_DONE\n", iod->name); return 0; case IOCTL_MODEM_STATUS: - mif_debug("misc_ioctl : IOCTL_MODEM_STATUS\n"); + mif_debug("%s: IOCTL_MODEM_STATUS\n", iod->name); p_state = iod->mc->phone_state; if ((p_state == STATE_CRASH_RESET) || @@ -1126,7 +1048,7 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return p_state; case IOCTL_MODEM_PROTOCOL_SUSPEND: - mif_info("misc_ioctl : IOCTL_MODEM_PROTOCOL_SUSPEND\n"); + mif_info("%s: IOCTL_MODEM_PROTOCOL_SUSPEND\n", iod->name); if (iod->format != IPC_MULTI_RAW) return -EINVAL; @@ -1134,8 +1056,16 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) iodevs_for_each(iod->msd, iodev_netif_stop, 0); return 0; + case IOCTL_MODEM_DL_START: + mif_info("%s: IOCTL_MODEM_DL_START\n", iod->name); + return ld->dload_start(ld, iod); + + case IOCTL_MODEM_FW_UPDATE: + mif_info("%s: IOCTL_MODEM_FW_UPDATE\n", iod->name); + return ld->firm_update(ld, iod, arg); + case IOCTL_MODEM_PROTOCOL_RESUME: - mif_info("misc_ioctl : IOCTL_MODEM_PROTOCOL_RESUME\n"); + mif_info("%s: IOCTL_MODEM_PROTOCOL_RESUME\n", iod->name); if (iod->format != IPC_MULTI_RAW) return -EINVAL; @@ -1144,21 +1074,29 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return 0; case IOCTL_MODEM_DUMP_START: - mif_err("misc_ioctl : IOCTL_MODEM_DUMP_START\n"); + mif_err("%s: IOCTL_MODEM_DUMP_START\n", iod->name); + return ld->dump_start(ld, iod); + + case IOCTL_MODEM_RAMDUMP_START: + mif_err("%s: IOCTL_MODEM_RAMDUMP_START\n", iod->name); return ld->dump_start(ld, iod); case IOCTL_MODEM_DUMP_UPDATE: - mif_debug("misc_ioctl : IOCTL_MODEM_DUMP_UPDATE\n"); + mif_debug("%s: IOCTL_MODEM_DUMP_UPDATE\n", iod->name); return ld->dump_update(ld, iod, arg); + case IOCTL_MODEM_RAMDUMP_STOP: + mif_info("%s: IOCTL_MODEM_RAMDUMP_STOP\n", iod->name); + return ld->dump_finish(ld, iod, arg); + case IOCTL_MODEM_FORCE_CRASH_EXIT: - mif_debug("misc_ioctl : IOCTL_MODEM_FORCE_CRASH_EXIT\n"); + mif_debug("%s: IOCTL_MODEM_FORCE_CRASH_EXIT\n", iod->name); if (iod->mc->ops.modem_force_crash_exit) return iod->mc->ops.modem_force_crash_exit(iod->mc); return -EINVAL; case IOCTL_MODEM_CP_UPLOAD: - mif_err("misc_ioctl : IOCTL_MODEM_CP_UPLOAD\n"); + mif_err("%s: IOCTL_MODEM_CP_UPLOAD\n", iod->name); if (copy_from_user(cpinfo_buf + strlen(cpinfo_buf), (void __user *)arg, MAX_CPINFO_SIZE) != 0) panic("CP Crash"); @@ -1167,12 +1105,12 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return 0; case IOCTL_MODEM_DUMP_RESET: - mif_err("misc_ioctl : IOCTL_MODEM_DUMP_RESET\n"); + mif_err("%s: IOCTL_MODEM_DUMP_RESET\n", iod->name); return iod->mc->ops.modem_dump_reset(iod->mc); #if defined(CONFIG_SEC_DUAL_MODEM_MODE) case IOCTL_MODEM_SWITCH_MODEM: - mif_err("misc_ioctl : IOCTL_MODEM_SWITCH_MODEM\n"); + mif_err("%s: IOCTL_MODEM_SWITCH_MODEM\n", iod->name); iod->mc->phone_state = STATE_MODEM_SWITCH; wake_up(&iod->wq); return 0; @@ -1188,20 +1126,6 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) mif_dump_log(iod->mc->msd, iod); return 0; - case IOCTL_MIF_DPRAM_DUMP: -#ifdef CONFIG_LINK_DEVICE_DPRAM - if (iod->mc->mdm_data->link_types & LINKTYPE(LINKDEV_DPRAM)) { - size = iod->mc->mdm_data->dpram_ctl->dp_size; - ret = copy_to_user((void __user *)arg, &size, - sizeof(unsigned long)); - if (ret < 0) - return -EFAULT; - mif_dump_dpram(iod); - return 0; - } -#endif - return -EINVAL; - default: /* If you need to handle the ioctl for specific link device, * then assign the link ioctl handler to ld->ioctl @@ -1209,12 +1133,48 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (ld->ioctl) return ld->ioctl(ld, iod, cmd, arg); - mif_err("misc_ioctl : ioctl 0x%X is not defined.\n", cmd); + mif_err("%s: ioctl 0x%X is not defined\n", iod->name, cmd); return -EINVAL; } return 0; } +static size_t _boot_write(struct io_device *iod, const char __user *buf, + size_t count) +{ + int rest_len = count, frame_len = 0; + char *cur = (char *)buf; + struct sk_buff *skb = NULL; + struct link_device *ld = get_current_link(iod); + int ret; + + while (rest_len) { + frame_len = min(rest_len, MAX_BOOTDATA_SIZE); + skb = alloc_skb(frame_len, GFP_KERNEL); + if (!skb) { + mif_err("fail alloc skb (%d)\n", __LINE__); + return -ENOMEM; + } + if (copy_from_user( + skb_put(skb, frame_len), cur, frame_len) != 0) { + dev_kfree_skb_any(skb); + return -EFAULT; + } + rest_len -= frame_len; + cur += frame_len; + + skbpriv(skb)->iod = iod; + skbpriv(skb)->ld = ld; + + ret = ld->send(ld, iod, skb); + if (ret < 0) { + dev_kfree_skb_any(skb); + return ret; + } + } + return count; +} + static ssize_t misc_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { @@ -1237,6 +1197,10 @@ static ssize_t misc_write(struct file *filp, const char __user *buf, skb = alloc_skb(frame_len, GFP_KERNEL); if (!skb) { + if (frame_len > MAX_BOOTDATA_SIZE && iod->format == IPC_BOOT) { + mif_info("large alloc fail\n"); + return _boot_write(iod, buf, count); + } mif_err("fail alloc skb (%d)\n", __LINE__); return -ENOMEM; } @@ -1278,31 +1242,6 @@ static ssize_t misc_write(struct file *filp, const char __user *buf, skb_put(skb, calc_padding_size(iod, ld, skb->len)); -#if 0 - if (iod->format == IPC_FMT) { - mif_err("\n<%s> Tx HDLC FMT frame (len %d)\n", - iod->name, skb->len); - print_sipc4_hdlc_fmt_frame(skb->data); - mif_err("\n"); - } -#endif -#if 0 - if (iod->format == IPC_RAW) { - mif_err("\n<%s> Tx HDLC RAW frame (len %d)\n", - iod->name, skb->len); - mif_print_data(skb->data, (skb->len < 64 ? skb->len : 64)); - mif_err("\n"); - } -#endif -#if 0 - if (iod->format == IPC_RFS) { - mif_err("\n<%s> Tx HDLC RFS frame (len %d)\n", - iod->name, skb->len); - mif_print_data(skb->data, (skb->len < 64 ? skb->len : 64)); - mif_err("\n"); - } -#endif - /* send data with sk_buff, link device will put sk_buff * into the specific sk_buff_q and run work-q to send data */ @@ -1409,43 +1348,6 @@ static ssize_t misc_read(struct file *filp, char *buf, size_t count, return pktsize; } -#ifdef CONFIG_LINK_DEVICE_C2C -static int misc_mmap(struct file *filp, struct vm_area_struct *vma) -{ - int r = 0; - unsigned long size = 0; - unsigned long pfn = 0; - unsigned long offset = 0; - struct io_device *iod = (struct io_device *)filp->private_data; - - if (!vma) - return -EFAULT; - - size = vma->vm_end - vma->vm_start; - offset = vma->vm_pgoff << PAGE_SHIFT; - if (offset + size > (C2C_CP_RGN_SIZE + C2C_SH_RGN_SIZE)) { - mif_err("offset + size > C2C_CP_RGN_SIZE\n"); - return -EINVAL; - } - - /* Set the noncacheable property to the region */ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_RESERVED | VM_IO; - - pfn = __phys_to_pfn(C2C_CP_RGN_ADDR + offset); - r = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); - if (r) { - mif_err("Failed in remap_pfn_range()!!!\n"); - return -EAGAIN; - } - - mif_err("VA = 0x%08lx, offset = 0x%lx, size = %lu\n", - vma->vm_start, offset, size); - - return 0; -} -#endif - static const struct file_operations misc_io_fops = { .owner = THIS_MODULE, .open = misc_open, @@ -1454,9 +1356,6 @@ static const struct file_operations misc_io_fops = { .unlocked_ioctl = misc_ioctl, .write = misc_write, .read = misc_read, -#ifdef CONFIG_LINK_DEVICE_C2C - .mmap = misc_mmap, -#endif }; static int vnet_open(struct net_device *ndev) diff --git a/drivers/misc/modem_if/sipc4_modem.c b/drivers/misc/modem_if/sipc4_modem.c index 59e2de9..b4f9c2a 100644 --- a/drivers/misc/modem_if/sipc4_modem.c +++ b/drivers/misc/modem_if/sipc4_modem.c @@ -32,7 +32,7 @@ #include <linux/delay.h> #include <linux/wakelock.h> -#include <linux/platform_data/modem.h> +#include "modem.h" #include "modem_prj.h" #include "modem_variation.h" #include "modem_utils.h" @@ -328,9 +328,22 @@ static int modem_resume(struct device *pdev) return 0; } +#ifdef CONFIG_FAST_BOOT +static void modem_complete(struct device *pdev) +{ + struct modem_ctl *mc = dev_get_drvdata(pdev); + + if (mc->modem_complete) + mc->modem_complete(mc); +} +#endif + static const struct dev_pm_ops modem_pm_ops = { .suspend = modem_suspend, .resume = modem_resume, +#ifdef CONFIG_FAST_BOOT + .complete = modem_complete, +#endif }; static struct platform_driver modem_driver = { diff --git a/drivers/misc/modem_if/sipc5_common.c b/drivers/misc/modem_if/sipc5_common.c new file mode 100644 index 0000000..e8574c2 --- /dev/null +++ b/drivers/misc/modem_if/sipc5_common.c @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2010 Samsung Electronics. + * + * 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/init.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/if_arp.h> +#include <linux/ip.h> +#include <linux/if_ether.h> +#include <linux/etherdevice.h> +#include <linux/device.h> + +#include "modem.h" +#include "modem_prj.h" +#include "modem_utils.h" + +/** + * sipc5_start_valid + * @cfg: configuration field of an SIPC5 link frame + * + * Returns TRUE if the start (configuration field) of an SIPC5 link frame + * is valid or returns FALSE if it is not valid. + * + */ +bool sipc5_start_valid(u8 *frm) +{ + return (*frm & SIPC5_START_MASK) == SIPC5_START_MASK; +} + +bool sipc5_padding_exist(u8 *frm) +{ + return (*frm & SIPC5_PADDING_EXIST) ? true : false; +} + +bool sipc5_multi_frame(u8 *frm) +{ + return (*frm & SIPC5_EXT_FIELD_MASK) == SIPC5_CTL_FIELD_MASK; +} + +bool sipc5_ext_len(u8 *frm) +{ + return (*frm & SIPC5_EXT_FIELD_MASK) == SIPC5_EXT_LENGTH_MASK; +} + +/** + * sipc5_get_hdr_len + * @cfg: configuration field of an SIPC5 link frame + * + * Returns the length of SIPC5 link layer header in an SIPC5 link frame + * + */ +int sipc5_get_hdr_len(u8 *frm) +{ + if (*frm & SIPC5_EXT_FIELD_EXIST) { + if (*frm & SIPC5_CTL_FIELD_EXIST) + return SIPC5_HEADER_SIZE_WITH_CTL_FLD; + else + return SIPC5_HEADER_SIZE_WITH_EXT_LEN; + } else { + return SIPC5_MIN_HEADER_SIZE; + } +} + +/** + * sipc5_get_ch_id + * @frm: pointer to an SIPC5 frame + * + * Returns the channel ID in an SIPC5 link frame + * + */ +u8 sipc5_get_ch_id(u8 *frm) +{ + return *(frm + SIPC5_CH_ID_OFFSET); +} + +/** + * sipc5_get_ctrl_field + * @frm: pointer to an SIPC5 frame + * + * Returns the control field in an SIPC5 link frame + * + */ +u8 sipc5_get_ctrl_field(u8 *frm) +{ + return *(frm + SIPC5_CTL_OFFSET); +} + +/** + * sipc5_get_frame_len + * @frm: pointer to an SIPC5 link frame + * + * Returns the length of an SIPC5 link frame + * + */ +int sipc5_get_frame_len(u8 *frm) +{ + u8 cfg = frm[0]; + u16 *sz16 = (u16 *)(frm + SIPC5_LEN_OFFSET); + u32 *sz32 = (u32 *)(frm + SIPC5_LEN_OFFSET); + + if (unlikely(cfg & SIPC5_EXT_FIELD_EXIST)) { + if (cfg & SIPC5_CTL_FIELD_EXIST) + return (int)(*sz16); + else + return (int)(*sz32); + } else { + return (int)(*sz16); + } +} + +/** + * sipc5_calc_padding_size + * @len: length of an SIPC5 link frame + * + * Returns the padding size for an SIPC5 link frame + * + */ +int sipc5_calc_padding_size(int len) +{ + int residue = len & 0x3; + return residue ? (4 - residue) : 0; +} + +/** + * sipc5_get_total_len + * @frm: pointer to an SIPC5 link frame + * + * Returns the total length of an SIPC5 link frame with padding + * + */ +int sipc5_get_total_len(u8 *frm) +{ + int len = sipc5_get_frame_len(frm); + int pad = sipc5_padding_exist(frm) ? sipc5_calc_padding_size(len) : 0; + return len + pad; +} + +/** + * sipc5_build_config + * @iod: pointer to the IO device + * @ld: pointer to the link device + * @count: length of the data to be transmitted + * + * Builds a config value for an SIPC5 link frame header + * + * Returns the config value for the header or 0 for non-SIPC formats + */ +u8 sipc5_build_config(struct io_device *iod, struct link_device *ld, u32 count) +{ + u8 cfg = SIPC5_START_MASK; + + if (iod->format > IPC_MULTI_RAW && iod->id == 0) + return 0; + + if (ld->aligned) + cfg |= SIPC5_PADDING_EXIST; + +#if 0 + if ((count + SIPC5_MIN_HEADER_SIZE) > ld->mtu[dev]) + cfg |= SIPC5_CTL_FIELD_MASK; + else +#endif + if ((count + SIPC5_MIN_HEADER_SIZE) > 0xFFFF) + cfg |= SIPC5_EXT_LENGTH_MASK; + + return cfg; +} + +/** + * sipc5_build_header + * @iod: pointer to the IO device + * @ld: pointer to the link device + * @buff: pointer to a buffer in which an SIPC5 link frame header will be stored + * @cfg: value for the config field in the header + * @ctrl: value for the control field in the header + * @count: length of data in the SIPC5 link frame to be transmitted + * + * Builds the link layer header of an SIPC5 frame + */ +void sipc5_build_header(struct io_device *iod, struct link_device *ld, + u8 *buff, u8 cfg, u8 ctrl, u32 count) +{ + u16 *sz16 = (u16 *)(buff + SIPC5_LEN_OFFSET); + u32 *sz32 = (u32 *)(buff + SIPC5_LEN_OFFSET); + u32 hdr_len = sipc5_get_hdr_len(&cfg); + + /* Store the config field and the channel ID field */ + buff[SIPC5_CONFIG_OFFSET] = cfg; + buff[SIPC5_CH_ID_OFFSET] = iod->id; + + /* Store the frame length field */ + if (sipc5_ext_len(buff)) + *sz32 = (u32)(hdr_len + count); + else + *sz16 = (u16)(hdr_len + count); + + /* Store the control field */ + if (sipc5_multi_frame(buff)) + buff[SIPC5_CTL_OFFSET] = ctrl; +} + +/** + * std_udl_get_cmd + * @frm: pointer to an SIPC5 link frame + * + * Returns the standard BOOT/DUMP (STD_UDL) command in an SIPC5 BOOT/DUMP frame. + */ +u32 std_udl_get_cmd(u8 *frm) +{ + u8 *cmd = frm + sipc5_get_hdr_len(frm); + return *((u32 *)cmd); +} + +/** + * std_udl_with_payload + * @cmd: standard BOOT/DUMP command + * + * Returns true if the STD_UDL command has a payload. + */ +bool std_udl_with_payload(u32 cmd) +{ + u32 mask = cmd & STD_UDL_STEP_MASK; + return (mask && mask < STD_UDL_CRC) ? true : false; +} + diff --git a/drivers/misc/modem_if/sipc5_io_device.c b/drivers/misc/modem_if/sipc5_io_device.c index a9932c1..71596ae 100644 --- a/drivers/misc/modem_if/sipc5_io_device.c +++ b/drivers/misc/modem_if/sipc5_io_device.c @@ -1,5 +1,4 @@ -/* /linux/drivers/misc/modem_if/sipc5_io_device.c - * +/* * Copyright (C) 2010 Samsung Electronics. * * This software is licensed under the terms of the GNU General Public @@ -24,11 +23,9 @@ #include <linux/if_ether.h> #include <linux/etherdevice.h> #include <linux/device.h> +#include <linux/module.h> -#include <linux/platform_data/modem.h> -#ifdef CONFIG_LINK_DEVICE_C2C -#include <linux/platform_data/c2c.h> -#endif +#include "modem.h" #include "modem_prj.h" #include "modem_utils.h" @@ -104,7 +101,7 @@ static void iodev_showtxlink(struct io_device *iod, void *args) struct link_device *ld = get_current_link(iod); if (iod->io_typ == IODEV_NET && IS_CONNECTED(iod, ld)) - *p += sprintf(*p, "%s: %s\n", iod->name, ld->name); + *p += sprintf(*p, "%s<->%s\n", iod->name, ld->name); } static ssize_t show_txlink(struct device *dev, @@ -130,181 +127,107 @@ static ssize_t store_txlink(struct device *dev, static struct device_attribute attr_txlink = __ATTR(txlink, S_IRUGO | S_IWUSR, show_txlink, store_txlink); -/** - * rx_check_frame_cfg - * @cfg: configuration field of a link layer header - * @frm: pointer to the sipc5_frame_data buffer - * - * 1) Checks whether or not an extended field exists - * 2) Calculates the length of a link layer header - * - * Returns the size of a link layer header - * - * Must be invoked only when the configuration field of the link layer header - * is validated with sipc5_start_valid() function - */ -static int rx_check_frame_cfg(u8 cfg, struct sipc5_frame_data *frm) +static int netif_flow_ctrl(struct link_device *ld, struct sk_buff *skb) { - frm->config = cfg; - - if (likely(cfg & SIPC5_PADDING_EXIST)) - frm->padding = true; - - if (unlikely(cfg & SIPC5_EXT_FIELD_EXIST)) { - if (cfg & SIPC5_CTL_FIELD_EXIST) { - frm->ctl_fld = true; - frm->hdr_len = SIPC5_HEADER_SIZE_WITH_CTL_FLD; - } else { - frm->ext_len = true; - frm->hdr_len = SIPC5_HEADER_SIZE_WITH_EXT_LEN; - } + u8 cmd = skb->data[0]; + + if (cmd == FLOW_CTRL_SUSPEND) { + if (ld->suspend_netif_tx) + goto exit; + ld->suspend_netif_tx = true; + mif_netif_stop(ld); + mif_info("%s: FLOW_CTRL_SUSPEND\n", ld->name); + } else if (cmd == FLOW_CTRL_RESUME) { + if (!ld->suspend_netif_tx) + goto exit; + ld->suspend_netif_tx = false; + mif_netif_wake(ld); + mif_info("%s: FLOW_CTRL_RESUME\n", ld->name); } else { - frm->hdr_len = SIPC5_MIN_HEADER_SIZE; + mif_info("%s: ERR! invalid command %02X\n", ld->name, cmd); } - return frm->hdr_len; -} - -/** - * rx_build_meta_data - * @ld: pointer to the link device - * @frm: pointer to the sipc5_frame_data buffer - * - * Fills each field of sipc5_frame_data from a link layer header - * 1) Extracts the channel ID - * 2) Calculates the length of a link layer frame - * 3) Extracts a control field if exists - * 4) Calculates the length of an IPC message packet in the link layer frame - * - */ -static void rx_build_meta_data(struct link_device *ld, - struct sipc5_frame_data *frm) -{ - u16 *sz16 = (u16 *)(frm->hdr + SIPC5_LEN_OFFSET); - u32 *sz32 = (u32 *)(frm->hdr + SIPC5_LEN_OFFSET); - - frm->ch_id = frm->hdr[SIPC5_CH_ID_OFFSET]; - - if (unlikely(frm->ext_len)) - frm->len = *sz32; - else - frm->len = *sz16; - - if (unlikely(frm->ctl_fld)) - frm->control = frm->hdr[SIPC5_CTL_OFFSET]; - - frm->data_len = frm->len - frm->hdr_len; - - mif_debug("%s: FRM ch:%d len:%d ctl:%02X data.len:%d\n", - ld->name, frm->ch_id, frm->len, frm->control, frm->data_len); +exit: + dev_kfree_skb_any(skb); + return 0; } -/** - * tx_build_link_header - * @frm: pointer to the sipc5_frame_data buffer - * @iod: pointer to the IO device - * @ld: pointer to the link device - * @count: length of the data to be transmitted - * - * Builds the meta data for an SIPC5 frame and the link layer header of it - * Returns the link layer header length for an SIPC5 frame or 0 for other frame - */ -static unsigned tx_build_link_header(struct sipc5_frame_data *frm, - struct io_device *iod, struct link_device *ld, ssize_t count) +static inline int queue_skb_to_iod(struct sk_buff *skb, struct io_device *iod) { - u8 *buff = frm->hdr; - u16 *sz16 = (u16 *)(buff + SIPC5_LEN_OFFSET); - u32 *sz32 = (u32 *)(buff + SIPC5_LEN_OFFSET); + struct sk_buff_head *rxq = &iod->sk_rx_q; - memset(frm, 0, sizeof(struct sipc5_frame_data)); + skb_queue_tail(rxq, skb); - if (iod->format == IPC_CMD || - iod->format == IPC_BOOT || - iod->format == IPC_RAMDUMP) { - frm->len = count; + if (iod->format < IPC_MULTI_RAW && rxq->qlen > MAX_IOD_RXQ_LEN) { + struct sk_buff *victim = skb_dequeue(rxq); + mif_err("%s: %s application may be dead (rxq->qlen %d > %d)\n", + iod->name, iod->app ? iod->app : "corresponding", + rxq->qlen, MAX_IOD_RXQ_LEN); + if (victim) + dev_kfree_skb_any(victim); + return -ENOSPC; + } else { + mif_debug("%s: rxq->qlen = %d\n", iod->name, rxq->qlen); return 0; } +} - frm->config = SIPC5_START_MASK; +static int rx_drain(struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + return 0; +} - if (iod->format == IPC_FMT && count > 2048) { - frm->ctl_fld = true; - frm->config |= SIPC5_EXT_FIELD_EXIST; - frm->config |= SIPC5_CTL_FIELD_EXIST; - } +static int rx_loopback(struct sk_buff *skb) +{ + struct io_device *iod = skbpriv(skb)->iod; + struct link_device *ld = skbpriv(skb)->ld; + int ret; - if (iod->id >= SIPC5_CH_ID_RFS_0 && count > 0xFFFF) { - frm->ext_len = true; - frm->config |= SIPC5_EXT_FIELD_EXIST; + ret = ld->send(ld, iod, skb); + if (ret < 0) { + mif_err("%s->%s: ERR! ld->send fail (err %d)\n", + iod->name, ld->name, ret); } - if (ld->aligned) - frm->config |= SIPC5_PADDING_EXIST; - - frm->ch_id = iod->id; - - frm->hdr_len = sipc5_get_hdr_len(frm->config); - frm->data_len = count; - frm->len = frm->hdr_len + frm->data_len; - - buff[SIPC5_CONFIG_OFFSET] = frm->config; - buff[SIPC5_CH_ID_OFFSET] = frm->ch_id; - - if (unlikely(frm->ext_len)) - *sz32 = (u32)frm->len; - else - *sz16 = (u16)frm->len; - - if (unlikely(frm->ctl_fld)) - buff[SIPC5_CTL_OFFSET] = frm->control; - - return frm->hdr_len; + return ret; } static int rx_fmt_frame(struct sk_buff *skb) { - struct io_device *iod = skbpriv(skb)->iod; struct link_device *ld = skbpriv(skb)->ld; - struct sk_buff_head *rxq = &iod->sk_rx_q; - struct sipc_fmt_hdr *fh; + struct io_device *iod = skbpriv(skb)->iod; struct sk_buff *rx_skb; - u8 ctrl = skbpriv(skb)->control; - unsigned id = ctrl & 0x7F; + int hdr_len = sipc5_get_hdr_len(skb->data); + u8 ctrl; + u8 id; - if (iod->skb[id] == NULL) { - /* - ** There has been no multiple frame with this ID. - */ - if ((ctrl & 0x80) == 0) { - /* - ** It is a single frame because the "more" bit is 0. - */ - skb_queue_tail(rxq, skb); - if (unlikely(rxq->qlen > 2048)) { - struct sk_buff *victim; - mif_info("%s: WARNING! rxq->qlen %d > 2048\n", - iod->name, rxq->qlen); - victim = skb_dequeue(rxq); - dev_kfree_skb_any(victim); - } else { - mif_debug("%s: rxq->qlen = %d\n", - iod->name, rxq->qlen); - } + if (!sipc5_multi_frame(skb->data)) { + skb_pull(skb, hdr_len); + queue_skb_to_iod(skb, iod); + wake_up(&iod->wq); + return 0; + } - wake_up(&iod->wq); - return 0; - } + /* Get the control field */ + ctrl = sipc5_get_ctrl_field(skb->data); - /* - ** The start of multiple frames - */ - fh = (struct sipc_fmt_hdr *)skb->data; - mif_debug("%s: start multi-frame (ID:%d len:%d)\n", - iod->name, id, fh->len); + /* Extract the control ID from the control field */ + id = ctrl & 0x7F; + + /* Remove SIPC5 link header */ + skb_pull(skb, hdr_len); + + /* If there has been no multiple frame with this ID, ... */ + if (iod->skb[id] == NULL) { + struct sipc_fmt_hdr *fh = (struct sipc_fmt_hdr *)skb->data; + + mif_err("%s->%s: start of multi-frame (ID:%d len:%d)\n", + ld->name, iod->name, id, fh->len); rx_skb = rx_alloc_skb(fh->len, iod, ld); if (!rx_skb) { - mif_info("%s: ERR! rx_alloc_skb fail\n", iod->name); + mif_err("%s: ERR! rx_alloc_skb fail\n", iod->name); return -ENOMEM; } @@ -313,31 +236,19 @@ static int rx_fmt_frame(struct sk_buff *skb) rx_skb = iod->skb[id]; } - /* - ** Start multi-frame processing - */ + /* Perform multi-frame processing */ memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len); dev_kfree_skb_any(skb); if (ctrl & 0x80) { /* The last frame has not arrived yet. */ - mif_debug("%s: recv multi-frame (ID:%d rcvd:%d)\n", - iod->name, id, rx_skb->len); + mif_info("%s->%s: recv multi-frame (ID:%d rcvd:%d)\n", + ld->name, iod->name, id, rx_skb->len); } else { /* It is the last frame because the "more" bit is 0. */ - mif_debug("%s: end multi-frame (ID:%d rcvd:%d)\n", - iod->name, id, rx_skb->len); - skb_queue_tail(rxq, rx_skb); - if (unlikely(rxq->qlen > 2048)) { - struct sk_buff *victim; - mif_info("%s: WARNING! rxq->qlen %d > 2048\n", - iod->name, rxq->qlen); - victim = skb_dequeue(rxq); - dev_kfree_skb_any(victim); - } else { - mif_debug("%s: rxq->qlen = %d\n", iod->name, rxq->qlen); - } - + mif_err("%s->%s: end of multi-frame (ID:%d rcvd:%d)\n", + ld->name, iod->name, id, rx_skb->len); + queue_skb_to_iod(rx_skb, iod); iod->skb[id] = NULL; wake_up(&iod->wq); } @@ -345,76 +256,14 @@ static int rx_fmt_frame(struct sk_buff *skb) return 0; } -static int rx_rfs_frame(struct sk_buff *skb) -{ - struct io_device *iod = skbpriv(skb)->iod; - struct sk_buff_head *rxq = &iod->sk_rx_q; - - skb_queue_tail(rxq, skb); - if (unlikely(rxq->qlen > 2048)) { - struct sk_buff *victim; - mif_debug("%s: rxq->qlen %d > 2048\n", iod->name, rxq->qlen); - victim = skb_dequeue(rxq); - dev_kfree_skb_any(victim); - } else { - mif_debug("%s: rxq->qlen %d\n", iod->name, rxq->qlen); - } - - wake_up(&iod->wq); - - return 0; -} - -static int rx_loopback(struct sk_buff *skb) -{ - struct io_device *iod = skbpriv(skb)->iod; - struct link_device *ld = get_current_link(iod); - struct sipc5_frame_data frm; - unsigned headroom; - unsigned tailroom = 0; - int ret; - - headroom = tx_build_link_header(&frm, iod, ld, skb->len); - - if (ld->aligned) - tailroom = sipc5_calc_padding_size(headroom + skb->len); - - /* We need not to expand skb in here. dev_alloc_skb (in rx_alloc_skb) - * already alloc 32bytes padding in headroom. 32bytes are enough. - */ - - /* store IPC link header to start of skb - * this is skb_push not skb_put. different with misc_write. - */ - memcpy(skb_push(skb, headroom), frm.hdr, headroom); - - /* store padding */ - if (tailroom) - skb_put(skb, tailroom); - - /* forward */ - ret = ld->send(ld, iod, skb); - if (ret < 0) - mif_err("%s->%s: ld->send fail: %d\n", iod->name, - ld->name, ret); - return ret; -} - static int rx_raw_misc(struct sk_buff *skb) { - struct io_device *iod = skbpriv(skb)->iod; /* same with real_iod */ - struct sk_buff_head *rxq = &iod->sk_rx_q; + struct io_device *iod = skbpriv(skb)->iod; - skb_queue_tail(rxq, skb); - if (unlikely(rxq->qlen > 2048)) { - struct sk_buff *victim; - mif_debug("%s: rxq->qlen %d > 2048\n", iod->name, rxq->qlen); - victim = skb_dequeue(rxq); - dev_kfree_skb_any(victim); - } else { - mif_debug("%s: rxq->qlen %d\n", iod->name, rxq->qlen); - } + /* Remove the SIPC5 link header */ + skb_pull(skb, sipc5_get_hdr_len(skb->data)); + queue_skb_to_iod(skb, iod); wake_up(&iod->wq); return 0; @@ -422,12 +271,11 @@ static int rx_raw_misc(struct sk_buff *skb) static int rx_multi_pdp(struct sk_buff *skb) { - struct io_device *iod = skbpriv(skb)->iod; /* same with real_iod */ + struct link_device *ld = skbpriv(skb)->ld; + struct io_device *iod = skbpriv(skb)->iod; struct net_device *ndev; struct iphdr *iphdr; - struct ethhdr *ehdr; int ret; - const char source[ETH_ALEN] = SOURCE_MAC_ADDR; ndev = iod->ndev; if (!ndev) { @@ -435,6 +283,9 @@ static int rx_multi_pdp(struct sk_buff *skb) return -ENODEV; } + /* Remove the SIPC5 link header */ + skb_pull(skb, sipc5_get_hdr_len(skb->data)); + skb->dev = ndev; ndev->stats.rx_packets++; ndev->stats.rx_bytes += skb->len; @@ -447,14 +298,15 @@ static int rx_multi_pdp(struct sk_buff *skb) skb->protocol = htons(ETH_P_IP); if (iod->use_handover) { - skb_push(skb, sizeof(struct ethhdr)); - ehdr = (void *)skb->data; + struct ethhdr *ehdr; + const char source[ETH_ALEN] = SOURCE_MAC_ADDR; + + ehdr = (struct ethhdr *)skb_push(skb, sizeof(struct ethhdr)); memcpy(ehdr->h_dest, ndev->dev_addr, ETH_ALEN); memcpy(ehdr->h_source, source, ETH_ALEN); ehdr->h_proto = skb->protocol; skb->ip_summed = CHECKSUM_UNNECESSARY; skb_reset_mac_header(skb); - skb_pull(skb, sizeof(struct ethhdr)); } @@ -463,48 +315,82 @@ static int rx_multi_pdp(struct sk_buff *skb) else ret = netif_rx_ni(skb); - if (ret != NET_RX_SUCCESS) - mif_info("%s: ERR! netif_rx fail (err %d)\n", iod->name, ret); + if (ret != NET_RX_SUCCESS) { + mif_err("%s->%s: ERR! netif_rx fail (err %d)\n", + ld->name, iod->name, ret); + } return ret; } static int rx_demux(struct link_device *ld, struct sk_buff *skb) { - struct io_device *iod = NULL; - char *link = ld->name; - u8 ch = skbpriv(skb)->ch_id; + struct io_device *iod; + u8 ch = sipc5_get_ch_id(skb->data); +#ifdef DEBUG_MODEM_IF + struct modem_ctl *mc = ld->mc; + size_t len = (skb->len > 20) ? 20 : skb->len; + char tag[MIF_MAX_STR_LEN]; +#endif - if (unlikely(ch == SIPC5_CH_ID_MAX || ch == 0)) { - mif_info("%s: ERR! invalid ch# %d\n", link, ch); + if (unlikely(ch == 0)) { + mif_err("%s: ERR! invalid ch# %d\n", ld->name, ch); return -ENODEV; } + if (unlikely(ch == SIPC5_CH_ID_FLOW_CTRL)) + return netif_flow_ctrl(ld, skb); + /* IP loopback */ if (ch == DATA_LOOPBACK_CHANNEL && ld->msd->loopback_ipaddr) ch = RMNET0_CH_ID; iod = link_get_iod_with_channel(ld, ch); if (unlikely(!iod)) { - mif_info("%s: ERR! no iod for ch# %d\n", link, ch); + mif_err("%s: ERR! no iod with ch# %d\n", ld->name, ch); return -ENODEV; } skbpriv(skb)->ld = ld; skbpriv(skb)->iod = iod; - skbpriv(skb)->real_iod = iod; - /* don't care about CP2AP_LOOPBACK_CHANNEL is opened */ - if (unlikely(iod->id == CP2AP_LOOPBACK_CHANNEL)) + /* Don't care whether or not DATA_DRAIN_CHANNEL is opened */ + if (iod->id == DATA_DRAIN_CHANNEL) + return rx_drain(skb); + + /* Don't care whether or not DATA_LOOPBACK_CHANNEL is opened */ + if (iod->id == DATA_LOOPBACK_CHANNEL) return rx_loopback(skb); +#ifdef DEBUG_MODEM_IF + snprintf(tag, MIF_MAX_STR_LEN, "LNK: %s->%s", mc->name, iod->name); + if (unlikely(iod->format == IPC_FMT)) + pr_ipc(1, tag, skb->data, len); +#if 0 + if (iod->format == IPC_RAW) + pr_ipc(0, tag, skb->data, len); +#endif +#if 0 + if (iod->format == IPC_BOOT) + pr_ipc(0, tag, skb->data, len); +#endif +#if 0 + if (iod->format == IPC_RAMDUMP) + pr_ipc(0, tag, skb->data, len); +#endif +#if 0 + if (ch == 28) + pr_ipc(0, tag, skb->data, len); +#endif +#endif /*DEBUG_MODEM_IF*/ + if (atomic_read(&iod->opened) <= 0) { - mif_info("%s: ERR! %s is not opened\n", link, iod->name); + mif_err("%s: ERR! %s is not opened\n", ld->name, iod->name); return -ENODEV; } if (ch >= SIPC5_CH_ID_RFS_0) - return rx_rfs_frame(skb); + return rx_raw_misc(skb); else if (ch >= SIPC5_CH_ID_FMT_0) return rx_fmt_frame(skb); else if (iod->io_typ == IODEV_MISC) @@ -513,342 +399,337 @@ static int rx_demux(struct link_device *ld, struct sk_buff *skb) return rx_multi_pdp(skb); } -/* Check and store link layer header, then alloc an skb */ -static int rx_header_from_serial(struct io_device *iod, struct link_device *ld, - u8 *buff, unsigned size, struct sipc5_frame_data *frm) +/** + * rx_frame_config + * @iod: pointer to an instance of io_device structure + * @ld: pointer to an instance of link_device structure + * @buff: pointer to a buffer in which incoming data is stored + * @size: size of data in the buffer + * @frm: pointer to an instance of sipc5_frame_data structure + * + * 1) Checks a config field + * 2) Calculates the length of link layer header in an incoming frame and stores + * the value to "frm->hdr_len" + * 3) Stores the config field to "frm->hdr" and add the size of config field to + * "frm->hdr_rcvd" + * + * Returns the length of a config field that was copied to "frm" + */ +static int rx_frame_config(struct io_device *iod, struct link_device *ld, + u8 *buff, int size, struct sipc5_frame_data *frm) { - char *link = ld->name; - struct sk_buff *skb; - int len; - u8 cfg = buff[0]; - - mif_debug("%s: size %d\n", link, size); - - if (!frm->config) { - if (unlikely(!sipc5_start_valid(cfg))) { - mif_info("%s: ERR! wrong start (0x%02x)\n", link, cfg); - return -EBADMSG; - } - rx_check_frame_cfg(cfg, frm); - - /* Copy the link layer header to the header buffer */ - len = min(frm->hdr_len, size); - memcpy(frm->hdr, buff, len); - } else { - /* Copy the link layer header to the header buffer */ - len = min((frm->hdr_len - frm->hdr_rcvd), size); - memcpy((frm->hdr + frm->hdr_rcvd), buff, len); - } + int rest; + int rcvd; - frm->hdr_rcvd += len; - - mif_debug("%s: FRM hdr_len:%d, hdr_rcvd:%d\n", - link, frm->hdr_len, frm->hdr_rcvd); - - if (frm->hdr_rcvd >= frm->hdr_len) { - rx_build_meta_data(ld, frm); - skb = rx_alloc_skb(frm->data_len, iod, ld); - fragdata(iod, ld)->skb_recv = skb; - skbpriv(skb)->ch_id = frm->ch_id; - skbpriv(skb)->control = frm->control; + if (unlikely(!sipc5_start_valid(buff))) { + mif_err("%s->%s: ERR! INVALID config 0x%02x\n", + ld->name, iod->name, buff[0]); + return -EBADMSG; } - return len; -} - -/* copy data to skb */ -static int rx_payload_from_serial(struct io_device *iod, struct link_device *ld, - u8 *buff, unsigned size, struct sipc5_frame_data *frm) -{ - struct sk_buff *skb = fragdata(iod, ld)->skb_recv; - char *link = ld->name; - unsigned rest = frm->data_len - frm->data_rcvd; - unsigned len; - - /* rest == (frm->data_len - frm->data_rcvd) == tailroom of skb */ - rest = frm->data_len - frm->data_rcvd; - mif_debug("%s: FRM data.len:%d data.rcvd:%d rest:%d size:%d\n", - link, frm->data_len, frm->data_rcvd, rest, size); - - /* If there is no skb, data must be dropped. */ - len = min(rest, size); - if (skb) - memcpy(skb_put(skb, len), buff, len); + frm->hdr_len = sipc5_get_hdr_len(buff); - frm->data_rcvd += len; + /* Calculate the size of a segment that will be copied */ + rest = frm->hdr_len; + rcvd = SIPC5_CONFIG_SIZE; + mif_debug("%s->%s: hdr_len:%d hdr_rcvd:%d rest:%d size:%d rcvd:%d\n", + ld->name, iod->name, frm->hdr_len, frm->hdr_rcvd, rest, size, + rcvd); - mif_debug("%s: FRM data_len:%d, data_rcvd:%d\n", - link, frm->data_len, frm->data_rcvd); + /* Copy the config field of an SIPC5 link header to the header buffer */ + memcpy(frm->hdr, buff, rcvd); + frm->hdr_rcvd += rcvd; - return len; + return rcvd; } -static int rx_frame_from_serial(struct io_device *iod, struct link_device *ld, - const char *data, unsigned size) +/** + * rx_frame_prepare_skb + * @iod: pointer to an instance of io_device structure + * @ld: pointer to an instance of link_device structure + * @frm: pointer to an instance of sipc5_frame_data structure + * + * 1) Extracts the length of a link frame from the link header in "frm->hdr" + * 2) Allocates an skb + * 3) Calculates the payload size in the link frame + * 4) Calculates the padding size in the link frame + * + * Returns the pointer to an skb + */ +static struct sk_buff *rx_frame_prepare_skb(struct io_device *iod, + struct link_device *ld, struct sipc5_frame_data *frm) { - struct sipc5_frame_data *frm = &fragdata(iod, ld)->f_data; struct sk_buff *skb; - char *link = ld->name; - u8 *buff = (u8 *)data; - int rest = (int)size; - int err = 0; - int done = 0; - mif_debug("%s: size = %d\n", link, size); + /* Get the frame length */ + frm->len = sipc5_get_frame_len(frm->hdr); - if (frm->hdr_rcvd >= frm->hdr_len && frm->data_rcvd < frm->data_len) { - /* - ** There is an skb that is waiting for more SIPC5 data. - ** In this case, rx_header_from_serial() must be skipped. - */ - mif_debug("%s: FRM data.len:%d data.rcvd:%d -> recv_data\n", - link, frm->data_len, frm->data_rcvd); - goto recv_data; + /* Allocate an skb */ + skb = rx_alloc_skb(frm->len, iod, ld); + if (!skb) { + mif_err("%s->%s: ERR! rx_alloc_skb fail (size %d)\n", + ld->name, iod->name, frm->len); + return NULL; } -next_frame: - /* Receive and analyze header, then prepare an akb */ - err = done = rx_header_from_serial(iod, ld, buff, rest, frm); - if (err < 0) - goto err_exit; - - buff += done; - rest -= done; - mif_debug("%s: rx_header() -> done:%d rest:%d\n", link, done, rest); - if (rest < 0) - goto err_range; + /* Calculates the payload size */ + frm->pay_len = frm->len - frm->hdr_len; - if (rest == 0) - return size; + /* Calculates the padding size */ + if (sipc5_padding_exist(frm->hdr)) + frm->pad_len = sipc5_calc_padding_size(frm->len); -recv_data: - err = 0; + mif_debug("%s->%s: size %d (header:%d payload:%d padding:%d)\n", + ld->name, iod->name, frm->len, frm->hdr_len, frm->pay_len, + frm->pad_len); - mif_debug("%s: done:%d rest:%d -> rx_payload()\n", link, done, rest); - - done = rx_payload_from_serial(iod, ld, buff, rest, frm); - buff += done; - rest -= done; + return skb; +} - mif_debug("%s: rx_payload() -> done:%d rest:%d\n", link, done, rest); +/** + * rx_frame_header + * @iod: pointer to an instance of io_device structure + * @ld: pointer to an instance of link_device structure + * @buff: pointer to a buffer in which incoming data is stored + * @size: size of data in the buffer + * @frm: pointer to an instance of sipc5_frame_data structure + * + * 1) Stores a link layer header to "frm->hdr" temporarily while "frm->hdr_rcvd" + * is less than "frm->hdr_len" + * 2) Then, + * Allocates an skb + * Copies the link header from "frm" to "skb" + * Register the skb to receive payload + * + * Returns the size of a segment that was copied to "frm" + */ +static int rx_frame_header(struct io_device *iod, struct link_device *ld, + u8 *buff, int size, struct sipc5_frame_data *frm) +{ + struct sk_buff *skb; + int rest; + int rcvd; - if (rest == 0 && frm->data_rcvd < frm->data_len) { - /* - Data is being received and more data will come within the next - frame from the link device. - */ - return size; - } + /* Calculate the size of a segment that will be copied */ + rest = frm->hdr_len - frm->hdr_rcvd; + rcvd = min(rest, size); + mif_debug("%s->%s: hdr_len:%d hdr_rcvd:%d rest:%d size:%d rcvd:%d\n", + ld->name, iod->name, frm->hdr_len, frm->hdr_rcvd, rest, size, + rcvd); - /* At this point, one complete link layer frame has been received. */ + /* Copy a segment of an SIPC5 link header to "frm" */ + memcpy((frm->hdr + frm->hdr_rcvd), buff, rcvd); + frm->hdr_rcvd += rcvd; - /* A padding size is applied to access the next IPC frame. */ - if (frm->padding) { - done = sipc5_calc_padding_size(frm->len); - if (done > rest) { - mif_info("%s: ERR! padding %d > rest %d\n", - link, done, rest); - goto err_exit; + if (frm->hdr_rcvd >= frm->hdr_len) { + /* Prepare an skb with the information in {iod, ld, frm} */ + skb = rx_frame_prepare_skb(iod, ld, frm); + if (!skb) { + mif_err("%s->%s: ERR! rx_frame_prepare_skb fail\n", + ld->name, iod->name); + return -ENOMEM; } - buff += done; - rest -= done; - - mif_debug("%s: padding:%d -> rest:%d\n", link, done, rest); - - if (rest < 0) - goto err_range; - - } - - skb = fragdata(iod, ld)->skb_recv; - if (likely(skb)) { - mif_debug("%s: len:%d -> rx_demux()\n", link, skb->len); - err = rx_demux(ld, skb); - if (err < 0) - dev_kfree_skb_any(skb); - } else { - mif_debug("%s: len:%d -> drop\n", link, skb->len); - } - - /* initialize the skb_recv and the frame_data buffer */ - fragdata(iod, ld)->skb_recv = NULL; - memset(frm, 0, sizeof(struct sipc5_frame_data)); + /* Copy an SIPC5 link header from "frm" to "skb" */ + memcpy(skb_put(skb, frm->hdr_len), frm->hdr, frm->hdr_len); - if (rest > 0) - goto next_frame; - - if (rest <= 0) - return size; - -err_exit: - if (fragdata(iod, ld)->skb_recv && - frm->hdr_rcvd >= frm->hdr_len && frm->data_rcvd >= frm->data_len) { - dev_kfree_skb_any(fragdata(iod, ld)->skb_recv); - memset(frm, 0, sizeof(struct sipc5_frame_data)); - fragdata(iod, ld)->skb_recv = NULL; - mif_info("%s: ERR! clear frag\n", link); + /* Register the skb to receive payload */ + fragdata(iod, ld)->skb_recv = skb; } - return err; -err_range: - mif_info("%s: ERR! size:%d vs. rest:%d\n", link, size, rest); - return size; + return rcvd; } /** - * rx_header_from_mem - * @ld: pointer to the link device - * @buff: pointer to the frame - * @rest: size of the frame - * @frm: pointer to the sipc5_frame_data buffer + * rx_frame_payload + * @iod: pointer to an instance of io_device structure + * @ld: pointer to an instance of link_device structure + * @buff: pointer to a buffer in which incoming data is stored + * @size: size of data in the buffer + * @frm: pointer to an instance of sipc5_frame_data structure * - * 1) Verifies a link layer header configuration of a frame - * 2) Stores the link layer header to the header buffer - * 3) Builds and stores the meta data of the frame into a meta data buffer - * 4) Verifies the length of the frame + * Stores a link layer payload to "skb" * - * Returns SIPC5 header length + * Returns the size of a segment that was copied to "skb" */ -static int rx_header_from_mem(struct link_device *ld, u8 *buff, unsigned rest, - struct sipc5_frame_data *frm) +static int rx_frame_payload(struct io_device *iod, struct link_device *ld, + u8 *buff, int size, struct sipc5_frame_data *frm) { - char *link = ld->name; - u8 cfg = buff[0]; + struct sk_buff *skb = fragdata(iod, ld)->skb_recv; + int rest; + int rcvd; - /* Verify link layer header configuration */ - if (unlikely(!sipc5_start_valid(cfg))) { - mif_info("%s: ERR! wrong start (0x%02x)\n", link, cfg); - return -EBADMSG; - } - rx_check_frame_cfg(cfg, frm); + /* Calculate the size of a segment that will be copied */ + rest = frm->pay_len - frm->pay_rcvd; + rcvd = min(rest, size); + mif_debug("%s->%s: pay_len:%d pay_rcvd:%d rest:%d size:%d rcvd:%d\n", + ld->name, iod->name, frm->pay_len, frm->pay_rcvd, rest, size, + rcvd); - /* Store the link layer header to the header buffer */ - memcpy(frm->hdr, buff, frm->hdr_len); - frm->hdr_rcvd = frm->hdr_len; + /* Copy an SIPC5 link payload to "skb" */ + memcpy(skb_put(skb, rcvd), buff, rcvd); + frm->pay_rcvd += rcvd; - /* Build and store the meta data of this frame */ - rx_build_meta_data(ld, frm); + return rcvd; +} - /* Verify frame length */ - if (unlikely(frm->len > rest)) { - mif_info("%s: ERR! frame length %d > rest %d\n", - link, frm->len, rest); - return -EBADMSG; - } +static int rx_frame_padding(struct io_device *iod, struct link_device *ld, + u8 *buff, int size, struct sipc5_frame_data *frm) +{ + struct sk_buff *skb = fragdata(iod, ld)->skb_recv; + int rest; + int rcvd; + + /* Calculate the size of a segment that will be dropped as padding */ + rest = frm->pad_len - frm->pad_rcvd; + rcvd = min(rest, size); + mif_debug("%s->%s: pad_len:%d pad_rcvd:%d rest:%d size:%d rcvd:%d\n", + ld->name, iod->name, frm->pad_len, frm->pad_rcvd, rest, size, + rcvd); - return frm->hdr_rcvd; + /* Copy an SIPC5 link padding to "skb" */ + memcpy(skb_put(skb, rcvd), buff, rcvd); + frm->pad_rcvd += rcvd; + + return rcvd; } -/* copy data to skb */ -static int rx_payload_from_mem(struct sk_buff *skb, u8 *buff, unsigned len) +static int rx_frame_done(struct io_device *iod, struct link_device *ld, + struct sk_buff *skb) { - /* If there is no skb, data must be dropped. */ - if (skb) - memcpy(skb_put(skb, len), buff, len); - return len; + /* Cut off the padding of the current frame */ + skb_trim(skb, sipc5_get_frame_len(skb->data)); + mif_debug("%s->%s: frame length = %d\n", ld->name, iod->name, skb->len); + + return rx_demux(ld, skb); } -static int rx_frame_from_mem(struct io_device *iod, struct link_device *ld, +static int recv_frame_from_buff(struct io_device *iod, struct link_device *ld, const char *data, unsigned size) { struct sipc5_frame_data *frm = &fragdata(iod, ld)->f_data; struct sk_buff *skb; - char *link = ld->name; u8 *buff = (u8 *)data; int rest = (int)size; - int len; - int done; + int done = 0; + int err = 0; - mif_debug("%s: size = %d\n", link, size); + mif_debug("%s->%s: size %d (RX state = %s)\n", ld->name, iod->name, + size, get_rx_state_str(iod->curr_rx_state)); while (rest > 0) { - /* Initialize the frame data buffer */ - memset(frm, 0, sizeof(struct sipc5_frame_data)); - skb = NULL; + switch (iod->curr_rx_state) { + case IOD_RX_ON_STANDBY: + fragdata(iod, ld)->skb_recv = NULL; + memset(frm, 0, sizeof(struct sipc5_frame_data)); + + done = rx_frame_config(iod, ld, buff, rest, frm); + if (done < 0) { + err = done; + goto err_exit; + } - /* Receive and analyze link layer header */ - done = rx_header_from_mem(ld, buff, rest, frm); - if (unlikely(done < 0)) - return -EBADMSG; + iod->next_rx_state = IOD_RX_HEADER; - /* Verify rest size */ - rest -= done; - if (rest < 0) { - mif_info("%s: ERR! rx_header -> rest %d\n", link, rest); - return -ERANGE; - } + break; - /* Move buff pointer to the payload */ - buff += done; + case IOD_RX_HEADER: + done = rx_frame_header(iod, ld, buff, rest, frm); + if (done < 0) { + err = done; + goto err_exit; + } - /* Prepare an akb */ - len = frm->data_len; - skb = rx_alloc_skb(len, iod, ld); + if (frm->hdr_rcvd >= frm->hdr_len) + iod->next_rx_state = IOD_RX_PAYLOAD; + else + iod->next_rx_state = IOD_RX_HEADER; - /* Store channel ID and control fields to the CB of the skb */ - skbpriv(skb)->ch_id = frm->ch_id; - skbpriv(skb)->control = frm->control; + break; - /* Receive payload */ - mif_debug("%s: done:%d rest:%d len:%d -> rx_payload()\n", - link, done, rest, len); - done = rx_payload_from_mem(skb, buff, len); - rest -= done; - if (rest < 0) { - mif_info("%s: ERR! rx_payload() -> rest %d\n", - link, rest); - if (skb) - dev_kfree_skb_any(skb); - return -ERANGE; - } - buff += done; + case IOD_RX_PAYLOAD: + done = rx_frame_payload(iod, ld, buff, rest, frm); + if (done < 0) { + err = done; + goto err_exit; + } - /* A padding size is applied to access the next IPC frame. */ - if (frm->padding) { - done = sipc5_calc_padding_size(frm->len); - if (done > rest) { - mif_info("%s: ERR! padding %d > rest %d\n", - link, done, rest); - if (skb) - dev_kfree_skb_any(skb); - return -ERANGE; + if (frm->pay_rcvd >= frm->pay_len) { + if (frm->pad_len > 0) + iod->next_rx_state = IOD_RX_PADDING; + else + iod->next_rx_state = IOD_RX_ON_STANDBY; + } else { + iod->next_rx_state = IOD_RX_PAYLOAD; } - buff += done; - rest -= done; + + break; + + case IOD_RX_PADDING: + done = rx_frame_padding(iod, ld, buff, rest, frm); + if (done < 0) { + err = done; + goto err_exit; + } + + if (frm->pad_rcvd >= frm->pad_len) + iod->next_rx_state = IOD_RX_ON_STANDBY; + else + iod->next_rx_state = IOD_RX_PADDING; + + break; + + default: + mif_err("%s->%s: ERR! INVALID RX state %d\n", + ld->name, iod->name, iod->curr_rx_state); + err = -EINVAL; + goto err_exit; } - if (likely(skb)) { - mif_debug("%s: len:%d -> rx_demux()\n", link, skb->len); - if (rx_demux(ld, skb) < 0) - dev_kfree_skb_any(skb); - } else { - mif_debug("%s: len:%d -> drop\n", link, skb->len); + if (iod->next_rx_state == IOD_RX_ON_STANDBY) { + /* + ** A complete frame is in fragdata(iod, ld)->skb_recv. + */ + skb = fragdata(iod, ld)->skb_recv; + err = rx_frame_done(iod, ld, skb); + if (err < 0) + goto err_exit; } + + buff += done; + rest -= done; + if (rest < 0) + goto err_range; + + iod->curr_rx_state = iod->next_rx_state; } - return 0; + return size; + +err_exit: + if (fragdata(iod, ld)->skb_recv) { + mif_err("%s->%s: ERR! clear frag (size:%d done:%d rest:%d)\n", + ld->name, iod->name, size, done, rest); + dev_kfree_skb_any(fragdata(iod, ld)->skb_recv); + fragdata(iod, ld)->skb_recv = NULL; + } + iod->curr_rx_state = IOD_RX_ON_STANDBY; + return err; + +err_range: + mif_err("%s->%s: ERR! size:%d done:%d rest:%d\n", + ld->name, iod->name, size, done, rest); + iod->curr_rx_state = IOD_RX_ON_STANDBY; + return size; } /* called from link device when a packet arrives for this io device */ static int io_dev_recv_data_from_link_dev(struct io_device *iod, struct link_device *ld, const char *data, unsigned int len) { - struct sk_buff_head *rxq = &iod->sk_rx_q; struct sk_buff *skb; - char *link = ld->name; int err; - if (!data) { - mif_info("%s: ERR! !data\n", link); - return -EINVAL; - } - - if (len <= 0) { - mif_info("%s: ERR! len %d <= 0\n", link, len); - return -EINVAL; - } - switch (iod->format) { case IPC_FMT: case IPC_RAW: @@ -857,97 +738,151 @@ static int io_dev_recv_data_from_link_dev(struct io_device *iod, if (iod->waketime) wake_lock_timeout(&iod->wakelock, iod->waketime); - if (ld->link_type == LINKDEV_DPRAM && ld->aligned) - err = rx_frame_from_mem(iod, ld, data, len); - else - err = rx_frame_from_serial(iod, ld, data, len); - - if (err < 0) - mif_info("%s: ERR! rx_frame_from_link fail (err %d)\n", - link, err); + err = recv_frame_from_buff(iod, ld, data, len); + if (err < 0) { + mif_err("%s->%s: ERR! recv_frame_from_buff fail " + "(err %d)\n", ld->name, iod->name, err); + } return err; - case IPC_CMD: - case IPC_BOOT: - case IPC_RAMDUMP: + default: + mif_debug("%s->%s: len %d\n", ld->name, iod->name, len); + /* save packet to sk_buff */ skb = rx_alloc_skb(len, iod, ld); if (!skb) { - mif_info("%s: ERR! rx_alloc_skb fail\n", link); + mif_info("%s->%s: ERR! rx_alloc_skb fail\n", + ld->name, iod->name); return -ENOMEM; } - mif_debug("%s: len:%d -> iod:%s\n", link, len, iod->name); - memcpy(skb_put(skb, len), data, len); - skb_queue_tail(rxq, skb); - if (unlikely(rxq->qlen > 2048)) { - struct sk_buff *victim; - mif_info("%s: ERR! rxq->qlen %d > 2048\n", - iod->name, rxq->qlen); - victim = skb_dequeue(rxq); - dev_kfree_skb_any(victim); - } + + queue_skb_to_iod(skb, iod); + wake_up(&iod->wq); return len; - - default: - mif_info("%s: ERR! unknown format %d\n", link, iod->format); - return -EINVAL; } } -static int rx_frame_from_skb(struct io_device *iod, struct link_device *ld, +static int recv_frame_from_skb(struct io_device *iod, struct link_device *ld, struct sk_buff *skb) { - struct sipc5_frame_data *frm = &fragdata(iod, ld)->f_data; - u8 cfg = skb->data[0]; + struct sk_buff *clone; + unsigned int rest; + unsigned int rcvd; + int tot; /* total length including padding */ + int err = 0; - /* Initialize the frame data buffer */ - memset(frm, 0, sizeof(struct sipc5_frame_data)); + /* + ** If there is only one SIPC5 frame in @skb, receive the SIPC5 frame and + ** return immediately. In this case, the frame verification must already + ** have been done at the link device. + */ + if (skbpriv(skb)->single_frame) { + err = rx_frame_done(iod, ld, skb); + if (err < 0) + goto exit; + return 0; + } /* - ** The start of a link layer header has already been checked in the - ** link device. + ** The routine from here is used only if there may be multiple SIPC5 + ** frames in @skb. */ - /* Analyze the configuration of the link layer header */ - rx_check_frame_cfg(cfg, frm); + /* Check the config field of the first frame in @skb */ + if (!sipc5_start_valid(skb->data)) { + mif_err("%s->%s: ERR! INVALID config 0x%02X\n", + ld->name, iod->name, skb->data[0]); + err = -EINVAL; + goto exit; + } + + /* Get the total length of the frame with a padding */ + tot = sipc5_get_total_len(skb->data); - /* Store the link layer header to the header buffer */ - memcpy(frm->hdr, skb->data, frm->hdr_len); - frm->hdr_rcvd = frm->hdr_len; + /* Verify the total length of the first frame */ + rest = skb->len; + if (unlikely(tot > rest)) { + mif_err("%s->%s: ERR! tot %d > skb->len %d)\n", + ld->name, iod->name, tot, rest); + err = -EINVAL; + goto exit; + } - /* Build and store the meta data of this frame */ - rx_build_meta_data(ld, frm); + /* If there is only one SIPC5 frame in @skb, */ + if (likely(tot == rest)) { + /* Receive the SIPC5 frame and return immediately */ + err = rx_frame_done(iod, ld, skb); + if (err < 0) + goto exit; + return 0; + } /* - ** The length of the frame has already been checked in the link device. + ** This routine is used only if there are multiple SIPC5 frames in @skb. */ + rcvd = 0; + while (rest > 0) { + clone = skb_clone(skb, GFP_ATOMIC); + if (unlikely(!clone)) { + mif_err("%s->%s: ERR! skb_clone fail\n", + ld->name, iod->name); + err = -ENOMEM; + goto exit; + } - /* Trim the link layer header off the frame */ - skb_pull(skb, frm->hdr_len); + /* Get the start of an SIPC5 frame */ + skb_pull(clone, rcvd); + if (!sipc5_start_valid(clone->data)) { + mif_err("%s->%s: ERR! INVALID config 0x%02X\n", + ld->name, iod->name, clone->data[0]); + dev_kfree_skb_any(clone); + err = -EINVAL; + goto exit; + } - /* Store channel ID and control fields to the CB of the skb */ - skbpriv(skb)->ch_id = frm->ch_id; - skbpriv(skb)->control = frm->control; + /* Get the total length of the current frame with a padding */ + tot = sipc5_get_total_len(clone->data); + if (unlikely(tot > rest)) { + mif_err("%s->%s: ERR! dirty frame (tot %d > rest %d)\n", + ld->name, iod->name, tot, rest); + dev_kfree_skb_any(clone); + err = -EINVAL; + goto exit; + } - /* Demux the frame */ - if (rx_demux(ld, skb) < 0) { - mif_err("%s: ERR! rx_demux fail\n", ld->name); - return -EINVAL; + /* Cut off the padding of the current frame */ + skb_trim(clone, sipc5_get_frame_len(clone->data)); + + /* Demux the frame */ + err = rx_demux(ld, clone); + if (err < 0) { + mif_err("%s->%s: ERR! rx_demux fail (err %d)\n", + ld->name, iod->name, err); + dev_kfree_skb_any(clone); + goto exit; + } + + /* Calculate the start of the next frame */ + rcvd += tot; + + /* Calculate the rest size of data in @skb */ + rest -= tot; } - return 0; +exit: + dev_kfree_skb_any(skb); + return err; } /* called from link device when a packet arrives for this io device */ static int io_dev_recv_skb_from_link_dev(struct io_device *iod, struct link_device *ld, struct sk_buff *skb) { - char *link = ld->name; enum dev_format dev = iod->format; int err; @@ -959,17 +894,35 @@ static int io_dev_recv_skb_from_link_dev(struct io_device *iod, if (iod->waketime) wake_lock_timeout(&iod->wakelock, iod->waketime); - err = rx_frame_from_skb(iod, ld, skb); + err = recv_frame_from_skb(iod, ld, skb); if (err < 0) { - dev_kfree_skb_any(skb); - mif_info("%s: ERR! rx_frame_from_skb fail (err %d)\n", - link, err); + mif_err("%s->%s: ERR! recv_frame_from_skb fail " + "(err %d)\n", ld->name, iod->name, err); + } + + return err; + + case IPC_BOOT: + case IPC_RAMDUMP: + if (!iod->id) { + mif_err("%s->%s: ERR! invalid iod\n", + ld->name, iod->name); + return -ENODEV; + } + + if (iod->waketime) + wake_lock_timeout(&iod->wakelock, iod->waketime); + + err = recv_frame_from_skb(iod, ld, skb); + if (err < 0) { + mif_err("%s->%s: ERR! recv_frame_from_skb fail " + "(err %d)\n", ld->name, iod->name, err); } return err; default: - mif_info("%s: ERR! unknown device %d\n", link, dev); + mif_err("%s->%s: ERR! invalid iod\n", ld->name, iod->name); return -EINVAL; } } @@ -980,10 +933,14 @@ static int io_dev_recv_skb_from_link_dev(struct io_device *iod, static void io_dev_modem_state_changed(struct io_device *iod, enum modem_state state) { - mif_info("%s: %s state changed (state %d)\n", - iod->name, iod->mc->name, state); + struct modem_ctl *mc = iod->mc; + int old_state = mc->phone_state; - iod->mc->phone_state = state; + if (old_state != state) { + mc->phone_state = state; + mif_err("%s state changed (%s -> %s)\n", mc->name, + get_cp_state_str(old_state), get_cp_state_str(state)); + } if (state == STATE_CRASH_RESET || state == STATE_CRASH_EXIT || state == STATE_NV_REBUILDING) @@ -1024,23 +981,27 @@ static int misc_open(struct inode *inode, struct file *filp) struct io_device *iod = to_io_device(filp->private_data); struct modem_shared *msd = iod->msd; struct link_device *ld; + int ref_cnt; int ret; filp->private_data = (void *)iod; - atomic_inc(&iod->opened); - list_for_each_entry(ld, &msd->link_dev_list, list) { if (IS_CONNECTED(iod, ld) && ld->init_comm) { ret = ld->init_comm(ld, iod); if (ret < 0) { - mif_info("%s: init_comm fail(%d)\n", - ld->name, ret); + mif_err("%s<->%s: ERR! init_comm fail(%d)\n", + iod->name, ld->name, ret); return ret; } } } - mif_err("%s (opened %d)\n", iod->name, atomic_read(&iod->opened)); + ref_cnt = atomic_inc_return(&iod->opened); + + if (iod->format == IPC_BOOT || iod->format == IPC_RAMDUMP) + mif_err("%s (opened %d)\n", iod->name, ref_cnt); + else + mif_info("%s (opened %d)\n", iod->name, ref_cnt); return 0; } @@ -1050,8 +1011,8 @@ static int misc_release(struct inode *inode, struct file *filp) struct io_device *iod = (struct io_device *)filp->private_data; struct modem_shared *msd = iod->msd; struct link_device *ld; + int ref_cnt; - atomic_dec(&iod->opened); skb_queue_purge(&iod->sk_rx_q); list_for_each_entry(ld, &msd->link_dev_list, list) { @@ -1059,7 +1020,12 @@ static int misc_release(struct inode *inode, struct file *filp) ld->terminate_comm(ld, iod); } - mif_err("%s (opened %d)\n", iod->name, atomic_read(&iod->opened)); + ref_cnt = atomic_dec_return(&iod->opened); + + if (iod->format == IPC_BOOT || iod->format == IPC_RAMDUMP) + mif_err("%s (opened %d)\n", iod->name, ref_cnt); + else + mif_info("%s (opened %d)\n", iod->name, ref_cnt); return 0; } @@ -1067,20 +1033,23 @@ static int misc_release(struct inode *inode, struct file *filp) static unsigned int misc_poll(struct file *filp, struct poll_table_struct *wait) { struct io_device *iod = (struct io_device *)filp->private_data; + struct modem_ctl *mc = iod->mc; poll_wait(filp, &iod->wq, wait); - if (!skb_queue_empty(&iod->sk_rx_q) && - iod->mc->phone_state != STATE_OFFLINE) { + if (!skb_queue_empty(&iod->sk_rx_q) && mc->phone_state != STATE_OFFLINE) return POLLIN | POLLRDNORM; - } else if ((iod->mc->phone_state == STATE_CRASH_RESET) || - (iod->mc->phone_state == STATE_CRASH_EXIT) || - (iod->mc->phone_state == STATE_NV_REBUILDING) || - (iod->mc->sim_state.changed)) { + + if (mc->phone_state == STATE_CRASH_RESET + || mc->phone_state == STATE_CRASH_EXIT + || mc->phone_state == STATE_NV_REBUILDING + || mc->sim_state.changed) { if (iod->format == IPC_RAW) { msleep(20); return 0; } + if (iod->format == IPC_RAMDUMP) + return 0; return POLLHUP; } else { return 0; @@ -1089,132 +1058,191 @@ static unsigned int misc_poll(struct file *filp, struct poll_table_struct *wait) static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - int p_state; struct io_device *iod = (struct io_device *)filp->private_data; struct link_device *ld = get_current_link(iod); - char cpinfo_buf[530] = "CP Crash "; + struct modem_ctl *mc = iod->mc; + int p_state; + char *buff; + void __user *user_buff; unsigned long size; - int ret; switch (cmd) { case IOCTL_MODEM_ON: - mif_info("%s: IOCTL_MODEM_ON\n", iod->name); - return iod->mc->ops.modem_on(iod->mc); + if (mc->ops.modem_on) { + mif_err("%s: IOCTL_MODEM_ON\n", iod->name); + return mc->ops.modem_on(mc); + } + mif_err("%s: !mc->ops.modem_on\n", iod->name); + return -EINVAL; case IOCTL_MODEM_OFF: - mif_info("%s: IOCTL_MODEM_OFF\n", iod->name); - return iod->mc->ops.modem_off(iod->mc); + if (mc->ops.modem_off) { + mif_err("%s: IOCTL_MODEM_OFF\n", iod->name); + return mc->ops.modem_off(mc); + } + mif_err("%s: !mc->ops.modem_off\n", iod->name); + return -EINVAL; case IOCTL_MODEM_RESET: - mif_info("%s: IOCTL_MODEM_RESET\n", iod->name); - return iod->mc->ops.modem_reset(iod->mc); + if (mc->ops.modem_reset) { + mif_err("%s: IOCTL_MODEM_RESET\n", iod->name); + return mc->ops.modem_reset(mc); + } + mif_err("%s: !mc->ops.modem_reset\n", iod->name); + return -EINVAL; case IOCTL_MODEM_BOOT_ON: - mif_info("%s: IOCTL_MODEM_BOOT_ON\n", iod->name); - return iod->mc->ops.modem_boot_on(iod->mc); + if (mc->ops.modem_boot_on) { + mif_err("%s: IOCTL_MODEM_BOOT_ON\n", iod->name); + return mc->ops.modem_boot_on(mc); + } + mif_err("%s: !mc->ops.modem_boot_on\n", iod->name); + return -EINVAL; case IOCTL_MODEM_BOOT_OFF: - mif_info("%s: IOCTL_MODEM_BOOT_OFF\n", iod->name); - return iod->mc->ops.modem_boot_off(iod->mc); + if (mc->ops.modem_boot_off) { + mif_err("%s: IOCTL_MODEM_BOOT_OFF\n", iod->name); + return mc->ops.modem_boot_off(mc); + } + mif_err("%s: !mc->ops.modem_boot_off\n", iod->name); + return -EINVAL; case IOCTL_MODEM_BOOT_DONE: mif_err("%s: IOCTL_MODEM_BOOT_DONE\n", iod->name); - if (iod->mc->ops.modem_boot_done) - return iod->mc->ops.modem_boot_done(iod->mc); - else - return 0; + if (mc->ops.modem_boot_done) + return mc->ops.modem_boot_done(mc); + return 0; case IOCTL_MODEM_STATUS: mif_debug("%s: IOCTL_MODEM_STATUS\n", iod->name); - p_state = iod->mc->phone_state; + p_state = mc->phone_state; if ((p_state == STATE_CRASH_RESET) || (p_state == STATE_CRASH_EXIT)) { - mif_info("%s: IOCTL_MODEM_STATUS (state %d)\n", - iod->name, p_state); - } else if (iod->mc->sim_state.changed) { - int s_state = iod->mc->sim_state.online ? + mif_info("%s: IOCTL_MODEM_STATUS (state %s)\n", + iod->name, get_cp_state_str(p_state)); + } else if (mc->sim_state.changed) { + int s_state = mc->sim_state.online ? STATE_SIM_ATTACH : STATE_SIM_DETACH; - iod->mc->sim_state.changed = false; + mc->sim_state.changed = false; return s_state; } else if (p_state == STATE_NV_REBUILDING) { - mif_info("%s: IOCTL_MODEM_STATUS (state %d)\n", - iod->name, p_state); - iod->mc->phone_state = STATE_ONLINE; + mif_info("%s: IOCTL_MODEM_STATUS (state %s)\n", + iod->name, get_cp_state_str(p_state)); + mc->phone_state = STATE_ONLINE; } return p_state; - case IOCTL_MODEM_PROTOCOL_SUSPEND: - mif_debug("%s: IOCTL_MODEM_PROTOCOL_SUSPEND\n", - iod->name); - - if (iod->format != IPC_MULTI_RAW) - return -EINVAL; + case IOCTL_MODEM_XMIT_BOOT: + if (ld->xmit_boot) { + mif_info("%s: IOCTL_MODEM_XMIT_BOOT\n", iod->name); + return ld->xmit_boot(ld, iod, arg); + } + mif_err("%s: !ld->xmit_boot\n", iod->name); + return -EINVAL; - iodevs_for_each(iod->msd, iodev_netif_stop, 0); - return 0; + case IOCTL_MODEM_DL_START: + if (ld->dload_start) { + mif_info("%s: IOCTL_MODEM_DL_START\n", iod->name); + return ld->dload_start(ld, iod); + } + mif_err("%s: !ld->dload_start\n", iod->name); + return -EINVAL; - case IOCTL_MODEM_PROTOCOL_RESUME: - mif_info("%s: IOCTL_MODEM_PROTOCOL_RESUME\n", - iod->name); + case IOCTL_MODEM_FW_UPDATE: + if (ld->firm_update) { + mif_info("%s: IOCTL_MODEM_FW_UPDATE\n", iod->name); + return ld->firm_update(ld, iod, arg); + } + mif_err("%s: !ld->firm_update\n", iod->name); + return -EINVAL; - if (iod->format != IPC_MULTI_RAW) - return -EINVAL; + case IOCTL_MODEM_FORCE_CRASH_EXIT: + if (mc->ops.modem_force_crash_exit) { + mif_err("%s: IOCTL_MODEM_FORCE_CRASH_EXIT\n", + iod->name); + return mc->ops.modem_force_crash_exit(mc); + } + mif_err("%s: !mc->ops.modem_force_crash_exit\n", iod->name); + return -EINVAL; - iodevs_for_each(iod->msd, iodev_netif_wake, 0); - return 0; + case IOCTL_MODEM_DUMP_RESET: + if (mc->ops.modem_dump_reset) { + mif_info("%s: IOCTL_MODEM_DUMP_RESET\n", iod->name); + return mc->ops.modem_dump_reset(mc); + } + mif_err("%s: !mc->ops.modem_dump_reset\n", iod->name); + return -EINVAL; case IOCTL_MODEM_DUMP_START: - mif_info("%s: IOCTL_MODEM_DUMP_START\n", iod->name); - return ld->dump_start(ld, iod); + if (ld->dump_start) { + mif_err("%s: IOCTL_MODEM_DUMP_START\n", iod->name); + return ld->dump_start(ld, iod); + } + mif_err("%s: !ld->dump_start\n", iod->name); + return -EINVAL; + + case IOCTL_MODEM_RAMDUMP_START: + if (ld->dump_start) { + mif_info("%s: IOCTL_MODEM_RAMDUMP_START\n", iod->name); + return ld->dump_start(ld, iod); + } + mif_err("%s: !ld->dump_start\n", iod->name); + return -EINVAL; case IOCTL_MODEM_DUMP_UPDATE: - mif_debug("%s: IOCTL_MODEM_DUMP_UPDATE\n", iod->name); - return ld->dump_update(ld, iod, arg); + if (ld->dump_update) { + mif_info("%s: IOCTL_MODEM_DUMP_UPDATE\n", iod->name); + return ld->dump_update(ld, iod, arg); + } + mif_err("%s: !ld->dump_update\n", iod->name); + return -EINVAL; - case IOCTL_MODEM_FORCE_CRASH_EXIT: - mif_info("%s: IOCTL_MODEM_FORCE_CRASH_EXIT\n", iod->name); - if (iod->mc->ops.modem_force_crash_exit) - return iod->mc->ops.modem_force_crash_exit(iod->mc); + case IOCTL_MODEM_RAMDUMP_STOP: + if (ld->dump_finish) { + mif_info("%s: IOCTL_MODEM_RAMDUMP_STOP\n", iod->name); + return ld->dump_finish(ld, iod, arg); + } + mif_err("%s: !ld->dump_finish\n", iod->name); return -EINVAL; case IOCTL_MODEM_CP_UPLOAD: mif_info("%s: IOCTL_MODEM_CP_UPLOAD\n", iod->name); - if (copy_from_user(cpinfo_buf + strlen(cpinfo_buf), - (void __user *)arg, MAX_CPINFO_SIZE) != 0) - return -EFAULT; - panic(cpinfo_buf); + strcpy(iod->msd->cp_crash_info, CP_CRASH_TAG); + if (arg) { + buff = iod->msd->cp_crash_info + strlen(CP_CRASH_TAG); + user_buff = (void __user *)arg; + if (copy_from_user(buff, user_buff, MAX_CPINFO_SIZE)) + return -EFAULT; + } + panic(iod->msd->cp_crash_info); return 0; - case IOCTL_MODEM_DUMP_RESET: - mif_info("%s: IOCTL_MODEM_DUMP_RESET\n", iod->name); - return iod->mc->ops.modem_dump_reset(iod->mc); + case IOCTL_MODEM_PROTOCOL_SUSPEND: + mif_info("%s: IOCTL_MODEM_PROTOCOL_SUSPEND\n", iod->name); + if (iod->format == IPC_MULTI_RAW) { + iodevs_for_each(iod->msd, iodev_netif_stop, 0); + return 0; + } + return -EINVAL; + + case IOCTL_MODEM_PROTOCOL_RESUME: + mif_info("%s: IOCTL_MODEM_PROTOCOL_RESUME\n", iod->name); + if (iod->format != IPC_MULTI_RAW) { + iodevs_for_each(iod->msd, iodev_netif_wake, 0); + return 0; + } + return -EINVAL; case IOCTL_MIF_LOG_DUMP: iodevs_for_each(iod->msd, iodev_dump_status, 0); + user_buff = (void __user *)arg; size = MAX_MIF_BUFF_SIZE; - ret = copy_to_user((void __user *)arg, &size, - sizeof(unsigned long)); - if (ret < 0) + if (copy_to_user(user_buff, &size, sizeof(unsigned long))) return -EFAULT; - - mif_dump_log(iod->mc->msd, iod); + mif_dump_log(mc->msd, iod); return 0; - case IOCTL_MIF_DPRAM_DUMP: -#ifdef CONFIG_LINK_DEVICE_DPRAM - if (iod->mc->mdm_data->link_types & LINKTYPE(LINKDEV_DPRAM)) { - size = iod->mc->mdm_data->dpram_ctl->dp_size; - ret = copy_to_user((void __user *)arg, &size, - sizeof(unsigned long)); - if (ret < 0) - return -EFAULT; - mif_dump_dpram(iod); - return 0; - } -#endif - return -EINVAL; - default: /* If you need to handle the ioctl for specific link device, * then assign the link ioctl handler to ld->ioctl @@ -1222,9 +1250,10 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (ld->ioctl) return ld->ioctl(ld, iod, cmd, arg); - mif_info("%s: ERR! cmd 0x%X not defined.\n", iod->name, cmd); + mif_info("%s: ERR! undefined cmd 0x%X\n", iod->name, cmd); return -EINVAL; } + return 0; } @@ -1234,49 +1263,76 @@ static ssize_t misc_write(struct file *filp, const char __user *data, struct io_device *iod = (struct io_device *)filp->private_data; struct link_device *ld = get_current_link(iod); struct sk_buff *skb; + u8 *buff; int ret; - unsigned headroom = 0; - unsigned tailroom = 0; - size_t tx_size; - struct sipc5_frame_data frm; - struct timespec epoch; + size_t headroom; + size_t tailroom; + size_t tx_bytes; + u8 cfg; if (iod->format <= IPC_RFS && iod->id == 0) return -EINVAL; - headroom = tx_build_link_header(&frm, iod, ld, count); + cfg = sipc5_build_config(iod, ld, count); + + if (cfg) + headroom = sipc5_get_hdr_len(&cfg); + else + headroom = 0; if (ld->aligned) tailroom = sipc5_calc_padding_size(headroom + count); + else + tailroom = 0; - tx_size = headroom + count + tailroom; + tx_bytes = headroom + count + tailroom; - skb = alloc_skb(tx_size, GFP_KERNEL); + skb = alloc_skb(tx_bytes, GFP_KERNEL); if (!skb) { - mif_info("%s: ERR! alloc_skb fail (tx_size:%d)\n", - iod->name, tx_size); + mif_info("%s: ERR! alloc_skb fail (tx_bytes:%d)\n", + iod->name, tx_bytes); return -ENOMEM; } - /* store IPC link header*/ - memcpy(skb_put(skb, headroom), frm.hdr, headroom); + /* Build SIPC5 link header*/ + if (cfg) { + buff = skb_put(skb, headroom); + sipc5_build_header(iod, ld, buff, cfg, 0, count); + } - /* store IPC message */ - if (copy_from_user(skb_put(skb, count), data, count) != 0) { - if (skb) - dev_kfree_skb_any(skb); + /* Store IPC message */ + buff = skb_put(skb, count); + if (copy_from_user(buff, data, count)) { + mif_err("%s->%s: ERR! copy_from_user fail (count %d)\n", + iod->name, ld->name, count); + dev_kfree_skb_any(skb); return -EFAULT; } - if (iod->id == SIPC5_CH_ID_FMT_0) { + /* Apply padding */ + if (tailroom) + skb_put(skb, tailroom); + + if (iod->format == IPC_FMT) { + struct timespec epoch; + u8 *msg = (skb->data + headroom); +#if 0 + char tag[MIF_MAX_STR_LEN]; + snprintf(tag, MIF_MAX_STR_LEN, "%s: RIL2MIF", iod->mc->name); + pr_ipc(1, tag, msg, (count > 20 ? 20 : count)); +#endif getnstimeofday(&epoch); mif_time_log(iod->mc->msd, epoch, NULL, 0); - mif_ipc_log(MIF_IPC_RL2AP, iod->mc->msd, skb->data, skb->len); + mif_ipc_log(MIF_IPC_RL2AP, iod->mc->msd, msg, count); } - /* store padding */ - if (tailroom) - skb_put(skb, tailroom); +#if 0 + if (iod->format == IPC_RAMDUMP) { + char tag[MIF_MAX_STR_LEN]; + snprintf(tag, MIF_MAX_STR_LEN, "%s: DUMP2MIF", iod->name); + pr_ipc(1, tag, skb->data, (skb->len > 20 ? 20 : skb->len)); + } +#endif /* send data with sk_buff, link device will put sk_buff * into the specific sk_buff_q and run work-q to send data @@ -1286,13 +1342,15 @@ static ssize_t misc_write(struct file *filp, const char __user *data, ret = ld->send(ld, iod, skb); if (ret < 0) { - mif_info("%s: ERR! ld->send fail (err %d)\n", iod->name, ret); + mif_info("%s->%s: ERR! ld->send fail (err %d, tx_bytes %d)\n", + iod->name, ld->name, ret, tx_bytes); return ret; } - if (ret != tx_size) - mif_info("%s: wrong tx size (count:%d tx_size:%d ret:%d)\n", - iod->name, count, tx_size, ret); + if (ret != tx_bytes) { + mif_info("%s->%s: WARNING! ret %d != tx_bytes %d (count %d)\n", + iod->name, ld->name, ret, tx_bytes, count); + } return count; } @@ -1304,24 +1362,38 @@ static ssize_t misc_read(struct file *filp, char *buf, size_t count, struct sk_buff_head *rxq = &iod->sk_rx_q; struct sk_buff *skb; int copied = 0; - struct timespec epoch; - skb = skb_dequeue(rxq); - if (!skb) { + if (skb_queue_empty(rxq)) { mif_info("%s: ERR! no data in rxq\n", iod->name); return 0; } - if (iod->id == SIPC5_CH_ID_FMT_0) { + skb = skb_dequeue(rxq); + + if (iod->format == IPC_FMT) { + struct timespec epoch; +#if 0 + char tag[MIF_MAX_STR_LEN]; + snprintf(tag, MIF_MAX_STR_LEN, "%s: MIF2RIL", iod->mc->name); + pr_ipc(0, tag, skb->data, (skb->len > 20 ? 20 : skb->len)); +#endif getnstimeofday(&epoch); mif_time_log(iod->mc->msd, epoch, NULL, 0); mif_ipc_log(MIF_IPC_AP2RL, iod->mc->msd, skb->data, skb->len); } +#if 0 + if (iod->format == IPC_RAMDUMP) { + char tag[MIF_MAX_STR_LEN]; + snprintf(tag, MIF_MAX_STR_LEN, "%s: MIF2DUMP", iod->name); + pr_ipc(1, tag, skb->data, (skb->len > 20 ? 20 : skb->len)); + } +#endif + copied = skb->len > count ? count : skb->len; if (copy_to_user(buf, skb->data, copied)) { - mif_info("%s: ERR! copy_to_user fail\n", iod->name); + mif_err("%s: ERR! copy_to_user fail\n", iod->name); dev_kfree_skb_any(skb); return -EFAULT; } @@ -1339,43 +1411,6 @@ static ssize_t misc_read(struct file *filp, char *buf, size_t count, return copied; } -#ifdef CONFIG_LINK_DEVICE_C2C -static int misc_mmap(struct file *filp, struct vm_area_struct *vma) -{ - int r = 0; - unsigned long size = 0; - unsigned long pfn = 0; - unsigned long offset = 0; - struct io_device *iod = (struct io_device *)filp->private_data; - - if (!vma) - return -EFAULT; - - size = vma->vm_end - vma->vm_start; - offset = vma->vm_pgoff << PAGE_SHIFT; - if (offset + size > (C2C_CP_RGN_SIZE + C2C_SH_RGN_SIZE)) { - mif_info("ERR: offset + size > C2C_CP_RGN_SIZE\n"); - return -EINVAL; - } - - /* Set the noncacheable property to the region */ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_RESERVED | VM_IO; - - pfn = __phys_to_pfn(C2C_CP_RGN_ADDR + offset); - r = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); - if (r) { - mif_info("ERR: Failed in remap_pfn_range()!!!\n"); - return -EAGAIN; - } - - mif_info("%s: VA = 0x%08lx, offset = 0x%lx, size = %lu\n", - iod->name, vma->vm_start, offset, size); - - return 0; -} -#endif - static const struct file_operations misc_io_fops = { .owner = THIS_MODULE, .open = misc_open, @@ -1384,9 +1419,6 @@ static const struct file_operations misc_io_fops = { .unlocked_ioctl = misc_ioctl, .write = misc_write, .read = misc_read, -#ifdef CONFIG_LINK_DEVICE_C2C - .mmap = misc_mmap, -#endif }; static int vnet_open(struct net_device *ndev) @@ -1419,11 +1451,13 @@ static int vnet_xmit(struct sk_buff *skb, struct net_device *ndev) struct link_device *ld = get_current_link(iod); struct sk_buff *skb_new; int ret; - unsigned headroom = 0; - unsigned tailroom = 0; - unsigned long tx_bytes = skb->len; + unsigned headroom; + unsigned tailroom; + size_t count; + size_t tx_bytes; struct iphdr *ip_header = NULL; - struct sipc5_frame_data frm; + u8 *buff; + u8 cfg; /* When use `handover' with Network Bridge, * user -> bridge device(rmnet0) -> real rmnet(xxxx_rmnet0) -> here. @@ -1436,19 +1470,18 @@ static int vnet_xmit(struct sk_buff *skb, struct net_device *ndev) skb_pull(skb, sizeof(struct ethhdr)); } - headroom = tx_build_link_header(&frm, iod, ld, skb->len); + count = skb->len; - /* ip loop-back */ - ip_header = (struct iphdr *)skb->data; - if (iod->msd->loopback_ipaddr && - ip_header->daddr == iod->msd->loopback_ipaddr) { - swap(ip_header->saddr, ip_header->daddr); - frm.ch_id = DATA_LOOPBACK_CHANNEL; - frm.hdr[SIPC5_CH_ID_OFFSET] = DATA_LOOPBACK_CHANNEL; - } + cfg = sipc5_build_config(iod, ld, count); + + headroom = sipc5_get_hdr_len(&cfg); if (ld->aligned) - tailroom = sipc5_calc_padding_size(frm.len); + tailroom = sipc5_calc_padding_size(headroom + count); + else + tailroom = 0; + + tx_bytes = headroom + count + tailroom; if (skb_headroom(skb) < headroom || skb_tailroom(skb) < tailroom) { mif_debug("%s: skb_copy_expand needed\n", iod->name); @@ -1463,7 +1496,18 @@ static int vnet_xmit(struct sk_buff *skb, struct net_device *ndev) skb_new = skb; } - memcpy(skb_push(skb_new, headroom), frm.hdr, headroom); + /* Build SIPC5 link header*/ + buff = skb_push(skb_new, headroom); + sipc5_build_header(iod, ld, buff, cfg, 0, count); + + /* IP loop-back */ + ip_header = (struct iphdr *)skb->data; + if (iod->msd->loopback_ipaddr && + ip_header->daddr == iod->msd->loopback_ipaddr) { + swap(ip_header->saddr, ip_header->daddr); + buff[SIPC5_CH_ID_OFFSET] = DATA_LOOPBACK_CHANNEL; + } + if (tailroom) skb_put(skb_new, tailroom); @@ -1473,12 +1517,18 @@ static int vnet_xmit(struct sk_buff *skb, struct net_device *ndev) ret = ld->send(ld, iod, skb_new); if (ret < 0) { netif_stop_queue(ndev); - mif_info("%s: ERR! ld->send fail (err %d)\n", iod->name, ret); + mif_info("%s->%s: ERR! ld->send fail (err %d, tx_bytes %d)\n", + iod->name, ld->name, ret, tx_bytes); return NETDEV_TX_BUSY; } + if (ret != tx_bytes) { + mif_info("%s->%s: WARNING! ret %d != tx_bytes %d (count %d)\n", + iod->name, ld->name, ret, tx_bytes, count); + } + ndev->stats.tx_packets++; - ndev->stats.tx_bytes += tx_bytes; + ndev->stats.tx_bytes += count; return NETDEV_TX_OK; } @@ -1581,16 +1631,19 @@ int sipc5_init_io_device(struct io_device *iod) ret = misc_register(&iod->miscdev); if (ret) mif_info("%s: ERR! misc_register fail\n", iod->name); + ret = device_create_file(iod->miscdev.this_device, &attr_waketime); if (ret) mif_info("%s: ERR! device_create_file fail\n", iod->name); + ret = device_create_file(iod->miscdev.this_device, &attr_loopback); if (ret) mif_err("failed to create `loopback file' : %s\n", iod->name); + ret = device_create_file(iod->miscdev.this_device, &attr_txlink); if (ret) diff --git a/drivers/misc/modem_if/sipc5_modem.c b/drivers/misc/modem_if/sipc5_modem.c index f5e33d3..8a173d4 100644 --- a/drivers/misc/modem_if/sipc5_modem.c +++ b/drivers/misc/modem_if/sipc5_modem.c @@ -33,7 +33,8 @@ #include <linux/delay.h> #include <linux/wakelock.h> -#include <linux/platform_data/modem.h> +#include "modem.h" +#include <mach/c2c.h> #include "modem_prj.h" #include "modem_variation.h" #include "modem_utils.h" @@ -77,27 +78,31 @@ static struct modem_shared *create_modem_shared_data(void) static struct modem_ctl *create_modemctl_device(struct platform_device *pdev, struct modem_shared *msd) { - int ret = 0; - struct modem_data *pdata; + struct modem_data *pdata = pdev->dev.platform_data; struct modem_ctl *modemctl; - struct device *dev = &pdev->dev; + int ret; /* create modem control device */ modemctl = kzalloc(sizeof(struct modem_ctl), GFP_KERNEL); - if (!modemctl) + if (!modemctl) { + mif_err("%s: modemctl kzalloc fail\n", pdata->name); + mif_err("%s: xxx\n", pdata->name); return NULL; + } modemctl->msd = msd; - modemctl->dev = dev; + modemctl->dev = &pdev->dev; modemctl->phone_state = STATE_OFFLINE; - pdata = pdev->dev.platform_data; modemctl->mdm_data = pdata; modemctl->name = pdata->name; /* init modemctl device for getting modemctl operations */ ret = call_modem_init_func(modemctl, pdata); if (ret) { + mif_err("%s: call_modem_init_func fail (err %d)\n", + pdata->name, ret); + mif_err("%s: xxx\n", pdata->name); kfree(modemctl); return NULL; } @@ -111,8 +116,8 @@ static struct io_device *create_io_device(struct modem_io_t *io_t, struct modem_shared *msd, struct modem_ctl *modemctl, struct modem_data *pdata) { - int ret = 0; - struct io_device *iod = NULL; + int ret; + struct io_device *iod; iod = kzalloc(sizeof(struct io_device), GFP_KERNEL); if (!iod) { @@ -128,6 +133,7 @@ static struct io_device *create_io_device(struct modem_io_t *io_t, iod->format = io_t->format; iod->io_typ = io_t->io_type; iod->link_types = io_t->links; + iod->app = io_t->app; iod->net_typ = pdata->modem_net; iod->use_handover = pdata->use_handover; iod->ipc_version = pdata->ipc_version; @@ -139,7 +145,7 @@ static struct io_device *create_io_device(struct modem_io_t *io_t, modemctl->iod = iod; if (iod->format == IPC_BOOT) { modemctl->bootd = iod; - mif_info("Bood device = %s\n", iod->name); + mif_err("BOOT device = %s\n", iod->name); } /* link between io device and modem shared */ @@ -160,7 +166,7 @@ static struct io_device *create_io_device(struct modem_io_t *io_t, return NULL; } - mif_debug("%s is created!!!\n", iod->name); + mif_info("%s created\n", iod->name); return iod; } @@ -168,7 +174,6 @@ static int attach_devices(struct io_device *iod, enum modem_link tx_link) { struct modem_shared *msd = iod->msd; struct link_device *ld; - unsigned ch; /* find link type for this io device */ list_for_each_entry(ld, &msd->link_dev_list, list) { @@ -232,36 +237,36 @@ static int __devinit modem_probe(struct platform_device *pdev) { int i; struct modem_data *pdata = pdev->dev.platform_data; - struct modem_shared *msd = NULL; - struct modem_ctl *modemctl = NULL; + struct modem_shared *msd; + struct modem_ctl *modemctl; struct io_device *iod[pdata->num_iodevs]; struct link_device *ld; - - mif_err("%s\n", pdev->name); - memset(iod, 0, sizeof(iod)); + mif_err("%s: +++\n", pdata->name); msd = create_modem_shared_data(); if (!msd) { - mif_err("msd == NULL\n"); - goto err_free_modemctl; + mif_err("%s: msd == NULL\n", pdata->name); + return -ENOMEM; } modemctl = create_modemctl_device(pdev, msd); if (!modemctl) { - mif_err("modemctl == NULL\n"); - goto err_free_modemctl; + mif_err("%s: modemctl == NULL\n", pdata->name); + kfree(msd); + return -ENOMEM; } /* create link device */ /* support multi-link device */ + memset(iod, 0, sizeof(iod)); for (i = 0; i < LINKDEV_MAX ; i++) { /* find matching link type */ if (pdata->link_types & LINKTYPE(i)) { ld = call_link_init_func(pdev, i); if (!ld) - goto err_free_modemctl; + goto free_mc; - mif_err("link created: %s\n", ld->name); + mif_err("%s: %s link created\n", pdata->name, ld->name); ld->link_type = i; ld->mc = modemctl; ld->msd = msd; @@ -274,8 +279,8 @@ static int __devinit modem_probe(struct platform_device *pdev) iod[i] = create_io_device(&pdata->iodevs[i], msd, modemctl, pdata); if (!iod[i]) { - mif_err("iod[%d] == NULL\n", i); - goto err_free_modemctl; + mif_err("%s: iod[%d] == NULL\n", pdata->name, i); + goto free_iod; } attach_devices(iod[i], pdata->iodevs[i].tx_link); @@ -283,21 +288,23 @@ static int __devinit modem_probe(struct platform_device *pdev) platform_set_drvdata(pdev, modemctl); - mif_err("Complete!!!\n"); - + mif_err("%s: ---\n", pdata->name); return 0; -err_free_modemctl: - for (i = 0; i < pdata->num_iodevs; i++) - if (iod[i] != NULL) +free_iod: + for (i = 0; i < pdata->num_iodevs; i++) { + if (iod[i]) kfree(iod[i]); + } - if (modemctl != NULL) +free_mc: + if (modemctl) kfree(modemctl); - if (msd != NULL) + if (msd) kfree(msd); + mif_err("%s: xxx\n", pdata->name); return -ENOMEM; } @@ -305,13 +312,19 @@ static void modem_shutdown(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct modem_ctl *mc = dev_get_drvdata(dev); + struct utc_time utc; + mc->ops.modem_off(mc); mc->phone_state = STATE_OFFLINE; + + get_utc_time(&utc); + mif_info("%s: at [%02d:%02d:%02d.%03d]\n", + mc->name, utc.hour, utc.min, utc.sec, utc.msec); } static int modem_suspend(struct device *pdev) { -#ifndef CONFIG_LINK_DEVICE_HSIC +#if !defined(CONFIG_LINK_DEVICE_HSIC) struct modem_ctl *mc = dev_get_drvdata(pdev); if (mc->gpio_pda_active) @@ -323,7 +336,7 @@ static int modem_suspend(struct device *pdev) static int modem_resume(struct device *pdev) { -#ifndef CONFIG_LINK_DEVICE_HSIC +#if !defined(CONFIG_LINK_DEVICE_HSIC) struct modem_ctl *mc = dev_get_drvdata(pdev); if (mc->gpio_pda_active) @@ -334,8 +347,8 @@ static int modem_resume(struct device *pdev) } static const struct dev_pm_ops modem_pm_ops = { - .suspend = modem_suspend, - .resume = modem_resume, + .suspend = modem_suspend, + .resume = modem_resume, }; static struct platform_driver modem_driver = { @@ -343,7 +356,7 @@ static struct platform_driver modem_driver = { .shutdown = modem_shutdown, .driver = { .name = "mif_sipc5", - .pm = &modem_pm_ops, + .pm = &modem_pm_ops, }, }; diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c deleted file mode 100644 index c7c9179..0000000 --- a/drivers/misc/pmem.c +++ /dev/null @@ -1,1386 +0,0 @@ -/* drivers/android/pmem.c - * - * Copyright (C) 2007 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/miscdevice.h> -#include <linux/platform_device.h> -#include <linux/fs.h> -#include <linux/file.h> -#include <linux/mm.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/debugfs.h> -#include <linux/android_pmem.h> -#include <linux/mempolicy.h> -#include <linux/sched.h> -#include <linux/vmalloc.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/cacheflush.h> -#if defined(CONFIG_S5P_MEM_CMA) -#include <linux/cma.h> -#endif - -#define PMEM_MAX_DEVICES 10 -#define PMEM_MAX_ORDER 128 -#define PMEM_MIN_ALLOC PAGE_SIZE - -#define PMEM_DEBUG 1 - -/* indicates that a refernce to this file has been taken via get_pmem_file, - * the file should not be released until put_pmem_file is called */ -#define PMEM_FLAGS_BUSY 0x1 -/* indicates that this is a suballocation of a larger master range */ -#define PMEM_FLAGS_CONNECTED 0x1 << 1 -/* indicates this is a master and not a sub allocation and that it is mmaped */ -#define PMEM_FLAGS_MASTERMAP 0x1 << 2 -/* submap and unsubmap flags indicate: - * 00: subregion has never been mmaped - * 10: subregion has been mmaped, reference to the mm was taken - * 11: subretion has ben released, refernece to the mm still held - * 01: subretion has been released, reference to the mm has been released - */ -#define PMEM_FLAGS_SUBMAP 0x1 << 3 -#define PMEM_FLAGS_UNSUBMAP 0x1 << 4 - - -struct pmem_data { - /* in alloc mode: an index into the bitmap - * in no_alloc mode: the size of the allocation */ - int index; - /* see flags above for descriptions */ - unsigned int flags; - /* protects this data field, if the mm_mmap sem will be held at the - * same time as this sem, the mm sem must be taken first (as this is - * the order for vma_open and vma_close ops */ - struct rw_semaphore sem; - /* info about the mmaping process */ - struct vm_area_struct *vma; - /* task struct of the mapping process */ - struct task_struct *task; - /* process id of teh mapping process */ - pid_t pid; - /* file descriptor of the master */ - int master_fd; - /* file struct of the master */ - struct file *master_file; - /* a list of currently available regions if this is a suballocation */ - struct list_head region_list; - /* a linked list of data so we can access them for debugging */ - struct list_head list; -#if PMEM_DEBUG - int ref; -#endif -}; - -struct pmem_bits { - unsigned allocated:1; /* 1 if allocated, 0 if free */ - unsigned order:7; /* size of the region in pmem space */ -}; - -struct pmem_region_node { - struct pmem_region region; - struct list_head list; -}; - -#define PMEM_DEBUG_MSGS 0 -#if PMEM_DEBUG_MSGS -#define DLOG(fmt,args...) \ - do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \ - ##args); } \ - while (0) -#else -#define DLOG(x...) do {} while (0) -#endif - -struct pmem_info { - struct miscdevice dev; - /* physical start address of the remaped pmem space */ - unsigned long base; - /* vitual start address of the remaped pmem space */ - unsigned char __iomem *vbase; - /* total size of the pmem space */ - unsigned long size; - /* number of entries in the pmem space */ - unsigned long num_entries; - /* pfn of the garbage page in memory */ - unsigned long garbage_pfn; - /* index of the garbage page in the pmem space */ - int garbage_index; - /* the bitmap for the region indicating which entries are allocated - * and which are free */ - struct pmem_bits *bitmap; - /* indicates the region should not be managed with an allocator */ - unsigned no_allocator; - /* indicates maps of this region should be cached, if a mix of - * cached and uncached is desired, set this and open the device with - * O_SYNC to get an uncached region */ - unsigned cached; - unsigned buffered; - /* in no_allocator mode the first mapper gets the whole space and sets - * this flag */ - unsigned allocated; - /* for debugging, creates a list of pmem file structs, the - * data_list_lock should be taken before pmem_data->sem if both are - * needed */ - struct mutex data_list_lock; - struct list_head data_list; - /* pmem_sem protects the bitmap array - * a write lock should be held when modifying entries in bitmap - * a read lock should be held when reading data from bits or - * dereferencing a pointer into bitmap - * - * pmem_data->sem protects the pmem data of a particular file - * Many of the function that require the pmem_data->sem have a non- - * locking version for when the caller is already holding that sem. - * - * IF YOU TAKE BOTH LOCKS TAKE THEM IN THIS ORDER: - * down(pmem_data->sem) => down(bitmap_sem) - */ - struct rw_semaphore bitmap_sem; - - long (*ioctl)(struct file *, unsigned int, unsigned long); - int (*release)(struct inode *, struct file *); -}; - -static struct pmem_info pmem[PMEM_MAX_DEVICES]; -static int id_count; - -#define PMEM_IS_FREE(id, index) !(pmem[id].bitmap[index].allocated) -#define PMEM_ORDER(id, index) pmem[id].bitmap[index].order -#define PMEM_BUDDY_INDEX(id, index) (index ^ (1 << PMEM_ORDER(id, index))) -#define PMEM_NEXT_INDEX(id, index) (index + (1 << PMEM_ORDER(id, index))) -#define PMEM_OFFSET(index) (index * PMEM_MIN_ALLOC) -#define PMEM_START_ADDR(id, index) (PMEM_OFFSET(index) + pmem[id].base) -#define PMEM_LEN(id, index) ((1 << PMEM_ORDER(id, index)) * PMEM_MIN_ALLOC) -#define PMEM_END_ADDR(id, index) (PMEM_START_ADDR(id, index) + \ - PMEM_LEN(id, index)) -#define PMEM_START_VADDR(id, index) (PMEM_OFFSET(id, index) + pmem[id].vbase) -#define PMEM_END_VADDR(id, index) (PMEM_START_VADDR(id, index) + \ - PMEM_LEN(id, index)) -#define PMEM_REVOKED(data) (data->flags & PMEM_FLAGS_REVOKED) -#define PMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK))) -#define PMEM_IS_SUBMAP(data) ((data->flags & PMEM_FLAGS_SUBMAP) && \ - (!(data->flags & PMEM_FLAGS_UNSUBMAP))) - -static int pmem_release(struct inode *, struct file *); -static int pmem_mmap(struct file *, struct vm_area_struct *); -static int pmem_open(struct inode *, struct file *); -static long pmem_ioctl(struct file *, unsigned int, unsigned long); - -struct file_operations pmem_fops = { - .release = pmem_release, - .mmap = pmem_mmap, - .open = pmem_open, - .unlocked_ioctl = pmem_ioctl, -}; - -static int get_id(struct file *file) -{ - return MINOR(file->f_dentry->d_inode->i_rdev); -} - -int is_pmem_file(struct file *file) -{ - int id; - - if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode)) - return 0; - id = get_id(file); - if (unlikely(id >= PMEM_MAX_DEVICES)) - return 0; - if (unlikely(file->f_dentry->d_inode->i_rdev != - MKDEV(MISC_MAJOR, pmem[id].dev.minor))) - return 0; - return 1; -} - -static int has_allocation(struct file *file) -{ - struct pmem_data *data; - /* check is_pmem_file first if not accessed via pmem_file_ops */ - - if (unlikely(!file->private_data)) - return 0; - data = (struct pmem_data *)file->private_data; - if (unlikely(data->index < 0)) - return 0; - return 1; -} - -static int is_master_owner(struct file *file) -{ - struct file *master_file; - struct pmem_data *data; - int put_needed, ret = 0; - - if (!is_pmem_file(file) || !has_allocation(file)) - return 0; - data = (struct pmem_data *)file->private_data; - if (PMEM_FLAGS_MASTERMAP & data->flags) - return 1; - master_file = fget_light(data->master_fd, &put_needed); - if (master_file && data->master_file == master_file) - ret = 1; - fput_light(master_file, put_needed); - return ret; -} - -static int pmem_free(int id, int index) -{ - /* caller should hold the write lock on pmem_sem! */ - int buddy, curr = index; - DLOG("index %d\n", index); - - if (pmem[id].no_allocator) { - pmem[id].allocated = 0; - return 0; - } - /* clean up the bitmap, merging any buddies */ - pmem[id].bitmap[curr].allocated = 0; - /* find a slots buddy Buddy# = Slot# ^ (1 << order) - * if the buddy is also free merge them - * repeat until the buddy is not free or end of the bitmap is reached - */ - do { - buddy = PMEM_BUDDY_INDEX(id, curr); - if (PMEM_IS_FREE(id, buddy) && - PMEM_ORDER(id, buddy) == PMEM_ORDER(id, curr)) { - PMEM_ORDER(id, buddy)++; - PMEM_ORDER(id, curr)++; - curr = min(buddy, curr); - } else { - break; - } - } while (curr < pmem[id].num_entries); - - return 0; -} - -static void pmem_revoke(struct file *file, struct pmem_data *data); - -static int pmem_release(struct inode *inode, struct file *file) -{ - struct pmem_data *data = (struct pmem_data *)file->private_data; - struct pmem_region_node *region_node; - struct list_head *elt, *elt2; - int id = get_id(file), ret = 0; - - - mutex_lock(&pmem[id].data_list_lock); - /* if this file is a master, revoke all the memory in the connected - * files */ - if (PMEM_FLAGS_MASTERMAP & data->flags) { - struct pmem_data *sub_data; - list_for_each(elt, &pmem[id].data_list) { - sub_data = list_entry(elt, struct pmem_data, list); - down_read(&sub_data->sem); - if (PMEM_IS_SUBMAP(sub_data) && - file == sub_data->master_file) { - up_read(&sub_data->sem); - pmem_revoke(file, sub_data); - } else - up_read(&sub_data->sem); - } - } - list_del(&data->list); - mutex_unlock(&pmem[id].data_list_lock); - - - down_write(&data->sem); - - /* if its not a conencted file and it has an allocation, free it */ - if (!(PMEM_FLAGS_CONNECTED & data->flags) && has_allocation(file)) { - down_write(&pmem[id].bitmap_sem); - ret = pmem_free(id, data->index); - up_write(&pmem[id].bitmap_sem); - } - - /* if this file is a submap (mapped, connected file), downref the - * task struct */ - if (PMEM_FLAGS_SUBMAP & data->flags) - if (data->task) { - put_task_struct(data->task); - data->task = NULL; - } - - file->private_data = NULL; - - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, list); - list_del(elt); - kfree(region_node); - } - BUG_ON(!list_empty(&data->region_list)); - - up_write(&data->sem); - kfree(data); - if (pmem[id].release) - ret = pmem[id].release(inode, file); - - return ret; -} - -static int pmem_open(struct inode *inode, struct file *file) -{ - struct pmem_data *data; - int id = get_id(file); - int ret = 0; - - DLOG("current %u file %p(%d)\n", current->pid, file, file_count(file)); - /* setup file->private_data to indicate its unmapped */ - /* you can only open a pmem device one time */ - if (file->private_data != NULL && file_count(file) != 1) - return -1; - data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL); - if (!data) { - printk("pmem: unable to allocate memory for pmem metadata."); - return -1; - } - data->flags = 0; - data->index = -1; - data->task = NULL; - data->vma = NULL; - data->pid = 0; - data->master_file = NULL; -#if PMEM_DEBUG - data->ref = 0; -#endif - INIT_LIST_HEAD(&data->region_list); - init_rwsem(&data->sem); - - file->private_data = data; - INIT_LIST_HEAD(&data->list); - - mutex_lock(&pmem[id].data_list_lock); - list_add(&data->list, &pmem[id].data_list); - mutex_unlock(&pmem[id].data_list_lock); - return ret; -} - -static unsigned long pmem_order(unsigned long len) -{ - int i; - - len = (len + PMEM_MIN_ALLOC - 1)/PMEM_MIN_ALLOC; - len--; - for (i = 0; i < sizeof(len)*8; i++) - if (len >> i == 0) - break; - return i; -} - -static int pmem_allocate(int id, unsigned long len) -{ - /* caller should hold the write lock on pmem_sem! */ - /* return the corresponding pdata[] entry */ - int curr = 0; - int end = pmem[id].num_entries; - int best_fit = -1; - unsigned long order = pmem_order(len); - - if (pmem[id].no_allocator) { - DLOG("no allocator"); - if ((len > pmem[id].size) || pmem[id].allocated) - return -1; - pmem[id].allocated = 1; - return len; - } - - if (order > PMEM_MAX_ORDER) - return -1; - DLOG("order %lx\n", order); - - /* look through the bitmap: - * if you find a free slot of the correct order use it - * otherwise, use the best fit (smallest with size > order) slot - */ - while (curr < end) { - if (PMEM_IS_FREE(id, curr)) { - if (PMEM_ORDER(id, curr) == (unsigned char)order) { - /* set the not free bit and clear others */ - best_fit = curr; - break; - } - if (PMEM_ORDER(id, curr) > (unsigned char)order && - (best_fit < 0 || - PMEM_ORDER(id, curr) < PMEM_ORDER(id, best_fit))) - best_fit = curr; - } - curr = PMEM_NEXT_INDEX(id, curr); - } - - /* if best_fit < 0, there are no suitable slots, - * return an error - */ - if (best_fit < 0) { - printk("pmem: no space left to allocate!\n"); - return -1; - } - - /* now partition the best fit: - * split the slot into 2 buddies of order - 1 - * repeat until the slot is of the correct order - */ - while (PMEM_ORDER(id, best_fit) > (unsigned char)order) { - int buddy; - PMEM_ORDER(id, best_fit) -= 1; - buddy = PMEM_BUDDY_INDEX(id, best_fit); - PMEM_ORDER(id, buddy) = PMEM_ORDER(id, best_fit); - } - pmem[id].bitmap[best_fit].allocated = 1; - return best_fit; -} - -static pgprot_t pmem_access_prot(struct file *file, pgprot_t vma_prot) -{ - int id = get_id(file); -#ifdef pgprot_noncached - if (pmem[id].cached == 0 || file->f_flags & O_SYNC) - return pgprot_noncached(vma_prot); -#endif -#ifdef pgprot_ext_buffered - else if (pmem[id].buffered) - return pgprot_ext_buffered(vma_prot); -#endif - return vma_prot; -} - -static unsigned long pmem_start_addr(int id, struct pmem_data *data) -{ - if (pmem[id].no_allocator) - return PMEM_START_ADDR(id, 0); - else - return PMEM_START_ADDR(id, data->index); - -} - -static void *pmem_start_vaddr(int id, struct pmem_data *data) -{ - return pmem_start_addr(id, data) - pmem[id].base + pmem[id].vbase; -} - -static unsigned long pmem_len(int id, struct pmem_data *data) -{ - if (pmem[id].no_allocator) - return data->index; - else - return PMEM_LEN(id, data->index); -} - -static int pmem_map_garbage(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - int i, garbage_pages = len >> PAGE_SHIFT; - - vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP | VM_SHARED | VM_WRITE; - for (i = 0; i < garbage_pages; i++) { - if (vm_insert_pfn(vma, vma->vm_start + offset + (i * PAGE_SIZE), - pmem[id].garbage_pfn)) - return -EAGAIN; - } - return 0; -} - -static int pmem_unmap_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - int garbage_pages; - DLOG("unmap offset %lx len %lx\n", offset, len); - - BUG_ON(!PMEM_IS_PAGE_ALIGNED(len)); - - garbage_pages = len >> PAGE_SHIFT; - zap_page_range(vma, vma->vm_start + offset, len, NULL); - pmem_map_garbage(id, vma, data, offset, len); - return 0; -} - -static int pmem_map_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - DLOG("map offset %lx len %lx\n", offset, len); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_start)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_end)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(len)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(offset)); - - if (io_remap_pfn_range(vma, vma->vm_start + offset, - (pmem_start_addr(id, data) + offset) >> PAGE_SHIFT, - len, vma->vm_page_prot)) { - return -EAGAIN; - } - return 0; -} - -static int pmem_remap_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - /* hold the mm semp for the vma you are modifying when you call this */ - BUG_ON(!vma); - zap_page_range(vma, vma->vm_start + offset, len, NULL); - return pmem_map_pfn_range(id, vma, data, offset, len); -} - -static void pmem_vma_open(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct pmem_data *data = file->private_data; - int id = get_id(file); - /* this should never be called as we don't support copying pmem - * ranges via fork */ - BUG_ON(!has_allocation(file)); - down_write(&data->sem); - /* remap the garbage pages, forkers don't get access to the data */ - pmem_unmap_pfn_range(id, vma, data, 0, vma->vm_start - vma->vm_end); - up_write(&data->sem); -} - -static void pmem_vma_close(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct pmem_data *data = file->private_data; - - DLOG("current %u ppid %u file %p count %d\n", current->pid, - current->parent->pid, file, file_count(file)); - if (unlikely(!is_pmem_file(file) || !has_allocation(file))) { - printk(KERN_WARNING "pmem: something is very wrong, you are " - "closing a vm backing an allocation that doesn't " - "exist!\n"); - return; - } - down_write(&data->sem); - if (data->vma == vma) { - data->vma = NULL; - if ((data->flags & PMEM_FLAGS_CONNECTED) && - (data->flags & PMEM_FLAGS_SUBMAP)) - data->flags |= PMEM_FLAGS_UNSUBMAP; - } - /* the kernel is going to free this vma now anyway */ - up_write(&data->sem); -} - -static struct vm_operations_struct vm_ops = { - .open = pmem_vma_open, - .close = pmem_vma_close, -}; - -static int pmem_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct pmem_data *data; - int index; - unsigned long vma_size = vma->vm_end - vma->vm_start; - int ret = 0, id = get_id(file); - - if (vma->vm_pgoff || !PMEM_IS_PAGE_ALIGNED(vma_size)) { -#if PMEM_DEBUG - printk(KERN_ERR "pmem: mmaps must be at offset zero, aligned" - " and a multiple of pages_size.\n"); -#endif - return -EINVAL; - } - - data = (struct pmem_data *)file->private_data; - down_write(&data->sem); - /* check this file isn't already mmaped, for submaps check this file - * has never been mmaped */ - if ((data->flags & PMEM_FLAGS_SUBMAP) || - (data->flags & PMEM_FLAGS_UNSUBMAP)) { -#if PMEM_DEBUG - printk(KERN_ERR "pmem: you can only mmap a pmem file once, " - "this file is already mmaped. %x\n", data->flags); -#endif - ret = -EINVAL; - goto error; - } - /* if file->private_data == unalloced, alloc*/ - if (data && data->index == -1) { - down_write(&pmem[id].bitmap_sem); - index = pmem_allocate(id, vma->vm_end - vma->vm_start); - up_write(&pmem[id].bitmap_sem); - data->index = index; - } - /* either no space was available or an error occured */ - if (!has_allocation(file)) { - ret = -EINVAL; - printk("pmem: could not find allocation for map.\n"); - goto error; - } - - if (pmem_len(id, data) < vma_size) { -#if PMEM_DEBUG - printk(KERN_WARNING "pmem: mmap size [%lu] does not match" - "size of backing region [%lu].\n", vma_size, - pmem_len(id, data)); -#endif - ret = -EINVAL; - goto error; - } - - vma->vm_pgoff = pmem_start_addr(id, data) >> PAGE_SHIFT; - vma->vm_page_prot = pmem_access_prot(file, vma->vm_page_prot); - - if (data->flags & PMEM_FLAGS_CONNECTED) { - struct pmem_region_node *region_node; - struct list_head *elt; - if (pmem_map_garbage(id, vma, data, 0, vma_size)) { - printk("pmem: mmap failed in kernel!\n"); - ret = -EAGAIN; - goto error; - } - list_for_each(elt, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - DLOG("remapping file: %p %lx %lx\n", file, - region_node->region.offset, - region_node->region.len); - if (pmem_remap_pfn_range(id, vma, data, - region_node->region.offset, - region_node->region.len)) { - ret = -EAGAIN; - goto error; - } - } - data->flags |= PMEM_FLAGS_SUBMAP; - get_task_struct(current->group_leader); - data->task = current->group_leader; - data->vma = vma; -#if PMEM_DEBUG - data->pid = current->pid; -#endif - DLOG("submmapped file %p vma %p pid %u\n", file, vma, - current->pid); - } else { - if (pmem_map_pfn_range(id, vma, data, 0, vma_size)) { - printk(KERN_INFO "pmem: mmap failed in kernel!\n"); - ret = -EAGAIN; - goto error; - } - data->flags |= PMEM_FLAGS_MASTERMAP; - data->pid = current->pid; - } - vma->vm_ops = &vm_ops; -error: - up_write(&data->sem); - return ret; -} - -/* the following are the api for accessing pmem regions by other drivers - * from inside the kernel */ -int get_pmem_user_addr(struct file *file, unsigned long *start, - unsigned long *len) -{ - struct pmem_data *data; - if (!is_pmem_file(file) || !has_allocation(file)) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: requested pmem data from invalid" - "file.\n"); -#endif - return -1; - } - data = (struct pmem_data *)file->private_data; - down_read(&data->sem); - if (data->vma) { - *start = data->vma->vm_start; - *len = data->vma->vm_end - data->vma->vm_start; - } else { - *start = 0; - *len = 0; - } - up_read(&data->sem); - return 0; -} - -int get_pmem_addr(struct file *file, unsigned long *start, - unsigned long *vstart, unsigned long *len) -{ - struct pmem_data *data; - int id; - - if (!is_pmem_file(file) || !has_allocation(file)) { - return -1; - } - - data = (struct pmem_data *)file->private_data; - if (data->index == -1) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: requested pmem data from file with no " - "allocation.\n"); - return -1; -#endif - } - id = get_id(file); - - down_read(&data->sem); - *start = pmem_start_addr(id, data); - *len = pmem_len(id, data); - *vstart = (unsigned long)pmem_start_vaddr(id, data); - up_read(&data->sem); -#if PMEM_DEBUG - down_write(&data->sem); - data->ref++; - up_write(&data->sem); -#endif - return 0; -} - -int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart, - unsigned long *len, struct file **filp) -{ - struct file *file; - - file = fget(fd); - if (unlikely(file == NULL)) { - printk(KERN_INFO "pmem: requested data from file descriptor " - "that doesn't exist."); - return -1; - } - - if (get_pmem_addr(file, start, vstart, len)) - goto end; - - if (filp) - *filp = file; - return 0; -end: - fput(file); - return -1; -} - -void put_pmem_file(struct file *file) -{ - struct pmem_data *data; - int id; - - if (!is_pmem_file(file)) - return; - id = get_id(file); - data = (struct pmem_data *)file->private_data; -#if PMEM_DEBUG - down_write(&data->sem); - if (data->ref == 0) { - printk("pmem: pmem_put > pmem_get %s (pid %d)\n", - pmem[id].dev.name, data->pid); - BUG(); - } - data->ref--; - up_write(&data->sem); -#endif - fput(file); -} - -void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len) -{ - struct pmem_data *data; - int id; - void *vaddr; - struct pmem_region_node *region_node; - struct list_head *elt; - void *flush_start, *flush_end; - - if (!is_pmem_file(file) || !has_allocation(file)) { - return; - } - - id = get_id(file); - data = (struct pmem_data *)file->private_data; - if (!pmem[id].cached || file->f_flags & O_SYNC) - return; - - down_read(&data->sem); - vaddr = pmem_start_vaddr(id, data); - /* if this isn't a submmapped file, flush the whole thing */ - if (unlikely(!(data->flags & PMEM_FLAGS_CONNECTED))) { - if (pmem_len(id, data) >= SZ_1M) { - flush_all_cpu_caches(); - outer_flush_all(); - } else if (pmem_len(id, data) >= SZ_64K) { - flush_all_cpu_caches(); - outer_flush_range(virt_to_phys(vaddr), virt_to_phys(vaddr + pmem_len(id, data))); - } else { - dmac_flush_range(vaddr, vaddr + pmem_len(id, data)); - outer_flush_range(virt_to_phys(vaddr), virt_to_phys(vaddr + pmem_len(id, data))); - } - goto end; - } - /* otherwise, flush the region of the file we are drawing */ - list_for_each(elt, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, list); - if ((offset >= region_node->region.offset) && - ((offset + len) <= (region_node->region.offset + - region_node->region.len))) { - flush_start = vaddr + region_node->region.offset; - flush_end = flush_start + region_node->region.len; - - if (pmem_len(id, data) >= SZ_1M) { - flush_all_cpu_caches(); - outer_flush_all(); - } else if (pmem_len(id, data) >= SZ_64K) { - flush_all_cpu_caches(); - outer_flush_range(virt_to_phys(flush_start), virt_to_phys(flush_end)); - } else { - dmac_flush_range(flush_start, flush_end); - outer_flush_range(virt_to_phys(flush_start), virt_to_phys(flush_end)); - } - break; - } - } -end: - up_read(&data->sem); -} - -static int pmem_connect(unsigned long connect, struct file *file) -{ - struct pmem_data *data = (struct pmem_data *)file->private_data; - struct pmem_data *src_data; - struct file *src_file; - int ret = 0, put_needed; - - down_write(&data->sem); - /* retrieve the src file and check it is a pmem file with an alloc */ - src_file = fget_light(connect, &put_needed); - DLOG("connect %p to %p\n", file, src_file); - if (!src_file) { - printk("pmem: src file not found!\n"); - ret = -EINVAL; - goto err_no_file; - } - if (unlikely(!is_pmem_file(src_file) || !has_allocation(src_file))) { - printk(KERN_INFO "pmem: src file is not a pmem file or has no " - "alloc!\n"); - ret = -EINVAL; - goto err_bad_file; - } - src_data = (struct pmem_data *)src_file->private_data; - - if (has_allocation(file) && (data->index != src_data->index)) { - printk("pmem: file is already mapped but doesn't match this" - " src_file!\n"); - ret = -EINVAL; - goto err_bad_file; - } - data->index = src_data->index; - data->flags |= PMEM_FLAGS_CONNECTED; - data->master_fd = connect; - data->master_file = src_file; - -err_bad_file: - fput_light(src_file, put_needed); -err_no_file: - up_write(&data->sem); - return ret; -} - -static void pmem_unlock_data_and_mm(struct pmem_data *data, - struct mm_struct *mm) -{ - up_write(&data->sem); - if (mm != NULL) { - up_write(&mm->mmap_sem); - mmput(mm); - } -} - -static int pmem_lock_data_and_mm(struct file *file, struct pmem_data *data, - struct mm_struct **locked_mm) -{ - int ret = 0; - struct mm_struct *mm = NULL; - *locked_mm = NULL; -lock_mm: - down_read(&data->sem); - if (PMEM_IS_SUBMAP(data)) { - mm = get_task_mm(data->task); - if (!mm) { -#if PMEM_DEBUG - printk("pmem: can't remap task is gone!\n"); -#endif - up_read(&data->sem); - return -1; - } - } - up_read(&data->sem); - - if (mm) - down_write(&mm->mmap_sem); - - down_write(&data->sem); - /* check that the file didn't get mmaped before we could take the - * data sem, this should be safe b/c you can only submap each file - * once */ - if (PMEM_IS_SUBMAP(data) && !mm) { - pmem_unlock_data_and_mm(data, mm); - goto lock_mm; - } - /* now check that vma.mm is still there, it could have been - * deleted by vma_close before we could get the data->sem */ - if ((data->flags & PMEM_FLAGS_UNSUBMAP) && (mm != NULL)) { - /* might as well release this */ - if (data->flags & PMEM_FLAGS_SUBMAP) { - put_task_struct(data->task); - data->task = NULL; - /* lower the submap flag to show the mm is gone */ - data->flags &= ~(PMEM_FLAGS_SUBMAP); - } - pmem_unlock_data_and_mm(data, mm); - return -1; - } - *locked_mm = mm; - return ret; -} - -int pmem_remap(struct pmem_region *region, struct file *file, - unsigned operation) -{ - int ret; - struct pmem_region_node *region_node; - struct mm_struct *mm = NULL; - struct list_head *elt, *elt2; - int id = get_id(file); - struct pmem_data *data = (struct pmem_data *)file->private_data; - - /* pmem region must be aligned on a page boundry */ - if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) || - !PMEM_IS_PAGE_ALIGNED(region->len))) { -#if PMEM_DEBUG - printk("pmem: request for unaligned pmem suballocation " - "%lx %lx\n", region->offset, region->len); -#endif - return -EINVAL; - } - - /* if userspace requests a region of len 0, there's nothing to do */ - if (region->len == 0) - return 0; - - /* lock the mm and data */ - ret = pmem_lock_data_and_mm(file, data, &mm); - if (ret) - return 0; - - /* only the owner of the master file can remap the client fds - * that back in it */ - if (!is_master_owner(file)) { -#if PMEM_DEBUG - printk("pmem: remap requested from non-master process\n"); -#endif - ret = -EINVAL; - goto err; - } - - /* check that the requested range is within the src allocation */ - if (unlikely((region->offset > pmem_len(id, data)) || - (region->len > pmem_len(id, data)) || - (region->offset + region->len > pmem_len(id, data)))) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: suballoc doesn't fit in src_file!\n"); -#endif - ret = -EINVAL; - goto err; - } - - if (operation == PMEM_MAP) { - region_node = kmalloc(sizeof(struct pmem_region_node), - GFP_KERNEL); - if (!region_node) { - ret = -ENOMEM; -#if PMEM_DEBUG - printk(KERN_INFO "No space to allocate metadata!"); -#endif - goto err; - } - region_node->region = *region; - list_add(®ion_node->list, &data->region_list); - } else if (operation == PMEM_UNMAP) { - int found = 0; - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - if (region->len == 0 || - (region_node->region.offset == region->offset && - region_node->region.len == region->len)) { - list_del(elt); - kfree(region_node); - found = 1; - } - } - if (!found) { -#if PMEM_DEBUG - printk("pmem: Unmap region does not map any mapped " - "region!"); -#endif - ret = -EINVAL; - goto err; - } - } - - if (data->vma && PMEM_IS_SUBMAP(data)) { - if (operation == PMEM_MAP) - ret = pmem_remap_pfn_range(id, data->vma, data, - region->offset, region->len); - else if (operation == PMEM_UNMAP) - ret = pmem_unmap_pfn_range(id, data->vma, data, - region->offset, region->len); - } - -err: - pmem_unlock_data_and_mm(data, mm); - return ret; -} - -static void pmem_revoke(struct file *file, struct pmem_data *data) -{ - struct pmem_region_node *region_node; - struct list_head *elt, *elt2; - struct mm_struct *mm = NULL; - int id = get_id(file); - int ret = 0; - - data->master_file = NULL; - ret = pmem_lock_data_and_mm(file, data, &mm); - /* if lock_data_and_mm fails either the task that mapped the fd, or - * the vma that mapped it have already gone away, nothing more - * needs to be done */ - if (ret) - return; - /* unmap everything */ - /* delete the regions and region list nothing is mapped any more */ - if (data->vma) - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - pmem_unmap_pfn_range(id, data->vma, data, - region_node->region.offset, - region_node->region.len); - list_del(elt); - kfree(region_node); - } - /* delete the master file */ - pmem_unlock_data_and_mm(data, mm); -} - -static void pmem_get_size(struct pmem_region *region, struct file *file) -{ - struct pmem_data *data = (struct pmem_data *)file->private_data; - int id = get_id(file); - - if (!has_allocation(file)) { - region->offset = 0; - region->len = 0; - return; - } else { - region->offset = pmem_start_addr(id, data); - region->len = pmem_len(id, data); - } - DLOG("offset %lx len %lx\n", region->offset, region->len); -} - - -static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct pmem_data *data; - int id = get_id(file); - - switch (cmd) { - case PMEM_GET_PHYS: - { - struct pmem_region region; - DLOG("get_phys\n"); - if (!has_allocation(file)) { - region.offset = 0; - region.len = 0; - } else { - data = (struct pmem_data *)file->private_data; - region.offset = pmem_start_addr(id, data); - region.len = pmem_len(id, data); - } - printk(KERN_DEBUG "pmem: request for physical address of pmem region " - "from process %d.\n", current->pid); - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_MAP: - { - struct pmem_region region; - if (copy_from_user(®ion, (void __user *)arg, - sizeof(struct pmem_region))) - return -EFAULT; - data = (struct pmem_data *)file->private_data; - return pmem_remap(®ion, file, PMEM_MAP); - } - break; - case PMEM_UNMAP: - { - struct pmem_region region; - if (copy_from_user(®ion, (void __user *)arg, - sizeof(struct pmem_region))) - return -EFAULT; - data = (struct pmem_data *)file->private_data; - return pmem_remap(®ion, file, PMEM_UNMAP); - break; - } - case PMEM_GET_SIZE: - { - struct pmem_region region; - DLOG("get_size\n"); - pmem_get_size(®ion, file); - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_GET_TOTAL_SIZE: - { - struct pmem_region region; - DLOG("get total size\n"); - region.offset = 0; - get_id(file); - region.len = pmem[id].size; - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_ALLOCATE: - { - if (has_allocation(file)) - return -EINVAL; - data = (struct pmem_data *)file->private_data; - data->index = pmem_allocate(id, arg); - break; - } - case PMEM_CONNECT: - DLOG("connect\n"); - return pmem_connect(arg, file); - break; - case PMEM_CACHE_FLUSH: - { - struct pmem_region region; - DLOG("flush\n"); - if (copy_from_user(®ion, (void __user *)arg, - sizeof(struct pmem_region))) - return -EFAULT; - flush_pmem_file(file, region.offset, region.len); - break; - } - default: - if (pmem[id].ioctl) - return pmem[id].ioctl(file, cmd, arg); - return -EINVAL; - } - return 0; -} - -#if PMEM_DEBUG -static ssize_t debug_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t debug_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct list_head *elt, *elt2; - struct pmem_data *data; - struct pmem_region_node *region_node; - int id = (int)file->private_data; - const int debug_bufmax = 4096; - static char buffer[4096]; - int n = 0; - - DLOG("debug open\n"); - n = scnprintf(buffer, debug_bufmax, - "pid #: mapped regions (offset, len) (offset,len)...\n"); - - mutex_lock(&pmem[id].data_list_lock); - list_for_each(elt, &pmem[id].data_list) { - data = list_entry(elt, struct pmem_data, list); - down_read(&data->sem); - n += scnprintf(buffer + n, debug_bufmax - n, "pid %u:", - data->pid); - list_for_each(elt2, &data->region_list) { - region_node = list_entry(elt2, struct pmem_region_node, - list); - n += scnprintf(buffer + n, debug_bufmax - n, - "(%lx,%lx) ", - region_node->region.offset, - region_node->region.len); - } - n += scnprintf(buffer + n, debug_bufmax - n, "\n"); - up_read(&data->sem); - } - mutex_unlock(&pmem[id].data_list_lock); - - n++; - buffer[n] = 0; - return simple_read_from_buffer(buf, count, ppos, buffer, n); -} - -static struct file_operations debug_fops = { - .read = debug_read, - .open = debug_open, -}; -#endif - -#if 0 -static struct miscdevice pmem_dev = { - .name = "pmem", - .fops = &pmem_fops, -}; -#endif - -int pmem_setup(struct android_pmem_platform_data *pdata, - long (*ioctl)(struct file *, unsigned int, unsigned long), - int (*release)(struct inode *, struct file *)) -{ - int err = 0; - int i, index = 0; - int id = id_count; - struct page **pages; - int nr_pages; - int prot; - id_count++; - -#if defined(CONFIG_S5P_MEM_CMA) - pdata->start = cma_alloc_from(pdata->name, pdata->size, 0); -#endif - - pmem[id].no_allocator = pdata->no_allocator; - pmem[id].cached = pdata->cached; - pmem[id].buffered = pdata->buffered; - pmem[id].base = pdata->start; - pmem[id].size = pdata->size; - pmem[id].ioctl = ioctl; - pmem[id].release = release; - init_rwsem(&pmem[id].bitmap_sem); - mutex_init(&pmem[id].data_list_lock); - INIT_LIST_HEAD(&pmem[id].data_list); - pmem[id].dev.name = pdata->name; - pmem[id].dev.minor = id; - pmem[id].dev.fops = &pmem_fops; - printk(KERN_INFO "%s: %d init\n", pdata->name, pdata->cached); - - err = misc_register(&pmem[id].dev); - if (err) { - printk(KERN_ALERT "Unable to register pmem driver!\n"); - goto err_cant_register_device; - } - pmem[id].num_entries = pmem[id].size / PMEM_MIN_ALLOC; - - pmem[id].bitmap = kmalloc(pmem[id].num_entries * - sizeof(struct pmem_bits), GFP_KERNEL); - if (!pmem[id].bitmap) - goto err_no_mem_for_metadata; - - memset(pmem[id].bitmap, 0, sizeof(struct pmem_bits) * - pmem[id].num_entries); - - for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--) { - if ((pmem[id].num_entries) & 1<<i) { - PMEM_ORDER(id, index) = i; - index = PMEM_NEXT_INDEX(id, index); - } - } - - nr_pages = pmem[id].size >> PAGE_SHIFT; - pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL); - if (!pages) - goto err_no_mem_for_pages; - - for (i = 0; i < nr_pages; i++) - pages[i] = phys_to_page(pmem[id].base + i * PAGE_SIZE); - - if (pmem[id].cached) - prot = PAGE_KERNEL; - else if (pmem[id].buffered) - prot = pgprot_writecombine(PAGE_KERNEL); - else - prot = pgprot_noncached(PAGE_KERNEL); - - pmem[id].vbase = vmap(pages, nr_pages, VM_MAP, prot); - - kfree(pages); - - if (pmem[id].vbase == 0) - goto error_cant_remap; - - pmem[id].garbage_pfn = page_to_pfn(alloc_page(GFP_KERNEL)); - if (pmem[id].no_allocator) - pmem[id].allocated = 0; - -#if PMEM_DEBUG - debugfs_create_file(pdata->name, S_IFREG | S_IRUGO, NULL, (void *)id, - &debug_fops); -#endif - return 0; -error_cant_remap: -err_no_mem_for_pages: - kfree(pmem[id].bitmap); -err_no_mem_for_metadata: - misc_deregister(&pmem[id].dev); -err_cant_register_device: - return -1; -} - -static int pmem_probe(struct platform_device *pdev) -{ - struct android_pmem_platform_data *pdata; - - if (!pdev || !pdev->dev.platform_data) { - printk(KERN_ALERT "Unable to probe pmem!\n"); - return -1; - } - pdata = pdev->dev.platform_data; - return pmem_setup(pdata, NULL, NULL); -} - - -static int pmem_remove(struct platform_device *pdev) -{ - int id = pdev->id; - __free_page(pfn_to_page(pmem[id].garbage_pfn)); -#if defined(CONFIG_S5P_MEM_CMA) - cma_free(((struct android_pmem_platform_data *)(pdev->dev.platform_data))->start); -#endif - misc_deregister(&pmem[id].dev); - return 0; -} - -static struct platform_driver pmem_driver = { - .probe = pmem_probe, - .remove = pmem_remove, - .driver = { .name = "android_pmem" } -}; - - -static int __init pmem_init(void) -{ - return platform_driver_register(&pmem_driver); -} - -static void __exit pmem_exit(void) -{ - platform_driver_unregister(&pmem_driver); -} - -module_init(pmem_init); -module_exit(pmem_exit); - diff --git a/drivers/misc/tzic.c b/drivers/misc/tzic.c index 6a5e3ba..643e078 100644 --- a/drivers/misc/tzic.c +++ b/drivers/misc/tzic.c @@ -23,7 +23,6 @@ #include <linux/sched.h> #include <linux/list.h> #include <linux/mutex.h> -#include <linux/android_pmem.h> #include <linux/io.h> #include <linux/types.h> #include <asm/smc.h> diff --git a/drivers/motor/max77693_haptic.c b/drivers/motor/max77693_haptic.c index beb7f2a..9c83c25 100644 --- a/drivers/motor/max77693_haptic.c +++ b/drivers/motor/max77693_haptic.c @@ -24,6 +24,11 @@ #include <linux/mfd/max77693.h> #include <linux/mfd/max77693-private.h> +#define PWM_MIN 0 +#define PWM_DEFAULT 50 +#define PWM_THRESH 75 +#define PWM_MAX 100 + static unsigned long pwm_val = 50; /* duty in percent */ static int pwm_duty = 27787; /* duty value, 37050=100%, 27787=50%, 18525=0% */ @@ -301,6 +306,42 @@ ssize_t pwm_value_store(struct device *dev, static DEVICE_ATTR(pwm_value, S_IRUGO | S_IWUSR, pwm_value_show, pwm_value_store); +static ssize_t pwm_default_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", PWM_DEFAULT); +} + +static DEVICE_ATTR(pwm_default, S_IRUGO, + pwm_default_show, NULL); + +static ssize_t pwm_max_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", PWM_MAX); +} + +static DEVICE_ATTR(pwm_max, S_IRUGO, + pwm_max_show, NULL); + +static ssize_t pwm_min_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", PWM_MIN); +} + +static DEVICE_ATTR(pwm_min, S_IRUGO, + pwm_min_show, NULL); + +static ssize_t pwm_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", PWM_THRESH); +} + +static DEVICE_ATTR(pwm_threshold, S_IRUGO, + pwm_threshold_show, NULL); + static int max77693_haptic_probe(struct platform_device *pdev) { int error = 0; @@ -378,6 +419,23 @@ static int max77693_haptic_probe(struct platform_device *pdev) if (error < 0) { pr_err("[VIB] create sysfs fail: pwm_value\n"); } + error = device_create_file(hap_data->tout_dev.dev, &dev_attr_pwm_max); + if (error < 0) { + pr_err("[VIB] create sysfs fail: pwm_max\n"); + } + error = device_create_file(hap_data->tout_dev.dev, &dev_attr_pwm_min); + if (error < 0) { + pr_err("[VIB] create sysfs fail: pwm_min\n"); + } + error = device_create_file(hap_data->tout_dev.dev, &dev_attr_pwm_default); + if (error < 0) { + pr_err("[VIB] create sysfs fail: pwm_default\n"); + } + error = device_create_file(hap_data->tout_dev.dev, &dev_attr_pwm_threshold); + if (error < 0) { + pr_err("[VIB] create sysfs fail: pwm_threshold\n"); + } + #endif pr_debug("[VIB] -- %s\n", __func__); diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index b890401..3253731 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -2172,7 +2172,7 @@ int ppp_register_net_channel(struct net *net, struct ppp_channel *chan) pch->ppp = NULL; pch->chan = chan; - pch->chan_net = net; + pch->chan_net = get_net(net); chan->ppp = pch; init_ppp_file(&pch->file, CHANNEL); pch->file.hdrlen = chan->hdrlen; @@ -2269,6 +2269,8 @@ ppp_unregister_channel(struct ppp_channel *chan) spin_lock_bh(&pn->all_channels_lock); list_del(&pch->list); spin_unlock_bh(&pn->all_channels_lock); + put_net(pch->chan_net); + pch->chan_net = NULL; pch->file.dead = 1; wake_up_interruptible(&pch->file.rwait); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index bc2e489..460979d 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1523,6 +1523,13 @@ out3: if (info->unbind) info->unbind (dev, udev); out1: + /* subdrivers must undo all they did in bind() if they + * fail it, but we may fail later and a deferred kevent + * may trigger an error resubmitting itself and, worse, + * schedule a timer. So we kill it all just in case. + */ + cancel_work_sync(&dev->kevent); + del_timer_sync(&dev->delay); free_netdev(net); out: usb_put_dev(xdev); diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig index d148725..f4f5b96 100644 --- a/drivers/net/wireless/bcmdhd/Kconfig +++ b/drivers/net/wireless/bcmdhd/Kconfig @@ -89,6 +89,12 @@ config BROADCOM_WIFI_RESERVED_MEM ---help--- This is a configuration for broadcom WLAN driver. +config WIFI_BROADCOM_COB + bool "BROADCOM WIFI COB" + depends on (BCM4334) + ---help--- + This is a configuration for broadcom WIFI COB Type. + config BCM4335BT bool "BROADCOM BTLOCK Enable" depends on BCM4335 diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 7ac8f56..12f7b1d 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -2906,6 +2906,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) ret = -EINVAL; goto exit; } + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + goto exit; + } if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) { ret = -EFAULT; goto exit; diff --git a/drivers/power/max17042_fuelgauge_u1.c b/drivers/power/max17042_fuelgauge_u1.c index 39b931c..378dafe 100644 --- a/drivers/power/max17042_fuelgauge_u1.c +++ b/drivers/power/max17042_fuelgauge_u1.c @@ -884,7 +884,7 @@ static int __devinit max17042_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); chip->battery.name = "fuelgauge"; - chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; + chip->battery.type = POWER_SUPPLY_TYPE_UNKNOWN; chip->battery.get_property = max17042_get_property; chip->battery.set_property = max17042_set_property; chip->battery.properties = max17042_battery_props; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 909ed9e..4172f89 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -739,8 +739,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return k; /* probably out of space --> ENOMEM */ } if (sdp->detached) { - if (srp->bio) + if (srp->bio) { + if (srp->rq->cmd != srp->rq->__cmd) + kfree(srp->rq->cmd); + blk_end_request_all(srp->rq, -EIO); + srp->rq = NULL; + } + sg_finish_rem_req(srp); return -ENODEV; } diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 11a4b5b..d0f6718 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -104,8 +104,6 @@ source "drivers/staging/iio/Kconfig" source "drivers/staging/cs5535_gpio/Kconfig" -source "drivers/staging/zram/Kconfig" - source "drivers/staging/zcache/Kconfig" source "drivers/staging/wlags49_h2/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ae62e92..9400eb7 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -43,8 +43,6 @@ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio/ -obj-$(CONFIG_ZRAM) += zram/ -obj-$(CONFIG_XVMALLOC) += zram/ obj-$(CONFIG_ZCACHE) += zcache/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 2471949..30ad4d2 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -90,6 +90,23 @@ config ANDROID_LOW_MEMORY_KILLER ---help--- Register processes to be killed when memory is low +config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES + bool "Android Low Memory Killer: detect oom_adj values" + depends on ANDROID_LOW_MEMORY_KILLER + default y + ---help--- + Detect oom_adj values written to + /sys/module/lowmemorykiller/parameters/adj and convert them + to oom_score_adj values. + +config ANDROID_LMK_ADJ_RBTREE + bool "Use RBTREE for Android Low Memory Killer" + depends on ANDROID_LOW_MEMORY_KILLER + default y + ---help--- + Use oom_score_adj rbtree to select the best proecss to kill + when system in low memory status. + endif # if ANDROID endmenu diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index e2b69f2..72db295 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -3346,7 +3346,7 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) static void print_binder_ref(struct seq_file *m, struct binder_ref *ref) { - seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n", + seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n", ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ", ref->node->debug_id, ref->strong, ref->weak, ref->death); } diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 15bbcd3..5a9835b 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -1,16 +1,17 @@ /* drivers/misc/lowmemorykiller.c * * The lowmemorykiller driver lets user-space specify a set of memory thresholds - * where processes with a range of oom_adj values will get killed. Specify the - * minimum oom_adj values in /sys/module/lowmemorykiller/parameters/adj and the - * number of free pages in /sys/module/lowmemorykiller/parameters/minfree. Both - * files take a comma separated list of numbers in ascending order. + * where processes with a range of oom_score_adj values will get killed. Specify + * the minimum oom_score_adj values in + * /sys/module/lowmemorykiller/parameters/adj and the number of free pages in + * /sys/module/lowmemorykiller/parameters/minfree. Both files take a comma + * separated list of numbers in ascending order. * * For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and - * "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill processes - * with a oom_adj value of 8 or higher when the free memory drops below 4096 pages - * and kill processes with a oom_adj value of 0 or higher when the free memory - * drops below 1024 pages. + * "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill + * processes with a oom_score_adj value of 8 or higher when the free memory + * drops below 4096 pages and kill processes with a oom_score_adj value of 0 or + * higher when the free memory drops below 1024 pages. * * The driver considers memory used for caches to be free, but if a large * percentage of the cached memory is locked this can be very inaccurate @@ -29,25 +30,18 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/oom.h> #include <linux/sched.h> -#include <linux/notifier.h> -#ifdef CONFIG_ZRAM_FOR_ANDROID #include <linux/swap.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/mm_inline.h> -#endif /* CONFIG_ZRAM_FOR_ANDROID */ -#define ENHANCED_LMK_ROUTINE - -#ifdef ENHANCED_LMK_ROUTINE -#define LOWMEM_DEATHPENDING_DEPTH 3 -#endif +#include <linux/rcupdate.h> +#include <linux/notifier.h> -static uint32_t lowmem_debug_level = 2; +static uint32_t lowmem_debug_level = 1; static int lowmem_adj[6] = { 0, 1, @@ -55,54 +49,20 @@ static int lowmem_adj[6] = { 12, }; static int lowmem_adj_size = 4; -static size_t lowmem_minfree[6] = { +static int lowmem_minfree[6] = { 3 * 512, /* 6MB */ 2 * 1024, /* 8MB */ 4 * 1024, /* 16MB */ 16 * 1024, /* 64MB */ }; static int lowmem_minfree_size = 4; -#ifdef CONFIG_ZRAM_FOR_ANDROID -static struct class *lmk_class; -static struct device *lmk_dev; -static int lmk_kill_pid = 0; -static int lmk_kill_ok = 0; - -extern atomic_t optimize_comp_on; - -extern int isolate_lru_page_compcache(struct page *page); -extern void putback_lru_page(struct page *page); -extern unsigned int zone_id_shrink_pagelist(struct zone *zone_id,struct list_head *page_list); - -#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)) - -#define SWAP_PROCESS_DEBUG_LOG 0 -/* free RAM 8M(2048 pages) */ -#define CHECK_FREE_MEMORY 2048 -/* free swap (10240 pages) */ -#define CHECK_FREE_SWAPSPACE 10240 - -static unsigned int check_free_memory = 0; - -enum pageout_io { - PAGEOUT_IO_ASYNC, - PAGEOUT_IO_SYNC, -}; - - -#endif /* CONFIG_ZRAM_FOR_ANDROID */ - -#ifdef ENHANCED_LMK_ROUTINE -static struct task_struct *lowmem_deathpending[LOWMEM_DEATHPENDING_DEPTH] = {NULL,}; -#else static struct task_struct *lowmem_deathpending; -#endif static unsigned long lowmem_deathpending_timeout; #define lowmem_print(level, x...) \ do { \ if (lowmem_debug_level >= (level)) \ - printk(x); \ + pr_info(x); \ } while (0) static int @@ -117,44 +77,31 @@ task_notify_func(struct notifier_block *self, unsigned long val, void *data) { struct task_struct *task = data; -#ifdef ENHANCED_LMK_ROUTINE - int i = 0; - for (i = 0; i < LOWMEM_DEATHPENDING_DEPTH; i++) - if (task == lowmem_deathpending[i]) { - lowmem_deathpending[i] = NULL; - break; - } -#else if (task == lowmem_deathpending) lowmem_deathpending = NULL; -#endif return NOTIFY_OK; } +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE +static struct task_struct *pick_next_from_adj_tree(struct task_struct *task); +static struct task_struct *pick_first_task(void); +static struct task_struct *pick_last_task(void); +#endif + static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) { - struct task_struct *p; -#ifdef ENHANCED_LMK_ROUTINE - struct task_struct *selected[LOWMEM_DEATHPENDING_DEPTH] = {NULL,}; -#else + struct task_struct *tsk; struct task_struct *selected = NULL; -#endif int rem = 0; int tasksize; int i; - int min_adj = OOM_ADJUST_MAX + 1; -#ifdef ENHANCED_LMK_ROUTINE - int selected_tasksize[LOWMEM_DEATHPENDING_DEPTH] = {0,}; - int selected_oom_adj[LOWMEM_DEATHPENDING_DEPTH] = {OOM_ADJUST_MAX,}; - int all_selected_oom = 0; - int max_selected_oom_idx = 0; -#else + int min_score_adj = OOM_SCORE_ADJ_MAX + 1; + int minfree = 0; int selected_tasksize = 0; - int selected_oom_adj; -#endif + int selected_oom_score_adj; int array_size = ARRAY_SIZE(lowmem_adj); #ifndef CONFIG_DMA_CMA - int other_free = global_page_state(NR_FREE_PAGES); + int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages; #else int other_free = global_page_state(NR_FREE_PAGES) - global_page_state(NR_FREE_CMA_PAGES); @@ -169,152 +116,111 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) * this pass. * */ -#ifdef ENHANCED_LMK_ROUTINE - for (i = 0; i < LOWMEM_DEATHPENDING_DEPTH; i++) { - if (lowmem_deathpending[i] && - time_before_eq(jiffies, lowmem_deathpending_timeout)) - return 0; - } -#else if (lowmem_deathpending && time_before_eq(jiffies, lowmem_deathpending_timeout)) return 0; -#endif if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; for (i = 0; i < array_size; i++) { - if (other_free < lowmem_minfree[i] && - other_file < lowmem_minfree[i]) { - min_adj = lowmem_adj[i]; + minfree = lowmem_minfree[i]; + if (other_free < minfree && other_file < minfree) { + min_score_adj = lowmem_adj[i]; break; } } if (sc->nr_to_scan > 0) lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n", - sc->nr_to_scan, sc->gfp_mask, other_free, other_file, - min_adj); + sc->nr_to_scan, sc->gfp_mask, other_free, + other_file, min_score_adj); rem = global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + global_page_state(NR_INACTIVE_FILE); - if (sc->nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) { + if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) { lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n", sc->nr_to_scan, sc->gfp_mask, rem); return rem; } -#ifdef ENHANCED_LMK_ROUTINE - for (i = 0; i < LOWMEM_DEATHPENDING_DEPTH; i++) - selected_oom_adj[i] = min_adj; + selected_oom_score_adj = min_score_adj; + rcu_read_lock(); + +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE + for (tsk = pick_first_task(); + tsk != pick_last_task() && tsk != NULL; + tsk = pick_next_from_adj_tree(tsk)) { #else - selected_oom_adj = min_adj; + for_each_process(tsk) { #endif + struct task_struct *p; + int oom_score_adj; + if (tsk->flags & PF_KTHREAD) + continue; - read_lock(&tasklist_lock); - for_each_process(p) { - struct mm_struct *mm; - struct signal_struct *sig; - int oom_adj; -#ifdef ENHANCED_LMK_ROUTINE - int is_exist_oom_task = 0; -#endif - task_lock(p); - mm = p->mm; - sig = p->signal; - if (!mm || !sig) { + p = find_lock_task_mm(tsk); + if (!p) + continue; + + oom_score_adj = p->signal->oom_score_adj; + if (oom_score_adj < min_score_adj) { task_unlock(p); +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE + break; +#else continue; +#endif } - oom_adj = sig->oom_adj; - if (oom_adj < min_adj) { + if (fatal_signal_pending(p)) { + lowmem_print(2, "skip slow dying process %d\n", p->pid); task_unlock(p); continue; } - tasksize = get_mm_rss(mm); + tasksize = get_mm_rss(p->mm); task_unlock(p); if (tasksize <= 0) continue; -#ifdef ENHANCED_LMK_ROUTINE - if (all_selected_oom < LOWMEM_DEATHPENDING_DEPTH) { - for (i = 0; i < LOWMEM_DEATHPENDING_DEPTH; i++) { - if (!selected[i]) { - is_exist_oom_task = 1; - max_selected_oom_idx = i; - break; - } - } - } else if (selected_oom_adj[max_selected_oom_idx] < oom_adj || - (selected_oom_adj[max_selected_oom_idx] == oom_adj && - selected_tasksize[max_selected_oom_idx] < tasksize)) { - is_exist_oom_task = 1; - } - - if (is_exist_oom_task) { - selected[max_selected_oom_idx] = p; - selected_tasksize[max_selected_oom_idx] = tasksize; - selected_oom_adj[max_selected_oom_idx] = oom_adj; - - if (all_selected_oom < LOWMEM_DEATHPENDING_DEPTH) - all_selected_oom++; - - if (all_selected_oom == LOWMEM_DEATHPENDING_DEPTH) { - for (i = 0; i < LOWMEM_DEATHPENDING_DEPTH; i++) { - if (selected_oom_adj[i] < selected_oom_adj[max_selected_oom_idx]) - max_selected_oom_idx = i; - else if (selected_oom_adj[i] == selected_oom_adj[max_selected_oom_idx] && - selected_tasksize[i] < selected_tasksize[max_selected_oom_idx]) - max_selected_oom_idx = i; - } - } - - lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", - p->pid, p->comm, oom_adj, tasksize); - } -#else if (selected) { - if (oom_adj < selected_oom_adj) + if (oom_score_adj < selected_oom_score_adj) +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE + break; +#else continue; - if (oom_adj == selected_oom_adj && +#endif + if (oom_score_adj == selected_oom_score_adj && tasksize <= selected_tasksize) continue; } selected = p; selected_tasksize = tasksize; - selected_oom_adj = oom_adj; - lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", - p->pid, p->comm, oom_adj, tasksize); -#endif + selected_oom_score_adj = oom_score_adj; + lowmem_print(2, "select '%s' (%d), adj %d, size %d, to kill\n", + p->comm, p->pid, oom_score_adj, tasksize); } -#ifdef ENHANCED_LMK_ROUTINE - for (i = 0; i < LOWMEM_DEATHPENDING_DEPTH; i++) { - if (selected[i]) { - lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", - selected[i]->pid, selected[i]->comm, - selected_oom_adj[i], selected_tasksize[i]); - lowmem_deathpending[i] = selected[i]; - lowmem_deathpending_timeout = jiffies + HZ; - force_sig(SIGKILL, selected[i]); - rem -= selected_tasksize[i]; - } - } -#else if (selected) { - lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", - selected->pid, selected->comm, - selected_oom_adj, selected_tasksize); + lowmem_print(1, "Killing '%s' (%d), adj %d,\n" \ + " to free %ldkB on behalf of '%s' (%d) because\n" \ + " cache %ldkB is below limit %ldkB for oom_score_adj %d\n" \ + " Free memory is %ldkB above reserved\n", + selected->comm, selected->pid, + selected_oom_score_adj, + selected_tasksize * (long)(PAGE_SIZE / 1024), + current->comm, current->pid, + other_file * (long)(PAGE_SIZE / 1024), + minfree * (long)(PAGE_SIZE / 1024), + min_score_adj, + other_free * (long)(PAGE_SIZE / 1024)); lowmem_deathpending = selected; lowmem_deathpending_timeout = jiffies + HZ; - force_sig(SIGKILL, selected); + send_sig(SIGKILL, selected, 0); rem -= selected_tasksize; } -#endif lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n", sc->nr_to_scan, sc->gfp_mask, rem); - read_unlock(&tasklist_lock); + rcu_read_unlock(); return rem; } @@ -323,241 +229,203 @@ static struct shrinker lowmem_shrinker = { .seeks = DEFAULT_SEEKS * 16 }; -#ifdef CONFIG_ZRAM_FOR_ANDROID -/* - * zone_id_shrink_pagelist() clear page flags, - * update the memory zone status, and swap pagelist - */ - -static unsigned int shrink_pages(struct mm_struct *mm, - struct list_head *zone0_page_list, - struct list_head *zone1_page_list, - unsigned int num_to_scan) +static int __init lowmem_init(void) { - unsigned long addr; - unsigned int isolate_pages_countter = 0; - - struct vm_area_struct *vma = mm->mmap; - while (vma != NULL) { - - for (addr = vma->vm_start; addr < vma->vm_end; - addr += PAGE_SIZE) { - struct page *page; - /*get the page address from virtual memory address */ - page = follow_page(vma, addr, FOLL_GET); - - if (page && !IS_ERR(page)) { - - put_page(page); - /* only moveable, anonymous and not dirty pages can be swapped */ - if ((!PageUnevictable(page)) - && (!PageDirty(page)) && ((PageAnon(page))) - && (0 == page_is_file_cache(page))) { - switch (page_zone_id(page)) { - case 0: - if (!isolate_lru_page_compcache(page)) { - /* isolate page from LRU and add to temp list */ - /*create new page list, it will be used in shrink_page_list */ - list_add_tail(&page->lru, zone0_page_list); - isolate_pages_countter++; - } - break; - case 1: - if (!isolate_lru_page_compcache(page)) { - /* isolate page from LRU and add to temp list */ - /*create new page list, it will be used in shrink_page_list */ - list_add_tail(&page->lru, zone1_page_list); - isolate_pages_countter++; - } - break; - default: - break; - } - } - } - - if (isolate_pages_countter >= num_to_scan) { - return isolate_pages_countter; - } - } + task_free_register(&task_nb); + register_shrinker(&lowmem_shrinker); + return 0; +} - vma = vma->vm_next; - } +static void __exit lowmem_exit(void) +{ + unregister_shrinker(&lowmem_shrinker); + task_free_unregister(&task_nb); +} - return isolate_pages_countter; +#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES +static int lowmem_oom_adj_to_oom_score_adj(int oom_adj) +{ + if (oom_adj == OOM_ADJUST_MAX) + return OOM_SCORE_ADJ_MAX; + else + return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; } -/* - * swap_application_pages() will search the - * pages which can be swapped, then call - * zone_id_shrink_pagelist to update zone - * status - */ -static unsigned int swap_pages(struct list_head *zone0_page_list, - struct list_head *zone1_page_list) +static void lowmem_autodetect_oom_adj_values(void) { - struct zone *zone_id_0 = &NODE_DATA(0)->node_zones[0]; - struct zone *zone_id_1 = &NODE_DATA(0)->node_zones[1]; - unsigned int pages_counter = 0; - - /*if the page list is not empty, call zone_id_shrink_pagelist to update zone status */ - if ((zone_id_0) && (!list_empty(zone0_page_list))) { - pages_counter += - zone_id_shrink_pagelist(zone_id_0, zone0_page_list); - } - if ((zone_id_1) && (!list_empty(zone1_page_list))) { - pages_counter += - zone_id_shrink_pagelist(zone_id_1, zone1_page_list); + int i; + int oom_adj; + int oom_score_adj; + int array_size = ARRAY_SIZE(lowmem_adj); + + if (lowmem_adj_size < array_size) + array_size = lowmem_adj_size; + + if (array_size <= 0) + return; + + oom_adj = lowmem_adj[array_size - 1]; + if (oom_adj > OOM_ADJUST_MAX) + return; + + oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj); + if (oom_score_adj <= OOM_ADJUST_MAX) + return; + + lowmem_print(1, "lowmem_shrink: convert oom_adj to oom_score_adj:\n"); + for (i = 0; i < array_size; i++) { + oom_adj = lowmem_adj[i]; + oom_score_adj = lowmem_oom_adj_to_oom_score_adj(oom_adj); + lowmem_adj[i] = oom_score_adj; + lowmem_print(1, "oom_adj %d => oom_score_adj %d\n", + oom_adj, oom_score_adj); } - return pages_counter; } -static ssize_t lmk_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static int lowmem_adj_array_set(const char *val, const struct kernel_param *kp) { - return sprintf(buf, "%d,%d\n", lmk_kill_pid, lmk_kill_ok); + int ret; + + ret = param_array_ops.set(val, kp); + + /* HACK: Autodetect oom_adj values in lowmem_adj array */ + lowmem_autodetect_oom_adj_values(); + + return ret; } -/* - * lmk_state_store() will called by framework, - * the framework will send the pid of process that need to be swapped - */ -static ssize_t lmk_state_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) +static int lowmem_adj_array_get(char *buffer, const struct kernel_param *kp) { - sscanf(buf, "%d,%d", &lmk_kill_pid, &lmk_kill_ok); + return param_array_ops.get(buffer, kp); +} - /* if the screen on, the optimized compcache will stop */ - if (atomic_read(&optimize_comp_on) != 1) - return size; +static void lowmem_adj_array_free(void *arg) +{ + param_array_ops.free(arg); +} - if (lmk_kill_ok == 1) { - struct task_struct *p; - struct task_struct *selected = NULL; - struct sysinfo ramzswap_info = { 0 }; - struct mm_struct *mm_scan = NULL; - - /* - * check the free RAM and swap area, - * stop the optimized compcache in cpu idle case; - * leave some swap area for using in low memory case - */ - si_swapinfo(&ramzswap_info); - si_meminfo(&ramzswap_info); - - if ((ramzswap_info.freeswap < CHECK_FREE_SWAPSPACE) || - (ramzswap_info.freeram < check_free_memory)) { -#if SWAP_PROCESS_DEBUG_LOG > 0 - printk(KERN_INFO "idletime compcache is ignored : free RAM %lu, free swap %lu\n", - ramzswap_info.freeram, ramzswap_info.freeswap); -#endif - lmk_kill_ok = 0; - return size; - } +static struct kernel_param_ops lowmem_adj_array_ops = { + .set = lowmem_adj_array_set, + .get = lowmem_adj_array_get, + .free = lowmem_adj_array_free, +}; - read_lock(&tasklist_lock); - for_each_process(p) { - if ((p->pid == lmk_kill_pid) && - (__task_cred(p)->uid > 10000)) { - task_lock(p); - selected = p; - if (!selected->mm || !selected->signal) { - task_unlock(p); - selected = NULL; - break; - } - mm_scan = selected->mm; - if (mm_scan) { - if (selected->flags & PF_KTHREAD) - mm_scan = NULL; - else - atomic_inc(&mm_scan->mm_users); - } - task_unlock(selected); - -#if SWAP_PROCESS_DEBUG_LOG > 0 - printk(KERN_INFO "idle time compcache: swap process pid %d, name %s, oom %d, task size %ld\n", - p->pid, p->comm, - p->signal->oom_adj, - get_mm_rss(p->mm)); +static const struct kparam_array __param_arr_adj = { + .max = ARRAY_SIZE(lowmem_adj), + .num = &lowmem_adj_size, + .ops = ¶m_ops_int, + .elemsize = sizeof(lowmem_adj[0]), + .elem = lowmem_adj, +}; #endif - break; - } - } - read_unlock(&tasklist_lock); - - if (mm_scan) { - LIST_HEAD(zone0_page_list); - LIST_HEAD(zone1_page_list); - int pages_tofree = 0, pages_freed = 0; - - down_read(&mm_scan->mmap_sem); - pages_tofree = - shrink_pages(mm_scan, &zone0_page_list, - &zone1_page_list, 0x7FFFFFFF); - up_read(&mm_scan->mmap_sem); - mmput(mm_scan); - pages_freed = - swap_pages(&zone0_page_list, - &zone1_page_list); - lmk_kill_ok = 0; - } +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE +DEFINE_SPINLOCK(lmk_lock); +struct rb_root tasks_scoreadj = RB_ROOT; +/* + * Makesure to invoke the function with holding sighand->siglock + */ +void add_2_adj_tree(struct task_struct *task) +{ + struct rb_node **link; + struct rb_node *parent = NULL; + struct signal_struct *sig_entry; + s64 key = task->signal->oom_score_adj; + + /* + * Find the right place in the rbtree: + */ + spin_lock(&lmk_lock); + link = &tasks_scoreadj.rb_node; + while (*link) { + parent = *link; + sig_entry = rb_entry(parent, struct signal_struct, adj_node); + + if (key < sig_entry->oom_score_adj) + link = &parent->rb_right; + else + link = &parent->rb_left; } - return size; + rb_link_node(&task->signal->adj_node, parent, link); + rb_insert_color(&task->signal->adj_node, &tasks_scoreadj); + spin_unlock(&lmk_lock); } -static DEVICE_ATTR(lmk_state, 0664, lmk_state_show, lmk_state_store); +/* + * Makesure to invoke the function with holding sighand->siglock + */ +void delete_from_adj_tree(struct task_struct *task) +{ + spin_lock(&lmk_lock); + if (!RB_EMPTY_NODE(&task->signal->adj_node)) { + rb_erase(&task->signal->adj_node, &tasks_scoreadj); + RB_CLEAR_NODE(&task->signal->adj_node); + } + spin_unlock(&lmk_lock); +} -#endif /* CONFIG_ZRAM_FOR_ANDROID */ -static int __init lowmem_init(void) +static struct task_struct *pick_next_from_adj_tree(struct task_struct *task) { -#ifdef CONFIG_ZRAM_FOR_ANDROID - struct zone *zone; - unsigned int high_wmark = 0; -#endif - task_free_register(&task_nb); - register_shrinker(&lowmem_shrinker); + struct rb_node *next; + struct signal_struct *next_tsk_sig; -#ifdef CONFIG_ZRAM_FOR_ANDROID - for_each_zone(zone) { - if (high_wmark < zone->watermark[WMARK_HIGH]) - high_wmark = zone->watermark[WMARK_HIGH]; - } - check_free_memory = (high_wmark != 0) ? high_wmark : CHECK_FREE_MEMORY; + spin_lock(&lmk_lock); + next = rb_next(&task->signal->adj_node); + spin_unlock(&lmk_lock); - lmk_class = class_create(THIS_MODULE, "lmk"); - if (IS_ERR(lmk_class)) { - printk(KERN_ERR "Failed to create class(lmk)\n"); - return 0; - } - lmk_dev = device_create(lmk_class, NULL, 0, NULL, "lowmemorykiller"); - if (IS_ERR(lmk_dev)) { - printk(KERN_ERR - "Failed to create device(lowmemorykiller)!= %ld\n", - IS_ERR(lmk_dev)); - return 0; - } - if (device_create_file(lmk_dev, &dev_attr_lmk_state) < 0) - printk(KERN_ERR "Failed to create device file(%s)!\n", - dev_attr_lmk_state.attr.name); -#endif /* CONFIG_ZRAM_FOR_ANDROID */ + if (!next) + return NULL; - return 0; + next_tsk_sig = rb_entry(next, struct signal_struct, adj_node); + return next_tsk_sig->curr_target->group_leader; } -static void __exit lowmem_exit(void) +static struct task_struct *pick_first_task(void) { - unregister_shrinker(&lowmem_shrinker); - task_free_unregister(&task_nb); + struct rb_node *left; + struct signal_struct *first_tsk_sig; + + spin_lock(&lmk_lock); + left = rb_first(&tasks_scoreadj); + spin_unlock(&lmk_lock); + + if (!left) + return NULL; + + first_tsk_sig = rb_entry(left, struct signal_struct, adj_node); + return first_tsk_sig->curr_target->group_leader; +} + +static struct task_struct *pick_last_task(void) +{ + struct rb_node *right; + struct signal_struct *last_tsk_sig; + + spin_lock(&lmk_lock); + right = rb_last(&tasks_scoreadj); + spin_unlock(&lmk_lock); + + if (!right) + return NULL; + + last_tsk_sig = rb_entry(right, struct signal_struct, adj_node); + return last_tsk_sig->curr_target->group_leader; } +#endif module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); +#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES +__module_param_call(MODULE_PARAM_PREFIX, adj, + &lowmem_adj_array_ops, + .arr = &__param_arr_adj, + S_IRUGO | S_IWUSR, 0664); +__MODULE_PARM_TYPE(adj, "array of int"); +#else module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, S_IRUGO | S_IWUSR); +#endif module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, S_IRUGO | S_IWUSR); module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c index 80c2ee5..c43c7e3 100644 --- a/drivers/staging/tidspbridge/rmgr/drv_interface.c +++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c @@ -617,11 +617,7 @@ err: static int bridge_mmap(struct file *filp, struct vm_area_struct *vma) { u32 offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long base_pgoff; - int status; - - struct omap_dsp_platform_data *pdata = - omap_dspbridge_dev->dev.platform_data; + u32 status; DBC_ASSERT(vma->vm_start < vma->vm_end); @@ -632,27 +628,11 @@ static int bridge_mmap(struct file *filp, struct vm_area_struct *vma) "%lx flags %lx\n", __func__, filp, offset, vma->vm_start, vma->vm_end, vma->vm_page_prot, vma->vm_flags); - /* - * vm_iomap_memory() expects vma->vm_pgoff to be expressed as an offset - * from the start of the physical memory pool, but we're called with - * a pfn (physical page number) stored there instead. - * - * To avoid duplicating lots of tricky overflow checking logic, - * temporarily convert vma->vm_pgoff to the offset vm_iomap_memory() - * expects, but restore the original value once the mapping has been - * created. - */ - base_pgoff = pdata->phys_mempool_base >> PAGE_SHIFT; - if (vma->vm_pgoff < base_pgoff) - return -EINVAL; - vma->vm_pgoff -= base_pgoff; - - status = vm_iomap_memory(vma, - pdata->phys_mempool_base, - pdata->phys_mempool_size); - - /* Restore the original value of vma->vm_pgoff */ - vma->vm_pgoff += base_pgoff; + status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); + if (status != 0) + status = -EAGAIN; return status; } diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig index 7fabcb2..4881839 100644 --- a/drivers/staging/zcache/Kconfig +++ b/drivers/staging/zcache/Kconfig @@ -1,13 +1,11 @@ config ZCACHE - tristate "Dynamic compression of swap pages and clean pagecache pages" - depends on CLEANCACHE || FRONTSWAP - select XVMALLOC - select LZO_COMPRESS - select LZO_DECOMPRESS + bool "Dynamic compression of swap pages and clean pagecache pages" + depends on (CLEANCACHE || FRONTSWAP) && CRYPTO=y && ZSMALLOC=y + select CRYPTO_LZO default n help Zcache doubles RAM efficiency while providing a significant - performance boosts on many workloads. Zcache uses lzo1x + performance boosts on many workloads. Zcache uses compression and an in-kernel implementation of transcendent memory to store clean page cache pages and swap in RAM, providing a noticeable reduction in disk I/O. diff --git a/drivers/staging/zcache/Makefile b/drivers/staging/zcache/Makefile index f5ec64f..60daa27 100644 --- a/drivers/staging/zcache/Makefile +++ b/drivers/staging/zcache/Makefile @@ -1,3 +1,3 @@ -zcache-y := tmem.o +zcache-y := zcache-main.o tmem.o obj-$(CONFIG_ZCACHE) += zcache.o diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c index e954d40..1ca66ea 100644 --- a/drivers/staging/zcache/tmem.c +++ b/drivers/staging/zcache/tmem.c @@ -142,6 +142,7 @@ static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb, obj->oid = *oidp; obj->objnode_count = 0; obj->pampd_count = 0; + (*tmem_pamops.new_obj)(obj); SET_SENTINEL(obj, OBJ); while (*new) { BUG_ON(RB_EMPTY_NODE(*new)); @@ -274,7 +275,7 @@ static void tmem_objnode_free(struct tmem_objnode *objnode) /* * lookup index in object and return associated pampd (or NULL if not found) */ -static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index) +static void **__tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index) { unsigned int height, shift; struct tmem_objnode **slot = NULL; @@ -303,9 +304,33 @@ static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index) height--; } out: + return slot != NULL ? (void **)slot : NULL; +} + +static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index) +{ + struct tmem_objnode **slot; + + slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index); return slot != NULL ? *slot : NULL; } +static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index, + void *new_pampd) +{ + struct tmem_objnode **slot; + void *ret = NULL; + + slot = (struct tmem_objnode **)__tmem_pampd_lookup_in_obj(obj, index); + if ((slot != NULL) && (*slot != NULL)) { + void *old_pampd = *(void **)slot; + *(void **)slot = new_pampd; + (*tmem_pamops.free)(old_pampd, obj->pool, NULL, 0); + ret = new_pampd; + } + return ret; +} + static int tmem_pampd_add_to_obj(struct tmem_obj *obj, uint32_t index, void *pampd) { @@ -456,7 +481,7 @@ static void tmem_objnode_node_destroy(struct tmem_obj *obj, if (ht == 1) { obj->pampd_count--; (*tmem_pamops.free)(objnode->slots[i], - obj->pool); + obj->pool, NULL, 0); objnode->slots[i] = NULL; continue; } @@ -473,7 +498,7 @@ static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj) return; if (obj->objnode_tree_height == 0) { obj->pampd_count--; - (*tmem_pamops.free)(obj->objnode_tree_root, obj->pool); + (*tmem_pamops.free)(obj->objnode_tree_root, obj->pool, NULL, 0); } else { tmem_objnode_node_destroy(obj, obj->objnode_tree_root, obj->objnode_tree_height); @@ -481,6 +506,7 @@ static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj) obj->objnode_tree_height = 0; } obj->objnode_tree_root = NULL; + (*tmem_pamops.free_obj)(obj->pool, obj); } /* @@ -503,15 +529,13 @@ static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj) * always flushes for simplicity. */ int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, - struct page *page) + char *data, size_t size, bool raw, bool ephemeral) { struct tmem_obj *obj = NULL, *objfound = NULL, *objnew = NULL; void *pampd = NULL, *pampd_del = NULL; int ret = -ENOMEM; - bool ephemeral; struct tmem_hashbucket *hb; - ephemeral = is_ephemeral(pool); hb = &pool->hashbucket[tmem_oid_hash(oidp)]; spin_lock(&hb->lock); obj = objfound = tmem_obj_find(hb, oidp); @@ -521,7 +545,7 @@ int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, /* if found, is a dup put, flush the old one */ pampd_del = tmem_pampd_delete_from_obj(obj, index); BUG_ON(pampd_del != pampd); - (*tmem_pamops.free)(pampd, pool); + (*tmem_pamops.free)(pampd, pool, oidp, index); if (obj->pampd_count == 0) { objnew = obj; objfound = NULL; @@ -538,7 +562,8 @@ int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, } BUG_ON(obj == NULL); BUG_ON(((objnew != obj) && (objfound != obj)) || (objnew == objfound)); - pampd = (*tmem_pamops.create)(obj->pool, &obj->oid, index, page); + pampd = (*tmem_pamops.create)(data, size, raw, ephemeral, + obj->pool, &obj->oid, index); if (unlikely(pampd == NULL)) goto free; ret = tmem_pampd_add_to_obj(obj, index, pampd); @@ -551,7 +576,7 @@ delete_and_free: (void)tmem_pampd_delete_from_obj(obj, index); free: if (pampd) - (*tmem_pamops.free)(pampd, pool); + (*tmem_pamops.free)(pampd, pool, NULL, 0); if (objnew) { tmem_obj_free(objnew, hb); (*tmem_hostops.obj_free)(objnew, pool); @@ -573,41 +598,52 @@ out: * "put" done with the same handle). */ -int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, - uint32_t index, struct page *page) +int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, + char *data, size_t *size, bool raw, int get_and_free) { struct tmem_obj *obj; void *pampd; bool ephemeral = is_ephemeral(pool); - uint32_t ret = -1; + int ret = -1; struct tmem_hashbucket *hb; + bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral); + bool lock_held = false; hb = &pool->hashbucket[tmem_oid_hash(oidp)]; spin_lock(&hb->lock); + lock_held = true; obj = tmem_obj_find(hb, oidp); if (obj == NULL) goto out; - ephemeral = is_ephemeral(pool); - if (ephemeral) + if (free) pampd = tmem_pampd_delete_from_obj(obj, index); else pampd = tmem_pampd_lookup_in_obj(obj, index); if (pampd == NULL) goto out; - ret = (*tmem_pamops.get_data)(page, pampd, pool); - if (ret < 0) - goto out; - if (ephemeral) { - (*tmem_pamops.free)(pampd, pool); + if (free) { if (obj->pampd_count == 0) { tmem_obj_free(obj, hb); (*tmem_hostops.obj_free)(obj, pool); obj = NULL; } } + if (tmem_pamops.is_remote(pampd)) { + lock_held = false; + spin_unlock(&hb->lock); + } + if (free) + ret = (*tmem_pamops.get_data_and_free)( + data, size, raw, pampd, pool, oidp, index); + else + ret = (*tmem_pamops.get_data)( + data, size, raw, pampd, pool, oidp, index); + if (ret < 0) + goto out; ret = 0; out: - spin_unlock(&hb->lock); + if (lock_held) + spin_unlock(&hb->lock); return ret; } @@ -632,7 +668,7 @@ int tmem_flush_page(struct tmem_pool *pool, pampd = tmem_pampd_delete_from_obj(obj, index); if (pampd == NULL) goto out; - (*tmem_pamops.free)(pampd, pool); + (*tmem_pamops.free)(pampd, pool, oidp, index); if (obj->pampd_count == 0) { tmem_obj_free(obj, hb); (*tmem_hostops.obj_free)(obj, pool); @@ -645,6 +681,30 @@ out: } /* + * If a page in tmem matches the handle, replace the page so that any + * subsequent "get" gets the new page. Returns 0 if + * there was a page to replace, else returns -1. + */ +int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp, + uint32_t index, void *new_pampd) +{ + struct tmem_obj *obj; + int ret = -1; + struct tmem_hashbucket *hb; + + hb = &pool->hashbucket[tmem_oid_hash(oidp)]; + spin_lock(&hb->lock); + obj = tmem_obj_find(hb, oidp); + if (obj == NULL) + goto out; + new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd); + ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj); +out: + spin_unlock(&hb->lock); + return ret; +} + +/* * "Flush" all pages in tmem matching this oid. */ int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp) diff --git a/drivers/staging/zcache/tmem.h b/drivers/staging/zcache/tmem.h index 2e07e21..0d4aa82 100644 --- a/drivers/staging/zcache/tmem.h +++ b/drivers/staging/zcache/tmem.h @@ -47,7 +47,7 @@ #define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0) #endif -#define ASSERT_SPINLOCK(_l) WARN_ON(!spin_is_locked(_l)) +#define ASSERT_SPINLOCK(_l) lockdep_assert_held(_l) /* * A pool is the highest-level data structure managed by tmem and @@ -147,6 +147,7 @@ struct tmem_obj { unsigned int objnode_tree_height; unsigned long objnode_count; long pampd_count; + void *extra; /* for private use by pampd implementation */ DECL_SENTINEL }; @@ -166,10 +167,18 @@ struct tmem_objnode { /* pampd abstract datatype methods provided by the PAM implementation */ struct tmem_pamops { - void *(*create)(struct tmem_pool *, struct tmem_oid *, uint32_t, - struct page *); - int (*get_data)(struct page *, void *, struct tmem_pool *); - void (*free)(void *, struct tmem_pool *); + void *(*create)(char *, size_t, bool, int, + struct tmem_pool *, struct tmem_oid *, uint32_t); + int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *, + struct tmem_oid *, uint32_t); + int (*get_data_and_free)(char *, size_t *, bool, void *, + struct tmem_pool *, struct tmem_oid *, + uint32_t); + void (*free)(void *, struct tmem_pool *, struct tmem_oid *, uint32_t); + void (*free_obj)(struct tmem_pool *, struct tmem_obj *); + bool (*is_remote)(void *); + void (*new_obj)(struct tmem_obj *); + int (*replace_in_obj)(void *, struct tmem_obj *); }; extern void tmem_register_pamops(struct tmem_pamops *m); @@ -184,9 +193,11 @@ extern void tmem_register_hostops(struct tmem_hostops *m); /* core tmem accessor functions */ extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index, - struct page *page); + char *, size_t, bool, bool); extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index, - struct page *page); + char *, size_t *, bool, int); +extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index, + void *); extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *, uint32_t index); extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *); diff --git a/drivers/staging/zcache/zcache.c b/drivers/staging/zcache/zcache-main.c index 77ac2d4..eb65043 100644 --- a/drivers/staging/zcache/zcache.c +++ b/drivers/staging/zcache/zcache-main.c @@ -6,9 +6,10 @@ * * Zcache provides an in-kernel "host implementation" for transcendent memory * and, thus indirectly, for cleancache and frontswap. Zcache includes two - * page-accessible memory [1] interfaces, both utilizing lzo1x compression: + * page-accessible memory [1] interfaces, both utilizing the crypto compression + * API: * 1) "compression buddies" ("zbud") is used for ephemeral pages - * 2) xvmalloc is used for persistent pages. + * 2) zsmalloc is used for persistent pages. * Xvmalloc (based on the TLSF allocator) has very low fragmentation * so maximizes space efficiency, while zbud allows pairs (and potentially, * in the future, more than a pair of) compressed pages to be closely linked @@ -19,17 +20,20 @@ * http://marc.info/?l=linux-mm&m=127811271605009 */ +#include <linux/module.h> #include <linux/cpu.h> #include <linux/highmem.h> #include <linux/list.h> -#include <linux/lzo.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/types.h> #include <linux/atomic.h> +#include <linux/math64.h> +#include <linux/crypto.h> +#include <linux/string.h> #include "tmem.h" -#include "../zram/xvmalloc.h" /* if built in drivers/staging */ +#include <linux/zsmalloc.h> #if (!defined(CONFIG_CLEANCACHE) && !defined(CONFIG_FRONTSWAP)) #error "zcache is useless without CONFIG_CLEANCACHE or CONFIG_FRONTSWAP" @@ -49,6 +53,68 @@ (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC) #endif +#define MAX_POOLS_PER_CLIENT 16 + +#define MAX_CLIENTS 16 +#define LOCAL_CLIENT ((uint16_t)-1) + +MODULE_LICENSE("GPL"); + +struct zcache_client { + struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT]; + struct zs_pool *zspool; + bool allocated; + atomic_t refcount; +}; + +static struct zcache_client zcache_host; +static struct zcache_client zcache_clients[MAX_CLIENTS]; + +static inline uint16_t get_client_id_from_client(struct zcache_client *cli) +{ + BUG_ON(cli == NULL); + if (cli == &zcache_host) + return LOCAL_CLIENT; + return cli - &zcache_clients[0]; +} + +static inline bool is_local_client(struct zcache_client *cli) +{ + return cli == &zcache_host; +} + +/* crypto API for zcache */ +#define ZCACHE_COMP_NAME_SZ CRYPTO_MAX_ALG_NAME +static char zcache_comp_name[ZCACHE_COMP_NAME_SZ]; +static struct crypto_comp * __percpu *zcache_comp_pcpu_tfms; + +enum comp_op { + ZCACHE_COMPOP_COMPRESS, + ZCACHE_COMPOP_DECOMPRESS +}; + +static inline int zcache_comp_op(enum comp_op op, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + struct crypto_comp *tfm; + int ret; + + BUG_ON(!zcache_comp_pcpu_tfms); + tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, get_cpu()); + BUG_ON(!tfm); + switch (op) { + case ZCACHE_COMPOP_COMPRESS: + ret = crypto_comp_compress(tfm, src, slen, dst, dlen); + break; + case ZCACHE_COMPOP_DECOMPRESS: + ret = crypto_comp_decompress(tfm, src, slen, dst, dlen); + break; + } + put_cpu(); + return ret; +} + /********** * Compression buddies ("zbud") provides for packing two (or, possibly * in the future, more) compressed ephemeral pages into a single "raw" @@ -72,7 +138,8 @@ #define ZBUD_MAX_BUDS 2 struct zbud_hdr { - uint32_t pool_id; + uint16_t client_id; + uint16_t pool_id; struct tmem_oid oid; uint32_t index; uint16_t size; /* compressed size in bytes, zero means unused */ @@ -120,6 +187,7 @@ static unsigned long zcache_zbud_curr_zbytes; static unsigned long zcache_zbud_cumul_zpages; static unsigned long zcache_zbud_cumul_zbytes; static unsigned long zcache_compress_poor; +static unsigned long zcache_mean_compress_poor; /* forward references */ static void *zcache_get_free_page(void); @@ -265,10 +333,12 @@ static void zbud_free_and_delist(struct zbud_hdr *zh) struct zbud_page *zbpg = container_of(zh, struct zbud_page, buddy[budnum]); + spin_lock(&zbud_budlists_spinlock); spin_lock(&zbpg->lock); if (list_empty(&zbpg->bud_list)) { /* ignore zombie page... see zbud_evict_pages() */ spin_unlock(&zbpg->lock); + spin_unlock(&zbud_budlists_spinlock); return; } size = zbud_free(zh); @@ -276,7 +346,6 @@ static void zbud_free_and_delist(struct zbud_hdr *zh) zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0]; if (zh_other->size == 0) { /* was unbuddied: unlist and free */ chunks = zbud_size_to_chunks(size) ; - spin_lock(&zbud_budlists_spinlock); BUG_ON(list_empty(&zbud_unbuddied[chunks].list)); list_del_init(&zbpg->bud_list); zbud_unbuddied[chunks].count--; @@ -284,7 +353,6 @@ static void zbud_free_and_delist(struct zbud_hdr *zh) zbud_free_raw_page(zbpg); } else { /* was buddied: move remaining buddy to unbuddied list */ chunks = zbud_size_to_chunks(zh_other->size) ; - spin_lock(&zbud_budlists_spinlock); list_del_init(&zbpg->bud_list); zcache_zbud_buddied_count--; list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list); @@ -294,7 +362,8 @@ static void zbud_free_and_delist(struct zbud_hdr *zh) } } -static struct zbud_hdr *zbud_create(uint32_t pool_id, struct tmem_oid *oid, +static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id, + struct tmem_oid *oid, uint32_t index, struct page *page, void *cdata, unsigned size) { @@ -323,8 +392,8 @@ static struct zbud_hdr *zbud_create(uint32_t pool_id, struct tmem_oid *oid, if (unlikely(zbpg == NULL)) goto out; /* ok, have a page, now compress the data before taking locks */ - spin_lock(&zbpg->lock); spin_lock(&zbud_budlists_spinlock); + spin_lock(&zbpg->lock); list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list); zbud_unbuddied[nchunks].count++; zh = &zbpg->buddy[0]; @@ -353,12 +422,12 @@ init_zh: zh->index = index; zh->oid = *oid; zh->pool_id = pool_id; - /* can wait to copy the data until the list locks are dropped */ - spin_unlock(&zbud_budlists_spinlock); - + zh->client_id = client_id; to = zbud_data(zh, size); memcpy(to, cdata, size); spin_unlock(&zbpg->lock); + spin_unlock(&zbud_budlists_spinlock); + zbud_cumul_chunk_counts[nchunks]++; atomic_inc(&zcache_zbud_curr_zpages); zcache_zbud_cumul_zpages++; @@ -372,7 +441,7 @@ static int zbud_decompress(struct page *page, struct zbud_hdr *zh) { struct zbud_page *zbpg; unsigned budnum = zbud_budnum(zh); - size_t out_len = PAGE_SIZE; + unsigned int out_len = PAGE_SIZE; char *to_va, *from_va; unsigned size; int ret = 0; @@ -389,8 +458,9 @@ static int zbud_decompress(struct page *page, struct zbud_hdr *zh) to_va = kmap_atomic(page, KM_USER0); size = zh->size; from_va = zbud_data(zh, size); - ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len); - BUG_ON(ret != LZO_E_OK); + ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size, + to_va, &out_len); + BUG_ON(ret); BUG_ON(out_len != PAGE_SIZE); kunmap_atomic(to_va, KM_USER0); out: @@ -407,7 +477,8 @@ static unsigned long zcache_evicted_raw_pages; static unsigned long zcache_evicted_buddied_pages; static unsigned long zcache_evicted_unbuddied_pages; -static struct tmem_pool *zcache_get_pool_by_id(uint32_t poolid); +static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, + uint16_t poolid); static void zcache_put_pool(struct tmem_pool *pool); /* @@ -417,7 +488,8 @@ static void zbud_evict_zbpg(struct zbud_page *zbpg) { struct zbud_hdr *zh; int i, j; - uint32_t pool_id[ZBUD_MAX_BUDS], index[ZBUD_MAX_BUDS]; + uint32_t pool_id[ZBUD_MAX_BUDS], client_id[ZBUD_MAX_BUDS]; + uint32_t index[ZBUD_MAX_BUDS]; struct tmem_oid oid[ZBUD_MAX_BUDS]; struct tmem_pool *pool; @@ -426,6 +498,7 @@ static void zbud_evict_zbpg(struct zbud_page *zbpg) for (i = 0, j = 0; i < ZBUD_MAX_BUDS; i++) { zh = &zbpg->buddy[i]; if (zh->size) { + client_id[j] = zh->client_id; pool_id[j] = zh->pool_id; oid[j] = zh->oid; index[j] = zh->index; @@ -435,7 +508,7 @@ static void zbud_evict_zbpg(struct zbud_page *zbpg) } spin_unlock(&zbpg->lock); for (i = 0; i < j; i++) { - pool = zcache_get_pool_by_id(pool_id[i]); + pool = zcache_get_pool_by_id(client_id[i], pool_id[i]); if (pool != NULL) { tmem_flush_page(pool, &oid[i], index[i]); zcache_put_pool(pool); @@ -552,9 +625,8 @@ static int zbud_show_unbuddied_list_counts(char *buf) int i; char *p = buf; - for (i = 0; i < NCHUNKS - 1; i++) + for (i = 0; i < NCHUNKS; i++) p += sprintf(p, "%u ", zbud_unbuddied[i].count); - p += sprintf(p, "%d\n", zbud_unbuddied[i].count); return p - buf; } @@ -585,8 +657,8 @@ static int zbud_show_cumul_chunk_counts(char *buf) #endif /********** - * This "zv" PAM implementation combines the TLSF-based xvMalloc - * with lzo1x compression to maximize the amount of data that can + * This "zv" PAM implementation combines the slab-based zsmalloc + * with the crypto compression API to maximize the amount of data that can * be packed into a physical page. * * Zv represents a PAM page with the index and object (plus a "size" value @@ -599,72 +671,250 @@ struct zv_hdr { uint32_t pool_id; struct tmem_oid oid; uint32_t index; + size_t size; DECL_SENTINEL }; -static const int zv_max_page_size = (PAGE_SIZE / 8) * 7; +/* rudimentary policy limits */ +/* total number of persistent pages may not exceed this percentage */ +static unsigned int zv_page_count_policy_percent = 75; +/* + * byte count defining poor compression; pages with greater zsize will be + * rejected + */ +static unsigned int zv_max_zsize = (PAGE_SIZE / 8) * 7; +/* + * byte count defining poor *mean* compression; pages with greater zsize + * will be rejected until sufficient better-compressed pages are accepted + * driving the mean below this threshold + */ +static unsigned int zv_max_mean_zsize = (PAGE_SIZE / 8) * 5; + +static atomic_t zv_curr_dist_counts[NCHUNKS]; +static atomic_t zv_cumul_dist_counts[NCHUNKS]; -static struct zv_hdr *zv_create(struct xv_pool *xvpool, uint32_t pool_id, +static unsigned long zv_create(struct zs_pool *pool, uint32_t pool_id, struct tmem_oid *oid, uint32_t index, void *cdata, unsigned clen) { - struct page *page; - struct zv_hdr *zv = NULL; - uint32_t offset; - int ret; + struct zv_hdr *zv; + u32 size = clen + sizeof(struct zv_hdr); + int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT; + unsigned long handle = 0; BUG_ON(!irqs_disabled()); - ret = xv_malloc(xvpool, clen + sizeof(struct zv_hdr), - &page, &offset, ZCACHE_GFP_MASK); - if (unlikely(ret)) + BUG_ON(chunks >= NCHUNKS); + handle = zs_malloc(pool, size); + if (!handle) goto out; - zv = kmap_atomic(page, KM_USER0) + offset; + atomic_inc(&zv_curr_dist_counts[chunks]); + atomic_inc(&zv_cumul_dist_counts[chunks]); + zv = zs_map_object(pool, handle, ZS_MM_WO); zv->index = index; zv->oid = *oid; zv->pool_id = pool_id; + zv->size = clen; SET_SENTINEL(zv, ZVH); memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen); - kunmap_atomic(zv, KM_USER0); + zs_unmap_object(pool, handle); out: - return zv; + return handle; } -static void zv_free(struct xv_pool *xvpool, struct zv_hdr *zv) +static void zv_free(struct zs_pool *pool, unsigned long handle) { unsigned long flags; - struct page *page; - uint32_t offset; + struct zv_hdr *zv; uint16_t size; + int chunks; + zv = zs_map_object(pool, handle, ZS_MM_RW); ASSERT_SENTINEL(zv, ZVH); - size = xv_get_object_size(zv) - sizeof(*zv); - BUG_ON(size == 0 || size > zv_max_page_size); + size = zv->size + sizeof(struct zv_hdr); INVERT_SENTINEL(zv, ZVH); - page = virt_to_page(zv); - offset = (unsigned long)zv & ~PAGE_MASK; + zs_unmap_object(pool, handle); + + chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT; + BUG_ON(chunks >= NCHUNKS); + atomic_dec(&zv_curr_dist_counts[chunks]); + local_irq_save(flags); - xv_free(xvpool, page, offset); + zs_free(pool, handle); local_irq_restore(flags); } -static void zv_decompress(struct page *page, struct zv_hdr *zv) +static void zv_decompress(struct page *page, unsigned long handle) { - size_t clen = PAGE_SIZE; + unsigned int clen = PAGE_SIZE; char *to_va; - unsigned size; int ret; + struct zv_hdr *zv; + zv = zs_map_object(zcache_host.zspool, handle, ZS_MM_RO); + BUG_ON(zv->size == 0); ASSERT_SENTINEL(zv, ZVH); - size = xv_get_object_size(zv) - sizeof(*zv); - BUG_ON(size == 0 || size > zv_max_page_size); to_va = kmap_atomic(page, KM_USER0); - ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv), - size, to_va, &clen); + ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, (char *)zv + sizeof(*zv), + zv->size, to_va, &clen); kunmap_atomic(to_va, KM_USER0); - BUG_ON(ret != LZO_E_OK); + zs_unmap_object(zcache_host.zspool, handle); + BUG_ON(ret); BUG_ON(clen != PAGE_SIZE); } +#ifdef CONFIG_SYSFS +/* + * show a distribution of compression stats for zv pages. + */ + +static int zv_curr_dist_counts_show(char *buf) +{ + unsigned long i, n, chunks = 0, sum_total_chunks = 0; + char *p = buf; + + for (i = 0; i < NCHUNKS; i++) { + n = atomic_read(&zv_curr_dist_counts[i]); + p += sprintf(p, "%lu ", n); + chunks += n; + sum_total_chunks += i * n; + } + p += sprintf(p, "mean:%lu\n", + chunks == 0 ? 0 : sum_total_chunks / chunks); + return p - buf; +} + +static int zv_cumul_dist_counts_show(char *buf) +{ + unsigned long i, n, chunks = 0, sum_total_chunks = 0; + char *p = buf; + + for (i = 0; i < NCHUNKS; i++) { + n = atomic_read(&zv_cumul_dist_counts[i]); + p += sprintf(p, "%lu ", n); + chunks += n; + sum_total_chunks += i * n; + } + p += sprintf(p, "mean:%lu\n", + chunks == 0 ? 0 : sum_total_chunks / chunks); + return p - buf; +} + +/* + * setting zv_max_zsize via sysfs causes all persistent (e.g. swap) + * pages that don't compress to less than this value (including metadata + * overhead) to be rejected. We don't allow the value to get too close + * to PAGE_SIZE. + */ +static ssize_t zv_max_zsize_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", zv_max_zsize); +} + +static ssize_t zv_max_zsize_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned long val; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + err = kstrtoul(buf, 10, &val); + if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7)) + return -EINVAL; + zv_max_zsize = val; + return count; +} + +/* + * setting zv_max_mean_zsize via sysfs causes all persistent (e.g. swap) + * pages that don't compress to less than this value (including metadata + * overhead) to be rejected UNLESS the mean compression is also smaller + * than this value. In other words, we are load-balancing-by-zsize the + * accepted pages. Again, we don't allow the value to get too close + * to PAGE_SIZE. + */ +static ssize_t zv_max_mean_zsize_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", zv_max_mean_zsize); +} + +static ssize_t zv_max_mean_zsize_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned long val; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + err = kstrtoul(buf, 10, &val); + if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7)) + return -EINVAL; + zv_max_mean_zsize = val; + return count; +} + +/* + * setting zv_page_count_policy_percent via sysfs sets an upper bound of + * persistent (e.g. swap) pages that will be retained according to: + * (zv_page_count_policy_percent * totalram_pages) / 100) + * when that limit is reached, further puts will be rejected (until + * some pages have been flushed). Note that, due to compression, + * this number may exceed 100; it defaults to 75 and we set an + * arbitary limit of 150. A poor choice will almost certainly result + * in OOM's, so this value should only be changed prudently. + */ +static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", zv_page_count_policy_percent); +} + +static ssize_t zv_page_count_policy_percent_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned long val; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + err = kstrtoul(buf, 10, &val); + if (err || (val == 0) || (val > 150)) + return -EINVAL; + zv_page_count_policy_percent = val; + return count; +} + +static struct kobj_attribute zcache_zv_max_zsize_attr = { + .attr = { .name = "zv_max_zsize", .mode = 0644 }, + .show = zv_max_zsize_show, + .store = zv_max_zsize_store, +}; + +static struct kobj_attribute zcache_zv_max_mean_zsize_attr = { + .attr = { .name = "zv_max_mean_zsize", .mode = 0644 }, + .show = zv_max_mean_zsize_show, + .store = zv_max_mean_zsize_store, +}; + +static struct kobj_attribute zcache_zv_page_count_policy_percent_attr = { + .attr = { .name = "zv_page_count_policy_percent", + .mode = 0644 }, + .show = zv_page_count_policy_percent_show, + .store = zv_page_count_policy_percent_store, +}; +#endif + /* * zcache core code starts here */ @@ -677,51 +927,76 @@ static unsigned long zcache_flobj_found; static unsigned long zcache_failed_eph_puts; static unsigned long zcache_failed_pers_puts; -#define MAX_POOLS_PER_CLIENT 16 - -static struct { - struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT]; - struct xv_pool *xvpool; -} zcache_client; - /* * Tmem operations assume the poolid implies the invoking client. - * Zcache only has one client (the kernel itself), so translate - * the poolid into the tmem_pool allocated for it. A KVM version + * Zcache only has one client (the kernel itself): LOCAL_CLIENT. + * RAMster has each client numbered by cluster node, and a KVM version * of zcache would have one client per guest and each client might * have a poolid==N. */ -static struct tmem_pool *zcache_get_pool_by_id(uint32_t poolid) +static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid) { struct tmem_pool *pool = NULL; + struct zcache_client *cli = NULL; - if (poolid >= 0) { - pool = zcache_client.tmem_pools[poolid]; + if (cli_id == LOCAL_CLIENT) + cli = &zcache_host; + else { + if (cli_id >= MAX_CLIENTS) + goto out; + cli = &zcache_clients[cli_id]; + if (cli == NULL) + goto out; + atomic_inc(&cli->refcount); + } + if (poolid < MAX_POOLS_PER_CLIENT) { + pool = cli->tmem_pools[poolid]; if (pool != NULL) atomic_inc(&pool->refcount); } +out: return pool; } static void zcache_put_pool(struct tmem_pool *pool) { - if (pool != NULL) - atomic_dec(&pool->refcount); + struct zcache_client *cli = NULL; + + if (pool == NULL) + BUG(); + cli = pool->client; + atomic_dec(&pool->refcount); + atomic_dec(&cli->refcount); +} + +int zcache_new_client(uint16_t cli_id) +{ + struct zcache_client *cli = NULL; + int ret = -1; + + if (cli_id == LOCAL_CLIENT) + cli = &zcache_host; + else if ((unsigned int)cli_id < MAX_CLIENTS) + cli = &zcache_clients[cli_id]; + if (cli == NULL) + goto out; + if (cli->allocated) + goto out; + cli->allocated = 1; +#ifdef CONFIG_FRONTSWAP + cli->zspool = zs_create_pool("zcache", ZCACHE_GFP_MASK); + if (cli->zspool == NULL) + goto out; +#endif + ret = 0; +out: + return ret; } /* counters for debugging */ static unsigned long zcache_failed_get_free_pages; static unsigned long zcache_failed_alloc; static unsigned long zcache_put_to_flush; -static unsigned long zcache_aborted_preload; -static unsigned long zcache_aborted_shrink; - -/* - * Ensure that memory allocation requests in zcache don't result - * in direct reclaim requests via the shrinker, which would cause - * an infinite loop. Maybe a GFP flag would be better? - */ -static DEFINE_SPINLOCK(zcache_direct_reclaim_lock); /* * for now, used named slabs so can easily track usage; later can @@ -760,10 +1035,6 @@ static int zcache_do_preload(struct tmem_pool *pool) goto out; if (unlikely(zcache_obj_cache == NULL)) goto out; - if (!spin_trylock(&zcache_direct_reclaim_lock)) { - zcache_aborted_preload++; - goto out; - } preempt_disable(); kp = &__get_cpu_var(zcache_preloads); while (kp->nr < ARRAY_SIZE(kp->objnodes)) { @@ -772,7 +1043,7 @@ static int zcache_do_preload(struct tmem_pool *pool) ZCACHE_GFP_MASK); if (unlikely(objnode == NULL)) { zcache_failed_alloc++; - goto unlock_out; + goto out; } preempt_disable(); kp = &__get_cpu_var(zcache_preloads); @@ -785,13 +1056,13 @@ static int zcache_do_preload(struct tmem_pool *pool) obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK); if (unlikely(obj == NULL)) { zcache_failed_alloc++; - goto unlock_out; + goto out; } page = (void *)__get_free_page(ZCACHE_GFP_MASK); if (unlikely(page == NULL)) { zcache_failed_get_free_pages++; kmem_cache_free(zcache_obj_cache, obj); - goto unlock_out; + goto out; } preempt_disable(); kp = &__get_cpu_var(zcache_preloads); @@ -804,8 +1075,6 @@ static int zcache_do_preload(struct tmem_pool *pool) else free_page((unsigned long)page); ret = 0; -unlock_out: - spin_unlock(&zcache_direct_reclaim_lock); out: return ret; } @@ -899,50 +1168,63 @@ static atomic_t zcache_curr_pers_pampd_count = ATOMIC_INIT(0); static unsigned long zcache_curr_pers_pampd_count_max; /* forward reference */ -static int zcache_compress(struct page *from, void **out_va, size_t *out_len); +static int zcache_compress(struct page *from, void **out_va, unsigned *out_len); -static void *zcache_pampd_create(struct tmem_pool *pool, struct tmem_oid *oid, - uint32_t index, struct page *page) +static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph, + struct tmem_pool *pool, struct tmem_oid *oid, + uint32_t index) { void *pampd = NULL, *cdata; - size_t clen; + unsigned clen; int ret; - bool ephemeral = is_ephemeral(pool); unsigned long count; - - if (ephemeral) { + struct page *page = (struct page *)(data); + struct zcache_client *cli = pool->client; + uint16_t client_id = get_client_id_from_client(cli); + unsigned long zv_mean_zsize; + unsigned long curr_pers_pampd_count; + u64 total_zsize; + + if (eph) { ret = zcache_compress(page, &cdata, &clen); if (ret == 0) - goto out; if (clen == 0 || clen > zbud_max_buddy_size()) { zcache_compress_poor++; goto out; } - pampd = (void *)zbud_create(pool->pool_id, oid, index, - page, cdata, clen); + pampd = (void *)zbud_create(client_id, pool->pool_id, oid, + index, page, cdata, clen); if (pampd != NULL) { count = atomic_inc_return(&zcache_curr_eph_pampd_count); if (count > zcache_curr_eph_pampd_count_max) zcache_curr_eph_pampd_count_max = count; } } else { - /* - * FIXME: This is all the "policy" there is for now. - * 3/4 totpages should allow ~37% of RAM to be filled with - * compressed frontswap pages - */ - if (atomic_read(&zcache_curr_pers_pampd_count) > - 3 * totalram_pages / 4) + curr_pers_pampd_count = + atomic_read(&zcache_curr_pers_pampd_count); + if (curr_pers_pampd_count > + (zv_page_count_policy_percent * totalram_pages) / 100) goto out; ret = zcache_compress(page, &cdata, &clen); if (ret == 0) goto out; - if (clen > zv_max_page_size) { + /* reject if compression is too poor */ + if (clen > zv_max_zsize) { zcache_compress_poor++; goto out; } - pampd = (void *)zv_create(zcache_client.xvpool, pool->pool_id, + /* reject if mean compression is too poor */ + if ((clen > zv_max_mean_zsize) && (curr_pers_pampd_count > 0)) { + total_zsize = zs_get_total_pages(cli->zspool) << PAGE_SHIFT; + zv_mean_zsize = div_u64(total_zsize, + curr_pers_pampd_count); + if (zv_mean_zsize > zv_max_mean_zsize) { + zcache_mean_compress_poor++; + goto out; + } + } + pampd = (void *)zv_create(cli->zspool, pool->pool_id, oid, index, cdata, clen); if (pampd == NULL) goto out; @@ -958,64 +1240,104 @@ out: * fill the pageframe corresponding to the struct page with the data * from the passed pampd */ -static int zcache_pampd_get_data(struct page *page, void *pampd, - struct tmem_pool *pool) +static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw, + void *pampd, struct tmem_pool *pool, + struct tmem_oid *oid, uint32_t index) { int ret = 0; - if (is_ephemeral(pool)) - ret = zbud_decompress(page, pampd); - else - zv_decompress(page, pampd); + BUG_ON(is_ephemeral(pool)); + zv_decompress((struct page *)(data), (unsigned long)pampd); return ret; } /* + * fill the pageframe corresponding to the struct page with the data + * from the passed pampd + */ +static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw, + void *pampd, struct tmem_pool *pool, + struct tmem_oid *oid, uint32_t index) +{ + BUG_ON(!is_ephemeral(pool)); + if (zbud_decompress((struct page *)(data), pampd) < 0) + return -EINVAL; + zbud_free_and_delist((struct zbud_hdr *)pampd); + atomic_dec(&zcache_curr_eph_pampd_count); + return 0; +} + +/* * free the pampd and remove it from any zcache lists * pampd must no longer be pointed to from any tmem data structures! */ -static void zcache_pampd_free(void *pampd, struct tmem_pool *pool) +static void zcache_pampd_free(void *pampd, struct tmem_pool *pool, + struct tmem_oid *oid, uint32_t index) { + struct zcache_client *cli = pool->client; + if (is_ephemeral(pool)) { zbud_free_and_delist((struct zbud_hdr *)pampd); atomic_dec(&zcache_curr_eph_pampd_count); BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0); } else { - zv_free(zcache_client.xvpool, (struct zv_hdr *)pampd); + zv_free(cli->zspool, (unsigned long)pampd); atomic_dec(&zcache_curr_pers_pampd_count); BUG_ON(atomic_read(&zcache_curr_pers_pampd_count) < 0); } } +static void zcache_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj) +{ +} + +static void zcache_pampd_new_obj(struct tmem_obj *obj) +{ +} + +static int zcache_pampd_replace_in_obj(void *pampd, struct tmem_obj *obj) +{ + return -1; +} + +static bool zcache_pampd_is_remote(void *pampd) +{ + return 0; +} + static struct tmem_pamops zcache_pamops = { .create = zcache_pampd_create, .get_data = zcache_pampd_get_data, + .get_data_and_free = zcache_pampd_get_data_and_free, .free = zcache_pampd_free, + .free_obj = zcache_pampd_free_obj, + .new_obj = zcache_pampd_new_obj, + .replace_in_obj = zcache_pampd_replace_in_obj, + .is_remote = zcache_pampd_is_remote, }; /* * zcache compression/decompression and related per-cpu stuff */ -#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS -#define LZO_DSTMEM_PAGE_ORDER 1 -static DEFINE_PER_CPU(unsigned char *, zcache_workmem); static DEFINE_PER_CPU(unsigned char *, zcache_dstmem); +#define ZCACHE_DSTMEM_ORDER 1 -static int zcache_compress(struct page *from, void **out_va, size_t *out_len) +static int zcache_compress(struct page *from, void **out_va, unsigned *out_len) { int ret = 0; unsigned char *dmem = __get_cpu_var(zcache_dstmem); - unsigned char *wmem = __get_cpu_var(zcache_workmem); char *from_va; BUG_ON(!irqs_disabled()); - if (unlikely(dmem == NULL || wmem == NULL)) - goto out; /* no buffer, so can't compress */ + if (unlikely(dmem == NULL)) + goto out; /* no buffer or no compressor so can't compress */ + *out_len = PAGE_SIZE << ZCACHE_DSTMEM_ORDER; from_va = kmap_atomic(from, KM_USER0); mb(); - ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem); - BUG_ON(ret != LZO_E_OK); + ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem, + out_len); + BUG_ON(ret); *out_va = dmem; kunmap_atomic(from_va, KM_USER0); ret = 1; @@ -1023,29 +1345,48 @@ out: return ret; } +static int zcache_comp_cpu_up(int cpu) +{ + struct crypto_comp *tfm; + + tfm = crypto_alloc_comp(zcache_comp_name, 0, 0); + if (IS_ERR(tfm)) + return NOTIFY_BAD; + *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = tfm; + return NOTIFY_OK; +} + +static void zcache_comp_cpu_down(int cpu) +{ + struct crypto_comp *tfm; + + tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu); + crypto_free_comp(tfm); + *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = NULL; +} static int zcache_cpu_notifier(struct notifier_block *nb, unsigned long action, void *pcpu) { - int cpu = (long)pcpu; + int ret, cpu = (long)pcpu; struct zcache_preload *kp; switch (action) { case CPU_UP_PREPARE: + ret = zcache_comp_cpu_up(cpu); + if (ret != NOTIFY_OK) { + pr_err("zcache: can't allocate compressor transform\n"); + return ret; + } per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages( - GFP_KERNEL | __GFP_REPEAT, - LZO_DSTMEM_PAGE_ORDER), - per_cpu(zcache_workmem, cpu) = - kzalloc(LZO1X_MEM_COMPRESS, - GFP_KERNEL | __GFP_REPEAT); + GFP_KERNEL | __GFP_REPEAT, ZCACHE_DSTMEM_ORDER); break; case CPU_DEAD: case CPU_UP_CANCELED: + zcache_comp_cpu_down(cpu); free_pages((unsigned long)per_cpu(zcache_dstmem, cpu), - LZO_DSTMEM_PAGE_ORDER); + ZCACHE_DSTMEM_ORDER); per_cpu(zcache_dstmem, cpu) = NULL; - kfree(per_cpu(zcache_workmem, cpu)); - per_cpu(zcache_workmem, cpu) = NULL; kp = &per_cpu(zcache_preloads, cpu); while (kp->nr) { kmem_cache_free(zcache_objnode_cache, @@ -1053,8 +1394,14 @@ static int zcache_cpu_notifier(struct notifier_block *nb, kp->objnodes[kp->nr - 1] = NULL; kp->nr--; } - kmem_cache_free(zcache_obj_cache, kp->obj); - free_page((unsigned long)kp->page); + if (kp->obj) { + kmem_cache_free(zcache_obj_cache, kp->obj); + kp->obj = NULL; + } + if (kp->page) { + free_page((unsigned long)kp->page); + kp->page = NULL; + } break; default: break; @@ -1119,9 +1466,8 @@ ZCACHE_SYSFS_RO(evicted_buddied_pages); ZCACHE_SYSFS_RO(failed_get_free_pages); ZCACHE_SYSFS_RO(failed_alloc); ZCACHE_SYSFS_RO(put_to_flush); -ZCACHE_SYSFS_RO(aborted_preload); -ZCACHE_SYSFS_RO(aborted_shrink); ZCACHE_SYSFS_RO(compress_poor); +ZCACHE_SYSFS_RO(mean_compress_poor); ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages); ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages); ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count); @@ -1130,6 +1476,10 @@ ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts, zbud_show_unbuddied_list_counts); ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts, zbud_show_cumul_chunk_counts); +ZCACHE_SYSFS_RO_CUSTOM(zv_curr_dist_counts, + zv_curr_dist_counts_show); +ZCACHE_SYSFS_RO_CUSTOM(zv_cumul_dist_counts, + zv_cumul_dist_counts_show); static struct attribute *zcache_attrs[] = { &zcache_curr_obj_count_attr.attr, @@ -1143,6 +1493,7 @@ static struct attribute *zcache_attrs[] = { &zcache_failed_eph_puts_attr.attr, &zcache_failed_pers_puts_attr.attr, &zcache_compress_poor_attr.attr, + &zcache_mean_compress_poor_attr.attr, &zcache_zbud_curr_raw_pages_attr.attr, &zcache_zbud_curr_zpages_attr.attr, &zcache_zbud_curr_zbytes_attr.attr, @@ -1156,10 +1507,13 @@ static struct attribute *zcache_attrs[] = { &zcache_failed_get_free_pages_attr.attr, &zcache_failed_alloc_attr.attr, &zcache_put_to_flush_attr.attr, - &zcache_aborted_preload_attr.attr, - &zcache_aborted_shrink_attr.attr, &zcache_zbud_unbuddied_list_counts_attr.attr, &zcache_zbud_cumul_chunk_counts_attr.attr, + &zcache_zv_curr_dist_counts_attr.attr, + &zcache_zv_cumul_dist_counts_attr.attr, + &zcache_zv_max_zsize_attr.attr, + &zcache_zv_max_mean_zsize_attr.attr, + &zcache_zv_page_count_policy_percent_attr.attr, NULL, }; @@ -1192,11 +1546,7 @@ static int shrink_zcache_memory(struct shrinker *shrink, if (!(gfp_mask & __GFP_FS)) /* does this case really need to be skipped? */ goto out; - if (spin_trylock(&zcache_direct_reclaim_lock)) { - zbud_evict_pages(nr); - spin_unlock(&zcache_direct_reclaim_lock); - } else - zcache_aborted_shrink++; + zbud_evict_pages(nr); } ret = (int)atomic_read(&zcache_zbud_curr_raw_pages); out: @@ -1212,19 +1562,20 @@ static struct shrinker zcache_shrinker = { * zcache shims between cleancache/frontswap ops and tmem */ -static int zcache_put_page(int pool_id, struct tmem_oid *oidp, +static int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp, uint32_t index, struct page *page) { struct tmem_pool *pool; int ret = -1; BUG_ON(!irqs_disabled()); - pool = zcache_get_pool_by_id(pool_id); + pool = zcache_get_pool_by_id(cli_id, pool_id); if (unlikely(pool == NULL)) goto out; if (!zcache_freeze && zcache_do_preload(pool) == 0) { /* preload does preempt_disable on success */ - ret = tmem_put(pool, oidp, index, page); + ret = tmem_put(pool, oidp, index, (char *)(page), + PAGE_SIZE, 0, is_ephemeral(pool)); if (ret < 0) { if (is_ephemeral(pool)) zcache_failed_eph_puts++; @@ -1244,25 +1595,28 @@ out: return ret; } -static int zcache_get_page(int pool_id, struct tmem_oid *oidp, +static int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp, uint32_t index, struct page *page) { struct tmem_pool *pool; int ret = -1; unsigned long flags; + size_t size = PAGE_SIZE; local_irq_save(flags); - pool = zcache_get_pool_by_id(pool_id); + pool = zcache_get_pool_by_id(cli_id, pool_id); if (likely(pool != NULL)) { if (atomic_read(&pool->obj_count) > 0) - ret = tmem_get(pool, oidp, index, page); + ret = tmem_get(pool, oidp, index, (char *)(page), + &size, 0, is_ephemeral(pool)); zcache_put_pool(pool); } local_irq_restore(flags); return ret; } -static int zcache_flush_page(int pool_id, struct tmem_oid *oidp, uint32_t index) +static int zcache_flush_page(int cli_id, int pool_id, + struct tmem_oid *oidp, uint32_t index) { struct tmem_pool *pool; int ret = -1; @@ -1270,7 +1624,7 @@ static int zcache_flush_page(int pool_id, struct tmem_oid *oidp, uint32_t index) local_irq_save(flags); zcache_flush_total++; - pool = zcache_get_pool_by_id(pool_id); + pool = zcache_get_pool_by_id(cli_id, pool_id); if (likely(pool != NULL)) { if (atomic_read(&pool->obj_count) > 0) ret = tmem_flush_page(pool, oidp, index); @@ -1282,7 +1636,8 @@ static int zcache_flush_page(int pool_id, struct tmem_oid *oidp, uint32_t index) return ret; } -static int zcache_flush_object(int pool_id, struct tmem_oid *oidp) +static int zcache_flush_object(int cli_id, int pool_id, + struct tmem_oid *oidp) { struct tmem_pool *pool; int ret = -1; @@ -1290,7 +1645,7 @@ static int zcache_flush_object(int pool_id, struct tmem_oid *oidp) local_irq_save(flags); zcache_flobj_total++; - pool = zcache_get_pool_by_id(pool_id); + pool = zcache_get_pool_by_id(cli_id, pool_id); if (likely(pool != NULL)) { if (atomic_read(&pool->obj_count) > 0) ret = tmem_flush_object(pool, oidp); @@ -1302,42 +1657,60 @@ static int zcache_flush_object(int pool_id, struct tmem_oid *oidp) return ret; } -static int zcache_destroy_pool(int pool_id) +static int zcache_destroy_pool(int cli_id, int pool_id) { struct tmem_pool *pool = NULL; + struct zcache_client *cli = NULL; int ret = -1; if (pool_id < 0) goto out; - pool = zcache_client.tmem_pools[pool_id]; + if (cli_id == LOCAL_CLIENT) + cli = &zcache_host; + else if ((unsigned int)cli_id < MAX_CLIENTS) + cli = &zcache_clients[cli_id]; + if (cli == NULL) + goto out; + atomic_inc(&cli->refcount); + pool = cli->tmem_pools[pool_id]; if (pool == NULL) goto out; - zcache_client.tmem_pools[pool_id] = NULL; + cli->tmem_pools[pool_id] = NULL; /* wait for pool activity on other cpus to quiesce */ while (atomic_read(&pool->refcount) != 0) ; + atomic_dec(&cli->refcount); local_bh_disable(); ret = tmem_destroy_pool(pool); local_bh_enable(); kfree(pool); - pr_info("zcache: destroyed pool id=%d\n", pool_id); + pr_info("zcache: destroyed pool id=%d, cli_id=%d\n", + pool_id, cli_id); out: return ret; } -static int zcache_new_pool(uint32_t flags) +static int zcache_new_pool(uint16_t cli_id, uint32_t flags) { int poolid = -1; struct tmem_pool *pool; + struct zcache_client *cli = NULL; - pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL); + if (cli_id == LOCAL_CLIENT) + cli = &zcache_host; + else if ((unsigned int)cli_id < MAX_CLIENTS) + cli = &zcache_clients[cli_id]; + if (cli == NULL) + goto out; + atomic_inc(&cli->refcount); + pool = kmalloc(sizeof(struct tmem_pool), GFP_ATOMIC); if (pool == NULL) { pr_info("zcache: pool creation failed: out of memory\n"); goto out; } for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++) - if (zcache_client.tmem_pools[poolid] == NULL) + if (cli->tmem_pools[poolid] == NULL) break; if (poolid >= MAX_POOLS_PER_CLIENT) { pr_info("zcache: pool creation failed: max exceeded\n"); @@ -1346,14 +1719,16 @@ static int zcache_new_pool(uint32_t flags) goto out; } atomic_set(&pool->refcount, 0); - pool->client = &zcache_client; + pool->client = cli; pool->pool_id = poolid; tmem_new_pool(pool, flags); - zcache_client.tmem_pools[poolid] = pool; - pr_info("zcache: created %s tmem pool, id=%d\n", + cli->tmem_pools[poolid] = pool; + pr_info("zcache: created %s tmem pool, id=%d, client=%d\n", flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral", - poolid); + poolid, cli_id); out: + if (cli != NULL) + atomic_dec(&cli->refcount); return poolid; } @@ -1373,8 +1748,10 @@ static void zcache_cleancache_put_page(int pool_id, u32 ind = (u32) index; struct tmem_oid oid = *(struct tmem_oid *)&key; + if (!PageWasActive(page)) + return; if (likely(ind == index)) - (void)zcache_put_page(pool_id, &oid, index, page); + (void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index, page); } static int zcache_cleancache_get_page(int pool_id, @@ -1386,7 +1763,9 @@ static int zcache_cleancache_get_page(int pool_id, int ret = -1; if (likely(ind == index)) - ret = zcache_get_page(pool_id, &oid, index, page); + ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index, page); + if (ret == 0) + SetPageWasActive(page); return ret; } @@ -1398,7 +1777,7 @@ static void zcache_cleancache_flush_page(int pool_id, struct tmem_oid oid = *(struct tmem_oid *)&key; if (likely(ind == index)) - (void)zcache_flush_page(pool_id, &oid, ind); + (void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind); } static void zcache_cleancache_flush_inode(int pool_id, @@ -1406,13 +1785,13 @@ static void zcache_cleancache_flush_inode(int pool_id, { struct tmem_oid oid = *(struct tmem_oid *)&key; - (void)zcache_flush_object(pool_id, &oid); + (void)zcache_flush_object(LOCAL_CLIENT, pool_id, &oid); } static void zcache_cleancache_flush_fs(int pool_id) { if (pool_id >= 0) - (void)zcache_destroy_pool(pool_id); + (void)zcache_destroy_pool(LOCAL_CLIENT, pool_id); } static int zcache_cleancache_init_fs(size_t pagesize) @@ -1420,7 +1799,7 @@ static int zcache_cleancache_init_fs(size_t pagesize) BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid)); BUG_ON(pagesize != PAGE_SIZE); - return zcache_new_pool(0); + return zcache_new_pool(LOCAL_CLIENT, 0); } static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize) @@ -1429,15 +1808,15 @@ static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize) BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid)); BUG_ON(pagesize != PAGE_SIZE); - return zcache_new_pool(0); + return zcache_new_pool(LOCAL_CLIENT, 0); } static struct cleancache_ops zcache_cleancache_ops = { .put_page = zcache_cleancache_put_page, .get_page = zcache_cleancache_get_page, - .flush_page = zcache_cleancache_flush_page, - .flush_inode = zcache_cleancache_flush_inode, - .flush_fs = zcache_cleancache_flush_fs, + .invalidate_page = zcache_cleancache_flush_page, + .invalidate_inode = zcache_cleancache_flush_inode, + .invalidate_fs = zcache_cleancache_flush_fs, .init_shared_fs = zcache_cleancache_init_shared_fs, .init_fs = zcache_cleancache_init_fs }; @@ -1458,8 +1837,10 @@ static int zcache_frontswap_poolid = -1; /* * Swizzling increases objects per swaptype, increasing tmem concurrency * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS + * Setting SWIZ_BITS to 27 basically reconstructs the swap entry from + * frontswap_get_page(), but has side-effects. Hence using 8. */ -#define SWIZ_BITS 4 +#define SWIZ_BITS 8 #define SWIZ_MASK ((1 << SWIZ_BITS) - 1) #define _oswiz(_type, _ind) ((_type << SWIZ_BITS) | (_ind & SWIZ_MASK)) #define iswiz(_ind) (_ind >> SWIZ_BITS) @@ -1483,8 +1864,8 @@ static int zcache_frontswap_put_page(unsigned type, pgoff_t offset, BUG_ON(!PageLocked(page)); if (likely(ind64 == ind)) { local_irq_save(flags); - ret = zcache_put_page(zcache_frontswap_poolid, &oid, - iswiz(ind), page); + ret = zcache_put_page(LOCAL_CLIENT, zcache_frontswap_poolid, + &oid, iswiz(ind), page); local_irq_restore(flags); } return ret; @@ -1502,8 +1883,8 @@ static int zcache_frontswap_get_page(unsigned type, pgoff_t offset, BUG_ON(!PageLocked(page)); if (likely(ind64 == ind)) - ret = zcache_get_page(zcache_frontswap_poolid, &oid, - iswiz(ind), page); + ret = zcache_get_page(LOCAL_CLIENT, zcache_frontswap_poolid, + &oid, iswiz(ind), page); return ret; } @@ -1515,8 +1896,8 @@ static void zcache_frontswap_flush_page(unsigned type, pgoff_t offset) struct tmem_oid oid = oswiz(type, ind); if (likely(ind64 == ind)) - (void)zcache_flush_page(zcache_frontswap_poolid, &oid, - iswiz(ind)); + (void)zcache_flush_page(LOCAL_CLIENT, zcache_frontswap_poolid, + &oid, iswiz(ind)); } /* flush all pages from the passed swaptype */ @@ -1527,7 +1908,8 @@ static void zcache_frontswap_flush_area(unsigned type) for (ind = SWIZ_MASK; ind >= 0; ind--) { oid = oswiz(type, ind); - (void)zcache_flush_object(zcache_frontswap_poolid, &oid); + (void)zcache_flush_object(LOCAL_CLIENT, + zcache_frontswap_poolid, &oid); } } @@ -1535,14 +1917,15 @@ static void zcache_frontswap_init(unsigned ignored) { /* a single tmem poolid is used for all frontswap "types" (swapfiles) */ if (zcache_frontswap_poolid < 0) - zcache_frontswap_poolid = zcache_new_pool(TMEM_POOL_PERSIST); + zcache_frontswap_poolid = + zcache_new_pool(LOCAL_CLIENT, TMEM_POOL_PERSIST); } static struct frontswap_ops zcache_frontswap_ops = { .put_page = zcache_frontswap_put_page, .get_page = zcache_frontswap_get_page, - .flush_page = zcache_frontswap_flush_page, - .flush_area = zcache_frontswap_flush_area, + .invalidate_page = zcache_frontswap_flush_page, + .invalidate_area = zcache_frontswap_flush_area, .init = zcache_frontswap_init }; @@ -1592,11 +1975,49 @@ static int __init no_frontswap(char *s) __setup("nofrontswap", no_frontswap); +static int __init enable_zcache_compressor(char *s) +{ + strncpy(zcache_comp_name, s, ZCACHE_COMP_NAME_SZ); + zcache_enabled = 1; + return 1; +} +__setup("zcache=", enable_zcache_compressor); + + +static int zcache_comp_init(void) +{ + int ret = 0; + + /* check crypto algorithm */ + if (*zcache_comp_name != '\0') { + ret = crypto_has_comp(zcache_comp_name, 0, 0); + if (!ret) + pr_info("zcache: %s not supported\n", + zcache_comp_name); + } + if (!ret) + strcpy(zcache_comp_name, "lzo"); + ret = crypto_has_comp(zcache_comp_name, 0, 0); + if (!ret) { + ret = 1; + goto out; + } + pr_info("zcache: using %s compressor\n", zcache_comp_name); + + /* alloc percpu transforms */ + ret = 0; + zcache_comp_pcpu_tfms = alloc_percpu(struct crypto_comp *); + if (!zcache_comp_pcpu_tfms) + ret = 1; +out: + return ret; +} + static int __init zcache_init(void) { -#ifdef CONFIG_SYSFS int ret = 0; +#ifdef CONFIG_SYSFS ret = sysfs_create_group(mm_kobj, &zcache_attr_group); if (ret) { pr_err("zcache: can't create sysfs\n"); @@ -1614,6 +2035,11 @@ static int __init zcache_init(void) pr_err("zcache: can't register cpu notifier\n"); goto out; } + ret = zcache_comp_init(); + if (ret) { + pr_err("zcache: compressor initialization failed\n"); + goto out; + } for_each_online_cpu(cpu) { void *pcpu = (void *)(long)cpu; zcache_cpu_notifier(&zcache_cpu_notifier_block, @@ -1624,6 +2050,11 @@ static int __init zcache_init(void) sizeof(struct tmem_objnode), 0, 0, NULL); zcache_obj_cache = kmem_cache_create("zcache_obj", sizeof(struct tmem_obj), 0, 0, NULL); + ret = zcache_new_client(LOCAL_CLIENT); + if (ret) { + pr_err("zcache: can't create client\n"); + goto out; + } #endif #ifdef CONFIG_CLEANCACHE if (zcache_enabled && use_cleancache) { @@ -1642,16 +2073,11 @@ static int __init zcache_init(void) if (zcache_enabled && use_frontswap) { struct frontswap_ops old_ops; - zcache_client.xvpool = xv_create_pool(); - if (zcache_client.xvpool == NULL) { - pr_err("zcache: can't create xvpool\n"); - goto out; - } old_ops = zcache_frontswap_register_ops(); pr_info("zcache: frontswap enabled using kernel " - "transcendent memory and xvmalloc\n"); + "transcendent memory and zsmalloc\n"); if (old_ops.init != NULL) - pr_warning("ktmem: frontswap_ops overridden"); + pr_warning("zcache: frontswap_ops overridden"); } #endif out: diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile deleted file mode 100644 index 2a6d321..0000000 --- a/drivers/staging/zram/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -zram-y := zram_drv.o zram_sysfs.o - -obj-$(CONFIG_ZRAM) += zram.o -obj-$(CONFIG_XVMALLOC) += xvmalloc.o
\ No newline at end of file diff --git a/drivers/staging/zram/xvmalloc.c b/drivers/staging/zram/xvmalloc.c deleted file mode 100644 index 1f9c508..0000000 --- a/drivers/staging/zram/xvmalloc.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * xvmalloc memory allocator - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - */ - -#ifdef CONFIG_ZRAM_DEBUG -#define DEBUG -#endif - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/bitops.h> -#include <linux/errno.h> -#include <linux/highmem.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/slab.h> - -#include "xvmalloc.h" -#include "xvmalloc_int.h" - -static void stat_inc(u64 *value) -{ - *value = *value + 1; -} - -static void stat_dec(u64 *value) -{ - *value = *value - 1; -} - -static int test_flag(struct block_header *block, enum blockflags flag) -{ - return block->prev & BIT(flag); -} - -static void set_flag(struct block_header *block, enum blockflags flag) -{ - block->prev |= BIT(flag); -} - -static void clear_flag(struct block_header *block, enum blockflags flag) -{ - block->prev &= ~BIT(flag); -} - -/* - * Given <page, offset> pair, provide a dereferencable pointer. - * This is called from xv_malloc/xv_free path, so it - * needs to be fast. - */ -static void *get_ptr_atomic(struct page *page, u16 offset, enum km_type type) -{ - unsigned char *base; - - base = kmap_atomic(page, type); - return base + offset; -} - -static void put_ptr_atomic(void *ptr, enum km_type type) -{ - kunmap_atomic(ptr, type); -} - -static u32 get_blockprev(struct block_header *block) -{ - return block->prev & PREV_MASK; -} - -static void set_blockprev(struct block_header *block, u16 new_offset) -{ - block->prev = new_offset | (block->prev & FLAGS_MASK); -} - -static struct block_header *BLOCK_NEXT(struct block_header *block) -{ - return (struct block_header *) - ((char *)block + block->size + XV_ALIGN); -} - -/* - * Get index of free list containing blocks of maximum size - * which is less than or equal to given size. - */ -static u32 get_index_for_insert(u32 size) -{ - if (unlikely(size > XV_MAX_ALLOC_SIZE)) - size = XV_MAX_ALLOC_SIZE; - size &= ~FL_DELTA_MASK; - return (size - XV_MIN_ALLOC_SIZE) >> FL_DELTA_SHIFT; -} - -/* - * Get index of free list having blocks of size greater than - * or equal to requested size. - */ -static u32 get_index(u32 size) -{ - if (unlikely(size < XV_MIN_ALLOC_SIZE)) - size = XV_MIN_ALLOC_SIZE; - size = ALIGN(size, FL_DELTA); - return (size - XV_MIN_ALLOC_SIZE) >> FL_DELTA_SHIFT; -} - -/** - * find_block - find block of at least given size - * @pool: memory pool to search from - * @size: size of block required - * @page: page containing required block - * @offset: offset within the page where block is located. - * - * Searches two level bitmap to locate block of at least - * the given size. If such a block is found, it provides - * <page, offset> to identify this block and returns index - * in freelist where we found this block. - * Otherwise, returns 0 and <page, offset> params are not touched. - */ -static u32 find_block(struct xv_pool *pool, u32 size, - struct page **page, u32 *offset) -{ - ulong flbitmap, slbitmap; - u32 flindex, slindex, slbitstart; - - /* There are no free blocks in this pool */ - if (!pool->flbitmap) - return 0; - - /* Get freelist index correspoding to this size */ - slindex = get_index(size); - slbitmap = pool->slbitmap[slindex / BITS_PER_LONG]; - slbitstart = slindex % BITS_PER_LONG; - - /* - * If freelist is not empty at this index, we found the - * block - head of this list. This is approximate best-fit match. - */ - if (test_bit(slbitstart, &slbitmap)) { - *page = pool->freelist[slindex].page; - *offset = pool->freelist[slindex].offset; - return slindex; - } - - /* - * No best-fit found. Search a bit further in bitmap for a free block. - * Second level bitmap consists of series of 32-bit chunks. Search - * further in the chunk where we expected a best-fit, starting from - * index location found above. - */ - slbitstart++; - slbitmap >>= slbitstart; - - /* Skip this search if we were already at end of this bitmap chunk */ - if ((slbitstart != BITS_PER_LONG) && slbitmap) { - slindex += __ffs(slbitmap) + 1; - *page = pool->freelist[slindex].page; - *offset = pool->freelist[slindex].offset; - return slindex; - } - - /* Now do a full two-level bitmap search to find next nearest fit */ - flindex = slindex / BITS_PER_LONG; - - flbitmap = (pool->flbitmap) >> (flindex + 1); - if (!flbitmap) - return 0; - - flindex += __ffs(flbitmap) + 1; - slbitmap = pool->slbitmap[flindex]; - slindex = (flindex * BITS_PER_LONG) + __ffs(slbitmap); - *page = pool->freelist[slindex].page; - *offset = pool->freelist[slindex].offset; - - return slindex; -} - -/* - * Insert block at <page, offset> in freelist of given pool. - * freelist used depends on block size. - */ -static void insert_block(struct xv_pool *pool, struct page *page, u32 offset, - struct block_header *block) -{ - u32 flindex, slindex; - struct block_header *nextblock; - - slindex = get_index_for_insert(block->size); - flindex = slindex / BITS_PER_LONG; - - block->link.prev_page = NULL; - block->link.prev_offset = 0; - block->link.next_page = pool->freelist[slindex].page; - block->link.next_offset = pool->freelist[slindex].offset; - pool->freelist[slindex].page = page; - pool->freelist[slindex].offset = offset; - - if (block->link.next_page) { - nextblock = get_ptr_atomic(block->link.next_page, - block->link.next_offset, KM_USER1); - nextblock->link.prev_page = page; - nextblock->link.prev_offset = offset; - put_ptr_atomic(nextblock, KM_USER1); - /* If there was a next page then the free bits are set. */ - return; - } - - __set_bit(slindex % BITS_PER_LONG, &pool->slbitmap[flindex]); - __set_bit(flindex, &pool->flbitmap); -} - -/* - * Remove block from freelist. Index 'slindex' identifies the freelist. - */ -static void remove_block(struct xv_pool *pool, struct page *page, u32 offset, - struct block_header *block, u32 slindex) -{ - u32 flindex = slindex / BITS_PER_LONG; - struct block_header *tmpblock; - - if (block->link.prev_page) { - tmpblock = get_ptr_atomic(block->link.prev_page, - block->link.prev_offset, KM_USER1); - tmpblock->link.next_page = block->link.next_page; - tmpblock->link.next_offset = block->link.next_offset; - put_ptr_atomic(tmpblock, KM_USER1); - } - - if (block->link.next_page) { - tmpblock = get_ptr_atomic(block->link.next_page, - block->link.next_offset, KM_USER1); - tmpblock->link.prev_page = block->link.prev_page; - tmpblock->link.prev_offset = block->link.prev_offset; - put_ptr_atomic(tmpblock, KM_USER1); - } - - /* Is this block is at the head of the freelist? */ - if (pool->freelist[slindex].page == page - && pool->freelist[slindex].offset == offset) { - - pool->freelist[slindex].page = block->link.next_page; - pool->freelist[slindex].offset = block->link.next_offset; - - if (pool->freelist[slindex].page) { - struct block_header *tmpblock; - tmpblock = get_ptr_atomic(pool->freelist[slindex].page, - pool->freelist[slindex].offset, - KM_USER1); - tmpblock->link.prev_page = NULL; - tmpblock->link.prev_offset = 0; - put_ptr_atomic(tmpblock, KM_USER1); - } else { - /* This freelist bucket is empty */ - __clear_bit(slindex % BITS_PER_LONG, - &pool->slbitmap[flindex]); - if (!pool->slbitmap[flindex]) - __clear_bit(flindex, &pool->flbitmap); - } - } - - block->link.prev_page = NULL; - block->link.prev_offset = 0; - block->link.next_page = NULL; - block->link.next_offset = 0; -} - -/* - * Allocate a page and add it to freelist of given pool. - */ -static int grow_pool(struct xv_pool *pool, gfp_t flags) -{ - struct page *page; - struct block_header *block; - - page = alloc_page(flags); - if (unlikely(!page)) - return -ENOMEM; - - stat_inc(&pool->total_pages); - - spin_lock(&pool->lock); - block = get_ptr_atomic(page, 0, KM_USER0); - - block->size = PAGE_SIZE - XV_ALIGN; - set_flag(block, BLOCK_FREE); - clear_flag(block, PREV_FREE); - set_blockprev(block, 0); - - insert_block(pool, page, 0, block); - - put_ptr_atomic(block, KM_USER0); - spin_unlock(&pool->lock); - - return 0; -} - -/* - * Create a memory pool. Allocates freelist, bitmaps and other - * per-pool metadata. - */ -struct xv_pool *xv_create_pool(void) -{ - u32 ovhd_size; - struct xv_pool *pool; - - ovhd_size = roundup(sizeof(*pool), PAGE_SIZE); - pool = kzalloc(ovhd_size, GFP_KERNEL); - if (!pool) - return NULL; - - spin_lock_init(&pool->lock); - - return pool; -} -EXPORT_SYMBOL_GPL(xv_create_pool); - -void xv_destroy_pool(struct xv_pool *pool) -{ - kfree(pool); -} -EXPORT_SYMBOL_GPL(xv_destroy_pool); - -/** - * xv_malloc - Allocate block of given size from pool. - * @pool: pool to allocate from - * @size: size of block to allocate - * @page: page no. that holds the object - * @offset: location of object within page - * - * On success, <page, offset> identifies block allocated - * and 0 is returned. On failure, <page, offset> is set to - * 0 and -ENOMEM is returned. - * - * Allocation requests with size > XV_MAX_ALLOC_SIZE will fail. - */ -int xv_malloc(struct xv_pool *pool, u32 size, struct page **page, - u32 *offset, gfp_t flags) -{ - int error; - u32 index, tmpsize, origsize, tmpoffset; - struct block_header *block, *tmpblock; - - *page = NULL; - *offset = 0; - origsize = size; - - if (unlikely(!size || size > XV_MAX_ALLOC_SIZE)) - return -ENOMEM; - - size = ALIGN(size, XV_ALIGN); - - spin_lock(&pool->lock); - - index = find_block(pool, size, page, offset); - - if (!*page) { - spin_unlock(&pool->lock); - if (flags & GFP_NOWAIT) - return -ENOMEM; - error = grow_pool(pool, flags); - if (unlikely(error)) - return error; - - spin_lock(&pool->lock); - index = find_block(pool, size, page, offset); - } - - if (!*page) { - spin_unlock(&pool->lock); - return -ENOMEM; - } - - block = get_ptr_atomic(*page, *offset, KM_USER0); - - remove_block(pool, *page, *offset, block, index); - - /* Split the block if required */ - tmpoffset = *offset + size + XV_ALIGN; - tmpsize = block->size - size; - tmpblock = (struct block_header *)((char *)block + size + XV_ALIGN); - if (tmpsize) { - tmpblock->size = tmpsize - XV_ALIGN; - set_flag(tmpblock, BLOCK_FREE); - clear_flag(tmpblock, PREV_FREE); - - set_blockprev(tmpblock, *offset); - if (tmpblock->size >= XV_MIN_ALLOC_SIZE) - insert_block(pool, *page, tmpoffset, tmpblock); - - if (tmpoffset + XV_ALIGN + tmpblock->size != PAGE_SIZE) { - tmpblock = BLOCK_NEXT(tmpblock); - set_blockprev(tmpblock, tmpoffset); - } - } else { - /* This block is exact fit */ - if (tmpoffset != PAGE_SIZE) - clear_flag(tmpblock, PREV_FREE); - } - - block->size = origsize; - clear_flag(block, BLOCK_FREE); - - put_ptr_atomic(block, KM_USER0); - spin_unlock(&pool->lock); - - *offset += XV_ALIGN; - - return 0; -} -EXPORT_SYMBOL_GPL(xv_malloc); - -/* - * Free block identified with <page, offset> - */ -void xv_free(struct xv_pool *pool, struct page *page, u32 offset) -{ - void *page_start; - struct block_header *block, *tmpblock; - - offset -= XV_ALIGN; - - spin_lock(&pool->lock); - - page_start = get_ptr_atomic(page, 0, KM_USER0); - block = (struct block_header *)((char *)page_start + offset); - - /* Catch double free bugs */ - BUG_ON(test_flag(block, BLOCK_FREE)); - - block->size = ALIGN(block->size, XV_ALIGN); - - tmpblock = BLOCK_NEXT(block); - if (offset + block->size + XV_ALIGN == PAGE_SIZE) - tmpblock = NULL; - - /* Merge next block if its free */ - if (tmpblock && test_flag(tmpblock, BLOCK_FREE)) { - /* - * Blocks smaller than XV_MIN_ALLOC_SIZE - * are not inserted in any free list. - */ - if (tmpblock->size >= XV_MIN_ALLOC_SIZE) { - remove_block(pool, page, - offset + block->size + XV_ALIGN, tmpblock, - get_index_for_insert(tmpblock->size)); - } - block->size += tmpblock->size + XV_ALIGN; - } - - /* Merge previous block if its free */ - if (test_flag(block, PREV_FREE)) { - tmpblock = (struct block_header *)((char *)(page_start) + - get_blockprev(block)); - offset = offset - tmpblock->size - XV_ALIGN; - - if (tmpblock->size >= XV_MIN_ALLOC_SIZE) - remove_block(pool, page, offset, tmpblock, - get_index_for_insert(tmpblock->size)); - - tmpblock->size += block->size + XV_ALIGN; - block = tmpblock; - } - - /* No used objects in this page. Free it. */ - if (block->size == PAGE_SIZE - XV_ALIGN) { - put_ptr_atomic(page_start, KM_USER0); - spin_unlock(&pool->lock); - - __free_page(page); - stat_dec(&pool->total_pages); - return; - } - - set_flag(block, BLOCK_FREE); - if (block->size >= XV_MIN_ALLOC_SIZE) - insert_block(pool, page, offset, block); - - if (offset + block->size + XV_ALIGN != PAGE_SIZE) { - tmpblock = BLOCK_NEXT(block); - set_flag(tmpblock, PREV_FREE); - set_blockprev(tmpblock, offset); - } - - put_ptr_atomic(page_start, KM_USER0); - spin_unlock(&pool->lock); -} -EXPORT_SYMBOL_GPL(xv_free); - -u32 xv_get_object_size(void *obj) -{ - struct block_header *blk; - - blk = (struct block_header *)((char *)(obj) - XV_ALIGN); - return blk->size; -} -EXPORT_SYMBOL_GPL(xv_get_object_size); - -/* - * Returns total memory used by allocator (userdata + metadata) - */ -u64 xv_get_total_size_bytes(struct xv_pool *pool) -{ - return pool->total_pages << PAGE_SHIFT; -} -EXPORT_SYMBOL_GPL(xv_get_total_size_bytes); diff --git a/drivers/staging/zram/xvmalloc.h b/drivers/staging/zram/xvmalloc.h deleted file mode 100644 index 5b1a81a..0000000 --- a/drivers/staging/zram/xvmalloc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * xvmalloc memory allocator - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - */ - -#ifndef _XV_MALLOC_H_ -#define _XV_MALLOC_H_ - -#include <linux/types.h> - -struct xv_pool; - -struct xv_pool *xv_create_pool(void); -void xv_destroy_pool(struct xv_pool *pool); - -int xv_malloc(struct xv_pool *pool, u32 size, struct page **page, - u32 *offset, gfp_t flags); -void xv_free(struct xv_pool *pool, struct page *page, u32 offset); - -u32 xv_get_object_size(void *obj); -u64 xv_get_total_size_bytes(struct xv_pool *pool); - -#endif diff --git a/drivers/staging/zram/xvmalloc_int.h b/drivers/staging/zram/xvmalloc_int.h deleted file mode 100644 index b5f1f7f..0000000 --- a/drivers/staging/zram/xvmalloc_int.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * xvmalloc memory allocator - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - */ - -#ifndef _XV_MALLOC_INT_H_ -#define _XV_MALLOC_INT_H_ - -#include <linux/kernel.h> -#include <linux/types.h> - -/* User configurable params */ - -/* Must be power of two */ -#ifdef CONFIG_64BIT -#define XV_ALIGN_SHIFT 3 -#else -#define XV_ALIGN_SHIFT 2 -#endif -#define XV_ALIGN (1 << XV_ALIGN_SHIFT) -#define XV_ALIGN_MASK (XV_ALIGN - 1) - -/* This must be greater than sizeof(link_free) */ -#define XV_MIN_ALLOC_SIZE 32 -#define XV_MAX_ALLOC_SIZE (PAGE_SIZE - XV_ALIGN) - -/* - * Free lists are separated by FL_DELTA bytes - * This value is 3 for 4k pages and 4 for 64k pages, for any - * other page size, a conservative (PAGE_SHIFT - 9) is used. - */ -#if PAGE_SHIFT == 16 -#define FL_DELTA_SHIFT 4 -#else -#define FL_DELTA_SHIFT (PAGE_SHIFT - 9) -#endif -#define FL_DELTA (1 << FL_DELTA_SHIFT) -#define FL_DELTA_MASK (FL_DELTA - 1) -#define NUM_FREE_LISTS ((XV_MAX_ALLOC_SIZE - XV_MIN_ALLOC_SIZE) \ - / FL_DELTA + 1) - -#define MAX_FLI DIV_ROUND_UP(NUM_FREE_LISTS, BITS_PER_LONG) - -/* End of user params */ - -enum blockflags { - BLOCK_FREE, - PREV_FREE, - __NR_BLOCKFLAGS, -}; - -#define FLAGS_MASK XV_ALIGN_MASK -#define PREV_MASK (~FLAGS_MASK) - -struct freelist_entry { - struct page *page; - u16 offset; - u16 pad; -}; - -struct link_free { - struct page *prev_page; - struct page *next_page; - u16 prev_offset; - u16 next_offset; -}; - -struct block_header { - union { - /* This common header must be XV_ALIGN bytes */ - u8 common[XV_ALIGN]; - struct { - u16 size; - u16 prev; - }; - }; - struct link_free link; -}; - -struct xv_pool { - ulong flbitmap; - ulong slbitmap[MAX_FLI]; - u64 total_pages; /* stats */ - struct freelist_entry freelist[NUM_FREE_LISTS]; - spinlock_t lock; -}; - -#endif diff --git a/drivers/staging/zram/zram.txt b/drivers/staging/zram/zram.txt deleted file mode 100644 index 5f75d29..0000000 --- a/drivers/staging/zram/zram.txt +++ /dev/null @@ -1,76 +0,0 @@ -zram: Compressed RAM based block devices ----------------------------------------- - -Project home: http://compcache.googlecode.com/ - -* Introduction - -The zram module creates RAM based block devices named /dev/zram<id> -(<id> = 0, 1, ...). Pages written to these disks are compressed and stored -in memory itself. These disks allow very fast I/O and compression provides -good amounts of memory savings. Some of the usecases include /tmp storage, -use as swap disks, various caches under /var and maybe many more :) - -Statistics for individual zram devices are exported through sysfs nodes at -/sys/block/zram<id>/ - -* Usage - -Following shows a typical sequence of steps for using zram. - -1) Load Module: - modprobe zram num_devices=4 - This creates 4 devices: /dev/zram{0,1,2,3} - (num_devices parameter is optional. Default: 1) - -2) Set Disksize (Optional): - Set disk size by writing the value to sysfs node 'disksize' - (in bytes). If disksize is not given, default value of 25% - of RAM is used. - - # Initialize /dev/zram0 with 50MB disksize - echo $((50*1024*1024)) > /sys/block/zram0/disksize - - NOTE: disksize cannot be changed if the disk contains any - data. So, for such a disk, you need to issue 'reset' (see below) - before you can change its disksize. - -3) Activate: - mkswap /dev/zram0 - swapon /dev/zram0 - - mkfs.ext4 /dev/zram1 - mount /dev/zram1 /tmp - -4) Stats: - Per-device statistics are exported as various nodes under - /sys/block/zram<id>/ - disksize - num_reads - num_writes - invalid_io - notify_free - discard - zero_pages - orig_data_size - compr_data_size - mem_used_total - -5) Deactivate: - swapoff /dev/zram0 - umount /dev/zram1 - -6) Reset: - Write any positive value to 'reset' sysfs node - echo 1 > /sys/block/zram0/reset - echo 1 > /sys/block/zram1/reset - - (This frees all the memory allocated for the given device). - - -Please report any problems at: - - Mailing list: linux-mm-cc at laptop dot org - - Issue tracker: http://code.google.com/p/compcache/issues/list - -Nitin Gupta -ngupta@vflare.org diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c deleted file mode 100644 index 5258c78..0000000 --- a/drivers/staging/zram/zram_drv.c +++ /dev/null @@ -1,769 +0,0 @@ -/* - * Compressed RAM block device - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - * - * Project home: http://compcache.googlecode.com - */ - -#define KMSG_COMPONENT "zram" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt - -#ifdef CONFIG_ZRAM_DEBUG -#define DEBUG -#endif - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/bio.h> -#include <linux/bitops.h> -#include <linux/blkdev.h> -#include <linux/buffer_head.h> -#include <linux/device.h> -#include <linux/genhd.h> -#include <linux/highmem.h> -#include <linux/slab.h> -#include <linux/lzo.h> -#include <linux/string.h> -#include <linux/vmalloc.h> -#ifdef CONFIG_ZRAM_FOR_ANDROID -#include <linux/swap.h> -#endif /* CONFIG_ZRAM_FOR_ANDROID */ - - -#include "zram_drv.h" - -/* Globals */ -static int zram_major; -struct zram *zram_devices; - -/* Module params (documentation at end) */ -unsigned int num_devices; - -static void zram_stat_inc(u32 *v) -{ - *v = *v + 1; -} - -static void zram_stat_dec(u32 *v) -{ - *v = *v - 1; -} - -static void zram_stat64_add(struct zram *zram, u64 *v, u64 inc) -{ - spin_lock(&zram->stat64_lock); - *v = *v + inc; - spin_unlock(&zram->stat64_lock); -} - -static void zram_stat64_sub(struct zram *zram, u64 *v, u64 dec) -{ - spin_lock(&zram->stat64_lock); - *v = *v - dec; - spin_unlock(&zram->stat64_lock); -} - -static void zram_stat64_inc(struct zram *zram, u64 *v) -{ - zram_stat64_add(zram, v, 1); -} - -static int zram_test_flag(struct zram *zram, u32 index, - enum zram_pageflags flag) -{ - return zram->table[index].flags & BIT(flag); -} - -static void zram_set_flag(struct zram *zram, u32 index, - enum zram_pageflags flag) -{ - zram->table[index].flags |= BIT(flag); -} - -static void zram_clear_flag(struct zram *zram, u32 index, - enum zram_pageflags flag) -{ - zram->table[index].flags &= ~BIT(flag); -} - -static int page_zero_filled(void *ptr) -{ - unsigned int pos; - unsigned long *page; - - page = (unsigned long *)ptr; - - for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) { - if (page[pos]) - return 0; - } - - return 1; -} - -static void zram_set_disksize(struct zram *zram, size_t totalram_bytes) -{ - if (!zram->disksize) { - pr_info( - "disk size not provided. You can use disksize_kb module " - "param to specify size.\nUsing default: (%u%% of RAM).\n", - default_disksize_perc_ram - ); - zram->disksize = default_disksize_perc_ram * - (totalram_bytes / 100); - } - - if (zram->disksize > 2 * (totalram_bytes)) { - pr_info( - "There is little point creating a zram of greater than " - "twice the size of memory since we expect a 2:1 compression " - "ratio. Note that zram uses about 0.1%% of the size of " - "the disk when not in use so a huge zram is " - "wasteful.\n" - "\tMemory Size: %zu kB\n" - "\tSize you selected: %llu kB\n" - "Continuing anyway ...\n", - totalram_bytes >> 10, zram->disksize - ); - } - - zram->disksize &= PAGE_MASK; -} - -#ifdef CONFIG_ZRAM_FOR_ANDROID -/* - * Swap header (1st page of swap device) contains information - * about a swap file/partition. Prepare such a header for the - * given ramzswap device so that swapon can identify it as a - * swap partition. - */ -static void setup_swap_header(struct zram *zram, union swap_header *s) -{ - s->info.version = 1; - s->info.last_page = (zram->disksize >> PAGE_SHIFT) - 1; - s->info.nr_badpages = 0; - memcpy(s->magic.magic, "SWAPSPACE2", 10); -} -#endif /* CONFIG_ZRAM_FOR_ANDROID */ - -static void zram_free_page(struct zram *zram, size_t index) -{ - u32 clen; - void *obj; - - struct page *page = zram->table[index].page; - u32 offset = zram->table[index].offset; - - if (unlikely(!page)) { - /* - * No memory is allocated for zero filled pages. - * Simply clear zero page flag. - */ - if (zram_test_flag(zram, index, ZRAM_ZERO)) { - zram_clear_flag(zram, index, ZRAM_ZERO); - zram_stat_dec(&zram->stats.pages_zero); - } - return; - } - - if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) { - clen = PAGE_SIZE; - __free_page(page); - zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED); - zram_stat_dec(&zram->stats.pages_expand); - goto out; - } - - obj = kmap_atomic(page, KM_USER0) + offset; - clen = xv_get_object_size(obj) - sizeof(struct zobj_header); - kunmap_atomic(obj, KM_USER0); - - xv_free(zram->mem_pool, page, offset); - if (clen <= PAGE_SIZE / 2) - zram_stat_dec(&zram->stats.good_compress); - -out: - zram_stat64_sub(zram, &zram->stats.compr_size, clen); - zram_stat_dec(&zram->stats.pages_stored); - - zram->table[index].page = NULL; - zram->table[index].offset = 0; -} - -static void handle_zero_page(struct page *page) -{ - void *user_mem; - - user_mem = kmap_atomic(page, KM_USER0); - memset(user_mem, 0, PAGE_SIZE); - kunmap_atomic(user_mem, KM_USER0); - - flush_dcache_page(page); -} - -static void handle_uncompressed_page(struct zram *zram, - struct page *page, u32 index) -{ - unsigned char *user_mem, *cmem; - - user_mem = kmap_atomic(page, KM_USER0); - cmem = kmap_atomic(zram->table[index].page, KM_USER1) + - zram->table[index].offset; - - memcpy(user_mem, cmem, PAGE_SIZE); - kunmap_atomic(user_mem, KM_USER0); - kunmap_atomic(cmem, KM_USER1); - - flush_dcache_page(page); -} - -static void zram_read(struct zram *zram, struct bio *bio) -{ - - int i; - u32 index; - struct bio_vec *bvec; - - zram_stat64_inc(zram, &zram->stats.num_reads); - index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT; - - bio_for_each_segment(bvec, bio, i) { - int ret; - size_t clen; - struct page *page; - struct zobj_header *zheader; - unsigned char *user_mem, *cmem; - - page = bvec->bv_page; - - if (zram_test_flag(zram, index, ZRAM_ZERO)) { - handle_zero_page(page); - index++; - continue; - } - - /* Requested page is not present in compressed area */ - if (unlikely(!zram->table[index].page)) { - pr_debug("Read before write: sector=%lu, size=%u", - (ulong)(bio->bi_sector), bio->bi_size); - handle_zero_page(page); - index++; - continue; - } - - /* Page is stored uncompressed since it's incompressible */ - if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) { - handle_uncompressed_page(zram, page, index); - index++; - continue; - } - - user_mem = kmap_atomic(page, KM_USER0); - clen = PAGE_SIZE; - - cmem = kmap_atomic(zram->table[index].page, KM_USER1) + - zram->table[index].offset; - - ret = lzo1x_decompress_safe( - cmem + sizeof(*zheader), - xv_get_object_size(cmem) - sizeof(*zheader), - user_mem, &clen); - - kunmap_atomic(user_mem, KM_USER0); - kunmap_atomic(cmem, KM_USER1); - - /* Should NEVER happen. Return bio error if it does. */ - if (unlikely(ret != LZO_E_OK)) { - pr_err("Decompression failed! err=%d, page=%u\n", - ret, index); - zram_stat64_inc(zram, &zram->stats.failed_reads); - goto out; - } - - flush_dcache_page(page); - index++; - } - - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_endio(bio, 0); - return; - -out: - bio_io_error(bio); -} - -static void zram_write(struct zram *zram, struct bio *bio) -{ - int i; - u32 index; - struct bio_vec *bvec; - - zram_stat64_inc(zram, &zram->stats.num_writes); - index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT; - - bio_for_each_segment(bvec, bio, i) { - int ret; - u32 offset; - size_t clen; - struct zobj_header *zheader; - struct page *page, *page_store; - unsigned char *user_mem, *cmem, *src; - - page = bvec->bv_page; - src = zram->compress_buffer; - - /* - * System overwrites unused sectors. Free memory associated - * with this sector now. - */ - if (zram->table[index].page || - zram_test_flag(zram, index, ZRAM_ZERO)) - zram_free_page(zram, index); - - mutex_lock(&zram->lock); - - user_mem = kmap_atomic(page, KM_USER0); - if (page_zero_filled(user_mem)) { - kunmap_atomic(user_mem, KM_USER0); - mutex_unlock(&zram->lock); - zram_stat_inc(&zram->stats.pages_zero); - zram_set_flag(zram, index, ZRAM_ZERO); - index++; - continue; - } - - ret = lzo1x_1_compress(user_mem, PAGE_SIZE, src, &clen, - zram->compress_workmem); - - kunmap_atomic(user_mem, KM_USER0); - - if (unlikely(ret != LZO_E_OK)) { - mutex_unlock(&zram->lock); - pr_err("Compression failed! err=%d\n", ret); - zram_stat64_inc(zram, &zram->stats.failed_writes); - goto out; - } - - /* - * Page is incompressible. Store it as-is (uncompressed) - * since we do not want to return too many disk write - * errors which has side effect of hanging the system. - */ - if (unlikely(clen > max_zpage_size)) { - clen = PAGE_SIZE; - page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM); - if (unlikely(!page_store)) { - mutex_unlock(&zram->lock); - pr_info("Error allocating memory for " - "incompressible page: %u\n", index); - zram_stat64_inc(zram, - &zram->stats.failed_writes); - goto out; - } - - offset = 0; - zram_set_flag(zram, index, ZRAM_UNCOMPRESSED); - zram_stat_inc(&zram->stats.pages_expand); - zram->table[index].page = page_store; - src = kmap_atomic(page, KM_USER0); - goto memstore; - } - - if (xv_malloc(zram->mem_pool, clen + sizeof(*zheader), - &zram->table[index].page, &offset, - GFP_NOIO | __GFP_HIGHMEM)) { - mutex_unlock(&zram->lock); - pr_info("Error allocating memory for compressed " - "page: %u, size=%zu\n", index, clen); - zram_stat64_inc(zram, &zram->stats.failed_writes); - goto out; - } - -memstore: - zram->table[index].offset = offset; - - cmem = kmap_atomic(zram->table[index].page, KM_USER1) + - zram->table[index].offset; - -#if 0 - /* Back-reference needed for memory defragmentation */ - if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) { - zheader = (struct zobj_header *)cmem; - zheader->table_idx = index; - cmem += sizeof(*zheader); - } -#endif - - memcpy(cmem, src, clen); - - kunmap_atomic(cmem, KM_USER1); - if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) - kunmap_atomic(src, KM_USER0); - - /* Update stats */ - zram_stat64_add(zram, &zram->stats.compr_size, clen); - zram_stat_inc(&zram->stats.pages_stored); - if (clen <= PAGE_SIZE / 2) - zram_stat_inc(&zram->stats.good_compress); - - mutex_unlock(&zram->lock); - index++; - } - - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_endio(bio, 0); - return; - -out: - bio_io_error(bio); -} - -/* - * Check if request is within bounds and page aligned. - */ -static inline int valid_io_request(struct zram *zram, struct bio *bio) -{ - if (unlikely( - (bio->bi_sector >= (zram->disksize >> SECTOR_SHIFT)) || - (bio->bi_sector & (SECTORS_PER_PAGE - 1)) || - (bio->bi_size & (PAGE_SIZE - 1)))) { - - return 0; - } - - /* I/O request is valid */ - return 1; -} - -/* - * Handler function for all zram I/O requests. - */ -static int zram_make_request(struct request_queue *queue, struct bio *bio) -{ - struct zram *zram = queue->queuedata; - - if (!valid_io_request(zram, bio)) { - zram_stat64_inc(zram, &zram->stats.invalid_io); - bio_io_error(bio); - return 0; - } - - if (unlikely(!zram->init_done) && zram_init_device(zram)) { - bio_io_error(bio); - return 0; - } - - switch (bio_data_dir(bio)) { - case READ: - zram_read(zram, bio); - break; - - case WRITE: - zram_write(zram, bio); - break; - } - - return 0; -} - -void zram_reset_device(struct zram *zram) -{ - size_t index; - - mutex_lock(&zram->init_lock); - zram->init_done = 0; - - /* Free various per-device buffers */ - kfree(zram->compress_workmem); - free_pages((unsigned long)zram->compress_buffer, 1); - - zram->compress_workmem = NULL; - zram->compress_buffer = NULL; - - /* Free all pages that are still in this zram device */ - for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) { - struct page *page; - u16 offset; - - page = zram->table[index].page; - offset = zram->table[index].offset; - - if (!page) - continue; - - if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) - __free_page(page); - else - xv_free(zram->mem_pool, page, offset); - } - - vfree(zram->table); - zram->table = NULL; - - xv_destroy_pool(zram->mem_pool); - zram->mem_pool = NULL; - - /* Reset stats */ - memset(&zram->stats, 0, sizeof(zram->stats)); - - zram->disksize = 0; - mutex_unlock(&zram->init_lock); -} - -int zram_init_device(struct zram *zram) -{ - int ret; - size_t num_pages; -#ifdef CONFIG_ZRAM_FOR_ANDROID - struct page *page; - union swap_header *swap_header; -#endif /* CONFIG_ZRAM_FOR_ANDROID */ - - mutex_lock(&zram->init_lock); - - if (zram->init_done) { - mutex_unlock(&zram->init_lock); - return 0; - } - - zram_set_disksize(zram, totalram_pages << PAGE_SHIFT); - - zram->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); - if (!zram->compress_workmem) { - pr_err("Error allocating compressor working memory!\n"); - ret = -ENOMEM; - goto fail; - } - - zram->compress_buffer = (void *)__get_free_pages(__GFP_ZERO, 1); - if (!zram->compress_buffer) { - pr_err("Error allocating compressor buffer space\n"); - ret = -ENOMEM; - goto fail; - } - - num_pages = zram->disksize >> PAGE_SHIFT; - zram->table = vzalloc(num_pages * sizeof(*zram->table)); - if (!zram->table) { - pr_err("Error allocating zram address table\n"); - /* To prevent accessing table entries during cleanup */ - zram->disksize = 0; - ret = -ENOMEM; - goto fail; - } - -#ifdef CONFIG_ZRAM_FOR_ANDROID - page = alloc_page(__GFP_ZERO); - if (!page) { - pr_err("Error allocating swap header page\n"); - ret = -ENOMEM; - goto fail; - } - zram->table[0].page = page; - zram_set_flag(zram, 0, ZRAM_UNCOMPRESSED); - swap_header = kmap(page); - setup_swap_header(zram, swap_header); - kunmap(page); -#endif /* CONFIG_ZRAM_FOR_ANDROID */ - set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT); - - /* zram devices sort of resembles non-rotational disks */ - queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue); - - zram->mem_pool = xv_create_pool(); - if (!zram->mem_pool) { - pr_err("Error creating memory pool\n"); - ret = -ENOMEM; - goto fail; - } - - zram->init_done = 1; - mutex_unlock(&zram->init_lock); - - pr_debug("Initialization done!\n"); - return 0; - -fail: - mutex_unlock(&zram->init_lock); - zram_reset_device(zram); - - pr_err("Initialization failed: err=%d\n", ret); - return ret; -} - -void zram_slot_free_notify(struct block_device *bdev, unsigned long index) -{ - struct zram *zram; - - zram = bdev->bd_disk->private_data; - zram_free_page(zram, index); - zram_stat64_inc(zram, &zram->stats.notify_free); -} - -static const struct block_device_operations zram_devops = { - .swap_slot_free_notify = zram_slot_free_notify, - .owner = THIS_MODULE -}; - -static int create_device(struct zram *zram, int device_id) -{ - int ret = 0; - - mutex_init(&zram->lock); - mutex_init(&zram->init_lock); - spin_lock_init(&zram->stat64_lock); - - zram->queue = blk_alloc_queue(GFP_KERNEL); - if (!zram->queue) { - pr_err("Error allocating disk queue for device %d\n", - device_id); - ret = -ENOMEM; - goto out; - } - - blk_queue_make_request(zram->queue, zram_make_request); - zram->queue->queuedata = zram; - - /* gendisk structure */ - zram->disk = alloc_disk(1); - if (!zram->disk) { - blk_cleanup_queue(zram->queue); - pr_warning("Error allocating disk structure for device %d\n", - device_id); - ret = -ENOMEM; - goto out; - } - - zram->disk->major = zram_major; - zram->disk->first_minor = device_id; - zram->disk->fops = &zram_devops; - zram->disk->queue = zram->queue; - zram->disk->private_data = zram; - snprintf(zram->disk->disk_name, 16, "zram%d", device_id); - - /* Actual capacity set using syfs (/sys/block/zram<id>/disksize */ - set_capacity(zram->disk, 0); - - /* - * To ensure that we always get PAGE_SIZE aligned - * and n*PAGE_SIZED sized I/O requests. - */ - blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE); - blk_queue_logical_block_size(zram->disk->queue, - ZRAM_LOGICAL_BLOCK_SIZE); - blk_queue_io_min(zram->disk->queue, PAGE_SIZE); - blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); - - add_disk(zram->disk); - - ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj, - &zram_disk_attr_group); - if (ret < 0) { - pr_warning("Error creating sysfs group"); - goto out; - } - - zram->init_done = 0; - -out: - return ret; -} - -static void destroy_device(struct zram *zram) -{ - sysfs_remove_group(&disk_to_dev(zram->disk)->kobj, - &zram_disk_attr_group); - - if (zram->disk) { - del_gendisk(zram->disk); - put_disk(zram->disk); - } - - if (zram->queue) - blk_cleanup_queue(zram->queue); -} - -static int __init zram_init(void) -{ - int ret, dev_id; - - if (num_devices > max_num_devices) { - pr_warning("Invalid value for num_devices: %u\n", - num_devices); - ret = -EINVAL; - goto out; - } - - zram_major = register_blkdev(0, "zram"); - if (zram_major <= 0) { - pr_warning("Unable to get major number\n"); - ret = -EBUSY; - goto out; - } - - if (!num_devices) { - pr_info("num_devices not specified. Using default: 1\n"); - num_devices = 1; - } - - /* Allocate the device array and initialize each one */ - pr_info("Creating %u devices ...\n", num_devices); - zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL); - if (!zram_devices) { - ret = -ENOMEM; - goto unregister; - } - - for (dev_id = 0; dev_id < num_devices; dev_id++) { - ret = create_device(&zram_devices[dev_id], dev_id); - if (ret) - goto free_devices; - } - - return 0; - -free_devices: - while (dev_id) - destroy_device(&zram_devices[--dev_id]); - kfree(zram_devices); -unregister: - unregister_blkdev(zram_major, "zram"); -out: - return ret; -} - -static void __exit zram_exit(void) -{ - int i; - struct zram *zram; - - for (i = 0; i < num_devices; i++) { - zram = &zram_devices[i]; - - destroy_device(zram); - if (zram->init_done) - zram_reset_device(zram); - } - - unregister_blkdev(zram_major, "zram"); - - kfree(zram_devices); - pr_debug("Cleanup done!\n"); -} - -module_param(num_devices, uint, 0); -MODULE_PARM_DESC(num_devices, "Number of zram devices"); - -module_init(zram_init); -module_exit(zram_exit); - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>"); -MODULE_DESCRIPTION("Compressed RAM Block Device"); diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h deleted file mode 100644 index 3ad9486..0000000 --- a/drivers/staging/zram/zram_drv.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Compressed RAM block device - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - * - * Project home: http://compcache.googlecode.com - */ - -#ifndef _ZRAM_DRV_H_ -#define _ZRAM_DRV_H_ - -#include <linux/spinlock.h> -#include <linux/mutex.h> - -#include "xvmalloc.h" - -/* - * Some arbitrary value. This is just to catch - * invalid value for num_devices module parameter. - */ -static const unsigned max_num_devices = 32; - -/* - * Stored at beginning of each compressed object. - * - * It stores back-reference to table entry which points to this - * object. This is required to support memory defragmentation. - */ -struct zobj_header { -#if 0 - u32 table_idx; -#endif -}; - -/*-- Configurable parameters */ - -/* Default zram disk size: 25% of total RAM */ -static const unsigned default_disksize_perc_ram = 25; - -/* - * Pages that compress to size greater than this are stored - * uncompressed in memory. - */ -static const unsigned max_zpage_size = PAGE_SIZE / 4 * 3; - -/* - * NOTE: max_zpage_size must be less than or equal to: - * XV_MAX_ALLOC_SIZE - sizeof(struct zobj_header) - * otherwise, xv_malloc() would always return failure. - */ - -/*-- End of configurable params */ - -#define SECTOR_SHIFT 9 -#define SECTOR_SIZE (1 << SECTOR_SHIFT) -#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) -#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT) -#define ZRAM_LOGICAL_BLOCK_SIZE 4096 - -/* Flags for zram pages (table[page_no].flags) */ -enum zram_pageflags { - /* Page is stored uncompressed */ - ZRAM_UNCOMPRESSED, - - /* Page consists entirely of zeros */ - ZRAM_ZERO, - - __NR_ZRAM_PAGEFLAGS, -}; - -/*-- Data structures */ - -/* Allocated for each disk page */ -struct table { - struct page *page; - u16 offset; - u8 count; /* object ref count (not yet used) */ - u8 flags; -} __attribute__((aligned(4))); - -struct zram_stats { - u64 compr_size; /* compressed size of pages stored */ - u64 num_reads; /* failed + successful */ - u64 num_writes; /* --do-- */ - u64 failed_reads; /* should NEVER! happen */ - u64 failed_writes; /* can happen when memory is too low */ - u64 invalid_io; /* non-page-aligned I/O requests */ - u64 notify_free; /* no. of swap slot free notifications */ - u32 pages_zero; /* no. of zero filled pages */ - u32 pages_stored; /* no. of pages currently stored */ - u32 good_compress; /* % of pages with compression ratio<=50% */ - u32 pages_expand; /* % of incompressible pages */ -}; - -struct zram { - struct xv_pool *mem_pool; - void *compress_workmem; - void *compress_buffer; - struct table *table; - spinlock_t stat64_lock; /* protect 64-bit stats */ - struct mutex lock; /* protect compression buffers against - * concurrent writes */ - struct request_queue *queue; - struct gendisk *disk; - int init_done; - /* Prevent concurrent execution of device init and reset */ - struct mutex init_lock; - /* - * This is the limit on amount of *uncompressed* worth of data - * we can store in a disk. - */ - u64 disksize; /* bytes */ - - struct zram_stats stats; -}; - -extern struct zram *zram_devices; -extern unsigned int num_devices; -#ifdef CONFIG_SYSFS -extern struct attribute_group zram_disk_attr_group; -#endif - -extern int zram_init_device(struct zram *zram); -extern void zram_reset_device(struct zram *zram); - -#endif diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c deleted file mode 100644 index 8a23554..0000000 --- a/drivers/staging/zram/zram_sysfs.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Compressed RAM block device - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - * - * Project home: http://compcache.googlecode.com/ - */ - -#include <linux/device.h> -#include <linux/genhd.h> -#include <linux/mm.h> - -#include "zram_drv.h" - -static u64 zram_stat64_read(struct zram *zram, u64 *v) -{ - u64 val; - - spin_lock(&zram->stat64_lock); - val = *v; - spin_unlock(&zram->stat64_lock); - - return val; -} - -static struct zram *dev_to_zram(struct device *dev) -{ - int i; - struct zram *zram = NULL; - - for (i = 0; i < num_devices; i++) { - zram = &zram_devices[i]; - if (disk_to_dev(zram->disk) == dev) - break; - } - - return zram; -} - -static ssize_t disksize_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%llu\n", zram->disksize); -} - -static ssize_t disksize_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t len) -{ - int ret; - struct zram *zram = dev_to_zram(dev); - - if (zram->init_done) { - pr_info("Cannot change disksize for initialized device\n"); - return -EBUSY; - } - - ret = strict_strtoull(buf, 10, &zram->disksize); - if (ret) - return ret; - - zram->disksize = PAGE_ALIGN(zram->disksize); - set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT); - - return len; -} - -static ssize_t initstate_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%u\n", zram->init_done); -} - -#ifdef CONFIG_ZRAM_FOR_ANDROID -extern int swapon(const char*specialfile, int swap_flags); - -static ssize_t initstate_store(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t len) -{ - int ret; - unsigned long do_init; - struct zram *zram = dev_to_zram(dev); - - if (zram->init_done) { - pr_info("the device is initialized device\n"); - return -EBUSY; - } - - ret = strict_strtoul(buf, 10, &do_init); - if (ret) - return ret; - if (!do_init) - return -EINVAL; - - zram_init_device(zram); - swapon("/dev/block/zram0", 0); - return len; -} -#else -static inline ssize_t initstate_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - return 0; -} -#endif /* CONFIG_ZRAM_FOR_ANDROID */ - - -static ssize_t reset_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t len) -{ - int ret; - unsigned long do_reset; - struct zram *zram; - struct block_device *bdev; - - zram = dev_to_zram(dev); - bdev = bdget_disk(zram->disk, 0); - - /* Do not reset an active device! */ - if (bdev->bd_holders) - return -EBUSY; - - ret = strict_strtoul(buf, 10, &do_reset); - if (ret) - return ret; - - if (!do_reset) - return -EINVAL; - - /* Make sure all pending I/O is finished */ - if (bdev) - fsync_bdev(bdev); - - if (zram->init_done) - zram_reset_device(zram); - - return len; -} - -static ssize_t num_reads_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%llu\n", - zram_stat64_read(zram, &zram->stats.num_reads)); -} - -static ssize_t num_writes_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%llu\n", - zram_stat64_read(zram, &zram->stats.num_writes)); -} - -static ssize_t invalid_io_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%llu\n", - zram_stat64_read(zram, &zram->stats.invalid_io)); -} - -static ssize_t notify_free_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%llu\n", - zram_stat64_read(zram, &zram->stats.notify_free)); -} - -static ssize_t zero_pages_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%u\n", zram->stats.pages_zero); -} - -static ssize_t orig_data_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%llu\n", - (u64)(zram->stats.pages_stored) << PAGE_SHIFT); -} - -static ssize_t compr_data_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zram *zram = dev_to_zram(dev); - - return sprintf(buf, "%llu\n", - zram_stat64_read(zram, &zram->stats.compr_size)); -} - -static ssize_t mem_used_total_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u64 val = 0; - struct zram *zram = dev_to_zram(dev); - - if (zram->init_done) { - val = xv_get_total_size_bytes(zram->mem_pool) + - ((u64)(zram->stats.pages_expand) << PAGE_SHIFT); - } - - return sprintf(buf, "%llu\n", val); -} - -static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR, - disksize_show, disksize_store); -static DEVICE_ATTR(initstate, S_IRUGO | S_IWUSR, initstate_show, initstate_store); -static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store); -static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL); -static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL); -static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL); -static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL); -static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL); -static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL); -static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL); -static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL); - -static struct attribute *zram_disk_attrs[] = { - &dev_attr_disksize.attr, - &dev_attr_initstate.attr, - &dev_attr_reset.attr, - &dev_attr_num_reads.attr, - &dev_attr_num_writes.attr, - &dev_attr_invalid_io.attr, - &dev_attr_notify_free.attr, - &dev_attr_zero_pages.attr, - &dev_attr_orig_data_size.attr, - &dev_attr_compr_data_size.attr, - &dev_attr_mem_used_total.attr, - NULL, -}; - -struct attribute_group zram_disk_attr_group = { - .attrs = zram_disk_attrs, -}; diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index a76c808..606c0956 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -424,6 +424,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * they are not on hot paths so a little discipline won't do * any harm. * + * The line discipline-related tty_struct fields are reset to + * prevent the ldisc driver from re-using stale information for + * the new ldisc instance. + * * Locking: takes termios_mutex */ @@ -432,6 +436,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) mutex_lock(&tty->termios_mutex); tty->termios->c_line = num; mutex_unlock(&tty->termios_mutex); + + tty->disc_data = NULL; + tty->receive_room = 0; } /** diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 84e69ea..c8fee56 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -895,6 +895,9 @@ static int acm_probe(struct usb_interface *intf, if (quirks == NO_UNION_NORMAL) { data_interface = usb_ifnum_to_if(usb_dev, 1); control_interface = usb_ifnum_to_if(usb_dev, 0); + /* we would crash */ + if (!data_interface || !control_interface) + return -ENODEV; goto skip_normal_probe; } diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 461e785..8aff636 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1012,10 +1012,11 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) static int proc_connectinfo(struct dev_state *ps, void __user *arg) { - struct usbdevfs_connectinfo ci = { - .devnum = ps->dev->devnum, - .slow = ps->dev->speed == USB_SPEED_LOW - }; + struct usbdevfs_connectinfo ci; + + memset(&ci, 0, sizeof(ci)); + ci.devnum = ps->dev->devnum; + ci.slow = ps->dev->speed == USB_SPEED_LOW; if (copy_to_user(arg, &ci, sizeof(ci))) return -EFAULT; diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c index 5c3960d..b1d63b5 100644 --- a/drivers/video/fbcmap.c +++ b/drivers/video/fbcmap.c @@ -166,6 +166,9 @@ int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) int tooff = 0, fromoff = 0; int size; + if (!to || !from) + return -EINVAL; + if (to->start > from->start) fromoff = to->start - from->start; else @@ -177,9 +180,12 @@ int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) return -EINVAL; size *= sizeof(u16); - memcpy(to->red+tooff, from->red+fromoff, size); - memcpy(to->green+tooff, from->green+fromoff, size); - memcpy(to->blue+tooff, from->blue+fromoff, size); + if (from->red && to->red) + memcpy(to->red+tooff, from->red+fromoff, size); + if (from->green && to->green) + memcpy(to->green+tooff, from->green+fromoff, size); + if (from->blue && to->blue) + memcpy(to->blue+tooff, from->blue+fromoff, size); if (from->transp && to->transp) memcpy(to->transp+tooff, from->transp+fromoff, size); return 0; @@ -190,6 +196,9 @@ int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) int tooff = 0, fromoff = 0; int size; + if (!to || !from || (int)(to->start) < 0) + return -EINVAL; + if (to->start > from->start) fromoff = to->start - from->start; else @@ -201,12 +210,15 @@ int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) return -EINVAL; size *= sizeof(u16); - if (copy_to_user(to->red+tooff, from->red+fromoff, size)) - return -EFAULT; - if (copy_to_user(to->green+tooff, from->green+fromoff, size)) - return -EFAULT; - if (copy_to_user(to->blue+tooff, from->blue+fromoff, size)) - return -EFAULT; + if (from->red && to->red) + if (copy_to_user(to->red+tooff, from->red+fromoff, size)) + return -EFAULT; + if (from->green && to->green) + if (copy_to_user(to->green+tooff, from->green+fromoff, size)) + return -EFAULT; + if (from->blue && to->blue) + if (copy_to_user(to->blue+tooff, from->blue+fromoff, size)) + return -EFAULT; if (from->transp && to->transp) if (copy_to_user(to->transp+tooff, from->transp+fromoff, size)) return -EFAULT; @@ -285,8 +297,8 @@ int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) rc = -ENODEV; goto out; } - if (cmap->start < 0 || (!info->fbops->fb_setcolreg && - !info->fbops->fb_setcmap)) { + if (!info->fbops->fb_setcolreg && + !info->fbops->fb_setcmap) { rc = -EINVAL; goto out1; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index fcc52d4..4716e62 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1108,6 +1108,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, if (copy_from_user(&cmap, argp, sizeof(cmap))) return -EFAULT; ret = fb_set_user_cmap(&cmap, info); + if (ret) { + if (info) + fb_dealloc_cmap(&info->cmap); + } break; case FBIOGETCMAP: if (copy_from_user(&cmap, argp, sizeof(cmap))) diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c index 816a449..4cac54a 100644 --- a/drivers/xen/tmem.c +++ b/drivers/xen/tmem.c @@ -234,9 +234,9 @@ __setup("nocleancache", no_cleancache); static struct cleancache_ops tmem_cleancache_ops = { .put_page = tmem_cleancache_put_page, .get_page = tmem_cleancache_get_page, - .flush_page = tmem_cleancache_flush_page, - .flush_inode = tmem_cleancache_flush_inode, - .flush_fs = tmem_cleancache_flush_fs, + .invalidate_page = tmem_cleancache_flush_page, + .invalidate_inode = tmem_cleancache_flush_inode, + .invalidate_fs = tmem_cleancache_flush_fs, .init_shared_fs = tmem_cleancache_init_shared_fs, .init_fs = tmem_cleancache_init_fs }; @@ -957,12 +957,23 @@ static int de_thread(struct task_struct *tsk) transfer_pid(leader, tsk, PIDTYPE_SID); list_replace_rcu(&leader->tasks, &tsk->tasks); + delete_from_adj_tree(leader); + add_2_adj_tree(tsk); list_replace_init(&leader->sibling, &tsk->sibling); tsk->group_leader = tsk; leader->group_leader = tsk; tsk->exit_signal = SIGCHLD; + /* + * need to delete leader from adj tree, because it will not be + * group leader (exit_signal = -1) soon. release_task(leader) + * can't delete it. + */ + spin_lock_irq(lock); + delete_from_adj_tree(leader); + add_2_adj_tree(tsk); + spin_unlock_irq(lock); BUG_ON(leader->exit_state != EXIT_ZOMBIE); leader->exit_state = EXIT_DEAD; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 294bc8f..c2bd302 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4484,6 +4484,7 @@ int ext4_can_truncate(struct inode *inode) int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) { +#if 0 struct inode *inode = file->f_path.dentry->d_inode; if (!S_ISREG(inode->i_mode)) return -ENOTSUPP; @@ -4494,6 +4495,12 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) } return ext4_ext_punch_hole(file, offset, length); +#else + /* + * Disabled as per b/28760453 + */ + return -EOPNOTSUPP; +#endif } /* diff --git a/fs/ioprio.c b/fs/ioprio.c index 7da2a06..e325e9f 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -160,8 +160,10 @@ static int get_task_ioprio(struct task_struct *p) if (ret) goto out; ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); + task_lock(p); if (p->io_context) ret = p->io_context->ioprio; + task_unlock(p); out: return ret; } diff --git a/fs/namespace.c b/fs/namespace.c index 900812f..8b34a97 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1477,8 +1477,14 @@ struct vfsmount *collect_mounts(struct path *path) { struct vfsmount *tree; down_write(&namespace_sem); - tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE); + if (!check_mnt(path->mnt)) + tree = ERR_PTR(-EINVAL); + else + tree = copy_tree(path->mnt, path->dentry, + CL_COPY_ALL | CL_PRIVATE); up_write(&namespace_sem); + if (IS_ERR(tree)) + return NULL; return tree; } @@ -35,6 +35,12 @@ unsigned int pipe_max_size = 1048576; */ unsigned int pipe_min_size = PAGE_SIZE; +/* Maximum allocatable pages per user. Hard limit is unset by default, soft + * matches default values. + */ +unsigned long pipe_user_pages_hard; +unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR; + /* * We use a start+len construction, which provides full use of the * allocated memory. @@ -389,6 +395,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, void *addr; size_t chars = buf->len, remaining; int error, atomic; + int offset; if (chars > total_len) chars = total_len; @@ -402,9 +409,10 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, atomic = !iov_fault_in_pages_write(iov, chars); remaining = chars; + offset = buf->offset; redo: addr = ops->map(pipe, buf, atomic); - error = pipe_iov_copy_to_user(iov, addr, &buf->offset, + error = pipe_iov_copy_to_user(iov, addr, &offset, &remaining, atomic); ops->unmap(pipe, buf, addr); if (unlikely(error)) { @@ -420,6 +428,7 @@ redo: break; } ret += chars; + buf->offset += chars; buf->len -= chars; /* Was it a packet buffer? Clean up and exit */ @@ -929,20 +938,49 @@ const struct file_operations rdwr_pipefifo_fops = { .fasync = pipe_rdwr_fasync, }; +static void account_pipe_buffers(struct pipe_inode_info *pipe, + unsigned long old, unsigned long new) +{ + atomic_long_add(new - old, &pipe->user->pipe_bufs); +} + +static bool too_many_pipe_buffers_soft(struct user_struct *user) +{ + return pipe_user_pages_soft && + atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_soft; +} + +static bool too_many_pipe_buffers_hard(struct user_struct *user) +{ + return pipe_user_pages_hard && + atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_hard; +} + struct pipe_inode_info * alloc_pipe_info(struct inode *inode) { struct pipe_inode_info *pipe; pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); if (pipe) { - pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL); + unsigned long pipe_bufs = PIPE_DEF_BUFFERS; + struct user_struct *user = get_current_user(); + + if (!too_many_pipe_buffers_hard(user)) { + if (too_many_pipe_buffers_soft(user)) + pipe_bufs = 1; + pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * pipe_bufs, GFP_KERNEL); + } + if (pipe->bufs) { init_waitqueue_head(&pipe->wait); pipe->r_counter = pipe->w_counter = 1; pipe->inode = inode; - pipe->buffers = PIPE_DEF_BUFFERS; + pipe->buffers = pipe_bufs; + pipe->user = user; + account_pipe_buffers(pipe, 0, pipe_bufs); return pipe; } + free_uid(user); kfree(pipe); } @@ -953,6 +991,8 @@ void __free_pipe_info(struct pipe_inode_info *pipe) { int i; + account_pipe_buffers(pipe, pipe->buffers, 0); + free_uid(pipe->user); for (i = 0; i < pipe->buffers; i++) { struct pipe_buffer *buf = pipe->bufs + i; if (buf->ops) @@ -1201,6 +1241,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); } + account_pipe_buffers(pipe, pipe->buffers, nr_pages); pipe->curbuf = 0; kfree(pipe->bufs); pipe->bufs = bufs; @@ -1274,6 +1315,11 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { ret = -EPERM; goto out; + } else if ((too_many_pipe_buffers_hard(pipe->user) || + too_many_pipe_buffers_soft(pipe->user)) && + !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + goto out; } ret = pipe_set_size(pipe, nr_pages); break; diff --git a/fs/proc/base.c b/fs/proc/base.c index 1a140ca..56d23e1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1063,6 +1063,8 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, else task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; + delete_from_adj_tree(task); + add_2_adj_tree(task); err_sighand: unlock_task_sighand(task, &flags); err_task_lock: @@ -1187,6 +1189,8 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf, atomic_dec(&task->mm->oom_disable_count); } task->signal->oom_score_adj = oom_score_adj; + delete_from_adj_tree(task); + add_2_adj_tree(task); if (has_capability_noaudit(current, CAP_SYS_RESOURCE)) task->signal->oom_score_adj_min = oom_score_adj; /* diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 00e7ac4..f43c540 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -88,6 +88,56 @@ static void pad_len_spaces(struct seq_file *m, int len) seq_printf(m, "%*c", len, ' '); } +static void seq_print_vma_name(struct seq_file *m, struct vm_area_struct *vma) +{ + const char __user *name = vma_get_anon_name(vma); + struct mm_struct *mm = vma->vm_mm; + + unsigned long page_start_vaddr; + unsigned long page_offset; + unsigned long num_pages; + unsigned long max_len = NAME_MAX; + int i; + + page_start_vaddr = (unsigned long)name & PAGE_MASK; + page_offset = (unsigned long)name - page_start_vaddr; + num_pages = DIV_ROUND_UP(page_offset + max_len, PAGE_SIZE); + + seq_puts(m, "[anon:"); + + for (i = 0; i < num_pages; i++) { + int len; + int write_len; + const char *kaddr; + long pages_pinned; + struct page *page; + + pages_pinned = get_user_pages(current, mm, page_start_vaddr, + 1, 0, 0, &page, NULL); + if (pages_pinned < 1) { + seq_puts(m, "<fault>]"); + return; + } + + kaddr = (const char *)kmap(page); + len = min(max_len, PAGE_SIZE - page_offset); + write_len = strnlen(kaddr + page_offset, len); + seq_write(m, kaddr + page_offset, write_len); + kunmap(page); + put_page(page); + + /* if strnlen hit a null terminator then we're done */ + if (write_len != len) + break; + + max_len -= len; + page_offset = 0; + page_start_vaddr += PAGE_SIZE; + } + + seq_putc(m, ']'); +} + static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma) { if (vma && vma != priv->tail_vma) { @@ -264,7 +314,14 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) } else { name = "[vdso]"; } + goto done; } + + if (vma_get_anon_name(vma)) { + pad_len_spaces(m, len); + seq_print_vma_name(m, vma); + } +done: if (name) { pad_len_spaces(m, len); seq_puts(m, name); @@ -474,6 +531,12 @@ static int show_smap(struct seq_file *m, void *v) (vma->vm_flags & VM_LOCKED) ? (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); + if (vma_get_anon_name(vma)) { + seq_puts(m, "Name: "); + seq_print_vma_name(m, vma); + seq_putc(m, '\n'); + } + if (m->count < m->size) /* vma is copied successfully */ m->version = (vma != get_gate_vma(task->mm)) ? vma->vm_start : 0; diff --git a/include/linux/android_pmem.h b/include/linux/android_pmem.h deleted file mode 100644 index f633621..0000000 --- a/include/linux/android_pmem.h +++ /dev/null @@ -1,93 +0,0 @@ -/* include/linux/android_pmem.h - * - * Copyright (C) 2007 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 _ANDROID_PMEM_H_ -#define _ANDROID_PMEM_H_ - -#define PMEM_IOCTL_MAGIC 'p' -#define PMEM_GET_PHYS _IOW(PMEM_IOCTL_MAGIC, 1, unsigned int) -#define PMEM_MAP _IOW(PMEM_IOCTL_MAGIC, 2, unsigned int) -#define PMEM_GET_SIZE _IOW(PMEM_IOCTL_MAGIC, 3, unsigned int) -#define PMEM_UNMAP _IOW(PMEM_IOCTL_MAGIC, 4, unsigned int) -/* This ioctl will allocate pmem space, backing the file, it will fail - * if the file already has an allocation, pass it the len as the argument - * to the ioctl */ -#define PMEM_ALLOCATE _IOW(PMEM_IOCTL_MAGIC, 5, unsigned int) -/* This will connect a one pmem file to another, pass the file that is already - * backed in memory as the argument to the ioctl - */ -#define PMEM_CONNECT _IOW(PMEM_IOCTL_MAGIC, 6, unsigned int) -/* Returns the total size of the pmem region it is sent to as a pmem_region - * struct (with offset set to 0). - */ -#define PMEM_GET_TOTAL_SIZE _IOW(PMEM_IOCTL_MAGIC, 7, unsigned int) -#define PMEM_CACHE_FLUSH _IOW(PMEM_IOCTL_MAGIC, 8, unsigned int) - -struct android_pmem_platform_data -{ - const char* name; - /* starting physical address of memory region */ - unsigned long start; - /* size of memory region */ - unsigned long size; - /* set to indicate the region should not be managed with an allocator */ - unsigned no_allocator; - /* set to indicate maps of this region should be cached, if a mix of - * cached and uncached is desired, set this and open the device with - * O_SYNC to get an uncached region */ - unsigned cached; - /* The MSM7k has bits to enable a write buffer in the bus controller*/ - unsigned buffered; -}; - -struct pmem_region { - unsigned long offset; - unsigned long len; -}; - -#ifdef CONFIG_ANDROID_PMEM -int is_pmem_file(struct file *file); -int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart, - unsigned long *end, struct file **filp); -int get_pmem_user_addr(struct file *file, unsigned long *start, - unsigned long *end); -void put_pmem_file(struct file* file); -void flush_pmem_file(struct file *file, unsigned long start, unsigned long len); -int pmem_setup(struct android_pmem_platform_data *pdata, - long (*ioctl)(struct file *, unsigned int, unsigned long), - int (*release)(struct inode *, struct file *)); -int pmem_remap(struct pmem_region *region, struct file *file, - unsigned operation); - -#else -static inline int is_pmem_file(struct file *file) { return 0; } -static inline int get_pmem_file(int fd, unsigned long *start, - unsigned long *vstart, unsigned long *end, - struct file **filp) { return -ENOSYS; } -static inline int get_pmem_user_addr(struct file *file, unsigned long *start, - unsigned long *end) { return -ENOSYS; } -static inline void put_pmem_file(struct file* file) { return; } -static inline void flush_pmem_file(struct file *file, unsigned long start, - unsigned long len) { return; } -static inline int pmem_setup(struct android_pmem_platform_data *pdata, - long (*ioctl)(struct file *, unsigned int, unsigned long), - int (*release)(struct inode *, struct file *)) { return -ENOSYS; } - -static inline int pmem_remap(struct pmem_region *region, struct file *file, - unsigned operation) { return -ENOSYS; } -#endif - -#endif //_ANDROID_PPP_H_ - diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1b13021..af75d16 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -403,6 +403,7 @@ struct request_queue #define QUEUE_FLAG_NOXMERGES 15 /* No extended merges */ #define QUEUE_FLAG_ADD_RANDOM 16 /* Contributes to random pool */ #define QUEUE_FLAG_SECDISCARD 17 /* supports SECDISCARD */ +#define QUEUE_FLAG_FAST 20 /* fast block device (e.g. ram based) */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ @@ -487,6 +488,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define blk_queue_discard(q) test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags) #define blk_queue_secdiscard(q) (blk_queue_discard(q) && \ test_bit(QUEUE_FLAG_SECDISCARD, &(q)->queue_flags)) +#define blk_queue_fast(q) test_bit(QUEUE_FLAG_FAST, &(q)->queue_flags) #define blk_noretry_request(rq) \ ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ diff --git a/include/linux/cleancache.h b/include/linux/cleancache.h index 04ffb2e..1ccdcea 100644 --- a/include/linux/cleancache.h +++ b/include/linux/cleancache.h @@ -28,9 +28,9 @@ struct cleancache_ops { pgoff_t, struct page *); void (*put_page)(int, struct cleancache_filekey, pgoff_t, struct page *); - void (*flush_page)(int, struct cleancache_filekey, pgoff_t); - void (*flush_inode)(int, struct cleancache_filekey); - void (*flush_fs)(int); + void (*invalidate_page)(int, struct cleancache_filekey, pgoff_t); + void (*invalidate_inode)(int, struct cleancache_filekey); + void (*invalidate_fs)(int); }; extern struct cleancache_ops diff --git a/include/linux/decompress/unlz4.h b/include/linux/decompress/unlz4.h new file mode 100644 index 0000000..d5b68bf --- /dev/null +++ b/include/linux/decompress/unlz4.h @@ -0,0 +1,10 @@ +#ifndef DECOMPRESS_UNLZ4_H +#define DECOMPRESS_UNLZ4_H + +int unlz4(unsigned char *inbuf, int len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *output, + int *pos, + void(*error)(char *x)); +#endif diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index ef820a3..ee4410a 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -390,7 +390,7 @@ struct lock_class_key { }; #define lockdep_depth(tsk) (0) -#define lockdep_assert_held(l) do { } while (0) +#define lockdep_assert_held(l) do { (void)(l); } while (0) #endif /* !LOCKDEP */ diff --git a/include/linux/lz4.h b/include/linux/lz4.h new file mode 100644 index 0000000..4356686 --- /dev/null +++ b/include/linux/lz4.h @@ -0,0 +1,87 @@ +#ifndef __LZ4_H__ +#define __LZ4_H__ +/* + * LZ4 Kernel Interface + * + * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define LZ4_MEM_COMPRESS (4096 * sizeof(unsigned char *)) +#define LZ4HC_MEM_COMPRESS (65538 * sizeof(unsigned char *)) + +/* + * lz4_compressbound() + * Provides the maximum size that LZ4 may output in a "worst case" scenario + * (input data not compressible) + */ +static inline size_t lz4_compressbound(size_t isize) +{ + return isize + (isize / 255) + 16; +} + +/* + * lz4_compress() + * src : source address of the original data + * src_len : size of the original data + * dst : output buffer address of the compressed data + * This requires 'dst' of size LZ4_COMPRESSBOUND. + * dst_len : is the output size, which is returned after compress done + * workmem : address of the working memory. + * This requires 'workmem' of size LZ4_MEM_COMPRESS. + * return : Success if return 0 + * Error if return (< 0) + * note : Destination buffer and workmem must be already allocated with + * the defined size. + */ +int lz4_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem); + + /* + * lz4hc_compress() + * src : source address of the original data + * src_len : size of the original data + * dst : output buffer address of the compressed data + * This requires 'dst' of size LZ4_COMPRESSBOUND. + * dst_len : is the output size, which is returned after compress done + * workmem : address of the working memory. + * This requires 'workmem' of size LZ4HC_MEM_COMPRESS. + * return : Success if return 0 + * Error if return (< 0) + * note : Destination buffer and workmem must be already allocated with + * the defined size. + */ +int lz4hc_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem); + +/* + * lz4_decompress() + * src : source address of the compressed data + * src_len : is the input size, whcih is returned after decompress done + * dest : output buffer address of the decompressed data + * actual_dest_len: is the size of uncompressed data, supposing it's known + * return : Success if return 0 + * Error if return (< 0) + * note : Destination buffer must be already allocated. + * slightly faster than lz4_decompress_unknownoutputsize() + */ +int lz4_decompress(const unsigned char *src, size_t *src_len, + unsigned char *dest, size_t actual_dest_len); + +/* + * lz4_decompress_unknownoutputsize() + * src : source address of the compressed data + * src_len : is the input size, therefore the compressed size + * dest : output buffer address of the decompressed data + * dest_len: is the max size of the destination buffer, which is + * returned with actual size of decompressed data after + * decompress done + * return : Success if return 0 + * Error if return (< 0) + * note : Destination buffer must be already allocated. + */ +int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len, + unsigned char *dest, size_t *dest_len); +#endif diff --git a/include/linux/mm.h b/include/linux/mm.h index d5dc6af..b465c7f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1418,7 +1418,7 @@ extern int vma_adjust(struct vm_area_struct *vma, unsigned long start, extern struct vm_area_struct *vma_merge(struct mm_struct *, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t, - struct mempolicy *); + struct mempolicy *, const char __user *); extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *); extern int split_vma(struct mm_struct *, struct vm_area_struct *, unsigned long addr, int new_below); @@ -1574,6 +1574,7 @@ struct page *follow_page(struct vm_area_struct *, unsigned long address, #define FOLL_SPLIT 0x80 /* don't return transhuge pages, split them */ #define FOLL_HWPOISON 0x100 /* check page is hwpoisoned */ #define FOLL_NO_CMA 0x200 /* avoid putting pages to CMA regions */ +#define FOLL_COW 0x4000 /* internal GUP flag */ typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, void *data); diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 0f230ce..557f9b6 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -162,6 +162,10 @@ struct vm_area_struct { * linkage into the address_space->i_mmap prio tree, or * linkage to the list of like vmas hanging off its node, or * linkage of vma in the address_space->i_mmap_nonlinear list. + * + * For private anonymous mappings, a pointer to a null terminated string + * in the user process containing the name given to the vma, or NULL + * if unnamed. */ union { struct { @@ -171,6 +175,7 @@ struct vm_area_struct { } vm_set; struct raw_prio_tree_node prio_tree_node; + const char __user *anon_name; } shared; /* @@ -198,9 +203,6 @@ struct vm_area_struct { #ifdef CONFIG_NUMA struct mempolicy *vm_policy; /* NUMA policy for the VMA */ #endif -#ifdef CONFIG_ZRAM_FOR_ANDROID - int vma_swap_done; -#endif /* CONFIG_ZRAM_FOR_ANDROID */ }; struct core_thread { @@ -333,9 +335,6 @@ struct mm_struct { #ifdef CONFIG_CPUMASK_OFFSTACK struct cpumask cpumask_allocation; #endif -#ifdef CONFIG_ZRAM_FOR_ANDROID - int mm_swap_done; -#endif /* CONFIG_ZRAM_FOR_ANDROID */ }; static inline void mm_init_cpumask(struct mm_struct *mm) @@ -351,4 +350,14 @@ static inline cpumask_t *mm_cpumask(struct mm_struct *mm) return mm->cpu_vm_mask_var; } + +/* Return the name for an anonymous mapping or NULL for a file-backed mapping */ +static inline const char __user *vma_get_anon_name(struct vm_area_struct *vma) +{ + if (vma->vm_file) + return NULL; + + return vma->shared.anon_name; +} + #endif /* _LINUX_MM_TYPES_H */ diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 87a0009..657ba2c 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -51,6 +51,9 @@ * PG_hwpoison indicates that a page got corrupted in hardware and contains * data with incorrect ECC bits that triggered a machine check. Accessing is * not safe since it may cause another machine check. Don't touch! + * + * PG_wasactive reflects that a page previously was promoted to active status. + * Such pages should be considered higher priority for cleancache backends. */ /* @@ -107,6 +110,9 @@ enum pageflags { #ifdef CONFIG_TRANSPARENT_HUGEPAGE PG_compound_lock, #endif +#ifdef CONFIG_CLEANCACHE + PG_was_active, +#endif __NR_PAGEFLAGS, /* Filesystems */ @@ -264,6 +270,10 @@ __PAGEFLAG(SlobFree, slob_free) __PAGEFLAG(SlubFrozen, slub_frozen) +#ifdef CONFIG_CLEANCACHE +PAGEFLAG(WasActive, was_active) +#endif + /* * Private page markings that may be used by the filesystem that owns the page * for its own purposes. diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index e4d3640..82660a6 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -757,6 +757,12 @@ struct perf_event { int nr_siblings; int group_flags; struct perf_event *group_leader; + + /* + * Protect the pmu, attributes and context of a group leader. + * Note: does not protect the pointer to the group_leader. + */ + struct mutex group_leader_mutex; struct pmu *pmu; enum perf_event_active_state state; @@ -979,6 +985,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, struct task_struct *task, perf_overflow_handler_t callback); +extern void perf_pmu_migrate_context(struct pmu *pmu, + int src_cpu, int dst_cpu); extern u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running); diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 0072a53..1aefc3f 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -43,6 +43,7 @@ struct pipe_buffer { * @fasync_writers: writer side fasync * @inode: inode this pipe is attached to * @bufs: the circular array of pipe buffers + * @user: the user who created this pipe **/ struct pipe_inode_info { wait_queue_head_t wait; @@ -57,6 +58,7 @@ struct pipe_inode_info { struct fasync_struct *fasync_writers; struct inode *inode; struct pipe_buffer *bufs; + struct user_struct *user; }; /* @@ -142,6 +144,8 @@ void pipe_unlock(struct pipe_inode_info *); void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *); extern unsigned int pipe_max_size, pipe_min_size; +extern unsigned long pipe_user_pages_hard; +extern unsigned long pipe_user_pages_soft; int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 8289fca..35b7ed6 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -146,6 +146,7 @@ enum power_supply_type { POWER_SUPPLY_TYPE_WIRELESS, POWER_SUPPLY_TYPE_UARTOFF, POWER_SUPPLY_TYPE_OTG, + POWER_SUPPLY_TYPE_UNKNOWN, }; enum { diff --git a/include/linux/prctl.h b/include/linux/prctl.h index a3baeb2..dd90287 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -102,4 +102,7 @@ #define PR_MCE_KILL_GET 34 +#define PR_SET_VMA 0x53564d41 +# define PR_SET_VMA_ANON_NAME 0 + #endif /* _LINUX_PRCTL_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 8ff666c..6b030a5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -645,11 +645,13 @@ struct signal_struct { struct rw_semaphore threadgroup_fork_lock; #endif - int oom_adj; /* OOM kill score adjustment (bit shift) */ - int oom_score_adj; /* OOM kill score adjustment */ - int oom_score_adj_min; /* OOM kill score adjustment minimum value. + int oom_adj; /* OOM kill score adjustment (bit shift) */ + short oom_score_adj; /* OOM kill score adjustment */ + short oom_score_adj_min;/* OOM kill score adjustment min value. * Only settable by CAP_SYS_RESOURCE. */ - +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE + struct rb_node adj_node; +#endif struct mutex cred_guard_mutex; /* guard against foreign influences on * credential calculations * (notably. ptrace) */ @@ -705,6 +707,7 @@ struct user_struct { unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */ #endif unsigned long locked_shm; /* How many pages of mlocked shm ? */ + atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */ #ifdef CONFIG_KEYS struct key *uid_keyring; /* UID specific keyring */ @@ -1281,6 +1284,9 @@ struct task_struct { #endif struct list_head tasks; +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE + struct rb_node adj_node; +#endif #ifdef CONFIG_SMP struct plist_node pushable_tasks; #endif @@ -1620,6 +1626,13 @@ static inline struct pid *task_tgid(struct task_struct *task) return task->group_leader->pids[PIDTYPE_PID].pid; } +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE +extern void add_2_adj_tree(struct task_struct *task); +extern void delete_from_adj_tree(struct task_struct *task); +#else +static inline void add_2_adj_tree(struct task_struct *task) { } +static inline void delete_from_adj_tree(struct task_struct *task) { } +#endif /* * Without tasklist or rcu lock it is not safe to dereference * the result of task_pgrp/task_session even if task == current, diff --git a/include/linux/swap.h b/include/linux/swap.h index e73799d..bd6e937 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -150,6 +150,7 @@ enum { SWP_BLKDEV = (1 << 6), /* its a block device */ /* add others here before... */ SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */ + SWP_FAST = (1 << 9), /* blkdev access is fast and cheap */ }; #define SWAP_CLUSTER_MAX 32 @@ -201,9 +202,6 @@ struct swap_list_t { int next; /* swapfile to be used next */ }; -/* Swap 50% full? Release swapcache more aggressively.. */ -#define vm_swap_full() (nr_swap_pages*2 < total_swap_pages) - /* linux/mm/page_alloc.c */ extern unsigned long totalram_pages; extern unsigned long totalreserve_pages; @@ -320,6 +318,21 @@ extern struct page *swapin_readahead(swp_entry_t, gfp_t, /* linux/mm/swapfile.c */ extern long nr_swap_pages; extern long total_swap_pages; +extern bool is_swap_fast(swp_entry_t entry); + +/* Swap 50% full? Release swapcache more aggressively.. */ +static inline bool vm_swap_full(struct swap_info_struct *si) +{ + /* + * If the swap device is fast, return true + * not to delay swap free. + */ + if (si->flags & SWP_FAST) + return true; + + return nr_swap_pages*2 < total_swap_pages; +} + extern void si_swapinfo(struct sysinfo *); extern swp_entry_t get_swap_page(void); extern swp_entry_t get_swap_page_of_type(int); @@ -335,6 +348,7 @@ extern int swap_type_of(dev_t, sector_t, struct block_device **); extern unsigned int count_swap_pages(int, int); extern sector_t map_swap_page(struct page *, struct block_device **); extern sector_t swapdev_block(int, pgoff_t); +extern struct swap_info_struct *page_swap_info(struct page *); extern int reuse_swap_page(struct page *); extern int try_to_free_swap(struct page *); struct backing_dev_info; @@ -379,6 +393,7 @@ static inline void mem_cgroup_uncharge_swap(swp_entry_t ent) #define nr_swap_pages 0L #define total_swap_pages 0L #define total_swapcache_pages 0UL +#define vm_swap_full(si) 0 #define si_swapinfo(val) \ do { (val)->freeswap = (val)->totalswap = 0; } while (0) diff --git a/include/linux/zsmalloc.h b/include/linux/zsmalloc.h new file mode 100644 index 0000000..05c2147 --- /dev/null +++ b/include/linux/zsmalloc.h @@ -0,0 +1,51 @@ +/* + * zsmalloc memory allocator + * + * Copyright (C) 2011 Nitin Gupta + * Copyright (C) 2012, 2013 Minchan Kim + * + * This code is released using a dual license strategy: BSD/GPL + * You can choose the license that better fits your requirements. + * + * Released under the terms of 3-clause BSD License + * Released under the terms of GNU General Public License Version 2.0 + */ + +#ifndef _ZS_MALLOC_H_ +#define _ZS_MALLOC_H_ + +#include <linux/types.h> + +/* + * zsmalloc mapping modes + * + * NOTE: These only make a difference when a mapped object spans pages. + * They also have no effect when PGTABLE_MAPPING is selected. + */ +enum zs_mapmode { + ZS_MM_RW, /* normal read-write mapping */ + ZS_MM_RO, /* read-only (no copy-out at unmap time) */ + ZS_MM_WO /* write-only (no copy-in at map time) */ + /* + * NOTE: ZS_MM_WO should only be used for initializing new + * (uninitialized) allocations. Partial writes to already + * initialized allocations should use ZS_MM_RW to preserve the + * existing data. + */ +}; + +struct zs_pool; + +struct zs_pool *zs_create_pool(gfp_t flags); +void zs_destroy_pool(struct zs_pool *pool); + +unsigned long zs_malloc(struct zs_pool *pool, size_t size); +void zs_free(struct zs_pool *pool, unsigned long obj); + +void *zs_map_object(struct zs_pool *pool, unsigned long handle, + enum zs_mapmode mm); +void zs_unmap_object(struct zs_pool *pool, unsigned long handle); + +unsigned long zs_get_total_pages(struct zs_pool *pool); + +#endif diff --git a/include/net/tcp.h b/include/net/tcp.h index 0f6a452..4fdc312 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1250,6 +1250,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli { if (sk->sk_send_head == skb_unlinked) sk->sk_send_head = NULL; + if (tcp_sk(sk)->highest_sack == skb_unlinked) + tcp_sk(sk)->highest_sack = NULL; } static inline void tcp_init_send_head(struct sock *sk) diff --git a/init/Kconfig b/init/Kconfig index ae99e63..ac45380 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -130,10 +130,13 @@ config HAVE_KERNEL_XZ config HAVE_KERNEL_LZO bool +config HAVE_KERNEL_LZ4 + bool + choice prompt "Kernel compression mode" default KERNEL_GZIP - depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO + depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 help The linux kernel is a kind of self-extracting executable. Several compression algorithms are available, which differ @@ -201,6 +204,18 @@ config KERNEL_LZO size is about 10% bigger than gzip; however its speed (both compression and decompression) is the fastest. +config KERNEL_LZ4 + bool "LZ4" + depends on HAVE_KERNEL_LZ4 + help + LZ4 is an LZ77-type compressor with a fixed, byte-oriented encoding. + A preliminary version of LZ4 de/compression tool is available at + <https://code.google.com/p/lz4/>. + + Its compression ratio is worse than LZO. The size of the kernel + is about 8% bigger than LZO. But the decompression speed is + faster than LZO. + endchoice config DEFAULT_HOSTNAME diff --git a/kernel/events/core.c b/kernel/events/core.c index acdc087..466213f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -604,6 +604,77 @@ static void put_ctx(struct perf_event_context *ctx) } } +/* + * Because of perf_event::ctx migration in sys_perf_event_open::move_group and + * perf_pmu_migrate_context() we need some magic. + * + * Those places that change perf_event::ctx will hold both + * perf_event_ctx::mutex of the 'old' and 'new' ctx value. + * + * Lock ordering is by mutex address. There is one other site where + * perf_event_context::mutex nests and that is put_event(). But remember that + * that is a parent<->child context relation, and migration does not affect + * children, therefore these two orderings should not interact. + * + * The change in perf_event::ctx does not affect children (as claimed above) + * because the sys_perf_event_open() case will install a new event and break + * the ctx parent<->child relation, and perf_pmu_migrate_context() is only + * concerned with cpuctx and that doesn't have children. + * + * The places that change perf_event::ctx will issue: + * + * perf_remove_from_context(); + * synchronize_rcu(); + * perf_install_in_context(); + * + * to affect the change. The remove_from_context() + synchronize_rcu() should + * quiesce the event, after which we can install it in the new location. This + * means that only external vectors (perf_fops, prctl) can perturb the event + * while in transit. Therefore all such accessors should also acquire + * perf_event_context::mutex to serialize against this. + * + * However; because event->ctx can change while we're waiting to acquire + * ctx->mutex we must be careful and use the below perf_event_ctx_lock() + * function. + * + * Lock order: + * task_struct::perf_event_mutex + * perf_event_context::mutex + * perf_event_context::lock + * perf_event::child_mutex; + * perf_event::mmap_mutex + * mmap_sem + */ +static struct perf_event_context *perf_event_ctx_lock(struct perf_event *event) +{ + struct perf_event_context *ctx; + +again: + rcu_read_lock(); + ctx = ACCESS_ONCE(event->ctx); + if (!atomic_inc_not_zero(&ctx->refcount)) { + rcu_read_unlock(); + goto again; + } + rcu_read_unlock(); + + mutex_lock(&ctx->mutex); + if (event->ctx != ctx) { + mutex_unlock(&ctx->mutex); + put_ctx(ctx); + goto again; + } + + return ctx; +} + +static void perf_event_ctx_unlock(struct perf_event *event, + struct perf_event_context *ctx) +{ + mutex_unlock(&ctx->mutex); + put_ctx(ctx); +} + static void unclone_ctx(struct perf_event_context *ctx) { if (ctx->parent_ctx) { @@ -1245,7 +1316,7 @@ static int __perf_event_disable(void *info) * is the current context on this CPU and preemption is disabled, * hence we can't get into perf_event_task_sched_out for this context. */ -void perf_event_disable(struct perf_event *event) +static void _perf_event_disable(struct perf_event *event) { struct perf_event_context *ctx = event->ctx; struct task_struct *task = ctx->task; @@ -1287,6 +1358,19 @@ retry: raw_spin_unlock_irq(&ctx->lock); } +/* + * Strictly speaking kernel users cannot create groups and therefore this + * interface does not need the perf_event_ctx_lock() magic. + */ +void perf_event_disable(struct perf_event *event) +{ + struct perf_event_context *ctx; + + ctx = perf_event_ctx_lock(event); + _perf_event_disable(event); + perf_event_ctx_unlock(event, ctx); +} + static void perf_set_shadow_time(struct perf_event *event, struct perf_event_context *ctx, u64 tstamp) @@ -1580,6 +1664,8 @@ perf_install_in_context(struct perf_event_context *ctx, lockdep_assert_held(&ctx->mutex); event->ctx = ctx; + if (event->cpu != -1) + event->cpu = cpu; if (!task) { /* @@ -1720,7 +1806,7 @@ unlock: * perf_event_for_each_child or perf_event_for_each as described * for perf_event_disable. */ -void perf_event_enable(struct perf_event *event) +static void _perf_event_enable(struct perf_event *event) { struct perf_event_context *ctx = event->ctx; struct task_struct *task = ctx->task; @@ -1777,7 +1863,19 @@ out: raw_spin_unlock_irq(&ctx->lock); } -static int perf_event_refresh(struct perf_event *event, int refresh) +/* + * See perf_event_disable(); + */ +void perf_event_enable(struct perf_event *event) +{ + struct perf_event_context *ctx; + + ctx = perf_event_ctx_lock(event); + _perf_event_enable(event); + perf_event_ctx_unlock(event, ctx); +} + +static int _perf_event_refresh(struct perf_event *event, int refresh) { /* * not supported on inherited events @@ -1786,11 +1884,26 @@ static int perf_event_refresh(struct perf_event *event, int refresh) return -EINVAL; atomic_add(refresh, &event->event_limit); - perf_event_enable(event); + _perf_event_enable(event); return 0; } +/* + * See perf_event_disable() + */ +int perf_event_refresh(struct perf_event *event, int refresh) +{ + struct perf_event_context *ctx; + int ret; + + ctx = perf_event_ctx_lock(event); + ret = _perf_event_refresh(event, refresh); + perf_event_ctx_unlock(event, ctx); + + return ret; +} + static void ctx_sched_out(struct perf_event_context *ctx, struct perf_cpu_context *cpuctx, enum event_type_t event_type) @@ -3034,7 +3147,16 @@ static void put_event(struct perf_event *event) rcu_read_unlock(); if (owner) { - mutex_lock(&owner->perf_event_mutex); + /* + * If we're here through perf_event_exit_task() we're already + * holding ctx->mutex which would be an inversion wrt. the + * normal lock order. + * + * However we can safely take this lock because its the child + * ctx->mutex. + */ + mutex_lock_nested(&owner->perf_event_mutex, SINGLE_DEPTH_NESTING); + /* * We have to re-check the event->owner field, if it is cleared * we raced with perf_event_exit_task(), acquiring the mutex @@ -3086,12 +3208,13 @@ static int perf_event_read_group(struct perf_event *event, u64 read_format, char __user *buf) { struct perf_event *leader = event->group_leader, *sub; - int n = 0, size = 0, ret = -EFAULT; struct perf_event_context *ctx = leader->ctx; - u64 values[5]; + int n = 0, size = 0, ret; u64 count, enabled, running; + u64 values[5]; + + lockdep_assert_held(&ctx->mutex); - mutex_lock(&ctx->mutex); count = perf_event_read_value(leader, &enabled, &running); values[n++] = 1 + leader->nr_siblings; @@ -3106,7 +3229,7 @@ static int perf_event_read_group(struct perf_event *event, size = n * sizeof(u64); if (copy_to_user(buf, values, size)) - goto unlock; + return -EFAULT; ret = size; @@ -3120,14 +3243,12 @@ static int perf_event_read_group(struct perf_event *event, size = n * sizeof(u64); if (copy_to_user(buf + ret, values, size)) { - ret = -EFAULT; - goto unlock; + return -EFAULT; } ret += size; } -unlock: - mutex_unlock(&ctx->mutex); + return ret; } @@ -3186,8 +3307,14 @@ static ssize_t perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct perf_event *event = file->private_data; + struct perf_event_context *ctx; + int ret; + + ctx = perf_event_ctx_lock(event); + ret = perf_read_hw(event, buf, count); + perf_event_ctx_unlock(event, ctx); - return perf_read_hw(event, buf, count); + return ret; } static unsigned int perf_poll(struct file *file, poll_table *wait) @@ -3207,7 +3334,7 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) return events; } -static void perf_event_reset(struct perf_event *event) +static void _perf_event_reset(struct perf_event *event) { (void)perf_event_read(event); local64_set(&event->count, 0); @@ -3306,25 +3433,24 @@ static int perf_event_set_output(struct perf_event *event, struct perf_event *output_event); static int perf_event_set_filter(struct perf_event *event, void __user *arg); -static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned long arg) { - struct perf_event *event = file->private_data; void (*func)(struct perf_event *); u32 flags = arg; switch (cmd) { case PERF_EVENT_IOC_ENABLE: - func = perf_event_enable; + func = _perf_event_enable; break; case PERF_EVENT_IOC_DISABLE: - func = perf_event_disable; + func = _perf_event_disable; break; case PERF_EVENT_IOC_RESET: - func = perf_event_reset; + func = _perf_event_reset; break; case PERF_EVENT_IOC_REFRESH: - return perf_event_refresh(event, arg); + return _perf_event_refresh(event, arg); case PERF_EVENT_IOC_PERIOD: return perf_event_period(event, (u64 __user *)arg); @@ -3365,13 +3491,30 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; } +static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct perf_event *event = file->private_data; + struct perf_event_context *ctx; + long ret; + + ctx = perf_event_ctx_lock(event); + ret = _perf_ioctl(event, cmd, arg); + perf_event_ctx_unlock(event, ctx); + + return ret; +} + int perf_event_task_enable(void) { + struct perf_event_context *ctx; struct perf_event *event; mutex_lock(¤t->perf_event_mutex); - list_for_each_entry(event, ¤t->perf_event_list, owner_entry) - perf_event_for_each_child(event, perf_event_enable); + list_for_each_entry(event, ¤t->perf_event_list, owner_entry) { + ctx = perf_event_ctx_lock(event); + perf_event_for_each_child(event, _perf_event_enable); + perf_event_ctx_unlock(event, ctx); + } mutex_unlock(¤t->perf_event_mutex); return 0; @@ -3379,11 +3522,15 @@ int perf_event_task_enable(void) int perf_event_task_disable(void) { + struct perf_event_context *ctx; struct perf_event *event; mutex_lock(¤t->perf_event_mutex); - list_for_each_entry(event, ¤t->perf_event_list, owner_entry) - perf_event_for_each_child(event, perf_event_disable); + list_for_each_entry(event, ¤t->perf_event_list, owner_entry) { + ctx = perf_event_ctx_lock(event); + perf_event_for_each_child(event, _perf_event_disable); + perf_event_ctx_unlock(event, ctx); + } mutex_unlock(¤t->perf_event_mutex); return 0; @@ -5416,7 +5563,6 @@ static int swevent_hlist_get_cpu(struct perf_event *event, int cpu) int err = 0; mutex_lock(&swhash->hlist_mutex); - if (!swevent_hlist_deref(swhash) && cpu_online(cpu)) { struct swevent_hlist *hlist; @@ -6216,6 +6362,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, if (!group_leader) group_leader = event; + mutex_init(&event->group_leader_mutex); mutex_init(&event->child_mutex); INIT_LIST_HEAD(&event->child_list); @@ -6444,6 +6591,15 @@ out: return ret; } +static void mutex_lock_double(struct mutex *a, struct mutex *b) +{ + if (b < a) + swap(a, b); + + mutex_lock(a); + mutex_lock_nested(b, SINGLE_DEPTH_NESTING); +} + /** * sys_perf_event_open - open a performance event, associate it to a task/cpu * @@ -6459,7 +6615,7 @@ SYSCALL_DEFINE5(perf_event_open, struct perf_event *group_leader = NULL, *output_event = NULL; struct perf_event *event, *sibling; struct perf_event_attr attr; - struct perf_event_context *ctx; + struct perf_event_context *ctx, *uninitialized_var(gctx); struct file *event_file = NULL; struct file *group_file = NULL; struct task_struct *task = NULL; @@ -6513,6 +6669,16 @@ SYSCALL_DEFINE5(perf_event_open, group_leader = NULL; } + /* + * Take the group_leader's group_leader_mutex before observing + * anything in the group leader that leads to changes in ctx, + * many of which may be changing on another thread. + * In particular, we want to take this lock before deciding + * whether we need to move_group. + */ + if (group_leader) + mutex_lock(&group_leader->group_leader_mutex); + if (pid != -1 && !(flags & PERF_FLAG_PID_CGROUP)) { task = find_lively_task_by_vpid(pid); if (IS_ERR(task)) { @@ -6572,7 +6738,7 @@ SYSCALL_DEFINE5(perf_event_open, /* * Get the target context (task or percpu): */ - ctx = find_get_context(pmu, task, cpu); + ctx = find_get_context(pmu, task, event->cpu); if (IS_ERR(ctx)) { err = PTR_ERR(ctx); goto err_alloc; @@ -6627,9 +6793,14 @@ SYSCALL_DEFINE5(perf_event_open, } if (move_group) { - struct perf_event_context *gctx = group_leader->ctx; + gctx = group_leader->ctx; + + /* + * See perf_event_ctx_lock() for comments on the details + * of swizzling perf_event::ctx. + */ + mutex_lock_double(&gctx->mutex, &ctx->mutex); - mutex_lock(&gctx->mutex); perf_remove_from_context(group_leader); /* @@ -6644,28 +6815,41 @@ SYSCALL_DEFINE5(perf_event_open, perf_event__state_init(sibling); put_ctx(gctx); } - mutex_unlock(&gctx->mutex); - put_ctx(gctx); + } else { + mutex_lock(&ctx->mutex); } WARN_ON_ONCE(ctx->parent_ctx); - mutex_lock(&ctx->mutex); if (move_group) { - perf_install_in_context(ctx, group_leader, cpu); + /* + * Wait for everybody to stop referencing the events through + * the old lists, before installing it on new lists. + */ + synchronize_rcu(); + + perf_install_in_context(ctx, group_leader, event->cpu); get_ctx(ctx); list_for_each_entry(sibling, &group_leader->sibling_list, group_entry) { - perf_install_in_context(ctx, sibling, cpu); + perf_install_in_context(ctx, sibling, event->cpu); get_ctx(ctx); } } - perf_install_in_context(ctx, event, cpu); + perf_install_in_context(ctx, event, event->cpu); ++ctx->generation; perf_unpin_context(ctx); + + if (move_group) { + mutex_unlock(&gctx->mutex); + put_ctx(gctx); + } mutex_unlock(&ctx->mutex); + if (group_leader) + mutex_unlock(&group_leader->group_leader_mutex); + event->owner = current; mutex_lock(¤t->perf_event_mutex); @@ -6697,6 +6881,8 @@ err_task: if (task) put_task_struct(task); err_group_fd: + if (group_leader) + mutex_unlock(&group_leader->group_leader_mutex); fput_light(group_file, fput_needed); err_fd: put_unused_fd(event_fd); @@ -6751,6 +6937,42 @@ err: } EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter); +void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu) +{ + struct perf_event_context *src_ctx; + struct perf_event_context *dst_ctx; + struct perf_event *event, *tmp; + LIST_HEAD(events); + + src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx; + dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx; + + /* + * See perf_event_ctx_lock() for comments on the details + * of swizzling perf_event::ctx. + */ + mutex_lock_double(&src_ctx->mutex, &dst_ctx->mutex); + list_for_each_entry_safe(event, tmp, &src_ctx->event_list, + event_entry) { + perf_remove_from_context(event); + put_ctx(src_ctx); + list_add(&event->event_entry, &events); + } + + synchronize_rcu(); + + list_for_each_entry_safe(event, tmp, &events, event_entry) { + list_del(&event->event_entry); + if (event->state >= PERF_EVENT_STATE_OFF) + event->state = PERF_EVENT_STATE_INACTIVE; + perf_install_in_context(dst_ctx, event, dst_cpu); + get_ctx(dst_ctx); + } + mutex_unlock(&dst_ctx->mutex); + mutex_unlock(&src_ctx->mutex); +} +EXPORT_SYMBOL_GPL(perf_pmu_migrate_context); + static void sync_child_event(struct perf_event *child_event, struct task_struct *child) { @@ -7309,12 +7531,6 @@ static void perf_event_exit_cpu_context(int cpu) static void perf_event_exit_cpu(int cpu) { - struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); - - mutex_lock(&swhash->hlist_mutex); - swevent_hlist_release(swhash); - mutex_unlock(&swhash->hlist_mutex); - perf_event_exit_cpu_context(cpu); } #else diff --git a/kernel/exit.c b/kernel/exit.c index 97dd317..6b8a7af 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -68,6 +68,7 @@ static void __unhash_process(struct task_struct *p, bool group_dead) detach_pid(p, PIDTYPE_SID); list_del_rcu(&p->tasks); + delete_from_adj_tree(p); list_del_init(&p->sibling); __this_cpu_dec(process_counts); } diff --git a/kernel/fork.c b/kernel/fork.c index 158ca4f..ba7e2bc 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -317,6 +317,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) account_kernel_stack(ti, 1); + RB_CLEAR_NODE(&tsk->adj_node); + return tsk; out: @@ -1009,6 +1011,10 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) sig->oom_score_adj = current->signal->oom_score_adj; sig->oom_score_adj_min = current->signal->oom_score_adj_min; +#ifdef CONFIG_ANDROID_LMK_ADJ_RBTREE + RB_CLEAR_NODE(&sig->adj_node); +#endif + mutex_init(&sig->cred_guard_mutex); return 0; @@ -1375,6 +1381,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, attach_pid(p, PIDTYPE_SID, task_session(current)); list_add_tail(&p->sibling, &p->real_parent->children); list_add_tail_rcu(&p->tasks, &init_task.tasks); + add_2_adj_tree(p); __this_cpu_inc(process_counts); } attach_pid(p, PIDTYPE_PID, pid); diff --git a/kernel/futex.c b/kernel/futex.c index 7517c78..c7c19cb 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -588,55 +588,6 @@ void exit_pi_state_list(struct task_struct *curr) raw_spin_unlock_irq(&curr->pi_lock); } -/* - * We need to check the following states: - * - * Waiter | pi_state | pi->owner | uTID | uODIED | ? - * - * [1] NULL | --- | --- | 0 | 0/1 | Valid - * [2] NULL | --- | --- | >0 | 0/1 | Valid - * - * [3] Found | NULL | -- | Any | 0/1 | Invalid - * - * [4] Found | Found | NULL | 0 | 1 | Valid - * [5] Found | Found | NULL | >0 | 1 | Invalid - * - * [6] Found | Found | task | 0 | 1 | Valid - * - * [7] Found | Found | NULL | Any | 0 | Invalid - * - * [8] Found | Found | task | ==taskTID | 0/1 | Valid - * [9] Found | Found | task | 0 | 0 | Invalid - * [10] Found | Found | task | !=taskTID | 0/1 | Invalid - * - * [1] Indicates that the kernel can acquire the futex atomically. We - * came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit. - * - * [2] Valid, if TID does not belong to a kernel thread. If no matching - * thread is found then it indicates that the owner TID has died. - * - * [3] Invalid. The waiter is queued on a non PI futex - * - * [4] Valid state after exit_robust_list(), which sets the user space - * value to FUTEX_WAITERS | FUTEX_OWNER_DIED. - * - * [5] The user space value got manipulated between exit_robust_list() - * and exit_pi_state_list() - * - * [6] Valid state after exit_pi_state_list() which sets the new owner in - * the pi_state but cannot access the user space value. - * - * [7] pi_state->owner can only be NULL when the OWNER_DIED bit is set. - * - * [8] Owner and user space value match - * - * [9] There is no transient state which sets the user space TID to 0 - * except exit_robust_list(), but this is indicated by the - * FUTEX_OWNER_DIED bit. See [4] - * - * [10] There is no transient state which leaves owner and user space - * TID out of sync. - */ static int lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, union futex_key *key, struct futex_pi_state **ps) @@ -652,13 +603,12 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, plist_for_each_entry_safe(this, next, head, list) { if (match_futex(&this->key, key)) { /* - * Sanity check the waiter before increasing - * the refcount and attaching to it. + * Another waiter already exists - bump up + * the refcount and return its pi_state: */ pi_state = this->pi_state; /* - * Userspace might have messed up non-PI and - * PI futexes [3] + * Userspace might have messed up non-PI and PI futexes */ if (unlikely(!pi_state)) return -EINVAL; @@ -666,70 +616,34 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, WARN_ON(!atomic_read(&pi_state->refcount)); /* - * Handle the owner died case: + * When pi_state->owner is NULL then the owner died + * and another waiter is on the fly. pi_state->owner + * is fixed up by the task which acquires + * pi_state->rt_mutex. + * + * We do not check for pid == 0 which can happen when + * the owner died and robust_list_exit() cleared the + * TID. */ - if (uval & FUTEX_OWNER_DIED) { + if (pid && pi_state->owner) { /* - * exit_pi_state_list sets owner to NULL and - * wakes the topmost waiter. The task which - * acquires the pi_state->rt_mutex will fixup - * owner. + * Bail out if user space manipulated the + * futex value. */ - if (!pi_state->owner) { - /* - * No pi state owner, but the user - * space TID is not 0. Inconsistent - * state. [5] - */ - if (pid) - return -EINVAL; - /* - * Take a ref on the state and - * return. [4] - */ - goto out_state; - } - - /* - * If TID is 0, then either the dying owner - * has not yet executed exit_pi_state_list() - * or some waiter acquired the rtmutex in the - * pi state, but did not yet fixup the TID in - * user space. - * - * Take a ref on the state and return. [6] - */ - if (!pid) - goto out_state; - } else { - /* - * If the owner died bit is not set, - * then the pi_state must have an - * owner. [7] - */ - if (!pi_state->owner) + if (pid != task_pid_vnr(pi_state->owner)) return -EINVAL; } - /* - * Bail out if user space manipulated the - * futex value. If pi state exists then the - * owner TID must be the same as the user - * space TID. [9/10] - */ - if (pid != task_pid_vnr(pi_state->owner)) - return -EINVAL; - - out_state: atomic_inc(&pi_state->refcount); *ps = pi_state; + return 0; } } /* * We are the first waiter - try to look up the real owner and attach - * the new pi_state to it, but bail out when TID = 0 [1] + * the new pi_state to it, but bail out when TID = 0 */ if (!pid) return -ESRCH; @@ -737,11 +651,6 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, if (!p) return -ESRCH; - if (!p->mm) { - put_task_struct(p); - return -EPERM; - } - /* * We need to look at the task state flags to figure out, * whether the task is exiting. To protect against the do_exit @@ -762,9 +671,6 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, return ret; } - /* - * No existing pi state. First waiter. [2] - */ pi_state = alloc_pi_state(); /* @@ -836,18 +742,10 @@ retry: return -EDEADLK; /* - * Surprise - we got the lock, but we do not trust user space at all. + * Surprise - we got the lock. Just return to userspace: */ - if (unlikely(!curval)) { - /* - * We verify whether there is kernel state for this - * futex. If not, we can safely assume, that the 0 -> - * TID transition is correct. If state exists, we do - * not bother to fixup the user space state as it was - * corrupted already. - */ - return futex_top_waiter(hb, key) ? -EINVAL : 1; - } + if (unlikely(!curval)) + return 1; uval = curval; @@ -977,7 +875,6 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) struct task_struct *new_owner; struct futex_pi_state *pi_state = this->pi_state; u32 curval, newval; - int ret = 0; if (!pi_state) return -EINVAL; @@ -1001,19 +898,23 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) new_owner = this->task; /* - * We pass it to the next owner. The WAITERS bit is always - * kept enabled while there is PI state around. We cleanup the - * owner died bit, because we are the owner. + * We pass it to the next owner. (The WAITERS bit is always + * kept enabled while there is PI state around. We must also + * preserve the owner died bit.) */ - newval = FUTEX_WAITERS | task_pid_vnr(new_owner); + if (!(uval & FUTEX_OWNER_DIED)) { + int ret = 0; - if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) - ret = -EFAULT; - else if (curval != uval) - ret = -EINVAL; - if (ret) { - raw_spin_unlock(&pi_state->pi_mutex.wait_lock); - return ret; + newval = FUTEX_WAITERS | task_pid_vnr(new_owner); + + if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) + ret = -EFAULT; + else if (curval != uval) + ret = -EINVAL; + if (ret) { + raw_spin_unlock(&pi_state->pi_mutex.wait_lock); + return ret; + } } raw_spin_lock_irq(&pi_state->owner->pi_lock); @@ -1292,7 +1193,7 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, * * Returns: * 0 - failed to acquire the lock atomicly - * >0 - acquired the lock, return value is vpid of the top_waiter + * 1 - acquired the lock * <0 - error */ static int futex_proxy_trylock_atomic(u32 __user *pifutex, @@ -1303,7 +1204,7 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, { struct futex_q *top_waiter = NULL; u32 curval; - int ret, vpid; + int ret; if (get_futex_value_locked(&curval, pifutex)) return -EFAULT; @@ -1331,14 +1232,11 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, * the contended case or if set_waiters is 1. The pi_state is returned * in ps in contended cases. */ - vpid = task_pid_vnr(top_waiter->task); ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task, set_waiters); - if (ret == 1) { + if (ret == 1) requeue_pi_wake_futex(top_waiter, key2, hb2); - return vpid; - } return ret; } @@ -1370,6 +1268,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, struct futex_hash_bucket *hb1, *hb2; struct plist_head *head1; struct futex_q *this, *next; + u32 curval2; if (requeue_pi) { /* @@ -1471,25 +1370,16 @@ retry_private: * At this point the top_waiter has either taken uaddr2 or is * waiting on it. If the former, then the pi_state will not * exist yet, look it up one more time to ensure we have a - * reference to it. If the lock was taken, ret contains the - * vpid of the top waiter task. + * reference to it. */ - if (ret > 0) { + if (ret == 1) { WARN_ON(pi_state); drop_count++; task_count++; - /* - * If we acquired the lock, then the user - * space value of uaddr2 should be vpid. It - * cannot be changed by the top waiter as it - * is blocked on hb2 lock if it tries to do - * so. If something fiddled with it behind our - * back the pi state lookup might unearth - * it. So we rather use the known value than - * rereading and handing potential crap to - * lookup_pi_state. - */ - ret = lookup_pi_state(ret, hb2, &key2, &pi_state); + ret = get_futex_value_locked(&curval2, uaddr2); + if (!ret) + ret = lookup_pi_state(curval2, hb2, &key2, + &pi_state); } switch (ret) { @@ -2259,10 +2149,9 @@ retry: /* * To avoid races, try to do the TID -> 0 atomic transition * again. If it succeeds then we can return without waking - * anyone else up. We only try this if neither the waiters nor - * the owner died bit are set. + * anyone else up: */ - if (!(uval & ~FUTEX_TID_MASK) && + if (!(uval & FUTEX_OWNER_DIED) && cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0)) goto pi_faulted; /* @@ -2294,9 +2183,11 @@ retry: /* * No waiters - kernel unlocks the futex: */ - ret = unlock_futex_pi(uaddr, uval); - if (ret == -EFAULT) - goto pi_faulted; + if (!(uval & FUTEX_OWNER_DIED)) { + ret = unlock_futex_pi(uaddr, uval); + if (ret == -EFAULT) + goto pi_faulted; + } out_unlock: spin_unlock(&hb->lock); diff --git a/kernel/power/earlysuspend.c b/kernel/power/earlysuspend.c index e6303fd..f0fb629 100644 --- a/kernel/power/earlysuspend.c +++ b/kernel/power/earlysuspend.c @@ -20,9 +20,6 @@ #include <linux/syscalls.h> /* sys_sync */ #include <linux/wakelock.h> #include <linux/workqueue.h> -#ifdef CONFIG_ZRAM_FOR_ANDROID -#include <asm/atomic.h> -#endif /* CONFIG_ZRAM_FOR_ANDROID */ #include "power.h" @@ -32,10 +29,6 @@ enum { DEBUG_VERBOSE = 1U << 3, }; static int debug_mask = DEBUG_USER_STATE; -#ifdef CONFIG_ZRAM_FOR_ANDROID -atomic_t optimize_comp_on = ATOMIC_INIT(0); -EXPORT_SYMBOL(optimize_comp_on); -#endif /* CONFIG_ZRAM_FOR_ANDROID */ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); @@ -102,9 +95,6 @@ static void early_suspend(struct work_struct *work) mutex_lock(&early_suspend_lock); spin_lock_irqsave(&state_lock, irqflags); -#ifdef CONFIG_ZRAM_FOR_ANDROID - atomic_set(&optimize_comp_on, 1); -#endif /* CONFIG_ZRAM_FOR_ANDROID */ if (state == SUSPEND_REQUESTED) state |= SUSPENDED; else @@ -156,9 +146,6 @@ static void late_resume(struct work_struct *work) mutex_lock(&early_suspend_lock); spin_lock_irqsave(&state_lock, irqflags); -#ifdef CONFIG_ZRAM_FOR_ANDROID - atomic_set(&optimize_comp_on, 0); -#endif /* CONFIG_ZRAM_FOR_ANDROID */ if (state == SUSPENDED) state &= ~SUSPENDED; else diff --git a/kernel/sys.c b/kernel/sys.c index be53817..79b66c0 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -40,6 +40,9 @@ #include <linux/syscore_ops.h> #include <linux/version.h> #include <linux/ctype.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/mempolicy.h> #include <linux/compat.h> #include <linux/syscalls.h> @@ -1660,6 +1663,146 @@ SYSCALL_DEFINE1(umask, int, mask) return mask; } + +static int prctl_update_vma_anon_name(struct vm_area_struct *vma, + struct vm_area_struct **prev, + unsigned long start, unsigned long end, + const char __user *name_addr) +{ + struct mm_struct * mm = vma->vm_mm; + int error = 0; + pgoff_t pgoff; + + if (name_addr == vma_get_anon_name(vma)) { + *prev = vma; + goto out; + } + + pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); + *prev = vma_merge(mm, *prev, start, end, vma->vm_flags, vma->anon_vma, + vma->vm_file, pgoff, vma_policy(vma), + name_addr); + if (*prev) { + vma = *prev; + goto success; + } + + *prev = vma; + + if (start != vma->vm_start) { + error = split_vma(mm, vma, start, 1); + if (error) + goto out; + } + + if (end != vma->vm_end) { + error = split_vma(mm, vma, end, 0); + if (error) + goto out; + } + +success: + if (!vma->vm_file) + vma->shared.anon_name = name_addr; + +out: + if (error == -ENOMEM) + error = -EAGAIN; + return error; +} + +static int prctl_set_vma_anon_name(unsigned long start, unsigned long end, + unsigned long arg) +{ + unsigned long tmp; + struct vm_area_struct * vma, *prev; + int unmapped_error = 0; + int error = -EINVAL; + + /* + * If the interval [start,end) covers some unmapped address + * ranges, just ignore them, but return -ENOMEM at the end. + * - this matches the handling in madvise. + */ + vma = find_vma_prev(current->mm, start, &prev); + if (vma && start > vma->vm_start) + prev = vma; + + for (;;) { + /* Still start < end. */ + error = -ENOMEM; + if (!vma) + return error; + + /* Here start < (end|vma->vm_end). */ + if (start < vma->vm_start) { + unmapped_error = -ENOMEM; + start = vma->vm_start; + if (start >= end) + return error; + } + + /* Here vma->vm_start <= start < (end|vma->vm_end) */ + tmp = vma->vm_end; + if (end < tmp) + tmp = end; + + /* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */ + error = prctl_update_vma_anon_name(vma, &prev, start, end, + (const char __user *)arg); + if (error) + return error; + start = tmp; + if (prev && start < prev->vm_end) + start = prev->vm_end; + error = unmapped_error; + if (start >= end) + return error; + if (prev) + vma = prev->vm_next; + else /* madvise_remove dropped mmap_sem */ + vma = find_vma(current->mm, start); + } +} + +static int prctl_set_vma(unsigned long opt, unsigned long start, + unsigned long len_in, unsigned long arg) +{ + struct mm_struct *mm = current->mm; + int error; + unsigned long len; + unsigned long end; + + if (start & ~PAGE_MASK) + return -EINVAL; + len = (len_in + ~PAGE_MASK) & PAGE_MASK; + + /* Check to see whether len was rounded up from small -ve to zero */ + if (len_in && !len) + return -EINVAL; + + end = start + len; + if (end < start) + return -EINVAL; + + if (end == start) + return 0; + + down_write(&mm->mmap_sem); + + switch (opt) { + case PR_SET_VMA_ANON_NAME: + error = prctl_set_vma_anon_name(start, end, arg); + break; + default: + error = -EINVAL; + } + + up_write(&mm->mmap_sem); + + return error; +} + SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5) { @@ -1808,6 +1951,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else error = PR_MCE_KILL_DEFAULT; break; + case PR_SET_VMA: + error = prctl_set_vma(arg2, arg3, arg4, arg5); + break; default: error = -EINVAL; break; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 5b6afb2..3cd04f1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1515,6 +1515,20 @@ static struct ctl_table fs_table[] = { .proc_handler = &pipe_proc_fn, .extra1 = &pipe_min_size, }, + { + .procname = "pipe-user-pages-hard", + .data = &pipe_user_pages_hard, + .maxlen = sizeof(pipe_user_pages_hard), + .mode = 0644, + .proc_handler = proc_doulongvec_minmax, + }, + { + .procname = "pipe-user-pages-soft", + .data = &pipe_user_pages_soft, + .maxlen = sizeof(pipe_user_pages_soft), + .mode = 0644, + .proc_handler = proc_doulongvec_minmax, + }, { } }; diff --git a/lib/Kconfig b/lib/Kconfig index 830181c..e07b9a0 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -99,6 +99,15 @@ config LZO_COMPRESS config LZO_DECOMPRESS tristate +config LZ4_COMPRESS + tristate + +config LZ4HC_COMPRESS + tristate + +config LZ4_DECOMPRESS + tristate + source "lib/xz/Kconfig" # @@ -123,6 +132,10 @@ config DECOMPRESS_LZO select LZO_DECOMPRESS tristate +config DECOMPRESS_LZ4 + select LZ4_DECOMPRESS + tristate + # # Generic allocator support is selected if needed # diff --git a/lib/Makefile b/lib/Makefile index 578414a..a2b9ff8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -69,6 +69,9 @@ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ obj-$(CONFIG_BCH) += bch.o obj-$(CONFIG_LZO_COMPRESS) += lzo/ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ +obj-$(CONFIG_LZ4_COMPRESS) += lz4/ +obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/ +obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/ obj-$(CONFIG_XZ_DEC) += xz/ obj-$(CONFIG_RAID6_PQ) += raid6/ @@ -77,6 +80,7 @@ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o +lib-$(CONFIG_DECOMPRESS_LZ4) += decompress_unlz4.o obj-$(CONFIG_TEXTSEARCH) += textsearch.o obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o diff --git a/lib/decompress.c b/lib/decompress.c index 3d766b7..fc3f2dd 100644 --- a/lib/decompress.c +++ b/lib/decompress.c @@ -11,6 +11,7 @@ #include <linux/decompress/unxz.h> #include <linux/decompress/inflate.h> #include <linux/decompress/unlzo.h> +#include <linux/decompress/unlz4.h> #include <linux/types.h> #include <linux/string.h> @@ -30,6 +31,9 @@ #ifndef CONFIG_DECOMPRESS_LZO # define unlzo NULL #endif +#ifndef CONFIG_DECOMPRESS_LZ4 +# define unlz4 NULL +#endif static const struct compress_format { unsigned char magic[2]; @@ -42,6 +46,7 @@ static const struct compress_format { { {0x5d, 0x00}, "lzma", unlzma }, { {0xfd, 0x37}, "xz", unxz }, { {0x89, 0x4c}, "lzo", unlzo }, + { {0x02, 0x21}, "lz4", unlz4 }, { {0, 0}, NULL, NULL } }; diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c new file mode 100644 index 0000000..3e67cfa --- /dev/null +++ b/lib/decompress_unlz4.c @@ -0,0 +1,187 @@ +/* + * Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd + * + * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifdef STATIC +#define PREBOOT +#include "lz4/lz4_decompress.c" +#else +#include <linux/decompress/unlz4.h> +#endif +#include <linux/types.h> +#include <linux/lz4.h> +#include <linux/decompress/mm.h> +#include <linux/compiler.h> + +#include <asm/unaligned.h> + +/* + * Note: Uncompressed chunk size is used in the compressor side + * (userspace side for compression). + * It is hardcoded because there is not proper way to extract it + * from the binary stream which is generated by the preliminary + * version of LZ4 tool so far. + */ +#define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20) +#define ARCHIVE_MAGICNUMBER 0x184C2102 + +STATIC inline int INIT unlz4(u8 *input, int in_len, + int (*fill) (void *, unsigned int), + int (*flush) (void *, unsigned int), + u8 *output, int *posp, + void (*error) (char *x)) +{ + int ret = -1; + size_t chunksize = 0; + size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE; + u8 *inp; + u8 *inp_start; + u8 *outp; + int size = in_len; +#ifdef PREBOOT + size_t out_len = get_unaligned_le32(input + in_len); +#endif + size_t dest_len; + + + if (output) { + outp = output; + } else if (!flush) { + error("NULL output pointer and no flush function provided"); + goto exit_0; + } else { + outp = large_malloc(uncomp_chunksize); + if (!outp) { + error("Could not allocate output buffer"); + goto exit_0; + } + } + + if (input && fill) { + error("Both input pointer and fill function provided,"); + goto exit_1; + } else if (input) { + inp = input; + } else if (!fill) { + error("NULL input pointer and missing fill function"); + goto exit_1; + } else { + inp = large_malloc(lz4_compressbound(uncomp_chunksize)); + if (!inp) { + error("Could not allocate input buffer"); + goto exit_1; + } + } + inp_start = inp; + + if (posp) + *posp = 0; + + if (fill) + fill(inp, 4); + + chunksize = get_unaligned_le32(inp); + if (chunksize == ARCHIVE_MAGICNUMBER) { + inp += 4; + size -= 4; + } else { + error("invalid header"); + goto exit_2; + } + + if (posp) + *posp += 4; + + for (;;) { + + if (fill) + fill(inp, 4); + + chunksize = get_unaligned_le32(inp); + if (chunksize == ARCHIVE_MAGICNUMBER) { + inp += 4; + size -= 4; + if (posp) + *posp += 4; + continue; + } + inp += 4; + size -= 4; + + if (posp) + *posp += 4; + + if (fill) { + if (chunksize > lz4_compressbound(uncomp_chunksize)) { + error("chunk length is longer than allocated"); + goto exit_2; + } + fill(inp, chunksize); + } +#ifdef PREBOOT + if (out_len >= uncomp_chunksize) { + dest_len = uncomp_chunksize; + out_len -= dest_len; + } else + dest_len = out_len; + ret = lz4_decompress(inp, &chunksize, outp, dest_len); +#else + dest_len = uncomp_chunksize; + ret = lz4_decompress_unknownoutputsize(inp, chunksize, outp, + &dest_len); +#endif + if (ret < 0) { + error("Decoding failed"); + goto exit_2; + } + + if (flush && flush(outp, dest_len) != dest_len) + goto exit_2; + if (output) + outp += dest_len; + if (posp) + *posp += chunksize; + + size -= chunksize; + + if (size == 0) + break; + else if (size < 0) { + error("data corrupted"); + goto exit_2; + } + + inp += chunksize; + if (fill) + inp = inp_start; + } + + ret = 0; +exit_2: + if (!input) + large_free(inp_start); +exit_1: + if (!output) + large_free(outp); +exit_0: + return ret; +} + +#ifdef PREBOOT +STATIC int INIT decompress(unsigned char *buf, int in_len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *output, + int *posp, + void(*error)(char *x) + ) +{ + return unlz4(buf, in_len - 4, fill, flush, output, posp, error); +} +#endif diff --git a/lib/lz4/Makefile b/lib/lz4/Makefile new file mode 100644 index 0000000..8085d04 --- /dev/null +++ b/lib/lz4/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_LZ4_COMPRESS) += lz4_compress.o +obj-$(CONFIG_LZ4HC_COMPRESS) += lz4hc_compress.o +obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o diff --git a/lib/lz4/lz4_compress.c b/lib/lz4/lz4_compress.c new file mode 100644 index 0000000..28321d8 --- /dev/null +++ b/lib/lz4/lz4_compress.c @@ -0,0 +1,443 @@ +/* + * LZ4 - Fast LZ compression algorithm + * Copyright (C) 2011-2012, Yann Collet. + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html + * - LZ4 source repository : http://code.google.com/p/lz4/ + * + * Changed for kernel use by: + * Chanho Min <chanho.min@lge.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/lz4.h> +#include <asm/unaligned.h> +#include "lz4defs.h" + +/* + * LZ4_compressCtx : + * ----------------- + * Compress 'isize' bytes from 'source' into an output buffer 'dest' of + * maximum size 'maxOutputSize'. * If it cannot achieve it, compression + * will stop, and result of the function will be zero. + * return : the number of bytes written in buffer 'dest', or 0 if the + * compression fails + */ +static inline int lz4_compressctx(void *ctx, + const char *source, + char *dest, + int isize, + int maxoutputsize) +{ + HTYPE *hashtable = (HTYPE *)ctx; + const u8 *ip = (u8 *)source; +#if LZ4_ARCH64 + const BYTE * const base = ip; +#else + const int base = 0; +#endif + const u8 *anchor = ip; + const u8 *const iend = ip + isize; + const u8 *const mflimit = iend - MFLIMIT; + #define MATCHLIMIT (iend - LASTLITERALS) + + u8 *op = (u8 *) dest; + u8 *const oend = op + maxoutputsize; + int length; + const int skipstrength = SKIPSTRENGTH; + u32 forwardh; + int lastrun; + + /* Init */ + if (isize < MINLENGTH) + goto _last_literals; + + memset((void *)hashtable, 0, LZ4_MEM_COMPRESS); + + /* First Byte */ + hashtable[LZ4_HASH_VALUE(ip)] = ip - base; + ip++; + forwardh = LZ4_HASH_VALUE(ip); + + /* Main Loop */ + for (;;) { + int findmatchattempts = (1U << skipstrength) + 3; + const u8 *forwardip = ip; + const u8 *ref; + u8 *token; + + /* Find a match */ + do { + u32 h = forwardh; + int step = findmatchattempts++ >> skipstrength; + ip = forwardip; + forwardip = ip + step; + + if (unlikely(forwardip > mflimit)) + goto _last_literals; + + forwardh = LZ4_HASH_VALUE(forwardip); + ref = base + hashtable[h]; + hashtable[h] = ip - base; + } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip))); + + /* Catch up */ + while ((ip > anchor) && (ref > (u8 *)source) && + unlikely(ip[-1] == ref[-1])) { + ip--; + ref--; + } + + /* Encode Literal length */ + length = (int)(ip - anchor); + token = op++; + /* check output limit */ + if (unlikely(op + length + (2 + 1 + LASTLITERALS) + + (length >> 8) > oend)) + return 0; + + if (length >= (int)RUN_MASK) { + int len; + *token = (RUN_MASK << ML_BITS); + len = length - RUN_MASK; + for (; len > 254 ; len -= 255) + *op++ = 255; + *op++ = (u8)len; + } else + *token = (length << ML_BITS); + + /* Copy Literals */ + LZ4_BLINDCOPY(anchor, op, length); +_next_match: + /* Encode Offset */ + LZ4_WRITE_LITTLEENDIAN_16(op, (u16)(ip - ref)); + + /* Start Counting */ + ip += MINMATCH; + /* MinMatch verified */ + ref += MINMATCH; + anchor = ip; + while (likely(ip < MATCHLIMIT - (STEPSIZE - 1))) { + #if LZ4_ARCH64 + u64 diff = A64(ref) ^ A64(ip); + #else + u32 diff = A32(ref) ^ A32(ip); + #endif + if (!diff) { + ip += STEPSIZE; + ref += STEPSIZE; + continue; + } + ip += LZ4_NBCOMMONBYTES(diff); + goto _endcount; + } + #if LZ4_ARCH64 + if ((ip < (MATCHLIMIT - 3)) && (A32(ref) == A32(ip))) { + ip += 4; + ref += 4; + } + #endif + if ((ip < (MATCHLIMIT - 1)) && (A16(ref) == A16(ip))) { + ip += 2; + ref += 2; + } + if ((ip < MATCHLIMIT) && (*ref == *ip)) + ip++; +_endcount: + /* Encode MatchLength */ + length = (int)(ip - anchor); + /* Check output limit */ + if (unlikely(op + (1 + LASTLITERALS) + (length >> 8) > oend)) + return 0; + if (length >= (int)ML_MASK) { + *token += ML_MASK; + length -= ML_MASK; + for (; length > 509 ; length -= 510) { + *op++ = 255; + *op++ = 255; + } + if (length > 254) { + length -= 255; + *op++ = 255; + } + *op++ = (u8)length; + } else + *token += length; + + /* Test end of chunk */ + if (ip > mflimit) { + anchor = ip; + break; + } + + /* Fill table */ + hashtable[LZ4_HASH_VALUE(ip-2)] = ip - 2 - base; + + /* Test next position */ + ref = base + hashtable[LZ4_HASH_VALUE(ip)]; + hashtable[LZ4_HASH_VALUE(ip)] = ip - base; + if ((ref > ip - (MAX_DISTANCE + 1)) && (A32(ref) == A32(ip))) { + token = op++; + *token = 0; + goto _next_match; + } + + /* Prepare next loop */ + anchor = ip++; + forwardh = LZ4_HASH_VALUE(ip); + } + +_last_literals: + /* Encode Last Literals */ + lastrun = (int)(iend - anchor); + if (((char *)op - dest) + lastrun + 1 + + ((lastrun + 255 - RUN_MASK) / 255) > (u32)maxoutputsize) + return 0; + + if (lastrun >= (int)RUN_MASK) { + *op++ = (RUN_MASK << ML_BITS); + lastrun -= RUN_MASK; + for (; lastrun > 254 ; lastrun -= 255) + *op++ = 255; + *op++ = (u8)lastrun; + } else + *op++ = (lastrun << ML_BITS); + memcpy(op, anchor, iend - anchor); + op += iend - anchor; + + /* End */ + return (int)(((char *)op) - dest); +} + +static inline int lz4_compress64kctx(void *ctx, + const char *source, + char *dest, + int isize, + int maxoutputsize) +{ + u16 *hashtable = (u16 *)ctx; + const u8 *ip = (u8 *) source; + const u8 *anchor = ip; + const u8 *const base = ip; + const u8 *const iend = ip + isize; + const u8 *const mflimit = iend - MFLIMIT; + #define MATCHLIMIT (iend - LASTLITERALS) + + u8 *op = (u8 *) dest; + u8 *const oend = op + maxoutputsize; + int len, length; + const int skipstrength = SKIPSTRENGTH; + u32 forwardh; + int lastrun; + + /* Init */ + if (isize < MINLENGTH) + goto _last_literals; + + memset((void *)hashtable, 0, LZ4_MEM_COMPRESS); + + /* First Byte */ + ip++; + forwardh = LZ4_HASH64K_VALUE(ip); + + /* Main Loop */ + for (;;) { + int findmatchattempts = (1U << skipstrength) + 3; + const u8 *forwardip = ip; + const u8 *ref; + u8 *token; + + /* Find a match */ + do { + u32 h = forwardh; + int step = findmatchattempts++ >> skipstrength; + ip = forwardip; + forwardip = ip + step; + + if (forwardip > mflimit) + goto _last_literals; + + forwardh = LZ4_HASH64K_VALUE(forwardip); + ref = base + hashtable[h]; + hashtable[h] = (u16)(ip - base); + } while (A32(ref) != A32(ip)); + + /* Catch up */ + while ((ip > anchor) && (ref > (u8 *)source) + && (ip[-1] == ref[-1])) { + ip--; + ref--; + } + + /* Encode Literal length */ + length = (int)(ip - anchor); + token = op++; + /* Check output limit */ + if (unlikely(op + length + (2 + 1 + LASTLITERALS) + + (length >> 8) > oend)) + return 0; + if (length >= (int)RUN_MASK) { + *token = (RUN_MASK << ML_BITS); + len = length - RUN_MASK; + for (; len > 254 ; len -= 255) + *op++ = 255; + *op++ = (u8)len; + } else + *token = (length << ML_BITS); + + /* Copy Literals */ + LZ4_BLINDCOPY(anchor, op, length); + +_next_match: + /* Encode Offset */ + LZ4_WRITE_LITTLEENDIAN_16(op, (u16)(ip - ref)); + + /* Start Counting */ + ip += MINMATCH; + /* MinMatch verified */ + ref += MINMATCH; + anchor = ip; + + while (ip < MATCHLIMIT - (STEPSIZE - 1)) { + #if LZ4_ARCH64 + u64 diff = A64(ref) ^ A64(ip); + #else + u32 diff = A32(ref) ^ A32(ip); + #endif + + if (!diff) { + ip += STEPSIZE; + ref += STEPSIZE; + continue; + } + ip += LZ4_NBCOMMONBYTES(diff); + goto _endcount; + } + #if LZ4_ARCH64 + if ((ip < (MATCHLIMIT - 3)) && (A32(ref) == A32(ip))) { + ip += 4; + ref += 4; + } + #endif + if ((ip < (MATCHLIMIT - 1)) && (A16(ref) == A16(ip))) { + ip += 2; + ref += 2; + } + if ((ip < MATCHLIMIT) && (*ref == *ip)) + ip++; +_endcount: + + /* Encode MatchLength */ + len = (int)(ip - anchor); + /* Check output limit */ + if (unlikely(op + (1 + LASTLITERALS) + (len >> 8) > oend)) + return 0; + if (len >= (int)ML_MASK) { + *token += ML_MASK; + len -= ML_MASK; + for (; len > 509 ; len -= 510) { + *op++ = 255; + *op++ = 255; + } + if (len > 254) { + len -= 255; + *op++ = 255; + } + *op++ = (u8)len; + } else + *token += len; + + /* Test end of chunk */ + if (ip > mflimit) { + anchor = ip; + break; + } + + /* Fill table */ + hashtable[LZ4_HASH64K_VALUE(ip-2)] = (u16)(ip - 2 - base); + + /* Test next position */ + ref = base + hashtable[LZ4_HASH64K_VALUE(ip)]; + hashtable[LZ4_HASH64K_VALUE(ip)] = (u16)(ip - base); + if (A32(ref) == A32(ip)) { + token = op++; + *token = 0; + goto _next_match; + } + + /* Prepare next loop */ + anchor = ip++; + forwardh = LZ4_HASH64K_VALUE(ip); + } + +_last_literals: + /* Encode Last Literals */ + lastrun = (int)(iend - anchor); + if (op + lastrun + 1 + (lastrun - RUN_MASK + 255) / 255 > oend) + return 0; + if (lastrun >= (int)RUN_MASK) { + *op++ = (RUN_MASK << ML_BITS); + lastrun -= RUN_MASK; + for (; lastrun > 254 ; lastrun -= 255) + *op++ = 255; + *op++ = (u8)lastrun; + } else + *op++ = (lastrun << ML_BITS); + memcpy(op, anchor, iend - anchor); + op += iend - anchor; + /* End */ + return (int)(((char *)op) - dest); +} + +int lz4_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem) +{ + int ret = -1; + int out_len = 0; + + if (src_len < LZ4_64KLIMIT) + out_len = lz4_compress64kctx(wrkmem, src, dst, src_len, + lz4_compressbound(src_len)); + else + out_len = lz4_compressctx(wrkmem, src, dst, src_len, + lz4_compressbound(src_len)); + + if (out_len < 0) + goto exit; + + *dst_len = out_len; + + return 0; +exit: + return ret; +} +EXPORT_SYMBOL(lz4_compress); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("LZ4 compressor"); diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c new file mode 100644 index 0000000..7a85967 --- /dev/null +++ b/lib/lz4/lz4_decompress.c @@ -0,0 +1,334 @@ +/* + * LZ4 Decompressor for Linux kernel + * + * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com> + * + * Based on LZ4 implementation by Yann Collet. + * + * LZ4 - Fast LZ compression algorithm + * Copyright (C) 2011-2012, Yann Collet. + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html + * - LZ4 source repository : http://code.google.com/p/lz4/ + */ + +#ifndef STATIC +#include <linux/module.h> +#include <linux/kernel.h> +#endif +#include <linux/lz4.h> + +#include <asm/unaligned.h> + +#include "lz4defs.h" + +static int lz4_uncompress(const char *source, char *dest, int osize) +{ + const BYTE *ip = (const BYTE *) source; + const BYTE *ref; + BYTE *op = (BYTE *) dest; + BYTE * const oend = op + osize; + BYTE *cpy; + unsigned token; + size_t length; + size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; +#if LZ4_ARCH64 + size_t dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; +#endif + + while (1) { + + /* get runlength */ + token = *ip++; + length = (token >> ML_BITS); + if (length == RUN_MASK) { + size_t len; + + len = *ip++; + for (; len == 255; length += 255) + len = *ip++; + if (unlikely(length > (size_t)(length + len))) + goto _output_error; + length += len; + } + + /* copy literals */ + cpy = op + length; + if (unlikely(cpy > oend - COPYLENGTH)) { + /* + * Error: not enough place for another match + * (min 4) + 5 literals + */ + if (cpy != oend) + goto _output_error; + + memcpy(op, ip, length); + ip += length; + break; /* EOF */ + } + LZ4_WILDCOPY(ip, op, cpy); + ip -= (op - cpy); + op = cpy; + + /* get offset */ + LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); + ip += 2; + + /* Error: offset create reference outside destination buffer */ + if (unlikely(ref < (BYTE *const) dest)) + goto _output_error; + + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + for (; *ip == 255; length += 255) + ip++; + if (unlikely(length > (size_t)(length + *ip))) + goto _output_error; + length += *ip++; + } + + /* copy repeated sequence */ + if (unlikely((op - ref) < STEPSIZE)) { +#if LZ4_ARCH64 + size_t dec64 = dec64table[op - ref]; +#else + const int dec64 = 0; +#endif + op[0] = ref[0]; + op[1] = ref[1]; + op[2] = ref[2]; + op[3] = ref[3]; + op += 4; + ref += 4; + ref -= dec32table[op-ref]; + PUT4(ref, op); + op += STEPSIZE - 4; + ref -= dec64; + } else { + LZ4_COPYSTEP(ref, op); + } + cpy = op + length - (STEPSIZE - 4); + if (cpy > (oend - COPYLENGTH)) { + + /* Error: request to write beyond destination buffer */ + if (cpy > oend) + goto _output_error; + LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); + while (op < cpy) + *op++ = *ref++; + op = cpy; + /* + * Check EOF (should never happen, since last 5 bytes + * are supposed to be literals) + */ + if (op == oend) + goto _output_error; + continue; + } + LZ4_SECURECOPY(ref, op, cpy); + op = cpy; /* correction */ + } + /* end of decoding */ + return (int) (((char *)ip) - source); + + /* write overflow error detected */ +_output_error: + return -1; +} + +static int lz4_uncompress_unknownoutputsize(const char *source, char *dest, + int isize, size_t maxoutputsize) +{ + const BYTE *ip = (const BYTE *) source; + const BYTE *const iend = ip + isize; + const BYTE *ref; + + + BYTE *op = (BYTE *) dest; + BYTE * const oend = op + maxoutputsize; + BYTE *cpy; + + size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; +#if LZ4_ARCH64 + size_t dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; +#endif + + /* Main Loop */ + while (ip < iend) { + + unsigned token; + size_t length; + + /* get runlength */ + token = *ip++; + length = (token >> ML_BITS); + if (length == RUN_MASK) { + int s = 255; + while ((ip < iend) && (s == 255)) { + s = *ip++; + if (unlikely(length > (size_t)(length + s))) + goto _output_error; + length += s; + } + } + /* copy literals */ + cpy = op + length; + if ((cpy > oend - COPYLENGTH) || + (ip + length > iend - COPYLENGTH)) { + + if (cpy > oend) + goto _output_error;/* writes beyond buffer */ + + if (ip + length != iend) + goto _output_error;/* + * Error: LZ4 format requires + * to consume all input + * at this stage + */ + memcpy(op, ip, length); + op += length; + break;/* Necessarily EOF, due to parsing restrictions */ + } + LZ4_WILDCOPY(ip, op, cpy); + ip -= (op - cpy); + op = cpy; + + /* get offset */ + LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); + ip += 2; + if (ref < (BYTE * const) dest) + goto _output_error; + /* + * Error : offset creates reference + * outside of destination buffer + */ + + /* get matchlength */ + length = (token & ML_MASK); + if (length == ML_MASK) { + while (ip < iend) { + int s = *ip++; + if (unlikely(length > (size_t)(length + s))) + goto _output_error; + length += s; + if (s == 255) + continue; + break; + } + } + + /* copy repeated sequence */ + if (unlikely((op - ref) < STEPSIZE)) { +#if LZ4_ARCH64 + size_t dec64 = dec64table[op - ref]; +#else + const int dec64 = 0; +#endif + op[0] = ref[0]; + op[1] = ref[1]; + op[2] = ref[2]; + op[3] = ref[3]; + op += 4; + ref += 4; + ref -= dec32table[op - ref]; + PUT4(ref, op); + op += STEPSIZE - 4; + ref -= dec64; + } else { + LZ4_COPYSTEP(ref, op); + } + cpy = op + length - (STEPSIZE-4); + if (cpy > oend - COPYLENGTH) { + if (cpy > oend) + goto _output_error; /* write outside of buf */ + + LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); + while (op < cpy) + *op++ = *ref++; + op = cpy; + /* + * Check EOF (should never happen, since last 5 bytes + * are supposed to be literals) + */ + if (op == oend) + goto _output_error; + continue; + } + LZ4_SECURECOPY(ref, op, cpy); + op = cpy; /* correction */ + } + /* end of decoding */ + return (int) (((char *) op) - dest); + + /* write overflow error detected */ +_output_error: + return -1; +} + +int lz4_decompress(const unsigned char *src, size_t *src_len, + unsigned char *dest, size_t actual_dest_len) +{ + int ret = -1; + int input_len = 0; + + input_len = lz4_uncompress(src, dest, actual_dest_len); + if (input_len < 0) + goto exit_0; + *src_len = input_len; + + return 0; +exit_0: + return ret; +} +#ifndef STATIC +EXPORT_SYMBOL(lz4_decompress); +#endif + +int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len, + unsigned char *dest, size_t *dest_len) +{ + int ret = -1; + int out_len = 0; + + out_len = lz4_uncompress_unknownoutputsize(src, dest, src_len, + *dest_len); + if (out_len < 0) + goto exit_0; + *dest_len = out_len; + + return 0; +exit_0: + return ret; +} +#ifndef STATIC +EXPORT_SYMBOL(lz4_decompress_unknownoutputsize); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("LZ4 Decompressor"); +#endif diff --git a/lib/lz4/lz4defs.h b/lib/lz4/lz4defs.h new file mode 100644 index 0000000..9b4182f --- /dev/null +++ b/lib/lz4/lz4defs.h @@ -0,0 +1,157 @@ +/* + * lz4defs.h -- architecture specific defines + * + * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Detects 64 bits mode + */ +#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) \ + || defined(__ppc64__) || defined(__LP64__)) +#define LZ4_ARCH64 1 +#else +#define LZ4_ARCH64 0 +#endif + +/* + * Architecture-specific macros + */ +#define ARM_EFFICIENT_UNALIGNED_ACCESS +#define BYTE u8 +typedef struct _U16_S { u16 v; } U16_S; +typedef struct _U32_S { u32 v; } U32_S; +typedef struct _U64_S { u64 v; } U64_S; +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) \ + || defined(CONFIG_ARM) && __LINUX_ARM_ARCH__ >= 6 \ + && defined(ARM_EFFICIENT_UNALIGNED_ACCESS) + +#define A16(x) (((U16_S *)(x))->v) +#define A32(x) (((U32_S *)(x))->v) +#define A64(x) (((U64_S *)(x))->v) + +#define PUT4(s, d) (A32(d) = A32(s)) +#define PUT8(s, d) (A64(d) = A64(s)) +#define LZ4_WRITE_LITTLEENDIAN_16(p, v) \ + do { \ + A16(p) = v; \ + p += 2; \ + } while (0) +#else /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ + +#define A64(x) get_unaligned((u64 *)&(((U16_S *)(x))->v)) +#define A32(x) get_unaligned((u32 *)&(((U16_S *)(x))->v)) +#define A16(x) get_unaligned((u16 *)&(((U16_S *)(x))->v)) + +#define PUT4(s, d) \ + put_unaligned(get_unaligned((const u32 *) s), (u32 *) d) +#define PUT8(s, d) \ + put_unaligned(get_unaligned((const u64 *) s), (u64 *) d) + +#define LZ4_WRITE_LITTLEENDIAN_16(p, v) \ + do { \ + put_unaligned(v, (u16 *)(p)); \ + p += 2; \ + } while (0) +#endif + +#define COPYLENGTH 8 +#define ML_BITS 4 +#define ML_MASK ((1U << ML_BITS) - 1) +#define RUN_BITS (8 - ML_BITS) +#define RUN_MASK ((1U << RUN_BITS) - 1) +#define MEMORY_USAGE 14 +#define MINMATCH 4 +#define SKIPSTRENGTH 6 +#define LASTLITERALS 5 +#define MFLIMIT (COPYLENGTH + MINMATCH) +#define MINLENGTH (MFLIMIT + 1) +#define MAXD_LOG 16 +#define MAXD (1 << MAXD_LOG) +#define MAXD_MASK (u32)(MAXD - 1) +#define MAX_DISTANCE (MAXD - 1) +#define HASH_LOG (MAXD_LOG - 1) +#define HASHTABLESIZE (1 << HASH_LOG) +#define MAX_NB_ATTEMPTS 256 +#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH) +#define LZ4_64KLIMIT ((1<<16) + (MFLIMIT - 1)) +#define HASHLOG64K ((MEMORY_USAGE - 2) + 1) +#define HASH64KTABLESIZE (1U << HASHLOG64K) +#define LZ4_HASH_VALUE(p) (((A32(p)) * 2654435761U) >> \ + ((MINMATCH * 8) - (MEMORY_USAGE-2))) +#define LZ4_HASH64K_VALUE(p) (((A32(p)) * 2654435761U) >> \ + ((MINMATCH * 8) - HASHLOG64K)) +#define HASH_VALUE(p) (((A32(p)) * 2654435761U) >> \ + ((MINMATCH * 8) - HASH_LOG)) + +#if LZ4_ARCH64/* 64-bit */ +#define STEPSIZE 8 + +#define LZ4_COPYSTEP(s, d) \ + do { \ + PUT8(s, d); \ + d += 8; \ + s += 8; \ + } while (0) + +#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d) + +#define LZ4_SECURECOPY(s, d, e) \ + do { \ + if (d < e) { \ + LZ4_WILDCOPY(s, d, e); \ + } \ + } while (0) +#define HTYPE u32 + +#ifdef __BIG_ENDIAN +#define LZ4_NBCOMMONBYTES(val) (__builtin_clzll(val) >> 3) +#else +#define LZ4_NBCOMMONBYTES(val) (__builtin_ctzll(val) >> 3) +#endif + +#else /* 32-bit */ +#define STEPSIZE 4 + +#define LZ4_COPYSTEP(s, d) \ + do { \ + PUT4(s, d); \ + d += 4; \ + s += 4; \ + } while (0) + +#define LZ4_COPYPACKET(s, d) \ + do { \ + LZ4_COPYSTEP(s, d); \ + LZ4_COPYSTEP(s, d); \ + } while (0) + +#define LZ4_SECURECOPY LZ4_WILDCOPY +#define HTYPE const u8* + +#ifdef __BIG_ENDIAN +#define LZ4_NBCOMMONBYTES(val) (__builtin_clz(val) >> 3) +#else +#define LZ4_NBCOMMONBYTES(val) (__builtin_ctz(val) >> 3) +#endif + +#endif + +#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \ + (d = s - get_unaligned_le16(p)) + +#define LZ4_WILDCOPY(s, d, e) \ + do { \ + LZ4_COPYPACKET(s, d); \ + } while (d < e) + +#define LZ4_BLINDCOPY(s, d, l) \ + do { \ + u8 *e = (d) + l; \ + LZ4_WILDCOPY(s, d, e); \ + d = e; \ + } while (0) diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c new file mode 100644 index 0000000..f344f76 --- /dev/null +++ b/lib/lz4/lz4hc_compress.c @@ -0,0 +1,539 @@ +/* + * LZ4 HC - High Compression Mode of LZ4 + * Copyright (C) 2011-2012, Yann Collet. + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html + * - LZ4 source repository : http://code.google.com/p/lz4/ + * + * Changed for kernel use by: + * Chanho Min <chanho.min@lge.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/lz4.h> +#include <asm/unaligned.h> +#include "lz4defs.h" + +struct lz4hc_data { + const u8 *base; + HTYPE hashtable[HASHTABLESIZE]; + u16 chaintable[MAXD]; + const u8 *nexttoupdate; +} __attribute__((__packed__)); + +static inline int lz4hc_init(struct lz4hc_data *hc4, const u8 *base) +{ + memset((void *)hc4->hashtable, 0, sizeof(hc4->hashtable)); + memset(hc4->chaintable, 0xFF, sizeof(hc4->chaintable)); + +#if LZ4_ARCH64 + hc4->nexttoupdate = base + 1; +#else + hc4->nexttoupdate = base; +#endif + hc4->base = base; + return 1; +} + +/* Update chains up to ip (excluded) */ +static inline void lz4hc_insert(struct lz4hc_data *hc4, const u8 *ip) +{ + u16 *chaintable = hc4->chaintable; + HTYPE *hashtable = hc4->hashtable; +#if LZ4_ARCH64 + const BYTE * const base = hc4->base; +#else + const int base = 0; +#endif + + while (hc4->nexttoupdate < ip) { + const u8 *p = hc4->nexttoupdate; + size_t delta = p - (hashtable[HASH_VALUE(p)] + base); + if (delta > MAX_DISTANCE) + delta = MAX_DISTANCE; + chaintable[(size_t)(p) & MAXD_MASK] = (u16)delta; + hashtable[HASH_VALUE(p)] = (p) - base; + hc4->nexttoupdate++; + } +} + +static inline size_t lz4hc_commonlength(const u8 *p1, const u8 *p2, + const u8 *const matchlimit) +{ + const u8 *p1t = p1; + + while (p1t < matchlimit - (STEPSIZE - 1)) { +#if LZ4_ARCH64 + u64 diff = A64(p2) ^ A64(p1t); +#else + u32 diff = A32(p2) ^ A32(p1t); +#endif + if (!diff) { + p1t += STEPSIZE; + p2 += STEPSIZE; + continue; + } + p1t += LZ4_NBCOMMONBYTES(diff); + return p1t - p1; + } +#if LZ4_ARCH64 + if ((p1t < (matchlimit-3)) && (A32(p2) == A32(p1t))) { + p1t += 4; + p2 += 4; + } +#endif + + if ((p1t < (matchlimit - 1)) && (A16(p2) == A16(p1t))) { + p1t += 2; + p2 += 2; + } + if ((p1t < matchlimit) && (*p2 == *p1t)) + p1t++; + return p1t - p1; +} + +static inline int lz4hc_insertandfindbestmatch(struct lz4hc_data *hc4, + const u8 *ip, const u8 *const matchlimit, const u8 **matchpos) +{ + u16 *const chaintable = hc4->chaintable; + HTYPE *const hashtable = hc4->hashtable; + const u8 *ref; +#if LZ4_ARCH64 + const BYTE * const base = hc4->base; +#else + const int base = 0; +#endif + int nbattempts = MAX_NB_ATTEMPTS; + size_t repl = 0, ml = 0; + u16 delta; + + /* HC4 match finder */ + lz4hc_insert(hc4, ip); + ref = hashtable[HASH_VALUE(ip)] + base; + + /* potential repetition */ + if (ref >= ip-4) { + /* confirmed */ + if (A32(ref) == A32(ip)) { + delta = (u16)(ip-ref); + repl = ml = lz4hc_commonlength(ip + MINMATCH, + ref + MINMATCH, matchlimit) + MINMATCH; + *matchpos = ref; + } + ref -= (size_t)chaintable[(size_t)(ref) & MAXD_MASK]; + } + + while ((ref >= ip - MAX_DISTANCE) && nbattempts) { + nbattempts--; + if (*(ref + ml) == *(ip + ml)) { + if (A32(ref) == A32(ip)) { + size_t mlt = + lz4hc_commonlength(ip + MINMATCH, + ref + MINMATCH, matchlimit) + MINMATCH; + if (mlt > ml) { + ml = mlt; + *matchpos = ref; + } + } + } + ref -= (size_t)chaintable[(size_t)(ref) & MAXD_MASK]; + } + + /* Complete table */ + if (repl) { + const BYTE *ptr = ip; + const BYTE *end; + end = ip + repl - (MINMATCH-1); + /* Pre-Load */ + while (ptr < end - delta) { + chaintable[(size_t)(ptr) & MAXD_MASK] = delta; + ptr++; + } + do { + chaintable[(size_t)(ptr) & MAXD_MASK] = delta; + /* Head of chain */ + hashtable[HASH_VALUE(ptr)] = (ptr) - base; + ptr++; + } while (ptr < end); + hc4->nexttoupdate = end; + } + + return (int)ml; +} + +static inline int lz4hc_insertandgetwidermatch(struct lz4hc_data *hc4, + const u8 *ip, const u8 *startlimit, const u8 *matchlimit, int longest, + const u8 **matchpos, const u8 **startpos) +{ + u16 *const chaintable = hc4->chaintable; + HTYPE *const hashtable = hc4->hashtable; +#if LZ4_ARCH64 + const BYTE * const base = hc4->base; +#else + const int base = 0; +#endif + const u8 *ref; + int nbattempts = MAX_NB_ATTEMPTS; + int delta = (int)(ip - startlimit); + + /* First Match */ + lz4hc_insert(hc4, ip); + ref = hashtable[HASH_VALUE(ip)] + base; + + while ((ref >= ip - MAX_DISTANCE) && (ref >= hc4->base) + && (nbattempts)) { + nbattempts--; + if (*(startlimit + longest) == *(ref - delta + longest)) { + if (A32(ref) == A32(ip)) { + const u8 *reft = ref + MINMATCH; + const u8 *ipt = ip + MINMATCH; + const u8 *startt = ip; + + while (ipt < matchlimit-(STEPSIZE - 1)) { + #if LZ4_ARCH64 + u64 diff = A64(reft) ^ A64(ipt); + #else + u32 diff = A32(reft) ^ A32(ipt); + #endif + + if (!diff) { + ipt += STEPSIZE; + reft += STEPSIZE; + continue; + } + ipt += LZ4_NBCOMMONBYTES(diff); + goto _endcount; + } + #if LZ4_ARCH64 + if ((ipt < (matchlimit - 3)) + && (A32(reft) == A32(ipt))) { + ipt += 4; + reft += 4; + } + ipt += 2; + #endif + if ((ipt < (matchlimit - 1)) + && (A16(reft) == A16(ipt))) { + reft += 2; + } + if ((ipt < matchlimit) && (*reft == *ipt)) + ipt++; +_endcount: + reft = ref; + + while ((startt > startlimit) + && (reft > hc4->base) + && (startt[-1] == reft[-1])) { + startt--; + reft--; + } + + if ((ipt - startt) > longest) { + longest = (int)(ipt - startt); + *matchpos = reft; + *startpos = startt; + } + } + } + ref -= (size_t)chaintable[(size_t)(ref) & MAXD_MASK]; + } + return longest; +} + +static inline int lz4_encodesequence(const u8 **ip, u8 **op, const u8 **anchor, + int ml, const u8 *ref) +{ + int length, len; + u8 *token; + + /* Encode Literal length */ + length = (int)(*ip - *anchor); + token = (*op)++; + if (length >= (int)RUN_MASK) { + *token = (RUN_MASK << ML_BITS); + len = length - RUN_MASK; + for (; len > 254 ; len -= 255) + *(*op)++ = 255; + *(*op)++ = (u8)len; + } else + *token = (length << ML_BITS); + + /* Copy Literals */ + LZ4_BLINDCOPY(*anchor, *op, length); + + /* Encode Offset */ + LZ4_WRITE_LITTLEENDIAN_16(*op, (u16)(*ip - ref)); + + /* Encode MatchLength */ + len = (int)(ml - MINMATCH); + if (len >= (int)ML_MASK) { + *token += ML_MASK; + len -= ML_MASK; + for (; len > 509 ; len -= 510) { + *(*op)++ = 255; + *(*op)++ = 255; + } + if (len > 254) { + len -= 255; + *(*op)++ = 255; + } + *(*op)++ = (u8)len; + } else + *token += len; + + /* Prepare next loop */ + *ip += ml; + *anchor = *ip; + + return 0; +} + +static int lz4_compresshcctx(struct lz4hc_data *ctx, + const char *source, + char *dest, + int isize) +{ + const u8 *ip = (const u8 *)source; + const u8 *anchor = ip; + const u8 *const iend = ip + isize; + const u8 *const mflimit = iend - MFLIMIT; + const u8 *const matchlimit = (iend - LASTLITERALS); + + u8 *op = (u8 *)dest; + + int ml, ml2, ml3, ml0; + const u8 *ref = NULL; + const u8 *start2 = NULL; + const u8 *ref2 = NULL; + const u8 *start3 = NULL; + const u8 *ref3 = NULL; + const u8 *start0; + const u8 *ref0; + int lastrun; + + ip++; + + /* Main Loop */ + while (ip < mflimit) { + ml = lz4hc_insertandfindbestmatch(ctx, ip, matchlimit, (&ref)); + if (!ml) { + ip++; + continue; + } + + /* saved, in case we would skip too much */ + start0 = ip; + ref0 = ref; + ml0 = ml; +_search2: + if (ip+ml < mflimit) + ml2 = lz4hc_insertandgetwidermatch(ctx, ip + ml - 2, + ip + 1, matchlimit, ml, &ref2, &start2); + else + ml2 = ml; + /* No better match */ + if (ml2 == ml) { + lz4_encodesequence(&ip, &op, &anchor, ml, ref); + continue; + } + + if (start0 < ip) { + /* empirical */ + if (start2 < ip + ml0) { + ip = start0; + ref = ref0; + ml = ml0; + } + } + /* + * Here, start0==ip + * First Match too small : removed + */ + if ((start2 - ip) < 3) { + ml = ml2; + ip = start2; + ref = ref2; + goto _search2; + } + +_search3: + /* + * Currently we have : + * ml2 > ml1, and + * ip1+3 <= ip2 (usually < ip1+ml1) + */ + if ((start2 - ip) < OPTIMAL_ML) { + int correction; + int new_ml = ml; + if (new_ml > OPTIMAL_ML) + new_ml = OPTIMAL_ML; + if (ip + new_ml > start2 + ml2 - MINMATCH) + new_ml = (int)(start2 - ip) + ml2 - MINMATCH; + correction = new_ml - (int)(start2 - ip); + if (correction > 0) { + start2 += correction; + ref2 += correction; + ml2 -= correction; + } + } + /* + * Now, we have start2 = ip+new_ml, + * with new_ml=min(ml, OPTIMAL_ML=18) + */ + if (start2 + ml2 < mflimit) + ml3 = lz4hc_insertandgetwidermatch(ctx, + start2 + ml2 - 3, start2, matchlimit, + ml2, &ref3, &start3); + else + ml3 = ml2; + + /* No better match : 2 sequences to encode */ + if (ml3 == ml2) { + /* ip & ref are known; Now for ml */ + if (start2 < ip+ml) + ml = (int)(start2 - ip); + + /* Now, encode 2 sequences */ + lz4_encodesequence(&ip, &op, &anchor, ml, ref); + ip = start2; + lz4_encodesequence(&ip, &op, &anchor, ml2, ref2); + continue; + } + + /* Not enough space for match 2 : remove it */ + if (start3 < ip + ml + 3) { + /* + * can write Seq1 immediately ==> Seq2 is removed, + * so Seq3 becomes Seq1 + */ + if (start3 >= (ip + ml)) { + if (start2 < ip + ml) { + int correction = + (int)(ip + ml - start2); + start2 += correction; + ref2 += correction; + ml2 -= correction; + if (ml2 < MINMATCH) { + start2 = start3; + ref2 = ref3; + ml2 = ml3; + } + } + + lz4_encodesequence(&ip, &op, &anchor, ml, ref); + ip = start3; + ref = ref3; + ml = ml3; + + start0 = start2; + ref0 = ref2; + ml0 = ml2; + goto _search2; + } + + start2 = start3; + ref2 = ref3; + ml2 = ml3; + goto _search3; + } + + /* + * OK, now we have 3 ascending matches; let's write at least + * the first one ip & ref are known; Now for ml + */ + if (start2 < ip + ml) { + if ((start2 - ip) < (int)ML_MASK) { + int correction; + if (ml > OPTIMAL_ML) + ml = OPTIMAL_ML; + if (ip + ml > start2 + ml2 - MINMATCH) + ml = (int)(start2 - ip) + ml2 + - MINMATCH; + correction = ml - (int)(start2 - ip); + if (correction > 0) { + start2 += correction; + ref2 += correction; + ml2 -= correction; + } + } else + ml = (int)(start2 - ip); + } + lz4_encodesequence(&ip, &op, &anchor, ml, ref); + + ip = start2; + ref = ref2; + ml = ml2; + + start2 = start3; + ref2 = ref3; + ml2 = ml3; + + goto _search3; + } + + /* Encode Last Literals */ + lastrun = (int)(iend - anchor); + if (lastrun >= (int)RUN_MASK) { + *op++ = (RUN_MASK << ML_BITS); + lastrun -= RUN_MASK; + for (; lastrun > 254 ; lastrun -= 255) + *op++ = 255; + *op++ = (u8) lastrun; + } else + *op++ = (lastrun << ML_BITS); + memcpy(op, anchor, iend - anchor); + op += iend - anchor; + /* End */ + return (int) (((char *)op) - dest); +} + +int lz4hc_compress(const unsigned char *src, size_t src_len, + unsigned char *dst, size_t *dst_len, void *wrkmem) +{ + int ret = -1; + int out_len = 0; + + struct lz4hc_data *hc4 = (struct lz4hc_data *)wrkmem; + lz4hc_init(hc4, (const u8 *)src); + out_len = lz4_compresshcctx((struct lz4hc_data *)hc4, (const u8 *)src, + (char *)dst, (int)src_len); + + if (out_len < 0) + goto exit; + + *dst_len = out_len; + return 0; + +exit: + return ret; +} +EXPORT_SYMBOL(lz4hc_compress); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("LZ4HC compressor"); diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile index e764116..f0f7d7c 100644 --- a/lib/lzo/Makefile +++ b/lib/lzo/Makefile @@ -1,5 +1,5 @@ lzo_compress-objs := lzo1x_compress.o -lzo_decompress-objs := lzo1x_decompress.o +lzo_decompress-objs := lzo1x_decompress_safe.o obj-$(CONFIG_LZO_COMPRESS) += lzo_compress.o obj-$(CONFIG_LZO_DECOMPRESS) += lzo_decompress.o diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c index a604099..236eb21 100644 --- a/lib/lzo/lzo1x_compress.c +++ b/lib/lzo/lzo1x_compress.c @@ -1,194 +1,243 @@ /* - * LZO1X Compressor from MiniLZO + * LZO1X Compressor from LZO * - * Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com> + * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com> * * The full LZO package can be found at: * http://www.oberhumer.com/opensource/lzo/ * - * Changed for kernel use by: + * Changed for Linux kernel use by: * Nitin Gupta <nitingupta910@gmail.com> * Richard Purdie <rpurdie@openedhand.com> */ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/lzo.h> #include <asm/unaligned.h> +#include <linux/lzo.h> #include "lzodefs.h" static noinline size_t -_lzo1x_1_do_compress(const unsigned char *in, size_t in_len, - unsigned char *out, size_t *out_len, void *wrkmem) +lzo1x_1_do_compress(const unsigned char *in, size_t in_len, + unsigned char *out, size_t *out_len, + size_t ti, void *wrkmem) { + const unsigned char *ip; + unsigned char *op; const unsigned char * const in_end = in + in_len; - const unsigned char * const ip_end = in + in_len - M2_MAX_LEN - 5; - const unsigned char ** const dict = wrkmem; - const unsigned char *ip = in, *ii = ip; - const unsigned char *end, *m, *m_pos; - size_t m_off, m_len, dindex; - unsigned char *op = out; + const unsigned char * const ip_end = in + in_len - 20; + const unsigned char *ii; + lzo_dict_t * const dict = (lzo_dict_t *) wrkmem; - ip += 4; + op = out; + ip = in; + ii = ip; + ip += ti < 4 ? 4 - ti : 0; for (;;) { - dindex = ((size_t)(0x21 * DX3(ip, 5, 5, 6)) >> 5) & D_MASK; - m_pos = dict[dindex]; - - if (m_pos < in) - goto literal; - - if (ip == m_pos || ((size_t)(ip - m_pos) > M4_MAX_OFFSET)) - goto literal; - - m_off = ip - m_pos; - if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) - goto try_match; - - dindex = (dindex & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f); - m_pos = dict[dindex]; - - if (m_pos < in) - goto literal; - - if (ip == m_pos || ((size_t)(ip - m_pos) > M4_MAX_OFFSET)) - goto literal; - - m_off = ip - m_pos; - if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) - goto try_match; - - goto literal; - -try_match: - if (get_unaligned((const unsigned short *)m_pos) - == get_unaligned((const unsigned short *)ip)) { - if (likely(m_pos[2] == ip[2])) - goto match; - } - + const unsigned char *m_pos; + size_t t, m_len, m_off; + u32 dv; literal: - dict[dindex] = ip; - ++ip; + ip += 1 + ((ip - ii) >> 5); +next: if (unlikely(ip >= ip_end)) break; - continue; - -match: - dict[dindex] = ip; - if (ip != ii) { - size_t t = ip - ii; + dv = get_unaligned_le32(ip); + t = ((dv * 0x1824429d) >> (32 - D_BITS)) & D_MASK; + m_pos = in + dict[t]; + dict[t] = (lzo_dict_t) (ip - in); + if (unlikely(dv != get_unaligned_le32(m_pos))) + goto literal; + ii -= ti; + ti = 0; + t = ip - ii; + if (t != 0) { if (t <= 3) { op[-2] |= t; - } else if (t <= 18) { + COPY4(op, ii); + op += t; + } else if (t <= 16) { *op++ = (t - 3); + COPY8(op, ii); + COPY8(op + 8, ii + 8); + op += t; } else { - size_t tt = t - 18; - - *op++ = 0; - while (tt > 255) { - tt -= 255; + if (t <= 18) { + *op++ = (t - 3); + } else { + size_t tt = t - 18; *op++ = 0; + while (unlikely(tt > 255)) { + tt -= 255; + *op++ = 0; + } + *op++ = tt; } - *op++ = tt; + do { + COPY8(op, ii); + COPY8(op + 8, ii + 8); + op += 16; + ii += 16; + t -= 16; + } while (t >= 16); + if (t > 0) do { + *op++ = *ii++; + } while (--t > 0); } - do { - *op++ = *ii++; - } while (--t > 0); } - ip += 3; - if (m_pos[3] != *ip++ || m_pos[4] != *ip++ - || m_pos[5] != *ip++ || m_pos[6] != *ip++ - || m_pos[7] != *ip++ || m_pos[8] != *ip++) { - --ip; - m_len = ip - ii; + m_len = 4; + { +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ64) + u64 v; + v = get_unaligned((const u64 *) (ip + m_len)) ^ + get_unaligned((const u64 *) (m_pos + m_len)); + if (unlikely(v == 0)) { + do { + m_len += 8; + v = get_unaligned((const u64 *) (ip + m_len)) ^ + get_unaligned((const u64 *) (m_pos + m_len)); + if (unlikely(ip + m_len >= ip_end)) + goto m_len_done; + } while (v == 0); + } +# if defined(__LITTLE_ENDIAN) + m_len += (unsigned) __builtin_ctzll(v) / 8; +# elif defined(__BIG_ENDIAN) + m_len += (unsigned) __builtin_clzll(v) / 8; +# else +# error "missing endian definition" +# endif +#elif defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ32) + u32 v; + v = get_unaligned((const u32 *) (ip + m_len)) ^ + get_unaligned((const u32 *) (m_pos + m_len)); + if (unlikely(v == 0)) { + do { + m_len += 4; + v = get_unaligned((const u32 *) (ip + m_len)) ^ + get_unaligned((const u32 *) (m_pos + m_len)); + if (v != 0) + break; + m_len += 4; + v = get_unaligned((const u32 *) (ip + m_len)) ^ + get_unaligned((const u32 *) (m_pos + m_len)); + if (unlikely(ip + m_len >= ip_end)) + goto m_len_done; + } while (v == 0); + } +# if defined(__LITTLE_ENDIAN) + m_len += (unsigned) __builtin_ctz(v) / 8; +# elif defined(__BIG_ENDIAN) + m_len += (unsigned) __builtin_clz(v) / 8; +# else +# error "missing endian definition" +# endif +#else + if (unlikely(ip[m_len] == m_pos[m_len])) { + do { + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (ip[m_len] != m_pos[m_len]) + break; + m_len += 1; + if (unlikely(ip + m_len >= ip_end)) + goto m_len_done; + } while (ip[m_len] == m_pos[m_len]); + } +#endif + } +m_len_done: - if (m_off <= M2_MAX_OFFSET) { - m_off -= 1; - *op++ = (((m_len - 1) << 5) - | ((m_off & 7) << 2)); - *op++ = (m_off >> 3); - } else if (m_off <= M3_MAX_OFFSET) { - m_off -= 1; + m_off = ip - m_pos; + ip += m_len; + ii = ip; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { + m_off -= 1; + *op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = (m_off >> 3); + } else if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; + if (m_len <= M3_MAX_LEN) *op++ = (M3_MARKER | (m_len - 2)); - goto m3_m4_offset; - } else { - m_off -= 0x4000; - - *op++ = (M4_MARKER | ((m_off & 0x4000) >> 11) - | (m_len - 2)); - goto m3_m4_offset; + else { + m_len -= M3_MAX_LEN; + *op++ = M3_MARKER | 0; + while (unlikely(m_len > 255)) { + m_len -= 255; + *op++ = 0; + } + *op++ = (m_len); } + *op++ = (m_off << 2); + *op++ = (m_off >> 6); } else { - end = in_end; - m = m_pos + M2_MAX_LEN + 1; - - while (ip < end && *m == *ip) { - m++; - ip++; - } - m_len = ip - ii; - - if (m_off <= M3_MAX_OFFSET) { - m_off -= 1; - if (m_len <= 33) { - *op++ = (M3_MARKER | (m_len - 2)); - } else { - m_len -= 33; - *op++ = M3_MARKER | 0; - goto m3_m4_len; - } - } else { - m_off -= 0x4000; - if (m_len <= M4_MAX_LEN) { - *op++ = (M4_MARKER - | ((m_off & 0x4000) >> 11) + m_off -= 0x4000; + if (m_len <= M4_MAX_LEN) + *op++ = (M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2)); - } else { - m_len -= M4_MAX_LEN; - *op++ = (M4_MARKER - | ((m_off & 0x4000) >> 11)); -m3_m4_len: - while (m_len > 255) { - m_len -= 255; - *op++ = 0; - } - - *op++ = (m_len); + else { + m_len -= M4_MAX_LEN; + *op++ = (M4_MARKER | ((m_off >> 11) & 8)); + while (unlikely(m_len > 255)) { + m_len -= 255; + *op++ = 0; } + *op++ = (m_len); } -m3_m4_offset: - *op++ = ((m_off & 63) << 2); + *op++ = (m_off << 2); *op++ = (m_off >> 6); } - - ii = ip; - if (unlikely(ip >= ip_end)) - break; + goto next; } - *out_len = op - out; - return in_end - ii; + return in_end - (ii - ti); } -int lzo1x_1_compress(const unsigned char *in, size_t in_len, unsigned char *out, - size_t *out_len, void *wrkmem) +int lzo1x_1_compress(const unsigned char *in, size_t in_len, + unsigned char *out, size_t *out_len, + void *wrkmem) { - const unsigned char *ii; + const unsigned char *ip = in; unsigned char *op = out; - size_t t; + size_t l = in_len; + size_t t = 0; - if (unlikely(in_len <= M2_MAX_LEN + 5)) { - t = in_len; - } else { - t = _lzo1x_1_do_compress(in, in_len, op, out_len, wrkmem); + while (l > 20) { + size_t ll = l <= (M4_MAX_OFFSET + 1) ? l : (M4_MAX_OFFSET + 1); + uintptr_t ll_end = (uintptr_t) ip + ll; + if ((ll_end + ((t + ll) >> 5)) <= ll_end) + break; + BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS); + memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t)); + t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem); + ip += ll; op += *out_len; + l -= ll; } + t += l; if (t > 0) { - ii = in + in_len - t; + const unsigned char *ii = in + in_len - t; if (op == out && t <= 238) { *op++ = (17 + t); @@ -198,16 +247,21 @@ int lzo1x_1_compress(const unsigned char *in, size_t in_len, unsigned char *out, *op++ = (t - 3); } else { size_t tt = t - 18; - *op++ = 0; while (tt > 255) { tt -= 255; *op++ = 0; } - *op++ = tt; } - do { + if (t >= 16) do { + COPY8(op, ii); + COPY8(op + 8, ii + 8); + op += 16; + ii += 16; + t -= 16; + } while (t >= 16); + if (t > 0) do { *op++ = *ii++; } while (--t > 0); } @@ -223,4 +277,3 @@ EXPORT_SYMBOL_GPL(lzo1x_1_compress); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("LZO1X-1 Compressor"); - diff --git a/lib/lzo/lzo1x_decompress.c b/lib/lzo/lzo1x_decompress.c deleted file mode 100644 index f2fd098..0000000 --- a/lib/lzo/lzo1x_decompress.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * LZO1X Decompressor from MiniLZO - * - * Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com> - * - * The full LZO package can be found at: - * http://www.oberhumer.com/opensource/lzo/ - * - * Changed for kernel use by: - * Nitin Gupta <nitingupta910@gmail.com> - * Richard Purdie <rpurdie@openedhand.com> - */ - -#ifndef STATIC -#include <linux/module.h> -#include <linux/kernel.h> -#endif - -#include <asm/unaligned.h> -#include <linux/lzo.h> -#include "lzodefs.h" - -#define HAVE_IP(x, ip_end, ip) ((size_t)(ip_end - ip) < (x)) -#define HAVE_OP(x, op_end, op) ((size_t)(op_end - op) < (x)) -#define HAVE_LB(m_pos, out, op) (m_pos < out || m_pos >= op) - -#define COPY4(dst, src) \ - put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) - -int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, - unsigned char *out, size_t *out_len) -{ - const unsigned char * const ip_end = in + in_len; - unsigned char * const op_end = out + *out_len; - const unsigned char *ip = in, *m_pos; - unsigned char *op = out; - size_t t; - - *out_len = 0; - - if (*ip > 17) { - t = *ip++ - 17; - if (t < 4) - goto match_next; - if (HAVE_OP(t, op_end, op)) - goto output_overrun; - if (HAVE_IP(t + 1, ip_end, ip)) - goto input_overrun; - do { - *op++ = *ip++; - } while (--t > 0); - goto first_literal_run; - } - - while ((ip < ip_end)) { - t = *ip++; - if (t >= 16) - goto match; - if (t == 0) { - if (HAVE_IP(1, ip_end, ip)) - goto input_overrun; - while (*ip == 0) { - t += 255; - ip++; - if (HAVE_IP(1, ip_end, ip)) - goto input_overrun; - } - t += 15 + *ip++; - } - if (HAVE_OP(t + 3, op_end, op)) - goto output_overrun; - if (HAVE_IP(t + 4, ip_end, ip)) - goto input_overrun; - - COPY4(op, ip); - op += 4; - ip += 4; - if (--t > 0) { - if (t >= 4) { - do { - COPY4(op, ip); - op += 4; - ip += 4; - t -= 4; - } while (t >= 4); - if (t > 0) { - do { - *op++ = *ip++; - } while (--t > 0); - } - } else { - do { - *op++ = *ip++; - } while (--t > 0); - } - } - -first_literal_run: - t = *ip++; - if (t >= 16) - goto match; - m_pos = op - (1 + M2_MAX_OFFSET); - m_pos -= t >> 2; - m_pos -= *ip++ << 2; - - if (HAVE_LB(m_pos, out, op)) - goto lookbehind_overrun; - - if (HAVE_OP(3, op_end, op)) - goto output_overrun; - *op++ = *m_pos++; - *op++ = *m_pos++; - *op++ = *m_pos; - - goto match_done; - - do { -match: - if (t >= 64) { - m_pos = op - 1; - m_pos -= (t >> 2) & 7; - m_pos -= *ip++ << 3; - t = (t >> 5) - 1; - if (HAVE_LB(m_pos, out, op)) - goto lookbehind_overrun; - if (HAVE_OP(t + 3 - 1, op_end, op)) - goto output_overrun; - goto copy_match; - } else if (t >= 32) { - t &= 31; - if (t == 0) { - if (HAVE_IP(1, ip_end, ip)) - goto input_overrun; - while (*ip == 0) { - t += 255; - ip++; - if (HAVE_IP(1, ip_end, ip)) - goto input_overrun; - } - t += 31 + *ip++; - } - m_pos = op - 1; - m_pos -= get_unaligned_le16(ip) >> 2; - ip += 2; - } else if (t >= 16) { - m_pos = op; - m_pos -= (t & 8) << 11; - - t &= 7; - if (t == 0) { - if (HAVE_IP(1, ip_end, ip)) - goto input_overrun; - while (*ip == 0) { - t += 255; - ip++; - if (HAVE_IP(1, ip_end, ip)) - goto input_overrun; - } - t += 7 + *ip++; - } - m_pos -= get_unaligned_le16(ip) >> 2; - ip += 2; - if (m_pos == op) - goto eof_found; - m_pos -= 0x4000; - } else { - m_pos = op - 1; - m_pos -= t >> 2; - m_pos -= *ip++ << 2; - - if (HAVE_LB(m_pos, out, op)) - goto lookbehind_overrun; - if (HAVE_OP(2, op_end, op)) - goto output_overrun; - - *op++ = *m_pos++; - *op++ = *m_pos; - goto match_done; - } - - if (HAVE_LB(m_pos, out, op)) - goto lookbehind_overrun; - if (HAVE_OP(t + 3 - 1, op_end, op)) - goto output_overrun; - - if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { - COPY4(op, m_pos); - op += 4; - m_pos += 4; - t -= 4 - (3 - 1); - do { - COPY4(op, m_pos); - op += 4; - m_pos += 4; - t -= 4; - } while (t >= 4); - if (t > 0) - do { - *op++ = *m_pos++; - } while (--t > 0); - } else { -copy_match: - *op++ = *m_pos++; - *op++ = *m_pos++; - do { - *op++ = *m_pos++; - } while (--t > 0); - } -match_done: - t = ip[-2] & 3; - if (t == 0) - break; -match_next: - if (HAVE_OP(t, op_end, op)) - goto output_overrun; - if (HAVE_IP(t + 1, ip_end, ip)) - goto input_overrun; - - *op++ = *ip++; - if (t > 1) { - *op++ = *ip++; - if (t > 2) - *op++ = *ip++; - } - - t = *ip++; - } while (ip < ip_end); - } - - *out_len = op - out; - return LZO_E_EOF_NOT_FOUND; - -eof_found: - *out_len = op - out; - return (ip == ip_end ? LZO_E_OK : - (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); -input_overrun: - *out_len = op - out; - return LZO_E_INPUT_OVERRUN; - -output_overrun: - *out_len = op - out; - return LZO_E_OUTPUT_OVERRUN; - -lookbehind_overrun: - *out_len = op - out; - return LZO_E_LOOKBEHIND_OVERRUN; -} -#ifndef STATIC -EXPORT_SYMBOL_GPL(lzo1x_decompress_safe); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("LZO1X Decompressor"); - -#endif diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_safe.c new file mode 100644 index 0000000..a5f3d0e --- /dev/null +++ b/lib/lzo/lzo1x_decompress_safe.c @@ -0,0 +1,261 @@ +/* + * LZO1X Decompressor from LZO + * + * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com> + * + * The full LZO package can be found at: + * http://www.oberhumer.com/opensource/lzo/ + * + * Changed for Linux kernel use by: + * Nitin Gupta <nitingupta910@gmail.com> + * Richard Purdie <rpurdie@openedhand.com> + */ + +#ifndef STATIC +#include <linux/module.h> +#include <linux/kernel.h> +#endif +#include <asm/unaligned.h> +#include <linux/lzo.h> +#include "lzodefs.h" + +#define HAVE_IP(t, x) \ + (((size_t)(ip_end - ip) >= (size_t)(t + x)) && \ + (((t + x) >= t) && ((t + x) >= x))) + +#define HAVE_OP(t, x) \ + (((size_t)(op_end - op) >= (size_t)(t + x)) && \ + (((t + x) >= t) && ((t + x) >= x))) + +#define NEED_IP(t, x) \ + do { \ + if (!HAVE_IP(t, x)) \ + goto input_overrun; \ + } while (0) + +#define NEED_OP(t, x) \ + do { \ + if (!HAVE_OP(t, x)) \ + goto output_overrun; \ + } while (0) + +#define TEST_LB(m_pos) \ + do { \ + if ((m_pos) < out) \ + goto lookbehind_overrun; \ + } while (0) + +int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, + unsigned char *out, size_t *out_len) +{ + unsigned char *op; + const unsigned char *ip; + size_t t, next; + size_t state = 0; + const unsigned char *m_pos; + const unsigned char * const ip_end = in + in_len; + unsigned char * const op_end = out + *out_len; + + op = out; + ip = in; + + if (unlikely(in_len < 3)) + goto input_overrun; + if (*ip > 17) { + t = *ip++ - 17; + if (t < 4) { + next = t; + goto match_next; + } + goto copy_literal_run; + } + + for (;;) { + t = *ip++; + if (t < 16) { + if (likely(state == 0)) { + if (unlikely(t == 0)) { + while (unlikely(*ip == 0)) { + t += 255; + ip++; + NEED_IP(1, 0); + } + t += 15 + *ip++; + } + t += 3; +copy_literal_run: +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + if (likely(HAVE_IP(t, 15) && HAVE_OP(t, 15))) { + const unsigned char *ie = ip + t; + unsigned char *oe = op + t; + do { + COPY8(op, ip); + op += 8; + ip += 8; +# if !defined(__arm__) + COPY8(op, ip); + op += 8; + ip += 8; +# endif + } while (ip < ie); + ip = ie; + op = oe; + } else +#endif + { + NEED_OP(t, 0); + NEED_IP(t, 3); + do { + *op++ = *ip++; + } while (--t > 0); + } + state = 4; + continue; + } else if (state != 4) { + next = t & 3; + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; + TEST_LB(m_pos); + NEED_OP(2, 0); + op[0] = m_pos[0]; + op[1] = m_pos[1]; + op += 2; + goto match_next; + } else { + next = t & 3; + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; + t = 3; + } + } else if (t >= 64) { + next = t & 3; + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1 + (3 - 1); + } else if (t >= 32) { + t = (t & 31) + (3 - 1); + if (unlikely(t == 2)) { + while (unlikely(*ip == 0)) { + t += 255; + ip++; + NEED_IP(1, 0); + } + t += 31 + *ip++; + NEED_IP(2, 0); + } + m_pos = op - 1; + next = get_unaligned_le16(ip); + ip += 2; + m_pos -= next >> 2; + next &= 3; + } else { + m_pos = op; + m_pos -= (t & 8) << 11; + t = (t & 7) + (3 - 1); + if (unlikely(t == 2)) { + while (unlikely(*ip == 0)) { + t += 255; + ip++; + NEED_IP(1, 0); + } + t += 7 + *ip++; + NEED_IP(2, 0); + } + next = get_unaligned_le16(ip); + ip += 2; + m_pos -= next >> 2; + next &= 3; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; + } + TEST_LB(m_pos); +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + if (op - m_pos >= 8) { + unsigned char *oe = op + t; + if (likely(HAVE_OP(t, 15))) { + do { + COPY8(op, m_pos); + op += 8; + m_pos += 8; +# if !defined(__arm__) + COPY8(op, m_pos); + op += 8; + m_pos += 8; +# endif + } while (op < oe); + op = oe; + if (HAVE_IP(6, 0)) { + state = next; + COPY4(op, ip); + op += next; + ip += next; + continue; + } + } else { + NEED_OP(t, 0); + do { + *op++ = *m_pos++; + } while (op < oe); + } + } else +#endif + { + unsigned char *oe = op + t; + NEED_OP(t, 0); + op[0] = m_pos[0]; + op[1] = m_pos[1]; + op += 2; + m_pos += 2; + do { + *op++ = *m_pos++; + } while (op < oe); + } +match_next: + state = next; + t = next; +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + if (likely(HAVE_IP(6, 0) && HAVE_OP(4, 0))) { + COPY4(op, ip); + op += t; + ip += t; + } else +#endif + { + NEED_IP(t, 3); + NEED_OP(t, 0); + while (t > 0) { + *op++ = *ip++; + t--; + } + } + } + +eof_found: + *out_len = op - out; + return (t != 3 ? LZO_E_ERROR : + ip == ip_end ? LZO_E_OK : + ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN); + +input_overrun: + *out_len = op - out; + return LZO_E_INPUT_OVERRUN; + +output_overrun: + *out_len = op - out; + return LZO_E_OUTPUT_OVERRUN; + +lookbehind_overrun: + *out_len = op - out; + return LZO_E_LOOKBEHIND_OVERRUN; +} +#ifndef STATIC +EXPORT_SYMBOL_GPL(lzo1x_decompress_safe); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LZO1X Decompressor"); + +#endif diff --git a/lib/lzo/lzodefs.h b/lib/lzo/lzodefs.h index b6d482c..db756cc 100644 --- a/lib/lzo/lzodefs.h +++ b/lib/lzo/lzodefs.h @@ -1,19 +1,43 @@ /* * lzodefs.h -- architecture, OS and compiler specific defines * - * Copyright (C) 1996-2005 Markus F.X.J. Oberhumer <markus@oberhumer.com> + * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com> * * The full LZO package can be found at: * http://www.oberhumer.com/opensource/lzo/ * - * Changed for kernel use by: + * Changed for Linux kernel use by: * Nitin Gupta <nitingupta910@gmail.com> * Richard Purdie <rpurdie@openedhand.com> */ -#define LZO_VERSION 0x2020 -#define LZO_VERSION_STRING "2.02" -#define LZO_VERSION_DATE "Oct 17 2005" + +#if 1 && defined(__arm__) && ((__LINUX_ARM_ARCH__ >= 6) || defined(__ARM_FEATURE_UNALIGNED)) +#define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 +#define COPY4(dst, src) \ + * (u32 *) (void *) (dst) = * (const u32 *) (const void *) (src) +#else +#define COPY4(dst, src) \ + put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) +#endif +#if defined(__x86_64__) +#define COPY8(dst, src) \ + put_unaligned(get_unaligned((const u64 *)(src)), (u64 *)(dst)) +#else +#define COPY8(dst, src) \ + COPY4(dst, src); COPY4((dst) + 4, (src) + 4) +#endif + +#if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) +#error "conflicting endian definitions" +#elif defined(__x86_64__) +#define LZO_USE_CTZ64 1 +#define LZO_USE_CTZ32 1 +#elif defined(__i386__) || defined(__powerpc__) +#define LZO_USE_CTZ32 1 +#elif defined(__arm__) && (__LINUX_ARM_ARCH__ >= 5) +#define LZO_USE_CTZ32 1 +#endif #define M1_MAX_OFFSET 0x0400 #define M2_MAX_OFFSET 0x0800 @@ -34,10 +58,8 @@ #define M3_MARKER 32 #define M4_MARKER 16 -#define D_BITS 14 -#define D_MASK ((1u << D_BITS) - 1) +#define lzo_dict_t unsigned short +#define D_BITS 13 +#define D_SIZE (1u << D_BITS) +#define D_MASK (D_SIZE - 1) #define D_HIGH ((D_MASK >> 1) + 1) - -#define DX2(p, s1, s2) (((((size_t)((p)[2]) << (s2)) ^ (p)[1]) \ - << (s1)) ^ (p)[0]) -#define DX3(p, s1, s2, s3) ((DX2((p)+1, s2, s3) << (s1)) ^ (p)[0]) @@ -371,6 +371,31 @@ config CLEANCACHE If unsure, say Y to enable cleancache +config ZSMALLOC + bool "Memory allocator for compressed pages" + depends on MMU + default n + help + zsmalloc is a slab-based memory allocator designed to store + compressed RAM pages. zsmalloc uses virtual memory mapping + in order to reduce fragmentation. However, this results in a + non-standard allocator interface where a handle, not a pointer, is + returned by an alloc(). This handle must be mapped in order to + access the allocated space. + +config PGTABLE_MAPPING + bool "Use page table mapping to access object in zsmalloc" + depends on ZSMALLOC + help + By default, zsmalloc uses a copy-based object mapping method to + access allocations that span two pages. However, if a particular + architecture (ex, ARM) performs VM mapping faster than copying, + then you should select this. This causes zsmalloc to use page table + mapping rather than copying for object mapping. + + You can check speed with zsmalloc benchmark[1]. + [1] https://github.com/spartacus06/zsmalloc + config CMA bool "Contiguous Memory Allocator framework" # Currently there is only one allocator so force it on diff --git a/mm/Makefile b/mm/Makefile index 9b994ce..47ebf93 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -78,5 +78,7 @@ obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o obj-$(CONFIG_CLEANCACHE) += cleancache.o +obj-$(CONFIG_ZSMALLOC) += zsmalloc.o + obj-$(CONFIG_CMA) += cma.o obj-$(CONFIG_CMA_BEST_FIT) += cma-best-fit.o diff --git a/mm/cleancache.c b/mm/cleancache.c index bcaae4c..83a8241 100644 --- a/mm/cleancache.c +++ b/mm/cleancache.c @@ -160,7 +160,8 @@ void __cleancache_flush_page(struct address_space *mapping, struct page *page) if (pool_id >= 0) { VM_BUG_ON(!PageLocked(page)); if (cleancache_get_key(mapping->host, &key) >= 0) { - (*cleancache_ops.flush_page)(pool_id, key, page->index); + (*cleancache_ops.invalidate_page)(pool_id, + key, page->index); cleancache_flushes++; } } @@ -178,7 +179,7 @@ void __cleancache_flush_inode(struct address_space *mapping) struct cleancache_filekey key = { .u.key = { 0 } }; if (pool_id >= 0 && cleancache_get_key(mapping->host, &key) >= 0) - (*cleancache_ops.flush_inode)(pool_id, key); + (*cleancache_ops.invalidate_inode)(pool_id, key); } EXPORT_SYMBOL(__cleancache_flush_inode); @@ -192,7 +193,7 @@ void __cleancache_flush_fs(struct super_block *sb) if (sb->cleancache_poolid >= 0) { int old_poolid = sb->cleancache_poolid; sb->cleancache_poolid = -1; - (*cleancache_ops.flush_fs)(old_poolid); + (*cleancache_ops.invalidate_fs)(old_poolid); } } EXPORT_SYMBOL(__cleancache_flush_fs); diff --git a/mm/madvise.c b/mm/madvise.c index deabe5f6..5a273af 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -87,7 +87,8 @@ static long madvise_behavior(struct vm_area_struct * vma, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma, - vma->vm_file, pgoff, vma_policy(vma)); + vma->vm_file, pgoff, vma_policy(vma), + vma_get_anon_name(vma)); if (*prev) { vma = *prev; goto success; diff --git a/mm/memory.c b/mm/memory.c index 5331e67..29c8112 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1436,6 +1436,16 @@ int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, } EXPORT_SYMBOL_GPL(zap_vma_ptes); +/* + * FOLL_FORCE can write to even unwritable pte's, but only + * after we've gone through a COW cycle and they are dirty. + */ +static inline bool can_follow_write_pte(pte_t pte, unsigned int flags) +{ + return pte_write(pte) || + ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte)); +} + /** * follow_page - look up a page descriptor from a user-virtual address * @vma: vm_area_struct mapping @address @@ -1518,7 +1528,7 @@ split_fallthrough: pte = *ptep; if (!pte_present(pte)) goto no_page; - if ((flags & FOLL_WRITE) && !pte_write(pte)) + if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) goto unlock; page = vm_normal_page(vma, address, pte); @@ -1832,7 +1842,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, */ if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE)) - foll_flags &= ~FOLL_WRITE; + foll_flags |= FOLL_COW; cond_resched(); } @@ -3140,7 +3150,8 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, mem_cgroup_commit_charge_swapin(page, ptr); swap_free(entry); - if (vm_swap_full() || (vma->vm_flags & VM_LOCKED) || PageMlocked(page)) + if ((PageSwapCache(page) && vm_swap_full(page_swap_info(page))) || + (vma->vm_flags & VM_LOCKED) || PageMlocked(page)) try_to_free_swap(page); unlock_page(page); if (swapcache) { diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 7065fb3..7c8caa9 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -664,8 +664,9 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, vmend = min(end, vma->vm_end); pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); - prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, - vma->anon_vma, vma->vm_file, pgoff, new_pol); + prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, + vma->anon_vma, vma->vm_file, pgoff, + new_pol, vma_get_anon_name(name)); if (prev) { vma = prev; next = vma->vm_next; @@ -321,7 +321,8 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma, - vma->vm_file, pgoff, vma_policy(vma)); + vma->vm_file, pgoff, vma_policy(vma), + vma_get_anon_name(vma)); if (*prev) { vma = *prev; goto success; @@ -656,7 +656,8 @@ again: remove_next = 1 + (end > next->vm_end); * per-vma resources, so we don't attempt to merge those. */ static inline int is_mergeable_vma(struct vm_area_struct *vma, - struct file *file, unsigned long vm_flags) + struct file *file, unsigned long vm_flags, + const char __user *anon_name) { /* VM_CAN_NONLINEAR may get set later by f_op->mmap() */ if ((vma->vm_flags ^ vm_flags) & ~VM_CAN_NONLINEAR) @@ -665,6 +666,8 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma, return 0; if (vma->vm_ops && vma->vm_ops->close) return 0; + if (vma_get_anon_name(vma) != anon_name) + return 0; return 1; } @@ -695,9 +698,10 @@ static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1, */ static int can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, - struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) + struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff, + const char __user *anon_name) { - if (is_mergeable_vma(vma, file, vm_flags) && + if (is_mergeable_vma(vma, file, vm_flags, anon_name) && is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { if (vma->vm_pgoff == vm_pgoff) return 1; @@ -714,9 +718,10 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, */ static int can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags, - struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) + struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff, + const char __user *anon_name) { - if (is_mergeable_vma(vma, file, vm_flags) && + if (is_mergeable_vma(vma, file, vm_flags, anon_name) && is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { pgoff_t vm_pglen; vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; @@ -727,9 +732,9 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags, } /* - * Given a mapping request (addr,end,vm_flags,file,pgoff), figure out - * whether that can be merged with its predecessor or its successor. - * Or both (it neatly fills a hole). + * Given a mapping request (addr,end,vm_flags,file,pgoff,anon_name), + * figure out whether that can be merged with its predecessor or its + * successor. Or both (it neatly fills a hole). * * In most cases - when called for mmap, brk or mremap - [addr,end) is * certain not to be mapped by the time vma_merge is called; but when @@ -759,7 +764,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, struct anon_vma *anon_vma, struct file *file, - pgoff_t pgoff, struct mempolicy *policy) + pgoff_t pgoff, struct mempolicy *policy, + const char __user *anon_name) { pgoff_t pglen = (end - addr) >> PAGE_SHIFT; struct vm_area_struct *area, *next; @@ -785,15 +791,15 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, */ if (prev && prev->vm_end == addr && mpol_equal(vma_policy(prev), policy) && - can_vma_merge_after(prev, vm_flags, - anon_vma, file, pgoff)) { + can_vma_merge_after(prev, vm_flags, anon_vma, + file, pgoff, anon_name)) { /* * OK, it can. Can we now merge in the successor as well? */ if (next && end == next->vm_start && mpol_equal(policy, vma_policy(next)) && - can_vma_merge_before(next, vm_flags, - anon_vma, file, pgoff+pglen) && + can_vma_merge_before(next, vm_flags, anon_vma, + file, pgoff+pglen, anon_name) && is_mergeable_anon_vma(prev->anon_vma, next->anon_vma, NULL)) { /* cases 1, 6 */ @@ -813,8 +819,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, */ if (next && end == next->vm_start && mpol_equal(policy, vma_policy(next)) && - can_vma_merge_before(next, vm_flags, - anon_vma, file, pgoff+pglen)) { + can_vma_merge_before(next, vm_flags, anon_vma, + file, pgoff+pglen, anon_name)) { if (prev && addr < prev->vm_end) /* case 4 */ err = vma_adjust(prev, prev->vm_start, addr, prev->vm_pgoff, NULL); @@ -1251,7 +1257,8 @@ munmap_back: /* * Can we just expand an old mapping? */ - vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, NULL); + vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, + NULL, NULL); if (vma) goto out; @@ -2202,7 +2209,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) /* Can we just expand an old private anonymous mapping? */ vma = vma_merge(mm, prev, addr, addr + len, flags, - NULL, NULL, pgoff, NULL); + NULL, NULL, pgoff, NULL, NULL); if (vma) goto out; @@ -2340,7 +2347,8 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags, - vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma)); + vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), + vma_get_anon_name(vma)); if (new_vma) { /* * Source vma may have been merged into new_vma diff --git a/mm/mprotect.c b/mm/mprotect.c index 5a688a2..5f168eb 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -179,7 +179,8 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, */ pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *pprev = vma_merge(mm, *pprev, start, end, newflags, - vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma)); + vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), + vma_get_anon_name(vma)); if (*pprev) { vma = *pprev; goto success; diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 7c72487..678cf2b 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -38,6 +38,28 @@ int sysctl_oom_kill_allocating_task; int sysctl_oom_dump_tasks = 1; static DEFINE_SPINLOCK(zone_scan_lock); +/* + * compare_swap_oom_score_adj() - compare and swap current's oom_score_adj + * @old_val: old oom_score_adj for compare + * @new_val: new oom_score_adj for swap + * + * Sets the oom_score_adj value for current to @new_val iff its present value is + * @old_val. Usually used to reinstate a previous value to prevent racing with + * userspacing tuning the value in the interim. + */ +void compare_swap_oom_score_adj(int old_val, int new_val) +{ + struct sighand_struct *sighand = current->sighand; + + spin_lock_irq(&sighand->siglock); + if (current->signal->oom_score_adj == old_val) { + current->signal->oom_score_adj = new_val; + delete_from_adj_tree(current); + add_2_adj_tree(current); + } + spin_unlock_irq(&sighand->siglock); +} + /** * test_set_oom_score_adj() - set current's oom_score_adj and return old value * @new_val: new oom_score_adj value diff --git a/mm/page_io.c b/mm/page_io.c index dc76b4d..f57da45 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -18,6 +18,8 @@ #include <linux/bio.h> #include <linux/swapops.h> #include <linux/writeback.h> +#include <linux/aio.h> +#include <linux/blkdev.h> #include <asm/pgtable.h> static struct bio *get_swap_bio(gfp_t gfp_flags, @@ -78,9 +80,49 @@ void end_swap_bio_read(struct bio *bio, int err) imajor(bio->bi_bdev->bd_inode), iminor(bio->bi_bdev->bd_inode), (unsigned long long)bio->bi_sector); - } else { - SetPageUptodate(page); + goto out; + } + + SetPageUptodate(page); + + /* + * There is no guarantee that the page is in swap cache - the software + * suspend code (at least) uses end_swap_bio_read() against a non- + * swapcache page. So we must check PG_swapcache before proceeding with + * this optimization. + */ + if (likely(PageSwapCache(page))) { + /* + * The swap subsystem performs lazy swap slot freeing, + * expecting that the page will be swapped out again. + * So we can avoid an unnecessary write if the page + * isn't redirtied. + * This is good for real swap storage because we can + * reduce unnecessary I/O and enhance wear-leveling + * if an SSD is used as the as swap device. + * But if in-memory swap device (eg zram) is used, + * this causes a duplicated copy between uncompressed + * data in VM-owned memory and compressed data in + * zram-owned memory. So let's free zram-owned memory + * and make the VM-owned decompressed page *dirty*, + * so the page should be swapped out somewhere again if + * we again wish to reclaim it. + */ + struct gendisk *disk = bio->bi_bdev->bd_disk; + if (disk->fops->swap_slot_free_notify) { + swp_entry_t entry; + unsigned long offset; + + entry.val = page_private(page); + offset = swp_offset(entry); + + SetPageDirty(page); + disk->fops->swap_slot_free_notify(bio->bi_bdev, + offset); + } } + +out: unlock_page(page); bio_put(bio); } @@ -1060,17 +1060,8 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) info = SHMEM_I(inode); if (info->flags & VM_LOCKED) goto redirty; -#ifdef CONFIG_ZRAM_FOR_ANDROID - /* - * Modification for compcache - * shmem_writepage can be reason of kernel panic when using swap. - * This modification prevent using swap by shmem. - */ - goto redirty; -#else if (!total_swap_pages) goto redirty; -#endif /* * shmem_backing_dev_info's capabilities prevent regular writeback or diff --git a/mm/swapfile.c b/mm/swapfile.c index 3e5a3a7..4add436 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -69,6 +69,26 @@ static inline unsigned char swap_count(unsigned char ent) return ent & ~SWAP_HAS_CACHE; /* may include SWAP_HAS_CONT flag */ } +bool is_swap_fast(swp_entry_t entry) +{ + struct swap_info_struct *p; + unsigned long type; + + if (non_swap_entry(entry)) + return false; + + type = swp_type(entry); + if (type >= nr_swapfiles) + return false; + + p = swap_info[type]; + + if (p->flags & SWP_FAST) + return true; + + return false; +} + /* returns 1 if swap entry is freed */ static int __try_to_reclaim_swap(struct swap_info_struct *si, unsigned long offset) @@ -289,7 +309,7 @@ checks: scan_base = offset = si->lowest_bit; /* reuse swap entry of cache-only swap if not busy. */ - if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + if (vm_swap_full(si) && si->swap_map[offset] == SWAP_HAS_CACHE) { int swap_was_freed; spin_unlock(&swap_lock); swap_was_freed = __try_to_reclaim_swap(si, offset); @@ -378,7 +398,8 @@ scan: spin_lock(&swap_lock); goto checks; } - if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + if (vm_swap_full(si) && + si->swap_map[offset] == SWAP_HAS_CACHE) { spin_lock(&swap_lock); goto checks; } @@ -393,7 +414,8 @@ scan: spin_lock(&swap_lock); goto checks; } - if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { + if (vm_swap_full(si) && + si->swap_map[offset] == SWAP_HAS_CACHE) { spin_lock(&swap_lock); goto checks; } @@ -708,7 +730,8 @@ int free_swap_and_cache(swp_entry_t entry) * Also recheck PageSwapCache now page is locked (above). */ if (PageSwapCache(page) && !PageWriteback(page) && - (!page_mapped(page) || vm_swap_full())) { + (!page_mapped(page) || + vm_swap_full(page_swap_info(page)))) { delete_from_swap_cache(page); SetPageDirty(page); } @@ -2012,159 +2035,6 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, return nr_extents; } -#ifdef CONFIG_ZRAM_FOR_ANDROID -int swapon(char *name, int swap_flags) -{ - struct swap_info_struct *p; - - struct file *swap_file = NULL; - struct address_space *mapping; - int i; - int prio; - int error; - union swap_header *swap_header; - int nr_extents; - sector_t span; - unsigned long maxpages; - unsigned char *swap_map = NULL; - struct page *page = NULL; - struct inode *inode = NULL; - - p = alloc_swap_info(); - if (IS_ERR(p)) - return PTR_ERR(p); - - swap_file = filp_open(name, O_RDWR | O_LARGEFILE, 0); - if (IS_ERR(swap_file)) { - error = PTR_ERR(swap_file); - swap_file = NULL; - printk("zfqin, filp_open failed\n"); - goto bad_swap; - } - - printk("zfqin, filp_open succeeded\n"); - p->swap_file = swap_file; - mapping = swap_file->f_mapping; - - for (i = 0; i < nr_swapfiles; i++) { - struct swap_info_struct *q = swap_info[i]; - - if (q == p || !q->swap_file) - continue; - if (mapping == q->swap_file->f_mapping) { - error = -EBUSY; - goto bad_swap; - } - } - - inode = mapping->host; - /* If S_ISREG(inode->i_mode) will do mutex_lock(&inode->i_mutex); */ - error = claim_swapfile(p, inode); - if (unlikely(error)) - goto bad_swap; - - /* - * Read the swap header. - */ - if (!mapping->a_ops->readpage) { - error = -EINVAL; - goto bad_swap; - } - page = read_mapping_page(mapping, 0, swap_file); - if (IS_ERR(page)) { - error = PTR_ERR(page); - goto bad_swap; - } - swap_header = kmap(page); - - maxpages = read_swap_header(p, swap_header, inode); - if (unlikely(!maxpages)) { - error = -EINVAL; - goto bad_swap; - } - - /* OK, set up the swap map and apply the bad block list */ - swap_map = vzalloc(maxpages); - if (!swap_map) { - error = -ENOMEM; - goto bad_swap; - } - - error = swap_cgroup_swapon(p->type, maxpages); - if (error) - goto bad_swap; - - nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map, - maxpages, &span); - if (unlikely(nr_extents < 0)) { - error = nr_extents; - goto bad_swap; - } - - if (p->bdev) { - if (blk_queue_nonrot(bdev_get_queue(p->bdev))) { - p->flags |= SWP_SOLIDSTATE; - p->cluster_next = 1 + (random32() % p->highest_bit); - } - if (discard_swap(p) == 0 && (swap_flags & SWAP_FLAG_DISCARD)) - p->flags |= SWP_DISCARDABLE; - } - - mutex_lock(&swapon_mutex); - prio = -1; - if (swap_flags & SWAP_FLAG_PREFER) - prio = - (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT; - enable_swap_info(p, prio, swap_map); - - printk(KERN_INFO "Adding %uk swap on %s. " - "Priority:%d extents:%d across:%lluk %s%s\n", - p->pages << (PAGE_SHIFT - 10), name, p->prio, - nr_extents, (unsigned long long)span << (PAGE_SHIFT - 10), - (p->flags & SWP_SOLIDSTATE) ? "SS" : "", - (p->flags & SWP_DISCARDABLE) ? "D" : ""); - - mutex_unlock(&swapon_mutex); - atomic_inc(&proc_poll_event); - wake_up_interruptible(&proc_poll_wait); - - if (S_ISREG(inode->i_mode)) - inode->i_flags |= S_SWAPFILE; - error = 0; - goto out; - bad_swap: - if (inode && S_ISBLK(inode->i_mode) && p->bdev) { - set_blocksize(p->bdev, p->old_block_size); - blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); - } - destroy_swap_extents(p); - swap_cgroup_swapoff(p->type); - spin_lock(&swap_lock); - p->swap_file = NULL; - p->flags = 0; - spin_unlock(&swap_lock); - vfree(swap_map); - if (swap_file) { - if (inode && S_ISREG(inode->i_mode)) { - mutex_unlock(&inode->i_mutex); - inode = NULL; - } - filp_close(swap_file, NULL); - } - out: - if (page && !IS_ERR(page)) { - kunmap(page); - page_cache_release(page); - } - - if (inode && S_ISREG(inode->i_mode)) - mutex_unlock(&inode->i_mutex); - return error; -} - -EXPORT_SYMBOL(swapon); -#endif /* CONFIG_ZRAM_FOR_ANDROID */ - SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) { struct swap_info_struct *p; @@ -2267,6 +2137,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) } if (discard_swap(p) == 0 && (swap_flags & SWAP_FLAG_DISCARD)) p->flags |= SWP_DISCARDABLE; + if (blk_queue_fast(bdev_get_queue(p->bdev))) + p->flags |= SWP_FAST; } mutex_lock(&swapon_mutex); @@ -2449,6 +2321,13 @@ int swapcache_prepare(swp_entry_t entry) return __swap_duplicate(entry, SWAP_HAS_CACHE); } +struct swap_info_struct *page_swap_info(struct page *page) +{ + swp_entry_t swap = { .val = page_private(page) }; + BUG_ON(!PageSwapCache(page)); + return swap_info[swp_type(swap)]; +} + /* * swap_lock prevents swap_map being freed. Don't grab an extra * reference on the swaphandle, it doesn't matter if it becomes unused. diff --git a/mm/vmscan.c b/mm/vmscan.c index b0d3366..ce6e2e5 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -624,6 +624,10 @@ void putback_lru_page(struct page *page) int was_unevictable = PageUnevictable(page); VM_BUG_ON(PageLRU(page)); +#ifdef CONFIG_CLEANCACHE + if (active) + SetPageWasActive(page); +#endif redo: ClearPageUnevictable(page); @@ -771,9 +775,6 @@ static noinline_for_stack void free_page_list(struct list_head *free_pages) /* * shrink_page_list() returns the number of reclaimed pages */ -#ifndef CONFIG_ZRAM_FOR_ANDROID -static -#endif /* CONFIG_ZRAM_FOR_ANDROID */ unsigned long shrink_page_list(struct list_head *page_list, struct zone *zone, struct scan_control *sc) @@ -989,7 +990,7 @@ cull_mlocked: activate_locked: /* Not a candidate for swapping, so reclaim swap space. */ - if (PageSwapCache(page) && vm_swap_full()) + if (PageSwapCache(page) && vm_swap_full(page_swap_info(page))) try_to_free_swap(page); VM_BUG_ON(PageActive(page)); SetPageActive(page); @@ -1281,9 +1282,6 @@ static unsigned long isolate_pages_global(unsigned long nr, * clear_active_flags() is a helper for shrink_active_list(), clearing * any active bits from the pages in the list. */ -#ifndef CONFIG_ZRAM_FOR_ANDROID -static -#endif /* CONFIG_ZRAM_FOR_ANDROID */ unsigned long clear_active_flags(struct list_head *page_list, unsigned int *count) { @@ -1297,6 +1295,9 @@ unsigned long clear_active_flags(struct list_head *page_list, if (PageActive(page)) { lru += LRU_ACTIVE; ClearPageActive(page); +#ifdef CONFIG_CLEANCACHE + SetPageWasActive(page); +#endif nr_active += numpages; } if (count) @@ -1354,40 +1355,6 @@ int isolate_lru_page(struct page *page) return ret; } -#ifdef CONFIG_ZRAM_FOR_ANDROID -/** - * isolate_lru_page_compcache - tries to isolate a page for compcache - * @page: page to isolate from its LRU list - * - * Isolates a @page from an LRU list, clears PageLRU,but - * does not adjusts the vmstat statistic - * Returns 0 if the page was removed from an LRU list. - * Returns -EBUSY if the page was not on an LRU list. - */ -int isolate_lru_page_compcache(struct page *page) -{ - int ret = -EBUSY; - - VM_BUG_ON(!page_count(page)); - - if (PageLRU(page)) { - struct zone *zone = page_zone(page); - - spin_lock_irq(&zone->lru_lock); - if (PageLRU(page)) { - int lru = page_lru(page); - ret = 0; - get_page(page); - ClearPageLRU(page); - list_del(&page->lru); - mem_cgroup_del_lru_list(page, lru); - } - spin_unlock_irq(&zone->lru_lock); - } - return ret; -} -#endif - /* * Are there way too many processes in the direct reclaim path already? */ @@ -1624,44 +1591,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone, return nr_reclaimed; } -#ifdef CONFIG_ZRAM_FOR_ANDROID -unsigned long -zone_id_shrink_pagelist(struct zone *zone, struct list_head *page_list) -{ - unsigned long nr_reclaimed = 0; - unsigned long nr_anon; - unsigned long nr_file; - - struct scan_control sc = { - .gfp_mask = GFP_USER, - .may_writepage = 1, - .nr_to_reclaim = SWAP_CLUSTER_MAX, - .may_unmap = 1, - .may_swap = 1, - .swappiness = vm_swappiness, - .order = 0, - .mem_cgroup = NULL, - .nodemask = NULL, - }; - - spin_lock_irq(&zone->lru_lock); - - update_isolated_counts(zone, &sc, &nr_anon, &nr_file, page_list); - - spin_unlock_irq(&zone->lru_lock); - - nr_reclaimed = shrink_page_list(page_list, zone, &sc); - - __count_zone_vm_events(PGSTEAL, zone, nr_reclaimed); - - putback_lru_pages(zone, &sc, nr_anon, nr_file, page_list); - - return nr_reclaimed; -} - -EXPORT_SYMBOL(zone_id_shrink_pagelist); -#endif /* CONFIG_ZRAM_FOR_ANDROID */ - /* * This moves pages from the active list to the inactive list. * @@ -1790,6 +1719,9 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone, } ClearPageActive(page); /* we are de-activating */ +#ifdef CONFIG_CLEANCACHE + SetPageWasActive(page); +#endif list_add(&page->lru, &l_inactive); } diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c new file mode 100644 index 0000000..5e17643 --- /dev/null +++ b/mm/zsmalloc.c @@ -0,0 +1,1148 @@ +/* + * zsmalloc memory allocator + * + * Copyright (C) 2011 Nitin Gupta + * Copyright (C) 2012, 2013 Minchan Kim + * + * This code is released using a dual license strategy: BSD/GPL + * You can choose the license that better fits your requirements. + * + * Released under the terms of 3-clause BSD License + * Released under the terms of GNU General Public License Version 2.0 + */ + +/* + * This allocator is designed for use with zram. Thus, the allocator is + * supposed to work well under low memory conditions. In particular, it + * never attempts higher order page allocation which is very likely to + * fail under memory pressure. On the other hand, if we just use single + * (0-order) pages, it would suffer from very high fragmentation -- + * any object of size PAGE_SIZE/2 or larger would occupy an entire page. + * This was one of the major issues with its predecessor (xvmalloc). + * + * To overcome these issues, zsmalloc allocates a bunch of 0-order pages + * and links them together using various 'struct page' fields. These linked + * pages act as a single higher-order page i.e. an object can span 0-order + * page boundaries. The code refers to these linked pages as a single entity + * called zspage. + * + * For simplicity, zsmalloc can only allocate objects of size up to PAGE_SIZE + * since this satisfies the requirements of all its current users (in the + * worst case, page is incompressible and is thus stored "as-is" i.e. in + * uncompressed form). For allocation requests larger than this size, failure + * is returned (see zs_malloc). + * + * Additionally, zs_malloc() does not return a dereferenceable pointer. + * Instead, it returns an opaque handle (unsigned long) which encodes actual + * location of the allocated object. The reason for this indirection is that + * zsmalloc does not keep zspages permanently mapped since that would cause + * issues on 32-bit systems where the VA region for kernel space mappings + * is very small. So, before using the allocating memory, the object has to + * be mapped using zs_map_object() to get a usable pointer and subsequently + * unmapped using zs_unmap_object(). + * + * Following is how we use various fields and flags of underlying + * struct page(s) to form a zspage. + * + * Usage of struct page fields: + * page->first_page: points to the first component (0-order) page + * page->index (union with page->freelist): offset of the first object + * starting in this page. For the first page, this is + * always 0, so we use this field (aka freelist) to point + * to the first free object in zspage. + * page->lru: links together all component pages (except the first page) + * of a zspage + * + * For _first_ page only: + * + * page->private (union with page->first_page): refers to the + * component page after the first page + * page->freelist: points to the first free object in zspage. + * Free objects are linked together using in-place + * metadata. + * page->objects: maximum number of objects we can store in this + * zspage (class->zspage_order * PAGE_SIZE / class->size) + * page->lru: links together first pages of various zspages. + * Basically forming list of zspages in a fullness group. + * page->mapping: class index and fullness group of the zspage + * + * Usage of struct page flags: + * PG_private: identifies the first component page + * PG_private2: identifies the last component page + * + */ + +#ifdef CONFIG_ZSMALLOC_DEBUG +#define DEBUG +#endif + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/highmem.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <asm/tlbflush.h> +#include <asm/pgtable.h> +#include <linux/cpumask.h> +#include <linux/cpu.h> +#include <linux/vmalloc.h> +#include <linux/hardirq.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/zsmalloc.h> + +/* + * This must be power of 2 and greater than of equal to sizeof(link_free). + * These two conditions ensure that any 'struct link_free' itself doesn't + * span more than 1 page which avoids complex case of mapping 2 pages simply + * to restore link_free pointer values. + */ +#define ZS_ALIGN 8 + +/* + * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single) + * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N. + */ +#define ZS_MAX_ZSPAGE_ORDER 2 +#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER) + +/* + * Object location (<PFN>, <obj_idx>) is encoded as + * as single (unsigned long) handle value. + * + * Note that object index <obj_idx> is relative to system + * page <PFN> it is stored in, so for each sub-page belonging + * to a zspage, obj_idx starts with 0. + * + * This is made more complicated by various memory models and PAE. + */ + +#ifndef MAX_PHYSMEM_BITS +#ifdef CONFIG_HIGHMEM64G +#define MAX_PHYSMEM_BITS 36 +#else /* !CONFIG_HIGHMEM64G */ +/* + * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just + * be PAGE_SHIFT + */ +#define MAX_PHYSMEM_BITS BITS_PER_LONG +#endif +#endif +#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT) +#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS) +#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1) + +#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */ +#define ZS_MIN_ALLOC_SIZE \ + MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS)) +#define ZS_MAX_ALLOC_SIZE PAGE_SIZE + +/* + * On systems with 4K page size, this gives 254 size classes! There is a + * trader-off here: + * - Large number of size classes is potentially wasteful as free page are + * spread across these classes + * - Small number of size classes causes large internal fragmentation + * - Probably its better to use specific size classes (empirically + * determined). NOTE: all those class sizes must be set as multiple of + * ZS_ALIGN to make sure link_free itself never has to span 2 pages. + * + * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN + * (reason above) + */ +#define ZS_SIZE_CLASS_DELTA (PAGE_SIZE >> 8) +#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \ + ZS_SIZE_CLASS_DELTA + 1) + +/* + * We do not maintain any list for completely empty or full pages + */ +enum fullness_group { + ZS_ALMOST_FULL, + ZS_ALMOST_EMPTY, + _ZS_NR_FULLNESS_GROUPS, + + ZS_EMPTY, + ZS_FULL +}; + +/* + * We assign a page to ZS_ALMOST_EMPTY fullness group when: + * n <= N / f, where + * n = number of allocated objects + * N = total number of objects zspage can store + * f = 1/fullness_threshold_frac + * + * Similarly, we assign zspage to: + * ZS_ALMOST_FULL when n > N / f + * ZS_EMPTY when n == 0 + * ZS_FULL when n == N + * + * (see: fix_fullness_group()) + */ +static const int fullness_threshold_frac = 4; + +struct size_class { + /* + * Size of objects stored in this class. Must be multiple + * of ZS_ALIGN. + */ + int size; + unsigned int index; + + /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */ + int pages_per_zspage; + + spinlock_t lock; + + struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS]; +}; + +/* + * Placed within free objects to form a singly linked list. + * For every zspage, first_page->freelist gives head of this list. + * + * This must be power of 2 and less than or equal to ZS_ALIGN + */ +struct link_free { + /* Handle of next free chunk (encodes <PFN, obj_idx>) */ + void *next; +}; + +struct zs_pool { + struct size_class *size_class[ZS_SIZE_CLASSES]; + + gfp_t flags; /* allocation flags used when growing pool */ + atomic_long_t pages_allocated; +}; + +/* + * A zspage's class index and fullness group + * are encoded in its (first)page->mapping + */ +#define CLASS_IDX_BITS 28 +#define FULLNESS_BITS 4 +#define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1) +#define FULLNESS_MASK ((1 << FULLNESS_BITS) - 1) + +struct mapping_area { +#ifdef CONFIG_PGTABLE_MAPPING + struct vm_struct *vm; /* vm area for mapping object that span pages */ +#else + char *vm_buf; /* copy buffer for objects that span pages */ +#endif + char *vm_addr; /* address of kmap_atomic()'ed pages */ + enum zs_mapmode vm_mm; /* mapping mode */ +}; + +/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */ +static DEFINE_PER_CPU(struct mapping_area, zs_map_area); + +static int is_first_page(struct page *page) +{ + return PagePrivate(page); +} + +static int is_last_page(struct page *page) +{ + return PagePrivate2(page); +} + +static void get_zspage_mapping(struct page *page, unsigned int *class_idx, + enum fullness_group *fullness) +{ + unsigned long m; + BUG_ON(!is_first_page(page)); + + m = (unsigned long)page->mapping; + *fullness = m & FULLNESS_MASK; + *class_idx = (m >> FULLNESS_BITS) & CLASS_IDX_MASK; +} + +static void set_zspage_mapping(struct page *page, unsigned int class_idx, + enum fullness_group fullness) +{ + unsigned long m; + BUG_ON(!is_first_page(page)); + + m = ((class_idx & CLASS_IDX_MASK) << FULLNESS_BITS) | + (fullness & FULLNESS_MASK); + page->mapping = (struct address_space *)m; +} + +/* + * zsmalloc divides the pool into various size classes where each + * class maintains a list of zspages where each zspage is divided + * into equal sized chunks. Each allocation falls into one of these + * classes depending on its size. This function returns index of the + * size class which has chunk size big enough to hold the give size. + */ +static int get_size_class_index(int size) +{ + int idx = 0; + + if (likely(size > ZS_MIN_ALLOC_SIZE)) + idx = DIV_ROUND_UP(size - ZS_MIN_ALLOC_SIZE, + ZS_SIZE_CLASS_DELTA); + + return idx; +} + +/* + * For each size class, zspages are divided into different groups + * depending on how "full" they are. This was done so that we could + * easily find empty or nearly empty zspages when we try to shrink + * the pool (not yet implemented). This function returns fullness + * status of the given page. + */ +static enum fullness_group get_fullness_group(struct page *page) +{ + int inuse, max_objects; + enum fullness_group fg; + BUG_ON(!is_first_page(page)); + + inuse = page->inuse; + max_objects = page->objects; + + if (inuse == 0) + fg = ZS_EMPTY; + else if (inuse == max_objects) + fg = ZS_FULL; + else if (inuse <= max_objects / fullness_threshold_frac) + fg = ZS_ALMOST_EMPTY; + else + fg = ZS_ALMOST_FULL; + + return fg; +} + +/* + * Each size class maintains various freelists and zspages are assigned + * to one of these freelists based on the number of live objects they + * have. This functions inserts the given zspage into the freelist + * identified by <class, fullness_group>. + */ +static void insert_zspage(struct page *page, struct size_class *class, + enum fullness_group fullness) +{ + struct page **head; + + BUG_ON(!is_first_page(page)); + + if (fullness >= _ZS_NR_FULLNESS_GROUPS) + return; + + head = &class->fullness_list[fullness]; + if (*head) + list_add_tail(&page->lru, &(*head)->lru); + + *head = page; +} + +/* + * This function removes the given zspage from the freelist identified + * by <class, fullness_group>. + */ +static void remove_zspage(struct page *page, struct size_class *class, + enum fullness_group fullness) +{ + struct page **head; + + BUG_ON(!is_first_page(page)); + + if (fullness >= _ZS_NR_FULLNESS_GROUPS) + return; + + head = &class->fullness_list[fullness]; + BUG_ON(!*head); + if (list_empty(&(*head)->lru)) + *head = NULL; + else if (*head == page) + *head = (struct page *)list_entry((*head)->lru.next, + struct page, lru); + + list_del_init(&page->lru); +} + +/* + * Each size class maintains zspages in different fullness groups depending + * on the number of live objects they contain. When allocating or freeing + * objects, the fullness status of the page can change, say, from ALMOST_FULL + * to ALMOST_EMPTY when freeing an object. This function checks if such + * a status change has occurred for the given page and accordingly moves the + * page from the freelist of the old fullness group to that of the new + * fullness group. + */ +static enum fullness_group fix_fullness_group(struct zs_pool *pool, + struct page *page) +{ + int class_idx; + struct size_class *class; + enum fullness_group currfg, newfg; + + BUG_ON(!is_first_page(page)); + + get_zspage_mapping(page, &class_idx, &currfg); + newfg = get_fullness_group(page); + if (newfg == currfg) + goto out; + + class = pool->size_class[class_idx]; + remove_zspage(page, class, currfg); + insert_zspage(page, class, newfg); + set_zspage_mapping(page, class_idx, newfg); + +out: + return newfg; +} + +/* + * We have to decide on how many pages to link together + * to form a zspage for each size class. This is important + * to reduce wastage due to unusable space left at end of + * each zspage which is given as: + * wastage = Zp - Zp % size_class + * where Zp = zspage size = k * PAGE_SIZE where k = 1, 2, ... + * + * For example, for size class of 3/8 * PAGE_SIZE, we should + * link together 3 PAGE_SIZE sized pages to form a zspage + * since then we can perfectly fit in 8 such objects. + */ +static int get_pages_per_zspage(int class_size) +{ + int i, max_usedpc = 0; + /* zspage order which gives maximum used size per KB */ + int max_usedpc_order = 1; + + for (i = 1; i <= ZS_MAX_PAGES_PER_ZSPAGE; i++) { + int zspage_size; + int waste, usedpc; + + zspage_size = i * PAGE_SIZE; + waste = zspage_size % class_size; + usedpc = (zspage_size - waste) * 100 / zspage_size; + + if (usedpc > max_usedpc) { + max_usedpc = usedpc; + max_usedpc_order = i; + } + } + + return max_usedpc_order; +} + +/* + * A single 'zspage' is composed of many system pages which are + * linked together using fields in struct page. This function finds + * the first/head page, given any component page of a zspage. + */ +static struct page *get_first_page(struct page *page) +{ + if (is_first_page(page)) + return page; + else + return page->first_page; +} + +static struct page *get_next_page(struct page *page) +{ + struct page *next; + + if (is_last_page(page)) + next = NULL; + else if (is_first_page(page)) + next = (struct page *)page_private(page); + else + next = list_entry(page->lru.next, struct page, lru); + + return next; +} + +/* + * Encode <page, obj_idx> as a single handle value. + * On hardware platforms with physical memory starting at 0x0 the pfn + * could be 0 so we ensure that the handle will never be 0 by adjusting the + * encoded obj_idx value before encoding. + */ +static void *obj_location_to_handle(struct page *page, unsigned long obj_idx) +{ + unsigned long handle; + + if (!page) { + BUG_ON(obj_idx); + return NULL; + } + + handle = page_to_pfn(page) << OBJ_INDEX_BITS; + handle |= ((obj_idx + 1) & OBJ_INDEX_MASK); + + return (void *)handle; +} + +/* + * Decode <page, obj_idx> pair from the given object handle. We adjust the + * decoded obj_idx back to its original value since it was adjusted in + * obj_location_to_handle(). + */ +static void obj_handle_to_location(unsigned long handle, struct page **page, + unsigned long *obj_idx) +{ + *page = pfn_to_page(handle >> OBJ_INDEX_BITS); + *obj_idx = (handle & OBJ_INDEX_MASK) - 1; +} + +static unsigned long obj_idx_to_offset(struct page *page, + unsigned long obj_idx, int class_size) +{ + unsigned long off = 0; + + if (!is_first_page(page)) + off = page->index; + + return off + obj_idx * class_size; +} + +static void reset_page(struct page *page) +{ + clear_bit(PG_private, &page->flags); + clear_bit(PG_private_2, &page->flags); + set_page_private(page, 0); + page->mapping = NULL; + page->freelist = NULL; + reset_page_mapcount(page); +} + +static void free_zspage(struct page *first_page) +{ + struct page *nextp, *tmp, *head_extra; + + BUG_ON(!is_first_page(first_page)); + BUG_ON(first_page->inuse); + + head_extra = (struct page *)page_private(first_page); + + reset_page(first_page); + __free_page(first_page); + + /* zspage with only 1 system page */ + if (!head_extra) + return; + + list_for_each_entry_safe(nextp, tmp, &head_extra->lru, lru) { + list_del(&nextp->lru); + reset_page(nextp); + __free_page(nextp); + } + reset_page(head_extra); + __free_page(head_extra); +} + +/* Initialize a newly allocated zspage */ +static void init_zspage(struct page *first_page, struct size_class *class) +{ + unsigned long off = 0; + struct page *page = first_page; + + BUG_ON(!is_first_page(first_page)); + while (page) { + struct page *next_page; + struct link_free *link; + unsigned int i = 1; + void *vaddr; + + /* + * page->index stores offset of first object starting + * in the page. For the first page, this is always 0, + * so we use first_page->index (aka ->freelist) to store + * head of corresponding zspage's freelist. + */ + if (page != first_page) + page->index = off; + + vaddr = kmap_atomic(page); + link = (struct link_free *)vaddr + off / sizeof(*link); + + while ((off += class->size) < PAGE_SIZE) { + link->next = obj_location_to_handle(page, i++); + link += class->size / sizeof(*link); + } + + /* + * We now come to the last (full or partial) object on this + * page, which must point to the first object on the next + * page (if present) + */ + next_page = get_next_page(page); + link->next = obj_location_to_handle(next_page, 0); + kunmap_atomic(vaddr); + page = next_page; + off %= PAGE_SIZE; + } +} + +/* + * Allocate a zspage for the given size class + */ +static struct page *alloc_zspage(struct size_class *class, gfp_t flags) +{ + int i, error; + struct page *first_page = NULL, *uninitialized_var(prev_page); + + /* + * Allocate individual pages and link them together as: + * 1. first page->private = first sub-page + * 2. all sub-pages are linked together using page->lru + * 3. each sub-page is linked to the first page using page->first_page + * + * For each size class, First/Head pages are linked together using + * page->lru. Also, we set PG_private to identify the first page + * (i.e. no other sub-page has this flag set) and PG_private_2 to + * identify the last page. + */ + error = -ENOMEM; + for (i = 0; i < class->pages_per_zspage; i++) { + struct page *page; + + page = alloc_page(flags); + if (!page) + goto cleanup; + + INIT_LIST_HEAD(&page->lru); + if (i == 0) { /* first page */ + SetPagePrivate(page); + set_page_private(page, 0); + first_page = page; + first_page->inuse = 0; + } + if (i == 1) + set_page_private(first_page, (unsigned long)page); + if (i >= 1) + page->first_page = first_page; + if (i >= 2) + list_add(&page->lru, &prev_page->lru); + if (i == class->pages_per_zspage - 1) /* last page */ + SetPagePrivate2(page); + prev_page = page; + } + + init_zspage(first_page, class); + + first_page->freelist = obj_location_to_handle(first_page, 0); + /* Maximum number of objects we can store in this zspage */ + first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size; + + error = 0; /* Success */ + +cleanup: + if (unlikely(error) && first_page) { + free_zspage(first_page); + first_page = NULL; + } + + return first_page; +} + +static struct page *find_get_zspage(struct size_class *class) +{ + int i; + struct page *page; + + for (i = 0; i < _ZS_NR_FULLNESS_GROUPS; i++) { + page = class->fullness_list[i]; + if (page) + break; + } + + return page; +} + +#ifdef CONFIG_PGTABLE_MAPPING +static inline int __zs_cpu_up(struct mapping_area *area) +{ + /* + * Make sure we don't leak memory if a cpu UP notification + * and zs_init() race and both call zs_cpu_up() on the same cpu + */ + if (area->vm) + return 0; + area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL); + if (!area->vm) + return -ENOMEM; + return 0; +} + +static inline void __zs_cpu_down(struct mapping_area *area) +{ + if (area->vm) + free_vm_area(area->vm); + area->vm = NULL; +} + +static inline void *__zs_map_object(struct mapping_area *area, + struct page *pages[2], int off, int size) +{ + BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages)); + area->vm_addr = area->vm->addr; + return area->vm_addr + off; +} + +static inline void __zs_unmap_object(struct mapping_area *area, + struct page *pages[2], int off, int size) +{ + unsigned long addr = (unsigned long)area->vm_addr; + + unmap_kernel_range(addr, PAGE_SIZE * 2); +} + +#else /* CONFIG_PGTABLE_MAPPING */ + +static inline int __zs_cpu_up(struct mapping_area *area) +{ + /* + * Make sure we don't leak memory if a cpu UP notification + * and zs_init() race and both call zs_cpu_up() on the same cpu + */ + if (area->vm_buf) + return 0; + area->vm_buf = (char *)__get_free_page(GFP_KERNEL); + if (!area->vm_buf) + return -ENOMEM; + return 0; +} + +static inline void __zs_cpu_down(struct mapping_area *area) +{ + if (area->vm_buf) + free_page((unsigned long)area->vm_buf); + area->vm_buf = NULL; +} + +static void *__zs_map_object(struct mapping_area *area, + struct page *pages[2], int off, int size) +{ + int sizes[2]; + void *addr; + char *buf = area->vm_buf; + + /* disable page faults to match kmap_atomic() return conditions */ + pagefault_disable(); + + /* no read fastpath */ + if (area->vm_mm == ZS_MM_WO) + goto out; + + sizes[0] = PAGE_SIZE - off; + sizes[1] = size - sizes[0]; + + /* copy object to per-cpu buffer */ + addr = kmap_atomic(pages[0]); + memcpy(buf, addr + off, sizes[0]); + kunmap_atomic(addr); + addr = kmap_atomic(pages[1]); + memcpy(buf + sizes[0], addr, sizes[1]); + kunmap_atomic(addr); +out: + return area->vm_buf; +} + +static void __zs_unmap_object(struct mapping_area *area, + struct page *pages[2], int off, int size) +{ + int sizes[2]; + void *addr; + char *buf = area->vm_buf; + + /* no write fastpath */ + if (area->vm_mm == ZS_MM_RO) + goto out; + + sizes[0] = PAGE_SIZE - off; + sizes[1] = size - sizes[0]; + + /* copy per-cpu buffer to object */ + addr = kmap_atomic(pages[0]); + memcpy(addr + off, buf, sizes[0]); + kunmap_atomic(addr); + addr = kmap_atomic(pages[1]); + memcpy(addr, buf + sizes[0], sizes[1]); + kunmap_atomic(addr); + +out: + /* enable page faults to match kunmap_atomic() return conditions */ + pagefault_enable(); +} + +#endif /* CONFIG_PGTABLE_MAPPING */ + +static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action, + void *pcpu) +{ + int ret, cpu = (long)pcpu; + struct mapping_area *area; + + switch (action) { + case CPU_UP_PREPARE: + area = &per_cpu(zs_map_area, cpu); + ret = __zs_cpu_up(area); + if (ret) + return notifier_from_errno(ret); + break; + case CPU_DEAD: + case CPU_UP_CANCELED: + area = &per_cpu(zs_map_area, cpu); + __zs_cpu_down(area); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block zs_cpu_nb = { + .notifier_call = zs_cpu_notifier +}; + +static void zs_exit(void) +{ + int cpu; + + for_each_online_cpu(cpu) + zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu); + unregister_cpu_notifier(&zs_cpu_nb); +} + +static int zs_init(void) +{ + int cpu, ret; + + register_cpu_notifier(&zs_cpu_nb); + for_each_online_cpu(cpu) { + ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu); + if (notifier_to_errno(ret)) + goto fail; + } + return 0; +fail: + zs_exit(); + return notifier_to_errno(ret); +} + +static unsigned int get_maxobj_per_zspage(int size, int pages_per_zspage) +{ + return pages_per_zspage * PAGE_SIZE / size; +} + +static bool can_merge(struct size_class *prev, int size, int pages_per_zspage) +{ + if (prev->pages_per_zspage != pages_per_zspage) + return false; + + if (get_maxobj_per_zspage(prev->size, prev->pages_per_zspage) + != get_maxobj_per_zspage(size, pages_per_zspage)) + return false; + + return true; +} + +/** + * zs_create_pool - Creates an allocation pool to work from. + * @flags: allocation flags used to allocate pool metadata + * + * This function must be called before anything when using + * the zsmalloc allocator. + * + * On success, a pointer to the newly created pool is returned, + * otherwise NULL. + */ +struct zs_pool *zs_create_pool(gfp_t flags) +{ + int i; + struct zs_pool *pool; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return NULL; + + /* + * Iterate reversly, because, size of size_class that we want to use + * for merging should be larger or equal to current size. + */ + for (i = ZS_SIZE_CLASSES - 1; i >= 0; i--) { + int size; + int pages_per_zspage; + struct size_class *class; + struct size_class *prev_class; + + size = ZS_MIN_ALLOC_SIZE + i * ZS_SIZE_CLASS_DELTA; + if (size > ZS_MAX_ALLOC_SIZE) + size = ZS_MAX_ALLOC_SIZE; + pages_per_zspage = get_pages_per_zspage(size); + + /* + * size_class is used for normal zsmalloc operation such + * as alloc/free for that size. Although it is natural that we + * have one size_class for each size, there is a chance that we + * can get more memory utilization if we use one size_class for + * many different sizes whose size_class have same + * characteristics. So, we makes size_class point to + * previous size_class if possible. + */ + if (i < ZS_SIZE_CLASSES - 1) { + prev_class = pool->size_class[i + 1]; + if (can_merge(prev_class, size, pages_per_zspage)) { + pool->size_class[i] = prev_class; + continue; + } + } + + class = kzalloc(sizeof(struct size_class), GFP_KERNEL); + if (!class) + goto err; + + class->size = size; + class->index = i; + class->pages_per_zspage = pages_per_zspage; + spin_lock_init(&class->lock); + pool->size_class[i] = class; + } + + pool->flags = flags; + + return pool; + +err: + zs_destroy_pool(pool); + return NULL; +} +EXPORT_SYMBOL_GPL(zs_create_pool); + +void zs_destroy_pool(struct zs_pool *pool) +{ + int i; + + for (i = 0; i < ZS_SIZE_CLASSES; i++) { + int fg; + struct size_class *class = pool->size_class[i]; + + if (!class) + continue; + + if (class->index != i) + continue; + + for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) { + if (class->fullness_list[fg]) { + pr_info("Freeing non-empty class with size %db, fullness group %d\n", + class->size, fg); + } + } + kfree(class); + } + kfree(pool); +} +EXPORT_SYMBOL_GPL(zs_destroy_pool); + +/** + * zs_malloc - Allocate block of given size from pool. + * @pool: pool to allocate from + * @size: size of block to allocate + * + * On success, handle to the allocated object is returned, + * otherwise 0. + * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail. + */ +unsigned long zs_malloc(struct zs_pool *pool, size_t size) +{ + unsigned long obj; + struct link_free *link; + struct size_class *class; + void *vaddr; + + struct page *first_page, *m_page; + unsigned long m_objidx, m_offset; + + if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE)) + return 0; + + class = pool->size_class[get_size_class_index(size)]; + + spin_lock(&class->lock); + first_page = find_get_zspage(class); + + if (!first_page) { + spin_unlock(&class->lock); + first_page = alloc_zspage(class, pool->flags); + if (unlikely(!first_page)) + return 0; + + set_zspage_mapping(first_page, class->index, ZS_EMPTY); + atomic_long_add(class->pages_per_zspage, + &pool->pages_allocated); + spin_lock(&class->lock); + } + + obj = (unsigned long)first_page->freelist; + obj_handle_to_location(obj, &m_page, &m_objidx); + m_offset = obj_idx_to_offset(m_page, m_objidx, class->size); + + vaddr = kmap_atomic(m_page); + link = (struct link_free *)vaddr + m_offset / sizeof(*link); + first_page->freelist = link->next; + memset(link, POISON_INUSE, sizeof(*link)); + kunmap_atomic(vaddr); + + first_page->inuse++; + /* Now move the zspage to another fullness group, if required */ + fix_fullness_group(pool, first_page); + spin_unlock(&class->lock); + + return obj; +} +EXPORT_SYMBOL_GPL(zs_malloc); + +void zs_free(struct zs_pool *pool, unsigned long obj) +{ + struct link_free *link; + struct page *first_page, *f_page; + unsigned long f_objidx, f_offset; + void *vaddr; + + int class_idx; + struct size_class *class; + enum fullness_group fullness; + + if (unlikely(!obj)) + return; + + obj_handle_to_location(obj, &f_page, &f_objidx); + first_page = get_first_page(f_page); + + get_zspage_mapping(first_page, &class_idx, &fullness); + class = pool->size_class[class_idx]; + f_offset = obj_idx_to_offset(f_page, f_objidx, class->size); + + spin_lock(&class->lock); + + /* Insert this object in containing zspage's freelist */ + vaddr = kmap_atomic(f_page); + link = (struct link_free *)(vaddr + f_offset); + link->next = first_page->freelist; + kunmap_atomic(vaddr); + first_page->freelist = (void *)obj; + + first_page->inuse--; + fullness = fix_fullness_group(pool, first_page); + spin_unlock(&class->lock); + + if (fullness == ZS_EMPTY) { + atomic_long_sub(class->pages_per_zspage, + &pool->pages_allocated); + free_zspage(first_page); + } +} +EXPORT_SYMBOL_GPL(zs_free); + +/** + * zs_map_object - get address of allocated object from handle. + * @pool: pool from which the object was allocated + * @handle: handle returned from zs_malloc + * + * Before using an object allocated from zs_malloc, it must be mapped using + * this function. When done with the object, it must be unmapped using + * zs_unmap_object. + * + * Only one object can be mapped per cpu at a time. There is no protection + * against nested mappings. + * + * This function returns with preemption and page faults disabled. + */ +void *zs_map_object(struct zs_pool *pool, unsigned long handle, + enum zs_mapmode mm) +{ + struct page *page; + unsigned long obj_idx, off; + + unsigned int class_idx; + enum fullness_group fg; + struct size_class *class; + struct mapping_area *area; + struct page *pages[2]; + + BUG_ON(!handle); + + /* + * Because we use per-cpu mapping areas shared among the + * pools/users, we can't allow mapping in interrupt context + * because it can corrupt another users mappings. + */ + BUG_ON(in_interrupt()); + + obj_handle_to_location(handle, &page, &obj_idx); + get_zspage_mapping(get_first_page(page), &class_idx, &fg); + class = pool->size_class[class_idx]; + off = obj_idx_to_offset(page, obj_idx, class->size); + + area = &get_cpu_var(zs_map_area); + area->vm_mm = mm; + if (off + class->size <= PAGE_SIZE) { + /* this object is contained entirely within a page */ + area->vm_addr = kmap_atomic(page); + return area->vm_addr + off; + } + + /* this object spans two pages */ + pages[0] = page; + pages[1] = get_next_page(page); + BUG_ON(!pages[1]); + + return __zs_map_object(area, pages, off, class->size); +} +EXPORT_SYMBOL_GPL(zs_map_object); + +void zs_unmap_object(struct zs_pool *pool, unsigned long handle) +{ + struct page *page; + unsigned long obj_idx, off; + + unsigned int class_idx; + enum fullness_group fg; + struct size_class *class; + struct mapping_area *area; + + BUG_ON(!handle); + + obj_handle_to_location(handle, &page, &obj_idx); + get_zspage_mapping(get_first_page(page), &class_idx, &fg); + class = pool->size_class[class_idx]; + off = obj_idx_to_offset(page, obj_idx, class->size); + + area = &__get_cpu_var(zs_map_area); + if (off + class->size <= PAGE_SIZE) + kunmap_atomic(area->vm_addr); + else { + struct page *pages[2]; + + pages[0] = page; + pages[1] = get_next_page(page); + BUG_ON(!pages[1]); + + __zs_unmap_object(area, pages, off, class->size); + } + put_cpu_var(zs_map_area); +} +EXPORT_SYMBOL_GPL(zs_unmap_object); + +unsigned long zs_get_total_pages(struct zs_pool *pool) +{ + return atomic_long_read(&pool->pages_allocated); +} +EXPORT_SYMBOL_GPL(zs_get_total_pages); + +module_init(zs_init); +module_exit(zs_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>"); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b6aaa7a..75727c6 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -915,14 +915,14 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias); if (1) { - struct rtnl_link_ifmap map = { - .mem_start = dev->mem_start, - .mem_end = dev->mem_end, - .base_addr = dev->base_addr, - .irq = dev->irq, - .dma = dev->dma, - .port = dev->if_port, - }; + struct rtnl_link_ifmap map; + memset(&map, 0, sizeof(map)); + map.mem_start = dev->mem_start; + map.mem_end = dev->mem_end; + map.base_addr = dev->base_addr; + map.irq = dev->irq; + map.dma = dev->dma; + map.port = dev->if_port; NLA_PUT(skb, IFLA_MAP, sizeof(map), &map); } diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 76db592..085d63f 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -327,6 +327,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, ASSERT_RTNL(); + if (in_dev->dead) + goto no_promotions; + /* 1. Deleting primary ifaddr forces deletion all secondaries * unless alias promotion is set **/ @@ -373,6 +376,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, fib_del_ifaddr(ifa, ifa1); } +no_promotions: /* 2. Unlink it */ *ifap = ifa1->ifa_next; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index a54817a..f7b8dbe 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -765,6 +765,9 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) subnet = 1; } + if (in_dev->dead) + goto no_promotions; + /* Deletion is more complicated than add. * We should take care of not to delete too much :-) * @@ -840,6 +843,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) } } +no_promotions: if (!(ok & BRD_OK)) fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); if (subnet && ifa->ifa_prefixlen < 31) { diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index fd7a3f6..42536c6 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -350,11 +350,12 @@ unsigned int arpt_do_table(struct sk_buff *skb, } /* All zeroes == unconditional rule. */ -static inline bool unconditional(const struct arpt_arp *arp) +static inline bool unconditional(const struct arpt_entry *e) { static const struct arpt_arp uncond; - return memcmp(arp, &uncond, sizeof(uncond)) == 0; + return e->target_offset == sizeof(struct arpt_entry) && + memcmp(&e->arp, &uncond, sizeof(uncond)) == 0; } /* Figures out from what hook each rule can be called: returns 0 if @@ -393,11 +394,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo, |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS)); /* Unconditional return/END. */ - if ((e->target_offset == sizeof(struct arpt_entry) && + if ((unconditional(e) && (strcmp(t->target.u.user.name, XT_STANDARD_TARGET) == 0) && - t->verdict < 0 && unconditional(&e->arp)) || - visited) { + t->verdict < 0) || visited) { unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, @@ -542,7 +542,7 @@ static bool check_underflow(const struct arpt_entry *e) const struct xt_entry_target *t; unsigned int verdict; - if (!unconditional(&e->arp)) + if (!unconditional(e)) return false; t = arpt_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) @@ -563,7 +563,8 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, unsigned int h; if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 || - (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { + (unsigned char *)e + sizeof(struct arpt_entry) >= limit || + (unsigned char *)e + e->next_offset > limit) { duprintf("Bad offset %p\n", e); return -EINVAL; } @@ -583,9 +584,9 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { if (!check_underflow(e)) { - pr_err("Underflows must be unconditional and " - "use the STANDARD target with " - "ACCEPT/DROP\n"); + pr_debug("Underflows must be unconditional and " + "use the STANDARD target with " + "ACCEPT/DROP\n"); return -EINVAL; } newinfo->underflow[h] = underflows[h]; @@ -1217,7 +1218,8 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 || - (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit) { + (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit || + (unsigned char *)e + e->next_offset > limit) { duprintf("Bad offset %p, limit = %p\n", e, limit); return -EINVAL; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 24e556e..2f5ef5b 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -168,11 +168,12 @@ get_entry(const void *base, unsigned int offset) /* All zeroes == unconditional rule. */ /* Mildly perf critical (only if packet tracing is on) */ -static inline bool unconditional(const struct ipt_ip *ip) +static inline bool unconditional(const struct ipt_entry *e) { static const struct ipt_ip uncond; - return memcmp(ip, &uncond, sizeof(uncond)) == 0; + return e->target_offset == sizeof(struct ipt_entry) && + memcmp(&e->ip, &uncond, sizeof(uncond)) == 0; #undef FWINV } @@ -230,11 +231,10 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e, } else if (s == e) { (*rulenum)++; - if (s->target_offset == sizeof(struct ipt_entry) && + if (unconditional(s) && strcmp(t->target.u.kernel.target->name, XT_STANDARD_TARGET) == 0 && - t->verdict < 0 && - unconditional(&s->ip)) { + t->verdict < 0) { /* Tail of chains: STANDARD target (return/policy) */ *comment = *chainname == hookname ? comments[NF_IP_TRACE_COMMENT_POLICY] @@ -468,11 +468,10 @@ mark_source_chains(const struct xt_table_info *newinfo, e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); /* Unconditional return/END. */ - if ((e->target_offset == sizeof(struct ipt_entry) && + if ((unconditional(e) && (strcmp(t->target.u.user.name, XT_STANDARD_TARGET) == 0) && - t->verdict < 0 && unconditional(&e->ip)) || - visited) { + t->verdict < 0) || visited) { unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, @@ -705,7 +704,7 @@ static bool check_underflow(const struct ipt_entry *e) const struct xt_entry_target *t; unsigned int verdict; - if (!unconditional(&e->ip)) + if (!unconditional(e)) return false; t = ipt_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) @@ -727,7 +726,8 @@ check_entry_size_and_hooks(struct ipt_entry *e, unsigned int h; if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 || - (unsigned char *)e + sizeof(struct ipt_entry) >= limit) { + (unsigned char *)e + sizeof(struct ipt_entry) >= limit || + (unsigned char *)e + e->next_offset > limit) { duprintf("Bad offset %p\n", e); return -EINVAL; } @@ -747,9 +747,9 @@ check_entry_size_and_hooks(struct ipt_entry *e, newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { if (!check_underflow(e)) { - pr_err("Underflows must be unconditional and " - "use the STANDARD target with " - "ACCEPT/DROP\n"); + pr_debug("Underflows must be unconditional and " + "use the STANDARD target with " + "ACCEPT/DROP\n"); return -EINVAL; } newinfo->underflow[h] = underflows[h]; @@ -1484,7 +1484,8 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 || - (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) { + (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit || + (unsigned char *)e + e->next_offset > limit) { duprintf("Bad offset %p, limit = %p\n", e, limit); return -EINVAL; } diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 9931152..9a30807 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -123,8 +123,16 @@ static int masq_inet_event(struct notifier_block *this, unsigned long event, void *ptr) { - struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; - return masq_device_event(this, event, dev); + struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev; + /* The masq_dev_notifier will catch the case of the device going + * down. So if the inetdev is dead and being destroyed we have + * no work to do. Otherwise this is an individual address removal + * and we have to perform the flush. + */ + if (idev->dead) + return NOTIFY_DONE; + + return masq_device_event(this, event, idev->dev); } static struct notifier_block masq_dev_notifier = { diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 93fbd72..02743c2 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -641,7 +641,7 @@ 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) + if (len > 0xFFFF || len < icmph_len) return -EMSGSIZE; /* diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 14cb310..387fc82 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -208,11 +208,12 @@ get_entry(const void *base, unsigned int offset) /* All zeroes == unconditional rule. */ /* Mildly perf critical (only if packet tracing is on) */ -static inline bool unconditional(const struct ip6t_ip6 *ipv6) +static inline bool unconditional(const struct ip6t_entry *e) { static const struct ip6t_ip6 uncond; - return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; + return e->target_offset == sizeof(struct ip6t_entry) && + memcmp(&e->ipv6, &uncond, sizeof(uncond)) == 0; } static inline const struct xt_entry_target * @@ -269,11 +270,10 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, } else if (s == e) { (*rulenum)++; - if (s->target_offset == sizeof(struct ip6t_entry) && + if (unconditional(s) && strcmp(t->target.u.kernel.target->name, XT_STANDARD_TARGET) == 0 && - t->verdict < 0 && - unconditional(&s->ipv6)) { + t->verdict < 0) { /* Tail of chains: STANDARD target (return/policy) */ *comment = *chainname == hookname ? comments[NF_IP6_TRACE_COMMENT_POLICY] @@ -490,11 +490,10 @@ mark_source_chains(const struct xt_table_info *newinfo, e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); /* Unconditional return/END. */ - if ((e->target_offset == sizeof(struct ip6t_entry) && + if ((unconditional(e) && (strcmp(t->target.u.user.name, XT_STANDARD_TARGET) == 0) && - t->verdict < 0 && - unconditional(&e->ipv6)) || visited) { + t->verdict < 0) || visited) { unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, @@ -728,7 +727,7 @@ static bool check_underflow(const struct ip6t_entry *e) const struct xt_entry_target *t; unsigned int verdict; - if (!unconditional(&e->ipv6)) + if (!unconditional(e)) return false; t = ip6t_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) @@ -750,7 +749,8 @@ check_entry_size_and_hooks(struct ip6t_entry *e, unsigned int h; if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 || - (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { + (unsigned char *)e + sizeof(struct ip6t_entry) >= limit || + (unsigned char *)e + e->next_offset > limit) { duprintf("Bad offset %p\n", e); return -EINVAL; } @@ -770,9 +770,9 @@ check_entry_size_and_hooks(struct ip6t_entry *e, newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { if (!check_underflow(e)) { - pr_err("Underflows must be unconditional and " - "use the STANDARD target with " - "ACCEPT/DROP\n"); + pr_debug("Underflows must be unconditional and " + "use the STANDARD target with " + "ACCEPT/DROP\n"); return -EINVAL; } newinfo->underflow[h] = underflows[h]; @@ -1508,7 +1508,8 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 || - (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) { + (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit || + (unsigned char *)e + e->next_offset > limit) { duprintf("Bad offset %p, limit = %p\n", e, limit); return -EINVAL; } diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 3b44d0f..b4da958 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -177,7 +177,7 @@ EXPORT_SYMBOL_GPL(nf_ct_invert_tuple); static void clean_from_lists(struct nf_conn *ct) { - pr_debug("clean_from_lists(%p)\n", ct); + pr_debug("clean_from_lists(%pK)\n", ct); hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); @@ -192,7 +192,7 @@ destroy_conntrack(struct nf_conntrack *nfct) struct net *net = nf_ct_net(ct); struct nf_conntrack_l4proto *l4proto; - pr_debug("destroy_conntrack(%p)\n", ct); + pr_debug("destroy_conntrack(%pK)\n", ct); NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); @@ -225,7 +225,7 @@ destroy_conntrack(struct nf_conntrack *nfct) if (ct->master) nf_ct_put(ct->master); - pr_debug("destroy_conntrack: returning ct=%p to slab\n", ct); + pr_debug("destroy_conntrack: returning ct=%pK to slab\n", ct); nf_conntrack_free(ct); } @@ -470,7 +470,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) /* No external references means no one else could have confirmed us. */ NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); - pr_debug("Confirming conntrack %p\n", ct); + pr_debug("Confirming conntrack %pK\n", ct); spin_lock_bh(&nf_conntrack_lock); @@ -786,7 +786,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, spin_lock_bh(&nf_conntrack_lock); exp = nf_ct_find_expectation(net, zone, tuple); if (exp) { - pr_debug("conntrack: expectation arrives ct=%p exp=%p\n", + pr_debug("conntrack: expectation arrives ct=%pK exp=%pK\n", ct, exp); /* Welcome, Mr. Bond. We've been expecting you... */ __set_bit(IPS_EXPECTED_BIT, &ct->status); @@ -871,14 +871,14 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, } else { /* Once we've had two way comms, always ESTABLISHED. */ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { - pr_debug("nf_conntrack_in: normal packet for %p\n", ct); + pr_debug("nf_conntrack_in: normal packet for %pK\n", ct); *ctinfo = IP_CT_ESTABLISHED; } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) { - pr_debug("nf_conntrack_in: related packet for %p\n", + pr_debug("nf_conntrack_in: related packet for %pK\n", ct); *ctinfo = IP_CT_RELATED; } else { - pr_debug("nf_conntrack_in: new packet for %p\n", ct); + pr_debug("nf_conntrack_in: new packet for %pK\n", ct); *ctinfo = IP_CT_NEW; } *set_reply = 0; @@ -1016,7 +1016,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, /* Should be unconfirmed, so not in hash table yet */ NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); - pr_debug("Altering reply tuple of %p to ", ct); + pr_debug("Altering reply tuple of %pK to ", ct); nf_ct_dump_tuple(newreply); ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; @@ -1516,7 +1516,7 @@ static int nf_conntrack_init_net(struct net *net) goto err_stat; } - net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net); + net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%pK", net); if (!net->ct.slabname) { ret = -ENOMEM; goto err_slabname; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index b0869fe..9d4ad83 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -663,6 +663,10 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size) { struct xt_table_info *newinfo; int cpu; + size_t sz = sizeof(*newinfo) + size; + + if (sz < sizeof(*newinfo)) + return NULL; /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > totalram_pages) diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index c8a53e5..5fa5e46 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -1987,7 +1987,7 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned, f_count = atomic_long_read( &sock_tag_entry->socket->file->f_count); len = snprintf(outp, char_count, - "sock=%p tag=0x%llx (uid=%u) pid=%u " + "sock=%pK tag=0x%llx (uid=%u) pid=%u " "f_count=%lu\n", sock_tag_entry->sk, sock_tag_entry->tag, uid, diff --git a/net/socket.c b/net/socket.c index e4c7f90..3b5e6bb 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1683,6 +1683,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, if (len > INT_MAX) len = INT_MAX; + if (unlikely(!access_ok(VERIFY_READ, buff, len))) + return -EFAULT; sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@ -1742,6 +1744,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, if (size > INT_MAX) size = INT_MAX; + if (unlikely(!access_ok(VERIFY_WRITE, ubuf, size))) + return -EFAULT; sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@ -2294,31 +2298,31 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, break; } -out_put: - fput_light(sock->file, fput_needed); - if (err == 0) - return datagrams; + goto out_put; + + if (datagrams == 0) { + datagrams = err; + goto out_put; + } - if (datagrams != 0) { + /* + * We may return less entries than requested (vlen) if the + * sock is non block and there aren't enough datagrams... + */ + if (err != -EAGAIN) { /* - * We may return less entries than requested (vlen) if the - * sock is non block and there aren't enough datagrams... + * ... or if recvmsg returns an error after we + * received some datagrams, where we record the + * error to return on the next call or if the + * app asks about it using getsockopt(SO_ERROR). */ - if (err != -EAGAIN) { - /* - * ... or if recvmsg returns an error after we - * received some datagrams, where we record the - * error to return on the next call or if the - * app asks about it using getsockopt(SO_ERROR). - */ - sock->sk->sk_err = -err; - } - - return datagrams; + sock->sk->sk_err = -err; } +out_put: + fput_light(sock->file, fput_needed); - return err; + return datagrams; } SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 93b2b59..7eb36fd 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -262,6 +262,11 @@ cmd_lzo = (cat $(filter-out FORCE,$^) | \ lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) +quiet_cmd_lz4 = LZ4 $@ +cmd_lz4 = (cat $(filter-out FORCE,$^) | \ + lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + # XZ # --------------------------------------------------------------------------- # Use xzkern to compress the kernel image and xzmisc to compress other things. diff --git a/security/keys/key.c b/security/keys/key.c index e1704f6..d2765e4 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -580,7 +580,7 @@ int key_reject_and_link(struct key *key, mutex_unlock(&key_construction_mutex); - if (keyring) + if (keyring && link_ret == 0) __key_link_end(keyring, key->type, prealloc); /* wake up anyone waiting for a key to be constructed */ diff --git a/security/keys/proc.c b/security/keys/proc.c index 49bbc97..3f7b410 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -188,7 +188,7 @@ static int proc_keys_show(struct seq_file *m, void *v) struct timespec now; unsigned long timo; key_ref_t key_ref, skey_ref; - char xbuf[12]; + char xbuf[16]; int rc; key_ref = make_key_ref(key, 0); diff --git a/sound/core/control.c b/sound/core/control.c index 6128f69..2b79043 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1077,9 +1077,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, long private_size; struct user_element *ue; int idx, err; - - if (card->user_ctl_count >= MAX_USER_CONTROLS) - return -ENOMEM; + if (info->count < 1) return -EINVAL; access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : @@ -1088,21 +1086,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); info->id.numid = 0; memset(&kctl, 0, sizeof(kctl)); - down_write(&card->controls_rwsem); - _kctl = snd_ctl_find_id(card, &info->id); - err = 0; - if (_kctl) { - if (replace) - err = snd_ctl_remove(card, _kctl); - else - err = -EBUSY; - } else { - if (replace) - err = -ENOENT; + + if (replace) { + err = snd_ctl_remove_user_ctl(file, &info->id); + if (err) + return err; } - up_write(&card->controls_rwsem); - if (err < 0) - return err; + + if (card->user_ctl_count >= MAX_USER_CONTROLS) + return -ENOMEM; + memcpy(&kctl.id, &info->id, sizeof(info->id)); kctl.count = info->owner ? info->owner : 1; access |= SNDRV_CTL_ELEM_ACCESS_USER; diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index b8b31c4..14d483d 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -90,7 +90,7 @@ static int snd_hrtimer_start(struct snd_timer *t) struct snd_hrtimer *stime = t->private_data; atomic_set(&stime->running, 0); - hrtimer_cancel(&stime->hrt); + hrtimer_try_to_cancel(&stime->hrt); hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), HRTIMER_MODE_REL); atomic_set(&stime->running, 1); @@ -101,6 +101,7 @@ static int snd_hrtimer_stop(struct snd_timer *t) { struct snd_hrtimer *stime = t->private_data; atomic_set(&stime->running, 0); + hrtimer_try_to_cancel(&stime->hrt); return 0; } diff --git a/sound/core/timer.c b/sound/core/timer.c index 950eed0..22c43b3 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -72,7 +72,7 @@ struct snd_timer_user { struct timespec tstamp; /* trigger tstamp */ wait_queue_head_t qchange_sleep; struct fasync_struct *fasync; - struct mutex tread_sem; + struct mutex ioctl_lock; }; /* list of timers */ @@ -214,11 +214,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master) slave->slave_id == master->slave_id) { list_move_tail(&slave->open_list, &master->slave_list_head); spin_lock_irq(&slave_active_lock); + spin_lock(&master->timer->lock); slave->master = master; slave->timer = master->timer; if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) list_add_tail(&slave->active_list, &master->slave_active_head); + spin_unlock(&master->timer->lock); spin_unlock_irq(&slave_active_lock); } } @@ -342,15 +344,18 @@ int snd_timer_close(struct snd_timer_instance *timeri) timer->hw.close) timer->hw.close(timer); /* remove slave links */ + spin_lock_irq(&slave_active_lock); + spin_lock(&timer->lock); list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) { - spin_lock_irq(&slave_active_lock); - _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); list_move_tail(&slave->open_list, &snd_timer_slave_list); slave->master = NULL; slave->timer = NULL; - spin_unlock_irq(&slave_active_lock); + list_del_init(&slave->ack_list); + list_del_init(&slave->active_list); } + spin_unlock(&timer->lock); + spin_unlock_irq(&slave_active_lock); mutex_unlock(®ister_mutex); } if (timeri->private_free) @@ -436,9 +441,12 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) spin_lock_irqsave(&slave_active_lock, flags); timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; - if (timeri->master) + if (timeri->master && timeri->timer) { + spin_lock(&timeri->timer->lock); list_add_tail(&timeri->active_list, &timeri->master->slave_active_head); + spin_unlock(&timeri->timer->lock); + } spin_unlock_irqrestore(&slave_active_lock, flags); return 1; /* delayed start */ } @@ -484,6 +492,8 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, if (!keep_flag) { spin_lock_irqsave(&slave_active_lock, flags); timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); spin_unlock_irqrestore(&slave_active_lock, flags); } goto __end; @@ -689,7 +699,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (--timer->running) - list_del(&ti->active_list); + list_del_init(&ti->active_list); } if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) @@ -1170,6 +1180,7 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, tu->tstamp = *tstamp; if ((tu->filter & (1 << event)) == 0 || !tu->tread) return; + memset(&r1, 0, sizeof(r1)); r1.event = event; r1.tstamp = *tstamp; r1.val = resolution; @@ -1204,6 +1215,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, } if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { + memset(&r1, 0, sizeof(r1)); r1.event = SNDRV_TIMER_EVENT_RESOLUTION; r1.tstamp = tstamp; r1.val = resolution; @@ -1252,7 +1264,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) return -ENOMEM; spin_lock_init(&tu->qlock); init_waitqueue_head(&tu->qchange_sleep); - mutex_init(&tu->tread_sem); + mutex_init(&tu->ioctl_lock); tu->ticks = 1; tu->queue_size = 128; tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), @@ -1272,8 +1284,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) if (file->private_data) { tu = file->private_data; file->private_data = NULL; + mutex_lock(&tu->ioctl_lock); if (tu->timeri) snd_timer_close(tu->timeri); + mutex_unlock(&tu->ioctl_lock); kfree(tu->queue); kfree(tu->tqueue); kfree(tu); @@ -1511,7 +1525,6 @@ static int snd_timer_user_tselect(struct file *file, int err = 0; tu = file->private_data; - mutex_lock(&tu->tread_sem); if (tu->timeri) { snd_timer_close(tu->timeri); tu->timeri = NULL; @@ -1555,7 +1568,6 @@ static int snd_timer_user_tselect(struct file *file, } __err: - mutex_unlock(&tu->tread_sem); return err; } @@ -1669,6 +1681,7 @@ static int snd_timer_user_params(struct file *file, if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { if (tu->tread) { struct snd_timer_tread tread; + memset(&tread, 0, sizeof(tread)); tread.event = SNDRV_TIMER_EVENT_EARLY; tread.tstamp.tv_sec = 0; tread.tstamp.tv_nsec = 0; @@ -1768,7 +1781,7 @@ enum { SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), }; -static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, +static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_timer_user *tu; @@ -1785,17 +1798,11 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, { int xarg; - mutex_lock(&tu->tread_sem); - if (tu->timeri) { /* too late */ - mutex_unlock(&tu->tread_sem); + if (tu->timeri) /* too late */ return -EBUSY; - } - if (get_user(xarg, p)) { - mutex_unlock(&tu->tread_sem); + if (get_user(xarg, p)) return -EFAULT; - } tu->tread = xarg ? 1 : 0; - mutex_unlock(&tu->tread_sem); return 0; } case SNDRV_TIMER_IOCTL_GINFO: @@ -1828,6 +1835,18 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, return -ENOTTY; } +static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct snd_timer_user *tu = file->private_data; + long ret; + + mutex_lock(&tu->ioctl_lock); + ret = __snd_timer_user_ioctl(file, cmd, arg); + mutex_unlock(&tu->ioctl_lock); + return ret; +} + static int snd_timer_user_fasync(int fd, struct file * file, int on) { struct snd_timer_user *tu; diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 05842c8..2d7b5e7 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -393,6 +393,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) * (fp->maxpacksize & 0x7ff); fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); fp->clock = clock; + INIT_LIST_HEAD(&fp->list); /* some quirks for attributes here */ @@ -434,6 +435,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); err = snd_usb_add_audio_endpoint(chip, stream, fp); if (err < 0) { + list_del(&fp->list); /* unlink for avoiding double-free */ kfree(fp->rate_table); kfree(fp); return err; diff --git a/sound/usb/midi.c b/sound/usb/midi.c index c635a2d..9e864e9 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2213,7 +2213,6 @@ int snd_usbmidi_create(struct snd_card *card, else err = snd_usbmidi_create_endpoints(umidi, endpoints); if (err < 0) { - snd_usbmidi_free(umidi); return err; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 4a650ab..d7f1822 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -139,6 +139,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, kfree(fp); return -EINVAL; } + INIT_LIST_HEAD(&fp->list); if (fp->nr_rates > 0) { rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL); if (!rate_table) { @@ -152,24 +153,31 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, stream = (fp->endpoint & USB_DIR_IN) ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; err = snd_usb_add_audio_endpoint(chip, stream, fp); - if (err < 0) { - kfree(fp); - kfree(rate_table); - return err; - } + if (err < 0) + goto error; if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber || fp->altset_idx >= iface->num_altsetting) { - kfree(fp); - kfree(rate_table); - return -EINVAL; + err = -EINVAL; + goto error; } alts = &iface->altsetting[fp->altset_idx]; + if (get_iface_desc(alts)->bNumEndpoints < 1) { + err = -EINVAL; + goto error; + } + fp->datainterval = snd_usb_parse_datainterval(chip, alts); fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); usb_set_interface(chip->dev, fp->iface, 0); snd_usb_init_pitch(chip, fp->iface, alts, fp); snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max); return 0; + + error: + list_del(&fp->list); /* unlink for avoiding double-free */ + kfree(fp); + kfree(rate_table); + return err; } /* @@ -237,6 +245,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; fp->datainterval = 0; fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + INIT_LIST_HEAD(&fp->list); switch (fp->maxpacksize) { case 0x120: @@ -260,6 +269,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; err = snd_usb_add_audio_endpoint(chip, stream, fp); if (err < 0) { + list_del(&fp->list); /* unlink for avoiding double-free */ kfree(fp); return err; } diff --git a/usr/Kconfig b/usr/Kconfig index 65b845b..16ffe99 100644 --- a/usr/Kconfig +++ b/usr/Kconfig @@ -90,6 +90,15 @@ config RD_LZO Support loading of a LZO encoded initial ramdisk or cpio buffer If unsure, say N. +config RD_LZ4 + bool "Support initial ramdisks compressed using LZ4" if EXPERT + default !EXPERT + depends on BLK_DEV_INITRD + select DECOMPRESS_LZ4 + help + Support loading of a LZ4 encoded initial ramdisk or cpio buffer + If unsure, say N. + choice prompt "Built-in initramfs compression mode" if INITRAMFS_SOURCE!="" help |