diff --git a/include/cmake.mk b/include/cmake.mk index 96c4d7df34..b38d440039 100644 --- a/include/cmake.mk +++ b/include/cmake.mk @@ -1,5 +1,13 @@ cmake_bool = $(patsubst %,-D%:BOOL=$(if $($(1)),ON,OFF),$(2)) +PKG_USE_NINJA ?= 1 +HOST_USE_NINJA ?= 1 +ifeq ($(PKG_USE_NINJA),1) + PKG_BUILD_PARALLEL ?= 1 +endif +ifeq ($(HOST_USE_NINJA),1) + HOST_BUILD_PARALLEL ?= 1 +endif PKG_INSTALL:=1 ifneq ($(findstring c,$(OPENWRT_VERBOSE)),) @@ -44,6 +52,34 @@ CMAKE_FIND_ROOT_PATH:=$(STAGING_DIR)/usr;$(TOOLCHAIN_DIR)$(if $(CONFIG_EXTERNAL_ CMAKE_HOST_FIND_ROOT_PATH:=$(STAGING_DIR)/host;$(STAGING_DIR_HOSTPKG);$(STAGING_DIR_HOST) CMAKE_SHARED_LDFLAGS:=-Wl,-Bsymbolic-functions +ifeq ($(HOST_USE_NINJA),1) + CMAKE_HOST_OPTIONS += -DCMAKE_GENERATOR="Ninja" + + define Host/Compile/Default + +$(NINJA) -C $(HOST_BUILD_DIR) $(1) + endef + + define Host/Install/Default + +$(NINJA) -C $(HOST_BUILD_DIR) install + endef + + define Host/Uninstall/Default + +$(NINJA) -C $(HOST_BUILD_DIR) uninstall + endef +endif + +ifeq ($(PKG_USE_NINJA),1) + CMAKE_OPTIONS += -DCMAKE_GENERATOR="Ninja" + + define Build/Compile/Default + +$(NINJA) -C $(CMAKE_BINARY_DIR) $(1) + endef + + define Build/Install/Default + +DESTDIR="$(PKG_INSTALL_DIR)" $(NINJA) -C $(CMAKE_BINARY_DIR) install + endef +endif + define Build/Configure/Default mkdir -p $(CMAKE_BINARY_DIR) (cd $(CMAKE_BINARY_DIR); \ diff --git a/include/feeds.mk b/include/feeds.mk index 98e315bceb..e499ac2684 100644 --- a/include/feeds.mk +++ b/include/feeds.mk @@ -43,5 +43,11 @@ endef # 1: package name define GetABISuffix -$(if $(filter-out kmod-%,$(1)),$(if $(ABIV_$(1)),$(ABIV_$(1)),$(foreach v,$(wildcard $(STAGING_DIR)/pkginfo/$(1).version),$(shell cat $(v))))) +$(call FormatABISuffix,$(1),$(if $(ABIV_$(1)),$(ABIV_$(1)),$(foreach v,$(wildcard $(STAGING_DIR)/pkginfo/$(1).version),$(shell cat $(v))))) +endef + +# 1: package name +# 2: abi version +define FormatABISuffix +$(if $(filter-out kmod-%,$(1)),$(if $(2),$(if $(filter %0 %1 %2 %3 %4 %5 %6 %7 %8 %9,$(1)),-)$(2))) endef diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 85178f5195..fb18167cfe 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -7,10 +7,10 @@ ifdef CONFIG_TESTING_KERNEL endif LINUX_VERSION-5.4 = .124 -LINUX_VERSION-5.10 = .42 +LINUX_VERSION-5.10 = .43 LINUX_KERNEL_HASH-5.4.124 = f7f29dda2b042d7b5986d18274413131cf70e17288c05e9a683df1f46c507d82 -LINUX_KERNEL_HASH-5.10.42 = 8ba027c73bd67b8ded2649a741d2f018db630c1cbc081700d8ffd07ab0d906e5 +LINUX_KERNEL_HASH-5.10.43 = 83b81e433ba2f8ee143064fb163699ee857e26dd789006bc1e9edf1ccd0bd403 remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1))))))) diff --git a/include/package-ipkg.mk b/include/package-ipkg.mk index b066e116f7..19f09c2311 100644 --- a/include/package-ipkg.mk +++ b/include/package-ipkg.mk @@ -99,7 +99,7 @@ _endef=endef ifeq ($(DUMP),) define BuildTarget/ipkg - ABIV_$(1):=$(if $(filter-out kmod-%,$(1)),$(ABI_VERSION)) + ABIV_$(1):=$(call FormatABISuffix,$(1),$(ABI_VERSION)) PDIR_$(1):=$(call FeedPackageDir,$(1)) IPKG_$(1):=$$(PDIR_$(1))/$(1)$$(ABIV_$(1))_$(VERSION)_$(PKGARCH).ipk IDIR_$(1):=$(PKG_BUILD_DIR)/ipkg-$(PKGARCH)/$(1) diff --git a/include/prereq-build.mk b/include/prereq-build.mk index 639d1ad0fa..8fbf6f22c4 100644 --- a/include/prereq-build.mk +++ b/include/prereq-build.mk @@ -102,9 +102,9 @@ $(eval $(call SetupHostCommand,patch,Please install GNU 'patch', \ gpatch --version 2>&1 | grep 'Free Software Foundation', \ patch --version 2>&1 | grep 'Free Software Foundation')) -$(eval $(call SetupHostCommand,diff,Please install diffutils, \ - gdiff --version 2>&1 | grep diff, \ - diff --version 2>&1 | grep diff)) +$(eval $(call SetupHostCommand,diff,Please install GNU diffutils, \ + gdiff --version 2>&1 | grep GNU, \ + diff --version 2>&1 | grep GNU)) $(eval $(call SetupHostCommand,cp,Please install GNU fileutils, \ gcp --help 2>&1 | grep 'Copy SOURCE', \ diff --git a/include/u-boot.mk b/include/u-boot.mk index ec9fb15b6c..c0a1e87bf3 100644 --- a/include/u-boot.mk +++ b/include/u-boot.mk @@ -44,7 +44,8 @@ TARGET_DEP = TARGET_$(BUILD_TARGET)$(if $(BUILD_SUBTARGET),_$(BUILD_SUBTARGET)) UBOOT_MAKE_FLAGS = \ HOSTCC="$(HOSTCC)" \ HOSTCFLAGS="$(HOST_CFLAGS) $(HOST_CPPFLAGS) -std=gnu11" \ - HOSTLDFLAGS="$(HOST_LDFLAGS)" + HOSTLDFLAGS="$(HOST_LDFLAGS)" \ + $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') define Build/U-Boot/Target $(eval $(call U-Boot/Init,$(1))) diff --git a/package/base-files/files/lib/upgrade/stage2 b/package/base-files/files/lib/upgrade/stage2 index e2259e3472..b00d0c079a 100755 --- a/package/base-files/files/lib/upgrade/stage2 +++ b/package/base-files/files/lib/upgrade/stage2 @@ -123,15 +123,31 @@ kill_remaining() { # [ [ ] ] indicate_upgrade +while read -r a b c; do + case "$a" in + MemT*) mem="$b" ;; esac +done < /proc/meminfo + +[ "$mem" -gt 32768 ] && \ + skip_services="dnsmasq log network" +for service in /etc/init.d/*; do + service=${service##*/} + + case " $skip_services " in + *" $service "*) continue ;; esac + + ubus call service delete '{ "name": "'"$service"'" }' 2>/dev/null +done + killall -9 telnetd killall -9 dropbear killall -9 ash kill_remaining TERM -sleep 3 +sleep 4 kill_remaining KILL 1 -sleep 1 +sleep 6 echo 3 > /proc/sys/vm/drop_caches diff --git a/package/boot/uboot-rockchip/patches/102-arm64-rk3399-Add-support-NanoPi-R4s.patch b/package/boot/uboot-rockchip/patches/102-arm64-rk3399-Add-support-NanoPi-R4s.patch new file mode 100644 index 0000000000..f926f52efe --- /dev/null +++ b/package/boot/uboot-rockchip/patches/102-arm64-rk3399-Add-support-NanoPi-R4s.patch @@ -0,0 +1,290 @@ +From b69b9f3f54732c303939eb748aad97cd4cf60168 Mon Sep 17 00:00:00 2001 +From: Xiaobo Tian +Date: Sat, 27 Feb 2021 22:39:11 +0800 +Subject: [PATCH] arm64: rk3399: Add support NanoPi R4s + +NanoPi R4s is SBC base on Rockchip RK3399 hexa-core processor with +dual-Core Cortex-A72 and Mali-T864 GPU with 4GiB(LPDDR4) of RAM, SD card support, +including 2 gigabit ethernet(RTL8211E 1Gbps - RTL8111H 1Gbps) and 2 USB 3.0 port. +port.It also has two GPIO headers which allows further peripherals to be used. + +The devicetree file is taken of the rk3399 nanopi4 Linux kernel [1]. + +[1] https://github.com/torvalds/linux/commit/e7a095908227fb3ccc86d001d9e13c9ae2bef8e6 + +Signed-off-by: xiaobo +Reviewed-by: Kever Yang +--- + arch/arm/dts/Makefile | 1 + + arch/arm/dts/rk3399-nanopi-r4s-u-boot.dtsi | 16 +++ + arch/arm/dts/rk3399-nanopi-r4s.dts | 138 +++++++++++++++++++++ + board/rockchip/evb_rk3399/MAINTAINERS | 6 + + configs/nanopi-r4s-rk3399_defconfig | 62 +++++++++ + 5 files changed, 223 insertions(+) + create mode 100644 arch/arm/dts/rk3399-nanopi-r4s-u-boot.dtsi + create mode 100644 arch/arm/dts/rk3399-nanopi-r4s.dts + create mode 100644 configs/nanopi-r4s-rk3399_defconfig + +diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile +index dd4d4efed31..0a139473811 100644 +--- a/arch/arm/dts/Makefile ++++ b/arch/arm/dts/Makefile +@@ -132,6 +132,7 @@ dtb-$(CONFIG_ROCKCHIP_RK3399) += \ + rk3399-nanopi-m4.dtb \ + rk3399-nanopi-m4-2gb.dtb \ + rk3399-nanopi-neo4.dtb \ ++ rk3399-nanopi-r4s.dtb \ + rk3399-orangepi.dtb \ + rk3399-pinebook-pro.dtb \ + rk3399-puma-haikou.dtb \ +diff --git a/arch/arm/dts/rk3399-nanopi-r4s-u-boot.dtsi b/arch/arm/dts/rk3399-nanopi-r4s-u-boot.dtsi +new file mode 100644 +index 00000000000..cd1642527ba +--- /dev/null ++++ b/arch/arm/dts/rk3399-nanopi-r4s-u-boot.dtsi +@@ -0,0 +1,16 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * RK3399-based FriendlyElec boards device tree source ++ * ++ * Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd ++ * ++ * Copyright (c) 2018 FriendlyElec Computer Tech. Co., Ltd. ++ * (http://www.friendlyarm.com) ++ * ++ * Copyright (c) 2018 Collabora Ltd. ++ * Copyright (c) 2019 Arm Ltd. ++ * Copyright (C) 2020 Xiaobo ++ */ ++ ++#include "rk3399-nanopi4-u-boot.dtsi" ++#include "rk3399-sdram-lpddr4-100.dtsi" +diff --git a/arch/arm/dts/rk3399-nanopi-r4s.dts b/arch/arm/dts/rk3399-nanopi-r4s.dts +new file mode 100644 +index 00000000000..6f2cf17bf1b +--- /dev/null ++++ b/arch/arm/dts/rk3399-nanopi-r4s.dts +@@ -0,0 +1,138 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2016 Fuzhou Rockchip Electronics Co., Ltd ++ * ++ * Copyright (c) 2018 FriendlyElec Computer Tech. Co., Ltd. ++ * (http://www.friendlyarm.com) ++ * ++ * Copyright (c) 2018 Collabora Ltd. ++ * Copyright (c) 2019 Arm Ltd. ++ * Copyright (C) 2020 Xiaobo ++ */ ++ ++/dts-v1/; ++#include "rk3399-nanopi4.dtsi" ++ ++/ { ++ model = "FriendlyElec NanoPi R4S"; ++ compatible = "friendlyarm,nanopi-r4s", "rockchip,rk3399"; ++ ++ aliases { ++ ethernet1 = &r8169; ++ }; ++ ++ vdd_5v: vdd-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd_5v"; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ fan: pwm-fan { ++ compatible = "pwm-fan"; ++ cooling-levels = <0 12 18 255>; ++ #cooling-cells = <2>; ++ fan-supply = <&vdd_5v>; ++ pwms = <&pwm1 0 50000 0>; ++ }; ++}; ++ ++&cpu_thermal { ++ trips { ++ cpu_warm: cpu_warm { ++ temperature = <55000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ ++ cpu_hot: cpu_hot { ++ temperature = <65000>; ++ hysteresis = <2000>; ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ map2 { ++ trip = <&cpu_warm>; ++ cooling-device = <&fan THERMAL_NO_LIMIT 1>; ++ }; ++ ++ map3 { ++ trip = <&cpu_hot>; ++ cooling-device = <&fan 2 THERMAL_NO_LIMIT>; ++ }; ++ }; ++}; ++ ++&emmc_phy { ++ status = "disabled"; ++}; ++ ++&fusb0 { ++ status = "disabled"; ++}; ++ ++&leds { ++ lan_led: led-1 { ++ gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>; ++ label = "nanopi-r4s:green:lan"; ++ }; ++ ++ wan_led: led-2 { ++ gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; ++ label = "nanopi-r4s:green:wan"; ++ }; ++}; ++ ++&leds_gpio { ++ rockchip,pins = ++ <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>, ++ <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>, ++ <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; ++}; ++ ++&pcie0 { ++ max-link-speed = <1>; ++ num-lanes = <1>; ++ vpcie3v3-supply = <&vcc3v3_sys>; ++ ++ pcie@0 { ++ reg = <0x00000000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ r8169: pcie@0,0 { ++ reg = <0x000000 0 0 0 0>; ++ local-mac-address = [ 00 00 00 00 00 00 ]; ++ }; ++ }; ++}; ++ ++&sdhci { ++ status = "disabled"; ++}; ++ ++&sdio0 { ++ status = "disabled"; ++}; ++ ++&sdmmc { ++ host-index-min = <1>; ++}; ++ ++&u2phy0_host { ++ phy-supply = <&vdd_5v>; ++}; ++ ++&u2phy1_host { ++ status = "disabled"; ++}; ++ ++&usbdrd_dwc3_0 { ++ dr_mode = "host"; ++}; ++ ++&vcc3v3_sys { ++ vin-supply = <&vcc5v0_sys>; ++}; +diff --git a/board/rockchip/evb_rk3399/MAINTAINERS b/board/rockchip/evb_rk3399/MAINTAINERS +index 4c889e06a63..3b9d60eccd4 100644 +--- a/board/rockchip/evb_rk3399/MAINTAINERS ++++ b/board/rockchip/evb_rk3399/MAINTAINERS +@@ -55,6 +55,12 @@ S: Maintained + F: configs/nanopi-neo4-rk3399_defconfig + F: arch/arm/dts/rk3399-nanopi-neo4-u-boot.dtsi + ++NANOPI-R4S ++M: Xiaobo Tian ++S: Maintained ++F: configs/nanopi-r4s-rk3399_defconfig ++F: arch/arm/dts/rk3399-nanopi-r4s-u-boot.dtsi ++ + ORANGEPI-RK3399 + M: Jagan Teki + S: Maintained +diff --git a/configs/nanopi-r4s-rk3399_defconfig b/configs/nanopi-r4s-rk3399_defconfig +new file mode 100644 +index 00000000000..0a3c28b0126 +--- /dev/null ++++ b/configs/nanopi-r4s-rk3399_defconfig +@@ -0,0 +1,62 @@ ++CONFIG_ARM=y ++CONFIG_ARCH_ROCKCHIP=y ++CONFIG_SYS_TEXT_BASE=0x00200000 ++CONFIG_ENV_OFFSET=0x3F8000 ++CONFIG_ROCKCHIP_RK3399=y ++CONFIG_TARGET_EVB_RK3399=y ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEBUG_UART_BASE=0xFF1A0000 ++CONFIG_DEBUG_UART_CLOCK=24000000 ++CONFIG_DEBUG_UART=y ++CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-nanopi-r4s.dtb" ++CONFIG_DISPLAY_BOARDINFO_LATE=y ++# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set ++CONFIG_SPL_STACK_R=y ++CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x10000 ++CONFIG_TPL=y ++CONFIG_CMD_BOOTZ=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_USB=y ++# CONFIG_CMD_SETEXPR is not set ++CONFIG_CMD_TIME=y ++CONFIG_SPL_OF_CONTROL=y ++CONFIG_DEFAULT_DEVICE_TREE="rk3399-nanopi-r4s" ++CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents" ++CONFIG_ENV_IS_IN_MMC=y ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++CONFIG_ROCKCHIP_GPIO=y ++CONFIG_SYS_I2C_ROCKCHIP=y ++CONFIG_MMC_DW=y ++CONFIG_MMC_DW_ROCKCHIP=y ++CONFIG_MMC_SDHCI=y ++CONFIG_MMC_SDHCI_ROCKCHIP=y ++CONFIG_DM_ETH=y ++CONFIG_ETH_DESIGNWARE=y ++CONFIG_GMAC_ROCKCHIP=y ++CONFIG_PMIC_RK8XX=y ++CONFIG_REGULATOR_PWM=y ++CONFIG_REGULATOR_RK8XX=y ++CONFIG_PWM_ROCKCHIP=y ++CONFIG_RAM_RK3399_LPDDR4=y ++CONFIG_BAUDRATE=1500000 ++CONFIG_DEBUG_UART_SHIFT=2 ++CONFIG_SYSRESET=y ++CONFIG_USB=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_DWC3=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_GENERIC=y ++CONFIG_USB_KEYBOARD=y ++CONFIG_USB_HOST_ETHER=y ++CONFIG_USB_ETHER_ASIX=y ++CONFIG_USB_ETHER_ASIX88179=y ++CONFIG_USB_ETHER_MCS7830=y ++CONFIG_USB_ETHER_RTL8152=y ++CONFIG_USB_ETHER_SMSC95XX=y ++CONFIG_DM_VIDEO=y ++CONFIG_DISPLAY=y ++CONFIG_VIDEO_ROCKCHIP=y ++CONFIG_DISPLAY_ROCKCHIP_HDMI=y ++CONFIG_SPL_TINY_MEMSET=y ++CONFIG_ERRNO_STR=y diff --git a/package/kernel/mac80211/patches/subsys/374-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch b/package/kernel/mac80211/patches/subsys/374-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch new file mode 100644 index 0000000000..49b1212213 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/374-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch @@ -0,0 +1,114 @@ +From: Ryder Lee +Date: Fri, 28 May 2021 14:05:41 +0800 +Subject: [PATCH] mac80211: call ieee80211_tx_h_rate_ctrl() when dequeue + +Make ieee80211_tx_h_rate_ctrl() get called on dequeue to improve +performance since it reduces the turnaround time for rate control. + +Signed-off-by: Ryder Lee +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1780,8 +1780,6 @@ static int invoke_tx_handlers_early(stru + CALL_TXH(ieee80211_tx_h_ps_buf); + CALL_TXH(ieee80211_tx_h_check_control_port_protocol); + CALL_TXH(ieee80211_tx_h_select_key); +- if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) +- CALL_TXH(ieee80211_tx_h_rate_ctrl); + + txh_done: + if (unlikely(res == TX_DROP)) { +@@ -1814,6 +1812,9 @@ static int invoke_tx_handlers_late(struc + goto txh_done; + } + ++ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) ++ CALL_TXH(ieee80211_tx_h_rate_ctrl); ++ + CALL_TXH(ieee80211_tx_h_michael_mic_add); + CALL_TXH(ieee80211_tx_h_sequence); + CALL_TXH(ieee80211_tx_h_fragment); +@@ -3384,15 +3385,21 @@ out: + * Can be called while the sta lock is held. Anything that can cause packets to + * be generated will cause deadlock! + */ +-static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, +- struct sta_info *sta, u8 pn_offs, +- struct ieee80211_key *key, +- struct sk_buff *skb) ++static ieee80211_tx_result ++ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, ++ struct sta_info *sta, u8 pn_offs, ++ struct ieee80211_key *key, ++ struct ieee80211_tx_data *tx) + { ++ struct sk_buff *skb = tx->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (void *)skb->data; + u8 tid = IEEE80211_NUM_TIDS; + ++ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL) && ++ ieee80211_tx_h_rate_ctrl(tx) != TX_CONTINUE) ++ return TX_DROP; ++ + if (key) + info->control.hw_key = &key->conf; + +@@ -3441,6 +3448,8 @@ static void ieee80211_xmit_fast_finish(s + break; + } + } ++ ++ return TX_CONTINUE; + } + + static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, +@@ -3544,24 +3553,17 @@ static bool ieee80211_xmit_fast(struct i + tx.sta = sta; + tx.key = fast_tx->key; + +- if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) { +- tx.skb = skb; +- r = ieee80211_tx_h_rate_ctrl(&tx); +- skb = tx.skb; +- tx.skb = NULL; +- +- if (r != TX_CONTINUE) { +- if (r != TX_QUEUED) +- kfree_skb(skb); +- return true; +- } +- } +- + if (ieee80211_queue_skb(local, sdata, sta, skb)) + return true; + +- ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, +- fast_tx->key, skb); ++ tx.skb = skb; ++ r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, ++ fast_tx->key, &tx); ++ tx.skb = NULL; ++ if (r == TX_DROP) { ++ kfree_skb(skb); ++ return true; ++ } + + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(sdata->bss, +@@ -3672,8 +3674,12 @@ begin: + (tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) + pn_offs = ieee80211_hdrlen(hdr->frame_control); + +- ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, +- tx.key, skb); ++ r = ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, ++ tx.key, &tx); ++ if (r != TX_CONTINUE) { ++ ieee80211_free_txskb(&local->hw, skb); ++ goto begin; ++ } + } else { + if (invoke_tx_handlers_late(&tx)) + goto begin; diff --git a/package/kernel/mac80211/patches/subsys/375-mac80211-minstrel_ht-fix-minstrel_aggr_check-for-enc.patch b/package/kernel/mac80211/patches/subsys/375-mac80211-minstrel_ht-fix-minstrel_aggr_check-for-enc.patch new file mode 100644 index 0000000000..2fe19dfd94 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/375-mac80211-minstrel_ht-fix-minstrel_aggr_check-for-enc.patch @@ -0,0 +1,39 @@ +From: Ryder Lee +Date: Fri, 28 May 2021 14:05:42 +0800 +Subject: [PATCH] mac80211: minstrel_ht: fix minstrel_aggr_check for encap + offload + +Avoid checking ieee80211_hdr to support encap offload. + +Signed-off-by: Ryder Lee +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -1156,19 +1156,24 @@ static void + minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) + { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + u16 tid; + + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + +- if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) ++ if (unlikely(!pubsta->wme)) ++ return; ++ ++ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && ++ unlikely(!ieee80211_is_data_qos(hdr->frame_control))) + return; + + if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) + return; + +- tid = ieee80211_get_tid(hdr); ++ tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + if (likely(sta->ampdu_mlme.tid_tx[tid])) + return; + diff --git a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch b/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch new file mode 100644 index 0000000000..eefeaa4a8d --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch @@ -0,0 +1,119 @@ +From: Ryder Lee +Date: Fri, 28 May 2021 14:05:43 +0800 +Subject: [PATCH] mac80211: add rate control support for encap offload + +The software rate control cannot deal with encap offload, so fix it. + +Signed-off-by: Ryder Lee +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2024,6 +2024,15 @@ static inline void ieee80211_tx_skb(stru + ieee80211_tx_skb_tid(sdata, skb, 7); + } + ++static inline bool ieee80211_is_tx_data(struct sk_buff *skb) ++{ ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ ++ return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP || ++ ieee80211_is_data(hdr->frame_control); ++} ++ + u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, + struct ieee802_11_elems *elems, + u64 filter, u32 crc, u8 *transmitter_bssid, +--- a/net/mac80211/rate.c ++++ b/net/mac80211/rate.c +@@ -297,15 +297,11 @@ void ieee80211_check_rate_mask(struct ie + static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc) + { + struct sk_buff *skb = txrc->skb; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +- __le16 fc; +- +- fc = hdr->frame_control; + + return (info->flags & (IEEE80211_TX_CTL_NO_ACK | + IEEE80211_TX_CTL_USE_MINRATE)) || +- !ieee80211_is_data(fc); ++ !ieee80211_is_tx_data(skb); + } + + static void rc_send_low_basicrate(struct ieee80211_tx_rate *rate, +@@ -870,7 +866,6 @@ void ieee80211_get_tx_rates(struct ieee8 + int max_rates) + { + struct ieee80211_sub_if_data *sdata; +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_supported_band *sband; + +@@ -882,7 +877,7 @@ void ieee80211_get_tx_rates(struct ieee8 + sdata = vif_to_sdata(vif); + sband = sdata->local->hw.wiphy->bands[info->band]; + +- if (ieee80211_is_data(hdr->frame_control)) ++ if (ieee80211_is_tx_data(skb)) + rate_control_apply_mask(sdata, sta, sband, dest, max_rates); + + if (dest[0].idx < 0) +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -679,6 +679,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 + u32 len; + struct ieee80211_tx_rate_control txrc; + struct ieee80211_sta_rates *ratetbl = NULL; ++ bool encap = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + bool assoc = false; + + memset(&txrc, 0, sizeof(txrc)); +@@ -720,7 +721,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 + * just wants a probe response. + */ + if (tx->sdata->vif.bss_conf.use_short_preamble && +- (ieee80211_is_data(hdr->frame_control) || ++ (ieee80211_is_tx_data(tx->skb) || + (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) + txrc.short_preamble = true; + +@@ -742,7 +743,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 + "%s: Dropped data frame as no usable bitrate found while " + "scanning and associated. Target station: " + "%pM on %d GHz band\n", +- tx->sdata->name, hdr->addr1, ++ tx->sdata->name, ++ encap ? ((struct ethhdr *)hdr)->h_dest : hdr->addr1, + info->band ? 5 : 2)) + return TX_DROP; + +@@ -776,7 +778,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 + + if (txrc.reported_rate.idx < 0) { + txrc.reported_rate = tx->rate; +- if (tx->sta && ieee80211_is_data(hdr->frame_control)) ++ if (tx->sta && ieee80211_is_tx_data(tx->skb)) + tx->sta->tx_stats.last_rate = txrc.reported_rate; + } else if (tx->sta) + tx->sta->tx_stats.last_rate = txrc.reported_rate; +@@ -3662,8 +3664,16 @@ begin: + else + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + +- if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) ++ if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { ++ if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) { ++ r = ieee80211_tx_h_rate_ctrl(&tx); ++ if (r != TX_CONTINUE) { ++ ieee80211_free_txskb(&local->hw, skb); ++ goto begin; ++ } ++ } + goto encap_out; ++ } + + if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { + struct sta_info *sta = container_of(txq->sta, struct sta_info, diff --git a/package/kernel/mt76/Makefile b/package/kernel/mt76/Makefile index e4051d8347..74d5950545 100644 --- a/package/kernel/mt76/Makefile +++ b/package/kernel/mt76/Makefile @@ -13,6 +13,7 @@ PKG_SOURCE_VERSION:=22b690334c0f49b11534cc2e331c9d5e17c4a0bc PKG_MIRROR_HASH:=ff5e563935919d2e40c1e7254ef3bc06f7ecc5e69f8ddd12903e8f5de942d630 PKG_MAINTAINER:=Felix Fietkau +PKG_USE_NINJA:=0 PKG_BUILD_PARALLEL:=1 PKG_CONFIG_DEPENDS += \ diff --git a/package/libs/libjson-c/Makefile b/package/libs/libjson-c/Makefile index 13cf955960..0ea3fe80b5 100644 --- a/package/libs/libjson-c/Makefile +++ b/package/libs/libjson-c/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=json-c PKG_VERSION:=0.15 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-nodoc.tar.gz PKG_SOURCE_URL:=https://s3.amazonaws.com/json-c_releases/releases/ @@ -20,6 +20,7 @@ PKG_LICENSE:=MIT PKG_LICENSE_FILES:=COPYING PKG_CPE_ID:=cpe:/a:json-c_project:json-c +PKG_FLAGS := nonshared PKG_BUILD_PARALLEL:=1 HOST_BUILD_PREFIX:=$(STAGING_DIR_HOST) diff --git a/package/libs/libnl-tiny/Makefile b/package/libs/libnl-tiny/Makefile index b2eafe259a..ff3da5b518 100644 --- a/package/libs/libnl-tiny/Makefile +++ b/package/libs/libnl-tiny/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libnl-tiny -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/libnl-tiny.git @@ -17,6 +17,8 @@ PKG_SOURCE_VERSION:=c291088f631d1694f7ba0444b59677b194348da8 PKG_MIRROR_HASH:=99bcce12701bb34dadb39689d95c2c5cf1e27719d0ecfd645d3957a8947025ac CMAKE_INSTALL:=1 +PKG_FLAGS := nonshared + PKG_LICENSE:=LGPL-2.1 PKG_MAINTAINER:=Felix Fietkau diff --git a/package/libs/libubox/Makefile b/package/libs/libubox/Makefile index ac4effb6f8..cc5d7f7ae6 100644 --- a/package/libs/libubox/Makefile +++ b/package/libs/libubox/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libubox -PKG_RELEASE=1 +PKG_RELEASE=2 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/libubox.git @@ -11,6 +11,8 @@ PKG_SOURCE_VERSION:=b14c4688612c05c78ce984d7bde633bce8703b1e PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE)) CMAKE_INSTALL:=1 +PKG_FLAGS := nonshared + PKG_LICENSE:=ISC PKG_LICENSE_FILES:= @@ -67,7 +69,7 @@ define Package/libubox-lua endef TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include -CMAKE_OPTIONS = \ +CMAKE_OPTIONS += \ -DLUAPATH=/usr/lib/lua \ -DABIVERSION="$(PKG_ABI_VERSION)" diff --git a/package/network/services/odhcpd/Makefile b/package/network/services/odhcpd/Makefile index 9ecae8a919..d9a320d17a 100644 --- a/package/network/services/odhcpd/Makefile +++ b/package/network/services/odhcpd/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/odhcpd.git -PKG_SOURCE_DATE:=2021-05-15 -PKG_SOURCE_VERSION:=a12fcb3cee2d489b8648a2398812d7bed2f25faa -PKG_MIRROR_HASH:=26a0dd58e29509471bd2be181a59fa1d75541426137d6ca87c98806199751efb +PKG_SOURCE_DATE:=2021-06-19 +PKG_SOURCE_VERSION:=564d25e53fad925fa3ed56e3004c107d40925fa4 +PKG_MIRROR_HASH:=a0644d31f99f20e5c2cee74153b81a0c2eae9ebeb644662cc76b0984b44dd490 PKG_MAINTAINER:=Hans Dedecker PKG_LICENSE:=GPL-2.0 diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile index 87b3690515..8f58271127 100644 --- a/package/network/services/uhttpd/Makefile +++ b/package/network/services/uhttpd/Makefile @@ -85,7 +85,7 @@ endif TARGET_LDFLAGS += -lcrypt -CMAKE_OPTIONS = -DTLS_SUPPORT=on +CMAKE_OPTIONS += -DTLS_SUPPORT=on define Package/uhttpd/install $(INSTALL_DIR) $(1)/etc/init.d diff --git a/package/system/opkg/Makefile b/package/system/opkg/Makefile index 99234978a1..65bdf6dba9 100644 --- a/package/system/opkg/Makefile +++ b/package/system/opkg/Makefile @@ -11,10 +11,10 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_FLAGS:=essential PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=$(PROJECT_GIT)/project/opkg-lede.git -PKG_SOURCE_DATE:=2021-03-15 -PKG_SOURCE_VERSION:=5936c4f9660248284e8a9b040ea3153d3ea888de -PKG_MIRROR_HASH:=b873c209baaf4f150c89646d58e4a0072f807d24b02c320ab8c7ae9180c13240 +PKG_SOURCE_URL=$(PROJECT_GIT)/project/opkg-lede.git +PKG_SOURCE_DATE:=2021-06-13 +PKG_SOURCE_VERSION:=1bf042dd06751b693a8544d2317e5b969d666b69 +PKG_MIRROR_HASH:=aeda4e0f11805bf95fc7be6d38391ce579acd965c8ba6a490b3e8669815b7264 PKG_LICENSE:=GPL-2.0 PKG_LICENSE_FILES:=COPYING diff --git a/package/system/ubus/Makefile b/package/system/ubus/Makefile index 885307107b..9b29bf0e01 100644 --- a/package/system/ubus/Makefile +++ b/package/system/ubus/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ubus -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/ubus.git @@ -15,6 +15,7 @@ PKG_LICENSE:=LGPL-2.1 PKG_LICENSE_FILES:= PKG_MAINTAINER:=Felix Fietkau +PKG_FLAGS := nonshared PKG_ASLR_PIE_REGULAR:=1 include $(INCLUDE_DIR)/package.mk @@ -53,7 +54,7 @@ endef TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include -flto TARGET_LDFLAGS += -flto -CMAKE_OPTIONS = \ +CMAKE_OPTIONS += \ -DLUAPATH=/usr/lib/lua \ -DABIVERSION="$(PKG_ABI_VERSION)" diff --git a/package/system/uci/Makefile b/package/system/uci/Makefile index 3c1e168717..3d9fdf7391 100644 --- a/package/system/uci/Makefile +++ b/package/system/uci/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=uci -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_SOURCE_URL=$(PROJECT_GIT)/project/uci.git PKG_SOURCE_PROTO:=git @@ -23,6 +23,7 @@ PKG_LICENSE_FILES:= PKG_MAINTAINER:=Felix Fietkau PKG_BUILD_PARALLEL:=0 +PKG_FLAGS := nonshared include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/cmake.mk @@ -55,7 +56,7 @@ endef TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include TARGET_LDFLAGS += -L$(STAGING_DIR)/usr/lib -CMAKE_OPTIONS = \ +CMAKE_OPTIONS += \ -DLUAPATH=/usr/lib/lua \ $(if $(DEBUG),-DUCI_DEBUG=ON) diff --git a/package/utils/lua/Makefile b/package/utils/lua/Makefile index a54ef7d25a..83b83e4856 100644 --- a/package/utils/lua/Makefile +++ b/package/utils/lua/Makefile @@ -9,13 +9,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=lua PKG_VERSION:=5.1.5 -PKG_RELEASE:=8 +PKG_RELEASE:=9 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=http://www.lua.org/ftp/ \ http://www.tecgraf.puc-rio.br/lua/ftp/ PKG_HASH:=2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333 PKG_BUILD_PARALLEL:=1 +PKG_FLAGS := nonshared PKG_LICENSE:=MIT PKG_LICENSE_FILES:=COPYRIGHT diff --git a/rules.mk b/rules.mk index 51f822e3f1..8b24d3a3bb 100644 --- a/rules.mk +++ b/rules.mk @@ -342,6 +342,12 @@ else $(SCRIPT_DIR)/rstrip.sh endif +NINJA = \ + MAKEFLAGS="$(MAKE_JOBSERVER)" \ + $(STAGING_DIR_HOST)/bin/ninja \ + $(if $(findstring c,$(OPENWRT_VERBOSE)),-v) \ + $(if $(MAKE_JOBSERVER),,-j1) + ifeq ($(CONFIG_IPV6),y) DISABLE_IPV6:= else diff --git a/target/linux/apm821xx/config-5.10 b/target/linux/apm821xx/config-5.10 index c9c720de29..b729bee903 100644 --- a/target/linux/apm821xx/config-5.10 +++ b/target/linux/apm821xx/config-5.10 @@ -250,6 +250,7 @@ CONFIG_PTE_64BIT=y # CONFIG_RAINIER is not set CONFIG_RAS=y CONFIG_RATIONAL=y +CONFIG_REGULATOR=y CONFIG_RSEQ=y # CONFIG_SAM440EP is not set # CONFIG_SCOM_DEBUGFS is not set diff --git a/target/linux/apm821xx/config-5.4 b/target/linux/apm821xx/config-5.4 index 2b9594c3d4..e47186a444 100644 --- a/target/linux/apm821xx/config-5.4 +++ b/target/linux/apm821xx/config-5.4 @@ -304,6 +304,7 @@ CONFIG_PPC_WERROR=y CONFIG_PTE_64BIT=y # CONFIG_RAINIER is not set CONFIG_RAS=y +CONFIG_REGULATOR=y CONFIG_RSEQ=y # CONFIG_SAM440EP is not set # CONFIG_SCOM_DEBUGFS is not set diff --git a/target/linux/apm821xx/sata/config-default b/target/linux/apm821xx/sata/config-default index db2c5c8a30..c3f41c785b 100644 --- a/target/linux/apm821xx/sata/config-default +++ b/target/linux/apm821xx/sata/config-default @@ -40,5 +40,4 @@ CONFIG_PPC_EARLY_DEBUG_44x=y # CONFIG_PPC_EARLY_DEBUG_MEMCONS is not set CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x4 CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0xef600300 -CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y diff --git a/target/linux/at91/sama5/config-default b/target/linux/at91/sama5/config-default index 4e4c857c1f..10d7d4d3b0 100644 --- a/target/linux/at91/sama5/config-default +++ b/target/linux/at91/sama5/config-default @@ -172,7 +172,6 @@ CONFIG_DRM_PANEL=y CONFIG_DRM_PANEL_BRIDGE=y CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y CONFIG_DRM_PANEL_SIMPLE=y -# CONFIG_DRM_TVE200 is not set CONFIG_DTC=y CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y diff --git a/target/linux/ath79/dts/qca9533_tplink_tl-wr841hp-v3.dts b/target/linux/ath79/dts/qca9533_tplink_tl-wr841hp-v3.dts new file mode 100644 index 0000000000..7170601f6a --- /dev/null +++ b/target/linux/ath79/dts/qca9533_tplink_tl-wr841hp-v3.dts @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qca953x.dtsi" + +#include +#include + +/ { + compatible = "tplink,tl-wr841hp-v3", "qca,qca9533"; + model = "TP-Link TL-WR841HP v3"; + + aliases { + label-mac-device = &wmac; + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; + }; + + leds { + compatible = "gpio-leds"; + + wifi { + label = "green:wifi"; + gpios = <&gpio 15 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy0tpt"; + }; + + led_power: power { + label = "green:power"; + gpios = <&gpio 16 GPIO_ACTIVE_LOW>; + default-state = "on"; + }; + + wan_green { + label = "green:wan"; + gpios = <&gpio 12 GPIO_ACTIVE_LOW>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + }; + + lan { + label = "green:lan"; + gpios = <&gpio 14 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "green:wps"; + gpios = <&gpio 4 GPIO_ACTIVE_LOW>; + }; + + re { + label = "green:re"; + gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "Reset button"; + linux,code = ; + gpios = <&gpio 1 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + + wifi { + label = "WiFi button"; + linux,code = ; + gpios = <&gpio 0 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + + wps { + label = "WPS button"; + linux,code = ; + gpios = <&gpio 2 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + + re { + label = "RE button"; + linux,code = ; + gpios = <&gpio 17 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + }; +}; + +&spi { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <25000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + uboot: partition@0 { + label = "u-boot"; + reg = <0x000000 0x020000>; + read-only; + }; + + partition@20000 { + compatible = "tplink,firmware"; + label = "firmware"; + reg = <0x020000 0x7d0000>; + }; + + art: partition@7f0000 { + label = "art"; + reg = <0x7f0000 0x010000>; + read-only; + }; + }; + }; +}; + +ð0 { + status = "okay"; + + phy-handle = <&swphy4>; + + mtd-mac-address = <&uboot 0x1fc00>; + mtd-mac-address-increment = <1>; +}; + +ð1 { + mtd-mac-address = <&uboot 0x1fc00>; +}; + +&wmac { + status = "okay"; + + mtd-cal-data = <&art 0x1000>; + mtd-mac-address = <&uboot 0x1fc00>; +}; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/01_leds b/target/linux/ath79/generic/base-files/etc/board.d/01_leds index a7459db378..44c06668e1 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/01_leds +++ b/target/linux/ath79/generic/base-files/etc/board.d/01_leds @@ -71,7 +71,8 @@ tplink,archer-c59-v1|\ tplink,archer-c59-v2|\ tplink,archer-c60-v1|\ tplink,archer-c60-v2|\ -tplink,archer-c60-v3) +tplink,archer-c60-v3|\ +tplink,tl-wr841hp-v3) ucidef_set_led_switch "lan" "LAN" "green:lan" "switch0" "0x1e" ucidef_set_led_netdev "wan" "WAN" "green:wan" "eth1" ;; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index 43a853053a..b97bdaa1d6 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -195,7 +195,8 @@ ath79_setup_interfaces() ;; comfast,cf-e560ac|\ qca,ap143-8m|\ - qca,ap143-16m) + qca,ap143-16m|\ + tplink,tl-wr841hp-v3) ucidef_set_interface_wan "eth1" ucidef_add_switch "switch0" \ "0@eth0" "1:lan" "2:lan" "3:lan" "4:lan" diff --git a/target/linux/ath79/image/generic-tp-link.mk b/target/linux/ath79/image/generic-tp-link.mk index be6aa06b55..8b228a73d2 100644 --- a/target/linux/ath79/image/generic-tp-link.mk +++ b/target/linux/ath79/image/generic-tp-link.mk @@ -742,6 +742,15 @@ define Device/tplink_tl-wr810n-v2 endef TARGET_DEVICES += tplink_tl-wr810n-v2 +define Device/tplink_tl-wr841hp-v3 + $(Device/tplink-8mlzma) + SOC := qca9533 + DEVICE_MODEL := TL-WR841HP + DEVICE_VARIANT := v3 + TPLINK_HWID := 0x08411003 +endef +TARGET_DEVICES += tplink_tl-wr841hp-v3 + define Device/tplink_tl-wr842n-v1 $(Device/tplink-8m) SOC := ar7241 diff --git a/target/linux/ath79/patches-5.10/425-at803x-allow-sgmii-aneg-override.patch b/target/linux/ath79/patches-5.10/425-at803x-allow-sgmii-aneg-override.patch index b42102a966..db3427683f 100644 --- a/target/linux/ath79/patches-5.10/425-at803x-allow-sgmii-aneg-override.patch +++ b/target/linux/ath79/patches-5.10/425-at803x-allow-sgmii-aneg-override.patch @@ -1,6 +1,6 @@ --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c -@@ -698,6 +698,13 @@ static int at803x_aneg_done(struct phy_d +@@ -733,6 +733,13 @@ static int at803x_aneg_done(struct phy_d if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) { phydev_warn(phydev, "803x_aneg_done: SGMII link is not ok\n"); aneg_done = 0; diff --git a/target/linux/generic/backport-5.10/610-v5.13-02-netfilter-Fix-fall-through-warnings-for-Clang.patch b/target/linux/generic/backport-5.10/610-v5.13-02-netfilter-Fix-fall-through-warnings-for-Clang.patch index 04e3945d2f..52d04b051f 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-02-netfilter-Fix-fall-through-warnings-for-Clang.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-02-netfilter-Fix-fall-through-warnings-for-Clang.patch @@ -24,7 +24,7 @@ Signed-off-by: Pablo Neira Ayuso case CT_DCCP_INVALID: --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c -@@ -8367,6 +8367,7 @@ static int nf_tables_check_loops(const s +@@ -8369,6 +8369,7 @@ static int nf_tables_check_loops(const s data->verdict.chain); if (err < 0) return err; diff --git a/target/linux/generic/backport-5.10/610-v5.13-10-netfilter-nftables-update-table-flags-from-the-commi.patch b/target/linux/generic/backport-5.10/610-v5.13-10-netfilter-nftables-update-table-flags-from-the-commi.patch index eb6c31aa0f..ccfdb9384d 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-10-netfilter-nftables-update-table-flags-from-the-commi.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-10-netfilter-nftables-update-table-flags-from-the-commi.patch @@ -70,7 +70,7 @@ Signed-off-by: Pablo Neira Ayuso nft_trans_table_update(trans) = true; list_add_tail(&trans->list, &ctx->net->nft.commit_list); return 0; -@@ -7876,11 +7880,10 @@ static int nf_tables_commit(struct net * +@@ -7878,11 +7882,10 @@ static int nf_tables_commit(struct net * switch (trans->msg_type) { case NFT_MSG_NEWTABLE: if (nft_trans_table_update(trans)) { @@ -86,7 +86,7 @@ Signed-off-by: Pablo Neira Ayuso } else { nft_clear(net, trans->ctx.table); } -@@ -8093,11 +8096,9 @@ static int __nf_tables_abort(struct net +@@ -8095,11 +8098,9 @@ static int __nf_tables_abort(struct net switch (trans->msg_type) { case NFT_MSG_NEWTABLE: if (nft_trans_table_update(trans)) { diff --git a/target/linux/generic/backport-5.4/790-net-phy-at803x-select-correct-page-on-config-init.patch b/target/linux/generic/backport-5.4/790-net-phy-at803x-select-correct-page-on-config-init.patch index c6811736f8..b7e3201fb7 100644 --- a/target/linux/generic/backport-5.4/790-net-phy-at803x-select-correct-page-on-config-init.patch +++ b/target/linux/generic/backport-5.4/790-net-phy-at803x-select-correct-page-on-config-init.patch @@ -71,7 +71,7 @@ Signed-off-by: David S. Miller { struct device *dev = &phydev->mdio.dev; struct at803x_priv *priv; -+ int ret; ++ int ret = 0; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) diff --git a/target/linux/generic/config-5.10 b/target/linux/generic/config-5.10 index 7eb5a61ea3..42f1a2f252 100644 --- a/target/linux/generic/config-5.10 +++ b/target/linux/generic/config-5.10 @@ -1507,6 +1507,7 @@ CONFIG_DQL=y # CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set # CONFIG_DRM_PANEL_TPO_TPG110 is not set # CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set +# CONFIG_DRM_PANEL_VISIONOX_RM69299 is not set # CONFIG_DRM_PANFROST is not set # CONFIG_DRM_PARADE_PS8622 is not set # CONFIG_DRM_PARADE_PS8640 is not set @@ -1535,6 +1536,7 @@ CONFIG_DQL=y # CONFIG_DRM_TOSHIBA_TC358767 is not set # CONFIG_DRM_TOSHIBA_TC358768 is not set # CONFIG_DRM_TOSHIBA_TC358775 is not set +# CONFIG_DRM_TVE200 is not set # CONFIG_DRM_UDL is not set # CONFIG_DRM_VBOXVIDEO is not set # CONFIG_DRM_VC4_HDMI_CEC is not set diff --git a/target/linux/generic/config-5.4 b/target/linux/generic/config-5.4 index c532eafc1c..c60707447b 100644 --- a/target/linux/generic/config-5.4 +++ b/target/linux/generic/config-5.4 @@ -1423,6 +1423,7 @@ CONFIG_DQL=y # CONFIG_DRM_TI_TFP410 is not set # CONFIG_DRM_TOSHIBA_TC358764 is not set # CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_TVE200 is not set # CONFIG_DRM_UDL is not set # CONFIG_DRM_VBOXVIDEO is not set # CONFIG_DRM_VC4_HDMI_CEC is not set diff --git a/target/linux/generic/hack-5.10/901-debloat_sock_diag.patch b/target/linux/generic/hack-5.10/901-debloat_sock_diag.patch index fc2a0a4862..88895b4572 100644 --- a/target/linux/generic/hack-5.10/901-debloat_sock_diag.patch +++ b/target/linux/generic/hack-5.10/901-debloat_sock_diag.patch @@ -77,7 +77,7 @@ Signed-off-by: Felix Fietkau struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) { struct dst_entry *dst = __sk_dst_get(sk); -@@ -1808,9 +1822,11 @@ static void __sk_free(struct sock *sk) +@@ -1816,9 +1830,11 @@ static void __sk_free(struct sock *sk) if (likely(sk->sk_net_refcnt)) sock_inuse_add(sock_net(sk), -1); diff --git a/target/linux/generic/hack-5.10/902-debloat_proc.patch b/target/linux/generic/hack-5.10/902-debloat_proc.patch index 31ed45b19e..6f7a1876cd 100644 --- a/target/linux/generic/hack-5.10/902-debloat_proc.patch +++ b/target/linux/generic/hack-5.10/902-debloat_proc.patch @@ -330,7 +330,7 @@ Signed-off-by: Felix Fietkau --- a/net/core/sock.c +++ b/net/core/sock.c -@@ -3674,6 +3674,8 @@ static __net_initdata struct pernet_oper +@@ -3682,6 +3682,8 @@ static __net_initdata struct pernet_oper static int __init proto_init(void) { diff --git a/target/linux/generic/pending-5.10/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/pending-5.10/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch index b6f492fcb5..6fe3b327c5 100644 --- a/target/linux/generic/pending-5.10/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch +++ b/target/linux/generic/pending-5.10/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -157,7 +157,7 @@ Signed-off-by: Jonas Gorski case RTN_THROW: case RTN_UNREACHABLE: default: -@@ -4414,6 +4433,17 @@ static int ip6_pkt_prohibit_out(struct n +@@ -4418,6 +4437,17 @@ static int ip6_pkt_prohibit_out(struct n return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); } @@ -175,7 +175,7 @@ Signed-off-by: Jonas Gorski /* * Allocate a dst for local (unicast / anycast) address. */ -@@ -4894,7 +4924,8 @@ static int rtm_to_fib6_config(struct sk_ +@@ -4898,7 +4928,8 @@ static int rtm_to_fib6_config(struct sk_ if (rtm->rtm_type == RTN_UNREACHABLE || rtm->rtm_type == RTN_BLACKHOLE || rtm->rtm_type == RTN_PROHIBIT || @@ -185,7 +185,7 @@ Signed-off-by: Jonas Gorski cfg->fc_flags |= RTF_REJECT; if (rtm->rtm_type == RTN_LOCAL) -@@ -6064,6 +6095,8 @@ static int ip6_route_dev_notify(struct n +@@ -6068,6 +6099,8 @@ static int ip6_route_dev_notify(struct n #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.ip6_prohibit_entry->dst.dev = dev; net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); @@ -194,7 +194,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_blk_hole_entry->dst.dev = dev; net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); #endif -@@ -6075,6 +6108,7 @@ static int ip6_route_dev_notify(struct n +@@ -6079,6 +6112,7 @@ static int ip6_route_dev_notify(struct n in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); @@ -202,7 +202,7 @@ Signed-off-by: Jonas Gorski in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev); #endif } -@@ -6266,6 +6300,8 @@ static int __net_init ip6_route_net_init +@@ -6270,6 +6304,8 @@ static int __net_init ip6_route_net_init #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.fib6_has_custom_rules = false; @@ -211,7 +211,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, sizeof(*net->ipv6.ip6_prohibit_entry), GFP_KERNEL); -@@ -6276,11 +6312,21 @@ static int __net_init ip6_route_net_init +@@ -6280,11 +6316,21 @@ static int __net_init ip6_route_net_init ip6_template_metrics, true); INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->rt6i_uncached); @@ -234,7 +234,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, ip6_template_metrics, true); -@@ -6307,6 +6353,8 @@ out: +@@ -6311,6 +6357,8 @@ out: return ret; #ifdef CONFIG_IPV6_MULTIPLE_TABLES @@ -243,7 +243,7 @@ Signed-off-by: Jonas Gorski out_ip6_prohibit_entry: kfree(net->ipv6.ip6_prohibit_entry); out_ip6_null_entry: -@@ -6326,6 +6374,7 @@ static void __net_exit ip6_route_net_exi +@@ -6330,6 +6378,7 @@ static void __net_exit ip6_route_net_exi kfree(net->ipv6.ip6_null_entry); #ifdef CONFIG_IPV6_MULTIPLE_TABLES kfree(net->ipv6.ip6_prohibit_entry); @@ -251,7 +251,7 @@ Signed-off-by: Jonas Gorski kfree(net->ipv6.ip6_blk_hole_entry); #endif dst_entries_destroy(&net->ipv6.ip6_dst_ops); -@@ -6403,6 +6452,9 @@ void __init ip6_route_init_special_entri +@@ -6407,6 +6456,9 @@ void __init ip6_route_init_special_entri init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); diff --git a/target/linux/omap/config-5.4 b/target/linux/omap/config-5.4 index 742fdd213e..f202758c69 100644 --- a/target/linux/omap/config-5.4 +++ b/target/linux/omap/config-5.4 @@ -228,7 +228,6 @@ CONFIG_DRM_PANEL_SONY_ACX565AKM=y CONFIG_DRM_PANEL_TPO_TD028TTEC1=y CONFIG_DRM_PANEL_TPO_TD043MTEA1=y CONFIG_DRM_TI_TFP410=y -# CONFIG_DRM_TVE200 is not set CONFIG_DTC=y CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y diff --git a/target/linux/ramips/dts/mt7621_tplink_archer-a6-v3.dts b/target/linux/ramips/dts/mt7621_tplink_archer-a6-v3.dts index 46cb365da7..01fea5bde5 100644 --- a/target/linux/ramips/dts/mt7621_tplink_archer-a6-v3.dts +++ b/target/linux/ramips/dts/mt7621_tplink_archer-a6-v3.dts @@ -1,188 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later OR MIT -#include "mt7621.dtsi" - -#include -#include +#include "mt7621_tplink_archer-x6-v3.dtsi" / { compatible = "tplink,archer-a6-v3", "mediatek,mt7621-soc"; model = "TP-Link Archer A6 v3"; - aliases { - label-mac-device = &gmac0; - led-boot = &led_power; - led-failsafe = &led_power; - led-running = &led_power; - led-upgrade = &led_power; - }; - - chosen { - bootargs = "console=ttyS0,115200n8"; - }; - - keys { - compatible = "gpio-keys"; - - wps { - label = "wps"; - gpios = <&gpio 28 GPIO_ACTIVE_LOW>; - debounce-interval = <60>; - linux,code = ; - }; - - reset { - label = "reset"; - gpios = <&gpio 8 GPIO_ACTIVE_LOW>; - debounce-interval = <60>; - linux,code = ; - }; - }; - - leds { - compatible = "gpio-leds"; - - led_power: power { - label = "green:power"; - gpios = <&gpio 4 GPIO_ACTIVE_LOW>; - }; - - wan_orange { - label = "orange:wan"; - gpios = <&gpio 14 GPIO_ACTIVE_LOW>; - }; - - lan { - label = "green:lan"; - gpios = <&gpio 15 GPIO_ACTIVE_LOW>; - }; - - wifi5g { - label = "green:wifi5g"; - gpios = <&gpio 16 GPIO_ACTIVE_LOW>; - linux,default-trigger = "phy1tpt"; - }; - - wifi2g { - label = "green:wifi2g"; - gpios = <&gpio 18 GPIO_ACTIVE_LOW>; - linux,default-trigger = "phy0tpt"; - }; - - wan_green { - label = "green:wan"; - gpios = <&gpio 45 GPIO_ACTIVE_LOW>; - }; - }; -}; - -&spi0 { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <40000000>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "u-boot"; - reg = <0x0 0x40000>; - read-only; - }; - - partition@40000 { - label = "firmware"; - compatible = "denx,uimage"; - reg = <0x40000 0xf60000>; - }; - - config: partition@fa0000 { - label = "config"; - reg = <0xfa0000 0x50000>; - read-only; - }; - - radio: partition@ff0000 { - label = "radio"; - reg = <0xff0000 0x10000>; - read-only; - }; - }; - }; -}; - -&state_default { - gpio { - groups = "i2c", "uart2", "uart3", "jtag", "wdt"; - function = "gpio"; - }; -}; - -ðernet { - pinctrl-names = "default"; - pinctrl-0 = <&rgmii1_pins &mdio_pins>; -}; - -&pcie { - status = "okay"; -}; - -&pcie0 { - wifi@0,0 { - compatible = "mediatek,mt76"; - reg = <0x0000 0 0 0 0>; - mediatek,mtd-eeprom = <&radio 0x0>; - mtd-mac-address = <&config 0x8>; - mtd-mac-address-increment = <1>; - ieee80211-freq-limit = <2400000 2500000>; - }; -}; - -&pcie1 { - wifi@0,0 { - compatible = "mediatek,mt76"; - reg = <0x0000 0 0 0 0>; - mediatek,mtd-eeprom = <&radio 0x8000>; - mtd-mac-address = <&config 0x8>; - mtd-mac-address-increment = <2>; - ieee80211-freq-limit = <5000000 6000000>; - }; -}; - -&gmac0 { - mtd-mac-address = <&config 0x8>; -}; - -&switch0 { - ports { - port@0 { - status = "okay"; - label = "wan"; - }; - - port@1 { - status = "okay"; - label = "lan1"; - }; - - port@2 { - status = "okay"; - label = "lan2"; - }; - - port@3 { - status = "okay"; - label = "lan3"; - }; - - port@4 { - status = "okay"; - label = "lan4"; - }; - }; }; diff --git a/target/linux/ramips/dts/mt7621_tplink_archer-c6-v3.dts b/target/linux/ramips/dts/mt7621_tplink_archer-c6-v3.dts new file mode 100644 index 0000000000..07d808ca20 --- /dev/null +++ b/target/linux/ramips/dts/mt7621_tplink_archer-c6-v3.dts @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7621_tplink_archer-x6-v3.dtsi" + +/ { + compatible = "tplink,archer-c6-v3", "mediatek,mt7621-soc"; + model = "TP-Link Archer C6 v3"; + +}; diff --git a/target/linux/ramips/dts/mt7621_tplink_archer-x6-v3.dtsi b/target/linux/ramips/dts/mt7621_tplink_archer-x6-v3.dtsi new file mode 100644 index 0000000000..76d9908fb9 --- /dev/null +++ b/target/linux/ramips/dts/mt7621_tplink_archer-x6-v3.dtsi @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "mt7621.dtsi" + +#include +#include + +/ { + aliases { + label-mac-device = &gmac0; + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; + }; + + chosen { + bootargs = "console=ttyS0,115200n8"; + }; + + keys { + compatible = "gpio-keys"; + + wps { + label = "wps"; + gpios = <&gpio 28 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + linux,code = ; + }; + + reset { + label = "reset"; + gpios = <&gpio 8 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + led_power: power { + label = "green:power"; + gpios = <&gpio 4 GPIO_ACTIVE_LOW>; + }; + + wan_orange { + label = "orange:wan"; + gpios = <&gpio 14 GPIO_ACTIVE_LOW>; + }; + + lan { + label = "green:lan"; + gpios = <&gpio 15 GPIO_ACTIVE_LOW>; + }; + + wifi5g { + label = "green:wifi5g"; + gpios = <&gpio 16 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy1tpt"; + }; + + wifi2g { + label = "green:wifi2g"; + gpios = <&gpio 18 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy0tpt"; + }; + + wan_green { + label = "green:wan"; + gpios = <&gpio 45 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <40000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "firmware"; + compatible = "denx,uimage"; + reg = <0x40000 0xf60000>; + }; + + config: partition@fa0000 { + label = "config"; + reg = <0xfa0000 0x50000>; + read-only; + }; + + radio: partition@ff0000 { + label = "radio"; + reg = <0xff0000 0x10000>; + read-only; + }; + }; + }; +}; + +&state_default { + gpio { + groups = "i2c", "uart2", "uart3", "jtag", "wdt"; + function = "gpio"; + }; +}; + +ðernet { + pinctrl-names = "default"; + pinctrl-0 = <&rgmii1_pins &mdio_pins>; +}; + +&pcie { + status = "okay"; +}; + +&pcie0 { + wifi@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + mediatek,mtd-eeprom = <&radio 0x0>; + mtd-mac-address = <&config 0x8>; + mtd-mac-address-increment = <1>; + ieee80211-freq-limit = <2400000 2500000>; + }; +}; + +&pcie1 { + wifi@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + mediatek,mtd-eeprom = <&radio 0x8000>; + mtd-mac-address = <&config 0x8>; + mtd-mac-address-increment = <2>; + ieee80211-freq-limit = <5000000 6000000>; + }; +}; + +&gmac0 { + mtd-mac-address = <&config 0x8>; +}; + +&switch0 { + ports { + port@0 { + status = "okay"; + label = "wan"; + }; + + port@1 { + status = "okay"; + label = "lan1"; + }; + + port@2 { + status = "okay"; + label = "lan2"; + }; + + port@3 { + status = "okay"; + label = "lan3"; + }; + + port@4 { + status = "okay"; + label = "lan4"; + }; + }; +}; diff --git a/target/linux/ramips/image/mt7621.mk b/target/linux/ramips/image/mt7621.mk index 02da05648c..569fdc1948 100644 --- a/target/linux/ramips/image/mt7621.mk +++ b/target/linux/ramips/image/mt7621.mk @@ -1244,6 +1244,19 @@ define Device/tplink_archer-a6-v3 endef TARGET_DEVICES += tplink_archer-a6-v3 +define Device/tplink_archer-c6-v3 + $(Device/dsa-migration) + $(Device/tplink-safeloader) + DEVICE_MODEL := Archer C6 + DEVICE_VARIANT := V3 + DEVICE_PACKAGES := kmod-mt7603 kmod-mt7615e \ + kmod-mt7663-firmware-ap kmod-mt7663-firmware-sta + TPLINK_BOARD_ID := ARCHER-C6-V3 + KERNEL := $(KERNEL_DTB) | uImage lzma + IMAGE_SIZE := 15744k +endef +TARGET_DEVICES += tplink_archer-c6-v3 + define Device/tplink_archer-c6u-v1 $(Device/dsa-migration) $(Device/tplink-safeloader) diff --git a/target/linux/ramips/mt7621/base-files/etc/board.d/01_leds b/target/linux/ramips/mt7621/base-files/etc/board.d/01_leds index 5322bc9db0..c04dae4f0d 100644 --- a/target/linux/ramips/mt7621/base-files/etc/board.d/01_leds +++ b/target/linux/ramips/mt7621/base-files/etc/board.d/01_leds @@ -90,6 +90,7 @@ netgear,r6800) ucidef_set_led_netdev "lan4" "LAN4" "white:lan4" "lan4" ;; tplink,archer-a6-v3|\ +tplink,archer-c6-v3|\ tplink,archer-c6u-v1) ucidef_set_led_netdev "lan" "LAN" "green:lan" "br-lan" ucidef_set_led_netdev "wan" "WAN" "green:wan" "wan" diff --git a/target/linux/ramips/patches-5.4/991-at803x.patch b/target/linux/ramips/patches-5.4/991-at803x.patch index 6e178b80ce..4de3118547 100644 --- a/target/linux/ramips/patches-5.4/991-at803x.patch +++ b/target/linux/ramips/patches-5.4/991-at803x.patch @@ -105,7 +105,7 @@ Signed-off-by: RenĂ© van Dorst { struct device *dev = &phydev->mdio.dev; struct at803x_priv *priv; - int ret; + int ret = 0; + if (at803x_mode(phydev) == AT803X_MODE_FIBER) { + ret = phy_sfp_probe(phydev, &at803x_sfp_ops); diff --git a/target/linux/rockchip/patches-5.10/004-v5.13-rockchip-rk3399-Add-support-for-FriendlyARM-NanoPi-R.patch b/target/linux/rockchip/patches-5.10/004-v5.13-rockchip-rk3399-Add-support-for-FriendlyARM-NanoPi-R.patch new file mode 100644 index 0000000000..461a5ae7dd --- /dev/null +++ b/target/linux/rockchip/patches-5.10/004-v5.13-rockchip-rk3399-Add-support-for-FriendlyARM-NanoPi-R.patch @@ -0,0 +1,177 @@ +From db792e9adbf85ffc9d6b0b060ac3c8e3148c8992 Mon Sep 17 00:00:00 2001 +From: Tianling Shen +Date: Fri, 19 Mar 2021 13:16:27 +0800 +Subject: [PATCH] rockchip: rk3399: Add support for FriendlyARM NanoPi R4S + +This adds support for the NanoPi R4S from FriendlyArm. + +Rockchip RK3399 SoC +1GB DDR3 or 4GB LPDDR4 RAM +Gigabit Ethernet (WAN) +Gigabit Ethernet (PCIe) (LAN) +USB 3.0 Port x 2 +MicroSD slot +Reset button +WAN - LAN - SYS LED + +Co-developed-by: Jensen Huang +Signed-off-by: Jensen Huang +[minor adjustments] +Co-developed-by: Marty Jones +Signed-off-by: Marty Jones +[further adjustments, fixed format issues] +Signed-off-by: Tianling Shen +Link: https://lore.kernel.org/r/20210319051627.814-2-cnsztl@gmail.com +Signed-off-by: Heiko Stuebner +--- + arch/arm64/boot/dts/rockchip/Makefile | 1 + + .../boot/dts/rockchip/rk3399-nanopi-r4s.dts | 133 +++++++++++++++++++++ + 2 files changed, 134 insertions(+) + create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts + +--- a/arch/arm64/boot/dts/rockchip/Makefile ++++ b/arch/arm64/boot/dts/rockchip/Makefile +@@ -30,6 +30,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-le + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-neo4.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-r4s.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-orangepi.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-pinebook-pro.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-puma-haikou.dtb +--- /dev/null ++++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts +@@ -0,0 +1,133 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * FriendlyElec NanoPC-T4 board device tree source ++ * ++ * Copyright (c) 2020 FriendlyElec Computer Tech. Co., Ltd. ++ * (http://www.friendlyarm.com) ++ * ++ * Copyright (c) 2018 Collabora Ltd. ++ * ++ * Copyright (c) 2020 Jensen Huang ++ * Copyright (c) 2020 Marty Jones ++ * Copyright (c) 2021 Tianling Shen ++ */ ++ ++/dts-v1/; ++#include "rk3399-nanopi4.dtsi" ++ ++/ { ++ model = "FriendlyElec NanoPi R4S"; ++ compatible = "friendlyarm,nanopi-r4s", "rockchip,rk3399"; ++ ++ /delete-node/ display-subsystem; ++ ++ gpio-leds { ++ pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>; ++ ++ /delete-node/ led-0; ++ ++ lan_led: led-lan { ++ gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>; ++ label = "green:lan"; ++ }; ++ ++ sys_led: led-sys { ++ gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; ++ label = "red:sys"; ++ default-state = "on"; ++ }; ++ ++ wan_led: led-wan { ++ gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; ++ label = "green:wan"; ++ }; ++ }; ++ ++ gpio-keys { ++ pinctrl-0 = <&reset_button_pin>; ++ ++ /delete-node/ power; ++ ++ reset { ++ debounce-interval = <50>; ++ gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>; ++ label = "reset"; ++ linux,code = ; ++ }; ++ }; ++ ++ vdd_5v: vdd-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd_5v"; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++}; ++ ++&emmc_phy { ++ status = "disabled"; ++}; ++ ++&i2c4 { ++ status = "disabled"; ++}; ++ ++&pcie0 { ++ max-link-speed = <1>; ++ num-lanes = <1>; ++ vpcie3v3-supply = <&vcc3v3_sys>; ++}; ++ ++&pinctrl { ++ gpio-leds { ++ /delete-node/ status-led-pin; ++ ++ lan_led_pin: lan-led-pin { ++ rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ sys_led_pin: sys-led-pin { ++ rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ wan_led_pin: wan-led-pin { ++ rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ rockchip-key { ++ /delete-node/ power-key; ++ ++ reset_button_pin: reset-button-pin { ++ rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++}; ++ ++&sdhci { ++ status = "disabled"; ++}; ++ ++&sdio0 { ++ status = "disabled"; ++}; ++ ++&u2phy0_host { ++ phy-supply = <&vdd_5v>; ++}; ++ ++&u2phy1_host { ++ status = "disabled"; ++}; ++ ++&uart0 { ++ status = "disabled"; ++}; ++ ++&usbdrd_dwc3_0 { ++ dr_mode = "host"; ++}; ++ ++&vcc3v3_sys { ++ vin-supply = <&vcc5v0_sys>; ++}; diff --git a/target/linux/rockchip/patches-5.10/005-arm64-dts-rockchip-add-EEPROM-node-for-NanoPi-R4S.patch b/target/linux/rockchip/patches-5.10/005-arm64-dts-rockchip-add-EEPROM-node-for-NanoPi-R4S.patch new file mode 100644 index 0000000000..792028b292 --- /dev/null +++ b/target/linux/rockchip/patches-5.10/005-arm64-dts-rockchip-add-EEPROM-node-for-NanoPi-R4S.patch @@ -0,0 +1,31 @@ +From af20b3384e8723077cc6484160b0cf4e9be321de Mon Sep 17 00:00:00 2001 +From: Tianling Shen +Date: Mon, 7 Jun 2021 15:45:37 +0800 +Subject: [PATCH] arm64: dts: rockchip: add EEPROM node for NanoPi R4S + +NanoPi R4S has a EEPROM attached to the 2nd I2C bus (U92), which +stores the MAC address. + +Signed-off-by: Tianling Shen +--- + arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts +@@ -68,6 +68,15 @@ + status = "disabled"; + }; + ++&i2c2 { ++ eeprom@51 { ++ compatible = "microchip,24c02", "atmel,24c02"; ++ reg = <0x51>; ++ pagesize = <16>; ++ read-only; /* This holds our MAC */ ++ }; ++}; ++ + &i2c4 { + status = "disabled"; + }; diff --git a/target/linux/rockchip/patches-5.10/105-rockchip-rock-pi-4.patch b/target/linux/rockchip/patches-5.10/105-rockchip-rock-pi-4.patch index d2c81e4d08..404f64ab95 100644 --- a/target/linux/rockchip/patches-5.10/105-rockchip-rock-pi-4.patch +++ b/target/linux/rockchip/patches-5.10/105-rockchip-rock-pi-4.patch @@ -1,6 +1,6 @@ --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile -@@ -35,6 +35,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-pi +@@ -36,6 +36,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-pi dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-puma-haikou.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-roc-pc.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-roc-pc-mezzanine.dtb diff --git a/target/linux/rockchip/patches-5.4/007-v5.13-rockchip-rk3399-Add-support-for-FriendlyARM-NanoPi-R.patch b/target/linux/rockchip/patches-5.4/007-v5.13-rockchip-rk3399-Add-support-for-FriendlyARM-NanoPi-R.patch new file mode 100644 index 0000000000..c508d71317 --- /dev/null +++ b/target/linux/rockchip/patches-5.4/007-v5.13-rockchip-rk3399-Add-support-for-FriendlyARM-NanoPi-R.patch @@ -0,0 +1,177 @@ +From db792e9adbf85ffc9d6b0b060ac3c8e3148c8992 Mon Sep 17 00:00:00 2001 +From: Tianling Shen +Date: Fri, 19 Mar 2021 13:16:27 +0800 +Subject: [PATCH] rockchip: rk3399: Add support for FriendlyARM NanoPi R4S + +This adds support for the NanoPi R4S from FriendlyArm. + +Rockchip RK3399 SoC +1GB DDR3 or 4GB LPDDR4 RAM +Gigabit Ethernet (WAN) +Gigabit Ethernet (PCIe) (LAN) +USB 3.0 Port x 2 +MicroSD slot +Reset button +WAN - LAN - SYS LED + +Co-developed-by: Jensen Huang +Signed-off-by: Jensen Huang +[minor adjustments] +Co-developed-by: Marty Jones +Signed-off-by: Marty Jones +[further adjustments, fixed format issues] +Signed-off-by: Tianling Shen +Link: https://lore.kernel.org/r/20210319051627.814-2-cnsztl@gmail.com +Signed-off-by: Heiko Stuebner +--- + arch/arm64/boot/dts/rockchip/Makefile | 1 + + .../boot/dts/rockchip/rk3399-nanopi-r4s.dts | 133 +++++++++++++++++++++ + 2 files changed, 134 insertions(+) + create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts + +--- a/arch/arm64/boot/dts/rockchip/Makefile ++++ b/arch/arm64/boot/dts/rockchip/Makefile +@@ -25,6 +25,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-le + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopc-t4.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-neo4.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-r4s.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-orangepi.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-puma-haikou.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-roc-pc.dtb +--- /dev/null ++++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts +@@ -0,0 +1,133 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * FriendlyElec NanoPC-T4 board device tree source ++ * ++ * Copyright (c) 2020 FriendlyElec Computer Tech. Co., Ltd. ++ * (http://www.friendlyarm.com) ++ * ++ * Copyright (c) 2018 Collabora Ltd. ++ * ++ * Copyright (c) 2020 Jensen Huang ++ * Copyright (c) 2020 Marty Jones ++ * Copyright (c) 2021 Tianling Shen ++ */ ++ ++/dts-v1/; ++#include "rk3399-nanopi4.dtsi" ++ ++/ { ++ model = "FriendlyElec NanoPi R4S"; ++ compatible = "friendlyarm,nanopi-r4s", "rockchip,rk3399"; ++ ++ /delete-node/ display-subsystem; ++ ++ gpio-leds { ++ pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>; ++ ++ /delete-node/ status; ++ ++ lan_led: led-lan { ++ gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>; ++ label = "green:lan"; ++ }; ++ ++ sys_led: led-sys { ++ gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; ++ label = "red:sys"; ++ default-state = "on"; ++ }; ++ ++ wan_led: led-wan { ++ gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; ++ label = "green:wan"; ++ }; ++ }; ++ ++ gpio-keys { ++ pinctrl-0 = <&reset_button_pin>; ++ ++ /delete-node/ power; ++ ++ reset { ++ debounce-interval = <50>; ++ gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>; ++ label = "reset"; ++ linux,code = ; ++ }; ++ }; ++ ++ vdd_5v: vdd-5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "vdd_5v"; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++}; ++ ++&emmc_phy { ++ status = "disabled"; ++}; ++ ++&i2c4 { ++ status = "disabled"; ++}; ++ ++&pcie0 { ++ max-link-speed = <1>; ++ num-lanes = <1>; ++ vpcie3v3-supply = <&vcc3v3_sys>; ++}; ++ ++&pinctrl { ++ gpio-leds { ++ /delete-node/ leds-gpio; ++ ++ lan_led_pin: lan-led-pin { ++ rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ sys_led_pin: sys-led-pin { ++ rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ wan_led_pin: wan-led-pin { ++ rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ ++ rockchip-key { ++ /delete-node/ power-key; ++ ++ reset_button_pin: reset-button-pin { ++ rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++}; ++ ++&sdhci { ++ status = "disabled"; ++}; ++ ++&sdio0 { ++ status = "disabled"; ++}; ++ ++&u2phy0_host { ++ phy-supply = <&vdd_5v>; ++}; ++ ++&u2phy1_host { ++ status = "disabled"; ++}; ++ ++&uart0 { ++ status = "disabled"; ++}; ++ ++&usbdrd_dwc3_0 { ++ dr_mode = "host"; ++}; ++ ++&vcc3v3_sys { ++ vin-supply = <&vcc5v0_sys>; ++}; diff --git a/target/linux/rockchip/patches-5.4/008-arm64-dts-rockchip-add-EEPROM-node-for-NanoPi-R4S.patch b/target/linux/rockchip/patches-5.4/008-arm64-dts-rockchip-add-EEPROM-node-for-NanoPi-R4S.patch new file mode 100644 index 0000000000..792028b292 --- /dev/null +++ b/target/linux/rockchip/patches-5.4/008-arm64-dts-rockchip-add-EEPROM-node-for-NanoPi-R4S.patch @@ -0,0 +1,31 @@ +From af20b3384e8723077cc6484160b0cf4e9be321de Mon Sep 17 00:00:00 2001 +From: Tianling Shen +Date: Mon, 7 Jun 2021 15:45:37 +0800 +Subject: [PATCH] arm64: dts: rockchip: add EEPROM node for NanoPi R4S + +NanoPi R4S has a EEPROM attached to the 2nd I2C bus (U92), which +stores the MAC address. + +Signed-off-by: Tianling Shen +--- + arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts +@@ -68,6 +68,15 @@ + status = "disabled"; + }; + ++&i2c2 { ++ eeprom@51 { ++ compatible = "microchip,24c02", "atmel,24c02"; ++ reg = <0x51>; ++ pagesize = <16>; ++ read-only; /* This holds our MAC */ ++ }; ++}; ++ + &i2c4 { + status = "disabled"; + }; diff --git a/target/linux/tegra/Makefile b/target/linux/tegra/Makefile index 4d4b0e5ea4..98c1dece16 100644 --- a/target/linux/tegra/Makefile +++ b/target/linux/tegra/Makefile @@ -12,7 +12,7 @@ CPU_TYPE := cortex-a9 CPU_SUBTYPE := vfpv3-d16 KERNEL_PATCHVER := 5.4 -KERNEL_TESTING_PATCHVER := 5.4 +KERNEL_TESTING_PATCHVER := 5.10 include $(INCLUDE_DIR)/target.mk diff --git a/target/linux/tegra/config-5.10 b/target/linux/tegra/config-5.10 new file mode 100644 index 0000000000..e4b1c66f52 --- /dev/null +++ b/target/linux/tegra/config-5.10 @@ -0,0 +1,493 @@ +CONFIG_AC97_BUS=y +# CONFIG_AHCI_TEGRA is not set +CONFIG_ALIGNMENT_TRAP=y +CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED=y +CONFIG_ARCH_NR_GPIO=1024 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_TEGRA=y +# CONFIG_ARCH_TEGRA_114_SOC is not set +# CONFIG_ARCH_TEGRA_124_SOC is not set +CONFIG_ARCH_TEGRA_2x_SOC=y +# CONFIG_ARCH_TEGRA_3x_SOC is not set +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_ARM_CRYPTO=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_HEAVY_MB=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_PL172_MPMC is not set +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_TEGRA_CPUIDLE=y +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_ASN1=y +CONFIG_ATA=y +CONFIG_ATAGS=y +CONFIG_AUTO_ZRELADDR=y +CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_PM=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BOUNCE=y +CONFIG_CACHE_L2X0=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CLZ_TAB=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=16 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_CONTIG_ALLOC=y +# CONFIG_CPUFREQ_DT is not set +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_STAT is not set +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_LZ4HC=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA256_ARM=y +CONFIG_CRYPTO_SHA512_ARM=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEVPORT is not set +CONFIG_DMADEVICES=y +CONFIG_DMA_CMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_OPS=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DNOTIFY=y +CONFIG_DRM=y +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FBDEV_OVERALLOC=100 +CONFIG_DRM_KMS_FB_HELPER=y +CONFIG_DRM_KMS_HELPER=y +CONFIG_DRM_MIPI_DSI=y +CONFIG_DRM_PANEL=y +CONFIG_DRM_PANEL_BRIDGE=y +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y +CONFIG_DRM_TEGRA=y +# CONFIG_DRM_TEGRA_DEBUG is not set +# CONFIG_DRM_TEGRA_STAGING is not set +CONFIG_DTC=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_EXT4_FS=y +CONFIG_EXTCON=y +CONFIG_F2FS_FS=y +CONFIG_FB=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_SYS_IMAGEBLIT=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FREEZER=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +# CONFIG_FW_CACHE is not set +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_VDSO_32=y +CONFIG_GLOB=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_TEGRA=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_SMP=y +CONFIG_HDMI=y +CONFIG_HID=y +CONFIG_HIDRAW=y +CONFIG_HID_GENERIC=y +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +CONFIG_HOTPLUG_CPU=y +CONFIG_HWMON=y +CONFIG_HZ_FIXED=0 +CONFIG_HZ_PERIODIC=y +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_TEGRA=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_IOMMU_API=y +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_IOMMU_IOVA=y +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KCMP=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_LIBFDT=y +CONFIG_LLD_VERSION=0 +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZ4HC_COMPRESS=y +CONFIG_LZ4_COMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MEMFD_CREATE=y +CONFIG_MEMORY=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_MFD_NVEC is not set +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_CQHCI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MPILIB=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +# CONFIG_NEON is not set +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NLS=y +CONFIG_NR_CPUS=4 +CONFIG_NVMEM=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IOMMU=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_NET=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEASPM=y +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_PERFORMANCE is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_PME=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_ARCH_FALLBACKS=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCI_TEGRA=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHY_TEGRA_XUSB=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_TEGRA=y +CONFIG_PINCTRL_TEGRA20=y +CONFIG_PINCTRL_TEGRA_XUSB=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_PL353_SMC=y +CONFIG_PM=y +CONFIG_PM_CLK=y +CONFIG_PM_OPP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_SUPPLY=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +CONFIG_PWM_TEGRA=y +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_EXPERT is not set +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_TEGRA=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_NVMEM=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_SCSI=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_TEGRA=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_TEGRA=y +CONFIG_SERIO=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SGL_ALLOC=y +CONFIG_SG_POOL=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_SND=y +# CONFIG_SND_COMPRESS_OFFLOAD is not set +CONFIG_SND_DMAENGINE_PCM=y +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_HDA_TEGRA is not set +CONFIG_SND_JACK=y +CONFIG_SND_JACK_INPUT_DEV=y +# CONFIG_SND_PCI is not set +CONFIG_SND_PCM=y +# CONFIG_SND_PROC_FS is not set +CONFIG_SND_SIMPLE_CARD=y +CONFIG_SND_SIMPLE_CARD_UTILS=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_AC97_BUS=y +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y +CONFIG_SND_SOC_I2C_AND_SPI=y +CONFIG_SND_SOC_TEGRA=y +# CONFIG_SND_SOC_TEGRA186_DSPK is not set +CONFIG_SND_SOC_TEGRA20_AC97=y +CONFIG_SND_SOC_TEGRA20_DAS=y +CONFIG_SND_SOC_TEGRA20_I2S=y +CONFIG_SND_SOC_TEGRA20_SPDIF=y +# CONFIG_SND_SOC_TEGRA210_ADMAIF is not set +# CONFIG_SND_SOC_TEGRA210_AHUB is not set +# CONFIG_SND_SOC_TEGRA210_DMIC is not set +# CONFIG_SND_SOC_TEGRA210_I2S is not set +# CONFIG_SND_SOC_TEGRA30_AHUB is not set +# CONFIG_SND_SOC_TEGRA30_I2S is not set +# CONFIG_SND_SOC_TEGRA_ALC5632 is not set +# CONFIG_SND_SOC_TEGRA_MAX98090 is not set +# CONFIG_SND_SOC_TEGRA_RT5640 is not set +# CONFIG_SND_SOC_TEGRA_RT5677 is not set +# CONFIG_SND_SOC_TEGRA_SGTL5000 is not set +CONFIG_SND_SOC_TEGRA_TRIMSLICE=y +# CONFIG_SND_SOC_TEGRA_WM8753 is not set +# CONFIG_SND_SOC_TEGRA_WM8903 is not set +# CONFIG_SND_SOC_TEGRA_WM9712 is not set +CONFIG_SND_SOC_TLV320AIC23=y +CONFIG_SND_SOC_TLV320AIC23_I2C=y +# CONFIG_SND_USB is not set +CONFIG_SOC_BUS=y +CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER=y +CONFIG_SOC_TEGRA_FLOWCTRL=y +CONFIG_SOC_TEGRA_FUSE=y +CONFIG_SOC_TEGRA_PMC=y +CONFIG_SOUND=y +CONFIG_SOUND_OSS_CORE=y +CONFIG_SOUND_OSS_CORE_PRECLAIM=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +# CONFIG_SPI_TEGRA114 is not set +CONFIG_SPI_TEGRA20_SFLASH=y +CONFIG_SPI_TEGRA20_SLINK=y +CONFIG_SRCU=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWP_EMULATE=y +CONFIG_SYNC_FILE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_TEGRA20_APB_DMA=y +CONFIG_TEGRA20_EMC=y +CONFIG_TEGRA_AHB=y +CONFIG_TEGRA_GMI=y +CONFIG_TEGRA_HOST1X=y +CONFIG_TEGRA_HOST1X_FIREWALL=y +CONFIG_TEGRA_IOMMU_GART=y +# CONFIG_TEGRA_IOMMU_SMMU is not set +# CONFIG_TEGRA_IVC is not set +CONFIG_TEGRA_MC=y +CONFIG_TEGRA_TIMER=y +CONFIG_TEGRA_WATCHDOG=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +# CONFIG_UACCE is not set +# CONFIG_UCLAMP_TASK is not set +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNWINDER_ARM=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_CONN_GPIO=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +CONFIG_USB_EHCI_TEGRA=y +CONFIG_USB_HID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_PHY=y +CONFIG_USB_ROLE_SWITCH=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_TEGRA_PHY=y +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +CONFIG_USE_OF=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y diff --git a/target/linux/tegra/config-5.4 b/target/linux/tegra/config-5.4 index 6c9cc1af3c..b487296ce3 100644 --- a/target/linux/tegra/config-5.4 +++ b/target/linux/tegra/config-5.4 @@ -3,23 +3,6 @@ CONFIG_AC97_BUS=y CONFIG_ALIGNMENT_TRAP=y CONFIG_ARCH_32BIT_OFF_T=y CONFIG_ARCH_CLOCKSOURCE_DATA=y -CONFIG_ARCH_HAS_BINFMT_FLAT=y -CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y -CONFIG_ARCH_HAS_ELF_RANDOMIZE=y -CONFIG_ARCH_HAS_FORTIFY_SOURCE=y -CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y -CONFIG_ARCH_HAS_KCOV=y -CONFIG_ARCH_HAS_KEEPINITRD=y -CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y -CONFIG_ARCH_HAS_PHYS_TO_DMA=y -CONFIG_ARCH_HAS_RESET_CONTROLLER=y -CONFIG_ARCH_HAS_SETUP_DMA_OPS=y -CONFIG_ARCH_HAS_SET_MEMORY=y -CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y -CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y -CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y -CONFIG_ARCH_HAS_TICK_BROADCAST=y -CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y @@ -30,23 +13,14 @@ CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED=y CONFIG_ARCH_NR_GPIO=1024 CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y -CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y -CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_ARCH_TEGRA=y # CONFIG_ARCH_TEGRA_114_SOC is not set # CONFIG_ARCH_TEGRA_124_SOC is not set CONFIG_ARCH_TEGRA_2x_SOC=y # CONFIG_ARCH_TEGRA_3x_SOC is not set -CONFIG_ARCH_USE_BUILTIN_BSWAP=y -CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y -CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y -CONFIG_ARCH_WANT_GENERAL_HUGETLB=y -CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_ARM=y CONFIG_ARM_AMBA=y -CONFIG_ARM_ARCH_TIMER=y -CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y CONFIG_ARM_CPU_SUSPEND=y CONFIG_ARM_CRYPTO=y CONFIG_ARM_ERRATA_720789=y @@ -57,12 +31,10 @@ CONFIG_ARM_HAS_SG_CHAIN=y CONFIG_ARM_HEAVY_MB=y CONFIG_ARM_L1_CACHE_SHIFT=6 CONFIG_ARM_L1_CACHE_SHIFT_6=y -# CONFIG_ARM_LPAE is not set CONFIG_ARM_PATCH_IDIV=y CONFIG_ARM_PATCH_PHYS_VIRT=y # CONFIG_ARM_PL172_MPMC is not set # CONFIG_ARM_SMMU is not set -# CONFIG_ARM_SP805_WATCHDOG is not set CONFIG_ARM_TEGRA20_CPUFREQ=y CONFIG_ARM_THUMB=y CONFIG_ARM_THUMBEE=y @@ -80,7 +52,6 @@ CONFIG_BLK_PM=y CONFIG_BLK_SCSI_REQUEST=y CONFIG_BOUNCE=y CONFIG_CACHE_L2X0=y -CONFIG_CC_HAS_KASAN_GENERIC=y CONFIG_CLKDEV_LOOKUP=y CONFIG_CLKSRC_MMIO=y CONFIG_CLONE_BACKWARDS=y @@ -102,7 +73,6 @@ CONFIG_CONTIG_ALLOC=y CONFIG_CPU_32v6K=y CONFIG_CPU_32v7=y CONFIG_CPU_ABRT_EV7=y -# CONFIG_CPU_BPREDICT_DISABLE is not set CONFIG_CPU_CACHE_V7=y CONFIG_CPU_CACHE_VIPT=y CONFIG_CPU_COPY_V6=y @@ -121,9 +91,6 @@ CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_CPU_FREQ_GOV_USERSPACE=y # CONFIG_CPU_FREQ_STAT is not set CONFIG_CPU_HAS_ASID=y -# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set -# CONFIG_CPU_ICACHE_DISABLE is not set -# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_CPU_PABRT_V7=y @@ -178,7 +145,6 @@ CONFIG_CRYPTO_TWOFISH_COMMON=y CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" -# CONFIG_DEBUG_USER is not set # CONFIG_DEVPORT is not set CONFIG_DMADEVICES=y CONFIG_DMA_CMA=y @@ -193,17 +159,13 @@ CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_FBDEV_OVERALLOC=100 CONFIG_DRM_KMS_FB_HELPER=y CONFIG_DRM_KMS_HELPER=y -# CONFIG_DRM_MCDE is not set CONFIG_DRM_MIPI_DSI=y CONFIG_DRM_PANEL=y CONFIG_DRM_PANEL_BRIDGE=y CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y -# CONFIG_DRM_PANEL_SAMSUNG_S6D16D0 is not set -# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set CONFIG_DRM_TEGRA=y # CONFIG_DRM_TEGRA_DEBUG is not set # CONFIG_DRM_TEGRA_STAGING is not set -# CONFIG_DRM_TVE200 is not set CONFIG_DTC=y CONFIG_EDAC_ATOMIC_SCRUB=y CONFIG_EDAC_SUPPORT=y @@ -260,50 +222,7 @@ CONFIG_HARDIRQS_SW_RESEND=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT_MAP=y -CONFIG_HAVE_ARCH_AUDITSYSCALL=y -CONFIG_HAVE_ARCH_BITREVERSE=y -CONFIG_HAVE_ARCH_JUMP_LABEL=y -CONFIG_HAVE_ARCH_KGDB=y -CONFIG_HAVE_ARCH_PFN_VALID=y -CONFIG_HAVE_ARCH_SECCOMP_FILTER=y -CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y -CONFIG_HAVE_ARCH_TRACEHOOK=y -CONFIG_HAVE_ARM_ARCH_TIMER=y -CONFIG_HAVE_ARM_SCU=y -CONFIG_HAVE_ARM_SMCCC=y -CONFIG_HAVE_ARM_TWD=y -CONFIG_HAVE_CLK=y -CONFIG_HAVE_CLK_PREPARE=y -CONFIG_HAVE_CONTEXT_TRACKING=y -CONFIG_HAVE_COPY_THREAD_TLS=y -CONFIG_HAVE_C_RECORDMCOUNT=y -CONFIG_HAVE_DEBUG_KMEMLEAK=y -CONFIG_HAVE_DMA_CONTIGUOUS=y -CONFIG_HAVE_DYNAMIC_FTRACE=y -CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y -CONFIG_HAVE_EBPF_JIT=y -CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y -CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y -CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y -CONFIG_HAVE_FUNCTION_TRACER=y -CONFIG_HAVE_IDE=y -CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y -CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y -CONFIG_HAVE_MOD_ARCH_SPECIFIC=y -CONFIG_HAVE_NET_DSA=y -CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_OPTPROBES=y -CONFIG_HAVE_PCI=y -CONFIG_HAVE_PERF_EVENTS=y -CONFIG_HAVE_PERF_REGS=y -CONFIG_HAVE_PERF_USER_STACK_DUMP=y -CONFIG_HAVE_PROC_CPU=y -CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y -CONFIG_HAVE_RSEQ=y CONFIG_HAVE_SMP=y -CONFIG_HAVE_SYSCALL_TRACEPOINTS=y -CONFIG_HAVE_UID16=y -CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HDMI=y CONFIG_HID=y CONFIG_HIDRAW=y @@ -406,14 +325,11 @@ CONFIG_PINCTRL=y CONFIG_PINCTRL_TEGRA=y CONFIG_PINCTRL_TEGRA20=y CONFIG_PINCTRL_TEGRA_XUSB=y -# CONFIG_PL310_ERRATA_588369 is not set CONFIG_PL310_ERRATA_727915=y -# CONFIG_PL310_ERRATA_753970 is not set CONFIG_PL310_ERRATA_769419=y CONFIG_PL353_SMC=y CONFIG_PM=y CONFIG_PM_CLK=y -# CONFIG_PM_DEBUG is not set CONFIG_PM_OPP=y CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y @@ -444,13 +360,14 @@ CONFIG_RPS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_TEGRA=y CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTC_MC146818_LIB=y CONFIG_RTC_NVMEM=y CONFIG_RWSEM_SPIN_ON_OWNER=y CONFIG_SCSI=y # CONFIG_SCSI_LOWLEVEL is not set # CONFIG_SCSI_PROC_FS is not set +# CONFIG_SENSORS_DRIVETEMP is not set CONFIG_SERIAL_8250_FSL=y -# CONFIG_SERIAL_AMBA_PL011 is not set CONFIG_SERIAL_MCTRL_GPIO=y CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_TEGRA=y @@ -474,7 +391,6 @@ CONFIG_SND_SIMPLE_CARD=y CONFIG_SND_SIMPLE_CARD_UTILS=y CONFIG_SND_SOC=y CONFIG_SND_SOC_AC97_BUS=y -# CONFIG_SND_SOC_DMIC is not set CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y CONFIG_SND_SOC_I2C_AND_SPI=y CONFIG_SND_SOC_TEGRA=y @@ -528,7 +444,6 @@ CONFIG_TEGRA_IOMMU_GART=y CONFIG_TEGRA_MC=y CONFIG_TEGRA_TIMER=y CONFIG_TEGRA_WATCHDOG=y -# CONFIG_THUMB2_KERNEL is not set CONFIG_TICK_CPU_ACCOUNTING=y CONFIG_TIMER_OF=y CONFIG_TIMER_PROBE=y @@ -537,10 +452,8 @@ CONFIG_TREE_SRCU=y # CONFIG_UCLAMP_TASK is not set CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" CONFIG_UNWINDER_ARM=y -# CONFIG_UNWINDER_FRAME_POINTER is not set CONFIG_USB=y CONFIG_USB_COMMON=y -# CONFIG_USB_EHCI_FSL is not set CONFIG_USB_EHCI_HCD=y # CONFIG_USB_EHCI_HCD_PLATFORM is not set CONFIG_USB_EHCI_TEGRA=y diff --git a/target/linux/tegra/patches-5.10/100-serial8250-on-tegra-hsuart-recover-from-spurious-interrupts-due-to-tegra2-silicon-bug.patch b/target/linux/tegra/patches-5.10/100-serial8250-on-tegra-hsuart-recover-from-spurious-interrupts-due-to-tegra2-silicon-bug.patch new file mode 100644 index 0000000000..08ed9d441c --- /dev/null +++ b/target/linux/tegra/patches-5.10/100-serial8250-on-tegra-hsuart-recover-from-spurious-interrupts-due-to-tegra2-silicon-bug.patch @@ -0,0 +1,77 @@ +From patchwork Fri Jul 13 11:32:42 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: serial8250 on tegra hsuart: recover from spurious interrupts due to + tegra2 silicon bug +X-Patchwork-Submitter: "David R. Piegdon" +X-Patchwork-Id: 943440 +Message-Id: <4676ea34-69ce-5422-1ded-94218b89f7d9@p23q.org> +To: linux-tegra@vger.kernel.org +Date: Fri, 13 Jul 2018 11:32:42 +0000 +From: "David R. Piegdon" +List-Id: + +Hi, +a while back I sent a few mails regarding spurious interrupts in the +UARTA (hsuart) block of the Tegra2 SoC, when using the 8250 driver for +it instead of the hsuart driver. After going down a pretty deep +debugging/testing hole, I think I found a patch that fixes the issue. So +far testing in a reboot-cycle suggests that the error frequency dropped +from >3% of all reboots to at least <0.05% of all reboots. Tests +continue to run over the weekend. + +The patch below already is a second iteration; the first did not reset +the MCR or contain the lines below '// clear interrupts'. This resulted +in no more spurious interrupts, but in a few % of spurious interrupts +that were recovered the UART block did not receive any characters any +more. So further resetting was required to fully reacquire operational +state of the UART block. + +I'd love any comments/suggestions on this! + +Cheers, + +David + +--- a/drivers/tty/serial/8250/8250_core.c ++++ b/drivers/tty/serial/8250/8250_core.c +@@ -133,6 +133,38 @@ static irqreturn_t serial8250_interrupt( + + if (l == i->head && pass_counter++ > PASS_LIMIT) + break; ++ ++#ifdef CONFIG_ARCH_TEGRA_2x_SOC ++ if (!handled && (port->type == PORT_TEGRA)) { ++ /* ++ * Fix Tegra 2 CPU silicon bug where sometimes ++ * "TX holding register empty" interrupts result in a ++ * bad (metastable?) state in Tegras HSUART IP core. ++ * Only way to recover seems to be to reset all ++ * interrupts as well as the TX queue and the MCR. ++ * But we don't want to loose any outgoing characters, ++ * so only do it if the RX and TX queues are empty. ++ */ ++ unsigned char lsr = port->serial_in(port, UART_LSR); ++ const unsigned char fifo_empty_mask = ++ (UART_LSR_TEMT | UART_LSR_THRE); ++ if (((lsr & (UART_LSR_DR | fifo_empty_mask)) == ++ fifo_empty_mask)) { ++ port->serial_out(port, UART_IER, 0); ++ port->serial_out(port, UART_MCR, 0); ++ serial8250_clear_and_reinit_fifos(up); ++ port->serial_out(port, UART_MCR, up->mcr); ++ port->serial_out(port, UART_IER, up->ier); ++ // clear interrupts ++ serial_port_in(port, UART_LSR); ++ serial_port_in(port, UART_RX); ++ serial_port_in(port, UART_IIR); ++ serial_port_in(port, UART_MSR); ++ up->lsr_saved_flags = 0; ++ up->msr_saved_flags = 0; ++ } ++ } ++#endif + } while (l != end); + + spin_unlock(&i->lock); diff --git a/target/linux/tegra/patches-5.10/101-ARM-dtc-tegra-enable-front-panel-leds-in-TrimSlice.patch b/target/linux/tegra/patches-5.10/101-ARM-dtc-tegra-enable-front-panel-leds-in-TrimSlice.patch new file mode 100644 index 0000000000..b1e210b212 --- /dev/null +++ b/target/linux/tegra/patches-5.10/101-ARM-dtc-tegra-enable-front-panel-leds-in-TrimSlice.patch @@ -0,0 +1,46 @@ +--- a/arch/arm/boot/dts/tegra20-trimslice.dts ++++ b/arch/arm/boot/dts/tegra20-trimslice.dts +@@ -201,16 +201,17 @@ + conf_ata { + nvidia,pins = "ata", "atc", "atd", "ate", + "crtp", "dap2", "dap3", "dap4", "dta", +- "dtb", "dtc", "dtd", "dte", "gmb", +- "gme", "i2cp", "pta", "slxc", "slxd", +- "spdi", "spdo", "uda"; ++ "dtb", "dtc", "dtd", "gmb", "gme", ++ "i2cp", "pta", "slxc", "slxd", "spdi", ++ "spdo", "uda"; + nvidia,pull = ; + nvidia,tristate = ; + }; + conf_atb { + nvidia,pins = "atb", "cdev1", "cdev2", "dap1", +- "gma", "gmc", "gmd", "gpu", "gpu7", +- "gpv", "sdio1", "slxa", "slxk", "uac"; ++ "dte", "gma", "gmc", "gmd", "gpu", ++ "gpu7", "gpv", "sdio1", "slxa", "slxk", ++ "uac"; + nvidia,pull = ; + nvidia,tristate = ; + }; +@@ -396,6 +397,20 @@ + }; + }; + ++ gpio-leds { ++ compatible = "gpio-leds"; ++ ++ ds2 { ++ label = "trimslice:green:right"; ++ gpios = <&gpio TEGRA_GPIO(D, 2) GPIO_ACTIVE_LOW>; ++ }; ++ ++ ds3 { ++ label = "trimslice:green:left"; ++ gpios = <&gpio TEGRA_GPIO(BB, 5) GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ + poweroff { + compatible = "gpio-poweroff"; + gpios = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_LOW>; diff --git a/target/linux/x86/base-files/etc/diag.sh b/target/linux/x86/base-files/etc/diag.sh index d043e4f035..303dcbcdea 100644 --- a/target/linux/x86/base-files/etc/diag.sh +++ b/target/linux/x86/base-files/etc/diag.sh @@ -73,6 +73,10 @@ set_state() { status_led_blink_preinit_regular ;; + upgrade) + status_led_blink_preinit_regular + ;; + done) status_led_on ;; diff --git a/target/linux/zynq/config-5.4 b/target/linux/zynq/config-5.4 index b25d789db7..bfa5792dda 100644 --- a/target/linux/zynq/config-5.4 +++ b/target/linux/zynq/config-5.4 @@ -187,7 +187,6 @@ CONFIG_DRM_KMS_HELPER=y CONFIG_DRM_PANEL=y CONFIG_DRM_PANEL_BRIDGE=y CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y -# CONFIG_DRM_TVE200 is not set CONFIG_DTC=y CONFIG_DUMMY_CONSOLE=y CONFIG_E1000E=y diff --git a/tools/Makefile b/tools/Makefile index 0e99e442db..40407f008b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -24,8 +24,8 @@ endif tools-y += autoconf autoconf-archive automake bc bison cmake cpio dosfstools tools-y += e2fsprogs fakeroot findutils firmware-utils flex gengetopt tools-y += libressl libtool lzma m4 make-ext4fs missing-macros mkimage -tools-y += mklibs mm-macros mtd-utils mtools padjffs2 patch-image patchelf -tools-y += pkgconf quilt squashfskit4 sstrip ucl upx xxd zip zlib zstd +tools-y += mklibs mm-macros mtd-utils mtools ninja padjffs2 patch-image +tools-y += patchelf pkgconf quilt squashfskit4 sstrip ucl upx xxd zip zlib zstd tools-$(BUILD_B43_TOOLS) += b43-tools tools-$(BUILD_ISL) += isl tools-$(BUILD_TOOLCHAIN) += expat gmp mpc mpfr @@ -44,7 +44,7 @@ $(curdir)/b43-tools/compile := $(curdir)/bison/compile $(curdir)/bc/compile := $(curdir)/bison/compile $(curdir)/libtool/compile $(curdir)/bison/compile := $(curdir)/flex/compile $(curdir)/cbootimage/compile += $(curdir)/automake/compile -$(curdir)/cmake/compile += $(curdir)/libressl/compile +$(curdir)/cmake/compile += $(curdir)/libressl/compile $(curdir)/ninja/compile $(curdir)/dosfstools/compile := $(curdir)/autoconf/compile $(curdir)/automake/compile $(curdir)/e2fsprogs/compile := $(curdir)/libtool/compile $(curdir)/fakeroot/compile := $(curdir)/libtool/compile @@ -82,7 +82,7 @@ ifneq ($(HOST_OS),Linux) endif ifneq ($(CONFIG_CCACHE)$(CONFIG_SDK),) -$(foreach tool, $(filter-out xz zstd patch pkgconf libressl cmake,$(tools-y)), $(eval $(curdir)/$(tool)/compile += $(curdir)/ccache/compile)) +$(foreach tool, $(filter-out xz zstd patch pkgconf libressl ninja cmake,$(tools-y)), $(eval $(curdir)/$(tool)/compile += $(curdir)/ccache/compile)) tools-y += ccache $(curdir)/ccache/compile := $(curdir)/zstd/compile endif diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c index e5974325ae..86d51db269 100644 --- a/tools/firmware-utils/src/tplink-safeloader.c +++ b/tools/firmware-utils/src/tplink-safeloader.c @@ -1050,6 +1050,47 @@ static struct device_info boards[] = { .first_sysupgrade_partition = "os-image", .last_sysupgrade_partition = "file-system", }, + /** Firmware layout for the Archer C6 v3 */ + { + .id = "ARCHER-C6-V3", + .vendor = "", + .support_list = + "SupportList:\n" + "{product_name:Archer C6,product_ver:3.20,special_id:55530000}" + "{product_name:Archer C6,product_ver:3.20,special_id:45550000}" + "{product_name:Archer C6,product_ver:3.20,special_id:52550000}" + "{product_name:Archer C6,product_ver:3.20,special_id:4A500000}" + "{product_name:Archer C6,product_ver:3.20,special_id:4B520000}", + .part_trail = 0x00, + .soft_ver = "soft_ver:1.0.9\n", + + .partitions = { + {"fs-uboot", 0x00000, 0x40000}, + {"firmware", 0x40000, 0xf60000}, + {"default-mac", 0xfa0000, 0x00200}, + {"pin", 0xfa0200, 0x00100}, + {"device-id", 0xfa0300, 0x00100}, + {"product-info", 0xfa0400, 0x0fc00}, + {"default-config", 0xfb0000, 0x08000}, + {"ap-def-config", 0xfb8000, 0x08000}, + {"user-config", 0xfc0000, 0x0a000}, + {"ag-config", 0xfca000, 0x04000}, + {"certificate", 0xfce000, 0x02000}, + {"ap-config", 0xfd0000, 0x06000}, + {"router-config", 0xfd6000, 0x06000}, + {"favicon", 0xfdc000, 0x02000}, + {"logo", 0xfde000, 0x02000}, + {"partition-table", 0xfe0000, 0x00800}, + {"soft-version", 0xfe0800, 0x00100}, + {"support-list", 0xfe0900, 0x00200}, + {"profile", 0xfe0b00, 0x03000}, + {"extra-para", 0xfe3b00, 0x00100}, + {"radio", 0xff0000, 0x10000}, + {NULL, 0, 0} + }, + .first_sysupgrade_partition = "os-image", + .last_sysupgrade_partition = "file-system", + }, /** Firmware layout for the Archer A6 v3 */ { .id = "ARCHER-A6-V3", @@ -2896,6 +2937,7 @@ static void build_image(const char *output, strcasecmp(info->id, "ARCHER-C60-V2") == 0 || strcasecmp(info->id, "ARCHER-C60-V3") == 0 || strcasecmp(info->id, "ARCHER-C6U-V1") == 0 || + strcasecmp(info->id, "ARCHER-C6-V3") == 0 || strcasecmp(info->id, "TLWR1043NV5") == 0) { const uint8_t extra_para[2] = {0x01, 0x00}; parts[5] = make_extra_para(info, extra_para, diff --git a/tools/ninja/Makefile b/tools/ninja/Makefile new file mode 100644 index 0000000000..0ff642a740 --- /dev/null +++ b/tools/ninja/Makefile @@ -0,0 +1,39 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=ninja +PKG_VERSION:=1.10.2 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/ninja-build/ninja/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=ce35865411f0490368a8fc383f29071de6690cbadc27704734978221f25e2bed + +include $(INCLUDE_DIR)/host-build.mk + +CONFIGURE_ARGS:= +ifneq ($(findstring c,$(OPENWRT_VERBOSE)),) + CONFIGURE_ARGS+=--verbose +endif + +define Host/Configure +endef + +define Host/Compile + cd $(HOST_BUILD_DIR) && \ + CXX="$(HOSTCXX_NOCACHE)" \ + CXXFLAGS="$(HOST_CXXFLAGS) $(HOST_CPPFLAGS)" \ + LDFLAGS="$(HOST_LDFLAGS)" \ + $(STAGING_DIR_HOST)/bin/$(PYTHON) configure.py --bootstrap $(CONFIGURE_ARGS) +endef + +define Host/Install + $(INSTALL_DIR) $(STAGING_DIR_HOST)/bin + $(INSTALL_BIN) $(HOST_BUILD_DIR)/ninja $(STAGING_DIR_HOST)/bin/ +endef + +define Host/Clean + $(call Host/Clean/Default) + rm -f $(STAGING_DIR_HOST)/bin/ninja +endef + +$(eval $(call HostBuild)) diff --git a/tools/ninja/patches/100-make_jobserver_support.patch b/tools/ninja/patches/100-make_jobserver_support.patch new file mode 100644 index 0000000000..ecceaf23ca --- /dev/null +++ b/tools/ninja/patches/100-make_jobserver_support.patch @@ -0,0 +1,2279 @@ +From c1a081c00f803fc28e51f155f25abe8346ce5f13 Mon Sep 17 00:00:00 2001 +From: Stefan Becker +Date: Tue, 22 Mar 2016 13:48:07 +0200 +Subject: [PATCH] Add GNU make jobserver client support + +- add new TokenPool interface +- GNU make implementation for TokenPool parses and verifies the magic + information from the MAKEFLAGS environment variable +- RealCommandRunner tries to acquire TokenPool + * if no token pool is available then there is no change in behaviour +- When a token pool is available then RealCommandRunner behaviour + changes as follows + * CanRunMore() only returns true if TokenPool::Acquire() returns true + * StartCommand() calls TokenPool::Reserve() + * WaitForCommand() calls TokenPool::Release() + +Documentation for GNU make jobserver + + http://make.mad-scientist.net/papers/jobserver-implementation/ + +Fixes https://github.com/ninja-build/ninja/issues/1139 + +Add TokenPool monitoring to SubprocessSet::DoWork() + +Improve on the original jobserver client implementation. This makes +ninja a more aggressive GNU make jobserver client. + +- add monitor interface to TokenPool +- TokenPool is passed down when main loop indicates that more work is + ready and would be allowed to start if a token becomes available +- posix: update DoWork() to monitor TokenPool read file descriptor +- WaitForCommand() exits when DoWork() sets token flag +- Main loop starts over when WaitForCommand() sets token exit status + +Ignore jobserver when -jN is forced on command line + +This emulates the behaviour of GNU make. + +- add parallelism_from_cmdline flag to build configuration +- set the flag when -jN is given on command line +- pass the flag to TokenPool::Get() +- GNUmakeTokenPool::Setup() + * prints a warning when the flag is true and jobserver was detected + * returns false, i.e. jobserver will be ignored +- ignore config.parallelism in CanRunMore() when we have a valid + TokenPool, because it gets always initialized to a default when not + given on the command line + +Honor -lN from MAKEFLAGS + +This emulates the behaviour of GNU make. + +- build: make a copy of max_load_average and pass it to TokenPool. +- GNUmakeTokenPool: if we detect a jobserver and a valid -lN argument in + MAKEFLAGS then set max_load_average to N. + +Use LinePrinter for TokenPool messages + +- replace printf() with calls to LinePrinter +- print GNU make jobserver message only when verbose build is requested + +Prepare PR for merging + +- fix Windows build error in no-op TokenPool implementation +- improve Acquire() to block for a maximum of 100ms +- address review comments + +Add tests for TokenPool + +- TokenPool setup +- GetMonitorFd() API +- implicit token and tokens in jobserver pipe +- Acquire() / Reserve() / Release() protocol +- Clear() API + +Add tests for subprocess module + +- add TokenPoolTest stub to provide TokenPool::GetMonitorFd() +- add two tests + * both tests set up a dummy GNUmake jobserver pipe + * both tests call DoWork() with TokenPoolTest + * test 1: verify that DoWork() detects when a token is available + * test 2: verify that DoWork() works as before without a token +- the tests are not compiled in under Windows + +Add tests for build module + +Add tests that verify the token functionality of the builder main loop. +We replace the default fake command runner with a special version where +the tests can control each call to AcquireToken(), CanRunMore() and +WaitForCommand(). + +Add Win32 implementation for GNUmakeTokenPool + +GNU make uses a semaphore as jobserver protocol on Win32. See also + + https://www.gnu.org/software/make/manual/html_node/Windows-Jobserver.html + +Usage is pretty simple and straightforward, i.e. WaitForSingleObject() +to obtain a token and ReleaseSemaphore() to return it. + +Unfortunately subprocess-win32.cc uses an I/O completion port (IOCP). +IOCPs aren't waitable objects, i.e. we can't use WaitForMultipleObjects() +to wait on the IOCP and the token semaphore at the same time. + +Therefore GNUmakeTokenPoolWin32 creates a child thread that waits on the +token semaphore and posts a dummy I/O completion status on the IOCP when +it was able to obtain a token. That unblocks SubprocessSet::DoWork() and +it can then check if a token became available or not. + +- split existing GNUmakeTokenPool into common and platform bits +- add GNUmakeTokenPool interface +- move the Posix bits to GNUmakeTokenPoolPosix +- add the Win32 bits as GNUmakeTokenPoolWin32 +- move Setup() method up to TokenPool interface +- update Subprocess & TokenPool tests accordingly + +Prepare PR for merging - part II + +- remove unnecessary "struct" from TokenPool +- add PAPCFUNC cast to QueryUserAPC() +- remove hard-coded MAKEFLAGS string from win32 +- remove useless build test CompleteNoWork +- rename TokenPoolTest to TestTokenPool +- add tokenpool modules to CMake build +- remove unused no-op TokenPool implementation +- address review comments from + +https://github.com/ninja-build/ninja/pull/1140#pullrequestreview-195195803 +https://github.com/ninja-build/ninja/pull/1140#pullrequestreview-185089255 +https://github.com/ninja-build/ninja/pull/1140#issuecomment-473898963 +https://github.com/ninja-build/ninja/pull/1140#issuecomment-596624610 +--- + CMakeLists.txt | 8 +- + configure.py | 7 +- + src/build.cc | 127 ++++++++--- + src/build.h | 12 +- + src/build_test.cc | 363 +++++++++++++++++++++++++++++++- + src/exit_status.h | 3 +- + src/ninja.cc | 1 + + src/subprocess-posix.cc | 33 ++- + src/subprocess-win32.cc | 11 +- + src/subprocess.h | 8 +- + src/subprocess_test.cc | 149 +++++++++++-- + src/tokenpool-gnu-make-posix.cc | 202 ++++++++++++++++++ + src/tokenpool-gnu-make-win32.cc | 239 +++++++++++++++++++++ + src/tokenpool-gnu-make.cc | 108 ++++++++++ + src/tokenpool-gnu-make.h | 40 ++++ + src/tokenpool.h | 42 ++++ + src/tokenpool_test.cc | 269 +++++++++++++++++++++++ + 17 files changed, 1562 insertions(+), 60 deletions(-) + create mode 100644 src/tokenpool-gnu-make-posix.cc + create mode 100644 src/tokenpool-gnu-make-win32.cc + create mode 100644 src/tokenpool-gnu-make.cc + create mode 100644 src/tokenpool-gnu-make.h + create mode 100644 src/tokenpool.h + create mode 100644 src/tokenpool_test.cc + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -94,6 +94,7 @@ add_library(libninja OBJECT + src/parser.cc + src/state.cc + src/string_piece_util.cc ++ src/tokenpool-gnu-make.cc + src/util.cc + src/version.cc + ) +@@ -104,12 +105,16 @@ if(WIN32) + src/msvc_helper-win32.cc + src/msvc_helper_main-win32.cc + src/getopt.c ++ src/tokenpool-gnu-make-win32.cc + ) + if(MSVC) + target_sources(libninja PRIVATE src/minidump-win32.cc) + endif() + else() +- target_sources(libninja PRIVATE src/subprocess-posix.cc) ++ target_sources(libninja PRIVATE ++ src/subprocess-posix.cc ++ src/tokenpool-gnu-make-posix.cc ++ ) + if(CMAKE_SYSTEM_NAME STREQUAL "OS400" OR CMAKE_SYSTEM_NAME STREQUAL "AIX") + target_sources(libninja PRIVATE src/getopt.c) + endif() +@@ -182,6 +187,7 @@ if(BUILD_TESTING) + src/string_piece_util_test.cc + src/subprocess_test.cc + src/test.cc ++ src/tokenpool_test.cc + src/util_test.cc + ) + if(WIN32) +--- a/configure.py ++++ b/configure.py +@@ -514,11 +514,13 @@ for name in ['build', + 'parser', + 'state', + 'string_piece_util', ++ 'tokenpool-gnu-make', + 'util', + 'version']: + objs += cxx(name, variables=cxxvariables) + if platform.is_windows(): + for name in ['subprocess-win32', ++ 'tokenpool-gnu-make-win32', + 'includes_normalize-win32', + 'msvc_helper-win32', + 'msvc_helper_main-win32']: +@@ -527,7 +529,9 @@ if platform.is_windows(): + objs += cxx('minidump-win32', variables=cxxvariables) + objs += cc('getopt') + else: +- objs += cxx('subprocess-posix') ++ for name in ['subprocess-posix', ++ 'tokenpool-gnu-make-posix']: ++ objs += cxx(name) + if platform.is_aix(): + objs += cc('getopt') + if platform.is_msvc(): +@@ -582,6 +586,7 @@ for name in ['build_log_test', + 'string_piece_util_test', + 'subprocess_test', + 'test', ++ 'tokenpool_test', + 'util_test']: + objs += cxx(name, variables=cxxvariables) + if platform.is_windows(): +--- a/src/build.cc ++++ b/src/build.cc +@@ -38,6 +38,7 @@ + #include "graph.h" + #include "state.h" + #include "subprocess.h" ++#include "tokenpool.h" + #include "util.h" + + using namespace std; +@@ -50,8 +51,9 @@ struct DryRunCommandRunner : public Comm + + // Overridden from CommandRunner: + virtual bool CanRunMore() const; ++ virtual bool AcquireToken(); + virtual bool StartCommand(Edge* edge); +- virtual bool WaitForCommand(Result* result); ++ virtual bool WaitForCommand(Result* result, bool more_ready); + + private: + queue finished_; +@@ -61,12 +63,16 @@ bool DryRunCommandRunner::CanRunMore() c + return true; + } + ++bool DryRunCommandRunner::AcquireToken() { ++ return true; ++} ++ + bool DryRunCommandRunner::StartCommand(Edge* edge) { + finished_.push(edge); + return true; + } + +-bool DryRunCommandRunner::WaitForCommand(Result* result) { ++bool DryRunCommandRunner::WaitForCommand(Result* result, bool more_ready) { + if (finished_.empty()) + return false; + +@@ -379,7 +385,7 @@ void Plan::EdgeWanted(const Edge* edge) + } + + Edge* Plan::FindWork() { +- if (ready_.empty()) ++ if (!more_ready()) + return NULL; + set::iterator e = ready_.begin(); + Edge* edge = *e; +@@ -665,19 +671,39 @@ void Plan::Dump() const { + } + + struct RealCommandRunner : public CommandRunner { +- explicit RealCommandRunner(const BuildConfig& config) : config_(config) {} +- virtual ~RealCommandRunner() {} ++ explicit RealCommandRunner(const BuildConfig& config); ++ virtual ~RealCommandRunner(); + virtual bool CanRunMore() const; ++ virtual bool AcquireToken(); + virtual bool StartCommand(Edge* edge); +- virtual bool WaitForCommand(Result* result); ++ virtual bool WaitForCommand(Result* result, bool more_ready); + virtual vector GetActiveEdges(); + virtual void Abort(); + + const BuildConfig& config_; ++ // copy of config_.max_load_average; can be modified by TokenPool setup ++ double max_load_average_; + SubprocessSet subprocs_; ++ TokenPool* tokens_; + map subproc_to_edge_; + }; + ++RealCommandRunner::RealCommandRunner(const BuildConfig& config) : config_(config) { ++ max_load_average_ = config.max_load_average; ++ if ((tokens_ = TokenPool::Get()) != NULL) { ++ if (!tokens_->Setup(config_.parallelism_from_cmdline, ++ config_.verbosity == BuildConfig::VERBOSE, ++ max_load_average_)) { ++ delete tokens_; ++ tokens_ = NULL; ++ } ++ } ++} ++ ++RealCommandRunner::~RealCommandRunner() { ++ delete tokens_; ++} ++ + vector RealCommandRunner::GetActiveEdges() { + vector edges; + for (map::iterator e = subproc_to_edge_.begin(); +@@ -688,14 +714,23 @@ vector RealCommandRunner::GetActi + + void RealCommandRunner::Abort() { + subprocs_.Clear(); ++ if (tokens_) ++ tokens_->Clear(); + } + + bool RealCommandRunner::CanRunMore() const { +- size_t subproc_number = +- subprocs_.running_.size() + subprocs_.finished_.size(); +- return (int)subproc_number < config_.parallelism +- && ((subprocs_.running_.empty() || config_.max_load_average <= 0.0f) +- || GetLoadAverage() < config_.max_load_average); ++ bool parallelism_limit_not_reached = ++ tokens_ || // ignore config_.parallelism ++ ((int) (subprocs_.running_.size() + ++ subprocs_.finished_.size()) < config_.parallelism); ++ return parallelism_limit_not_reached ++ && (subprocs_.running_.empty() || ++ (max_load_average_ <= 0.0f || ++ GetLoadAverage() < max_load_average_)); ++} ++ ++bool RealCommandRunner::AcquireToken() { ++ return (!tokens_ || tokens_->Acquire()); + } + + bool RealCommandRunner::StartCommand(Edge* edge) { +@@ -703,19 +738,33 @@ bool RealCommandRunner::StartCommand(Edg + Subprocess* subproc = subprocs_.Add(command, edge->use_console()); + if (!subproc) + return false; ++ if (tokens_) ++ tokens_->Reserve(); + subproc_to_edge_.insert(make_pair(subproc, edge)); + + return true; + } + +-bool RealCommandRunner::WaitForCommand(Result* result) { ++bool RealCommandRunner::WaitForCommand(Result* result, bool more_ready) { + Subprocess* subproc; +- while ((subproc = subprocs_.NextFinished()) == NULL) { +- bool interrupted = subprocs_.DoWork(); ++ subprocs_.ResetTokenAvailable(); ++ while (((subproc = subprocs_.NextFinished()) == NULL) && ++ !subprocs_.IsTokenAvailable()) { ++ bool interrupted = subprocs_.DoWork(more_ready ? tokens_ : NULL); + if (interrupted) + return false; + } + ++ // token became available ++ if (subproc == NULL) { ++ result->status = ExitTokenAvailable; ++ return true; ++ } ++ ++ // command completed ++ if (tokens_) ++ tokens_->Release(); ++ + result->status = subproc->Finish(); + result->output = subproc->GetOutput(); + +@@ -825,38 +874,42 @@ bool Builder::Build(string* err) { + // command runner. + // Second, we attempt to wait for / reap the next finished command. + while (plan_.more_to_do()) { +- // See if we can start any more commands. +- if (failures_allowed && command_runner_->CanRunMore()) { +- if (Edge* edge = plan_.FindWork()) { +- if (edge->GetBindingBool("generator")) { +- scan_.build_log()->Close(); +- } ++ // See if we can start any more commands... ++ bool can_run_more = ++ failures_allowed && ++ plan_.more_ready() && ++ command_runner_->CanRunMore(); ++ ++ // ... but we also need a token to do that. ++ if (can_run_more && command_runner_->AcquireToken()) { ++ Edge* edge = plan_.FindWork(); ++ if (edge->GetBindingBool("generator")) { ++ scan_.build_log()->Close(); ++ } ++ if (!StartEdge(edge, err)) { ++ Cleanup(); ++ status_->BuildFinished(); ++ return false; ++ } + +- if (!StartEdge(edge, err)) { ++ if (edge->is_phony()) { ++ if (!plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, err)) { + Cleanup(); + status_->BuildFinished(); + return false; + } +- +- if (edge->is_phony()) { +- if (!plan_.EdgeFinished(edge, Plan::kEdgeSucceeded, err)) { +- Cleanup(); +- status_->BuildFinished(); +- return false; +- } +- } else { +- ++pending_commands; +- } +- +- // We made some progress; go back to the main loop. +- continue; ++ } else { ++ ++pending_commands; + } ++ ++ // We made some progress; go back to the main loop. ++ continue; + } + + // See if we can reap any finished commands. + if (pending_commands) { + CommandRunner::Result result; +- if (!command_runner_->WaitForCommand(&result) || ++ if (!command_runner_->WaitForCommand(&result, can_run_more) || + result.status == ExitInterrupted) { + Cleanup(); + status_->BuildFinished(); +@@ -864,6 +917,10 @@ bool Builder::Build(string* err) { + return false; + } + ++ // We might be able to start another command; start the main loop over. ++ if (result.status == ExitTokenAvailable) ++ continue; ++ + --pending_commands; + if (!FinishCommand(&result, err)) { + Cleanup(); +--- a/src/build.h ++++ b/src/build.h +@@ -55,6 +55,9 @@ struct Plan { + /// Returns true if there's more work to be done. + bool more_to_do() const { return wanted_edges_ > 0 && command_edges_ > 0; } + ++ /// Returns true if there's more edges ready to start ++ bool more_ready() const { return !ready_.empty(); } ++ + /// Dumps the current state of the plan. + void Dump() const; + +@@ -139,6 +142,7 @@ private: + struct CommandRunner { + virtual ~CommandRunner() {} + virtual bool CanRunMore() const = 0; ++ virtual bool AcquireToken() = 0; + virtual bool StartCommand(Edge* edge) = 0; + + /// The result of waiting for a command. +@@ -150,7 +154,9 @@ struct CommandRunner { + bool success() const { return status == ExitSuccess; } + }; + /// Wait for a command to complete, or return false if interrupted. +- virtual bool WaitForCommand(Result* result) = 0; ++ /// If more_ready is true then the optional TokenPool is monitored too ++ /// and we return when a token becomes available. ++ virtual bool WaitForCommand(Result* result, bool more_ready) = 0; + + virtual std::vector GetActiveEdges() { return std::vector(); } + virtual void Abort() {} +@@ -158,7 +164,8 @@ struct CommandRunner { + + /// Options (e.g. verbosity, parallelism) passed to a build. + struct BuildConfig { +- BuildConfig() : verbosity(NORMAL), dry_run(false), parallelism(1), ++ BuildConfig() : verbosity(NORMAL), dry_run(false), ++ parallelism(1), parallelism_from_cmdline(false), + failures_allowed(1), max_load_average(-0.0f) {} + + enum Verbosity { +@@ -169,6 +176,7 @@ struct BuildConfig { + Verbosity verbosity; + bool dry_run; + int parallelism; ++ bool parallelism_from_cmdline; + int failures_allowed; + /// The maximum load average we must not exceed. A negative value + /// means that we do not have any limit. +--- a/src/build_test.cc ++++ b/src/build_test.cc +@@ -15,6 +15,7 @@ + #include "build.h" + + #include ++#include + + #include "build_log.h" + #include "deps_log.h" +@@ -473,8 +474,9 @@ struct FakeCommandRunner : public Comman + + // CommandRunner impl + virtual bool CanRunMore() const; ++ virtual bool AcquireToken(); + virtual bool StartCommand(Edge* edge); +- virtual bool WaitForCommand(Result* result); ++ virtual bool WaitForCommand(Result* result, bool more_ready); + virtual vector GetActiveEdges(); + virtual void Abort(); + +@@ -580,6 +582,10 @@ bool FakeCommandRunner::CanRunMore() con + return active_edges_.size() < max_active_edges_; + } + ++bool FakeCommandRunner::AcquireToken() { ++ return true; ++} ++ + bool FakeCommandRunner::StartCommand(Edge* edge) { + assert(active_edges_.size() < max_active_edges_); + assert(find(active_edges_.begin(), active_edges_.end(), edge) +@@ -625,7 +631,7 @@ bool FakeCommandRunner::StartCommand(Edg + return true; + } + +-bool FakeCommandRunner::WaitForCommand(Result* result) { ++bool FakeCommandRunner::WaitForCommand(Result* result, bool more_ready) { + if (active_edges_.empty()) + return false; + +@@ -3302,3 +3308,356 @@ TEST_F(BuildTest, DyndepTwoLevelDiscover + EXPECT_EQ("touch tmp", command_runner_.commands_ran_[3]); + EXPECT_EQ("touch out", command_runner_.commands_ran_[4]); + } ++ ++/// The token tests are concerned with the main loop functionality when ++// the CommandRunner has an active TokenPool. It is therefore intentional ++// that the plan doesn't complete and that builder_.Build() returns false! ++ ++/// Fake implementation of CommandRunner that simulates a TokenPool ++struct FakeTokenCommandRunner : public CommandRunner { ++ explicit FakeTokenCommandRunner() {} ++ ++ // CommandRunner impl ++ virtual bool CanRunMore() const; ++ virtual bool AcquireToken(); ++ virtual bool StartCommand(Edge* edge); ++ virtual bool WaitForCommand(Result* result, bool more_ready); ++ virtual vector GetActiveEdges(); ++ virtual void Abort(); ++ ++ vector commands_ran_; ++ vector edges_; ++ ++ vector acquire_token_; ++ vector can_run_more_; ++ vector wait_for_command_; ++}; ++ ++bool FakeTokenCommandRunner::CanRunMore() const { ++ if (can_run_more_.size() == 0) { ++ EXPECT_FALSE("unexpected call to CommandRunner::CanRunMore()"); ++ return false; ++ } ++ ++ bool result = can_run_more_[0]; ++ ++ // Unfortunately CanRunMore() isn't "const" for tests ++ const_cast(this)->can_run_more_.erase( ++ const_cast(this)->can_run_more_.begin() ++ ); ++ ++ return result; ++} ++ ++bool FakeTokenCommandRunner::AcquireToken() { ++ if (acquire_token_.size() == 0) { ++ EXPECT_FALSE("unexpected call to CommandRunner::AcquireToken()"); ++ return false; ++ } ++ ++ bool result = acquire_token_[0]; ++ acquire_token_.erase(acquire_token_.begin()); ++ return result; ++} ++ ++bool FakeTokenCommandRunner::StartCommand(Edge* edge) { ++ commands_ran_.push_back(edge->EvaluateCommand()); ++ edges_.push_back(edge); ++ return true; ++} ++ ++bool FakeTokenCommandRunner::WaitForCommand(Result* result, bool more_ready) { ++ if (wait_for_command_.size() == 0) { ++ EXPECT_FALSE("unexpected call to CommandRunner::WaitForCommand()"); ++ return false; ++ } ++ ++ bool expected = wait_for_command_[0]; ++ if (expected != more_ready) { ++ EXPECT_EQ(expected, more_ready); ++ return false; ++ } ++ wait_for_command_.erase(wait_for_command_.begin()); ++ ++ if (edges_.size() == 0) ++ return false; ++ ++ Edge* edge = edges_[0]; ++ result->edge = edge; ++ ++ if (more_ready && ++ (edge->rule().name() == "token-available")) { ++ result->status = ExitTokenAvailable; ++ } else { ++ edges_.erase(edges_.begin()); ++ result->status = ExitSuccess; ++ } ++ ++ return true; ++} ++ ++vector FakeTokenCommandRunner::GetActiveEdges() { ++ return edges_; ++} ++ ++void FakeTokenCommandRunner::Abort() { ++ edges_.clear(); ++} ++ ++struct BuildTokenTest : public BuildTest { ++ virtual void SetUp(); ++ virtual void TearDown(); ++ ++ FakeTokenCommandRunner token_command_runner_; ++ ++ void ExpectAcquireToken(int count, ...); ++ void ExpectCanRunMore(int count, ...); ++ void ExpectWaitForCommand(int count, ...); ++ ++private: ++ void EnqueueBooleans(vector& booleans, int count, va_list ao); ++}; ++ ++void BuildTokenTest::SetUp() { ++ BuildTest::SetUp(); ++ ++ // replace FakeCommandRunner with FakeTokenCommandRunner ++ builder_.command_runner_.release(); ++ builder_.command_runner_.reset(&token_command_runner_); ++} ++void BuildTokenTest::TearDown() { ++ EXPECT_EQ(0u, token_command_runner_.acquire_token_.size()); ++ EXPECT_EQ(0u, token_command_runner_.can_run_more_.size()); ++ EXPECT_EQ(0u, token_command_runner_.wait_for_command_.size()); ++ ++ BuildTest::TearDown(); ++} ++ ++void BuildTokenTest::ExpectAcquireToken(int count, ...) { ++ va_list ap; ++ va_start(ap, count); ++ EnqueueBooleans(token_command_runner_.acquire_token_, count, ap); ++ va_end(ap); ++} ++ ++void BuildTokenTest::ExpectCanRunMore(int count, ...) { ++ va_list ap; ++ va_start(ap, count); ++ EnqueueBooleans(token_command_runner_.can_run_more_, count, ap); ++ va_end(ap); ++} ++ ++void BuildTokenTest::ExpectWaitForCommand(int count, ...) { ++ va_list ap; ++ va_start(ap, count); ++ EnqueueBooleans(token_command_runner_.wait_for_command_, count, ap); ++ va_end(ap); ++} ++ ++void BuildTokenTest::EnqueueBooleans(vector& booleans, int count, va_list ap) { ++ while (count--) { ++ int value = va_arg(ap, int); ++ booleans.push_back(!!value); // force bool ++ } ++} ++ ++TEST_F(BuildTokenTest, DoNotAquireToken) { ++ // plan should execute one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat1", &err)); ++ ASSERT_EQ("", err); ++ ++ // pretend we can't run anything ++ ExpectCanRunMore(1, false); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(0u, token_command_runner_.commands_ran_.size()); ++} ++ ++TEST_F(BuildTokenTest, DoNotStartWithoutToken) { ++ // plan should execute one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat1", &err)); ++ ASSERT_EQ("", err); ++ ++ // we could run a command but do not have a token for it ++ ExpectCanRunMore(1, true); ++ ExpectAcquireToken(1, false); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(0u, token_command_runner_.commands_ran_.size()); ++} ++ ++TEST_F(BuildTokenTest, CompleteOneStep) { ++ // plan should execute one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat1", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of one command ++ ExpectCanRunMore(1, true); ++ ExpectAcquireToken(1, true); ++ // block and wait for command to finalize ++ ExpectWaitForCommand(1, false); ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(1u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[0] == "cat in1 > cat1"); ++} ++ ++TEST_F(BuildTokenTest, AcquireOneToken) { ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat12", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of one command ++ ExpectCanRunMore(3, true, false, false); ++ ExpectAcquireToken(1, true); ++ // block and wait for command to finalize ++ ExpectWaitForCommand(1, false); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(1u, token_command_runner_.commands_ran_.size()); ++ // any of the two dependencies could have been executed ++ EXPECT_TRUE(token_command_runner_.commands_ran_[0] == "cat in1 > cat1" || ++ token_command_runner_.commands_ran_[0] == "cat in1 in2 > cat2"); ++} ++ ++TEST_F(BuildTokenTest, WantTwoTokens) { ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat12", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of one command ++ ExpectCanRunMore(3, true, true, false); ++ ExpectAcquireToken(2, true, false); ++ // wait for command to finalize or token to become available ++ ExpectWaitForCommand(1, true); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(1u, token_command_runner_.commands_ran_.size()); ++ // any of the two dependencies could have been executed ++ EXPECT_TRUE(token_command_runner_.commands_ran_[0] == "cat in1 > cat1" || ++ token_command_runner_.commands_ran_[0] == "cat in1 in2 > cat2"); ++} ++ ++TEST_F(BuildTokenTest, CompleteTwoSteps) { ++ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, ++"build out1: cat in1\n" ++"build out2: cat out1\n")); ++ ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("out2", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of two commands ++ ExpectCanRunMore(2, true, true); ++ ExpectAcquireToken(2, true, true); ++ // wait for commands to finalize ++ ExpectWaitForCommand(2, false, false); ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(2u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[0] == "cat in1 > out1"); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[1] == "cat out1 > out2"); ++} ++ ++TEST_F(BuildTokenTest, TwoCommandsInParallel) { ++ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, ++"rule token-available\n" ++" command = cat $in > $out\n" ++"build out1: token-available in1\n" ++"build out2: token-available in2\n" ++"build out12: cat out1 out2\n")); ++ ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("out12", &err)); ++ ASSERT_EQ("", err); ++ ++ // 1st command: token available -> allow running ++ // 2nd command: no token available but becomes available later ++ ExpectCanRunMore(4, true, true, true, false); ++ ExpectAcquireToken(3, true, false, true); ++ // 1st call waits for command to finalize or token to become available ++ // 2nd call waits for command to finalize ++ // 3rd call waits for command to finalize ++ ExpectWaitForCommand(3, true, false, false); ++ ++ EXPECT_FALSE(builder_.Build(&err)); ++ EXPECT_EQ("stuck [this is a bug]", err); ++ ++ EXPECT_EQ(2u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE((token_command_runner_.commands_ran_[0] == "cat in1 > out1" && ++ token_command_runner_.commands_ran_[1] == "cat in2 > out2") || ++ (token_command_runner_.commands_ran_[0] == "cat in2 > out2" && ++ token_command_runner_.commands_ran_[1] == "cat in1 > out1")); ++} ++ ++TEST_F(BuildTokenTest, CompleteThreeStepsSerial) { ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("cat12", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of all commands ++ ExpectCanRunMore(4, true, true, true, true); ++ ExpectAcquireToken(4, true, false, true, true); ++ // wait for commands to finalize ++ ExpectWaitForCommand(3, true, false, false); ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(3u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE((token_command_runner_.commands_ran_[0] == "cat in1 > cat1" && ++ token_command_runner_.commands_ran_[1] == "cat in1 in2 > cat2") || ++ (token_command_runner_.commands_ran_[0] == "cat in1 in2 > cat2" && ++ token_command_runner_.commands_ran_[1] == "cat in1 > cat1" )); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[2] == "cat cat1 cat2 > cat12"); ++} ++ ++TEST_F(BuildTokenTest, CompleteThreeStepsParallel) { ++ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, ++"rule token-available\n" ++" command = cat $in > $out\n" ++"build out1: token-available in1\n" ++"build out2: token-available in2\n" ++"build out12: cat out1 out2\n")); ++ ++ // plan should execute more than one command ++ string err; ++ EXPECT_TRUE(builder_.AddTarget("out12", &err)); ++ ASSERT_EQ("", err); ++ ++ // allow running of all commands ++ ExpectCanRunMore(4, true, true, true, true); ++ ExpectAcquireToken(4, true, false, true, true); ++ // wait for commands to finalize ++ ExpectWaitForCommand(4, true, false, false, false); ++ ++ EXPECT_TRUE(builder_.Build(&err)); ++ EXPECT_EQ("", err); ++ ++ EXPECT_EQ(3u, token_command_runner_.commands_ran_.size()); ++ EXPECT_TRUE((token_command_runner_.commands_ran_[0] == "cat in1 > out1" && ++ token_command_runner_.commands_ran_[1] == "cat in2 > out2") || ++ (token_command_runner_.commands_ran_[0] == "cat in2 > out2" && ++ token_command_runner_.commands_ran_[1] == "cat in1 > out1")); ++ EXPECT_TRUE(token_command_runner_.commands_ran_[2] == "cat out1 out2 > out12"); ++} +--- a/src/exit_status.h ++++ b/src/exit_status.h +@@ -18,7 +18,8 @@ + enum ExitStatus { + ExitSuccess, + ExitFailure, +- ExitInterrupted ++ ExitTokenAvailable, ++ ExitInterrupted, + }; + + #endif // NINJA_EXIT_STATUS_H_ +--- a/src/ninja.cc ++++ b/src/ninja.cc +@@ -1289,6 +1289,7 @@ int ReadFlags(int* argc, char*** argv, + // We want to run N jobs in parallel. For N = 0, INT_MAX + // is close enough to infinite for most sane builds. + config->parallelism = value > 0 ? value : INT_MAX; ++ config->parallelism_from_cmdline = true; + break; + } + case 'k': { +--- a/src/subprocess-posix.cc ++++ b/src/subprocess-posix.cc +@@ -13,6 +13,7 @@ + // limitations under the License. + + #include "subprocess.h" ++#include "tokenpool.h" + + #include + #include +@@ -249,7 +250,7 @@ Subprocess *SubprocessSet::Add(const str + } + + #ifdef USE_PPOLL +-bool SubprocessSet::DoWork() { ++bool SubprocessSet::DoWork(TokenPool* tokens) { + vector fds; + nfds_t nfds = 0; + +@@ -263,6 +264,12 @@ bool SubprocessSet::DoWork() { + ++nfds; + } + ++ if (tokens) { ++ pollfd pfd = { tokens->GetMonitorFd(), POLLIN | POLLPRI, 0 }; ++ fds.push_back(pfd); ++ ++nfds; ++ } ++ + interrupted_ = 0; + int ret = ppoll(&fds.front(), nfds, NULL, &old_mask_); + if (ret == -1) { +@@ -295,11 +302,20 @@ bool SubprocessSet::DoWork() { + ++i; + } + ++ if (tokens) { ++ pollfd *pfd = &fds[nfds - 1]; ++ if (pfd->fd >= 0) { ++ assert(pfd->fd == tokens->GetMonitorFd()); ++ if (pfd->revents != 0) ++ token_available_ = true; ++ } ++ } ++ + return IsInterrupted(); + } + + #else // !defined(USE_PPOLL) +-bool SubprocessSet::DoWork() { ++bool SubprocessSet::DoWork(TokenPool* tokens) { + fd_set set; + int nfds = 0; + FD_ZERO(&set); +@@ -314,6 +330,13 @@ bool SubprocessSet::DoWork() { + } + } + ++ if (tokens) { ++ int fd = tokens->GetMonitorFd(); ++ FD_SET(fd, &set); ++ if (nfds < fd+1) ++ nfds = fd+1; ++ } ++ + interrupted_ = 0; + int ret = pselect(nfds, &set, 0, 0, 0, &old_mask_); + if (ret == -1) { +@@ -342,6 +365,12 @@ bool SubprocessSet::DoWork() { + ++i; + } + ++ if (tokens) { ++ int fd = tokens->GetMonitorFd(); ++ if ((fd >= 0) && FD_ISSET(fd, &set)) ++ token_available_ = true; ++ } ++ + return IsInterrupted(); + } + #endif // !defined(USE_PPOLL) +--- a/src/subprocess-win32.cc ++++ b/src/subprocess-win32.cc +@@ -13,6 +13,7 @@ + // limitations under the License. + + #include "subprocess.h" ++#include "tokenpool.h" + + #include + #include +@@ -251,11 +252,14 @@ Subprocess *SubprocessSet::Add(const str + return subprocess; + } + +-bool SubprocessSet::DoWork() { ++bool SubprocessSet::DoWork(TokenPool* tokens) { + DWORD bytes_read; + Subprocess* subproc; + OVERLAPPED* overlapped; + ++ if (tokens) ++ tokens->WaitForTokenAvailability(ioport_); ++ + if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc, + &overlapped, INFINITE)) { + if (GetLastError() != ERROR_BROKEN_PIPE) +@@ -266,6 +270,11 @@ bool SubprocessSet::DoWork() { + // delivered by NotifyInterrupted above. + return true; + ++ if (tokens && tokens->TokenIsAvailable((ULONG_PTR)subproc)) { ++ token_available_ = true; ++ return false; ++ } ++ + subproc->OnPipeReady(); + + if (subproc->Done()) { +--- a/src/subprocess.h ++++ b/src/subprocess.h +@@ -76,6 +76,8 @@ struct Subprocess { + friend struct SubprocessSet; + }; + ++struct TokenPool; ++ + /// SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses. + /// DoWork() waits for any state change in subprocesses; finished_ + /// is a queue of subprocesses as they finish. +@@ -84,13 +86,17 @@ struct SubprocessSet { + ~SubprocessSet(); + + Subprocess* Add(const std::string& command, bool use_console = false); +- bool DoWork(); ++ bool DoWork(struct TokenPool* tokens); + Subprocess* NextFinished(); + void Clear(); + + std::vector running_; + std::queue finished_; + ++ bool token_available_; ++ bool IsTokenAvailable() { return token_available_; } ++ void ResetTokenAvailable() { token_available_ = false; } ++ + #ifdef _WIN32 + static BOOL WINAPI NotifyInterrupted(DWORD dwCtrlType); + static HANDLE ioport_; +--- a/src/subprocess_test.cc ++++ b/src/subprocess_test.cc +@@ -13,6 +13,7 @@ + // limitations under the License. + + #include "subprocess.h" ++#include "tokenpool.h" + + #include "test.h" + +@@ -34,8 +35,30 @@ const char* kSimpleCommand = "cmd /c dir + const char* kSimpleCommand = "ls /"; + #endif + ++struct TestTokenPool : public TokenPool { ++ bool Acquire() { return false; } ++ void Reserve() {} ++ void Release() {} ++ void Clear() {} ++ bool Setup(bool ignore_unused, bool verbose, double& max_load_average) { return false; } ++ ++#ifdef _WIN32 ++ bool _token_available; ++ void WaitForTokenAvailability(HANDLE ioport) { ++ if (_token_available) ++ // unblock GetQueuedCompletionStatus() ++ PostQueuedCompletionStatus(ioport, 0, (ULONG_PTR) this, NULL); ++ } ++ bool TokenIsAvailable(ULONG_PTR key) { return key == (ULONG_PTR) this; } ++#else ++ int _fd; ++ int GetMonitorFd() { return _fd; } ++#endif ++}; ++ + struct SubprocessTest : public testing::Test { + SubprocessSet subprocs_; ++ TestTokenPool tokens_; + }; + + } // anonymous namespace +@@ -45,10 +68,12 @@ TEST_F(SubprocessTest, BadCommandStderr) + Subprocess* subproc = subprocs_.Add("cmd /c ninja_no_such_command"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { + // Pretend we discovered that stderr was ready for writing. +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitFailure, subproc->Finish()); + EXPECT_NE("", subproc->GetOutput()); +@@ -59,10 +84,12 @@ TEST_F(SubprocessTest, NoSuchCommand) { + Subprocess* subproc = subprocs_.Add("ninja_no_such_command"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { + // Pretend we discovered that stderr was ready for writing. +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitFailure, subproc->Finish()); + EXPECT_NE("", subproc->GetOutput()); +@@ -78,9 +105,11 @@ TEST_F(SubprocessTest, InterruptChild) { + Subprocess* subproc = subprocs_.Add("kill -INT $$"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -90,7 +119,7 @@ TEST_F(SubprocessTest, InterruptParent) + ASSERT_NE((Subprocess *) 0, subproc); + + while (!subproc->Done()) { +- bool interrupted = subprocs_.DoWork(); ++ bool interrupted = subprocs_.DoWork(NULL); + if (interrupted) + return; + } +@@ -102,9 +131,11 @@ TEST_F(SubprocessTest, InterruptChildWit + Subprocess* subproc = subprocs_.Add("kill -TERM $$"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -114,7 +145,7 @@ TEST_F(SubprocessTest, InterruptParentWi + ASSERT_NE((Subprocess *) 0, subproc); + + while (!subproc->Done()) { +- bool interrupted = subprocs_.DoWork(); ++ bool interrupted = subprocs_.DoWork(NULL); + if (interrupted) + return; + } +@@ -126,9 +157,11 @@ TEST_F(SubprocessTest, InterruptChildWit + Subprocess* subproc = subprocs_.Add("kill -HUP $$"); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitInterrupted, subproc->Finish()); + } +@@ -138,7 +171,7 @@ TEST_F(SubprocessTest, InterruptParentWi + ASSERT_NE((Subprocess *) 0, subproc); + + while (!subproc->Done()) { +- bool interrupted = subprocs_.DoWork(); ++ bool interrupted = subprocs_.DoWork(NULL); + if (interrupted) + return; + } +@@ -153,9 +186,11 @@ TEST_F(SubprocessTest, Console) { + subprocs_.Add("test -t 0 -a -t 1 -a -t 2", /*use_console=*/true); + ASSERT_NE((Subprocess*)0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + + EXPECT_EQ(ExitSuccess, subproc->Finish()); + } +@@ -167,9 +202,11 @@ TEST_F(SubprocessTest, SetWithSingle) { + Subprocess* subproc = subprocs_.Add(kSimpleCommand); + ASSERT_NE((Subprocess *) 0, subproc); + ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + ASSERT_EQ(ExitSuccess, subproc->Finish()); + ASSERT_NE("", subproc->GetOutput()); + +@@ -200,12 +237,13 @@ TEST_F(SubprocessTest, SetWithMulti) { + ASSERT_EQ("", processes[i]->GetOutput()); + } + ++ subprocs_.ResetTokenAvailable(); + while (!processes[0]->Done() || !processes[1]->Done() || + !processes[2]->Done()) { + ASSERT_GT(subprocs_.running_.size(), 0u); +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } +- ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + ASSERT_EQ(0u, subprocs_.running_.size()); + ASSERT_EQ(3u, subprocs_.finished_.size()); + +@@ -237,8 +275,10 @@ TEST_F(SubprocessTest, SetWithLots) { + ASSERT_NE((Subprocess *) 0, subproc); + procs.push_back(subproc); + } ++ subprocs_.ResetTokenAvailable(); + while (!subprocs_.running_.empty()) +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + for (size_t i = 0; i < procs.size(); ++i) { + ASSERT_EQ(ExitSuccess, procs[i]->Finish()); + ASSERT_NE("", procs[i]->GetOutput()); +@@ -254,10 +294,91 @@ TEST_F(SubprocessTest, SetWithLots) { + // that stdin is closed. + TEST_F(SubprocessTest, ReadStdin) { + Subprocess* subproc = subprocs_.Add("cat -"); ++ subprocs_.ResetTokenAvailable(); + while (!subproc->Done()) { +- subprocs_.DoWork(); ++ subprocs_.DoWork(NULL); + } ++ ASSERT_FALSE(subprocs_.IsTokenAvailable()); + ASSERT_EQ(ExitSuccess, subproc->Finish()); + ASSERT_EQ(1u, subprocs_.finished_.size()); + } + #endif // _WIN32 ++ ++TEST_F(SubprocessTest, TokenAvailable) { ++ Subprocess* subproc = subprocs_.Add(kSimpleCommand); ++ ASSERT_NE((Subprocess *) 0, subproc); ++ ++ // simulate GNUmake jobserver pipe with 1 token ++#ifdef _WIN32 ++ tokens_._token_available = true; ++#else ++ int fds[2]; ++ ASSERT_EQ(0u, pipe(fds)); ++ tokens_._fd = fds[0]; ++ ASSERT_EQ(1u, write(fds[1], "T", 1)); ++#endif ++ ++ subprocs_.ResetTokenAvailable(); ++ subprocs_.DoWork(&tokens_); ++#ifdef _WIN32 ++ tokens_._token_available = false; ++ // we need to loop here as we have no conrol where the token ++ // I/O completion post ends up in the queue ++ while (!subproc->Done() && !subprocs_.IsTokenAvailable()) { ++ subprocs_.DoWork(&tokens_); ++ } ++#endif ++ ++ EXPECT_TRUE(subprocs_.IsTokenAvailable()); ++ EXPECT_EQ(0u, subprocs_.finished_.size()); ++ ++ // remove token to let DoWork() wait for command again ++#ifndef _WIN32 ++ char token; ++ ASSERT_EQ(1u, read(fds[0], &token, 1)); ++#endif ++ ++ while (!subproc->Done()) { ++ subprocs_.DoWork(&tokens_); ++ } ++ ++#ifndef _WIN32 ++ close(fds[1]); ++ close(fds[0]); ++#endif ++ ++ EXPECT_EQ(ExitSuccess, subproc->Finish()); ++ EXPECT_NE("", subproc->GetOutput()); ++ ++ EXPECT_EQ(1u, subprocs_.finished_.size()); ++} ++ ++TEST_F(SubprocessTest, TokenNotAvailable) { ++ Subprocess* subproc = subprocs_.Add(kSimpleCommand); ++ ASSERT_NE((Subprocess *) 0, subproc); ++ ++ // simulate GNUmake jobserver pipe with 0 tokens ++#ifdef _WIN32 ++ tokens_._token_available = false; ++#else ++ int fds[2]; ++ ASSERT_EQ(0u, pipe(fds)); ++ tokens_._fd = fds[0]; ++#endif ++ ++ subprocs_.ResetTokenAvailable(); ++ while (!subproc->Done()) { ++ subprocs_.DoWork(&tokens_); ++ } ++ ++#ifndef _WIN32 ++ close(fds[1]); ++ close(fds[0]); ++#endif ++ ++ EXPECT_FALSE(subprocs_.IsTokenAvailable()); ++ EXPECT_EQ(ExitSuccess, subproc->Finish()); ++ EXPECT_NE("", subproc->GetOutput()); ++ ++ EXPECT_EQ(1u, subprocs_.finished_.size()); ++} +--- /dev/null ++++ b/src/tokenpool-gnu-make-posix.cc +@@ -0,0 +1,202 @@ ++// Copyright 2016-2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool-gnu-make.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// TokenPool implementation for GNU make jobserver - POSIX implementation ++// (http://make.mad-scientist.net/papers/jobserver-implementation/) ++struct GNUmakeTokenPoolPosix : public GNUmakeTokenPool { ++ GNUmakeTokenPoolPosix(); ++ virtual ~GNUmakeTokenPoolPosix(); ++ ++ virtual int GetMonitorFd(); ++ ++ virtual const char* GetEnv(const char* name) { return getenv(name); }; ++ virtual bool ParseAuth(const char* jobserver); ++ virtual bool AcquireToken(); ++ virtual bool ReturnToken(); ++ ++ private: ++ int rfd_; ++ int wfd_; ++ ++ struct sigaction old_act_; ++ bool restore_; ++ ++ static int dup_rfd_; ++ static void CloseDupRfd(int signum); ++ ++ bool CheckFd(int fd); ++ bool SetAlarmHandler(); ++}; ++ ++GNUmakeTokenPoolPosix::GNUmakeTokenPoolPosix() : rfd_(-1), wfd_(-1), restore_(false) { ++} ++ ++GNUmakeTokenPoolPosix::~GNUmakeTokenPoolPosix() { ++ Clear(); ++ if (restore_) ++ sigaction(SIGALRM, &old_act_, NULL); ++} ++ ++bool GNUmakeTokenPoolPosix::CheckFd(int fd) { ++ if (fd < 0) ++ return false; ++ int ret = fcntl(fd, F_GETFD); ++ if (ret < 0) ++ return false; ++ return true; ++} ++ ++int GNUmakeTokenPoolPosix::dup_rfd_ = -1; ++ ++void GNUmakeTokenPoolPosix::CloseDupRfd(int signum) { ++ close(dup_rfd_); ++ dup_rfd_ = -1; ++} ++ ++bool GNUmakeTokenPoolPosix::SetAlarmHandler() { ++ struct sigaction act; ++ memset(&act, 0, sizeof(act)); ++ act.sa_handler = CloseDupRfd; ++ if (sigaction(SIGALRM, &act, &old_act_) < 0) { ++ perror("sigaction:"); ++ return false; ++ } ++ restore_ = true; ++ return true; ++} ++ ++bool GNUmakeTokenPoolPosix::ParseAuth(const char* jobserver) { ++ int rfd = -1; ++ int wfd = -1; ++ if ((sscanf(jobserver, "%*[^=]=%d,%d", &rfd, &wfd) == 2) && ++ CheckFd(rfd) && ++ CheckFd(wfd) && ++ SetAlarmHandler()) { ++ rfd_ = rfd; ++ wfd_ = wfd; ++ return true; ++ } ++ ++ return false; ++} ++ ++bool GNUmakeTokenPoolPosix::AcquireToken() { ++ // Please read ++ // ++ // http://make.mad-scientist.net/papers/jobserver-implementation/ ++ // ++ // for the reasoning behind the following code. ++ // ++ // Try to read one character from the pipe. Returns true on success. ++ // ++ // First check if read() would succeed without blocking. ++#ifdef USE_PPOLL ++ pollfd pollfds[] = {{rfd_, POLLIN, 0}}; ++ int ret = poll(pollfds, 1, 0); ++#else ++ fd_set set; ++ struct timeval timeout = { 0, 0 }; ++ FD_ZERO(&set); ++ FD_SET(rfd_, &set); ++ int ret = select(rfd_ + 1, &set, NULL, NULL, &timeout); ++#endif ++ if (ret > 0) { ++ // Handle potential race condition: ++ // - the above check succeeded, i.e. read() should not block ++ // - the character disappears before we call read() ++ // ++ // Create a duplicate of rfd_. The duplicate file descriptor dup_rfd_ ++ // can safely be closed by signal handlers without affecting rfd_. ++ dup_rfd_ = dup(rfd_); ++ ++ if (dup_rfd_ != -1) { ++ struct sigaction act, old_act; ++ int ret = 0; ++ ++ // Temporarily replace SIGCHLD handler with our own ++ memset(&act, 0, sizeof(act)); ++ act.sa_handler = CloseDupRfd; ++ if (sigaction(SIGCHLD, &act, &old_act) == 0) { ++ struct itimerval timeout; ++ ++ // install a 100ms timeout that generates SIGALARM on expiration ++ memset(&timeout, 0, sizeof(timeout)); ++ timeout.it_value.tv_usec = 100 * 1000; // [ms] -> [usec] ++ if (setitimer(ITIMER_REAL, &timeout, NULL) == 0) { ++ char buf; ++ ++ // Now try to read() from dup_rfd_. Return values from read(): ++ // ++ // 1. token read -> 1 ++ // 2. pipe closed -> 0 ++ // 3. alarm expires -> -1 (EINTR) ++ // 4. child exits -> -1 (EINTR) ++ // 5. alarm expired before entering read() -> -1 (EBADF) ++ // 6. child exited before entering read() -> -1 (EBADF) ++ // 7. child exited before handler is installed -> go to 1 - 3 ++ ret = read(dup_rfd_, &buf, 1); ++ ++ // disarm timer ++ memset(&timeout, 0, sizeof(timeout)); ++ setitimer(ITIMER_REAL, &timeout, NULL); ++ } ++ ++ sigaction(SIGCHLD, &old_act, NULL); ++ } ++ ++ CloseDupRfd(0); ++ ++ // Case 1 from above list ++ if (ret > 0) ++ return true; ++ } ++ } ++ ++ // read() would block, i.e. no token available, ++ // cases 2-6 from above list or ++ // select() / poll() / dup() / sigaction() / setitimer() failed ++ return false; ++} ++ ++bool GNUmakeTokenPoolPosix::ReturnToken() { ++ const char buf = '+'; ++ while (1) { ++ int ret = write(wfd_, &buf, 1); ++ if (ret > 0) ++ return true; ++ if ((ret != -1) || (errno != EINTR)) ++ return false; ++ // write got interrupted - retry ++ } ++} ++ ++int GNUmakeTokenPoolPosix::GetMonitorFd() { ++ return rfd_; ++} ++ ++TokenPool* TokenPool::Get() { ++ return new GNUmakeTokenPoolPosix; ++} +--- /dev/null ++++ b/src/tokenpool-gnu-make-win32.cc +@@ -0,0 +1,239 @@ ++// Copyright 2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool-gnu-make.h" ++ ++// Always include this first. ++// Otherwise the other system headers don't work correctly under Win32 ++#include ++ ++#include ++#include ++#include ++ ++#include "util.h" ++ ++// TokenPool implementation for GNU make jobserver - Win32 implementation ++// (https://www.gnu.org/software/make/manual/html_node/Windows-Jobserver.html) ++struct GNUmakeTokenPoolWin32 : public GNUmakeTokenPool { ++ GNUmakeTokenPoolWin32(); ++ virtual ~GNUmakeTokenPoolWin32(); ++ ++ virtual void WaitForTokenAvailability(HANDLE ioport); ++ virtual bool TokenIsAvailable(ULONG_PTR key); ++ ++ virtual const char* GetEnv(const char* name); ++ virtual bool ParseAuth(const char* jobserver); ++ virtual bool AcquireToken(); ++ virtual bool ReturnToken(); ++ ++ private: ++ // Semaphore for GNU make jobserver protocol ++ HANDLE semaphore_jobserver_; ++ // Semaphore Child -> Parent ++ // - child releases it before entering wait on jobserver semaphore ++ // - parent blocks on it to know when child enters wait ++ HANDLE semaphore_enter_wait_; ++ // Semaphore Parent -> Child ++ // - parent releases it to allow child to restart loop ++ // - child blocks on it to know when to restart loop ++ HANDLE semaphore_restart_; ++ // set to false if child should exit loop and terminate thread ++ bool running_; ++ // child thread ++ HANDLE child_; ++ // I/O completion port from SubprocessSet ++ HANDLE ioport_; ++ ++ ++ DWORD SemaphoreThread(); ++ void ReleaseSemaphore(HANDLE semaphore); ++ void WaitForObject(HANDLE object); ++ static DWORD WINAPI SemaphoreThreadWrapper(LPVOID param); ++ static void NoopAPCFunc(ULONG_PTR param); ++}; ++ ++GNUmakeTokenPoolWin32::GNUmakeTokenPoolWin32() : semaphore_jobserver_(NULL), ++ semaphore_enter_wait_(NULL), ++ semaphore_restart_(NULL), ++ running_(false), ++ child_(NULL), ++ ioport_(NULL) { ++} ++ ++GNUmakeTokenPoolWin32::~GNUmakeTokenPoolWin32() { ++ Clear(); ++ CloseHandle(semaphore_jobserver_); ++ semaphore_jobserver_ = NULL; ++ ++ if (child_) { ++ // tell child thread to exit ++ running_ = false; ++ ReleaseSemaphore(semaphore_restart_); ++ ++ // wait for child thread to exit ++ WaitForObject(child_); ++ CloseHandle(child_); ++ child_ = NULL; ++ } ++ ++ if (semaphore_restart_) { ++ CloseHandle(semaphore_restart_); ++ semaphore_restart_ = NULL; ++ } ++ ++ if (semaphore_enter_wait_) { ++ CloseHandle(semaphore_enter_wait_); ++ semaphore_enter_wait_ = NULL; ++ } ++} ++ ++const char* GNUmakeTokenPoolWin32::GetEnv(const char* name) { ++ // getenv() does not work correctly together with tokenpool_tests.cc ++ static char buffer[MAX_PATH + 1]; ++ if (GetEnvironmentVariable(name, buffer, sizeof(buffer)) == 0) ++ return NULL; ++ return buffer; ++} ++ ++bool GNUmakeTokenPoolWin32::ParseAuth(const char* jobserver) { ++ // match "--jobserver-auth=gmake_semaphore_..." ++ const char* start = strchr(jobserver, '='); ++ if (start) { ++ const char* end = start; ++ unsigned int len; ++ char c, *auth; ++ ++ while ((c = *++end) != '\0') ++ if (!(isalnum(c) || (c == '_'))) ++ break; ++ len = end - start; // includes string terminator in count ++ ++ if ((len > 1) && ((auth = (char*)malloc(len)) != NULL)) { ++ strncpy(auth, start + 1, len - 1); ++ auth[len - 1] = '\0'; ++ ++ if ((semaphore_jobserver_ = ++ OpenSemaphore(SEMAPHORE_ALL_ACCESS, /* Semaphore access setting */ ++ FALSE, /* Child processes DON'T inherit */ ++ auth /* Semaphore name */ ++ )) != NULL) { ++ free(auth); ++ return true; ++ } ++ ++ free(auth); ++ } ++ } ++ ++ return false; ++} ++ ++bool GNUmakeTokenPoolWin32::AcquireToken() { ++ return WaitForSingleObject(semaphore_jobserver_, 0) == WAIT_OBJECT_0; ++} ++ ++bool GNUmakeTokenPoolWin32::ReturnToken() { ++ ReleaseSemaphore(semaphore_jobserver_); ++ return true; ++} ++ ++DWORD GNUmakeTokenPoolWin32::SemaphoreThread() { ++ while (running_) { ++ // indicate to parent that we are entering wait ++ ReleaseSemaphore(semaphore_enter_wait_); ++ ++ // alertable wait forever on token semaphore ++ if (WaitForSingleObjectEx(semaphore_jobserver_, INFINITE, TRUE) == WAIT_OBJECT_0) { ++ // release token again for AcquireToken() ++ ReleaseSemaphore(semaphore_jobserver_); ++ ++ // indicate to parent on ioport that a token might be available ++ if (!PostQueuedCompletionStatus(ioport_, 0, (ULONG_PTR) this, NULL)) ++ Win32Fatal("PostQueuedCompletionStatus"); ++ } ++ ++ // wait for parent to allow loop restart ++ WaitForObject(semaphore_restart_); ++ // semaphore is now in nonsignaled state again for next run... ++ } ++ ++ return 0; ++} ++ ++DWORD WINAPI GNUmakeTokenPoolWin32::SemaphoreThreadWrapper(LPVOID param) { ++ GNUmakeTokenPoolWin32* This = (GNUmakeTokenPoolWin32*) param; ++ return This->SemaphoreThread(); ++} ++ ++void GNUmakeTokenPoolWin32::NoopAPCFunc(ULONG_PTR param) { ++} ++ ++void GNUmakeTokenPoolWin32::WaitForTokenAvailability(HANDLE ioport) { ++ if (child_ == NULL) { ++ // first invocation ++ // ++ // subprocess-win32.cc uses I/O completion port (IOCP) which can't be ++ // used as a waitable object. Therefore we can't use WaitMultipleObjects() ++ // to wait on the IOCP and the token semaphore at the same time. Create ++ // a child thread that waits on the semaphore and posts an I/O completion ++ ioport_ = ioport; ++ ++ // create both semaphores in nonsignaled state ++ if ((semaphore_enter_wait_ = CreateSemaphore(NULL, 0, 1, NULL)) ++ == NULL) ++ Win32Fatal("CreateSemaphore/enter_wait"); ++ if ((semaphore_restart_ = CreateSemaphore(NULL, 0, 1, NULL)) ++ == NULL) ++ Win32Fatal("CreateSemaphore/restart"); ++ ++ // start child thread ++ running_ = true; ++ if ((child_ = CreateThread(NULL, 0, &SemaphoreThreadWrapper, this, 0, NULL)) ++ == NULL) ++ Win32Fatal("CreateThread"); ++ ++ } else { ++ // all further invocations - allow child thread to loop ++ ReleaseSemaphore(semaphore_restart_); ++ } ++ ++ // wait for child thread to enter wait ++ WaitForObject(semaphore_enter_wait_); ++ // semaphore is now in nonsignaled state again for next run... ++ ++ // now SubprocessSet::DoWork() can enter GetQueuedCompletionStatus()... ++} ++ ++bool GNUmakeTokenPoolWin32::TokenIsAvailable(ULONG_PTR key) { ++ // alert child thread to break wait on token semaphore ++ QueueUserAPC((PAPCFUNC)&NoopAPCFunc, child_, (ULONG_PTR)NULL); ++ ++ // return true when GetQueuedCompletionStatus() returned our key ++ return key == (ULONG_PTR) this; ++} ++ ++void GNUmakeTokenPoolWin32::ReleaseSemaphore(HANDLE semaphore) { ++ if (!::ReleaseSemaphore(semaphore, 1, NULL)) ++ Win32Fatal("ReleaseSemaphore"); ++} ++ ++void GNUmakeTokenPoolWin32::WaitForObject(HANDLE object) { ++ if (WaitForSingleObject(object, INFINITE) != WAIT_OBJECT_0) ++ Win32Fatal("WaitForSingleObject"); ++} ++ ++TokenPool* TokenPool::Get() { ++ return new GNUmakeTokenPoolWin32; ++} +--- /dev/null ++++ b/src/tokenpool-gnu-make.cc +@@ -0,0 +1,108 @@ ++// Copyright 2016-2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool-gnu-make.h" ++ ++#include ++#include ++#include ++ ++#include "line_printer.h" ++ ++// TokenPool implementation for GNU make jobserver - common bits ++// every instance owns an implicit token -> available_ == 1 ++GNUmakeTokenPool::GNUmakeTokenPool() : available_(1), used_(0) { ++} ++ ++GNUmakeTokenPool::~GNUmakeTokenPool() { ++} ++ ++bool GNUmakeTokenPool::Setup(bool ignore, ++ bool verbose, ++ double& max_load_average) { ++ const char* value = GetEnv("MAKEFLAGS"); ++ if (!value) ++ return false; ++ ++ // GNU make <= 4.1 ++ const char* jobserver = strstr(value, "--jobserver-fds="); ++ if (!jobserver) ++ // GNU make => 4.2 ++ jobserver = strstr(value, "--jobserver-auth="); ++ if (jobserver) { ++ LinePrinter printer; ++ ++ if (ignore) { ++ printer.PrintOnNewLine("ninja: warning: -jN forced on command line; ignoring GNU make jobserver.\n"); ++ } else { ++ if (ParseAuth(jobserver)) { ++ const char* l_arg = strstr(value, " -l"); ++ int load_limit = -1; ++ ++ if (verbose) { ++ printer.PrintOnNewLine("ninja: using GNU make jobserver.\n"); ++ } ++ ++ // translate GNU make -lN to ninja -lN ++ if (l_arg && ++ (sscanf(l_arg + 3, "%d ", &load_limit) == 1) && ++ (load_limit > 0)) { ++ max_load_average = load_limit; ++ } ++ ++ return true; ++ } ++ } ++ } ++ ++ return false; ++} ++ ++bool GNUmakeTokenPool::Acquire() { ++ if (available_ > 0) ++ return true; ++ ++ if (AcquireToken()) { ++ // token acquired ++ available_++; ++ return true; ++ } ++ ++ // no token available ++ return false; ++} ++ ++void GNUmakeTokenPool::Reserve() { ++ available_--; ++ used_++; ++} ++ ++void GNUmakeTokenPool::Return() { ++ if (ReturnToken()) ++ available_--; ++} ++ ++void GNUmakeTokenPool::Release() { ++ available_++; ++ used_--; ++ if (available_ > 1) ++ Return(); ++} ++ ++void GNUmakeTokenPool::Clear() { ++ while (used_ > 0) ++ Release(); ++ while (available_ > 1) ++ Return(); ++} +--- /dev/null ++++ b/src/tokenpool-gnu-make.h +@@ -0,0 +1,40 @@ ++// Copyright 2016-2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool.h" ++ ++// interface to GNU make token pool ++struct GNUmakeTokenPool : public TokenPool { ++ GNUmakeTokenPool(); ++ ~GNUmakeTokenPool(); ++ ++ // token pool implementation ++ virtual bool Acquire(); ++ virtual void Reserve(); ++ virtual void Release(); ++ virtual void Clear(); ++ virtual bool Setup(bool ignore, bool verbose, double& max_load_average); ++ ++ // platform specific implementation ++ virtual const char* GetEnv(const char* name) = 0; ++ virtual bool ParseAuth(const char* jobserver) = 0; ++ virtual bool AcquireToken() = 0; ++ virtual bool ReturnToken() = 0; ++ ++ private: ++ int available_; ++ int used_; ++ ++ void Return(); ++}; +--- /dev/null ++++ b/src/tokenpool.h +@@ -0,0 +1,42 @@ ++// Copyright 2016-2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#ifdef _WIN32 ++#include ++#endif ++ ++// interface to token pool ++struct TokenPool { ++ virtual ~TokenPool() {} ++ ++ virtual bool Acquire() = 0; ++ virtual void Reserve() = 0; ++ virtual void Release() = 0; ++ virtual void Clear() = 0; ++ ++ // returns false if token pool setup failed ++ virtual bool Setup(bool ignore, bool verbose, double& max_load_average) = 0; ++ ++#ifdef _WIN32 ++ virtual void WaitForTokenAvailability(HANDLE ioport) = 0; ++ // returns true if a token has become available ++ // key is result from GetQueuedCompletionStatus() ++ virtual bool TokenIsAvailable(ULONG_PTR key) = 0; ++#else ++ virtual int GetMonitorFd() = 0; ++#endif ++ ++ // returns NULL if token pool is not available ++ static TokenPool* Get(); ++}; +--- /dev/null ++++ b/src/tokenpool_test.cc +@@ -0,0 +1,269 @@ ++// Copyright 2018 Google Inc. All Rights Reserved. ++// ++// Licensed under the Apache License, Version 2.0 (the "License"); ++// you may not use this file except in compliance with the License. ++// You may obtain a copy of the License at ++// ++// http://www.apache.org/licenses/LICENSE-2.0 ++// ++// Unless required by applicable law or agreed to in writing, software ++// distributed under the License is distributed on an "AS IS" BASIS, ++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++// See the License for the specific language governing permissions and ++// limitations under the License. ++ ++#include "tokenpool.h" ++ ++#include "test.h" ++ ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ ++#include ++#include ++ ++#ifdef _WIN32 ++// should contain all valid characters ++#define SEMAPHORE_NAME "abcdefghijklmnopqrstwxyz01234567890_" ++#define AUTH_FORMAT(tmpl) "foo " tmpl "=%s bar" ++#define ENVIRONMENT_CLEAR() SetEnvironmentVariable("MAKEFLAGS", NULL) ++#define ENVIRONMENT_INIT(v) SetEnvironmentVariable("MAKEFLAGS", v) ++#else ++#define AUTH_FORMAT(tmpl) "foo " tmpl "=%d,%d bar" ++#define ENVIRONMENT_CLEAR() unsetenv("MAKEFLAGS") ++#define ENVIRONMENT_INIT(v) setenv("MAKEFLAGS", v, true) ++#endif ++ ++namespace { ++ ++const double kLoadAverageDefault = -1.23456789; ++ ++struct TokenPoolTest : public testing::Test { ++ double load_avg_; ++ TokenPool* tokens_; ++ char buf_[1024]; ++#ifdef _WIN32 ++ const char* semaphore_name_; ++ HANDLE semaphore_; ++#else ++ int fds_[2]; ++#endif ++ ++ virtual void SetUp() { ++ load_avg_ = kLoadAverageDefault; ++ tokens_ = NULL; ++ ENVIRONMENT_CLEAR(); ++#ifdef _WIN32 ++ semaphore_name_ = SEMAPHORE_NAME; ++ if ((semaphore_ = CreateSemaphore(0, 0, 2, SEMAPHORE_NAME)) == NULL) ++#else ++ if (pipe(fds_) < 0) ++#endif ++ ASSERT_TRUE(false); ++ } ++ ++ void CreatePool(const char* format, bool ignore_jobserver = false) { ++ if (format) { ++ sprintf(buf_, format, ++#ifdef _WIN32 ++ semaphore_name_ ++#else ++ fds_[0], fds_[1] ++#endif ++ ); ++ ENVIRONMENT_INIT(buf_); ++ } ++ if ((tokens_ = TokenPool::Get()) != NULL) { ++ if (!tokens_->Setup(ignore_jobserver, false, load_avg_)) { ++ delete tokens_; ++ tokens_ = NULL; ++ } ++ } ++ } ++ ++ void CreateDefaultPool() { ++ CreatePool(AUTH_FORMAT("--jobserver-auth")); ++ } ++ ++ virtual void TearDown() { ++ if (tokens_) ++ delete tokens_; ++#ifdef _WIN32 ++ CloseHandle(semaphore_); ++#else ++ close(fds_[0]); ++ close(fds_[1]); ++#endif ++ ENVIRONMENT_CLEAR(); ++ } ++}; ++ ++} // anonymous namespace ++ ++// verifies none implementation ++TEST_F(TokenPoolTest, NoTokenPool) { ++ CreatePool(NULL, false); ++ ++ EXPECT_EQ(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, SuccessfulOldSetup) { ++ // GNUmake <= 4.1 ++ CreatePool(AUTH_FORMAT("--jobserver-fds")); ++ ++ EXPECT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, SuccessfulNewSetup) { ++ // GNUmake => 4.2 ++ CreateDefaultPool(); ++ ++ EXPECT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, IgnoreWithJN) { ++ CreatePool(AUTH_FORMAT("--jobserver-auth"), true); ++ ++ EXPECT_EQ(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, HonorLN) { ++ CreatePool(AUTH_FORMAT("-l9 --jobserver-auth")); ++ ++ EXPECT_NE(NULL, tokens_); ++ EXPECT_EQ(9.0, load_avg_); ++} ++ ++#ifdef _WIN32 ++TEST_F(TokenPoolTest, SemaphoreNotFound) { ++ semaphore_name_ = SEMAPHORE_NAME "_foobar"; ++ CreateDefaultPool(); ++ ++ EXPECT_EQ(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++} ++ ++TEST_F(TokenPoolTest, TokenIsAvailable) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ EXPECT_TRUE(tokens_->TokenIsAvailable((ULONG_PTR)tokens_)); ++} ++#else ++TEST_F(TokenPoolTest, MonitorFD) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ EXPECT_EQ(fds_[0], tokens_->GetMonitorFd()); ++} ++#endif ++ ++TEST_F(TokenPoolTest, ImplicitToken) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ tokens_->Release(); ++ EXPECT_TRUE(tokens_->Acquire()); ++} ++ ++TEST_F(TokenPoolTest, TwoTokens) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ // implicit token ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ ++ // jobserver offers 2nd token ++#ifdef _WIN32 ++ LONG previous; ++ ASSERT_TRUE(ReleaseSemaphore(semaphore_, 1, &previous)); ++ ASSERT_EQ(0, previous); ++#else ++ ASSERT_EQ(1u, write(fds_[1], "T", 1)); ++#endif ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ ++ // release 2nd token ++ tokens_->Release(); ++ EXPECT_TRUE(tokens_->Acquire()); ++ ++ // release implict token - must return 2nd token back to jobserver ++ tokens_->Release(); ++ EXPECT_TRUE(tokens_->Acquire()); ++ ++ // there must be one token available ++#ifdef _WIN32 ++ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(semaphore_, 0)); ++ EXPECT_TRUE(ReleaseSemaphore(semaphore_, 1, &previous)); ++ EXPECT_EQ(0, previous); ++#else ++ EXPECT_EQ(1u, read(fds_[0], buf_, sizeof(buf_))); ++#endif ++ ++ // implicit token ++ EXPECT_TRUE(tokens_->Acquire()); ++} ++ ++TEST_F(TokenPoolTest, Clear) { ++ CreateDefaultPool(); ++ ++ ASSERT_NE(NULL, tokens_); ++ EXPECT_EQ(kLoadAverageDefault, load_avg_); ++ ++ // implicit token ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ ++ // jobserver offers 2nd & 3rd token ++#ifdef _WIN32 ++ LONG previous; ++ ASSERT_TRUE(ReleaseSemaphore(semaphore_, 2, &previous)); ++ ASSERT_EQ(0, previous); ++#else ++ ASSERT_EQ(2u, write(fds_[1], "TT", 2)); ++#endif ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_TRUE(tokens_->Acquire()); ++ tokens_->Reserve(); ++ EXPECT_FALSE(tokens_->Acquire()); ++ ++ tokens_->Clear(); ++ EXPECT_TRUE(tokens_->Acquire()); ++ ++ // there must be two tokens available ++#ifdef _WIN32 ++ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(semaphore_, 0)); ++ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(semaphore_, 0)); ++ EXPECT_TRUE(ReleaseSemaphore(semaphore_, 2, &previous)); ++ EXPECT_EQ(0, previous); ++#else ++ EXPECT_EQ(2u, read(fds_[0], buf_, sizeof(buf_))); ++#endif ++ ++ // implicit token ++ EXPECT_TRUE(tokens_->Acquire()); ++}