From 69dab3376db7318c528d0a0c8deacc6c9bd8ec44 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 9 Jun 2021 13:16:11 +0200 Subject: [PATCH 01/24] toolchain/gdb: fix broken non-python build Append configure args instead of overwriting them Fixes: 74417f8b3a80 ("toolchain: gdb: Add optional python support") Signed-off-by: Felix Fietkau --- toolchain/gdb/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/gdb/Makefile b/toolchain/gdb/Makefile index 2708eff869..e769a3be3e 100644 --- a/toolchain/gdb/Makefile +++ b/toolchain/gdb/Makefile @@ -46,7 +46,7 @@ HOST_CONFIGURE_ARGS = \ ifneq ($(CONFIG_GDB_PYTHON),) HOST_CONFIGURE_ARGS+= --with-python else - HOST_CONFIGURE_ARGS:= --without-python + HOST_CONFIGURE_ARGS+= --without-python endif define Host/Install From afd4f84321900943611d3877530774b90d91aaba Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Fri, 11 Jun 2021 00:47:45 +0800 Subject: [PATCH 02/24] kernel: bump to 4.9.272, 4.14.236, 4.19.194 Refreshed all patches. Signed-off-by: Tianling Shen --- include/kernel-version.mk | 12 ++++++------ ...erial-option-fix-dwm-158-3g-modem-interface.patch | 2 +- ...4.15-netfilter-exit_net-cleanup-check-added.patch | 2 +- .../linux/generic/hack-4.14/902-debloat_proc.patch | 2 +- .../650-netfilter-add-xt_OFFLOAD-target.patch | 4 ++-- .../linux/generic/hack-4.19/902-debloat_proc.patch | 2 +- target/linux/generic/hack-4.9/902-debloat_proc.patch | 2 +- .../patches-4.14/998-ignore-stats-debug-info.patch | 6 +++--- .../patches-4.14/807-usb-support-layerscape.patch | 4 ++-- ...nk-copy-the-commandline-from-the-devicetree.patch | 2 +- .../patches-4.14/0048-asoc-add-mt7620-support.patch | 6 +++--- .../patches-4.14/105-mt7621-memory-detect.patch | 2 +- 12 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/kernel-version.mk b/include/kernel-version.mk index de5d1a7c42..fc215f2ab4 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -6,13 +6,13 @@ ifdef CONFIG_TESTING_KERNEL KERNEL_PATCHVER:=$(KERNEL_TESTING_PATCHVER) endif -LINUX_VERSION-4.9 = .270 -LINUX_VERSION-4.14 = .234 -LINUX_VERSION-4.19 = .192 +LINUX_VERSION-4.9 = .272 +LINUX_VERSION-4.14 = .236 +LINUX_VERSION-4.19 = .194 -LINUX_KERNEL_HASH-4.9.270 = c32b0026b6d7b06fdba6d1712756ddec7d5d64b351f6dcd90b49287aff526532 -LINUX_KERNEL_HASH-4.14.234 = 2b58cc4ecfef3ebc75783ccef10c71f7beebb26edaf7419f55a96183755a98d7 -LINUX_KERNEL_HASH-4.19.192 = 074dcda77c7c413dece370b3cf8713997d909a8c06724c910ae23cc9c96f0099 +LINUX_KERNEL_HASH-4.9.272 = f8bf0c390ae40ca736e104f10f744446bc534bf87ba1b6dbb2b7c9a8bece1058 +LINUX_KERNEL_HASH-4.14.236 = e4eae297a6fefefd8ce4781d98178a7c1ee51ca0a4c8a7e46e61b121fbab8b2a +LINUX_KERNEL_HASH-4.19.194 = aaaebdccf599f77148fe170642fa7dc2452cf994b5cbbb4d39cab9e7f4058896 remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1))))))) diff --git a/target/linux/generic/backport-4.14/030-USB-serial-option-fix-dwm-158-3g-modem-interface.patch b/target/linux/generic/backport-4.14/030-USB-serial-option-fix-dwm-158-3g-modem-interface.patch index 0b84643ff2..84874d3d93 100644 --- a/target/linux/generic/backport-4.14/030-USB-serial-option-fix-dwm-158-3g-modem-interface.patch +++ b/target/linux/generic/backport-4.14/030-USB-serial-option-fix-dwm-158-3g-modem-interface.patch @@ -30,7 +30,7 @@ Signed-off-by: Johan Hovold --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c -@@ -2024,7 +2024,8 @@ static const struct usb_device_id option +@@ -2028,7 +2028,8 @@ static const struct usb_device_id option { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d01, 0xff) }, /* D-Link DWM-156 (variant) */ { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d02, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d03, 0xff) }, diff --git a/target/linux/generic/backport-4.14/336-v4.15-netfilter-exit_net-cleanup-check-added.patch b/target/linux/generic/backport-4.14/336-v4.15-netfilter-exit_net-cleanup-check-added.patch index ee508f473a..79f4342d7e 100644 --- a/target/linux/generic/backport-4.14/336-v4.15-netfilter-exit_net-cleanup-check-added.patch +++ b/target/linux/generic/backport-4.14/336-v4.15-netfilter-exit_net-cleanup-check-added.patch @@ -80,7 +80,7 @@ Signed-off-by: Pablo Neira Ayuso static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list) --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c -@@ -1781,8 +1781,17 @@ static int __net_init xt_net_init(struct +@@ -1784,8 +1784,17 @@ static int __net_init xt_net_init(struct return 0; } diff --git a/target/linux/generic/hack-4.14/902-debloat_proc.patch b/target/linux/generic/hack-4.14/902-debloat_proc.patch index 222533c42b..b426b07573 100644 --- a/target/linux/generic/hack-4.14/902-debloat_proc.patch +++ b/target/linux/generic/hack-4.14/902-debloat_proc.patch @@ -243,7 +243,7 @@ Signed-off-by: Felix Fietkau } --- a/mm/vmstat.c +++ b/mm/vmstat.c -@@ -1951,10 +1951,12 @@ void __init init_mm_internals(void) +@@ -1954,10 +1954,12 @@ void __init init_mm_internals(void) start_shepherd_timer(); #endif #ifdef CONFIG_PROC_FS diff --git a/target/linux/generic/hack-4.19/650-netfilter-add-xt_OFFLOAD-target.patch b/target/linux/generic/hack-4.19/650-netfilter-add-xt_OFFLOAD-target.patch index 55247bc2a3..a847782841 100644 --- a/target/linux/generic/hack-4.19/650-netfilter-add-xt_OFFLOAD-target.patch +++ b/target/linux/generic/hack-4.19/650-netfilter-add-xt_OFFLOAD-target.patch @@ -70,7 +70,7 @@ Signed-off-by: Felix Fietkau help This option adds the flow table core infrastructure. -@@ -996,6 +995,15 @@ config NETFILTER_XT_TARGET_NOTRACK +@@ -1008,6 +1007,15 @@ config NETFILTER_XT_TARGET_NOTRACK depends on NETFILTER_ADVANCED select NETFILTER_XT_TARGET_CT @@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau +obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o - obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o + obj-$(CONFIG_NETFILTER_XT_TARGET_IMQ) += xt_IMQ.o --- /dev/null +++ b/net/netfilter/xt_FLOWOFFLOAD.c @@ -0,0 +1,422 @@ diff --git a/target/linux/generic/hack-4.19/902-debloat_proc.patch b/target/linux/generic/hack-4.19/902-debloat_proc.patch index f5a9e109b2..732948c3ca 100644 --- a/target/linux/generic/hack-4.19/902-debloat_proc.patch +++ b/target/linux/generic/hack-4.19/902-debloat_proc.patch @@ -243,7 +243,7 @@ Signed-off-by: Felix Fietkau &vmalloc_op, --- a/mm/vmstat.c +++ b/mm/vmstat.c -@@ -1972,10 +1972,12 @@ void __init init_mm_internals(void) +@@ -1975,10 +1975,12 @@ void __init init_mm_internals(void) start_shepherd_timer(); #endif #ifdef CONFIG_PROC_FS diff --git a/target/linux/generic/hack-4.9/902-debloat_proc.patch b/target/linux/generic/hack-4.9/902-debloat_proc.patch index 3c642b3d29..0996b88fe6 100644 --- a/target/linux/generic/hack-4.9/902-debloat_proc.patch +++ b/target/linux/generic/hack-4.9/902-debloat_proc.patch @@ -244,7 +244,7 @@ Signed-off-by: Felix Fietkau } --- a/mm/vmstat.c +++ b/mm/vmstat.c -@@ -1793,10 +1793,12 @@ static int __init setup_vmstat(void) +@@ -1796,10 +1796,12 @@ static int __init setup_vmstat(void) cpu_notifier_register_done(); #endif #ifdef CONFIG_PROC_FS diff --git a/target/linux/ipq40xx/patches-4.14/998-ignore-stats-debug-info.patch b/target/linux/ipq40xx/patches-4.14/998-ignore-stats-debug-info.patch index 5ef3815e27..87421ba13b 100644 --- a/target/linux/ipq40xx/patches-4.14/998-ignore-stats-debug-info.patch +++ b/target/linux/ipq40xx/patches-4.14/998-ignore-stats-debug-info.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c -@@ -2343,7 +2343,7 @@ ath10k_update_per_peer_tx_stats(struct a +@@ -2396,7 +2396,7 @@ ath10k_update_per_peer_tx_stats(struct a sgi = ATH10K_HW_GI(peer_stats->flags); if (txrate.flags == WMI_RATE_PREAMBLE_VHT && txrate.mcs > 9) { @@ -9,7 +9,7 @@ return; } -@@ -2401,7 +2401,7 @@ static void ath10k_htt_fetch_peer_stats( +@@ -2454,7 +2454,7 @@ static void ath10k_htt_fetch_peer_stats( ppdu_len = resp->peer_tx_stats.ppdu_len * sizeof(__le32); if (skb->len < sizeof(struct htt_resp_hdr) + num_ppdu * ppdu_len) { @@ -18,7 +18,7 @@ return; } -@@ -2413,8 +2413,8 @@ static void ath10k_htt_fetch_peer_stats( +@@ -2466,8 +2466,8 @@ static void ath10k_htt_fetch_peer_stats( spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, peer_id); if (!peer) { diff --git a/target/linux/layerscape/patches-4.14/807-usb-support-layerscape.patch b/target/linux/layerscape/patches-4.14/807-usb-support-layerscape.patch index e2599df474..4ea197ed66 100644 --- a/target/linux/layerscape/patches-4.14/807-usb-support-layerscape.patch +++ b/target/linux/layerscape/patches-4.14/807-usb-support-layerscape.patch @@ -528,7 +528,7 @@ Signed-off-by: Zhao Chenhui reg &= ~DWC3_DCTL_INITU2ENA; --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c -@@ -3241,6 +3241,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) +@@ -3245,6 +3245,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) { int ret; int irq; @@ -536,7 +536,7 @@ Signed-off-by: Zhao Chenhui irq = dwc3_gadget_get_irq(dwc); if (irq < 0) { -@@ -3319,6 +3320,12 @@ int dwc3_gadget_init(struct dwc3 *dwc) +@@ -3323,6 +3324,12 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc3_gadget_set_speed(&dwc->gadget, dwc->maximum_speed); diff --git a/target/linux/ramips/patches-4.14/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch b/target/linux/ramips/patches-4.14/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch index c05ee8018d..e03496a01a 100644 --- a/target/linux/ramips/patches-4.14/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch +++ b/target/linux/ramips/patches-4.14/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch @@ -10,7 +10,7 @@ Signed-off-by: John Crispin --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c -@@ -82,6 +82,8 @@ void __init plat_mem_setup(void) +@@ -84,6 +84,8 @@ void __init plat_mem_setup(void) __dt_setup_arch(dtb); diff --git a/target/linux/ramips/patches-4.14/0048-asoc-add-mt7620-support.patch b/target/linux/ramips/patches-4.14/0048-asoc-add-mt7620-support.patch index 1834e88538..afb9f72006 100644 --- a/target/linux/ramips/patches-4.14/0048-asoc-add-mt7620-support.patch +++ b/target/linux/ramips/patches-4.14/0048-asoc-add-mt7620-support.patch @@ -20,7 +20,7 @@ Signed-off-by: John Crispin --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c -@@ -15,6 +15,7 @@ +@@ -16,6 +16,7 @@ #include #include #include @@ -28,14 +28,14 @@ Signed-off-by: John Crispin #include #include -@@ -26,6 +27,7 @@ +@@ -27,6 +28,7 @@ #include "common.h" __iomem void *rt_sysc_membase; +EXPORT_SYMBOL(rt_sysc_membase); __iomem void *rt_memc_membase; + EXPORT_SYMBOL_GPL(rt_sysc_membase); - __iomem void *plat_of_remap_node(const char *node) --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -59,6 +59,7 @@ source "sound/soc/mxs/Kconfig" diff --git a/target/linux/ramips/patches-4.14/105-mt7621-memory-detect.patch b/target/linux/ramips/patches-4.14/105-mt7621-memory-detect.patch index b19b57fd66..2229612679 100644 --- a/target/linux/ramips/patches-4.14/105-mt7621-memory-detect.patch +++ b/target/linux/ramips/patches-4.14/105-mt7621-memory-detect.patch @@ -114,7 +114,7 @@ Signed-off-by: Chuanhong Guo --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c -@@ -89,6 +89,8 @@ void __init plat_mem_setup(void) +@@ -91,6 +91,8 @@ void __init plat_mem_setup(void) of_scan_flat_dt(early_init_dt_find_memory, NULL); if (memory_dtb) of_scan_flat_dt(early_init_dt_scan_memory, NULL); From a8aa2f0593b2e378397bfce69b667e799ba15bd6 Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Fri, 11 Jun 2021 15:50:53 +0800 Subject: [PATCH 03/24] sunxi: nanopi r1s h5: read mac address from eeprom NanoPi R1S H5 has a unique MAC address for the ethernet on board. As the USB NIC doesn't have, just reuse this MAC and flipp the LA bit for it. Signed-off-by: Tianling Shen --- target/linux/sunxi/base-files/etc/board.d/02_network | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/linux/sunxi/base-files/etc/board.d/02_network b/target/linux/sunxi/base-files/etc/board.d/02_network index 7020b5f29a..f4e013e119 100755 --- a/target/linux/sunxi/base-files/etc/board.d/02_network +++ b/target/linux/sunxi/base-files/etc/board.d/02_network @@ -47,7 +47,8 @@ sunxi_setup_macs() case "$board" in friendlyarm,nanopi-r1s-h5) - lan_mac=$(nanopi_generate_mac) + wan_mac=$(get_mac_binary "/sys/bus/i2c/devices/0-0051/eeprom" 0xfa) + lan_mac=$(macaddr_setbit_la "$wan_mac") ;; esac From 0196b5587ebe05f3573adf8495b927d2d036a232 Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Sat, 12 Jun 2021 01:03:30 +0800 Subject: [PATCH 04/24] r8125: bump to 9.005.06 Signed-off-by: Tianling Shen (cherry picked from commit 37284adecbca801135c203f25cb79118227f237e) --- package/kernel/r8125/Makefile | 2 +- package/kernel/r8125/src/Makefile | 5 + package/kernel/r8125/src/r8125.h | 47 +- package/kernel/r8125/src/r8125_firmware.c | 264 ++++ package/kernel/r8125/src/r8125_firmware.h | 68 + package/kernel/r8125/src/r8125_n.c | 1589 +++++++++++++-------- 6 files changed, 1376 insertions(+), 599 deletions(-) create mode 100644 package/kernel/r8125/src/r8125_firmware.c create mode 100644 package/kernel/r8125/src/r8125_firmware.h diff --git a/package/kernel/r8125/Makefile b/package/kernel/r8125/Makefile index add8a25df8..ef0499824a 100644 --- a/package/kernel/r8125/Makefile +++ b/package/kernel/r8125/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=r8125 -PKG_VERSION:=9.005.01 +PKG_VERSION:=9.005.06 PKG_RELEASE:=1 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) diff --git a/package/kernel/r8125/src/Makefile b/package/kernel/r8125/src/Makefile index 0674190954..3c57e3b0bd 100644 --- a/package/kernel/r8125/src/Makefile +++ b/package/kernel/r8125/src/Makefile @@ -46,6 +46,7 @@ ENABLE_PTP_SUPPORT = n ENABLE_PTP_MASTER_MODE = n ENABLE_RSS_SUPPORT = y ENABLE_LIB_SUPPORT = n +ENABLE_USE_FIRMWARE_FILE = n ifneq ($(KERNELRELEASE),) obj-m := r8125.o @@ -106,6 +107,10 @@ ifneq ($(KERNELRELEASE),) r8125-objs += r8125_lib.o EXTRA_CFLAGS += -DENABLE_LIB_SUPPORT endif + ifeq ($(ENABLE_USE_FIRMWARE_FILE), y) + r8125-objs += r8125_firmware.o + EXTRA_CFLAGS += -DENABLE_USE_FIRMWARE_FILE + endif else BASEDIR := /lib/modules/$(shell uname -r) KERNELDIR ?= $(BASEDIR)/build diff --git a/package/kernel/r8125/src/r8125.h b/package/kernel/r8125/src/r8125.h index 06893797b7..d05d6883a4 100644 --- a/package/kernel/r8125/src/r8125.h +++ b/package/kernel/r8125/src/r8125.h @@ -47,9 +47,15 @@ #include "r8125_lib.h" #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +typedef int netdev_tx_t; +#endif + +/* #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)&& !defined(ENABLE_LIB_SUPPORT) #define RTL_USE_NEW_INTR_API #endif +*/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) #define skb_transport_offset(skb) (skb->h.raw - skb->data) @@ -357,7 +363,7 @@ do { \ #define RSS_SUFFIX "" #endif -#define RTL8125_VERSION "9.005.01" NAPI_SUFFIX DASH_SUFFIX REALWOW_SUFFIX PTP_SUFFIX RSS_SUFFIX +#define RTL8125_VERSION "9.005.06" NAPI_SUFFIX DASH_SUFFIX REALWOW_SUFFIX PTP_SUFFIX RSS_SUFFIX #define MODULENAME "r8125" #define PFX MODULENAME ": " @@ -460,6 +466,8 @@ This is free software, and you are welcome to redistribute it under certain cond #define R8125_MAX_RX_QUEUES (4) #define R8125_MAX_QUEUES R8125_MAX_RX_QUEUES +#define OCP_STD_PHY_BASE 0xa400 + #ifdef ENABLE_LIB_SUPPORT #define R8125_MULTI_RX_Q(tp) 1 #else @@ -497,7 +505,7 @@ This is free software, and you are welcome to redistribute it under certain cond #endif #ifndef NETDEV_TX_LOCKED -#define NETDEV_TX_LOCKED -1 /* driver tx lock was already taken */ +#define NETDEV_TX_LOCKED -1t /* driver tx lock was already taken */ #endif #ifndef ADVERTISED_Pause @@ -533,6 +541,7 @@ This is free software, and you are welcome to redistribute it under certain cond #endif #define RTK_ADVERTISE_2500FULL 0x80 +#define RTK_LPA_ADVERTISE_2500FULL 0x20 /* Tx NO CLOSE */ #define MAX_TX_NO_CLOSE_DESC_PTR_V2 0x10000 @@ -1284,6 +1293,7 @@ enum RTL8125_register_content { RxCfg_128_int_en = (1 << 15), RxCfg_fet_multi_en = (1 << 14), RxCfg_half_refetch = (1 << 13), + RxCfg_pause_slot_en = (1 << 11), RxCfg_9356SEL = (1 << 6), /* TxConfigBits */ @@ -1911,10 +1921,6 @@ struct rtl8125_private { u8 random_mac; - u8 HwSuppGigaForceMode; - - u16 phy_reg_anlpar; - u32 HwPcieSNOffset; u8 HwSuppTxNoCloseVer; @@ -1931,6 +1937,12 @@ struct rtl8125_private { u8 HwSuppD0SpeedUpVer; u8 D0SpeedUpSpeed; + u8 ring_lib_enabled; + + const char *fw_name; + struct rtl8125_fw *rtl_fw; + u32 ocp_base; + //Dash+++++++++++++++++ u8 HwSuppDashVer; u8 DASH; @@ -2020,8 +2032,7 @@ struct rtl8125_private { //Realwow-------------- #endif //ENABLE_REALWOW_SUPPORT - u32 eee_adv_t; - u8 eee_enabled; + struct ethtool_eee eee; #ifdef ENABLE_R8125_PROCFS //Procfs support @@ -2123,8 +2134,8 @@ enum mcfg { CFG_METHOD_3, CFG_METHOD_4, CFG_METHOD_5, - CFG_METHOD_MAX, - CFG_METHOD_DEFAULT = 0xFF + CFG_METHOD_DEFAULT, + CFG_METHOD_MAX }; #define LSO_32K 32000 @@ -2164,15 +2175,15 @@ enum mcfg { static const u16 other_q_intr_mask = (RxOK1 | RxDU1); -void rtl8125_mdio_write(struct rtl8125_private *tp, u32 RegAddr, u32 value); +void rtl8125_mdio_write(struct rtl8125_private *tp, u16 RegAddr, u16 value); void rtl8125_mdio_prot_write(struct rtl8125_private *tp, u32 RegAddr, u32 value); void rtl8125_mdio_prot_direct_write_phy_ocp(struct rtl8125_private *tp, u32 RegAddr, u32 value); -u32 rtl8125_mdio_read(struct rtl8125_private *tp, u32 RegAddr); +u32 rtl8125_mdio_read(struct rtl8125_private *tp, u16 RegAddr); u32 rtl8125_mdio_prot_read(struct rtl8125_private *tp, u32 RegAddr); u32 rtl8125_mdio_prot_direct_read_phy_ocp(struct rtl8125_private *tp, u32 RegAddr); void rtl8125_ephy_write(struct rtl8125_private *tp, int RegAddr, int value); void rtl8125_mac_ocp_write(struct rtl8125_private *tp, u16 reg_addr, u16 value); -u16 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr); +u32 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr); void rtl8125_clear_eth_phy_bit(struct rtl8125_private *tp, u8 addr, u16 mask); void rtl8125_set_eth_phy_bit(struct rtl8125_private *tp, u8 addr, u16 mask); void rtl8125_ocp_write(struct rtl8125_private *tp, u16 addr, u8 len, u32 data); @@ -2180,7 +2191,6 @@ void rtl8125_oob_notify(struct rtl8125_private *tp, u8 cmd); void rtl8125_init_ring_indexes(struct rtl8125_private *tp); int rtl8125_eri_write(struct rtl8125_private *tp, int addr, int len, u32 value, int type); void rtl8125_oob_mutex_lock(struct rtl8125_private *tp); -u32 rtl8125_mdio_read(struct rtl8125_private *tp, u32 RegAddr); u32 rtl8125_ocp_read(struct rtl8125_private *tp, u16 addr, u8 len); u32 rtl8125_ocp_read_with_oob_base_address(struct rtl8125_private *tp, u16 addr, u8 len, u32 base_address); u32 rtl8125_ocp_write_with_oob_base_address(struct rtl8125_private *tp, u16 addr, u8 len, u32 value, u32 base_address); @@ -2232,6 +2242,9 @@ rtl8125_enable_hw_interrupt_v2(struct rtl8125_private *tp, u32 message_id) RTL_W32(tp, IMR_V2_SET_REG_8125, BIT(message_id)); } +int rtl8125_open(struct net_device *dev); +int rtl8125_close(struct net_device *dev); +void rtl8125_hw_config(struct net_device *dev); void rtl8125_hw_set_timer_int_8125(struct rtl8125_private *tp, u32 message_id, u8 timer_intmiti_val); void rtl8125_set_rx_q_num(struct rtl8125_private *tp, unsigned int num_rx_queues); void rtl8125_set_tx_q_num(struct rtl8125_private *tp, unsigned int num_tx_queues); @@ -2242,11 +2255,9 @@ void rtl8125_tx_clear(struct rtl8125_private *tp); void rtl8125_rx_clear(struct rtl8125_private *tp); int rtl8125_init_ring(struct net_device *dev); void rtl8125_hw_set_rx_packet_filter(struct net_device *dev); +void rtl8125_enable_hw_linkchg_interrupt(struct rtl8125_private *tp); -#ifdef ENABLE_LIB_SUPPORT -void rtl8125_lib_reset_prepare(struct rtl8125_private *tp); -void rtl8125_lib_reset_complete(struct rtl8125_private *tp); -#else +#ifndef ENABLE_LIB_SUPPORT static inline void rtl8125_lib_reset_prepare(struct rtl8125_private *tp) { } static inline void rtl8125_lib_reset_complete(struct rtl8125_private *tp) { } #endif diff --git a/package/kernel/r8125/src/r8125_firmware.c b/package/kernel/r8125/src/r8125_firmware.c new file mode 100644 index 0000000000..ac4ea626b9 --- /dev/null +++ b/package/kernel/r8125/src/r8125_firmware.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +################################################################################ +# +# r8168 is the Linux device driver released for Realtek Gigabit Ethernet +# controllers with PCI-Express interface. +# +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Author: +# Realtek NIC software team +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ + +/************************************************************************************ + * This product is covered by one or more of the following patents: + * US6,570,884, US6,115,776, and US6,327,625. + ***********************************************************************************/ + +#include +#include +#include + +#include "r8125_firmware.h" + +enum rtl_fw_opcode { + PHY_READ = 0x0, + PHY_DATA_OR = 0x1, + PHY_DATA_AND = 0x2, + PHY_BJMPN = 0x3, + PHY_MDIO_CHG = 0x4, + PHY_CLEAR_READCOUNT = 0x7, + PHY_WRITE = 0x8, + PHY_READCOUNT_EQ_SKIP = 0x9, + PHY_COMP_EQ_SKIPN = 0xa, + PHY_COMP_NEQ_SKIPN = 0xb, + PHY_WRITE_PREVIOUS = 0xc, + PHY_SKIPN = 0xd, + PHY_DELAY_MS = 0xe, +}; + +struct fw_info { + u32 magic; + char version[RTL8125_VER_SIZE]; + __le32 fw_start; + __le32 fw_len; + u8 chksum; +} __packed; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0) +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) +#endif +#define FW_OPCODE_SIZE sizeof_field(struct rtl8125_fw_phy_action, code[0]) + +static bool rtl8125_fw_format_ok(struct rtl8125_fw *rtl_fw) +{ + const struct firmware *fw = rtl_fw->fw; + struct fw_info *fw_info = (struct fw_info *)fw->data; + struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action; + + if (fw->size < FW_OPCODE_SIZE) + return false; + + if (!fw_info->magic) { + size_t i, size, start; + u8 checksum = 0; + + if (fw->size < sizeof(*fw_info)) + return false; + + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + if (checksum != 0) + return false; + + start = le32_to_cpu(fw_info->fw_start); + if (start > fw->size) + return false; + + size = le32_to_cpu(fw_info->fw_len); + if (size > (fw->size - start) / FW_OPCODE_SIZE) + return false; + + strscpy(rtl_fw->version, fw_info->version, RTL8125_VER_SIZE); + + pa->code = (__le32 *)(fw->data + start); + pa->size = size; + } else { + if (fw->size % FW_OPCODE_SIZE) + return false; + + strscpy(rtl_fw->version, rtl_fw->fw_name, RTL8125_VER_SIZE); + + pa->code = (__le32 *)fw->data; + pa->size = fw->size / FW_OPCODE_SIZE; + } + + return true; +} + +static bool rtl8125_fw_data_ok(struct rtl8125_fw *rtl_fw) +{ + struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action; + size_t index; + + for (index = 0; index < pa->size; index++) { + u32 action = le32_to_cpu(pa->code[index]); + u32 val = action & 0x0000ffff; + u32 regno = (action & 0x0fff0000) >> 16; + + switch (action >> 28) { + case PHY_READ: + case PHY_DATA_OR: + case PHY_DATA_AND: + case PHY_CLEAR_READCOUNT: + case PHY_WRITE: + case PHY_WRITE_PREVIOUS: + case PHY_DELAY_MS: + break; + + case PHY_MDIO_CHG: + if (val > 1) + goto out; + break; + + case PHY_BJMPN: + if (regno > index) + goto out; + break; + case PHY_READCOUNT_EQ_SKIP: + if (index + 2 >= pa->size) + goto out; + break; + case PHY_COMP_EQ_SKIPN: + case PHY_COMP_NEQ_SKIPN: + case PHY_SKIPN: + if (index + 1 + regno >= pa->size) + goto out; + break; + + default: + dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action); + return false; + } + } + + return true; +out: + dev_err(rtl_fw->dev, "Out of range of firmware\n"); + return false; +} + +void rtl8125_fw_write_firmware(struct rtl8125_private *tp, struct rtl8125_fw *rtl_fw) +{ + struct rtl8125_fw_phy_action *pa = &rtl_fw->phy_action; + rtl8125_fw_write_t fw_write = rtl_fw->phy_write; + rtl8125_fw_read_t fw_read = rtl_fw->phy_read; + int predata = 0, count = 0; + size_t index; + + for (index = 0; index < pa->size; index++) { + u32 action = le32_to_cpu(pa->code[index]); + u32 data = action & 0x0000ffff; + u32 regno = (action & 0x0fff0000) >> 16; + enum rtl_fw_opcode opcode = action >> 28; + + if (!action) + break; + + switch (opcode) { + case PHY_READ: + predata = fw_read(tp, regno); + count++; + break; + case PHY_DATA_OR: + predata |= data; + break; + case PHY_DATA_AND: + predata &= data; + break; + case PHY_BJMPN: + index -= (regno + 1); + break; + case PHY_MDIO_CHG: + if (data) { + fw_write = rtl_fw->mac_mcu_write; + fw_read = rtl_fw->mac_mcu_read; + } else { + fw_write = rtl_fw->phy_write; + fw_read = rtl_fw->phy_read; + } + + break; + case PHY_CLEAR_READCOUNT: + count = 0; + break; + case PHY_WRITE: + fw_write(tp, regno, data); + break; + case PHY_READCOUNT_EQ_SKIP: + if (count == data) + index++; + break; + case PHY_COMP_EQ_SKIPN: + if (predata == data) + index += regno; + break; + case PHY_COMP_NEQ_SKIPN: + if (predata != data) + index += regno; + break; + case PHY_WRITE_PREVIOUS: + fw_write(tp, regno, predata); + break; + case PHY_SKIPN: + index += regno; + break; + case PHY_DELAY_MS: + mdelay(data); + break; + } + } +} + +void rtl8125_fw_release_firmware(struct rtl8125_fw *rtl_fw) +{ + release_firmware(rtl_fw->fw); +} + +int rtl8125_fw_request_firmware(struct rtl8125_fw *rtl_fw) +{ + int rc; + + rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); + if (rc < 0) + goto out; + + if (!rtl8125_fw_format_ok(rtl_fw) || !rtl8125_fw_data_ok(rtl_fw)) { + release_firmware(rtl_fw->fw); + rc = -EINVAL; + goto out; + } + + return 0; +out: + dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n", + rtl_fw->fw_name, rc); + return rc; +} diff --git a/package/kernel/r8125/src/r8125_firmware.h b/package/kernel/r8125/src/r8125_firmware.h new file mode 100644 index 0000000000..1961be5d55 --- /dev/null +++ b/package/kernel/r8125/src/r8125_firmware.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +################################################################################ +# +# r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet +# controllers with PCI-Express interface. +# +# Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Author: +# Realtek NIC software team +# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan +# +################################################################################ +*/ + +/************************************************************************************ + * This product is covered by one or more of the following patents: + * US6,570,884, US6,115,776, and US6,327,625. + ***********************************************************************************/ + +#ifndef _LINUX_rtl8125_FIRMWARE_H +#define _LINUX_rtl8125_FIRMWARE_H + +#include +#include + +struct rtl8125_private; +typedef void (*rtl8125_fw_write_t)(struct rtl8125_private *tp, u16 reg, u16 val); +typedef u32 (*rtl8125_fw_read_t)(struct rtl8125_private *tp, u16 reg); + +#define RTL8125_VER_SIZE 32 + +struct rtl8125_fw { + rtl8125_fw_write_t phy_write; + rtl8125_fw_read_t phy_read; + rtl8125_fw_write_t mac_mcu_write; + rtl8125_fw_read_t mac_mcu_read; + const struct firmware *fw; + const char *fw_name; + struct device *dev; + + char version[RTL8125_VER_SIZE]; + + struct rtl8125_fw_phy_action { + __le32 *code; + size_t size; + } phy_action; +}; + +int rtl8125_fw_request_firmware(struct rtl8125_fw *rtl_fw); +void rtl8125_fw_release_firmware(struct rtl8125_fw *rtl_fw); +void rtl8125_fw_write_firmware(struct rtl8125_private *tp, struct rtl8125_fw *rtl_fw); + +#endif /* _LINUX_rtl8125_FIRMWARE_H */ diff --git a/package/kernel/r8125/src/r8125_n.c b/package/kernel/r8125/src/r8125_n.c index 608d8c2ee5..e0f3c4c870 100644 --- a/package/kernel/r8125/src/r8125_n.c +++ b/package/kernel/r8125/src/r8125_n.c @@ -83,17 +83,33 @@ #include "r8125.h" #include "rtl_eeprom.h" #include "rtltool.h" +#include "r8125_firmware.h" #ifdef ENABLE_R8125_PROCFS #include #include #endif +#define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" +#define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" + /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static const int multicast_filter_limit = 32; -#define _R(NAME,MAC,RCR,MASK, JumFrameSz) \ +static const struct { + const char *name; + const char *fw_name; +} rtl_chip_fw_infos[] = { + /* PCI-E devices. */ + [CFG_METHOD_2] = {"RTL8125A" }, + [CFG_METHOD_3] = {"RTL8125A", FIRMWARE_8125A_3}, + [CFG_METHOD_4] = {"RTL8125B", }, + [CFG_METHOD_5] = {"RTL8125B", FIRMWARE_8125B_2}, + [CFG_METHOD_DEFAULT] = {"Unknown", }, +}; + +#define _R(NAME,MAC,RCR,MASK,JumFrameSz) \ { .name = NAME, .mcfg = MAC, .RCR_Cfg = RCR, .RxConfigMask = MASK, .jumbo_frame_sz = JumFrameSz } static const struct { @@ -117,13 +133,13 @@ static const struct { _R("RTL8125B", CFG_METHOD_4, - BIT_30 | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), + BIT_30 | RxCfg_pause_slot_en | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), 0xff7e5880, Jumbo_Frame_9k), _R("RTL8125B", CFG_METHOD_5, - BIT_30 | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), + BIT_30 | RxCfg_pause_slot_en | EnableInnerVlan | EnableOuterVlan | (RX_DMA_BURST << RxCfgDMAShift), 0xff7e5880, Jumbo_Frame_9k), @@ -135,6 +151,7 @@ static const struct { }; #undef _R + #ifndef PCI_VENDOR_ID_DLINK #define PCI_VENDOR_ID_DLINK 0x1186 #endif @@ -261,6 +278,10 @@ MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); #endif//LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) MODULE_LICENSE("GPL"); +#ifdef ENABLE_USE_FIRMWARE_FILE +MODULE_FIRMWARE(FIRMWARE_8125A_3); +MODULE_FIRMWARE(FIRMWARE_8125B_2); +#endif MODULE_VERSION(RTL8125_VERSION); @@ -277,8 +298,7 @@ static void rtl8125_link_timer(struct timer_list *t); #endif */ -static int rtl8125_open(struct net_device *dev); -static int rtl8125_start_xmit(struct sk_buff *skb, struct net_device *dev); +static netdev_tx_t rtl8125_start_xmit(struct sk_buff *skb, struct net_device *dev); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) static irqreturn_t rtl8125_interrupt(int irq, void *dev_instance, struct pt_regs *regs); #else @@ -289,8 +309,6 @@ static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance, struct pt #else static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance); #endif -void rtl8125_hw_config(struct net_device *dev); -static int rtl8125_close(struct net_device *dev); static void rtl8125_set_rx_mode(struct net_device *dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) static void rtl8125_tx_timeout(struct net_device *dev, unsigned int txqueue); @@ -310,6 +328,8 @@ static void rtl8125_desc_addr_fill(struct rtl8125_private *); static void rtl8125_tx_desc_init(struct rtl8125_private *tp); static void rtl8125_rx_desc_init(struct rtl8125_private *tp); +static u32 mdio_direct_read_phy_ocp(struct rtl8125_private *tp, u16 RegAddr); +static u16 rtl8125_get_hw_phy_mcu_code_ver(struct rtl8125_private *tp); static void rtl8125_phy_power_up(struct net_device *dev); static void rtl8125_phy_power_down(struct net_device *dev); static int rtl8125_set_speed(struct net_device *dev, u8 autoneg, u32 speed, u8 duplex, u32 adv); @@ -320,6 +340,17 @@ static bool rtl8125_clear_phy_mcu_patch_request(struct rtl8125_private *tp); static int rtl8125_poll(napi_ptr napi, napi_budget budget); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void rtl8125_reset_task(void *_data); +#else +static void rtl8125_reset_task(struct work_struct *work); +#endif + +static inline struct device *tp_to_dev(struct rtl8125_private *tp) +{ + return &tp->pci_dev->dev; +} + #if ((LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) && \ LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,00))) void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst, @@ -605,6 +636,24 @@ struct rtl8125_counters { u16 tx_underun; }; +static u32 rtl8125_read_thermal_sensor(struct rtl8125_private *tp) +{ + u16 ts_digout; + + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + ts_digout = mdio_direct_read_phy_ocp(tp, 0xBD84); + ts_digout &= 0x3ff; + break; + default: + ts_digout = 0xffff; + break; + } + + return ts_digout; +} + #ifdef ENABLE_R8125_PROCFS /**************************************************************************** * -----------------------------PROCFS STUFF------------------------- @@ -700,7 +749,7 @@ static int proc_get_driver_variable(struct seq_file *m, void *v) seq_printf(m, "aspm\t0x%x\n", aspm); seq_printf(m, "s5wol\t0x%x\n", s5wol); seq_printf(m, "s5_keep_curr_mac\t0x%x\n", s5_keep_curr_mac); - seq_printf(m, "eee_enable\t0x%x\n", tp->eee_enabled); + seq_printf(m, "eee_enable\t0x%x\n", tp->eee.eee_enabled); seq_printf(m, "hwoptimize\t0x%lx\n", hwoptimize); seq_printf(m, "proc_init_num\t0x%x\n", proc_init_num); seq_printf(m, "s0_magic_packet\t0x%x\n", s0_magic_packet); @@ -710,7 +759,6 @@ static int proc_get_driver_variable(struct seq_file *m, void *v) seq_printf(m, "D0SpeedUpSpeed\t0x%x\n", tp->D0SpeedUpSpeed); seq_printf(m, "HwSuppCheckPhyDisableModeVer\t0x%x\n", tp->HwSuppCheckPhyDisableModeVer); seq_printf(m, "HwPkgDet\t0x%x\n", tp->HwPkgDet); - seq_printf(m, "HwSuppGigaForceMode\t0x%x\n", tp->HwSuppGigaForceMode); seq_printf(m, "HwSuppTxNoCloseVer\t0x%x\n", tp->HwSuppTxNoCloseVer); seq_printf(m, "EnableTxNoClose\t0x%x\n", tp->EnableTxNoClose); seq_printf(m, "NextHwDesCloPtr0\t0x%x\n", tp->tx_ring[0].NextHwDesCloPtr); @@ -728,6 +776,9 @@ static int proc_get_driver_variable(struct seq_file *m, void *v) seq_printf(m, "ptp_master_mode\t0x%x\n", tp->ptp_master_mode); seq_printf(m, "min_irq_nvecs\t0x%x\n", tp->min_irq_nvecs); seq_printf(m, "irq_nvecs\t0x%x\n", tp->irq_nvecs); + seq_printf(m, "ring_lib_enabled\t0x%x\n", tp->ring_lib_enabled); + seq_printf(m, "HwSuppIsrVer\t0x%x\n", tp->HwSuppIsrVer); + seq_printf(m, "HwCurrIsrVer\t0x%x\n", tp->HwCurrIsrVer); #ifdef ENABLE_PTP_SUPPORT seq_printf(m, "tx_hwtstamp_timeouts\t0x%x\n", tp->tx_hwtstamp_timeouts); seq_printf(m, "tx_hwtstamp_skipped\t0x%x\n", tp->tx_hwtstamp_skipped); @@ -939,6 +990,44 @@ static int proc_get_pci_registers(struct seq_file *m, void *v) seq_putc(m, '\n'); return 0; } + +static int proc_get_temperature(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct rtl8125_private *tp = netdev_priv(dev); + u16 ts_digout, tj, fah; + unsigned long flags; + + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + seq_puts(m, "\nChip Temperature\n"); + break; + default: + seq_puts(m, "\nThis Chip Does Not Support Dump Temperature\n"); + break; + } + + spin_lock_irqsave(&tp->lock, flags); + ts_digout = rtl8125_read_thermal_sensor(tp); + spin_unlock_irqrestore(&tp->lock, flags); + + tj = ts_digout / 2; + if (ts_digout <= 512) { + tj = ts_digout / 2; + seq_printf(m, "Cel:%d\n", tj); + fah = tj * (9/5) + 32; + seq_printf(m, "Fah:%d\n", fah); + } else { + tj = (512 - ((ts_digout / 2) - 512)) / 2; + seq_printf(m, "Cel:-%d\n", tj); + fah = tj * (9/5) + 32; + seq_printf(m, "Fah:-%d\n", fah); + } + + seq_putc(m, '\n'); + return 0; +} #else static int proc_get_driver_variable(char *page, char **start, @@ -1043,7 +1132,6 @@ static int proc_get_driver_variable(char *page, char **start, "D0SpeedUpSpeed\t0x%x\n" "HwSuppCheckPhyDisableModeVer\t0x%x\n" "HwPkgDet\t0x%x\n" - "HwSuppGigaForceMode\t0x%x\n" "HwSuppTxNoCloseVer\t0x%x\n" "EnableTxNoClose\t0x%x\n" "NextHwDesCloPtr0\t0x%x\n" @@ -1061,6 +1149,9 @@ static int proc_get_driver_variable(char *page, char **start, "ptp_master_mode\t0x%x\n" "min_irq_nvecs\t0x%x\n" "irq_nvecs\t0x%x\n" + "ring_lib_enabled\t0x%x\n" + "HwSuppIsrVer\t0x%x\n" + "HwCurrIsrVer\t0x%x\n" #ifdef ENABLE_PTP_SUPPORT "tx_hwtstamp_timeouts\t0x%x\n" "tx_hwtstamp_skipped\t0x%x\n" @@ -1146,7 +1237,7 @@ static int proc_get_driver_variable(char *page, char **start, aspm, s5wol, s5_keep_curr_mac, - tp->eee_enabled, + tp->eee.eee_enabled, hwoptimize, proc_init_num, s0_magic_packet, @@ -1156,7 +1247,6 @@ static int proc_get_driver_variable(char *page, char **start, tp->D0SpeedUpSpeed, tp->HwSuppCheckPhyDisableModeVer, tp->HwPkgDet, - tp->HwSuppGigaForceMode, tp->HwSuppTxNoCloseVer, tp->EnableTxNoClose, tp->tx_ring[0].NextHwDesCloPtr, @@ -1174,6 +1264,9 @@ static int proc_get_driver_variable(char *page, char **start, tp->ptp_master_mode, tp->min_irq_nvecs, tp->irq_nvecs, + tp->ring_lib_enabled, + tp->HwSuppIsrVer, + tp->HwCurrIsrVer, #ifdef ENABLE_PTP_SUPPORT tp->tx_hwtstamp_timeouts, tp->tx_hwtstamp_skipped, @@ -1467,6 +1560,60 @@ static int proc_get_pci_registers(char *page, char **start, *eof = 1; return len; } + +static int proc_get_temperature(char *page, char **start, + off_t offset, int count, + int *eof, void *data) +{ + struct net_device *dev = data; + struct rtl8125_private *tp = netdev_priv(dev); + u16 ts_digout, tj, fah; + unsigned long flags; + int len = 0; + + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + len += snprintf(page + len, count - len, + "\nChip Temperature\n"); + break; + default: + len += snprintf(page + len, count - len, + "\nThis Chip Does Not Support Dump Temperature\n"); + break; + } + + spin_lock_irqsave(&tp->lock, flags); + ts_digout = rtl8125_read_thermal_sensor(tp); + spin_unlock_irqrestore(&tp->lock, flags); + + tj = ts_digout / 2; + if (ts_digout <= 512) { + tj = ts_digout / 2; + len += snprintf(page + len, count - len, + "Cel:%d\n", + tj); + fah = tj * (9/5) + 32; + len += snprintf(page + len, count - len, + "Fah:%d\n", + fah); + + } else { + tj = (512 - ((ts_digout / 2) - 512)) / 2; + len += snprintf(page + len, count - len, + "Cel:-%d\n", + tj); + fah = tj * (9/5) + 32; + len += snprintf(page + len, count - len, + "Fah:-%d\n", + fah); + } + + len += snprintf(page + len, count - len, "\n"); + + *eof = 1; + return len; +} #endif static void rtl8125_proc_module_init(void) { @@ -1530,6 +1677,7 @@ static const struct rtl8125_proc_file rtl8125_proc_files[] = { { "eth_phy", &proc_get_eth_phy }, { "ext_regs", &proc_get_extended_registers }, { "pci_regs", &proc_get_pci_registers }, + { "temp", &proc_get_temperature }, { "", NULL } }; @@ -1697,8 +1845,8 @@ static void rtl8125_mdio_real_write_phy_ocp(struct rtl8125_private *tp, } static void mdio_real_write(struct rtl8125_private *tp, - u32 RegAddr, - u32 value) + u16 RegAddr, + u16 value) { if (RegAddr == 0x1F) { tp->cur_page = value; @@ -1708,8 +1856,8 @@ static void mdio_real_write(struct rtl8125_private *tp, } void rtl8125_mdio_write(struct rtl8125_private *tp, - u32 RegAddr, - u32 value) + u16 RegAddr, + u16 value) { if (tp->rtk_enable_diag) return; @@ -1787,13 +1935,13 @@ static u32 rtl8125_mdio_real_read_phy_ocp(struct rtl8125_private *tp, } static u32 mdio_real_read(struct rtl8125_private *tp, - u32 RegAddr) + u16 RegAddr) { return rtl8125_mdio_real_read_phy_ocp(tp, tp->cur_page, RegAddr); } u32 rtl8125_mdio_read(struct rtl8125_private *tp, - u32 RegAddr) + u16 RegAddr) { if (tp->rtk_enable_diag) return 0xffffffff; @@ -1884,7 +2032,7 @@ void rtl8125_mac_ocp_write(struct rtl8125_private *tp, u16 reg_addr, u16 value) RTL_W32(tp, MACOCP, data32); } -u16 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr) +u32 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr) { u32 data32; u16 data16 = 0; @@ -1902,6 +2050,23 @@ u16 rtl8125_mac_ocp_read(struct rtl8125_private *tp, u16 reg_addr) return data16; } +#ifdef ENABLE_USE_FIRMWARE_FILE +static void mac_mcu_write(struct rtl8125_private *tp, u16 reg, u16 value) +{ + if (reg == 0x1f) { + tp->ocp_base = value << 4; + return; + } + + rtl8125_mac_ocp_write(tp, tp->ocp_base + reg, value); +} + +static u32 mac_mcu_read(struct rtl8125_private *tp, u16 reg) +{ + return rtl8125_mac_ocp_read(tp, tp->ocp_base + reg); +} +#endif + static void ClearAndSetMcuAccessRegBit( struct rtl8125_private *tp, @@ -2609,36 +2774,6 @@ rtl8125_is_in_phy_disable_mode(struct net_device *dev) return in_phy_disable_mode; } -static void -rtl8125_enable_phy_disable_mode(struct net_device *dev) -{ - struct rtl8125_private *tp = netdev_priv(dev); - - switch (tp->HwSuppCheckPhyDisableModeVer) { - case 3: - RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) | BIT_5); - break; - } - - dprintk("enable phy disable mode.\n"); -} - -static void -rtl8125_disable_phy_disable_mode(struct net_device *dev) -{ - struct rtl8125_private *tp = netdev_priv(dev); - - switch (tp->HwSuppCheckPhyDisableModeVer) { - case 3: - RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) & ~BIT_5); - break; - } - - mdelay(1); - - dprintk("disable phy disable mode.\n"); -} - void rtl8125_wait_txrx_fifo_empty(struct net_device *dev) { @@ -2695,7 +2830,7 @@ rtl8125_disable_dash2_interrupt(struct rtl8125_private *tp) } #endif -static inline void +void rtl8125_enable_hw_linkchg_interrupt(struct rtl8125_private *tp) { switch (tp->HwCurrIsrVer) { @@ -2968,11 +3103,26 @@ rtl8125_xmii_link_ok(struct net_device *dev) return retval; } +static int +rtl8125_wait_phy_reset_complete(struct rtl8125_private *tp) +{ + int i, val; + + for (i = 0; i < 2500; i++) { + val = rtl8125_mdio_read(tp, MII_BMCR) & BMCR_RESET; + if (!val) + return 0; + + mdelay(1); + } + + return -1; +} + static void rtl8125_xmii_reset_enable(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - int i, val = 0; if (rtl8125_is_in_phy_disable_mode(dev)) { return; @@ -2987,15 +3137,7 @@ rtl8125_xmii_reset_enable(struct net_device *dev) mdio_direct_write_phy_ocp(tp, 0xA5D4, mdio_direct_read_phy_ocp(tp, 0xA5D4) & ~(RTK_ADVERTISE_2500FULL)); rtl8125_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); - for (i = 0; i < 2500; i++) { - val = rtl8125_mdio_read(tp, MII_BMCR) & BMCR_RESET; - - if (!val) { - return; - } - - mdelay(1); - } + if (rtl8125_wait_phy_reset_complete(tp) == 0) return; if (netif_msg_link(tp)) printk(KERN_ERR "%s: PHY reset failed.\n", dev->name); @@ -3082,7 +3224,7 @@ static int rtl8125_enable_eee_plus(struct rtl8125_private *tp) break; default: -// dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support EEEPlus\n"); +// dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support EEEPlus\n"); ret = -EOPNOTSUPP; break; } @@ -3104,7 +3246,7 @@ static int rtl8125_disable_eee_plus(struct rtl8125_private *tp) break; default: -// dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support EEEPlus\n"); +// dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support EEEPlus\n"); ret = -EOPNOTSUPP; break; } @@ -3159,9 +3301,6 @@ rtl8125_link_on_patch(struct net_device *dev) netif_carrier_on(dev); rtl8125_wakeup_all_tx_queue(dev); - - rtl8125_mdio_write(tp, 0x1F, 0x0000); - tp->phy_reg_anlpar = rtl8125_mdio_read(tp, MII_LPA); } static void @@ -3169,8 +3308,6 @@ rtl8125_link_down_patch(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - tp->phy_reg_anlpar = 0; - if (tp->mcfg == CFG_METHOD_2 || tp->mcfg == CFG_METHOD_3 || tp->mcfg == CFG_METHOD_4 || @@ -3201,31 +3338,33 @@ rtl8125_link_down_patch(struct net_device *dev) } static void -rtl8125_check_link_status(struct net_device *dev, bool force_set) +_rtl8125_check_link_status(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); - int link_status_on; - link_status_on = tp->link_ok(dev); + if (tp->link_ok(dev)) { + rtl8125_link_on_patch(dev); - if (force_set || (netif_carrier_ok(dev) != link_status_on)) { - if (link_status_on) { - rtl8125_link_on_patch(dev); + if (netif_msg_ifup(tp)) + printk(KERN_INFO PFX "%s: link up\n", dev->name); + } else { + if (netif_msg_ifdown(tp)) + printk(KERN_INFO PFX "%s: link down\n", dev->name); - if (netif_msg_ifup(tp)) - printk(KERN_INFO PFX "%s: link up\n", dev->name); - } else { - if (netif_msg_ifdown(tp)) - printk(KERN_INFO PFX "%s: link down\n", dev->name); - - rtl8125_link_down_patch(dev); - } - - if (!force_set) - tp->resume_not_chg_speed = 0; + rtl8125_link_down_patch(dev); } } +static void +rtl8125_check_link_status(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + _rtl8125_check_link_status(dev); + + tp->resume_not_chg_speed = 0; +} + static void rtl8125_link_option(u8 *aut, u32 *spd, @@ -3595,7 +3734,7 @@ rtl8125_enable_linkchg_wakeup(struct net_device *dev) switch (tp->HwSuppLinkChgWakeUpVer) { case 3: RTL_W8(tp, Config3, RTL_R8(tp, Config3) | LinkUp); - ClearAndSetMcuAccessRegBit(tp, 0xE0C6, (BIT_3 | BIT_2), (BIT_4 | BIT_1 | BIT_0)); + ClearAndSetMcuAccessRegBit(tp, 0xE0C6, (BIT_5 | BIT_3 | BIT_2), (BIT_4 | BIT_1 | BIT_0)); break; } } @@ -3608,7 +3747,7 @@ rtl8125_disable_linkchg_wakeup(struct net_device *dev) switch (tp->HwSuppLinkChgWakeUpVer) { case 3: RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~LinkUp); - ClearMcuAccessRegBit(tp, 0xE0C6, (BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0)); + ClearMcuAccessRegBit(tp, 0xE0C6, (BIT_5 | BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0)); break; } } @@ -3763,9 +3902,6 @@ rtl8125_phy_setup_force_mode(struct net_device *dev, u32 speed, u8 duplex) bmcr_true_force = BMCR_SPEED100; } else if ((speed == SPEED_100) && (duplex == DUPLEX_FULL)) { bmcr_true_force = BMCR_SPEED100 | BMCR_FULLDPLX; - } else if ((speed == SPEED_1000) && (duplex == DUPLEX_FULL) && - tp->HwSuppGigaForceMode) { - bmcr_true_force = BMCR_SPEED1000 | BMCR_FULLDPLX; } else { netif_err(tp, drv, dev, "Failed to set phy force mode!\n"); return; @@ -3799,44 +3935,67 @@ rtl8125_set_wol_link_speed(struct net_device *dev) struct rtl8125_private *tp = netdev_priv(dev); int auto_nego; int giga_ctrl; + int ctrl_2500; + u32 adv; u16 anlpar; + u16 gbsr; + u16 status_2500; + u16 aner; + + if (!tp->link_ok(dev) || tp->autoneg != AUTONEG_ENABLE) + goto exit; rtl8125_mdio_write(tp, 0x1F, 0x0000); + aner = rtl8125_mdio_read(tp, MII_EXPANSION); + if (!(aner & EXPANSION_NWAY)) goto exit; + auto_nego = rtl8125_mdio_read(tp, MII_ADVERTISE); auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL); - if (netif_running(dev)) - anlpar = tp->phy_reg_anlpar; - else - anlpar = rtl8125_mdio_read(tp, MII_LPA); + giga_ctrl = rtl8125_mdio_read(tp, MII_CTRL1000); + giga_ctrl &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); -#ifdef CONFIG_DOWN_SPEED_100 - auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); -#else - if (anlpar & (LPA_10HALF | LPA_10FULL)) - auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL); + ctrl_2500 = mdio_direct_read_phy_ocp(tp, 0xA5D4); + ctrl_2500 &= ~(RTK_ADVERTISE_2500FULL); + + anlpar = rtl8125_mdio_read(tp, MII_LPA); + gbsr = rtl8125_mdio_read(tp, MII_STAT1000); + status_2500 = mdio_direct_read_phy_ocp(tp, 0xA5D6); + + adv = tp->advertising; + if ((adv & ADVERTISED_10baseT_Half) && (anlpar & LPA_10HALF)) + auto_nego |= ADVERTISE_10HALF; + else if ((adv & ADVERTISED_10baseT_Full) && (anlpar & LPA_10FULL)) + auto_nego |= ADVERTISE_10FULL; + else if ((adv & ADVERTISED_100baseT_Half) && (anlpar & LPA_100HALF)) + auto_nego |= ADVERTISE_100HALF; + else if ((adv & ADVERTISED_100baseT_Full) && (anlpar & LPA_100FULL)) + auto_nego |= ADVERTISE_100FULL; + else if (adv & ADVERTISED_1000baseT_Half && (gbsr & LPA_1000HALF)) + giga_ctrl |= ADVERTISE_1000HALF; + else if (adv & ADVERTISED_1000baseT_Full && (gbsr & LPA_1000FULL)) + giga_ctrl |= ADVERTISE_1000FULL; + else if (adv & ADVERTISED_2500baseX_Full && (status_2500 & RTK_LPA_ADVERTISE_2500FULL)) + ctrl_2500 |= RTK_ADVERTISE_2500FULL; else - auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); -#endif + goto exit; if (tp->DASH) auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); - giga_ctrl = rtl8125_mdio_read(tp, MII_CTRL1000) & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); +#ifdef CONFIG_DOWN_SPEED_100 + auto_nego |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10HALF | ADVERTISE_10FULL); +#endif + rtl8125_mdio_write(tp, MII_ADVERTISE, auto_nego); rtl8125_mdio_write(tp, MII_CTRL1000, giga_ctrl); - if (tp->mcfg == CFG_METHOD_2 || - tp->mcfg == CFG_METHOD_3 || - tp->mcfg == CFG_METHOD_4 || - tp->mcfg == CFG_METHOD_5) { - int ctrl_2500; + mdio_direct_write_phy_ocp(tp, 0xA5D4, ctrl_2500); - ctrl_2500 = mdio_direct_read_phy_ocp(tp, 0xA5D4); - ctrl_2500 &= ~(RTK_ADVERTISE_2500FULL); - mdio_direct_write_phy_ocp(tp, 0xA5D4, ctrl_2500); - } rtl8125_phy_restart_nway(dev); + +exit: + return; } static bool @@ -3980,7 +4139,7 @@ rtl8125_set_wol(struct net_device *dev, spin_unlock_irqrestore(&tp->lock, flags); - device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts); + device_set_wakeup_enable(tp_to_dev(tp), wol->wolopts); return 0; } @@ -3990,12 +4149,17 @@ rtl8125_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct rtl8125_private *tp = netdev_priv(dev); + struct rtl8125_fw *rtl_fw = tp->rtl_fw; strcpy(info->driver, MODULENAME); strcpy(info->version, RTL8125_VERSION); strcpy(info->bus_info, pci_name(tp->pci_dev)); info->regdump_len = R8125_REGS_DUMP_SIZE; info->eedump_len = tp->eeprom_len; + BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version)); + if (rtl_fw) + strlcpy(info->fw_version, rtl_fw->version, + sizeof(info->fw_version)); } static int @@ -4010,12 +4174,13 @@ rtl8125_set_d0_speedup_speed(struct rtl8125_private *tp) { if (FALSE == HW_SUPPORT_D0_SPEED_UP(tp)) return; - if (tp->autoneg == AUTONEG_ENABLE || tp->speed == SPEED_2500) - tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_2500; - else if(tp->speed == SPEED_1000) - tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_1000; - else - tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_DISABLE; + tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_DISABLE; + if (tp->autoneg == AUTONEG_ENABLE) { + if (tp->speed == SPEED_2500) + tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_2500; + else if(tp->speed == SPEED_1000) + tp->D0SpeedUpSpeed = D0_SPEED_UP_SPEED_1000; + } } static int @@ -4087,11 +4252,9 @@ rtl8125_set_speed_xmii(struct net_device *dev, mdelay(20); } else { /*true force*/ - if (speed == SPEED_10 || speed == SPEED_100 || - (speed == SPEED_1000 && duplex == DUPLEX_FULL && - tp->HwSuppGigaForceMode)) { + if (speed == SPEED_10 || speed == SPEED_100) rtl8125_phy_setup_force_mode(dev, speed, duplex); - } else + else goto out; } @@ -4433,7 +4596,7 @@ static int rtl8125_hw_set_features(struct net_device *dev, else rx_config &= ~(AcceptErr | AcceptRunt); - if (dev->features & NETIF_F_HW_VLAN_RX) + if (features & NETIF_F_HW_VLAN_RX) rx_config |= (EnableInnerVlan | EnableOuterVlan); else rx_config &= ~(EnableInnerVlan | EnableOuterVlan); @@ -4814,10 +4977,10 @@ static int rtl_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u16 tmp; if (tp->eeprom_type == EEPROM_TYPE_NONE) { - dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Detect none EEPROM\n"); + dev_printk(KERN_DEBUG, tp_to_dev(tp), "Detect none EEPROM\n"); return -EOPNOTSUPP; } else if (eeprom->len == 0 || (eeprom->offset+eeprom->len) > tp->eeprom_len) { - dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Invalid parameter\n"); + dev_printk(KERN_DEBUG, tp_to_dev(tp), "Invalid parameter\n"); return -EINVAL; } @@ -4909,17 +5072,21 @@ static int _kc_ethtool_op_set_sg(struct net_device *dev, u32 data) static int rtl8125_enable_eee(struct rtl8125_private *tp) { + struct ethtool_eee *eee = &tp->eee; + u16 eee_adv_t = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); int ret; ret = 0; switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, eee->tx_lpi_timer); + SetMcuAccessRegBit(tp, 0xE040, (BIT_1|BIT_0)); SetMcuAccessRegBit(tp, 0xEB62, (BIT_2|BIT_1)); SetEthPhyOcpBit(tp, 0xA432, BIT_4); - SetEthPhyOcpBit(tp, 0xA5D0, tp->eee_adv_t); + SetEthPhyOcpBit(tp, 0xA5D0, eee_adv_t); ClearEthPhyOcpBit(tp, 0xA6D4, BIT_0); ClearEthPhyOcpBit(tp, 0xA6D8, BIT_4); @@ -4928,17 +5095,22 @@ static int rtl8125_enable_eee(struct rtl8125_private *tp) break; case CFG_METHOD_4: case CFG_METHOD_5: + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, eee->tx_lpi_timer); + SetMcuAccessRegBit(tp, 0xE040, (BIT_1|BIT_0)); - SetEthPhyOcpBit(tp, 0xA5D0, tp->eee_adv_t); - ClearEthPhyOcpBit(tp, 0xA6D4, BIT_0); + SetEthPhyOcpBit(tp, 0xA5D0, eee_adv_t); + if (eee->advertised & SUPPORTED_2500baseX_Full) + SetEthPhyOcpBit(tp, 0xA6D4, BIT_0); + else + ClearEthPhyOcpBit(tp, 0xA6D4, BIT_0); ClearEthPhyOcpBit(tp, 0xA6D8, BIT_4); ClearEthPhyOcpBit(tp, 0xA428, BIT_7); ClearEthPhyOcpBit(tp, 0xA4A2, BIT_9); break; default: -// dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support EEE\n"); +// dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support EEE\n"); ret = -EOPNOTSUPP; break; } @@ -4991,7 +5163,7 @@ static int rtl8125_disable_eee(struct rtl8125_private *tp) ClearEthPhyOcpBit(tp, 0xA4A2, BIT_9); break; default: -// dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support EEE\n"); +// dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support EEE\n"); ret = -EOPNOTSUPP; break; } @@ -5044,11 +5216,37 @@ static int rtl_nway_reset(struct net_device *dev) } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) +static u32 +rtl8125_tx_lpi_timer_to_us(struct rtl8125_private *tp , u32 tx_lpi_timer) +{ + u32 to_us; + u16 status; + + //2.5G : tx_lpi_timer * 3.2ns + //Giga: tx_lpi_timer * 8ns + //100M : tx_lpi_timer * 80ns + to_us = tx_lpi_timer * 80; + status = RTL_R16(tp, PHYstatus); + if (status & LinkStatus) { + /*link on*/ + if (status & _2500bpsF) + to_us = (tx_lpi_timer * 32) / 10; + else if (status & _1000bpsF) + to_us = tx_lpi_timer * 8; + } + + //ns to us + to_us /= 1000; + + return to_us; +} + static int -rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *eee) +rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) { struct rtl8125_private *tp = netdev_priv(net); - u32 lp, adv, supported = 0; + struct ethtool_eee *eee = &tp->eee; + u32 lp, adv, tx_lpi_timer, supported = 0; unsigned long flags; u16 val; @@ -5060,8 +5258,9 @@ rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *eee) } /* Get Supported EEE */ - val = mdio_direct_read_phy_ocp(tp, 0xA5C4); - supported = mmd_eee_cap_to_ethtool_sup_t(val); + //val = mdio_direct_read_phy_ocp(tp, 0xA5C4); + //supported = mmd_eee_cap_to_ethtool_sup_t(val); + supported = eee->supported; /* Get advertisement EEE */ val = mdio_direct_read_phy_ocp(tp, 0xA5D0); @@ -5071,25 +5270,33 @@ rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *eee) val = mdio_direct_read_phy_ocp(tp, 0xA5D2); lp = mmd_eee_adv_to_ethtool_adv_t(val); + /* Get EEE Tx LPI timer*/ + tx_lpi_timer = RTL_R16(tp, EEE_TXIDLE_TIMER_8125); + val = rtl8125_mac_ocp_read(tp, 0xE040); val &= BIT_1 | BIT_0; spin_unlock_irqrestore(&tp->lock, flags); - eee->eee_enabled = !!val; - eee->eee_active = !!(supported & adv & lp); - eee->supported = supported; - eee->advertised = adv; - eee->lp_advertised = lp; + edata->eee_enabled = !!val; + edata->eee_active = !!(supported & adv & lp); + edata->supported = supported; + edata->advertised = adv; + edata->lp_advertised = lp; + edata->tx_lpi_enabled = edata->eee_enabled; + edata->tx_lpi_timer = rtl8125_tx_lpi_timer_to_us(tp, tx_lpi_timer); return 0; } static int -rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *eee) +rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata) { struct rtl8125_private *tp = netdev_priv(net); + struct ethtool_eee *eee = &tp->eee; + u32 advertising; unsigned long flags; + int rc = 0; if (!HW_HAS_WRITE_PHY_MCU_RAM_CODE(tp) || tp->DASH) @@ -5098,24 +5305,71 @@ rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *eee) spin_lock_irqsave(&tp->lock, flags); if (unlikely(tp->rtk_enable_diag)) { - spin_unlock_irqrestore(&tp->lock, flags); - return -EBUSY; + dev_printk(KERN_WARNING, tp_to_dev(tp), "Diag Enabled\n"); + rc = -EBUSY; + goto exit_unlock; } - tp->eee_enabled = eee->eee_enabled; - tp->eee_adv_t = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); + if (tp->autoneg != AUTONEG_ENABLE) { + dev_printk(KERN_WARNING, tp_to_dev(tp), "EEE requires autoneg\n"); + rc = -EINVAL; + goto exit_unlock; + } - if (tp->eee_enabled) { + if (edata->tx_lpi_enabled) { + if (edata->tx_lpi_timer > tp->max_jumbo_frame_size || + edata->tx_lpi_timer < ETH_MIN_MTU) { + dev_printk(KERN_WARNING, tp_to_dev(tp), "Valid LPI timer range is %d to %d. \n", + ETH_MIN_MTU, tp->max_jumbo_frame_size); + rc = -EINVAL; + goto exit_unlock; + } + } + + advertising = tp->advertising; + if (!edata->advertised) { + edata->advertised = advertising & eee->supported; + } else if (edata->advertised & ~advertising) { + dev_printk(KERN_WARNING, tp_to_dev(tp), "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", + edata->advertised, advertising); + rc = -EINVAL; + goto exit_unlock; + } + + if (edata->advertised & ~eee->supported) { + dev_printk(KERN_WARNING, tp_to_dev(tp), "EEE advertised %x must be a subset of support %x\n", + edata->advertised, eee->supported); + rc = -EINVAL; + goto exit_unlock; + } + + //tp->eee.eee_enabled = edata->eee_enabled; + //tp->eee_adv_t = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + + dev_printk(KERN_WARNING, tp_to_dev(tp), "EEE tx_lpi_timer %x must be a subset of support %x\n", + edata->tx_lpi_timer, eee->tx_lpi_timer); + + eee->advertised = edata->advertised; + eee->tx_lpi_enabled = edata->tx_lpi_enabled; + eee->tx_lpi_timer = edata->tx_lpi_timer; + eee->eee_enabled = edata->eee_enabled; + + if (eee->eee_enabled) rtl8125_enable_eee(tp); - } else { + else rtl8125_disable_eee(tp); - } spin_unlock_irqrestore(&tp->lock, flags); rtl_nway_reset(net); - return 0; + return rc; + +exit_unlock: + + spin_unlock_irqrestore(&tp->lock, flags); + + return rc; } #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) */ @@ -5207,7 +5461,7 @@ static int rtl8125_enable_green_feature(struct rtl8125_private *tp) rtl8125_mdio_write(tp, 0x00, 0x9200); break; default: - dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support Green Feature\n"); + dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support Green Feature\n"); break; } @@ -5229,7 +5483,7 @@ static int rtl8125_disable_green_feature(struct rtl8125_private *tp) rtl8125_mdio_write(tp, 0x00, 0x9200); break; default: - dev_printk(KERN_DEBUG, &tp->pci_dev->dev, "Not Support Green Feature\n"); + dev_printk(KERN_DEBUG, tp_to_dev(tp), "Not Support Green Feature\n"); break; } @@ -5469,8 +5723,6 @@ rtl8125_exit_oob(struct net_device *dev) } break; }; - - tp->phy_reg_anlpar = 0; } void @@ -5518,6 +5770,7 @@ rtl8125_hw_disable_mac_mcu_bps(struct net_device *dev) } } +#ifndef ENABLE_USE_FIRMWARE_FILE static void rtl8125_set_mac_mcu_8125a_1(struct net_device *dev) { @@ -5638,6 +5891,38 @@ rtl8125_hw_mac_mcu_config(struct net_device *dev) break; } } +#endif + +#ifdef ENABLE_USE_FIRMWARE_FILE +static void rtl8125_release_firmware(struct rtl8125_private *tp) +{ + if (tp->rtl_fw) { + rtl8125_fw_release_firmware(tp->rtl_fw); + kfree(tp->rtl_fw); + tp->rtl_fw = NULL; + } +} + +void rtl8125_apply_firmware(struct rtl8125_private *tp) +{ + /* TODO: release firmware if rtl_fw_write_firmware signals failure. */ + if (tp->rtl_fw) { + rtl8125_fw_write_firmware(tp, tp->rtl_fw); + /* At least one firmware doesn't reset tp->ocp_base. */ + tp->ocp_base = OCP_STD_PHY_BASE; + + /* PHY soft reset may still be in progress */ + //phy_read_poll_timeout(tp->phydev, MII_BMCR, val, + // !(val & BMCR_RESET), + // 50000, 600000, true); + rtl8125_wait_phy_reset_complete(tp); + + tp->hw_ram_code_ver = rtl8125_get_hw_phy_mcu_code_ver(tp); + tp->sw_ram_code_ver = tp->hw_ram_code_ver; + tp->HwHasWrRamCodeToMicroP = TRUE; + } +} +#endif static void rtl8125_hw_init(struct net_device *dev) @@ -5668,7 +5953,10 @@ rtl8125_hw_init(struct net_device *dev) break; } - rtl8125_hw_mac_mcu_config(dev); +#ifndef ENABLE_USE_FIRMWARE_FILE + if (!tp->rtl_fw) + rtl8125_hw_mac_mcu_config(dev); +#endif /*disable ocp phy power saving*/ if (tp->mcfg == CFG_METHOD_2 || @@ -5690,6 +5978,14 @@ rtl8125_hw_init(struct net_device *dev) rtl8125_set_pci_pme(tp, 0); if (s0_magic_packet == 1) rtl8125_enable_magic_packet(dev); + +#ifdef ENABLE_USE_FIRMWARE_FILE + if (tp->rtl_fw && + !tp->resume_not_chg_speed && + !(HW_DASH_SUPPORT_TYPE_3(tp) && + tp->HwPkgDet == 0x06)) + rtl8125_apply_firmware(tp); +#endif } static void @@ -5803,11 +6099,10 @@ rtl8125_hw_ephy_config(struct net_device *dev) } } -static int -rtl8125_check_hw_phy_mcu_code_ver(struct net_device *dev) +static u16 +rtl8125_get_hw_phy_mcu_code_ver(struct rtl8125_private *tp) { - struct rtl8125_private *tp = netdev_priv(dev); - int ram_code_ver_match = 0; + u16 hw_ram_code_ver = ~0; switch (tp->mcfg) { case CFG_METHOD_2: @@ -5815,14 +6110,22 @@ rtl8125_check_hw_phy_mcu_code_ver(struct net_device *dev) case CFG_METHOD_4: case CFG_METHOD_5: mdio_direct_write_phy_ocp(tp, 0xA436, 0x801E); - tp->hw_ram_code_ver = mdio_direct_read_phy_ocp(tp, 0xA438); - break; - default: - tp->hw_ram_code_ver = ~0; + hw_ram_code_ver = mdio_direct_read_phy_ocp(tp, 0xA438); break; } - if ( tp->hw_ram_code_ver == tp->sw_ram_code_ver) { + return hw_ram_code_ver; +} + +static int +rtl8125_check_hw_phy_mcu_code_ver(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + int ram_code_ver_match = 0; + + tp->hw_ram_code_ver = rtl8125_get_hw_phy_mcu_code_ver(tp); + + if (tp->hw_ram_code_ver == tp->sw_ram_code_ver) { ram_code_ver_match = 1; tp->HwHasWrRamCodeToMicroP = TRUE; } @@ -5830,6 +6133,46 @@ rtl8125_check_hw_phy_mcu_code_ver(struct net_device *dev) return ram_code_ver_match; } +static bool +rtl8125_wait_phy_mcu_patch_request_ready(struct rtl8125_private *tp) +{ + u16 gphy_val; + u16 WaitCount; + bool bSuccess = TRUE; + + WaitCount = 0; + do { + gphy_val = mdio_direct_read_phy_ocp(tp, 0xB800); + gphy_val &= BIT_6; + udelay(100); + WaitCount++; + } while(gphy_val != BIT_6 && WaitCount < 1000); + + if (gphy_val != BIT_6 && WaitCount == 1000) bSuccess = FALSE; + + if (!bSuccess) + dprintk("rtl8125_wait_phy_mcu_patch_request_ready fail.\n"); + + return bSuccess; +} + +bool +rtl8125_set_phy_mcu_patch_request(struct rtl8125_private *tp) +{ + SetEthPhyOcpBit(tp, 0xB820, BIT_4); + + return rtl8125_wait_phy_mcu_patch_request_ready(tp); +} + +bool +rtl8125_clear_phy_mcu_patch_request(struct rtl8125_private *tp) +{ + ClearEthPhyOcpBit(tp, 0xB820, BIT_4); + + return rtl8125_wait_phy_mcu_patch_request_ready(tp); +} + +#ifndef ENABLE_USE_FIRMWARE_FILE static void rtl8125_write_hw_phy_mcu_code_ver(struct net_device *dev) { @@ -5893,45 +6236,6 @@ rtl8125_release_phy_mcu_patch_key_lock(struct rtl8125_private *tp) } } -static bool -rtl8125_wait_phy_mcu_patch_request_ready(struct rtl8125_private *tp) -{ - u16 gphy_val; - u16 WaitCount; - bool bSuccess = TRUE; - - WaitCount = 0; - do { - gphy_val = mdio_direct_read_phy_ocp(tp, 0xB800); - gphy_val &= BIT_6; - udelay(100); - WaitCount++; - } while(gphy_val != BIT_6 && WaitCount < 1000); - - if (gphy_val != BIT_6 && WaitCount == 1000) bSuccess = FALSE; - - if (!bSuccess) - dprintk("rtl8125_wait_phy_mcu_patch_request_ready fail.\n"); - - return bSuccess; -} - -bool -rtl8125_set_phy_mcu_patch_request(struct rtl8125_private *tp) -{ - SetEthPhyOcpBit(tp, 0xB820, BIT_4); - - return rtl8125_wait_phy_mcu_patch_request_ready(tp); -} - -bool -rtl8125_clear_phy_mcu_patch_request(struct rtl8125_private *tp) -{ - ClearEthPhyOcpBit(tp, 0xB820, BIT_4); - - return rtl8125_wait_phy_mcu_patch_request_ready(tp); -} - static void rtl8125_set_phy_mcu_ram_code(struct net_device *dev, const u16 *ramcode, u16 codesize) { @@ -5957,6 +6261,69 @@ out: return; } +static void +rtl8125_enable_phy_disable_mode(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + switch (tp->HwSuppCheckPhyDisableModeVer) { + case 3: + RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) | BIT_5); + break; + } + + dprintk("enable phy disable mode.\n"); +} + +static void +rtl8125_disable_phy_disable_mode(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + + switch (tp->HwSuppCheckPhyDisableModeVer) { + case 3: + RTL_W8(tp, 0xF2, RTL_R8(tp, 0xF2) & ~BIT_5); + break; + } + + mdelay(1); + + dprintk("disable phy disable mode.\n"); +} + +static void +rtl8125_set_hw_phy_before_init_phy_mcu(struct net_device *dev) +{ + struct rtl8125_private *tp = netdev_priv(dev); + u16 PhyRegValue; + + switch (tp->mcfg) { + case CFG_METHOD_4: + mdio_direct_write_phy_ocp(tp, 0xBF86, 0x9000); + + SetEthPhyOcpBit(tp, 0xC402, BIT_10); + ClearEthPhyOcpBit(tp, 0xC402, BIT_10); + + PhyRegValue = mdio_direct_read_phy_ocp(tp, 0xBF86); + PhyRegValue &= (BIT_1 | BIT_0); + if (PhyRegValue != 0) + dprintk("PHY watch dog not clear, value = 0x%x \n", PhyRegValue); + + mdio_direct_write_phy_ocp(tp, 0xBD86, 0x1010); + mdio_direct_write_phy_ocp(tp, 0xBD88, 0x1010); + + ClearAndSetEthPhyOcpBit(tp, + 0xBD4E, + BIT_11 | BIT_10, + BIT_11); + ClearAndSetEthPhyOcpBit(tp, + 0xBF46, + BIT_11 | BIT_10 | BIT_9 | BIT_8, + BIT_10 | BIT_9 | BIT_8); + break; + } +} + static void rtl8125_real_set_phy_mcu_8125a_1(struct net_device *dev) { @@ -8003,243 +8370,249 @@ static const u16 phy_mcu_ram_code_8125b_2[] = { 0xa436, 0x8024, 0xa438, 0x3701, 0xa436, 0xB82E, 0xa438, 0x0001, 0xb820, 0x0090, 0xa436, 0xA016, 0xa438, 0x0000, 0xa436, 0xA012, 0xa438, 0x0000, 0xa436, 0xA014, 0xa438, 0x1800, 0xa438, 0x8010, - 0xa438, 0x1800, 0xa438, 0x801a, 0xa438, 0x1800, 0xa438, 0x8024, - 0xa438, 0x1800, 0xa438, 0x802f, 0xa438, 0x1800, 0xa438, 0x8051, - 0xa438, 0x1800, 0xa438, 0x8057, 0xa438, 0x1800, 0xa438, 0x8063, - 0xa438, 0x1800, 0xa438, 0x8068, 0xa438, 0xd093, 0xa438, 0xd1c4, + 0xa438, 0x1800, 0xa438, 0x801a, 0xa438, 0x1800, 0xa438, 0x803f, + 0xa438, 0x1800, 0xa438, 0x8045, 0xa438, 0x1800, 0xa438, 0x8067, + 0xa438, 0x1800, 0xa438, 0x806d, 0xa438, 0x1800, 0xa438, 0x8079, + 0xa438, 0x1800, 0xa438, 0x807e, 0xa438, 0xd093, 0xa438, 0xd1c4, 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd704, 0xa438, 0x5fbc, 0xa438, 0xd504, 0xa438, 0xc9f1, 0xa438, 0x1800, 0xa438, 0x0fc9, 0xa438, 0xbb50, 0xa438, 0xd505, 0xa438, 0xa202, 0xa438, 0xd504, 0xa438, 0x8c0f, 0xa438, 0xd500, 0xa438, 0x1000, 0xa438, 0x1519, - 0xa438, 0x1800, 0xa438, 0x1548, 0xa438, 0x2f70, 0xa438, 0x802a, - 0xa438, 0x2f73, 0xa438, 0x156a, 0xa438, 0x1800, 0xa438, 0x155c, - 0xa438, 0xd505, 0xa438, 0xa202, 0xa438, 0xd500, 0xa438, 0x1800, - 0xa438, 0x1551, 0xa438, 0xc0c1, 0xa438, 0xc0c0, 0xa438, 0xd05a, - 0xa438, 0xd1ba, 0xa438, 0xd701, 0xa438, 0x2529, 0xa438, 0x022a, - 0xa438, 0xd0a7, 0xa438, 0xd1b9, 0xa438, 0xa208, 0xa438, 0x1000, - 0xa438, 0x080e, 0xa438, 0xd701, 0xa438, 0x408b, 0xa438, 0x1000, - 0xa438, 0x0a65, 0xa438, 0xf003, 0xa438, 0x1000, 0xa438, 0x0a6b, - 0xa438, 0xd701, 0xa438, 0x1000, 0xa438, 0x0920, 0xa438, 0x1000, - 0xa438, 0x0915, 0xa438, 0x1000, 0xa438, 0x0909, 0xa438, 0x228f, - 0xa438, 0x8038, 0xa438, 0x9801, 0xa438, 0xd71e, 0xa438, 0x5d61, - 0xa438, 0xd701, 0xa438, 0x1800, 0xa438, 0x022a, 0xa438, 0x2005, - 0xa438, 0x091a, 0xa438, 0x3bd9, 0xa438, 0x0919, 0xa438, 0x1800, - 0xa438, 0x0916, 0xa438, 0x1000, 0xa438, 0x14c5, 0xa438, 0xd703, - 0xa438, 0x3181, 0xa438, 0x8061, 0xa438, 0x60ad, 0xa438, 0x1000, - 0xa438, 0x135c, 0xa438, 0xd703, 0xa438, 0x5fba, 0xa438, 0x1800, - 0xa438, 0x0cc7, 0xa438, 0xd096, 0xa438, 0xd1a9, 0xa438, 0xd503, - 0xa438, 0x1800, 0xa438, 0x0c94, 0xa438, 0xa802, 0xa438, 0xa301, - 0xa438, 0xa801, 0xa438, 0xc004, 0xa438, 0xd710, 0xa438, 0x4000, - 0xa438, 0x1800, 0xa438, 0x1e79, 0xa436, 0xA026, 0xa438, 0x1e78, - 0xa436, 0xA024, 0xa438, 0x0c93, 0xa436, 0xA022, 0xa438, 0x0cc5, - 0xa436, 0xA020, 0xa438, 0x0915, 0xa436, 0xA006, 0xa438, 0x020a, - 0xa436, 0xA004, 0xa438, 0x155b, 0xa436, 0xA002, 0xa438, 0x1542, - 0xa436, 0xA000, 0xa438, 0x0fc7, 0xa436, 0xA008, 0xa438, 0xff00, - 0xa436, 0xA016, 0xa438, 0x0010, 0xa436, 0xA012, 0xa438, 0x0000, - 0xa436, 0xA014, 0xa438, 0x1800, 0xa438, 0x8010, 0xa438, 0x1800, - 0xa438, 0x801d, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, + 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd75e, 0xa438, 0x5fae, + 0xa438, 0x9b50, 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd75e, + 0xa438, 0x7fae, 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd707, + 0xa438, 0x40a7, 0xa438, 0xd719, 0xa438, 0x4071, 0xa438, 0x1800, + 0xa438, 0x1557, 0xa438, 0xd719, 0xa438, 0x2f70, 0xa438, 0x803b, + 0xa438, 0x2f73, 0xa438, 0x156a, 0xa438, 0x5e70, 0xa438, 0x1800, + 0xa438, 0x155d, 0xa438, 0xd505, 0xa438, 0xa202, 0xa438, 0xd500, + 0xa438, 0xffed, 0xa438, 0xd709, 0xa438, 0x4054, 0xa438, 0xa788, + 0xa438, 0xd70b, 0xa438, 0x1800, 0xa438, 0x172a, 0xa438, 0xc0c1, + 0xa438, 0xc0c0, 0xa438, 0xd05a, 0xa438, 0xd1ba, 0xa438, 0xd701, + 0xa438, 0x2529, 0xa438, 0x022a, 0xa438, 0xd0a7, 0xa438, 0xd1b9, + 0xa438, 0xa208, 0xa438, 0x1000, 0xa438, 0x080e, 0xa438, 0xd701, + 0xa438, 0x408b, 0xa438, 0x1000, 0xa438, 0x0a65, 0xa438, 0xf003, + 0xa438, 0x1000, 0xa438, 0x0a6b, 0xa438, 0xd701, 0xa438, 0x1000, + 0xa438, 0x0920, 0xa438, 0x1000, 0xa438, 0x0915, 0xa438, 0x1000, + 0xa438, 0x0909, 0xa438, 0x228f, 0xa438, 0x804e, 0xa438, 0x9801, + 0xa438, 0xd71e, 0xa438, 0x5d61, 0xa438, 0xd701, 0xa438, 0x1800, + 0xa438, 0x022a, 0xa438, 0x2005, 0xa438, 0x091a, 0xa438, 0x3bd9, + 0xa438, 0x0919, 0xa438, 0x1800, 0xa438, 0x0916, 0xa438, 0x1000, + 0xa438, 0x14c5, 0xa438, 0xd703, 0xa438, 0x3181, 0xa438, 0x8077, + 0xa438, 0x60ad, 0xa438, 0x1000, 0xa438, 0x135c, 0xa438, 0xd703, + 0xa438, 0x5fba, 0xa438, 0x1800, 0xa438, 0x0cc7, 0xa438, 0xd096, + 0xa438, 0xd1a9, 0xa438, 0xd503, 0xa438, 0x1800, 0xa438, 0x0c94, + 0xa438, 0xa802, 0xa438, 0xa301, 0xa438, 0xa801, 0xa438, 0xc004, + 0xa438, 0xd710, 0xa438, 0x4000, 0xa438, 0x1800, 0xa438, 0x1e79, + 0xa436, 0xA026, 0xa438, 0x1e78, 0xa436, 0xA024, 0xa438, 0x0c93, + 0xa436, 0xA022, 0xa438, 0x0cc5, 0xa436, 0xA020, 0xa438, 0x0915, + 0xa436, 0xA006, 0xa438, 0x020a, 0xa436, 0xA004, 0xa438, 0x1726, + 0xa436, 0xA002, 0xa438, 0x1542, 0xa436, 0xA000, 0xa438, 0x0fc7, + 0xa436, 0xA008, 0xa438, 0xff00, 0xa436, 0xA016, 0xa438, 0x0010, + 0xa436, 0xA012, 0xa438, 0x0000, 0xa436, 0xA014, 0xa438, 0x1800, + 0xa438, 0x8010, 0xa438, 0x1800, 0xa438, 0x801d, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0x1800, - 0xa438, 0x802c, 0xa438, 0xd700, 0xa438, 0x6090, 0xa438, 0x60d1, - 0xa438, 0xc95c, 0xa438, 0xf007, 0xa438, 0x60b1, 0xa438, 0xc95a, - 0xa438, 0xf004, 0xa438, 0xc956, 0xa438, 0xf002, 0xa438, 0xc94e, - 0xa438, 0x1800, 0xa438, 0x00cd, 0xa438, 0xd700, 0xa438, 0x6090, - 0xa438, 0x60d1, 0xa438, 0xc95c, 0xa438, 0xf007, 0xa438, 0x60b1, - 0xa438, 0xc95a, 0xa438, 0xf004, 0xa438, 0xc956, 0xa438, 0xf002, - 0xa438, 0xc94e, 0xa438, 0x1000, 0xa438, 0x022a, 0xa438, 0x1800, - 0xa438, 0x0132, 0xa436, 0xA08E, 0xa438, 0xffff, 0xa436, 0xA08C, - 0xa438, 0xffff, 0xa436, 0xA08A, 0xa438, 0xffff, 0xa436, 0xA088, - 0xa438, 0xffff, 0xa436, 0xA086, 0xa438, 0xffff, 0xa436, 0xA084, - 0xa438, 0xffff, 0xa436, 0xA082, 0xa438, 0x012f, 0xa436, 0xA080, - 0xa438, 0x00cc, 0xa436, 0xA090, 0xa438, 0x0103, 0xa436, 0xA016, - 0xa438, 0x0020, 0xa436, 0xA012, 0xa438, 0x0000, 0xa436, 0xA014, - 0xa438, 0x1800, 0xa438, 0x8010, 0xa438, 0x1800, 0xa438, 0x8020, - 0xa438, 0x1800, 0xa438, 0x802a, 0xa438, 0x1800, 0xa438, 0x8035, + 0xa438, 0x802c, 0xa438, 0x1800, 0xa438, 0x802c, 0xa438, 0xd700, + 0xa438, 0x6090, 0xa438, 0x60d1, 0xa438, 0xc95c, 0xa438, 0xf007, + 0xa438, 0x60b1, 0xa438, 0xc95a, 0xa438, 0xf004, 0xa438, 0xc956, + 0xa438, 0xf002, 0xa438, 0xc94e, 0xa438, 0x1800, 0xa438, 0x00cd, + 0xa438, 0xd700, 0xa438, 0x6090, 0xa438, 0x60d1, 0xa438, 0xc95c, + 0xa438, 0xf007, 0xa438, 0x60b1, 0xa438, 0xc95a, 0xa438, 0xf004, + 0xa438, 0xc956, 0xa438, 0xf002, 0xa438, 0xc94e, 0xa438, 0x1000, + 0xa438, 0x022a, 0xa438, 0x1800, 0xa438, 0x0132, 0xa436, 0xA08E, + 0xa438, 0xffff, 0xa436, 0xA08C, 0xa438, 0xffff, 0xa436, 0xA08A, + 0xa438, 0xffff, 0xa436, 0xA088, 0xa438, 0xffff, 0xa436, 0xA086, + 0xa438, 0xffff, 0xa436, 0xA084, 0xa438, 0xffff, 0xa436, 0xA082, + 0xa438, 0x012f, 0xa436, 0xA080, 0xa438, 0x00cc, 0xa436, 0xA090, + 0xa438, 0x0103, 0xa436, 0xA016, 0xa438, 0x0020, 0xa436, 0xA012, + 0xa438, 0x0000, 0xa436, 0xA014, 0xa438, 0x1800, 0xa438, 0x8010, + 0xa438, 0x1800, 0xa438, 0x8020, 0xa438, 0x1800, 0xa438, 0x802a, + 0xa438, 0x1800, 0xa438, 0x8035, 0xa438, 0x1800, 0xa438, 0x803c, 0xa438, 0x1800, 0xa438, 0x803c, 0xa438, 0x1800, 0xa438, 0x803c, - 0xa438, 0x1800, 0xa438, 0x803c, 0xa438, 0x1800, 0xa438, 0x803c, - 0xa438, 0xd107, 0xa438, 0xd042, 0xa438, 0xa404, 0xa438, 0x1000, - 0xa438, 0x09df, 0xa438, 0xd700, 0xa438, 0x5fb4, 0xa438, 0x8280, - 0xa438, 0xd700, 0xa438, 0x6065, 0xa438, 0xd125, 0xa438, 0xf002, - 0xa438, 0xd12b, 0xa438, 0xd040, 0xa438, 0x1800, 0xa438, 0x077f, - 0xa438, 0x0cf0, 0xa438, 0x0c50, 0xa438, 0xd104, 0xa438, 0xd040, - 0xa438, 0x1000, 0xa438, 0x0aa8, 0xa438, 0xd700, 0xa438, 0x5fb4, - 0xa438, 0x1800, 0xa438, 0x0a2e, 0xa438, 0xcb9b, 0xa438, 0xd110, - 0xa438, 0xd040, 0xa438, 0x1000, 0xa438, 0x0b7b, 0xa438, 0x1000, - 0xa438, 0x09df, 0xa438, 0xd700, 0xa438, 0x5fb4, 0xa438, 0x1800, - 0xa438, 0x081b, 0xa438, 0x1000, 0xa438, 0x09df, 0xa438, 0xd704, - 0xa438, 0x7fb8, 0xa438, 0xa718, 0xa438, 0x1800, 0xa438, 0x074e, - 0xa436, 0xA10E, 0xa438, 0xffff, 0xa436, 0xA10C, 0xa438, 0xffff, - 0xa436, 0xA10A, 0xa438, 0xffff, 0xa436, 0xA108, 0xa438, 0xffff, - 0xa436, 0xA106, 0xa438, 0x074d, 0xa436, 0xA104, 0xa438, 0x0818, - 0xa436, 0xA102, 0xa438, 0x0a2c, 0xa436, 0xA100, 0xa438, 0x077e, - 0xa436, 0xA110, 0xa438, 0x000f, 0xa436, 0xb87c, 0xa438, 0x8625, - 0xa436, 0xb87e, 0xa438, 0xaf86, 0xa438, 0x3daf, 0xa438, 0x8689, - 0xa438, 0xaf88, 0xa438, 0x69af, 0xa438, 0x8887, 0xa438, 0xaf88, - 0xa438, 0x9caf, 0xa438, 0x889c, 0xa438, 0xaf88, 0xa438, 0x9caf, - 0xa438, 0x889c, 0xa438, 0xbf86, 0xa438, 0x49d7, 0xa438, 0x0040, - 0xa438, 0x0277, 0xa438, 0x7daf, 0xa438, 0x2727, 0xa438, 0x0000, - 0xa438, 0x7205, 0xa438, 0x0000, 0xa438, 0x7208, 0xa438, 0x0000, - 0xa438, 0x71f3, 0xa438, 0x0000, 0xa438, 0x71f6, 0xa438, 0x0000, - 0xa438, 0x7229, 0xa438, 0x0000, 0xa438, 0x722c, 0xa438, 0x0000, - 0xa438, 0x7217, 0xa438, 0x0000, 0xa438, 0x721a, 0xa438, 0x0000, - 0xa438, 0x721d, 0xa438, 0x0000, 0xa438, 0x7211, 0xa438, 0x0000, - 0xa438, 0x7220, 0xa438, 0x0000, 0xa438, 0x7214, 0xa438, 0x0000, - 0xa438, 0x722f, 0xa438, 0x0000, 0xa438, 0x7223, 0xa438, 0x0000, - 0xa438, 0x7232, 0xa438, 0x0000, 0xa438, 0x7226, 0xa438, 0xf8f9, - 0xa438, 0xfae0, 0xa438, 0x85b3, 0xa438, 0x3802, 0xa438, 0xad27, - 0xa438, 0x02ae, 0xa438, 0x03af, 0xa438, 0x8830, 0xa438, 0x1f66, - 0xa438, 0xef65, 0xa438, 0xbfc2, 0xa438, 0x1f1a, 0xa438, 0x96f7, - 0xa438, 0x05ee, 0xa438, 0xffd2, 0xa438, 0x00da, 0xa438, 0xf605, - 0xa438, 0xbfc2, 0xa438, 0x2f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, - 0xa438, 0xffd2, 0xa438, 0x00db, 0xa438, 0xf605, 0xa438, 0xef02, - 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4202, - 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1b03, 0xa438, 0x1f11, - 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4502, 0xa438, 0x6e7d, - 0xa438, 0xef02, 0xa438, 0x1a03, 0xa438, 0x1f11, 0xa438, 0x0d42, - 0xa438, 0xbf88, 0xa438, 0x4802, 0xa438, 0x6e7d, 0xa438, 0xbfc2, - 0xa438, 0x3f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, - 0xa438, 0x00da, 0xa438, 0xf605, 0xa438, 0xbfc2, 0xa438, 0x4f1a, + 0xa438, 0x1800, 0xa438, 0x803c, 0xa438, 0xd107, 0xa438, 0xd042, + 0xa438, 0xa404, 0xa438, 0x1000, 0xa438, 0x09df, 0xa438, 0xd700, + 0xa438, 0x5fb4, 0xa438, 0x8280, 0xa438, 0xd700, 0xa438, 0x6065, + 0xa438, 0xd125, 0xa438, 0xf002, 0xa438, 0xd12b, 0xa438, 0xd040, + 0xa438, 0x1800, 0xa438, 0x077f, 0xa438, 0x0cf0, 0xa438, 0x0c50, + 0xa438, 0xd104, 0xa438, 0xd040, 0xa438, 0x1000, 0xa438, 0x0aa8, + 0xa438, 0xd700, 0xa438, 0x5fb4, 0xa438, 0x1800, 0xa438, 0x0a2e, + 0xa438, 0xcb9b, 0xa438, 0xd110, 0xa438, 0xd040, 0xa438, 0x1000, + 0xa438, 0x0b7b, 0xa438, 0x1000, 0xa438, 0x09df, 0xa438, 0xd700, + 0xa438, 0x5fb4, 0xa438, 0x1800, 0xa438, 0x081b, 0xa438, 0x1000, + 0xa438, 0x09df, 0xa438, 0xd704, 0xa438, 0x7fb8, 0xa438, 0xa718, + 0xa438, 0x1800, 0xa438, 0x074e, 0xa436, 0xA10E, 0xa438, 0xffff, + 0xa436, 0xA10C, 0xa438, 0xffff, 0xa436, 0xA10A, 0xa438, 0xffff, + 0xa436, 0xA108, 0xa438, 0xffff, 0xa436, 0xA106, 0xa438, 0x074d, + 0xa436, 0xA104, 0xa438, 0x0818, 0xa436, 0xA102, 0xa438, 0x0a2c, + 0xa436, 0xA100, 0xa438, 0x077e, 0xa436, 0xA110, 0xa438, 0x000f, + 0xa436, 0xb87c, 0xa438, 0x8625, 0xa436, 0xb87e, 0xa438, 0xaf86, + 0xa438, 0x3daf, 0xa438, 0x8689, 0xa438, 0xaf88, 0xa438, 0x69af, + 0xa438, 0x8887, 0xa438, 0xaf88, 0xa438, 0x9caf, 0xa438, 0x889c, + 0xa438, 0xaf88, 0xa438, 0x9caf, 0xa438, 0x889c, 0xa438, 0xbf86, + 0xa438, 0x49d7, 0xa438, 0x0040, 0xa438, 0x0277, 0xa438, 0x7daf, + 0xa438, 0x2727, 0xa438, 0x0000, 0xa438, 0x7205, 0xa438, 0x0000, + 0xa438, 0x7208, 0xa438, 0x0000, 0xa438, 0x71f3, 0xa438, 0x0000, + 0xa438, 0x71f6, 0xa438, 0x0000, 0xa438, 0x7229, 0xa438, 0x0000, + 0xa438, 0x722c, 0xa438, 0x0000, 0xa438, 0x7217, 0xa438, 0x0000, + 0xa438, 0x721a, 0xa438, 0x0000, 0xa438, 0x721d, 0xa438, 0x0000, + 0xa438, 0x7211, 0xa438, 0x0000, 0xa438, 0x7220, 0xa438, 0x0000, + 0xa438, 0x7214, 0xa438, 0x0000, 0xa438, 0x722f, 0xa438, 0x0000, + 0xa438, 0x7223, 0xa438, 0x0000, 0xa438, 0x7232, 0xa438, 0x0000, + 0xa438, 0x7226, 0xa438, 0xf8f9, 0xa438, 0xfae0, 0xa438, 0x85b3, + 0xa438, 0x3802, 0xa438, 0xad27, 0xa438, 0x02ae, 0xa438, 0x03af, + 0xa438, 0x8830, 0xa438, 0x1f66, 0xa438, 0xef65, 0xa438, 0xbfc2, + 0xa438, 0x1f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, + 0xa438, 0x00da, 0xa438, 0xf605, 0xa438, 0xbfc2, 0xa438, 0x2f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, 0xa438, 0xffd2, 0xa438, 0x00db, 0xa438, 0xf605, 0xa438, 0xef02, 0xa438, 0x1f11, 0xa438, 0x0d42, - 0xa438, 0xbf88, 0xa438, 0x4b02, 0xa438, 0x6e7d, 0xa438, 0xef02, + 0xa438, 0xbf88, 0xa438, 0x4202, 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1b03, 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, - 0xa438, 0x4e02, 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1a03, - 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x5102, - 0xa438, 0x6e7d, 0xa438, 0xef56, 0xa438, 0xd020, 0xa438, 0x1f11, - 0xa438, 0xbf88, 0xa438, 0x5402, 0xa438, 0x6e7d, 0xa438, 0xbf88, - 0xa438, 0x5702, 0xa438, 0x6e7d, 0xa438, 0xbf88, 0xa438, 0x5a02, - 0xa438, 0x6e7d, 0xa438, 0xe185, 0xa438, 0xa0ef, 0xa438, 0x0348, - 0xa438, 0x0a28, 0xa438, 0x05ef, 0xa438, 0x201b, 0xa438, 0x01ad, - 0xa438, 0x2735, 0xa438, 0x1f44, 0xa438, 0xe085, 0xa438, 0x88e1, - 0xa438, 0x8589, 0xa438, 0xbf88, 0xa438, 0x5d02, 0xa438, 0x6e7d, - 0xa438, 0xe085, 0xa438, 0x8ee1, 0xa438, 0x858f, 0xa438, 0xbf88, - 0xa438, 0x6002, 0xa438, 0x6e7d, 0xa438, 0xe085, 0xa438, 0x94e1, - 0xa438, 0x8595, 0xa438, 0xbf88, 0xa438, 0x6302, 0xa438, 0x6e7d, - 0xa438, 0xe085, 0xa438, 0x9ae1, 0xa438, 0x859b, 0xa438, 0xbf88, - 0xa438, 0x6602, 0xa438, 0x6e7d, 0xa438, 0xaf88, 0xa438, 0x3cbf, - 0xa438, 0x883f, 0xa438, 0x026e, 0xa438, 0x9cad, 0xa438, 0x2835, - 0xa438, 0x1f44, 0xa438, 0xe08f, 0xa438, 0xf8e1, 0xa438, 0x8ff9, - 0xa438, 0xbf88, 0xa438, 0x5d02, 0xa438, 0x6e7d, 0xa438, 0xe08f, - 0xa438, 0xfae1, 0xa438, 0x8ffb, 0xa438, 0xbf88, 0xa438, 0x6002, - 0xa438, 0x6e7d, 0xa438, 0xe08f, 0xa438, 0xfce1, 0xa438, 0x8ffd, - 0xa438, 0xbf88, 0xa438, 0x6302, 0xa438, 0x6e7d, 0xa438, 0xe08f, - 0xa438, 0xfee1, 0xa438, 0x8fff, 0xa438, 0xbf88, 0xa438, 0x6602, - 0xa438, 0x6e7d, 0xa438, 0xaf88, 0xa438, 0x3ce1, 0xa438, 0x85a1, - 0xa438, 0x1b21, 0xa438, 0xad37, 0xa438, 0x341f, 0xa438, 0x44e0, - 0xa438, 0x858a, 0xa438, 0xe185, 0xa438, 0x8bbf, 0xa438, 0x885d, - 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x8590, 0xa438, 0xe185, - 0xa438, 0x91bf, 0xa438, 0x8860, 0xa438, 0x026e, 0xa438, 0x7de0, - 0xa438, 0x8596, 0xa438, 0xe185, 0xa438, 0x97bf, 0xa438, 0x8863, - 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x859c, 0xa438, 0xe185, - 0xa438, 0x9dbf, 0xa438, 0x8866, 0xa438, 0x026e, 0xa438, 0x7dae, - 0xa438, 0x401f, 0xa438, 0x44e0, 0xa438, 0x858c, 0xa438, 0xe185, - 0xa438, 0x8dbf, 0xa438, 0x885d, 0xa438, 0x026e, 0xa438, 0x7de0, - 0xa438, 0x8592, 0xa438, 0xe185, 0xa438, 0x93bf, 0xa438, 0x8860, - 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x8598, 0xa438, 0xe185, - 0xa438, 0x99bf, 0xa438, 0x8863, 0xa438, 0x026e, 0xa438, 0x7de0, - 0xa438, 0x859e, 0xa438, 0xe185, 0xa438, 0x9fbf, 0xa438, 0x8866, - 0xa438, 0x026e, 0xa438, 0x7dae, 0xa438, 0x0ce1, 0xa438, 0x85b3, - 0xa438, 0x3904, 0xa438, 0xac2f, 0xa438, 0x04ee, 0xa438, 0x85b3, - 0xa438, 0x00af, 0xa438, 0x39d9, 0xa438, 0x22ac, 0xa438, 0xeaf0, - 0xa438, 0xacf6, 0xa438, 0xf0ac, 0xa438, 0xfaf0, 0xa438, 0xacf8, - 0xa438, 0xf0ac, 0xa438, 0xfcf0, 0xa438, 0xad00, 0xa438, 0xf0ac, - 0xa438, 0xfef0, 0xa438, 0xacf0, 0xa438, 0xf0ac, 0xa438, 0xf4f0, - 0xa438, 0xacf2, 0xa438, 0xf0ac, 0xa438, 0xb0f0, 0xa438, 0xacae, - 0xa438, 0xf0ac, 0xa438, 0xacf0, 0xa438, 0xacaa, 0xa438, 0xa100, - 0xa438, 0x0ce1, 0xa438, 0x8ff7, 0xa438, 0xbf88, 0xa438, 0x8402, - 0xa438, 0x6e7d, 0xa438, 0xaf26, 0xa438, 0xe9e1, 0xa438, 0x8ff6, + 0xa438, 0x4502, 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1a03, + 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4802, + 0xa438, 0x6e7d, 0xa438, 0xbfc2, 0xa438, 0x3f1a, 0xa438, 0x96f7, + 0xa438, 0x05ee, 0xa438, 0xffd2, 0xa438, 0x00da, 0xa438, 0xf605, + 0xa438, 0xbfc2, 0xa438, 0x4f1a, 0xa438, 0x96f7, 0xa438, 0x05ee, + 0xa438, 0xffd2, 0xa438, 0x00db, 0xa438, 0xf605, 0xa438, 0xef02, + 0xa438, 0x1f11, 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4b02, + 0xa438, 0x6e7d, 0xa438, 0xef02, 0xa438, 0x1b03, 0xa438, 0x1f11, + 0xa438, 0x0d42, 0xa438, 0xbf88, 0xa438, 0x4e02, 0xa438, 0x6e7d, + 0xa438, 0xef02, 0xa438, 0x1a03, 0xa438, 0x1f11, 0xa438, 0x0d42, + 0xa438, 0xbf88, 0xa438, 0x5102, 0xa438, 0x6e7d, 0xa438, 0xef56, + 0xa438, 0xd020, 0xa438, 0x1f11, 0xa438, 0xbf88, 0xa438, 0x5402, + 0xa438, 0x6e7d, 0xa438, 0xbf88, 0xa438, 0x5702, 0xa438, 0x6e7d, + 0xa438, 0xbf88, 0xa438, 0x5a02, 0xa438, 0x6e7d, 0xa438, 0xe185, + 0xa438, 0xa0ef, 0xa438, 0x0348, 0xa438, 0x0a28, 0xa438, 0x05ef, + 0xa438, 0x201b, 0xa438, 0x01ad, 0xa438, 0x2735, 0xa438, 0x1f44, + 0xa438, 0xe085, 0xa438, 0x88e1, 0xa438, 0x8589, 0xa438, 0xbf88, + 0xa438, 0x5d02, 0xa438, 0x6e7d, 0xa438, 0xe085, 0xa438, 0x8ee1, + 0xa438, 0x858f, 0xa438, 0xbf88, 0xa438, 0x6002, 0xa438, 0x6e7d, + 0xa438, 0xe085, 0xa438, 0x94e1, 0xa438, 0x8595, 0xa438, 0xbf88, + 0xa438, 0x6302, 0xa438, 0x6e7d, 0xa438, 0xe085, 0xa438, 0x9ae1, + 0xa438, 0x859b, 0xa438, 0xbf88, 0xa438, 0x6602, 0xa438, 0x6e7d, + 0xa438, 0xaf88, 0xa438, 0x3cbf, 0xa438, 0x883f, 0xa438, 0x026e, + 0xa438, 0x9cad, 0xa438, 0x2835, 0xa438, 0x1f44, 0xa438, 0xe08f, + 0xa438, 0xf8e1, 0xa438, 0x8ff9, 0xa438, 0xbf88, 0xa438, 0x5d02, + 0xa438, 0x6e7d, 0xa438, 0xe08f, 0xa438, 0xfae1, 0xa438, 0x8ffb, + 0xa438, 0xbf88, 0xa438, 0x6002, 0xa438, 0x6e7d, 0xa438, 0xe08f, + 0xa438, 0xfce1, 0xa438, 0x8ffd, 0xa438, 0xbf88, 0xa438, 0x6302, + 0xa438, 0x6e7d, 0xa438, 0xe08f, 0xa438, 0xfee1, 0xa438, 0x8fff, + 0xa438, 0xbf88, 0xa438, 0x6602, 0xa438, 0x6e7d, 0xa438, 0xaf88, + 0xa438, 0x3ce1, 0xa438, 0x85a1, 0xa438, 0x1b21, 0xa438, 0xad37, + 0xa438, 0x341f, 0xa438, 0x44e0, 0xa438, 0x858a, 0xa438, 0xe185, + 0xa438, 0x8bbf, 0xa438, 0x885d, 0xa438, 0x026e, 0xa438, 0x7de0, + 0xa438, 0x8590, 0xa438, 0xe185, 0xa438, 0x91bf, 0xa438, 0x8860, + 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x8596, 0xa438, 0xe185, + 0xa438, 0x97bf, 0xa438, 0x8863, 0xa438, 0x026e, 0xa438, 0x7de0, + 0xa438, 0x859c, 0xa438, 0xe185, 0xa438, 0x9dbf, 0xa438, 0x8866, + 0xa438, 0x026e, 0xa438, 0x7dae, 0xa438, 0x401f, 0xa438, 0x44e0, + 0xa438, 0x858c, 0xa438, 0xe185, 0xa438, 0x8dbf, 0xa438, 0x885d, + 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x8592, 0xa438, 0xe185, + 0xa438, 0x93bf, 0xa438, 0x8860, 0xa438, 0x026e, 0xa438, 0x7de0, + 0xa438, 0x8598, 0xa438, 0xe185, 0xa438, 0x99bf, 0xa438, 0x8863, + 0xa438, 0x026e, 0xa438, 0x7de0, 0xa438, 0x859e, 0xa438, 0xe185, + 0xa438, 0x9fbf, 0xa438, 0x8866, 0xa438, 0x026e, 0xa438, 0x7dae, + 0xa438, 0x0ce1, 0xa438, 0x85b3, 0xa438, 0x3904, 0xa438, 0xac2f, + 0xa438, 0x04ee, 0xa438, 0x85b3, 0xa438, 0x00af, 0xa438, 0x39d9, + 0xa438, 0x22ac, 0xa438, 0xeaf0, 0xa438, 0xacf6, 0xa438, 0xf0ac, + 0xa438, 0xfaf0, 0xa438, 0xacf8, 0xa438, 0xf0ac, 0xa438, 0xfcf0, + 0xa438, 0xad00, 0xa438, 0xf0ac, 0xa438, 0xfef0, 0xa438, 0xacf0, + 0xa438, 0xf0ac, 0xa438, 0xf4f0, 0xa438, 0xacf2, 0xa438, 0xf0ac, + 0xa438, 0xb0f0, 0xa438, 0xacae, 0xa438, 0xf0ac, 0xa438, 0xacf0, + 0xa438, 0xacaa, 0xa438, 0xa100, 0xa438, 0x0ce1, 0xa438, 0x8ff7, 0xa438, 0xbf88, 0xa438, 0x8402, 0xa438, 0x6e7d, 0xa438, 0xaf26, - 0xa438, 0xf520, 0xa438, 0xac86, 0xa438, 0xbf88, 0xa438, 0x3f02, - 0xa438, 0x6e9c, 0xa438, 0xad28, 0xa438, 0x03af, 0xa438, 0x3324, - 0xa438, 0xad38, 0xa438, 0x03af, 0xa438, 0x32e6, 0xa438, 0xaf32, - 0xa438, 0xfb00, 0xa436, 0xb87c, 0xa438, 0x8ff6, 0xa436, 0xb87e, - 0xa438, 0x0705, 0xa436, 0xb87c, 0xa438, 0x8ff8, 0xa436, 0xb87e, - 0xa438, 0x19cc, 0xa436, 0xb87c, 0xa438, 0x8ffa, 0xa436, 0xb87e, - 0xa438, 0x28e3, 0xa436, 0xb87c, 0xa438, 0x8ffc, 0xa436, 0xb87e, - 0xa438, 0x1047, 0xa436, 0xb87c, 0xa438, 0x8ffe, 0xa436, 0xb87e, - 0xa438, 0x0a45, 0xa436, 0xb85e, 0xa438, 0x271E, 0xa436, 0xb860, - 0xa438, 0x3846, 0xa436, 0xb862, 0xa438, 0x26E6, 0xa436, 0xb864, - 0xa438, 0x32E3, 0xa436, 0xb886, 0xa438, 0xffff, 0xa436, 0xb888, - 0xa438, 0xffff, 0xa436, 0xb88a, 0xa438, 0xffff, 0xa436, 0xb88c, - 0xa438, 0xffff, 0xa436, 0xb838, 0xa438, 0x000f, 0xb820, 0x0010, - 0xa436, 0x846e, 0xa438, 0xaf84, 0xa438, 0x86af, 0xa438, 0x8690, - 0xa438, 0xaf86, 0xa438, 0xa4af, 0xa438, 0x86a4, 0xa438, 0xaf86, - 0xa438, 0xa4af, 0xa438, 0x86a4, 0xa438, 0xaf86, 0xa438, 0xa4af, - 0xa438, 0x86a4, 0xa438, 0xee82, 0xa438, 0x5f00, 0xa438, 0x0284, - 0xa438, 0x90af, 0xa438, 0x0441, 0xa438, 0xf8e0, 0xa438, 0x8ff3, - 0xa438, 0xa000, 0xa438, 0x0502, 0xa438, 0x84a4, 0xa438, 0xae06, - 0xa438, 0xa001, 0xa438, 0x0302, 0xa438, 0x84c8, 0xa438, 0xfc04, - 0xa438, 0xf8f9, 0xa438, 0xef59, 0xa438, 0xe080, 0xa438, 0x15ad, - 0xa438, 0x2702, 0xa438, 0xae03, 0xa438, 0xaf84, 0xa438, 0xc3bf, - 0xa438, 0x53ca, 0xa438, 0x0252, 0xa438, 0xc8ad, 0xa438, 0x2807, - 0xa438, 0x0285, 0xa438, 0x2cee, 0xa438, 0x8ff3, 0xa438, 0x01ef, - 0xa438, 0x95fd, 0xa438, 0xfc04, 0xa438, 0xf8f9, 0xa438, 0xfaef, - 0xa438, 0x69bf, 0xa438, 0x53ca, 0xa438, 0x0252, 0xa438, 0xc8ac, - 0xa438, 0x2822, 0xa438, 0xd480, 0xa438, 0x00bf, 0xa438, 0x8684, - 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x8687, 0xa438, 0x0252, - 0xa438, 0xa9bf, 0xa438, 0x868a, 0xa438, 0x0252, 0xa438, 0xa9bf, - 0xa438, 0x868d, 0xa438, 0x0252, 0xa438, 0xa9ee, 0xa438, 0x8ff3, - 0xa438, 0x00af, 0xa438, 0x8526, 0xa438, 0xe08f, 0xa438, 0xf4e1, - 0xa438, 0x8ff5, 0xa438, 0xe28f, 0xa438, 0xf6e3, 0xa438, 0x8ff7, - 0xa438, 0x1b45, 0xa438, 0xac27, 0xa438, 0x0eee, 0xa438, 0x8ff4, - 0xa438, 0x00ee, 0xa438, 0x8ff5, 0xa438, 0x0002, 0xa438, 0x852c, - 0xa438, 0xaf85, 0xa438, 0x26e0, 0xa438, 0x8ff4, 0xa438, 0xe18f, - 0xa438, 0xf52c, 0xa438, 0x0001, 0xa438, 0xe48f, 0xa438, 0xf4e5, - 0xa438, 0x8ff5, 0xa438, 0xef96, 0xa438, 0xfefd, 0xa438, 0xfc04, - 0xa438, 0xf8f9, 0xa438, 0xef59, 0xa438, 0xbf53, 0xa438, 0x2202, - 0xa438, 0x52c8, 0xa438, 0xa18b, 0xa438, 0x02ae, 0xa438, 0x03af, - 0xa438, 0x85da, 0xa438, 0xbf57, 0xa438, 0x7202, 0xa438, 0x52c8, - 0xa438, 0xe48f, 0xa438, 0xf8e5, 0xa438, 0x8ff9, 0xa438, 0xbf57, - 0xa438, 0x7502, 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfae5, - 0xa438, 0x8ffb, 0xa438, 0xbf57, 0xa438, 0x7802, 0xa438, 0x52c8, - 0xa438, 0xe48f, 0xa438, 0xfce5, 0xa438, 0x8ffd, 0xa438, 0xbf57, - 0xa438, 0x7b02, 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfee5, - 0xa438, 0x8fff, 0xa438, 0xbf57, 0xa438, 0x6c02, 0xa438, 0x52c8, - 0xa438, 0xa102, 0xa438, 0x13ee, 0xa438, 0x8ffc, 0xa438, 0x80ee, - 0xa438, 0x8ffd, 0xa438, 0x00ee, 0xa438, 0x8ffe, 0xa438, 0x80ee, - 0xa438, 0x8fff, 0xa438, 0x00af, 0xa438, 0x8599, 0xa438, 0xa101, - 0xa438, 0x0cbf, 0xa438, 0x534c, 0xa438, 0x0252, 0xa438, 0xc8a1, - 0xa438, 0x0303, 0xa438, 0xaf85, 0xa438, 0x77bf, 0xa438, 0x5322, - 0xa438, 0x0252, 0xa438, 0xc8a1, 0xa438, 0x8b02, 0xa438, 0xae03, - 0xa438, 0xaf86, 0xa438, 0x64e0, 0xa438, 0x8ff8, 0xa438, 0xe18f, - 0xa438, 0xf9bf, 0xa438, 0x8684, 0xa438, 0x0252, 0xa438, 0xa9e0, - 0xa438, 0x8ffa, 0xa438, 0xe18f, 0xa438, 0xfbbf, 0xa438, 0x8687, - 0xa438, 0x0252, 0xa438, 0xa9e0, 0xa438, 0x8ffc, 0xa438, 0xe18f, - 0xa438, 0xfdbf, 0xa438, 0x868a, 0xa438, 0x0252, 0xa438, 0xa9e0, - 0xa438, 0x8ffe, 0xa438, 0xe18f, 0xa438, 0xffbf, 0xa438, 0x868d, - 0xa438, 0x0252, 0xa438, 0xa9af, 0xa438, 0x867f, 0xa438, 0xbf53, - 0xa438, 0x2202, 0xa438, 0x52c8, 0xa438, 0xa144, 0xa438, 0x3cbf, - 0xa438, 0x547b, 0xa438, 0x0252, 0xa438, 0xc8e4, 0xa438, 0x8ff8, - 0xa438, 0xe58f, 0xa438, 0xf9bf, 0xa438, 0x547e, 0xa438, 0x0252, - 0xa438, 0xc8e4, 0xa438, 0x8ffa, 0xa438, 0xe58f, 0xa438, 0xfbbf, - 0xa438, 0x5481, 0xa438, 0x0252, 0xa438, 0xc8e4, 0xa438, 0x8ffc, - 0xa438, 0xe58f, 0xa438, 0xfdbf, 0xa438, 0x5484, 0xa438, 0x0252, - 0xa438, 0xc8e4, 0xa438, 0x8ffe, 0xa438, 0xe58f, 0xa438, 0xffbf, - 0xa438, 0x5322, 0xa438, 0x0252, 0xa438, 0xc8a1, 0xa438, 0x4448, - 0xa438, 0xaf85, 0xa438, 0xa7bf, 0xa438, 0x5322, 0xa438, 0x0252, - 0xa438, 0xc8a1, 0xa438, 0x313c, 0xa438, 0xbf54, 0xa438, 0x7b02, - 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xf8e5, 0xa438, 0x8ff9, - 0xa438, 0xbf54, 0xa438, 0x7e02, 0xa438, 0x52c8, 0xa438, 0xe48f, - 0xa438, 0xfae5, 0xa438, 0x8ffb, 0xa438, 0xbf54, 0xa438, 0x8102, - 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfce5, 0xa438, 0x8ffd, - 0xa438, 0xbf54, 0xa438, 0x8402, 0xa438, 0x52c8, 0xa438, 0xe48f, - 0xa438, 0xfee5, 0xa438, 0x8fff, 0xa438, 0xbf53, 0xa438, 0x2202, - 0xa438, 0x52c8, 0xa438, 0xa131, 0xa438, 0x03af, 0xa438, 0x85a7, - 0xa438, 0xd480, 0xa438, 0x00bf, 0xa438, 0x8684, 0xa438, 0x0252, - 0xa438, 0xa9bf, 0xa438, 0x8687, 0xa438, 0x0252, 0xa438, 0xa9bf, - 0xa438, 0x868a, 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x868d, - 0xa438, 0x0252, 0xa438, 0xa9ef, 0xa438, 0x95fd, 0xa438, 0xfc04, - 0xa438, 0xf0d1, 0xa438, 0x2af0, 0xa438, 0xd12c, 0xa438, 0xf0d1, - 0xa438, 0x44f0, 0xa438, 0xd146, 0xa438, 0xbf86, 0xa438, 0xa102, - 0xa438, 0x52c8, 0xa438, 0xbf86, 0xa438, 0xa102, 0xa438, 0x52c8, - 0xa438, 0xd101, 0xa438, 0xaf06, 0xa438, 0xa570, 0xa438, 0xce42, - 0xa436, 0xb818, 0xa438, 0x043d, 0xa436, 0xb81a, 0xa438, 0x06a3, - 0xa436, 0xb81c, 0xa438, 0xffff, 0xa436, 0xb81e, 0xa438, 0xffff, - 0xa436, 0xb850, 0xa438, 0xffff, 0xa436, 0xb852, 0xa438, 0xffff, - 0xa436, 0xb878, 0xa438, 0xffff, 0xa436, 0xb884, 0xa438, 0xffff, - 0xa436, 0xb832, 0xa438, 0x0003, 0xa436, 0x0000, 0xa438, 0x0000, - 0xa436, 0xB82E, 0xa438, 0x0000, 0xa436, 0x8024, 0xa438, 0x0000, - 0xb820, 0x0000, 0xa436, 0x801E, 0xa438, 0x0019, 0xFFFF, 0xFFFF + 0xa438, 0xe9e1, 0xa438, 0x8ff6, 0xa438, 0xbf88, 0xa438, 0x8402, + 0xa438, 0x6e7d, 0xa438, 0xaf26, 0xa438, 0xf520, 0xa438, 0xac86, + 0xa438, 0xbf88, 0xa438, 0x3f02, 0xa438, 0x6e9c, 0xa438, 0xad28, + 0xa438, 0x03af, 0xa438, 0x3324, 0xa438, 0xad38, 0xa438, 0x03af, + 0xa438, 0x32e6, 0xa438, 0xaf32, 0xa438, 0xfb00, 0xa436, 0xb87c, + 0xa438, 0x8ff6, 0xa436, 0xb87e, 0xa438, 0x0705, 0xa436, 0xb87c, + 0xa438, 0x8ff8, 0xa436, 0xb87e, 0xa438, 0x19cc, 0xa436, 0xb87c, + 0xa438, 0x8ffa, 0xa436, 0xb87e, 0xa438, 0x28e3, 0xa436, 0xb87c, + 0xa438, 0x8ffc, 0xa436, 0xb87e, 0xa438, 0x1047, 0xa436, 0xb87c, + 0xa438, 0x8ffe, 0xa436, 0xb87e, 0xa438, 0x0a45, 0xa436, 0xb85e, + 0xa438, 0x271E, 0xa436, 0xb860, 0xa438, 0x3846, 0xa436, 0xb862, + 0xa438, 0x26E6, 0xa436, 0xb864, 0xa438, 0x32E3, 0xa436, 0xb886, + 0xa438, 0xffff, 0xa436, 0xb888, 0xa438, 0xffff, 0xa436, 0xb88a, + 0xa438, 0xffff, 0xa436, 0xb88c, 0xa438, 0xffff, 0xa436, 0xb838, + 0xa438, 0x000f, 0xb820, 0x0010, 0xa436, 0x846e, 0xa438, 0xaf84, + 0xa438, 0x86af, 0xa438, 0x8690, 0xa438, 0xaf86, 0xa438, 0xa4af, + 0xa438, 0x86a4, 0xa438, 0xaf86, 0xa438, 0xa4af, 0xa438, 0x86a4, + 0xa438, 0xaf86, 0xa438, 0xa4af, 0xa438, 0x86a4, 0xa438, 0xee82, + 0xa438, 0x5f00, 0xa438, 0x0284, 0xa438, 0x90af, 0xa438, 0x0441, + 0xa438, 0xf8e0, 0xa438, 0x8ff3, 0xa438, 0xa000, 0xa438, 0x0502, + 0xa438, 0x84a4, 0xa438, 0xae06, 0xa438, 0xa001, 0xa438, 0x0302, + 0xa438, 0x84c8, 0xa438, 0xfc04, 0xa438, 0xf8f9, 0xa438, 0xef59, + 0xa438, 0xe080, 0xa438, 0x15ad, 0xa438, 0x2702, 0xa438, 0xae03, + 0xa438, 0xaf84, 0xa438, 0xc3bf, 0xa438, 0x53ca, 0xa438, 0x0252, + 0xa438, 0xc8ad, 0xa438, 0x2807, 0xa438, 0x0285, 0xa438, 0x2cee, + 0xa438, 0x8ff3, 0xa438, 0x01ef, 0xa438, 0x95fd, 0xa438, 0xfc04, + 0xa438, 0xf8f9, 0xa438, 0xfaef, 0xa438, 0x69bf, 0xa438, 0x53ca, + 0xa438, 0x0252, 0xa438, 0xc8ac, 0xa438, 0x2822, 0xa438, 0xd480, + 0xa438, 0x00bf, 0xa438, 0x8684, 0xa438, 0x0252, 0xa438, 0xa9bf, + 0xa438, 0x8687, 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x868a, + 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x868d, 0xa438, 0x0252, + 0xa438, 0xa9ee, 0xa438, 0x8ff3, 0xa438, 0x00af, 0xa438, 0x8526, + 0xa438, 0xe08f, 0xa438, 0xf4e1, 0xa438, 0x8ff5, 0xa438, 0xe28f, + 0xa438, 0xf6e3, 0xa438, 0x8ff7, 0xa438, 0x1b45, 0xa438, 0xac27, + 0xa438, 0x0eee, 0xa438, 0x8ff4, 0xa438, 0x00ee, 0xa438, 0x8ff5, + 0xa438, 0x0002, 0xa438, 0x852c, 0xa438, 0xaf85, 0xa438, 0x26e0, + 0xa438, 0x8ff4, 0xa438, 0xe18f, 0xa438, 0xf52c, 0xa438, 0x0001, + 0xa438, 0xe48f, 0xa438, 0xf4e5, 0xa438, 0x8ff5, 0xa438, 0xef96, + 0xa438, 0xfefd, 0xa438, 0xfc04, 0xa438, 0xf8f9, 0xa438, 0xef59, + 0xa438, 0xbf53, 0xa438, 0x2202, 0xa438, 0x52c8, 0xa438, 0xa18b, + 0xa438, 0x02ae, 0xa438, 0x03af, 0xa438, 0x85da, 0xa438, 0xbf57, + 0xa438, 0x7202, 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xf8e5, + 0xa438, 0x8ff9, 0xa438, 0xbf57, 0xa438, 0x7502, 0xa438, 0x52c8, + 0xa438, 0xe48f, 0xa438, 0xfae5, 0xa438, 0x8ffb, 0xa438, 0xbf57, + 0xa438, 0x7802, 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfce5, + 0xa438, 0x8ffd, 0xa438, 0xbf57, 0xa438, 0x7b02, 0xa438, 0x52c8, + 0xa438, 0xe48f, 0xa438, 0xfee5, 0xa438, 0x8fff, 0xa438, 0xbf57, + 0xa438, 0x6c02, 0xa438, 0x52c8, 0xa438, 0xa102, 0xa438, 0x13ee, + 0xa438, 0x8ffc, 0xa438, 0x80ee, 0xa438, 0x8ffd, 0xa438, 0x00ee, + 0xa438, 0x8ffe, 0xa438, 0x80ee, 0xa438, 0x8fff, 0xa438, 0x00af, + 0xa438, 0x8599, 0xa438, 0xa101, 0xa438, 0x0cbf, 0xa438, 0x534c, + 0xa438, 0x0252, 0xa438, 0xc8a1, 0xa438, 0x0303, 0xa438, 0xaf85, + 0xa438, 0x77bf, 0xa438, 0x5322, 0xa438, 0x0252, 0xa438, 0xc8a1, + 0xa438, 0x8b02, 0xa438, 0xae03, 0xa438, 0xaf86, 0xa438, 0x64e0, + 0xa438, 0x8ff8, 0xa438, 0xe18f, 0xa438, 0xf9bf, 0xa438, 0x8684, + 0xa438, 0x0252, 0xa438, 0xa9e0, 0xa438, 0x8ffa, 0xa438, 0xe18f, + 0xa438, 0xfbbf, 0xa438, 0x8687, 0xa438, 0x0252, 0xa438, 0xa9e0, + 0xa438, 0x8ffc, 0xa438, 0xe18f, 0xa438, 0xfdbf, 0xa438, 0x868a, + 0xa438, 0x0252, 0xa438, 0xa9e0, 0xa438, 0x8ffe, 0xa438, 0xe18f, + 0xa438, 0xffbf, 0xa438, 0x868d, 0xa438, 0x0252, 0xa438, 0xa9af, + 0xa438, 0x867f, 0xa438, 0xbf53, 0xa438, 0x2202, 0xa438, 0x52c8, + 0xa438, 0xa144, 0xa438, 0x3cbf, 0xa438, 0x547b, 0xa438, 0x0252, + 0xa438, 0xc8e4, 0xa438, 0x8ff8, 0xa438, 0xe58f, 0xa438, 0xf9bf, + 0xa438, 0x547e, 0xa438, 0x0252, 0xa438, 0xc8e4, 0xa438, 0x8ffa, + 0xa438, 0xe58f, 0xa438, 0xfbbf, 0xa438, 0x5481, 0xa438, 0x0252, + 0xa438, 0xc8e4, 0xa438, 0x8ffc, 0xa438, 0xe58f, 0xa438, 0xfdbf, + 0xa438, 0x5484, 0xa438, 0x0252, 0xa438, 0xc8e4, 0xa438, 0x8ffe, + 0xa438, 0xe58f, 0xa438, 0xffbf, 0xa438, 0x5322, 0xa438, 0x0252, + 0xa438, 0xc8a1, 0xa438, 0x4448, 0xa438, 0xaf85, 0xa438, 0xa7bf, + 0xa438, 0x5322, 0xa438, 0x0252, 0xa438, 0xc8a1, 0xa438, 0x313c, + 0xa438, 0xbf54, 0xa438, 0x7b02, 0xa438, 0x52c8, 0xa438, 0xe48f, + 0xa438, 0xf8e5, 0xa438, 0x8ff9, 0xa438, 0xbf54, 0xa438, 0x7e02, + 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfae5, 0xa438, 0x8ffb, + 0xa438, 0xbf54, 0xa438, 0x8102, 0xa438, 0x52c8, 0xa438, 0xe48f, + 0xa438, 0xfce5, 0xa438, 0x8ffd, 0xa438, 0xbf54, 0xa438, 0x8402, + 0xa438, 0x52c8, 0xa438, 0xe48f, 0xa438, 0xfee5, 0xa438, 0x8fff, + 0xa438, 0xbf53, 0xa438, 0x2202, 0xa438, 0x52c8, 0xa438, 0xa131, + 0xa438, 0x03af, 0xa438, 0x85a7, 0xa438, 0xd480, 0xa438, 0x00bf, + 0xa438, 0x8684, 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x8687, + 0xa438, 0x0252, 0xa438, 0xa9bf, 0xa438, 0x868a, 0xa438, 0x0252, + 0xa438, 0xa9bf, 0xa438, 0x868d, 0xa438, 0x0252, 0xa438, 0xa9ef, + 0xa438, 0x95fd, 0xa438, 0xfc04, 0xa438, 0xf0d1, 0xa438, 0x2af0, + 0xa438, 0xd12c, 0xa438, 0xf0d1, 0xa438, 0x44f0, 0xa438, 0xd146, + 0xa438, 0xbf86, 0xa438, 0xa102, 0xa438, 0x52c8, 0xa438, 0xbf86, + 0xa438, 0xa102, 0xa438, 0x52c8, 0xa438, 0xd101, 0xa438, 0xaf06, + 0xa438, 0xa570, 0xa438, 0xce42, 0xa436, 0xb818, 0xa438, 0x043d, + 0xa436, 0xb81a, 0xa438, 0x06a3, 0xa436, 0xb81c, 0xa438, 0xffff, + 0xa436, 0xb81e, 0xa438, 0xffff, 0xa436, 0xb850, 0xa438, 0xffff, + 0xa436, 0xb852, 0xa438, 0xffff, 0xa436, 0xb878, 0xa438, 0xffff, + 0xa436, 0xb884, 0xa438, 0xffff, 0xa436, 0xb832, 0xa438, 0x0003, + 0xa436, 0x0000, 0xa438, 0x0000, 0xa436, 0xB82E, 0xa438, 0x0000, + 0xa436, 0x8024, 0xa438, 0x0000, 0xb820, 0x0000, 0xa436, 0x801E, + 0xa438, 0x0020, 0xFFFF, 0xFFFF }; static void @@ -8323,6 +8696,7 @@ rtl8125_init_hw_phy_mcu(struct net_device *dev) tp->HwHasWrRamCodeToMicroP = TRUE; } +#endif static void rtl8125_enable_phy_aldps(struct rtl8125_private *tp) @@ -8527,9 +8901,6 @@ rtl8125_hw_phy_config_8125a_2(struct net_device *dev) ); - RTL_W16(tp, EEE_TXIDLE_TIMER_8125, dev->mtu + ETH_HLEN + 0x20); - - mdio_direct_write_phy_ocp(tp, 0xB87C, 0x80A2); mdio_direct_write_phy_ocp(tp, 0xB87E, 0x0153); mdio_direct_write_phy_ocp(tp, 0xB87C, 0x809C); @@ -8943,9 +9314,6 @@ rtl8125_hw_phy_config_8125b_1(struct net_device *dev) mdio_direct_write_phy_ocp(tp, 0xB87E, 0x050E); - RTL_W16(tp, EEE_TXIDLE_TIMER_8125, dev->mtu + ETH_HLEN + 0x20); - - mdio_direct_write_phy_ocp(tp, 0xA436, 0x816C); mdio_direct_write_phy_ocp(tp, 0xA438, 0xC4A0); mdio_direct_write_phy_ocp(tp, 0xA436, 0x8170); @@ -9135,7 +9503,7 @@ rtl8125_hw_phy_config_8125b_2(struct net_device *dev) ); - RTL_W16(tp, EEE_TXIDLE_TIMER_8125, dev->mtu + ETH_HLEN + 0x20); + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, tp->eee.tx_lpi_timer); mdio_direct_write_phy_ocp(tp, 0xB87C, 0x80F5); mdio_direct_write_phy_ocp(tp, 0xB87E, 0x760E); @@ -9216,39 +9584,6 @@ rtl8125_hw_phy_config_8125b_2(struct net_device *dev) } } -static void -rtl8125_set_hw_phy_before_init_phy_mcu(struct net_device *dev) -{ - struct rtl8125_private *tp = netdev_priv(dev); - u16 PhyRegValue; - - switch (tp->mcfg) { - case CFG_METHOD_4: - mdio_direct_write_phy_ocp(tp, 0xBF86, 0x9000); - - SetEthPhyOcpBit(tp, 0xC402, BIT_10); - ClearEthPhyOcpBit(tp, 0xC402, BIT_10); - - PhyRegValue = mdio_direct_read_phy_ocp(tp, 0xBF86); - PhyRegValue &= (BIT_1 | BIT_0); - if (PhyRegValue != 0) - dprintk("PHY watch dog not clear, value = 0x%x \n", PhyRegValue); - - mdio_direct_write_phy_ocp(tp, 0xBD86, 0x1010); - mdio_direct_write_phy_ocp(tp, 0xBD88, 0x1010); - - ClearAndSetEthPhyOcpBit(tp, - 0xBD4E, - BIT_11 | BIT_10, - BIT_11); - ClearAndSetEthPhyOcpBit(tp, - 0xBF46, - BIT_11 | BIT_10 | BIT_9 | BIT_8, - BIT_10 | BIT_9 | BIT_8); - break; - } -} - static void rtl8125_hw_phy_config(struct net_device *dev) { @@ -9260,9 +9595,13 @@ rtl8125_hw_phy_config(struct net_device *dev) if (HW_DASH_SUPPORT_TYPE_3(tp) && tp->HwPkgDet == 0x06) return; - rtl8125_set_hw_phy_before_init_phy_mcu(dev); +#ifndef ENABLE_USE_FIRMWARE_FILE + if (!tp->rtl_fw) { + rtl8125_set_hw_phy_before_init_phy_mcu(dev); - rtl8125_init_hw_phy_mcu(dev); + rtl8125_init_hw_phy_mcu(dev); + } +#endif switch (tp->mcfg) { case CFG_METHOD_2: @@ -9303,13 +9642,24 @@ rtl8125_hw_phy_config(struct net_device *dev) rtl8125_mdio_write(tp, 0x1F, 0x0000); if (HW_HAS_WRITE_PHY_MCU_RAM_CODE(tp)) { - if (tp->eee_enabled == 1) + if (tp->eee.eee_enabled) rtl8125_enable_eee(tp); else rtl8125_disable_eee(tp); } } +static void +rtl8125_up(struct net_device *dev) +{ + rtl8125_hw_init(dev); + rtl8125_hw_reset(dev); + rtl8125_powerup_pll(dev); + rtl8125_hw_ephy_config(dev); + rtl8125_hw_phy_config(dev); + rtl8125_hw_config(dev); +} + static inline void rtl8125_delete_esd_timer(struct net_device *dev, struct timer_list *timer) { del_timer_sync(timer); @@ -9448,6 +9798,10 @@ rtl8125_init_software_variable(struct net_device *dev) rtl8125_get_bios_setting(dev); +#ifdef ENABLE_LIB_SUPPORT + tp->ring_lib_enabled = 1; +#endif + switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: @@ -9613,15 +9967,6 @@ rtl8125_init_software_variable(struct net_device *dev) break; } - switch (tp->mcfg) { - case CFG_METHOD_2: - case CFG_METHOD_3: - case CFG_METHOD_4: - case CFG_METHOD_5: - tp->HwSuppGigaForceMode = TRUE; - break; - } - switch (tp->mcfg) { case CFG_METHOD_2: case CFG_METHOD_3: @@ -9819,8 +10164,22 @@ rtl8125_init_software_variable(struct net_device *dev) dev->min_mtu = ETH_MIN_MTU; dev->max_mtu = tp->max_jumbo_frame_size; #endif //LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) - tp->eee_enabled = eee_enable; - tp->eee_adv_t = MDIO_EEE_1000T | MDIO_EEE_100TX; + + if (tp->mcfg != CFG_METHOD_DEFAULT) { + struct ethtool_eee *eee = &tp->eee; + + eee->eee_enabled = eee_enable; + eee->supported = SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full; + switch (tp->mcfg) { + case CFG_METHOD_4: + case CFG_METHOD_5: + eee->supported |= SUPPORTED_2500baseX_Full; + break; + } + eee->advertised = mmd_eee_adv_to_ethtool_adv_t(MDIO_EEE_1000T | MDIO_EEE_100TX); + eee->tx_lpi_timer = dev->mtu + ETH_HLEN + 0x20; + } tp->ptp_master_mode = enable_ptp_master_mode; } @@ -9849,6 +10208,7 @@ rtl8125_release_board(struct pci_dev *pdev, iounmap(ioaddr); pci_release_regions(pdev); + pci_clear_mwi(pdev); pci_disable_device(pdev); free_netdev(dev); } @@ -10774,9 +11134,12 @@ rtl8125_init_board(struct pci_dev *pdev, goto err_out_free_dev; } - rc = pci_set_mwi(pdev); - if (rc < 0) - goto err_out_disable; + if (pci_set_mwi(pdev) < 0) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + if (netif_msg_drv(&debug)) + dev_info(&pdev->dev, "Mem-Wr-Inval unavailable.\n"); +#endif //LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) + } /* save power state before pci_enable_device overwrites it */ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); @@ -10839,8 +11202,6 @@ rtl8125_init_board(struct pci_dev *pdev, } } - pci_set_master(pdev); - /* ioremap MMIO region */ ioaddr = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); if (ioaddr == NULL) { @@ -10884,13 +11245,9 @@ out: err_out_free_res: pci_release_regions(pdev); - err_out_mwi: pci_clear_mwi(pdev); - -err_out_disable: pci_disable_device(pdev); - err_out_free_dev: free_netdev(dev); err_out: @@ -11053,11 +11410,8 @@ rtl8125_esd_timer(struct timer_list *t) rtl8125_tx_clear(tp); rtl8125_rx_clear(tp); rtl8125_init_ring(dev); - rtl8125_hw_init(dev); - rtl8125_powerup_pll(dev); - rtl8125_hw_ephy_config(dev); - rtl8125_hw_phy_config(dev); - rtl8125_hw_config(dev); + rtl8125_up(dev); + rtl8125_enable_hw_linkchg_interrupt(tp); rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); tp->esd_flag = 0; } @@ -11086,7 +11440,7 @@ rtl8125_link_timer(struct timer_list *t) unsigned long flags; spin_lock_irqsave(&tp->lock, flags); - rtl8125_check_link_status(dev, 0); + rtl8125_check_link_status(dev); spin_unlock_irqrestore(&tp->lock, flags); mod_timer(timer, jiffies + RTL8125_LINK_TIMEOUT); @@ -11161,7 +11515,7 @@ static int rtl8125_try_msi(struct rtl8125_private *tp) break; } -#if defined(RTL_USE_NEW_INTR_API) +#if defined(RTL_USE_NEW_INTR_API) if ((nvecs = pci_alloc_irq_vectors(pdev, tp->min_irq_nvecs, tp->max_irq_nvecs, PCI_IRQ_MSIX)) > 0) msi |= RTL_FEATURE_MSIX; else if ((nvecs = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES)) > 0 && @@ -11188,7 +11542,7 @@ static int rtl8125_try_msi(struct rtl8125_private *tp) static void rtl8125_disable_msi(struct pci_dev *pdev, struct rtl8125_private *tp) { -#if defined(RTL_USE_NEW_INTR_API) +#if defined(RTL_USE_NEW_INTR_API) if (tp->features & (RTL_FEATURE_MSI | RTL_FEATURE_MSIX)) pci_free_irq_vectors(pdev); #elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13) @@ -11202,7 +11556,7 @@ static void rtl8125_disable_msi(struct pci_dev *pdev, struct rtl8125_private *tp static int rtl8125_get_irq(struct pci_dev *pdev) { -#if defined(RTL_USE_NEW_INTR_API) +#if defined(RTL_USE_NEW_INTR_API) return pci_irq_vector(pdev, 0); #else return pdev->irq; @@ -11613,6 +11967,8 @@ rtl8125_init_one(struct pci_dev *pdev, rtl8125_exit_oob(dev); + rtl8125_powerup_pll(dev); + rtl8125_hw_init(dev); rtl8125_hw_reset(dev); @@ -11625,6 +11981,8 @@ rtl8125_init_one(struct pci_dev *pdev, rtl8125_get_mac_address(dev); + tp->fw_name = rtl_chip_fw_infos[tp->mcfg].fw_name; + tp->tally_vaddr = dma_alloc_coherent(&pdev->dev, sizeof(*tp->tally_vaddr), &tp->tally_paddr, GFP_KERNEL); if (!tp->tally_vaddr) { @@ -11697,6 +12055,11 @@ rtl8125_remove_one(struct pci_dev *pdev) } rtl8125_release_board(pdev, dev); + +#ifdef ENABLE_USE_FIRMWARE_FILE + rtl8125_release_firmware(tp); +#endif + pci_set_drvdata(pdev, NULL); } @@ -11718,12 +12081,12 @@ static void rtl8125_free_irq(struct rtl8125_private *tp) struct r8125_napi *r8125napi = &tp->r8125napi[i]; if (irq->requested) { -#if defined(RTL_USE_NEW_INTR_API) + irq->requested = 0; +#if defined(RTL_USE_NEW_INTR_API) pci_free_irq(tp->pci_dev, i, r8125napi); #else free_irq(irq->vector, r8125napi); #endif - irq->requested = 0; } } } @@ -11886,7 +12249,34 @@ exit: return retval; } -static int rtl8125_open(struct net_device *dev) +#ifdef ENABLE_USE_FIRMWARE_FILE +static void rtl8125_request_firmware(struct rtl8125_private *tp) +{ + struct rtl8125_fw *rtl_fw; + + /* firmware loaded already or no firmware available */ + if (tp->rtl_fw || !tp->fw_name) + return; + + rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL); + if (!rtl_fw) + return; + + rtl_fw->phy_write = rtl8125_mdio_write; + rtl_fw->phy_read = rtl8125_mdio_read; + rtl_fw->mac_mcu_write = mac_mcu_write; + rtl_fw->mac_mcu_read = mac_mcu_read; + rtl_fw->fw_name = tp->fw_name; + rtl_fw->dev = tp_to_dev(tp); + + if (rtl8125_fw_request_firmware(rtl_fw)) + kfree(rtl_fw); + else + tp->rtl_fw = rtl_fw; +} +#endif + +int rtl8125_open(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); unsigned long flags; @@ -11928,12 +12318,18 @@ static int rtl8125_open(struct net_device *dev) dev->dev_addr[4], dev->dev_addr[5], dev->irq); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - INIT_WORK(&tp->task, NULL, dev); -#else - INIT_DELAYED_WORK(&tp->task, NULL); +#ifdef ENABLE_USE_FIRMWARE_FILE + rtl8125_request_firmware(tp); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&tp->task, rtl8125_reset_task, dev); +#else + INIT_DELAYED_WORK(&tp->task, rtl8125_reset_task); +#endif + + pci_set_master(tp->pci_dev); + #ifdef CONFIG_R8125_NAPI rtl8125_enable_napi(tp); #endif @@ -11942,29 +12338,17 @@ static int rtl8125_open(struct net_device *dev) rtl8125_exit_oob(dev); - rtl8125_hw_init(dev); - - rtl8125_hw_reset(dev); - - rtl8125_powerup_pll(dev); - - rtl8125_hw_ephy_config(dev); - - rtl8125_hw_phy_config(dev); - - rtl8125_hw_config(dev); + rtl8125_up(dev); #ifdef ENABLE_PTP_SUPPORT if (tp->EnablePtp) rtl8125_ptp_init(tp); #endif - rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); - - if (tp->resume_not_chg_speed) { - rtl8125_check_link_status(dev, 1); - tp->resume_not_chg_speed = 0; - } + if (tp->resume_not_chg_speed) + rtl8125_check_link_status(dev); + else + rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); spin_unlock_irqrestore(&tp->lock, flags); @@ -12254,7 +12638,7 @@ rtl8125_hw_config(struct net_device *dev) mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xE056); mac_ocp_data &= ~(BIT_7 | BIT_6 | BIT_5 | BIT_4); - mac_ocp_data |= (BIT_4 | BIT_5); + //mac_ocp_data |= (BIT_4 | BIT_5); rtl8125_mac_ocp_write(tp, 0xE056, mac_ocp_data); RTL_W8(tp, TDFNR, 0x10); @@ -12270,17 +12654,14 @@ rtl8125_hw_config(struct net_device *dev) mac_ocp_data |= (BIT_0); rtl8125_mac_ocp_write(tp, 0xEA1C, mac_ocp_data); - mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xE0C0); - mac_ocp_data &= ~(BIT_14 | BIT_11 | BIT_10 | BIT_9 | BIT_8 | BIT_3 | BIT_2 | BIT_1 | BIT_0); - mac_ocp_data |= (BIT_14 | BIT_10 | BIT_1 | BIT_0); - rtl8125_mac_ocp_write(tp, 0xE0C0, mac_ocp_data); + rtl8125_mac_ocp_write(tp, 0xE0C0, 0x4000); - SetMcuAccessRegBit(tp, 0xE052, (BIT_6|BIT_5|BIT_3)); - ClearMcuAccessRegBit(tp, 0xE052, BIT_7); + SetMcuAccessRegBit(tp, 0xE052, (BIT_6 | BIT_5)); + ClearMcuAccessRegBit(tp, 0xE052, BIT_3 | BIT_7); mac_ocp_data = rtl8125_mac_ocp_read(tp, 0xD430); mac_ocp_data &= ~(BIT_11 | BIT_10 | BIT_9 | BIT_8 | BIT_7 | BIT_6 | BIT_5 | BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0); - mac_ocp_data |= 0x47F; + mac_ocp_data |= 0x45F; rtl8125_mac_ocp_write(tp, 0xD430, mac_ocp_data); //rtl8125_mac_ocp_write(tp, 0xE0C0, 0x4F87); @@ -12491,9 +12872,10 @@ rtl8125_change_mtu(struct net_device *dev, rtl8125_enable_napi(tp); #endif//CONFIG_R8125_NAPI - rtl8125_stop_all_tx_queue(dev); - netif_carrier_off(dev); + //rtl8125_stop_all_tx_queue(dev); + //netif_carrier_off(dev); rtl8125_hw_config(dev); + rtl8125_enable_hw_linkchg_interrupt(tp); rtl8125_set_speed(dev, tp->autoneg, tp->speed, tp->duplex, tp->advertising); @@ -12589,9 +12971,9 @@ rtl8125_alloc_rx_skb(struct rtl8125_private *tp, skb_reserve(skb, RTK_RX_ALIGN); - mapping = dma_map_single(&tp->pci_dev->dev, skb->data, rx_buf_sz, + mapping = dma_map_single(tp_to_dev(tp), skb->data, rx_buf_sz, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { + if (unlikely(dma_mapping_error(tp_to_dev(tp), mapping))) { if (unlikely(net_ratelimit())) netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n"); goto err_out; @@ -13067,9 +13449,9 @@ rtl8125_xmit_frags(struct rtl8125_private *tp, PktLenCnt < ETH_FRAME_LEN && len > 1) { len -= 1; - mapping = dma_map_single(&tp->pci_dev->dev, addr, len, DMA_TO_DEVICE); + mapping = dma_map_single(tp_to_dev(tp), addr, len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { + if (unlikely(dma_mapping_error(tp_to_dev(tp), mapping))) { if (unlikely(net_ratelimit())) netif_err(tp, drv, tp->dev, "Failed to map TX fragments DMA!\n"); @@ -13097,9 +13479,9 @@ rtl8125_xmit_frags(struct rtl8125_private *tp, LsoPatchEnabled = TRUE; } - mapping = dma_map_single(&tp->pci_dev->dev, addr, len, DMA_TO_DEVICE); + mapping = dma_map_single(tp_to_dev(tp), addr, len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { + if (unlikely(dma_mapping_error(tp_to_dev(tp), mapping))) { if (unlikely(net_ratelimit())) netif_err(tp, drv, tp->dev, "Failed to map TX fragments DMA!\n"); @@ -13151,14 +13533,21 @@ __be16 get_protocol(struct sk_buff *skb) static inline u8 rtl8125_get_l4_protocol(struct sk_buff *skb) { + int no = skb_network_offset(skb); + struct ipv6hdr *i6h, _i6h; + struct iphdr *ih, _ih; u8 ip_protocol = IPPROTO_RAW; switch (get_protocol(skb)) { case __constant_htons(ETH_P_IP): - ip_protocol = ip_hdr(skb)->protocol; + ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih); + if (ih) + ip_protocol = ih->protocol; break; case __constant_htons(ETH_P_IPV6): - ip_protocol = ipv6_hdr(skb)->nexthdr; + i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h); + if (i6h) + ip_protocol = i6h->nexthdr; break; } @@ -13421,7 +13810,7 @@ static bool rtl8125_tx_slots_avail(struct rtl8125_private *tp, return slots_avail > MAX_SKB_FRAGS; } -static int +static netdev_tx_t rtl8125_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -13431,7 +13820,7 @@ rtl8125_start_xmit(struct sk_buff *skb, dma_addr_t mapping; u32 len; u32 opts[2]; - int ret = NETDEV_TX_OK; + netdev_tx_t ret = NETDEV_TX_OK; //unsigned long flags; int frags; u8 EnableTxNoClose = tp->EnableTxNoClose; @@ -13490,8 +13879,8 @@ rtl8125_start_xmit(struct sk_buff *skb, } opts[0] = rtl8125_get_txd_opts1(opts[0], len, entry); - mapping = dma_map_single(&tp->pci_dev->dev, skb->data, len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(&tp->pci_dev->dev, mapping))) { + mapping = dma_map_single(tp_to_dev(tp), skb->data, len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(tp_to_dev(tp), mapping))) { if (unlikely(net_ratelimit())) netif_err(tp, drv, dev, "Failed to map TX DMA!\n"); goto err_dma_1; @@ -13867,47 +14256,63 @@ process_pkt: #ifdef ENABLE_PTP_SUPPORT if (tp->EnablePtp) { - struct RxDescV3 *desc_next; u8 desc_type; - u32 status_next; desc_type = rtl8125_rx_desc_type(status); if (desc_type == RXDESC_TYPE_NEXT && rx_left > 0) { + u32 status_next; + struct RxDescV3 *desc_next; unsigned int entry_next; struct sk_buff *skb_next; + entry_next = (cur_rx + 1) % NUM_RX_DESC; + desc_next = (struct RxDescV3 *)rtl8125_get_rxdesc(tp, ring->RxDescArray, entry_next); + rmb(); + status_next = le32_to_cpu(desc_next->RxDescNormalDDWord4.opts1); + if (unlikely(status_next & DescOwn)) { + udelay(1); + rmb(); + status_next = le32_to_cpu(desc_next->RxDescNormalDDWord4.opts1); + if (unlikely(status_next & DescOwn)) { + if (netif_msg_rx_err(tp)) { + printk(KERN_ERR + "%s: Rx Next Desc ERROR. status = %08x\n", + dev->name, status_next); + } + break; + } + } + cur_rx++; rx_left--; - entry_next = cur_rx % NUM_RX_DESC; - desc_next = (struct RxDescV3 *)rtl8125_get_rxdesc(tp, ring->RxDescArray, entry_next); - status_next = le32_to_cpu(desc_next->RxDescNormalDDWord4.opts1); - if (status_next & DescOwn) - break; - desc_type = rtl8125_rx_desc_type(status_next); - if (desc_type == RXDESC_TYPE_PTP) { + if (desc_type == RXDESC_TYPE_PTP) rtl8125_rx_ptp_pktstamp(tp, skb, desc_next); - skb_next = ring->Rx_skbuff[entry_next]; - dev_kfree_skb_any(skb_next); - ring->Rx_skbuff[entry_next] = NULL; - } else + else WARN_ON(1); + + rx_buf_phy_addr = le64_to_cpu(ring->RxDescPhyAddr[entry_next]); + dma_unmap_single(tp_to_dev(tp), rx_buf_phy_addr, + tp->rx_buf_sz, DMA_FROM_DEVICE); + skb_next = ring->Rx_skbuff[entry_next]; + dev_kfree_skb_any(skb_next); + ring->Rx_skbuff[entry_next] = NULL; } else WARN_ON(desc_type != RXDESC_TYPE_NORMAL); } #endif rx_buf_phy_addr = le64_to_cpu(ring->RxDescPhyAddr[entry]); - dma_sync_single_for_cpu(&tp->pci_dev->dev, + dma_sync_single_for_cpu(tp_to_dev(tp), rx_buf_phy_addr, tp->rx_buf_sz, DMA_FROM_DEVICE); if (rtl8125_try_rx_copy(tp, ring, &skb, pkt_size, desc, tp->rx_buf_sz)) { ring->Rx_skbuff[entry] = NULL; - dma_unmap_single(&tp->pci_dev->dev, rx_buf_phy_addr, + dma_unmap_single(tp_to_dev(tp), rx_buf_phy_addr, tp->rx_buf_sz, DMA_FROM_DEVICE); } else { - dma_sync_single_for_device(&tp->pci_dev->dev, rx_buf_phy_addr, + dma_sync_single_for_device(tp_to_dev(tp), rx_buf_phy_addr, tp->rx_buf_sz, DMA_FROM_DEVICE); } @@ -14007,12 +14412,16 @@ static irqreturn_t rtl8125_interrupt(int irq, void *dev_instance) handled = 1; +#if defined(RTL_USE_NEW_INTR_API) + if (!tp->irq_tbl[0].requested) + break; +#endif rtl8125_disable_hw_interrupt(tp); RTL_W32(tp, tp->isr_reg[0], status&~RxFIFOOver); if (rtl8125_linkchg_interrupt(tp, status)) - rtl8125_check_link_status(dev, 0); + rtl8125_check_link_status(dev); #ifdef ENABLE_DASH_SUPPORT if (tp->DASH) { @@ -14102,14 +14511,18 @@ static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance) #endif do { +#if defined(RTL_USE_NEW_INTR_API) + if (!tp->irq_tbl[message_id].requested) + break; +#endif rtl8125_disable_hw_interrupt_v2(tp, message_id); rtl8125_clear_hw_isr_v2(tp, message_id); //link change if (message_id == 21) { - rtl8125_check_link_status(dev, 0); - return IRQ_HANDLED; + rtl8125_check_link_status(dev); + break; } #ifdef CONFIG_R8125_NAPI @@ -14178,7 +14591,7 @@ static int rtl8125_resource_freed(struct rtl8125_private *tp) return 1; } -static int rtl8125_close(struct net_device *dev) +int rtl8125_close(struct net_device *dev) { struct rtl8125_private *tp = netdev_priv(dev); unsigned long flags; @@ -14188,6 +14601,8 @@ static int rtl8125_close(struct net_device *dev) rtl8125_down(dev); + pci_clear_master(tp->pci_dev); + spin_lock_irqsave(&tp->lock, flags); #ifdef ENABLE_PTP_SUPPORT rtl8125_ptp_stop(tp); @@ -14232,6 +14647,12 @@ static void rtl8125_shutdown(struct pci_dev *pdev) rtl8125_close(dev); rtl8125_disable_msi(pdev, tp); + + if (system_state == SYSTEM_POWER_OFF) { + pci_clear_master(tp->pci_dev); + pci_wake_from_d3(pdev, tp->wol_enabled); + pci_set_power_state(pdev, PCI_D3hot); + } } #endif @@ -14302,6 +14723,8 @@ rtl8125_suspend(struct pci_dev *pdev, pm_message_t state) #endif rtl8125_hw_reset(dev); + pci_clear_master(pdev); + rtl8125_hw_d3_para(dev); rtl8125_powerdown_pll(dev, 1); @@ -14312,6 +14735,8 @@ rtl8125_suspend(struct pci_dev *pdev, pm_message_t state) rtl8125_driver_stop(tp); out: + pci_disable_device(pdev); + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) pci_save_state(pdev, &pci_pm_state); #else @@ -14320,7 +14745,8 @@ out: #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled); #endif - //pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + pci_prepare_to_sleep(pdev); return 0; } @@ -14350,8 +14776,13 @@ rtl8125_resume(struct device *device) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) u32 pci_pm_state = PCI_D0; #endif + u32 err; - pci_set_power_state(pdev, PCI_D0); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Cannot enable PCI device from suspend\n"); + return err; + } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) pci_restore_state(pdev, &pci_pm_state); #else @@ -14376,29 +14807,27 @@ rtl8125_resume(struct device *device) if (!netif_running(dev)) goto out; + pci_set_master(pdev); + spin_lock_irqsave(&tp->lock, flags); rtl8125_exit_oob(dev); - rtl8125_hw_init(dev); - - rtl8125_powerup_pll(dev); - - rtl8125_hw_ephy_config(dev); - - rtl8125_hw_phy_config(dev); - - rtl8125_hw_config(dev); + rtl8125_up(dev); spin_unlock_irqrestore(&tp->lock, flags); - if (tp->resume_not_chg_speed) - rtl8125_check_link_status(dev, 1); - else - rtl8125_schedule_work(dev, rtl8125_reset_task); - netif_device_attach(dev); + if (tp->resume_not_chg_speed) { + spin_lock_irqsave(&tp->lock, flags); + + _rtl8125_check_link_status(dev); + + spin_unlock_irqrestore(&tp->lock, flags); + } else + rtl8125_schedule_work(dev, rtl8125_reset_task); + mod_timer(&tp->esd_timer, jiffies + RTL8125_ESD_TIMEOUT); //mod_timer(&tp->link_timer, jiffies + RTL8125_LINK_TIMEOUT); out: From b632ec7b90429feb741179942a5f69151fdbe91d Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Sat, 12 Jun 2021 23:55:01 +0800 Subject: [PATCH 05/24] sunxi: cortexa53: make at24 eeprom driver built-in Signed-off-by: Tianling Shen --- target/linux/sunxi/cortexa53/config-4.14 | 1 + target/linux/sunxi/cortexa53/config-4.19 | 1 + target/linux/sunxi/image/cortex-a53.mk | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/target/linux/sunxi/cortexa53/config-4.14 b/target/linux/sunxi/cortexa53/config-4.14 index 1ba379ea65..f58d687e65 100644 --- a/target/linux/sunxi/cortexa53/config-4.14 +++ b/target/linux/sunxi/cortexa53/config-4.14 @@ -45,6 +45,7 @@ CONFIG_ARM_GIC_V3=y # CONFIG_ARM_SP805_WATCHDOG is not set CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y CONFIG_DWMAC_SUN8I=y +CONFIG_EEPROM_AT24=y CONFIG_FRAME_POINTER=y CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y CONFIG_GENERIC_CSUM=y diff --git a/target/linux/sunxi/cortexa53/config-4.19 b/target/linux/sunxi/cortexa53/config-4.19 index 67ff2c2633..4103862716 100644 --- a/target/linux/sunxi/cortexa53/config-4.19 +++ b/target/linux/sunxi/cortexa53/config-4.19 @@ -47,6 +47,7 @@ CONFIG_ARM_AMBA=y CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y CONFIG_DMA_DIRECT_OPS=y CONFIG_DWMAC_SUN8I=y +CONFIG_EEPROM_AT24=y # CONFIG_FLATMEM_MANUAL is not set CONFIG_FRAME_POINTER=y CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y diff --git a/target/linux/sunxi/image/cortex-a53.mk b/target/linux/sunxi/image/cortex-a53.mk index 47b7ecf951..90789cfe2a 100644 --- a/target/linux/sunxi/image/cortex-a53.mk +++ b/target/linux/sunxi/image/cortex-a53.mk @@ -31,8 +31,8 @@ TARGET_DEVICES += friendlyarm_nanopi-neo2 define Device/friendlyarm_nanopi-r1s-h5 DEVICE_VENDOR := FriendlyARM DEVICE_MODEL := Nanopi R1S H5 - DEVICE_PACKAGES := kmod-eeprom-at24 kmod-gpio-button-hotplug kmod-leds-gpio \ - kmod-rtl8189es kmod-usb2 kmod-usb-net kmod-usb-net-rtl8152 wpad-basic + DEVICE_PACKAGES := kmod-gpio-button-hotplug kmod-rtl8189es \ + kmod-usb2 kmod-usb-net kmod-usb-net-rtl8152 wpad-basic SUPPORTED_DEVICES:=nanopi-r1s-h5 SUNXI_DTS_DIR := allwinner/ SOC := sun50i-h5 From 301c9ea4ede17199ff84ebb07f5bb09f91a57fb8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 29 Aug 2020 22:24:59 +0200 Subject: [PATCH 06/24] u-boot: support verbose build Signed-off-by: Felix Fietkau --- include/u-boot.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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))) From 056b0261351ed4b41b5fe80235ce62fb93911ec9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 6 Jun 2021 14:31:01 +0200 Subject: [PATCH 07/24] build: add ninja build tool and make it available for cmake ninja is faster at building cmake packages than make, and according to reports also more reliable at handling parallel builds This commit includes a patch that adds GNU make jobserver support, in order to allow more precise control over the number of parallel tasks Enable parallel build by default for packages using ninja Signed-off-by: Felix Fietkau Signed-off-by: Rosen Penev --- include/cmake.mk | 34 + rules.mk | 6 + tools/Makefile | 2 +- tools/ninja/Makefile | 39 + .../patches/100-make_jobserver_support.patch | 2279 +++++++++++++++++ 5 files changed, 2359 insertions(+), 1 deletion(-) create mode 100644 tools/ninja/Makefile create mode 100644 tools/ninja/patches/100-make_jobserver_support.patch diff --git a/include/cmake.mk b/include/cmake.mk index 96c4d7df34..8a1c4fc4d5 100644 --- a/include/cmake.mk +++ b/include/cmake.mk @@ -1,5 +1,11 @@ cmake_bool = $(patsubst %,-D%:BOOL=$(if $($(1)),ON,OFF),$(2)) +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 +50,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 + +DESTDIR="$(HOST_INSTALL_DIR)" $(NINJA) -C $(HOST_BUILD_DIR) install + endef + + define Host/Uninstall/Default + +DESTDIR="$(HOST_INSTALL_DIR)" $(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/rules.mk b/rules.mk index 971781e8bb..6733d01cc4 100644 --- a/rules.mk +++ b/rules.mk @@ -344,6 +344,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/tools/Makefile b/tools/Makefile index 7d0662a25e..0a227766df 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -24,7 +24,7 @@ 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 += mklibs mm-macros mtd-utils mtools ninja padjffs2 patch-image patchelf tools-y += pkg-config quilt squashfskit4 sstrip ucl upx xxd zip zlib zstd tools-$(BUILD_B43_TOOLS) += b43-tools tools-$(BUILD_ISL) += isl diff --git a/tools/ninja/Makefile b/tools/ninja/Makefile new file mode 100644 index 0000000000..3cbd6aebba --- /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)" \ + 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()); ++} From a80b18a363bcd794c22e383e0aa2a21119a3c7fb Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 6 Jun 2021 14:24:43 -0700 Subject: [PATCH 08/24] package: fix cmake packages build with ninja += is needed for CMAKE_OPTIONS. mt76 needs Ninja disabled as the kernel stuff uses normal make. Signed-off-by: Rosen Penev --- package/kernel/mt76/Makefile | 1 + package/libs/libubox/Makefile | 2 +- package/network/services/uhttpd/Makefile | 2 +- package/system/ubus/Makefile | 2 +- package/system/uci/Makefile | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package/kernel/mt76/Makefile b/package/kernel/mt76/Makefile index 2e6b84d6e2..f228f2c199 100644 --- a/package/kernel/mt76/Makefile +++ b/package/kernel/mt76/Makefile @@ -13,6 +13,7 @@ PKG_SOURCE_VERSION:=5c768dec13389700ff3fa3d25083fb43d8e7adda PKG_MIRROR_HASH:=2ef0cf233bedc20e77c61cd6dd6085e162cce5c2719b5285bcdd8bf92ebf88eb PKG_MAINTAINER:=Felix Fietkau +PKG_USE_NINJA:=0 PKG_BUILD_PARALLEL:=1 PKG_CONFIG_DEPENDS += \ diff --git a/package/libs/libubox/Makefile b/package/libs/libubox/Makefile index 025f6489e7..0f89e70d6d 100644 --- a/package/libs/libubox/Makefile +++ b/package/libs/libubox/Makefile @@ -64,7 +64,7 @@ define Package/libubox-lua endef TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include -CMAKE_OPTIONS = \ +CMAKE_OPTIONS += \ -DLUAPATH=/usr/lib/lua define Package/libubox/install diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile index 796eb61298..f41cbe9436 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/ubus/Makefile b/package/system/ubus/Makefile index 824e71924f..ce035e9696 100644 --- a/package/system/ubus/Makefile +++ b/package/system/ubus/Makefile @@ -51,7 +51,7 @@ endef TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include -flto TARGET_LDFLAGS += -flto -CMAKE_OPTIONS = \ +CMAKE_OPTIONS += \ -DLUAPATH=/usr/lib/lua define Package/ubus/install diff --git a/package/system/uci/Makefile b/package/system/uci/Makefile index 73f2e3fa45..f3764fea93 100644 --- a/package/system/uci/Makefile +++ b/package/system/uci/Makefile @@ -55,7 +55,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) From 345cbe4ce2d4426c596fd70b8a0e253149c15d56 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 10 Jun 2021 14:01:04 +0200 Subject: [PATCH 09/24] build: use ninja for cmake packages by default Speed goes from: Executed in 178.08 secs fish external usr time 20.16 mins 509.00 micros 20.16 mins sys time 2.88 mins 39.00 micros 2.88 mins To: Executed in 175.90 secs fish external usr time 20.19 mins 0.00 micros 20.19 mins sys time 2.85 mins 497.00 micros 2.85 mins Tested with "time make -j 12" on AMD Ryzen 3600 When building individual packages, the build time difference is often significantly bigger than that. Signed-off-by: Felix Fietkau Signed-off-by: Rosen Penev --- include/cmake.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/cmake.mk b/include/cmake.mk index 8a1c4fc4d5..7ccd872365 100644 --- a/include/cmake.mk +++ b/include/cmake.mk @@ -1,5 +1,7 @@ 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 From f17acc768943b839aac465dac71fb1bb9be6e6f8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 12 Jun 2021 14:32:41 +0200 Subject: [PATCH 10/24] build: do not override DESTDIR for cmake ninja host builds The full prefix is already passed to cmake Signed-off-by: Felix Fietkau --- include/cmake.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cmake.mk b/include/cmake.mk index 7ccd872365..b38d440039 100644 --- a/include/cmake.mk +++ b/include/cmake.mk @@ -60,11 +60,11 @@ ifeq ($(HOST_USE_NINJA),1) endef define Host/Install/Default - +DESTDIR="$(HOST_INSTALL_DIR)" $(NINJA) -C $(HOST_BUILD_DIR) install + +$(NINJA) -C $(HOST_BUILD_DIR) install endef define Host/Uninstall/Default - +DESTDIR="$(HOST_INSTALL_DIR)" $(NINJA) -C $(HOST_BUILD_DIR) uninstall + +$(NINJA) -C $(HOST_BUILD_DIR) uninstall endef endif From 00cd20c4b2df644eedc0888eb4953e5548cbe8f1 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sat, 12 Jun 2021 16:02:29 -0700 Subject: [PATCH 11/24] prereq-build: diff requirement to GNU tools/quilt requires GNU diffutils to compile. Failure can be simulated by installing Alpine Linux without diffutils. Signed-off-by: Rosen Penev --- include/prereq-build.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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', \ From 0c512fa3c4f887ec359f626cdb7281c53e9b22ce Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Wed, 26 May 2021 23:18:12 +0800 Subject: [PATCH 12/24] sunxi: 02_network: remove the extra part --- target/linux/sunxi/base-files/etc/board.d/02_network | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/target/linux/sunxi/base-files/etc/board.d/02_network b/target/linux/sunxi/base-files/etc/board.d/02_network index f4e013e119..19fdd5d060 100755 --- a/target/linux/sunxi/base-files/etc/board.d/02_network +++ b/target/linux/sunxi/base-files/etc/board.d/02_network @@ -31,13 +31,6 @@ sunxi_setup_interfaces() esac } -nanopi_generate_mac() -{ - local sd_hash=$(sha256sum /sys/class/block/mmcblk0/device/cid) - local mac_base=$(macaddr_canonicalize "$(echo "${sd_hash}" | dd bs=1 count=12 2>/dev/null)") - echo "$(macaddr_unsetbit_mc "$(macaddr_setbit_la "${mac_base}")")" -} - sunxi_setup_macs() { local board="$1" @@ -47,8 +40,7 @@ sunxi_setup_macs() case "$board" in friendlyarm,nanopi-r1s-h5) - wan_mac=$(get_mac_binary "/sys/bus/i2c/devices/0-0051/eeprom" 0xfa) - lan_mac=$(macaddr_setbit_la "$wan_mac") + lan_mac=$(get_mac_binary "/sys/bus/i2c/devices/0-0051/eeprom" 0xfa) ;; esac From aed47c6b81864919f5541ca0a3293244267606b2 Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Fri, 11 Jun 2021 23:20:02 +0800 Subject: [PATCH 13/24] feeds: routing: update project url --- feeds.conf.default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feeds.conf.default b/feeds.conf.default index b3384a73a7..4f6bd7411a 100644 --- a/feeds.conf.default +++ b/feeds.conf.default @@ -1,4 +1,4 @@ src-git packages https://github.com/immortalwrt/packages.git;openwrt-18.06 src-git luci https://github.com/immortalwrt/luci.git;openwrt-18.06 -src-git routing https://github.com/openwrt-routing/packages.git +src-git routing https://github.com/openwrt/routing.git src-git telephony https://github.com/openwrt/telephony.git From af7578867df0f01284d9f0367744db0b09880ece Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 5 Jun 2021 01:06:28 +0200 Subject: [PATCH 14/24] ramips: remove upstreamed patches Signed-off-by: Hauke Mehrtens Signed-off-by: Tianling Shen --- .../0048-asoc-add-mt7620-support.patch | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/target/linux/ramips/patches-4.14/0048-asoc-add-mt7620-support.patch b/target/linux/ramips/patches-4.14/0048-asoc-add-mt7620-support.patch index afb9f72006..dd68735b8a 100644 --- a/target/linux/ramips/patches-4.14/0048-asoc-add-mt7620-support.patch +++ b/target/linux/ramips/patches-4.14/0048-asoc-add-mt7620-support.patch @@ -18,24 +18,6 @@ Signed-off-by: John Crispin create mode 100644 sound/soc/ralink/mt7620-i2s.c create mode 100644 sound/soc/ralink/mt7620-wm8960.c ---- a/arch/mips/ralink/of.c -+++ b/arch/mips/ralink/of.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -27,6 +28,7 @@ - #include "common.h" - - __iomem void *rt_sysc_membase; -+EXPORT_SYMBOL(rt_sysc_membase); - __iomem void *rt_memc_membase; - EXPORT_SYMBOL_GPL(rt_sysc_membase); - --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -59,6 +59,7 @@ source "sound/soc/mxs/Kconfig" From 8124a5bbbadd186c1407a4f4594bddc2e9620415 Mon Sep 17 00:00:00 2001 From: Hannu Nyman Date: Sun, 6 Jun 2021 18:15:08 +0300 Subject: [PATCH 15/24] treewide: mark selected packages nonshared Mark uci, ubus, libubox, lua, libnl-tiny and libjson-c as nonshared packages. This helps to keep coherent dependencies if these ABI versioned packages are later updated. Before this commit it is possible to get missing dependencies in target-specific nonshared packages (like iwinfo) that depend on these shared ABI versioned packages. If these are later updated and rebuilt, only the new ABI version will be available for download, while the target-specific packages in releases continue to depend on the old ABI version. After this commit the packages are built along the other nonshared packages by the phase1 images buildbot and will be available at the target/ download directories instead of packages/base dir. That will help to keep a coherent set available. Signed-off-by: Hannu Nyman --- package/libs/libjson-c/Makefile | 3 ++- package/libs/libnl-tiny/Makefile | 4 +++- package/libs/libubox/Makefile | 4 +++- package/system/ubus/Makefile | 3 ++- package/system/uci/Makefile | 3 ++- package/utils/lua/Makefile | 3 ++- 6 files changed, 14 insertions(+), 6 deletions(-) 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 0f89e70d6d..fb6e6d9e4d 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 @@ -10,6 +10,8 @@ PKG_SOURCE_DATE:=2020-07-11 PKG_SOURCE_VERSION:=f4e9bf73ac5c0ee6b8f240e2a2100e70ca56d705 CMAKE_INSTALL:=1 +PKG_FLAGS := nonshared + PKG_LICENSE:=ISC PKG_LICENSE_FILES:= diff --git a/package/system/ubus/Makefile b/package/system/ubus/Makefile index ce035e9696..7931b8c079 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 @@ -14,6 +14,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 diff --git a/package/system/uci/Makefile b/package/system/uci/Makefile index f3764fea93..4a185fe6c9 100644 --- a/package/system/uci/Makefile +++ b/package/system/uci/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=uci -PKG_RELEASE:=3 +PKG_RELEASE:=4 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 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 From 73ddfb3eb8d8b9cd3c76f6ddce2a09831a74301e Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 13 Jun 2021 23:40:00 +0200 Subject: [PATCH 16/24] opkg: Fix download over git Set the PKG_SOURCE_URL using a lazy set to allow evaluating $(PROJECT_GIT) later. Without this change PKG_SOURCE_URL is evaluated immediately, before PROJECT_GIT is defined and the download over git is not working. Fixes: 6687a2483a09 ("opkg: use $(PROJECT_GIT), $(AUTORELEASE) and SPDX") Signed-off-by: Hauke Mehrtens --- package/system/opkg/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/system/opkg/Makefile b/package/system/opkg/Makefile index 99234978a1..cc295c12ba 100644 --- a/package/system/opkg/Makefile +++ b/package/system/opkg/Makefile @@ -11,7 +11,7 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_FLAGS:=essential PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=$(PROJECT_GIT)/project/opkg-lede.git +PKG_SOURCE_URL=$(PROJECT_GIT)/project/opkg-lede.git PKG_SOURCE_DATE:=2021-03-15 PKG_SOURCE_VERSION:=5936c4f9660248284e8a9b040ea3153d3ea888de PKG_MIRROR_HASH:=b873c209baaf4f150c89646d58e4a0072f807d24b02c320ab8c7ae9180c13240 From 3b42596bc9d8ee39ae3e223414a085887103345e Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 13 Jun 2021 23:43:36 +0200 Subject: [PATCH 17/24] opkg: update to git HEAD 1bf042d libopkg: pkg_hash: print unresolved dependencies Signed-off-by: Hauke Mehrtens --- package/system/opkg/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/system/opkg/Makefile b/package/system/opkg/Makefile index cc295c12ba..65bdf6dba9 100644 --- a/package/system/opkg/Makefile +++ b/package/system/opkg/Makefile @@ -12,9 +12,9 @@ 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_DATE:=2021-06-13 +PKG_SOURCE_VERSION:=1bf042dd06751b693a8544d2317e5b969d666b69 +PKG_MIRROR_HASH:=aeda4e0f11805bf95fc7be6d38391ce579acd965c8ba6a490b3e8669815b7264 PKG_LICENSE:=GPL-2.0 PKG_LICENSE_FILES:=COPYING From 4673ba070ec992681f191eaeaa4ff27e0caea6d8 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sat, 12 Jun 2021 21:26:17 -0700 Subject: [PATCH 18/24] exfat: update to 5.12.3 Major changes are: Avoid page allocation failure from upcase table allocation. Add support for FITRIM. Improve write perofmrance on dirsync mount. Improve lookup perofmrance. Fix a bug on discard mount. Signed-off-by: Rosen Penev --- package/kernel/exfat/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/kernel/exfat/Makefile b/package/kernel/exfat/Makefile index 965db54a01..6d6925648c 100644 --- a/package/kernel/exfat/Makefile +++ b/package/kernel/exfat/Makefile @@ -7,12 +7,12 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=exfat -PKG_VERSION:=5.11.1 +PKG_VERSION:=5.12.3 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/namjaejeon/linux-exfat-oot/tar.gz/$(PKG_VERSION)? -PKG_HASH:=85324f1edb1c03f65700164ba4f5750fe5cc7a8b956add321626be69149790f5 +PKG_HASH:=43889c73af76c466bbc904aff80354a62ecaa24c7b20e354ff735f5949907982 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/linux-exfat-oot-$(PKG_VERSION) PKG_MAINTAINER:= From 7f041100aeb12d9a54927aa32ee0410cc2a2216e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 12 Jun 2021 14:24:40 +0200 Subject: [PATCH 19/24] tools: build ninja before ccache to fix the build order Fixes: #405 Signed-off-by: Felix Fietkau (cherry picked from commit fa0aea53b2f1dccc2073efac8020151960d25513) --- tools/Makefile | 4 ++-- tools/ninja/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/Makefile b/tools/Makefile index 0a227766df..bae45d8373 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -46,7 +46,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 @@ -85,7 +85,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 pkg-config 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/ninja/Makefile b/tools/ninja/Makefile index 3cbd6aebba..0ff642a740 100644 --- a/tools/ninja/Makefile +++ b/tools/ninja/Makefile @@ -20,7 +20,7 @@ endef define Host/Compile cd $(HOST_BUILD_DIR) && \ - CXX="$(HOSTCXX)" \ + CXX="$(HOSTCXX_NOCACHE)" \ CXXFLAGS="$(HOST_CXXFLAGS) $(HOST_CPPFLAGS)" \ LDFLAGS="$(HOST_LDFLAGS)" \ $(STAGING_DIR_HOST)/bin/$(PYTHON) configure.py --bootstrap $(CONFIGURE_ARGS) From b8a3ca9c244de55dd2493da14bec57643baaafe6 Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Tue, 15 Jun 2021 18:20:43 +0800 Subject: [PATCH 20/24] Revert "exfat: update to 5.12.3" It was broken on kernel <= 4.19 at least, revert update and wait for fixes. This reverts commit 4673ba070ec992681f191eaeaa4ff27e0caea6d8. Signed-off-by: Tianling Shen --- package/kernel/exfat/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/kernel/exfat/Makefile b/package/kernel/exfat/Makefile index 6d6925648c..965db54a01 100644 --- a/package/kernel/exfat/Makefile +++ b/package/kernel/exfat/Makefile @@ -7,12 +7,12 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=exfat -PKG_VERSION:=5.12.3 +PKG_VERSION:=5.11.1 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/namjaejeon/linux-exfat-oot/tar.gz/$(PKG_VERSION)? -PKG_HASH:=43889c73af76c466bbc904aff80354a62ecaa24c7b20e354ff735f5949907982 +PKG_HASH:=85324f1edb1c03f65700164ba4f5750fe5cc7a8b956add321626be69149790f5 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/linux-exfat-oot-$(PKG_VERSION) PKG_MAINTAINER:= From 48307357af509c5b7c6aea366414bd50a98d5c29 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 14 Jun 2021 14:58:37 +0200 Subject: [PATCH 21/24] build: prepend ABI suffixes with a dash if package name ends with digit Ensure that ABI suffixes are separated with a dash from the package name if the name happens to end with a digit. This implementation detail got lost during the recent refactoring of the ABI_VERSION handling in buildroot. Fixes: c921650382 ("build: drop ABI version from metadata") Signed-off-by: Jo-Philipp Wich --- include/feeds.mk | 8 +++++++- include/package-ipkg.mk | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) 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/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) From 9f80b7d5be9a083a0e7a4298d1a16b92a67b571b Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Tue, 15 Jun 2021 09:54:45 +0200 Subject: [PATCH 22/24] build: ensure that dash isn't prepended twice to abi version suffix The ABIV_$(pkgname) variable already is formatted so return it as-is from the GetABISuffix macro and only filter through FormatABISuffix if we read the raw ABI version value from a version stamp file. This ensures that binary intra-package dependencies on ABI versioned libraries are properly formatted. Fixes: f6a03bff5b ("build: prepend ABI suffixes with a dash if package name ends with digit") Signed-off-by: Jo-Philipp Wich --- include/feeds.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/feeds.mk b/include/feeds.mk index e499ac2684..632fecb4a3 100644 --- a/include/feeds.mk +++ b/include/feeds.mk @@ -43,7 +43,7 @@ endef # 1: package name define GetABISuffix -$(call FormatABISuffix,$(1),$(if $(ABIV_$(1)),$(ABIV_$(1)),$(foreach v,$(wildcard $(STAGING_DIR)/pkginfo/$(1).version),$(shell cat $(v))))) +$(if $(ABIV_$(1)),$(ABIV_$(1)),$(call FormatABISuffix,$(1),$(foreach v,$(wildcard $(STAGING_DIR)/pkginfo/$(1).version),$(shell cat $(v))))) endef # 1: package name From 2fece79e6e237e71d8efd2d58dde038df4680c9a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 27 May 2021 12:34:38 +0200 Subject: [PATCH 23/24] ugps: start also in case device is absent Don't bail out from init script in case the GPS device is missing. Some modems take time to come up, and some people may use things like 'kplex' to feed ugpsd. Hence it is better to always start ugpsd unconditionally and let procd's respawn take care of retrying. Signed-off-by: Daniel Golle --- package/utils/ugps/files/ugps.init | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/package/utils/ugps/files/ugps.init b/package/utils/ugps/files/ugps.init index 3cd1ca1b8d..77c3603066 100644 --- a/package/utils/ugps/files/ugps.init +++ b/package/utils/ugps/files/ugps.init @@ -16,11 +16,16 @@ start_service() { local disabled="$(uci get gps.@gps[-1].disabled || echo 0)" [ "$disabled" == "0" ] || return + [ "$tty" ] || return - [ -c "$tty" ] || { - tty="/dev/$tty" - [ -c "$tty" ] || return - } + case "$tty" in + "/"*) + true + ;; + *) + tty="/dev/$tty" + ;; + esac procd_open_instance procd_set_param command "$PROG" From 7e33e24758994229a49cc10413ccbe37ab2a6860 Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Mon, 14 Jun 2021 23:20:25 +0800 Subject: [PATCH 24/24] ipq806x: m520: add gpio-led sys supportt (cherry picked from commit 6e017db) Signed-off-by: AmadeusGhost --- target/linux/ipq806x/config-4.14 | 2 + target/linux/ipq806x/config-4.19 | 2 + .../arm/boot/dts/qcom-ipq8064-mtfi-m520.dts | 35 ++++++++++------- .../arm/boot/dts/qcom-ipq8064-mtfi-m520.dts | 39 ++++++++++++------- target/linux/ipq806x/image/Makefile | 2 +- 5 files changed, 49 insertions(+), 31 deletions(-) diff --git a/target/linux/ipq806x/config-4.14 b/target/linux/ipq806x/config-4.14 index 38f5c94507..19f5f8ff7f 100644 --- a/target/linux/ipq806x/config-4.14 +++ b/target/linux/ipq806x/config-4.14 @@ -172,6 +172,8 @@ CONFIG_GENERIC_STRNLEN_USER=y CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_SYSFS=y CONFIG_HANDLE_DOMAIN_IRQ=y CONFIG_HARDEN_BRANCH_PREDICTOR=y diff --git a/target/linux/ipq806x/config-4.19 b/target/linux/ipq806x/config-4.19 index f4c27d7ae8..9ea74df644 100644 --- a/target/linux/ipq806x/config-4.19 +++ b/target/linux/ipq806x/config-4.19 @@ -180,6 +180,8 @@ CONFIG_GENERIC_STRNLEN_USER=y CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GPIOLIB=y CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_SYSFS=y CONFIG_HANDLE_DOMAIN_IRQ=y CONFIG_HARDEN_BRANCH_PREDICTOR=y diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-mtfi-m520.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-mtfi-m520.dts index 98ea681614..a552a52c8e 100644 --- a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-mtfi-m520.dts +++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-mtfi-m520.dts @@ -27,6 +27,11 @@ serial0 = &gsbi4_serial; mdio-gpio0 = &mdio0; sdcc1 = &sdcc1; + + led-boot = &led_sys; + led-failsafe = &led_sys; + led-running = &led_sys; + led-upgrade = &led_sys; }; chosen { @@ -34,6 +39,15 @@ stdout-path = "serial0:115200n8"; }; + leds { + compatible = "gpio-leds"; + + led_sys: sys { + label = "m520:green:sys"; + gpios = <&gpio_ext 15 GPIO_ACTIVE_LOW>; + }; + }; + soc { pinmux@800000 { button_pins: button_pins { @@ -54,15 +68,6 @@ }; }; - led_pins: led_pins { - mux { - pins = "gpio7", "gpio8", "gpio9", "gpio53"; - function = "gpio"; - drive-strength = <2>; - bias-pull-down; - }; - }; - mdio0_pins: mdio0_pins { mux { pins = "gpio0", "gpio1"; @@ -142,21 +147,21 @@ status = "ok"; lm75@48 { - status = "okay"; compatible = "lm75"; reg = <0x48>; }; pcf8563: rtc@51 { - status = "okay"; compatible = "nxp,pcf8563"; reg = <0x51>; }; - tca9539@74 { - status = "okay"; + gpio_ext: tca9539@74 { compatible = "ti,tca9539"; reg = <0x74>; + + gpio-controller; + #gpio-cells = <2>; }; }; }; @@ -377,8 +382,8 @@ amba { sdcc1: sdcc@12400000 { status = "okay"; - pinctrl-0 = <&sdcc1_pins>; - pinctrl-names = "default"; + pinctrl-0 = <&sdcc1_pins>; + pinctrl-names = "default"; }; }; }; diff --git a/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064-mtfi-m520.dts b/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064-mtfi-m520.dts index d757cd8085..0ef4b60be6 100644 --- a/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064-mtfi-m520.dts +++ b/target/linux/ipq806x/files-4.19/arch/arm/boot/dts/qcom-ipq8064-mtfi-m520.dts @@ -27,6 +27,11 @@ serial0 = &gsbi4_serial; mdio-gpio0 = &mdio0; sdcc1 = &sdcc1; + + led-boot = &led_sys; + led-failsafe = &led_sys; + led-running = &led_sys; + led-upgrade = &led_sys; }; chosen { @@ -34,6 +39,15 @@ stdout-path = "serial0:115200n8"; }; + leds { + compatible = "gpio-leds"; + + led_sys: sys { + label = "m520:green:sys"; + gpios = <&gpio_ext 15 GPIO_ACTIVE_LOW>; + }; + }; + soc { pinmux@800000 { button_pins: button_pins { @@ -54,15 +68,6 @@ }; }; - led_pins: led_pins { - mux { - pins = "gpio7", "gpio8", "gpio9", "gpio53"; - function = "gpio"; - drive-strength = <2>; - bias-pull-down; - }; - }; - mdio0_pins: mdio0_pins { mux { pins = "gpio0", "gpio1"; @@ -142,21 +147,21 @@ status = "okay"; lm75@48 { - status = "okay"; compatible = "lm75"; reg = <0x48>; }; pcf8563: rtc@51 { - status = "okay"; compatible = "nxp,pcf8563"; reg = <0x51>; }; - tca9539@74 { - status = "okay"; + gpio_ext: tca9539@74 { compatible = "ti,tca9539"; reg = <0x74>; + + gpio-controller; + #gpio-cells = <2>; }; }; }; @@ -362,8 +367,8 @@ amba { sdcc1: sdcc@12400000 { status = "okay"; - pinctrl-0 = <&sdcc1_pins>; - pinctrl-names = "default"; + pinctrl-0 = <&sdcc1_pins>; + pinctrl-names = "default"; }; }; }; @@ -384,3 +389,7 @@ &adm_dma { status = "okay"; }; + +&CPU_SPC { + status = "disabled"; +}; diff --git a/target/linux/ipq806x/image/Makefile b/target/linux/ipq806x/image/Makefile index 4540a5736f..4943627c48 100644 --- a/target/linux/ipq806x/image/Makefile +++ b/target/linux/ipq806x/image/Makefile @@ -275,7 +275,7 @@ define Device/ruijie_rg-mtfi-m520 IMAGE/mmcblk0p2-kernel.bin := append-kernel | pad-to $$$${KERNEL_SIZE} IMAGE/mmcblk0p3-rootfs.bin := append-rootfs | pad-rootfs DEVICE_PACKAGES := ath10k-firmware-qca988x-ct e2fsprogs f2fs-tools \ - kmod-gpio-pca953x kmod-hwmon-lm75 kmod-fs-ext4 kmod-fs-f2fs kmod-rtc-pcf8563 losetup + kmod-hwmon-lm75 kmod-fs-ext4 kmod-fs-f2fs kmod-rtc-pcf8563 losetup endef TARGET_DEVICES += ruijie_rg-mtfi-m520