diff --git a/linux57-rc-tkg/PKGBUILD b/linux57-rc-tkg/PKGBUILD new file mode 100644 index 0000000..d78b250 --- /dev/null +++ b/linux57-rc-tkg/PKGBUILD @@ -0,0 +1,1116 @@ +# Based on the file created for Arch Linux by: +# Tobias Powalowski +# Thomas Baechler + +# Contributor: Tk-Glitch + +plain ' .---.` `.---.' +plain ' `/syhhhyso- -osyhhhys/`' +plain ' .syNMdhNNhss/``.---.``/sshNNhdMNys.' +plain ' +sdMh.`+MNsssssssssssssssNM+`.hMds+' +plain ' :syNNdhNNhssssssssssssssshNNhdNNys:' +plain ' /ssyhhhysssssssssssssssssyhhhyss/' +plain ' .ossssssssssssssssssssssssssssso.' +plain ' :sssssssssssssssssssssssssssssssss:' +plain ' /sssssssssssssssssssssssssssssssssss/' +plain ' :sssssssssssssoosssssssoosssssssssssss:' +plain ' osssssssssssssoosssssssoossssssssssssso' +plain ' osssssssssssyyyyhhhhhhhyyyyssssssssssso' +plain ' /yyyyyyhhdmmmmNNNNNNNNNNNmmmmdhhyyyyyy/' +plain ' smmmNNNNNNNNNNNNNNNNNNNNNNNNNNNNNmmms' +plain ' /dNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNd/' +plain ' `:sdNNNNNNNNNNNNNNNNNNNNNNNNNds:`' +plain ' `-+shdNNNNNNNNNNNNNNNdhs+-`' +plain ' `.-:///////:-.`' + +_where="$PWD" # track basedir as different Arch based distros are moving srcdir around + +cp "$_where"/linux57-tkg-patches/* "$_where" # copy patches inside the PKGBUILD's dir to preserve makepkg sourcing and md5sum checking +cp "$_where"/linux57-tkg-config/* "$_where" # copy config files and hooks inside the PKGBUILD's dir to preserve makepkg sourcing and md5sum checking + +source "$_where"/customization.cfg # load default configuration from file + +# Load external configuration file if present. Available variable values will overwrite customization.cfg ones. +if [ -e "$_EXT_CONFIG_PATH" ]; then + source "$_EXT_CONFIG_PATH" && msg2 "External configuration file $_EXT_CONFIG_PATH will be used to override customization.cfg values." && msg2 "" +fi + +if [ -z "$_OPTIPROFILE" ] && [ ! -e "$_where"/cpuschedset ]; then + # Prompt about optimized configurations. Available variable values will overwrite customization.cfg/external config ones. + plain "Do you want to use a predefined optimized profile?" + read -rp "`echo $' > 1.Custom\n 2.Ryzen Desktop (Performance)\n 3.Other Desktop (Performance)\nchoice[1-3?]: '`" _OPTIPROFILE; +fi +if [ "$_OPTIPROFILE" == "2" ]; then + source "$_where"/ryzen-desktop-profile.cfg && msg2 "Ryzen Desktop (Performance) profile will be used." && msg2 "" +elif [ "$_OPTIPROFILE" == "3" ]; then + source "$_where"/generic-desktop-profile.cfg && msg2 "Generic Desktop (Performance) profile will be used." && msg2 "" +fi + +# source cpuschedset early if present +if [ -e "$_where"/cpuschedset ]; then + source "$_where"/cpuschedset +fi + +# CPU SCHED selector +if [ -z "$_cpusched" ] && [ ! -e "$_where"/cpuschedset ]; then +# plain "What CPU sched variant do you want to build/install?" +# read -rp "`echo $' > 1.PDS\n 2.MuQSS\n 3.BMQ\n 4.CFS\nchoice[1-4?]: '`" CONDITION; +# if [ "$CONDITION" == "2" ]; then +# echo "_cpusched=\"MuQSS\"" > "$_where"/cpuschedset +# elif [ "$CONDITION" == "3" ]; then +# echo "_cpusched=\"bmq\"" > "$_where"/cpuschedset +# elif [ "$CONDITION" == "4" ]; then + echo "_cpusched=\"cfs\"" > "$_where"/cpuschedset +# else +# echo "_cpusched=\"pds\"" > "$_where"/cpuschedset +# fi + if [ -n "$_custom_pkgbase" ]; then + echo "_custom_pkgbase=\"${_custom_pkgbase}\"" >> "$_where"/cpuschedset + fi +#elif [ "$_cpusched" == "muqss" ] || [ "$_cpusched" == "MuQSS" ]; then +# echo "_cpusched=\"MuQSS\"" > "$_where"/cpuschedset +#elif [ "$_cpusched" == "pds" ]; then +# echo "_cpusched=\"pds\"" > "$_where"/cpuschedset +#elif [ "$_cpusched" == "bmq" ]; then +# echo "_cpusched=\"bmq\"" > "$_where"/cpuschedset +else + echo "_cpusched=\"cfs\"" > "$_where"/cpuschedset +fi + +source "$_where"/cpuschedset + +_basever=57 +if [ -n "$_custom_pkgbase" ]; then + pkgbase="${_custom_pkgbase}" +else + pkgbase=linux"${_basever}"-tkg-"${_cpusched}" +fi +pkgname=("${pkgbase}" "${pkgbase}-headers") +_basekernel=5.7 +_sub=rc1 +pkgver="${_basekernel}"."${_sub}" +pkgrel=1 +pkgdesc='Linux-tkg' +arch=('x86_64') # no i686 in here +url="http://www.kernel.org/" +license=('GPL2') +makedepends=('xmlto' 'docbook-xsl' 'kmod' 'inetutils' 'bc' 'libelf' 'patchutils' 'flex' 'python-sphinx' 'python-sphinx_rtd_theme' 'graphviz' 'imagemagick' 'git') +optdepends=('schedtool') +options=('!strip') +source=("https://git.kernel.org/torvalds/t/linux-${_basekernel}-${_sub}.tar.gz" + 'config.x86_64' # stock Arch config + #'config_hardened.x86_64' # hardened Arch config + # ARCH Patches + 0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch + # TkG + 0002-clear-patches.patch + 0003-glitched-base.patch + 0003-glitched-cfs.patch +# 0004-glitched-ondemand-muqss.patch +# 0004-glitched-muqss.patch +# 0004-5.7-ck1.patch +# 0005-glitched-ondemand-pds.patch +# 0005-glitched-pds.patch +# 0005-v5.7_undead-pds099o.patch + 0006-add-acs-overrides_iommu.patch + 0007-v5.7-fsync.patch + #0008-5.6-bcachefs.patch +# 0009-glitched-ondemand-bmq.patch +# 0009-glitched-bmq.patch +# 0009-bmq_v5.7-r0.patch + 0011-ZFS-fix.patch + #0012-linux-hardened.patch + 0013-tp_smapi_ec.patch +) +sha256sums=('b2367bfb8247f821620d76305580caa1cc4f25ab31cabe3ad61c385d4ddf6df6' + '46a362f76188c1c409776f7b1a8852efb42b8f7ea49951f29ee565587133370a' + '31dc68e84aecfb7d069efb1305049122c65694676be8b955634abcf0675922a2' + 'd02bf5ca08fd610394b9d3a0c3b176d74af206f897dee826e5cbaec97bb4a4aa' + '3eec6cf265fc76428dac1a9bd9894307bab1564bc7583c4d8b9274e5287225ae' + '7058e57fd68367b029adc77f2a82928f1433daaf02c8c279cb2d13556c8804d7' + '19661ec0d39f9663452b34433214c755179894528bf73a42f6ba52ccf572832a' + '2d9260b80b43bbd605cf420d6bd53aa7262103dfd77196ba590ece5600b6dc0d' + '49262ce4a8089fa70275aad742fc914baa28d9c384f710c9a62f64796d13e104' + '7ba451d95d2bc07d983661a7e9602a9b239522c98d42197c706c01905f0efba2') + +export KBUILD_BUILD_HOST=archlinux +export KBUILD_BUILD_USER=$pkgbase +export KBUILD_BUILD_TIMESTAMP="$(date -Ru${SOURCE_DATE_EPOCH:+d @$SOURCE_DATE_EPOCH})" + +user_patcher() { + # To patch the user because all your base are belong to us + local _patches=("$_where"/*."${_userpatch_ext}revert") + if [ ${#_patches[@]} -ge 2 ] || [ -e "${_patches}" ]; then + if [ "$_user_patches_no_confirm" != "true" ]; then + msg2 "Found ${#_patches[@]} 'to revert' userpatches for ${_userpatch_target}:" + printf '%s\n' "${_patches[@]}" + read -rp "Do you want to install it/them? - Be careful with that ;)"$'\n> N/y : ' _CONDITION; + fi + if [ "$_CONDITION" == "y" ] || [ "$_user_patches_no_confirm" == "true" ]; then + for _f in "${_patches[@]}"; do + if [ -e "${_f}" ]; then + msg2 "######################################################" + msg2 "" + msg2 "Reverting your own ${_userpatch_target} patch ${_f}" + msg2 "" + msg2 "######################################################" + patch -Np1 -R < "${_f}" + echo "Reverted your own patch ${_f}" >> "$_where"/last_build_config.log + fi + done + fi + fi + + _patches=("$_where"/*."${_userpatch_ext}patch") + if [ ${#_patches[@]} -ge 2 ] || [ -e "${_patches}" ]; then + if [ "$_user_patches_no_confirm" != "true" ]; then + msg2 "Found ${#_patches[@]} userpatches for ${_userpatch_target}:" + printf '%s\n' "${_patches[@]}" + read -rp "Do you want to install it/them? - Be careful with that ;)"$'\n> N/y : ' _CONDITION; + fi + if [ "$_CONDITION" == "y" ] || [ "$_user_patches_no_confirm" == "true" ]; then + for _f in "${_patches[@]}"; do + if [ -e "${_f}" ]; then + msg2 "######################################################" + msg2 "" + msg2 "Applying your own ${_userpatch_target} patch ${_f}" + msg2 "" + msg2 "######################################################" + patch -Np1 < "${_f}" + echo "Applied your own patch ${_f}" >> "$_where"/last_build_config.log + fi + done + fi + fi +} + +prepare() { + rm -rf $pkgdir # Nuke the entire pkg folder so it'll get regenerated clean on next build + + ln -s "${_where}/customization.cfg" "${srcdir}" # workaround + + cd "${srcdir}/linux-${_basekernel}-${_sub}" + + msg2 "Setting version..." + scripts/setlocalversion --save-scmversion + echo "-$pkgrel-tkg-${_cpusched}" > localversion.10-pkgrel + echo "" > localversion.20-pkgname + + # add upstream patch + #patch -p1 -i ../patch-"${pkgver}" + + # ARCH Patches + if [ "${_configfile}" == "config_hardened.x86_64" ] && [ "${_cpusched}" == "cfs" ]; then + msg2 "Using linux hardened patchset" + patch -Np1 -i ../0012-linux-hardened.patch + else + patch -Np1 -i ../0001-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch + fi + + # TkG + patch -Np1 -i ../0002-clear-patches.patch + + patch -Np1 -i ../0003-glitched-base.patch + + if [ "${_tp_smapi_ec}" != "false" ]; then + patch -Np1 -i ../0013-tp_smapi_ec.patch + fi + + if [ "${_cpusched}" == "MuQSS" ]; then + # MuQSS + patch -Np1 -i ../0004-5.7-ck1.patch + if [ "${_aggressive_ondemand}" == "true" ]; then + patch -Np1 -i ../0004-glitched-ondemand-muqss.patch + fi + patch -Np1 -i ../0004-glitched-muqss.patch + elif [ "${_cpusched}" == "pds" ]; then + # PDS-mq + patch -Np1 -i ../0005-v5.7_undead-pds099o.patch + if [ "${_aggressive_ondemand}" == "true" ]; then + patch -Np1 -i ../0005-glitched-ondemand-pds.patch + fi + patch -Np1 -i ../0005-glitched-pds.patch + elif [ "${_cpusched}" == "bmq" ]; then + # BMQ + patch -Np1 -i ../0009-bmq_v5.7-r0.patch + if [ "${_aggressive_ondemand}" == "true" ]; then + patch -Np1 -i ../0009-glitched-ondemand-bmq.patch + fi + patch -Np1 -i ../0009-glitched-bmq.patch + else + patch -Np1 -i ../0003-glitched-cfs.patch + fi + + if [ -z "${_configfile}" ]; then + _configfile="config.x86_64" + fi + + cat "${srcdir}/${_configfile}" > ./.config + + # Set some -tkg defaults + echo "# CONFIG_DYNAMIC_FAULT is not set" >> ./.config + sed -i -e 's/CONFIG_DEFAULT_FQ_CODEL=y/# CONFIG_DEFAULT_FQ_CODEL is not set/' ./.config + echo "CONFIG_DEFAULT_CAKE=y" >> ./.config + echo "CONFIG_NR_TTY_DEVICES=63" >> ./.config + echo "CONFIG_TP_SMAPI=m" >> ./.config + echo "# CONFIG_NTP_PPS is not set" >> ./.config + sed -i -e 's/CONFIG_CRYPTO_LZ4=m/CONFIG_CRYPTO_LZ4=y/' ./.config + sed -i -e 's/CONFIG_CRYPTO_LZ4HC=m/CONFIG_CRYPTO_LZ4HC=y/' ./.config + sed -i -e 's/CONFIG_LZ4_COMPRESS=m/CONFIG_LZ4_COMPRESS=y/' ./.config + sed -i -e 's/CONFIG_LZ4HC_COMPRESS=m/CONFIG_LZ4HC_COMPRESS=y/' ./.config + #sed -i -e 's/CONFIG_RCU_BOOST_DELAY=500/CONFIG_RCU_BOOST_DELAY=0/' ./.config + sed -i -e 's/# CONFIG_CMDLINE_BOOL is not set/CONFIG_CMDLINE_BOOL=y/' ./.config + echo "CONFIG_CMDLINE=\"${_custom_commandline}\"" >> ./.config + echo "# CONFIG_CMDLINE_OVERRIDE is not set" >> ./.config + if [ "$_noccache" != "true" ] && pacman -Qq ccache &> /dev/null; then + sed -i -e 's/CONFIG_GCC_PLUGINS=y/# CONFIG_GCC_PLUGINS is not set/' ./.config + fi + + if [ "$_font_autoselect" != "false" ]; then + sed -i -e 's/CONFIG_FONT_TER16x32=y/# CONFIG_FONT_TER16x32 is not set\nCONFIG_FONT_AUTOSELECT=y/' ./.config + fi + + # Inject cpuopts options + echo "# CONFIG_MK8SSE3 is not set" >> ./.config + echo "# CONFIG_MK10 is not set" >> ./.config + echo "# CONFIG_MBARCELONA is not set" >> ./.config + echo "# CONFIG_MBOBCAT is not set" >> ./.config + echo "# CONFIG_MJAGUAR is not set" >> ./.config + echo "# CONFIG_MBULLDOZER is not set" >> ./.config + echo "# CONFIG_MPILEDRIVER is not set" >> ./.config + echo "# CONFIG_MSTEAMROLLER is not set" >> ./.config + echo "# CONFIG_MEXCAVATOR is not set" >> ./.config + echo "# CONFIG_MZEN is not set" >> ./.config + echo "# CONFIG_MZEN2 is not set" >> ./.config + echo "# CONFIG_MATOM is not set" >> ./.config + echo "# CONFIG_MNEHALEM is not set" >> ./.config + echo "# CONFIG_MWESTMERE is not set" >> ./.config + echo "# CONFIG_MSILVERMONT is not set" >> ./.config + echo "# CONFIG_MSANDYBRIDGE is not set" >> ./.config + echo "# CONFIG_MIVYBRIDGE is not set" >> ./.config + echo "# CONFIG_MHASWELL is not set" >> ./.config + echo "# CONFIG_MBROADWELL is not set" >> ./.config + echo "# CONFIG_MSKYLAKE is not set" >> ./.config + echo "# CONFIG_MSKYLAKEX is not set" >> ./.config + echo "# CONFIG_MCANNONLAKE is not set" >> ./.config + echo "# CONFIG_MICELAKE is not set" >> ./.config + echo "# CONFIG_MGOLDMONT is not set" >> ./.config + echo "# CONFIG_MGOLDMONTPLUS is not set" >> ./.config + echo "# CONFIG_MCASCADELAKE is not set" >> ./.config + + # Disable some debugging + if [ "${_debugdisable}" == "true" ]; then + sed -i -e 's/CONFIG_SLUB_DEBUG=y/# CONFIG_SLUB_DEBUG is not set/' ./.config + sed -i -e 's/CONFIG_PM_DEBUG=y/# CONFIG_PM_DEBUG is not set/' ./.config + sed -i -e 's/CONFIG_PM_ADVANCED_DEBUG=y/# CONFIG_PM_ADVANCED_DEBUG is not set/' ./.config + sed -i -e 's/CONFIG_PM_SLEEP_DEBUG=y/# CONFIG_PM_SLEEP_DEBUG is not set/' ./.config + sed -i -e 's/CONFIG_ACPI_DEBUG=y/# CONFIG_ACPI_DEBUG is not set/' ./.config + sed -i -e 's/CONFIG_SCHED_DEBUG=y/# CONFIG_SCHED_DEBUG is not set/' ./.config + sed -i -e 's/CONFIG_DEBUG_PREEMPT=y/# CONFIG_DEBUG_PREEMPT is not set/' ./.config + fi + + if [ "${_cpusched}" == "MuQSS" ]; then + # MuQSS default config + echo "CONFIG_SCHED_MUQSS=y" >> ./.config + elif [ "${_cpusched}" == "pds" ]; then + # PDS default config + echo "CONFIG_SCHED_PDS=y" >> ./.config + elif [ "${_cpusched}" == "bmq" ]; then + # BMQ default config + echo "CONFIG_SCHED_BMQ=y" >> ./.config + fi + + if [ "${_cpusched}" == "MuQSS" ] || [ "${_cpusched}" == "pds" ] || [ "${_cpusched}" == "bmq" ]; then + # Disable CFS + sed -i -e 's/CONFIG_FAIR_GROUP_SCHED=y/# CONFIG_FAIR_GROUP_SCHED is not set/' ./.config + sed -i -e 's/CONFIG_CFS_BANDWIDTH=y/# CONFIG_CFS_BANDWIDTH is not set/' ./.config + # sched yield type + if [ -n "$_sched_yield_type" ]; then + CONDITION0="$_sched_yield_type" + else + plain "" + plain "CPU sched_yield_type - Choose what sort of yield sched_yield will perform." + plain "" + plain "For PDS and MuQSS:" + plain "0: No yield." + plain "1: Yield only to better priority/deadline tasks." + plain "2: Expire timeslice and recalculate deadline." + plain "" + plain "For BMQ (experimental) - No recommended value yet, so try for yourself x) :" + plain "0: No yield." + plain "1: Deboost and requeue task. (default)" + plain "2: Set rq skip task." + read -rp "`echo $'\n > 0. Recommended option for gaming on PDS and MuQSS - "tkg" default\n 1. Default, but can lead to stability issues on some platforms\n 2. Can be a good option with low rr_interval on MuQSS\n [0-2?]: '`" CONDITION0; + fi + if [ "$CONDITION0" == "1" ]; then + msg2 "Using default CPU sched yield type (1)" + elif [ "$CONDITION0" == "2" ]; then + sed -i -e 's/int sched_yield_type __read_mostly = 1;/int sched_yield_type __read_mostly = 2;/' ./kernel/sched/"${_cpusched}".c + else + sed -i -e 's/int sched_yield_type __read_mostly = 1;/int sched_yield_type __read_mostly = 0;/' ./kernel/sched/"${_cpusched}".c + fi + fi + + # Round Robin interval + if [ "${_cpusched}" == "MuQSS" ] || [ "${_cpusched}" == "pds" ] || [ "${_cpusched}" == "bmq" ]; then + if [ -n "$_rr_interval" ]; then + CONDITION1="$_rr_interval" + else + plain "" + plain "Round Robin interval is the longest duration two tasks with the same nice level will" + plain "be delayed for. When CPU time is requested by a task, it receives a time slice equal" + plain "to the rr_interval in addition to a virtual deadline. When using yield_type 2, a low" + plain "value can help offset the disadvantages of rescheduling a process that has yielded." + plain "" + plain "MuQSS default: 6ms" + plain "PDS default: 4ms" + plain "BMQ default: 2ms" + read -rp "`echo $'\n > 0.Keep defaults\n 1.2ms\n 2.4ms\n 3.6ms\n 4.8ms\n [0-4?]: '`" CONDITION1; + fi + if [ "$CONDITION1" == "1" ]; then + msg2 "Using 2ms rr_interval" + _rrvalue="2" + elif [ "$CONDITION1" == "2" ]; then + msg2 "Using 4ms rr_interval" + _rrvalue="4" + elif [ "$CONDITION1" == "3" ]; then + msg2 "Using 6ms rr_interval" + _rrvalue="6" + elif [ "$CONDITION1" == "4" ]; then + msg2 "Using 8ms rr_interval" + _rrvalue="8" + else + msg2 "Using default rr_interval" + _rrvalue="default" + fi + if [ "$_rrvalue" != "default" ]; then + if [ "${_cpusched}" == "MuQSS" ]; then + sed -i -e "s/int rr_interval __read_mostly = 6;/int rr_interval __read_mostly = ${_rrvalue};/" ./kernel/sched/"${_cpusched}".c + elif [ "${_cpusched}" == "pds" ]; then + sed -i -e "s/#define SCHED_DEFAULT_RR (4)/#define SCHED_DEFAULT_RR (${_rrvalue})/" ./kernel/sched/"${_cpusched}".c + elif [ "${_cpusched}" == "bmq" ]; then + sed -i -e "s/u64 sched_timeslice_ns __read_mostly = (4 * 1000 * 1000);/u64 sched_timeslice_ns __read_mostly = (${_rrvalue} * 1000 * 1000);/" ./kernel/sched/"${_cpusched}".c + fi + else + if [ "${_cpusched}" == "bmq" ]; then + sed -i -e "s/u64 sched_timeslice_ns __read_mostly = (4 * 1000 * 1000);/u64 sched_timeslice_ns __read_mostly = (2 * 1000 * 1000);/" ./kernel/sched/"${_cpusched}".c + fi + fi + fi + + # zenify + if [ "$_zenify" == "true" ]; then + echo "CONFIG_ZENIFY=y" >> ./.config + elif [ "$_zenify" == "false" ]; then + echo "# CONFIG_ZENIFY is not set" >> ./.config + fi + + # compiler optimization level + if [ "$_compileroptlevel" == "1" ]; then + echo "# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3 is not set" >> ./.config + elif [ "$_compileroptlevel" == "2" ]; then + sed -i -e 's/CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y/# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set/' ./.config + echo "CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y" >> ./.config + elif [ "$_compileroptlevel" == "3" ]; then + sed -i -e 's/CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y/# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set/' ./.config + sed -i -e 's/# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set/CONFIG_CC_OPTIMIZE_FOR_SIZE=y/' ./.config + echo "# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3 is not set" >> ./.config + fi + + # cpu opt + if [ -n "$_processor_opt" ] && [ "$_processor_opt" != "native" ]; then + echo "# CONFIG_MNATIVE is not set" >> ./.config + fi + + if [ -n "$_processor_opt" ] && [ "$_processor_opt" != "generic" ]; then + sed -i -e 's/CONFIG_GENERIC_CPU=y/# CONFIG_GENERIC_CPU is not set/' ./.config + fi + + if [ "$_processor_opt" == "native" ]; then + echo "CONFIG_MNATIVE=y" >> ./.config + elif [ "$_processor_opt" == "k8" ]; then + sed -i -e 's/# CONFIG_MK8 is not set/CONFIG_MK8=y/' ./.config + elif [ "$_processor_opt" == "k8sse3" ]; then + sed -i -e 's/# CONFIG_MK8SSE3 is not set/CONFIG_MK8SSE3=y/' ./.config + elif [ "$_processor_opt" == "k10" ]; then + sed -i -e 's/# CONFIG_MK10 is not set/CONFIG_MK10=y/' ./.config + elif [ "$_processor_opt" == "barcelona" ]; then + sed -i -e 's/# CONFIG_MBARCELONA is not set/CONFIG_MBARCELONA=y/' ./.config + elif [ "$_processor_opt" == "bobcat" ]; then + sed -i -e 's/# CONFIG_MBOBCAT is not set/CONFIG_MBOBCAT=y/' ./.config + elif [ "$_processor_opt" == "jaguar" ]; then + sed -i -e 's/# CONFIG_MJAGUAR is not set/CONFIG_MJAGUAR=y/' ./.config + elif [ "$_processor_opt" == "bulldozer" ]; then + sed -i -e 's/# CONFIG_MBULLDOZER is not set/CONFIG_MBULLDOZER=y/' ./.config + elif [ "$_processor_opt" == "piledriver" ]; then + sed -i -e 's/# CONFIG_MPILEDRIVER is not set/CONFIG_MPILEDRIVER=y/' ./.config + elif [ "$_processor_opt" == "steamroller" ]; then + sed -i -e 's/# CONFIG_MSTEAMROLLER is not set/CONFIG_MSTEAMROLLER=y/' ./.config + elif [ "$_processor_opt" == "excavator" ]; then + sed -i -e 's/# CONFIG_MEXCAVATOR is not set/CONFIG_MEXCAVATOR=y/' ./.config + elif [ "$_processor_opt" == "zen" ]; then + sed -i -e 's/# CONFIG_MZEN is not set/CONFIG_MZEN=y/' ./.config + elif [ "$_processor_opt" == "zen2" ]; then + sed -i -e 's/# CONFIG_MZEN2 is not set/CONFIG_MZEN2=y/' ./.config + elif [ "$_processor_opt" == "mpsc" ]; then + sed -i -e 's/# CONFIG_MPSC is not set/CONFIG_MPSC=y/' ./.config + elif [ "$_processor_opt" == "atom" ]; then + sed -i -e 's/# CONFIG_MATOM is not set/CONFIG_MATOM=y/' ./.config + elif [ "$_processor_opt" == "core2" ]; then + sed -i -e 's/# CONFIG_MCORE2 is not set/CONFIG_MCORE2=y/' ./.config + elif [ "$_processor_opt" == "nehalem" ]; then + sed -i -e 's/# CONFIG_MNEHALEM is not set/CONFIG_MNEHALEM=y/' ./.config + elif [ "$_processor_opt" == "westmere" ]; then + sed -i -e 's/# CONFIG_MWESTMERE is not set/CONFIG_MWESTMERE=y/' ./.config + elif [ "$_processor_opt" == "silvermont" ]; then + sed -i -e 's/# CONFIG_MSILVERMONT is not set/CONFIG_MSILVERMONT=y/' ./.config + elif [ "$_processor_opt" == "sandybridge" ]; then + sed -i -e 's/# CONFIG_MSANDYBRIDGE is not set/CONFIG_MSANDYBRIDGE=y/' ./.config + elif [ "$_processor_opt" == "ivybridge" ]; then + sed -i -e 's/# CONFIG_MIVYBRIDGE is not set/CONFIG_MIVYBRIDGE=y/' ./.config + elif [ "$_processor_opt" == "haswell" ]; then + sed -i -e 's/# CONFIG_MHASWELL is not set/CONFIG_MHASWELL=y/' ./.config + elif [ "$_processor_opt" == "broadwell" ]; then + sed -i -e 's/# CONFIG_MBROADWELL is not set/CONFIG_MBROADWELL=y/' ./.config + elif [ "$_processor_opt" == "skylake" ]; then + sed -i -e 's/# CONFIG_MSKYLAKE is not set/CONFIG_MSKYLAKE=y/' ./.config + elif [ "$_processor_opt" == "skylakex" ]; then + sed -i -e 's/# CONFIG_MSKYLAKEX is not set/CONFIG_MSKYLAKEX=y/' ./.config + elif [ "$_processor_opt" == "cannonlake" ]; then + sed -i -e 's/# CONFIG_MCANNONLAKE is not set/CONFIG_MCANNONLAKE=y/' ./.config + elif [ "$_processor_opt" == "icelake" ]; then + sed -i -e 's/# CONFIG_MICELAKE is not set/CONFIG_MICELAKE=y/' ./.config + elif [ "$_processor_opt" == "goldmont" ]; then + sed -i -e 's/# CONFIG_MGOLDMONT is not set/CONFIG_MGOLDMONT=y/' ./.config + elif [ "$_processor_opt" == "goldmontplus" ]; then + sed -i -e 's/# CONFIG_MGOLDMONTPLUS is not set/CONFIG_MGOLDMONTPLUS=y/' ./.config + elif [ "$_processor_opt" == "cascadelake" ]; then + sed -i -e 's/# CONFIG_MCASCADELAKE is not set/CONFIG_MCASCADELAKE=y/' ./.config + fi + + # irq threading + if [ "$_irq_threading" == "true" ]; then + echo "CONFIG_FORCE_IRQ_THREADING=y" >> ./.config + elif [ "$_irq_threading" == "false" ]; then + echo "# CONFIG_FORCE_IRQ_THREADING is not set" >> ./.config + fi + + # smt nice + if [ "$_smt_nice" == "true" ]; then + echo "CONFIG_SMT_NICE=y" >> ./.config + elif [ "$_smt_nice" == "false" ]; then + echo "# CONFIG_SMT_NICE is not set" >> ./.config + fi + + # random trust cpu + if [ "$_random_trust_cpu" == "true" ]; then + sed -i -e 's/# CONFIG_RANDOM_TRUST_CPU is not set/CONFIG_RANDOM_TRUST_CPU=y/' ./.config + fi + + # rq sharing + if [ "$_runqueue_sharing" == "none" ]; then + echo -e "CONFIG_RQ_NONE=y\n# CONFIG_RQ_SMT is not set\n# CONFIG_RQ_MC is not set\n# CONFIG_RQ_MC_LLC is not set\n# CONFIG_RQ_SMP is not set\n# CONFIG_RQ_ALL is not set" >> ./.config + elif [ -z "$_runqueue_sharing" ] || [ "$_runqueue_sharing" == "smt" ]; then + echo -e "# CONFIG_RQ_NONE is not set\nCONFIG_RQ_SMT=y\n# CONFIG_RQ_MC is not set\n# CONFIG_RQ_MC_LLC is not set\n# CONFIG_RQ_SMP is not set\n# CONFIG_RQ_ALL is not set" >> ./.config + elif [ "$_runqueue_sharing" == "mc" ]; then + echo -e "# CONFIG_RQ_NONE is not set\n# CONFIG_RQ_SMT is not set\nCONFIG_RQ_MC=y\n# CONFIG_RQ_MC_LLC is not set\n# CONFIG_RQ_SMP is not set\n# CONFIG_RQ_ALL is not set" >> ./.config + elif [ "$_runqueue_sharing" == "smp" ]; then + echo -e "# CONFIG_RQ_NONE is not set\n# CONFIG_RQ_SMT is not set\n# CONFIG_RQ_MC is not set\n# CONFIG_RQ_MC_LLC is not set\nCONFIG_RQ_SMP=y\n# CONFIG_RQ_ALL is not set" >> ./.config + elif [ "$_runqueue_sharing" == "all" ]; then + echo -e "# CONFIG_RQ_NONE is not set\n# CONFIG_RQ_SMT is not set\n# CONFIG_RQ_MC is not set\n# CONFIG_RQ_MC_LLC is not set\n# CONFIG_RQ_SMP is not set\nCONFIG_RQ_ALL=y" >> ./.config + elif [ "$_runqueue_sharing" == "mc-llc" ]; then + echo -e "# CONFIG_RQ_NONE is not set\n# CONFIG_RQ_SMT is not set\n# CONFIG_RQ_MC is not set\nCONFIG_RQ_MC_LLC=y\n# CONFIG_RQ_SMP is not set\n# CONFIG_RQ_ALL is not set" >> ./.config + fi + + # timer freq + if [ -n "$_timer_freq" ] && [ "$_timer_freq" != "300" ]; then + sed -i -e 's/CONFIG_HZ_300=y/# CONFIG_HZ_300 is not set/' ./.config + sed -i -e 's/CONFIG_HZ_300_NODEF=y/# CONFIG_HZ_300_NODEF is not set/' ./.config + if [ "$_timer_freq" == "1000" ]; then + sed -i -e 's/# CONFIG_HZ_1000 is not set/CONFIG_HZ_1000=y/' ./.config + sed -i -e 's/CONFIG_HZ=300/CONFIG_HZ=1000/' ./.config + echo "# CONFIG_HZ_500 is not set" >> ./.config + echo "# CONFIG_HZ_500_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_750 is not set" >> ./.config + echo "# CONFIG_HZ_750_NODEF is not set" >> ./.config + echo "CONFIG_HZ_1000_NODEF=y" >> ./.config + echo "# CONFIG_HZ_250_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_300_NODEF is not set" >> ./.config + elif [ "$_timer_freq" == "750" ]; then + sed -i -e 's/CONFIG_HZ=300/CONFIG_HZ=750/' ./.config + echo "# CONFIG_HZ_500 is not set" >> ./.config + echo "# CONFIG_HZ_500_NODEF is not set" >> ./.config + echo "CONFIG_HZ_750=y" >> ./.config + echo "CONFIG_HZ_750_NODEF=y" >> ./.config + echo "# CONFIG_HZ_1000_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_250_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_300_NODEF is not set" >> ./.config + elif [ "$_timer_freq" == "500" ]; then + sed -i -e 's/CONFIG_HZ=300/CONFIG_HZ=500/' ./.config + echo "CONFIG_HZ_500=y" >> ./.config + echo "CONFIG_HZ_500_NODEF=y" >> ./.config + echo "# CONFIG_HZ_750 is not set" >> ./.config + echo "# CONFIG_HZ_750_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_1000_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_250_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_300_NODEF is not set" >> ./.config + elif [ "$_timer_freq" == "100" ]; then + sed -i -e 's/CONFIG_HZ=300/CONFIG_HZ=100/' ./.config + echo "# CONFIG_HZ_500 is not set" >> ./.config + echo "# CONFIG_HZ_750 is not set" >> ./.config + echo "# CONFIG_HZ_1000_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_750_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_500_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_250_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_300_NODEF is not set" >> ./.config + echo "CONFIG_HZ_100=y" >> ./.config + echo "CONFIG_HZ_100_NODEF=y" >> ./.config + fi + elif [ "${_cpusched}" == "MuQSS" ] && [ -z "$_timer_freq" ]; then + sed -i -e 's/CONFIG_HZ=300/CONFIG_HZ=100/' ./.config + echo "# CONFIG_HZ_500 is not set" >> ./.config + echo "# CONFIG_HZ_750 is not set" >> ./.config + echo "# CONFIG_HZ_1000_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_750_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_500_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_250_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_300_NODEF is not set" >> ./.config + echo "CONFIG_HZ_100=y" >> ./.config + echo "CONFIG_HZ_100_NODEF=y" >> ./.config + else + sed -i -e 's/CONFIG_HZ_300=y/# CONFIG_HZ_300 is not set/' ./.config + sed -i -e 's/CONFIG_HZ_300_NODEF=y/# CONFIG_HZ_300_NODEF is not set/' ./.config + sed -i -e 's/CONFIG_HZ=300/CONFIG_HZ=500/' ./.config + echo "CONFIG_HZ_500=y" >> ./.config + echo "CONFIG_HZ_500_NODEF=y" >> ./.config + echo "# CONFIG_HZ_250_NODEF is not set" >> ./.config + echo "# CONFIG_HZ_300_NODEF is not set" >> ./.config + fi + + # default cpu gov + if [ "$_default_cpu_gov" == "performance" ]; then + sed -i -e 's/CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y/# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set/' ./.config + sed -i -e 's/# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set/CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y/' ./.config + elif [ "$_default_cpu_gov" == "ondemand" ]; then + sed -i -e 's/CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y/# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set/' ./.config + sed -i -e 's/# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set/CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y/' ./.config + fi + + # ACPI_CPUFREQ disablement + if [ "$_disable_acpi_cpufreq" == "true" ]; then + sed -i -e 's/CONFIG_X86_ACPI_CPUFREQ=m/# CONFIG_X86_ACPI_CPUFREQ is not set/' ./.config + fi + + # ftrace + if [ -z "$_ftracedisable" ]; then + plain "" + plain "Disable FUNCTION_TRACER/GRAPH_TRACER? Lowers overhead but limits debugging" + plain "and analyzing of kernel functions." + read -rp "`echo $' > N/y : '`" CONDITION2; + fi + if [ "$CONDITION2" == "y" ] || [ "$_ftracedisable" == "true" ]; then + sed -i -e 's/CONFIG_FUNCTION_TRACER=y/# CONFIG_FUNCTION_TRACER is not set/' ./.config + sed -i -e 's/CONFIG_FUNCTION_GRAPH_TRACER=y/# CONFIG_FUNCTION_GRAPH_TRACER is not set/' ./.config + fi + + # disable numa + if [ -z "$_numadisable" ]; then + plain "" + plain "Disable NUMA? Lowers overhead, but breaks CUDA/NvEnc on Nvidia if disabled." + plain "https://bbs.archlinux.org/viewtopic.php?id=239174" + read -rp "`echo $' > N/y : '`" CONDITION3; + fi + if [ "$CONDITION3" == "y" ] || [ "$_numadisable" == "true" ]; then + # disable NUMA since 99.9% of users do not have multiple CPUs but do have multiple cores in one CPU + sed -i -e 's/CONFIG_NUMA=y/# CONFIG_NUMA is not set/' \ + -i -e '/CONFIG_AMD_NUMA=y/d' \ + -i -e '/CONFIG_X86_64_ACPI_NUMA=y/d' \ + -i -e '/CONFIG_NODES_SPAN_OTHER_NODES=y/d' \ + -i -e '/# CONFIG_NUMA_EMU is not set/d' \ + -i -e '/CONFIG_NODES_SHIFT=6/d' \ + -i -e '/CONFIG_NEED_MULTIPLE_NODES=y/d' \ + -i -e '/CONFIG_USE_PERCPU_NUMA_NODE_ID=y/d' \ + -i -e '/CONFIG_ACPI_NUMA=y/d' ./.config + fi + + # tickless + if [ -z "$_tickless" ]; then + plain "" + plain "Use CattaRappa mode (Tickless/Dynticks) ?" + plain "Can give higher performances in many cases but lower consistency on some hardware." + plain "Just tickless idle can perform better with some platforms (mostly AMD) or CPU schedulers (mostly MuQSS)." + if [ "${_cpusched}" == "MuQSS" ]; then + read -rp "`echo $'\n 0.No, use periodic ticks\n 1.Yes, full tickless baby!\n > 2.Just tickless idle plz\n [0-2?]: '`" CONDITION4; + else + read -rp "`echo $'\n 0.No, use periodic ticks\n > 1.Yes, full tickless baby!\n 2.Just tickless idle plz\n [0-2?]: '`" CONDITION4; + fi + fi + if [ "$CONDITION4" == "0" ] || [ "$_tickless" == "0" ]; then + echo "# CONFIG_NO_HZ_FULL_NODEF is not set" >> ./.config + sed -i -e 's/# CONFIG_HZ_PERIODIC is not set/CONFIG_HZ_PERIODIC=y/' ./.config + sed -i -e 's/CONFIG_NO_HZ_IDLE=y/# CONFIG_NO_HZ_IDLE is not set/' ./.config + sed -i -e 's/CONFIG_NO_HZ_FULL=y/# CONFIG_NO_HZ_FULL is not set/' ./.config + sed -i -e 's/CONFIG_NO_HZ=y/# CONFIG_NO_HZ is not set/' ./.config + sed -i -e 's/CONFIG_NO_HZ_COMMON=y/# CONFIG_NO_HZ_COMMON is not set/' ./.config + elif [ "$CONDITION4" == "2" ] || [ "$_tickless" == "2" ]; then + echo "# CONFIG_NO_HZ_FULL_NODEF is not set" >> ./.config + sed -i -e 's/CONFIG_HZ_PERIODIC=y/# CONFIG_HZ_PERIODIC is not set/' ./.config + sed -i -e 's/# CONFIG_NO_HZ_IDLE is not set/CONFIG_NO_HZ_IDLE=y/' ./.config + sed -i -e 's/CONFIG_NO_HZ_FULL=y/# CONFIG_NO_HZ_FULL is not set/' ./.config + sed -i -e 's/# CONFIG_NO_HZ is not set/CONFIG_NO_HZ=y/' ./.config + sed -i -e 's/# CONFIG_NO_HZ_COMMON is not set/CONFIG_NO_HZ_COMMON=y/' ./.config + else + if [ "${_cpusched}" == "MuQSS" ]; then + echo "# CONFIG_NO_HZ_FULL_NODEF is not set" >> ./.config + sed -i -e 's/CONFIG_HZ_PERIODIC=y/# CONFIG_HZ_PERIODIC is not set/' ./.config + sed -i -e 's/# CONFIG_NO_HZ_IDLE is not set/CONFIG_NO_HZ_IDLE=y/' ./.config + sed -i -e 's/CONFIG_NO_HZ_FULL=y/# CONFIG_NO_HZ_FULL is not set/' ./.config + sed -i -e 's/# CONFIG_NO_HZ is not set/CONFIG_NO_HZ=y/' ./.config + sed -i -e 's/# CONFIG_NO_HZ_COMMON is not set/CONFIG_NO_HZ_COMMON=y/' ./.config + else + echo "CONFIG_NO_HZ_FULL_NODEF=y" >> ./.config + sed -i -e 's/CONFIG_HZ_PERIODIC=y/# CONFIG_HZ_PERIODIC is not set/' ./.config + sed -i -e 's/CONFIG_NO_HZ_IDLE=y/# CONFIG_NO_HZ_IDLE is not set/' ./.config + sed -i -e 's/# CONFIG_NO_HZ_FULL is not set/CONFIG_NO_HZ_FULL=y/' ./.config + sed -i -e 's/# CONFIG_NO_HZ is not set/CONFIG_NO_HZ=y/' ./.config + sed -i -e 's/# CONFIG_NO_HZ_COMMON is not set/CONFIG_NO_HZ_COMMON=y/' ./.config + echo "CONFIG_CONTEXT_TRACKING=y" >> ./.config + echo "# CONFIG_CONTEXT_TRACKING_FORCE is not set" >> ./.config + fi + fi + + # voluntary preempt + if [ -z "$_voluntary_preempt" ]; then + plain "" + plain "Use explicit preemption points?" + plain "It can improve latency on PDS (at the cost of throughput)" + plain "and improve throughput on other schedulers (at the cost of latency)" + read -rp "`echo $' > N/y : '`" CONDITION5; + fi + if [ "$CONDITION5" == "y" ] || [ "$_voluntary_preempt" == "true" ]; then + sed -i -e 's/CONFIG_PREEMPT=y/# CONFIG_PREEMPT is not set/' ./.config + sed -i -e 's/CONFIG_PREEMPT_LL=y/# CONFIG_PREEMPT_LL is not set/' ./.config + sed -i -e 's/# CONFIG_PREEMPT_VOLUNTARY is not set/CONFIG_PREEMPT_VOLUNTARY=y/' ./.config + fi + + # Open Firmware support + if [ -z "$_OFenable" ]; then + plain "" + plain "Enable Device Tree and Open Firmware support?" + read -rp "`echo $' > N/y : '`" CONDITION6; + fi + if [ "$CONDITION6" == "y" ] || [ "$_OFenable" == "true" ]; then + sed -i -e 's/# CONFIG_OF is not set/CONFIG_OF=y/' ./.config + fi + + # acs override + if [ -z "$_acs_override" ]; then + plain "" + plain "Use ACS override patch?" + plain "https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF#Bypassing_the_IOMMU_groups_.28ACS_override_patch.29" + read -rp "`echo $' > N/y : '`" CONDITION7; + fi + if [ "$CONDITION7" == "y" ] || [ "$_acs_override" == "true" ]; then + patch -Np1 -i ../0006-add-acs-overrides_iommu.patch + fi + + # bcachefs +# if [ -z "$_bcachefs" ]; then +# plain "" +# plain "Add Bcache filesystem support? You'll have to install bcachefs-tools-git from AUR for utilities." +# plain "https://bcachefs.org/" +# read -rp "`echo $' > N/y : '`" CONDITION8; +# fi +# if [ "$CONDITION8" == "y" ] || [ "$_bcachefs" == "true" ]; then +# patch -Np1 -i ../0008-5.7-bcachefs.patch +# echo "CONFIG_BCACHEFS_FS=m" >> ./.config +# echo "CONFIG_BCACHEFS_QUOTA=y" >> ./.config +# echo "CONFIG_BCACHEFS_POSIX_ACL=y" >> ./.config +# echo "# CONFIG_BCACHEFS_DEBUG is not set" >> ./.config +# echo "# CONFIG_BCACHEFS_TESTS is not set" >> ./.config +# echo "# CONFIG_DEBUG_CLOSURES is not set" >> ./.config +# fi + + # fsync support + if [ -z "$_fsync" ]; then + plain "" + plain "Enable support for fsync, an experimental replacement for esync in Valve Proton 4.11+" + plain "https://steamcommunity.com/games/221410/announcements/detail/2957094910196249305" + read -rp "`echo $' > N/y : '`" CONDITION9; + fi + if [ "$CONDITION9" == "y" ] || [ "$_fsync" == "true" ]; then + patch -Np1 -i ../0007-v5.7-fsync.patch + fi + + # ZFS fix + if [ -z "$_zfsfix" ]; then + plain "" + plain "Add back missing symbol for AES-NI/AVX support on ZFS" + plain "https://github.com/NixOS/nixpkgs/blob/master/pkgs/os-specific/linux/kernel/export_kernel_fpu_functions_5_3.patch" + read -rp "`echo $' > N/y : '`" CONDITION11; + fi + if [ "$CONDITION11" == "y" ] || [ "$_zfsfix" == "true" ]; then + patch -Np1 -i ../0011-ZFS-fix.patch + fi + + # Community patches + if [ -n "$_community_patches" ]; then + _community_patches=($_community_patches) + for _p in ${_community_patches[@]}; do + ln -s "$_where"/../../community-patches/linux57-tkg/$_p "$_where"/ + done + fi + + # userpatches + if [ "$_user_patches" == "true" ]; then + _userpatch_target="linux-${_basekernel}" + _userpatch_ext="my" + user_patcher + fi + + # Community patches removal + for _p in ${_community_patches[@]}; do + rm -f "$_where"/$_p + done + + # don't run depmod on 'make install'. We'll do this ourselves in packaging + sed -i '2iexit 0' scripts/depmod.sh + + # get kernel version + make prepare + + # modprobed-db + if [ -z "$_modprobeddb" ]; then + plain "" + plain "Use modprobed db to clean config from unneeded modules?" + plain "Speeds up compilation considerably. Requires root." + plain "https://wiki.archlinux.org/index.php/Modprobed-db" + plain "!!!! Make sure to have a well populated db !!!!" + read -rp "`echo $' > N/y : '`" CONDITIONMPDB; + fi + if [ "$CONDITIONMPDB" == "y" ] || [ "$_modprobeddb" == "true" ]; then + sudo modprobed-db recall + make localmodconfig + fi + + if [ true = "$_config_fragments" ]; then + local fragments=() + mapfile -d '' -t fragments < <(find "$_where" -type f -name "*.myfrag" -print0) + + if [ true = "$_config_fragments_no_confirm" ]; then + printf 'Using config fragment %s\n' "${fragments[@]#$_where/}" + else + for i in "${!fragments[@]}"; do + while true; do + read -r -p 'Found config fragment '"${fragments[$i]#$_where/}"', apply it? [y/N] ' CONDITIONMPDB + CONDITIONMPDB="$(printf '%s' "$CONDITIONMPDB" | tr '[:upper:]' '[:lower:]')" + case "$CONDITIONMPDB" in + y|yes) + break;; + n|no|'') + unset fragments[$i] + break;; + *) + echo 'Please answer with yes or no' + esac + done + done + fi + + if [ 0 -lt "${#fragments[@]}" ]; then + scripts/kconfig/merge_config.sh -m .config "${fragments[@]}" + fi + fi + + # menuconfig / nconfig + if [ -z "$_menunconfig" ]; then + plain "" + plain "*Optional* For advanced users - Do you want to use make menuconfig or nconfig" + plain "to configure the kernel before building it?" + plain "If you do, make sure your terminal is currently" + plain "at least 19 lines by 80 columns large or you'll get an error :D" + read -rp "`echo $' > 0. nope\n 1. menuconfig\n 2. nconfig\n choice[0-2?]: '`" CONDITIONMNC; + _menunconfig="$CONDITIONMNC" + fi + if [ 1 = "$_menunconfig" ]; then + cp .config .config.orig + make menuconfig + elif [ 2 = "$_menunconfig" ]; then + cp .config .config.orig + make nconfig + else + # rewrite configuration + yes "" | make config >/dev/null + fi + if [ 1 = "$_menunconfig" ] || [ 2 = "$_menunconfig" ]; then + if [ -z "${_diffconfig}" ]; then + while true; do + read -r -p 'Generate a config fragment from your changes? [y/N] ' CONDITIONF + CONDITIONF="$(printf '%s' "$CONDITIONF" | tr '[:upper:]' '[:lower:]')" + case "$CONDITIONF" in + y|yes) + _diffconfig=true + break;; + n|no|'') + _diffconfig=false + break;; + *) + echo 'Please answer with yes or no' + esac + done + fi + if [ true = "$_diffconfig" ]; then + if [ -z "$_diffconfig_name" ]; then + IFS= read -r -p 'Filename for the config fragment [leave empty to not generate fragment]: ' _diffconfig_name + fi + if [ -z "$_diffconfig_name" ]; then + echo 'No file name given, not generating config fragment.' + else ( + prev_pwd="${PWD:-$(pwd)}" + cd "$_where" + "${prev_pwd}/scripts/diffconfig" -m "${prev_pwd}/.config.orig" "${prev_pwd}/.config" > "$_diffconfig_name" + ) fi + fi + rm .config.orig + fi + + make -s kernelrelease > version + msg2 "Prepared %s version %s" "$pkgbase" "$( /dev/null; then + export PATH="/usr/lib/ccache/bin/:$PATH" + export CCACHE_SLOPPINESS="file_macro,locale,time_macros" + export CCACHE_NOHASHDIR="true" + msg2 'ccache was found and will be used' + fi + + # build! + _runtime=$( time ( schedtool -B -n 1 -e ionice -n 1 make ${_force_all_threads} LOCALVERSION= bzImage modules 2>&1 ) 3>&1 1>&2 2>&3 ) || _runtime=$( time ( make ${_force_all_threads} LOCALVERSION= bzImage modules 2>&1 ) 3>&1 1>&2 2>&3 ) +} + +hackbase() { + pkgdesc="The $pkgdesc kernel and modules" + depends=('coreutils' 'kmod' 'initramfs') + optdepends=('linux-docs: Kernel hackers manual - HTML documentation that comes with the Linux kernel.' + 'crda: to set the correct wireless channels of your country.' + 'linux-firmware: Firmware files for Linux' + 'modprobed-db: Keeps track of EVERY kernel module that has ever been probed. Useful for make localmodconfig.' + 'nvidia-tkg: NVIDIA drivers for all installed kernels - non-dkms version.' + 'nvidia-dkms-tkg: NVIDIA drivers for all installed kernels - dkms version.' + 'update-grub: Simple wrapper around grub-mkconfig.') + provides=("linux=${pkgver}" "${pkgbase}" VIRTUALBOX-GUEST-MODULES WIREGUARD-MODULE) + replaces=(virtualbox-guest-modules-arch wireguard-arch) + + cd "${srcdir}/linux-${_basekernel}-${_sub}" + + # get kernel version + local _kernver="$( +From: Serge Hallyn +Date: Fri, 31 May 2013 19:12:12 +0100 +Subject: [PATCH] add sysctl to disallow unprivileged CLONE_NEWUSER by default + +Signed-off-by: Serge Hallyn +[bwh: Remove unneeded binary sysctl bits] +Signed-off-by: Daniel Micay +--- + kernel/fork.c | 15 +++++++++++++++ + kernel/sysctl.c | 12 ++++++++++++ + kernel/user_namespace.c | 3 +++ + 3 files changed, 30 insertions(+) + +diff --git a/kernel/fork.c b/kernel/fork.c +index 07cc743698d3668e..4011d68a8ff9305c 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -102,6 +102,11 @@ + + #define CREATE_TRACE_POINTS + #include ++#ifdef CONFIG_USER_NS ++extern int unprivileged_userns_clone; ++#else ++#define unprivileged_userns_clone 0 ++#endif + + /* + * Minimum number of threads to boot the kernel +@@ -1555,6 +1560,10 @@ static __latent_entropy struct task_struct *copy_process( + if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) + return ERR_PTR(-EINVAL); + ++ if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) ++ if (!capable(CAP_SYS_ADMIN)) ++ return ERR_PTR(-EPERM); ++ + /* + * Thread groups must share signals as well, and detached threads + * can only be started up within the thread group. +@@ -2348,6 +2357,12 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) + if (unshare_flags & CLONE_NEWNS) + unshare_flags |= CLONE_FS; + ++ if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { ++ err = -EPERM; ++ if (!capable(CAP_SYS_ADMIN)) ++ goto bad_unshare_out; ++ } ++ + err = check_unshare_flags(unshare_flags); + if (err) + goto bad_unshare_out; +diff --git a/kernel/sysctl.c b/kernel/sysctl.c +index b86520ed3fb60fbf..f7dab3760839f1a1 100644 +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -105,6 +105,9 @@ extern int core_uses_pid; + extern char core_pattern[]; + extern unsigned int core_pipe_limit; + #endif ++#ifdef CONFIG_USER_NS ++extern int unprivileged_userns_clone; ++#endif + extern int pid_max; + extern int pid_max_min, pid_max_max; + extern int percpu_pagelist_fraction; +@@ -513,6 +516,15 @@ static struct ctl_table kern_table[] = { + .proc_handler = proc_dointvec, + }, + #endif ++#ifdef CONFIG_USER_NS ++ { ++ .procname = "unprivileged_userns_clone", ++ .data = &unprivileged_userns_clone, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, ++#endif + #ifdef CONFIG_PROC_SYSCTL + { + .procname = "tainted", +diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c +index c490f1e4313b998a..dd03bd39d7bf194d 100644 +--- a/kernel/user_namespace.c ++++ b/kernel/user_namespace.c +@@ -24,6 +24,9 @@ + #include + #include + ++/* sysctl */ ++int unprivileged_userns_clone; ++ + static struct kmem_cache *user_ns_cachep __read_mostly; + static DEFINE_MUTEX(userns_state_mutex); + +-- +2.15.1 + +From b5202296055dd333db4425120d3f93ef4e6a0573 Mon Sep 17 00:00:00 2001 +From: "Jan Alexander Steffens (heftig)" +Date: Thu, 7 Dec 2017 13:50:48 +0100 +Subject: ZEN: Add CONFIG for unprivileged_userns_clone + +This way our default behavior continues to match the vanilla kernel. +--- + init/Kconfig | 16 ++++++++++++++++ + kernel/user_namespace.c | 4 ++++ + 2 files changed, 20 insertions(+) + +diff --git a/init/Kconfig b/init/Kconfig +index 4592bf7997c0..f3df02990aff 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1004,6 +1004,22 @@ config USER_NS + + If unsure, say N. + ++config USER_NS_UNPRIVILEGED ++ bool "Allow unprivileged users to create namespaces" ++ default y ++ depends on USER_NS ++ help ++ When disabled, unprivileged users will not be able to create ++ new namespaces. Allowing users to create their own namespaces ++ has been part of several recent local privilege escalation ++ exploits, so if you need user namespaces but are ++ paranoid^Wsecurity-conscious you want to disable this. ++ ++ This setting can be overridden at runtime via the ++ kernel.unprivileged_userns_clone sysctl. ++ ++ If unsure, say Y. ++ + config PID_NS + bool "PID Namespaces" + default y +diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c +index 6b9dbc257e34..107b17f0d528 100644 +--- a/kernel/user_namespace.c ++++ b/kernel/user_namespace.c +@@ -27,7 +27,11 @@ + #include + + /* sysctl */ ++#ifdef CONFIG_USER_NS_UNPRIVILEGED ++int unprivileged_userns_clone = 1; ++#else + int unprivileged_userns_clone; ++#endif + + static struct kmem_cache *user_ns_cachep __read_mostly; + static DEFINE_MUTEX(userns_state_mutex); diff --git a/linux57-rc-tkg/linux57-tkg-patches/0002-clear-patches.patch b/linux57-rc-tkg/linux57-tkg-patches/0002-clear-patches.patch new file mode 100644 index 0000000..a7c9d4a --- /dev/null +++ b/linux57-rc-tkg/linux57-tkg-patches/0002-clear-patches.patch @@ -0,0 +1,354 @@ +From 2ac70785613ef4c6b16414986bb18bd7b60d2a13 Mon Sep 17 00:00:00 2001 +From: Arjan van de Ven +Date: Mon, 14 Mar 2016 11:10:58 -0600 +Subject: [PATCH] pci pme wakeups + +Reduce wakeups for PME checks, which are a workaround for miswired +boards (sadly, too many of them) in laptops. +--- + drivers/pci/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index c25acace7d91..0ddebdad9f5b 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -61,7 +61,7 @@ struct pci_pme_device { + struct pci_dev *dev; + }; + +-#define PME_TIMEOUT 1000 /* How long between PME checks */ ++#define PME_TIMEOUT 4000 /* How long between PME checks */ + + static void pci_dev_d3_sleep(struct pci_dev *dev) + { +-- +2.20.1 + +From 7e7e36c67aa71d6a1ec5676d99d37c1fea389ceb Mon Sep 17 00:00:00 2001 +From: Arjan van de Ven +Date: Sat, 19 Mar 2016 21:32:19 -0400 +Subject: [PATCH] intel_idle: tweak cpuidle cstates + +Increase target_residency in cpuidle cstate + +Tune intel_idle to be a bit less agressive; +Clear linux is cleaner in hygiene (wakupes) than the average linux, +so we can afford changing these in a way that increases +performance while keeping power efficiency +--- + drivers/idle/intel_idle.c | 44 +++++++++++++++++++-------------------- + 1 file changed, 22 insertions(+), 22 deletions(-) + +diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c +index 8b5d85c91e9d..5e2d813a048d 100644 +--- a/drivers/idle/intel_idle.c ++++ b/drivers/idle/intel_idle.c +@@ -466,7 +466,7 @@ static struct cpuidle_state hsw_cstates[] = { + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01), + .exit_latency = 10, +- .target_residency = 20, ++ .target_residency = 120, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -474,7 +474,7 @@ static struct cpuidle_state hsw_cstates[] = { + .desc = "MWAIT 0x10", + .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 33, +- .target_residency = 100, ++ .target_residency = 900, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -482,7 +482,7 @@ static struct cpuidle_state hsw_cstates[] = { + .desc = "MWAIT 0x20", + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 133, +- .target_residency = 400, ++ .target_residency = 1000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -490,7 +490,7 @@ static struct cpuidle_state hsw_cstates[] = { + .desc = "MWAIT 0x32", + .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 166, +- .target_residency = 500, ++ .target_residency = 1500, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -498,7 +498,7 @@ static struct cpuidle_state hsw_cstates[] = { + .desc = "MWAIT 0x40", + .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 300, +- .target_residency = 900, ++ .target_residency = 2000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -506,7 +506,7 @@ static struct cpuidle_state hsw_cstates[] = { + .desc = "MWAIT 0x50", + .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 600, +- .target_residency = 1800, ++ .target_residency = 5000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -514,7 +514,7 @@ static struct cpuidle_state hsw_cstates[] = { + .desc = "MWAIT 0x60", + .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 2600, +- .target_residency = 7700, ++ .target_residency = 9000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -534,7 +534,7 @@ static struct cpuidle_state bdw_cstates[] = { + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01), + .exit_latency = 10, +- .target_residency = 20, ++ .target_residency = 120, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -542,7 +542,7 @@ static struct cpuidle_state bdw_cstates[] = { + .desc = "MWAIT 0x10", + .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 40, +- .target_residency = 100, ++ .target_residency = 1000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -550,7 +550,7 @@ static struct cpuidle_state bdw_cstates[] = { + .desc = "MWAIT 0x20", + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 133, +- .target_residency = 400, ++ .target_residency = 1000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -558,7 +558,7 @@ static struct cpuidle_state bdw_cstates[] = { + .desc = "MWAIT 0x32", + .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 166, +- .target_residency = 500, ++ .target_residency = 2000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -566,7 +566,7 @@ static struct cpuidle_state bdw_cstates[] = { + .desc = "MWAIT 0x40", + .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 300, +- .target_residency = 900, ++ .target_residency = 4000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -574,7 +574,7 @@ static struct cpuidle_state bdw_cstates[] = { + .desc = "MWAIT 0x50", + .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 600, +- .target_residency = 1800, ++ .target_residency = 7000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -582,7 +582,7 @@ static struct cpuidle_state bdw_cstates[] = { + .desc = "MWAIT 0x60", + .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 2600, +- .target_residency = 7700, ++ .target_residency = 9000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -603,7 +603,7 @@ static struct cpuidle_state skl_cstates[] = { + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01), + .exit_latency = 10, +- .target_residency = 20, ++ .target_residency = 120, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -611,7 +611,7 @@ static struct cpuidle_state skl_cstates[] = { + .desc = "MWAIT 0x10", + .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 70, +- .target_residency = 100, ++ .target_residency = 1000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -619,7 +619,7 @@ static struct cpuidle_state skl_cstates[] = { + .desc = "MWAIT 0x20", + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 85, +- .target_residency = 200, ++ .target_residency = 600, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -627,7 +627,7 @@ static struct cpuidle_state skl_cstates[] = { + .desc = "MWAIT 0x33", + .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 124, +- .target_residency = 800, ++ .target_residency = 3000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -635,7 +635,7 @@ static struct cpuidle_state skl_cstates[] = { + .desc = "MWAIT 0x40", + .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 200, +- .target_residency = 800, ++ .target_residency = 3200, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -643,7 +643,7 @@ static struct cpuidle_state skl_cstates[] = { + .desc = "MWAIT 0x50", + .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 480, +- .target_residency = 5000, ++ .target_residency = 9000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -651,7 +651,7 @@ static struct cpuidle_state skl_cstates[] = { + .desc = "MWAIT 0x60", + .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 890, +- .target_residency = 5000, ++ .target_residency = 9000, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +@@ -672,7 +672,7 @@ static struct cpuidle_state skx_cstates[] = { + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01), + .exit_latency = 10, +- .target_residency = 20, ++ .target_residency = 300, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { +-- +2.20.1 + +From b8211d4f79dd88dfc2d4bd52be46103ea0b70e3e Mon Sep 17 00:00:00 2001 +From: Arjan van de Ven +Date: Fri, 6 Jan 2017 15:34:09 +0000 +Subject: [PATCH] ipv4/tcp: allow the memory tuning for tcp to go a little + bigger than default + +--- + net/ipv4/tcp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index cf3c5095c10e..b30d51837b2d 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -3897,8 +3897,8 @@ void __init tcp_init(void) + tcp_init_mem(); + /* Set per-socket limits to no more than 1/128 the pressure threshold */ + limit = nr_free_buffer_pages() << (PAGE_SHIFT - 7); +- max_wshare = min(4UL*1024*1024, limit); +- max_rshare = min(6UL*1024*1024, limit); ++ max_wshare = min(16UL*1024*1024, limit); ++ max_rshare = min(16UL*1024*1024, limit); + + init_net.ipv4.sysctl_tcp_wmem[0] = SK_MEM_QUANTUM; + init_net.ipv4.sysctl_tcp_wmem[1] = 16*1024; +-- +2.20.1 + +From 050223869257b87e22636158a80da38d877248ed Mon Sep 17 00:00:00 2001 +From: Arjan van de Ven +Date: Sun, 18 Feb 2018 23:35:41 +0000 +Subject: [PATCH] locking: rwsem: spin faster + +tweak rwsem owner spinning a bit +--- + kernel/locking/rwsem.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c +index eef04551eae7..1ec5ab4c8ff7 100644 +--- a/kernel/locking/rwsem.c ++++ b/kernel/locking/rwsem.c +@@ -720,6 +720,7 @@ rwsem_spin_on_owner(struct rw_semaphore *sem, unsigned long nonspinnable) + struct task_struct *new, *owner; + unsigned long flags, new_flags; + enum owner_state state; ++ int i = 0; + + owner = rwsem_owner_flags(sem, &flags); + state = rwsem_owner_state(owner, flags, nonspinnable); +@@ -753,7 +754,8 @@ rwsem_spin_on_owner(struct rw_semaphore *sem, unsigned long nonspinnable) + break; + } + +- cpu_relax(); ++ if (i++ > 1000) ++ cpu_relax(); + } + rcu_read_unlock(); + +From b836ea320114643d4354b43acb6ec8bb06ada487 Mon Sep 17 00:00:00 2001 +From: Arjan van de Ven +Date: Thu, 2 Jun 2016 23:36:32 -0500 +Subject: [PATCH] drivers: Initialize ata before graphics + +ATA init is the long pole in the boot process, and its asynchronous. +move the graphics init after it so that ata and graphics initialize +in parallel +--- + drivers/Makefile | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/drivers/Makefile b/drivers/Makefile +index aaef17cc6512..d08f3a394929 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -58,15 +58,8 @@ obj-y += char/ + # iommu/ comes before gpu as gpu are using iommu controllers + obj-y += iommu/ + +-# gpu/ comes after char for AGP vs DRM startup and after iommu +-obj-y += gpu/ +- + obj-$(CONFIG_CONNECTOR) += connector/ + +-# i810fb and intelfb depend on char/agp/ +-obj-$(CONFIG_FB_I810) += video/fbdev/i810/ +-obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/ +- + obj-$(CONFIG_PARPORT) += parport/ + obj-$(CONFIG_NVM) += lightnvm/ + obj-y += base/ block/ misc/ mfd/ nfc/ +@@ -79,6 +72,14 @@ obj-$(CONFIG_IDE) += ide/ + obj-y += scsi/ + obj-y += nvme/ + obj-$(CONFIG_ATA) += ata/ ++ ++# gpu/ comes after char for AGP vs DRM startup and after iommu ++obj-y += gpu/ ++ ++# i810fb and intelfb depend on char/agp/ ++obj-$(CONFIG_FB_I810) += video/fbdev/i810/ ++obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/ ++ + obj-$(CONFIG_TARGET_CORE) += target/ + obj-$(CONFIG_MTD) += mtd/ + obj-$(CONFIG_SPI) += spi/ diff --git a/linux57-rc-tkg/linux57-tkg-patches/0003-glitched-base.patch b/linux57-rc-tkg/linux57-tkg-patches/0003-glitched-base.patch new file mode 100644 index 0000000..67d777f --- /dev/null +++ b/linux57-rc-tkg/linux57-tkg-patches/0003-glitched-base.patch @@ -0,0 +1,1447 @@ +From f7f49141a5dbe9c99d78196b58c44307fb2e6be3 Mon Sep 17 00:00:00 2001 +From: Tk-Glitch +Date: Wed, 4 Jul 2018 04:30:08 +0200 +Subject: glitched + +diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h +index 87f1fc9..b3be470 100755 +--- a/scripts/mkcompile_h ++++ b/scripts/mkcompile_h +@@ -50,8 +50,8 @@ else + fi + + UTS_VERSION="#$VERSION" +-CONFIG_FLAGS="" +-if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi ++CONFIG_FLAGS="TKG" ++if [ -n "$SMP" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS SMP"; fi + if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi + UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP" + +diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu +index af9c967782f6..bf07a8c0f495 100644 +--- a/arch/x86/Kconfig.cpu ++++ b/arch/x86/Kconfig.cpu +@@ -123,6 +123,7 @@ config MPENTIUMM + config MPENTIUM4 + bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/older Xeon" + depends on X86_32 ++ select X86_P6_NOP + ---help--- + Select this for Intel Pentium 4 chips. This includes the + Pentium 4, Pentium D, P4-based Celeron and Xeon, and +@@ -155,9 +156,8 @@ config MPENTIUM4 + -Paxville + -Dempsey + +- + config MK6 +- bool "K6/K6-II/K6-III" ++ bool "AMD K6/K6-II/K6-III" + depends on X86_32 + ---help--- + Select this for an AMD K6-family processor. Enables use of +@@ -165,7 +165,7 @@ config MK6 + flags to GCC. + + config MK7 +- bool "Athlon/Duron/K7" ++ bool "AMD Athlon/Duron/K7" + depends on X86_32 + ---help--- + Select this for an AMD Athlon K7-family processor. Enables use of +@@ -173,12 +173,90 @@ config MK7 + flags to GCC. + + config MK8 +- bool "Opteron/Athlon64/Hammer/K8" ++ bool "AMD Opteron/Athlon64/Hammer/K8" + ---help--- + Select this for an AMD Opteron or Athlon64 Hammer-family processor. + Enables use of some extended instructions, and passes appropriate + optimization flags to GCC. + ++config MK8SSE3 ++ bool "AMD Opteron/Athlon64/Hammer/K8 with SSE3" ++ ---help--- ++ Select this for improved AMD Opteron or Athlon64 Hammer-family processors. ++ Enables use of some extended instructions, and passes appropriate ++ optimization flags to GCC. ++ ++config MK10 ++ bool "AMD 61xx/7x50/PhenomX3/X4/II/K10" ++ ---help--- ++ Select this for an AMD 61xx Eight-Core Magny-Cours, Athlon X2 7x50, ++ Phenom X3/X4/II, Athlon II X2/X3/X4, or Turion II-family processor. ++ Enables use of some extended instructions, and passes appropriate ++ optimization flags to GCC. ++ ++config MBARCELONA ++ bool "AMD Barcelona" ++ ---help--- ++ Select this for AMD Family 10h Barcelona processors. ++ ++ Enables -march=barcelona ++ ++config MBOBCAT ++ bool "AMD Bobcat" ++ ---help--- ++ Select this for AMD Family 14h Bobcat processors. ++ ++ Enables -march=btver1 ++ ++config MJAGUAR ++ bool "AMD Jaguar" ++ ---help--- ++ Select this for AMD Family 16h Jaguar processors. ++ ++ Enables -march=btver2 ++ ++config MBULLDOZER ++ bool "AMD Bulldozer" ++ ---help--- ++ Select this for AMD Family 15h Bulldozer processors. ++ ++ Enables -march=bdver1 ++ ++config MPILEDRIVER ++ bool "AMD Piledriver" ++ ---help--- ++ Select this for AMD Family 15h Piledriver processors. ++ ++ Enables -march=bdver2 ++ ++config MSTEAMROLLER ++ bool "AMD Steamroller" ++ ---help--- ++ Select this for AMD Family 15h Steamroller processors. ++ ++ Enables -march=bdver3 ++ ++config MEXCAVATOR ++ bool "AMD Excavator" ++ ---help--- ++ Select this for AMD Family 15h Excavator processors. ++ ++ Enables -march=bdver4 ++ ++config MZEN ++ bool "AMD Zen" ++ ---help--- ++ Select this for AMD Family 17h Zen processors. ++ ++ Enables -march=znver1 ++ ++config MZEN2 ++ bool "AMD Zen 2" ++ ---help--- ++ Select this for AMD Family 17h Zen 2 processors. ++ ++ Enables -march=znver2 ++ + config MCRUSOE + bool "Crusoe" + depends on X86_32 +@@ -260,6 +338,7 @@ config MVIAC7 + + config MPSC + bool "Intel P4 / older Netburst based Xeon" ++ select X86_P6_NOP + depends on X86_64 + ---help--- + Optimize for Intel Pentium 4, Pentium D and older Nocona/Dempsey +@@ -269,8 +348,19 @@ config MPSC + using the cpu family field + in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one. + ++config MATOM ++ bool "Intel Atom" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for the Intel Atom platform. Intel Atom CPUs have an ++ in-order pipelining architecture and thus can benefit from ++ accordingly optimized code. Use a recent GCC with specific Atom ++ support in order to fully benefit from selecting this option. ++ + config MCORE2 +- bool "Core 2/newer Xeon" ++ bool "Intel Core 2" ++ select X86_P6_NOP + ---help--- + + Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and +@@ -278,14 +368,133 @@ config MCORE2 + family in /proc/cpuinfo. Newer ones have 6 and older ones 15 + (not a typo) + +-config MATOM +- bool "Intel Atom" ++ Enables -march=core2 ++ ++config MNEHALEM ++ bool "Intel Nehalem" ++ select X86_P6_NOP + ---help--- + +- Select this for the Intel Atom platform. Intel Atom CPUs have an +- in-order pipelining architecture and thus can benefit from +- accordingly optimized code. Use a recent GCC with specific Atom +- support in order to fully benefit from selecting this option. ++ Select this for 1st Gen Core processors in the Nehalem family. ++ ++ Enables -march=nehalem ++ ++config MWESTMERE ++ bool "Intel Westmere" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for the Intel Westmere formerly Nehalem-C family. ++ ++ Enables -march=westmere ++ ++config MSILVERMONT ++ bool "Intel Silvermont" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for the Intel Silvermont platform. ++ ++ Enables -march=silvermont ++ ++config MGOLDMONT ++ bool "Intel Goldmont" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for the Intel Goldmont platform including Apollo Lake and Denverton. ++ ++ Enables -march=goldmont ++ ++config MGOLDMONTPLUS ++ bool "Intel Goldmont Plus" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for the Intel Goldmont Plus platform including Gemini Lake. ++ ++ Enables -march=goldmont-plus ++ ++config MSANDYBRIDGE ++ bool "Intel Sandy Bridge" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for 2nd Gen Core processors in the Sandy Bridge family. ++ ++ Enables -march=sandybridge ++ ++config MIVYBRIDGE ++ bool "Intel Ivy Bridge" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for 3rd Gen Core processors in the Ivy Bridge family. ++ ++ Enables -march=ivybridge ++ ++config MHASWELL ++ bool "Intel Haswell" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for 4th Gen Core processors in the Haswell family. ++ ++ Enables -march=haswell ++ ++config MBROADWELL ++ bool "Intel Broadwell" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for 5th Gen Core processors in the Broadwell family. ++ ++ Enables -march=broadwell ++ ++config MSKYLAKE ++ bool "Intel Skylake" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for 6th Gen Core processors in the Skylake family. ++ ++ Enables -march=skylake ++ ++config MSKYLAKEX ++ bool "Intel Skylake X" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for 6th Gen Core processors in the Skylake X family. ++ ++ Enables -march=skylake-avx512 ++ ++config MCANNONLAKE ++ bool "Intel Cannon Lake" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for 8th Gen Core processors ++ ++ Enables -march=cannonlake ++ ++config MICELAKE ++ bool "Intel Ice Lake" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for 10th Gen Core processors in the Ice Lake family. ++ ++ Enables -march=icelake-client ++ ++config MCASCADELAKE ++ bool "Intel Cascade Lake" ++ select X86_P6_NOP ++ ---help--- ++ ++ Select this for Xeon processors in the Cascade Lake family. ++ ++ Enables -march=cascadelake + + config GENERIC_CPU + bool "Generic-x86-64" +@@ -294,6 +503,19 @@ config GENERIC_CPU + Generic x86-64 CPU. + Run equally well on all x86-64 CPUs. + ++config MNATIVE ++ bool "Native optimizations autodetected by GCC" ++ ---help--- ++ ++ GCC 4.2 and above support -march=native, which automatically detects ++ the optimum settings to use based on your processor. -march=native ++ also detects and applies additional settings beyond -march specific ++ to your CPU, (eg. -msse4). Unless you have a specific reason not to ++ (e.g. distcc cross-compiling), you should probably be using ++ -march=native rather than anything listed below. ++ ++ Enables -march=native ++ + endchoice + + config X86_GENERIC +@@ -318,7 +540,7 @@ config X86_INTERNODE_CACHE_SHIFT + config X86_L1_CACHE_SHIFT + int + default "7" if MPENTIUM4 || MPSC +- default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU ++ default "6" if MK7 || MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MZEN2 || MJAGUAR || MPENTIUMM || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MNATIVE || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU + default "4" if MELAN || M486SX || M486 || MGEODEGX1 + default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX + +@@ -336,35 +558,36 @@ config X86_ALIGNMENT_16 + + config X86_INTEL_USERCOPY + def_bool y +- depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2 ++ depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK8SSE3 || MK7 || MEFFICEON || MCORE2 || MK10 || MBARCELONA || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MNATIVE + + config X86_USE_PPRO_CHECKSUM + def_bool y +- depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM ++ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MK10 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MK8SSE3 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MATOM || MNATIVE + + config X86_USE_3DNOW + def_bool y + depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML + +-# +-# P6_NOPs are a relatively minor optimization that require a family >= +-# 6 processor, except that it is broken on certain VIA chips. +-# Furthermore, AMD chips prefer a totally different sequence of NOPs +-# (which work on all CPUs). In addition, it looks like Virtual PC +-# does not understand them. +-# +-# As a result, disallow these if we're not compiling for X86_64 (these +-# NOPs do work on all x86-64 capable chips); the list of processors in +-# the right-hand clause are the cores that benefit from this optimization. +-# + config X86_P6_NOP +- def_bool y +- depends on X86_64 +- depends on (MCORE2 || MPENTIUM4 || MPSC) ++ default n ++ bool "Support for P6_NOPs on Intel chips" ++ depends on (MCORE2 || MPENTIUM4 || MPSC || MATOM || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MNATIVE) ++ ---help--- ++ P6_NOPs are a relatively minor optimization that require a family >= ++ 6 processor, except that it is broken on certain VIA chips. ++ Furthermore, AMD chips prefer a totally different sequence of NOPs ++ (which work on all CPUs). In addition, it looks like Virtual PC ++ does not understand them. ++ ++ As a result, disallow these if we're not compiling for X86_64 (these ++ NOPs do work on all x86-64 capable chips); the list of processors in ++ the right-hand clause are the cores that benefit from this optimization. ++ ++ Say Y if you have Intel CPU newer than Pentium Pro, N otherwise. + + config X86_TSC + def_bool y +- depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64 ++ depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MK8SSE3 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MNATIVE || MATOM) || X86_64 + + config X86_CMPXCHG64 + def_bool y +@@ -374,7 +597,7 @@ config X86_CMPXCHG64 + # generates cmov. + config X86_CMOV + def_bool y +- depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX) ++ depends on (MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MZEN2 || MJAGUAR || MK7 || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MGOLDMONT || MGOLDMONTPLUS || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MCANNONLAKE || MICELAKE || MCASCADELAKE || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MNATIVE || MATOM || MGEODE_LX) + + config X86_MINIMUM_CPU_FAMILY + int +diff --git a/arch/x86/Makefile b/arch/x86/Makefile +index 94df0868804b..dcbed7e3a070 100644 +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -119,13 +119,53 @@ else + KBUILD_CFLAGS += $(call cc-option,-mskip-rax-setup) + + # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu) ++ cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native) + cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8) ++ cflags-$(CONFIG_MK8SSE3) += $(call cc-option,-march=k8-sse3,-mtune=k8) ++ cflags-$(CONFIG_MK10) += $(call cc-option,-march=amdfam10) ++ cflags-$(CONFIG_MBARCELONA) += $(call cc-option,-march=barcelona) ++ cflags-$(CONFIG_MBOBCAT) += $(call cc-option,-march=btver1) ++ cflags-$(CONFIG_MJAGUAR) += $(call cc-option,-march=btver2) ++ cflags-$(CONFIG_MBULLDOZER) += $(call cc-option,-march=bdver1) ++ cflags-$(CONFIG_MPILEDRIVER) += $(call cc-option,-march=bdver2) ++ cflags-$(CONFIG_MSTEAMROLLER) += $(call cc-option,-march=bdver3) ++ cflags-$(CONFIG_MEXCAVATOR) += $(call cc-option,-march=bdver4) ++ cflags-$(CONFIG_MZEN) += $(call cc-option,-march=znver1) ++ cflags-$(CONFIG_MZEN2) += $(call cc-option,-march=znver2) + cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona) + + cflags-$(CONFIG_MCORE2) += \ +- $(call cc-option,-march=core2,$(call cc-option,-mtune=generic)) +- cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom) \ +- $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic)) ++ $(call cc-option,-march=core2,$(call cc-option,-mtune=core2)) ++ cflags-$(CONFIG_MNEHALEM) += \ ++ $(call cc-option,-march=nehalem,$(call cc-option,-mtune=nehalem)) ++ cflags-$(CONFIG_MWESTMERE) += \ ++ $(call cc-option,-march=westmere,$(call cc-option,-mtune=westmere)) ++ cflags-$(CONFIG_MSILVERMONT) += \ ++ $(call cc-option,-march=silvermont,$(call cc-option,-mtune=silvermont)) ++ cflags-$(CONFIG_MGOLDMONT) += \ ++ $(call cc-option,-march=goldmont,$(call cc-option,-mtune=goldmont)) ++ cflags-$(CONFIG_MGOLDMONTPLUS) += \ ++ $(call cc-option,-march=goldmont-plus,$(call cc-option,-mtune=goldmont-plus)) ++ cflags-$(CONFIG_MSANDYBRIDGE) += \ ++ $(call cc-option,-march=sandybridge,$(call cc-option,-mtune=sandybridge)) ++ cflags-$(CONFIG_MIVYBRIDGE) += \ ++ $(call cc-option,-march=ivybridge,$(call cc-option,-mtune=ivybridge)) ++ cflags-$(CONFIG_MHASWELL) += \ ++ $(call cc-option,-march=haswell,$(call cc-option,-mtune=haswell)) ++ cflags-$(CONFIG_MBROADWELL) += \ ++ $(call cc-option,-march=broadwell,$(call cc-option,-mtune=broadwell)) ++ cflags-$(CONFIG_MSKYLAKE) += \ ++ $(call cc-option,-march=skylake,$(call cc-option,-mtune=skylake)) ++ cflags-$(CONFIG_MSKYLAKEX) += \ ++ $(call cc-option,-march=skylake-avx512,$(call cc-option,-mtune=skylake-avx512)) ++ cflags-$(CONFIG_MCANNONLAKE) += \ ++ $(call cc-option,-march=cannonlake,$(call cc-option,-mtune=cannonlake)) ++ cflags-$(CONFIG_MICELAKE) += \ ++ $(call cc-option,-march=icelake-client,$(call cc-option,-mtune=icelake-client)) ++ cflags-$(CONFIG_MCASCADELAKE) += \ ++ $(call cc-option,-march=cascadelake,$(call cc-option,-mtune=cascadelake)) ++ cflags-$(CONFIG_MATOM) += $(call cc-option,-march=bonnell) \ ++ $(call cc-option,-mtune=bonnell,$(call cc-option,-mtune=generic)) + cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic) + KBUILD_CFLAGS += $(cflags-y) + +diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu +index cd3056759880..2c81838df533 100644 +--- a/arch/x86/Makefile_32.cpu ++++ b/arch/x86/Makefile_32.cpu +@@ -24,7 +24,19 @@ cflags-$(CONFIG_MK6) += -march=k6 + # Please note, that patches that add -march=athlon-xp and friends are pointless. + # They make zero difference whatsosever to performance at this time. + cflags-$(CONFIG_MK7) += -march=athlon ++cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native) + cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,-march=athlon) ++cflags-$(CONFIG_MK8SSE3) += $(call cc-option,-march=k8-sse3,-march=athlon) ++cflags-$(CONFIG_MK10) += $(call cc-option,-march=amdfam10,-march=athlon) ++cflags-$(CONFIG_MBARCELONA) += $(call cc-option,-march=barcelona,-march=athlon) ++cflags-$(CONFIG_MBOBCAT) += $(call cc-option,-march=btver1,-march=athlon) ++cflags-$(CONFIG_MJAGUAR) += $(call cc-option,-march=btver2,-march=athlon) ++cflags-$(CONFIG_MBULLDOZER) += $(call cc-option,-march=bdver1,-march=athlon) ++cflags-$(CONFIG_MPILEDRIVER) += $(call cc-option,-march=bdver2,-march=athlon) ++cflags-$(CONFIG_MSTEAMROLLER) += $(call cc-option,-march=bdver3,-march=athlon) ++cflags-$(CONFIG_MEXCAVATOR) += $(call cc-option,-march=bdver4,-march=athlon) ++cflags-$(CONFIG_MZEN) += $(call cc-option,-march=znver1,-march=athlon) ++cflags-$(CONFIG_MZEN2) += $(call cc-option,-march=znver2,-march=athlon) + cflags-$(CONFIG_MCRUSOE) += -march=i686 -falign-functions=0 -falign-jumps=0 -falign-loops=0 + cflags-$(CONFIG_MEFFICEON) += -march=i686 $(call tune,pentium3) -falign-functions=0 -falign-jumps=0 -falign-loops=0 + cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586) +@@ -33,8 +45,22 @@ cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) -falign-fu + cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) + cflags-$(CONFIG_MVIAC7) += -march=i686 + cflags-$(CONFIG_MCORE2) += -march=i686 $(call tune,core2) +-cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom,$(call cc-option,-march=core2,-march=i686)) \ +- $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic)) ++cflags-$(CONFIG_MNEHALEM) += -march=i686 $(call tune,nehalem) ++cflags-$(CONFIG_MWESTMERE) += -march=i686 $(call tune,westmere) ++cflags-$(CONFIG_MSILVERMONT) += -march=i686 $(call tune,silvermont) ++cflags-$(CONFIG_MGOLDMONT) += -march=i686 $(call tune,goldmont) ++cflags-$(CONFIG_MGOLDMONTPLUS) += -march=i686 $(call tune,goldmont-plus) ++cflags-$(CONFIG_MSANDYBRIDGE) += -march=i686 $(call tune,sandybridge) ++cflags-$(CONFIG_MIVYBRIDGE) += -march=i686 $(call tune,ivybridge) ++cflags-$(CONFIG_MHASWELL) += -march=i686 $(call tune,haswell) ++cflags-$(CONFIG_MBROADWELL) += -march=i686 $(call tune,broadwell) ++cflags-$(CONFIG_MSKYLAKE) += -march=i686 $(call tune,skylake) ++cflags-$(CONFIG_MSKYLAKEX) += -march=i686 $(call tune,skylake-avx512) ++cflags-$(CONFIG_MCANNONLAKE) += -march=i686 $(call tune,cannonlake) ++cflags-$(CONFIG_MICELAKE) += -march=i686 $(call tune,icelake-client) ++cflags-$(CONFIG_MCASCADELAKE) += -march=i686 $(call tune,cascadelake) ++cflags-$(CONFIG_MATOM) += $(call cc-option,-march=bonnell,$(call cc-option,-march=core2,-march=i686)) \ ++ $(call cc-option,-mtune=bonnell,$(call cc-option,-mtune=generic)) + + # AMD Elan support + cflags-$(CONFIG_MELAN) += -march=i486 +diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h +index c215d2762488..a4fddfe3d4fb 100644 +--- a/arch/x86/include/asm/module.h ++++ b/arch/x86/include/asm/module.h +@@ -27,6 +27,36 @@ struct mod_arch_specific { + #define MODULE_PROC_FAMILY "586MMX " + #elif defined CONFIG_MCORE2 + #define MODULE_PROC_FAMILY "CORE2 " ++#elif defined CONFIG_MNATIVE ++#define MODULE_PROC_FAMILY "NATIVE " ++#elif defined CONFIG_MNEHALEM ++#define MODULE_PROC_FAMILY "NEHALEM " ++#elif defined CONFIG_MWESTMERE ++#define MODULE_PROC_FAMILY "WESTMERE " ++#elif defined CONFIG_MSILVERMONT ++#define MODULE_PROC_FAMILY "SILVERMONT " ++#elif defined CONFIG_MGOLDMONT ++#define MODULE_PROC_FAMILY "GOLDMONT " ++#elif defined CONFIG_MGOLDMONTPLUS ++#define MODULE_PROC_FAMILY "GOLDMONTPLUS " ++#elif defined CONFIG_MSANDYBRIDGE ++#define MODULE_PROC_FAMILY "SANDYBRIDGE " ++#elif defined CONFIG_MIVYBRIDGE ++#define MODULE_PROC_FAMILY "IVYBRIDGE " ++#elif defined CONFIG_MHASWELL ++#define MODULE_PROC_FAMILY "HASWELL " ++#elif defined CONFIG_MBROADWELL ++#define MODULE_PROC_FAMILY "BROADWELL " ++#elif defined CONFIG_MSKYLAKE ++#define MODULE_PROC_FAMILY "SKYLAKE " ++#elif defined CONFIG_MSKYLAKEX ++#define MODULE_PROC_FAMILY "SKYLAKEX " ++#elif defined CONFIG_MCANNONLAKE ++#define MODULE_PROC_FAMILY "CANNONLAKE " ++#elif defined CONFIG_MICELAKE ++#define MODULE_PROC_FAMILY "ICELAKE " ++#elif defined CONFIG_MCASCADELAKE ++#define MODULE_PROC_FAMILY "CASCADELAKE " + #elif defined CONFIG_MATOM + #define MODULE_PROC_FAMILY "ATOM " + #elif defined CONFIG_M686 +@@ -45,6 +75,28 @@ struct mod_arch_specific { + #define MODULE_PROC_FAMILY "K7 " + #elif defined CONFIG_MK8 + #define MODULE_PROC_FAMILY "K8 " ++#elif defined CONFIG_MK8SSE3 ++#define MODULE_PROC_FAMILY "K8SSE3 " ++#elif defined CONFIG_MK10 ++#define MODULE_PROC_FAMILY "K10 " ++#elif defined CONFIG_MBARCELONA ++#define MODULE_PROC_FAMILY "BARCELONA " ++#elif defined CONFIG_MBOBCAT ++#define MODULE_PROC_FAMILY "BOBCAT " ++#elif defined CONFIG_MBULLDOZER ++#define MODULE_PROC_FAMILY "BULLDOZER " ++#elif defined CONFIG_MPILEDRIVER ++#define MODULE_PROC_FAMILY "PILEDRIVER " ++#elif defined CONFIG_MSTEAMROLLER ++#define MODULE_PROC_FAMILY "STEAMROLLER " ++#elif defined CONFIG_MJAGUAR ++#define MODULE_PROC_FAMILY "JAGUAR " ++#elif defined CONFIG_MEXCAVATOR ++#define MODULE_PROC_FAMILY "EXCAVATOR " ++#elif defined CONFIG_MZEN ++#define MODULE_PROC_FAMILY "ZEN " ++#elif defined CONFIG_MZEN2 ++#define MODULE_PROC_FAMILY "ZEN2 " + #elif defined CONFIG_MELAN + #define MODULE_PROC_FAMILY "ELAN " + #elif defined CONFIG_MCRUSOE +diff --git a/fs/dcache.c b/fs/dcache.c +index 2acfc69878f5..3f1131431e06 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -69,7 +69,7 @@ + * If no ancestor relationship: + * arbitrary, since it's serialized on rename_lock + */ +-int sysctl_vfs_cache_pressure __read_mostly = 100; ++int sysctl_vfs_cache_pressure __read_mostly = 50; + EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); + + __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index 211890edf37e..37121563407d 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -41,7 +41,7 @@ const_debug unsigned int sysctl_sched_features = + * Number of tasks to iterate in a single balance run. + * Limited because this is done with IRQs disabled. + */ +-const_debug unsigned int sysctl_sched_nr_migrate = 32; ++const_debug unsigned int sysctl_sched_nr_migrate = 128; + + /* + * period over which we average the RT time consumption, measured +@@ -61,9 +61,9 @@ __read_mostly int scheduler_running; + + /* + * part of the period that we allow rt tasks to run in us. +- * default: 0.95s ++ * XanMod default: 0.98s + */ +-int sysctl_sched_rt_runtime = 950000; ++int sysctl_sched_rt_runtime = 980000; + + /* + * __task_rq_lock - lock the rq @p resides on. +diff --git a/scripts/setlocalversion b/scripts/setlocalversion +index 71f39410691b..288f9679e883 100755 +--- a/scripts/setlocalversion ++++ b/scripts/setlocalversion +@@ -54,7 +54,7 @@ scm_version() + # If only the short version is requested, don't bother + # running further git commands + if $short; then +- echo "+" ++ # echo "+" + return + fi + # If we are past a tagged commit (like + +From f85ed068b4d0e6c31edce8574a95757a60e58b87 Mon Sep 17 00:00:00 2001 +From: Etienne Juvigny +Date: Mon, 3 Sep 2018 17:36:25 +0200 +Subject: Zenify & stuff + + +diff --git a/Documentation/tp_smapi.txt b/Documentation/tp_smapi.txt +new file mode 100644 +index 000000000000..a249678a8866 +--- /dev/null ++++ b/Documentation/tp_smapi.txt +@@ -0,0 +1,275 @@ ++tp_smapi version 0.42 ++IBM ThinkPad hardware functions driver ++ ++Author: Shem Multinymous ++Project: http://sourceforge.net/projects/tpctl ++Wiki: http://thinkwiki.org/wiki/tp_smapi ++List: linux-thinkpad@linux-thinkpad.org ++ (http://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad) ++ ++Description ++----------- ++ ++ThinkPad laptops include a proprietary interface called SMAPI BIOS ++(System Management Application Program Interface) which provides some ++hardware control functionality that is not accessible by other means. ++ ++This driver exposes some features of the SMAPI BIOS through a sysfs ++interface. It is suitable for newer models, on which SMAPI is invoked ++through IO port writes. Older models use a different SMAPI interface; ++for those, try the "thinkpad" module from the "tpctl" package. ++ ++WARNING: ++This driver uses undocumented features and direct hardware access. ++It thus cannot be guaranteed to work, and may cause arbitrary damage ++(especially on models it wasn't tested on). ++ ++ ++Module parameters ++----------------- ++ ++thinkpad_ec module: ++ force_io=1 lets thinkpad_ec load on some recent ThinkPad models ++ (e.g., T400 and T500) whose BIOS's ACPI DSDT reserves the ports we need. ++tp_smapi module: ++ debug=1 enables verbose dmesg output. ++ ++ ++Usage ++----- ++ ++Control of battery charging thresholds (in percents of current full charge ++capacity): ++ ++# echo 40 > /sys/devices/platform/smapi/BAT0/start_charge_thresh ++# echo 70 > /sys/devices/platform/smapi/BAT0/stop_charge_thresh ++# cat /sys/devices/platform/smapi/BAT0/*_charge_thresh ++ ++ (This is useful since Li-Ion batteries wear out much faster at very ++ high or low charge levels. The driver will also keeps the thresholds ++ across suspend-to-disk with AC disconnected; this isn't done ++ automatically by the hardware.) ++ ++Inhibiting battery charging for 17 minutes (overrides thresholds): ++ ++# echo 17 > /sys/devices/platform/smapi/BAT0/inhibit_charge_minutes ++# echo 0 > /sys/devices/platform/smapi/BAT0/inhibit_charge_minutes # stop ++# cat /sys/devices/platform/smapi/BAT0/inhibit_charge_minutes ++ ++ (This can be used to control which battery is charged when using an ++ Ultrabay battery.) ++ ++Forcing battery discharging even if AC power available: ++ ++# echo 1 > /sys/devices/platform/smapi/BAT0/force_discharge # start discharge ++# echo 0 > /sys/devices/platform/smapi/BAT0/force_discharge # stop discharge ++# cat /sys/devices/platform/smapi/BAT0/force_discharge ++ ++ (When AC is connected, forced discharging will automatically stop ++ when battery is fully depleted -- this is useful for calibration. ++ Also, this attribute can be used to control which battery is discharged ++ when both a system battery and an Ultrabay battery are connected.) ++ ++Misc read-only battery status attributes (see note about HDAPS below): ++ ++/sys/devices/platform/smapi/BAT0/installed # 0 or 1 ++/sys/devices/platform/smapi/BAT0/state # idle/charging/discharging ++/sys/devices/platform/smapi/BAT0/cycle_count # integer counter ++/sys/devices/platform/smapi/BAT0/current_now # instantaneous current ++/sys/devices/platform/smapi/BAT0/current_avg # last minute average ++/sys/devices/platform/smapi/BAT0/power_now # instantaneous power ++/sys/devices/platform/smapi/BAT0/power_avg # last minute average ++/sys/devices/platform/smapi/BAT0/last_full_capacity # in mWh ++/sys/devices/platform/smapi/BAT0/remaining_percent # remaining percent of energy (set by calibration) ++/sys/devices/platform/smapi/BAT0/remaining_percent_error # error range of remaing_percent (not reset by calibration) ++/sys/devices/platform/smapi/BAT0/remaining_running_time # in minutes, by last minute average power ++/sys/devices/platform/smapi/BAT0/remaining_running_time_now # in minutes, by instantenous power ++/sys/devices/platform/smapi/BAT0/remaining_charging_time # in minutes ++/sys/devices/platform/smapi/BAT0/remaining_capacity # in mWh ++/sys/devices/platform/smapi/BAT0/design_capacity # in mWh ++/sys/devices/platform/smapi/BAT0/voltage # in mV ++/sys/devices/platform/smapi/BAT0/design_voltage # in mV ++/sys/devices/platform/smapi/BAT0/charging_max_current # max charging current ++/sys/devices/platform/smapi/BAT0/charging_max_voltage # max charging voltage ++/sys/devices/platform/smapi/BAT0/group{0,1,2,3}_voltage # see below ++/sys/devices/platform/smapi/BAT0/manufacturer # string ++/sys/devices/platform/smapi/BAT0/model # string ++/sys/devices/platform/smapi/BAT0/barcoding # string ++/sys/devices/platform/smapi/BAT0/chemistry # string ++/sys/devices/platform/smapi/BAT0/serial # integer ++/sys/devices/platform/smapi/BAT0/manufacture_date # YYYY-MM-DD ++/sys/devices/platform/smapi/BAT0/first_use_date # YYYY-MM-DD ++/sys/devices/platform/smapi/BAT0/temperature # in milli-Celsius ++/sys/devices/platform/smapi/BAT0/dump # see below ++/sys/devices/platform/smapi/ac_connected # 0 or 1 ++ ++The BAT0/group{0,1,2,3}_voltage attribute refers to the separate cell groups ++in each battery. For example, on the ThinkPad 600, X3x, T4x and R5x models, ++the battery contains 3 cell groups in series, where each group consisting of 2 ++or 3 cells connected in parallel. The voltage of each group is given by these ++attributes, and their sum (roughly) equals the "voltage" attribute. ++(The effective performance of the battery is determined by the weakest group, ++i.e., the one those voltage changes most rapidly during dis/charging.) ++ ++The "BAT0/dump" attribute gives a a hex dump of the raw status data, which ++contains additional data now in the above (if you can figure it out). Some ++unused values are autodetected and replaced by "--": ++ ++In all of the above, replace BAT0 with BAT1 to address the 2nd battery (e.g. ++in the UltraBay). ++ ++ ++Raw SMAPI calls: ++ ++/sys/devices/platform/smapi/smapi_request ++This performs raw SMAPI calls. It uses a bad interface that cannot handle ++multiple simultaneous access. Don't touch it, it's for development only. ++If you did touch it, you would so something like ++# echo '211a 100 0 0' > /sys/devices/platform/smapi/smapi_request ++# cat /sys/devices/platform/smapi/smapi_request ++and notice that in the output "211a 34b b2 0 0 0 'OK'", the "4b" in the 2nd ++value, converted to decimal is 75: the current charge stop threshold. ++ ++ ++Model-specific status ++--------------------- ++ ++Works (at least partially) on the following ThinkPad model: ++* A30 ++* G41 ++* R40, R50p, R51, R52 ++* T23, T40, T40p, T41, T41p, T42, T42p, T43, T43p, T60, T61, T400, T410, T420 (partially) ++* X24, X31, X32, X40, X41, X60, X61, X200, X201, X220 (partially) ++* Z60t, Z61m ++ ++Does not work on: ++* X230 and newer ++* T430 and newer ++* Any ThinkPad Edge ++* Any ThinkPad Yoga ++* Any ThinkPad L series ++* Any ThinkPad P series ++ ++Not all functions are available on all models; for detailed status, see: ++ http://thinkwiki.org/wiki/tp_smapi ++ ++Please report success/failure by e-mail or on the Wiki. ++If you get a "not implemented" or "not supported" message, your laptop ++probably just can't do that (at least not via the SMAPI BIOS). ++For negative reports, follow the bug reporting guidelines below. ++If you send me the necessary technical data (i.e., SMAPI function ++interfaces), I will support additional models. ++ ++ ++Additional HDAPS features ++------------------------- ++ ++The modified hdaps driver has several improvements on the one in mainline ++(beyond resolving the conflict with thinkpad_ec and tp_smapi): ++ ++- Fixes reliability and improves support for recent ThinkPad models ++ (especially *60 and newer). Unlike the mainline driver, the modified hdaps ++ correctly follows the Embedded Controller communication protocol. ++ ++- Extends the "invert" parameter to cover all possible axis orientations. ++ The possible values are as follows. ++ Let X,Y denote the hardware readouts. ++ Let R denote the laptop's roll (tilt left/right). ++ Let P denote the laptop's pitch (tilt forward/backward). ++ invert=0: R= X P= Y (same as mainline) ++ invert=1: R=-X P=-Y (same as mainline) ++ invert=2: R=-X P= Y (new) ++ invert=3: R= X P=-Y (new) ++ invert=4: R= Y P= X (new) ++ invert=5: R=-Y P=-X (new) ++ invert=6: R=-Y P= X (new) ++ invert=7: R= Y P=-X (new) ++ It's probably easiest to just try all 8 possibilities and see which yields ++ correct results (e.g., in the hdaps-gl visualisation). ++ ++- Adds a whitelist which automatically sets the correct axis orientation for ++ some models. If the value for your model is wrong or missing, you can override ++ it using the "invert" parameter. Please also update the tables at ++ http://www.thinkwiki.org/wiki/tp_smapi and ++ http://www.thinkwiki.org/wiki/List_of_DMI_IDs ++ and submit a patch for the whitelist in hdaps.c. ++ ++- Provides new attributes: ++ /sys/devices/platform/hdaps/sampling_rate: ++ This determines the frequency at which the host queries the embedded ++ controller for accelerometer data (and informs the hdaps input devices). ++ Default=50. ++ /sys/devices/platform/hdaps/oversampling_ratio: ++ When set to X, the embedded controller is told to do physical accelerometer ++ measurements at a rate that is X times higher than the rate at which ++ the driver reads those measurements (i.e., X*sampling_rate). This ++ makes the readouts from the embedded controller more fresh, and is also ++ useful for the running average filter (see next). Default=5 ++ /sys/devices/platform/hdaps/running_avg_filter_order: ++ When set to X, reported readouts will be the average of the last X physical ++ accelerometer measurements. Current firmware allows 1<=X<=8. Setting to a ++ high value decreases readout fluctuations. The averaging is handled by the ++ embedded controller, so no CPU resources are used. Higher values make the ++ readouts smoother, since it averages out both sensor noise (good) and abrupt ++ changes (bad). Default=2. ++ ++- Provides a second input device, which publishes the raw accelerometer ++ measurements (without the fuzzing needed for joystick emulation). This input ++ device can be matched by a udev rule such as the following (all on one line): ++ KERNEL=="event[0-9]*", ATTRS{phys}=="hdaps/input1", ++ ATTRS{modalias}=="input:b0019v1014p5054e4801-*", ++ SYMLINK+="input/hdaps/accelerometer-event ++ ++A new version of the hdapsd userspace daemon, which uses the input device ++interface instead of polling sysfs, is available seprately. Using this reduces ++the total interrupts per second generated by hdaps+hdapsd (on tickless kernels) ++to 50, down from a value that fluctuates between 50 and 100. Set the ++sampling_rate sysfs attribute to a lower value to further reduce interrupts, ++at the expense of response latency. ++ ++Licensing note: all my changes to the HDAPS driver are licensed under the ++GPL version 2 or, at your option and to the extent allowed by derivation from ++prior works, any later version. My version of hdaps is derived work from the ++mainline version, which at the time of writing is available only under ++GPL version 2. ++ ++Bug reporting ++------------- ++ ++Mail . Please include: ++* Details about your model, ++* Relevant "dmesg" output. Make sure thinkpad_ec and tp_smapi are loaded with ++ the "debug=1" parameter (e.g., use "make load HDAPS=1 DEBUG=1"). ++* Output of "dmidecode | grep -C5 Product" ++* Does the failed functionality works under Windows? ++ ++ ++More about SMAPI ++---------------- ++ ++For hints about what may be possible via the SMAPI BIOS and how, see: ++ ++* IBM Technical Reference Manual for the ThinkPad 770 ++ (http://www-307.ibm.com/pc/support/site.wss/document.do?lndocid=PFAN-3TUQQD) ++* Exported symbols in PWRMGRIF.DLL or TPPWRW32.DLL (e.g., use "objdump -x"). ++* drivers/char/mwave/smapi.c in the Linux kernel tree.* ++* The "thinkpad" SMAPI module (http://tpctl.sourceforge.net). ++* The SMAPI_* constants in tp_smapi.c. ++ ++Note that in the above Technical Reference and in the "thinkpad" module, ++SMAPI is invoked through a function call to some physical address. However, ++the interface used by tp_smapi and the above mwave drive, and apparently ++required by newer ThinkPad, is different: you set the parameters up in the ++CPU's registers and write to ports 0xB2 (the APM control port) and 0x4F; this ++triggers an SMI (System Management Interrupt), causing the CPU to enter ++SMM (System Management Mode) and run the BIOS firmware; the results are ++returned in the CPU's registers. It is not clear what is the relation between ++the two variants of SMAPI, though the assignment of error codes seems to be ++similar. ++ ++In addition, the embedded controller on ThinkPad laptops has a non-standard ++interface at IO ports 0x1600-0x161F (mapped to LCP channel 3 of the H8S chip). ++The interface provides various system management services (currently known: ++battery information and accelerometer readouts). For more information see the ++thinkpad_ec module and the H8S hardware documentation: ++http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf +diff --git a/init/Kconfig b/init/Kconfig +index b4daad2bac23..c1e59dc04209 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1244,7 +1244,6 @@ config CC_OPTIMIZE_FOR_PERFORMANCE + + config CC_OPTIMIZE_FOR_PERFORMANCE_O3 + bool "Optimize more for performance (-O3)" +- depends on ARC + imply CC_DISABLE_WARN_MAYBE_UNINITIALIZED # avoid false positives + help + Choosing this option will pass "-O3" to your compiler to optimize +diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c +index 4f32c4062fb6..c0bf039e1b40 100644 +--- a/drivers/infiniband/core/addr.c ++++ b/drivers/infiniband/core/addr.c +@@ -721,6 +721,7 @@ int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, + struct sockaddr _sockaddr; + struct sockaddr_in _sockaddr_in; + struct sockaddr_in6 _sockaddr_in6; ++ struct sockaddr_ib _sockaddr_ib; + } sgid_addr, dgid_addr; + int ret; + +diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig +index 0840d27381ea..73aba9a31064 100644 +--- a/drivers/tty/Kconfig ++++ b/drivers/tty/Kconfig +@@ -75,6 +75,19 @@ config VT_CONSOLE_SLEEP + def_bool y + depends on VT_CONSOLE && PM_SLEEP + ++config NR_TTY_DEVICES ++ int "Maximum tty device number" ++ depends on VT ++ range 12 63 ++ default 63 ++ ---help--- ++ This option is used to change the number of tty devices in /dev. ++ The default value is 63. The lowest number you can set is 12, ++ 63 is also the upper limit so we don't overrun the serial ++ consoles. ++ ++ If unsure, say 63. ++ + config HW_CONSOLE + bool + depends on VT && !UML +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 79226ca8f80f..2a30060e7e1d 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -47,7 +47,11 @@ struct blk_queue_stats; + struct blk_stat_callback; + + #define BLKDEV_MIN_RQ 4 ++#ifdef CONFIG_ZENIFY ++#define BLKDEV_MAX_RQ 512 ++#else + #define BLKDEV_MAX_RQ 128 /* Default maximum */ ++#endif + + /* Must be consistent with blk_mq_poll_stats_bkt() */ + #define BLK_MQ_POLL_STATS_BKTS 16 +diff --git a/include/uapi/linux/vt.h b/include/uapi/linux/vt.h +index e9d39c48520a..3bceead8da40 100644 +--- a/include/uapi/linux/vt.h ++++ b/include/uapi/linux/vt.h +@@ -3,12 +3,25 @@ + #define _UAPI_LINUX_VT_H + + ++/* ++ * We will make this definition solely for the purpose of making packages ++ * such as splashutils build, because they can not understand that ++ * NR_TTY_DEVICES is defined in the kernel configuration. ++ */ ++#ifndef CONFIG_NR_TTY_DEVICES ++#define CONFIG_NR_TTY_DEVICES 63 ++#endif ++ + /* + * These constants are also useful for user-level apps (e.g., VC + * resizing). + */ + #define MIN_NR_CONSOLES 1 /* must be at least 1 */ +-#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */ ++/* ++ * NR_TTY_DEVICES: ++ * Value MUST be at least 12 and must never be higher then 63 ++ */ ++#define MAX_NR_CONSOLES CONFIG_NR_TTY_DEVICES /* serial lines start above this */ + /* Note: the ioctl VT_GETSTATE does not work for + consoles 16 and higher (since it returns a short) */ + +diff --git a/init/Kconfig b/init/Kconfig +index 041f3a022122..5ed70eb1ad3a 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -45,6 +45,38 @@ config THREAD_INFO_IN_TASK + + menu "General setup" + ++config ZENIFY ++ bool "A selection of patches from Zen/Liquorix kernel and additional tweaks for a better gaming experience" ++ default y ++ help ++ Tunes the kernel for responsiveness at the cost of throughput and power usage. ++ ++ --- Virtual Memory Subsystem --------------------------- ++ ++ Mem dirty before bg writeback..: 10 % -> 20 % ++ Mem dirty before sync writeback: 20 % -> 50 % ++ ++ --- Block Layer ---------------------------------------- ++ ++ Queue depth...............: 128 -> 512 ++ Default MQ scheduler......: mq-deadline -> bfq ++ ++ --- CFS CPU Scheduler ---------------------------------- ++ ++ Scheduling latency.............: 6 -> 3 ms ++ Minimal granularity............: 0.75 -> 0.3 ms ++ Wakeup granularity.............: 1 -> 0.5 ms ++ CPU migration cost.............: 0.5 -> 0.25 ms ++ Bandwidth slice size...........: 5 -> 3 ms ++ Ondemand fine upscaling limit..: 95 % -> 85 % ++ ++ --- MuQSS CPU Scheduler -------------------------------- ++ ++ Scheduling interval............: 6 -> 3 ms ++ ISO task max realtime use......: 70 % -> 25 % ++ Ondemand coarse upscaling limit: 80 % -> 45 % ++ Ondemand fine upscaling limit..: 95 % -> 45 % ++ + config BROKEN + bool + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 2f0a0be4d344..bada807c7e59 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -37,8 +37,13 @@ + * + * (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds) + */ ++#ifdef CONFIG_ZENIFY ++unsigned int sysctl_sched_latency = 3000000ULL; ++static unsigned int normalized_sysctl_sched_latency = 3000000ULL; ++#else + unsigned int sysctl_sched_latency = 6000000ULL; + static unsigned int normalized_sysctl_sched_latency = 6000000ULL; ++#endif + + /* + * The initial- and re-scaling of tunables is configurable +@@ -58,13 +63,22 @@ enum sched_tunable_scaling sysctl_sched_tunable_scaling = SCHED_TUNABLESCALING_L + * + * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds) + */ ++#ifdef CONFIG_ZENIFY ++unsigned int sysctl_sched_min_granularity = 300000ULL; ++static unsigned int normalized_sysctl_sched_min_granularity = 300000ULL; ++#else + unsigned int sysctl_sched_min_granularity = 750000ULL; + static unsigned int normalized_sysctl_sched_min_granularity = 750000ULL; ++#endif + + /* + * This value is kept at sysctl_sched_latency/sysctl_sched_min_granularity + */ ++#ifdef CONFIG_ZENIFY ++static unsigned int sched_nr_latency = 10; ++#else + static unsigned int sched_nr_latency = 8; ++#endif + + /* + * After fork, child runs first. If set to 0 (default) then +@@ -81,10 +95,17 @@ unsigned int sysctl_sched_child_runs_first __read_mostly; + * + * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds) + */ ++#ifdef CONFIG_ZENIFY ++unsigned int sysctl_sched_wakeup_granularity = 500000UL; ++static unsigned int normalized_sysctl_sched_wakeup_granularity = 500000UL; ++ ++const_debug unsigned int sysctl_sched_migration_cost = 50000UL; ++#else + unsigned int sysctl_sched_wakeup_granularity = 1000000UL; + static unsigned int normalized_sysctl_sched_wakeup_granularity = 1000000UL; + + const_debug unsigned int sysctl_sched_migration_cost = 500000UL; ++#endif + + #ifdef CONFIG_SMP + /* +@@ -107,8 +128,12 @@ int __weak arch_asym_cpu_priority(int cpu) + * + * (default: 5 msec, units: microseconds) + */ ++#ifdef CONFIG_ZENIFY ++unsigned int sysctl_sched_cfs_bandwidth_slice = 3000UL; ++#else + unsigned int sysctl_sched_cfs_bandwidth_slice = 5000UL; + #endif ++#endif + + /* + * The margin used when comparing utilization with CPU capacity: +diff --git a/mm/page-writeback.c b/mm/page-writeback.c +index 337c6afb3345..9315e358f292 100644 +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -71,7 +71,11 @@ static long ratelimit_pages = 32; + /* + * Start background writeback (via writeback threads) at this percentage + */ ++#ifdef CONFIG_ZENIFY ++int dirty_background_ratio = 20; ++#else + int dirty_background_ratio = 10; ++#endif + + /* + * dirty_background_bytes starts at 0 (disabled) so that it is a function of +@@ -88,7 +92,11 @@ int vm_highmem_is_dirtyable; + /* + * The generator of dirty data starts writeback at this percentage + */ ++#ifdef CONFIG_ZENIFY ++int vm_dirty_ratio = 50; ++#else + int vm_dirty_ratio = 20; ++#endif + + /* + * vm_dirty_bytes starts at 0 (disabled) so that it is a function of +diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig +index 80dad301361d..42b7fa7d01f8 100644 +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -702,6 +702,9 @@ choice + config DEFAULT_VEGAS + bool "Vegas" if TCP_CONG_VEGAS=y + ++ config DEFAULT_YEAH ++ bool "YeAH" if TCP_CONG_YEAH=y ++ + config DEFAULT_VENO + bool "Veno" if TCP_CONG_VENO=y + +@@ -735,6 +738,7 @@ config DEFAULT_TCP_CONG + default "htcp" if DEFAULT_HTCP + default "hybla" if DEFAULT_HYBLA + default "vegas" if DEFAULT_VEGAS ++ default "yeah" if DEFAULT_YEAH + default "westwood" if DEFAULT_WESTWOOD + default "veno" if DEFAULT_VENO + default "reno" if DEFAULT_RENO + +From: Nick Desaulniers +Date: Mon, 24 Dec 2018 13:37:41 +0200 +Subject: include/linux/compiler*.h: define asm_volatile_goto + +asm_volatile_goto should also be defined for other compilers that +support asm goto. + +Fixes commit 815f0dd ("include/linux/compiler*.h: make compiler-*.h +mutually exclusive"). + +Signed-off-by: Nick Desaulniers +Signed-off-by: Miguel Ojeda + +diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h +index ba814f1..e77eeb0 100644 +--- a/include/linux/compiler_types.h ++++ b/include/linux/compiler_types.h +@@ -188,6 +188,10 @@ struct ftrace_likely_data { + #define asm_volatile_goto(x...) asm goto(x) + #endif + ++#ifndef asm_volatile_goto ++#define asm_volatile_goto(x...) asm goto(x) ++#endif ++ + /* Are two types/vars the same type (ignoring qualifiers)? */ + #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) + +From: Andy Lavr +Date: Mon, 24 Dec 2018 14:57:47 +0200 +Subject: avl: Use [defer+madvise] as default khugepaged defrag strategy + +For some reason, the default strategy to respond to THP fault fallbacks +is still just madvise, meaning stall if the program wants transparent +hugepages, but don't trigger a background reclaim / compaction if THP +begins to fail allocations. This creates a snowball affect where we +still use the THP code paths, but we almost always fail once a system +has been active and busy for a while. + +The option "defer" was created for interactive systems where THP can +still improve performance. If we have to fallback to a regular page due +to an allocation failure or anything else, we will trigger a background +reclaim and compaction so future THP attempts succeed and previous +attempts eventually have their smaller pages combined without stalling +running applications. + +We still want madvise to stall applications that explicitely want THP, +so defer+madvise _does_ make a ton of sense. Make it the default for +interactive systems, especially if the kernel maintainer left +transparent hugepages on "always". + +Reasoning and details in the original patch: +https://lwn.net/Articles/711248/ + +Signed-off-by: Andy Lavr + +diff --git a/mm/huge_memory.c b/mm/huge_memory.c +index e84a10b..21d62b7 100644 +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -53,7 +53,11 @@ unsigned long transparent_hugepage_flags __read_mostly = + #ifdef CONFIG_TRANSPARENT_HUGEPAGE_MADVISE + (1< +Date: Mon, 25 Nov 2019 15:13:06 -0300 +Subject: [PATCH] elevator: set default scheduler to bfq for blk-mq + +Signed-off-by: Alexandre Frade +--- + block/elevator.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/block/elevator.c b/block/elevator.c +index 076ba7308e65..81f89095aa77 100644 +--- a/block/elevator.c ++++ b/block/elevator.c +@@ -623,15 +623,15 @@ static inline bool elv_support_iosched(struct request_queue *q) + } + + /* +- * For single queue devices, default to using mq-deadline. If we have multiple +- * queues or mq-deadline is not available, default to "none". ++ * For single queue devices, default to using bfq. If we have multiple ++ * queues or bfq is not available, default to "none". + */ + static struct elevator_type *elevator_get_default(struct request_queue *q) + { + if (q->nr_hw_queues != 1) + return NULL; + +- return elevator_get(q, "mq-deadline", false); ++ return elevator_get(q, "bfq", false); + } + + /* +From c3ec05777c46e19a8a26d0fc4ca0c0db8a19de97 Mon Sep 17 00:00:00 2001 +From: Alexandre Frade +Date: Fri, 10 May 2019 16:45:59 -0300 +Subject: [PATCH] block: set rq_affinity = 2 for full multithreading I/O + requests + +Signed-off-by: Alexandre Frade +--- + include/linux/blkdev.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index f3ea78b0c91c..4dbacc6b073b 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -621,7 +621,8 @@ struct request_queue { + #define QUEUE_FLAG_RQ_ALLOC_TIME 27 /* record rq->alloc_time_ns */ + + #define QUEUE_FLAG_MQ_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ +- (1 << QUEUE_FLAG_SAME_COMP)) ++ (1 << QUEUE_FLAG_SAME_COMP) | \ ++ (1 << QUEUE_FLAG_SAME_FORCE)) + + void blk_queue_flag_set(unsigned int flag, struct request_queue *q); + void blk_queue_flag_clear(unsigned int flag, struct request_queue *q); +From 8171d33d0b84a953649863538fdbe4c26c035e4f Mon Sep 17 00:00:00 2001 +From: Alexandre Frade +Date: Fri, 10 May 2019 14:32:50 -0300 +Subject: [PATCH] mm: set 2 megabytes for address_space-level file read-ahead + pages size + +Signed-off-by: Alexandre Frade +--- + include/linux/mm.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/linux/mm.h b/include/linux/mm.h +index a2adf95b3f9c..e804d9f7583a 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -2416,7 +2416,7 @@ int __must_check write_one_page(struct page *page); + void task_dirty_inc(struct task_struct *tsk); + + /* readahead.c */ +-#define VM_READAHEAD_PAGES (SZ_128K / PAGE_SIZE) ++#define VM_READAHEAD_PAGES (SZ_2M / PAGE_SIZE) + + int force_page_cache_readahead(struct address_space *mapping, struct file *filp, + pgoff_t offset, unsigned long nr_to_read); +From de7119e3db9fdb4c704355854a02a7e9fad931d4 Mon Sep 17 00:00:00 2001 +From: Steven Barrett +Date: Wed, 15 Jan 2020 20:43:56 -0600 +Subject: [PATCH] ZEN: intel-pstate: Implement "enable" parameter + +If intel-pstate is compiled into the kernel, it will preempt the loading +of acpi-cpufreq so you can take advantage of hardware p-states without +any friction. + +However, intel-pstate is not completely superior to cpufreq's ondemand +for one reason. There's no concept of an up_threshold property. + +In ondemand, up_threshold essentially reduces the maximum utilization to +compare against, allowing you to hit max frequencies and turbo boost +from a much lower core utilization. + +With intel-pstate, you have the concept of minimum and maximum +performance, but no tunable that lets you define, maximum frequency +means 50% core utilization. For just this oversight, there's reasons +you may want ondemand. + +Lets support setting "enable" in kernel boot parameters. This lets +kernel maintainers include "intel_pstate=disable" statically in the +static boot parameters, but let users of the kernel override this +selection. +--- + Documentation/admin-guide/kernel-parameters.txt | 3 +++ + drivers/cpufreq/intel_pstate.c | 2 ++ + 2 files changed, 5 insertions(+) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index ade4e6ec23e03..0b613370d28d8 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -1765,6 +1765,9 @@ + disable + Do not enable intel_pstate as the default + scaling driver for the supported processors ++ enable ++ Enable intel_pstate in-case "disable" was passed ++ previously in the kernel boot parameters + passive + Use intel_pstate as a scaling driver, but configure it + to work with generic cpufreq governors (instead of +diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c +index d2fa3e9ccd97c..bd10cb02fc0ff 100644 +--- a/drivers/cpufreq/intel_pstate.c ++++ b/drivers/cpufreq/intel_pstate.c +@@ -2826,6 +2826,8 @@ static int __init intel_pstate_setup(char *str) + pr_info("HWP disabled\n"); + no_hwp = 1; + } ++ if (!strcmp(str, "enable")) ++ no_load = 0; + if (!strcmp(str, "force")) + force_load = 1; + if (!strcmp(str, "hwp_only")) + diff --git a/linux57-rc-tkg/linux57-tkg-patches/0003-glitched-cfs.patch b/linux57-rc-tkg/linux57-tkg-patches/0003-glitched-cfs.patch new file mode 100644 index 0000000..06b7f02 --- /dev/null +++ b/linux57-rc-tkg/linux57-tkg-patches/0003-glitched-cfs.patch @@ -0,0 +1,72 @@ +diff --git a/kernel/Kconfig.hz b/kernel/Kconfig.hz +index 2a202a846757..1d9c7ed79b11 100644 +--- a/kernel/Kconfig.hz ++++ b/kernel/Kconfig.hz +@@ -4,7 +4,7 @@ + + choice + prompt "Timer frequency" +- default HZ_250 ++ default HZ_500 + help + Allows the configuration of the timer frequency. It is customary + to have the timer interrupt run at 1000 Hz but 100 Hz may be more +@@ -39,6 +39,13 @@ choice + on SMP and NUMA systems and exactly dividing by both PAL and + NTSC frame rates for video and multimedia work. + ++ config HZ_500 ++ bool "500 HZ" ++ help ++ 500 Hz is a balanced timer frequency. Provides fast interactivity ++ on desktops with great smoothness without increasing CPU power ++ consumption and sacrificing the battery life on laptops. ++ + config HZ_1000 + bool "1000 HZ" + help +@@ -52,6 +59,7 @@ config HZ + default 100 if HZ_100 + default 250 if HZ_250 + default 300 if HZ_300 ++ default 500 if HZ_500 + default 1000 if HZ_1000 + + config SCHED_HRTICK + +diff --git a/kernel/Kconfig.hz b/kernel/Kconfig.hz +index 2a202a846757..1d9c7ed79b11 100644 +--- a/kernel/Kconfig.hz ++++ b/kernel/Kconfig.hz +@@ -4,7 +4,7 @@ + + choice + prompt "Timer frequency" +- default HZ_500 ++ default HZ_750 + help + Allows the configuration of the timer frequency. It is customary + to have the timer interrupt run at 1000 Hz but 100 Hz may be more +@@ -46,6 +46,13 @@ choice + on desktops with great smoothness without increasing CPU power + consumption and sacrificing the battery life on laptops. + ++ config HZ_750 ++ bool "750 HZ" ++ help ++ 750 Hz is a good timer frequency for desktops. Provides fast ++ interactivity with great smoothness without sacrificing too ++ much throughput. ++ + config HZ_1000 + bool "1000 HZ" + help +@@ -60,6 +67,7 @@ config HZ + default 250 if HZ_250 + default 300 if HZ_300 + default 500 if HZ_500 ++ default 750 if HZ_750 + default 1000 if HZ_1000 + + config SCHED_HRTICK + diff --git a/linux57-rc-tkg/linux57-tkg-patches/0006-add-acs-overrides_iommu.patch b/linux57-rc-tkg/linux57-tkg-patches/0006-add-acs-overrides_iommu.patch new file mode 100644 index 0000000..d1303a5 --- /dev/null +++ b/linux57-rc-tkg/linux57-tkg-patches/0006-add-acs-overrides_iommu.patch @@ -0,0 +1,193 @@ +From cdeab384f48dd9c88e2dff2e9ad8d57dca1a1b1c Mon Sep 17 00:00:00 2001 +From: Mark Weiman +Date: Sun, 12 Aug 2018 11:36:21 -0400 +Subject: [PATCH] pci: Enable overrides for missing ACS capabilities + +This an updated version of Alex Williamson's patch from: +https://lkml.org/lkml/2013/5/30/513 + +Original commit message follows: + +PCIe ACS (Access Control Services) is the PCIe 2.0+ feature that +allows us to control whether transactions are allowed to be redirected +in various subnodes of a PCIe topology. For instance, if two +endpoints are below a root port or downsteam switch port, the +downstream port may optionally redirect transactions between the +devices, bypassing upstream devices. The same can happen internally +on multifunction devices. The transaction may never be visible to the +upstream devices. + +One upstream device that we particularly care about is the IOMMU. If +a redirection occurs in the topology below the IOMMU, then the IOMMU +cannot provide isolation between devices. This is why the PCIe spec +encourages topologies to include ACS support. Without it, we have to +assume peer-to-peer DMA within a hierarchy can bypass IOMMU isolation. + +Unfortunately, far too many topologies do not support ACS to make this +a steadfast requirement. Even the latest chipsets from Intel are only +sporadically supporting ACS. We have trouble getting interconnect +vendors to include the PCIe spec required PCIe capability, let alone +suggested features. + +Therefore, we need to add some flexibility. The pcie_acs_override= +boot option lets users opt-in specific devices or sets of devices to +assume ACS support. The "downstream" option assumes full ACS support +on root ports and downstream switch ports. The "multifunction" +option assumes the subset of ACS features available on multifunction +endpoints and upstream switch ports are supported. The "id:nnnn:nnnn" +option enables ACS support on devices matching the provided vendor +and device IDs, allowing more strategic ACS overrides. These options +may be combined in any order. A maximum of 16 id specific overrides +are available. It's suggested to use the most limited set of options +necessary to avoid completely disabling ACS across the topology. +Note to hardware vendors, we have facilities to permanently quirk +specific devices which enforce isolation but not provide an ACS +capability. Please contact me to have your devices added and save +your customers the hassle of this boot option. + +Signed-off-by: Mark Weiman +--- + .../admin-guide/kernel-parameters.txt | 9 ++ + drivers/pci/quirks.c | 101 ++++++++++++++++++ + 2 files changed, 110 insertions(+) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index aefd358a5ca3..173b3596fd9e 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -3190,6 +3190,15 @@ + nomsi [MSI] If the PCI_MSI kernel config parameter is + enabled, this kernel boot option can be used to + disable the use of MSI interrupts system-wide. ++ pcie_acs_override = ++ [PCIE] Override missing PCIe ACS support for: ++ downstream ++ All downstream ports - full ACS capabilities ++ multifunction ++ All multifunction devices - multifunction ACS subset ++ id:nnnn:nnnn ++ Specific device - full ACS capabilities ++ Specified as vid:did (vendor/device ID) in hex + noioapicquirk [APIC] Disable all boot interrupt quirks. + Safety option to keep boot IRQs enabled. This + should never be necessary. +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index 4700d24e5d55..8f7a3d7fd9c1 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -3372,6 +3372,106 @@ static void quirk_no_bus_reset(struct pci_dev *dev) + dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET; + } + ++static bool acs_on_downstream; ++static bool acs_on_multifunction; ++ ++#define NUM_ACS_IDS 16 ++struct acs_on_id { ++ unsigned short vendor; ++ unsigned short device; ++}; ++static struct acs_on_id acs_on_ids[NUM_ACS_IDS]; ++static u8 max_acs_id; ++ ++static __init int pcie_acs_override_setup(char *p) ++{ ++ if (!p) ++ return -EINVAL; ++ ++ while (*p) { ++ if (!strncmp(p, "downstream", 10)) ++ acs_on_downstream = true; ++ if (!strncmp(p, "multifunction", 13)) ++ acs_on_multifunction = true; ++ if (!strncmp(p, "id:", 3)) { ++ char opt[5]; ++ int ret; ++ long val; ++ ++ if (max_acs_id >= NUM_ACS_IDS - 1) { ++ pr_warn("Out of PCIe ACS override slots (%d)\n", ++ NUM_ACS_IDS); ++ goto next; ++ } ++ ++ p += 3; ++ snprintf(opt, 5, "%s", p); ++ ret = kstrtol(opt, 16, &val); ++ if (ret) { ++ pr_warn("PCIe ACS ID parse error %d\n", ret); ++ goto next; ++ } ++ acs_on_ids[max_acs_id].vendor = val; ++ ++ p += strcspn(p, ":"); ++ if (*p != ':') { ++ pr_warn("PCIe ACS invalid ID\n"); ++ goto next; ++ } ++ ++ p++; ++ snprintf(opt, 5, "%s", p); ++ ret = kstrtol(opt, 16, &val); ++ if (ret) { ++ pr_warn("PCIe ACS ID parse error %d\n", ret); ++ goto next; ++ } ++ acs_on_ids[max_acs_id].device = val; ++ max_acs_id++; ++ } ++next: ++ p += strcspn(p, ","); ++ if (*p == ',') ++ p++; ++ } ++ ++ if (acs_on_downstream || acs_on_multifunction || max_acs_id) ++ pr_warn("Warning: PCIe ACS overrides enabled; This may allow non-IOMMU protected peer-to-peer DMA\n"); ++ ++ return 0; ++} ++early_param("pcie_acs_override", pcie_acs_override_setup); ++ ++static int pcie_acs_overrides(struct pci_dev *dev, u16 acs_flags) ++{ ++ int i; ++ ++ /* Never override ACS for legacy devices or devices with ACS caps */ ++ if (!pci_is_pcie(dev) || ++ pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS)) ++ return -ENOTTY; ++ ++ for (i = 0; i < max_acs_id; i++) ++ if (acs_on_ids[i].vendor == dev->vendor && ++ acs_on_ids[i].device == dev->device) ++ return 1; ++ ++ switch (pci_pcie_type(dev)) { ++ case PCI_EXP_TYPE_DOWNSTREAM: ++ case PCI_EXP_TYPE_ROOT_PORT: ++ if (acs_on_downstream) ++ return 1; ++ break; ++ case PCI_EXP_TYPE_ENDPOINT: ++ case PCI_EXP_TYPE_UPSTREAM: ++ case PCI_EXP_TYPE_LEG_END: ++ case PCI_EXP_TYPE_RC_END: ++ if (acs_on_multifunction && dev->multifunction) ++ return 1; ++ } ++ ++ return -ENOTTY; ++} + /* + * Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset. + * The device will throw a Link Down error on AER-capable systems and +@@ -4513,6 +4613,7 @@ static const struct pci_dev_acs_enabled { + { PCI_VENDOR_ID_ZHAOXIN, 0x9083, pci_quirk_mf_endpoint_acs }, + /* Zhaoxin Root/Downstream Ports */ + { PCI_VENDOR_ID_ZHAOXIN, PCI_ANY_ID, pci_quirk_zhaoxin_pcie_ports_acs }, ++ { PCI_ANY_ID, PCI_ANY_ID, pcie_acs_overrides }, + { 0 } + }; + + diff --git a/linux57-rc-tkg/linux57-tkg-patches/0007-v5.7-fsync.patch b/linux57-rc-tkg/linux57-tkg-patches/0007-v5.7-fsync.patch new file mode 100644 index 0000000..027116f --- /dev/null +++ b/linux57-rc-tkg/linux57-tkg-patches/0007-v5.7-fsync.patch @@ -0,0 +1,419 @@ +split the futex key setup from the queue locking and key reading. This +is useful to support the setup of multiple keys at the same time, like +what is done in futex_requeue() and what will be done for the +FUTEX_WAIT_MULTIPLE command. + +Signed-off-by: Gabriel Krisman Bertazi +--- + kernel/futex.c | 71 +++++++++++++++++++++++++++++--------------------- + 1 file changed, 42 insertions(+), 29 deletions(-) + +diff --git a/kernel/futex.c b/kernel/futex.c +index 6d50728ef2e7..91f3db335c57 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -2631,6 +2631,39 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q, + __set_current_state(TASK_RUNNING); + } + ++static int __futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, ++ struct futex_q *q, struct futex_hash_bucket **hb) ++{ ++ ++ u32 uval; ++ int ret; ++ ++retry_private: ++ *hb = queue_lock(q); ++ ++ ret = get_futex_value_locked(&uval, uaddr); ++ ++ if (ret) { ++ queue_unlock(*hb); ++ ++ ret = get_user(uval, uaddr); ++ if (ret) ++ return ret; ++ ++ if (!(flags & FLAGS_SHARED)) ++ goto retry_private; ++ ++ return 1; ++ } ++ ++ if (uval != val) { ++ queue_unlock(*hb); ++ ret = -EWOULDBLOCK; ++ } ++ ++ return ret; ++} ++ + /** + * futex_wait_setup() - Prepare to wait on a futex + * @uaddr: the futex userspace address +@@ -2651,7 +2684,6 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q, + static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, + struct futex_q *q, struct futex_hash_bucket **hb) + { +- u32 uval; + int ret; + + /* +@@ -2672,38 +2704,19 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, + * absorb a wakeup if *uaddr does not match the desired values + * while the syscall executes. + */ +-retry: +- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, FUTEX_READ); +- if (unlikely(ret != 0)) +- return ret; +- +-retry_private: +- *hb = queue_lock(q); ++ do { ++ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, ++ &q->key, FUTEX_READ); ++ if (unlikely(ret != 0)) ++ return ret; + +- ret = get_futex_value_locked(&uval, uaddr); ++ ret = __futex_wait_setup(uaddr, val, flags, q, hb); + +- if (ret) { +- queue_unlock(*hb); +- +- ret = get_user(uval, uaddr); ++ /* Drop key reference if retry or error. */ + if (ret) +- goto out; ++ put_futex_key(&q->key); ++ } while (ret > 0); + +- if (!(flags & FLAGS_SHARED)) +- goto retry_private; +- +- put_futex_key(&q->key); +- goto retry; +- } +- +- if (uval != val) { +- queue_unlock(*hb); +- ret = -EWOULDBLOCK; +- } +- +-out: +- if (ret) +- put_futex_key(&q->key); + return ret; + } + +-- +2.20.1 + +This is a new futex operation, called FUTEX_WAIT_MULTIPLE, which allows +a thread to wait on several futexes at the same time, and be awoken by +any of them. In a sense, it implements one of the features that was +supported by pooling on the old FUTEX_FD interface. + +My use case for this operation lies in Wine, where we want to implement +a similar interface available in Windows, used mainly for event +handling. The wine folks have an implementation that uses eventfd, but +it suffers from FD exhaustion (I was told they have application that go +to the order of multi-milion FDs), and higher CPU utilization. + +In time, we are also proposing modifications to glibc and libpthread to +make this feature available for Linux native multithreaded applications +using libpthread, which can benefit from the behavior of waiting on any +of a group of futexes. + +In particular, using futexes in our Wine use case reduced the CPU +utilization by 4% for the game Beat Saber and by 1.5% for the game +Shadow of Tomb Raider, both running over Proton (a wine based solution +for Windows emulation), when compared to the eventfd interface. This +implementation also doesn't rely of file descriptors, so it doesn't risk +overflowing the resource. + +Technically, the existing FUTEX_WAIT implementation can be easily +reworked by using do_futex_wait_multiple with a count of one, and I +have a patch showing how it works. I'm not proposing it, since +futex is such a tricky code, that I'd be more confortable to have +FUTEX_WAIT_MULTIPLE running upstream for a couple development cycles, +before considering modifying FUTEX_WAIT. + +From an implementation perspective, the futex list is passed as an array +of (pointer,value,bitset) to the kernel, which will enqueue all of them +and sleep if none was already triggered. It returns a hint of which +futex caused the wake up event to userspace, but the hint doesn't +guarantee that is the only futex triggered. Before calling the syscall +again, userspace should traverse the list, trying to re-acquire any of +the other futexes, to prevent an immediate -EWOULDBLOCK return code from +the kernel. + +This was tested using three mechanisms: + +1) By reimplementing FUTEX_WAIT in terms of FUTEX_WAIT_MULTIPLE and +running the unmodified tools/testing/selftests/futex and a full linux +distro on top of this kernel. + +2) By an example code that exercises the FUTEX_WAIT_MULTIPLE path on a +multi-threaded, event-handling setup. + +3) By running the Wine fsync implementation and executing multi-threaded +applications, in particular the modern games mentioned above, on top of +this implementation. + +Signed-off-by: Zebediah Figura +Signed-off-by: Steven Noonan +Signed-off-by: Pierre-Loup A. Griffais +Signed-off-by: Gabriel Krisman Bertazi +--- + include/uapi/linux/futex.h | 7 ++ + kernel/futex.c | 161 ++++++++++++++++++++++++++++++++++++- + 2 files changed, 164 insertions(+), 4 deletions(-) + +diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h +index a89eb0accd5e..2401c4cf5095 100644 +--- a/include/uapi/linux/futex.h ++++ b/include/uapi/linux/futex.h +@@ -21,6 +21,7 @@ + #define FUTEX_WAKE_BITSET 10 + #define FUTEX_WAIT_REQUEUE_PI 11 + #define FUTEX_CMP_REQUEUE_PI 12 ++#define FUTEX_WAIT_MULTIPLE 31 + + #define FUTEX_PRIVATE_FLAG 128 + #define FUTEX_CLOCK_REALTIME 256 +@@ -150,4 +151,10 @@ struct robust_list_head { + (((op & 0xf) << 28) | ((cmp & 0xf) << 24) \ + | ((oparg & 0xfff) << 12) | (cmparg & 0xfff)) + ++struct futex_wait_block { ++ __u32 __user *uaddr; ++ __u32 val; ++ __u32 bitset; ++}; ++ + #endif /* _UAPI_LINUX_FUTEX_H */ +diff --git a/kernel/futex.c b/kernel/futex.c +index 91f3db335c57..2623e8f152cd 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -183,6 +183,7 @@ static int __read_mostly futex_cmpxchg_enabled; + #endif + #define FLAGS_CLOCKRT 0x02 + #define FLAGS_HAS_TIMEOUT 0x04 ++#define FLAGS_WAKE_MULTIPLE 0x08 + + /* + * Priority Inheritance state: +@@ -2720,6 +2721,150 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, + return ret; + } + ++static int do_futex_wait_multiple(struct futex_wait_block *wb, ++ u32 count, unsigned int flags, ++ ktime_t *abs_time) ++{ ++ ++ struct hrtimer_sleeper timeout, *to; ++ struct futex_hash_bucket *hb; ++ struct futex_q *qs = NULL; ++ int ret; ++ int i; ++ ++ qs = kcalloc(count, sizeof(struct futex_q), GFP_KERNEL); ++ if (!qs) ++ return -ENOMEM; ++ ++ to = futex_setup_timer(abs_time, &timeout, flags, ++ current->timer_slack_ns); ++ retry: ++ for (i = 0; i < count; i++) { ++ qs[i].key = FUTEX_KEY_INIT; ++ qs[i].bitset = wb[i].bitset; ++ ++ ret = get_futex_key(wb[i].uaddr, flags & FLAGS_SHARED, ++ &qs[i].key, FUTEX_READ); ++ if (unlikely(ret != 0)) { ++ for (--i; i >= 0; i--) ++ put_futex_key(&qs[i].key); ++ goto out; ++ } ++ } ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ for (i = 0; i < count; i++) { ++ ret = __futex_wait_setup(wb[i].uaddr, wb[i].val, ++ flags, &qs[i], &hb); ++ if (ret) { ++ /* Drop the failed key directly. keys 0..(i-1) ++ * will be put by unqueue_me. ++ */ ++ put_futex_key(&qs[i].key); ++ ++ /* Undo the partial work we did. */ ++ for (--i; i >= 0; i--) ++ unqueue_me(&qs[i]); ++ ++ __set_current_state(TASK_RUNNING); ++ if (ret > 0) ++ goto retry; ++ goto out; ++ } ++ ++ /* We can't hold to the bucket lock when dealing with ++ * the next futex. Queue ourselves now so we can unlock ++ * it before moving on. ++ */ ++ queue_me(&qs[i], hb); ++ } ++ ++ if (to) ++ hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS); ++ ++ /* There is no easy to way to check if we are wake already on ++ * multiple futexes without waking through each one of them. So ++ * just sleep and let the scheduler handle it. ++ */ ++ if (!to || to->task) ++ freezable_schedule(); ++ ++ __set_current_state(TASK_RUNNING); ++ ++ ret = -ETIMEDOUT; ++ /* If we were woken (and unqueued), we succeeded. */ ++ for (i = 0; i < count; i++) ++ if (!unqueue_me(&qs[i])) ++ ret = i; ++ ++ /* Succeed wakeup */ ++ if (ret >= 0) ++ goto out; ++ ++ /* Woken by triggered timeout */ ++ if (to && !to->task) ++ goto out; ++ ++ /* ++ * We expect signal_pending(current), but we might be the ++ * victim of a spurious wakeup as well. ++ */ ++ if (!signal_pending(current)) ++ goto retry; ++ ++ ret = -ERESTARTSYS; ++ if (!abs_time) ++ goto out; ++ ++ ret = -ERESTART_RESTARTBLOCK; ++ out: ++ if (to) { ++ hrtimer_cancel(&to->timer); ++ destroy_hrtimer_on_stack(&to->timer); ++ } ++ ++ kfree(qs); ++ return ret; ++} ++ ++static int futex_wait_multiple(u32 __user *uaddr, unsigned int flags, ++ u32 count, ktime_t *abs_time) ++{ ++ struct futex_wait_block *wb; ++ struct restart_block *restart; ++ int ret; ++ ++ if (!count) ++ return -EINVAL; ++ ++ wb = kcalloc(count, sizeof(struct futex_wait_block), GFP_KERNEL); ++ if (!wb) ++ return -ENOMEM; ++ ++ if (copy_from_user(wb, uaddr, ++ count * sizeof(struct futex_wait_block))) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = do_futex_wait_multiple(wb, count, flags, abs_time); ++ ++ if (ret == -ERESTART_RESTARTBLOCK) { ++ restart = ¤t->restart_block; ++ restart->fn = futex_wait_restart; ++ restart->futex.uaddr = uaddr; ++ restart->futex.val = count; ++ restart->futex.time = *abs_time; ++ restart->futex.flags = (flags | FLAGS_HAS_TIMEOUT | ++ FLAGS_WAKE_MULTIPLE); ++ } ++ ++out: ++ kfree(wb); ++ return ret; ++} ++ + static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, + ktime_t *abs_time, u32 bitset) + { +@@ -2797,6 +2942,10 @@ static long futex_wait_restart(struct restart_block *restart) + } + restart->fn = do_no_restart_syscall; + ++ if (restart->futex.flags & FLAGS_WAKE_MULTIPLE) ++ return (long)futex_wait_multiple(uaddr, restart->futex.flags, ++ restart->futex.val, tp); ++ + return (long)futex_wait(uaddr, restart->futex.flags, + restart->futex.val, tp, restart->futex.bitset); + } +@@ -3680,6 +3829,8 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, + uaddr2); + case FUTEX_CMP_REQUEUE_PI: + return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1); ++ case FUTEX_WAIT_MULTIPLE: ++ return futex_wait_multiple(uaddr, flags, val, timeout); + } + return -ENOSYS; + } +@@ -3696,7 +3847,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, + + if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || + cmd == FUTEX_WAIT_BITSET || +- cmd == FUTEX_WAIT_REQUEUE_PI)) { ++ cmd == FUTEX_WAIT_REQUEUE_PI || ++ cmd == FUTEX_WAIT_MULTIPLE)) { + if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG)))) + return -EFAULT; + if (get_timespec64(&ts, utime)) +@@ -3705,7 +3857,7 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, + return -EINVAL; + + t = timespec64_to_ktime(ts); +- if (cmd == FUTEX_WAIT) ++ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE) + t = ktime_add_safe(ktime_get(), t); + tp = &t; + } +@@ -3889,14 +4041,15 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val, + + if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || + cmd == FUTEX_WAIT_BITSET || +- cmd == FUTEX_WAIT_REQUEUE_PI)) { ++ cmd == FUTEX_WAIT_REQUEUE_PI || ++ cmd == FUTEX_WAIT_MULTIPLE)) { + if (get_old_timespec32(&ts, utime)) + return -EFAULT; + if (!timespec64_valid(&ts)) + return -EINVAL; + + t = timespec64_to_ktime(ts); +- if (cmd == FUTEX_WAIT) ++ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE) + t = ktime_add_safe(ktime_get(), t); + tp = &t; + } +-- +2.20.1 diff --git a/linux57-rc-tkg/linux57-tkg-patches/0011-ZFS-fix.patch b/linux57-rc-tkg/linux57-tkg-patches/0011-ZFS-fix.patch new file mode 100644 index 0000000..af71d04 --- /dev/null +++ b/linux57-rc-tkg/linux57-tkg-patches/0011-ZFS-fix.patch @@ -0,0 +1,43 @@ +From 1e010beda2896bdf3082fb37a3e49f8ce20e04d8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= +Date: Thu, 2 May 2019 05:28:08 +0100 +Subject: [PATCH] x86/fpu: Export kernel_fpu_{begin,end}() with + EXPORT_SYMBOL_GPL +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We need these symbols in zfs as the fpu implementation breaks userspace: + +https://github.com/zfsonlinux/zfs/issues/9346 +Signed-off-by: Jörg Thalheim +--- + arch/x86/kernel/fpu/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c +index 12c70840980e..352538b3bb5d 100644 +--- a/arch/x86/kernel/fpu/core.c ++++ b/arch/x86/kernel/fpu/core.c +@@ -102,7 +102,7 @@ void kernel_fpu_begin(void) + } + __cpu_invalidate_fpregs_state(); + } +-EXPORT_SYMBOL_GPL(kernel_fpu_begin); ++EXPORT_SYMBOL(kernel_fpu_begin); + + void kernel_fpu_end(void) + { +@@ -111,7 +111,7 @@ void kernel_fpu_end(void) + this_cpu_write(in_kernel_fpu, false); + preempt_enable(); + } +-EXPORT_SYMBOL_GPL(kernel_fpu_end); ++EXPORT_SYMBOL(kernel_fpu_end); + + /* + * Save the FPU state (mark it for reload if necessary): +-- +2.23.0 + + diff --git a/linux57-rc-tkg/linux57-tkg-patches/0013-tp_smapi_ec.patch b/linux57-rc-tkg/linux57-tkg-patches/0013-tp_smapi_ec.patch new file mode 100644 index 0000000..fa83c1a --- /dev/null +++ b/linux57-rc-tkg/linux57-tkg-patches/0013-tp_smapi_ec.patch @@ -0,0 +1,2416 @@ +diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c +index 55d33500d55e..744e84228a1f 100644 +--- a/drivers/input/mouse/synaptics.c ++++ b/drivers/input/mouse/synaptics.c +@@ -1338,7 +1338,9 @@ static int set_input_params(struct psmouse *psmouse, + if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && + !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10)) + __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit); +- } ++ } else if (SYN_CAP_CLICKPAD2BTN(info->ext_cap_0c) || ++ SYN_CAP_CLICKPAD2BTN2(info->ext_cap_0c)) ++ __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); + + return 0; + } +diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h +index fc00e005c611..4cfbeec3ae4c 100644 +--- a/drivers/input/mouse/synaptics.h ++++ b/drivers/input/mouse/synaptics.h +@@ -86,6 +86,7 @@ + */ + #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & BIT(20)) /* 1-button ClickPad */ + #define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & BIT(8)) /* 2-button ClickPad */ ++#define SYN_CAP_CLICKPAD2BTN2(ex0c) ((ex0c) & BIT(21)) /* 2-button ClickPad */ + #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & BIT(17)) + #define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & BIT(13)) + #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & BIT(19)) +diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig +index 97a420c11eed..c8621e9b2e4a 100644 +--- a/drivers/macintosh/Kconfig ++++ b/drivers/macintosh/Kconfig +@@ -159,6 +159,13 @@ config INPUT_ADBHID + + If unsure, say Y. + ++config ADB_TRACKPAD_ABSOLUTE ++ bool "Enable absolute mode for adb trackpads" ++ depends on INPUT_ADBHID ++ help ++ Enable absolute mode in adb-base trackpads. This feature adds ++ compatibility with synaptics Xorg / Xfree drivers. ++ + config MAC_EMUMOUSEBTN + tristate "Support for mouse button 2+3 emulation" + depends on SYSCTL && INPUT +diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c +index a261892c03b3..a85192de840c 100644 +--- a/drivers/macintosh/adbhid.c ++++ b/drivers/macintosh/adbhid.c +@@ -262,6 +262,15 @@ static struct adb_ids buttons_ids; + #define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */ + #define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */ + ++#ifdef CONFIG_ADB_TRACKPAD_ABSOLUTE ++#define ABS_XMIN 310 ++#define ABS_XMAX 1700 ++#define ABS_YMIN 200 ++#define ABS_YMAX 1000 ++#define ABS_ZMIN 0 ++#define ABS_ZMAX 55 ++#endif ++ + static void + adbhid_keyboard_input(unsigned char *data, int nb, int apoll) + { +@@ -405,6 +414,9 @@ static void + adbhid_mouse_input(unsigned char *data, int nb, int autopoll) + { + int id = (data[0] >> 4) & 0x0f; ++#ifdef CONFIG_ADB_TRACKPAD_ABSOLUTE ++ int btn = 0; int x_axis = 0; int y_axis = 0; int z_axis = 0; ++#endif + + if (!adbhid[id]) { + pr_err("ADB HID on ID %d not yet registered\n", id); +@@ -436,6 +448,17 @@ adbhid_mouse_input(unsigned char *data, int nb, int autopoll) + high bits of y-axis motion. XY is additional + high bits of x-axis motion. + ++ For ADB Absolute motion protocol the data array will contain the ++ following values: ++ ++ BITS COMMENTS ++ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. ++ data[1] = byyy yyyy Left button and y-axis motion. ++ data[2] = bxxx xxxx Second button and x-axis motion. ++ data[3] = 1yyy 1xxx Half bits of y-axis and x-axis motion. ++ data[4] = 1yyy 1xxx Higher bits of y-axis and x-axis motion. ++ data[5] = 1zzz 1zzz Higher and lower bits of z-pressure. ++ + MacAlly 2-button mouse protocol. + + For MacAlly 2-button mouse protocol the data array will contain the +@@ -458,8 +481,17 @@ adbhid_mouse_input(unsigned char *data, int nb, int autopoll) + switch (adbhid[id]->mouse_kind) + { + case ADBMOUSE_TRACKPAD: ++#ifdef CONFIG_ADB_TRACKPAD_ABSOLUTE ++ x_axis = (data[2] & 0x7f) | ((data[3] & 0x07) << 7) | ++ ((data[4] & 0x07) << 10); ++ y_axis = (data[1] & 0x7f) | ((data[3] & 0x70) << 3) | ++ ((data[4] & 0x70) << 6); ++ z_axis = (data[5] & 0x07) | ((data[5] & 0x70) >> 1); ++ btn = (!(data[1] >> 7)) & 1; ++#else + data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80); + data[2] = data[2] | 0x80; ++#endif + break; + case ADBMOUSE_MICROSPEED: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); +@@ -485,17 +517,39 @@ adbhid_mouse_input(unsigned char *data, int nb, int autopoll) + break; + } + +- input_report_key(adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); +- input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); ++#ifdef CONFIG_ADB_TRACKPAD_ABSOLUTE ++ if ( adbhid[id]->mouse_kind == ADBMOUSE_TRACKPAD ) { + +- if (nb >= 4 && adbhid[id]->mouse_kind != ADBMOUSE_TRACKPAD) +- input_report_key(adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); ++ if(z_axis > 30) input_report_key(adbhid[id]->input, BTN_TOUCH, 1); ++ if(z_axis < 25) input_report_key(adbhid[id]->input, BTN_TOUCH, 0); + +- input_report_rel(adbhid[id]->input, REL_X, +- ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); +- input_report_rel(adbhid[id]->input, REL_Y, +- ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); ++ if(z_axis > 0){ ++ input_report_abs(adbhid[id]->input, ABS_X, x_axis); ++ input_report_abs(adbhid[id]->input, ABS_Y, y_axis); ++ input_report_key(adbhid[id]->input, BTN_TOOL_FINGER, 1); ++ input_report_key(adbhid[id]->input, ABS_TOOL_WIDTH, 5); ++ } else { ++ input_report_key(adbhid[id]->input, BTN_TOOL_FINGER, 0); ++ input_report_key(adbhid[id]->input, ABS_TOOL_WIDTH, 0); ++ } ++ ++ input_report_abs(adbhid[id]->input, ABS_PRESSURE, z_axis); ++ input_report_key(adbhid[id]->input, BTN_LEFT, btn); ++ } else { ++#endif ++ input_report_key(adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); ++ input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); ++ ++ if (nb >= 4 && adbhid[id]->mouse_kind != ADBMOUSE_TRACKPAD) ++ input_report_key(adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); + ++ input_report_rel(adbhid[id]->input, REL_X, ++ ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); ++ input_report_rel(adbhid[id]->input, REL_Y, ++ ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); ++#ifdef CONFIG_ADB_TRACKPAD_ABSOLUTE ++ } ++#endif + input_sync(adbhid[id]->input); + } + +@@ -849,6 +903,15 @@ adbhid_input_register(int id, int default_id, int original_handler_id, + input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | + BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); + input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); ++#ifdef CONFIG_ADB_TRACKPAD_ABSOLUTE ++ set_bit(EV_ABS, input_dev->evbit); ++ input_set_abs_params(input_dev, ABS_X, ABS_XMIN, ABS_XMAX, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, ABS_YMIN, ABS_YMAX, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, ABS_ZMIN, ABS_ZMAX, 0, 0); ++ set_bit(BTN_TOUCH, input_dev->keybit); ++ set_bit(BTN_TOOL_FINGER, input_dev->keybit); ++ set_bit(ABS_TOOL_WIDTH, input_dev->absbit); ++#endif + break; + + case ADB_MISC: +@@ -1132,7 +1195,11 @@ init_trackpad(int id) + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], ++#ifdef CONFIG_ADB_TRACKPAD_ABSOLUTE ++ 0x00, /* Enable absolute mode */ ++#else + 0x03, /*r1_buffer[6],*/ ++#endif + r1_buffer[7]); + + /* Without this flush, the trackpad may be locked up */ +diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig +index ac4d48830415..b272132ac742 100644 +--- a/drivers/platform/x86/Kconfig ++++ b/drivers/platform/x86/Kconfig +@@ -573,9 +573,28 @@ config THINKPAD_ACPI_HOTKEY_POLL + If you are not sure, say Y here. The driver enables polling only if + it is strictly necessary to do so. + ++config THINKPAD_EC ++ tristate ++ ---help--- ++ This is a low-level driver for accessing the ThinkPad H8S embedded ++ controller over the LPC bus (not to be confused with the ACPI Embedded ++ Controller interface). ++ ++config TP_SMAPI ++ tristate "ThinkPad SMAPI Support" ++ select THINKPAD_EC ++ default n ++ help ++ This adds SMAPI support on Lenovo/IBM ThinkPads, for features such ++ as battery charging control. For more information about this driver ++ see . ++ ++ If you have a Lenovo/IBM ThinkPad laptop, say Y or M here. ++ + config SENSORS_HDAPS + tristate "Thinkpad Hard Drive Active Protection System (hdaps)" + depends on INPUT ++ select THINKPAD_EC + help + This driver provides support for the IBM Hard Drive Active Protection + System (hdaps), which provides an accelerometer and other misc. data. +diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile +index 2ba6cb795338..399f8b88646f 100644 +--- a/drivers/platform/x86/Makefile ++++ b/drivers/platform/x86/Makefile +@@ -65,6 +65,8 @@ obj-$(CONFIG_IBM_RTL) += ibm_rtl.o + obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o + obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o + obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o ++obj-$(CONFIG_THINKPAD_EC) += thinkpad_ec.o ++obj-$(CONFIG_TP_SMAPI) += tp_smapi.o + + # Intel + obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o +diff --git a/drivers/platform/x86/thinkpad_ec.c b/drivers/platform/x86/thinkpad_ec.c +new file mode 100644 +index 000000000000..597614bc17e6 +--- /dev/null ++++ b/drivers/platform/x86/thinkpad_ec.c +@@ -0,0 +1,513 @@ ++/* ++ * thinkpad_ec.c - ThinkPad embedded controller LPC3 functions ++ * ++ * The embedded controller on ThinkPad laptops has a non-standard interface, ++ * where LPC channel 3 of the H8S EC chip is hooked up to IO ports ++ * 0x1600-0x161F and implements (a special case of) the H8S LPC protocol. ++ * The EC LPC interface provides various system management services (currently ++ * known: battery information and accelerometer readouts). This driver ++ * provides access and mutual exclusion for the EC interface. ++* ++ * The LPC protocol and terminology are documented here: ++ * "H8S/2104B Group Hardware Manual", ++ * http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf ++ * ++ * Copyright (C) 2006-2007 Shem Multinymous ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) ++ #include ++#else ++ #include ++#endif ++ ++#define TP_VERSION "0.42" ++ ++MODULE_AUTHOR("Shem Multinymous"); ++MODULE_DESCRIPTION("ThinkPad embedded controller hardware access"); ++MODULE_VERSION(TP_VERSION); ++MODULE_LICENSE("GPL"); ++ ++/* IO ports used by embedded controller LPC channel 3: */ ++#define TPC_BASE_PORT 0x1600 ++#define TPC_NUM_PORTS 0x20 ++#define TPC_STR3_PORT 0x1604 /* Reads H8S EC register STR3 */ ++#define TPC_TWR0_PORT 0x1610 /* Mapped to H8S EC register TWR0MW/SW */ ++#define TPC_TWR15_PORT 0x161F /* Mapped to H8S EC register TWR15. */ ++ /* (and port TPC_TWR0_PORT+i is mapped to H8S reg TWRi for 00x%02x", \ ++ msg, args->val[0x0], args->val[0xF], code) ++ ++/* State of request prefetching: */ ++static u8 prefetch_arg0, prefetch_argF; /* Args of last prefetch */ ++static u64 prefetch_jiffies; /* time of prefetch, or: */ ++#define TPC_PREFETCH_NONE INITIAL_JIFFIES /* No prefetch */ ++#define TPC_PREFETCH_JUNK (INITIAL_JIFFIES+1) /* Ignore prefetch */ ++ ++/* Locking: */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) ++static DECLARE_MUTEX(thinkpad_ec_mutex); ++#else ++static DEFINE_SEMAPHORE(thinkpad_ec_mutex); ++#endif ++ ++/* Kludge in case the ACPI DSDT reserves the ports we need. */ ++static bool force_io; /* Willing to do IO to ports we couldn't reserve? */ ++static int reserved_io; /* Successfully reserved the ports? */ ++module_param_named(force_io, force_io, bool, 0600); ++MODULE_PARM_DESC(force_io, "Force IO even if region already reserved (0=off, 1=on)"); ++ ++/** ++ * thinkpad_ec_lock - get lock on the ThinkPad EC ++ * ++ * Get exclusive lock for accesing the ThinkPad embedded controller LPC3 ++ * interface. Returns 0 iff lock acquired. ++ */ ++int thinkpad_ec_lock(void) ++{ ++ int ret; ++ ret = down_interruptible(&thinkpad_ec_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(thinkpad_ec_lock); ++ ++/** ++ * thinkpad_ec_try_lock - try getting lock on the ThinkPad EC ++ * ++ * Try getting an exclusive lock for accesing the ThinkPad embedded ++ * controller LPC3. Returns immediately if lock is not available; neither ++ * blocks nor sleeps. Returns 0 iff lock acquired . ++ */ ++int thinkpad_ec_try_lock(void) ++{ ++ return down_trylock(&thinkpad_ec_mutex); ++} ++EXPORT_SYMBOL_GPL(thinkpad_ec_try_lock); ++ ++/** ++ * thinkpad_ec_unlock - release lock on ThinkPad EC ++ * ++ * Release a previously acquired exclusive lock on the ThinkPad ebmedded ++ * controller LPC3 interface. ++ */ ++void thinkpad_ec_unlock(void) ++{ ++ up(&thinkpad_ec_mutex); ++} ++EXPORT_SYMBOL_GPL(thinkpad_ec_unlock); ++ ++/** ++ * thinkpad_ec_request_row - tell embedded controller to prepare a row ++ * @args Input register arguments ++ * ++ * Requests a data row by writing to H8S LPC registers TRW0 through TWR15 (or ++ * a subset thereof) following the protocol prescribed by the "H8S/2104B Group ++ * Hardware Manual". Does sanity checks via status register STR3. ++ */ ++static int thinkpad_ec_request_row(const struct thinkpad_ec_row *args) ++{ ++ u8 str3; ++ int i; ++ ++ /* EC protocol requires write to TWR0 (function code): */ ++ if (!(args->mask & 0x0001)) { ++ printk(KERN_ERR MSG_FMT("bad args->mask=0x%02x", args->mask)); ++ return -EINVAL; ++ } ++ ++ /* Check initial STR3 status: */ ++ str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; ++ if (str3 & H8S_STR3_OBF3B) { /* data already pending */ ++ inb(TPC_TWR15_PORT); /* marks end of previous transaction */ ++ if (prefetch_jiffies == TPC_PREFETCH_NONE) ++ printk(KERN_WARNING REQ_FMT( ++ "EC has result from unrequested transaction", ++ str3)); ++ return -EBUSY; /* EC will be ready in a few usecs */ ++ } else if (str3 == H8S_STR3_SWMF) { /* busy with previous request */ ++ if (prefetch_jiffies == TPC_PREFETCH_NONE) ++ printk(KERN_WARNING REQ_FMT( ++ "EC is busy with unrequested transaction", ++ str3)); ++ return -EBUSY; /* data will be pending in a few usecs */ ++ } else if (str3 != 0x00) { /* unexpected status? */ ++ printk(KERN_WARNING REQ_FMT("unexpected initial STR3", str3)); ++ return -EIO; ++ } ++ ++ /* Send TWR0MW: */ ++ outb(args->val[0], TPC_TWR0_PORT); ++ str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; ++ if (str3 != H8S_STR3_MWMF) { /* not accepted? */ ++ printk(KERN_WARNING REQ_FMT("arg0 rejected", str3)); ++ return -EIO; ++ } ++ ++ /* Send TWR1 through TWR14: */ ++ for (i = 1; i < TP_CONTROLLER_ROW_LEN-1; i++) ++ if ((args->mask>>i)&1) ++ outb(args->val[i], TPC_TWR0_PORT+i); ++ ++ /* Send TWR15 (default to 0x01). This marks end of command. */ ++ outb((args->mask & 0x8000) ? args->val[0xF] : 0x01, TPC_TWR15_PORT); ++ ++ /* Wait until EC starts writing its reply (~60ns on average). ++ * Releasing locks before this happens may cause an EC hang ++ * due to firmware bug! ++ */ ++ for (i = 0; i < TPC_REQUEST_RETRIES; i++) { ++ str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; ++ if (str3 & H8S_STR3_SWMF) /* EC started replying */ ++ return 0; ++ else if (!(str3 & ~(H8S_STR3_IBF3B|H8S_STR3_MWMF))) ++ /* Normal progress (the EC hasn't seen the request ++ * yet, or is processing it). Wait it out. */ ++ ndelay(TPC_REQUEST_NDELAY); ++ else { /* weird EC status */ ++ printk(KERN_WARNING ++ REQ_FMT("bad end STR3", str3)); ++ return -EIO; ++ } ++ } ++ printk(KERN_WARNING REQ_FMT("EC is mysteriously silent", str3)); ++ return -EIO; ++} ++ ++/** ++ * thinkpad_ec_read_data - read pre-requested row-data from EC ++ * @args Input register arguments of pre-requested rows ++ * @data Output register values ++ * ++ * Reads current row data from the controller, assuming it's already ++ * requested. Follows the H8S spec for register access and status checks. ++ */ ++static int thinkpad_ec_read_data(const struct thinkpad_ec_row *args, ++ struct thinkpad_ec_row *data) ++{ ++ int i; ++ u8 str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; ++ /* Once we make a request, STR3 assumes the sequence of values listed ++ * in the following 'if' as it reads the request and writes its data. ++ * It takes about a few dozen nanosecs total, with very high variance. ++ */ ++ if (str3 == (H8S_STR3_IBF3B|H8S_STR3_MWMF) || ++ str3 == 0x00 || /* the 0x00 is indistinguishable from idle EC! */ ++ str3 == H8S_STR3_SWMF) ++ return -EBUSY; /* not ready yet */ ++ /* Finally, the EC signals output buffer full: */ ++ if (str3 != (H8S_STR3_OBF3B|H8S_STR3_SWMF)) { ++ printk(KERN_WARNING ++ REQ_FMT("bad initial STR3", str3)); ++ return -EIO; ++ } ++ ++ /* Read first byte (signals start of read transactions): */ ++ data->val[0] = inb(TPC_TWR0_PORT); ++ /* Optionally read 14 more bytes: */ ++ for (i = 1; i < TP_CONTROLLER_ROW_LEN-1; i++) ++ if ((data->mask >> i)&1) ++ data->val[i] = inb(TPC_TWR0_PORT+i); ++ /* Read last byte from 0x161F (signals end of read transaction): */ ++ data->val[0xF] = inb(TPC_TWR15_PORT); ++ ++ /* Readout still pending? */ ++ str3 = inb(TPC_STR3_PORT) & H8S_STR3_MASK; ++ if (str3 & H8S_STR3_OBF3B) ++ printk(KERN_WARNING ++ REQ_FMT("OBF3B=1 after read", str3)); ++ /* If port 0x161F returns 0x80 too often, the EC may lock up. Warn: */ ++ if (data->val[0xF] == 0x80) ++ printk(KERN_WARNING ++ REQ_FMT("0x161F reports error", data->val[0xF])); ++ return 0; ++} ++ ++/** ++ * thinkpad_ec_is_row_fetched - is the given row currently prefetched? ++ * ++ * To keep things simple we compare only the first and last args; ++ * this suffices for all known cases. ++ */ ++static int thinkpad_ec_is_row_fetched(const struct thinkpad_ec_row *args) ++{ ++ return (prefetch_jiffies != TPC_PREFETCH_NONE) && ++ (prefetch_jiffies != TPC_PREFETCH_JUNK) && ++ (prefetch_arg0 == args->val[0]) && ++ (prefetch_argF == args->val[0xF]) && ++ (get_jiffies_64() < prefetch_jiffies + TPC_PREFETCH_TIMEOUT); ++} ++ ++/** ++ * thinkpad_ec_read_row - request and read data from ThinkPad EC ++ * @args Input register arguments ++ * @data Output register values ++ * ++ * Read a data row from the ThinkPad embedded controller LPC3 interface. ++ * Does fetching and retrying if needed. The row is specified by an ++ * array of 16 bytes, some of which may be undefined (but the first is ++ * mandatory). These bytes are given in @args->val[], where @args->val[i] is ++ * used iff (@args->mask>>i)&1). The resulting row data is stored in ++ * @data->val[], but is only guaranteed to be valid for indices corresponding ++ * to set bit in @data->mask. That is, if @data->mask&(1<val[i] is undefined. ++ * ++ * Returns -EBUSY on transient error and -EIO on abnormal condition. ++ * Caller must hold controller lock. ++ */ ++int thinkpad_ec_read_row(const struct thinkpad_ec_row *args, ++ struct thinkpad_ec_row *data) ++{ ++ int retries, ret; ++ ++ if (thinkpad_ec_is_row_fetched(args)) ++ goto read_row; /* already requested */ ++ ++ /* Request the row */ ++ for (retries = 0; retries < TPC_READ_RETRIES; ++retries) { ++ ret = thinkpad_ec_request_row(args); ++ if (!ret) ++ goto read_row; ++ if (ret != -EBUSY) ++ break; ++ ndelay(TPC_READ_NDELAY); ++ } ++ printk(KERN_ERR REQ_FMT("failed requesting row", ret)); ++ goto out; ++ ++read_row: ++ /* Read the row's data */ ++ for (retries = 0; retries < TPC_READ_RETRIES; ++retries) { ++ ret = thinkpad_ec_read_data(args, data); ++ if (!ret) ++ goto out; ++ if (ret != -EBUSY) ++ break; ++ ndelay(TPC_READ_NDELAY); ++ } ++ ++ printk(KERN_ERR REQ_FMT("failed waiting for data", ret)); ++ ++out: ++ prefetch_jiffies = TPC_PREFETCH_JUNK; ++ return ret; ++} ++EXPORT_SYMBOL_GPL(thinkpad_ec_read_row); ++ ++/** ++ * thinkpad_ec_try_read_row - try reading prefetched data from ThinkPad EC ++ * @args Input register arguments ++ * @data Output register values ++ * ++ * Try reading a data row from the ThinkPad embedded controller LPC3 ++ * interface, if this raw was recently prefetched using ++ * thinkpad_ec_prefetch_row(). Does not fetch, retry or block. ++ * The parameters have the same meaning as in thinkpad_ec_read_row(). ++ * ++ * Returns -EBUSY is data not ready and -ENODATA if row not prefetched. ++ * Caller must hold controller lock. ++ */ ++int thinkpad_ec_try_read_row(const struct thinkpad_ec_row *args, ++ struct thinkpad_ec_row *data) ++{ ++ int ret; ++ if (!thinkpad_ec_is_row_fetched(args)) { ++ ret = -ENODATA; ++ } else { ++ ret = thinkpad_ec_read_data(args, data); ++ if (!ret) ++ prefetch_jiffies = TPC_PREFETCH_NONE; /* eaten up */ ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(thinkpad_ec_try_read_row); ++ ++/** ++ * thinkpad_ec_prefetch_row - prefetch data from ThinkPad EC ++ * @args Input register arguments ++ * ++ * Prefetch a data row from the ThinkPad embedded controller LCP3 ++ * interface. A subsequent call to thinkpad_ec_read_row() with the ++ * same arguments will be faster, and a subsequent call to ++ * thinkpad_ec_try_read_row() stands a good chance of succeeding if ++ * done neither too soon nor too late. See ++ * thinkpad_ec_read_row() for the meaning of @args. ++ * ++ * Returns -EBUSY on transient error and -EIO on abnormal condition. ++ * Caller must hold controller lock. ++ */ ++int thinkpad_ec_prefetch_row(const struct thinkpad_ec_row *args) ++{ ++ int ret; ++ ret = thinkpad_ec_request_row(args); ++ if (ret) { ++ prefetch_jiffies = TPC_PREFETCH_JUNK; ++ } else { ++ prefetch_jiffies = get_jiffies_64(); ++ prefetch_arg0 = args->val[0x0]; ++ prefetch_argF = args->val[0xF]; ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(thinkpad_ec_prefetch_row); ++ ++/** ++ * thinkpad_ec_invalidate - invalidate prefetched ThinkPad EC data ++ * ++ * Invalidate the data prefetched via thinkpad_ec_prefetch_row() from the ++ * ThinkPad embedded controller LPC3 interface. ++ * Must be called before unlocking by any code that accesses the controller ++ * ports directly. ++ */ ++void thinkpad_ec_invalidate(void) ++{ ++ prefetch_jiffies = TPC_PREFETCH_JUNK; ++} ++EXPORT_SYMBOL_GPL(thinkpad_ec_invalidate); ++ ++ ++/*** Checking for EC hardware ***/ ++ ++/** ++ * thinkpad_ec_test - verify the EC is present and follows protocol ++ * ++ * Ensure the EC LPC3 channel really works on this machine by making ++ * an EC request and seeing if the EC follows the documented H8S protocol. ++ * The requested row just reads battery status, so it should be harmless to ++ * access it (on a correct EC). ++ * This test writes to IO ports, so execute only after checking DMI. ++ */ ++static int __init thinkpad_ec_test(void) ++{ ++ int ret; ++ const struct thinkpad_ec_row args = /* battery 0 basic status */ ++ { .mask = 0x8001, .val = {0x01,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x00} }; ++ struct thinkpad_ec_row data = { .mask = 0x0000 }; ++ ret = thinkpad_ec_lock(); ++ if (ret) ++ return ret; ++ ret = thinkpad_ec_read_row(&args, &data); ++ thinkpad_ec_unlock(); ++ return ret; ++} ++ ++/* Search all DMI device names of a given type for a substring */ ++static int __init dmi_find_substring(int type, const char *substr) ++{ ++ const struct dmi_device *dev = NULL; ++ while ((dev = dmi_find_device(type, NULL, dev))) { ++ if (strstr(dev->name, substr)) ++ return 1; ++ } ++ return 0; ++} ++ ++#define TP_DMI_MATCH(vendor,model) { \ ++ .ident = vendor " " model, \ ++ .matches = { \ ++ DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ ++ DMI_MATCH(DMI_PRODUCT_VERSION, model) \ ++ } \ ++} ++ ++/* Check DMI for existence of ThinkPad embedded controller */ ++static int __init check_dmi_for_ec(void) ++{ ++ /* A few old models that have a good EC but don't report it in DMI */ ++ struct dmi_system_id tp_whitelist[] = { ++ TP_DMI_MATCH("IBM", "ThinkPad A30"), ++ TP_DMI_MATCH("IBM", "ThinkPad T23"), ++ TP_DMI_MATCH("IBM", "ThinkPad X24"), ++ TP_DMI_MATCH("LENOVO", "ThinkPad"), ++ { .ident = NULL } ++ }; ++ return dmi_find_substring(DMI_DEV_TYPE_OEM_STRING, ++ "IBM ThinkPad Embedded Controller") || ++ dmi_check_system(tp_whitelist); ++} ++ ++/*** Init and cleanup ***/ ++ ++static int __init thinkpad_ec_init(void) ++{ ++ if (!check_dmi_for_ec()) { ++ printk(KERN_WARNING ++ "thinkpad_ec: no ThinkPad embedded controller!\n"); ++ return -ENODEV; ++ } ++ ++ if (request_region(TPC_BASE_PORT, TPC_NUM_PORTS, "thinkpad_ec")) { ++ reserved_io = 1; ++ } else { ++ printk(KERN_ERR "thinkpad_ec: cannot claim IO ports %#x-%#x... ", ++ TPC_BASE_PORT, ++ TPC_BASE_PORT + TPC_NUM_PORTS - 1); ++ if (force_io) { ++ printk("forcing use of unreserved IO ports.\n"); ++ } else { ++ printk("consider using force_io=1.\n"); ++ return -ENXIO; ++ } ++ } ++ prefetch_jiffies = TPC_PREFETCH_JUNK; ++ if (thinkpad_ec_test()) { ++ printk(KERN_ERR "thinkpad_ec: initial ec test failed\n"); ++ if (reserved_io) ++ release_region(TPC_BASE_PORT, TPC_NUM_PORTS); ++ return -ENXIO; ++ } ++ printk(KERN_INFO "thinkpad_ec: thinkpad_ec " TP_VERSION " loaded.\n"); ++ return 0; ++} ++ ++static void __exit thinkpad_ec_exit(void) ++{ ++ if (reserved_io) ++ release_region(TPC_BASE_PORT, TPC_NUM_PORTS); ++ printk(KERN_INFO "thinkpad_ec: unloaded.\n"); ++} ++ ++module_init(thinkpad_ec_init); ++module_exit(thinkpad_ec_exit); +diff --git a/drivers/platform/x86/tp_smapi.c b/drivers/platform/x86/tp_smapi.c +new file mode 100644 +index 000000000000..209cb6487e24 +--- /dev/null ++++ b/drivers/platform/x86/tp_smapi.c +@@ -0,0 +1,1493 @@ ++/* ++ * tp_smapi.c - ThinkPad SMAPI support ++ * ++ * This driver exposes some features of the System Management Application ++ * Program Interface (SMAPI) BIOS found on ThinkPad laptops. It works on ++ * models in which the SMAPI BIOS runs in SMM and is invoked by writing ++ * to the APM control port 0xB2. ++ * It also exposes battery status information, obtained from the ThinkPad ++ * embedded controller (via the thinkpad_ec module). ++ * Ancient ThinkPad models use a different interface, supported by the ++ * "thinkpad" module from "tpctl". ++ * ++ * Many of the battery status values obtained from the EC simply mirror ++ * values provided by the battery's Smart Battery System (SBS) interface, so ++ * their meaning is defined by the Smart Battery Data Specification (see ++ * http://sbs-forum.org/specs/sbdat110.pdf). References to this SBS spec ++ * are given in the code where relevant. ++ * ++ * Copyright (C) 2006 Shem Multinymous . ++ * SMAPI access code based on the mwave driver by Mike Sullivan. ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include /* CMOS defines */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TP_VERSION "0.42" ++#define TP_DESC "ThinkPad SMAPI Support" ++#define TP_DIR "smapi" ++ ++MODULE_AUTHOR("Shem Multinymous"); ++MODULE_DESCRIPTION(TP_DESC); ++MODULE_VERSION(TP_VERSION); ++MODULE_LICENSE("GPL"); ++ ++static struct platform_device *pdev; ++ ++static int tp_debug; ++module_param_named(debug, tp_debug, int, 0600); ++MODULE_PARM_DESC(debug, "Debug level (0=off, 1=on)"); ++ ++/* A few macros for printk()ing: */ ++#define TPRINTK(level, fmt, args...) \ ++ dev_printk(level, &(pdev->dev), "%s: " fmt "\n", __func__, ## args) ++#define DPRINTK(fmt, args...) \ ++ do { if (tp_debug) TPRINTK(KERN_DEBUG, fmt, ## args); } while (0) ++ ++/********************************************************************* ++ * SMAPI interface ++ */ ++ ++/* SMAPI functions (register BX when making the SMM call). */ ++#define SMAPI_GET_INHIBIT_CHARGE 0x2114 ++#define SMAPI_SET_INHIBIT_CHARGE 0x2115 ++#define SMAPI_GET_THRESH_START 0x2116 ++#define SMAPI_SET_THRESH_START 0x2117 ++#define SMAPI_GET_FORCE_DISCHARGE 0x2118 ++#define SMAPI_SET_FORCE_DISCHARGE 0x2119 ++#define SMAPI_GET_THRESH_STOP 0x211a ++#define SMAPI_SET_THRESH_STOP 0x211b ++ ++/* SMAPI error codes (see ThinkPad 770 Technical Reference Manual p.83 at ++ http://www-307.ibm.com/pc/support/site.wss/document.do?lndocid=PFAN-3TUQQD */ ++#define SMAPI_RETCODE_EOF 0xff ++static struct { u8 rc; char *msg; int ret; } smapi_retcode[] = ++{ ++ {0x00, "OK", 0}, ++ {0x53, "SMAPI function is not available", -ENXIO}, ++ {0x81, "Invalid parameter", -EINVAL}, ++ {0x86, "Function is not supported by SMAPI BIOS", -EOPNOTSUPP}, ++ {0x90, "System error", -EIO}, ++ {0x91, "System is invalid", -EIO}, ++ {0x92, "System is busy, -EBUSY"}, ++ {0xa0, "Device error (disk read error)", -EIO}, ++ {0xa1, "Device is busy", -EBUSY}, ++ {0xa2, "Device is not attached", -ENXIO}, ++ {0xa3, "Device is disbled", -EIO}, ++ {0xa4, "Request parameter is out of range", -EINVAL}, ++ {0xa5, "Request parameter is not accepted", -EINVAL}, ++ {0xa6, "Transient error", -EBUSY}, /* ? */ ++ {SMAPI_RETCODE_EOF, "Unknown error code", -EIO} ++}; ++ ++ ++#define SMAPI_MAX_RETRIES 10 ++#define SMAPI_PORT2 0x4F /* fixed port, meaning unclear */ ++static unsigned short smapi_port; /* APM control port, normally 0xB2 */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) ++static DECLARE_MUTEX(smapi_mutex); ++#else ++static DEFINE_SEMAPHORE(smapi_mutex); ++#endif ++ ++/** ++ * find_smapi_port - read SMAPI port from NVRAM ++ */ ++static int __init find_smapi_port(void) ++{ ++ u16 smapi_id = 0; ++ unsigned short port = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&rtc_lock, flags); ++ smapi_id = CMOS_READ(0x7C); ++ smapi_id |= (CMOS_READ(0x7D) << 8); ++ spin_unlock_irqrestore(&rtc_lock, flags); ++ ++ if (smapi_id != 0x5349) { ++ printk(KERN_ERR "SMAPI not supported (ID=0x%x)\n", smapi_id); ++ return -ENXIO; ++ } ++ spin_lock_irqsave(&rtc_lock, flags); ++ port = CMOS_READ(0x7E); ++ port |= (CMOS_READ(0x7F) << 8); ++ spin_unlock_irqrestore(&rtc_lock, flags); ++ if (port == 0) { ++ printk(KERN_ERR "unable to read SMAPI port number\n"); ++ return -ENXIO; ++ } ++ return port; ++} ++ ++/** ++ * smapi_request - make a SMAPI call ++ * @inEBX, @inECX, @inEDI, @inESI: input registers ++ * @outEBX, @outECX, @outEDX, @outEDI, @outESI: outputs registers ++ * @msg: textual error message ++ * Invokes the SMAPI SMBIOS with the given input and outpu args. ++ * All outputs are optional (can be %NULL). ++ * Returns 0 when successful, and a negative errno constant ++ * (see smapi_retcode above) upon failure. ++ */ ++static int smapi_request(u32 inEBX, u32 inECX, ++ u32 inEDI, u32 inESI, ++ u32 *outEBX, u32 *outECX, u32 *outEDX, ++ u32 *outEDI, u32 *outESI, const char **msg) ++{ ++ int ret = 0; ++ int i; ++ int retries; ++ u8 rc; ++ /* Must use local vars for output regs, due to reg pressure. */ ++ u32 tmpEAX, tmpEBX, tmpECX, tmpEDX, tmpEDI, tmpESI; ++ ++ for (retries = 0; retries < SMAPI_MAX_RETRIES; ++retries) { ++ DPRINTK("req_in: BX=%x CX=%x DI=%x SI=%x", ++ inEBX, inECX, inEDI, inESI); ++ ++ /* SMAPI's SMBIOS call and thinkpad_ec end up using use ++ * different interfaces to the same chip, so play it safe. */ ++ ret = thinkpad_ec_lock(); ++ if (ret) ++ return ret; ++ ++ __asm__ __volatile__( ++ "movl $0x00005380,%%eax\n\t" ++ "movl %6,%%ebx\n\t" ++ "movl %7,%%ecx\n\t" ++ "movl %8,%%edi\n\t" ++ "movl %9,%%esi\n\t" ++ "xorl %%edx,%%edx\n\t" ++ "movw %10,%%dx\n\t" ++ "out %%al,%%dx\n\t" /* trigger SMI to SMBIOS */ ++ "out %%al,$0x4F\n\t" ++ "movl %%eax,%0\n\t" ++ "movl %%ebx,%1\n\t" ++ "movl %%ecx,%2\n\t" ++ "movl %%edx,%3\n\t" ++ "movl %%edi,%4\n\t" ++ "movl %%esi,%5\n\t" ++ :"=m"(tmpEAX), ++ "=m"(tmpEBX), ++ "=m"(tmpECX), ++ "=m"(tmpEDX), ++ "=m"(tmpEDI), ++ "=m"(tmpESI) ++ :"m"(inEBX), "m"(inECX), "m"(inEDI), "m"(inESI), ++ "m"((u16)smapi_port) ++ :"%eax", "%ebx", "%ecx", "%edx", "%edi", ++ "%esi"); ++ ++ thinkpad_ec_invalidate(); ++ thinkpad_ec_unlock(); ++ ++ /* Don't let the next SMAPI access happen too quickly, ++ * may case problems. (We're hold smapi_mutex). */ ++ msleep(50); ++ ++ if (outEBX) *outEBX = tmpEBX; ++ if (outECX) *outECX = tmpECX; ++ if (outEDX) *outEDX = tmpEDX; ++ if (outESI) *outESI = tmpESI; ++ if (outEDI) *outEDI = tmpEDI; ++ ++ /* Look up error code */ ++ rc = (tmpEAX>>8)&0xFF; ++ for (i = 0; smapi_retcode[i].rc != SMAPI_RETCODE_EOF && ++ smapi_retcode[i].rc != rc; ++i) {} ++ ret = smapi_retcode[i].ret; ++ if (msg) ++ *msg = smapi_retcode[i].msg; ++ ++ DPRINTK("req_out: AX=%x BX=%x CX=%x DX=%x DI=%x SI=%x r=%d", ++ tmpEAX, tmpEBX, tmpECX, tmpEDX, tmpEDI, tmpESI, ret); ++ if (ret) ++ TPRINTK(KERN_NOTICE, "SMAPI error: %s (func=%x)", ++ smapi_retcode[i].msg, inEBX); ++ ++ if (ret != -EBUSY) ++ return ret; ++ } ++ return ret; ++} ++ ++/* Convenience wrapper: discard output arguments */ ++static int smapi_write(u32 inEBX, u32 inECX, ++ u32 inEDI, u32 inESI, const char **msg) ++{ ++ return smapi_request(inEBX, inECX, inEDI, inESI, ++ NULL, NULL, NULL, NULL, NULL, msg); ++} ++ ++ ++/********************************************************************* ++ * Specific SMAPI services ++ * All of these functions return 0 upon success, and a negative errno ++ * constant (see smapi_retcode) on failure. ++ */ ++ ++enum thresh_type { ++ THRESH_STOP = 0, /* the code assumes this is 0 for brevity */ ++ THRESH_START ++}; ++#define THRESH_NAME(which) ((which == THRESH_START) ? "start" : "stop") ++ ++/** ++ * __get_real_thresh - read battery charge start/stop threshold from SMAPI ++ * @bat: battery number (0 or 1) ++ * @which: THRESH_START or THRESH_STOP ++ * @thresh: 1..99, 0=default 1..99, 0=default (pass this as-is to SMAPI) ++ * @outEDI: some additional state that needs to be preserved, meaning unknown ++ * @outESI: some additional state that needs to be preserved, meaning unknown ++ */ ++static int __get_real_thresh(int bat, enum thresh_type which, int *thresh, ++ u32 *outEDI, u32 *outESI) ++{ ++ u32 ebx = (which == THRESH_START) ? SMAPI_GET_THRESH_START ++ : SMAPI_GET_THRESH_STOP; ++ u32 ecx = (bat+1)<<8; ++ const char *msg; ++ int ret = smapi_request(ebx, ecx, 0, 0, NULL, ++ &ecx, NULL, outEDI, outESI, &msg); ++ if (ret) { ++ TPRINTK(KERN_NOTICE, "cannot get %s_thresh of bat=%d: %s", ++ THRESH_NAME(which), bat, msg); ++ return ret; ++ } ++ if (!(ecx&0x00000100)) { ++ TPRINTK(KERN_NOTICE, "cannot get %s_thresh of bat=%d: ecx=0%x", ++ THRESH_NAME(which), bat, ecx); ++ return -EIO; ++ } ++ if (thresh) ++ *thresh = ecx&0xFF; ++ return 0; ++} ++ ++/** ++ * get_real_thresh - read battery charge start/stop threshold from SMAPI ++ * @bat: battery number (0 or 1) ++ * @which: THRESH_START or THRESH_STOP ++ * @thresh: 1..99, 0=default (passes as-is to SMAPI) ++ */ ++static int get_real_thresh(int bat, enum thresh_type which, int *thresh) ++{ ++ return __get_real_thresh(bat, which, thresh, NULL, NULL); ++} ++ ++/** ++ * set_real_thresh - write battery start/top charge threshold to SMAPI ++ * @bat: battery number (0 or 1) ++ * @which: THRESH_START or THRESH_STOP ++ * @thresh: 1..99, 0=default (passes as-is to SMAPI) ++ */ ++static int set_real_thresh(int bat, enum thresh_type which, int thresh) ++{ ++ u32 ebx = (which == THRESH_START) ? SMAPI_SET_THRESH_START ++ : SMAPI_SET_THRESH_STOP; ++ u32 ecx = ((bat+1)<<8) + thresh; ++ u32 getDI, getSI; ++ const char *msg; ++ int ret; ++ ++ /* verify read before writing */ ++ ret = __get_real_thresh(bat, which, NULL, &getDI, &getSI); ++ if (ret) ++ return ret; ++ ++ ret = smapi_write(ebx, ecx, getDI, getSI, &msg); ++ if (ret) ++ TPRINTK(KERN_NOTICE, "set %s to %d for bat=%d failed: %s", ++ THRESH_NAME(which), thresh, bat, msg); ++ else ++ TPRINTK(KERN_INFO, "set %s to %d for bat=%d", ++ THRESH_NAME(which), thresh, bat); ++ return ret; ++} ++ ++/** ++ * __get_inhibit_charge_minutes - get inhibit charge period from SMAPI ++ * @bat: battery number (0 or 1) ++ * @minutes: period in minutes (1..65535 minutes, 0=disabled) ++ * @outECX: some additional state that needs to be preserved, meaning unknown ++ * Note that @minutes is the originally set value, it does not count down. ++ */ ++static int __get_inhibit_charge_minutes(int bat, int *minutes, u32 *outECX) ++{ ++ u32 ecx = (bat+1)<<8; ++ u32 esi; ++ const char *msg; ++ int ret = smapi_request(SMAPI_GET_INHIBIT_CHARGE, ecx, 0, 0, ++ NULL, &ecx, NULL, NULL, &esi, &msg); ++ if (ret) { ++ TPRINTK(KERN_NOTICE, "failed for bat=%d: %s", bat, msg); ++ return ret; ++ } ++ if (!(ecx&0x0100)) { ++ TPRINTK(KERN_NOTICE, "bad ecx=0x%x for bat=%d", ecx, bat); ++ return -EIO; ++ } ++ if (minutes) ++ *minutes = (ecx&0x0001)?esi:0; ++ if (outECX) ++ *outECX = ecx; ++ return 0; ++} ++ ++/** ++ * get_inhibit_charge_minutes - get inhibit charge period from SMAPI ++ * @bat: battery number (0 or 1) ++ * @minutes: period in minutes (1..65535 minutes, 0=disabled) ++ * Note that @minutes is the originally set value, it does not count down. ++ */ ++static int get_inhibit_charge_minutes(int bat, int *minutes) ++{ ++ return __get_inhibit_charge_minutes(bat, minutes, NULL); ++} ++ ++/** ++ * set_inhibit_charge_minutes - write inhibit charge period to SMAPI ++ * @bat: battery number (0 or 1) ++ * @minutes: period in minutes (1..65535 minutes, 0=disabled) ++ */ ++static int set_inhibit_charge_minutes(int bat, int minutes) ++{ ++ u32 ecx; ++ const char *msg; ++ int ret; ++ ++ /* verify read before writing */ ++ ret = __get_inhibit_charge_minutes(bat, NULL, &ecx); ++ if (ret) ++ return ret; ++ ++ ecx = ((bat+1)<<8) | (ecx&0x00FE) | (minutes > 0 ? 0x0001 : 0x0000); ++ if (minutes > 0xFFFF) ++ minutes = 0xFFFF; ++ ret = smapi_write(SMAPI_SET_INHIBIT_CHARGE, ecx, 0, minutes, &msg); ++ if (ret) ++ TPRINTK(KERN_NOTICE, ++ "set to %d failed for bat=%d: %s", minutes, bat, msg); ++ else ++ TPRINTK(KERN_INFO, "set to %d for bat=%d\n", minutes, bat); ++ return ret; ++} ++ ++ ++/** ++ * get_force_discharge - get status of forced discharging from SMAPI ++ * @bat: battery number (0 or 1) ++ * @enabled: 1 if forced discharged is enabled, 0 if not ++ */ ++static int get_force_discharge(int bat, int *enabled) ++{ ++ u32 ecx = (bat+1)<<8; ++ const char *msg; ++ int ret = smapi_request(SMAPI_GET_FORCE_DISCHARGE, ecx, 0, 0, ++ NULL, &ecx, NULL, NULL, NULL, &msg); ++ if (ret) { ++ TPRINTK(KERN_NOTICE, "failed for bat=%d: %s", bat, msg); ++ return ret; ++ } ++ *enabled = (!(ecx&0x00000100) && (ecx&0x00000001))?1:0; ++ return 0; ++} ++ ++/** ++ * set_force_discharge - write status of forced discharging to SMAPI ++ * @bat: battery number (0 or 1) ++ * @enabled: 1 if forced discharged is enabled, 0 if not ++ */ ++static int set_force_discharge(int bat, int enabled) ++{ ++ u32 ecx = (bat+1)<<8; ++ const char *msg; ++ int ret = smapi_request(SMAPI_GET_FORCE_DISCHARGE, ecx, 0, 0, ++ NULL, &ecx, NULL, NULL, NULL, &msg); ++ if (ret) { ++ TPRINTK(KERN_NOTICE, "get failed for bat=%d: %s", bat, msg); ++ return ret; ++ } ++ if (ecx&0x00000100) { ++ TPRINTK(KERN_NOTICE, "cannot force discharge bat=%d", bat); ++ return -EIO; ++ } ++ ++ ecx = ((bat+1)<<8) | (ecx&0x000000FA) | (enabled?0x00000001:0); ++ ret = smapi_write(SMAPI_SET_FORCE_DISCHARGE, ecx, 0, 0, &msg); ++ if (ret) ++ TPRINTK(KERN_NOTICE, "set to %d failed for bat=%d: %s", ++ enabled, bat, msg); ++ else ++ TPRINTK(KERN_INFO, "set to %d for bat=%d", enabled, bat); ++ return ret; ++} ++ ++ ++/********************************************************************* ++ * Wrappers to threshold-related SMAPI functions, which handle default ++ * thresholds and related quirks. ++ */ ++ ++/* Minimum, default and minimum difference for battery charging thresholds: */ ++#define MIN_THRESH_DELTA 4 /* Min delta between start and stop thresh */ ++#define MIN_THRESH_START 2 ++#define MAX_THRESH_START (100-MIN_THRESH_DELTA) ++#define MIN_THRESH_STOP (MIN_THRESH_START + MIN_THRESH_DELTA) ++#define MAX_THRESH_STOP 100 ++#define DEFAULT_THRESH_START MAX_THRESH_START ++#define DEFAULT_THRESH_STOP MAX_THRESH_STOP ++ ++/* The GUI of IBM's Battery Maximizer seems to show a start threshold that ++ * is 1 more than the value we set/get via SMAPI. Since the threshold is ++ * maintained across reboot, this can be confusing. So we kludge our ++ * interface for interoperability: */ ++#define BATMAX_FIX 1 ++ ++/* Get charge start/stop threshold (1..100), ++ * substituting default values if needed and applying BATMAT_FIX. */ ++static int get_thresh(int bat, enum thresh_type which, int *thresh) ++{ ++ int ret = get_real_thresh(bat, which, thresh); ++ if (ret) ++ return ret; ++ if (*thresh == 0) ++ *thresh = (which == THRESH_START) ? DEFAULT_THRESH_START ++ : DEFAULT_THRESH_STOP; ++ else if (which == THRESH_START) ++ *thresh += BATMAX_FIX; ++ return 0; ++} ++ ++ ++/* Set charge start/stop threshold (1..100), ++ * substituting default values if needed and applying BATMAT_FIX. */ ++static int set_thresh(int bat, enum thresh_type which, int thresh) ++{ ++ if (which == THRESH_STOP && thresh == DEFAULT_THRESH_STOP) ++ thresh = 0; /* 100 is out of range, but default means 100 */ ++ if (which == THRESH_START) ++ thresh -= BATMAX_FIX; ++ return set_real_thresh(bat, which, thresh); ++} ++ ++/********************************************************************* ++ * ThinkPad embedded controller readout and basic functions ++ */ ++ ++/** ++ * read_tp_ec_row - read data row from the ThinkPad embedded controller ++ * @arg0: EC command code ++ * @bat: battery number, 0 or 1 ++ * @j: the byte value to be used for "junk" (unused) input/outputs ++ * @dataval: result vector ++ */ ++static int read_tp_ec_row(u8 arg0, int bat, u8 j, u8 *dataval) ++{ ++ int ret; ++ const struct thinkpad_ec_row args = { .mask = 0xFFFF, ++ .val = {arg0, j,j,j,j,j,j,j,j,j,j,j,j,j,j, (u8)bat} }; ++ struct thinkpad_ec_row data = { .mask = 0xFFFF }; ++ ++ ret = thinkpad_ec_lock(); ++ if (ret) ++ return ret; ++ ret = thinkpad_ec_read_row(&args, &data); ++ thinkpad_ec_unlock(); ++ memcpy(dataval, &data.val, TP_CONTROLLER_ROW_LEN); ++ return ret; ++} ++ ++/** ++ * power_device_present - check for presence of battery or AC power ++ * @bat: 0 for battery 0, 1 for battery 1, otherwise AC power ++ * Returns 1 if present, 0 if not present, negative if error. ++ */ ++static int power_device_present(int bat) ++{ ++ u8 row[TP_CONTROLLER_ROW_LEN]; ++ u8 test; ++ int ret = read_tp_ec_row(1, bat, 0, row); ++ if (ret) ++ return ret; ++ switch (bat) { ++ case 0: test = 0x40; break; /* battery 0 */ ++ case 1: test = 0x20; break; /* battery 1 */ ++ default: test = 0x80; /* AC power */ ++ } ++ return (row[0] & test) ? 1 : 0; ++} ++ ++/** ++ * bat_has_status - check if battery can report detailed status ++ * @bat: 0 for battery 0, 1 for battery 1 ++ * Returns 1 if yes, 0 if no, negative if error. ++ */ ++static int bat_has_status(int bat) ++{ ++ u8 row[TP_CONTROLLER_ROW_LEN]; ++ int ret = read_tp_ec_row(1, bat, 0, row); ++ if (ret) ++ return ret; ++ if ((row[0] & (bat?0x20:0x40)) == 0) /* no battery */ ++ return 0; ++ if ((row[1] & (0x60)) == 0) /* no status */ ++ return 0; ++ return 1; ++} ++ ++/** ++ * get_tp_ec_bat_16 - read a 16-bit value from EC battery status data ++ * @arg0: first argument to EC ++ * @off: offset in row returned from EC ++ * @bat: battery (0 or 1) ++ * @val: the 16-bit value obtained ++ * Returns nonzero on error. ++ */ ++static int get_tp_ec_bat_16(u8 arg0, int offset, int bat, u16 *val) ++{ ++ u8 row[TP_CONTROLLER_ROW_LEN]; ++ int ret; ++ if (bat_has_status(bat) != 1) ++ return -ENXIO; ++ ret = read_tp_ec_row(arg0, bat, 0, row); ++ if (ret) ++ return ret; ++ *val = *(u16 *)(row+offset); ++ return 0; ++} ++ ++/********************************************************************* ++ * sysfs attributes for batteries - ++ * definitions and helper functions ++ */ ++ ++/* A custom device attribute struct which holds a battery number */ ++struct bat_device_attribute { ++ struct device_attribute dev_attr; ++ int bat; ++}; ++ ++/** ++ * attr_get_bat - get the battery to which the attribute belongs ++ */ ++static int attr_get_bat(struct device_attribute *attr) ++{ ++ return container_of(attr, struct bat_device_attribute, dev_attr)->bat; ++} ++ ++/** ++ * show_tp_ec_bat_u16 - show an unsigned 16-bit battery attribute ++ * @arg0: specified 1st argument of EC raw to read ++ * @offset: byte offset in EC raw data ++ * @mul: correction factor to multiply by ++ * @na_msg: string to output is value not available (0xFFFFFFFF) ++ * @attr: battery attribute ++ * @buf: output buffer ++ * The 16-bit value is read from the EC, treated as unsigned, ++ * transformed as x->mul*x, and printed to the buffer. ++ * If the value is 0xFFFFFFFF and na_msg!=%NULL, na_msg is printed instead. ++ */ ++static ssize_t show_tp_ec_bat_u16(u8 arg0, int offset, int mul, ++ const char *na_msg, ++ struct device_attribute *attr, char *buf) ++{ ++ u16 val; ++ int ret = get_tp_ec_bat_16(arg0, offset, attr_get_bat(attr), &val); ++ if (ret) ++ return ret; ++ if (na_msg && val == 0xFFFF) ++ return sprintf(buf, "%s\n", na_msg); ++ else ++ return sprintf(buf, "%u\n", mul*(unsigned int)val); ++} ++ ++/** ++ * show_tp_ec_bat_s16 - show an signed 16-bit battery attribute ++ * @arg0: specified 1st argument of EC raw to read ++ * @offset: byte offset in EC raw data ++ * @mul: correction factor to multiply by ++ * @add: correction term to add after multiplication ++ * @attr: battery attribute ++ * @buf: output buffer ++ * The 16-bit value is read from the EC, treated as signed, ++ * transformed as x->mul*x+add, and printed to the buffer. ++ */ ++static ssize_t show_tp_ec_bat_s16(u8 arg0, int offset, int mul, int add, ++ struct device_attribute *attr, char *buf) ++{ ++ u16 val; ++ int ret = get_tp_ec_bat_16(arg0, offset, attr_get_bat(attr), &val); ++ if (ret) ++ return ret; ++ return sprintf(buf, "%d\n", mul*(s16)val+add); ++} ++ ++/** ++ * show_tp_ec_bat_str - show a string from EC battery status data ++ * @arg0: specified 1st argument of EC raw to read ++ * @offset: byte offset in EC raw data ++ * @maxlen: maximum string length ++ * @attr: battery attribute ++ * @buf: output buffer ++ */ ++static ssize_t show_tp_ec_bat_str(u8 arg0, int offset, int maxlen, ++ struct device_attribute *attr, char *buf) ++{ ++ int bat = attr_get_bat(attr); ++ u8 row[TP_CONTROLLER_ROW_LEN]; ++ int ret; ++ if (bat_has_status(bat) != 1) ++ return -ENXIO; ++ ret = read_tp_ec_row(arg0, bat, 0, row); ++ if (ret) ++ return ret; ++ strncpy(buf, (char *)row+offset, maxlen); ++ buf[maxlen] = 0; ++ strcat(buf, "\n"); ++ return strlen(buf); ++} ++ ++/** ++ * show_tp_ec_bat_power - show a power readout from EC battery status data ++ * @arg0: specified 1st argument of EC raw to read ++ * @offV: byte offset of voltage in EC raw data ++ * @offI: byte offset of current in EC raw data ++ * @attr: battery attribute ++ * @buf: output buffer ++ * Computes the power as current*voltage from the two given readout offsets. ++ */ ++static ssize_t show_tp_ec_bat_power(u8 arg0, int offV, int offI, ++ struct device_attribute *attr, char *buf) ++{ ++ u8 row[TP_CONTROLLER_ROW_LEN]; ++ int milliamp, millivolt, ret; ++ int bat = attr_get_bat(attr); ++ if (bat_has_status(bat) != 1) ++ return -ENXIO; ++ ret = read_tp_ec_row(1, bat, 0, row); ++ if (ret) ++ return ret; ++ millivolt = *(u16 *)(row+offV); ++ milliamp = *(s16 *)(row+offI); ++ return sprintf(buf, "%d\n", milliamp*millivolt/1000); /* units: mW */ ++} ++ ++/** ++ * show_tp_ec_bat_date - decode and show a date from EC battery status data ++ * @arg0: specified 1st argument of EC raw to read ++ * @offset: byte offset in EC raw data ++ * @attr: battery attribute ++ * @buf: output buffer ++ */ ++static ssize_t show_tp_ec_bat_date(u8 arg0, int offset, ++ struct device_attribute *attr, char *buf) ++{ ++ u8 row[TP_CONTROLLER_ROW_LEN]; ++ u16 v; ++ int ret; ++ int day, month, year; ++ int bat = attr_get_bat(attr); ++ if (bat_has_status(bat) != 1) ++ return -ENXIO; ++ ret = read_tp_ec_row(arg0, bat, 0, row); ++ if (ret) ++ return ret; ++ ++ /* Decode bit-packed: v = day | (month<<5) | ((year-1980)<<9) */ ++ v = *(u16 *)(row+offset); ++ day = v & 0x1F; ++ month = (v >> 5) & 0xF; ++ year = (v >> 9) + 1980; ++ ++ return sprintf(buf, "%04d-%02d-%02d\n", year, month, day); ++} ++ ++ ++/********************************************************************* ++ * sysfs attribute I/O for batteries - ++ * the actual attribute show/store functions ++ */ ++ ++static ssize_t show_battery_start_charge_thresh(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int thresh; ++ int bat = attr_get_bat(attr); ++ int ret = get_thresh(bat, THRESH_START, &thresh); ++ if (ret) ++ return ret; ++ return sprintf(buf, "%d\n", thresh); /* units: percent */ ++} ++ ++static ssize_t show_battery_stop_charge_thresh(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int thresh; ++ int bat = attr_get_bat(attr); ++ int ret = get_thresh(bat, THRESH_STOP, &thresh); ++ if (ret) ++ return ret; ++ return sprintf(buf, "%d\n", thresh); /* units: percent */ ++} ++ ++/** ++ * store_battery_start_charge_thresh - store battery_start_charge_thresh attr ++ * Since this is a kernel<->user interface, we ensure a valid state for ++ * the hardware. We do this by clamping the requested threshold to the ++ * valid range and, if necessary, moving the other threshold so that ++ * it's MIN_THRESH_DELTA away from this one. ++ */ ++static ssize_t store_battery_start_charge_thresh(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int thresh, other_thresh, ret; ++ int bat = attr_get_bat(attr); ++ ++ if (sscanf(buf, "%d", &thresh) != 1 || thresh < 1 || thresh > 100) ++ return -EINVAL; ++ ++ if (thresh < MIN_THRESH_START) /* clamp up to MIN_THRESH_START */ ++ thresh = MIN_THRESH_START; ++ if (thresh > MAX_THRESH_START) /* clamp down to MAX_THRESH_START */ ++ thresh = MAX_THRESH_START; ++ ++ down(&smapi_mutex); ++ ret = get_thresh(bat, THRESH_STOP, &other_thresh); ++ if (ret != -EOPNOTSUPP && ret != -ENXIO) { ++ if (ret) /* other threshold is set? */ ++ goto out; ++ ret = get_real_thresh(bat, THRESH_START, NULL); ++ if (ret) /* this threshold is set? */ ++ goto out; ++ if (other_thresh < thresh+MIN_THRESH_DELTA) { ++ /* move other thresh to keep it above this one */ ++ ret = set_thresh(bat, THRESH_STOP, ++ thresh+MIN_THRESH_DELTA); ++ if (ret) ++ goto out; ++ } ++ } ++ ret = set_thresh(bat, THRESH_START, thresh); ++out: ++ up(&smapi_mutex); ++ return count; ++ ++} ++ ++/** ++ * store_battery_stop_charge_thresh - store battery_stop_charge_thresh attr ++ * Since this is a kernel<->user interface, we ensure a valid state for ++ * the hardware. We do this by clamping the requested threshold to the ++ * valid range and, if necessary, moving the other threshold so that ++ * it's MIN_THRESH_DELTA away from this one. ++ */ ++static ssize_t store_battery_stop_charge_thresh(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int thresh, other_thresh, ret; ++ int bat = attr_get_bat(attr); ++ ++ if (sscanf(buf, "%d", &thresh) != 1 || thresh < 1 || thresh > 100) ++ return -EINVAL; ++ ++ if (thresh < MIN_THRESH_STOP) /* clamp up to MIN_THRESH_STOP */ ++ thresh = MIN_THRESH_STOP; ++ ++ down(&smapi_mutex); ++ ret = get_thresh(bat, THRESH_START, &other_thresh); ++ if (ret != -EOPNOTSUPP && ret != -ENXIO) { /* other threshold exists? */ ++ if (ret) ++ goto out; ++ /* this threshold exists? */ ++ ret = get_real_thresh(bat, THRESH_STOP, NULL); ++ if (ret) ++ goto out; ++ if (other_thresh >= thresh-MIN_THRESH_DELTA) { ++ /* move other thresh to be below this one */ ++ ret = set_thresh(bat, THRESH_START, ++ thresh-MIN_THRESH_DELTA); ++ if (ret) ++ goto out; ++ } ++ } ++ ret = set_thresh(bat, THRESH_STOP, thresh); ++out: ++ up(&smapi_mutex); ++ return count; ++} ++ ++static ssize_t show_battery_inhibit_charge_minutes(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int minutes; ++ int bat = attr_get_bat(attr); ++ int ret = get_inhibit_charge_minutes(bat, &minutes); ++ if (ret) ++ return ret; ++ return sprintf(buf, "%d\n", minutes); /* units: minutes */ ++} ++ ++static ssize_t store_battery_inhibit_charge_minutes(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int ret; ++ int minutes; ++ int bat = attr_get_bat(attr); ++ if (sscanf(buf, "%d", &minutes) != 1 || minutes < 0) { ++ TPRINTK(KERN_ERR, "inhibit_charge_minutes: " ++ "must be a non-negative integer"); ++ return -EINVAL; ++ } ++ ret = set_inhibit_charge_minutes(bat, minutes); ++ if (ret) ++ return ret; ++ return count; ++} ++ ++static ssize_t show_battery_force_discharge(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int enabled; ++ int bat = attr_get_bat(attr); ++ int ret = get_force_discharge(bat, &enabled); ++ if (ret) ++ return ret; ++ return sprintf(buf, "%d\n", enabled); /* type: boolean */ ++} ++ ++static ssize_t store_battery_force_discharge(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ int ret; ++ int enabled; ++ int bat = attr_get_bat(attr); ++ if (sscanf(buf, "%d", &enabled) != 1 || enabled < 0 || enabled > 1) ++ return -EINVAL; ++ ret = set_force_discharge(bat, enabled); ++ if (ret) ++ return ret; ++ return count; ++} ++ ++static ssize_t show_battery_installed( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int bat = attr_get_bat(attr); ++ int ret = power_device_present(bat); ++ if (ret < 0) ++ return ret; ++ return sprintf(buf, "%d\n", ret); /* type: boolean */ ++} ++ ++static ssize_t show_battery_state( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ u8 row[TP_CONTROLLER_ROW_LEN]; ++ const char *txt; ++ int ret; ++ int bat = attr_get_bat(attr); ++ if (bat_has_status(bat) != 1) ++ return sprintf(buf, "none\n"); ++ ret = read_tp_ec_row(1, bat, 0, row); ++ if (ret) ++ return ret; ++ switch (row[1] & 0xf0) { ++ case 0xc0: txt = "idle"; break; ++ case 0xd0: txt = "discharging"; break; ++ case 0xe0: txt = "charging"; break; ++ default: return sprintf(buf, "unknown (0x%x)\n", row[1]); ++ } ++ return sprintf(buf, "%s\n", txt); /* type: string from fixed set */ ++} ++ ++static ssize_t show_battery_manufacturer( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* type: string. SBS spec v1.1 p34: ManufacturerName() */ ++ return show_tp_ec_bat_str(4, 2, TP_CONTROLLER_ROW_LEN-2, attr, buf); ++} ++ ++static ssize_t show_battery_model( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* type: string. SBS spec v1.1 p34: DeviceName() */ ++ return show_tp_ec_bat_str(5, 2, TP_CONTROLLER_ROW_LEN-2, attr, buf); ++} ++ ++static ssize_t show_battery_barcoding( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* type: string */ ++ return show_tp_ec_bat_str(7, 2, TP_CONTROLLER_ROW_LEN-2, attr, buf); ++} ++ ++static ssize_t show_battery_chemistry( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* type: string. SBS spec v1.1 p34-35: DeviceChemistry() */ ++ return show_tp_ec_bat_str(6, 2, 5, attr, buf); ++} ++ ++static ssize_t show_battery_voltage( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mV. SBS spec v1.1 p24: Voltage() */ ++ return show_tp_ec_bat_u16(1, 6, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_design_voltage( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mV. SBS spec v1.1 p32: DesignVoltage() */ ++ return show_tp_ec_bat_u16(3, 4, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_charging_max_voltage( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mV. SBS spec v1.1 p37,39: ChargingVoltage() */ ++ return show_tp_ec_bat_u16(9, 8, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_group0_voltage( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mV */ ++ return show_tp_ec_bat_u16(0xA, 12, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_group1_voltage( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mV */ ++ return show_tp_ec_bat_u16(0xA, 10, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_group2_voltage( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mV */ ++ return show_tp_ec_bat_u16(0xA, 8, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_group3_voltage( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mV */ ++ return show_tp_ec_bat_u16(0xA, 6, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_current_now( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mA. SBS spec v1.1 p24: Current() */ ++ return show_tp_ec_bat_s16(1, 8, 1, 0, attr, buf); ++} ++ ++static ssize_t show_battery_current_avg( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mA. SBS spec v1.1 p24: AverageCurrent() */ ++ return show_tp_ec_bat_s16(1, 10, 1, 0, attr, buf); ++} ++ ++static ssize_t show_battery_charging_max_current( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mA. SBS spec v1.1 p36,38: ChargingCurrent() */ ++ return show_tp_ec_bat_s16(9, 6, 1, 0, attr, buf); ++} ++ ++static ssize_t show_battery_power_now( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mW. SBS spec v1.1: Voltage()*Current() */ ++ return show_tp_ec_bat_power(1, 6, 8, attr, buf); ++} ++ ++static ssize_t show_battery_power_avg( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mW. SBS spec v1.1: Voltage()*AverageCurrent() */ ++ return show_tp_ec_bat_power(1, 6, 10, attr, buf); ++} ++ ++static ssize_t show_battery_remaining_percent( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: percent. SBS spec v1.1 p25: RelativeStateOfCharge() */ ++ return show_tp_ec_bat_u16(1, 12, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_remaining_percent_error( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: percent. SBS spec v1.1 p25: MaxError() */ ++ return show_tp_ec_bat_u16(9, 4, 1, NULL, attr, buf); ++} ++ ++static ssize_t show_battery_remaining_charging_time( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: minutes. SBS spec v1.1 p27: AverageTimeToFull() */ ++ return show_tp_ec_bat_u16(2, 8, 1, "not_charging", attr, buf); ++} ++ ++static ssize_t show_battery_remaining_running_time( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: minutes. SBS spec v1.1 p27: RunTimeToEmpty() */ ++ return show_tp_ec_bat_u16(2, 6, 1, "not_discharging", attr, buf); ++} ++ ++static ssize_t show_battery_remaining_running_time_now( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: minutes. SBS spec v1.1 p27: RunTimeToEmpty() */ ++ return show_tp_ec_bat_u16(2, 4, 1, "not_discharging", attr, buf); ++} ++ ++static ssize_t show_battery_remaining_capacity( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mWh. SBS spec v1.1 p26. */ ++ return show_tp_ec_bat_u16(1, 14, 10, "", attr, buf); ++} ++ ++static ssize_t show_battery_last_full_capacity( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mWh. SBS spec v1.1 p26: FullChargeCapacity() */ ++ return show_tp_ec_bat_u16(2, 2, 10, "", attr, buf); ++} ++ ++static ssize_t show_battery_design_capacity( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: mWh. SBS spec v1.1 p32: DesignCapacity() */ ++ return show_tp_ec_bat_u16(3, 2, 10, "", attr, buf); ++} ++ ++static ssize_t show_battery_cycle_count( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: ordinal. SBS spec v1.1 p32: CycleCount() */ ++ return show_tp_ec_bat_u16(2, 12, 1, "", attr, buf); ++} ++ ++static ssize_t show_battery_temperature( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* units: millicelsius. SBS spec v1.1: Temperature()*10 */ ++ return show_tp_ec_bat_s16(1, 4, 100, -273100, attr, buf); ++} ++ ++static ssize_t show_battery_serial( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* type: int. SBS spec v1.1 p34: SerialNumber() */ ++ return show_tp_ec_bat_u16(3, 10, 1, "", attr, buf); ++} ++ ++static ssize_t show_battery_manufacture_date( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* type: YYYY-MM-DD. SBS spec v1.1 p34: ManufactureDate() */ ++ return show_tp_ec_bat_date(3, 8, attr, buf); ++} ++ ++static ssize_t show_battery_first_use_date( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ /* type: YYYY-MM-DD */ ++ return show_tp_ec_bat_date(8, 2, attr, buf); ++} ++ ++/** ++ * show_battery_dump - show the battery's dump attribute ++ * The dump attribute gives a hex dump of all EC readouts related to a ++ * battery. Some of the enumerated values don't really exist (i.e., the ++ * EC function just leaves them untouched); we use a kludge to detect and ++ * denote these. ++ */ ++#define MIN_DUMP_ARG0 0x00 ++#define MAX_DUMP_ARG0 0x0a /* 0x0b is useful too but hangs old EC firmware */ ++static ssize_t show_battery_dump( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int i; ++ char *p = buf; ++ int bat = attr_get_bat(attr); ++ u8 arg0; /* first argument to EC */ ++ u8 rowa[TP_CONTROLLER_ROW_LEN], ++ rowb[TP_CONTROLLER_ROW_LEN]; ++ const u8 junka = 0xAA, ++ junkb = 0x55; /* junk values for testing changes */ ++ int ret; ++ ++ for (arg0 = MIN_DUMP_ARG0; arg0 <= MAX_DUMP_ARG0; ++arg0) { ++ if ((p-buf) > PAGE_SIZE-TP_CONTROLLER_ROW_LEN*5) ++ return -ENOMEM; /* don't overflow sysfs buf */ ++ /* Read raw twice with different junk values, ++ * to detect unused output bytes which are left unchaged: */ ++ ret = read_tp_ec_row(arg0, bat, junka, rowa); ++ if (ret) ++ return ret; ++ ret = read_tp_ec_row(arg0, bat, junkb, rowb); ++ if (ret) ++ return ret; ++ for (i = 0; i < TP_CONTROLLER_ROW_LEN; i++) { ++ if (rowa[i] == junka && rowb[i] == junkb) ++ p += sprintf(p, "-- "); /* unused by EC */ ++ else ++ p += sprintf(p, "%02x ", rowa[i]); ++ } ++ p += sprintf(p, "\n"); ++ } ++ return p-buf; ++} ++ ++ ++/********************************************************************* ++ * sysfs attribute I/O, other than batteries ++ */ ++ ++static ssize_t show_ac_connected( ++ struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int ret = power_device_present(0xFF); ++ if (ret < 0) ++ return ret; ++ return sprintf(buf, "%d\n", ret); /* type: boolean */ ++} ++ ++/********************************************************************* ++ * The the "smapi_request" sysfs attribute executes a raw SMAPI call. ++ * You write to make a request and read to get the result. The state ++ * is saved globally rather than per fd (sysfs limitation), so ++ * simultaenous requests may get each other's results! So this is for ++ * development and debugging only. ++ */ ++#define MAX_SMAPI_ATTR_ANSWER_LEN 128 ++static char smapi_attr_answer[MAX_SMAPI_ATTR_ANSWER_LEN] = ""; ++ ++static ssize_t show_smapi_request(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int ret = snprintf(buf, PAGE_SIZE, "%s", smapi_attr_answer); ++ smapi_attr_answer[0] = '\0'; ++ return ret; ++} ++ ++static ssize_t store_smapi_request(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned int inEBX, inECX, inEDI, inESI; ++ u32 outEBX, outECX, outEDX, outEDI, outESI; ++ const char *msg; ++ int ret; ++ if (sscanf(buf, "%x %x %x %x", &inEBX, &inECX, &inEDI, &inESI) != 4) { ++ smapi_attr_answer[0] = '\0'; ++ return -EINVAL; ++ } ++ ret = smapi_request( ++ inEBX, inECX, inEDI, inESI, ++ &outEBX, &outECX, &outEDX, &outEDI, &outESI, &msg); ++ snprintf(smapi_attr_answer, MAX_SMAPI_ATTR_ANSWER_LEN, ++ "%x %x %x %x %x %d '%s'\n", ++ (unsigned int)outEBX, (unsigned int)outECX, ++ (unsigned int)outEDX, (unsigned int)outEDI, ++ (unsigned int)outESI, ret, msg); ++ if (ret) ++ return ret; ++ else ++ return count; ++} ++ ++/********************************************************************* ++ * Power management: the embedded controller forgets the battery ++ * thresholds when the system is suspended to disk and unplugged from ++ * AC and battery, so we restore it upon resume. ++ */ ++ ++static int saved_threshs[4] = {-1, -1, -1, -1}; /* -1 = don't know */ ++ ++static int tp_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ int restore = (state.event == PM_EVENT_HIBERNATE || ++ state.event == PM_EVENT_FREEZE); ++ if (!restore || get_real_thresh(0, THRESH_STOP , &saved_threshs[0])) ++ saved_threshs[0] = -1; ++ if (!restore || get_real_thresh(0, THRESH_START, &saved_threshs[1])) ++ saved_threshs[1] = -1; ++ if (!restore || get_real_thresh(1, THRESH_STOP , &saved_threshs[2])) ++ saved_threshs[2] = -1; ++ if (!restore || get_real_thresh(1, THRESH_START, &saved_threshs[3])) ++ saved_threshs[3] = -1; ++ DPRINTK("suspend saved: %d %d %d %d", saved_threshs[0], ++ saved_threshs[1], saved_threshs[2], saved_threshs[3]); ++ return 0; ++} ++ ++static int tp_resume(struct platform_device *dev) ++{ ++ DPRINTK("resume restoring: %d %d %d %d", saved_threshs[0], ++ saved_threshs[1], saved_threshs[2], saved_threshs[3]); ++ if (saved_threshs[0] >= 0) ++ set_real_thresh(0, THRESH_STOP , saved_threshs[0]); ++ if (saved_threshs[1] >= 0) ++ set_real_thresh(0, THRESH_START, saved_threshs[1]); ++ if (saved_threshs[2] >= 0) ++ set_real_thresh(1, THRESH_STOP , saved_threshs[2]); ++ if (saved_threshs[3] >= 0) ++ set_real_thresh(1, THRESH_START, saved_threshs[3]); ++ return 0; ++} ++ ++ ++/********************************************************************* ++ * Driver model ++ */ ++ ++static struct platform_driver tp_driver = { ++ .suspend = tp_suspend, ++ .resume = tp_resume, ++ .driver = { ++ .name = "smapi", ++ .owner = THIS_MODULE ++ }, ++}; ++ ++ ++/********************************************************************* ++ * Sysfs device model ++ */ ++ ++/* Attributes in /sys/devices/platform/smapi/ */ ++ ++static DEVICE_ATTR(ac_connected, 0444, show_ac_connected, NULL); ++static DEVICE_ATTR(smapi_request, 0600, show_smapi_request, ++ store_smapi_request); ++ ++static struct attribute *tp_root_attributes[] = { ++ &dev_attr_ac_connected.attr, ++ &dev_attr_smapi_request.attr, ++ NULL ++}; ++static struct attribute_group tp_root_attribute_group = { ++ .attrs = tp_root_attributes ++}; ++ ++/* Attributes under /sys/devices/platform/smapi/BAT{0,1}/ : ++ * Every attribute needs to be defined (i.e., statically allocated) for ++ * each battery, and then referenced in the attribute list of each battery. ++ * We use preprocessor voodoo to avoid duplicating the list of attributes 4 ++ * times. The preprocessor output is just normal sysfs attributes code. ++ */ ++ ++/** ++ * FOREACH_BAT_ATTR - invoke the given macros on all our battery attributes ++ * @_BAT: battery number (0 or 1) ++ * @_ATTR_RW: macro to invoke for each read/write attribute ++ * @_ATTR_R: macro to invoke for each read-only attribute ++ */ ++#define FOREACH_BAT_ATTR(_BAT, _ATTR_RW, _ATTR_R) \ ++ _ATTR_RW(_BAT, start_charge_thresh) \ ++ _ATTR_RW(_BAT, stop_charge_thresh) \ ++ _ATTR_RW(_BAT, inhibit_charge_minutes) \ ++ _ATTR_RW(_BAT, force_discharge) \ ++ _ATTR_R(_BAT, installed) \ ++ _ATTR_R(_BAT, state) \ ++ _ATTR_R(_BAT, manufacturer) \ ++ _ATTR_R(_BAT, model) \ ++ _ATTR_R(_BAT, barcoding) \ ++ _ATTR_R(_BAT, chemistry) \ ++ _ATTR_R(_BAT, voltage) \ ++ _ATTR_R(_BAT, group0_voltage) \ ++ _ATTR_R(_BAT, group1_voltage) \ ++ _ATTR_R(_BAT, group2_voltage) \ ++ _ATTR_R(_BAT, group3_voltage) \ ++ _ATTR_R(_BAT, current_now) \ ++ _ATTR_R(_BAT, current_avg) \ ++ _ATTR_R(_BAT, charging_max_current) \ ++ _ATTR_R(_BAT, power_now) \ ++ _ATTR_R(_BAT, power_avg) \ ++ _ATTR_R(_BAT, remaining_percent) \ ++ _ATTR_R(_BAT, remaining_percent_error) \ ++ _ATTR_R(_BAT, remaining_charging_time) \ ++ _ATTR_R(_BAT, remaining_running_time) \ ++ _ATTR_R(_BAT, remaining_running_time_now) \ ++ _ATTR_R(_BAT, remaining_capacity) \ ++ _ATTR_R(_BAT, last_full_capacity) \ ++ _ATTR_R(_BAT, design_voltage) \ ++ _ATTR_R(_BAT, charging_max_voltage) \ ++ _ATTR_R(_BAT, design_capacity) \ ++ _ATTR_R(_BAT, cycle_count) \ ++ _ATTR_R(_BAT, temperature) \ ++ _ATTR_R(_BAT, serial) \ ++ _ATTR_R(_BAT, manufacture_date) \ ++ _ATTR_R(_BAT, first_use_date) \ ++ _ATTR_R(_BAT, dump) ++ ++/* Define several macros we will feed into FOREACH_BAT_ATTR: */ ++ ++#define DEFINE_BAT_ATTR_RW(_BAT,_NAME) \ ++ static struct bat_device_attribute dev_attr_##_NAME##_##_BAT = { \ ++ .dev_attr = __ATTR(_NAME, 0644, show_battery_##_NAME, \ ++ store_battery_##_NAME), \ ++ .bat = _BAT \ ++ }; ++ ++#define DEFINE_BAT_ATTR_R(_BAT,_NAME) \ ++ static struct bat_device_attribute dev_attr_##_NAME##_##_BAT = { \ ++ .dev_attr = __ATTR(_NAME, 0644, show_battery_##_NAME, 0), \ ++ .bat = _BAT \ ++ }; ++ ++#define REF_BAT_ATTR(_BAT,_NAME) \ ++ &dev_attr_##_NAME##_##_BAT.dev_attr.attr, ++ ++/* This provide all attributes for one battery: */ ++ ++#define PROVIDE_BAT_ATTRS(_BAT) \ ++ FOREACH_BAT_ATTR(_BAT, DEFINE_BAT_ATTR_RW, DEFINE_BAT_ATTR_R) \ ++ static struct attribute *tp_bat##_BAT##_attributes[] = { \ ++ FOREACH_BAT_ATTR(_BAT, REF_BAT_ATTR, REF_BAT_ATTR) \ ++ NULL \ ++ }; \ ++ static struct attribute_group tp_bat##_BAT##_attribute_group = { \ ++ .name = "BAT" #_BAT, \ ++ .attrs = tp_bat##_BAT##_attributes \ ++ }; ++ ++/* Finally genereate the attributes: */ ++ ++PROVIDE_BAT_ATTRS(0) ++PROVIDE_BAT_ATTRS(1) ++ ++/* List of attribute groups */ ++ ++static struct attribute_group *attr_groups[] = { ++ &tp_root_attribute_group, ++ &tp_bat0_attribute_group, ++ &tp_bat1_attribute_group, ++ NULL ++}; ++ ++ ++/********************************************************************* ++ * Init and cleanup ++ */ ++ ++static struct attribute_group **next_attr_group; /* next to register */ ++ ++static int __init tp_init(void) ++{ ++ int ret; ++ printk(KERN_INFO "tp_smapi " TP_VERSION " loading...\n"); ++ ++ ret = find_smapi_port(); ++ if (ret < 0) ++ goto err; ++ else ++ smapi_port = ret; ++ ++ if (!request_region(smapi_port, 1, "smapi")) { ++ printk(KERN_ERR "tp_smapi cannot claim port 0x%x\n", ++ smapi_port); ++ ret = -ENXIO; ++ goto err; ++ } ++ ++ if (!request_region(SMAPI_PORT2, 1, "smapi")) { ++ printk(KERN_ERR "tp_smapi cannot claim port 0x%x\n", ++ SMAPI_PORT2); ++ ret = -ENXIO; ++ goto err_port1; ++ } ++ ++ ret = platform_driver_register(&tp_driver); ++ if (ret) ++ goto err_port2; ++ ++ pdev = platform_device_alloc("smapi", -1); ++ if (!pdev) { ++ ret = -ENOMEM; ++ goto err_driver; ++ } ++ ++ ret = platform_device_add(pdev); ++ if (ret) ++ goto err_device_free; ++ ++ for (next_attr_group = attr_groups; *next_attr_group; ++ ++next_attr_group) { ++ ret = sysfs_create_group(&pdev->dev.kobj, *next_attr_group); ++ if (ret) ++ goto err_attr; ++ } ++ ++ printk(KERN_INFO "tp_smapi successfully loaded (smapi_port=0x%x).\n", ++ smapi_port); ++ return 0; ++ ++err_attr: ++ while (--next_attr_group >= attr_groups) ++ sysfs_remove_group(&pdev->dev.kobj, *next_attr_group); ++ platform_device_unregister(pdev); ++err_device_free: ++ platform_device_put(pdev); ++err_driver: ++ platform_driver_unregister(&tp_driver); ++err_port2: ++ release_region(SMAPI_PORT2, 1); ++err_port1: ++ release_region(smapi_port, 1); ++err: ++ printk(KERN_ERR "tp_smapi init failed (ret=%d)!\n", ret); ++ return ret; ++} ++ ++static void __exit tp_exit(void) ++{ ++ while (next_attr_group && --next_attr_group >= attr_groups) ++ sysfs_remove_group(&pdev->dev.kobj, *next_attr_group); ++ platform_device_unregister(pdev); ++ platform_driver_unregister(&tp_driver); ++ release_region(SMAPI_PORT2, 1); ++ if (smapi_port) ++ release_region(smapi_port, 1); ++ ++ printk(KERN_INFO "tp_smapi unloaded.\n"); ++} ++ ++module_init(tp_init); ++module_exit(tp_exit); +diff --git a/fs/exec.c b/fs/exec.c +index 65eaacaba4f4..1d3b310bd5f0 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -63,6 +63,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -866,9 +868,12 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags) + if (err) + goto exit; + +- if (name->name[0] != '\0') ++ if (name->name[0] != '\0') { + fsnotify_open(file); + ++ trace_open_exec(name->name); ++ } ++ + out: + return file; + +diff --git a/fs/open.c b/fs/open.c +index cb81623a8b09..a92b0f6061ac 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -34,6 +34,9 @@ + + #include "internal.h" + ++#define CREATE_TRACE_POINTS ++#include ++ + int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, + struct file *filp) + { +@@ -1068,8 +1071,11 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) + + long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) + { ++ struct filename *tmp; ++ tmp = getname(filename); + struct open_how how = build_open_how(flags, mode); + return do_sys_openat2(dfd, filename, &how); ++ trace_do_sys_open(tmp->name, flags, mode); + } + + +diff --git a/include/trace/events/fs.h b/include/trace/events/fs.h +new file mode 100644 +index 000000000000..fb634b74adf3 +--- /dev/null ++++ b/include/trace/events/fs.h +@@ -0,0 +1,53 @@ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM fs ++ ++#if !defined(_TRACE_FS_H) || defined(TRACE_HEADER_MULTI_READ) ++#define _TRACE_FS_H ++ ++#include ++#include ++ ++TRACE_EVENT(do_sys_open, ++ ++ TP_PROTO(const char *filename, int flags, int mode), ++ ++ TP_ARGS(filename, flags, mode), ++ ++ TP_STRUCT__entry( ++ __string( filename, filename ) ++ __field( int, flags ) ++ __field( int, mode ) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(filename, filename); ++ __entry->flags = flags; ++ __entry->mode = mode; ++ ), ++ ++ TP_printk("\"%s\" %x %o", ++ __get_str(filename), __entry->flags, __entry->mode) ++); ++ ++TRACE_EVENT(open_exec, ++ ++ TP_PROTO(const char *filename), ++ ++ TP_ARGS(filename), ++ ++ TP_STRUCT__entry( ++ __string( filename, filename ) ++ ), ++ ++ TP_fast_assign( ++ __assign_str(filename, filename); ++ ), ++ ++ TP_printk("\"%s\"", ++ __get_str(filename)) ++); ++ ++#endif /* _TRACE_FS_H */ ++ ++/* This part must be outside protection */ ++#include +diff --git a/include/linux/thinkpad_ec.h b/include/linux/thinkpad_ec.h +new file mode 100644 +index 000000000000..1b80d7ee5493 +--- /dev/null ++++ b/include/linux/thinkpad_ec.h +@@ -0,0 +1,47 @@ ++/* ++ * thinkpad_ec.h - interface to ThinkPad embedded controller LPC3 functions ++ * ++ * Copyright (C) 2005 Shem Multinymous ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef _THINKPAD_EC_H ++#define _THINKPAD_EC_H ++ ++#ifdef __KERNEL__ ++ ++#define TP_CONTROLLER_ROW_LEN 16 ++ ++/* EC transactions input and output (possibly partial) vectors of 16 bytes. */ ++struct thinkpad_ec_row { ++ u16 mask; /* bitmap of which entries of val[] are meaningful */ ++ u8 val[TP_CONTROLLER_ROW_LEN]; ++}; ++ ++extern int __must_check thinkpad_ec_lock(void); ++extern int __must_check thinkpad_ec_try_lock(void); ++extern void thinkpad_ec_unlock(void); ++ ++extern int thinkpad_ec_read_row(const struct thinkpad_ec_row *args, ++ struct thinkpad_ec_row *data); ++extern int thinkpad_ec_try_read_row(const struct thinkpad_ec_row *args, ++ struct thinkpad_ec_row *mask); ++extern int thinkpad_ec_prefetch_row(const struct thinkpad_ec_row *args); ++extern void thinkpad_ec_invalidate(void); ++ ++ ++#endif /* __KERNEL */ ++#endif /* _THINKPAD_EC_H */