From 9779ee021d30508eb9e7ebf1ec0a28a4be3c4c19 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 24 Mar 2023 13:32:36 +0100 Subject: [PATCH 01/53] mac80211: fix invalid calls to drv_sta_pre_rcu_remove Potentially fixes some driver data structure corruption issues Signed-off-by: Felix Fietkau --- ...x-invalid-drv_sta_pre_rcu_remove-cal.patch | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 package/kernel/mac80211/patches/subsys/328-wifi-mac80211-fix-invalid-drv_sta_pre_rcu_remove-cal.patch diff --git a/package/kernel/mac80211/patches/subsys/328-wifi-mac80211-fix-invalid-drv_sta_pre_rcu_remove-cal.patch b/package/kernel/mac80211/patches/subsys/328-wifi-mac80211-fix-invalid-drv_sta_pre_rcu_remove-cal.patch new file mode 100644 index 00000000000..289906c88c6 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/328-wifi-mac80211-fix-invalid-drv_sta_pre_rcu_remove-cal.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau +Date: Fri, 24 Mar 2023 13:04:17 +0100 +Subject: [PATCH] wifi: mac80211: fix invalid drv_sta_pre_rcu_remove calls for + non-uploaded sta + +Avoid potential data corruption issues caused by uninitialized driver +private data structures. + +Reported-by: Brian Coverstone +Fixes: 6a9d1b91f34d ("mac80211: add pre-RCU-sync sta removal driver operation") +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -1241,7 +1241,8 @@ static int __must_check __sta_info_destr + list_del_rcu(&sta->list); + sta->removed = true; + +- drv_sta_pre_rcu_remove(local, sta->sdata, sta); ++ if (sta->uploaded) ++ drv_sta_pre_rcu_remove(local, sta->sdata, sta); + + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + rcu_access_pointer(sdata->u.vlan.sta) == sta) From 47de2c686291e69afc9f443e27e1dfd11ed5fbe7 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Thu, 23 Mar 2023 23:53:47 +0100 Subject: [PATCH 02/53] ramips: add support for Mercusys MR70X Hardware ======== - SoC: MediaTek MT7621AT (880MHz, Duel-Core) - RAM: DDR3 128MB - Flash: Winbond W25Q128JV (SPI-NOR 16MB) - WiFi: MediaTek MT7915D (2.4GHz, 5GHz, DBDC) - Ethernet: MediaTek MT7530 (WAN x1, LAN x3, SoC) - UART: >TX RX GND 3v3 (115200 8N1, J1) Do not connect 3v3. TX is marked with an arrow. Installation ============ Flash factory image. This can be done using stock web ui. Revert to stock firmware ======================== Flash stock firmware via OEM Web UI Recovery mode. Web UI Recovery method ====================== 1. Unplug the router 2. Plug in and hold reset button 5~10 secs 3. Set your computer IP address manually to 192.168.1.x / 255.255.255.0 4. Flash image with web browser to 192.168.1.1 Co-authored-by: Robert Senderek Co-authored-by: Yoonji Park Signed-off-by: David Bauer --- .../ramips/dts/mt7621_mercusys_mr70x-v1.dts | 165 ++++++++++++++++++ target/linux/ramips/image/mt7621.mk | 13 ++ .../etc/hotplug.d/ieee80211/10_fix_wifi_mac | 9 +- 3 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 target/linux/ramips/dts/mt7621_mercusys_mr70x-v1.dts diff --git a/target/linux/ramips/dts/mt7621_mercusys_mr70x-v1.dts b/target/linux/ramips/dts/mt7621_mercusys_mr70x-v1.dts new file mode 100644 index 00000000000..7eb94ba9cfc --- /dev/null +++ b/target/linux/ramips/dts/mt7621_mercusys_mr70x-v1.dts @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7621.dtsi" + +#include +#include + +/ { + compatible = "mercusys,mr70x-v1", "mediatek,mt7621-soc"; + model = "Mercusys MR70X v1"; + + aliases { + led-boot = &led_power_green; + led-failsafe = &led_power_orange; + led-running = &led_power_green; + led-upgrade = &led_power_orange; + label-mac-device = &gmac0; + }; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&gpio 8 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + led_power_green: power-green { + label = "green:power"; + gpios = <&gpio 4 GPIO_ACTIVE_LOW>; + }; + + led_power_orange: power-orange { + label = "orange:power"; + gpios = <&gpio 3 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <80000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x000000 0x040000>; + read-only; + }; + + partition@40000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x040000 0xf60000>; + }; + + config: partition@fa0000 { + label = "config"; + reg = <0xfa0000 0x010000>; + read-only; + }; + + partition@fb0000 { + label = "tplink"; + reg = <0xfb0000 0x040000>; + read-only; + }; + + radio: partition@ff0000 { + label = "radio"; + reg = <0xff0000 0x010000>; + read-only; + }; + }; + }; +}; + +&pcie { + status = "okay"; +}; + +&pcie1 { + wifi@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + mediatek,mtd-eeprom = <&radio 0x0>; + nvmem-cells = <&macaddr_config_8>; + nvmem-cell-names = "mac-address"; + mediatek,disable-radar-background; + }; +}; + +&gmac0 { + nvmem-cells = <&macaddr_config_8>; + nvmem-cell-names = "mac-address"; +}; + +&gmac1 { + status = "okay"; + label = "wan"; + phy-handle = <ðphy0>; + + nvmem-cells = <&macaddr_config_8>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <1>; +}; + +&mdio { + ethphy0: ethernet-phy@0 { + reg = <0>; + }; +}; + +&switch0 { + ports { + port@1 { + status = "okay"; + label = "lan1"; + }; + + port@2 { + status = "okay"; + label = "lan2"; + }; + + port@3 { + status = "okay"; + label = "lan3"; + }; + }; +}; + +&state_default { + gpio { + groups = "i2c", "uart3"; + function = "gpio"; + }; +}; + +&config { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_config_8: macaddr@8 { + reg = <0x8 0x6>; + }; +}; diff --git a/target/linux/ramips/image/mt7621.mk b/target/linux/ramips/image/mt7621.mk index 5d2a4844269..dfe9d346f10 100644 --- a/target/linux/ramips/image/mt7621.mk +++ b/target/linux/ramips/image/mt7621.mk @@ -1496,6 +1496,19 @@ define Device/mediatek_mt7621-eval-board endef TARGET_DEVICES += mediatek_mt7621-eval-board +define Device/mercusys_mr70x-v1 + $(Device/dsa-migration) + $(Device/tplink-safeloader) + DEVICE_VENDOR := Mercusys + DEVICE_MODEL := MR70X + DEVICE_VARIANT := v1 + DEVICE_PACKAGES := kmod-mt7915-firmware -uboot-envtools + TPLINK_BOARD_ID := MR70X + KERNEL := $(KERNEL_DTB) | uImage lzma + IMAGE_SIZE := 15744k +endef +TARGET_DEVICES += mercusys_mr70x-v1 + define Device/MikroTik $(Device/dsa-migration) DEVICE_VENDOR := MikroTik diff --git a/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac b/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac index bf6c55a8fe0..b23464bebec 100644 --- a/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac +++ b/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac @@ -120,6 +120,11 @@ case "$board" in [ "$PHYNBR" = "0" ] && macaddr_add $hw_mac_addr 2 > /sys${DEVPATH}/macaddress [ "$PHYNBR" = "1" ] && macaddr_add $hw_mac_addr 3 > /sys${DEVPATH}/macaddress ;; + mercusys,mr70x-v1|\ + tplink,archer-ax23-v1) + hw_mac_addr="$(mtd_get_mac_binary config 0x8)" + [ "$PHYNBR" = "1" ] && macaddr_add "$hw_mac_addr" -1 > "/sys${DEVPATH}/macaddress" + ;; mts,wg430223) hw_mac_addr=$(macaddr_add $(mtd_get_mac_encrypted_arcadyan "board_data") 1) [ "$PHYNBR" = "0" ] && echo -n "$hw_mac_addr" > /sys${DEVPATH}/macaddress @@ -147,10 +152,6 @@ case "$board" in hw_mac_addr="$(mtd_get_mac_binary factory 0x4)" [ "$PHYNBR" = "1" ] && macaddr_add $hw_mac_addr "0x100000" > /sys${DEVPATH}/macaddress ;; - tplink,archer-ax23-v1) - hw_mac_addr="$(mtd_get_mac_binary config 0x8)" - [ "$PHYNBR" = "1" ] && macaddr_add "$hw_mac_addr" -1 > "/sys${DEVPATH}/macaddress" - ;; tplink,eap615-wall-v1) hw_mac_addr="$(mtd_get_mac_binary product-info 0x8)" macaddr_add "$hw_mac_addr" "$PHYNBR" > "/sys${DEVPATH}/macaddress" From 4ce0405e1880fa4a0dd565e0369ad2472f4b6848 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 19 Feb 2023 15:01:43 +0100 Subject: [PATCH 03/53] kernel: add support for threaded network backlog processing This can improve load balancing by pushing backlog (and RPS) processing to separate threads, allowing the scheduler to distribute the load. It can be enabled with: echo 1 > /proc/sys/net/core/backlog_threaded Signed-off-by: Felix Fietkau --- .../721-net-add-packet-mangeling.patch | 10 +- ...ional-threading-for-backlog-processi.patch | 224 ++++++++++++++++++ 2 files changed, 229 insertions(+), 5 deletions(-) create mode 100644 target/linux/generic/pending-5.15/760-net-core-add-optional-threading-for-backlog-processi.patch diff --git a/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch b/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch index 9dc86303a7a..a1d621a7a9e 100644 --- a/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch +++ b/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -1676,6 +1676,10 @@ enum netdev_priv_flags { +@@ -1677,6 +1677,10 @@ enum netdev_priv_flags { IFF_TX_SKB_NO_LINEAR = BIT_ULL(31), }; @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN #define IFF_EBRIDGE IFF_EBRIDGE #define IFF_BONDING IFF_BONDING -@@ -1708,6 +1712,7 @@ enum netdev_priv_flags { +@@ -1709,6 +1713,7 @@ enum netdev_priv_flags { #define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER #define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK #define IFF_TX_SKB_NO_LINEAR IFF_TX_SKB_NO_LINEAR @@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau /* Specifies the type of the struct net_device::ml_priv pointer */ enum netdev_ml_priv_type { -@@ -2009,6 +2014,7 @@ struct net_device { +@@ -2010,6 +2015,7 @@ struct net_device { /* Read-mostly cache-line for fast-path access */ unsigned int flags; unsigned int priv_flags; @@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau const struct net_device_ops *netdev_ops; int ifindex; unsigned short gflags; -@@ -2069,6 +2075,11 @@ struct net_device { +@@ -2070,6 +2076,11 @@ struct net_device { const struct tlsdev_ops *tlsdev_ops; #endif @@ -58,7 +58,7 @@ Signed-off-by: Felix Fietkau const struct header_ops *header_ops; unsigned char operstate; -@@ -2143,6 +2154,10 @@ struct net_device { +@@ -2144,6 +2155,10 @@ struct net_device { struct mctp_dev __rcu *mctp_ptr; #endif diff --git a/target/linux/generic/pending-5.15/760-net-core-add-optional-threading-for-backlog-processi.patch b/target/linux/generic/pending-5.15/760-net-core-add-optional-threading-for-backlog-processi.patch new file mode 100644 index 00000000000..463f405f3a1 --- /dev/null +++ b/target/linux/generic/pending-5.15/760-net-core-add-optional-threading-for-backlog-processi.patch @@ -0,0 +1,224 @@ +From: Felix Fietkau +Date: Thu, 16 Feb 2023 18:39:04 +0100 +Subject: [PATCH] net/core: add optional threading for backlog processing + +When dealing with few flows or an imbalance on CPU utilization, static RPS +CPU assignment can be too inflexible. Add support for enabling threaded NAPI +for backlog processing in order to allow the scheduler to better balance +processing. This helps better spread the load across idle CPUs. + +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -500,6 +500,7 @@ static inline bool napi_complete(struct + } + + int dev_set_threaded(struct net_device *dev, bool threaded); ++int backlog_set_threaded(bool threaded); + + /** + * napi_disable - prevent NAPI from scheduling +@@ -3363,6 +3364,7 @@ struct softnet_data { + unsigned int processed; + unsigned int time_squeeze; + unsigned int received_rps; ++ unsigned int process_queue_empty; + #ifdef CONFIG_RPS + struct softnet_data *rps_ipi_list; + #endif +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4574,7 +4574,7 @@ static int rps_ipi_queued(struct softnet + #ifdef CONFIG_RPS + struct softnet_data *mysd = this_cpu_ptr(&softnet_data); + +- if (sd != mysd) { ++ if (sd != mysd && !test_bit(NAPI_STATE_THREADED, &sd->backlog.state)) { + sd->rps_ipi_next = mysd->rps_ipi_list; + mysd->rps_ipi_list = sd; + +@@ -5755,6 +5755,8 @@ static DEFINE_PER_CPU(struct work_struct + /* Network device is going away, flush any packets still pending */ + static void flush_backlog(struct work_struct *work) + { ++ unsigned int process_queue_empty; ++ bool threaded, flush_processq; + struct sk_buff *skb, *tmp; + struct softnet_data *sd; + +@@ -5770,9 +5772,18 @@ static void flush_backlog(struct work_st + input_queue_head_incr(sd); + } + } ++ ++ threaded = test_bit(NAPI_STATE_THREADED, &sd->backlog.state); ++ flush_processq = threaded && ++ !skb_queue_empty_lockless(&sd->process_queue); ++ if (flush_processq) ++ process_queue_empty = sd->process_queue_empty; + rps_unlock(sd); + local_irq_enable(); + ++ if (threaded) ++ goto out; ++ + skb_queue_walk_safe(&sd->process_queue, skb, tmp) { + if (skb->dev->reg_state == NETREG_UNREGISTERING) { + __skb_unlink(skb, &sd->process_queue); +@@ -5780,7 +5791,18 @@ static void flush_backlog(struct work_st + input_queue_head_incr(sd); + } + } ++ ++out: + local_bh_enable(); ++ ++ while (flush_processq) { ++ msleep(1); ++ local_irq_disable(); ++ rps_lock(sd); ++ flush_processq = process_queue_empty == sd->process_queue_empty; ++ rps_unlock(sd); ++ local_irq_enable(); ++ } + } + + static bool flush_required(int cpu) +@@ -6463,6 +6485,7 @@ static int process_backlog(struct napi_s + + local_irq_disable(); + rps_lock(sd); ++ sd->process_queue_empty++; + if (skb_queue_empty(&sd->input_pkt_queue)) { + /* + * Inline a custom version of __napi_complete(). +@@ -6472,7 +6495,8 @@ static int process_backlog(struct napi_s + * We can use a plain write instead of clear_bit(), + * and we dont need an smp_mb() memory barrier. + */ +- napi->state = 0; ++ napi->state &= ~(NAPIF_STATE_SCHED | ++ NAPIF_STATE_SCHED_THREADED); + again = false; + } else { + skb_queue_splice_tail_init(&sd->input_pkt_queue, +@@ -6889,6 +6913,57 @@ int dev_set_threaded(struct net_device * + } + EXPORT_SYMBOL(dev_set_threaded); + ++int backlog_set_threaded(bool threaded) ++{ ++ static bool backlog_threaded; ++ int err = 0; ++ int i; ++ ++ if (backlog_threaded == threaded) ++ return 0; ++ ++ for_each_possible_cpu(i) { ++ struct softnet_data *sd = &per_cpu(softnet_data, i); ++ struct napi_struct *n = &sd->backlog; ++ ++ if (n->thread) ++ continue; ++ n->thread = kthread_run(napi_threaded_poll, n, "napi/backlog-%d", i); ++ if (IS_ERR(n->thread)) { ++ err = PTR_ERR(n->thread); ++ pr_err("kthread_run failed with err %d\n", err); ++ n->thread = NULL; ++ threaded = false; ++ break; ++ } ++ ++ } ++ ++ backlog_threaded = threaded; ++ ++ /* Make sure kthread is created before THREADED bit ++ * is set. ++ */ ++ smp_mb__before_atomic(); ++ ++ for_each_possible_cpu(i) { ++ struct softnet_data *sd = &per_cpu(softnet_data, i); ++ struct napi_struct *n = &sd->backlog; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ rps_lock(sd); ++ if (threaded) ++ n->state |= NAPIF_STATE_THREADED; ++ else ++ n->state &= ~NAPIF_STATE_THREADED; ++ rps_unlock(sd); ++ local_irq_restore(flags); ++ } ++ ++ return err; ++} ++ + void netif_napi_add(struct net_device *dev, struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), int weight) + { +@@ -11367,6 +11442,9 @@ static int dev_cpu_dead(unsigned int old + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_enable(); + ++ if (test_bit(NAPI_STATE_THREADED, &oldsd->backlog.state)) ++ return 0; ++ + #ifdef CONFIG_RPS + remsd = oldsd->rps_ipi_list; + oldsd->rps_ipi_list = NULL; +--- a/net/core/sysctl_net_core.c ++++ b/net/core/sysctl_net_core.c +@@ -28,6 +28,7 @@ static int int_3600 = 3600; + static int min_sndbuf = SOCK_MIN_SNDBUF; + static int min_rcvbuf = SOCK_MIN_RCVBUF; + static int max_skb_frags = MAX_SKB_FRAGS; ++static int backlog_threaded; + static long long_one __maybe_unused = 1; + static long long_max __maybe_unused = LONG_MAX; + +@@ -114,6 +115,23 @@ static int rps_sock_flow_sysctl(struct c + } + #endif /* CONFIG_RPS */ + ++static int backlog_threaded_sysctl(struct ctl_table *table, int write, ++ void *buffer, size_t *lenp, loff_t *ppos) ++{ ++ static DEFINE_MUTEX(backlog_threaded_mutex); ++ int ret; ++ ++ mutex_lock(&backlog_threaded_mutex); ++ ++ ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); ++ if (write && !ret) ++ ret = backlog_set_threaded(backlog_threaded); ++ ++ mutex_unlock(&backlog_threaded_mutex); ++ ++ return ret; ++} ++ + #ifdef CONFIG_NET_FLOW_LIMIT + static DEFINE_MUTEX(flow_limit_update_mutex); + +@@ -470,6 +488,15 @@ static struct ctl_table net_core_table[] + .proc_handler = rps_sock_flow_sysctl + }, + #endif ++ { ++ .procname = "backlog_threaded", ++ .data = &backlog_threaded, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = backlog_threaded_sysctl, ++ .extra1 = SYSCTL_ZERO, ++ .extra2 = SYSCTL_ONE ++ }, + #ifdef CONFIG_NET_FLOW_LIMIT + { + .procname = "flow_limit_cpu_bitmap", From 156c00dedc1861131d11ea6f0ca217d019f2ee85 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 10 Mar 2023 02:19:37 +0100 Subject: [PATCH 04/53] generic: backport Winbond W25N02KV SPI-NAND support This flash-chip is used on the Asus TUF-AX4200 and TUF-AX6000 routers. As the filogic target only uses kernel 5.15, skip the 5.10 backport. Signed-off-by: David Bauer --- ...-spinand-winbond-fix-flash-detection.patch | 40 +++++++ ...6.1-mtd-spinand-winbond-add-W25N02KV.patch | 106 ++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 target/linux/generic/backport-5.15/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch create mode 100644 target/linux/generic/backport-5.15/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch diff --git a/target/linux/generic/backport-5.15/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch b/target/linux/generic/backport-5.15/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch new file mode 100644 index 00000000000..38fbc3a3d73 --- /dev/null +++ b/target/linux/generic/backport-5.15/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch @@ -0,0 +1,40 @@ +From dbf70fc204d2fbb0d8ad8f42038a60846502efda Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Mon, 10 Oct 2022 13:51:09 +0300 +Subject: [PATCH] mtd: spinand: winbond: fix flash identification + +Winbond uses 3 bytes to identify flash: vendor_id, dev_id_0, dev_id_1, +but current driver uses only first 2 bytes of it for devices +identification. As result Winbond W25N02KV flash (id_bytes: EF, AA, 22) +is identified as W25N01GV (id_bytes: EF, AA, 21). + +Fix this by adding missed identification bytes. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: Frieder Schrempf +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221010105110.446674-1-mikhail.kshevetskiy@iopsys.eu +--- + drivers/mtd/nand/spi/winbond.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -76,7 +76,7 @@ static int w25m02gv_select_target(struct + + static const struct spinand_info winbond_spinand_table[] = { + SPINAND_INFO("W25M02GV", +- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab), ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, +@@ -86,7 +86,7 @@ static const struct spinand_info winbond + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), + SPINAND_SELECT_TARGET(w25m02gv_select_target)), + SPINAND_INFO("W25N01GV", +- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa), ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, diff --git a/target/linux/generic/backport-5.15/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch b/target/linux/generic/backport-5.15/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch new file mode 100644 index 00000000000..d75a1acc57c --- /dev/null +++ b/target/linux/generic/backport-5.15/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch @@ -0,0 +1,106 @@ +From 6154c7a583483d7b69f53bea868efdc369edd563 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Mon, 10 Oct 2022 13:51:10 +0300 +Subject: [PATCH] mtd: spinand: winbond: add Winbond W25N02KV flash support + +Add support of Winbond W25N02KV flash + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: Frieder Schrempf +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221010105110.446674-2-mikhail.kshevetskiy@iopsys.eu +--- + drivers/mtd/nand/spi/winbond.c | 75 ++++++++++++++++++++++++++++++++++ + 1 file changed, 75 insertions(+) + +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -74,6 +74,72 @@ static int w25m02gv_select_target(struct + return spi_mem_exec_op(spinand->spimem, &op); + } + ++static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = 64 + (16 * section); ++ region->length = 13; ++ ++ return 0; ++} ++ ++static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = (16 * section) + 2; ++ region->length = 14; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops w25n02kv_ooblayout = { ++ .ecc = w25n02kv_ooblayout_ecc, ++ .free = w25n02kv_ooblayout_free, ++}; ++ ++static int w25n02kv_ecc_get_status(struct spinand_device *spinand, ++ u8 status) ++{ ++ struct nand_device *nand = spinand_to_nand(spinand); ++ u8 mbf = 0; ++ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); ++ ++ switch (status & STATUS_ECC_MASK) { ++ case STATUS_ECC_NO_BITFLIPS: ++ return 0; ++ ++ case STATUS_ECC_UNCOR_ERROR: ++ return -EBADMSG; ++ ++ case STATUS_ECC_HAS_BITFLIPS: ++ /* ++ * Let's try to retrieve the real maximum number of bitflips ++ * in order to avoid forcing the wear-leveling layer to move ++ * data around if it's not necessary. ++ */ ++ if (spi_mem_exec_op(spinand->spimem, &op)) ++ return nanddev_get_ecc_conf(nand)->strength; ++ ++ mbf >>= 4; ++ ++ if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) ++ return nanddev_get_ecc_conf(nand)->strength; ++ ++ return mbf; ++ ++ default: ++ break; ++ } ++ ++ return -EINVAL; ++} ++ + static const struct spinand_info winbond_spinand_table[] = { + SPINAND_INFO("W25M02GV", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), +@@ -94,6 +160,15 @@ static const struct spinand_info winbond + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), ++ SPINAND_INFO("W25N02KV", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ 0, ++ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + }; + + static int winbond_spinand_init(struct spinand_device *spinand) From 90691f450543fa0a7f0258ffce06ec22e516445b Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sat, 11 Mar 2023 01:38:19 +0100 Subject: [PATCH 05/53] generic: mxl-gpy: allow configuring LED registers Add a patch to allow modification of the PHY LED configuration. This is required for boards, where the reset configuration of LED functions is incompatibe with the usage of the device LEDs. This is the case for the ASUS TUF-AX4200 Wireless router. It requires modification of the LED configuration because as the WAN LED on the front of the device is driven by the PHY. Without patching, it would only illuminate in case the Link speed is 100 Mbit/s. Signed-off-by: David Bauer --- .../765-mxl-gpy-control-LED-reg-from-DT.patch | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 target/linux/generic/hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch diff --git a/target/linux/generic/hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch b/target/linux/generic/hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch new file mode 100644 index 00000000000..75014c05283 --- /dev/null +++ b/target/linux/generic/hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch @@ -0,0 +1,106 @@ +From 94b90966095f3fa625897e8f53d215882f6e19b3 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Sat, 11 Mar 2023 17:00:01 +0100 +Subject: [PATCH] mxl-gpy: control LED reg from DT + +Add dynamic configuration for the LED control registers on MXL PHYs. + +This patch has been tested with MaxLinear GPY211C. It is unlikely to be +accepted upstream, as upstream plans on integrating their own framework +for handling these LEDs. + +For the time being, use this hack to configure PHY driven device-LEDs to +show the correct state. + +A possible alternative might be to expose the LEDs using the kernel LED +framework and bind it to the netdevice. This might also be upstreamable, +although it is a considerable extra amount of work. + +Signed-off-by: David Bauer +--- + drivers/net/phy/mxl-gpy.c | 37 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c +index 5ce1bf03bbd7..ec10ad5ccad6 100644 +--- a/drivers/net/phy/mxl-gpy.c ++++ b/drivers/net/phy/mxl-gpy.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + +@@ -30,6 +31,7 @@ + #define PHY_MIISTAT 0x18 /* MII state */ + #define PHY_IMASK 0x19 /* interrupt mask */ + #define PHY_ISTAT 0x1A /* interrupt status */ ++#define PHY_LED 0x1B /* LED control */ + #define PHY_FWV 0x1E /* firmware version */ + + #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0) +@@ -53,10 +55,15 @@ + PHY_IMASK_ADSC | \ + PHY_IMASK_ANC) + ++#define PHY_LED_NUM_LEDS 4 ++ + #define PHY_FWV_REL_MASK BIT(15) + #define PHY_FWV_TYPE_MASK GENMASK(11, 8) + #define PHY_FWV_MINOR_MASK GENMASK(7, 0) + ++/* LED */ ++#define VSPEC1_LED(x) (0x1 + x) ++ + /* SGMII */ + #define VSPEC1_SGMII_CTRL 0x08 + #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */ +@@ -80,6 +87,31 @@ static const struct { + {9, 0x73}, + }; + ++static int gpy_led_write(struct phy_device *phydev) ++{ ++ struct device_node *node = phydev->mdio.dev.of_node; ++ u32 led_regs[PHY_LED_NUM_LEDS]; ++ int i, ret; ++ ++ if (!IS_ENABLED(CONFIG_OF_MDIO)) ++ return 0; ++ ++ if (of_property_read_u32_array(node, "mxl,led-config", led_regs, PHY_LED_NUM_LEDS)) ++ return 0; ++ ++ /* Enable LED function handling on all ports*/ ++ phy_write(phydev, PHY_LED, 0xFF00); ++ ++ /* Write LED register values */ ++ for (i = 0; i < PHY_LED_NUM_LEDS; i++) { ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(i), (u16)led_regs[i]); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int gpy_config_init(struct phy_device *phydev) + { + int ret; +@@ -91,7 +123,10 @@ static int gpy_config_init(struct phy_device *phydev) + + /* Clear all pending interrupts */ + ret = phy_read(phydev, PHY_ISTAT); +- return ret < 0 ? ret : 0; ++ if (ret < 0) ++ return ret; ++ ++ return gpy_led_write(phydev); + } + + static int gpy_probe(struct phy_device *phydev) +-- +2.39.2 + From 652d5ac1526ffb5e5d5894dbde4064b2d56723e0 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Mon, 13 Mar 2023 03:14:42 +0100 Subject: [PATCH 06/53] mediatek: enable bootargs-override for filogic subtarget The ASUS TUF-AX4200 bootloader adds invalid parameters for the rootfs. Without overwriting the cmdline, the kernel crashes when trying to attach the rootfs, as OpenWrt uses a different partition than the vendor OS. Signed-off-by: David Bauer --- target/linux/mediatek/filogic/config-5.15 | 1 + .../901-arm-add-cmdline-override.patch | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/target/linux/mediatek/filogic/config-5.15 b/target/linux/mediatek/filogic/config-5.15 index 6a989310df9..a1c2e64acd4 100644 --- a/target/linux/mediatek/filogic/config-5.15 +++ b/target/linux/mediatek/filogic/config-5.15 @@ -50,6 +50,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y CONFIG_CLKSRC_MMIO=y CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE_OVERRIDE=y CONFIG_COMMON_CLK=y CONFIG_COMMON_CLK_MEDIATEK=y # CONFIG_COMMON_CLK_MT2712 is not set diff --git a/target/linux/mediatek/patches-5.15/901-arm-add-cmdline-override.patch b/target/linux/mediatek/patches-5.15/901-arm-add-cmdline-override.patch index acbb190030c..6016128bd4a 100644 --- a/target/linux/mediatek/patches-5.15/901-arm-add-cmdline-override.patch +++ b/target/linux/mediatek/patches-5.15/901-arm-add-cmdline-override.patch @@ -35,3 +35,20 @@ /* * CONFIG_CMDLINE is meant to be a default in case nothing else * managed to set the command line, unless CONFIG_CMDLINE_FORCE +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -1942,6 +1942,14 @@ config CMDLINE_FORCE + + endchoice + ++config CMDLINE_OVERRIDE ++ bool "Use alternative cmdline from device tree" ++ help ++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can ++ be used, this is not a good option for kernels that are shared across ++ devices. This setting enables using "chosen/cmdline-override" as the ++ cmdline if it exists in the device tree. ++ + config EFI_STUB + bool + From e7c399bee677e9bac66e1bea697aefb8d828edfe Mon Sep 17 00:00:00 2001 From: David Bauer Date: Thu, 26 Jan 2023 17:39:43 +0100 Subject: [PATCH 07/53] filogic: add support for ASUS TUF-AX4200 Hardware -------- SOC: MediaTek MT7986 RAM: 512MB DDR3 FLASH: 256MB SPI-NAND (Winbond W25N02KV) WIFI: Mediatek MT7986 DBDC 802.11ax 2.4/5 GHz ETH: MediaTek MT7531 Switch MaxLinear GPY211C 2.5 N-Base-T PHY UART: 3V3 115200 8N1 (Pinout silkscreened / Do not ocnnect VCC) Installation ------------ 1. Download the OpenWrt initramfs image. Copy the image to a TFTP server reachable at 192.168.1.66/24. Rename the image to tufax4200.bin. 2. Connect the TFTP server to the AX4200. Conect to the serial console, interrupt the autoboot process by pressing '4' when prompted. 3. Download & Boot the OpenWrt initramfs image. $ setenv ipaddr 192.168.1.1 $ setenv serverip 192.168.1.66 $ tftpboot 0x46000000 tufax4200.bin $ bootm 0x46000000 4. Wait for OpenWrt to boot. Transfer the sysupgrade image to the device using scp and install using sysupgrade. $ sysupgrade -n Missing features ---------------- - The LAN port LEDs are driven by the switch but OpenWrt does not correctly configure the output. Signed-off-by: David Bauer --- .../mediatek/dts/mt7986a-asus-tuf-ax4200.dts | 291 ++++++++++++++++++ .../filogic/base-files/etc/board.d/02_network | 10 + .../etc/hotplug.d/firmware/11-mt76-caldata | 21 ++ .../etc/hotplug.d/ieee80211/11_fix_wifi_mac | 9 + .../base-files/lib/preinit/10_fix_eth_mac.sh | 14 + .../base-files/lib/upgrade/platform.sh | 5 + target/linux/mediatek/image/filogic.mk | 18 ++ 7 files changed, 368 insertions(+) create mode 100644 target/linux/mediatek/dts/mt7986a-asus-tuf-ax4200.dts create mode 100644 target/linux/mediatek/filogic/base-files/etc/hotplug.d/firmware/11-mt76-caldata create mode 100644 target/linux/mediatek/filogic/base-files/lib/preinit/10_fix_eth_mac.sh diff --git a/target/linux/mediatek/dts/mt7986a-asus-tuf-ax4200.dts b/target/linux/mediatek/dts/mt7986a-asus-tuf-ax4200.dts new file mode 100644 index 00000000000..0a2f1d1d596 --- /dev/null +++ b/target/linux/mediatek/dts/mt7986a-asus-tuf-ax4200.dts @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; +#include +#include +#include + +#include "mt7986a.dtsi" + +/ { + model = "ASUS TUF-AX4200"; + compatible = "asus,tuf-ax4200", "mediatek,mt7986a"; + + aliases { + serial0 = &uart0; + led-boot = &led_system; + led-failsafe = &led_system; + led-running = &led_system; + led-upgrade = &led_system; + }; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs-override = "ubi.mtd=UBI_DEV"; + }; + + memory { + reg = <0 0x40000000 0 0x20000000>; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&pio 9 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + mesh { + label = "wps"; + gpios = <&pio 10 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + wlan24 { + label = "white:wlan24"; + gpios = <&pio 1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tpt"; + }; + + wlan5 { + label = "white:wlan5"; + gpios = <&pio 2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy1tpt"; + }; + + led_system: system { + label = "white:system"; + gpios = <&pio 11 GPIO_ACTIVE_HIGH>; + }; + + wan-red { + label = "red:wan"; + gpios = <&pio 12 GPIO_ACTIVE_LOW>; + }; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_5v: regulator-5v { + compatible = "regulator-fixed"; + regulator-name = "fixed-5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + }; +}; + +ð { + status = "okay"; + + gmac0: mac@0 { + /* LAN */ + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "2500base-x"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + /* WAN */ + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "2500base-x"; + phy-handle = <&phy6>; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&mdio { + phy6: phy@6 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <6>; + + reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>; + reset-assert-us = <10000>; + reset-deassert-us = <10000>; + + /* LED0: CONN (WAN white) */ + mxl,led-config = <0x00f0 0x0 0x0 0x0>; + }; + + switch: switch@0 { + compatible = "mediatek,mt7531"; + reg = <31>; + + reset-gpios = <&pio 5 GPIO_ACTIVE_HIGH>; + reset-assert-us = <10000>; + reset-deassert-us = <10000>; + }; +}; + +&pio { + spi_flash_pins: spi-flash-pins-33-to-38 { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + conf-pu { + pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; + drive-strength = <8>; + mediatek,pull-up-adv = <0>; /* bias-disable */ + }; + conf-pd { + pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; + drive-strength = <8>; + mediatek,pull-down-adv = <0>; /* bias-disable */ + }; + }; + + wf_2g_5g_pins: wf_2g_5g-pins { + mux { + function = "wifi"; + groups = "wf_2g", "wf_5g"; + }; + conf { + pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4", + "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6", + "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10", + "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1", + "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0", + "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8", + "WF1_TOP_CLK", "WF1_TOP_DATA"; + drive-strength = <4>; + }; + }; + + wf_dbdc_pins: wf-dbdc-pins { + mux { + function = "wifi"; + groups = "wf_dbdc"; + }; + conf { + pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4", + "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6", + "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10", + "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1", + "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0", + "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8", + "WF1_TOP_CLK", "WF1_TOP_DATA"; + drive-strength = <4>; + }; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi_flash_pins>; + status = "okay"; + + spi_nand_flash: flash@0 { + compatible = "spi-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; + + spi-max-frequency = <20000000>; + spi-tx-buswidth = <4>; + spi-rx-buswidth = <4>; + + partitions: partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x400000>; + read-only; + }; + + partition@400000 { + label = "UBI_DEV"; + reg = <0x400000 0xfc00000>; + }; + }; + }; +}; + +&switch { + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + label = "lan1"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + port@3 { + reg = <3>; + label = "lan3"; + }; + + port@4 { + reg = <4>; + label = "lan4"; + }; + + port@6 { + reg = <6>; + label = "cpu"; + ethernet = <&gmac0>; + phy-mode = "2500base-x"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; + }; +}; + +&wmac { + status = "okay"; + pinctrl-names = "default", "dbdc"; + pinctrl-0 = <&wf_2g_5g_pins>; + pinctrl-1 = <&wf_dbdc_pins>; +}; + +&uart0 { + status = "okay"; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; \ No newline at end of file diff --git a/target/linux/mediatek/filogic/base-files/etc/board.d/02_network b/target/linux/mediatek/filogic/base-files/etc/board.d/02_network index 13f52587c35..3d76e4d5029 100644 --- a/target/linux/mediatek/filogic/base-files/etc/board.d/02_network +++ b/target/linux/mediatek/filogic/base-files/etc/board.d/02_network @@ -8,6 +8,10 @@ mediatek_setup_interfaces() local board="$1" case $board in + asus,tuf-ax4200) + CI_UBIPART="UBI_DEV" + ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "eth1" + ;; mediatek,mt7986a-rfb|\ mediatek,mt7986b-rfb) ucidef_set_interfaces_lan_wan "lan0 lan1 lan2 lan3" eth1 @@ -34,6 +38,12 @@ mediatek_setup_macs() local label_mac="" case $board in + asus,tuf-ax4200) + CI_UBIPART="UBI_DEV" + addr=$(mtd_get_mac_binary_ubi "Factory" 0x4) + wan_mac="${addr}" + lan_mac="${addr}" + ;; xiaomi,redmi-router-ax6000-stock|\ xiaomi,redmi-router-ax6000-ubootmod) wan_mac=$(mtd_get_mac_ascii Bdata ethaddr_wan) diff --git a/target/linux/mediatek/filogic/base-files/etc/hotplug.d/firmware/11-mt76-caldata b/target/linux/mediatek/filogic/base-files/etc/hotplug.d/firmware/11-mt76-caldata new file mode 100644 index 00000000000..0fe4c699887 --- /dev/null +++ b/target/linux/mediatek/filogic/base-files/etc/hotplug.d/firmware/11-mt76-caldata @@ -0,0 +1,21 @@ +#!/bin/sh + +[ -e /lib/firmware/$FIRMWARE ] && exit 0 + +. /lib/functions/caldata.sh + +board=$(board_name) + +case "$FIRMWARE" in +"mediatek/mt7986_eeprom_mt7976_dbdc.bin") + case "$board" in + asus,tuf-ax4200) + CI_UBIPART="UBI_DEV" + caldata_extract_ubi "Factory" 0x0 0x1000 + ;; + esac + ;; +*) + exit 1 + ;; +esac diff --git a/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac b/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac index fd822e3d4ce..ecaf2eadcdb 100644 --- a/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac +++ b/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac @@ -10,6 +10,15 @@ PHYNBR=${DEVPATH##*/phy} board=$(board_name) case "$board" in + asus,tuf-ax4200) + CI_UBIPART="UBI_DEV" + addr=$(mtd_get_mac_binary_ubi "Factory" 0x4) + # Originally, phy0 is phy1 mac with LA bit set. However, this would conflict + # addresses on mutiple VIFs with the other radio. Set LA bit and increment + # mac-address instead. + [ "$PHYNBR" = "0" ] && macaddr_setbit_la $(macaddr_add $addr 1) > /sys${DEVPATH}/macaddress + [ "$PHYNBR" = "1" ] && echo "$addr" > /sys${DEVPATH}/macaddress + ;; bananapi,bpi-r3) addr=$(macaddr_add $(cat /sys/class/net/eth0/address) 2) [ "$PHYNBR" = "0" ] && macaddr_unsetbit $addr 6 > /sys${DEVPATH}/macaddress diff --git a/target/linux/mediatek/filogic/base-files/lib/preinit/10_fix_eth_mac.sh b/target/linux/mediatek/filogic/base-files/lib/preinit/10_fix_eth_mac.sh new file mode 100644 index 00000000000..ec078741c98 --- /dev/null +++ b/target/linux/mediatek/filogic/base-files/lib/preinit/10_fix_eth_mac.sh @@ -0,0 +1,14 @@ +. /lib/functions/system.sh + +preinit_set_mac_address() { + case $(board_name) in + asus,tuf-ax4200) + CI_UBIPART="UBI_DEV" + addr=$(mtd_get_mac_binary_ubi "Factory" 0x4) + ip link set dev eth0 address "$addr" + ip link set dev eth1 address "$addr" + ;; + esac +} + +boot_hook_add preinit_main preinit_set_mac_address diff --git a/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh b/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh index 9a389d59b1d..ca097410308 100755 --- a/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh +++ b/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh @@ -42,6 +42,11 @@ platform_do_upgrade() { local board=$(board_name) case "$board" in + asus,tuf-ax4200) + CI_UBIPART="UBI_DEV" + CI_KERNPART="linux" + nand_do_upgrade "$1" + ;; bananapi,bpi-r3) local rootdev="$(cmdline_get_var root)" rootdev="${rootdev##*/}" diff --git a/target/linux/mediatek/image/filogic.mk b/target/linux/mediatek/image/filogic.mk index 5c223d04ff1..2e9becb241e 100644 --- a/target/linux/mediatek/image/filogic.mk +++ b/target/linux/mediatek/image/filogic.mk @@ -38,6 +38,24 @@ define Build/mt7986-gpt rm $@.tmp endef +define Device/asus_tuf-ax4200 + DEVICE_VENDOR := ASUS + DEVICE_MODEL := TUF-AX4200 + DEVICE_DTS := mt7986a-asus-tuf-ax4200 + DEVICE_DTS_DIR := ../dts + DEVICE_DTS_LOADADDR := 0x47000000 + DEVICE_PACKAGES := kmod-usb3 + IMAGES := sysupgrade.bin + KERNEL_LOADADDR := 0x48000000 + KERNEL = kernel-bin | lzma | \ + fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb + KERNEL_INITRAMFS := kernel-bin | lzma | \ + fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd | pad-to 64k + IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata +endef +TARGET_DEVICES += asus_tuf-ax4200 + + define Device/bananapi_bpi-r3 DEVICE_VENDOR := Bananapi DEVICE_MODEL := BPi-R3 From 67c28dde09b4ab370971b58e330842247cef0d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 25 Mar 2023 10:23:32 +0100 Subject: [PATCH 08/53] bmips: sercomm,h500-s: fix upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sercomm H500-s devices don't need the JFFS2 cleanmarkers as opposed to the other bmips NAND devices. Fixes: 6df12200d903 ("bmips: add support for Sercomm H-500s") Signed-off-by: Álvaro Fernández Rojas --- target/linux/bmips/nand/base-files/lib/upgrade/platform.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target/linux/bmips/nand/base-files/lib/upgrade/platform.sh b/target/linux/bmips/nand/base-files/lib/upgrade/platform.sh index 69901eb29c4..33217ed975b 100644 --- a/target/linux/bmips/nand/base-files/lib/upgrade/platform.sh +++ b/target/linux/bmips/nand/base-files/lib/upgrade/platform.sh @@ -47,9 +47,7 @@ platform_do_upgrade() { case "$(board_name)" in comtrend,vr-3032u|\ huawei,hg253s-v2|\ - netgear,dgnd3700-v2|\ - sercomm,h500-s-lowi|\ - sercomm,h500-s-vfes) + netgear,dgnd3700-v2) cfe_jffs2_nand_upgrade "$1" ;; *) From 21b89b06478c65122462813dcc3fe8bbb49cc53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 25 Mar 2023 10:33:06 +0100 Subject: [PATCH 09/53] kernel: backport dsa b53 patches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These patches have been merged upstream, so let's move them to backport. Signed-off-by: Álvaro Fernández Rojas --- ...dsa-b53-mmap-fix-device-tree-support.patch | 30 ++++ ...cm-legacy-fix-daisy-chained-switches.patch | 65 ++++++++ ...dsa-b53-mmap-fix-device-tree-support.patch | 104 ------------- ...cm-legacy-fix-daisy-chained-switches.patch | 140 ------------------ 4 files changed, 95 insertions(+), 244 deletions(-) create mode 100644 target/linux/generic/backport-5.15/743-v6.3-0005-net-dsa-b53-mmap-fix-device-tree-support.patch create mode 100644 target/linux/generic/backport-5.15/743-v6.3-0006-net-dsa-tag_brcm-legacy-fix-daisy-chained-switches.patch delete mode 100644 target/linux/generic/pending-5.15/770-net-dsa-b53-mmap-fix-device-tree-support.patch delete mode 100644 target/linux/generic/pending-5.15/771-net-dsa-tag_brcm-legacy-fix-daisy-chained-switches.patch diff --git a/target/linux/generic/backport-5.15/743-v6.3-0005-net-dsa-b53-mmap-fix-device-tree-support.patch b/target/linux/generic/backport-5.15/743-v6.3-0005-net-dsa-b53-mmap-fix-device-tree-support.patch new file mode 100644 index 00000000000..8c277e6a3ef --- /dev/null +++ b/target/linux/generic/backport-5.15/743-v6.3-0005-net-dsa-b53-mmap-fix-device-tree-support.patch @@ -0,0 +1,30 @@ +From 30796d0dcb6e41c6558a07950f2ce60c209da867 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Thu, 16 Mar 2023 18:28:07 +0100 +Subject: [PATCH] net: dsa: b53: mmap: fix device tree support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +CPU port should also be enabled in order to get a working switch. + +Fixes: a5538a777b73 ("net: dsa: b53: mmap: Add device tree support") +Signed-off-by: Álvaro Fernández Rojas +Acked-by: Florian Fainelli +Link: https://lore.kernel.org/r/20230316172807.460146-1-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_mmap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/b53/b53_mmap.c ++++ b/drivers/net/dsa/b53/b53_mmap.c +@@ -263,7 +263,7 @@ static int b53_mmap_probe_of(struct plat + if (of_property_read_u32(of_port, "reg", ®)) + continue; + +- if (reg < B53_CPU_PORT) ++ if (reg < B53_N_PORTS) + pdata->enabled_ports |= BIT(reg); + } + diff --git a/target/linux/generic/backport-5.15/743-v6.3-0006-net-dsa-tag_brcm-legacy-fix-daisy-chained-switches.patch b/target/linux/generic/backport-5.15/743-v6.3-0006-net-dsa-tag_brcm-legacy-fix-daisy-chained-switches.patch new file mode 100644 index 00000000000..fdefa9ffb69 --- /dev/null +++ b/target/linux/generic/backport-5.15/743-v6.3-0006-net-dsa-tag_brcm-legacy-fix-daisy-chained-switches.patch @@ -0,0 +1,65 @@ +From 032a954061afd4b7426c3eb6bfd2952ef1e9a384 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sun, 19 Mar 2023 10:55:40 +0100 +Subject: [PATCH] net: dsa: tag_brcm: legacy: fix daisy-chained switches +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When BCM63xx internal switches are connected to switches with a 4-byte +Broadcom tag, it does not identify the packet as VLAN tagged, so it adds one +based on its PVID (which is likely 0). +Right now, the packet is received by the BCM63xx internal switch and the 6-byte +tag is properly processed. The next step would to decode the corresponding +4-byte tag. However, the internal switch adds an invalid VLAN tag after the +6-byte tag and the 4-byte tag handling fails. +In order to fix this we need to remove the invalid VLAN tag after the 6-byte +tag before passing it to the 4-byte tag decoding. + +Fixes: 964dbf186eaa ("net: dsa: tag_brcm: add support for legacy tags") +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Michal Swiatkowski +Reviewed-by: Florian Fainelli +Link: https://lore.kernel.org/r/20230319095540.239064-1-noltari@gmail.com +Signed-off-by: Jakub Kicinski +--- + net/dsa/tag_brcm.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/net/dsa/tag_brcm.c ++++ b/net/dsa/tag_brcm.c +@@ -7,6 +7,7 @@ + + #include + #include ++#include + #include + #include + +@@ -248,6 +249,7 @@ static struct sk_buff *brcm_leg_tag_xmit + static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, + struct net_device *dev) + { ++ int len = BRCM_LEG_TAG_LEN; + int source_port; + u8 *brcm_tag; + +@@ -262,12 +264,16 @@ static struct sk_buff *brcm_leg_tag_rcv( + if (!skb->dev) + return NULL; + ++ /* VLAN tag is added by BCM63xx internal switch */ ++ if (netdev_uses_dsa(skb->dev)) ++ len += VLAN_HLEN; ++ + /* Remove Broadcom tag and update checksum */ +- skb_pull_rcsum(skb, BRCM_LEG_TAG_LEN); ++ skb_pull_rcsum(skb, len); + + dsa_default_offload_fwd_mark(skb); + +- dsa_strip_etype_header(skb, BRCM_LEG_TAG_LEN); ++ dsa_strip_etype_header(skb, len); + + return skb; + } diff --git a/target/linux/generic/pending-5.15/770-net-dsa-b53-mmap-fix-device-tree-support.patch b/target/linux/generic/pending-5.15/770-net-dsa-b53-mmap-fix-device-tree-support.patch deleted file mode 100644 index 50db56af274..00000000000 --- a/target/linux/generic/pending-5.15/770-net-dsa-b53-mmap-fix-device-tree-support.patch +++ /dev/null @@ -1,104 +0,0 @@ -From patchwork Thu Mar 16 17:28:07 2023 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 8bit -X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= - -X-Patchwork-Id: 13178135 -X-Patchwork-Delegate: kuba@kernel.org -Return-Path: -X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on - aws-us-west-2-korg-lkml-1.web.codeaurora.org -Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) - by smtp.lore.kernel.org (Postfix) with ESMTP id 9F385C6FD19 - for ; Thu, 16 Mar 2023 17:29:18 +0000 (UTC) -Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand - id S229918AbjCPR3Q (ORCPT ); - Thu, 16 Mar 2023 13:29:16 -0400 -Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44474 "EHLO - lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org - with ESMTP id S229902AbjCPR3G (ORCPT - ); Thu, 16 Mar 2023 13:29:06 -0400 -Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com - [IPv6:2a00:1450:4864:20::433]) - by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DB3CC1D929; - Thu, 16 Mar 2023 10:29:03 -0700 (PDT) -Received: by mail-wr1-x433.google.com with SMTP id y14so2246984wrq.4; - Thu, 16 Mar 2023 10:29:03 -0700 (PDT) -DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; - d=gmail.com; s=20210112; t=1678987742; - h=content-transfer-encoding:mime-version:references:in-reply-to - :message-id:date:subject:cc:to:from:from:to:cc:subject:date - :message-id:reply-to; - bh=n/Cr1XNCJNfBa+dPDtalOZXIIV6S3ucGcQ6qFqXXuSc=; - b=Ka0GgVg9azCPEBkuB0FcSt9tMYqZVblZJl1uT4KWVRAEgVcgqi44vSYpvlzc3TfFMI - Ulqrk15TYN022WhQxI63v/NQum/s+yKg2G7wZYj2wHxsGAaoaLtFw8lsjoqTx8NZjsXO - OIlTQqkyvDBE4t4FkO9w47A9Q2ruNzohH7Mng3Kraup/9Wyb3PGdybj/sC9/Pvnw6aPz - 4Ep0ufMhgNjCk8X2buy346Tcow1zyQVQeGAZrxQzPbWcwa5rFbWGv6iD4wYbHKYm/DZV - ah4lc+p0anRvAsNDlqj9fa+VY96nD4X/R7q5M3u7jTEL5YPvrOH5a8y5P5c92mWXiI7i - RABA== -X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; - d=1e100.net; s=20210112; t=1678987742; - h=content-transfer-encoding:mime-version:references:in-reply-to - :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc - :subject:date:message-id:reply-to; - bh=n/Cr1XNCJNfBa+dPDtalOZXIIV6S3ucGcQ6qFqXXuSc=; - b=RnTP/w7AloNUBWmU5C26i+lQQMLIbND8o8gY/M87Dw22DuDdCIQQxRQypN9pzW4fmS - VfNg/kh5Hydzm2bSw7AXMtT0hrbTfBZr2sB6BEKlojw3txmRVCoDGvlZLhTCRtPYGECX - WqK1d37sgZ+bBEtjsPfCoVxdLpMCAjxlzLTCnwIclXsHLJg6Tsup33wu6kCFaQz1GYi1 - hDlc0KC9TZBXr0+3kzzXVyp0X3P30TlAamlojgoi44oa8246DcMBMtsbhiRPLUsdcIfs - k+UDK2IemrCvgh5hfN3tX/DtwzoOxPjmB2FZjdxi7+6+c/abS5IYjQ8I1b30JOzDZeMs - E6nA== -X-Gm-Message-State: AO0yUKXFx+XUMUlLCdoCi82z77K5Ax1VNa78esJmOz5Jv6sQIYmKTgvD - VrU+Kl3YdJgxxLbxpm1e8RI= -X-Google-Smtp-Source: - AK7set8fFjLrpZ1Ll4TW9iTex7qD+OJccAtDrfibvtBWYkVr0jRxWbwBsrVExeDl051bEIdDmJrszQ== -X-Received: by 2002:a5d:61c7:0:b0:2ce:a697:75c7 with SMTP id - q7-20020a5d61c7000000b002cea69775c7mr4660631wrv.33.1678987742168; - Thu, 16 Mar 2023 10:29:02 -0700 (PDT) -Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. - [79.146.124.255]) - by smtp.gmail.com with ESMTPSA id - n7-20020a5d4847000000b002c5d3f0f737sm7719124wrs.30.2023.03.16.10.29.01 - (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); - Thu, 16 Mar 2023 10:29:01 -0700 (PDT) -From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= -To: f.fainelli@gmail.com, jonas.gorski@gmail.com, andrew@lunn.ch, - olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, - kuba@kernel.org, pabeni@redhat.com, netdev@vger.kernel.org, - linux-kernel@vger.kernel.org -Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= -Subject: [PATCH v2] net: dsa: b53: mmap: fix device tree support -Date: Thu, 16 Mar 2023 18:28:07 +0100 -Message-Id: <20230316172807.460146-1-noltari@gmail.com> -X-Mailer: git-send-email 2.30.2 -In-Reply-To: <20230310121059.4498-1-noltari@gmail.com> -References: <20230310121059.4498-1-noltari@gmail.com> -MIME-Version: 1.0 -Precedence: bulk -List-ID: -X-Mailing-List: netdev@vger.kernel.org -X-Patchwork-Delegate: kuba@kernel.org - -CPU port should also be enabled in order to get a working switch. - -Fixes: a5538a777b73 ("net: dsa: b53: mmap: Add device tree support") -Signed-off-by: Álvaro Fernández Rojas -Acked-by: Florian Fainelli ---- - v2: switch to B53_N_PORTS - - drivers/net/dsa/b53/b53_mmap.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/dsa/b53/b53_mmap.c -+++ b/drivers/net/dsa/b53/b53_mmap.c -@@ -263,7 +263,7 @@ static int b53_mmap_probe_of(struct plat - if (of_property_read_u32(of_port, "reg", ®)) - continue; - -- if (reg < B53_CPU_PORT) -+ if (reg < B53_N_PORTS) - pdata->enabled_ports |= BIT(reg); - } - diff --git a/target/linux/generic/pending-5.15/771-net-dsa-tag_brcm-legacy-fix-daisy-chained-switches.patch b/target/linux/generic/pending-5.15/771-net-dsa-tag_brcm-legacy-fix-daisy-chained-switches.patch deleted file mode 100644 index 6c79bffdf41..00000000000 --- a/target/linux/generic/pending-5.15/771-net-dsa-tag_brcm-legacy-fix-daisy-chained-switches.patch +++ /dev/null @@ -1,140 +0,0 @@ -From patchwork Sun Mar 19 09:55:40 2023 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 8bit -X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= - -X-Patchwork-Id: 13180301 -X-Patchwork-Delegate: kuba@kernel.org -Return-Path: -X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on - aws-us-west-2-korg-lkml-1.web.codeaurora.org -Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) - by smtp.lore.kernel.org (Postfix) with ESMTP id 59CF8C7618A - for ; Sun, 19 Mar 2023 09:55:59 +0000 (UTC) -Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand - id S229723AbjCSJzz (ORCPT ); - Sun, 19 Mar 2023 05:55:55 -0400 -Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33746 "EHLO - lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org - with ESMTP id S229468AbjCSJzv (ORCPT - ); Sun, 19 Mar 2023 05:55:51 -0400 -Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com - [IPv6:2a00:1450:4864:20::333]) - by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 83BCD23A6E; - Sun, 19 Mar 2023 02:55:49 -0700 (PDT) -Received: by mail-wm1-x333.google.com with SMTP id - l15-20020a05600c4f0f00b003ed58a9a15eso5776403wmq.5; - Sun, 19 Mar 2023 02:55:49 -0700 (PDT) -DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; - d=gmail.com; s=20210112; t=1679219748; - h=content-transfer-encoding:mime-version:references:in-reply-to - :message-id:date:subject:cc:to:from:from:to:cc:subject:date - :message-id:reply-to; - bh=yaNuTTfeHI1WnGa3QC7carZ37ibM4EyUyUnDDBSr6nM=; - b=bTf0pdvAUXMqrJw4A+PLFfwONMAaXL3S4GDMJH3tYgRz/0Vpy7FkmgpWveMhjrqiDM - O6v17DizCYtzUrLXC9z9mMD3F8tl0SETaor8aE/MtvnxVq/Yq80WT5xnEh0iJBhWnRP1 - 0ZKyuoqWZQPnQ9vXbctEu3ZPxub9szdfmxWCtutESvAIvY7Y1qt4ZGg4ZDexov88P4lN - pgP6KaBNSVKSsVlDL4ukHqWyrkzpPtcOmDrPC8/HUTsraFnQ4iOL8vVR2Q26qKf2JI6m - yKwAd88ZKSnFRAyGdXAoXqiAKkcmDW5523samaxmBI23gxG5ryD3JnZBlo5r55gnPGo9 - C0uQ== -X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; - d=1e100.net; s=20210112; t=1679219748; - h=content-transfer-encoding:mime-version:references:in-reply-to - :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc - :subject:date:message-id:reply-to; - bh=yaNuTTfeHI1WnGa3QC7carZ37ibM4EyUyUnDDBSr6nM=; - b=buUr8oNY3Rb4YRuvXOFLPRXT0v9e8f87X1i1bsLfYPL/CokAJIhwAaChGjvMN1l3zP - YCfM9Xynl3tF3k4nrb1xKGmc7LuHONe8KjOgFgFuvtepBg7uvBdwi7A3UmbznhgUpzlo - HE7X3S5dfDNX/LLwpOyWM34Hk+w6i6pXP2FD7CB/1TwvdZFjnPHbhDhQTnJQNFaFmXz2 - d4WxBzxqU6k+4PC4AHRhGkn8QunICQ90MDk9NgNtuT5E1tTh5Bz4ykQ95sKKeTih3OBO - sx0mBrCqsTwpteTweNvnMuoOxmyKbM8Ca8cwS1QpfIWI0ASy+j7j2SiTG7nrKl2hUJTW - heAQ== -X-Gm-Message-State: AO0yUKWVY0SzDxRYNSJrKpnV6m176lCPK8B2N12aX56FfpuGNCuaPAmf - wYaBrXYVORDSYFVtNsY7gc3xMZp1z+ba7A== -X-Google-Smtp-Source: - AK7set8q+UMyrNpNNfcRo8o3ynviTGRk1oKu2CmzwYJVZxCAYYvXmLtyXvhcnqpBROVi7Kj+1rKDuw== -X-Received: by 2002:a05:600c:4f50:b0:3ed:4b0f:5378 with SMTP id - m16-20020a05600c4f5000b003ed4b0f5378mr11519857wmq.27.1679219747816; - Sun, 19 Mar 2023 02:55:47 -0700 (PDT) -Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. - [79.146.124.255]) - by smtp.gmail.com with ESMTPSA id - i26-20020a1c541a000000b003ed246f76a2sm13390609wmb.1.2023.03.19.02.55.46 - (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); - Sun, 19 Mar 2023 02:55:47 -0700 (PDT) -From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= -To: andrew@lunn.ch, f.fainelli@gmail.com, jonas.gorski@gmail.com, - olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, - kuba@kernel.org, pabeni@redhat.com, netdev@vger.kernel.org, - linux-kernel@vger.kernel.org -Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= , - Michal Swiatkowski -Subject: [PATCH v2] net: dsa: tag_brcm: legacy: fix daisy-chained switches -Date: Sun, 19 Mar 2023 10:55:40 +0100 -Message-Id: <20230319095540.239064-1-noltari@gmail.com> -X-Mailer: git-send-email 2.30.2 -In-Reply-To: <20230317120815.321871-1-noltari@gmail.com> -References: <20230317120815.321871-1-noltari@gmail.com> -MIME-Version: 1.0 -Precedence: bulk -List-ID: -X-Mailing-List: netdev@vger.kernel.org -X-Patchwork-Delegate: kuba@kernel.org - -When BCM63xx internal switches are connected to switches with a 4-byte -Broadcom tag, it does not identify the packet as VLAN tagged, so it adds one -based on its PVID (which is likely 0). -Right now, the packet is received by the BCM63xx internal switch and the 6-byte -tag is properly processed. The next step would to decode the corresponding -4-byte tag. However, the internal switch adds an invalid VLAN tag after the -6-byte tag and the 4-byte tag handling fails. -In order to fix this we need to remove the invalid VLAN tag after the 6-byte -tag before passing it to the 4-byte tag decoding. - -Fixes: 964dbf186eaa ("net: dsa: tag_brcm: add support for legacy tags") -Signed-off-by: Álvaro Fernández Rojas -Reviewed-by: Michal Swiatkowski ---- - v2: add missing fixes tag. - - net/dsa/tag_brcm.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - ---- a/net/dsa/tag_brcm.c -+++ b/net/dsa/tag_brcm.c -@@ -7,6 +7,7 @@ - - #include - #include -+#include - #include - #include - -@@ -248,6 +249,7 @@ static struct sk_buff *brcm_leg_tag_xmit - static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, - struct net_device *dev) - { -+ int len = BRCM_LEG_TAG_LEN; - int source_port; - u8 *brcm_tag; - -@@ -262,12 +264,16 @@ static struct sk_buff *brcm_leg_tag_rcv( - if (!skb->dev) - return NULL; - -+ /* VLAN tag is added by BCM63xx internal switch */ -+ if (netdev_uses_dsa(skb->dev)) -+ len += VLAN_HLEN; -+ - /* Remove Broadcom tag and update checksum */ -- skb_pull_rcsum(skb, BRCM_LEG_TAG_LEN); -+ skb_pull_rcsum(skb, len); - - dsa_default_offload_fwd_mark(skb); - -- dsa_strip_etype_header(skb, BRCM_LEG_TAG_LEN); -+ dsa_strip_etype_header(skb, len); - - return skb; - } From 09115a17058125e1683d90db38dd7b80541f3964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 25 Mar 2023 10:35:19 +0100 Subject: [PATCH 10/53] kernel: refresh mxl-gpy LED patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the patches apply cleanly again. Fixes: 90691f450543 ("generic: mxl-gpy: allow configuring LED registers") Signed-off-by: Álvaro Fernández Rojas --- .../hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/target/linux/generic/hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch b/target/linux/generic/hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch index 75014c05283..8de3668def2 100644 --- a/target/linux/generic/hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch +++ b/target/linux/generic/hack-5.15/765-mxl-gpy-control-LED-reg-from-DT.patch @@ -21,8 +21,6 @@ Signed-off-by: David Bauer drivers/net/phy/mxl-gpy.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) -diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c -index 5ce1bf03bbd7..ec10ad5ccad6 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -8,6 +8,7 @@ @@ -89,7 +87,7 @@ index 5ce1bf03bbd7..ec10ad5ccad6 100644 static int gpy_config_init(struct phy_device *phydev) { int ret; -@@ -91,7 +123,10 @@ static int gpy_config_init(struct phy_device *phydev) +@@ -91,7 +123,10 @@ static int gpy_config_init(struct phy_de /* Clear all pending interrupts */ ret = phy_read(phydev, PHY_ISTAT); @@ -101,6 +99,3 @@ index 5ce1bf03bbd7..ec10ad5ccad6 100644 } static int gpy_probe(struct phy_device *phydev) --- -2.39.2 - From 95cae498b6ab4613a0b4915393c798c750dac396 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 25 Mar 2023 11:58:19 +0100 Subject: [PATCH 11/53] kernel: fix mtk flow offload list corruption issue with l2 flows The same node was accidentally used for two different lists, causing an invalid pointer chain. Signed-off-by: Felix Fietkau --- ..._eth_soc-improve-keeping-track-of-of.patch | 49 +++++++++++++------ ...iatek-fix-ppe-flow-accounting-for-L2.patch | 24 ++++----- ..._eth_soc-add-missing-ppe-cache-flush.patch | 2 +- ...iatek-fix-ppe-flow-accounting-for-v1.patch | 4 +- 4 files changed, 48 insertions(+), 31 deletions(-) diff --git a/target/linux/generic/pending-5.15/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch b/target/linux/generic/pending-5.15/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch index f43d15d1149..29d6e0b0991 100644 --- a/target/linux/generic/pending-5.15/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch +++ b/target/linux/generic/pending-5.15/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -466,26 +466,30 @@ int mtk_foe_entry_set_queue(struct mtk_e +@@ -466,42 +466,43 @@ int mtk_foe_entry_set_queue(struct mtk_e return 0; } @@ -51,15 +51,17 @@ Signed-off-by: Felix Fietkau +__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + bool set_state) { - struct hlist_head *head; +- struct hlist_head *head; struct hlist_node *tmp; -@@ -495,13 +499,12 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + + if (entry->type == MTK_FLOW_TYPE_L2) { + rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, mtk_flow_l2_ht_params); - head = &entry->l2_flows; +- head = &entry->l2_flows; - hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) - __mtk_foe_entry_clear(ppe, entry); -+ hlist_for_each_entry_safe(entry, tmp, head, list) ++ hlist_for_each_entry_safe(entry, tmp, &entry->l2_flows, l2_list) + __mtk_foe_entry_clear(ppe, entry, set_state); return; } @@ -70,16 +72,17 @@ Signed-off-by: Felix Fietkau struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); hwe->ib1 &= ~MTK_FOE_IB1_STATE; -@@ -520,7 +523,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp +@@ -520,7 +521,8 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) return; - hlist_del_init(&entry->l2_data.list); ++ hlist_del_init(&entry->l2_list); + hlist_del_init(&entry->list); kfree(entry); } -@@ -536,66 +539,55 @@ static int __mtk_foe_entry_idle_time(str +@@ -536,66 +538,55 @@ static int __mtk_foe_entry_idle_time(str return now - timestamp; } @@ -118,7 +121,7 @@ Signed-off-by: Felix Fietkau idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); - hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { -+ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, list) { ++ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { int cur_idle; - u32 ib1; - @@ -175,7 +178,7 @@ Signed-off-by: Felix Fietkau } static void -@@ -632,7 +624,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -632,7 +623,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { spin_lock_bh(&ppe_lock); @@ -185,7 +188,7 @@ Signed-off-by: Felix Fietkau spin_unlock_bh(&ppe_lock); } -@@ -679,8 +672,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ +@@ -679,8 +671,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ { const struct mtk_soc_data *soc = ppe->eth->soc; struct mtk_flow_entry *flow_info; @@ -195,7 +198,7 @@ Signed-off-by: Felix Fietkau u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; int type; -@@ -688,30 +681,30 @@ mtk_foe_entry_commit_subflow(struct mtk_ +@@ -688,30 +680,30 @@ mtk_foe_entry_commit_subflow(struct mtk_ if (!flow_info) return; @@ -205,7 +208,7 @@ Signed-off-by: Felix Fietkau hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / soc->hash_offset]); - hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); -+ hlist_add_head(&flow_info->list, &entry->l2_flows); ++ hlist_add_head(&flow_info->l2_list, &entry->l2_flows); hwe = mtk_foe_get_entry(ppe, hash); - memcpy(&foe, hwe, soc->foe_entry_size); @@ -236,7 +239,7 @@ Signed-off-by: Felix Fietkau } void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) -@@ -721,9 +714,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe +@@ -721,9 +713,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); struct mtk_flow_entry *entry; struct mtk_foe_bridge key = {}; @@ -248,7 +251,7 @@ Signed-off-by: Felix Fietkau u8 *tag; spin_lock_bh(&ppe_lock); -@@ -731,20 +726,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe +@@ -731,20 +725,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) goto out; @@ -275,7 +278,7 @@ Signed-off-by: Felix Fietkau continue; } -@@ -795,9 +784,17 @@ out: +@@ -795,9 +783,17 @@ out: int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { @@ -297,7 +300,21 @@ Signed-off-by: Felix Fietkau int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) --- a/drivers/net/ethernet/mediatek/mtk_ppe.h +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -275,13 +275,7 @@ struct mtk_flow_entry { +@@ -265,7 +265,12 @@ enum { + + struct mtk_flow_entry { + union { +- struct hlist_node list; ++ /* regular flows + L2 subflows */ ++ struct { ++ struct hlist_node list; ++ struct hlist_node l2_list; ++ }; ++ /* L2 flows */ + struct { + struct rhash_head l2_node; + struct hlist_head l2_flows; +@@ -275,13 +280,7 @@ struct mtk_flow_entry { s8 wed_index; u8 ppe_index; u16 hash; diff --git a/target/linux/generic/pending-5.15/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch b/target/linux/generic/pending-5.15/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch index 43be09102e6..fdc3d520c11 100644 --- a/target/linux/generic/pending-5.15/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch +++ b/target/linux/generic/pending-5.15/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch @@ -77,7 +77,7 @@ Signed-off-by: Felix Fietkau } static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) -@@ -510,13 +525,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp +@@ -508,13 +523,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp hwe->ib1 &= ~MTK_FOE_IB1_STATE; hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); dma_wmb(); @@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau } entry->hash = 0xffff; -@@ -540,11 +548,14 @@ static int __mtk_foe_entry_idle_time(str +@@ -539,11 +547,14 @@ static int __mtk_foe_entry_idle_time(str } static bool @@ -107,7 +107,7 @@ Signed-off-by: Felix Fietkau int len; if (hash == 0xffff) -@@ -555,18 +566,35 @@ mtk_flow_entry_update(struct mtk_ppe *pp +@@ -554,18 +565,35 @@ mtk_flow_entry_update(struct mtk_ppe *pp memcpy(&foe, hwe, len); if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || @@ -146,8 +146,8 @@ Signed-off-by: Felix Fietkau struct mtk_flow_entry *cur; struct hlist_node *tmp; int idle; -@@ -575,7 +603,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe - hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, list) { +@@ -574,7 +602,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe + hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { int cur_idle; - if (!mtk_flow_entry_update(ppe, cur)) { @@ -157,7 +157,7 @@ Signed-off-by: Felix Fietkau __mtk_foe_entry_clear(ppe, entry, false); continue; } -@@ -590,10 +620,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe +@@ -589,10 +619,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe } } @@ -187,7 +187,7 @@ Signed-off-by: Felix Fietkau struct mtk_eth *eth = ppe->eth; u16 timestamp = mtk_eth_timestamp(eth); struct mtk_foe_entry *hwe; -@@ -618,6 +667,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -617,6 +666,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *p dma_wmb(); @@ -200,7 +200,7 @@ Signed-off-by: Felix Fietkau mtk_ppe_cache_clear(ppe); } -@@ -782,21 +837,6 @@ out: +@@ -781,21 +836,6 @@ out: spin_unlock_bh(&ppe_lock); } @@ -222,7 +222,7 @@ Signed-off-by: Felix Fietkau int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) { if (!ppe) -@@ -824,32 +864,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe +@@ -823,32 +863,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe return mtk_ppe_wait_busy(ppe); } @@ -257,7 +257,7 @@ Signed-off-by: Felix Fietkau bool accounting = eth->soc->has_accounting; --- a/drivers/net/ethernet/mediatek/mtk_ppe.h +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -278,6 +278,8 @@ struct mtk_flow_entry { +@@ -283,6 +283,8 @@ struct mtk_flow_entry { struct mtk_foe_entry data; struct rhash_head node; unsigned long cookie; @@ -266,7 +266,7 @@ Signed-off-by: Felix Fietkau }; struct mtk_mib_entry { -@@ -320,6 +322,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ +@@ -325,6 +327,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ void mtk_ppe_start(struct mtk_ppe *ppe); int mtk_ppe_stop(struct mtk_ppe *ppe); int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); @@ -274,7 +274,7 @@ Signed-off-by: Felix Fietkau void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); -@@ -368,9 +371,8 @@ int mtk_foe_entry_set_queue(struct mtk_e +@@ -373,9 +376,8 @@ int mtk_foe_entry_set_queue(struct mtk_e unsigned int queue); int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); diff --git a/target/linux/generic/pending-5.15/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch b/target/linux/generic/pending-5.15/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch index 0b876acacf7..30839319c7d 100644 --- a/target/linux/generic/pending-5.15/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch +++ b/target/linux/generic/pending-5.15/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -525,6 +525,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp +@@ -523,6 +523,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp hwe->ib1 &= ~MTK_FOE_IB1_STATE; hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); dma_wmb(); diff --git a/target/linux/generic/pending-5.15/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch b/target/linux/generic/pending-5.15/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch index c3d6dd4bbbf..3dfa193e707 100644 --- a/target/linux/generic/pending-5.15/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch +++ b/target/linux/generic/pending-5.15/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -647,6 +647,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -646,6 +646,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *p struct mtk_eth *eth = ppe->eth; u16 timestamp = mtk_eth_timestamp(eth); struct mtk_foe_entry *hwe; @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP_V2; -@@ -663,8 +664,13 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -662,8 +663,13 @@ __mtk_foe_entry_commit(struct mtk_ppe *p wmb(); hwe->ib1 = entry->ib1; From d59d69f9e1cb5bb8a11aba023b09550bc9c0ed35 Mon Sep 17 00:00:00 2001 From: John Audia Date: Sat, 18 Mar 2023 12:46:48 -0400 Subject: [PATCH 12/53] kernel: bump 5.15 to 5.15.103 Manually rebased: backport-5.15/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch Removed upstreamed: backport-5.15/060-v6.0-01-tools-build-Add-feature-test-for-init_disassemble_in.patch[1] backport-5.15/060-v6.0-02-tools-include-add-dis-asm-compat.h-to-handle-version.patch[2] backport-5.15/060-v6.0-03-tools-perf-Fix-compilation-error-with-new-binutils.patch[3] backport-5.15/060-v6.0-04-tools-bpf_jit_disasm-Fix-compilation-error-with-new-.patch[4] backport-5.15/060-v6.0-05-tools-bpftool-Fix-compilation-error-with-new-binutil.patch[5] pending-5.15/733-02-net-ethernet-mtk_eth_soc-fix-RX-data-corruption-issu.patch[6] bcm47xx/patches-5.15/170-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch[7] All other patches automatically rebased. 1. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.15.103&id=51b99dc38c1a053e2e732d7f9e2740e343ae7eae 2. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.15.103&id=451c9d7b16169645ed291ebb2ca9844caa088f2d 3. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.15.103&id=97f005c0bdbaf656a7808586d234965385a06c58 4. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.15.103&id=1c27fab243333821375e4d63128d60093fdbe149 5. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.15.103&id=4441a90091931fd81607567961dc122f24f735bb 6. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.15.103&id=2adc29350a5b4669544566f71f208d2abaec60ab 7. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=v5.15.103&id=04bfc5bcdfc0fdb73587487c71b04d63807ae15a Build system: x86_64 Build-tested: bcm2711/RPi4B, ramips/tplink_archer-a6-v3, filogic/xiaomi_redmi-router-ax6000-ubootmod Run-tested: bcm2711/RPi4B, ramips/tplink_archer-a6-v3, filogic/xiaomi_redmi-router-ax6000-ubootmod Signed-off-by: John Audia --- include/kernel-5.15 | 4 +- ...8xx-Enable-LEDs-and-auto-negotiation.patch | 6 +- ...78xx-Read-initial-EEE-status-from-DT.patch | 2 +- ...Disable-TCP-Segmentation-Offload-TSO.patch | 2 +- ...e-enabling-of-EEE-into-PHY-init-code.patch | 4 +- ...e-link-events-to-minimize-poll-storm.patch | 2 +- ...xx-EEE-support-is-now-a-PHY-property.patch | 2 +- ...use-default-alignment-for-rx-buffers.patch | 2 +- ...87xx-Allow-more-time-for-link-detect.patch | 2 +- ...hy-lan87xx-Decrease-phy-polling-rate.patch | 6 +- ...nitial-chip-reset-to-support-BCM5358.patch | 76 ------- ...feature-test-for-init_disassemble_in.patch | 95 --------- ...d-dis-asm-compat.h-to-handle-version.patch | 96 --------- ...-compilation-error-with-new-binutils.patch | 111 ---------- ...sasm-Fix-compilation-error-with-new-.patch | 102 --------- ...x-compilation-error-with-new-binutil.patch | 146 ------------- ..._eth_soc-add-support-for-coherent-DM.patch | 46 ++--- ..._eth_soc-add-support-for-Wireless-Et.patch | 2 +- ..._eth_soc-allocate-struct-mtk_ppe-sep.patch | 8 +- ..._eth_soc-rework-hardware-flow-table-.patch | 6 +- ..._eth_soc-use-standard-property-for-c.patch | 2 +- ..._eth_soc-rely-on-GFP_KERNEL-for-dma_.patch | 8 +- ..._eth_soc-move-tx-dma-desc-configurat.patch | 10 +- ..._eth_soc-add-txd_size-to-mtk_soc_dat.patch | 24 +-- ..._eth_soc-rely-on-txd_size-in-mtk_tx_.patch | 10 +- ..._eth_soc-rely-on-txd_size-in-mtk_des.patch | 18 +- ..._eth_soc-rely-on-txd_size-in-txd_to_.patch | 4 +- ..._eth_soc-add-rxd_size-to-mtk_soc_dat.patch | 20 +- ..._eth_soc-rely-on-txd_size-field-in-m.patch | 6 +- ..._eth_soc-rely-on-rxd_size-field-in-m.patch | 4 +- ..._eth_soc-introduce-device-register-m.patch | 80 ++++---- ..._eth_soc-introduce-MTK_NETSYS_V2-sup.patch | 94 ++++----- ..._eth_soc-convert-ring-dma-pointer-to.patch | 22 +- ..._eth_soc-convert-scratch_ring-pointe.patch | 4 +- ..._eth_soc-introduce-support-for-mt798.patch | 10 +- ..._eth_soc-enable-rx-cksum-offload-for.patch | 6 +- ...populate-supported_interfaces-member.patch | 2 +- ...remove-interface-checks-in-mtk_valid.patch | 6 +- ...drop-use-of-phylink_helper_basex_spe.patch | 4 +- ...eth_soc-use-phylink_generic_validate.patch | 4 +- ...mark-as-a-legacy_pre_march2020-drive.patch | 2 +- ...remove-a-copy-of-the-NAPI_POLL_WEIGH.patch | 2 +- ...9-mtk_eth_soc-remove-unused-mac-mode.patch | 4 +- ...tk_eth_soc-remove-unused-sgmii-flags.patch | 2 +- ...add-mask-and-update-PCS-speed-defini.patch | 2 +- ...th_soc-correct-802.3z-duplex-setting.patch | 6 +- ...stop-passing-phylink-state-to-sgmii-.patch | 2 +- ...mtk_eth_soc-provide-mtk_sgmii_config.patch | 2 +- ...c-move-MAC_MCR-setting-to-mac_finish.patch | 66 +++--- ...move-restoration-of-SYSCFG0-to-mac_f.patch | 2 +- ...convert-code-structure-to-suit-split.patch | 2 +- ...soc-partially-convert-to-phylink_pcs.patch | 10 +- ...terate-using-dsa_switch_for_each_use.patch | 4 +- ...opulate-supported_interfaces-and-mac.patch | 16 +- ...t-dsa-mt7530-remove-interface-checks.patch | 16 +- ...rop-use-of-phylink_helper_basex_spee.patch | 2 +- ...nly-indicate-linkmodes-that-can-be-s.patch | 6 +- ...-switch-to-use-phylink_get_linkmodes.patch | 12 +- ...530-partially-convert-to-phylink_pcs.patch | 30 +-- ...ove-autoneg-handling-to-PCS-validati.patch | 6 +- ...19-net-dsa-mt7530-mark-as-non-legacy.patch | 2 +- ...mt753x-fix-pcs-conversion-regression.patch | 4 +- ...t7530-rework-mt7530_hw_vlan_-add-del.patch | 6 +- ...et-dsa-mt7530-rework-mt753-01-_setup.patch | 8 +- ...et-cpu-port-via-dp-cpu_dp-instead-of.patch | 16 +- ..._eth_soc-rely-on-page_pool-for-singl.patch | 22 +- ...et-mtk_eth_soc-add-basic-XDP-support.patch | 26 +-- ..._eth_soc-introduce-xdp-ethtool-count.patch | 10 +- ...net-mtk_eth_soc-add-xmit-XDP-support.patch | 28 +-- ..._eth_soc-add-support-for-page_pool_g.patch | 6 +- ..._eth_soc-introduce-mtk_xdp_frame_map.patch | 6 +- ..._eth_soc-introduce-xdp-multi-frag-su.patch | 12 +- ..._eth_soc-fix-hw-hash-reporting-for-M.patch | 4 +- ..._eth_soc-enable-XDP-support-just-for.patch | 2 +- ..._eth_soc-move-gdma_to_ppe-and-ppe_ba.patch | 8 +- ..._eth_soc-move-ppe-table-hash-offset-.patch | 12 +- ..._eth_soc-add-the-capability-to-run-m.patch | 14 +- ..._eth_soc-move-wdma_base-definitions-.patch | 4 +- ..._eth_soc-add-foe_entry_size-to-mtk_e.patch | 12 +- ..._eth_wed-add-wed-support-for-mt7986-.patch | 4 +- ..._eth_soc-introduce-flow-offloading-s.patch | 14 +- ..._eth_soc-enable-flow-offloading-supp.patch | 2 +- ..._eth_soc-fix-possible-memory-leak-in.patch | 8 +- ..._eth_soc-do-not-overwrite-mtu-config.patch | 8 +- ..._eth_soc-remove-cpu_relax-in-mtk_pen.patch | 4 +- ..._eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch | 4 +- ..._eth_soc-introduce-mtk_hw_reset-util.patch | 4 +- ..._eth_soc-introduce-mtk_hw_warm_reset.patch | 8 +- ..._eth_soc-align-reset-procedure-to-ve.patch | 10 +- ..._eth_soc-add-dma-checks-to-mtk_hw_re.patch | 18 +- ..._wed-add-reset-reset_complete-callba.patch | 4 +- ..._eth_soc-increase-tx-ring-side-for-Q.patch | 14 +- ..._eth_soc-avoid-port_mg-assignment-on.patch | 4 +- ..._eth_soc-implement-multi-queue-suppo.patch | 68 +++--- ..._eth_soc-compile-out-netsys-v2-code-.patch | 2 +- ..._eth_soc-fix-VLAN-rx-hardware-accele.patch | 12 +- ..._eth_soc-drop-packets-to-WDMA-if-the.patch | 2 +- ..._eth_soc-disable-hardware-DSA-untagg.patch | 4 +- ..._eth_soc-enable-special-tag-when-any.patch | 6 +- ..._eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch | 4 +- ...ii-ensure-the-SGMII-PHY-is-powered-d.patch | 2 +- ...iatek-sgmii-fix-duplex-configuration.patch | 2 +- ...icro-stmmac-move-queue-reset-to-dedi.patch | 16 +- ...icro-stmmac-first-disable-all-queues.patch | 4 +- ...icro-stmmac-move-dma-conf-to-dedicat.patch | 194 +++++++++--------- ...icro-stmmac-generate-stmmac-dma-conf.patch | 114 +++++----- ...icro-stmmac-permit-MTU-change-with-i.patch | 4 +- ...-add-support-for-in-band-link-status.patch | 12 +- .../hack-5.15/221-module_exports.patch | 2 +- .../hack-5.15/773-bgmac-add-srab-switch.patch | 10 +- .../generic/hack-5.15/902-debloat_proc.patch | 2 +- ...net-mtk_eth_soc-enable-threaded-NAPI.patch | 6 +- ...e-all-MACs-are-powered-down-before-r.patch | 2 +- ...iatek-ppe-add-support-for-flow-accou.patch | 12 +- ..._eth_soc-drop-generic-vlan-rx-offloa.patch | 14 +- ..._eth_soc-work-around-issue-with-send.patch | 6 +- ...ethernet-mtk_eth_soc-reset-PCS-state.patch | 2 +- ..._eth_soc-fix-RX-data-corruption-issu.patch | 46 ----- ..._eth_soc-implement-Clause-45-MDIO-ac.patch | 2 +- ...ethernet-mediatek-support-net-labels.patch | 4 +- 120 files changed, 721 insertions(+), 1393 deletions(-) delete mode 100644 target/linux/bcm47xx/patches-5.15/170-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch delete mode 100644 target/linux/generic/backport-5.15/060-v6.0-01-tools-build-Add-feature-test-for-init_disassemble_in.patch delete mode 100644 target/linux/generic/backport-5.15/060-v6.0-02-tools-include-add-dis-asm-compat.h-to-handle-version.patch delete mode 100644 target/linux/generic/backport-5.15/060-v6.0-03-tools-perf-Fix-compilation-error-with-new-binutils.patch delete mode 100644 target/linux/generic/backport-5.15/060-v6.0-04-tools-bpf_jit_disasm-Fix-compilation-error-with-new-.patch delete mode 100644 target/linux/generic/backport-5.15/060-v6.0-05-tools-bpftool-Fix-compilation-error-with-new-binutil.patch delete mode 100644 target/linux/generic/pending-5.15/733-02-net-ethernet-mtk_eth_soc-fix-RX-data-corruption-issu.patch diff --git a/include/kernel-5.15 b/include/kernel-5.15 index c50a5eb61fa..16eabc74ded 100644 --- a/include/kernel-5.15 +++ b/include/kernel-5.15 @@ -1,2 +1,2 @@ -LINUX_VERSION-5.15 = .102 -LINUX_KERNEL_HASH-5.15.102 = 441cddfb970b97759eebdb9b142673662ce0770500e3ae8bcd4b90af369b01e6 +LINUX_VERSION-5.15 = .103 +LINUX_KERNEL_HASH-5.15.103 = 0876ba81631cca532f72a8d633f7031c3068669a0ecdd77d23b74e8dfc8dd705 diff --git a/target/linux/bcm27xx/patches-5.15/950-0055-lan78xx-Enable-LEDs-and-auto-negotiation.patch b/target/linux/bcm27xx/patches-5.15/950-0055-lan78xx-Enable-LEDs-and-auto-negotiation.patch index 47fbf510fad..79928b1ddef 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0055-lan78xx-Enable-LEDs-and-auto-negotiation.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0055-lan78xx-Enable-LEDs-and-auto-negotiation.patch @@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c -@@ -2716,6 +2716,11 @@ static int lan78xx_reset(struct lan78xx_ +@@ -2691,6 +2691,11 @@ static int lan78xx_reset(struct lan78xx_ int ret; u32 buf; u8 sig; @@ -26,7 +26,7 @@ Signed-off-by: Phil Elwell ret = lan78xx_read_reg(dev, HW_CFG, &buf); if (ret < 0) -@@ -2797,6 +2802,10 @@ static int lan78xx_reset(struct lan78xx_ +@@ -2772,6 +2777,10 @@ static int lan78xx_reset(struct lan78xx_ buf |= HW_CFG_MEF_; @@ -37,7 +37,7 @@ Signed-off-by: Phil Elwell ret = lan78xx_write_reg(dev, HW_CFG, buf); if (ret < 0) return ret; -@@ -2895,6 +2904,9 @@ static int lan78xx_reset(struct lan78xx_ +@@ -2870,6 +2879,9 @@ static int lan78xx_reset(struct lan78xx_ buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_; } } diff --git a/target/linux/bcm27xx/patches-5.15/950-0098-lan78xx-Read-initial-EEE-status-from-DT.patch b/target/linux/bcm27xx/patches-5.15/950-0098-lan78xx-Read-initial-EEE-status-from-DT.patch index ea0001b745a..50ea9f4c5b9 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0098-lan78xx-Read-initial-EEE-status-from-DT.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0098-lan78xx-Read-initial-EEE-status-from-DT.patch @@ -15,7 +15,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c -@@ -2960,6 +2960,22 @@ static int lan78xx_open(struct net_devic +@@ -2935,6 +2935,22 @@ static int lan78xx_open(struct net_devic netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); diff --git a/target/linux/bcm27xx/patches-5.15/950-0104-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch b/target/linux/bcm27xx/patches-5.15/950-0104-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch index e716abb71e2..1b6c1d1f2b4 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0104-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0104-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch @@ -37,7 +37,7 @@ Signed-off-by: Dave Stevenson static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) { u32 *buf; -@@ -3288,8 +3297,14 @@ static int lan78xx_bind(struct lan78xx_n +@@ -3263,8 +3272,14 @@ static int lan78xx_bind(struct lan78xx_n if (DEFAULT_RX_CSUM_ENABLE) dev->net->features |= NETIF_F_RXCSUM; diff --git a/target/linux/bcm27xx/patches-5.15/950-0105-lan78xx-Move-enabling-of-EEE-into-PHY-init-code.patch b/target/linux/bcm27xx/patches-5.15/950-0105-lan78xx-Move-enabling-of-EEE-into-PHY-init-code.patch index 5f0221e9f8b..91d27b82d93 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0105-lan78xx-Move-enabling-of-EEE-into-PHY-init-code.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0105-lan78xx-Move-enabling-of-EEE-into-PHY-init-code.patch @@ -16,7 +16,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c -@@ -2277,6 +2277,22 @@ static int lan78xx_phy_init(struct lan78 +@@ -2252,6 +2252,22 @@ static int lan78xx_phy_init(struct lan78 mii_adv_to_linkmode_adv_t(fc, mii_adv); linkmode_or(phydev->advertising, fc, phydev->advertising); @@ -39,7 +39,7 @@ Signed-off-by: Phil Elwell if (phydev->mdio.dev.of_node) { u32 reg; int len; -@@ -2969,22 +2985,6 @@ static int lan78xx_open(struct net_devic +@@ -2944,22 +2960,6 @@ static int lan78xx_open(struct net_devic netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); diff --git a/target/linux/bcm27xx/patches-5.15/950-0114-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch b/target/linux/bcm27xx/patches-5.15/950-0114-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch index bfe1c991bc3..334d391c1b3 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0114-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0114-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch @@ -28,7 +28,7 @@ See: https://github.com/raspberrypi/linux/issues/2447 static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) { u32 *buf; -@@ -4148,7 +4153,13 @@ static int lan78xx_probe(struct usb_inte +@@ -4123,7 +4128,13 @@ static int lan78xx_probe(struct usb_inte netdev->max_mtu = MAX_SINGLE_PACKET_SIZE; netif_set_gso_max_size(netdev, MAX_SINGLE_PACKET_SIZE - MAX_HEADER); diff --git a/target/linux/bcm27xx/patches-5.15/950-0115-lan78xx-EEE-support-is-now-a-PHY-property.patch b/target/linux/bcm27xx/patches-5.15/950-0115-lan78xx-EEE-support-is-now-a-PHY-property.patch index d62b6df5fbd..4bbf9ec6cb3 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0115-lan78xx-EEE-support-is-now-a-PHY-property.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0115-lan78xx-EEE-support-is-now-a-PHY-property.patch @@ -15,7 +15,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c -@@ -2282,7 +2282,7 @@ static int lan78xx_phy_init(struct lan78 +@@ -2257,7 +2257,7 @@ static int lan78xx_phy_init(struct lan78 mii_adv_to_linkmode_adv_t(fc, mii_adv); linkmode_or(phydev->advertising, fc, phydev->advertising); diff --git a/target/linux/bcm27xx/patches-5.15/950-0118-lan78xx-use-default-alignment-for-rx-buffers.patch b/target/linux/bcm27xx/patches-5.15/950-0118-lan78xx-use-default-alignment-for-rx-buffers.patch index a903f92d150..6bb311b5766 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0118-lan78xx-use-default-alignment-for-rx-buffers.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0118-lan78xx-use-default-alignment-for-rx-buffers.patch @@ -12,7 +12,7 @@ in both dwc_otg and in ipv6 processing. --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c -@@ -3527,7 +3527,7 @@ static int rx_submit(struct lan78xx_net +@@ -3502,7 +3502,7 @@ static int rx_submit(struct lan78xx_net size_t size = dev->rx_urb_size; int ret = 0; diff --git a/target/linux/bcm27xx/patches-5.15/950-0500-net-phy-lan87xx-Allow-more-time-for-link-detect.patch b/target/linux/bcm27xx/patches-5.15/950-0500-net-phy-lan87xx-Allow-more-time-for-link-detect.patch index f6eb87a5f01..91265071380 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0500-net-phy-lan87xx-Allow-more-time-for-link-detect.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0500-net-phy-lan87xx-Allow-more-time-for-link-detect.patch @@ -21,7 +21,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c -@@ -230,12 +230,12 @@ static int lan87xx_read_status(struct ph +@@ -220,12 +220,12 @@ static int lan87xx_read_status(struct ph if (rc < 0) return rc; diff --git a/target/linux/bcm27xx/patches-5.15/950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch b/target/linux/bcm27xx/patches-5.15/950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch index 3abac8ec259..62d7ea93d3a 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch @@ -18,7 +18,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c -@@ -220,6 +220,8 @@ static int lan87xx_read_status(struct ph +@@ -210,6 +210,8 @@ static int lan87xx_read_status(struct ph int err = genphy_read_status(phydev); if (!phydev->link && priv->energy_enable && phydev->irq == PHY_POLL) { @@ -27,7 +27,7 @@ Signed-off-by: Phil Elwell /* Disable EDPD to wake up PHY */ int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); if (rc < 0) -@@ -235,7 +237,7 @@ static int lan87xx_read_status(struct ph +@@ -225,7 +227,7 @@ static int lan87xx_read_status(struct ph */ read_poll_timeout(phy_read, rc, rc & MII_LAN83C185_ENERGYON || rc < 0, @@ -36,7 +36,7 @@ Signed-off-by: Phil Elwell MII_LAN83C185_CTRL_STATUS); if (rc < 0) return rc; -@@ -245,10 +247,16 @@ static int lan87xx_read_status(struct ph +@@ -235,10 +237,16 @@ static int lan87xx_read_status(struct ph if (rc < 0) return rc; diff --git a/target/linux/bcm47xx/patches-5.15/170-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch b/target/linux/bcm47xx/patches-5.15/170-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch deleted file mode 100644 index f5f998e0f51..00000000000 --- a/target/linux/bcm47xx/patches-5.15/170-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 327dabbd0111910a7d174b0b812d608d6b67bead Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Mon, 8 Aug 2022 23:05:25 +0200 -Subject: [PATCH] bgmac: fix *initial* chip reset to support BCM5358 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -While bringing hardware up we should perform a full reset including the -switch bit (BGMAC_BCMA_IOCTL_SW_RESET aka SICF_SWRST). It's what -specification says and what reference driver does. - -This seems to be critical for the BCM5358. Without this hardware doesn't -get initialized properly and doesn't seem to transmit or receive any -packets. - -Originally bgmac was calling bgmac_chip_reset() before setting -"has_robosw" property which resulted in expected behaviour. That has -changed as a side effect of adding platform device support which -regressed BCM5358 support. - -Fixes: f6a95a24957a ("net: ethernet: bgmac: Add platform device support") -Cc: Jon Mason -Signed-off-by: Rafał Miłecki ---- - drivers/net/ethernet/broadcom/bgmac.c | 8 ++++++-- - drivers/net/ethernet/broadcom/bgmac.h | 2 ++ - 2 files changed, 8 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/broadcom/bgmac.c -+++ b/drivers/net/ethernet/broadcom/bgmac.c -@@ -891,13 +891,13 @@ static void bgmac_chip_reset_idm_config( - - if (iost & BGMAC_BCMA_IOST_ATTACHED) { - flags = BGMAC_BCMA_IOCTL_SW_CLKEN; -- if (!bgmac->has_robosw) -+ if (bgmac->in_init || !bgmac->has_robosw) - flags |= BGMAC_BCMA_IOCTL_SW_RESET; - } - bgmac_clk_enable(bgmac, flags); - } - -- if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw) -+ if (iost & BGMAC_BCMA_IOST_ATTACHED && (bgmac->in_init || !bgmac->has_robosw)) - bgmac_idm_write(bgmac, BCMA_IOCTL, - bgmac_idm_read(bgmac, BCMA_IOCTL) & - ~BGMAC_BCMA_IOCTL_SW_RESET); -@@ -1502,6 +1502,8 @@ int bgmac_enet_probe(struct bgmac *bgmac - struct net_device *net_dev = bgmac->net_dev; - int err; - -+ bgmac->in_init = true; -+ - bgmac_chip_intrs_off(bgmac); - - net_dev->irq = bgmac->irq; -@@ -1562,6 +1564,8 @@ int bgmac_enet_probe(struct bgmac *bgmac - bgmac->b53_device = &bgmac_b53_dev; - } - -+ bgmac->in_init = false; -+ - err = register_netdev(bgmac->net_dev); - if (err) { - dev_err(bgmac->dev, "Cannot register net device\n"); ---- a/drivers/net/ethernet/broadcom/bgmac.h -+++ b/drivers/net/ethernet/broadcom/bgmac.h -@@ -475,6 +475,8 @@ struct bgmac { - int irq; - u32 int_mask; - -+ bool in_init; -+ - /* Current MAC state */ - int mac_speed; - int mac_duplex; diff --git a/target/linux/generic/backport-5.15/060-v6.0-01-tools-build-Add-feature-test-for-init_disassemble_in.patch b/target/linux/generic/backport-5.15/060-v6.0-01-tools-build-Add-feature-test-for-init_disassemble_in.patch deleted file mode 100644 index f25e9ff917b..00000000000 --- a/target/linux/generic/backport-5.15/060-v6.0-01-tools-build-Add-feature-test-for-init_disassemble_in.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 598ada195606eb0e577db0487dd59a2536f206ce Mon Sep 17 00:00:00 2001 -From: Andres Freund -Date: Sun, 31 Jul 2022 18:38:27 -0700 -Subject: [PATCH 1/5] tools build: Add feature test for init_disassemble_info - API changes - -binutils changed the signature of init_disassemble_info(), which now causes -compilation failures for tools/{perf,bpf}, e.g. on debian unstable. - -Relevant binutils commit: - - https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=60a3da00bd5407f07 - -This commit adds a feature test to detect the new signature. Subsequent -commits will use it to fix the build failures. - -Signed-off-by: Andres Freund -Acked-by: Quentin Monnet -Cc: Alexei Starovoitov -Cc: Ben Hutchings -Cc: Jiri Olsa -Cc: Quentin Monnet -Cc: Sedat Dilek -Cc: bpf@vger.kernel.org -Link: http://lore.kernel.org/lkml/20220622181918.ykrs5rsnmx3og4sv@alap3.anarazel.de -Link: https://lore.kernel.org/r/20220801013834.156015-2-andres@anarazel.de -Signed-off-by: Arnaldo Carvalho de Melo -(cherry picked from commit cfd59ca91467056bb2c36907b2fa67b8e1af9952) ---- - tools/build/Makefile.feature | 1 + - tools/build/feature/Makefile | 4 ++++ - tools/build/feature/test-all.c | 4 ++++ - tools/build/feature/test-disassembler-init-styled.c | 13 +++++++++++++ - 4 files changed, 22 insertions(+) - create mode 100644 tools/build/feature/test-disassembler-init-styled.c - ---- a/tools/build/Makefile.feature -+++ b/tools/build/Makefile.feature -@@ -69,6 +69,7 @@ FEATURE_TESTS_BASIC := - libaio \ - libzstd \ - disassembler-four-args \ -+ disassembler-init-styled \ - file-handle - - # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list ---- a/tools/build/feature/Makefile -+++ b/tools/build/feature/Makefile -@@ -18,6 +18,7 @@ FILES= - test-libbfd.bin \ - test-libbfd-buildid.bin \ - test-disassembler-four-args.bin \ -+ test-disassembler-init-styled.bin \ - test-reallocarray.bin \ - test-libbfd-liberty.bin \ - test-libbfd-liberty-z.bin \ -@@ -239,6 +240,9 @@ $(OUTPUT)test-libbfd-buildid.bin: - $(OUTPUT)test-disassembler-four-args.bin: - $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes - -+$(OUTPUT)test-disassembler-init-styled.bin: -+ $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes -+ - $(OUTPUT)test-reallocarray.bin: - $(BUILD) - ---- a/tools/build/feature/test-all.c -+++ b/tools/build/feature/test-all.c -@@ -166,6 +166,10 @@ - # include "test-disassembler-four-args.c" - #undef main - -+#define main main_test_disassembler_init_styled -+# include "test-disassembler-init-styled.c" -+#undef main -+ - #define main main_test_libzstd - # include "test-libzstd.c" - #undef main ---- /dev/null -+++ b/tools/build/feature/test-disassembler-init-styled.c -@@ -0,0 +1,13 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include -+#include -+ -+int main(void) -+{ -+ struct disassemble_info info; -+ -+ init_disassemble_info(&info, stdout, -+ NULL, NULL); -+ -+ return 0; -+} diff --git a/target/linux/generic/backport-5.15/060-v6.0-02-tools-include-add-dis-asm-compat.h-to-handle-version.patch b/target/linux/generic/backport-5.15/060-v6.0-02-tools-include-add-dis-asm-compat.h-to-handle-version.patch deleted file mode 100644 index 8c6ba187180..00000000000 --- a/target/linux/generic/backport-5.15/060-v6.0-02-tools-include-add-dis-asm-compat.h-to-handle-version.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 08ec5766e5cf7b24fdebefb83b6f760bceeddf40 Mon Sep 17 00:00:00 2001 -From: Andres Freund -Date: Sun, 31 Jul 2022 18:38:29 -0700 -Subject: [PATCH 2/5] tools include: add dis-asm-compat.h to handle version - differences - -binutils changed the signature of init_disassemble_info(), which now causes -compilation failures for tools/{perf,bpf}, e.g. on debian unstable. - -Relevant binutils commit: - - https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=60a3da00bd5407f07 - -This commit introduces a wrapper for init_disassemble_info(), to avoid -spreading #ifdef DISASM_INIT_STYLED to a bunch of places. Subsequent -commits will use it to fix the build failures. - -It likely is worth adding a wrapper for disassember(), to avoid the already -existing DISASM_FOUR_ARGS_SIGNATURE ifdefery. - -Signed-off-by: Andres Freund -Signed-off-by: Ben Hutchings -Acked-by: Quentin Monnet -Cc: Alexei Starovoitov -Cc: Ben Hutchings -Cc: Jiri Olsa -Cc: Quentin Monnet -Cc: Sedat Dilek -Cc: bpf@vger.kernel.org -Link: http://lore.kernel.org/lkml/20220622181918.ykrs5rsnmx3og4sv@alap3.anarazel.de -Link: https://lore.kernel.org/r/20220801013834.156015-4-andres@anarazel.de -Signed-off-by: Arnaldo Carvalho de Melo -(cherry picked from commit a45b3d6926231c3d024ea0de4f7bd967f83709ee) ---- - tools/include/tools/dis-asm-compat.h | 55 ++++++++++++++++++++++++++++ - 1 file changed, 55 insertions(+) - create mode 100644 tools/include/tools/dis-asm-compat.h - ---- /dev/null -+++ b/tools/include/tools/dis-asm-compat.h -@@ -0,0 +1,55 @@ -+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ -+#ifndef _TOOLS_DIS_ASM_COMPAT_H -+#define _TOOLS_DIS_ASM_COMPAT_H -+ -+#include -+#include -+ -+/* define types for older binutils version, to centralize ifdef'ery a bit */ -+#ifndef DISASM_INIT_STYLED -+enum disassembler_style {DISASSEMBLER_STYLE_NOT_EMPTY}; -+typedef int (*fprintf_styled_ftype) (void *, enum disassembler_style, const char*, ...); -+#endif -+ -+/* -+ * Trivial fprintf wrapper to be used as the fprintf_styled_func argument to -+ * init_disassemble_info_compat() when normal fprintf suffices. -+ */ -+static inline int fprintf_styled(void *out, -+ enum disassembler_style style, -+ const char *fmt, ...) -+{ -+ va_list args; -+ int r; -+ -+ (void)style; -+ -+ va_start(args, fmt); -+ r = vfprintf(out, fmt, args); -+ va_end(args); -+ -+ return r; -+} -+ -+/* -+ * Wrapper for init_disassemble_info() that hides version -+ * differences. Depending on binutils version and architecture either -+ * fprintf_func or fprintf_styled_func will be called. -+ */ -+static inline void init_disassemble_info_compat(struct disassemble_info *info, -+ void *stream, -+ fprintf_ftype unstyled_func, -+ fprintf_styled_ftype styled_func) -+{ -+#ifdef DISASM_INIT_STYLED -+ init_disassemble_info(info, stream, -+ unstyled_func, -+ styled_func); -+#else -+ (void)styled_func; -+ init_disassemble_info(info, stream, -+ unstyled_func); -+#endif -+} -+ -+#endif /* _TOOLS_DIS_ASM_COMPAT_H */ diff --git a/target/linux/generic/backport-5.15/060-v6.0-03-tools-perf-Fix-compilation-error-with-new-binutils.patch b/target/linux/generic/backport-5.15/060-v6.0-03-tools-perf-Fix-compilation-error-with-new-binutils.patch deleted file mode 100644 index 27fb4011fc9..00000000000 --- a/target/linux/generic/backport-5.15/060-v6.0-03-tools-perf-Fix-compilation-error-with-new-binutils.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 3bc373152a3a00742750dbbe974d541af78231e6 Mon Sep 17 00:00:00 2001 -From: Andres Freund -Date: Sun, 31 Jul 2022 18:38:30 -0700 -Subject: [PATCH 3/5] tools perf: Fix compilation error with new binutils - -binutils changed the signature of init_disassemble_info(), which now causes -compilation failures for tools/perf/util/annotate.c, e.g. on debian -unstable. - -Relevant binutils commit: - - https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=60a3da00bd5407f07 - -Wire up the feature test and switch to init_disassemble_info_compat(), -which were introduced in prior commits, fixing the compilation failure. - -I verified that perf can still disassemble bpf programs by using bpftrace -under load, recording a perf trace, and then annotating the bpf "function" -with and without the changes. With old binutils there's no change in output -before/after this patch. When comparing the output from old binutils (2.35) -to new bintuils with the patch (upstream snapshot) there are a few output -differences, but they are unrelated to this patch. An example hunk is: - - 1.15 : 55:mov %rbp,%rdx - 0.00 : 58:add $0xfffffffffffffff8,%rdx - 0.00 : 5c:xor %ecx,%ecx - - 1.03 : 5e:callq 0xffffffffe12aca3c - + 1.03 : 5e:call 0xffffffffe12aca3c - 0.00 : 63:xor %eax,%eax - - 2.18 : 65:leaveq - - 2.82 : 66:retq - + 2.18 : 65:leave - + 2.82 : 66:ret - -Signed-off-by: Andres Freund -Acked-by: Quentin Monnet -Cc: Alexei Starovoitov -Cc: Ben Hutchings -Cc: Jiri Olsa -Cc: Sedat Dilek -Cc: bpf@vger.kernel.org -Link: http://lore.kernel.org/lkml/20220622181918.ykrs5rsnmx3og4sv@alap3.anarazel.de -Link: https://lore.kernel.org/r/20220801013834.156015-5-andres@anarazel.de -Signed-off-by: Arnaldo Carvalho de Melo -(cherry picked from commit 83aa0120487e8bc3f231e72c460add783f71f17c) ---- - tools/perf/Makefile.config | 8 ++++++++ - tools/perf/util/annotate.c | 7 ++++--- - 2 files changed, 12 insertions(+), 3 deletions(-) - ---- a/tools/perf/Makefile.config -+++ b/tools/perf/Makefile.config -@@ -296,6 +296,7 @@ FEATURE_CHECK_LDFLAGS-libpython := $(PYT - FEATURE_CHECK_LDFLAGS-libaio = -lrt - - FEATURE_CHECK_LDFLAGS-disassembler-four-args = -lbfd -lopcodes -ldl -+FEATURE_CHECK_LDFLAGS-disassembler-init-styled = -lbfd -lopcodes -ldl - - CORE_CFLAGS += -fno-omit-frame-pointer - CORE_CFLAGS += -ggdb3 -@@ -872,13 +873,16 @@ ifndef NO_LIBBFD - ifeq ($(feature-libbfd-liberty), 1) - EXTLIBS += -lbfd -lopcodes -liberty - FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -ldl -+ FEATURE_CHECK_LDFLAGS-disassembler-init-styled += -liberty -ldl - else - ifeq ($(feature-libbfd-liberty-z), 1) - EXTLIBS += -lbfd -lopcodes -liberty -lz - FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -lz -ldl -+ FEATURE_CHECK_LDFLAGS-disassembler-init-styled += -liberty -lz -ldl - endif - endif - $(call feature_check,disassembler-four-args) -+ $(call feature_check,disassembler-init-styled) - endif - - ifeq ($(feature-libbfd-buildid), 1) -@@ -992,6 +996,10 @@ ifeq ($(feature-disassembler-four-args), - CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE - endif - -+ifeq ($(feature-disassembler-init-styled), 1) -+ CFLAGS += -DDISASM_INIT_STYLED -+endif -+ - ifeq (${IS_64_BIT}, 1) - ifndef NO_PERF_READ_VDSO32 - $(call feature_check,compile-32) ---- a/tools/perf/util/annotate.c -+++ b/tools/perf/util/annotate.c -@@ -1694,6 +1694,7 @@ fallback: - #include - #include - #include -+#include - - static int symbol__disassemble_bpf(struct symbol *sym, - struct annotate_args *args) -@@ -1736,9 +1737,9 @@ static int symbol__disassemble_bpf(struc - ret = errno; - goto out; - } -- init_disassemble_info(&info, s, -- (fprintf_ftype) fprintf); -- -+ init_disassemble_info_compat(&info, s, -+ (fprintf_ftype) fprintf, -+ fprintf_styled); - info.arch = bfd_get_arch(bfdf); - info.mach = bfd_get_mach(bfdf); - diff --git a/target/linux/generic/backport-5.15/060-v6.0-04-tools-bpf_jit_disasm-Fix-compilation-error-with-new-.patch b/target/linux/generic/backport-5.15/060-v6.0-04-tools-bpf_jit_disasm-Fix-compilation-error-with-new-.patch deleted file mode 100644 index f8f5bcc6b80..00000000000 --- a/target/linux/generic/backport-5.15/060-v6.0-04-tools-bpf_jit_disasm-Fix-compilation-error-with-new-.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 042e7f11769adac0736d77d76262912b90724d7d Mon Sep 17 00:00:00 2001 -From: Andres Freund -Date: Sun, 31 Jul 2022 18:38:31 -0700 -Subject: [PATCH 4/5] tools bpf_jit_disasm: Fix compilation error with new - binutils - -binutils changed the signature of init_disassemble_info(), which now causes -compilation to fail for tools/bpf/bpf_jit_disasm.c, e.g. on debian -unstable. - -Relevant binutils commit: - - https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=60a3da00bd5407f07 - -Wire up the feature test and switch to init_disassemble_info_compat(), -which were introduced in prior commits, fixing the compilation failure. - -I verified that bpf_jit_disasm can still disassemble bpf programs, both -with the old and new dis-asm.h API. With old binutils there's no change in -output before/after this patch. When comparing the output from old -binutils (2.35) to new bintuils with the patch (upstream snapshot) there -are a few output differences, but they are unrelated to this patch. An -example hunk is: - - f4: mov %r14,%rsi - f7: mov %r15,%rdx - fa: mov $0x2a,%ecx - - ff: callq 0xffffffffea8c4988 - + ff: call 0xffffffffea8c4988 - 104: test %rax,%rax - 107: jge 0x0000000000000110 - 109: xor %eax,%eax - - 10b: jmpq 0x0000000000000073 - + 10b: jmp 0x0000000000000073 - 110: cmp $0x16,%rax - -However, I had to use an older kernel to generate the bpf_jit_enabled = -2 output, as that has been broken since 5.18 / 1022a5498f6f745c ("bpf, -x86_64: Use bpf_jit_binary_pack_alloc"). - - https://lore.kernel.org/20220703030210.pmjft7qc2eajzi6c@alap3.anarazel.de - -Signed-off-by: Andres Freund -Acked-by: Quentin Monnet -Cc: Alexei Starovoitov -Cc: Ben Hutchings -Cc: Daniel Borkmann -Cc: Jiri Olsa -Cc: Quentin Monnet -Cc: Sedat Dilek -Cc: bpf@vger.kernel.org -Link: http://lore.kernel.org/lkml/20220622181918.ykrs5rsnmx3og4sv@alap3.anarazel.de -Link: https://lore.kernel.org/r/20220801013834.156015-6-andres@anarazel.de -Signed-off-by: Arnaldo Carvalho de Melo -(cherry picked from commit 96ed066054abf11c7d3e106e3011a51f3f1227a3) ---- - tools/bpf/Makefile | 5 ++++- - tools/bpf/bpf_jit_disasm.c | 5 ++++- - 2 files changed, 8 insertions(+), 2 deletions(-) - ---- a/tools/bpf/Makefile -+++ b/tools/bpf/Makefile -@@ -34,7 +34,7 @@ else - endif - - FEATURE_USER = .bpf --FEATURE_TESTS = libbfd disassembler-four-args -+FEATURE_TESTS = libbfd disassembler-four-args disassembler-init-styled - FEATURE_DISPLAY = libbfd disassembler-four-args - - check_feat := 1 -@@ -56,6 +56,9 @@ endif - ifeq ($(feature-disassembler-four-args), 1) - CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE - endif -+ifeq ($(feature-disassembler-init-styled), 1) -+CFLAGS += -DDISASM_INIT_STYLED -+endif - - $(OUTPUT)%.yacc.c: $(srctree)/tools/bpf/%.y - $(QUIET_BISON)$(YACC) -o $@ -d $< ---- a/tools/bpf/bpf_jit_disasm.c -+++ b/tools/bpf/bpf_jit_disasm.c -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - - #define CMD_ACTION_SIZE_BUFFER 10 - #define CMD_ACTION_READ_ALL 3 -@@ -64,7 +65,9 @@ static void get_asm_insns(uint8_t *image - assert(bfdf); - assert(bfd_check_format(bfdf, bfd_object)); - -- init_disassemble_info(&info, stdout, (fprintf_ftype) fprintf); -+ init_disassemble_info_compat(&info, stdout, -+ (fprintf_ftype) fprintf, -+ fprintf_styled); - info.arch = bfd_get_arch(bfdf); - info.mach = bfd_get_mach(bfdf); - info.buffer = image; diff --git a/target/linux/generic/backport-5.15/060-v6.0-05-tools-bpftool-Fix-compilation-error-with-new-binutil.patch b/target/linux/generic/backport-5.15/060-v6.0-05-tools-bpftool-Fix-compilation-error-with-new-binutil.patch deleted file mode 100644 index 66ac3d94096..00000000000 --- a/target/linux/generic/backport-5.15/060-v6.0-05-tools-bpftool-Fix-compilation-error-with-new-binutil.patch +++ /dev/null @@ -1,146 +0,0 @@ -From a82db18ab34ba7f9d38319e8cc01ffe382e3e55e Mon Sep 17 00:00:00 2001 -From: Andres Freund -Date: Sun, 31 Jul 2022 18:38:33 -0700 -Subject: [PATCH 5/5] tools bpftool: Fix compilation error with new binutils - -binutils changed the signature of init_disassemble_info(), which now causes -compilation to fail for tools/bpf/bpftool/jit_disasm.c, e.g. on debian -unstable. - -Relevant binutils commit: - - https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=60a3da00bd5407f07 - -Wire up the feature test and switch to init_disassemble_info_compat(), -which were introduced in prior commits, fixing the compilation failure. - -I verified that bpftool can still disassemble bpf programs, both with an -old and new dis-asm.h API. There are no output changes for plain and json -formats. When comparing the output from old binutils (2.35) -to new bintuils with the patch (upstream snapshot) there are a few output -differences, but they are unrelated to this patch. An example hunk is: - - 2f: pop %r14 - 31: pop %r13 - 33: pop %rbx - - 34: leaveq - - 35: retq - + 34: leave - + 35: ret - -Signed-off-by: Andres Freund -Acked-by: Quentin Monnet -Cc: Alexei Starovoitov -Cc: Ben Hutchings -Cc: Jiri Olsa -Cc: Quentin Monnet -Cc: Sedat Dilek -Cc: bpf@vger.kernel.org -Link: http://lore.kernel.org/lkml/20220622181918.ykrs5rsnmx3og4sv@alap3.anarazel.de -Link: https://lore.kernel.org/r/20220801013834.156015-8-andres@anarazel.de -Signed-off-by: Arnaldo Carvalho de Melo -(cherry picked from commit 600b7b26c07a070d0153daa76b3806c1e52c9e00) ---- - tools/bpf/bpftool/Makefile | 5 +++- - tools/bpf/bpftool/jit_disasm.c | 42 +++++++++++++++++++++++++++------- - 2 files changed, 38 insertions(+), 9 deletions(-) - ---- a/tools/bpf/bpftool/Makefile -+++ b/tools/bpf/bpftool/Makefile -@@ -76,7 +76,7 @@ INSTALL ?= install - RM ?= rm -f - - FEATURE_USER = .bpftool --FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \ -+FEATURE_TESTS = libbfd disassembler-four-args disassembler-init-styled reallocarray zlib libcap \ - clang-bpf-co-re - FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \ - clang-bpf-co-re -@@ -100,6 +100,9 @@ endif - ifeq ($(feature-disassembler-four-args), 1) - CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE - endif -+ifeq ($(feature-disassembler-init-styled), 1) -+ CFLAGS += -DDISASM_INIT_STYLED -+endif - - ifeq ($(feature-reallocarray), 0) - CFLAGS += -DCOMPAT_NEED_REALLOCARRAY ---- a/tools/bpf/bpftool/jit_disasm.c -+++ b/tools/bpf/bpftool/jit_disasm.c -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - - #include "json_writer.h" - #include "main.h" -@@ -39,15 +40,12 @@ static void get_exec_path(char *tpath, s - } - - static int oper_count; --static int fprintf_json(void *out, const char *fmt, ...) -+static int printf_json(void *out, const char *fmt, va_list ap) - { -- va_list ap; - char *s; - int err; - -- va_start(ap, fmt); - err = vasprintf(&s, fmt, ap); -- va_end(ap); - if (err < 0) - return -1; - -@@ -73,6 +71,32 @@ static int fprintf_json(void *out, const - return 0; - } - -+static int fprintf_json(void *out, const char *fmt, ...) -+{ -+ va_list ap; -+ int r; -+ -+ va_start(ap, fmt); -+ r = printf_json(out, fmt, ap); -+ va_end(ap); -+ -+ return r; -+} -+ -+static int fprintf_json_styled(void *out, -+ enum disassembler_style style __maybe_unused, -+ const char *fmt, ...) -+{ -+ va_list ap; -+ int r; -+ -+ va_start(ap, fmt); -+ r = printf_json(out, fmt, ap); -+ va_end(ap); -+ -+ return r; -+} -+ - void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, - const char *arch, const char *disassembler_options, - const struct btf *btf, -@@ -99,11 +123,13 @@ void disasm_print_insn(unsigned char *im - assert(bfd_check_format(bfdf, bfd_object)); - - if (json_output) -- init_disassemble_info(&info, stdout, -- (fprintf_ftype) fprintf_json); -+ init_disassemble_info_compat(&info, stdout, -+ (fprintf_ftype) fprintf_json, -+ fprintf_json_styled); - else -- init_disassemble_info(&info, stdout, -- (fprintf_ftype) fprintf); -+ init_disassemble_info_compat(&info, stdout, -+ (fprintf_ftype) fprintf, -+ fprintf_styled); - - /* Update architecture info for offload. */ - if (arch) { diff --git a/target/linux/generic/backport-5.15/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch b/target/linux/generic/backport-5.15/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch index e13616fd834..c83d659d1c0 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau #include #include #include -@@ -839,7 +840,7 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -840,7 +841,7 @@ static int mtk_init_fq_dma(struct mtk_et dma_addr_t dma_addr; int i; @@ -29,7 +29,7 @@ Signed-off-by: Felix Fietkau cnt * sizeof(struct mtk_tx_dma), ð->phy_scratch_ring, GFP_ATOMIC); -@@ -851,10 +852,10 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -852,10 +853,10 @@ static int mtk_init_fq_dma(struct mtk_et if (unlikely(!eth->scratch_head)) return -ENOMEM; @@ -42,7 +42,7 @@ Signed-off-by: Felix Fietkau return -ENOMEM; phy_ring_tail = eth->phy_scratch_ring + -@@ -908,26 +909,26 @@ static void mtk_tx_unmap(struct mtk_eth +@@ -909,26 +910,26 @@ static void mtk_tx_unmap(struct mtk_eth { if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { @@ -73,7 +73,7 @@ Signed-off-by: Felix Fietkau dma_unmap_addr(tx_buf, dma_addr1), dma_unmap_len(tx_buf, dma_len1), DMA_TO_DEVICE); -@@ -1005,9 +1006,9 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1006,9 +1007,9 @@ static int mtk_tx_map(struct sk_buff *sk if (skb_vlan_tag_present(skb)) txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); @@ -85,7 +85,7 @@ Signed-off-by: Felix Fietkau return -ENOMEM; WRITE_ONCE(itxd->txd1, mapped_addr); -@@ -1046,10 +1047,10 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1047,10 +1048,10 @@ static int mtk_tx_map(struct sk_buff *sk frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN); @@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau goto err_dma; if (i == nr_frags - 1 && -@@ -1330,18 +1331,18 @@ static int mtk_poll_rx(struct napi_struc +@@ -1331,18 +1332,18 @@ static int mtk_poll_rx(struct napi_struc netdev->stats.rx_dropped++; goto release_desc; } @@ -120,7 +120,7 @@ Signed-off-by: Felix Fietkau ring->buf_size, DMA_FROM_DEVICE); /* receive data */ -@@ -1614,7 +1615,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1615,7 +1616,7 @@ static int mtk_tx_alloc(struct mtk_eth * if (!ring->buf) goto no_tx_mem; @@ -129,7 +129,7 @@ Signed-off-by: Felix Fietkau &ring->phys, GFP_ATOMIC); if (!ring->dma) goto no_tx_mem; -@@ -1632,7 +1633,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1633,7 +1634,7 @@ static int mtk_tx_alloc(struct mtk_eth * * descriptors in ring->dma_pdma. */ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { @@ -138,7 +138,7 @@ Signed-off-by: Felix Fietkau &ring->phys_pdma, GFP_ATOMIC); if (!ring->dma_pdma) -@@ -1691,7 +1692,7 @@ static void mtk_tx_clean(struct mtk_eth +@@ -1692,7 +1693,7 @@ static void mtk_tx_clean(struct mtk_eth } if (ring->dma) { @@ -147,7 +147,7 @@ Signed-off-by: Felix Fietkau MTK_DMA_SIZE * sizeof(*ring->dma), ring->dma, ring->phys); -@@ -1699,7 +1700,7 @@ static void mtk_tx_clean(struct mtk_eth +@@ -1700,7 +1701,7 @@ static void mtk_tx_clean(struct mtk_eth } if (ring->dma_pdma) { @@ -156,7 +156,7 @@ Signed-off-by: Felix Fietkau MTK_DMA_SIZE * sizeof(*ring->dma_pdma), ring->dma_pdma, ring->phys_pdma); -@@ -1747,18 +1748,18 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1748,18 +1749,18 @@ static int mtk_rx_alloc(struct mtk_eth * return -ENOMEM; } @@ -178,7 +178,7 @@ Signed-off-by: Felix Fietkau return -ENOMEM; ring->dma[i].rxd1 = (unsigned int)dma_addr; -@@ -1794,7 +1795,7 @@ static void mtk_rx_clean(struct mtk_eth +@@ -1795,7 +1796,7 @@ static void mtk_rx_clean(struct mtk_eth continue; if (!ring->dma[i].rxd1) continue; @@ -187,7 +187,7 @@ Signed-off-by: Felix Fietkau ring->dma[i].rxd1, ring->buf_size, DMA_FROM_DEVICE); -@@ -1805,7 +1806,7 @@ static void mtk_rx_clean(struct mtk_eth +@@ -1806,7 +1807,7 @@ static void mtk_rx_clean(struct mtk_eth } if (ring->dma) { @@ -196,7 +196,7 @@ Signed-off-by: Felix Fietkau ring->dma_size * sizeof(*ring->dma), ring->dma, ring->phys); -@@ -2161,7 +2162,7 @@ static void mtk_dma_free(struct mtk_eth +@@ -2162,7 +2163,7 @@ static void mtk_dma_free(struct mtk_eth if (eth->netdev[i]) netdev_reset_queue(eth->netdev[i]); if (eth->scratch_ring) { @@ -205,7 +205,7 @@ Signed-off-by: Felix Fietkau MTK_DMA_SIZE * sizeof(struct mtk_tx_dma), eth->scratch_ring, eth->phy_scratch_ring); -@@ -2513,6 +2514,8 @@ static void mtk_dim_tx(struct work_struc +@@ -2514,6 +2515,8 @@ static void mtk_dim_tx(struct work_struc static int mtk_hw_init(struct mtk_eth *eth) { @@ -214,7 +214,7 @@ Signed-off-by: Felix Fietkau int i, val, ret; if (test_and_set_bit(MTK_HW_INIT, ð->state)) -@@ -2525,6 +2528,10 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -2526,6 +2529,10 @@ static int mtk_hw_init(struct mtk_eth *e if (ret) goto err_disable_pm; @@ -225,7 +225,7 @@ Signed-off-by: Felix Fietkau if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { ret = device_reset(eth->dev); if (ret) { -@@ -3078,6 +3085,35 @@ free_netdev: +@@ -3079,6 +3086,35 @@ free_netdev: return err; } @@ -261,7 +261,7 @@ Signed-off-by: Felix Fietkau static int mtk_probe(struct platform_device *pdev) { struct device_node *mac_np; -@@ -3091,6 +3127,7 @@ static int mtk_probe(struct platform_dev +@@ -3092,6 +3128,7 @@ static int mtk_probe(struct platform_dev eth->soc = of_device_get_match_data(&pdev->dev); eth->dev = &pdev->dev; @@ -269,7 +269,7 @@ Signed-off-by: Felix Fietkau eth->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(eth->base)) return PTR_ERR(eth->base); -@@ -3139,6 +3176,16 @@ static int mtk_probe(struct platform_dev +@@ -3140,6 +3177,16 @@ static int mtk_probe(struct platform_dev } } @@ -288,7 +288,7 @@ Signed-off-by: Felix Fietkau GFP_KERNEL); --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -462,6 +462,12 @@ +@@ -463,6 +463,12 @@ #define RSTCTRL_FE BIT(6) #define RSTCTRL_PPE BIT(31) @@ -301,7 +301,7 @@ Signed-off-by: Felix Fietkau /* SGMII subsystem config registers */ /* Register to auto-negotiation restart */ #define SGMSYS_PCS_CONTROL_1 0x0 -@@ -879,6 +885,7 @@ struct mtk_sgmii { +@@ -880,6 +886,7 @@ struct mtk_sgmii { /* struct mtk_eth - This is the main datasructure for holding the state * of the driver * @dev: The device pointer @@ -309,7 +309,7 @@ Signed-off-by: Felix Fietkau * @base: The mapped register i/o base * @page_lock: Make sure that register operations are atomic * @tx_irq__lock: Make sure that IRQ register operations are atomic -@@ -922,6 +929,7 @@ struct mtk_sgmii { +@@ -923,6 +930,7 @@ struct mtk_sgmii { struct mtk_eth { struct device *dev; @@ -317,7 +317,7 @@ Signed-off-by: Felix Fietkau void __iomem *base; spinlock_t page_lock; spinlock_t tx_irq_lock; -@@ -1020,6 +1028,7 @@ int mtk_gmac_rgmii_path_setup(struct mtk +@@ -1021,6 +1029,7 @@ int mtk_gmac_rgmii_path_setup(struct mtk int mtk_eth_offload_init(struct mtk_eth *eth); int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data); diff --git a/target/linux/generic/backport-5.15/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch b/target/linux/generic/backport-5.15/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch index a623aa14d78..2f3a0827fe4 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch @@ -56,7 +56,7 @@ Signed-off-by: Felix Fietkau static int mtk_msg_level = -1; module_param_named(msg_level, mtk_msg_level, int, 0); -@@ -3208,6 +3209,22 @@ static int mtk_probe(struct platform_dev +@@ -3209,6 +3210,22 @@ static int mtk_probe(struct platform_dev } } diff --git a/target/linux/generic/backport-5.15/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch b/target/linux/generic/backport-5.15/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch index 5002c38dc9c..bc75d152114 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2334,7 +2334,7 @@ static int mtk_open(struct net_device *d +@@ -2335,7 +2335,7 @@ static int mtk_open(struct net_device *d return err; } @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau gdm_config = MTK_GDMA_TO_PPE; mtk_gdm_config(eth, gdm_config); -@@ -2408,7 +2408,7 @@ static int mtk_stop(struct net_device *d +@@ -2409,7 +2409,7 @@ static int mtk_stop(struct net_device *d mtk_dma_free(eth); if (eth->soc->offload_version) @@ -28,7 +28,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3300,10 +3300,11 @@ static int mtk_probe(struct platform_dev +@@ -3301,10 +3301,11 @@ static int mtk_probe(struct platform_dev } if (eth->soc->offload_version) { @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau if (err) --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -982,7 +982,7 @@ struct mtk_eth { +@@ -983,7 +983,7 @@ struct mtk_eth { u32 rx_dma_l4_valid; int ip_align; diff --git a/target/linux/generic/backport-5.15/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch b/target/linux/generic/backport-5.15/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch index 52b3add875d..2609cbedec2 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch @@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau #include #include "mtk_eth_soc.h" -@@ -1292,7 +1293,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1293,7 +1294,7 @@ static int mtk_poll_rx(struct napi_struc struct net_device *netdev; unsigned int pktlen; dma_addr_t dma_addr; @@ -42,7 +42,7 @@ Signed-off-by: Felix Fietkau int mac; ring = mtk_get_rx_ring(eth); -@@ -1371,6 +1372,11 @@ static int mtk_poll_rx(struct napi_struc +@@ -1372,6 +1373,11 @@ static int mtk_poll_rx(struct napi_struc skb_set_hash(skb, hash, PKT_HASH_TYPE_L4); } @@ -54,7 +54,7 @@ Signed-off-by: Felix Fietkau if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && (trxd.rxd2 & RX_DMA_VTAG)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), -@@ -3300,7 +3306,7 @@ static int mtk_probe(struct platform_dev +@@ -3301,7 +3307,7 @@ static int mtk_probe(struct platform_dev } if (eth->soc->offload_version) { diff --git a/target/linux/generic/backport-5.15/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch b/target/linux/generic/backport-5.15/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch index c893d8c8bbe..a7c5f08f100 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch @@ -24,7 +24,7 @@ Signed-off-by: David S. Miller mediatek,hifsys = <&hifsys>; --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3187,7 +3187,7 @@ static int mtk_probe(struct platform_dev +@@ -3188,7 +3188,7 @@ static int mtk_probe(struct platform_dev struct regmap *cci; cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, diff --git a/target/linux/generic/backport-5.15/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch b/target/linux/generic/backport-5.15/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch index 97677670cc1..9b6321f1daf 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch @@ -13,7 +13,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -845,7 +845,7 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -846,7 +846,7 @@ static int mtk_init_fq_dma(struct mtk_et eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, cnt * sizeof(struct mtk_tx_dma), ð->phy_scratch_ring, @@ -22,7 +22,7 @@ Signed-off-by: David S. Miller if (unlikely(!eth->scratch_ring)) return -ENOMEM; -@@ -1623,7 +1623,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1624,7 +1624,7 @@ static int mtk_tx_alloc(struct mtk_eth * goto no_tx_mem; ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, @@ -31,7 +31,7 @@ Signed-off-by: David S. Miller if (!ring->dma) goto no_tx_mem; -@@ -1641,8 +1641,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1642,8 +1642,7 @@ static int mtk_tx_alloc(struct mtk_eth * */ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, @@ -41,7 +41,7 @@ Signed-off-by: David S. Miller if (!ring->dma_pdma) goto no_tx_mem; -@@ -1757,7 +1756,7 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1758,7 +1757,7 @@ static int mtk_rx_alloc(struct mtk_eth * ring->dma = dma_alloc_coherent(eth->dma_dev, rx_dma_size * sizeof(*ring->dma), diff --git a/target/linux/generic/backport-5.15/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch b/target/linux/generic/backport-5.15/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch index 95f122f730f..8e16ea25566 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch @@ -14,7 +14,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -971,18 +971,51 @@ static void setup_tx_buf(struct mtk_eth +@@ -972,18 +972,51 @@ static void setup_tx_buf(struct mtk_eth } } @@ -69,7 +69,7 @@ Signed-off-by: David S. Miller int k = 0; itxd = ring->next_free; -@@ -990,49 +1023,32 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -991,49 +1024,32 @@ static int mtk_tx_map(struct sk_buff *sk if (itxd == ring->last_free) return -ENOMEM; @@ -126,7 +126,7 @@ Signed-off-by: David S. Miller bool new_desc = true; if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) || -@@ -1047,23 +1063,17 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1048,23 +1064,17 @@ static int mtk_tx_map(struct sk_buff *sk new_desc = false; } @@ -159,7 +159,7 @@ Signed-off-by: David S. Miller tx_buf = mtk_desc_to_tx_buf(ring, txd); if (new_desc) -@@ -1073,20 +1083,17 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1074,20 +1084,17 @@ static int mtk_tx_map(struct sk_buff *sk tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; @@ -186,7 +186,7 @@ Signed-off-by: David S. Miller txd_pdma->txd2 |= TX_DMA_LS0; --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -842,6 +842,17 @@ enum mkt_eth_capabilities { +@@ -843,6 +843,17 @@ enum mkt_eth_capabilities { MTK_MUX_U3_GMAC2_TO_QPHY | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) diff --git a/target/linux/generic/backport-5.15/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch b/target/linux/generic/backport-5.15/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch index d3feef28eb8..f5206bba00b 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch @@ -14,7 +14,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -837,20 +837,20 @@ static void *mtk_max_lro_buf_alloc(gfp_t +@@ -838,20 +838,20 @@ static void *mtk_max_lro_buf_alloc(gfp_t /* the qdma core needs scratch memory to be setup */ static int mtk_init_fq_dma(struct mtk_eth *eth) { @@ -38,7 +38,7 @@ Signed-off-by: David S. Miller if (unlikely(!eth->scratch_head)) return -ENOMEM; -@@ -860,16 +860,19 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -861,16 +861,19 @@ static int mtk_init_fq_dma(struct mtk_et if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) return -ENOMEM; @@ -65,7 +65,7 @@ Signed-off-by: David S. Miller } mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD); -@@ -2169,6 +2172,7 @@ static int mtk_dma_init(struct mtk_eth * +@@ -2170,6 +2173,7 @@ static int mtk_dma_init(struct mtk_eth * static void mtk_dma_free(struct mtk_eth *eth) { @@ -73,7 +73,7 @@ Signed-off-by: David S. Miller int i; for (i = 0; i < MTK_MAC_COUNT; i++) -@@ -2176,9 +2180,8 @@ static void mtk_dma_free(struct mtk_eth +@@ -2177,9 +2181,8 @@ static void mtk_dma_free(struct mtk_eth netdev_reset_queue(eth->netdev[i]); if (eth->scratch_ring) { dma_free_coherent(eth->dma_dev, @@ -85,7 +85,7 @@ Signed-off-by: David S. Miller eth->scratch_ring = NULL; eth->phy_scratch_ring = 0; } -@@ -3390,6 +3393,9 @@ static const struct mtk_soc_data mt2701_ +@@ -3391,6 +3394,9 @@ static const struct mtk_soc_data mt2701_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7623_CLKS_BITMAP, .required_pctl = true, @@ -95,7 +95,7 @@ Signed-off-by: David S. Miller }; static const struct mtk_soc_data mt7621_data = { -@@ -3398,6 +3404,9 @@ static const struct mtk_soc_data mt7621_ +@@ -3399,6 +3405,9 @@ static const struct mtk_soc_data mt7621_ .required_clks = MT7621_CLKS_BITMAP, .required_pctl = false, .offload_version = 2, @@ -105,7 +105,7 @@ Signed-off-by: David S. Miller }; static const struct mtk_soc_data mt7622_data = { -@@ -3407,6 +3416,9 @@ static const struct mtk_soc_data mt7622_ +@@ -3408,6 +3417,9 @@ static const struct mtk_soc_data mt7622_ .required_clks = MT7622_CLKS_BITMAP, .required_pctl = false, .offload_version = 2, @@ -115,7 +115,7 @@ Signed-off-by: David S. Miller }; static const struct mtk_soc_data mt7623_data = { -@@ -3415,6 +3427,9 @@ static const struct mtk_soc_data mt7623_ +@@ -3416,6 +3428,9 @@ static const struct mtk_soc_data mt7623_ .required_clks = MT7623_CLKS_BITMAP, .required_pctl = true, .offload_version = 2, @@ -125,7 +125,7 @@ Signed-off-by: David S. Miller }; static const struct mtk_soc_data mt7629_data = { -@@ -3423,6 +3438,9 @@ static const struct mtk_soc_data mt7629_ +@@ -3424,6 +3439,9 @@ static const struct mtk_soc_data mt7629_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7629_CLKS_BITMAP, .required_pctl = false, @@ -135,7 +135,7 @@ Signed-off-by: David S. Miller }; static const struct mtk_soc_data rt5350_data = { -@@ -3430,6 +3448,9 @@ static const struct mtk_soc_data rt5350_ +@@ -3431,6 +3449,9 @@ static const struct mtk_soc_data rt5350_ .hw_features = MTK_HW_FEATURES_MT7628, .required_clks = MT7628_CLKS_BITMAP, .required_pctl = false, @@ -147,7 +147,7 @@ Signed-off-by: David S. Miller const struct of_device_id of_mtk_match[] = { --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -863,6 +863,7 @@ struct mtk_tx_dma_desc_info { +@@ -864,6 +864,7 @@ struct mtk_tx_dma_desc_info { * the target SoC * @required_pctl A bool value to show whether the SoC requires * the extra setup for those pins used by GMAC. @@ -155,7 +155,7 @@ Signed-off-by: David S. Miller */ struct mtk_soc_data { u32 ana_rgc3; -@@ -871,6 +872,9 @@ struct mtk_soc_data { +@@ -872,6 +873,9 @@ struct mtk_soc_data { bool required_pctl; u8 offload_version; netdev_features_t hw_features; diff --git a/target/linux/generic/backport-5.15/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch b/target/linux/generic/backport-5.15/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch index 01dbca0753b..ebe1ee3d59a 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch @@ -12,7 +12,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1624,8 +1624,10 @@ static int mtk_napi_rx(struct napi_struc +@@ -1625,8 +1625,10 @@ static int mtk_napi_rx(struct napi_struc static int mtk_tx_alloc(struct mtk_eth *eth) { @@ -24,7 +24,7 @@ Signed-off-by: David S. Miller ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf), GFP_KERNEL); -@@ -1641,8 +1643,10 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1642,8 +1644,10 @@ static int mtk_tx_alloc(struct mtk_eth * int next = (i + 1) % MTK_DMA_SIZE; u32 next_ptr = ring->phys + next * sz; @@ -37,7 +37,7 @@ Signed-off-by: David S. Miller } /* On MT7688 (PDMA only) this driver uses the ring->dma structs -@@ -1664,7 +1668,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1665,7 +1669,7 @@ static int mtk_tx_alloc(struct mtk_eth * ring->dma_size = MTK_DMA_SIZE; atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); ring->next_free = &ring->dma[0]; @@ -46,7 +46,7 @@ Signed-off-by: David S. Miller ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz)); ring->thresh = MAX_SKB_FRAGS; -@@ -1697,6 +1701,7 @@ no_tx_mem: +@@ -1698,6 +1702,7 @@ no_tx_mem: static void mtk_tx_clean(struct mtk_eth *eth) { @@ -54,7 +54,7 @@ Signed-off-by: David S. Miller struct mtk_tx_ring *ring = ð->tx_ring; int i; -@@ -1709,17 +1714,15 @@ static void mtk_tx_clean(struct mtk_eth +@@ -1710,17 +1715,15 @@ static void mtk_tx_clean(struct mtk_eth if (ring->dma) { dma_free_coherent(eth->dma_dev, diff --git a/target/linux/generic/backport-5.15/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch b/target/linux/generic/backport-5.15/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch index 1d23a178b4b..053412e7490 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch @@ -12,7 +12,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -890,10 +890,11 @@ static inline void *mtk_qdma_phys_to_vir +@@ -891,10 +891,11 @@ static inline void *mtk_qdma_phys_to_vir return ret + (desc - ring->phys); } @@ -27,7 +27,7 @@ Signed-off-by: David S. Miller return &ring->buf[idx]; } -@@ -1015,6 +1016,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1016,6 +1017,7 @@ static int mtk_tx_map(struct sk_buff *sk }; struct mtk_mac *mac = netdev_priv(dev); struct mtk_eth *eth = mac->hw; @@ -35,7 +35,7 @@ Signed-off-by: David S. Miller struct mtk_tx_dma *itxd, *txd; struct mtk_tx_dma *itxd_pdma, *txd_pdma; struct mtk_tx_buf *itx_buf, *tx_buf; -@@ -1026,7 +1028,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1027,7 +1029,7 @@ static int mtk_tx_map(struct sk_buff *sk if (itxd == ring->last_free) return -ENOMEM; @@ -44,7 +44,7 @@ Signed-off-by: David S. Miller memset(itx_buf, 0, sizeof(*itx_buf)); txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, -@@ -1054,7 +1056,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1055,7 +1057,7 @@ static int mtk_tx_map(struct sk_buff *sk while (frag_size) { bool new_desc = true; @@ -53,7 +53,7 @@ Signed-off-by: David S. Miller (i & 0x1)) { txd = mtk_qdma_phys_to_virt(ring, txd->txd2); txd_pdma = qdma_to_pdma(ring, txd); -@@ -1078,7 +1080,8 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1079,7 +1081,8 @@ static int mtk_tx_map(struct sk_buff *sk mtk_tx_set_dma_desc(dev, txd, &txd_info); @@ -63,7 +63,7 @@ Signed-off-by: David S. Miller if (new_desc) memset(tx_buf, 0, sizeof(*tx_buf)); tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; -@@ -1097,7 +1100,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1098,7 +1101,7 @@ static int mtk_tx_map(struct sk_buff *sk /* store skb to cleanup */ itx_buf->skb = skb; @@ -72,7 +72,7 @@ Signed-off-by: David S. Miller if (k & 0x1) txd_pdma->txd2 |= TX_DMA_LS0; else -@@ -1115,7 +1118,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1116,7 +1119,7 @@ static int mtk_tx_map(struct sk_buff *sk */ wmb(); @@ -81,7 +81,7 @@ Signed-off-by: David S. Miller if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || !netdev_xmit_more()) mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); -@@ -1129,13 +1132,13 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1130,13 +1133,13 @@ static int mtk_tx_map(struct sk_buff *sk err_dma: do { @@ -97,7 +97,7 @@ Signed-off-by: David S. Miller itxd_pdma->txd2 = TX_DMA_DESP2_DEF; itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); -@@ -1449,7 +1452,8 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -1450,7 +1453,8 @@ static int mtk_poll_tx_qdma(struct mtk_e if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0) break; diff --git a/target/linux/generic/backport-5.15/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch b/target/linux/generic/backport-5.15/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch index 2989d190d82..251d583f296 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch @@ -11,7 +11,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -905,9 +905,10 @@ static struct mtk_tx_dma *qdma_to_pdma(s +@@ -906,9 +906,10 @@ static struct mtk_tx_dma *qdma_to_pdma(s return ring->dma_pdma - ring->dma + dma; } @@ -24,7 +24,7 @@ Signed-off-by: David S. Miller } static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, -@@ -1123,8 +1124,10 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1124,8 +1125,10 @@ static int mtk_tx_map(struct sk_buff *sk !netdev_xmit_more()) mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); } else { diff --git a/target/linux/generic/backport-5.15/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch b/target/linux/generic/backport-5.15/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch index 5436e92dbea..ec206f28d64 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch @@ -13,7 +13,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1775,7 +1775,7 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1776,7 +1776,7 @@ static int mtk_rx_alloc(struct mtk_eth * } ring->dma = dma_alloc_coherent(eth->dma_dev, @@ -22,7 +22,7 @@ Signed-off-by: David S. Miller &ring->phys, GFP_KERNEL); if (!ring->dma) return -ENOMEM; -@@ -1833,9 +1833,8 @@ static void mtk_rx_clean(struct mtk_eth +@@ -1834,9 +1834,8 @@ static void mtk_rx_clean(struct mtk_eth if (ring->dma) { dma_free_coherent(eth->dma_dev, @@ -34,7 +34,7 @@ Signed-off-by: David S. Miller ring->dma = NULL; } } -@@ -3405,6 +3404,7 @@ static const struct mtk_soc_data mt2701_ +@@ -3406,6 +3405,7 @@ static const struct mtk_soc_data mt2701_ .required_pctl = true, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), @@ -42,7 +42,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3416,6 +3416,7 @@ static const struct mtk_soc_data mt7621_ +@@ -3417,6 +3417,7 @@ static const struct mtk_soc_data mt7621_ .offload_version = 2, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), @@ -50,7 +50,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3428,6 +3429,7 @@ static const struct mtk_soc_data mt7622_ +@@ -3429,6 +3430,7 @@ static const struct mtk_soc_data mt7622_ .offload_version = 2, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), @@ -58,7 +58,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3439,6 +3441,7 @@ static const struct mtk_soc_data mt7623_ +@@ -3440,6 +3442,7 @@ static const struct mtk_soc_data mt7623_ .offload_version = 2, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), @@ -66,7 +66,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3450,6 +3453,7 @@ static const struct mtk_soc_data mt7629_ +@@ -3451,6 +3454,7 @@ static const struct mtk_soc_data mt7629_ .required_pctl = false, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), @@ -74,7 +74,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3460,6 +3464,7 @@ static const struct mtk_soc_data rt5350_ +@@ -3461,6 +3465,7 @@ static const struct mtk_soc_data rt5350_ .required_pctl = false, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), @@ -84,7 +84,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -864,6 +864,7 @@ struct mtk_tx_dma_desc_info { +@@ -865,6 +865,7 @@ struct mtk_tx_dma_desc_info { * @required_pctl A bool value to show whether the SoC requires * the extra setup for those pins used by GMAC. * @txd_size Tx DMA descriptor size. @@ -92,7 +92,7 @@ Signed-off-by: David S. Miller */ struct mtk_soc_data { u32 ana_rgc3; -@@ -874,6 +875,7 @@ struct mtk_soc_data { +@@ -875,6 +876,7 @@ struct mtk_soc_data { netdev_features_t hw_features; struct { u32 txd_size; diff --git a/target/linux/generic/backport-5.15/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch b/target/linux/generic/backport-5.15/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch index 53af586b6c0..eb92b8c7a22 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch @@ -12,7 +12,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1264,9 +1264,12 @@ static struct mtk_rx_ring *mtk_get_rx_ri +@@ -1265,9 +1265,12 @@ static struct mtk_rx_ring *mtk_get_rx_ri return ð->rx_ring[0]; for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) { @@ -26,7 +26,7 @@ Signed-off-by: David S. Miller ring->calc_idx_update = true; return ring; } -@@ -1317,7 +1320,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1318,7 +1321,7 @@ static int mtk_poll_rx(struct napi_struc goto rx_done; idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); @@ -35,7 +35,7 @@ Signed-off-by: David S. Miller data = ring->data[idx]; if (!mtk_rx_get_desc(&trxd, rxd)) -@@ -1509,7 +1512,7 @@ static int mtk_poll_tx_pdma(struct mtk_e +@@ -1510,7 +1513,7 @@ static int mtk_poll_tx_pdma(struct mtk_e mtk_tx_unmap(eth, tx_buf, true); diff --git a/target/linux/generic/backport-5.15/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch b/target/linux/generic/backport-5.15/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch index 1f4fa1dfb50..456eec247c5 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch @@ -14,7 +14,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1784,18 +1784,25 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1785,18 +1785,25 @@ static int mtk_rx_alloc(struct mtk_eth * return -ENOMEM; for (i = 0; i < rx_dma_size; i++) { @@ -43,7 +43,7 @@ Signed-off-by: David S. Miller } ring->dma_size = rx_dma_size; ring->calc_idx_update = false; -@@ -1820,14 +1827,17 @@ static void mtk_rx_clean(struct mtk_eth +@@ -1821,14 +1828,17 @@ static void mtk_rx_clean(struct mtk_eth if (ring->data && ring->dma) { for (i = 0; i < ring->dma_size; i++) { diff --git a/target/linux/generic/backport-5.15/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch b/target/linux/generic/backport-5.15/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch index 945d4d9bb2e..272f782877f 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch @@ -73,7 +73,7 @@ Signed-off-by: David S. Miller /* strings used by ethtool */ static const struct mtk_ethtool_stats { char str[ETH_GSTRING_LEN]; -@@ -618,8 +671,8 @@ static inline void mtk_tx_irq_disable(st +@@ -619,8 +672,8 @@ static inline void mtk_tx_irq_disable(st u32 val; spin_lock_irqsave(ð->tx_irq_lock, flags); @@ -84,7 +84,7 @@ Signed-off-by: David S. Miller spin_unlock_irqrestore(ð->tx_irq_lock, flags); } -@@ -629,8 +682,8 @@ static inline void mtk_tx_irq_enable(str +@@ -630,8 +683,8 @@ static inline void mtk_tx_irq_enable(str u32 val; spin_lock_irqsave(ð->tx_irq_lock, flags); @@ -95,7 +95,7 @@ Signed-off-by: David S. Miller spin_unlock_irqrestore(ð->tx_irq_lock, flags); } -@@ -640,8 +693,8 @@ static inline void mtk_rx_irq_disable(st +@@ -641,8 +694,8 @@ static inline void mtk_rx_irq_disable(st u32 val; spin_lock_irqsave(ð->rx_irq_lock, flags); @@ -106,7 +106,7 @@ Signed-off-by: David S. Miller spin_unlock_irqrestore(ð->rx_irq_lock, flags); } -@@ -651,8 +704,8 @@ static inline void mtk_rx_irq_enable(str +@@ -652,8 +705,8 @@ static inline void mtk_rx_irq_enable(str u32 val; spin_lock_irqsave(ð->rx_irq_lock, flags); @@ -117,7 +117,7 @@ Signed-off-by: David S. Miller spin_unlock_irqrestore(ð->rx_irq_lock, flags); } -@@ -703,39 +756,39 @@ void mtk_stats_update_mac(struct mtk_mac +@@ -704,39 +757,39 @@ void mtk_stats_update_mac(struct mtk_mac hw_stats->rx_checksum_errors += mtk_r32(mac->hw, MT7628_SDM_CS_ERR); } else { @@ -172,7 +172,7 @@ Signed-off-by: David S. Miller } u64_stats_update_end(&hw_stats->syncp); -@@ -875,10 +928,10 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -876,10 +929,10 @@ static int mtk_init_fq_dma(struct mtk_et txd->txd4 = 0; } @@ -187,7 +187,7 @@ Signed-off-by: David S. Miller return 0; } -@@ -1122,7 +1175,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1123,7 +1176,7 @@ static int mtk_tx_map(struct sk_buff *sk if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || !netdev_xmit_more()) @@ -196,7 +196,7 @@ Signed-off-by: David S. Miller } else { int next_idx; -@@ -1439,6 +1492,7 @@ rx_done: +@@ -1440,6 +1493,7 @@ rx_done: static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, unsigned int *done, unsigned int *bytes) { @@ -204,7 +204,7 @@ Signed-off-by: David S. Miller struct mtk_tx_ring *ring = ð->tx_ring; struct mtk_tx_dma *desc; struct sk_buff *skb; -@@ -1446,7 +1500,7 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -1447,7 +1501,7 @@ static int mtk_poll_tx_qdma(struct mtk_e u32 cpu, dma; cpu = ring->last_free_ptr; @@ -213,7 +213,7 @@ Signed-off-by: David S. Miller desc = mtk_qdma_phys_to_virt(ring, cpu); -@@ -1481,7 +1535,7 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -1482,7 +1536,7 @@ static int mtk_poll_tx_qdma(struct mtk_e } ring->last_free_ptr = cpu; @@ -222,7 +222,7 @@ Signed-off-by: David S. Miller return budget; } -@@ -1574,24 +1628,25 @@ static void mtk_handle_status_irq(struct +@@ -1575,24 +1629,25 @@ static void mtk_handle_status_irq(struct static int mtk_napi_tx(struct napi_struct *napi, int budget) { struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi); @@ -252,7 +252,7 @@ Signed-off-by: David S. Miller return budget; if (napi_complete_done(napi, tx_done)) -@@ -1603,6 +1658,7 @@ static int mtk_napi_tx(struct napi_struc +@@ -1604,6 +1659,7 @@ static int mtk_napi_tx(struct napi_struc static int mtk_napi_rx(struct napi_struct *napi, int budget) { struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); @@ -260,7 +260,7 @@ Signed-off-by: David S. Miller int rx_done_total = 0; mtk_handle_status_irq(eth); -@@ -1610,21 +1666,21 @@ static int mtk_napi_rx(struct napi_struc +@@ -1611,21 +1667,21 @@ static int mtk_napi_rx(struct napi_struc do { int rx_done; @@ -286,7 +286,7 @@ Signed-off-by: David S. Miller if (napi_complete_done(napi, rx_done_total)) mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); -@@ -1687,20 +1743,20 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1688,20 +1744,20 @@ static int mtk_tx_alloc(struct mtk_eth * */ wmb(); @@ -314,7 +314,7 @@ Signed-off-by: David S. Miller } return 0; -@@ -1739,6 +1795,7 @@ static void mtk_tx_clean(struct mtk_eth +@@ -1740,6 +1796,7 @@ static void mtk_tx_clean(struct mtk_eth static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) { @@ -322,7 +322,7 @@ Signed-off-by: David S. Miller struct mtk_rx_ring *ring; int rx_data_len, rx_dma_size; int i; -@@ -1807,16 +1864,18 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1808,16 +1865,18 @@ static int mtk_rx_alloc(struct mtk_eth * ring->dma_size = rx_dma_size; ring->calc_idx_update = false; ring->calc_idx = rx_dma_size - 1; @@ -345,7 +345,7 @@ Signed-off-by: David S. Miller return 0; } -@@ -2125,9 +2184,9 @@ static int mtk_dma_busy_wait(struct mtk_ +@@ -2126,9 +2185,9 @@ static int mtk_dma_busy_wait(struct mtk_ u32 val; if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) @@ -357,7 +357,7 @@ Signed-off-by: David S. Miller ret = readx_poll_timeout_atomic(__raw_readl, eth->base + reg, val, !(val & (MTK_RX_DMA_BUSY | MTK_TX_DMA_BUSY)), -@@ -2185,8 +2244,8 @@ static int mtk_dma_init(struct mtk_eth * +@@ -2186,8 +2245,8 @@ static int mtk_dma_init(struct mtk_eth * * automatically */ mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN | @@ -368,7 +368,7 @@ Signed-off-by: David S. Miller } return 0; -@@ -2260,13 +2319,14 @@ static irqreturn_t mtk_handle_irq_tx(int +@@ -2261,13 +2320,14 @@ static irqreturn_t mtk_handle_irq_tx(int static irqreturn_t mtk_handle_irq(int irq, void *_eth) { struct mtk_eth *eth = _eth; @@ -387,7 +387,7 @@ Signed-off-by: David S. Miller mtk_handle_irq_tx(irq, _eth); } -@@ -2290,6 +2350,7 @@ static void mtk_poll_controller(struct n +@@ -2291,6 +2351,7 @@ static void mtk_poll_controller(struct n static int mtk_start_dma(struct mtk_eth *eth) { u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; @@ -395,7 +395,7 @@ Signed-off-by: David S. Miller int err; err = mtk_dma_init(eth); -@@ -2304,16 +2365,15 @@ static int mtk_start_dma(struct mtk_eth +@@ -2305,16 +2366,15 @@ static int mtk_start_dma(struct mtk_eth MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | MTK_RX_BT_32DWORDS, @@ -415,7 +415,7 @@ Signed-off-by: David S. Miller } return 0; -@@ -2439,8 +2499,8 @@ static int mtk_stop(struct net_device *d +@@ -2440,8 +2500,8 @@ static int mtk_stop(struct net_device *d cancel_work_sync(ð->tx_dim.work); if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) @@ -426,7 +426,7 @@ Signed-off-by: David S. Miller mtk_dma_free(eth); -@@ -2494,6 +2554,7 @@ static void mtk_dim_rx(struct work_struc +@@ -2495,6 +2555,7 @@ static void mtk_dim_rx(struct work_struc { struct dim *dim = container_of(work, struct dim, work); struct mtk_eth *eth = container_of(dim, struct mtk_eth, rx_dim); @@ -434,7 +434,7 @@ Signed-off-by: David S. Miller struct dim_cq_moder cur_profile; u32 val, cur; -@@ -2501,7 +2562,7 @@ static void mtk_dim_rx(struct work_struc +@@ -2502,7 +2563,7 @@ static void mtk_dim_rx(struct work_struc dim->profile_ix); spin_lock_bh(ð->dim_lock); @@ -443,7 +443,7 @@ Signed-off-by: David S. Miller val &= MTK_PDMA_DELAY_TX_MASK; val |= MTK_PDMA_DELAY_RX_EN; -@@ -2511,9 +2572,9 @@ static void mtk_dim_rx(struct work_struc +@@ -2512,9 +2573,9 @@ static void mtk_dim_rx(struct work_struc cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK); val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT; @@ -455,7 +455,7 @@ Signed-off-by: David S. Miller spin_unlock_bh(ð->dim_lock); -@@ -2524,6 +2585,7 @@ static void mtk_dim_tx(struct work_struc +@@ -2525,6 +2586,7 @@ static void mtk_dim_tx(struct work_struc { struct dim *dim = container_of(work, struct dim, work); struct mtk_eth *eth = container_of(dim, struct mtk_eth, tx_dim); @@ -463,7 +463,7 @@ Signed-off-by: David S. Miller struct dim_cq_moder cur_profile; u32 val, cur; -@@ -2531,7 +2593,7 @@ static void mtk_dim_tx(struct work_struc +@@ -2532,7 +2594,7 @@ static void mtk_dim_tx(struct work_struc dim->profile_ix); spin_lock_bh(ð->dim_lock); @@ -472,7 +472,7 @@ Signed-off-by: David S. Miller val &= MTK_PDMA_DELAY_RX_MASK; val |= MTK_PDMA_DELAY_TX_EN; -@@ -2541,9 +2603,9 @@ static void mtk_dim_tx(struct work_struc +@@ -2542,9 +2604,9 @@ static void mtk_dim_tx(struct work_struc cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK); val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT; @@ -484,7 +484,7 @@ Signed-off-by: David S. Miller spin_unlock_bh(ð->dim_lock); -@@ -2554,6 +2616,7 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -2555,6 +2617,7 @@ static int mtk_hw_init(struct mtk_eth *e { u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | ETHSYS_DMA_AG_MAP_PPE; @@ -492,7 +492,7 @@ Signed-off-by: David S. Miller int i, val, ret; if (test_and_set_bit(MTK_HW_INIT, ð->state)) -@@ -2628,10 +2691,10 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -2629,10 +2692,10 @@ static int mtk_hw_init(struct mtk_eth *e mtk_rx_irq_disable(eth, ~0); /* FE int grouping */ @@ -507,7 +507,7 @@ Signed-off-by: David S. Miller mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); return 0; -@@ -3170,14 +3233,6 @@ static int mtk_probe(struct platform_dev +@@ -3171,14 +3234,6 @@ static int mtk_probe(struct platform_dev if (IS_ERR(eth->base)) return PTR_ERR(eth->base); @@ -522,7 +522,7 @@ Signed-off-by: David S. Miller if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { eth->rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA; eth->ip_align = NET_IP_ALIGN; -@@ -3411,6 +3466,7 @@ static int mtk_remove(struct platform_de +@@ -3412,6 +3467,7 @@ static int mtk_remove(struct platform_de } static const struct mtk_soc_data mt2701_data = { @@ -530,7 +530,7 @@ Signed-off-by: David S. Miller .caps = MT7623_CAPS | MTK_HWLRO, .hw_features = MTK_HW_FEATURES, .required_clks = MT7623_CLKS_BITMAP, -@@ -3422,6 +3478,7 @@ static const struct mtk_soc_data mt2701_ +@@ -3423,6 +3479,7 @@ static const struct mtk_soc_data mt2701_ }; static const struct mtk_soc_data mt7621_data = { @@ -538,7 +538,7 @@ Signed-off-by: David S. Miller .caps = MT7621_CAPS, .hw_features = MTK_HW_FEATURES, .required_clks = MT7621_CLKS_BITMAP, -@@ -3434,6 +3491,7 @@ static const struct mtk_soc_data mt7621_ +@@ -3435,6 +3492,7 @@ static const struct mtk_soc_data mt7621_ }; static const struct mtk_soc_data mt7622_data = { @@ -546,7 +546,7 @@ Signed-off-by: David S. Miller .ana_rgc3 = 0x2028, .caps = MT7622_CAPS | MTK_HWLRO, .hw_features = MTK_HW_FEATURES, -@@ -3447,6 +3505,7 @@ static const struct mtk_soc_data mt7622_ +@@ -3448,6 +3506,7 @@ static const struct mtk_soc_data mt7622_ }; static const struct mtk_soc_data mt7623_data = { @@ -554,7 +554,7 @@ Signed-off-by: David S. Miller .caps = MT7623_CAPS | MTK_HWLRO, .hw_features = MTK_HW_FEATURES, .required_clks = MT7623_CLKS_BITMAP, -@@ -3459,6 +3518,7 @@ static const struct mtk_soc_data mt7623_ +@@ -3460,6 +3519,7 @@ static const struct mtk_soc_data mt7623_ }; static const struct mtk_soc_data mt7629_data = { @@ -562,7 +562,7 @@ Signed-off-by: David S. Miller .ana_rgc3 = 0x128, .caps = MT7629_CAPS | MTK_HWLRO, .hw_features = MTK_HW_FEATURES, -@@ -3471,6 +3531,7 @@ static const struct mtk_soc_data mt7629_ +@@ -3472,6 +3532,7 @@ static const struct mtk_soc_data mt7629_ }; static const struct mtk_soc_data rt5350_data = { @@ -748,7 +748,7 @@ Signed-off-by: David S. Miller #define MTK_STAT_OFFSET 0x40 #define MTK_WDMA0_BASE 0x2800 -@@ -853,8 +762,46 @@ struct mtk_tx_dma_desc_info { +@@ -854,8 +763,46 @@ struct mtk_tx_dma_desc_info { u8 last:1; }; @@ -795,7 +795,7 @@ Signed-off-by: David S. Miller * @ana_rgc3: The offset for register ANA_RGC3 related to * sgmiisys syscon * @caps Flags shown the extra capability for the SoC -@@ -867,6 +814,7 @@ struct mtk_tx_dma_desc_info { +@@ -868,6 +815,7 @@ struct mtk_tx_dma_desc_info { * @rxd_size Rx DMA descriptor size. */ struct mtk_soc_data { @@ -803,7 +803,7 @@ Signed-off-by: David S. Miller u32 ana_rgc3; u32 caps; u32 required_clks; -@@ -994,8 +942,6 @@ struct mtk_eth { +@@ -995,8 +943,6 @@ struct mtk_eth { u32 tx_bytes; struct dim tx_dim; diff --git a/target/linux/generic/backport-5.15/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch b/target/linux/generic/backport-5.15/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch index d1f19d6a454..4d6c94b13b8 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch @@ -13,7 +13,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -862,8 +862,8 @@ static inline int mtk_max_buf_size(int f +@@ -863,8 +863,8 @@ static inline int mtk_max_buf_size(int f return buf_size; } @@ -24,7 +24,7 @@ Signed-off-by: David S. Miller { rxd->rxd2 = READ_ONCE(dma_rxd->rxd2); if (!(rxd->rxd2 & RX_DMA_DONE)) -@@ -872,6 +872,10 @@ static inline bool mtk_rx_get_desc(struc +@@ -873,6 +873,10 @@ static inline bool mtk_rx_get_desc(struc rxd->rxd1 = READ_ONCE(dma_rxd->rxd1); rxd->rxd3 = READ_ONCE(dma_rxd->rxd3); rxd->rxd4 = READ_ONCE(dma_rxd->rxd4); @@ -35,7 +35,7 @@ Signed-off-by: David S. Miller return true; } -@@ -916,7 +920,7 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -917,7 +921,7 @@ static int mtk_init_fq_dma(struct mtk_et phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1); for (i = 0; i < cnt; i++) { @@ -44,7 +44,7 @@ Signed-off-by: David S. Miller txd = (void *)eth->scratch_ring + i * soc->txrx.txd_size; txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; -@@ -926,6 +930,12 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -927,6 +931,12 @@ static int mtk_init_fq_dma(struct mtk_et txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); txd->txd4 = 0; @@ -57,7 +57,7 @@ Signed-off-by: David S. Miller } mtk_w32(eth, eth->phy_scratch_ring, soc->reg_map->qdma.fq_head); -@@ -1029,10 +1039,12 @@ static void setup_tx_buf(struct mtk_eth +@@ -1030,10 +1040,12 @@ static void setup_tx_buf(struct mtk_eth } } @@ -72,7 +72,7 @@ Signed-off-by: David S. Miller u32 data; WRITE_ONCE(desc->txd1, info->addr); -@@ -1056,6 +1068,59 @@ static void mtk_tx_set_dma_desc(struct n +@@ -1057,6 +1069,59 @@ static void mtk_tx_set_dma_desc(struct n WRITE_ONCE(desc->txd4, data); } @@ -132,7 +132,7 @@ Signed-off-by: David S. Miller static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, int tx_num, struct mtk_tx_ring *ring, bool gso) { -@@ -1064,6 +1129,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1065,6 +1130,7 @@ static int mtk_tx_map(struct sk_buff *sk .gso = gso, .csum = skb->ip_summed == CHECKSUM_PARTIAL, .vlan = skb_vlan_tag_present(skb), @@ -140,7 +140,7 @@ Signed-off-by: David S. Miller .vlan_tci = skb_vlan_tag_get(skb), .first = true, .last = !skb_is_nonlinear(skb), -@@ -1123,7 +1189,9 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1124,7 +1190,9 @@ static int mtk_tx_map(struct sk_buff *sk } memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); @@ -151,7 +151,7 @@ Signed-off-by: David S. Miller txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && !(frag_size - txd_info.size); txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, -@@ -1204,17 +1272,16 @@ err_dma: +@@ -1205,17 +1273,16 @@ err_dma: return -ENOMEM; } @@ -172,7 +172,7 @@ Signed-off-by: David S. Miller } } else { nfrags += skb_shinfo(skb)->nr_frags; -@@ -1266,7 +1333,7 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1267,7 +1334,7 @@ static netdev_tx_t mtk_start_xmit(struct if (unlikely(test_bit(MTK_RESETTING, ð->state))) goto drop; @@ -181,7 +181,7 @@ Signed-off-by: David S. Miller if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { netif_stop_queue(dev); netif_err(eth, tx_queued, dev, -@@ -1358,7 +1425,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1359,7 +1426,7 @@ static int mtk_poll_rx(struct napi_struc int idx; struct sk_buff *skb; u8 *data, *new_data; @@ -190,7 +190,7 @@ Signed-off-by: David S. Miller int done = 0, bytes = 0; while (done < budget) { -@@ -1366,7 +1433,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1367,7 +1434,7 @@ static int mtk_poll_rx(struct napi_struc unsigned int pktlen; dma_addr_t dma_addr; u32 hash, reason; @@ -199,7 +199,7 @@ Signed-off-by: David S. Miller ring = mtk_get_rx_ring(eth); if (unlikely(!ring)) -@@ -1376,16 +1443,15 @@ static int mtk_poll_rx(struct napi_struc +@@ -1377,16 +1444,15 @@ static int mtk_poll_rx(struct napi_struc rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; data = ring->data[idx]; @@ -222,7 +222,7 @@ Signed-off-by: David S. Miller if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || !eth->netdev[mac])) -@@ -1431,7 +1497,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1432,7 +1498,7 @@ static int mtk_poll_rx(struct napi_struc pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); skb->dev = netdev; skb_put(skb, pktlen); @@ -231,7 +231,7 @@ Signed-off-by: David S. Miller skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); -@@ -1449,10 +1515,25 @@ static int mtk_poll_rx(struct napi_struc +@@ -1450,10 +1516,25 @@ static int mtk_poll_rx(struct napi_struc mtk_ppe_check_skb(eth->ppe, skb, trxd.rxd4 & MTK_RXD4_FOE_ENTRY); @@ -261,7 +261,7 @@ Signed-off-by: David S. Miller skb_record_rx_queue(skb, 0); napi_gro_receive(napi, skb); -@@ -1464,7 +1545,7 @@ release_desc: +@@ -1465,7 +1546,7 @@ release_desc: if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) rxd->rxd2 = RX_DMA_LSO; else @@ -270,7 +270,7 @@ Signed-off-by: David S. Miller ring->calc_idx = idx; -@@ -1666,7 +1747,8 @@ static int mtk_napi_rx(struct napi_struc +@@ -1667,7 +1748,8 @@ static int mtk_napi_rx(struct napi_struc do { int rx_done; @@ -280,7 +280,7 @@ Signed-off-by: David S. Miller rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth); rx_done_total += rx_done; -@@ -1680,10 +1762,11 @@ static int mtk_napi_rx(struct napi_struc +@@ -1681,10 +1763,11 @@ static int mtk_napi_rx(struct napi_struc if (rx_done_total == budget) return budget; @@ -294,7 +294,7 @@ Signed-off-by: David S. Miller return rx_done_total; } -@@ -1693,7 +1776,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1694,7 +1777,7 @@ static int mtk_tx_alloc(struct mtk_eth * const struct mtk_soc_data *soc = eth->soc; struct mtk_tx_ring *ring = ð->tx_ring; int i, sz = soc->txrx.txd_size; @@ -303,7 +303,7 @@ Signed-off-by: David S. Miller ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf), GFP_KERNEL); -@@ -1713,13 +1796,19 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1714,13 +1797,19 @@ static int mtk_tx_alloc(struct mtk_eth * txd->txd2 = next_ptr; txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; txd->txd4 = 0; @@ -324,7 +324,7 @@ Signed-off-by: David S. Miller ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, &ring->phys_pdma, GFP_KERNEL); if (!ring->dma_pdma) -@@ -1799,13 +1888,11 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1800,13 +1889,11 @@ static int mtk_rx_alloc(struct mtk_eth * struct mtk_rx_ring *ring; int rx_data_len, rx_dma_size; int i; @@ -338,7 +338,7 @@ Signed-off-by: David S. Miller } else { ring = ð->rx_ring[ring_no]; } -@@ -1841,7 +1928,7 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1842,7 +1929,7 @@ static int mtk_rx_alloc(struct mtk_eth * return -ENOMEM; for (i = 0; i < rx_dma_size; i++) { @@ -347,7 +347,7 @@ Signed-off-by: David S. Miller dma_addr_t dma_addr = dma_map_single(eth->dma_dev, ring->data[i] + NET_SKB_PAD + eth->ip_align, -@@ -1856,26 +1943,47 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1857,26 +1944,47 @@ static int mtk_rx_alloc(struct mtk_eth * if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) rxd->rxd2 = RX_DMA_LSO; else @@ -403,7 +403,7 @@ Signed-off-by: David S. Miller return 0; } -@@ -2297,7 +2405,7 @@ static irqreturn_t mtk_handle_irq_rx(int +@@ -2298,7 +2406,7 @@ static irqreturn_t mtk_handle_irq_rx(int eth->rx_events++; if (likely(napi_schedule_prep(ð->rx_napi))) { __napi_schedule(ð->rx_napi); @@ -412,7 +412,7 @@ Signed-off-by: David S. Miller } return IRQ_HANDLED; -@@ -2321,8 +2429,10 @@ static irqreturn_t mtk_handle_irq(int ir +@@ -2322,8 +2430,10 @@ static irqreturn_t mtk_handle_irq(int ir struct mtk_eth *eth = _eth; const struct mtk_reg_map *reg_map = eth->soc->reg_map; @@ -425,7 +425,7 @@ Signed-off-by: David S. Miller mtk_handle_irq_rx(irq, _eth); } if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) { -@@ -2340,16 +2450,16 @@ static void mtk_poll_controller(struct n +@@ -2341,16 +2451,16 @@ static void mtk_poll_controller(struct n struct mtk_eth *eth = mac->hw; mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); @@ -445,7 +445,7 @@ Signed-off-by: David S. Miller const struct mtk_reg_map *reg_map = eth->soc->reg_map; int err; -@@ -2360,12 +2470,19 @@ static int mtk_start_dma(struct mtk_eth +@@ -2361,12 +2471,19 @@ static int mtk_start_dma(struct mtk_eth } if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { @@ -471,7 +471,7 @@ Signed-off-by: David S. Miller mtk_w32(eth, MTK_RX_DMA_EN | rx_2b_offset | MTK_RX_BT_32DWORDS | MTK_MULTI_EN, -@@ -2439,7 +2556,7 @@ static int mtk_open(struct net_device *d +@@ -2440,7 +2557,7 @@ static int mtk_open(struct net_device *d napi_enable(ð->tx_napi); napi_enable(ð->rx_napi); mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); @@ -480,7 +480,7 @@ Signed-off-by: David S. Miller refcount_set(ð->dma_refcnt, 1); } else -@@ -2491,7 +2608,7 @@ static int mtk_stop(struct net_device *d +@@ -2492,7 +2609,7 @@ static int mtk_stop(struct net_device *d mtk_gdm_config(eth, MTK_GDMA_DROP_ALL); mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); @@ -489,7 +489,7 @@ Signed-off-by: David S. Miller napi_disable(ð->tx_napi); napi_disable(ð->rx_napi); -@@ -2651,9 +2768,25 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -2652,9 +2769,25 @@ static int mtk_hw_init(struct mtk_eth *e return 0; } @@ -518,7 +518,7 @@ Signed-off-by: David S. Miller if (eth->pctl) { /* Set GE2 driving and slew rate */ -@@ -2692,11 +2825,47 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -2693,11 +2826,47 @@ static int mtk_hw_init(struct mtk_eth *e /* FE int grouping */ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp); @@ -568,7 +568,7 @@ Signed-off-by: David S. Miller return 0; err_disable_pm: -@@ -3233,12 +3402,8 @@ static int mtk_probe(struct platform_dev +@@ -3234,12 +3403,8 @@ static int mtk_probe(struct platform_dev if (IS_ERR(eth->base)) return PTR_ERR(eth->base); @@ -582,7 +582,7 @@ Signed-off-by: David S. Miller spin_lock_init(ð->page_lock); spin_lock_init(ð->tx_irq_lock); -@@ -3474,6 +3639,10 @@ static const struct mtk_soc_data mt2701_ +@@ -3475,6 +3640,10 @@ static const struct mtk_soc_data mt2701_ .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), @@ -593,7 +593,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3487,6 +3656,10 @@ static const struct mtk_soc_data mt7621_ +@@ -3488,6 +3657,10 @@ static const struct mtk_soc_data mt7621_ .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), @@ -604,7 +604,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3501,6 +3674,10 @@ static const struct mtk_soc_data mt7622_ +@@ -3502,6 +3675,10 @@ static const struct mtk_soc_data mt7622_ .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), @@ -615,7 +615,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3514,6 +3691,10 @@ static const struct mtk_soc_data mt7623_ +@@ -3515,6 +3692,10 @@ static const struct mtk_soc_data mt7623_ .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), @@ -626,7 +626,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3527,6 +3708,10 @@ static const struct mtk_soc_data mt7629_ +@@ -3528,6 +3709,10 @@ static const struct mtk_soc_data mt7629_ .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), @@ -637,7 +637,7 @@ Signed-off-by: David S. Miller }, }; -@@ -3539,6 +3724,10 @@ static const struct mtk_soc_data rt5350_ +@@ -3540,6 +3725,10 @@ static const struct mtk_soc_data rt5350_ .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), @@ -804,7 +804,7 @@ Signed-off-by: David S. Miller /* PHY Indirect Access Control registers */ #define MTK_PHY_IAC 0x10004 #define PHY_IAC_ACCESS BIT(31) -@@ -370,6 +434,16 @@ +@@ -371,6 +435,16 @@ #define ETHSYS_TRGMII_MT7621_DDR_PLL BIT(5) /* ethernet reset control register */ @@ -821,7 +821,7 @@ Signed-off-by: David S. Miller #define ETHSYS_RSTCTRL 0x34 #define RSTCTRL_FE BIT(6) #define RSTCTRL_PPE BIT(31) -@@ -453,6 +527,17 @@ struct mtk_rx_dma { +@@ -454,6 +528,17 @@ struct mtk_rx_dma { unsigned int rxd4; } __packed __aligned(4); @@ -839,7 +839,7 @@ Signed-off-by: David S. Miller struct mtk_tx_dma { unsigned int txd1; unsigned int txd2; -@@ -460,6 +545,17 @@ struct mtk_tx_dma { +@@ -461,6 +546,17 @@ struct mtk_tx_dma { unsigned int txd4; } __packed __aligned(4); @@ -857,7 +857,7 @@ Signed-off-by: David S. Miller struct mtk_eth; struct mtk_mac; -@@ -646,7 +742,9 @@ enum mkt_eth_capabilities { +@@ -647,7 +743,9 @@ enum mkt_eth_capabilities { MTK_SHARED_INT_BIT, MTK_TRGMII_MT7621_CLK_BIT, MTK_QDMA_BIT, @@ -867,7 +867,7 @@ Signed-off-by: David S. Miller /* MUX BITS*/ MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, -@@ -678,7 +776,9 @@ enum mkt_eth_capabilities { +@@ -679,7 +777,9 @@ enum mkt_eth_capabilities { #define MTK_SHARED_INT BIT(MTK_SHARED_INT_BIT) #define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT) #define MTK_QDMA BIT(MTK_QDMA_BIT) @@ -877,7 +877,7 @@ Signed-off-by: David S. Miller #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) -@@ -755,6 +855,7 @@ struct mtk_tx_dma_desc_info { +@@ -756,6 +856,7 @@ struct mtk_tx_dma_desc_info { dma_addr_t addr; u32 size; u16 vlan_tci; @@ -885,7 +885,7 @@ Signed-off-by: David S. Miller u8 gso:1; u8 csum:1; u8 vlan:1; -@@ -812,6 +913,10 @@ struct mtk_reg_map { +@@ -813,6 +914,10 @@ struct mtk_reg_map { * the extra setup for those pins used by GMAC. * @txd_size Tx DMA descriptor size. * @rxd_size Rx DMA descriptor size. @@ -896,7 +896,7 @@ Signed-off-by: David S. Miller */ struct mtk_soc_data { const struct mtk_reg_map *reg_map; -@@ -824,6 +929,10 @@ struct mtk_soc_data { +@@ -825,6 +930,10 @@ struct mtk_soc_data { struct { u32 txd_size; u32 rxd_size; @@ -907,7 +907,7 @@ Signed-off-by: David S. Miller } txrx; }; -@@ -942,7 +1051,6 @@ struct mtk_eth { +@@ -943,7 +1052,6 @@ struct mtk_eth { u32 tx_bytes; struct dim tx_dim; diff --git a/target/linux/generic/backport-5.15/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch b/target/linux/generic/backport-5.15/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch index a9566392391..1ecb5e71b3a 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch @@ -10,7 +10,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -946,18 +946,15 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -947,18 +947,15 @@ static int mtk_init_fq_dma(struct mtk_et return 0; } @@ -33,7 +33,7 @@ Signed-off-by: David S. Miller return &ring->buf[idx]; } -@@ -965,13 +962,12 @@ static struct mtk_tx_buf *mtk_desc_to_tx +@@ -966,13 +963,12 @@ static struct mtk_tx_buf *mtk_desc_to_tx static struct mtk_tx_dma *qdma_to_pdma(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma) { @@ -50,7 +50,7 @@ Signed-off-by: David S. Miller } static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, -@@ -1388,7 +1384,7 @@ static struct mtk_rx_ring *mtk_get_rx_ri +@@ -1389,7 +1385,7 @@ static struct mtk_rx_ring *mtk_get_rx_ri ring = ð->rx_ring[i]; idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); @@ -59,7 +59,7 @@ Signed-off-by: David S. Miller if (rxd->rxd2 & RX_DMA_DONE) { ring->calc_idx_update = true; return ring; -@@ -1440,7 +1436,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1441,7 +1437,7 @@ static int mtk_poll_rx(struct napi_struc goto rx_done; idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); @@ -68,7 +68,7 @@ Signed-off-by: David S. Miller data = ring->data[idx]; if (!mtk_rx_get_desc(eth, &trxd, rxd)) -@@ -1647,7 +1643,7 @@ static int mtk_poll_tx_pdma(struct mtk_e +@@ -1648,7 +1644,7 @@ static int mtk_poll_tx_pdma(struct mtk_e mtk_tx_unmap(eth, tx_buf, true); @@ -77,7 +77,7 @@ Signed-off-by: David S. Miller ring->last_free = desc; atomic_inc(&ring->free_count); -@@ -1792,7 +1788,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1793,7 +1789,7 @@ static int mtk_tx_alloc(struct mtk_eth * int next = (i + 1) % MTK_DMA_SIZE; u32 next_ptr = ring->phys + next * sz; @@ -86,7 +86,7 @@ Signed-off-by: David S. Miller txd->txd2 = next_ptr; txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; txd->txd4 = 0; -@@ -1822,7 +1818,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -1823,7 +1819,7 @@ static int mtk_tx_alloc(struct mtk_eth * ring->dma_size = MTK_DMA_SIZE; atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); @@ -95,7 +95,7 @@ Signed-off-by: David S. Miller ring->last_free = (void *)txd; ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz)); ring->thresh = MAX_SKB_FRAGS; -@@ -1937,7 +1933,7 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1938,7 +1934,7 @@ static int mtk_rx_alloc(struct mtk_eth * if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) return -ENOMEM; @@ -104,7 +104,7 @@ Signed-off-by: David S. Miller rxd->rxd1 = (unsigned int)dma_addr; if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) -@@ -1999,7 +1995,7 @@ static void mtk_rx_clean(struct mtk_eth +@@ -2000,7 +1996,7 @@ static void mtk_rx_clean(struct mtk_eth if (!ring->data[i]) continue; @@ -115,7 +115,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -688,7 +688,7 @@ struct mtk_tx_buf { +@@ -689,7 +689,7 @@ struct mtk_tx_buf { * are present */ struct mtk_tx_ring { @@ -124,7 +124,7 @@ Signed-off-by: David S. Miller struct mtk_tx_buf *buf; dma_addr_t phys; struct mtk_tx_dma *next_free; -@@ -718,7 +718,7 @@ enum mtk_rx_flags { +@@ -719,7 +719,7 @@ enum mtk_rx_flags { * @calc_idx: The current head of ring */ struct mtk_rx_ring { diff --git a/target/linux/generic/backport-5.15/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch b/target/linux/generic/backport-5.15/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch index 459ffd54067..f7318e68bbd 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch @@ -11,7 +11,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -922,7 +922,7 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -923,7 +923,7 @@ static int mtk_init_fq_dma(struct mtk_et for (i = 0; i < cnt; i++) { struct mtk_tx_dma_v2 *txd; @@ -22,7 +22,7 @@ Signed-off-by: David S. Miller txd->txd2 = eth->phy_scratch_ring + --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1028,7 +1028,7 @@ struct mtk_eth { +@@ -1029,7 +1029,7 @@ struct mtk_eth { struct mtk_rx_ring rx_ring_qdma; struct napi_struct tx_napi; struct napi_struct rx_napi; diff --git a/target/linux/generic/backport-5.15/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch b/target/linux/generic/backport-5.15/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch index c14fcffcc54..a4698d7814d 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch @@ -65,7 +65,7 @@ Signed-off-by: David S. Miller }; void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) -@@ -3711,6 +3748,21 @@ static const struct mtk_soc_data mt7629_ +@@ -3712,6 +3749,21 @@ static const struct mtk_soc_data mt7629_ }, }; @@ -87,7 +87,7 @@ Signed-off-by: David S. Miller static const struct mtk_soc_data rt5350_data = { .reg_map = &mt7628_reg_map, .caps = MT7628_CAPS, -@@ -3733,6 +3785,7 @@ const struct of_device_id of_mtk_match[] +@@ -3734,6 +3786,7 @@ const struct of_device_id of_mtk_match[] { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, @@ -97,7 +97,7 @@ Signed-off-by: David S. Miller }; --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -623,6 +623,10 @@ enum mtk_clks_map { +@@ -624,6 +624,10 @@ enum mtk_clks_map { MTK_CLK_SGMII2_CDR_FB, MTK_CLK_SGMII_CK, MTK_CLK_ETH2PLL, @@ -108,7 +108,7 @@ Signed-off-by: David S. Miller MTK_CLK_MAX }; -@@ -653,6 +657,16 @@ enum mtk_clks_map { +@@ -654,6 +658,16 @@ enum mtk_clks_map { BIT(MTK_CLK_SGMII2_CDR_FB) | \ BIT(MTK_CLK_SGMII_CK) | \ BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) @@ -125,7 +125,7 @@ Signed-off-by: David S. Miller enum mtk_dev_state { MTK_HW_INIT, -@@ -851,6 +865,10 @@ enum mkt_eth_capabilities { +@@ -852,6 +866,10 @@ enum mkt_eth_capabilities { MTK_MUX_U3_GMAC2_TO_QPHY | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) diff --git a/target/linux/generic/backport-5.15/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch b/target/linux/generic/backport-5.15/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch index 56d0efb9031..d76df75dda8 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch @@ -12,7 +12,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1462,8 +1462,8 @@ static int mtk_poll_rx(struct napi_struc +@@ -1463,8 +1463,8 @@ static int mtk_poll_rx(struct napi_struc int done = 0, bytes = 0; while (done < budget) { @@ -22,7 +22,7 @@ Signed-off-by: Jakub Kicinski dma_addr_t dma_addr; u32 hash, reason; int mac = 0; -@@ -1530,7 +1530,13 @@ static int mtk_poll_rx(struct napi_struc +@@ -1531,7 +1531,13 @@ static int mtk_poll_rx(struct napi_struc pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); skb->dev = netdev; skb_put(skb, pktlen); @@ -37,7 +37,7 @@ Signed-off-by: Jakub Kicinski skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); -@@ -3758,6 +3764,7 @@ static const struct mtk_soc_data mt7986_ +@@ -3759,6 +3765,7 @@ static const struct mtk_soc_data mt7986_ .txd_size = sizeof(struct mtk_tx_dma_v2), .rxd_size = sizeof(struct mtk_rx_dma_v2), .rx_irq_done_mask = MTK_RX_DONE_INT_V2, diff --git a/target/linux/generic/backport-5.15/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch b/target/linux/generic/backport-5.15/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch index a602ed5c9c0..b6fe0dad4c8 100644 --- a/target/linux/generic/backport-5.15/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch +++ b/target/linux/generic/backport-5.15/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch @@ -14,7 +14,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3354,6 +3354,26 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -3355,6 +3355,26 @@ static int mtk_add_mac(struct mtk_eth *e mac->phylink_config.dev = ð->netdev[id]->dev; mac->phylink_config.type = PHYLINK_NETDEV; diff --git a/target/linux/generic/backport-5.15/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch b/target/linux/generic/backport-5.15/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch index 05a84c4f679..0a33ab00934 100644 --- a/target/linux/generic/backport-5.15/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch +++ b/target/linux/generic/backport-5.15/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch @@ -16,7 +16,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -567,24 +567,8 @@ static void mtk_validate(struct phylink_ +@@ -568,24 +568,8 @@ static void mtk_validate(struct phylink_ unsigned long *supported, struct phylink_link_state *state) { @@ -41,7 +41,7 @@ Signed-off-by: David S. Miller phylink_set_port_modes(mask); phylink_set(mask, Autoneg); -@@ -611,7 +595,6 @@ static void mtk_validate(struct phylink_ +@@ -612,7 +596,6 @@ static void mtk_validate(struct phylink_ case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_RMII: case PHY_INTERFACE_MODE_REVMII: @@ -49,7 +49,7 @@ Signed-off-by: David S. Miller default: phylink_set(mask, 10baseT_Half); phylink_set(mask, 10baseT_Full); -@@ -620,23 +603,6 @@ static void mtk_validate(struct phylink_ +@@ -621,23 +604,6 @@ static void mtk_validate(struct phylink_ break; } diff --git a/target/linux/generic/backport-5.15/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch b/target/linux/generic/backport-5.15/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch index a3cfab7f881..f8cc8105a4c 100644 --- a/target/linux/generic/backport-5.15/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch +++ b/target/linux/generic/backport-5.15/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch @@ -17,7 +17,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -577,8 +577,9 @@ static void mtk_validate(struct phylink_ +@@ -578,8 +578,9 @@ static void mtk_validate(struct phylink_ phylink_set(mask, 1000baseT_Full); break; case PHY_INTERFACE_MODE_1000BASEX: @@ -28,7 +28,7 @@ Signed-off-by: David S. Miller phylink_set(mask, 2500baseX_Full); break; case PHY_INTERFACE_MODE_GMII: -@@ -608,11 +609,6 @@ static void mtk_validate(struct phylink_ +@@ -609,11 +610,6 @@ static void mtk_validate(struct phylink_ linkmode_and(supported, supported, mask); linkmode_and(state->advertising, state->advertising, mask); diff --git a/target/linux/generic/backport-5.15/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch b/target/linux/generic/backport-5.15/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch index 2140a8267b3..f695991ec1f 100644 --- a/target/linux/generic/backport-5.15/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch +++ b/target/linux/generic/backport-5.15/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch @@ -14,7 +14,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -563,56 +563,8 @@ static void mtk_mac_link_up(struct phyli +@@ -564,56 +564,8 @@ static void mtk_mac_link_up(struct phyli mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); } @@ -72,7 +72,7 @@ Signed-off-by: David S. Miller .mac_pcs_get_state = mtk_mac_pcs_get_state, .mac_an_restart = mtk_mac_an_restart, .mac_config = mtk_mac_config, -@@ -3316,6 +3268,9 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -3317,6 +3269,9 @@ static int mtk_add_mac(struct mtk_eth *e mac->phylink_config.dev = ð->netdev[id]->dev; mac->phylink_config.type = PHYLINK_NETDEV; diff --git a/target/linux/generic/backport-5.15/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch b/target/linux/generic/backport-5.15/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch index 8b9a249e40e..cbff1bfbbc4 100644 --- a/target/linux/generic/backport-5.15/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch +++ b/target/linux/generic/backport-5.15/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch @@ -16,7 +16,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3268,6 +3268,10 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -3269,6 +3269,10 @@ static int mtk_add_mac(struct mtk_eth *e mac->phylink_config.dev = ð->netdev[id]->dev; mac->phylink_config.type = PHYLINK_NETDEV; diff --git a/target/linux/generic/backport-5.15/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch b/target/linux/generic/backport-5.15/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch index 97e0b3ccb06..c0b4a61cb6e 100644 --- a/target/linux/generic/backport-5.15/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch +++ b/target/linux/generic/backport-5.15/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch @@ -16,7 +16,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3567,9 +3567,9 @@ static int mtk_probe(struct platform_dev +@@ -3568,9 +3568,9 @@ static int mtk_probe(struct platform_dev */ init_dummy_netdev(ð->dummy_dev); netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx, diff --git a/target/linux/generic/backport-5.15/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch b/target/linux/generic/backport-5.15/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch index 9873edbc500..5940ac27df9 100644 --- a/target/linux/generic/backport-5.15/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch +++ b/target/linux/generic/backport-5.15/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch @@ -15,7 +15,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3263,7 +3263,6 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -3264,7 +3264,6 @@ static int mtk_add_mac(struct mtk_eth *e /* mac config is not set */ mac->interface = PHY_INTERFACE_MODE_NA; @@ -25,7 +25,7 @@ Signed-off-by: Jakub Kicinski mac->phylink_config.dev = ð->netdev[id]->dev; --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1085,7 +1085,6 @@ struct mtk_eth { +@@ -1086,7 +1086,6 @@ struct mtk_eth { struct mtk_mac { int id; phy_interface_t interface; diff --git a/target/linux/generic/backport-5.15/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch b/target/linux/generic/backport-5.15/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch index 39aa24157ed..a15914bd553 100644 --- a/target/linux/generic/backport-5.15/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch +++ b/target/linux/generic/backport-5.15/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch @@ -14,7 +14,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -956,23 +956,15 @@ struct mtk_soc_data { +@@ -957,23 +957,15 @@ struct mtk_soc_data { /* currently no SoC has more than 2 macs */ #define MTK_MAX_DEVS 2 diff --git a/target/linux/generic/backport-5.15/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch b/target/linux/generic/backport-5.15/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch index f2e1f86bacf..e16bc875e52 100644 --- a/target/linux/generic/backport-5.15/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch +++ b/target/linux/generic/backport-5.15/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch @@ -24,7 +24,7 @@ Signed-off-by: Jakub Kicinski #include "mtk_ppe.h" #define MTK_QDMA_PAGE_SIZE 2048 -@@ -473,9 +474,10 @@ +@@ -474,9 +475,10 @@ #define SGMSYS_SGMII_MODE 0x20 #define SGMII_IF_MODE_BIT0 BIT(0) #define SGMII_SPEED_DUPLEX_AN BIT(1) diff --git a/target/linux/generic/backport-5.15/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch b/target/linux/generic/backport-5.15/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch index d4a4d511016..78444903a8c 100644 --- a/target/linux/generic/backport-5.15/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch +++ b/target/linux/generic/backport-5.15/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch @@ -18,7 +18,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -532,8 +532,18 @@ static void mtk_mac_link_up(struct phyli +@@ -533,8 +533,18 @@ static void mtk_mac_link_up(struct phyli { struct mtk_mac *mac = container_of(config, struct mtk_mac, phylink_config); @@ -38,7 +38,7 @@ Signed-off-by: Jakub Kicinski mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | MAC_MCR_FORCE_RX_FC); -@@ -3267,9 +3277,7 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -3268,9 +3278,7 @@ static int mtk_add_mac(struct mtk_eth *e mac->phylink_config.dev = ð->netdev[id]->dev; mac->phylink_config.type = PHYLINK_NETDEV; @@ -51,7 +51,7 @@ Signed-off-by: Jakub Kicinski MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1103,6 +1103,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, +@@ -1104,6 +1104,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, const struct phylink_link_state *state); diff --git a/target/linux/generic/backport-5.15/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch b/target/linux/generic/backport-5.15/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch index 56b5e43e532..6556bb7d07d 100644 --- a/target/linux/generic/backport-5.15/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch +++ b/target/linux/generic/backport-5.15/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch @@ -29,7 +29,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1102,7 +1102,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, +@@ -1103,7 +1103,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, u32 ana_rgc3); int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, diff --git a/target/linux/generic/backport-5.15/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch b/target/linux/generic/backport-5.15/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch index 4c91cf68f4c..0e22c7fd674 100644 --- a/target/linux/generic/backport-5.15/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch +++ b/target/linux/generic/backport-5.15/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch @@ -32,7 +32,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1100,9 +1100,8 @@ u32 mtk_r32(struct mtk_eth *eth, unsigne +@@ -1101,9 +1101,8 @@ u32 mtk_r32(struct mtk_eth *eth, unsigne int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, u32 ana_rgc3); diff --git a/target/linux/generic/backport-5.15/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch b/target/linux/generic/backport-5.15/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch index 368db4cca26..337c6112d66 100644 --- a/target/linux/generic/backport-5.15/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch +++ b/target/linux/generic/backport-5.15/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch @@ -25,27 +25,22 @@ Signed-off-by: Jakub Kicinski /* MT76x8 has no hardware settings between for the MAC */ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && -@@ -455,16 +455,6 @@ static void mtk_mac_config(struct phylin +@@ -455,6 +455,25 @@ static void mtk_mac_config(struct phylin return; } -- /* Setup gmac */ -- mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); -- mcr_new = mcr_cur; -- mcr_new |= MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE | -- MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK; -- -- /* Only update control register when needed! */ -- if (mcr_new != mcr_cur) -- mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); -- - return; - - err_phy: -@@ -477,6 +467,26 @@ init_err: - mac->id, phy_modes(state->interface), err); - } - ++ return; ++ ++err_phy: ++ dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__, ++ mac->id, phy_modes(state->interface)); ++ return; ++ ++init_err: ++ dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__, ++ mac->id, phy_modes(state->interface), err); ++} ++ +static int mtk_mac_finish(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ @@ -53,23 +48,28 @@ Signed-off-by: Jakub Kicinski + phylink_config); + u32 mcr_cur, mcr_new; + -+ /* Setup gmac */ -+ mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); -+ mcr_new = mcr_cur; -+ mcr_new |= MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE | -+ MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK; -+ -+ /* Only update control register when needed! */ -+ if (mcr_new != mcr_cur) -+ mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); -+ + /* Setup gmac */ + mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr_new = mcr_cur; +@@ -466,16 +485,7 @@ static void mtk_mac_config(struct phylin + if (mcr_new != mcr_cur) + mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); + +- return; +- +-err_phy: +- dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__, +- mac->id, phy_modes(state->interface)); +- return; +- +-init_err: +- dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__, +- mac->id, phy_modes(state->interface), err); + return 0; -+} -+ + } + static void mtk_mac_pcs_get_state(struct phylink_config *config, - struct phylink_link_state *state) - { -@@ -581,6 +591,7 @@ static const struct phylink_mac_ops mtk_ +@@ -582,6 +592,7 @@ static const struct phylink_mac_ops mtk_ .mac_pcs_get_state = mtk_mac_pcs_get_state, .mac_an_restart = mtk_mac_an_restart, .mac_config = mtk_mac_config, diff --git a/target/linux/generic/backport-5.15/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch b/target/linux/generic/backport-5.15/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch index ad6ec60288f..b03ef436bdb 100644 --- a/target/linux/generic/backport-5.15/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch +++ b/target/linux/generic/backport-5.15/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch @@ -47,7 +47,7 @@ Signed-off-by: Jakub Kicinski mcr_new = mcr_cur; --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1087,6 +1087,7 @@ struct mtk_mac { +@@ -1088,6 +1088,7 @@ struct mtk_mac { struct mtk_hw_stats *hw_stats; __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; int hwlro_ip_cnt; diff --git a/target/linux/generic/backport-5.15/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch b/target/linux/generic/backport-5.15/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch index 623658f459c..4c84703cd94 100644 --- a/target/linux/generic/backport-5.15/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch +++ b/target/linux/generic/backport-5.15/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch @@ -18,7 +18,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -958,16 +958,23 @@ struct mtk_soc_data { +@@ -959,16 +959,23 @@ struct mtk_soc_data { /* currently no SoC has more than 2 macs */ #define MTK_MAX_DEVS 2 diff --git a/target/linux/generic/backport-5.15/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch b/target/linux/generic/backport-5.15/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch index df675e28999..b585867935e 100644 --- a/target/linux/generic/backport-5.15/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch +++ b/target/linux/generic/backport-5.15/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch @@ -69,7 +69,7 @@ Signed-off-by: Jakub Kicinski /* Save the syscfg0 value for mac_finish */ mac->syscfg0 = val; } else if (phylink_autoneg_inband(mode)) { -@@ -526,14 +536,6 @@ static void mtk_mac_pcs_get_state(struct +@@ -527,14 +537,6 @@ static void mtk_mac_pcs_get_state(struct state->pause |= MLO_PAUSE_TX; } @@ -84,7 +84,7 @@ Signed-off-by: Jakub Kicinski static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { -@@ -554,15 +556,6 @@ static void mtk_mac_link_up(struct phyli +@@ -555,15 +557,6 @@ static void mtk_mac_link_up(struct phyli phylink_config); u32 mcr; @@ -100,7 +100,7 @@ Signed-off-by: Jakub Kicinski mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | -@@ -595,8 +588,8 @@ static void mtk_mac_link_up(struct phyli +@@ -596,8 +589,8 @@ static void mtk_mac_link_up(struct phyli static const struct phylink_mac_ops mtk_phylink_ops = { .validate = phylink_generic_validate, @@ -112,7 +112,7 @@ Signed-off-by: Jakub Kicinski .mac_link_down = mtk_mac_link_down, --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -963,10 +963,12 @@ struct mtk_soc_data { +@@ -964,10 +964,12 @@ struct mtk_soc_data { * @regmap: The register map pointing at the range used to setup * SGMII modes * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap @@ -125,7 +125,7 @@ Signed-off-by: Jakub Kicinski }; /* struct mtk_sgmii - This is the structure holding sgmii regmap and its -@@ -1106,12 +1108,9 @@ void mtk_stats_update_mac(struct mtk_mac +@@ -1107,12 +1109,9 @@ void mtk_stats_update_mac(struct mtk_mac void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); u32 mtk_r32(struct mtk_eth *eth, unsigned reg); diff --git a/target/linux/generic/backport-5.15/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch b/target/linux/generic/backport-5.15/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch index a3fbf00629f..845f2fa4b20 100644 --- a/target/linux/generic/backport-5.15/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch +++ b/target/linux/generic/backport-5.15/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch @@ -21,7 +21,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -1191,27 +1191,31 @@ static int +@@ -1194,27 +1194,31 @@ static int mt7530_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *bridge) { @@ -65,7 +65,7 @@ Signed-off-by: Jakub Kicinski } /* Add the all other ports to this port matrix. */ -@@ -1316,24 +1320,28 @@ static void +@@ -1319,24 +1323,28 @@ static void mt7530_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *bridge) { diff --git a/target/linux/generic/backport-5.15/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch b/target/linux/generic/backport-5.15/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch index 6599f25c0fc..4ee326030dc 100644 --- a/target/linux/generic/backport-5.15/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch +++ b/target/linux/generic/backport-5.15/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch @@ -23,7 +23,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2402,6 +2402,32 @@ mt7531_setup(struct dsa_switch *ds) +@@ -2407,6 +2407,32 @@ mt7531_setup(struct dsa_switch *ds) return 0; } @@ -56,7 +56,7 @@ Signed-off-by: Paolo Abeni static bool mt7530_phy_mode_supported(struct dsa_switch *ds, int port, const struct phylink_link_state *state) -@@ -2438,6 +2464,37 @@ static bool mt7531_is_rgmii_port(struct +@@ -2443,6 +2469,37 @@ static bool mt7531_is_rgmii_port(struct return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); } @@ -94,7 +94,7 @@ Signed-off-by: Paolo Abeni static bool mt7531_phy_mode_supported(struct dsa_switch *ds, int port, const struct phylink_link_state *state) -@@ -2914,6 +2971,18 @@ mt7531_cpu_port_config(struct dsa_switch +@@ -2919,6 +2976,18 @@ mt7531_cpu_port_config(struct dsa_switch return 0; } @@ -113,7 +113,7 @@ Signed-off-by: Paolo Abeni static void mt7530_mac_port_validate(struct dsa_switch *ds, int port, unsigned long *supported) -@@ -3149,6 +3218,7 @@ static const struct dsa_switch_ops mt753 +@@ -3154,6 +3223,7 @@ static const struct dsa_switch_ops mt753 .port_vlan_del = mt7530_port_vlan_del, .port_mirror_add = mt753x_port_mirror_add, .port_mirror_del = mt753x_port_mirror_del, @@ -121,7 +121,7 @@ Signed-off-by: Paolo Abeni .phylink_validate = mt753x_phylink_validate, .phylink_mac_link_state = mt753x_phylink_mac_link_state, .phylink_mac_config = mt753x_phylink_mac_config, -@@ -3166,6 +3236,7 @@ static const struct mt753x_info mt753x_t +@@ -3171,6 +3241,7 @@ static const struct mt753x_info mt753x_t .phy_read = mt7530_phy_read, .phy_write = mt7530_phy_write, .pad_setup = mt7530_pad_clk_setup, @@ -129,7 +129,7 @@ Signed-off-by: Paolo Abeni .phy_mode_supported = mt7530_phy_mode_supported, .mac_port_validate = mt7530_mac_port_validate, .mac_port_get_state = mt7530_phylink_mac_link_state, -@@ -3177,6 +3248,7 @@ static const struct mt753x_info mt753x_t +@@ -3182,6 +3253,7 @@ static const struct mt753x_info mt753x_t .phy_read = mt7530_phy_read, .phy_write = mt7530_phy_write, .pad_setup = mt7530_pad_clk_setup, @@ -137,7 +137,7 @@ Signed-off-by: Paolo Abeni .phy_mode_supported = mt7530_phy_mode_supported, .mac_port_validate = mt7530_mac_port_validate, .mac_port_get_state = mt7530_phylink_mac_link_state, -@@ -3189,6 +3261,7 @@ static const struct mt753x_info mt753x_t +@@ -3194,6 +3266,7 @@ static const struct mt753x_info mt753x_t .phy_write = mt7531_ind_phy_write, .pad_setup = mt7531_pad_setup, .cpu_port_config = mt7531_cpu_port_config, @@ -145,7 +145,7 @@ Signed-off-by: Paolo Abeni .phy_mode_supported = mt7531_phy_mode_supported, .mac_port_validate = mt7531_mac_port_validate, .mac_port_get_state = mt7531_phylink_mac_link_state, -@@ -3251,6 +3324,7 @@ mt7530_probe(struct mdio_device *mdiodev +@@ -3256,6 +3329,7 @@ mt7530_probe(struct mdio_device *mdiodev */ if (!priv->info->sw_setup || !priv->info->pad_setup || !priv->info->phy_read || !priv->info->phy_write || diff --git a/target/linux/generic/backport-5.15/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch b/target/linux/generic/backport-5.15/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch index 325152603a1..1d74aac8f54 100644 --- a/target/linux/generic/backport-5.15/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch +++ b/target/linux/generic/backport-5.15/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch @@ -21,7 +21,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2428,37 +2428,6 @@ static void mt7530_mac_port_get_caps(str +@@ -2433,37 +2433,6 @@ static void mt7530_mac_port_get_caps(str } } @@ -59,7 +59,7 @@ Signed-off-by: Paolo Abeni static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port) { return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); -@@ -2495,44 +2464,6 @@ static void mt7531_mac_port_get_caps(str +@@ -2500,44 +2469,6 @@ static void mt7531_mac_port_get_caps(str } } @@ -104,7 +104,7 @@ Signed-off-by: Paolo Abeni static int mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state) { -@@ -2787,9 +2718,6 @@ mt753x_phylink_mac_config(struct dsa_swi +@@ -2792,9 +2723,6 @@ mt753x_phylink_mac_config(struct dsa_swi struct mt7530_priv *priv = ds->priv; u32 mcr_cur, mcr_new; @@ -114,7 +114,7 @@ Signed-off-by: Paolo Abeni switch (port) { case 0 ... 4: /* Internal phy */ if (state->interface != PHY_INTERFACE_MODE_GMII) -@@ -3005,12 +2933,6 @@ mt753x_phylink_validate(struct dsa_switc +@@ -3010,12 +2938,6 @@ mt753x_phylink_validate(struct dsa_switc __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; struct mt7530_priv *priv = ds->priv; @@ -127,7 +127,7 @@ Signed-off-by: Paolo Abeni phylink_set_port_modes(mask); if (state->interface != PHY_INTERFACE_MODE_TRGMII && -@@ -3237,7 +3159,6 @@ static const struct mt753x_info mt753x_t +@@ -3242,7 +3164,6 @@ static const struct mt753x_info mt753x_t .phy_write = mt7530_phy_write, .pad_setup = mt7530_pad_clk_setup, .mac_port_get_caps = mt7530_mac_port_get_caps, @@ -135,7 +135,7 @@ Signed-off-by: Paolo Abeni .mac_port_validate = mt7530_mac_port_validate, .mac_port_get_state = mt7530_phylink_mac_link_state, .mac_port_config = mt7530_mac_config, -@@ -3249,7 +3170,6 @@ static const struct mt753x_info mt753x_t +@@ -3254,7 +3175,6 @@ static const struct mt753x_info mt753x_t .phy_write = mt7530_phy_write, .pad_setup = mt7530_pad_clk_setup, .mac_port_get_caps = mt7530_mac_port_get_caps, @@ -143,7 +143,7 @@ Signed-off-by: Paolo Abeni .mac_port_validate = mt7530_mac_port_validate, .mac_port_get_state = mt7530_phylink_mac_link_state, .mac_port_config = mt7530_mac_config, -@@ -3262,7 +3182,6 @@ static const struct mt753x_info mt753x_t +@@ -3267,7 +3187,6 @@ static const struct mt753x_info mt753x_t .pad_setup = mt7531_pad_setup, .cpu_port_config = mt7531_cpu_port_config, .mac_port_get_caps = mt7531_mac_port_get_caps, @@ -151,7 +151,7 @@ Signed-off-by: Paolo Abeni .mac_port_validate = mt7531_mac_port_validate, .mac_port_get_state = mt7531_phylink_mac_link_state, .mac_port_config = mt7531_mac_config, -@@ -3325,7 +3244,6 @@ mt7530_probe(struct mdio_device *mdiodev +@@ -3330,7 +3249,6 @@ mt7530_probe(struct mdio_device *mdiodev if (!priv->info->sw_setup || !priv->info->pad_setup || !priv->info->phy_read || !priv->info->phy_write || !priv->info->mac_port_get_caps || diff --git a/target/linux/generic/backport-5.15/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch b/target/linux/generic/backport-5.15/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch index 76d89d0c542..3e97ad4a43e 100644 --- a/target/linux/generic/backport-5.15/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch +++ b/target/linux/generic/backport-5.15/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch @@ -20,7 +20,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2957,11 +2957,6 @@ mt753x_phylink_validate(struct dsa_switc +@@ -2962,11 +2962,6 @@ mt753x_phylink_validate(struct dsa_switc linkmode_and(supported, supported, mask); linkmode_and(state->advertising, state->advertising, mask); diff --git a/target/linux/generic/backport-5.15/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch b/target/linux/generic/backport-5.15/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch index 6ee017ea72e..97d3ff9c98c 100644 --- a/target/linux/generic/backport-5.15/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch +++ b/target/linux/generic/backport-5.15/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch @@ -23,7 +23,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2535,12 +2535,13 @@ static int mt7531_rgmii_setup(struct mt7 +@@ -2540,12 +2540,13 @@ static int mt7531_rgmii_setup(struct mt7 } static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port, @@ -38,7 +38,7 @@ Signed-off-by: Paolo Abeni phylink_set(supported, 2500baseX_Full); phylink_set(supported, 2500baseT_Full); } -@@ -2913,16 +2914,18 @@ static void mt753x_phylink_get_caps(stru +@@ -2918,16 +2919,18 @@ static void mt753x_phylink_get_caps(stru static void mt7530_mac_port_validate(struct dsa_switch *ds, int port, @@ -58,7 +58,7 @@ Signed-off-by: Paolo Abeni } static void -@@ -2945,12 +2948,13 @@ mt753x_phylink_validate(struct dsa_switc +@@ -2950,12 +2953,13 @@ mt753x_phylink_validate(struct dsa_switc } /* This switch only supports 1G full-duplex. */ diff --git a/target/linux/generic/backport-5.15/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch b/target/linux/generic/backport-5.15/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch index 670ac080cf0..009b2bb583f 100644 --- a/target/linux/generic/backport-5.15/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch +++ b/target/linux/generic/backport-5.15/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch @@ -20,7 +20,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2534,19 +2534,6 @@ static int mt7531_rgmii_setup(struct mt7 +@@ -2539,19 +2539,6 @@ static int mt7531_rgmii_setup(struct mt7 return 0; } @@ -40,7 +40,7 @@ Signed-off-by: Paolo Abeni static void mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface, -@@ -2913,51 +2900,21 @@ static void mt753x_phylink_get_caps(stru +@@ -2918,51 +2905,21 @@ static void mt753x_phylink_get_caps(stru } static void @@ -97,7 +97,7 @@ Signed-off-by: Paolo Abeni linkmode_and(supported, supported, mask); linkmode_and(state->advertising, state->advertising, mask); -@@ -3158,7 +3115,6 @@ static const struct mt753x_info mt753x_t +@@ -3163,7 +3120,6 @@ static const struct mt753x_info mt753x_t .phy_write = mt7530_phy_write, .pad_setup = mt7530_pad_clk_setup, .mac_port_get_caps = mt7530_mac_port_get_caps, @@ -105,7 +105,7 @@ Signed-off-by: Paolo Abeni .mac_port_get_state = mt7530_phylink_mac_link_state, .mac_port_config = mt7530_mac_config, }, -@@ -3169,7 +3125,6 @@ static const struct mt753x_info mt753x_t +@@ -3174,7 +3130,6 @@ static const struct mt753x_info mt753x_t .phy_write = mt7530_phy_write, .pad_setup = mt7530_pad_clk_setup, .mac_port_get_caps = mt7530_mac_port_get_caps, @@ -113,7 +113,7 @@ Signed-off-by: Paolo Abeni .mac_port_get_state = mt7530_phylink_mac_link_state, .mac_port_config = mt7530_mac_config, }, -@@ -3181,7 +3136,6 @@ static const struct mt753x_info mt753x_t +@@ -3186,7 +3141,6 @@ static const struct mt753x_info mt753x_t .pad_setup = mt7531_pad_setup, .cpu_port_config = mt7531_cpu_port_config, .mac_port_get_caps = mt7531_mac_port_get_caps, @@ -121,7 +121,7 @@ Signed-off-by: Paolo Abeni .mac_port_get_state = mt7531_phylink_mac_link_state, .mac_port_config = mt7531_mac_config, .mac_pcs_an_restart = mt7531_sgmii_restart_an, -@@ -3243,7 +3197,6 @@ mt7530_probe(struct mdio_device *mdiodev +@@ -3248,7 +3202,6 @@ mt7530_probe(struct mdio_device *mdiodev if (!priv->info->sw_setup || !priv->info->pad_setup || !priv->info->phy_read || !priv->info->phy_write || !priv->info->mac_port_get_caps || diff --git a/target/linux/generic/backport-5.15/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch b/target/linux/generic/backport-5.15/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch index 638127f56ce..c7e004e2e7b 100644 --- a/target/linux/generic/backport-5.15/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch +++ b/target/linux/generic/backport-5.15/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch @@ -33,7 +33,7 @@ Signed-off-by: Paolo Abeni /* String, offset, and register size in bytes if different from 4 bytes */ static const struct mt7530_mib_desc mt7530_mib[] = { MIB_DESC(1, 0x00, "TxDrop"), -@@ -2534,12 +2539,11 @@ static int mt7531_rgmii_setup(struct mt7 +@@ -2539,12 +2544,11 @@ static int mt7531_rgmii_setup(struct mt7 return 0; } @@ -50,7 +50,7 @@ Signed-off-by: Paolo Abeni unsigned int val; /* For adjusting speed and duplex of SGMII force mode. */ -@@ -2565,6 +2569,9 @@ mt7531_sgmii_link_up_force(struct dsa_sw +@@ -2570,6 +2574,9 @@ mt7531_sgmii_link_up_force(struct dsa_sw /* MT7531 SGMII 1G force mode can only work in full duplex mode, * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. @@ -60,7 +60,7 @@ Signed-off-by: Paolo Abeni */ if ((speed == SPEED_10 || speed == SPEED_100) && duplex != DUPLEX_FULL) -@@ -2640,9 +2647,10 @@ static int mt7531_sgmii_setup_mode_an(st +@@ -2645,9 +2652,10 @@ static int mt7531_sgmii_setup_mode_an(st return 0; } @@ -73,7 +73,7 @@ Signed-off-by: Paolo Abeni u32 val; /* Only restart AN when AN is enabled */ -@@ -2699,6 +2707,24 @@ mt753x_mac_config(struct dsa_switch *ds, +@@ -2704,6 +2712,24 @@ mt753x_mac_config(struct dsa_switch *ds, return priv->info->mac_port_config(ds, port, mode, state->interface); } @@ -98,7 +98,7 @@ Signed-off-by: Paolo Abeni static void mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) -@@ -2760,17 +2786,6 @@ unsupported: +@@ -2765,17 +2791,6 @@ unsupported: mt7530_write(priv, MT7530_PMCR_P(port), mcr_new); } @@ -116,7 +116,7 @@ Signed-off-by: Paolo Abeni static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) -@@ -2780,16 +2795,13 @@ static void mt753x_phylink_mac_link_down +@@ -2785,16 +2800,13 @@ static void mt753x_phylink_mac_link_down mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); } @@ -139,7 +139,7 @@ Signed-off-by: Paolo Abeni } static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, -@@ -2802,8 +2814,6 @@ static void mt753x_phylink_mac_link_up(s +@@ -2807,8 +2819,6 @@ static void mt753x_phylink_mac_link_up(s struct mt7530_priv *priv = ds->priv; u32 mcr; @@ -148,7 +148,7 @@ Signed-off-by: Paolo Abeni mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK; /* MT753x MAC works in 1G full duplex mode for all up-clocked -@@ -2881,6 +2891,8 @@ mt7531_cpu_port_config(struct dsa_switch +@@ -2886,6 +2896,8 @@ mt7531_cpu_port_config(struct dsa_switch return ret; mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPU_PORT_SETTING(priv->id)); @@ -157,7 +157,7 @@ Signed-off-by: Paolo Abeni mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL, speed, DUPLEX_FULL, true, true); -@@ -2920,16 +2932,13 @@ mt753x_phylink_validate(struct dsa_switc +@@ -2925,16 +2937,13 @@ mt753x_phylink_validate(struct dsa_switc linkmode_and(state->advertising, state->advertising, mask); } @@ -178,7 +178,7 @@ Signed-off-by: Paolo Abeni pmsr = mt7530_read(priv, MT7530_PMSR_P(port)); state->link = (pmsr & PMSR_LINK); -@@ -2956,8 +2965,6 @@ mt7530_phylink_mac_link_state(struct dsa +@@ -2961,8 +2970,6 @@ mt7530_phylink_mac_link_state(struct dsa state->pause |= MLO_PAUSE_RX; if (pmsr & PMSR_TX_FC) state->pause |= MLO_PAUSE_TX; @@ -187,7 +187,7 @@ Signed-off-by: Paolo Abeni } static int -@@ -2999,32 +3006,49 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 +@@ -3004,32 +3011,49 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 return 0; } @@ -249,7 +249,7 @@ Signed-off-by: Paolo Abeni if (ret) return ret; -@@ -3037,6 +3061,13 @@ mt753x_setup(struct dsa_switch *ds) +@@ -3042,6 +3066,13 @@ mt753x_setup(struct dsa_switch *ds) if (ret && priv->irq) mt7530_free_irq_common(priv); @@ -263,7 +263,7 @@ Signed-off-by: Paolo Abeni return ret; } -@@ -3098,9 +3129,8 @@ static const struct dsa_switch_ops mt753 +@@ -3103,9 +3134,8 @@ static const struct dsa_switch_ops mt753 .port_mirror_del = mt753x_port_mirror_del, .phylink_get_caps = mt753x_phylink_get_caps, .phylink_validate = mt753x_phylink_validate, @@ -274,7 +274,7 @@ Signed-off-by: Paolo Abeni .phylink_mac_link_down = mt753x_phylink_mac_link_down, .phylink_mac_link_up = mt753x_phylink_mac_link_up, .get_mac_eee = mt753x_get_mac_eee, -@@ -3110,36 +3140,34 @@ static const struct dsa_switch_ops mt753 +@@ -3115,36 +3145,34 @@ static const struct dsa_switch_ops mt753 static const struct mt753x_info mt753x_table[] = { [ID_MT7621] = { .id = ID_MT7621, @@ -314,7 +314,7 @@ Signed-off-by: Paolo Abeni }, }; -@@ -3197,7 +3225,7 @@ mt7530_probe(struct mdio_device *mdiodev +@@ -3202,7 +3230,7 @@ mt7530_probe(struct mdio_device *mdiodev if (!priv->info->sw_setup || !priv->info->pad_setup || !priv->info->phy_read || !priv->info->phy_write || !priv->info->mac_port_get_caps || diff --git a/target/linux/generic/backport-5.15/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch b/target/linux/generic/backport-5.15/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch index 19d3258af5c..2ddfe8ccd04 100644 --- a/target/linux/generic/backport-5.15/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch +++ b/target/linux/generic/backport-5.15/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch @@ -20,7 +20,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2911,25 +2911,16 @@ static void mt753x_phylink_get_caps(stru +@@ -2916,25 +2916,16 @@ static void mt753x_phylink_get_caps(stru priv->info->mac_port_get_caps(ds, port, config); } @@ -55,7 +55,7 @@ Signed-off-by: Paolo Abeni } static void mt7530_pcs_get_state(struct phylink_pcs *pcs, -@@ -3031,12 +3022,14 @@ static void mt7530_pcs_an_restart(struct +@@ -3036,12 +3027,14 @@ static void mt7530_pcs_an_restart(struct } static const struct phylink_pcs_ops mt7530_pcs_ops = { @@ -70,7 +70,7 @@ Signed-off-by: Paolo Abeni .pcs_get_state = mt7531_pcs_get_state, .pcs_config = mt753x_pcs_config, .pcs_an_restart = mt7531_pcs_an_restart, -@@ -3128,7 +3121,6 @@ static const struct dsa_switch_ops mt753 +@@ -3133,7 +3126,6 @@ static const struct dsa_switch_ops mt753 .port_mirror_add = mt753x_port_mirror_add, .port_mirror_del = mt753x_port_mirror_del, .phylink_get_caps = mt753x_phylink_get_caps, diff --git a/target/linux/generic/backport-5.15/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch b/target/linux/generic/backport-5.15/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch index 7d5e4ae6cec..e58089a3f85 100644 --- a/target/linux/generic/backport-5.15/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch +++ b/target/linux/generic/backport-5.15/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch @@ -19,7 +19,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2908,6 +2908,12 @@ static void mt753x_phylink_get_caps(stru +@@ -2913,6 +2913,12 @@ static void mt753x_phylink_get_caps(stru config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD; diff --git a/target/linux/generic/backport-5.15/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch b/target/linux/generic/backport-5.15/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch index 7066a87d71a..576d768fe21 100644 --- a/target/linux/generic/backport-5.15/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch +++ b/target/linux/generic/backport-5.15/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch @@ -81,7 +81,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -3046,9 +3046,16 @@ static int +@@ -3051,9 +3051,16 @@ static int mt753x_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; @@ -100,7 +100,7 @@ Signed-off-by: Jakub Kicinski if (ret) return ret; -@@ -3060,13 +3067,6 @@ mt753x_setup(struct dsa_switch *ds) +@@ -3065,13 +3072,6 @@ mt753x_setup(struct dsa_switch *ds) if (ret && priv->irq) mt7530_free_irq_common(priv); diff --git a/target/linux/generic/backport-5.15/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch b/target/linux/generic/backport-5.15/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch index 2476cd361a8..e33908c13d6 100644 --- a/target/linux/generic/backport-5.15/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch +++ b/target/linux/generic/backport-5.15/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch @@ -26,7 +26,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -1537,11 +1537,11 @@ static void +@@ -1540,11 +1540,11 @@ static void mt7530_hw_vlan_add(struct mt7530_priv *priv, struct mt7530_hw_vlan_entry *entry) { @@ -40,7 +40,7 @@ Signed-off-by: Jakub Kicinski /* Validate the entry with independent learning, create egress tag per * VLAN and joining the port as one of the port members. -@@ -1552,22 +1552,20 @@ mt7530_hw_vlan_add(struct mt7530_priv *p +@@ -1555,22 +1555,20 @@ mt7530_hw_vlan_add(struct mt7530_priv *p /* Decide whether adding tag or not for those outgoing packets from the * port inside the VLAN. @@ -72,7 +72,7 @@ Signed-off-by: Jakub Kicinski } static void -@@ -1586,11 +1584,7 @@ mt7530_hw_vlan_del(struct mt7530_priv *p +@@ -1589,11 +1587,7 @@ mt7530_hw_vlan_del(struct mt7530_priv *p return; } diff --git a/target/linux/generic/backport-5.15/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch b/target/linux/generic/backport-5.15/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch index 6928c5960a0..a50fe30164b 100644 --- a/target/linux/generic/backport-5.15/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch +++ b/target/linux/generic/backport-5.15/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch @@ -16,7 +16,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2102,11 +2102,12 @@ static int +@@ -2105,11 +2105,12 @@ static int mt7530_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; @@ -30,7 +30,7 @@ Signed-off-by: Jakub Kicinski u32 id, val; int ret, i; -@@ -2114,7 +2115,19 @@ mt7530_setup(struct dsa_switch *ds) +@@ -2117,7 +2118,19 @@ mt7530_setup(struct dsa_switch *ds) * controller also is the container for two GMACs nodes representing * as two netdev instances. */ @@ -51,7 +51,7 @@ Signed-off-by: Jakub Kicinski ds->assisted_learning_on_cpu_port = true; ds->mtu_enforcement_ingress = true; -@@ -2276,6 +2289,7 @@ mt7531_setup(struct dsa_switch *ds) +@@ -2281,6 +2294,7 @@ mt7531_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; struct mt7530_dummy_poll p; @@ -59,7 +59,7 @@ Signed-off-by: Jakub Kicinski u32 val, id; int ret, i; -@@ -2350,8 +2364,11 @@ mt7531_setup(struct dsa_switch *ds) +@@ -2355,8 +2369,11 @@ mt7531_setup(struct dsa_switch *ds) CORE_PLL_GROUP4, val); /* BPDU to CPU port */ diff --git a/target/linux/generic/backport-5.15/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch b/target/linux/generic/backport-5.15/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch index 828c2b52745..8563e7e136a 100644 --- a/target/linux/generic/backport-5.15/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch +++ b/target/linux/generic/backport-5.15/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch @@ -21,7 +21,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -1041,6 +1041,7 @@ static int +@@ -1044,6 +1044,7 @@ static int mt7530_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy) { @@ -29,7 +29,7 @@ Signed-off-by: Jakub Kicinski struct mt7530_priv *priv = ds->priv; mutex_lock(&priv->reg_mutex); -@@ -1049,7 +1050,11 @@ mt7530_port_enable(struct dsa_switch *ds +@@ -1052,7 +1053,11 @@ mt7530_port_enable(struct dsa_switch *ds * restore the port matrix if the port is the member of a certain * bridge. */ @@ -42,7 +42,7 @@ Signed-off-by: Jakub Kicinski priv->ports[port].enable = true; mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, priv->ports[port].pm); -@@ -1197,7 +1202,8 @@ mt7530_port_bridge_join(struct dsa_switc +@@ -1200,7 +1205,8 @@ mt7530_port_bridge_join(struct dsa_switc struct net_device *bridge) { struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; @@ -52,7 +52,7 @@ Signed-off-by: Jakub Kicinski struct mt7530_priv *priv = ds->priv; mutex_lock(&priv->reg_mutex); -@@ -1274,9 +1280,12 @@ mt7530_port_set_vlan_unaware(struct dsa_ +@@ -1277,9 +1283,12 @@ mt7530_port_set_vlan_unaware(struct dsa_ * the CPU port get out of VLAN filtering mode. */ if (all_user_ports_removed) { @@ -67,7 +67,7 @@ Signed-off-by: Jakub Kicinski | PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); } } -@@ -1326,6 +1335,7 @@ mt7530_port_bridge_leave(struct dsa_swit +@@ -1329,6 +1338,7 @@ mt7530_port_bridge_leave(struct dsa_swit struct net_device *bridge) { struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; @@ -75,7 +75,7 @@ Signed-off-by: Jakub Kicinski struct mt7530_priv *priv = ds->priv; mutex_lock(&priv->reg_mutex); -@@ -1354,8 +1364,8 @@ mt7530_port_bridge_leave(struct dsa_swit +@@ -1357,8 +1367,8 @@ mt7530_port_bridge_leave(struct dsa_swit */ if (priv->ports[port].enable) mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, @@ -86,7 +86,7 @@ Signed-off-by: Jakub Kicinski /* When a port is removed from the bridge, the port would be set up * back to the default as is at initial boot which is a VLAN-unaware -@@ -1518,6 +1528,9 @@ static int +@@ -1521,6 +1531,9 @@ static int mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, struct netlink_ext_ack *extack) { @@ -96,7 +96,7 @@ Signed-off-by: Jakub Kicinski if (vlan_filtering) { /* The port is being kept as VLAN-unaware port when bridge is * set up with vlan_filtering not being set, Otherwise, the -@@ -1525,7 +1538,7 @@ mt7530_port_vlan_filtering(struct dsa_sw +@@ -1528,7 +1541,7 @@ mt7530_port_vlan_filtering(struct dsa_sw * for becoming a VLAN-aware port. */ mt7530_port_set_vlan_aware(ds, port); diff --git a/target/linux/generic/backport-5.15/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch b/target/linux/generic/backport-5.15/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch index f9aa6fb67b4..c5501fb0402 100644 --- a/target/linux/generic/backport-5.15/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch +++ b/target/linux/generic/backport-5.15/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch @@ -27,7 +27,7 @@ Signed-off-by: David S. Miller MediaTek SoC family. --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1388,6 +1388,68 @@ static void mtk_update_rx_cpu_idx(struct +@@ -1389,6 +1389,68 @@ static void mtk_update_rx_cpu_idx(struct } } @@ -96,7 +96,7 @@ Signed-off-by: David S. Miller static int mtk_poll_rx(struct napi_struct *napi, int budget, struct mtk_eth *eth) { -@@ -1401,9 +1463,9 @@ static int mtk_poll_rx(struct napi_struc +@@ -1402,9 +1464,9 @@ static int mtk_poll_rx(struct napi_struc while (done < budget) { unsigned int pktlen, *rxdcsum; @@ -107,7 +107,7 @@ Signed-off-by: David S. Miller int mac = 0; ring = mtk_get_rx_ring(eth); -@@ -1434,36 +1496,54 @@ static int mtk_poll_rx(struct napi_struc +@@ -1435,36 +1497,54 @@ static int mtk_poll_rx(struct napi_struc goto release_desc; /* alloc new buffer */ @@ -184,7 +184,7 @@ Signed-off-by: David S. Miller pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); skb->dev = netdev; -@@ -1517,7 +1597,6 @@ static int mtk_poll_rx(struct napi_struc +@@ -1518,7 +1598,6 @@ static int mtk_poll_rx(struct napi_struc skip_rx: ring->data[idx] = new_data; rxd->rxd1 = (unsigned int)dma_addr; @@ -192,7 +192,7 @@ Signed-off-by: David S. Miller release_desc: if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) rxd->rxd2 = RX_DMA_LSO; -@@ -1525,7 +1604,6 @@ release_desc: +@@ -1526,7 +1605,6 @@ release_desc: rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); ring->calc_idx = idx; @@ -200,7 +200,7 @@ Signed-off-by: David S. Miller done++; } -@@ -1889,13 +1967,15 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1890,13 +1968,15 @@ static int mtk_rx_alloc(struct mtk_eth * if (!ring->data) return -ENOMEM; @@ -223,7 +223,7 @@ Signed-off-by: David S. Miller } ring->dma = dma_alloc_coherent(eth->dma_dev, -@@ -1906,16 +1986,33 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1907,16 +1987,33 @@ static int mtk_rx_alloc(struct mtk_eth * for (i = 0; i < rx_dma_size; i++) { struct mtk_rx_dma_v2 *rxd; @@ -264,7 +264,7 @@ Signed-off-by: David S. Miller if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) rxd->rxd2 = RX_DMA_LSO; -@@ -1931,6 +2028,7 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1932,6 +2029,7 @@ static int mtk_rx_alloc(struct mtk_eth * rxd->rxd8 = 0; } } @@ -272,7 +272,7 @@ Signed-off-by: David S. Miller ring->dma_size = rx_dma_size; ring->calc_idx_update = false; ring->calc_idx = rx_dma_size - 1; -@@ -1982,7 +2080,7 @@ static void mtk_rx_clean(struct mtk_eth +@@ -1983,7 +2081,7 @@ static void mtk_rx_clean(struct mtk_eth dma_unmap_single(eth->dma_dev, rxd->rxd1, ring->buf_size, DMA_FROM_DEVICE); @@ -281,7 +281,7 @@ Signed-off-by: David S. Miller } kfree(ring->data); ring->data = NULL; -@@ -1994,6 +2092,13 @@ static void mtk_rx_clean(struct mtk_eth +@@ -1995,6 +2093,13 @@ static void mtk_rx_clean(struct mtk_eth ring->dma, ring->phys); ring->dma = NULL; } @@ -318,7 +318,7 @@ Signed-off-by: David S. Miller #define MTK_QRX_OFFSET 0x10 #define MTK_MAX_RX_RING_NUM 4 -@@ -742,6 +749,9 @@ struct mtk_rx_ring { +@@ -743,6 +750,9 @@ struct mtk_rx_ring { bool calc_idx_update; u16 calc_idx; u32 crx_idx_reg; diff --git a/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch b/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch index f03f6a3a414..d94bdabd714 100644 --- a/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch +++ b/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch @@ -18,7 +18,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1388,6 +1388,11 @@ static void mtk_update_rx_cpu_idx(struct +@@ -1389,6 +1389,11 @@ static void mtk_update_rx_cpu_idx(struct } } @@ -30,7 +30,7 @@ Signed-off-by: David S. Miller static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, struct xdp_rxq_info *xdp_q, int id, int size) -@@ -1450,11 +1455,52 @@ static void mtk_rx_put_buff(struct mtk_r +@@ -1451,11 +1456,52 @@ static void mtk_rx_put_buff(struct mtk_r skb_free_frag(data); } @@ -83,7 +83,7 @@ Signed-off-by: David S. Miller int idx; struct sk_buff *skb; u8 *data, *new_data; -@@ -1463,9 +1509,9 @@ static int mtk_poll_rx(struct napi_struc +@@ -1464,9 +1510,9 @@ static int mtk_poll_rx(struct napi_struc while (done < budget) { unsigned int pktlen, *rxdcsum; @@ -94,7 +94,7 @@ Signed-off-by: David S. Miller int mac = 0; ring = mtk_get_rx_ring(eth); -@@ -1495,8 +1541,14 @@ static int mtk_poll_rx(struct napi_struc +@@ -1496,8 +1542,14 @@ static int mtk_poll_rx(struct napi_struc if (unlikely(test_bit(MTK_RESETTING, ð->state))) goto release_desc; @@ -109,7 +109,7 @@ Signed-off-by: David S. Miller new_data = mtk_page_pool_get_buff(ring->page_pool, &dma_addr, GFP_ATOMIC); -@@ -1504,6 +1556,34 @@ static int mtk_poll_rx(struct napi_struc +@@ -1505,6 +1557,34 @@ static int mtk_poll_rx(struct napi_struc netdev->stats.rx_dropped++; goto release_desc; } @@ -144,7 +144,7 @@ Signed-off-by: David S. Miller } else { if (ring->frag_size <= PAGE_SIZE) new_data = napi_alloc_frag(ring->frag_size); -@@ -1527,27 +1607,20 @@ static int mtk_poll_rx(struct napi_struc +@@ -1528,27 +1608,20 @@ static int mtk_poll_rx(struct napi_struc dma_unmap_single(eth->dma_dev, trxd.rxd1, ring->buf_size, DMA_FROM_DEVICE); @@ -181,7 +181,7 @@ Signed-off-by: David S. Miller if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) rxdcsum = &trxd.rxd3; -@@ -1559,7 +1632,6 @@ static int mtk_poll_rx(struct napi_struc +@@ -1560,7 +1633,6 @@ static int mtk_poll_rx(struct napi_struc else skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); @@ -189,7 +189,7 @@ Signed-off-by: David S. Miller hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; if (hash != MTK_RXD4_FOE_ENTRY) { -@@ -1622,6 +1694,9 @@ rx_done: +@@ -1623,6 +1695,9 @@ rx_done: &dim_sample); net_dim(ð->rx_dim, dim_sample); @@ -199,7 +199,7 @@ Signed-off-by: David S. Miller return done; } -@@ -1967,7 +2042,7 @@ static int mtk_rx_alloc(struct mtk_eth * +@@ -1968,7 +2043,7 @@ static int mtk_rx_alloc(struct mtk_eth * if (!ring->data) return -ENOMEM; @@ -208,7 +208,7 @@ Signed-off-by: David S. Miller struct page_pool *pp; pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, -@@ -2709,6 +2784,48 @@ static int mtk_stop(struct net_device *d +@@ -2710,6 +2785,48 @@ static int mtk_stop(struct net_device *d return 0; } @@ -257,7 +257,7 @@ Signed-off-by: David S. Miller static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) { regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, -@@ -3004,6 +3121,12 @@ static int mtk_change_mtu(struct net_dev +@@ -3005,6 +3122,12 @@ static int mtk_change_mtu(struct net_dev struct mtk_eth *eth = mac->hw; u32 mcr_cur, mcr_new; @@ -270,7 +270,7 @@ Signed-off-by: David S. Miller if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; -@@ -3331,6 +3454,7 @@ static const struct net_device_ops mtk_n +@@ -3332,6 +3455,7 @@ static const struct net_device_ops mtk_n .ndo_poll_controller = mtk_poll_controller, #endif .ndo_setup_tc = mtk_eth_setup_tc, @@ -280,7 +280,7 @@ Signed-off-by: David S. Miller static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1085,6 +1085,8 @@ struct mtk_eth { +@@ -1086,6 +1086,8 @@ struct mtk_eth { struct mtk_ppe *ppe; struct rhashtable flow_table; diff --git a/target/linux/generic/backport-5.15/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch b/target/linux/generic/backport-5.15/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch index b68f44aae2a..cf4d658684b 100644 --- a/target/linux/generic/backport-5.15/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch +++ b/target/linux/generic/backport-5.15/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch @@ -39,7 +39,7 @@ Signed-off-by: David S. Miller }; static const char * const mtk_clks_source_name[] = { -@@ -1458,6 +1469,9 @@ static void mtk_rx_put_buff(struct mtk_r +@@ -1459,6 +1470,9 @@ static void mtk_rx_put_buff(struct mtk_r static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, struct xdp_buff *xdp, struct net_device *dev) { @@ -49,7 +49,7 @@ Signed-off-by: David S. Miller struct bpf_prog *prog; u32 act = XDP_PASS; -@@ -1470,13 +1484,16 @@ static u32 mtk_xdp_run(struct mtk_eth *e +@@ -1471,13 +1485,16 @@ static u32 mtk_xdp_run(struct mtk_eth *e act = bpf_prog_run_xdp(prog, xdp); switch (act) { case XDP_PASS: @@ -68,7 +68,7 @@ Signed-off-by: David S. Miller default: bpf_warn_invalid_xdp_action(act); fallthrough; -@@ -1489,6 +1506,11 @@ static u32 mtk_xdp_run(struct mtk_eth *e +@@ -1490,6 +1507,11 @@ static u32 mtk_xdp_run(struct mtk_eth *e page_pool_put_full_page(ring->page_pool, virt_to_head_page(xdp->data), true); @@ -82,7 +82,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -567,6 +567,16 @@ struct mtk_tx_dma_v2 { +@@ -568,6 +568,16 @@ struct mtk_tx_dma_v2 { struct mtk_eth; struct mtk_mac; @@ -99,7 +99,7 @@ Signed-off-by: David S. Miller /* struct mtk_hw_stats - the structure that holds the traffic statistics. * @stats_lock: make sure that stats operations are atomic * @reg_offset: the status register offset of the SoC -@@ -590,6 +600,8 @@ struct mtk_hw_stats { +@@ -591,6 +601,8 @@ struct mtk_hw_stats { u64 rx_checksum_errors; u64 rx_flow_control_packets; diff --git a/target/linux/generic/backport-5.15/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch b/target/linux/generic/backport-5.15/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch index 345c6bed01b..58b49f28a25 100644 --- a/target/linux/generic/backport-5.15/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch +++ b/target/linux/generic/backport-5.15/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch @@ -15,7 +15,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -987,15 +987,26 @@ static void mtk_tx_unmap(struct mtk_eth +@@ -988,15 +988,26 @@ static void mtk_tx_unmap(struct mtk_eth } } @@ -49,7 +49,7 @@ Signed-off-by: David S. Miller } static void setup_tx_buf(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, -@@ -1012,7 +1023,7 @@ static void setup_tx_buf(struct mtk_eth +@@ -1013,7 +1024,7 @@ static void setup_tx_buf(struct mtk_eth dma_unmap_addr_set(tx_buf, dma_addr1, mapped_addr); dma_unmap_len_set(tx_buf, dma_len1, size); } else { @@ -58,7 +58,7 @@ Signed-off-by: David S. Miller txd->txd1 = mapped_addr; txd->txd2 = TX_DMA_PLEN0(size); dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); -@@ -1188,7 +1199,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1189,7 +1200,7 @@ static int mtk_tx_map(struct sk_buff *sk soc->txrx.txd_size); if (new_desc) memset(tx_buf, 0, sizeof(*tx_buf)); @@ -67,7 +67,7 @@ Signed-off-by: David S. Miller tx_buf->flags |= MTK_TX_FLAGS_PAGE0; tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; -@@ -1202,7 +1213,8 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1203,7 +1214,8 @@ static int mtk_tx_map(struct sk_buff *sk } /* store skb to cleanup */ @@ -77,7 +77,7 @@ Signed-off-by: David S. Miller if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { if (k & 0x1) -@@ -1414,13 +1426,14 @@ static struct page_pool *mtk_create_page +@@ -1415,13 +1427,14 @@ static struct page_pool *mtk_create_page .pool_size = size, .nid = NUMA_NO_NODE, .dev = eth->dma_dev, @@ -93,7 +93,7 @@ Signed-off-by: David S. Miller pp = page_pool_create(&pp_params); if (IS_ERR(pp)) return pp; -@@ -1466,6 +1479,122 @@ static void mtk_rx_put_buff(struct mtk_r +@@ -1467,6 +1480,122 @@ static void mtk_rx_put_buff(struct mtk_r skb_free_frag(data); } @@ -216,7 +216,7 @@ Signed-off-by: David S. Miller static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, struct xdp_buff *xdp, struct net_device *dev) { -@@ -1494,6 +1623,18 @@ static u32 mtk_xdp_run(struct mtk_eth *e +@@ -1495,6 +1624,18 @@ static u32 mtk_xdp_run(struct mtk_eth *e count = &hw_stats->xdp_stats.rx_xdp_redirect; goto update_stats; @@ -235,7 +235,7 @@ Signed-off-by: David S. Miller default: bpf_warn_invalid_xdp_action(act); fallthrough; -@@ -1727,9 +1868,8 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -1728,9 +1869,8 @@ static int mtk_poll_tx_qdma(struct mtk_e { const struct mtk_reg_map *reg_map = eth->soc->reg_map; struct mtk_tx_ring *ring = ð->tx_ring; @@ -246,7 +246,7 @@ Signed-off-by: David S. Miller u32 cpu, dma; cpu = ring->last_free_ptr; -@@ -1750,15 +1890,21 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -1751,15 +1891,21 @@ static int mtk_poll_tx_qdma(struct mtk_e if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) mac = 1; @@ -271,7 +271,7 @@ Signed-off-by: David S. Miller mtk_tx_unmap(eth, tx_buf, true); ring->last_free = desc; -@@ -1777,9 +1923,8 @@ static int mtk_poll_tx_pdma(struct mtk_e +@@ -1778,9 +1924,8 @@ static int mtk_poll_tx_pdma(struct mtk_e unsigned int *done, unsigned int *bytes) { struct mtk_tx_ring *ring = ð->tx_ring; @@ -282,7 +282,7 @@ Signed-off-by: David S. Miller u32 cpu, dma; cpu = ring->cpu_idx; -@@ -1787,14 +1932,18 @@ static int mtk_poll_tx_pdma(struct mtk_e +@@ -1788,14 +1933,18 @@ static int mtk_poll_tx_pdma(struct mtk_e while ((cpu != dma) && budget) { tx_buf = &ring->buf[cpu]; @@ -304,7 +304,7 @@ Signed-off-by: David S. Miller } mtk_tx_unmap(eth, tx_buf, true); -@@ -3477,6 +3626,7 @@ static const struct net_device_ops mtk_n +@@ -3478,6 +3627,7 @@ static const struct net_device_ops mtk_n #endif .ndo_setup_tc = mtk_eth_setup_tc, .ndo_bpf = mtk_xdp, @@ -314,7 +314,7 @@ Signed-off-by: David S. Miller static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -693,6 +693,12 @@ enum mtk_dev_state { +@@ -694,6 +694,12 @@ enum mtk_dev_state { MTK_RESETTING }; @@ -327,7 +327,7 @@ Signed-off-by: David S. Miller /* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at * by the TX descriptor s * @skb: The SKB pointer of the packet being sent -@@ -702,7 +708,9 @@ enum mtk_dev_state { +@@ -703,7 +709,9 @@ enum mtk_dev_state { * @dma_len1: The length of the second segment */ struct mtk_tx_buf { diff --git a/target/linux/generic/backport-5.15/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch b/target/linux/generic/backport-5.15/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch index 8302cb05c43..e93e0df544a 100644 --- a/target/linux/generic/backport-5.15/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch +++ b/target/linux/generic/backport-5.15/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch @@ -26,7 +26,7 @@ Signed-off-by: David S. Miller MediaTek SoC family. --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3487,11 +3487,18 @@ static void mtk_get_strings(struct net_d +@@ -3488,11 +3488,18 @@ static void mtk_get_strings(struct net_d int i; switch (stringset) { @@ -46,7 +46,7 @@ Signed-off-by: David S. Miller break; } } -@@ -3499,13 +3506,35 @@ static void mtk_get_strings(struct net_d +@@ -3500,13 +3507,35 @@ static void mtk_get_strings(struct net_d static int mtk_get_sset_count(struct net_device *dev, int sset) { switch (sset) { @@ -84,7 +84,7 @@ Signed-off-by: David S. Miller static void mtk_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { -@@ -3533,6 +3562,8 @@ static void mtk_get_ethtool_stats(struct +@@ -3534,6 +3563,8 @@ static void mtk_get_ethtool_stats(struct for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); diff --git a/target/linux/generic/backport-5.15/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch b/target/linux/generic/backport-5.15/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch index 33a76166521..8e6895fe97f 100644 --- a/target/linux/generic/backport-5.15/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch +++ b/target/linux/generic/backport-5.15/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch @@ -15,7 +15,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1479,6 +1479,41 @@ static void mtk_rx_put_buff(struct mtk_r +@@ -1480,6 +1480,41 @@ static void mtk_rx_put_buff(struct mtk_r skb_free_frag(data); } @@ -57,7 +57,7 @@ Signed-off-by: David S. Miller static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, struct net_device *dev, bool dma_map) { -@@ -1489,9 +1524,8 @@ static int mtk_xdp_submit_frame(struct m +@@ -1490,9 +1525,8 @@ static int mtk_xdp_submit_frame(struct m .first = true, .last = true, }; @@ -68,7 +68,7 @@ Signed-off-by: David S. Miller struct mtk_tx_buf *tx_buf; if (unlikely(test_bit(MTK_RESETTING, ð->state))) -@@ -1511,36 +1545,18 @@ static int mtk_xdp_submit_frame(struct m +@@ -1512,36 +1546,18 @@ static int mtk_xdp_submit_frame(struct m tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); memset(tx_buf, 0, sizeof(*tx_buf)); diff --git a/target/linux/generic/backport-5.15/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch b/target/linux/generic/backport-5.15/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch index e75861bc829..23e4a4dfcbf 100644 --- a/target/linux/generic/backport-5.15/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch +++ b/target/linux/generic/backport-5.15/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch @@ -14,7 +14,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -987,23 +987,22 @@ static void mtk_tx_unmap(struct mtk_eth +@@ -988,23 +988,22 @@ static void mtk_tx_unmap(struct mtk_eth } } @@ -47,7 +47,7 @@ Signed-off-by: David S. Miller } tx_buf->flags = 0; tx_buf->data = NULL; -@@ -1506,6 +1505,8 @@ static int mtk_xdp_frame_map(struct mtk_ +@@ -1507,6 +1506,8 @@ static int mtk_xdp_frame_map(struct mtk_ mtk_tx_set_dma_desc(dev, txd, txd_info); tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; @@ -56,7 +56,7 @@ Signed-off-by: David S. Miller txd_pdma = qdma_to_pdma(ring, txd); setup_tx_buf(eth, tx_buf, txd_pdma, txd_info->addr, txd_info->size, -@@ -1517,43 +1518,69 @@ static int mtk_xdp_frame_map(struct mtk_ +@@ -1518,43 +1519,69 @@ static int mtk_xdp_frame_map(struct mtk_ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, struct net_device *dev, bool dma_map) { @@ -140,7 +140,7 @@ Signed-off-by: David S. Miller if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { txd_pdma = qdma_to_pdma(ring, txd); -@@ -1580,7 +1607,24 @@ static int mtk_xdp_submit_frame(struct m +@@ -1581,7 +1608,24 @@ static int mtk_xdp_submit_frame(struct m mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), MT7628_TX_CTX_IDX0); } @@ -166,7 +166,7 @@ Signed-off-by: David S. Miller spin_unlock(ð->page_lock); return err; -@@ -1909,18 +1953,15 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -1910,18 +1954,15 @@ static int mtk_poll_tx_qdma(struct mtk_e if (!tx_buf->data) break; @@ -191,7 +191,7 @@ Signed-off-by: David S. Miller mtk_tx_unmap(eth, tx_buf, true); ring->last_free = desc; -@@ -1951,17 +1992,15 @@ static int mtk_poll_tx_pdma(struct mtk_e +@@ -1952,17 +1993,15 @@ static int mtk_poll_tx_pdma(struct mtk_e if (!tx_buf->data) break; diff --git a/target/linux/generic/backport-5.15/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch b/target/linux/generic/backport-5.15/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch index a3842d35f56..817b3e10fdf 100644 --- a/target/linux/generic/backport-5.15/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch +++ b/target/linux/generic/backport-5.15/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch @@ -18,7 +18,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1845,10 +1845,19 @@ static int mtk_poll_rx(struct napi_struc +@@ -1846,10 +1846,19 @@ static int mtk_poll_rx(struct napi_struc skb->dev = netdev; bytes += skb->len; @@ -40,7 +40,7 @@ Signed-off-by: Paolo Abeni if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid) skb->ip_summed = CHECKSUM_UNNECESSARY; -@@ -1856,16 +1865,9 @@ static int mtk_poll_rx(struct napi_struc +@@ -1857,16 +1866,9 @@ static int mtk_poll_rx(struct napi_struc skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); diff --git a/target/linux/generic/backport-5.15/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch b/target/linux/generic/backport-5.15/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch index f4eb030ef69..f6fc7340794 100644 --- a/target/linux/generic/backport-5.15/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch +++ b/target/linux/generic/backport-5.15/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch @@ -24,7 +24,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1412,7 +1412,7 @@ static void mtk_update_rx_cpu_idx(struct +@@ -1413,7 +1413,7 @@ static void mtk_update_rx_cpu_idx(struct static bool mtk_page_pool_enabled(struct mtk_eth *eth) { diff --git a/target/linux/generic/backport-5.15/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch b/target/linux/generic/backport-5.15/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch index ca2d161056d..f8bbea6c858 100644 --- a/target/linux/generic/backport-5.15/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch +++ b/target/linux/generic/backport-5.15/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch @@ -57,7 +57,7 @@ Signed-off-by: Lorenzo Bianconi }; /* strings used by ethtool */ -@@ -2924,6 +2928,7 @@ static int mtk_open(struct net_device *d +@@ -2925,6 +2929,7 @@ static int mtk_open(struct net_device *d /* we run 2 netdevs on the same dma ring so we only bring it up once */ if (!refcount_read(ð->dma_refcnt)) { @@ -65,7 +65,7 @@ Signed-off-by: Lorenzo Bianconi u32 gdm_config = MTK_GDMA_TO_PDMA; int err; -@@ -2933,15 +2938,15 @@ static int mtk_open(struct net_device *d +@@ -2934,15 +2939,15 @@ static int mtk_open(struct net_device *d return err; } @@ -84,7 +84,7 @@ Signed-off-by: Lorenzo Bianconi refcount_set(ð->dma_refcnt, 1); } else -@@ -4047,7 +4052,9 @@ static int mtk_probe(struct platform_dev +@@ -4048,7 +4053,9 @@ static int mtk_probe(struct platform_dev } if (eth->soc->offload_version) { @@ -105,7 +105,7 @@ Signed-off-by: Lorenzo Bianconi #define MTK_GDMA_DROP_ALL 0x7777 /* Unicast Filter MAC Address Register - Low */ -@@ -952,6 +951,8 @@ struct mtk_reg_map { +@@ -953,6 +952,8 @@ struct mtk_reg_map { u32 fq_blen; /* fq free page buffer length */ } qdma; u32 gdm1_cnt; diff --git a/target/linux/generic/backport-5.15/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch b/target/linux/generic/backport-5.15/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch index 89a3aa98931..7bed2785c99 100644 --- a/target/linux/generic/backport-5.15/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch +++ b/target/linux/generic/backport-5.15/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch @@ -44,7 +44,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4150,6 +4150,7 @@ static const struct mtk_soc_data mt7621_ +@@ -4151,6 +4151,7 @@ static const struct mtk_soc_data mt7621_ .required_clks = MT7621_CLKS_BITMAP, .required_pctl = false, .offload_version = 2, @@ -52,7 +52,7 @@ Signed-off-by: Lorenzo Bianconi .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4168,6 +4169,7 @@ static const struct mtk_soc_data mt7622_ +@@ -4169,6 +4170,7 @@ static const struct mtk_soc_data mt7622_ .required_clks = MT7622_CLKS_BITMAP, .required_pctl = false, .offload_version = 2, @@ -60,7 +60,7 @@ Signed-off-by: Lorenzo Bianconi .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4185,6 +4187,7 @@ static const struct mtk_soc_data mt7623_ +@@ -4186,6 +4188,7 @@ static const struct mtk_soc_data mt7623_ .required_clks = MT7623_CLKS_BITMAP, .required_pctl = true, .offload_version = 2, @@ -68,7 +68,7 @@ Signed-off-by: Lorenzo Bianconi .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4218,6 +4221,7 @@ static const struct mtk_soc_data mt7986_ +@@ -4219,6 +4222,7 @@ static const struct mtk_soc_data mt7986_ .caps = MT7986_CAPS, .required_clks = MT7986_CLKS_BITMAP, .required_pctl = false, @@ -78,7 +78,7 @@ Signed-off-by: Lorenzo Bianconi .rxd_size = sizeof(struct mtk_rx_dma_v2), --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -966,6 +966,7 @@ struct mtk_reg_map { +@@ -967,6 +967,7 @@ struct mtk_reg_map { * the target SoC * @required_pctl A bool value to show whether the SoC requires * the extra setup for those pins used by GMAC. @@ -86,7 +86,7 @@ Signed-off-by: Lorenzo Bianconi * @txd_size Tx DMA descriptor size. * @rxd_size Rx DMA descriptor size. * @rx_irq_done_mask Rx irq done register mask. -@@ -980,6 +981,7 @@ struct mtk_soc_data { +@@ -981,6 +982,7 @@ struct mtk_soc_data { u32 required_clks; bool required_pctl; u8 offload_version; diff --git a/target/linux/generic/backport-5.15/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch b/target/linux/generic/backport-5.15/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch index 9f4875eed3b..4d6dd4dcb44 100644 --- a/target/linux/generic/backport-5.15/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch +++ b/target/linux/generic/backport-5.15/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch @@ -48,7 +48,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1871,7 +1871,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1872,7 +1872,7 @@ static int mtk_poll_rx(struct napi_struc reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) @@ -57,7 +57,7 @@ Signed-off-by: Lorenzo Bianconi if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -@@ -2929,7 +2929,8 @@ static int mtk_open(struct net_device *d +@@ -2930,7 +2930,8 @@ static int mtk_open(struct net_device *d /* we run 2 netdevs on the same dma ring so we only bring it up once */ if (!refcount_read(ð->dma_refcnt)) { const struct mtk_soc_data *soc = eth->soc; @@ -67,7 +67,7 @@ Signed-off-by: Lorenzo Bianconi int err; err = mtk_start_dma(eth); -@@ -2938,8 +2939,11 @@ static int mtk_open(struct net_device *d +@@ -2939,8 +2940,11 @@ static int mtk_open(struct net_device *d return err; } @@ -81,7 +81,7 @@ Signed-off-by: Lorenzo Bianconi mtk_gdm_config(eth, gdm_config); -@@ -2984,6 +2988,7 @@ static int mtk_stop(struct net_device *d +@@ -2985,6 +2989,7 @@ static int mtk_stop(struct net_device *d { struct mtk_mac *mac = netdev_priv(dev); struct mtk_eth *eth = mac->hw; @@ -89,7 +89,7 @@ Signed-off-by: Lorenzo Bianconi phylink_stop(mac->phylink); -@@ -3011,8 +3016,8 @@ static int mtk_stop(struct net_device *d +@@ -3012,8 +3017,8 @@ static int mtk_stop(struct net_device *d mtk_dma_free(eth); @@ -100,7 +100,7 @@ Signed-off-by: Lorenzo Bianconi return 0; } -@@ -4052,12 +4057,19 @@ static int mtk_probe(struct platform_dev +@@ -4053,12 +4058,19 @@ static int mtk_probe(struct platform_dev } if (eth->soc->offload_version) { @@ -127,7 +127,7 @@ Signed-off-by: Lorenzo Bianconi err = mtk_eth_offload_init(eth); --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1111,7 +1111,7 @@ struct mtk_eth { +@@ -1112,7 +1112,7 @@ struct mtk_eth { int ip_align; diff --git a/target/linux/generic/backport-5.15/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch b/target/linux/generic/backport-5.15/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch index 9ac6875da14..a4b285632e1 100644 --- a/target/linux/generic/backport-5.15/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch +++ b/target/linux/generic/backport-5.15/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch @@ -39,7 +39,7 @@ Signed-off-by: Lorenzo Bianconi }; /* strings used by ethtool */ -@@ -3969,16 +3977,12 @@ static int mtk_probe(struct platform_dev +@@ -3970,16 +3978,12 @@ static int mtk_probe(struct platform_dev for (i = 0;; i++) { struct device_node *np = of_parse_phandle(pdev->dev.of_node, "mediatek,wed", i); @@ -70,7 +70,7 @@ Signed-off-by: Lorenzo Bianconi /* QDMA descriptor txd4 */ #define TX_DMA_CHKSUM (0x7 << 29) #define TX_DMA_TSO BIT(28) -@@ -953,6 +950,7 @@ struct mtk_reg_map { +@@ -954,6 +951,7 @@ struct mtk_reg_map { u32 gdm1_cnt; u32 gdma_to_ppe0; u32 ppe_base; diff --git a/target/linux/generic/backport-5.15/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch b/target/linux/generic/backport-5.15/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch index 16bc8e29fc1..2bce63c4c01 100644 --- a/target/linux/generic/backport-5.15/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch +++ b/target/linux/generic/backport-5.15/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch @@ -21,7 +21,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4167,6 +4167,7 @@ static const struct mtk_soc_data mt7621_ +@@ -4168,6 +4168,7 @@ static const struct mtk_soc_data mt7621_ .required_pctl = false, .offload_version = 2, .hash_offset = 2, @@ -29,7 +29,7 @@ Signed-off-by: Lorenzo Bianconi .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4186,6 +4187,7 @@ static const struct mtk_soc_data mt7622_ +@@ -4187,6 +4188,7 @@ static const struct mtk_soc_data mt7622_ .required_pctl = false, .offload_version = 2, .hash_offset = 2, @@ -37,7 +37,7 @@ Signed-off-by: Lorenzo Bianconi .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4204,6 +4206,7 @@ static const struct mtk_soc_data mt7623_ +@@ -4205,6 +4207,7 @@ static const struct mtk_soc_data mt7623_ .required_pctl = true, .offload_version = 2, .hash_offset = 2, @@ -47,7 +47,7 @@ Signed-off-by: Lorenzo Bianconi .rxd_size = sizeof(struct mtk_rx_dma), --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -965,6 +965,7 @@ struct mtk_reg_map { +@@ -966,6 +966,7 @@ struct mtk_reg_map { * @required_pctl A bool value to show whether the SoC requires * the extra setup for those pins used by GMAC. * @hash_offset Flow table hash offset. @@ -55,7 +55,7 @@ Signed-off-by: Lorenzo Bianconi * @txd_size Tx DMA descriptor size. * @rxd_size Rx DMA descriptor size. * @rx_irq_done_mask Rx irq done register mask. -@@ -980,6 +981,7 @@ struct mtk_soc_data { +@@ -981,6 +982,7 @@ struct mtk_soc_data { bool required_pctl; u8 offload_version; u8 hash_offset; @@ -63,7 +63,7 @@ Signed-off-by: Lorenzo Bianconi netdev_features_t hw_features; struct { u32 txd_size; -@@ -1140,6 +1142,14 @@ struct mtk_mac { +@@ -1141,6 +1143,14 @@ struct mtk_mac { /* the struct describing the SoC. these are declared in the soc_xyz.c files */ extern const struct of_device_id of_mtk_match[]; diff --git a/target/linux/generic/backport-5.15/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch b/target/linux/generic/backport-5.15/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch index cd841d2dafc..bfca7b20e45 100644 --- a/target/linux/generic/backport-5.15/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch +++ b/target/linux/generic/backport-5.15/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch @@ -26,7 +26,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3894,6 +3894,7 @@ void mtk_eth_set_dma_device(struct mtk_e +@@ -3895,6 +3895,7 @@ void mtk_eth_set_dma_device(struct mtk_e static int mtk_probe(struct platform_device *pdev) { @@ -34,7 +34,7 @@ Signed-off-by: Lorenzo Bianconi struct device_node *mac_np; struct mtk_eth *eth; int err, i; -@@ -3974,16 +3975,31 @@ static int mtk_probe(struct platform_dev +@@ -3975,16 +3976,31 @@ static int mtk_probe(struct platform_dev } } diff --git a/target/linux/generic/backport-5.15/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch b/target/linux/generic/backport-5.15/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch index 2fb0b1dfd67..fedcb6ccd89 100644 --- a/target/linux/generic/backport-5.15/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch +++ b/target/linux/generic/backport-5.15/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch @@ -26,7 +26,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1858,12 +1858,14 @@ static int mtk_poll_rx(struct napi_struc +@@ -1859,12 +1859,14 @@ static int mtk_poll_rx(struct napi_struc bytes += skb->len; if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { @@ -41,7 +41,7 @@ Signed-off-by: Lorenzo Bianconi hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; if (hash != MTK_RXD4_FOE_ENTRY) skb_set_hash(skb, jhash_1word(hash, 0), -@@ -1877,7 +1879,6 @@ static int mtk_poll_rx(struct napi_struc +@@ -1878,7 +1880,6 @@ static int mtk_poll_rx(struct napi_struc skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); @@ -49,7 +49,7 @@ Signed-off-by: Lorenzo Bianconi if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) mtk_ppe_check_skb(eth->ppe[0], skb, hash); -@@ -4183,7 +4184,7 @@ static const struct mtk_soc_data mt7621_ +@@ -4184,7 +4185,7 @@ static const struct mtk_soc_data mt7621_ .required_pctl = false, .offload_version = 2, .hash_offset = 2, @@ -58,7 +58,7 @@ Signed-off-by: Lorenzo Bianconi .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4203,7 +4204,7 @@ static const struct mtk_soc_data mt7622_ +@@ -4204,7 +4205,7 @@ static const struct mtk_soc_data mt7622_ .required_pctl = false, .offload_version = 2, .hash_offset = 2, @@ -67,7 +67,7 @@ Signed-off-by: Lorenzo Bianconi .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4222,7 +4223,7 @@ static const struct mtk_soc_data mt7623_ +@@ -4223,7 +4224,7 @@ static const struct mtk_soc_data mt7623_ .required_pctl = true, .offload_version = 2, .hash_offset = 2, @@ -76,7 +76,7 @@ Signed-off-by: Lorenzo Bianconi .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4254,9 +4255,11 @@ static const struct mtk_soc_data mt7986_ +@@ -4255,9 +4256,11 @@ static const struct mtk_soc_data mt7986_ .reg_map = &mt7986_reg_map, .ana_rgc3 = 0x128, .caps = MT7986_CAPS, @@ -90,7 +90,7 @@ Signed-off-by: Lorenzo Bianconi .rxd_size = sizeof(struct mtk_rx_dma_v2), --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1150,6 +1150,78 @@ mtk_foe_get_entry(struct mtk_ppe *ppe, u +@@ -1151,6 +1151,78 @@ mtk_foe_get_entry(struct mtk_ppe *ppe, u return ppe->foe_table + hash * soc->foe_entry_size; } diff --git a/target/linux/generic/backport-5.15/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch b/target/linux/generic/backport-5.15/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch index 5b94c3ad3a0..e8bb85ac940 100644 --- a/target/linux/generic/backport-5.15/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch +++ b/target/linux/generic/backport-5.15/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch @@ -16,7 +16,7 @@ Signed-off-by: Lorenzo Bianconi --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4258,6 +4258,7 @@ static const struct mtk_soc_data mt7986_ +@@ -4259,6 +4259,7 @@ static const struct mtk_soc_data mt7986_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7986_CLKS_BITMAP, .required_pctl = false, diff --git a/target/linux/generic/backport-5.15/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch b/target/linux/generic/backport-5.15/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch index 08ec7e1ab94..b41318afd76 100644 --- a/target/linux/generic/backport-5.15/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch +++ b/target/linux/generic/backport-5.15/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch @@ -17,7 +17,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4010,19 +4010,23 @@ static int mtk_probe(struct platform_dev +@@ -4011,19 +4011,23 @@ static int mtk_probe(struct platform_dev eth->irq[i] = platform_get_irq(pdev, i); if (eth->irq[i] < 0) { dev_err(&pdev->dev, "no IRQ%d resource found\n", i); @@ -45,7 +45,7 @@ Signed-off-by: David S. Miller } eth->clks[i] = NULL; } -@@ -4033,7 +4037,7 @@ static int mtk_probe(struct platform_dev +@@ -4034,7 +4038,7 @@ static int mtk_probe(struct platform_dev err = mtk_hw_init(eth); if (err) @@ -54,7 +54,7 @@ Signed-off-by: David S. Miller eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO); -@@ -4131,6 +4135,8 @@ err_free_dev: +@@ -4132,6 +4136,8 @@ err_free_dev: mtk_free_dev(eth); err_deinit_hw: mtk_hw_deinit(eth); @@ -63,7 +63,7 @@ Signed-off-by: David S. Miller return err; } -@@ -4150,6 +4156,7 @@ static int mtk_remove(struct platform_de +@@ -4151,6 +4157,7 @@ static int mtk_remove(struct platform_de phylink_disconnect_phy(mac->phylink); } diff --git a/target/linux/generic/backport-5.15/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch b/target/linux/generic/backport-5.15/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch index f9e7caa27cb..003ca9bae69 100644 --- a/target/linux/generic/backport-5.15/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch +++ b/target/linux/generic/backport-5.15/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch @@ -14,7 +14,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3175,6 +3175,30 @@ static void mtk_dim_tx(struct work_struc +@@ -3176,6 +3176,30 @@ static void mtk_dim_tx(struct work_struc dim->state = DIM_START_MEASURE; } @@ -45,7 +45,7 @@ Signed-off-by: David S. Miller static int mtk_hw_init(struct mtk_eth *eth) { u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | -@@ -3249,8 +3273,16 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3250,8 +3274,16 @@ static int mtk_hw_init(struct mtk_eth *e * up with the more appropriate value when mtk_mac_config call is being * invoked. */ @@ -63,7 +63,7 @@ Signed-off-by: David S. Miller /* Indicates CDM to parse the MTK special tag from CPU * which also is working out for untag packets. -@@ -3366,7 +3398,6 @@ static int mtk_change_mtu(struct net_dev +@@ -3367,7 +3399,6 @@ static int mtk_change_mtu(struct net_dev int length = new_mtu + MTK_RX_ETH_HLEN; struct mtk_mac *mac = netdev_priv(dev); struct mtk_eth *eth = mac->hw; @@ -71,7 +71,7 @@ Signed-off-by: David S. Miller if (rcu_access_pointer(eth->prog) && length > MTK_PP_MAX_BUF_SIZE) { -@@ -3374,23 +3405,7 @@ static int mtk_change_mtu(struct net_dev +@@ -3375,23 +3406,7 @@ static int mtk_change_mtu(struct net_dev return -EINVAL; } diff --git a/target/linux/generic/backport-5.15/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch b/target/linux/generic/backport-5.15/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch index e51dd7b97a9..342ffb99d2f 100644 --- a/target/linux/generic/backport-5.15/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch +++ b/target/linux/generic/backport-5.15/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch @@ -12,7 +12,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3436,11 +3436,8 @@ static void mtk_pending_work(struct work +@@ -3437,11 +3437,8 @@ static void mtk_pending_work(struct work rtnl_lock(); dev_dbg(eth->dev, "[%s][%d] reset\n", __func__, __LINE__); @@ -25,7 +25,7 @@ Signed-off-by: David S. Miller /* stop all devices to make sure that dma is properly shut down */ for (i = 0; i < MTK_MAC_COUNT; i++) { if (!eth->netdev[i]) -@@ -3474,7 +3471,7 @@ static void mtk_pending_work(struct work +@@ -3475,7 +3472,7 @@ static void mtk_pending_work(struct work dev_dbg(eth->dev, "[%s][%d] reset done\n", __func__, __LINE__); diff --git a/target/linux/generic/backport-5.15/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch b/target/linux/generic/backport-5.15/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch index 69df58eed1c..12aa3ebf6a7 100644 --- a/target/linux/generic/backport-5.15/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch +++ b/target/linux/generic/backport-5.15/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch @@ -13,7 +13,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3238,16 +3238,17 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3239,16 +3239,17 @@ static int mtk_hw_init(struct mtk_eth *e return 0; } @@ -39,7 +39,7 @@ Signed-off-by: David S. Miller regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -444,18 +444,14 @@ +@@ -445,18 +445,14 @@ /* ethernet reset control register */ #define ETHSYS_RSTCTRL 0x34 #define RSTCTRL_FE BIT(6) diff --git a/target/linux/generic/backport-5.15/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch b/target/linux/generic/backport-5.15/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch index f5e9dddd42f..45b85c06cb5 100644 --- a/target/linux/generic/backport-5.15/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch +++ b/target/linux/generic/backport-5.15/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch @@ -16,7 +16,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3199,6 +3199,27 @@ static void mtk_set_mcr_max_rx(struct mt +@@ -3200,6 +3200,27 @@ static void mtk_set_mcr_max_rx(struct mt mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); } @@ -44,7 +44,7 @@ Signed-off-by: Paolo Abeni static int mtk_hw_init(struct mtk_eth *eth) { u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | -@@ -3238,22 +3259,9 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3239,22 +3260,9 @@ static int mtk_hw_init(struct mtk_eth *e return 0; } diff --git a/target/linux/generic/backport-5.15/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch b/target/linux/generic/backport-5.15/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch index f2c9a7e53dc..c34e30c773e 100644 --- a/target/linux/generic/backport-5.15/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch +++ b/target/linux/generic/backport-5.15/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch @@ -17,7 +17,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3220,7 +3220,54 @@ static void mtk_hw_reset(struct mtk_eth +@@ -3221,7 +3221,54 @@ static void mtk_hw_reset(struct mtk_eth 0x3ffffff); } @@ -73,7 +73,7 @@ Signed-off-by: Paolo Abeni { u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | ETHSYS_DMA_AG_MAP_PPE; -@@ -3259,7 +3306,12 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3260,7 +3307,12 @@ static int mtk_hw_init(struct mtk_eth *e return 0; } @@ -87,7 +87,7 @@ Signed-off-by: Paolo Abeni if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { /* Set FE to PDMAv2 if necessary */ -@@ -3464,7 +3516,7 @@ static void mtk_pending_work(struct work +@@ -3465,7 +3517,7 @@ static void mtk_pending_work(struct work if (eth->dev->pins) pinctrl_select_state(eth->dev->pins->p, eth->dev->pins->default_state); @@ -96,7 +96,7 @@ Signed-off-by: Paolo Abeni /* restart DMA and enable IRQs */ for (i = 0; i < MTK_MAC_COUNT; i++) { -@@ -4056,7 +4108,7 @@ static int mtk_probe(struct platform_dev +@@ -4057,7 +4109,7 @@ static int mtk_probe(struct platform_dev eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); INIT_WORK(ð->pending_work, mtk_pending_work); diff --git a/target/linux/generic/backport-5.15/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch b/target/linux/generic/backport-5.15/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch index 02e34bb7cd4..29a5b627390 100644 --- a/target/linux/generic/backport-5.15/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch +++ b/target/linux/generic/backport-5.15/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch @@ -16,7 +16,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2785,14 +2785,29 @@ static void mtk_dma_free(struct mtk_eth +@@ -2786,14 +2786,29 @@ static void mtk_dma_free(struct mtk_eth kfree(eth->scratch_head); } @@ -48,7 +48,7 @@ Signed-off-by: Paolo Abeni schedule_work(ð->pending_work); } -@@ -3274,15 +3289,17 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3275,15 +3290,17 @@ static int mtk_hw_init(struct mtk_eth *e const struct mtk_reg_map *reg_map = eth->soc->reg_map; int i, val, ret; @@ -72,7 +72,7 @@ Signed-off-by: Paolo Abeni if (eth->ethsys) regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, dma_mask, -@@ -3408,8 +3425,10 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3409,8 +3426,10 @@ static int mtk_hw_init(struct mtk_eth *e return 0; err_disable_pm: @@ -85,7 +85,7 @@ Signed-off-by: Paolo Abeni return ret; } -@@ -3488,30 +3507,53 @@ static int mtk_do_ioctl(struct net_devic +@@ -3489,30 +3508,53 @@ static int mtk_do_ioctl(struct net_devic return -EOPNOTSUPP; } @@ -148,7 +148,7 @@ Signed-off-by: Paolo Abeni if (eth->dev->pins) pinctrl_select_state(eth->dev->pins->p, -@@ -3522,15 +3564,19 @@ static void mtk_pending_work(struct work +@@ -3523,15 +3565,19 @@ static void mtk_pending_work(struct work for (i = 0; i < MTK_MAC_COUNT; i++) { if (!test_bit(i, &restart)) continue; diff --git a/target/linux/generic/backport-5.15/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch b/target/linux/generic/backport-5.15/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch index 240e7897c6f..cebb750bf64 100644 --- a/target/linux/generic/backport-5.15/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch +++ b/target/linux/generic/backport-5.15/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch @@ -49,7 +49,7 @@ Signed-off-by: Paolo Abeni }; /* strings used by ethtool */ -@@ -3282,6 +3288,102 @@ static void mtk_hw_warm_reset(struct mtk +@@ -3283,6 +3289,102 @@ static void mtk_hw_warm_reset(struct mtk val, rst_mask); } @@ -152,7 +152,7 @@ Signed-off-by: Paolo Abeni static int mtk_hw_init(struct mtk_eth *eth, bool reset) { u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | -@@ -3614,6 +3716,7 @@ static int mtk_cleanup(struct mtk_eth *e +@@ -3615,6 +3717,7 @@ static int mtk_cleanup(struct mtk_eth *e mtk_unreg_dev(eth); mtk_free_dev(eth); cancel_work_sync(ð->pending_work); @@ -160,7 +160,7 @@ Signed-off-by: Paolo Abeni return 0; } -@@ -4041,6 +4144,7 @@ static int mtk_probe(struct platform_dev +@@ -4042,6 +4145,7 @@ static int mtk_probe(struct platform_dev eth->rx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; INIT_WORK(ð->rx_dim.work, mtk_dim_rx); @@ -168,7 +168,7 @@ Signed-off-by: Paolo Abeni eth->tx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; INIT_WORK(ð->tx_dim.work, mtk_dim_tx); -@@ -4245,6 +4349,8 @@ static int mtk_probe(struct platform_dev +@@ -4246,6 +4350,8 @@ static int mtk_probe(struct platform_dev NAPI_POLL_WEIGHT); platform_set_drvdata(pdev, eth); @@ -188,7 +188,7 @@ Signed-off-by: Paolo Abeni /* QDMA Interrupt grouping registers */ #define MTK_RLS_DONE_INT BIT(0) -@@ -537,6 +539,17 @@ +@@ -538,6 +540,17 @@ #define MT7628_SDM_RBCNT (MT7628_SDM_OFFSET + 0x10c) #define MT7628_SDM_CS_ERR (MT7628_SDM_OFFSET + 0x110) @@ -206,7 +206,7 @@ Signed-off-by: Paolo Abeni struct mtk_rx_dma { unsigned int rxd1; unsigned int rxd2; -@@ -933,6 +946,7 @@ struct mtk_reg_map { +@@ -934,6 +947,7 @@ struct mtk_reg_map { u32 delay_irq; /* delay interrupt */ u32 irq_status; /* interrupt status */ u32 irq_mask; /* interrupt mask */ @@ -214,7 +214,7 @@ Signed-off-by: Paolo Abeni u32 int_grp; } pdma; struct { -@@ -959,6 +973,8 @@ struct mtk_reg_map { +@@ -960,6 +974,8 @@ struct mtk_reg_map { u32 gdma_to_ppe0; u32 ppe_base; u32 wdma_base[2]; @@ -223,7 +223,7 @@ Signed-off-by: Paolo Abeni }; /* struct mtk_eth_data - This is the structure holding all differences -@@ -1001,6 +1017,8 @@ struct mtk_soc_data { +@@ -1002,6 +1018,8 @@ struct mtk_soc_data { } txrx; }; @@ -232,7 +232,7 @@ Signed-off-by: Paolo Abeni /* currently no SoC has more than 2 macs */ #define MTK_MAX_DEVS 2 -@@ -1123,6 +1141,14 @@ struct mtk_eth { +@@ -1124,6 +1142,14 @@ struct mtk_eth { struct rhashtable flow_table; struct bpf_prog __rcu *prog; diff --git a/target/linux/generic/backport-5.15/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch b/target/linux/generic/backport-5.15/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch index 9f67e97e6f0..2eca2686708 100644 --- a/target/linux/generic/backport-5.15/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch +++ b/target/linux/generic/backport-5.15/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch @@ -14,7 +14,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3645,6 +3645,11 @@ static void mtk_pending_work(struct work +@@ -3646,6 +3646,11 @@ static void mtk_pending_work(struct work set_bit(MTK_RESETTING, ð->state); mtk_prepare_for_reset(eth); @@ -26,7 +26,7 @@ Signed-off-by: Paolo Abeni /* stop all devices to make sure that dma is properly shut down */ for (i = 0; i < MTK_MAC_COUNT; i++) { -@@ -3682,6 +3687,8 @@ static void mtk_pending_work(struct work +@@ -3683,6 +3688,8 @@ static void mtk_pending_work(struct work clear_bit(MTK_RESETTING, ð->state); diff --git a/target/linux/generic/backport-5.15/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch b/target/linux/generic/backport-5.15/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch index 85c29e77de3..b3412df9e0c 100644 --- a/target/linux/generic/backport-5.15/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch +++ b/target/linux/generic/backport-5.15/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -900,7 +900,7 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -901,7 +901,7 @@ static int mtk_init_fq_dma(struct mtk_et { const struct mtk_soc_data *soc = eth->soc; dma_addr_t phy_ring_tail; @@ -21,7 +21,7 @@ Signed-off-by: Felix Fietkau dma_addr_t dma_addr; int i; -@@ -2154,19 +2154,25 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2155,19 +2155,25 @@ static int mtk_tx_alloc(struct mtk_eth * struct mtk_tx_ring *ring = ð->tx_ring; int i, sz = soc->txrx.txd_size; struct mtk_tx_dma_v2 *txd; @@ -51,7 +51,7 @@ Signed-off-by: Felix Fietkau u32 next_ptr = ring->phys + next * sz; txd = ring->dma + i * sz; -@@ -2186,22 +2192,22 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2187,22 +2193,22 @@ static int mtk_tx_alloc(struct mtk_eth * * descriptors in ring->dma_pdma. */ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { @@ -79,7 +79,7 @@ Signed-off-by: Felix Fietkau ring->thresh = MAX_SKB_FRAGS; /* make sure that all changes to the dma ring are flushed before we -@@ -2213,14 +2219,14 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2214,14 +2220,14 @@ static int mtk_tx_alloc(struct mtk_eth * mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr); mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr); mtk_w32(eth, @@ -96,7 +96,7 @@ Signed-off-by: Felix Fietkau mtk_w32(eth, 0, MT7628_TX_CTX_IDX0); mtk_w32(eth, MT7628_PST_DTX_IDX0, soc->reg_map->pdma.rst_idx); } -@@ -2238,7 +2244,7 @@ static void mtk_tx_clean(struct mtk_eth +@@ -2239,7 +2245,7 @@ static void mtk_tx_clean(struct mtk_eth int i; if (ring->buf) { @@ -105,7 +105,7 @@ Signed-off-by: Felix Fietkau mtk_tx_unmap(eth, &ring->buf[i], false); kfree(ring->buf); ring->buf = NULL; -@@ -2246,14 +2252,14 @@ static void mtk_tx_clean(struct mtk_eth +@@ -2247,14 +2253,14 @@ static void mtk_tx_clean(struct mtk_eth if (ring->dma) { dma_free_coherent(eth->dma_dev, @@ -122,7 +122,7 @@ Signed-off-by: Felix Fietkau ring->dma_pdma, ring->phys_pdma); ring->dma_pdma = NULL; } -@@ -2773,7 +2779,7 @@ static void mtk_dma_free(struct mtk_eth +@@ -2774,7 +2780,7 @@ static void mtk_dma_free(struct mtk_eth netdev_reset_queue(eth->netdev[i]); if (eth->scratch_ring) { dma_free_coherent(eth->dma_dev, diff --git a/target/linux/generic/backport-5.15/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch b/target/linux/generic/backport-5.15/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch index 67b389490b2..32dc5c37832 100644 --- a/target/linux/generic/backport-5.15/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch +++ b/target/linux/generic/backport-5.15/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4427,7 +4427,7 @@ static const struct mtk_soc_data mt7621_ +@@ -4428,7 +4428,7 @@ static const struct mtk_soc_data mt7621_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7621_CLKS_BITMAP, .required_pctl = false, @@ -21,7 +21,7 @@ Signed-off-by: Felix Fietkau .hash_offset = 2, .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, .txrx = { -@@ -4466,7 +4466,7 @@ static const struct mtk_soc_data mt7623_ +@@ -4467,7 +4467,7 @@ static const struct mtk_soc_data mt7623_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7623_CLKS_BITMAP, .required_pctl = true, diff --git a/target/linux/generic/backport-5.15/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch b/target/linux/generic/backport-5.15/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch index 79f2d0a38ab..cfbd510c8f2 100644 --- a/target/linux/generic/backport-5.15/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch +++ b/target/linux/generic/backport-5.15/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch @@ -54,7 +54,7 @@ Signed-off-by: Felix Fietkau }, .gdm1_cnt = 0x1c00, .gdma_to_ppe0 = 0x3333, -@@ -576,6 +580,75 @@ static void mtk_mac_link_down(struct phy +@@ -577,6 +581,75 @@ static void mtk_mac_link_down(struct phy mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); } @@ -130,7 +130,7 @@ Signed-off-by: Felix Fietkau static void mtk_mac_link_up(struct phylink_config *config, struct phy_device *phy, unsigned int mode, phy_interface_t interface, -@@ -601,6 +674,8 @@ static void mtk_mac_link_up(struct phyli +@@ -602,6 +675,8 @@ static void mtk_mac_link_up(struct phyli break; } @@ -139,7 +139,7 @@ Signed-off-by: Felix Fietkau /* Configure duplex */ if (duplex == DUPLEX_FULL) mcr |= MAC_MCR_FORCE_DPX; -@@ -1059,7 +1134,8 @@ static void mtk_tx_set_dma_desc_v1(struc +@@ -1060,7 +1135,8 @@ static void mtk_tx_set_dma_desc_v1(struc WRITE_ONCE(desc->txd1, info->addr); @@ -149,7 +149,7 @@ Signed-off-by: Felix Fietkau if (info->last) data |= TX_DMA_LS0; WRITE_ONCE(desc->txd3, data); -@@ -1093,9 +1169,6 @@ static void mtk_tx_set_dma_desc_v2(struc +@@ -1094,9 +1170,6 @@ static void mtk_tx_set_dma_desc_v2(struc data |= TX_DMA_LS0; WRITE_ONCE(desc->txd3, data); @@ -159,7 +159,7 @@ Signed-off-by: Felix Fietkau data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */ data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid); WRITE_ONCE(desc->txd4, data); -@@ -1139,11 +1212,12 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1140,11 +1213,12 @@ static int mtk_tx_map(struct sk_buff *sk .gso = gso, .csum = skb->ip_summed == CHECKSUM_PARTIAL, .vlan = skb_vlan_tag_present(skb), @@ -173,7 +173,7 @@ Signed-off-by: Felix Fietkau struct mtk_mac *mac = netdev_priv(dev); struct mtk_eth *eth = mac->hw; const struct mtk_soc_data *soc = eth->soc; -@@ -1151,8 +1225,10 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1152,8 +1226,10 @@ static int mtk_tx_map(struct sk_buff *sk struct mtk_tx_dma *itxd_pdma, *txd_pdma; struct mtk_tx_buf *itx_buf, *tx_buf; int i, n_desc = 1; @@ -184,7 +184,7 @@ Signed-off-by: Felix Fietkau itxd = ring->next_free; itxd_pdma = qdma_to_pdma(ring, itxd); if (itxd == ring->last_free) -@@ -1201,7 +1277,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1202,7 +1278,7 @@ static int mtk_tx_map(struct sk_buff *sk memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); txd_info.size = min_t(unsigned int, frag_size, soc->txrx.dma_max_len); @@ -193,7 +193,7 @@ Signed-off-by: Felix Fietkau txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && !(frag_size - txd_info.size); txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, -@@ -1240,7 +1316,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1241,7 +1317,7 @@ static int mtk_tx_map(struct sk_buff *sk txd_pdma->txd2 |= TX_DMA_LS1; } @@ -202,7 +202,7 @@ Signed-off-by: Felix Fietkau skb_tx_timestamp(skb); ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); -@@ -1252,8 +1328,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1253,8 +1329,7 @@ static int mtk_tx_map(struct sk_buff *sk wmb(); if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { @@ -212,7 +212,7 @@ Signed-off-by: Felix Fietkau mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); } else { int next_idx; -@@ -1322,7 +1397,7 @@ static void mtk_wake_queue(struct mtk_et +@@ -1323,7 +1398,7 @@ static void mtk_wake_queue(struct mtk_et for (i = 0; i < MTK_MAC_COUNT; i++) { if (!eth->netdev[i]) continue; @@ -221,7 +221,7 @@ Signed-off-by: Felix Fietkau } } -@@ -1346,7 +1421,7 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1347,7 +1422,7 @@ static netdev_tx_t mtk_start_xmit(struct tx_num = mtk_cal_txd_req(eth, skb); if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { @@ -230,7 +230,7 @@ Signed-off-by: Felix Fietkau netif_err(eth, tx_queued, dev, "Tx Ring full when queue awake!\n"); spin_unlock(ð->page_lock); -@@ -1372,7 +1447,7 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1373,7 +1448,7 @@ static netdev_tx_t mtk_start_xmit(struct goto drop; if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) @@ -239,7 +239,7 @@ Signed-off-by: Felix Fietkau spin_unlock(ð->page_lock); -@@ -1539,10 +1614,12 @@ static int mtk_xdp_submit_frame(struct m +@@ -1540,10 +1615,12 @@ static int mtk_xdp_submit_frame(struct m struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf); const struct mtk_soc_data *soc = eth->soc; struct mtk_tx_ring *ring = ð->tx_ring; @@ -252,7 +252,7 @@ Signed-off-by: Felix Fietkau }; int err, index = 0, n_desc = 1, nr_frags; struct mtk_tx_dma *htxd, *txd, *txd_pdma; -@@ -1593,6 +1670,7 @@ static int mtk_xdp_submit_frame(struct m +@@ -1594,6 +1671,7 @@ static int mtk_xdp_submit_frame(struct m memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); txd_info.size = skb_frag_size(&sinfo->frags[index]); txd_info.last = index + 1 == nr_frags; @@ -260,7 +260,7 @@ Signed-off-by: Felix Fietkau data = skb_frag_address(&sinfo->frags[index]); index++; -@@ -1944,8 +2022,46 @@ rx_done: +@@ -1945,8 +2023,46 @@ rx_done: return done; } @@ -308,7 +308,7 @@ Signed-off-by: Felix Fietkau { const struct mtk_reg_map *reg_map = eth->soc->reg_map; struct mtk_tx_ring *ring = ð->tx_ring; -@@ -1975,12 +2091,9 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -1976,12 +2092,9 @@ static int mtk_poll_tx_qdma(struct mtk_e break; if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { @@ -323,7 +323,7 @@ Signed-off-by: Felix Fietkau budget--; } mtk_tx_unmap(eth, tx_buf, true); -@@ -1998,7 +2111,7 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -1999,7 +2112,7 @@ static int mtk_poll_tx_qdma(struct mtk_e } static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget, @@ -332,7 +332,7 @@ Signed-off-by: Felix Fietkau { struct mtk_tx_ring *ring = ð->tx_ring; struct mtk_tx_buf *tx_buf; -@@ -2014,12 +2127,8 @@ static int mtk_poll_tx_pdma(struct mtk_e +@@ -2015,12 +2128,8 @@ static int mtk_poll_tx_pdma(struct mtk_e break; if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { @@ -347,7 +347,7 @@ Signed-off-by: Felix Fietkau budget--; } mtk_tx_unmap(eth, tx_buf, true); -@@ -2040,26 +2149,15 @@ static int mtk_poll_tx(struct mtk_eth *e +@@ -2041,26 +2150,15 @@ static int mtk_poll_tx(struct mtk_eth *e { struct mtk_tx_ring *ring = ð->tx_ring; struct dim_sample dim_sample = {}; @@ -379,7 +379,7 @@ Signed-off-by: Felix Fietkau dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes, &dim_sample); -@@ -2069,7 +2167,7 @@ static int mtk_poll_tx(struct mtk_eth *e +@@ -2070,7 +2168,7 @@ static int mtk_poll_tx(struct mtk_eth *e (atomic_read(&ring->free_count) > ring->thresh)) mtk_wake_queue(eth); @@ -388,7 +388,7 @@ Signed-off-by: Felix Fietkau } static void mtk_handle_status_irq(struct mtk_eth *eth) -@@ -2155,6 +2253,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2156,6 +2254,7 @@ static int mtk_tx_alloc(struct mtk_eth * int i, sz = soc->txrx.txd_size; struct mtk_tx_dma_v2 *txd; int ring_size; @@ -396,7 +396,7 @@ Signed-off-by: Felix Fietkau if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) ring_size = MTK_QDMA_RING_SIZE; -@@ -2222,8 +2321,25 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2223,8 +2322,25 @@ static int mtk_tx_alloc(struct mtk_eth * ring->phys + ((ring_size - 1) * sz), soc->reg_map->qdma.crx_ptr); mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr); @@ -424,7 +424,7 @@ Signed-off-by: Felix Fietkau } else { mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0); mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0); -@@ -2903,7 +3019,7 @@ static int mtk_start_dma(struct mtk_eth +@@ -2904,7 +3020,7 @@ static int mtk_start_dma(struct mtk_eth if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) val |= MTK_MUTLI_CNT | MTK_RESV_BUF | MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | @@ -433,7 +433,7 @@ Signed-off-by: Felix Fietkau else val |= MTK_RX_BT_32DWORDS; mtk_w32(eth, val, reg_map->qdma.glo_cfg); -@@ -2949,6 +3065,45 @@ static void mtk_gdm_config(struct mtk_et +@@ -2950,6 +3066,45 @@ static void mtk_gdm_config(struct mtk_et mtk_w32(eth, 0, MTK_RST_GL); } @@ -479,7 +479,7 @@ Signed-off-by: Felix Fietkau static int mtk_open(struct net_device *dev) { struct mtk_mac *mac = netdev_priv(dev); -@@ -2993,7 +3148,8 @@ static int mtk_open(struct net_device *d +@@ -2994,7 +3149,8 @@ static int mtk_open(struct net_device *d refcount_inc(ð->dma_refcnt); phylink_start(mac->phylink); @@ -489,7 +489,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3716,8 +3872,12 @@ static int mtk_unreg_dev(struct mtk_eth +@@ -3717,8 +3873,12 @@ static int mtk_unreg_dev(struct mtk_eth int i; for (i = 0; i < MTK_MAC_COUNT; i++) { @@ -502,7 +502,7 @@ Signed-off-by: Felix Fietkau unregister_netdev(eth->netdev[i]); } -@@ -3934,6 +4094,23 @@ static int mtk_set_rxnfc(struct net_devi +@@ -3935,6 +4095,23 @@ static int mtk_set_rxnfc(struct net_devi return ret; } @@ -526,7 +526,7 @@ Signed-off-by: Felix Fietkau static const struct ethtool_ops mtk_ethtool_ops = { .get_link_ksettings = mtk_get_link_ksettings, .set_link_ksettings = mtk_set_link_ksettings, -@@ -3969,6 +4146,7 @@ static const struct net_device_ops mtk_n +@@ -3970,6 +4147,7 @@ static const struct net_device_ops mtk_n .ndo_setup_tc = mtk_eth_setup_tc, .ndo_bpf = mtk_xdp, .ndo_xdp_xmit = mtk_xdp_xmit, @@ -534,7 +534,7 @@ Signed-off-by: Felix Fietkau }; static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) -@@ -3978,6 +4156,7 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -3979,6 +4157,7 @@ static int mtk_add_mac(struct mtk_eth *e struct phylink *phylink; struct mtk_mac *mac; int id, err; @@ -542,7 +542,7 @@ Signed-off-by: Felix Fietkau if (!_id) { dev_err(eth->dev, "missing mac id\n"); -@@ -3995,7 +4174,10 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -3996,7 +4175,10 @@ static int mtk_add_mac(struct mtk_eth *e return -EINVAL; } @@ -554,7 +554,7 @@ Signed-off-by: Felix Fietkau if (!eth->netdev[id]) { dev_err(eth->dev, "alloc_etherdev failed\n"); return -ENOMEM; -@@ -4092,6 +4274,11 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4093,6 +4275,11 @@ static int mtk_add_mac(struct mtk_eth *e else eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN; @@ -628,7 +628,7 @@ Signed-off-by: Felix Fietkau /* PDMA on MT7628 */ #define TX_DMA_DONE BIT(31) -@@ -952,6 +971,7 @@ struct mtk_reg_map { +@@ -953,6 +972,7 @@ struct mtk_reg_map { } pdma; struct { u32 qtx_cfg; /* tx queue configuration */ @@ -636,7 +636,7 @@ Signed-off-by: Felix Fietkau u32 rx_ptr; /* rx base pointer */ u32 rx_cnt_cfg; /* rx max count configuration */ u32 qcrx_ptr; /* rx cpu pointer */ -@@ -969,6 +989,7 @@ struct mtk_reg_map { +@@ -970,6 +990,7 @@ struct mtk_reg_map { u32 fq_tail; /* fq tail pointer */ u32 fq_count; /* fq free page count */ u32 fq_blen; /* fq free page buffer length */ @@ -644,7 +644,7 @@ Signed-off-by: Felix Fietkau } qdma; u32 gdm1_cnt; u32 gdma_to_ppe0; -@@ -1172,6 +1193,7 @@ struct mtk_mac { +@@ -1173,6 +1194,7 @@ struct mtk_mac { __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; int hwlro_ip_cnt; unsigned int syscfg0; diff --git a/target/linux/generic/backport-5.15/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch b/target/linux/generic/backport-5.15/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch index d7e7492aa27..44af9128b75 100644 --- a/target/linux/generic/backport-5.15/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch +++ b/target/linux/generic/backport-5.15/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -916,7 +916,13 @@ enum mkt_eth_capabilities { +@@ -917,7 +917,13 @@ enum mkt_eth_capabilities { #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) diff --git a/target/linux/generic/backport-5.15/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch b/target/linux/generic/backport-5.15/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch index a87a8101b76..beba07238fd 100644 --- a/target/linux/generic/backport-5.15/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch +++ b/target/linux/generic/backport-5.15/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch @@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau #include "mtk_eth_soc.h" #include "mtk_wed.h" -@@ -1973,16 +1974,22 @@ static int mtk_poll_rx(struct napi_struc +@@ -1974,16 +1975,22 @@ static int mtk_poll_rx(struct napi_struc htons(RX_DMA_VPID(trxd.rxd4)), RX_DMA_VID(trxd.rxd4)); } else if (trxd.rxd2 & RX_DMA_VTAG) { @@ -52,7 +52,7 @@ Signed-off-by: Felix Fietkau } skb_record_rx_queue(skb, 0); -@@ -2799,15 +2806,30 @@ static netdev_features_t mtk_fix_feature +@@ -2800,15 +2807,30 @@ static netdev_features_t mtk_fix_feature static int mtk_set_features(struct net_device *dev, netdev_features_t features) { @@ -88,7 +88,7 @@ Signed-off-by: Felix Fietkau } /* wait for DMA to finish whatever it is doing before we start using it again */ -@@ -3104,11 +3126,45 @@ found: +@@ -3105,11 +3127,45 @@ found: return NOTIFY_DONE; } @@ -135,7 +135,7 @@ Signed-off-by: Felix Fietkau err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); if (err) { -@@ -3631,6 +3687,10 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3632,6 +3688,10 @@ static int mtk_hw_init(struct mtk_eth *e */ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); @@ -146,7 +146,7 @@ Signed-off-by: Felix Fietkau /* Enable RX VLan Offloading */ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); -@@ -3864,6 +3924,12 @@ static int mtk_free_dev(struct mtk_eth * +@@ -3865,6 +3925,12 @@ static int mtk_free_dev(struct mtk_eth * free_netdev(eth->netdev[i]); } @@ -181,7 +181,7 @@ Signed-off-by: Felix Fietkau /* CDMP Ingress Control Register */ #define MTK_CDMP_IG_CTRL 0x400 #define MTK_CDMP_STAG_EN BIT(0) -@@ -1165,6 +1171,8 @@ struct mtk_eth { +@@ -1166,6 +1172,8 @@ struct mtk_eth { int ip_align; diff --git a/target/linux/generic/backport-5.15/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch b/target/linux/generic/backport-5.15/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch index d6b3c28ccc5..0bf48b07800 100644 --- a/target/linux/generic/backport-5.15/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch +++ b/target/linux/generic/backport-5.15/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3711,9 +3711,12 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3712,9 +3712,12 @@ static int mtk_hw_init(struct mtk_eth *e mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { diff --git a/target/linux/generic/backport-5.15/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch b/target/linux/generic/backport-5.15/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch index caffe890038..08bf608bc12 100644 --- a/target/linux/generic/backport-5.15/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch +++ b/target/linux/generic/backport-5.15/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch @@ -20,7 +20,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3142,7 +3142,8 @@ static int mtk_open(struct net_device *d +@@ -3143,7 +3143,8 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; int i, err; @@ -30,7 +30,7 @@ Signed-off-by: Jakub Kicinski for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { struct metadata_dst *md_dst = eth->dsa_meta[i]; -@@ -3159,7 +3160,8 @@ static int mtk_open(struct net_device *d +@@ -3160,7 +3161,8 @@ static int mtk_open(struct net_device *d } } else { /* Hardware special tag parsing needs to be disabled if at least diff --git a/target/linux/generic/backport-5.15/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch b/target/linux/generic/backport-5.15/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch index 14abdcd8763..efab99ada00 100644 --- a/target/linux/generic/backport-5.15/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch +++ b/target/linux/generic/backport-5.15/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch @@ -23,7 +23,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3077,7 +3077,7 @@ static void mtk_gdm_config(struct mtk_et +@@ -3078,7 +3078,7 @@ static void mtk_gdm_config(struct mtk_et val |= config; @@ -32,7 +32,7 @@ Signed-off-by: David S. Miller val |= MTK_GDMA_SPECIAL_TAG; mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); -@@ -3142,8 +3142,7 @@ static int mtk_open(struct net_device *d +@@ -3143,8 +3143,7 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; int i, err; @@ -42,7 +42,7 @@ Signed-off-by: David S. Miller for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { struct metadata_dst *md_dst = eth->dsa_meta[i]; -@@ -3160,8 +3159,7 @@ static int mtk_open(struct net_device *d +@@ -3161,8 +3160,7 @@ static int mtk_open(struct net_device *d } } else { /* Hardware special tag parsing needs to be disabled if at least diff --git a/target/linux/generic/backport-5.15/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch b/target/linux/generic/backport-5.15/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch index e75459696b6..c392429b887 100644 --- a/target/linux/generic/backport-5.15/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch +++ b/target/linux/generic/backport-5.15/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch @@ -77,7 +77,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1829,7 +1829,9 @@ static int mtk_poll_rx(struct napi_struc +@@ -1830,7 +1830,9 @@ static int mtk_poll_rx(struct napi_struc while (done < budget) { unsigned int pktlen, *rxdcsum; @@ -87,7 +87,7 @@ Signed-off-by: David S. Miller dma_addr_t dma_addr; u32 hash, reason; int mac = 0; -@@ -1969,27 +1971,29 @@ static int mtk_poll_rx(struct napi_struc +@@ -1970,27 +1972,29 @@ static int mtk_poll_rx(struct napi_struc if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { diff --git a/target/linux/generic/backport-5.15/733-v6.2-02-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch b/target/linux/generic/backport-5.15/733-v6.2-02-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch index 49ec12293ad..62830ebf106 100644 --- a/target/linux/generic/backport-5.15/733-v6.2-02-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch +++ b/target/linux/generic/backport-5.15/733-v6.2-02-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch @@ -34,7 +34,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1062,11 +1062,13 @@ struct mtk_soc_data { +@@ -1063,11 +1063,13 @@ struct mtk_soc_data { * @regmap: The register map pointing at the range used to setup * SGMII modes * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap diff --git a/target/linux/generic/backport-5.15/733-v6.2-03-net-mediatek-sgmii-fix-duplex-configuration.patch b/target/linux/generic/backport-5.15/733-v6.2-03-net-mediatek-sgmii-fix-duplex-configuration.patch index 9fac86da72e..eb6837f47a0 100644 --- a/target/linux/generic/backport-5.15/733-v6.2-03-net-mediatek-sgmii-fix-duplex-configuration.patch +++ b/target/linux/generic/backport-5.15/733-v6.2-03-net-mediatek-sgmii-fix-duplex-configuration.patch @@ -24,7 +24,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -523,7 +523,7 @@ +@@ -524,7 +524,7 @@ #define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) #define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) #define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) diff --git a/target/linux/generic/backport-5.15/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch b/target/linux/generic/backport-5.15/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch index 3df9bb62108..c8a3c96f376 100644 --- a/target/linux/generic/backport-5.15/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch +++ b/target/linux/generic/backport-5.15/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch @@ -27,7 +27,7 @@ Signed-off-by: Jakub Kicinski static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue); static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue); -@@ -1711,9 +1714,6 @@ static int __init_dma_rx_desc_rings(stru +@@ -1712,9 +1715,6 @@ static int __init_dma_rx_desc_rings(stru return -ENOMEM; } @@ -37,7 +37,7 @@ Signed-off-by: Jakub Kicinski /* Setup the chained descriptor addresses */ if (priv->mode == STMMAC_CHAIN_MODE) { if (priv->extend_desc) -@@ -1819,12 +1819,6 @@ static int __init_dma_tx_desc_rings(stru +@@ -1820,12 +1820,6 @@ static int __init_dma_tx_desc_rings(stru tx_q->tx_skbuff[i] = NULL; } @@ -50,7 +50,7 @@ Signed-off-by: Jakub Kicinski return 0; } -@@ -2693,10 +2687,7 @@ static void stmmac_tx_err(struct stmmac_ +@@ -2694,10 +2688,7 @@ static void stmmac_tx_err(struct stmmac_ stmmac_stop_tx_dma(priv, chan); dma_free_tx_skbufs(priv, chan); stmmac_clear_tx_descriptors(priv, chan); @@ -62,7 +62,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, tx_q->dma_tx_phy, chan); stmmac_start_tx_dma(priv, chan); -@@ -3780,6 +3771,8 @@ static int stmmac_open(struct net_device +@@ -3781,6 +3772,8 @@ static int stmmac_open(struct net_device } } @@ -71,7 +71,7 @@ Signed-off-by: Jakub Kicinski ret = stmmac_hw_setup(dev, true); if (ret < 0) { netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); -@@ -6423,6 +6416,7 @@ void stmmac_enable_rx_queue(struct stmma +@@ -6424,6 +6417,7 @@ void stmmac_enable_rx_queue(struct stmma return; } @@ -79,7 +79,7 @@ Signed-off-by: Jakub Kicinski stmmac_clear_rx_descriptors(priv, queue); stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, -@@ -6484,6 +6478,7 @@ void stmmac_enable_tx_queue(struct stmma +@@ -6485,6 +6479,7 @@ void stmmac_enable_tx_queue(struct stmma return; } @@ -87,7 +87,7 @@ Signed-off-by: Jakub Kicinski stmmac_clear_tx_descriptors(priv, queue); stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, -@@ -7406,6 +7401,25 @@ int stmmac_suspend(struct device *dev) +@@ -7407,6 +7402,25 @@ int stmmac_suspend(struct device *dev) } EXPORT_SYMBOL_GPL(stmmac_suspend); @@ -113,7 +113,7 @@ Signed-off-by: Jakub Kicinski /** * stmmac_reset_queues_param - reset queue parameters * @priv: device pointer -@@ -7416,22 +7430,11 @@ static void stmmac_reset_queues_param(st +@@ -7417,22 +7431,11 @@ static void stmmac_reset_queues_param(st u32 tx_cnt = priv->plat->tx_queues_to_use; u32 queue; diff --git a/target/linux/generic/backport-5.15/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch b/target/linux/generic/backport-5.15/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch index 5c033e9d524..8eca92a5c54 100644 --- a/target/linux/generic/backport-5.15/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch +++ b/target/linux/generic/backport-5.15/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch @@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -3832,8 +3832,6 @@ static int stmmac_release(struct net_dev +@@ -3833,8 +3833,6 @@ static int stmmac_release(struct net_dev struct stmmac_priv *priv = netdev_priv(dev); u32 chan; @@ -26,7 +26,7 @@ Signed-off-by: Jakub Kicinski if (device_may_wakeup(priv->device)) phylink_speed_down(priv->phylink, false); /* Stop and disconnect the PHY */ -@@ -3845,6 +3843,8 @@ static int stmmac_release(struct net_dev +@@ -3846,6 +3844,8 @@ static int stmmac_release(struct net_dev for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) hrtimer_cancel(&priv->tx_queue[chan].txtimer); diff --git a/target/linux/generic/backport-5.15/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch b/target/linux/generic/backport-5.15/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch index a717688125c..de1add41a50 100644 --- a/target/linux/generic/backport-5.15/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch +++ b/target/linux/generic/backport-5.15/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch @@ -189,7 +189,7 @@ Signed-off-by: Jakub Kicinski if (tx_q->dirty_tx != tx_q->cur_tx) return -EBUSY; /* still unfinished work */ -@@ -1308,7 +1308,7 @@ static void stmmac_display_rx_rings(stru +@@ -1309,7 +1309,7 @@ static void stmmac_display_rx_rings(stru /* Display RX rings */ for (queue = 0; queue < rx_cnt; queue++) { @@ -198,7 +198,7 @@ Signed-off-by: Jakub Kicinski pr_info("\tRX Queue %u rings\n", queue); -@@ -1321,7 +1321,7 @@ static void stmmac_display_rx_rings(stru +@@ -1322,7 +1322,7 @@ static void stmmac_display_rx_rings(stru } /* Display RX ring */ @@ -207,7 +207,7 @@ Signed-off-by: Jakub Kicinski rx_q->dma_rx_phy, desc_size); } } -@@ -1335,7 +1335,7 @@ static void stmmac_display_tx_rings(stru +@@ -1336,7 +1336,7 @@ static void stmmac_display_tx_rings(stru /* Display TX rings */ for (queue = 0; queue < tx_cnt; queue++) { @@ -216,7 +216,7 @@ Signed-off-by: Jakub Kicinski pr_info("\tTX Queue %d rings\n", queue); -@@ -1350,7 +1350,7 @@ static void stmmac_display_tx_rings(stru +@@ -1351,7 +1351,7 @@ static void stmmac_display_tx_rings(stru desc_size = sizeof(struct dma_desc); } @@ -225,7 +225,7 @@ Signed-off-by: Jakub Kicinski tx_q->dma_tx_phy, desc_size); } } -@@ -1391,21 +1391,21 @@ static int stmmac_set_bfsize(int mtu, in +@@ -1392,21 +1392,21 @@ static int stmmac_set_bfsize(int mtu, in */ static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, u32 queue) { @@ -253,7 +253,7 @@ Signed-off-by: Jakub Kicinski } /** -@@ -1417,12 +1417,12 @@ static void stmmac_clear_rx_descriptors( +@@ -1418,12 +1418,12 @@ static void stmmac_clear_rx_descriptors( */ static void stmmac_clear_tx_descriptors(struct stmmac_priv *priv, u32 queue) { @@ -269,7 +269,7 @@ Signed-off-by: Jakub Kicinski struct dma_desc *p; if (priv->extend_desc) -@@ -1470,7 +1470,7 @@ static void stmmac_clear_descriptors(str +@@ -1471,7 +1471,7 @@ static void stmmac_clear_descriptors(str static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, int i, gfp_t flags, u32 queue) { @@ -278,7 +278,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (!buf->page) { -@@ -1495,7 +1495,7 @@ static int stmmac_init_rx_buffers(struct +@@ -1496,7 +1496,7 @@ static int stmmac_init_rx_buffers(struct buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; stmmac_set_desc_addr(priv, p, buf->addr); @@ -287,7 +287,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_desc3(priv, p); return 0; -@@ -1509,7 +1509,7 @@ static int stmmac_init_rx_buffers(struct +@@ -1510,7 +1510,7 @@ static int stmmac_init_rx_buffers(struct */ static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) { @@ -296,7 +296,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (buf->page) -@@ -1529,7 +1529,7 @@ static void stmmac_free_rx_buffer(struct +@@ -1530,7 +1530,7 @@ static void stmmac_free_rx_buffer(struct */ static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i) { @@ -305,7 +305,7 @@ Signed-off-by: Jakub Kicinski if (tx_q->tx_skbuff_dma[i].buf && tx_q->tx_skbuff_dma[i].buf_type != STMMAC_TXBUF_T_XDP_TX) { -@@ -1574,17 +1574,17 @@ static void dma_free_rx_skbufs(struct st +@@ -1575,17 +1575,17 @@ static void dma_free_rx_skbufs(struct st { int i; @@ -326,7 +326,7 @@ Signed-off-by: Jakub Kicinski struct dma_desc *p; int ret; -@@ -1611,10 +1611,10 @@ static int stmmac_alloc_rx_buffers(struc +@@ -1612,10 +1612,10 @@ static int stmmac_alloc_rx_buffers(struc */ static void dma_free_rx_xskbufs(struct stmmac_priv *priv, u32 queue) { @@ -339,7 +339,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (!buf->xdp) -@@ -1627,10 +1627,10 @@ static void dma_free_rx_xskbufs(struct s +@@ -1628,10 +1628,10 @@ static void dma_free_rx_xskbufs(struct s static int stmmac_alloc_rx_buffers_zc(struct stmmac_priv *priv, u32 queue) { @@ -352,7 +352,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_rx_buffer *buf; dma_addr_t dma_addr; struct dma_desc *p; -@@ -1673,7 +1673,7 @@ static struct xsk_buff_pool *stmmac_get_ +@@ -1674,7 +1674,7 @@ static struct xsk_buff_pool *stmmac_get_ */ static int __init_dma_rx_desc_rings(struct stmmac_priv *priv, u32 queue, gfp_t flags) { @@ -361,7 +361,7 @@ Signed-off-by: Jakub Kicinski int ret; netif_dbg(priv, probe, priv->dev, -@@ -1719,11 +1719,11 @@ static int __init_dma_rx_desc_rings(stru +@@ -1720,11 +1720,11 @@ static int __init_dma_rx_desc_rings(stru if (priv->extend_desc) stmmac_mode_init(priv, rx_q->dma_erx, rx_q->dma_rx_phy, @@ -375,7 +375,7 @@ Signed-off-by: Jakub Kicinski } return 0; -@@ -1750,7 +1750,7 @@ static int init_dma_rx_desc_rings(struct +@@ -1751,7 +1751,7 @@ static int init_dma_rx_desc_rings(struct err_init_rx_buffers: while (queue >= 0) { @@ -384,7 +384,7 @@ Signed-off-by: Jakub Kicinski if (rx_q->xsk_pool) dma_free_rx_xskbufs(priv, queue); -@@ -1779,7 +1779,7 @@ err_init_rx_buffers: +@@ -1780,7 +1780,7 @@ err_init_rx_buffers: */ static int __init_dma_tx_desc_rings(struct stmmac_priv *priv, u32 queue) { @@ -393,7 +393,7 @@ Signed-off-by: Jakub Kicinski int i; netif_dbg(priv, probe, priv->dev, -@@ -1791,16 +1791,16 @@ static int __init_dma_tx_desc_rings(stru +@@ -1792,16 +1792,16 @@ static int __init_dma_tx_desc_rings(stru if (priv->extend_desc) stmmac_mode_init(priv, tx_q->dma_etx, tx_q->dma_tx_phy, @@ -413,7 +413,7 @@ Signed-off-by: Jakub Kicinski struct dma_desc *p; if (priv->extend_desc) -@@ -1870,12 +1870,12 @@ static int init_dma_desc_rings(struct ne +@@ -1871,12 +1871,12 @@ static int init_dma_desc_rings(struct ne */ static void dma_free_tx_skbufs(struct stmmac_priv *priv, u32 queue) { @@ -428,7 +428,7 @@ Signed-off-by: Jakub Kicinski stmmac_free_tx_buffer(priv, queue, i); if (tx_q->xsk_pool && tx_q->xsk_frames_done) { -@@ -1905,7 +1905,7 @@ static void stmmac_free_tx_skbufs(struct +@@ -1906,7 +1906,7 @@ static void stmmac_free_tx_skbufs(struct */ static void __free_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) { @@ -437,7 +437,7 @@ Signed-off-by: Jakub Kicinski /* Release the DMA RX socket buffers */ if (rx_q->xsk_pool) -@@ -1918,11 +1918,11 @@ static void __free_dma_rx_desc_resources +@@ -1919,11 +1919,11 @@ static void __free_dma_rx_desc_resources /* Free DMA regions of consistent memory previously allocated */ if (!priv->extend_desc) @@ -451,7 +451,7 @@ Signed-off-by: Jakub Kicinski sizeof(struct dma_extended_desc), rx_q->dma_erx, rx_q->dma_rx_phy); -@@ -1951,7 +1951,7 @@ static void free_dma_rx_desc_resources(s +@@ -1952,7 +1952,7 @@ static void free_dma_rx_desc_resources(s */ static void __free_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) { @@ -460,7 +460,7 @@ Signed-off-by: Jakub Kicinski size_t size; void *addr; -@@ -1969,7 +1969,7 @@ static void __free_dma_tx_desc_resources +@@ -1970,7 +1970,7 @@ static void __free_dma_tx_desc_resources addr = tx_q->dma_tx; } @@ -469,7 +469,7 @@ Signed-off-by: Jakub Kicinski dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy); -@@ -1998,7 +1998,7 @@ static void free_dma_tx_desc_resources(s +@@ -1999,7 +1999,7 @@ static void free_dma_tx_desc_resources(s */ static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) { @@ -478,7 +478,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_channel *ch = &priv->channel[queue]; bool xdp_prog = stmmac_xdp_is_enabled(priv); struct page_pool_params pp_params = { 0 }; -@@ -2010,8 +2010,8 @@ static int __alloc_dma_rx_desc_resources +@@ -2011,8 +2011,8 @@ static int __alloc_dma_rx_desc_resources rx_q->priv_data = priv; pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; @@ -489,7 +489,7 @@ Signed-off-by: Jakub Kicinski pp_params.order = ilog2(num_pages); pp_params.nid = dev_to_node(priv->device); pp_params.dev = priv->device; -@@ -2026,7 +2026,7 @@ static int __alloc_dma_rx_desc_resources +@@ -2027,7 +2027,7 @@ static int __alloc_dma_rx_desc_resources return ret; } @@ -498,7 +498,7 @@ Signed-off-by: Jakub Kicinski sizeof(*rx_q->buf_pool), GFP_KERNEL); if (!rx_q->buf_pool) -@@ -2034,7 +2034,7 @@ static int __alloc_dma_rx_desc_resources +@@ -2035,7 +2035,7 @@ static int __alloc_dma_rx_desc_resources if (priv->extend_desc) { rx_q->dma_erx = dma_alloc_coherent(priv->device, @@ -507,7 +507,7 @@ Signed-off-by: Jakub Kicinski sizeof(struct dma_extended_desc), &rx_q->dma_rx_phy, GFP_KERNEL); -@@ -2043,7 +2043,7 @@ static int __alloc_dma_rx_desc_resources +@@ -2044,7 +2044,7 @@ static int __alloc_dma_rx_desc_resources } else { rx_q->dma_rx = dma_alloc_coherent(priv->device, @@ -516,7 +516,7 @@ Signed-off-by: Jakub Kicinski sizeof(struct dma_desc), &rx_q->dma_rx_phy, GFP_KERNEL); -@@ -2100,20 +2100,20 @@ err_dma: +@@ -2101,20 +2101,20 @@ err_dma: */ static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) { @@ -540,7 +540,7 @@ Signed-off-by: Jakub Kicinski sizeof(struct sk_buff *), GFP_KERNEL); if (!tx_q->tx_skbuff) -@@ -2126,7 +2126,7 @@ static int __alloc_dma_tx_desc_resources +@@ -2127,7 +2127,7 @@ static int __alloc_dma_tx_desc_resources else size = sizeof(struct dma_desc); @@ -549,7 +549,7 @@ Signed-off-by: Jakub Kicinski addr = dma_alloc_coherent(priv->device, size, &tx_q->dma_tx_phy, GFP_KERNEL); -@@ -2370,7 +2370,7 @@ static void stmmac_dma_operation_mode(st +@@ -2371,7 +2371,7 @@ static void stmmac_dma_operation_mode(st /* configure all channels */ for (chan = 0; chan < rx_channels_count; chan++) { @@ -558,7 +558,7 @@ Signed-off-by: Jakub Kicinski u32 buf_size; qmode = priv->plat->rx_queues_cfg[chan].mode_to_use; -@@ -2385,7 +2385,7 @@ static void stmmac_dma_operation_mode(st +@@ -2386,7 +2386,7 @@ static void stmmac_dma_operation_mode(st chan); } else { stmmac_set_dma_bfsize(priv, priv->ioaddr, @@ -567,7 +567,7 @@ Signed-off-by: Jakub Kicinski chan); } } -@@ -2401,7 +2401,7 @@ static void stmmac_dma_operation_mode(st +@@ -2402,7 +2402,7 @@ static void stmmac_dma_operation_mode(st static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) { struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue); @@ -576,7 +576,7 @@ Signed-off-by: Jakub Kicinski struct xsk_buff_pool *pool = tx_q->xsk_pool; unsigned int entry = tx_q->cur_tx; struct dma_desc *tx_desc = NULL; -@@ -2476,7 +2476,7 @@ static bool stmmac_xdp_xmit_zc(struct st +@@ -2477,7 +2477,7 @@ static bool stmmac_xdp_xmit_zc(struct st stmmac_enable_dma_transmission(priv, priv->ioaddr); @@ -585,7 +585,7 @@ Signed-off-by: Jakub Kicinski entry = tx_q->cur_tx; } -@@ -2502,7 +2502,7 @@ static bool stmmac_xdp_xmit_zc(struct st +@@ -2503,7 +2503,7 @@ static bool stmmac_xdp_xmit_zc(struct st */ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) { @@ -594,7 +594,7 @@ Signed-off-by: Jakub Kicinski unsigned int bytes_compl = 0, pkts_compl = 0; unsigned int entry, xmits = 0, count = 0; -@@ -2515,7 +2515,7 @@ static int stmmac_tx_clean(struct stmmac +@@ -2516,7 +2516,7 @@ static int stmmac_tx_clean(struct stmmac entry = tx_q->dirty_tx; /* Try to clean all TX complete frame in 1 shot */ @@ -603,7 +603,7 @@ Signed-off-by: Jakub Kicinski struct xdp_frame *xdpf; struct sk_buff *skb; struct dma_desc *p; -@@ -2615,7 +2615,7 @@ static int stmmac_tx_clean(struct stmmac +@@ -2616,7 +2616,7 @@ static int stmmac_tx_clean(struct stmmac stmmac_release_tx_desc(priv, p, priv->mode); @@ -612,7 +612,7 @@ Signed-off-by: Jakub Kicinski } tx_q->dirty_tx = entry; -@@ -2680,7 +2680,7 @@ static int stmmac_tx_clean(struct stmmac +@@ -2681,7 +2681,7 @@ static int stmmac_tx_clean(struct stmmac */ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan) { @@ -621,7 +621,7 @@ Signed-off-by: Jakub Kicinski netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, chan)); -@@ -2747,8 +2747,8 @@ static int stmmac_napi_check(struct stmm +@@ -2748,8 +2748,8 @@ static int stmmac_napi_check(struct stmm { int status = stmmac_dma_interrupt_status(priv, priv->ioaddr, &priv->xstats, chan, dir); @@ -632,7 +632,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_channel *ch = &priv->channel[chan]; struct napi_struct *rx_napi; struct napi_struct *tx_napi; -@@ -2924,7 +2924,7 @@ static int stmmac_init_dma_engine(struct +@@ -2925,7 +2925,7 @@ static int stmmac_init_dma_engine(struct /* DMA RX Channel Configuration */ for (chan = 0; chan < rx_channels_count; chan++) { @@ -641,7 +641,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, rx_q->dma_rx_phy, chan); -@@ -2938,7 +2938,7 @@ static int stmmac_init_dma_engine(struct +@@ -2939,7 +2939,7 @@ static int stmmac_init_dma_engine(struct /* DMA TX Channel Configuration */ for (chan = 0; chan < tx_channels_count; chan++) { @@ -650,7 +650,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, tx_q->dma_tx_phy, chan); -@@ -2953,7 +2953,7 @@ static int stmmac_init_dma_engine(struct +@@ -2954,7 +2954,7 @@ static int stmmac_init_dma_engine(struct static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue) { @@ -659,7 +659,7 @@ Signed-off-by: Jakub Kicinski hrtimer_start(&tx_q->txtimer, STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]), -@@ -3003,7 +3003,7 @@ static void stmmac_init_coalesce(struct +@@ -3004,7 +3004,7 @@ static void stmmac_init_coalesce(struct u32 chan; for (chan = 0; chan < tx_channel_count; chan++) { @@ -668,7 +668,7 @@ Signed-off-by: Jakub Kicinski priv->tx_coal_frames[chan] = STMMAC_TX_FRAMES; priv->tx_coal_timer[chan] = STMMAC_COAL_TX_TIMER; -@@ -3025,12 +3025,12 @@ static void stmmac_set_rings_length(stru +@@ -3026,12 +3026,12 @@ static void stmmac_set_rings_length(stru /* set TX ring length */ for (chan = 0; chan < tx_channels_count; chan++) stmmac_set_tx_ring_len(priv, priv->ioaddr, @@ -683,7 +683,7 @@ Signed-off-by: Jakub Kicinski } /** -@@ -3365,7 +3365,7 @@ static int stmmac_hw_setup(struct net_de +@@ -3366,7 +3366,7 @@ static int stmmac_hw_setup(struct net_de /* Enable TSO */ if (priv->tso) { for (chan = 0; chan < tx_cnt; chan++) { @@ -692,7 +692,7 @@ Signed-off-by: Jakub Kicinski /* TSO and TBS cannot co-exist */ if (tx_q->tbs & STMMAC_TBS_AVAIL) -@@ -3387,7 +3387,7 @@ static int stmmac_hw_setup(struct net_de +@@ -3388,7 +3388,7 @@ static int stmmac_hw_setup(struct net_de /* TBS */ for (chan = 0; chan < tx_cnt; chan++) { @@ -701,7 +701,7 @@ Signed-off-by: Jakub Kicinski int enable = tx_q->tbs & STMMAC_TBS_AVAIL; stmmac_enable_tbs(priv, priv->ioaddr, enable, chan); -@@ -3431,7 +3431,7 @@ static void stmmac_free_irq(struct net_d +@@ -3432,7 +3432,7 @@ static void stmmac_free_irq(struct net_d for (j = irq_idx - 1; j >= 0; j--) { if (priv->tx_irq[j] > 0) { irq_set_affinity_hint(priv->tx_irq[j], NULL); @@ -710,7 +710,7 @@ Signed-off-by: Jakub Kicinski } } irq_idx = priv->plat->rx_queues_to_use; -@@ -3440,7 +3440,7 @@ static void stmmac_free_irq(struct net_d +@@ -3441,7 +3441,7 @@ static void stmmac_free_irq(struct net_d for (j = irq_idx - 1; j >= 0; j--) { if (priv->rx_irq[j] > 0) { irq_set_affinity_hint(priv->rx_irq[j], NULL); @@ -719,7 +719,7 @@ Signed-off-by: Jakub Kicinski } } -@@ -3573,7 +3573,7 @@ static int stmmac_request_irq_multi_msi( +@@ -3574,7 +3574,7 @@ static int stmmac_request_irq_multi_msi( sprintf(int_name, "%s:%s-%d", dev->name, "rx", i); ret = request_irq(priv->rx_irq[i], stmmac_msi_intr_rx, @@ -728,7 +728,7 @@ Signed-off-by: Jakub Kicinski if (unlikely(ret < 0)) { netdev_err(priv->dev, "%s: alloc rx-%d MSI %d (error: %d)\n", -@@ -3596,7 +3596,7 @@ static int stmmac_request_irq_multi_msi( +@@ -3597,7 +3597,7 @@ static int stmmac_request_irq_multi_msi( sprintf(int_name, "%s:%s-%d", dev->name, "tx", i); ret = request_irq(priv->tx_irq[i], stmmac_msi_intr_tx, @@ -737,7 +737,7 @@ Signed-off-by: Jakub Kicinski if (unlikely(ret < 0)) { netdev_err(priv->dev, "%s: alloc tx-%d MSI %d (error: %d)\n", -@@ -3727,21 +3727,21 @@ static int stmmac_open(struct net_device +@@ -3728,21 +3728,21 @@ static int stmmac_open(struct net_device bfsize = 0; if (bfsize < BUF_SIZE_16KiB) @@ -766,7 +766,7 @@ Signed-off-by: Jakub Kicinski int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en; /* Setup per-TXQ tbs flag before TX descriptor alloc */ -@@ -3799,7 +3799,7 @@ irq_error: +@@ -3800,7 +3800,7 @@ irq_error: phylink_stop(priv->phylink); for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) @@ -775,7 +775,7 @@ Signed-off-by: Jakub Kicinski stmmac_hw_teardown(dev); init_error: -@@ -3841,7 +3841,7 @@ static int stmmac_release(struct net_dev +@@ -3842,7 +3842,7 @@ static int stmmac_release(struct net_dev stmmac_disable_all_queues(priv); for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) @@ -784,7 +784,7 @@ Signed-off-by: Jakub Kicinski netif_tx_disable(dev); -@@ -3905,7 +3905,7 @@ static bool stmmac_vlan_insert(struct st +@@ -3906,7 +3906,7 @@ static bool stmmac_vlan_insert(struct st return false; stmmac_set_tx_owner(priv, p); @@ -793,7 +793,7 @@ Signed-off-by: Jakub Kicinski return true; } -@@ -3923,7 +3923,7 @@ static bool stmmac_vlan_insert(struct st +@@ -3924,7 +3924,7 @@ static bool stmmac_vlan_insert(struct st static void stmmac_tso_allocator(struct stmmac_priv *priv, dma_addr_t des, int total_len, bool last_segment, u32 queue) { @@ -802,7 +802,7 @@ Signed-off-by: Jakub Kicinski struct dma_desc *desc; u32 buff_size; int tmp_len; -@@ -3934,7 +3934,7 @@ static void stmmac_tso_allocator(struct +@@ -3935,7 +3935,7 @@ static void stmmac_tso_allocator(struct dma_addr_t curr_addr; tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, @@ -811,7 +811,7 @@ Signed-off-by: Jakub Kicinski WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); if (tx_q->tbs & STMMAC_TBS_AVAIL) -@@ -3962,7 +3962,7 @@ static void stmmac_tso_allocator(struct +@@ -3963,7 +3963,7 @@ static void stmmac_tso_allocator(struct static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue) { @@ -820,7 +820,7 @@ Signed-off-by: Jakub Kicinski int desc_size; if (likely(priv->extend_desc)) -@@ -4024,7 +4024,7 @@ static netdev_tx_t stmmac_tso_xmit(struc +@@ -4025,7 +4025,7 @@ static netdev_tx_t stmmac_tso_xmit(struc dma_addr_t des; int i; @@ -829,7 +829,7 @@ Signed-off-by: Jakub Kicinski first_tx = tx_q->cur_tx; /* Compute header lengths */ -@@ -4064,7 +4064,7 @@ static netdev_tx_t stmmac_tso_xmit(struc +@@ -4065,7 +4065,7 @@ static netdev_tx_t stmmac_tso_xmit(struc stmmac_set_mss(priv, mss_desc, mss); tx_q->mss = mss; tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, @@ -838,7 +838,7 @@ Signed-off-by: Jakub Kicinski WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); } -@@ -4176,7 +4176,7 @@ static netdev_tx_t stmmac_tso_xmit(struc +@@ -4177,7 +4177,7 @@ static netdev_tx_t stmmac_tso_xmit(struc * ndo_start_xmit will fill this descriptor the next time it's * called and stmmac_tx_clean may clean up to this descriptor. */ @@ -847,7 +847,7 @@ Signed-off-by: Jakub Kicinski if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) { netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n", -@@ -4264,7 +4264,7 @@ static netdev_tx_t stmmac_xmit(struct sk +@@ -4265,7 +4265,7 @@ static netdev_tx_t stmmac_xmit(struct sk int entry, first_tx; dma_addr_t des; @@ -856,7 +856,7 @@ Signed-off-by: Jakub Kicinski first_tx = tx_q->cur_tx; if (priv->tx_path_in_lpi_mode && priv->eee_sw_timer_en) -@@ -4327,7 +4327,7 @@ static netdev_tx_t stmmac_xmit(struct sk +@@ -4328,7 +4328,7 @@ static netdev_tx_t stmmac_xmit(struct sk int len = skb_frag_size(frag); bool last_segment = (i == (nfrags - 1)); @@ -865,7 +865,7 @@ Signed-off-by: Jakub Kicinski WARN_ON(tx_q->tx_skbuff[entry]); if (likely(priv->extend_desc)) -@@ -4398,7 +4398,7 @@ static netdev_tx_t stmmac_xmit(struct sk +@@ -4399,7 +4399,7 @@ static netdev_tx_t stmmac_xmit(struct sk * ndo_start_xmit will fill this descriptor the next time it's * called and stmmac_tx_clean may clean up to this descriptor. */ @@ -874,7 +874,7 @@ Signed-off-by: Jakub Kicinski tx_q->cur_tx = entry; if (netif_msg_pktdata(priv)) { -@@ -4513,7 +4513,7 @@ static void stmmac_rx_vlan(struct net_de +@@ -4514,7 +4514,7 @@ static void stmmac_rx_vlan(struct net_de */ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) { @@ -883,7 +883,7 @@ Signed-off-by: Jakub Kicinski int dirty = stmmac_rx_dirty(priv, queue); unsigned int entry = rx_q->dirty_rx; -@@ -4563,7 +4563,7 @@ static inline void stmmac_rx_refill(stru +@@ -4564,7 +4564,7 @@ static inline void stmmac_rx_refill(stru dma_wmb(); stmmac_set_rx_owner(priv, p, use_rx_wd); @@ -892,7 +892,7 @@ Signed-off-by: Jakub Kicinski } rx_q->dirty_rx = entry; rx_q->rx_tail_addr = rx_q->dma_rx_phy + -@@ -4591,12 +4591,12 @@ static unsigned int stmmac_rx_buf1_len(s +@@ -4592,12 +4592,12 @@ static unsigned int stmmac_rx_buf1_len(s /* First descriptor, not last descriptor and not split header */ if (status & rx_not_ls) @@ -907,7 +907,7 @@ Signed-off-by: Jakub Kicinski } static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, -@@ -4612,7 +4612,7 @@ static unsigned int stmmac_rx_buf2_len(s +@@ -4613,7 +4613,7 @@ static unsigned int stmmac_rx_buf2_len(s /* Not last descriptor */ if (status & rx_not_ls) @@ -916,7 +916,7 @@ Signed-off-by: Jakub Kicinski plen = stmmac_get_rx_frame_len(priv, p, coe); -@@ -4623,7 +4623,7 @@ static unsigned int stmmac_rx_buf2_len(s +@@ -4624,7 +4624,7 @@ static unsigned int stmmac_rx_buf2_len(s static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, struct xdp_frame *xdpf, bool dma_map) { @@ -925,7 +925,7 @@ Signed-off-by: Jakub Kicinski unsigned int entry = tx_q->cur_tx; struct dma_desc *tx_desc; dma_addr_t dma_addr; -@@ -4686,7 +4686,7 @@ static int stmmac_xdp_xmit_xdpf(struct s +@@ -4687,7 +4687,7 @@ static int stmmac_xdp_xmit_xdpf(struct s stmmac_enable_dma_transmission(priv, priv->ioaddr); @@ -934,7 +934,7 @@ Signed-off-by: Jakub Kicinski tx_q->cur_tx = entry; return STMMAC_XDP_TX; -@@ -4860,7 +4860,7 @@ static void stmmac_dispatch_skb_zc(struc +@@ -4861,7 +4861,7 @@ static void stmmac_dispatch_skb_zc(struc static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget) { @@ -943,7 +943,7 @@ Signed-off-by: Jakub Kicinski unsigned int entry = rx_q->dirty_rx; struct dma_desc *rx_desc = NULL; bool ret = true; -@@ -4903,7 +4903,7 @@ static bool stmmac_rx_refill_zc(struct s +@@ -4904,7 +4904,7 @@ static bool stmmac_rx_refill_zc(struct s dma_wmb(); stmmac_set_rx_owner(priv, rx_desc, use_rx_wd); @@ -952,7 +952,7 @@ Signed-off-by: Jakub Kicinski } if (rx_desc) { -@@ -4918,7 +4918,7 @@ static bool stmmac_rx_refill_zc(struct s +@@ -4919,7 +4919,7 @@ static bool stmmac_rx_refill_zc(struct s static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) { @@ -961,7 +961,7 @@ Signed-off-by: Jakub Kicinski unsigned int count = 0, error = 0, len = 0; int dirty = stmmac_rx_dirty(priv, queue); unsigned int next_entry = rx_q->cur_rx; -@@ -4940,7 +4940,7 @@ static int stmmac_rx_zc(struct stmmac_pr +@@ -4941,7 +4941,7 @@ static int stmmac_rx_zc(struct stmmac_pr desc_size = sizeof(struct dma_desc); } @@ -970,7 +970,7 @@ Signed-off-by: Jakub Kicinski rx_q->dma_rx_phy, desc_size); } while (count < limit) { -@@ -4987,7 +4987,7 @@ read_again: +@@ -4988,7 +4988,7 @@ read_again: /* Prefetch the next RX descriptor */ rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, @@ -979,7 +979,7 @@ Signed-off-by: Jakub Kicinski next_entry = rx_q->cur_rx; if (priv->extend_desc) -@@ -5108,7 +5108,7 @@ read_again: +@@ -5109,7 +5109,7 @@ read_again: */ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) { @@ -988,7 +988,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_channel *ch = &priv->channel[queue]; unsigned int count = 0, error = 0, len = 0; int status = 0, coe = priv->hw->rx_csum; -@@ -5121,7 +5121,7 @@ static int stmmac_rx(struct stmmac_priv +@@ -5122,7 +5122,7 @@ static int stmmac_rx(struct stmmac_priv int buf_sz; dma_dir = page_pool_get_dma_dir(rx_q->page_pool); @@ -997,7 +997,7 @@ Signed-off-by: Jakub Kicinski if (netif_msg_rx_status(priv)) { void *rx_head; -@@ -5135,7 +5135,7 @@ static int stmmac_rx(struct stmmac_priv +@@ -5136,7 +5136,7 @@ static int stmmac_rx(struct stmmac_priv desc_size = sizeof(struct dma_desc); } @@ -1006,7 +1006,7 @@ Signed-off-by: Jakub Kicinski rx_q->dma_rx_phy, desc_size); } while (count < limit) { -@@ -5179,7 +5179,7 @@ read_again: +@@ -5180,7 +5180,7 @@ read_again: break; rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, @@ -1015,7 +1015,7 @@ Signed-off-by: Jakub Kicinski next_entry = rx_q->cur_rx; if (priv->extend_desc) -@@ -5313,7 +5313,7 @@ read_again: +@@ -5314,7 +5314,7 @@ read_again: buf1_len, dma_dir); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, buf->page, buf->page_offset, buf1_len, @@ -1024,7 +1024,7 @@ Signed-off-by: Jakub Kicinski /* Data payload appended into SKB */ page_pool_release_page(rx_q->page_pool, buf->page); -@@ -5325,7 +5325,7 @@ read_again: +@@ -5326,7 +5326,7 @@ read_again: buf2_len, dma_dir); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, buf->sec_page, 0, buf2_len, @@ -1033,7 +1033,7 @@ Signed-off-by: Jakub Kicinski /* Data payload appended into SKB */ page_pool_release_page(rx_q->page_pool, buf->sec_page); -@@ -5767,11 +5767,13 @@ static irqreturn_t stmmac_safety_interru +@@ -5768,11 +5768,13 @@ static irqreturn_t stmmac_safety_interru static irqreturn_t stmmac_msi_intr_tx(int irq, void *data) { struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)data; @@ -1048,7 +1048,7 @@ Signed-off-by: Jakub Kicinski if (unlikely(!data)) { netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); -@@ -5811,10 +5813,12 @@ static irqreturn_t stmmac_msi_intr_tx(in +@@ -5812,10 +5814,12 @@ static irqreturn_t stmmac_msi_intr_tx(in static irqreturn_t stmmac_msi_intr_rx(int irq, void *data) { struct stmmac_rx_queue *rx_q = (struct stmmac_rx_queue *)data; @@ -1062,7 +1062,7 @@ Signed-off-by: Jakub Kicinski if (unlikely(!data)) { netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); -@@ -5845,10 +5849,10 @@ static void stmmac_poll_controller(struc +@@ -5846,10 +5850,10 @@ static void stmmac_poll_controller(struc if (priv->plat->multi_msi_en) { for (i = 0; i < priv->plat->rx_queues_to_use; i++) @@ -1075,7 +1075,7 @@ Signed-off-by: Jakub Kicinski } else { disable_irq(dev->irq); stmmac_interrupt(dev->irq, dev); -@@ -6029,34 +6033,34 @@ static int stmmac_rings_status_show(stru +@@ -6030,34 +6034,34 @@ static int stmmac_rings_status_show(stru return 0; for (queue = 0; queue < rx_count; queue++) { @@ -1116,7 +1116,7 @@ Signed-off-by: Jakub Kicinski } } -@@ -6397,7 +6401,7 @@ void stmmac_disable_rx_queue(struct stmm +@@ -6398,7 +6402,7 @@ void stmmac_disable_rx_queue(struct stmm void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue) { @@ -1125,7 +1125,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_channel *ch = &priv->channel[queue]; unsigned long flags; u32 buf_size; -@@ -6434,7 +6438,7 @@ void stmmac_enable_rx_queue(struct stmma +@@ -6435,7 +6439,7 @@ void stmmac_enable_rx_queue(struct stmma rx_q->queue_index); } else { stmmac_set_dma_bfsize(priv, priv->ioaddr, @@ -1134,7 +1134,7 @@ Signed-off-by: Jakub Kicinski rx_q->queue_index); } -@@ -6460,7 +6464,7 @@ void stmmac_disable_tx_queue(struct stmm +@@ -6461,7 +6465,7 @@ void stmmac_disable_tx_queue(struct stmm void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue) { @@ -1143,7 +1143,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_channel *ch = &priv->channel[queue]; unsigned long flags; int ret; -@@ -6510,7 +6514,7 @@ void stmmac_xdp_release(struct net_devic +@@ -6511,7 +6515,7 @@ void stmmac_xdp_release(struct net_devic stmmac_disable_all_queues(priv); for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) @@ -1152,7 +1152,7 @@ Signed-off-by: Jakub Kicinski /* Free the IRQ lines */ stmmac_free_irq(dev, REQ_IRQ_ERR_ALL, 0); -@@ -6569,7 +6573,7 @@ int stmmac_xdp_open(struct net_device *d +@@ -6570,7 +6574,7 @@ int stmmac_xdp_open(struct net_device *d /* DMA RX Channel Configuration */ for (chan = 0; chan < rx_cnt; chan++) { @@ -1161,7 +1161,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, rx_q->dma_rx_phy, chan); -@@ -6587,7 +6591,7 @@ int stmmac_xdp_open(struct net_device *d +@@ -6588,7 +6592,7 @@ int stmmac_xdp_open(struct net_device *d rx_q->queue_index); } else { stmmac_set_dma_bfsize(priv, priv->ioaddr, @@ -1170,7 +1170,7 @@ Signed-off-by: Jakub Kicinski rx_q->queue_index); } -@@ -6596,7 +6600,7 @@ int stmmac_xdp_open(struct net_device *d +@@ -6597,7 +6601,7 @@ int stmmac_xdp_open(struct net_device *d /* DMA TX Channel Configuration */ for (chan = 0; chan < tx_cnt; chan++) { @@ -1179,7 +1179,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, tx_q->dma_tx_phy, chan); -@@ -6629,7 +6633,7 @@ int stmmac_xdp_open(struct net_device *d +@@ -6630,7 +6634,7 @@ int stmmac_xdp_open(struct net_device *d irq_error: for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) @@ -1188,7 +1188,7 @@ Signed-off-by: Jakub Kicinski stmmac_hw_teardown(dev); init_error: -@@ -6656,8 +6660,8 @@ int stmmac_xsk_wakeup(struct net_device +@@ -6657,8 +6661,8 @@ int stmmac_xsk_wakeup(struct net_device queue >= priv->plat->tx_queues_to_use) return -EINVAL; @@ -1199,7 +1199,7 @@ Signed-off-by: Jakub Kicinski ch = &priv->channel[queue]; if (!rx_q->xsk_pool && !tx_q->xsk_pool) -@@ -6913,8 +6917,8 @@ int stmmac_reinit_ringparam(struct net_d +@@ -6914,8 +6918,8 @@ int stmmac_reinit_ringparam(struct net_d if (netif_running(dev)) stmmac_release(dev); @@ -1210,7 +1210,7 @@ Signed-off-by: Jakub Kicinski if (netif_running(dev)) ret = stmmac_open(dev); -@@ -7352,7 +7356,7 @@ int stmmac_suspend(struct device *dev) +@@ -7353,7 +7357,7 @@ int stmmac_suspend(struct device *dev) stmmac_disable_all_queues(priv); for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) @@ -1219,7 +1219,7 @@ Signed-off-by: Jakub Kicinski if (priv->eee_enabled) { priv->tx_path_in_lpi_mode = false; -@@ -7403,7 +7407,7 @@ EXPORT_SYMBOL_GPL(stmmac_suspend); +@@ -7404,7 +7408,7 @@ EXPORT_SYMBOL_GPL(stmmac_suspend); static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue) { @@ -1228,7 +1228,7 @@ Signed-off-by: Jakub Kicinski rx_q->cur_rx = 0; rx_q->dirty_rx = 0; -@@ -7411,7 +7415,7 @@ static void stmmac_reset_rx_queue(struct +@@ -7412,7 +7416,7 @@ static void stmmac_reset_rx_queue(struct static void stmmac_reset_tx_queue(struct stmmac_priv *priv, u32 queue) { diff --git a/target/linux/generic/backport-5.15/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch b/target/linux/generic/backport-5.15/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch index 8ad6f208cbd..a8f7bdb7d15 100644 --- a/target/linux/generic/backport-5.15/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch +++ b/target/linux/generic/backport-5.15/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch @@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -1299,7 +1299,8 @@ static int stmmac_phy_setup(struct stmma +@@ -1300,7 +1300,8 @@ static int stmmac_phy_setup(struct stmma return 0; } @@ -27,7 +27,7 @@ Signed-off-by: Jakub Kicinski { u32 rx_cnt = priv->plat->rx_queues_to_use; unsigned int desc_size; -@@ -1308,7 +1309,7 @@ static void stmmac_display_rx_rings(stru +@@ -1309,7 +1310,7 @@ static void stmmac_display_rx_rings(stru /* Display RX rings */ for (queue = 0; queue < rx_cnt; queue++) { @@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski pr_info("\tRX Queue %u rings\n", queue); -@@ -1321,12 +1322,13 @@ static void stmmac_display_rx_rings(stru +@@ -1322,12 +1323,13 @@ static void stmmac_display_rx_rings(stru } /* Display RX ring */ @@ -52,7 +52,7 @@ Signed-off-by: Jakub Kicinski { u32 tx_cnt = priv->plat->tx_queues_to_use; unsigned int desc_size; -@@ -1335,7 +1337,7 @@ static void stmmac_display_tx_rings(stru +@@ -1336,7 +1338,7 @@ static void stmmac_display_tx_rings(stru /* Display TX rings */ for (queue = 0; queue < tx_cnt; queue++) { @@ -61,7 +61,7 @@ Signed-off-by: Jakub Kicinski pr_info("\tTX Queue %d rings\n", queue); -@@ -1350,18 +1352,19 @@ static void stmmac_display_tx_rings(stru +@@ -1351,18 +1353,19 @@ static void stmmac_display_tx_rings(stru desc_size = sizeof(struct dma_desc); } @@ -85,7 +85,7 @@ Signed-off-by: Jakub Kicinski } static int stmmac_set_bfsize(int mtu, int bufsize) -@@ -1385,44 +1388,50 @@ static int stmmac_set_bfsize(int mtu, in +@@ -1386,44 +1389,50 @@ static int stmmac_set_bfsize(int mtu, in /** * stmmac_clear_rx_descriptors - clear RX descriptors * @priv: driver private structure @@ -147,7 +147,7 @@ Signed-off-by: Jakub Kicinski struct dma_desc *p; if (priv->extend_desc) -@@ -1439,10 +1448,12 @@ static void stmmac_clear_tx_descriptors( +@@ -1440,10 +1449,12 @@ static void stmmac_clear_tx_descriptors( /** * stmmac_clear_descriptors - clear descriptors * @priv: driver private structure @@ -161,7 +161,7 @@ Signed-off-by: Jakub Kicinski { u32 rx_queue_cnt = priv->plat->rx_queues_to_use; u32 tx_queue_cnt = priv->plat->tx_queues_to_use; -@@ -1450,16 +1461,17 @@ static void stmmac_clear_descriptors(str +@@ -1451,16 +1462,17 @@ static void stmmac_clear_descriptors(str /* Clear the RX descriptors */ for (queue = 0; queue < rx_queue_cnt; queue++) @@ -181,7 +181,7 @@ Signed-off-by: Jakub Kicinski * @p: descriptor pointer * @i: descriptor index * @flags: gfp flag -@@ -1467,10 +1479,12 @@ static void stmmac_clear_descriptors(str +@@ -1468,10 +1480,12 @@ static void stmmac_clear_descriptors(str * Description: this function is called to allocate a receive buffer, perform * the DMA mapping and init the descriptor. */ @@ -196,7 +196,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (!buf->page) { -@@ -1495,7 +1509,7 @@ static int stmmac_init_rx_buffers(struct +@@ -1496,7 +1510,7 @@ static int stmmac_init_rx_buffers(struct buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; stmmac_set_desc_addr(priv, p, buf->addr); @@ -205,7 +205,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_desc3(priv, p); return 0; -@@ -1504,12 +1518,13 @@ static int stmmac_init_rx_buffers(struct +@@ -1505,12 +1519,13 @@ static int stmmac_init_rx_buffers(struct /** * stmmac_free_rx_buffer - free RX dma buffers * @priv: private structure @@ -222,7 +222,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (buf->page) -@@ -1524,12 +1539,15 @@ static void stmmac_free_rx_buffer(struct +@@ -1525,12 +1540,15 @@ static void stmmac_free_rx_buffer(struct /** * stmmac_free_tx_buffer - free RX dma buffers * @priv: private structure @@ -240,7 +240,7 @@ Signed-off-by: Jakub Kicinski if (tx_q->tx_skbuff_dma[i].buf && tx_q->tx_skbuff_dma[i].buf_type != STMMAC_TXBUF_T_XDP_TX) { -@@ -1568,23 +1586,28 @@ static void stmmac_free_tx_buffer(struct +@@ -1569,23 +1587,28 @@ static void stmmac_free_tx_buffer(struct /** * dma_free_rx_skbufs - free RX dma buffers * @priv: private structure @@ -276,7 +276,7 @@ Signed-off-by: Jakub Kicinski struct dma_desc *p; int ret; -@@ -1593,7 +1616,7 @@ static int stmmac_alloc_rx_buffers(struc +@@ -1594,7 +1617,7 @@ static int stmmac_alloc_rx_buffers(struc else p = rx_q->dma_rx + i; @@ -285,7 +285,7 @@ Signed-off-by: Jakub Kicinski queue); if (ret) return ret; -@@ -1607,14 +1630,17 @@ static int stmmac_alloc_rx_buffers(struc +@@ -1608,14 +1631,17 @@ static int stmmac_alloc_rx_buffers(struc /** * dma_free_rx_xskbufs - free RX dma buffers from XSK pool * @priv: private structure @@ -306,7 +306,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; if (!buf->xdp) -@@ -1625,12 +1651,14 @@ static void dma_free_rx_xskbufs(struct s +@@ -1626,12 +1652,14 @@ static void dma_free_rx_xskbufs(struct s } } @@ -324,7 +324,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_rx_buffer *buf; dma_addr_t dma_addr; struct dma_desc *p; -@@ -1665,22 +1693,25 @@ static struct xsk_buff_pool *stmmac_get_ +@@ -1666,22 +1694,25 @@ static struct xsk_buff_pool *stmmac_get_ /** * __init_dma_rx_desc_rings - init the RX descriptor ring (per queue) * @priv: driver private structure @@ -353,7 +353,7 @@ Signed-off-by: Jakub Kicinski xdp_rxq_info_unreg_mem_model(&rx_q->xdp_rxq); -@@ -1707,9 +1738,9 @@ static int __init_dma_rx_desc_rings(stru +@@ -1708,9 +1739,9 @@ static int __init_dma_rx_desc_rings(stru /* RX XDP ZC buffer pool may not be populated, e.g. * xdpsock TX-only. */ @@ -365,7 +365,7 @@ Signed-off-by: Jakub Kicinski if (ret < 0) return -ENOMEM; } -@@ -1719,17 +1750,19 @@ static int __init_dma_rx_desc_rings(stru +@@ -1720,17 +1751,19 @@ static int __init_dma_rx_desc_rings(stru if (priv->extend_desc) stmmac_mode_init(priv, rx_q->dma_erx, rx_q->dma_rx_phy, @@ -388,7 +388,7 @@ Signed-off-by: Jakub Kicinski { struct stmmac_priv *priv = netdev_priv(dev); u32 rx_count = priv->plat->rx_queues_to_use; -@@ -1741,7 +1774,7 @@ static int init_dma_rx_desc_rings(struct +@@ -1742,7 +1775,7 @@ static int init_dma_rx_desc_rings(struct "SKB addresses:\nskb\t\tskb data\tdma data\n"); for (queue = 0; queue < rx_count; queue++) { @@ -397,7 +397,7 @@ Signed-off-by: Jakub Kicinski if (ret) goto err_init_rx_buffers; } -@@ -1750,12 +1783,12 @@ static int init_dma_rx_desc_rings(struct +@@ -1751,12 +1784,12 @@ static int init_dma_rx_desc_rings(struct err_init_rx_buffers: while (queue >= 0) { @@ -413,7 +413,7 @@ Signed-off-by: Jakub Kicinski rx_q->buf_alloc_num = 0; rx_q->xsk_pool = NULL; -@@ -1772,14 +1805,17 @@ err_init_rx_buffers: +@@ -1773,14 +1806,17 @@ err_init_rx_buffers: /** * __init_dma_tx_desc_rings - init the TX descriptor ring (per queue) * @priv: driver private structure @@ -434,7 +434,7 @@ Signed-off-by: Jakub Kicinski int i; netif_dbg(priv, probe, priv->dev, -@@ -1791,16 +1827,16 @@ static int __init_dma_tx_desc_rings(stru +@@ -1792,16 +1828,16 @@ static int __init_dma_tx_desc_rings(stru if (priv->extend_desc) stmmac_mode_init(priv, tx_q->dma_etx, tx_q->dma_tx_phy, @@ -454,7 +454,7 @@ Signed-off-by: Jakub Kicinski struct dma_desc *p; if (priv->extend_desc) -@@ -1822,7 +1858,8 @@ static int __init_dma_tx_desc_rings(stru +@@ -1823,7 +1859,8 @@ static int __init_dma_tx_desc_rings(stru return 0; } @@ -464,7 +464,7 @@ Signed-off-by: Jakub Kicinski { struct stmmac_priv *priv = netdev_priv(dev); u32 tx_queue_cnt; -@@ -1831,7 +1868,7 @@ static int init_dma_tx_desc_rings(struct +@@ -1832,7 +1869,7 @@ static int init_dma_tx_desc_rings(struct tx_queue_cnt = priv->plat->tx_queues_to_use; for (queue = 0; queue < tx_queue_cnt; queue++) @@ -473,7 +473,7 @@ Signed-off-by: Jakub Kicinski return 0; } -@@ -1839,26 +1876,29 @@ static int init_dma_tx_desc_rings(struct +@@ -1840,26 +1877,29 @@ static int init_dma_tx_desc_rings(struct /** * init_dma_desc_rings - init the RX/TX descriptor rings * @dev: net device structure @@ -508,7 +508,7 @@ Signed-off-by: Jakub Kicinski return ret; } -@@ -1866,17 +1906,20 @@ static int init_dma_desc_rings(struct ne +@@ -1867,17 +1907,20 @@ static int init_dma_desc_rings(struct ne /** * dma_free_tx_skbufs - free TX dma buffers * @priv: private structure @@ -533,7 +533,7 @@ Signed-off-by: Jakub Kicinski if (tx_q->xsk_pool && tx_q->xsk_frames_done) { xsk_tx_completed(tx_q->xsk_pool, tx_q->xsk_frames_done); -@@ -1895,34 +1938,37 @@ static void stmmac_free_tx_skbufs(struct +@@ -1896,34 +1939,37 @@ static void stmmac_free_tx_skbufs(struct u32 queue; for (queue = 0; queue < tx_queue_cnt; queue++) @@ -578,7 +578,7 @@ Signed-off-by: Jakub Kicinski sizeof(struct dma_extended_desc), rx_q->dma_erx, rx_q->dma_rx_phy); -@@ -1934,29 +1980,33 @@ static void __free_dma_rx_desc_resources +@@ -1935,29 +1981,33 @@ static void __free_dma_rx_desc_resources page_pool_destroy(rx_q->page_pool); } @@ -617,7 +617,7 @@ Signed-off-by: Jakub Kicinski if (priv->extend_desc) { size = sizeof(struct dma_extended_desc); -@@ -1969,7 +2019,7 @@ static void __free_dma_tx_desc_resources +@@ -1970,7 +2020,7 @@ static void __free_dma_tx_desc_resources addr = tx_q->dma_tx; } @@ -626,7 +626,7 @@ Signed-off-by: Jakub Kicinski dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy); -@@ -1977,28 +2027,32 @@ static void __free_dma_tx_desc_resources +@@ -1978,28 +2028,32 @@ static void __free_dma_tx_desc_resources kfree(tx_q->tx_skbuff); } @@ -663,7 +663,7 @@ Signed-off-by: Jakub Kicinski struct stmmac_channel *ch = &priv->channel[queue]; bool xdp_prog = stmmac_xdp_is_enabled(priv); struct page_pool_params pp_params = { 0 }; -@@ -2010,8 +2064,8 @@ static int __alloc_dma_rx_desc_resources +@@ -2011,8 +2065,8 @@ static int __alloc_dma_rx_desc_resources rx_q->priv_data = priv; pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; @@ -674,7 +674,7 @@ Signed-off-by: Jakub Kicinski pp_params.order = ilog2(num_pages); pp_params.nid = dev_to_node(priv->device); pp_params.dev = priv->device; -@@ -2026,7 +2080,7 @@ static int __alloc_dma_rx_desc_resources +@@ -2027,7 +2081,7 @@ static int __alloc_dma_rx_desc_resources return ret; } @@ -683,7 +683,7 @@ Signed-off-by: Jakub Kicinski sizeof(*rx_q->buf_pool), GFP_KERNEL); if (!rx_q->buf_pool) -@@ -2034,7 +2088,7 @@ static int __alloc_dma_rx_desc_resources +@@ -2035,7 +2089,7 @@ static int __alloc_dma_rx_desc_resources if (priv->extend_desc) { rx_q->dma_erx = dma_alloc_coherent(priv->device, @@ -692,7 +692,7 @@ Signed-off-by: Jakub Kicinski sizeof(struct dma_extended_desc), &rx_q->dma_rx_phy, GFP_KERNEL); -@@ -2043,7 +2097,7 @@ static int __alloc_dma_rx_desc_resources +@@ -2044,7 +2098,7 @@ static int __alloc_dma_rx_desc_resources } else { rx_q->dma_rx = dma_alloc_coherent(priv->device, @@ -701,7 +701,7 @@ Signed-off-by: Jakub Kicinski sizeof(struct dma_desc), &rx_q->dma_rx_phy, GFP_KERNEL); -@@ -2068,7 +2122,8 @@ static int __alloc_dma_rx_desc_resources +@@ -2069,7 +2123,8 @@ static int __alloc_dma_rx_desc_resources return 0; } @@ -711,7 +711,7 @@ Signed-off-by: Jakub Kicinski { u32 rx_count = priv->plat->rx_queues_to_use; u32 queue; -@@ -2076,7 +2131,7 @@ static int alloc_dma_rx_desc_resources(s +@@ -2077,7 +2132,7 @@ static int alloc_dma_rx_desc_resources(s /* RX queues buffers and DMA */ for (queue = 0; queue < rx_count; queue++) { @@ -720,7 +720,7 @@ Signed-off-by: Jakub Kicinski if (ret) goto err_dma; } -@@ -2084,7 +2139,7 @@ static int alloc_dma_rx_desc_resources(s +@@ -2085,7 +2140,7 @@ static int alloc_dma_rx_desc_resources(s return 0; err_dma: @@ -729,7 +729,7 @@ Signed-off-by: Jakub Kicinski return ret; } -@@ -2092,28 +2147,31 @@ err_dma: +@@ -2093,28 +2148,31 @@ err_dma: /** * __alloc_dma_tx_desc_resources - alloc TX resources (per queue). * @priv: private structure @@ -765,7 +765,7 @@ Signed-off-by: Jakub Kicinski sizeof(struct sk_buff *), GFP_KERNEL); if (!tx_q->tx_skbuff) -@@ -2126,7 +2184,7 @@ static int __alloc_dma_tx_desc_resources +@@ -2127,7 +2185,7 @@ static int __alloc_dma_tx_desc_resources else size = sizeof(struct dma_desc); @@ -774,7 +774,7 @@ Signed-off-by: Jakub Kicinski addr = dma_alloc_coherent(priv->device, size, &tx_q->dma_tx_phy, GFP_KERNEL); -@@ -2143,7 +2201,8 @@ static int __alloc_dma_tx_desc_resources +@@ -2144,7 +2202,8 @@ static int __alloc_dma_tx_desc_resources return 0; } @@ -784,7 +784,7 @@ Signed-off-by: Jakub Kicinski { u32 tx_count = priv->plat->tx_queues_to_use; u32 queue; -@@ -2151,7 +2210,7 @@ static int alloc_dma_tx_desc_resources(s +@@ -2152,7 +2211,7 @@ static int alloc_dma_tx_desc_resources(s /* TX queues buffers and DMA */ for (queue = 0; queue < tx_count; queue++) { @@ -793,7 +793,7 @@ Signed-off-by: Jakub Kicinski if (ret) goto err_dma; } -@@ -2159,27 +2218,29 @@ static int alloc_dma_tx_desc_resources(s +@@ -2160,27 +2219,29 @@ static int alloc_dma_tx_desc_resources(s return 0; err_dma: @@ -827,7 +827,7 @@ Signed-off-by: Jakub Kicinski return ret; } -@@ -2187,16 +2248,18 @@ static int alloc_dma_desc_resources(stru +@@ -2188,16 +2249,18 @@ static int alloc_dma_desc_resources(stru /** * free_dma_desc_resources - free dma desc resources * @priv: private structure @@ -849,7 +849,7 @@ Signed-off-by: Jakub Kicinski } /** -@@ -2685,8 +2748,8 @@ static void stmmac_tx_err(struct stmmac_ +@@ -2686,8 +2749,8 @@ static void stmmac_tx_err(struct stmmac_ netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, chan)); stmmac_stop_tx_dma(priv, chan); @@ -860,7 +860,7 @@ Signed-off-by: Jakub Kicinski stmmac_reset_tx_queue(priv, chan); stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, tx_q->dma_tx_phy, chan); -@@ -3683,19 +3746,93 @@ static int stmmac_request_irq(struct net +@@ -3684,19 +3747,93 @@ static int stmmac_request_irq(struct net } /** @@ -957,7 +957,7 @@ Signed-off-by: Jakub Kicinski u32 chan; int ret; -@@ -3722,45 +3859,10 @@ static int stmmac_open(struct net_device +@@ -3723,45 +3860,10 @@ static int stmmac_open(struct net_device memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); priv->xstats.threshold = tc; @@ -1005,7 +1005,7 @@ Signed-off-by: Jakub Kicinski if (priv->plat->serdes_powerup) { ret = priv->plat->serdes_powerup(dev, priv->plat->bsp_priv); -@@ -3803,14 +3905,28 @@ irq_error: +@@ -3804,14 +3906,28 @@ irq_error: stmmac_hw_teardown(dev); init_error: @@ -1036,7 +1036,7 @@ Signed-off-by: Jakub Kicinski static void stmmac_fpe_stop_wq(struct stmmac_priv *priv) { set_bit(__FPE_REMOVING, &priv->fpe_task_state); -@@ -3857,7 +3973,7 @@ static int stmmac_release(struct net_dev +@@ -3858,7 +3974,7 @@ static int stmmac_release(struct net_dev stmmac_stop_all_dma(priv); /* Release and free the Rx/Tx resources */ @@ -1045,7 +1045,7 @@ Signed-off-by: Jakub Kicinski /* Disable the MAC Rx/Tx */ stmmac_mac_set(priv, priv->ioaddr, false); -@@ -6396,7 +6512,7 @@ void stmmac_disable_rx_queue(struct stmm +@@ -6397,7 +6513,7 @@ void stmmac_disable_rx_queue(struct stmm spin_unlock_irqrestore(&ch->lock, flags); stmmac_stop_rx_dma(priv, queue); @@ -1054,7 +1054,7 @@ Signed-off-by: Jakub Kicinski } void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue) -@@ -6407,21 +6523,21 @@ void stmmac_enable_rx_queue(struct stmma +@@ -6408,21 +6524,21 @@ void stmmac_enable_rx_queue(struct stmma u32 buf_size; int ret; @@ -1080,7 +1080,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, rx_q->dma_rx_phy, rx_q->queue_index); -@@ -6459,7 +6575,7 @@ void stmmac_disable_tx_queue(struct stmm +@@ -6460,7 +6576,7 @@ void stmmac_disable_tx_queue(struct stmm spin_unlock_irqrestore(&ch->lock, flags); stmmac_stop_tx_dma(priv, queue); @@ -1089,7 +1089,7 @@ Signed-off-by: Jakub Kicinski } void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue) -@@ -6469,21 +6585,21 @@ void stmmac_enable_tx_queue(struct stmma +@@ -6470,21 +6586,21 @@ void stmmac_enable_tx_queue(struct stmma unsigned long flags; int ret; @@ -1115,7 +1115,7 @@ Signed-off-by: Jakub Kicinski stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, tx_q->dma_tx_phy, tx_q->queue_index); -@@ -6523,7 +6639,7 @@ void stmmac_xdp_release(struct net_devic +@@ -6524,7 +6640,7 @@ void stmmac_xdp_release(struct net_devic stmmac_stop_all_dma(priv); /* Release and free the Rx/Tx resources */ @@ -1124,7 +1124,7 @@ Signed-off-by: Jakub Kicinski /* Disable the MAC Rx/Tx */ stmmac_mac_set(priv, priv->ioaddr, false); -@@ -6548,14 +6664,14 @@ int stmmac_xdp_open(struct net_device *d +@@ -6549,14 +6665,14 @@ int stmmac_xdp_open(struct net_device *d u32 chan; int ret; @@ -1141,7 +1141,7 @@ Signed-off-by: Jakub Kicinski if (ret < 0) { netdev_err(dev, "%s: DMA descriptors initialization failed\n", __func__); -@@ -6637,7 +6753,7 @@ irq_error: +@@ -6638,7 +6754,7 @@ irq_error: stmmac_hw_teardown(dev); init_error: @@ -1150,7 +1150,7 @@ Signed-off-by: Jakub Kicinski dma_desc_error: return ret; } -@@ -7498,7 +7614,7 @@ int stmmac_resume(struct device *dev) +@@ -7499,7 +7615,7 @@ int stmmac_resume(struct device *dev) stmmac_reset_queues_param(priv); stmmac_free_tx_skbufs(priv); diff --git a/target/linux/generic/backport-5.15/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch b/target/linux/generic/backport-5.15/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch index 2576df45224..8fccc716597 100644 --- a/target/linux/generic/backport-5.15/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch +++ b/target/linux/generic/backport-5.15/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch @@ -19,7 +19,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -5625,18 +5625,15 @@ static int stmmac_change_mtu(struct net_ +@@ -5626,18 +5626,15 @@ static int stmmac_change_mtu(struct net_ { struct stmmac_priv *priv = netdev_priv(dev); int txfifosz = priv->plat->tx_fifo_size; @@ -40,7 +40,7 @@ Signed-off-by: Jakub Kicinski if (stmmac_xdp_is_enabled(priv) && new_mtu > ETH_DATA_LEN) { netdev_dbg(priv->dev, "Jumbo frames not supported for XDP\n"); return -EINVAL; -@@ -5648,8 +5645,29 @@ static int stmmac_change_mtu(struct net_ +@@ -5649,8 +5646,29 @@ static int stmmac_change_mtu(struct net_ if ((txfifosz < new_mtu) || (new_mtu > BUF_SIZE_16KiB)) return -EINVAL; diff --git a/target/linux/generic/backport-5.15/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch b/target/linux/generic/backport-5.15/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch index 988dfa317de..4a7e6ef7ad2 100644 --- a/target/linux/generic/backport-5.15/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch +++ b/target/linux/generic/backport-5.15/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch @@ -19,7 +19,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2711,9 +2711,6 @@ mt7531_mac_config(struct dsa_switch *ds, +@@ -2716,9 +2716,6 @@ mt7531_mac_config(struct dsa_switch *ds, case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: @@ -29,7 +29,7 @@ Signed-off-by: David S. Miller return mt7531_sgmii_setup_mode_force(priv, port, interface); default: return -EINVAL; -@@ -2789,13 +2786,6 @@ unsupported: +@@ -2794,13 +2791,6 @@ unsupported: return; } @@ -43,7 +43,7 @@ Signed-off-by: David S. Miller mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); mcr_new = mcr_cur; mcr_new &= ~PMCR_LINK_SETTINGS_MASK; -@@ -2932,6 +2922,9 @@ static void mt753x_phylink_get_caps(stru +@@ -2937,6 +2927,9 @@ static void mt753x_phylink_get_caps(stru config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD; @@ -53,7 +53,7 @@ Signed-off-by: David S. Miller /* This driver does not make use of the speed, duplex, pause or the * advertisement in its mac_config, so it is safe to mark this driver * as non-legacy. -@@ -2997,6 +2990,7 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 +@@ -3002,6 +2995,7 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); state->link = !!(status & MT7531_SGMII_LINK_STATUS); @@ -61,7 +61,7 @@ Signed-off-by: David S. Miller if (state->interface == PHY_INTERFACE_MODE_SGMII && (status & MT7531_SGMII_AN_ENABLE)) { val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); -@@ -3027,16 +3021,44 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 +@@ -3032,16 +3026,44 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 return 0; } @@ -109,7 +109,7 @@ Signed-off-by: David S. Miller } static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, -@@ -3077,6 +3099,8 @@ mt753x_setup(struct dsa_switch *ds) +@@ -3082,6 +3104,8 @@ mt753x_setup(struct dsa_switch *ds) priv->pcs[i].pcs.ops = priv->info->pcs_ops; priv->pcs[i].priv = priv; priv->pcs[i].port = i; diff --git a/target/linux/generic/hack-5.15/221-module_exports.patch b/target/linux/generic/hack-5.15/221-module_exports.patch index 405dc5f78ce..87f541b46f2 100644 --- a/target/linux/generic/hack-5.15/221-module_exports.patch +++ b/target/linux/generic/hack-5.15/221-module_exports.patch @@ -56,7 +56,7 @@ Signed-off-by: Felix Fietkau } \ \ /* __*init sections */ \ -@@ -1017,6 +1027,8 @@ +@@ -1022,6 +1032,8 @@ #define COMMON_DISCARDS \ SANITIZER_DISCARDS \ diff --git a/target/linux/generic/hack-5.15/773-bgmac-add-srab-switch.patch b/target/linux/generic/hack-5.15/773-bgmac-add-srab-switch.patch index 1e4fc446ce4..7127aa136c6 100644 --- a/target/linux/generic/hack-5.15/773-bgmac-add-srab-switch.patch +++ b/target/linux/generic/hack-5.15/773-bgmac-add-srab-switch.patch @@ -50,9 +50,9 @@ Signed-off-by: Hauke Mehrtens /************************************************** * MII **************************************************/ -@@ -1542,6 +1554,14 @@ int bgmac_enet_probe(struct bgmac *bgmac - /* Omit FCS from max MTU size */ - net_dev->max_mtu = BGMAC_RX_MAX_FRAME_SIZE - ETH_FCS_LEN; +@@ -1546,6 +1558,14 @@ int bgmac_enet_probe(struct bgmac *bgmac + + bgmac->in_init = false; + if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) { + bgmac_b53_pdata.regs = ioremap(0x18007000, 0x1000); @@ -65,7 +65,7 @@ Signed-off-by: Hauke Mehrtens err = register_netdev(bgmac->net_dev); if (err) { dev_err(bgmac->dev, "Cannot register net device\n"); -@@ -1564,6 +1584,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe); +@@ -1568,6 +1588,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe); void bgmac_enet_remove(struct bgmac *bgmac) { @@ -86,7 +86,7 @@ Signed-off-by: Hauke Mehrtens struct bgmac_slot_info { union { -@@ -495,6 +496,9 @@ struct bgmac { +@@ -497,6 +498,9 @@ struct bgmac { void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask, u32 set); int (*phy_connect)(struct bgmac *bgmac); diff --git a/target/linux/generic/hack-5.15/902-debloat_proc.patch b/target/linux/generic/hack-5.15/902-debloat_proc.patch index ef2fe47ae9a..a7a73cc885f 100644 --- a/target/linux/generic/hack-5.15/902-debloat_proc.patch +++ b/target/linux/generic/hack-5.15/902-debloat_proc.patch @@ -29,7 +29,7 @@ Signed-off-by: Felix Fietkau --- a/fs/locks.c +++ b/fs/locks.c -@@ -2952,6 +2952,8 @@ static const struct seq_operations locks +@@ -2953,6 +2953,8 @@ static const struct seq_operations locks static int __init proc_locks_init(void) { diff --git a/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch b/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch index 99cfa04db0f..6cde5d8589c 100644 --- a/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch +++ b/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2971,8 +2971,8 @@ static irqreturn_t mtk_handle_irq_rx(int +@@ -2972,8 +2972,8 @@ static irqreturn_t mtk_handle_irq_rx(int eth->rx_events++; if (likely(napi_schedule_prep(ð->rx_napi))) { @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -2984,8 +2984,8 @@ static irqreturn_t mtk_handle_irq_tx(int +@@ -2985,8 +2985,8 @@ static irqreturn_t mtk_handle_irq_tx(int eth->tx_events++; if (likely(napi_schedule_prep(ð->tx_napi))) { @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -4616,6 +4616,8 @@ static int mtk_probe(struct platform_dev +@@ -4617,6 +4617,8 @@ static int mtk_probe(struct platform_dev * for NAPI to work */ init_dummy_netdev(ð->dummy_dev); diff --git a/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch b/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch index 12a3044d057..01cc5fd18ef 100644 --- a/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch +++ b/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch @@ -15,7 +15,7 @@ Signed-off-by: Alexander Couzens --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2336,6 +2336,10 @@ mt7531_setup(struct dsa_switch *ds) +@@ -2341,6 +2341,10 @@ mt7531_setup(struct dsa_switch *ds) return -ENODEV; } diff --git a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch index d3aca7f849d..9268d3e428f 100644 --- a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch +++ b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch @@ -53,7 +53,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4585,8 +4585,8 @@ static int mtk_probe(struct platform_dev +@@ -4586,8 +4586,8 @@ static int mtk_probe(struct platform_dev for (i = 0; i < num_ppe; i++) { u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; @@ -64,7 +64,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov if (!eth->ppe[i]) { err = -ENOMEM; goto err_free_dev; -@@ -4711,6 +4711,7 @@ static const struct mtk_soc_data mt7622_ +@@ -4712,6 +4712,7 @@ static const struct mtk_soc_data mt7622_ .required_pctl = false, .offload_version = 2, .hash_offset = 2, @@ -72,7 +72,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), -@@ -4748,6 +4749,7 @@ static const struct mtk_soc_data mt7629_ +@@ -4749,6 +4750,7 @@ static const struct mtk_soc_data mt7629_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7629_CLKS_BITMAP, .required_pctl = false, @@ -80,7 +80,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4768,6 +4770,7 @@ static const struct mtk_soc_data mt7986_ +@@ -4769,6 +4771,7 @@ static const struct mtk_soc_data mt7986_ .offload_version = 2, .hash_offset = 4, .foe_entry_size = sizeof(struct mtk_foe_entry), @@ -90,7 +90,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .rxd_size = sizeof(struct mtk_rx_dma_v2), --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1025,6 +1025,8 @@ struct mtk_reg_map { +@@ -1026,6 +1026,8 @@ struct mtk_reg_map { * the extra setup for those pins used by GMAC. * @hash_offset Flow table hash offset. * @foe_entry_size Foe table entry size. @@ -99,7 +99,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov * @txd_size Tx DMA descriptor size. * @rxd_size Rx DMA descriptor size. * @rx_irq_done_mask Rx irq done register mask. -@@ -1042,6 +1044,7 @@ struct mtk_soc_data { +@@ -1043,6 +1045,7 @@ struct mtk_soc_data { u8 hash_offset; u16 foe_entry_size; netdev_features_t hw_features; diff --git a/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch b/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch index cb20b97c285..c2b411d2e9d 100644 --- a/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch +++ b/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch @@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1829,9 +1829,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1830,9 +1830,7 @@ static int mtk_poll_rx(struct napi_struc while (done < budget) { unsigned int pktlen, *rxdcsum; @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau dma_addr_t dma_addr; u32 hash, reason; int mac = 0; -@@ -1966,36 +1964,21 @@ static int mtk_poll_rx(struct napi_struc +@@ -1967,36 +1965,21 @@ static int mtk_poll_rx(struct napi_struc skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); @@ -70,7 +70,7 @@ Signed-off-by: Felix Fietkau skb_record_rx_queue(skb, 0); napi_gro_receive(napi, skb); -@@ -2810,29 +2793,11 @@ static netdev_features_t mtk_fix_feature +@@ -2811,29 +2794,11 @@ static netdev_features_t mtk_fix_feature static int mtk_set_features(struct net_device *dev, netdev_features_t features) { @@ -100,7 +100,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3146,30 +3111,6 @@ static int mtk_open(struct net_device *d +@@ -3147,30 +3112,6 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; int i, err; @@ -131,7 +131,7 @@ Signed-off-by: Felix Fietkau err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); if (err) { netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, -@@ -3210,6 +3151,35 @@ static int mtk_open(struct net_device *d +@@ -3211,6 +3152,35 @@ static int mtk_open(struct net_device *d phylink_start(mac->phylink); netif_tx_start_all_queues(dev); @@ -167,7 +167,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3694,10 +3664,9 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3695,10 +3665,9 @@ static int mtk_hw_init(struct mtk_eth *e if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { val = mtk_r32(eth, MTK_CDMP_IG_CTRL); mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); @@ -180,7 +180,7 @@ Signed-off-by: Felix Fietkau /* set interrupt delays based on current Net DIM sample */ mtk_dim_rx(ð->rx_dim.work); -@@ -4335,7 +4304,7 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4336,7 +4305,7 @@ static int mtk_add_mac(struct mtk_eth *e eth->netdev[id]->hw_features |= NETIF_F_LRO; eth->netdev[id]->vlan_features = eth->soc->hw_features & diff --git a/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch b/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch index 777e6f0ed13..961d970c4d2 100644 --- a/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch +++ b/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch @@ -16,7 +16,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1402,12 +1402,28 @@ static void mtk_wake_queue(struct mtk_et +@@ -1403,12 +1403,28 @@ static void mtk_wake_queue(struct mtk_et } } @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau bool gso = false; int tx_num; -@@ -1429,6 +1445,18 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1430,6 +1446,18 @@ static netdev_tx_t mtk_start_xmit(struct return NETDEV_TX_BUSY; } @@ -64,7 +64,7 @@ Signed-off-by: Felix Fietkau /* TSO: fill MSS info in tcp checksum field */ if (skb_is_gso(skb)) { if (skb_cow_head(skb, 0)) { -@@ -1444,8 +1472,14 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1445,8 +1473,14 @@ static netdev_tx_t mtk_start_xmit(struct } } diff --git a/target/linux/generic/pending-5.15/733-01-net-ethernet-mtk_eth_soc-reset-PCS-state.patch b/target/linux/generic/pending-5.15/733-01-net-ethernet-mtk_eth_soc-reset-PCS-state.patch index 67c0974417a..4d52d7be393 100644 --- a/target/linux/generic/pending-5.15/733-01-net-ethernet-mtk_eth_soc-reset-PCS-state.patch +++ b/target/linux/generic/pending-5.15/733-01-net-ethernet-mtk_eth_soc-reset-PCS-state.patch @@ -18,7 +18,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -529,6 +529,10 @@ +@@ -530,6 +530,10 @@ #define SGMII_SEND_AN_ERROR_EN BIT(11) #define SGMII_IF_MODE_MASK GENMASK(5, 1) diff --git a/target/linux/generic/pending-5.15/733-02-net-ethernet-mtk_eth_soc-fix-RX-data-corruption-issu.patch b/target/linux/generic/pending-5.15/733-02-net-ethernet-mtk_eth_soc-fix-RX-data-corruption-issu.patch deleted file mode 100644 index 2d95c402dc4..00000000000 --- a/target/linux/generic/pending-5.15/733-02-net-ethernet-mtk_eth_soc-fix-RX-data-corruption-issu.patch +++ /dev/null @@ -1,46 +0,0 @@ -From e0eb504b1c9f973427a33d7ffef29ddecdb464b9 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Mon, 23 Jan 2023 00:56:02 +0000 -Subject: [PATCH] net: ethernet: mtk_eth_soc: fix RX data corruption issue -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Also set bit 12 when setting up MAC MCR, as MediaTek SDK did the same -change stating: -"If without this patch, kernel might receive invalid packets that are -corrupted by GMAC."[1] -This fixes issues with <= 1G speed where we could previously observe -about 30% packet loss while the bad packet counter was increasing. -Unfortunately the meaning of bit 12 is not documented anywhere in SDK -code or datasheets. - -[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/d8a2975939a12686c4a95c40db21efdc3f821f63 -Tested-by: Bjørn Mork -Signed-off-by: Daniel Golle ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -528,7 +528,7 @@ static int mtk_mac_finish(struct phylink - /* Setup gmac */ - mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); - mcr_new = mcr_cur; -- mcr_new |= MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE | -+ mcr_new |= MAC_MCR_IPG_CFG | MAC_MCR_BIT_12 | MAC_MCR_FORCE_MODE | - MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK; - - /* Only update control register when needed! */ ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -392,6 +392,7 @@ - #define MAC_MCR_FORCE_MODE BIT(15) - #define MAC_MCR_TX_EN BIT(14) - #define MAC_MCR_RX_EN BIT(13) -+#define MAC_MCR_BIT_12 BIT(12) - #define MAC_MCR_BACKOFF_EN BIT(9) - #define MAC_MCR_BACKPR_EN BIT(8) - #define MAC_MCR_FORCE_RX_FC BIT(5) diff --git a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch index 757750832c3..554619c0179 100644 --- a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch +++ b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch @@ -103,7 +103,7 @@ Signed-off-by: David S. Miller ret = mtk_mdio_busy_wait(eth); if (ret < 0) -@@ -726,6 +769,7 @@ static int mtk_mdio_init(struct mtk_eth +@@ -727,6 +770,7 @@ static int mtk_mdio_init(struct mtk_eth eth->mii_bus->name = "mdio"; eth->mii_bus->read = mtk_mdio_read; eth->mii_bus->write = mtk_mdio_write; diff --git a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch index 29aba20e97d..72faba8a9ee 100644 --- a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch +++ b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch @@ -14,7 +14,7 @@ Signed-off-by: René van Dorst --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4227,6 +4227,7 @@ static const struct net_device_ops mtk_n +@@ -4228,6 +4228,7 @@ static const struct net_device_ops mtk_n static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) { @@ -22,7 +22,7 @@ Signed-off-by: René van Dorst const __be32 *_id = of_get_property(np, "reg", NULL); phy_interface_t phy_mode; struct phylink *phylink; -@@ -4355,6 +4356,9 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4356,6 +4357,9 @@ static int mtk_add_mac(struct mtk_eth *e register_netdevice_notifier(&mac->device_notifier); } From f0bc2636cec9000ae6f6411e510555140dbc6537 Mon Sep 17 00:00:00 2001 From: John Audia Date: Wed, 22 Mar 2023 11:08:27 -0400 Subject: [PATCH 13/53] kernel: bump 5.15 to 5.15.104 All patches automatically rebased. Build system: x86_64 Build-tested: bcm2711/RPi4B, ramips/tplink_archer-a6-v3, filogic/xiaomi_redmi-router-ax6000-ubootmod Run-tested: bcm2711/RPi4B, ramips/tplink_archer-a6-v3, filogic/xiaomi_redmi-router-ax6000-ubootmod Signed-off-by: John Audia --- include/kernel-5.15 | 4 ++-- ...t-phy-lan87xx-Allow-more-time-for-link-detect.patch | 2 +- ...700-net-phy-lan87xx-Decrease-phy-polling-rate.patch | 8 ++++---- ...0-v6.1-04-mm-multigenerational-lru-groundwork.patch | 2 +- ...ernet-mtk_eth_soc-implement-flow-offloading-t.patch | 4 ++-- .../hack-5.15/721-net-add-packet-mangeling.patch | 10 +++++----- .../680-NET-skip-GRO-for-foreign-MAC-addresses.patch | 2 +- ...e-add-optional-threading-for-backlog-processi.patch | 4 ++-- ...88e6xxx-Request-assisted-learning-on-CPU-port.patch | 2 +- .../0001-MIPS-lantiq-add-pcie-driver.patch | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/kernel-5.15 b/include/kernel-5.15 index 16eabc74ded..51d1c3c6fe7 100644 --- a/include/kernel-5.15 +++ b/include/kernel-5.15 @@ -1,2 +1,2 @@ -LINUX_VERSION-5.15 = .103 -LINUX_KERNEL_HASH-5.15.103 = 0876ba81631cca532f72a8d633f7031c3068669a0ecdd77d23b74e8dfc8dd705 +LINUX_VERSION-5.15 = .104 +LINUX_KERNEL_HASH-5.15.104 = 71c532ce09992e470f3259ffeb38d2b5bba990c243a559e4726a57412bd36b54 diff --git a/target/linux/bcm27xx/patches-5.15/950-0500-net-phy-lan87xx-Allow-more-time-for-link-detect.patch b/target/linux/bcm27xx/patches-5.15/950-0500-net-phy-lan87xx-Allow-more-time-for-link-detect.patch index 91265071380..7c620c4400c 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0500-net-phy-lan87xx-Allow-more-time-for-link-detect.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0500-net-phy-lan87xx-Allow-more-time-for-link-detect.patch @@ -21,7 +21,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c -@@ -220,12 +220,12 @@ static int lan87xx_read_status(struct ph +@@ -223,12 +223,12 @@ static int lan87xx_read_status(struct ph if (rc < 0) return rc; diff --git a/target/linux/bcm27xx/patches-5.15/950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch b/target/linux/bcm27xx/patches-5.15/950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch index 62d7ea93d3a..0341a0b7bf8 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0700-net-phy-lan87xx-Decrease-phy-polling-rate.patch @@ -18,8 +18,8 @@ Signed-off-by: Phil Elwell --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c -@@ -210,6 +210,8 @@ static int lan87xx_read_status(struct ph - int err = genphy_read_status(phydev); +@@ -213,6 +213,8 @@ static int lan87xx_read_status(struct ph + return err; if (!phydev->link && priv->energy_enable && phydev->irq == PHY_POLL) { + int energy_detected; @@ -27,7 +27,7 @@ Signed-off-by: Phil Elwell /* Disable EDPD to wake up PHY */ int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); if (rc < 0) -@@ -225,7 +227,7 @@ static int lan87xx_read_status(struct ph +@@ -228,7 +230,7 @@ static int lan87xx_read_status(struct ph */ read_poll_timeout(phy_read, rc, rc & MII_LAN83C185_ENERGYON || rc < 0, @@ -36,7 +36,7 @@ Signed-off-by: Phil Elwell MII_LAN83C185_CTRL_STATUS); if (rc < 0) return rc; -@@ -235,10 +237,16 @@ static int lan87xx_read_status(struct ph +@@ -238,10 +240,16 @@ static int lan87xx_read_status(struct ph if (rc < 0) return rc; diff --git a/target/linux/generic/backport-5.15/020-v6.1-04-mm-multigenerational-lru-groundwork.patch b/target/linux/generic/backport-5.15/020-v6.1-04-mm-multigenerational-lru-groundwork.patch index 1cb82d1b8f9..aec67c23eb2 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-04-mm-multigenerational-lru-groundwork.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-04-mm-multigenerational-lru-groundwork.patch @@ -581,7 +581,7 @@ Change-Id: I71de7cd15b8dfa6f9fdd838023474693c4fee0a7 extern struct list_head cgroup_roots; --- a/mm/huge_memory.c +++ b/mm/huge_memory.c -@@ -2364,7 +2364,8 @@ static void __split_huge_page_tail(struc +@@ -2366,7 +2366,8 @@ static void __split_huge_page_tail(struc #ifdef CONFIG_64BIT (1L << PG_arch_2) | #endif diff --git a/target/linux/generic/backport-5.15/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch b/target/linux/generic/backport-5.15/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch index d5b1d214133..50d65b1eb6f 100644 --- a/target/linux/generic/backport-5.15/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch +++ b/target/linux/generic/backport-5.15/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch @@ -233,7 +233,7 @@ Signed-off-by: Felix Fietkau static inline void --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -870,6 +870,7 @@ enum net_device_path_type { +@@ -872,6 +872,7 @@ enum net_device_path_type { DEV_PATH_BRIDGE, DEV_PATH_PPPOE, DEV_PATH_DSA, @@ -241,7 +241,7 @@ Signed-off-by: Felix Fietkau }; struct net_device_path { -@@ -895,6 +896,12 @@ struct net_device_path { +@@ -897,6 +898,12 @@ struct net_device_path { int port; u16 proto; } dsa; diff --git a/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch b/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch index a1d621a7a9e..16bb4855ff3 100644 --- a/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch +++ b/target/linux/generic/hack-5.15/721-net-add-packet-mangeling.patch @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -1677,6 +1677,10 @@ enum netdev_priv_flags { +@@ -1679,6 +1679,10 @@ enum netdev_priv_flags { IFF_TX_SKB_NO_LINEAR = BIT_ULL(31), }; @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN #define IFF_EBRIDGE IFF_EBRIDGE #define IFF_BONDING IFF_BONDING -@@ -1709,6 +1713,7 @@ enum netdev_priv_flags { +@@ -1711,6 +1715,7 @@ enum netdev_priv_flags { #define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER #define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK #define IFF_TX_SKB_NO_LINEAR IFF_TX_SKB_NO_LINEAR @@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau /* Specifies the type of the struct net_device::ml_priv pointer */ enum netdev_ml_priv_type { -@@ -2010,6 +2015,7 @@ struct net_device { +@@ -2012,6 +2017,7 @@ struct net_device { /* Read-mostly cache-line for fast-path access */ unsigned int flags; unsigned int priv_flags; @@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau const struct net_device_ops *netdev_ops; int ifindex; unsigned short gflags; -@@ -2070,6 +2076,11 @@ struct net_device { +@@ -2072,6 +2078,11 @@ struct net_device { const struct tlsdev_ops *tlsdev_ops; #endif @@ -58,7 +58,7 @@ Signed-off-by: Felix Fietkau const struct header_ops *header_ops; unsigned char operstate; -@@ -2144,6 +2155,10 @@ struct net_device { +@@ -2146,6 +2157,10 @@ struct net_device { struct mctp_dev __rcu *mctp_ptr; #endif diff --git a/target/linux/generic/pending-5.15/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/pending-5.15/680-NET-skip-GRO-for-foreign-MAC-addresses.patch index 2d3efb73d00..e9705fae461 100644 --- a/target/linux/generic/pending-5.15/680-NET-skip-GRO-for-foreign-MAC-addresses.patch +++ b/target/linux/generic/pending-5.15/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -2096,6 +2096,8 @@ struct net_device { +@@ -2098,6 +2098,8 @@ struct net_device { struct netdev_hw_addr_list mc; struct netdev_hw_addr_list dev_addrs; diff --git a/target/linux/generic/pending-5.15/760-net-core-add-optional-threading-for-backlog-processi.patch b/target/linux/generic/pending-5.15/760-net-core-add-optional-threading-for-backlog-processi.patch index 463f405f3a1..c26491abdbe 100644 --- a/target/linux/generic/pending-5.15/760-net-core-add-optional-threading-for-backlog-processi.patch +++ b/target/linux/generic/pending-5.15/760-net-core-add-optional-threading-for-backlog-processi.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -500,6 +500,7 @@ static inline bool napi_complete(struct +@@ -502,6 +502,7 @@ static inline bool napi_complete(struct } int dev_set_threaded(struct net_device *dev, bool threaded); @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau /** * napi_disable - prevent NAPI from scheduling -@@ -3363,6 +3364,7 @@ struct softnet_data { +@@ -3365,6 +3366,7 @@ struct softnet_data { unsigned int processed; unsigned int time_squeeze; unsigned int received_rps; diff --git a/target/linux/generic/pending-5.15/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch b/target/linux/generic/pending-5.15/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch index 8a718a02f21..335a2b04ed9 100644 --- a/target/linux/generic/pending-5.15/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch +++ b/target/linux/generic/pending-5.15/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch @@ -17,7 +17,7 @@ Signed-off-by: Tobias Waldekranz --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c -@@ -6319,6 +6319,7 @@ static int mv88e6xxx_register_switch(str +@@ -6327,6 +6327,7 @@ static int mv88e6xxx_register_switch(str ds->ops = &mv88e6xxx_switch_ops; ds->ageing_time_min = chip->info->age_time_coeff; ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; diff --git a/target/linux/lantiq/patches-5.15/0001-MIPS-lantiq-add-pcie-driver.patch b/target/linux/lantiq/patches-5.15/0001-MIPS-lantiq-add-pcie-driver.patch index ab88b108631..294bafed4a6 100644 --- a/target/linux/lantiq/patches-5.15/0001-MIPS-lantiq-add-pcie-driver.patch +++ b/target/linux/lantiq/patches-5.15/0001-MIPS-lantiq-add-pcie-driver.patch @@ -5479,7 +5479,7 @@ Signed-off-by: John Crispin (transaction layer end-to-end CRC checking). --- a/include/linux/pci.h +++ b/include/linux/pci.h -@@ -1481,6 +1481,8 @@ void pci_walk_bus(struct pci_bus *top, i +@@ -1482,6 +1482,8 @@ void pci_walk_bus(struct pci_bus *top, i void *userdata); int pci_cfg_space_size(struct pci_dev *dev); unsigned char pci_bus_max_busnr(struct pci_bus *bus); From f598880162e83ddc0139e00c5248497d06f5fff7 Mon Sep 17 00:00:00 2001 From: John Audia Date: Wed, 22 Mar 2023 12:07:50 -0400 Subject: [PATCH 14/53] kernel: bump 5.10 to 5.10.176 All patches automatically rebased. Signed-off-by: John Audia --- include/kernel-5.10 | 4 ++-- ...lement-threaded-able-napi-poll-loop-support.patch | 12 ++++++------ ...ysfs-attribute-to-control-napi-threaded-mod.patch | 2 +- ...ace-between-napi-kthread-mode-and-busy-poll.patch | 4 ++-- ...ve-forwarding-path-from-virtual-netdevice-a.patch | 8 ++++---- ...1q-resolve-forwarding-path-for-vlan-devices.patch | 2 +- ...e-resolve-forwarding-path-for-bridge-device.patch | 2 +- ...e-resolve-forwarding-path-for-VLAN-tag-acti.patch | 4 ++-- ...esolve-forwarding-path-for-bridge-pppoe-dev.patch | 4 ++-- ...resolve-forwarding-path-for-dsa-slave-ports.patch | 4 ++-- ...-flowtable-bridge-vlan-hardware-offload-and.patch | 2 +- ...at-IPv4-segment-s-lowest-address-as-unicast.patch | 2 +- .../hack-5.10/721-net-add-packet-mangeling.patch | 8 ++++---- .../680-NET-skip-GRO-for-foreign-MAC-addresses.patch | 2 +- ...net-mtk_eth_soc-implement-flow-offloading-t.patch | 4 ++-- ...fix-dev_fill_forward_path-with-pppoe-bridge.patch | 2 +- .../760-net-dsa-mv88e6xxx-fix-vlan-setup.patch | 2 +- ...e6xxx-Request-assisted-learning-on-CPU-port.patch | 2 +- 18 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/kernel-5.10 b/include/kernel-5.10 index 7488f6c0eb3..61a182a2cd9 100644 --- a/include/kernel-5.10 +++ b/include/kernel-5.10 @@ -1,2 +1,2 @@ -LINUX_VERSION-5.10 = .175 -LINUX_KERNEL_HASH-5.10.175 = e277562e28f234e36665ae12b7585f9557a83a86bc4a8de8840a305af6307bce +LINUX_VERSION-5.10 = .176 +LINUX_KERNEL_HASH-5.10.176 = ce072c60ba04173e05b2a1de3fefdeba5ac8b28b1958d92d21bdbf9b736ef793 diff --git a/target/linux/generic/backport-5.10/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch b/target/linux/generic/backport-5.10/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch index ca8d98b5736..9d5fb6e20ca 100644 --- a/target/linux/generic/backport-5.10/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch +++ b/target/linux/generic/backport-5.10/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch @@ -30,7 +30,7 @@ Signed-off-by: David S. Miller --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -354,6 +354,7 @@ struct napi_struct { +@@ -356,6 +356,7 @@ struct napi_struct { struct list_head dev_list; struct hlist_node napi_hash_node; unsigned int napi_id; @@ -38,7 +38,7 @@ Signed-off-by: David S. Miller }; enum { -@@ -364,6 +365,7 @@ enum { +@@ -366,6 +367,7 @@ enum { NAPI_STATE_LISTED, /* NAPI added to system lists */ NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */ NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */ @@ -46,7 +46,7 @@ Signed-off-by: David S. Miller }; enum { -@@ -374,6 +376,7 @@ enum { +@@ -376,6 +378,7 @@ enum { NAPIF_STATE_LISTED = BIT(NAPI_STATE_LISTED), NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL), NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL), @@ -54,7 +54,7 @@ Signed-off-by: David S. Miller }; enum gro_result { -@@ -504,20 +507,7 @@ static inline bool napi_complete(struct +@@ -506,20 +509,7 @@ static inline bool napi_complete(struct */ void napi_disable(struct napi_struct *n); @@ -76,7 +76,7 @@ Signed-off-by: David S. Miller /** * napi_synchronize - wait until NAPI is not running -@@ -1863,6 +1853,8 @@ enum netdev_ml_priv_type { +@@ -1865,6 +1855,8 @@ enum netdev_ml_priv_type { * * @wol_enabled: Wake-on-LAN is enabled * @@ -85,7 +85,7 @@ Signed-off-by: David S. Miller * @net_notifier_list: List of per-net netdev notifier block * that follow this device when it is moved * to another network namespace. -@@ -2182,6 +2174,7 @@ struct net_device { +@@ -2184,6 +2176,7 @@ struct net_device { struct lock_class_key *qdisc_running_key; bool proto_down; unsigned wol_enabled:1; diff --git a/target/linux/generic/backport-5.10/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch b/target/linux/generic/backport-5.10/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch index fdb06703ee8..05d5f59f807 100644 --- a/target/linux/generic/backport-5.10/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch +++ b/target/linux/generic/backport-5.10/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch @@ -46,7 +46,7 @@ Signed-off-by: David S. Miller + == ================================== --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -498,6 +498,8 @@ static inline bool napi_complete(struct +@@ -500,6 +500,8 @@ static inline bool napi_complete(struct return napi_complete_done(n, 0); } diff --git a/target/linux/generic/backport-5.10/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch b/target/linux/generic/backport-5.10/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch index 1afeb9ddc58..b83078d51c7 100644 --- a/target/linux/generic/backport-5.10/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch +++ b/target/linux/generic/backport-5.10/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch @@ -27,7 +27,7 @@ Cc: Hannes Frederic Sowa --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -366,6 +366,7 @@ enum { +@@ -368,6 +368,7 @@ enum { NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */ NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */ NAPI_STATE_THREADED, /* The poll is performed inside its own thread*/ @@ -35,7 +35,7 @@ Cc: Hannes Frederic Sowa }; enum { -@@ -377,6 +378,7 @@ enum { +@@ -379,6 +380,7 @@ enum { NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL), NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL), NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED), diff --git a/target/linux/generic/backport-5.10/610-v5.13-11-net-resolve-forwarding-path-from-virtual-netdevice-a.patch b/target/linux/generic/backport-5.10/610-v5.13-11-net-resolve-forwarding-path-from-virtual-netdevice-a.patch index 30a183a4a57..b3c0c2e9271 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-11-net-resolve-forwarding-path-from-virtual-netdevice-a.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-11-net-resolve-forwarding-path-from-virtual-netdevice-a.patch @@ -58,7 +58,7 @@ Signed-off-by: Pablo Neira Ayuso --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -848,6 +848,27 @@ typedef u16 (*select_queue_fallback_t)(s +@@ -850,6 +850,27 @@ typedef u16 (*select_queue_fallback_t)(s struct sk_buff *skb, struct net_device *sb_dev); @@ -86,7 +86,7 @@ Signed-off-by: Pablo Neira Ayuso enum tc_setup_type { TC_SETUP_QDISC_MQPRIO, TC_SETUP_CLSU32, -@@ -1294,6 +1315,8 @@ struct netdev_net_notifier { +@@ -1296,6 +1317,8 @@ struct netdev_net_notifier { * struct net_device *(*ndo_get_peer_dev)(struct net_device *dev); * If a device is paired with a peer device, return the peer instance. * The caller must be under RCU read context. @@ -95,7 +95,7 @@ Signed-off-by: Pablo Neira Ayuso */ struct net_device_ops { int (*ndo_init)(struct net_device *dev); -@@ -1502,6 +1525,8 @@ struct net_device_ops { +@@ -1504,6 +1527,8 @@ struct net_device_ops { int (*ndo_tunnel_ctl)(struct net_device *dev, struct ip_tunnel_parm *p, int cmd); struct net_device * (*ndo_get_peer_dev)(struct net_device *dev); @@ -104,7 +104,7 @@ Signed-off-by: Pablo Neira Ayuso }; /** -@@ -2849,6 +2874,8 @@ void dev_remove_offload(struct packet_of +@@ -2851,6 +2876,8 @@ void dev_remove_offload(struct packet_of int dev_get_iflink(const struct net_device *dev); int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb); diff --git a/target/linux/generic/backport-5.10/610-v5.13-12-net-8021q-resolve-forwarding-path-for-vlan-devices.patch b/target/linux/generic/backport-5.10/610-v5.13-12-net-8021q-resolve-forwarding-path-for-vlan-devices.patch index 4da3e388e78..a906dc06ce0 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-12-net-8021q-resolve-forwarding-path-for-vlan-devices.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-12-net-8021q-resolve-forwarding-path-for-vlan-devices.patch @@ -28,7 +28,7 @@ Signed-off-by: Pablo Neira Ayuso --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -850,11 +850,18 @@ typedef u16 (*select_queue_fallback_t)(s +@@ -852,11 +852,18 @@ typedef u16 (*select_queue_fallback_t)(s enum net_device_path_type { DEV_PATH_ETHERNET = 0, diff --git a/target/linux/generic/backport-5.10/610-v5.13-13-net-bridge-resolve-forwarding-path-for-bridge-device.patch b/target/linux/generic/backport-5.10/610-v5.13-13-net-bridge-resolve-forwarding-path-for-bridge-device.patch index d6bbc77abee..f5a6dd6ebc1 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-13-net-bridge-resolve-forwarding-path-for-bridge-device.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-13-net-bridge-resolve-forwarding-path-for-bridge-device.patch @@ -9,7 +9,7 @@ Signed-off-by: Pablo Neira Ayuso --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -851,6 +851,7 @@ typedef u16 (*select_queue_fallback_t)(s +@@ -853,6 +853,7 @@ typedef u16 (*select_queue_fallback_t)(s enum net_device_path_type { DEV_PATH_ETHERNET = 0, DEV_PATH_VLAN, diff --git a/target/linux/generic/backport-5.10/610-v5.13-14-net-bridge-resolve-forwarding-path-for-VLAN-tag-acti.patch b/target/linux/generic/backport-5.10/610-v5.13-14-net-bridge-resolve-forwarding-path-for-VLAN-tag-acti.patch index cf110cd066b..9e62546a6cc 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-14-net-bridge-resolve-forwarding-path-for-VLAN-tag-acti.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-14-net-bridge-resolve-forwarding-path-for-VLAN-tag-acti.patch @@ -15,7 +15,7 @@ Signed-off-by: Pablo Neira Ayuso --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -862,10 +862,20 @@ struct net_device_path { +@@ -864,10 +864,20 @@ struct net_device_path { u16 id; __be16 proto; } encap; @@ -36,7 +36,7 @@ Signed-off-by: Pablo Neira Ayuso struct net_device_path_stack { int num_paths; -@@ -875,6 +885,12 @@ struct net_device_path_stack { +@@ -877,6 +887,12 @@ struct net_device_path_stack { struct net_device_path_ctx { const struct net_device *dev; const u8 *daddr; diff --git a/target/linux/generic/backport-5.10/610-v5.13-15-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch b/target/linux/generic/backport-5.10/610-v5.13-15-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch index 8e76c1fa523..c714ff05841 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-15-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-15-net-ppp-resolve-forwarding-path-for-bridge-pppoe-dev.patch @@ -83,7 +83,7 @@ Signed-off-by: Pablo Neira Ayuso static int pppoe_recvmsg(struct socket *sock, struct msghdr *m, --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -852,6 +852,7 @@ enum net_device_path_type { +@@ -854,6 +854,7 @@ enum net_device_path_type { DEV_PATH_ETHERNET = 0, DEV_PATH_VLAN, DEV_PATH_BRIDGE, @@ -91,7 +91,7 @@ Signed-off-by: Pablo Neira Ayuso }; struct net_device_path { -@@ -861,6 +862,7 @@ struct net_device_path { +@@ -863,6 +864,7 @@ struct net_device_path { struct { u16 id; __be16 proto; diff --git a/target/linux/generic/backport-5.10/610-v5.13-16-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch b/target/linux/generic/backport-5.10/610-v5.13-16-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch index 5c1a0bdf136..a277f0ccf04 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-16-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-16-net-dsa-resolve-forwarding-path-for-dsa-slave-ports.patch @@ -10,7 +10,7 @@ Signed-off-by: Pablo Neira Ayuso --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -853,6 +853,7 @@ enum net_device_path_type { +@@ -855,6 +855,7 @@ enum net_device_path_type { DEV_PATH_VLAN, DEV_PATH_BRIDGE, DEV_PATH_PPPOE, @@ -18,7 +18,7 @@ Signed-off-by: Pablo Neira Ayuso }; struct net_device_path { -@@ -873,6 +874,10 @@ struct net_device_path { +@@ -875,6 +876,10 @@ struct net_device_path { u16 vlan_id; __be16 vlan_proto; } bridge; diff --git a/target/linux/generic/backport-5.10/610-v5.13-27-netfilter-flowtable-bridge-vlan-hardware-offload-and.patch b/target/linux/generic/backport-5.10/610-v5.13-27-netfilter-flowtable-bridge-vlan-hardware-offload-and.patch index 37f9033b112..08c92d731a3 100644 --- a/target/linux/generic/backport-5.10/610-v5.13-27-netfilter-flowtable-bridge-vlan-hardware-offload-and.patch +++ b/target/linux/generic/backport-5.10/610-v5.13-27-netfilter-flowtable-bridge-vlan-hardware-offload-and.patch @@ -12,7 +12,7 @@ Signed-off-by: Pablo Neira Ayuso --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -870,6 +870,7 @@ struct net_device_path { +@@ -872,6 +872,7 @@ struct net_device_path { DEV_PATH_BR_VLAN_KEEP, DEV_PATH_BR_VLAN_TAG, DEV_PATH_BR_VLAN_UNTAG, diff --git a/target/linux/generic/backport-5.10/615-v5.14-ip-Treat-IPv4-segment-s-lowest-address-as-unicast.patch b/target/linux/generic/backport-5.10/615-v5.14-ip-Treat-IPv4-segment-s-lowest-address-as-unicast.patch index 8aabbe28599..76e50d15eb2 100644 --- a/target/linux/generic/backport-5.10/615-v5.14-ip-Treat-IPv4-segment-s-lowest-address-as-unicast.patch +++ b/target/linux/generic/backport-5.10/615-v5.14-ip-Treat-IPv4-segment-s-lowest-address-as-unicast.patch @@ -18,7 +18,7 @@ Link: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c -@@ -1129,10 +1129,8 @@ void fib_add_ifaddr(struct in_ifaddr *if +@@ -1132,10 +1132,8 @@ void fib_add_ifaddr(struct in_ifaddr *if prefix, ifa->ifa_prefixlen, prim, ifa->ifa_rt_priority); diff --git a/target/linux/generic/hack-5.10/721-net-add-packet-mangeling.patch b/target/linux/generic/hack-5.10/721-net-add-packet-mangeling.patch index df58bf4bd7f..a80ce4baae8 100644 --- a/target/linux/generic/hack-5.10/721-net-add-packet-mangeling.patch +++ b/target/linux/generic/hack-5.10/721-net-add-packet-mangeling.patch @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -1646,6 +1646,7 @@ enum netdev_priv_flags { +@@ -1648,6 +1648,7 @@ enum netdev_priv_flags { IFF_FAILOVER_SLAVE = 1<<28, IFF_L3MDEV_RX_HANDLER = 1<<29, IFF_LIVE_RENAME_OK = 1<<30, @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau }; #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN -@@ -1678,6 +1679,7 @@ enum netdev_priv_flags { +@@ -1680,6 +1681,7 @@ enum netdev_priv_flags { #define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE #define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER #define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK @@ -35,7 +35,7 @@ Signed-off-by: Felix Fietkau /* Specifies the type of the struct net_device::ml_priv pointer */ enum netdev_ml_priv_type { -@@ -2018,6 +2020,11 @@ struct net_device { +@@ -2020,6 +2022,11 @@ struct net_device { const struct tlsdev_ops *tlsdev_ops; #endif @@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau const struct header_ops *header_ops; unsigned int flags; -@@ -2108,6 +2115,10 @@ struct net_device { +@@ -2110,6 +2117,10 @@ struct net_device { struct mpls_dev __rcu *mpls_ptr; #endif diff --git a/target/linux/generic/pending-5.10/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/pending-5.10/680-NET-skip-GRO-for-foreign-MAC-addresses.patch index d990cee90b0..12a7fb5a7d6 100644 --- a/target/linux/generic/pending-5.10/680-NET-skip-GRO-for-foreign-MAC-addresses.patch +++ b/target/linux/generic/pending-5.10/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -2057,6 +2057,8 @@ struct net_device { +@@ -2059,6 +2059,8 @@ struct net_device { struct netdev_hw_addr_list mc; struct netdev_hw_addr_list dev_addrs; diff --git a/target/linux/generic/pending-5.10/701-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch b/target/linux/generic/pending-5.10/701-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch index a31929d58a8..b9c6d4378a1 100644 --- a/target/linux/generic/pending-5.10/701-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch +++ b/target/linux/generic/pending-5.10/701-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch @@ -233,7 +233,7 @@ Signed-off-by: Felix Fietkau static inline void --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -854,6 +854,7 @@ enum net_device_path_type { +@@ -856,6 +856,7 @@ enum net_device_path_type { DEV_PATH_BRIDGE, DEV_PATH_PPPOE, DEV_PATH_DSA, @@ -241,7 +241,7 @@ Signed-off-by: Felix Fietkau }; struct net_device_path { -@@ -879,6 +880,12 @@ struct net_device_path { +@@ -881,6 +882,12 @@ struct net_device_path { int port; u16 proto; } dsa; diff --git a/target/linux/generic/pending-5.10/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch b/target/linux/generic/pending-5.10/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch index 1a1f6ab412f..c0660e50c4e 100644 --- a/target/linux/generic/pending-5.10/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch +++ b/target/linux/generic/pending-5.10/704-02-net-fix-dev_fill_forward_path-with-pppoe-bridge.patch @@ -40,7 +40,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -899,7 +899,7 @@ struct net_device_path_stack { +@@ -901,7 +901,7 @@ struct net_device_path_stack { struct net_device_path_ctx { const struct net_device *dev; diff --git a/target/linux/generic/pending-5.10/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch b/target/linux/generic/pending-5.10/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch index fff817dd8c1..a9c2f7ed129 100644 --- a/target/linux/generic/pending-5.10/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch +++ b/target/linux/generic/pending-5.10/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch @@ -17,7 +17,7 @@ Signed-off-by: DENG Qingfang --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c -@@ -2921,6 +2921,7 @@ static int mv88e6xxx_setup(struct dsa_sw +@@ -2929,6 +2929,7 @@ static int mv88e6xxx_setup(struct dsa_sw chip->ds = ds; ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); diff --git a/target/linux/generic/pending-5.10/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch b/target/linux/generic/pending-5.10/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch index 80e2b481bf5..10781da152c 100644 --- a/target/linux/generic/pending-5.10/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch +++ b/target/linux/generic/pending-5.10/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch @@ -17,7 +17,7 @@ Signed-off-by: Tobias Waldekranz --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c -@@ -5490,6 +5490,7 @@ static int mv88e6xxx_register_switch(str +@@ -5498,6 +5498,7 @@ static int mv88e6xxx_register_switch(str ds->ops = &mv88e6xxx_switch_ops; ds->ageing_time_min = chip->info->age_time_coeff; ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; From 1558bbd116ec74b10672caa29c17a5f0279715f7 Mon Sep 17 00:00:00 2001 From: Oskari Rauta Date: Sun, 19 Mar 2023 19:39:25 +0200 Subject: [PATCH 15/53] util-linux: add rev utility package I found use for this in my scripts; I noticed that it is already compiled with util-linux - there just isn't package for it - let's package it then. Description: The rev utility copies the specified files to the standard output, reversing the order of characters in everyline. Signed-off-by: Oskari Rauta --- package/utils/util-linux/Makefile | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/package/utils/util-linux/Makefile b/package/utils/util-linux/Makefile index 21764a2d270..1ae6bb7b2d8 100644 --- a/package/utils/util-linux/Makefile +++ b/package/utils/util-linux/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=util-linux PKG_VERSION:=2.38.1 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/utils/$(PKG_NAME)/v2.38 @@ -415,6 +415,17 @@ define Package/rename/description expression in their name by replacement endef +define Package/rev +$(call Package/util-linux/Default) + TITLE:=Reverse lines characterwise +endef + +define Package/rev/description + rev utility copies the specified files to the standard output, reversing the + order of characters in every line. If no files are specified, the standard + input is read. +endef + define Package/partx-utils $(call Package/util-linux/Default) TITLE:=inform kernel about the presence and numbering of on-disk partitions @@ -804,6 +815,11 @@ define Package/rename/install $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/rename $(1)/usr/bin/ endef +define Package/rev/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/rev $(1)/usr/bin/ +endef + define Package/partx-utils/install $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/partx $(1)/usr/sbin/ @@ -904,6 +920,7 @@ $(eval $(call BuildPackage,namei)) $(eval $(call BuildPackage,nsenter)) $(eval $(call BuildPackage,prlimit)) $(eval $(call BuildPackage,rename)) +$(eval $(call BuildPackage,rev)) $(eval $(call BuildPackage,partx-utils)) $(eval $(call BuildPackage,script-utils)) $(eval $(call BuildPackage,setterm)) From 8634c1080d5033e8cf0069ee7447821726232b95 Mon Sep 17 00:00:00 2001 From: Jeff Kletsky Date: Tue, 3 Jan 2023 23:17:03 -0800 Subject: [PATCH 16/53] ipq40xx: Fix Linksys upgrade, restore config step It appears that the refactor of the upgrade process for NAND devices resulted in the nand_do_upgrade_success step not being called for devices using the linksys.sh script. As a result, configuration was not preserved over sysupgrade steps. This was restored for some devices in commit 84ff6c90dda1 ("base-files: bring back nand_do_upgrade_success"). This restored preservation of config for ipq40xx devices using the linksys.sh script. Other devices and targets have not been examined. Closes: #11677 Fixes: e25e6d8e54 ("base-files: fix and clean up nand sysupgrade code") Tested-on: EA8300 Signed-off-by: Jeff Kletsky (checkpatch nitpick) Signed-off-by: Christian Lamparter --- target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh b/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh index c0d45d640dd..696f653eb9e 100644 --- a/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh +++ b/target/linux/ipq40xx/base-files/lib/upgrade/linksys.sh @@ -100,7 +100,12 @@ platform_do_upgrade_linksys() { fi # complete std upgrade - nand_upgrade_tar "$1" + if nand_upgrade_tar "$1" ; then + nand_do_upgrade_success + else + nand_do_upgrade_failure + fi + } [ "$magic_long" = "27051956" ] && { From 4ca858f1a082414bf7ace719c1b61ae54fd8e015 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 2 Jan 2023 11:04:11 +0100 Subject: [PATCH 17/53] apm821xx: Migrate to libdeflate libdeflate's gzip compressor provides a better compression ratio and uboot's decompressor has no problem with the data streams. Tested on MX60, WNDR4700, WNDAP660 Signed-off-by: Christian Lamparter --- target/linux/apm821xx/image/nand.mk | 6 +++--- target/linux/apm821xx/image/sata.mk | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target/linux/apm821xx/image/nand.mk b/target/linux/apm821xx/image/nand.mk index db3c9c07228..1d28df98e51 100644 --- a/target/linux/apm821xx/image/nand.mk +++ b/target/linux/apm821xx/image/nand.mk @@ -51,7 +51,7 @@ define Device/meraki_mx60 IMAGES := sysupgrade.bin DTB_SIZE := 20480 IMAGE_SIZE := 1021m - KERNEL := kernel-bin | gzip | dtb | MuImage-initramfs gzip + KERNEL := kernel-bin | libdeflate-gzip | dtb | MuImage-initramfs gzip IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata UBINIZE_OPTS := -E 5 DEVICE_COMPAT_VERSION := 2.0 @@ -70,7 +70,7 @@ define Device/netgear_wndap6x0 IMAGE_SIZE := 27392k IMAGES := sysupgrade.bin factory.img KERNEL_SIZE := 6080k - KERNEL := dtb | kernel-bin | gzip | MuImage-initramfs gzip + KERNEL := dtb | kernel-bin | libdeflate-gzip | MuImage-initramfs gzip IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata IMAGE/factory.img := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi UBINIZE_OPTS := -E 5 @@ -114,7 +114,7 @@ define Device/netgear_wndr4700 # CHECK_DNI_FIRMWARE_ROOTFS_INTEGRITY in do_chk_dniimg() KERNEL := kernel-bin | lzma -d16 | uImage lzma | pad-offset $$(BLOCKSIZE) 64 | \ append-uImage-fakehdr filesystem | dtb | create-uImage-dtb | prepend-dtb - KERNEL_INITRAMFS := kernel-bin | gzip | dtb | MuImage-initramfs gzip + KERNEL_INITRAMFS := kernel-bin | libdeflate-gzip | dtb | MuImage-initramfs gzip IMAGE/factory.img := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi | \ netgear-dni | check-size IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata diff --git a/target/linux/apm821xx/image/sata.mk b/target/linux/apm821xx/image/sata.mk index 89af488e097..8a9bd579881 100644 --- a/target/linux/apm821xx/image/sata.mk +++ b/target/linux/apm821xx/image/sata.mk @@ -12,14 +12,14 @@ define Device/wd_mybooklive SUPPORTED_DEVICES += mbl wd,mybooklive-duo BLOCKSIZE := 1k DTB_SIZE := 16384 - KERNEL := kernel-bin | dtb | gzip | uImage gzip - KERNEL_INITRAMFS := kernel-bin | gzip | dtb | MuImage-initramfs gzip + KERNEL := kernel-bin | dtb | libdeflate-gzip | uImage gzip + KERNEL_INITRAMFS := kernel-bin | libdeflate-gzip | dtb | MuImage-initramfs gzip IMAGES := factory.img.gz sysupgrade.img.gz ARTIFACTS := apollo3g.dtb DEVICE_DTB := apollo3g.dtb FILESYSTEMS := ext4 squashfs - IMAGE/factory.img.gz := boot-script | boot-img | hdd-img | gzip - IMAGE/sysupgrade.img.gz := boot-script | boot-img | hdd-img | gzip | append-metadata + IMAGE/factory.img.gz := boot-script | boot-img | hdd-img | libdeflate-gzip + IMAGE/sysupgrade.img.gz := boot-script | boot-img | hdd-img | libdeflate-gzip | append-metadata ARTIFACT/apollo3g.dtb := export-dtb endef From c2d1c32d1ef7f2797aa424a6c94d143e9ddaddc8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 13 Mar 2023 22:49:50 +0100 Subject: [PATCH 18/53] lantiq: xrx200: convert FritzBox 7360v2's wifi to nvmem this was thoroughly tested (warm and cold boots). on a real 7360v2. This is because there have been documented hick-ups with other lantiq devices that need the owl-loader too. It's likely that the 7360(sl) could be converted in the same way as well. However the 7362sl uses a reversed caldata format, so the "qca,no-eeprom" stays in place. The patch also moves the urloader nvmem partition definition into the partition section. Signed-off-by: Christian Lamparter --- .../boot/dts/lantiq/vr9_avm_fritz7360-v2.dts | 24 ++++++++++++------- .../boot/dts/lantiq/vr9_avm_fritz736x.dtsi | 2 +- .../etc/hotplug.d/firmware/12-ath9k-eeprom | 3 +-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz7360-v2.dts b/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz7360-v2.dts index 063d6dca5e0..a30746cde2b 100644 --- a/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz7360-v2.dts +++ b/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz7360-v2.dts @@ -42,6 +42,18 @@ label = "urlader"; reg = <0x00000 0x20000>; read-only; + + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + cal_urlader_985: cal@985 { + reg = <0x985 0x440>; + }; + + macaddr_urlader_a91: macaddr@a91 { + reg = <0xa91 0x6>; + }; }; partition@20000 { @@ -78,12 +90,8 @@ reset-gpios = <&gpio 44 GPIO_ACTIVE_LOW>; }; -&urlader { - compatible = "nvmem-cells"; - #address-cells = <1>; - #size-cells = <1>; - - macaddr_urlader_a91: macaddr@a91 { - reg = <0xa91 0x6>; - }; +&wifi { + /delete-property/ qca,no-eeprom; + nvmem-cells = <&cal_urlader_985>; + nvmem-cell-names = "calibration"; }; diff --git a/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi b/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi index 73f6e152bfa..7324127d2a8 100644 --- a/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi +++ b/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi @@ -151,7 +151,7 @@ #address-cells = <2>; device_type = "pci"; - wifi@168c,002e { + wifi: wifi@168c,002e { compatible = "pci168c,002e"; reg = <0 0 0 0 0>; qca,no-eeprom; /* load from ath9k-eeprom-pci-0000:01:00.0.bin */ diff --git a/target/linux/lantiq/xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom b/target/linux/lantiq/xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom index c6bacb8d3c1..eefc39b30b4 100644 --- a/target/linux/lantiq/xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom +++ b/target/linux/lantiq/xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom @@ -19,8 +19,7 @@ case "$FIRMWARE" in avm,fritz3390) caldata_extract_reverse "urlader" 0x2546 0x440 ;; - avm,fritz7360sl|\ - avm,fritz7360-v2) + avm,fritz7360sl) caldata_extract "urlader" 0x985 0x1000 ;; avm,fritz7412|\ From de3d60b982c7b8e1821b90b312db57287e74ede3 Mon Sep 17 00:00:00 2001 From: Edward Chow Date: Sun, 20 Nov 2022 13:49:45 +0800 Subject: [PATCH 19/53] ath79: calibrate dlink dir-825 b1 with nvmem Driver for both soc (2.4GHz Wifi) and pci (5 GHz) now pull the calibration data from the nvmem subsystem. This allows us to move the userspace caldata extraction for the pci-e ath9k supported wifi into the device-tree definition of the device. Currently, only ethernet devices uses the mac address of "mac-address-ascii" cells, while PCI ath9k devices uses the mac address within calibration data. Signed-off-by: Edward Chow (restored switch configuration in 02_network, integrated caldata into partition) Signed-off-by: Christian Lamparter --- .../ath79/dts/ar7161_dlink_dir-825-b1.dts | 33 +++++++++++++++++-- .../generic/base-files/etc/board.d/02_network | 1 - .../etc/hotplug.d/firmware/10-ath9k-eeprom | 2 -- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/target/linux/ath79/dts/ar7161_dlink_dir-825-b1.dts b/target/linux/ath79/dts/ar7161_dlink_dir-825-b1.dts index 6934a8f952b..0e39be7d0bb 100644 --- a/target/linux/ath79/dts/ar7161_dlink_dir-825-b1.dts +++ b/target/linux/ath79/dts/ar7161_dlink_dir-825-b1.dts @@ -139,7 +139,8 @@ ath9k0: wifi@0,11 { compatible = "pci168c,0029"; reg = <0x8800 0 0 0 0>; - qca,no-eeprom; + nvmem-cells = <&macaddr_lan>, <&cal_art_1000>; + nvmem-cell-names = "mac-address-ascii", "calibration"; #gpio-cells = <2>; gpio-controller; }; @@ -147,7 +148,9 @@ ath9k1: wifi@0,12 { compatible = "pci168c,0029"; reg = <0x9000 0 0 0 0>; - qca,no-eeprom; + nvmem-cells = <&macaddr_wan>, <&cal_art_5000>; + nvmem-cell-names = "mac-address-ascii", "calibration"; + mac-address-increment = <1>; #gpio-cells = <2>; gpio-controller; }; @@ -184,9 +187,28 @@ }; partition@660000 { + compatible = "nvmem-cells"; label = "caldata"; reg = <0x660000 0x010000>; read-only; + #address-cells = <1>; + #size-cells = <1>; + + cal_art_1000: cal@1000 { + reg = <0x1000 0xeb8>; + }; + + cal_art_5000: cal@5000 { + reg = <0x5000 0xeb8>; + }; + + macaddr_lan: macaddr@ffa0 { + reg = <0xffa0 0x11>; + }; + + macaddr_wan: macaddr@ffb4 { + reg = <0xffb4 0x11>; + }; }; fwconcat1: partition@670000 { @@ -202,6 +224,9 @@ pll-data = <0x11110000 0x00001099 0x00991099>; + nvmem-cells = <&macaddr_lan>; + nvmem-cell-names = "mac-address-ascii"; + fixed-link { speed = <1000>; full-duplex; @@ -213,5 +238,9 @@ pll-data = <0x11110000 0x00001099 0x00991099>; + nvmem-cells = <&macaddr_wan>; + nvmem-cell-names = "mac-address-ascii"; + phy-handle = <&phy4>; }; + diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index 31ea891d572..1e439b1e2f4 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -634,7 +634,6 @@ ath79_setup_macs() dlink,dir-629-a1) wan_mac=$(mtd_get_mac_text "mfcdata" 0x6a) ;; - dlink,dir-825-b1|\ trendnet,tew-673gru) lan_mac=$(mtd_get_mac_text "caldata" 0xffa0) wan_mac=$(mtd_get_mac_text "caldata" 0xffb4) diff --git a/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom b/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom index 9827508c04a..022f5e29477 100644 --- a/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom +++ b/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom @@ -124,7 +124,6 @@ case "$FIRMWARE" in buffalo,wzr-hp-ag300h) caldata_extract "art" 0x1000 0xeb8 ;; - dlink,dir-825-b1|\ trendnet,tew-673gru) caldata_extract "caldata" 0x1000 0xeb8 ath9k_patch_mac_crc $(mtd_get_mac_text "caldata" 0xffa0) 0x20c @@ -143,7 +142,6 @@ case "$FIRMWARE" in buffalo,wzr-hp-ag300h) caldata_extract "art" 0x5000 0xeb8 ;; - dlink,dir-825-b1|\ trendnet,tew-673gru) caldata_extract "caldata" 0x5000 0xeb8 ath9k_patch_mac_crc $(macaddr_add $(mtd_get_mac_text "caldata" 0xffb4) 1) 0x20c From 3ab670b24eee8adef77a71d9d11ee362c1668b26 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 26 Mar 2023 17:19:03 +0200 Subject: [PATCH 20/53] mac80211: fix receiving mesh packets in forwarding=0 networks When forwarding is set to 0, frames are typically sent with ttl=1. Move the ttl decrement check below the check for local receive in order to fix packet drops. Signed-off-by: Felix Fietkau --- ...x-receiving-mesh-packets-in-forwardi.patch | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 package/kernel/mac80211/patches/subsys/329-wifi-mac80211-fix-receiving-mesh-packets-in-forwardi.patch diff --git a/package/kernel/mac80211/patches/subsys/329-wifi-mac80211-fix-receiving-mesh-packets-in-forwardi.patch b/package/kernel/mac80211/patches/subsys/329-wifi-mac80211-fix-receiving-mesh-packets-in-forwardi.patch new file mode 100644 index 00000000000..6882694da8e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/329-wifi-mac80211-fix-receiving-mesh-packets-in-forwardi.patch @@ -0,0 +1,50 @@ +From: Felix Fietkau +Date: Sun, 26 Mar 2023 17:11:34 +0200 +Subject: [PATCH] wifi: mac80211: fix receiving mesh packets in forwarding=0 + networks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When forwarding is set to 0, frames are typically sent with ttl=1. +Move the ttl decrement check below the check for local receive in order to +fix packet drops. + +Reported-by: Thomas Hühn +Reported-by: Nick Hainke +Fixes: 986e43b19ae9 ("wifi: mac80211: fix receiving A-MSDU frames on mesh interfaces") +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2828,14 +2828,6 @@ ieee80211_rx_mesh_data(struct ieee80211_ + if (sdata->crypto_tx_tailroom_needed_cnt) + tailroom = IEEE80211_ENCRYPT_TAILROOM; + +- if (!--mesh_hdr->ttl) { +- if (multicast) +- goto rx_accept; +- +- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); +- return RX_DROP_MONITOR; +- } +- + if (mesh_hdr->flags & MESH_FLAGS_AE) { + struct mesh_path *mppath; + char *proxied_addr; +@@ -2874,6 +2866,14 @@ ieee80211_rx_mesh_data(struct ieee80211_ + if (ether_addr_equal(sdata->vif.addr, eth->h_dest)) + goto rx_accept; + ++ if (!--mesh_hdr->ttl) { ++ if (multicast) ++ goto rx_accept; ++ ++ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); ++ return RX_DROP_MONITOR; ++ } ++ + if (!ifmsh->mshcfg.dot11MeshForwarding) { + if (is_multicast_ether_addr(eth->h_dest)) + goto rx_accept; From 212632540043cc9b911c2efb86156479f2710836 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Sun, 26 Mar 2023 23:50:43 +0800 Subject: [PATCH 21/53] ramips: fix 5g mac for TOTOLINK X5000R There's no valid mac address for the second band in the eeprom. The vendor fw uses 2.4G mac + 4 as the mac for 5G radio. Do the same in our firmware. Fixes: 23be410b3d ("ramips: add support for TOTOLINK X5000R") Signed-off-by: Chuanhong Guo --- .../mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac b/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac index b23464bebec..b3de1f39cf0 100644 --- a/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac +++ b/target/linux/ramips/mt7621/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac @@ -152,6 +152,10 @@ case "$board" in hw_mac_addr="$(mtd_get_mac_binary factory 0x4)" [ "$PHYNBR" = "1" ] && macaddr_add $hw_mac_addr "0x100000" > /sys${DEVPATH}/macaddress ;; + totolink,x5000r) + hw_mac_addr="$(mtd_get_mac_binary factory 0x4)" + [ "$PHYNBR" = "1" ] && macaddr_add $hw_mac_addr 4 > /sys${DEVPATH}/macaddress + ;; tplink,eap615-wall-v1) hw_mac_addr="$(mtd_get_mac_binary product-info 0x8)" macaddr_add "$hw_mac_addr" "$PHYNBR" > "/sys${DEVPATH}/macaddress" From 88d76bb455c8fdb525ac2495feda71c14a558296 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Tue, 21 Mar 2023 16:50:56 +0800 Subject: [PATCH 22/53] ramips: mt7621: enable unused PCIe port to fix potential boot failure One user reported that his SIMAX1800T couldn't boot like the others. After debugging, I found that this was caused by the disabled PCIe port. I cannot reproduce this issue on my SIMAX1800T. But when I disabled pcie2 on the ASUS RT-AC57U, I got the same result. It seems that disabling these unused PCIe ports on some mt7621 revisions will cause PCIe to fail to initialize. So we'd better to re-enable them on all related mt7621 devices. Signed-off-by: Shiji Yang --- target/linux/ramips/dts/mt7621_h3c_tx180x.dtsi | 4 ---- target/linux/ramips/dts/mt7621_haier-sim_wr1800k.dtsi | 4 ---- target/linux/ramips/dts/mt7621_netgear_wax202.dts | 4 ---- target/linux/ramips/dts/mt7621_tplink_eap615-wall-v1.dts | 4 ---- 4 files changed, 16 deletions(-) diff --git a/target/linux/ramips/dts/mt7621_h3c_tx180x.dtsi b/target/linux/ramips/dts/mt7621_h3c_tx180x.dtsi index 54d7908e406..fe374bfa6b0 100644 --- a/target/linux/ramips/dts/mt7621_h3c_tx180x.dtsi +++ b/target/linux/ramips/dts/mt7621_h3c_tx180x.dtsi @@ -138,10 +138,6 @@ }; }; -&pcie2 { - status = "disabled"; -}; - &state_default { gpio { groups = "jtag"; diff --git a/target/linux/ramips/dts/mt7621_haier-sim_wr1800k.dtsi b/target/linux/ramips/dts/mt7621_haier-sim_wr1800k.dtsi index a272d1ad755..4dd6f3b0ae5 100644 --- a/target/linux/ramips/dts/mt7621_haier-sim_wr1800k.dtsi +++ b/target/linux/ramips/dts/mt7621_haier-sim_wr1800k.dtsi @@ -152,10 +152,6 @@ }; }; -&pcie2 { - status = "disabled"; -}; - &state_default { gpio { groups = "i2c", "uart3", "wdt"; diff --git a/target/linux/ramips/dts/mt7621_netgear_wax202.dts b/target/linux/ramips/dts/mt7621_netgear_wax202.dts index 02f540d7431..fbe17ef0d38 100644 --- a/target/linux/ramips/dts/mt7621_netgear_wax202.dts +++ b/target/linux/ramips/dts/mt7621_netgear_wax202.dts @@ -217,10 +217,6 @@ }; }; -&pcie2 { - status = "disabled"; -}; - &state_default { gpio { groups = "uart3", "uart2", "jtag", "wdt"; diff --git a/target/linux/ramips/dts/mt7621_tplink_eap615-wall-v1.dts b/target/linux/ramips/dts/mt7621_tplink_eap615-wall-v1.dts index 36809d48ff2..58e4bbf7574 100644 --- a/target/linux/ramips/dts/mt7621_tplink_eap615-wall-v1.dts +++ b/target/linux/ramips/dts/mt7621_tplink_eap615-wall-v1.dts @@ -148,10 +148,6 @@ }; }; -&pcie2 { - status = "disabled"; -}; - &gmac0 { nvmem-cells = <&macaddr_info_8>; nvmem-cell-names = "mac-address"; From 12f52336d2b18951d883af07f398fc9697adba24 Mon Sep 17 00:00:00 2001 From: Martin Kennedy Date: Sun, 18 Sep 2022 12:15:57 -0400 Subject: [PATCH 23/53] ath79: Add Aruba AP-175 support This board is very similar to the Aruba AP-105, but is outdoor-first. It is very similar to the MSR2000 (though certain MSR2000 models have a different PHY[^1]). A U-Boot replacement is required to install OpenWrt on these devices[^2]. Specifications -------------- * Device: Aruba AP-175 * SoC: Atheros AR7161 680 MHz MIPS * RAM: 128MB - 2x Mira P3S12D40ETP * Flash: 16MB MXIC MX25L12845EMI-10G (SPI-NOR) * WiFi: 2 x DNMA-H92 Atheros AR9220-AC1A 802.11abgn * ETH: IC+ IP1001 Gigabit + PoE PHY * LED: 2x int., plus 12 ext. on TCA6416 GPIO expander * Console: CP210X linking USB-A Port to CPU console @ 115200 * RTC: DS1374C, with internal battery * Temp: LM75 temperature sensor Factory installation: - Needs a u-boot replacement. The process is almost identical to that of the AP105, except that the case is easier to open, and that you need to compile u-boot from a slightly different branch: https://github.com/Hurricos/u-boot-ap105/tree/ap175 The instructions for performing an in-circuit reflash with an SPI-Flasher like a CH314A can be found on the OpenWrt Wiki (https://openwrt.org/toh/aruba/ap-105); in addition a detailed guide may be found on YouTube[^3]. - Once u-boot has been replaced, a USB-A-to-A cable may be used to connect your PC to the CP210X inside the AP at 115200 baud; at this point, the normal u-boot serial flashing procedure will work (set up networking; tftpboot and boot an OpenWrt initramfs; sysupgrade to OpenWrt proper.) - There is no built-in functionality to revert back to stock firmware, because the AP-175 has been declared by the vendor[^4] end-of-life as of 31 Jul 2020. If for some reason you wish to return to stock firmware, take a backup of the 16MiB flash before flashing u-boot. [^1]: https://github.com/shalzz/aruba-ap-310/blob/master/platform/bootloader/apboot-11n/include/configs/msr2k.h#L186 [^2]: https://github.com/Hurricos/u-boot-ap105/tree/ap175 [^3]: https://www.youtube.com/watch?v=Vof__dPiprs [^4]: https://www.arubanetworks.com/support-services/end-of-life/#product=access-points&version=0 Signed-off-by: Martin Kennedy --- package/boot/uboot-envtools/files/ath79 | 22 +- .../linux/ath79/dts/ar7161_aruba_ap-175.dts | 244 ++++++++++++++++++ .../generic/base-files/etc/board.d/02_network | 1 + target/linux/ath79/image/generic.mk | 9 + 4 files changed, 266 insertions(+), 10 deletions(-) create mode 100644 target/linux/ath79/dts/ar7161_aruba_ap-175.dts diff --git a/package/boot/uboot-envtools/files/ath79 b/package/boot/uboot-envtools/files/ath79 index b968fa8fdec..c7049f70292 100644 --- a/package/boot/uboot-envtools/files/ath79 +++ b/package/boot/uboot-envtools/files/ath79 @@ -88,6 +88,18 @@ ziking,cpe46b|\ zyxel,nbg6616) ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000" ;; +aruba,ap-105|\ +aruba,ap-175|\ +dongwon,dw02-412h-64m|\ +dongwon,dw02-412h-128m|\ +glinet,gl-ar300m-lite|\ +glinet,gl-ar300m-nand|\ +glinet,gl-ar300m-nor|\ +glinet,gl-ar300m16) + idx="$(find_mtd_index u-boot-env)" + [ -n "$idx" ] && \ + ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x10000" + ;; buffalo,wzr-hp-ag300h) ubootenv_add_uci_config "/dev/mtd3" "0x0" "0x10000" "0x10000" ;; @@ -99,16 +111,6 @@ linksys,ea4500-v3) domywifi,dw33d) ubootenv_add_uci_config "/dev/mtd4" "0x0" "0x10000" "0x10000" ;; -dongwon,dw02-412h-64m|\ -dongwon,dw02-412h-128m|\ -glinet,gl-ar300m-lite|\ -glinet,gl-ar300m-nand|\ -glinet,gl-ar300m-nor|\ -glinet,gl-ar300m16) - idx="$(find_mtd_index u-boot-env)" - [ -n "$idx" ] && \ - ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x10000" - ;; glinet,gl-ar150) ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x8000" "0x10000" ;; diff --git a/target/linux/ath79/dts/ar7161_aruba_ap-175.dts b/target/linux/ath79/dts/ar7161_aruba_ap-175.dts new file mode 100644 index 00000000000..dd29a687ba0 --- /dev/null +++ b/target/linux/ath79/dts/ar7161_aruba_ap-175.dts @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "ar7100.dtsi" + +#include +#include + +/ { + compatible = "aruba,ap-175", "qca,ar7161"; + model = "Aruba AP-175"; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + aliases { + led-boot = &led_power_amber; + led-failsafe = &led_power_amber; + led-upgrade = &led_power_amber; + label-mac-device = ð0; + }; + + leds { + compatible = "gpio-leds"; + + /* These internal LEDs cannot be seen when case is closed */ + internal_2g_green { + label = "green:internal_2g"; + gpios = <&gpio 3 GPIO_ACTIVE_HIGH>; + }; + + internal_5g_green { + label = "green:internal_5g"; + gpios = <&gpio 4 GPIO_ACTIVE_HIGH>; + }; + + /* These external LEDs are visible from the bottom panel */ + + led_power_amber: power_amber { + label = "amber:power"; + gpios = <&gpio_ext 5 GPIO_ACTIVE_HIGH>; + panic-indicator; + }; + + r1_act_blue { + label = "blue:r1_act"; + gpios = <&gpio_ext 0 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy1tpt"; + }; + + r1_rssi1_blue { + label = "blue:r1_rssi1"; + gpios = <&gpio_ext 1 GPIO_ACTIVE_HIGH>; + }; + + r1_rssi2_blue { + label = "blue:r1_rssi2"; + gpios = <&gpio_ext 2 GPIO_ACTIVE_HIGH>; + }; + + r1_rssi3_blue { + label = "blue:r1_rssi3"; + gpios = <&gpio_ext 3 GPIO_ACTIVE_HIGH>; + }; + + r1_rssi4_blue { + label = "blue:r1_rssi4"; + gpios = <&gpio_ext 4 GPIO_ACTIVE_HIGH>; + }; + + r0_act_amber { + label = "amber:r0_act"; + gpios = <&gpio_ext 8 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tpt"; + }; + + r0_rssi1_amber { + label = "amber:r0_rssi1"; + gpios = <&gpio_ext 9 GPIO_ACTIVE_HIGH>; + }; + + r0_rssi2_amber { + label = "amber:r0_rssi2"; + gpios = <&gpio_ext 10 GPIO_ACTIVE_HIGH>; + }; + + r0_rssi3_amber { + label = "amber:r0_rssi3"; + gpios = <&gpio_ext 11 GPIO_ACTIVE_HIGH>; + }; + + r0_rssi4_amber { + label = "amber:r0_rssi4"; + gpios = <&gpio_ext 12 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + linux,code = ; + gpios = <&gpio 6 GPIO_ACTIVE_LOW>; + }; + }; + + i2c0: i2c { + compatible = "i2c-gpio"; + i2c-gpio,delay-us = <10>; + i2c-gpio,timeout-ms = <1>; + sda-gpios = <&gpio 1 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio 2 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&pcie0 { + status = "okay"; + + ath9k0: wifi@0,11 { + compatible = "pci168c,0029"; + nvmem-cells = <&macaddr_hwinfo_1c>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <1>; + reg = <0x8800 0 0 0 0>; + #gpio-cells = <2>; + gpio-controller; + }; + + ath9k1: wifi@0,12 { + compatible = "pci168c,0029"; + nvmem-cells = <&macaddr_hwinfo_1c>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <2>; + reg = <0x9000 0 0 0 0>; + #gpio-cells = <2>; + gpio-controller; + }; +}; + +&mdio0 { + status = "okay"; + + phy1: ethernet-phy@1 { + reg = <0x1>; + }; +}; + +ð0 { + status = "okay"; + nvmem-cells = <&macaddr_hwinfo_1c>; + nvmem-cell-names = "mac-address"; + + phy-mode = "rgmii"; + phy-handle = <&phy1>; +}; + +&spi { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <25000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x000000 0x40000>; + read-only; + }; + + partition@40000 { + label = "firmware"; + reg = <0x40000 0xfa0000>; + compatible = "denx,uimage"; + }; + + hwinfo: partition@fe0000 { + label = "hwinfo"; + reg = <0xfe0000 0x10000>; + read-only; + }; + + partition@ff0000 { + label = "u-boot-env"; + reg = <0xff0000 0x10000>; + read-only; + }; + }; + }; +}; + +&hwinfo { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_hwinfo_1c: macaddr@1c { + reg = <0x1c 0x6>; + }; +}; + +&i2c0 { + gpio_ext: gpio@21 { + status = "okay"; + + compatible = "ti,tca6416"; + reg = <0x21>; + + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + }; + + temp-sensor@4a { + compatible = "national,lm75"; + reg = <0x4a>; + }; + + eeprom@50 { /* 24lc2561 */ + compatible = "atmel,24c256","at24"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x50>; + size = <256>; + }; + + ds1374c: rtc@68 { + status = "okay"; + + compatible = "dallas,ds1374"; + reg = <0x68>; + }; +}; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index 1e439b1e2f4..c6284edafd0 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -19,6 +19,7 @@ ath79_setup_interfaces() araknis,an-700-ap-i-ac|\ arduino,yun|\ aruba,ap-105|\ + aruba,ap-175|\ asus,rp-ac51|\ asus,rp-ac66|\ avm,fritz1750e|\ diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk index 608b51766fa..328861de037 100644 --- a/target/linux/ath79/image/generic.mk +++ b/target/linux/ath79/image/generic.mk @@ -395,6 +395,15 @@ define Device/aruba_ap-105 endef TARGET_DEVICES += aruba_ap-105 +define Device/aruba_ap-175 + SOC := ar7161 + DEVICE_VENDOR := Aruba + DEVICE_MODEL := AP-175 + IMAGE_SIZE := 16000k + DEVICE_PACKAGES := kmod-gpio-pca953x kmod-hwmon-lm75 kmod-i2c-gpio kmod-rtc-ds1374 +endef +TARGET_DEVICES += aruba_ap-175 + define Device/asus_pl-ac56 SOC := qca9563 DEVICE_VENDOR := ASUS From ceac4ae3b403d52735f371b741f9fd6cbbe08b31 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Mon, 1 Nov 2021 22:52:21 +0100 Subject: [PATCH 24/53] lantiq: xway: add support for AVM FRITZ!Box 7330 The AVM FRITZ!Box 7330 shares hardware with the AVM Fritzbox 7320 except for the second ethernet port, which only supports 100M. Hardware: - SoC: Lantiq ARX 188 - CPU: 2x MIPS 34Kc 393 MHz - RAM: 64 MiB 196 MHz - Flash: 16 MiB NAND - Ethernet: Built-in Gigabit Ethernet switch, 1x 1GbE, 1x 100M - Wifi: Atheros AR9227-BC2A b/g/n with 2 pcb/internal antennas - USB: 2x USB 2.0 - DSL: Built-in ADSL2+ modem - DECT: Dialog SC14441 - LEDs: 1 two-color, 4 one-color - Buttons: 1x DECT, 1x WIFI - Telephone connectors: 1 FXS port via TAE or RJ11 connector Installation: The installation process is described on the wiki. Unsupported (same as AVM 7320): - VoIP (DECT and FXS), - Second Ethernet port. Signed-off-by: Aleksander Jan Bajkowski --- target/linux/lantiq/image/ar9.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/linux/lantiq/image/ar9.mk b/target/linux/lantiq/image/ar9.mk index 4d9a008f6fc..43f91d0ee45 100644 --- a/target/linux/lantiq/image/ar9.mk +++ b/target/linux/lantiq/image/ar9.mk @@ -17,6 +17,8 @@ define Device/avm_fritz7320 DEVICE_MODEL := FRITZ!Box 7320 DEVICE_ALT0_VENDOR := 1&1 DEVICE_ALT0_MODEL := HomeServer + DEVICE_ALT1_VENDOR := AVM + DEVICE_ALT1_MODEL := Fritz!box 7330 SOC := ar9 IMAGE_SIZE := 15744k LOADER_FLASH_OFFS := 0x31000 From b094c6976c161643d5c656b16738a65d28722b18 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 14 Mar 2023 05:03:24 -0400 Subject: [PATCH 25/53] tools/automake: verbose variable compatibility An old patch attempted to harmonize the way that both Openwrt and Automake uses the $(V) variable. However, it was reverted because of the side-effects. This method is more simple and just allows Automake to accept any string as part of the verbosity toggle, falling back to the default if null. Ref: e6901bf90 ("tools/automake: Revert "Do not use $(V) - force AM_V=1"") Ref: 43365ca66 ("Do not use $(V) - force AM_V=1") Signed-off-by: Michael Pratt --- .../200-other-V-values-for-verbosity.patch | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tools/automake/patches/200-other-V-values-for-verbosity.patch diff --git a/tools/automake/patches/200-other-V-values-for-verbosity.patch b/tools/automake/patches/200-other-V-values-for-verbosity.patch new file mode 100644 index 00000000000..1ea9d38b0ed --- /dev/null +++ b/tools/automake/patches/200-other-V-values-for-verbosity.patch @@ -0,0 +1,59 @@ +From: Bogdan Drozdowski +Date: Sat, 31 Dec 2022 20:17:35 +0100 +Subject: [PATCH] Allow other V values for verbosity + +--- + m4/silent.m4 | 2 +- + t/silent-gen.sh | 24 ++++++++++++++++++++++++ + 2 files changed, 25 insertions(+), 1 deletion(-) + +--- a/m4/silent.m4 ++++ b/m4/silent.m4 +@@ -43,7 +43,7 @@ else + fi]) + if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. +- AM_V='$(V)' ++ AM_V='$(shell if ( test "x$(V)" = "x0" ); then echo 0; elif ( test "x$(V)" = "x" ); then echo $(AM_DEFAULT_VERBOSITY); else echo 1; fi)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' + else + AM_V=$AM_DEFAULT_VERBOSITY +--- a/t/silent-gen.sh ++++ b/t/silent-gen.sh +@@ -54,6 +54,18 @@ grep 'cp ' stdout + grep 'echo ' stdout + + $MAKE clean ++run_make -O V=99 ++grep 'GEN ' stdout && exit 1 ++grep 'cp ' stdout ++grep 'echo ' stdout ++ ++$MAKE clean ++run_make -O V=vvv ++grep 'GEN ' stdout && exit 1 ++grep 'cp ' stdout ++grep 'echo ' stdout ++ ++$MAKE clean + run_make -O V=0 + grep 'GEN .*foo' stdout + grep 'cp ' stdout && exit 1 +@@ -78,5 +90,17 @@ run_make -O V=1 + grep 'GEN ' stdout && exit 1 + grep 'cp ' stdout + grep 'echo ' stdout ++ ++$MAKE clean ++run_make -O V=99 ++grep 'GEN ' stdout && exit 1 ++grep 'cp ' stdout ++grep 'echo ' stdout ++ ++$MAKE clean ++run_make -O V=v ++grep 'GEN ' stdout && exit 1 ++grep 'cp ' stdout ++grep 'echo ' stdout + + : From 83c1bf2cd43c89c6488cdae2891264593ee8c0c1 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 15 Mar 2023 21:22:37 -0400 Subject: [PATCH 26/53] autotools: remove specialized version of libtool Remove the specialized copy of libtool which was used for linking to uClibc++, which is now removed. Also remove references to the deprecated fixup targets that invoked this specialized libtool, which no package uses. Ref: 6b2ed6101 ("uclibc++: remove") Ref: c10515db6 ("re-enable the libtool PKG_BUILD_DEPENDS for PKG_FIXUP") Ref: 246a5b334 ("More libtool madness") Signed-off-by: Michael Pratt --- include/autotools.mk | 13 ------------- tools/libtool/Makefile | 2 -- 2 files changed, 15 deletions(-) diff --git a/include/autotools.mk b/include/autotools.mk index cba36ccd9fa..c378efe6f9d 100644 --- a/include/autotools.mk +++ b/include/autotools.mk @@ -124,13 +124,6 @@ ifneq ($(filter libtool-abiver,$(PKG_FIXUP)),) Hooks/Configure/Post += set_libtool_abiver endif -ifneq ($(filter libtool-ucxx,$(PKG_FIXUP)),) - PKG_BUILD_DEPENDS += libtool - ifeq ($(filter no-autoreconf,$(PKG_FIXUP)),) - Hooks/Configure/Pre += autoreconf_target - endif -endif - ifneq ($(filter autoreconf,$(PKG_FIXUP)),) ifeq ($(filter autoreconf,$(Hooks/Configure/Pre)),) Hooks/Configure/Pre += autoreconf_target @@ -166,12 +159,6 @@ ifneq ($(filter libtool,$(HOST_FIXUP)),) endif endif -ifneq ($(filter libtool-ucxx,$(HOST_FIXUP)),) - ifeq ($(filter no-autoreconf,$(HOST_FIXUP)),) - Hooks/HostConfigure/Pre += autoreconf_host - endif -endif - ifneq ($(filter autoreconf,$(HOST_FIXUP)),) ifeq ($(filter autoreconf,$(Hooks/HostConfigure/Pre)),) Hooks/HostConfigure/Pre += autoreconf_host diff --git a/tools/libtool/Makefile b/tools/libtool/Makefile index 66261422949..cc9e8a68fbd 100644 --- a/tools/libtool/Makefile +++ b/tools/libtool/Makefile @@ -35,8 +35,6 @@ endef define Host/Install $(MAKE) -C $(HOST_BUILD_DIR) install $(SED) 's,\(hardcode_into_libs\)=yes,\1=no,g' $(STAGING_DIR_HOST)/bin/libtool - $(CP) $(STAGING_DIR_HOST)/bin/libtool $(STAGING_DIR_HOST)/bin/libtool-ucxx - $(SED) 's,-lstdc++,-luClibc++,g' $(STAGING_DIR_HOST)/bin/libtool-ucxx endef define Host/Uninstall From 7c0727c26330d12253ec98463279a564ae0f9efa Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 15 Mar 2023 01:45:02 -0400 Subject: [PATCH 27/53] tools/libtool: clean up build recipes Host/Clean/Default is no longer defined. Use the uninstall makefile target to remove the obsolete m4 files, and more. Signed-off-by: Michael Pratt --- tools/libtool/Makefile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/libtool/Makefile b/tools/libtool/Makefile index cc9e8a68fbd..b4f3ecc36ba 100644 --- a/tools/libtool/Makefile +++ b/tools/libtool/Makefile @@ -23,7 +23,7 @@ HOST_CONFIGURE_VARS += \ define Host/Prepare $(call Host/Prepare/Default) - (cd $(STAGING_DIR_HOST)/share/aclocal/ && rm -f libtool.m4 ltdl.m4 lt~obsolete.m4 ltoptions.m4 ltsugar.m4 ltversion.m4) + $(call Host/Uninstall) $(if $(QUILT),,(cd $(HOST_BUILD_DIR); touch README-release; $(AM_TOOL_PATHS) ./bootstrap --skip-git --skip-po --force)) endef @@ -33,16 +33,13 @@ define Host/Configure endef define Host/Install - $(MAKE) -C $(HOST_BUILD_DIR) install + $(call Host/Compile/Default,install) $(SED) 's,\(hardcode_into_libs\)=yes,\1=no,g' $(STAGING_DIR_HOST)/bin/libtool endef define Host/Uninstall -$(call Host/Compile/Default,uninstall) -endef - -define Host/Clean - $(call Host/Clean/Default) + (cd $(STAGING_DIR_HOST)/share/aclocal/ && rm -f libtool.m4 ltdl.m4 lt~obsolete.m4 ltoptions.m4 ltsugar.m4 ltversion.m4) endef $(eval $(call HostBuild)) From 2bb8e4a88149e09389b409517219b4ade4e7578e Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 14 Mar 2023 05:10:50 -0400 Subject: [PATCH 28/53] rules.mk: add FILECMD variable Some packages using Libtool have the possibility of using this environment variable if set, instead of the direct command for "file" using PATH, or the need to patch a hard-coded path. This is a new feature of Libtool 2.4.7 Ref: bf261073d ("tools/libtool: bump to 2.4.7") Signed-off-by: Michael Pratt --- rules.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/rules.mk b/rules.mk index a2f5bcca4b0..57d7995d4fa 100644 --- a/rules.mk +++ b/rules.mk @@ -252,6 +252,7 @@ TARGET_NM:=$(TARGET_CROSS)gcc-nm TARGET_CC:=$(TARGET_CROSS)gcc TARGET_CXX:=$(TARGET_CROSS)g++ KPATCH:=$(SCRIPT_DIR)/patch-kernel.sh +FILECMD:=$(STAGING_DIR_HOST)/bin/file SED:=$(STAGING_DIR_HOST)/bin/sed -i -e ESED:=$(STAGING_DIR_HOST)/bin/sed -E -i -e MKHASH:=$(STAGING_DIR_HOST)/bin/mkhash From 9215f556a0ad92727aa6a7bccb057c180f5ec18d Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Sat, 11 Mar 2023 12:43:34 +0100 Subject: [PATCH 29/53] bcm47xx: refresh config This was done by executing these command: $ make kernel_oldconfig CONFIG_TARGET=subtarget Signed-off-by: Aleksander Jan Bajkowski --- target/linux/bcm47xx/legacy/config-default | 1 - target/linux/bcm47xx/mips74k/config-default | 15 ++++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/target/linux/bcm47xx/legacy/config-default b/target/linux/bcm47xx/legacy/config-default index 8a52e475c7f..4cd487e74ce 100644 --- a/target/linux/bcm47xx/legacy/config-default +++ b/target/linux/bcm47xx/legacy/config-default @@ -4,5 +4,4 @@ CONFIG_B44_PCICORE_AUTOSELECT=y CONFIG_B44_PCI_AUTOSELECT=y # CONFIG_BCM47XX_BCMA is not set # CONFIG_BCMA is not set -# CONFIG_MTD_NAND is not set # CONFIG_SSB_DRIVER_GIGE is not set diff --git a/target/linux/bcm47xx/mips74k/config-default b/target/linux/bcm47xx/mips74k/config-default index 2c3c40377ae..96aecf0aa66 100644 --- a/target/linux/bcm47xx/mips74k/config-default +++ b/target/linux/bcm47xx/mips74k/config-default @@ -3,18 +3,15 @@ CONFIG_BGMAC=y CONFIG_BGMAC_BCMA=y CONFIG_BOUNCE=y +CONFIG_CPU_HAS_DIEI=y +CONFIG_CPU_HAS_RIXI=y # CONFIG_CPU_MIPS32_R1 is not set -# CONFIG_CPU_MIPSR1 is not set CONFIG_CPU_MIPS32_R2=y CONFIG_CPU_MIPSR2=y -# CONFIG_FIXED_PHY is not set +CONFIG_CPU_SUPPORTS_MSA=y # CONFIG_GPIO_WDT is not set CONFIG_HIGHMEM=y +CONFIG_KMAP_LOCAL=y +CONFIG_MIPS_SPRAM=y # CONFIG_SSB is not set -# CONFIG_SSB_DRIVER_EXTIF is not set -# CONFIG_SSB_DRIVER_GIGE is not set -# CONFIG_SSB_DRIVER_MIPS is not set -# CONFIG_SSB_EMBEDDED is not set -# CONFIG_SSB_PCICORE_HOSTMODE is not set -# CONFIG_SSB_SERIAL is not set -# CONFIG_SSB_SFLASH is not set +CONFIG_TARGET_ISA_REV=2 From 11c28cfceb5ec3cf734a155b45e5fb389e8fd422 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Sun, 18 Dec 2022 00:26:19 +0100 Subject: [PATCH 30/53] bcm47xx: enable adm6996 only on legacy subtarget The generic subtarget supports only a few devices. None of these devices are equipped with a ADM6996 switch. On the mips74k subtarget, the driver for the adm6996 switch is disabled. So it seems that the ADM6996 driver should be enabled only on the legacy subtarget. Support for ADM6996 switches was enabled in commit 68081fc1c8c7814b1c064431eb2e364f9226801a. At the time when this driver was enabled the bcm47xx target had only one subtarget. Switches used by individual devices suported by the generic subtarget are listed below. Device Switch Edimax PS-1208MFG int. SoC Linksys WRT300N v1.1 Broadcom BCM5325 Linksys WRT310N v1 Broadcom BCM5397 Linksys WRT350N v1 Broadcom BCM5397 Linksys WRT610N v1 Broadcom BCM53115 Linksys WRT610N v2 Broadcom BCM53115 Linksys E3000 v1 Broadcom BCM53115 Reduce uncompressed kernel size by 8320 Bytes. Signed-off-by: Aleksander Jan Bajkowski --- target/linux/bcm47xx/config-5.10 | 1 - target/linux/bcm47xx/config-5.15 | 1 - target/linux/bcm47xx/legacy/config-default | 1 + target/linux/bcm47xx/mips74k/config-default | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/target/linux/bcm47xx/config-5.10 b/target/linux/bcm47xx/config-5.10 index 31d6d1de390..bee300d9c02 100644 --- a/target/linux/bcm47xx/config-5.10 +++ b/target/linux/bcm47xx/config-5.10 @@ -1,4 +1,3 @@ -CONFIG_ADM6996_PHY=y CONFIG_ARCH_BINFMT_ELF_STATE=y CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_DISCARD_MEMBLOCK=y diff --git a/target/linux/bcm47xx/config-5.15 b/target/linux/bcm47xx/config-5.15 index 0714c9a57c6..6f091c0e7fe 100644 --- a/target/linux/bcm47xx/config-5.15 +++ b/target/linux/bcm47xx/config-5.15 @@ -1,4 +1,3 @@ -CONFIG_ADM6996_PHY=y CONFIG_ARCH_32BIT_OFF_T=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_KEEP_MEMBLOCK=y diff --git a/target/linux/bcm47xx/legacy/config-default b/target/linux/bcm47xx/legacy/config-default index 4cd487e74ce..b80b03b5cb7 100644 --- a/target/linux/bcm47xx/legacy/config-default +++ b/target/linux/bcm47xx/legacy/config-default @@ -1,3 +1,4 @@ +CONFIG_ADM6996_PHY=y CONFIG_B44=y CONFIG_B44_PCI=y CONFIG_B44_PCICORE_AUTOSELECT=y diff --git a/target/linux/bcm47xx/mips74k/config-default b/target/linux/bcm47xx/mips74k/config-default index 96aecf0aa66..3ba49507d42 100644 --- a/target/linux/bcm47xx/mips74k/config-default +++ b/target/linux/bcm47xx/mips74k/config-default @@ -1,4 +1,3 @@ -# CONFIG_ADM6996_PHY is not set # CONFIG_BCM47XX_SSB is not set CONFIG_BGMAC=y CONFIG_BGMAC_BCMA=y From dc79b51533cfe9a7806353f6c6fd6b22cd80d536 Mon Sep 17 00:00:00 2001 From: Alexey Bartenev <41exey@proton.me> Date: Fri, 10 Mar 2023 10:35:30 -0500 Subject: [PATCH 31/53] ramips: add support for Keenetic Lite III rev. A MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit General specification: SoC Type: MediaTek MT7620N (580MHz) ROM: 8 MB SPI-NOR (W25Q64FV) RAM: 64 MB DDR (EM6AB160TSD-5G) Switch: MediaTek MT7530 Ethernet: 5 ports - 5×100MbE (WAN, LAN1-4) Wireless: 2.4 GHz (MediaTek RT5390): b/g/n Buttons: 3 button (POWER, RESET, WPS) Slide switch: 4 position (BASE, ADAPTER, BOOSTER, ACCESS POINT) Bootloader: U-Boot 1.1.3 Power: 9 VDC, 0.6 A MAC in stock: |- + | | LAN | RF-EEPROM + 0x04 | | WLAN | RF-EEPROM + 0x04 | | WAN | RF-EEPROM + 0x28 | OEM easy installation 1. Use a PC to browse to http://my.keenetic.net. 2. Go to the System section and open the Files tab. 3. Under the Files tab, there will be a list of system files. Click on the Firmware file. 4. When a modal window appears, click on the Choose File button and upload the firmware image. 5. Wait for the router to flash and reboot. OEM installation using the TFTP method 1. Download the latest firmware image and rename it to klite3_recovery.bin. 2. Set up a Tftp server on a PC (e.g. Tftpd32) and place the firmware image to the root directory of the server. 3. Power off the router and use a twisted pair cable to connect the PC to any of the router's LAN ports. 4. Configure the network adapter of the PC to use IP address 192.168.1.2 and subnet mask 255.255.255.0. 5. Power up the router while holding the reset button pressed. 6. Wait approximately for 5 seconds and then release the reset button. 7. The router should download the firmware via TFTP and complete flashing in a few minutes. After flashing is complete, use the PC to browse to http://192.168.1.1 or ssh to proceed with the configuration. Signed-off-by: Alexey Bartenev <41exey@proton.me> --- package/boot/uboot-envtools/files/ramips | 3 +- .../dts/mt7620n_zyxel_keenetic-lite-iii-a.dts | 144 ++++++++++++++++++ target/linux/ramips/image/mt7620.mk | 12 ++ .../mt7620/base-files/etc/board.d/01_leds | 1 + .../mt7620/base-files/etc/board.d/02_network | 6 + 5 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 target/linux/ramips/dts/mt7620n_zyxel_keenetic-lite-iii-a.dts diff --git a/package/boot/uboot-envtools/files/ramips b/package/boot/uboot-envtools/files/ramips index 6a0256c568d..bc562100365 100644 --- a/package/boot/uboot-envtools/files/ramips +++ b/package/boot/uboot-envtools/files/ramips @@ -19,7 +19,8 @@ alfa-network,r36m-e4g|\ alfa-network,tube-e4g|\ engenius,epg600|\ engenius,esr600h|\ -sitecom,wlr-4100-v1-002) +sitecom,wlr-4100-v1-002|\ +zyxel,keenetic-lite-iii-a) ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x1000" ;; arcadyan,we420223-99) diff --git a/target/linux/ramips/dts/mt7620n_zyxel_keenetic-lite-iii-a.dts b/target/linux/ramips/dts/mt7620n_zyxel_keenetic-lite-iii-a.dts new file mode 100644 index 00000000000..0d1c4696d79 --- /dev/null +++ b/target/linux/ramips/dts/mt7620n_zyxel_keenetic-lite-iii-a.dts @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "mt7620n.dtsi" + +#include +#include +#include + +/ { + compatible = "zyxel,keenetic-lite-iii-a", "ralink,mt7620n-soc"; + model = "ZyXEL Keenetic Lite III (rev. A)"; + + aliases { + led-boot = &led_wan; + led-failsafe = &led_wan; + led-running = &led_wan; + led-upgrade = &led_wan; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; // #GPIO1 + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; // #GPIO2 + linux,code = ; + }; + + sw0 { + label = "sw0"; + gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; // #GPIO17 + linux,code = ; + }; + + sw1 { + label = "sw1"; + gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; // #GPIO20 + linux,code = ; + }; + + sw2 { + label = "sw2"; + gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; // #GPIO21 + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + led_wan: wan { + label = "green:wan"; + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; // #GPIO38 + }; + + wifi { + label = "green:wifi"; + color = ; + function = LED_FUNCTION_WLAN; + gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>; // #GPIO72 + }; + }; + +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio3 { + status = "okay"; +}; + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <48000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "U-Boot"; + reg = <0x0 0x30000>; + read-only; + }; + + partition@30000 { + label = "U-Config"; + reg = <0x30000 0x10000>; + }; + + factory: partition@40000 { + label = "RF-EEPROM"; + reg = <0x40000 0x10000>; + read-only; + }; + + partition@50000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x50000 0x7a0000>; + }; + + partition@7f0000 { + label = "Config"; + reg = <0x7f0000 0x10000>; + }; + + partition@0_1 { + label = "Full"; + reg = <0x0 0x800000>; + }; + }; + }; +}; + +&state_default { + gpio { + groups = "i2c"; + function = "gpio"; + }; +}; + +&wmac { + ralink,mtd-eeprom = <&factory 0x0>; +}; diff --git a/target/linux/ramips/image/mt7620.mk b/target/linux/ramips/image/mt7620.mk index 6e528a930b5..de84b232c13 100644 --- a/target/linux/ramips/image/mt7620.mk +++ b/target/linux/ramips/image/mt7620.mk @@ -1471,6 +1471,18 @@ define Device/zte_q7 endef TARGET_DEVICES += zte_q7 +define Device/zyxel_keenetic-lite-iii-a + SOC := mt7620n + IMAGE_SIZE := 7872k + DEVICE_VENDOR := ZyXEL + DEVICE_MODEL := Keenetic Lite III + DEVICE_VARIANT := A + IMAGES += factory.bin + IMAGE/factory.bin := $$(sysupgrade_bin) | pad-to 64k | check-size | \ + zyimage -d 2102018 -v "ZyXEL Keenetic Lite III" +endef +TARGET_DEVICES += zyxel_keenetic-lite-iii-a + define Device/zyxel_keenetic-omni SOC := mt7620n IMAGE_SIZE := 7872k diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds index 36e3045a38a..2deda0861a9 100644 --- a/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds +++ b/target/linux/ramips/mt7620/base-files/etc/board.d/01_leds @@ -55,6 +55,7 @@ planex,mzk-ex300np|\ zbtlink,zbt-we826-16m|\ zbtlink,zbt-we826-32m|\ zbtlink,zbt-wr8305rt|\ +zyxel,keenetic-lite-iii-a|\ zyxel,keenetic-omni|\ zyxel,keenetic-omni-ii|\ zyxel,keenetic-viva) diff --git a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network index 992d8a9c40c..787e123e31b 100644 --- a/target/linux/ramips/mt7620/base-files/etc/board.d/02_network +++ b/target/linux/ramips/mt7620/base-files/etc/board.d/02_network @@ -28,6 +28,7 @@ ramips_setup_interfaces() zbtlink,zbt-we826-32m|\ zbtlink,zbt-we826-e|\ zbtlink,zbt-wr8305rt|\ + zyxel,keenetic-lite-iii-a|\ zyxel,keenetic-omni) ucidef_add_switch "switch0" \ "0:lan" "1:lan" "2:lan" "3:lan" "4:wan" "6@eth0" @@ -404,6 +405,11 @@ ramips_setup_macs() zbtlink,zbt-we1026-5g-16m) label_mac=$(mtd_get_mac_binary factory 0x4) ;; + zyxel,keenetic-lite-iii-a) + lan_mac=$(mtd_get_mac_binary RF-EEPROM 0x4) + wan_mac=$(mtd_get_mac_binary RF-EEPROM 0x28) + label_mac=$wan_mac + ;; zyxel,keenetic-omni|\ zyxel,keenetic-omni-ii|\ zyxel,keenetic-viva) From 0d0928f58795e336646ad31ea96d2919b5328f39 Mon Sep 17 00:00:00 2001 From: Kazuki H Date: Tue, 21 Mar 2023 06:51:03 +0900 Subject: [PATCH 32/53] kernel: Update MGLRU patchset The current patches are old, update them from mainline. Backports taken from https://github.com/yuzhaogoogle/linux/commits/mglru-5.15 Tested-by: Kazuki H #mt7622/Linksys E8450 UBI Signed-off-by: Kazuki H --- ...-x86-arm64-add-arch_has_hw_pte_young.patch | 443 ++++- ...dd-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch | 109 +- ...-03-mm-vmscan.c-refactor-shrink_node.patch | 78 +- ...inux-mm_inline.h-fold-__update_lru_s.patch | 87 + ...-mm-multigenerational-lru-groundwork.patch | 996 ---------- ...-v6.1-05-mm-multi-gen-LRU-groundwork.patch | 842 ++++++++ ...multigenerational-lru-mm_struct-list.patch | 760 -------- ...multi-gen-LRU-minimal-implementation.patch | 1466 ++++++++++++++ ....1-06-mm-multigenerational-lru-aging.patch | 1176 ------------ ...lti-gen-LRU-exploit-locality-in-rmap.patch | 508 +++++ ...07-mm-multigenerational-lru-eviction.patch | 1002 ---------- ...lti-gen-LRU-support-page-table-walks.patch | 1710 +++++++++++++++++ ...multigenerational-lru-user-interface.patch | 496 ----- ...lti-gen-LRU-optimize-multiple-memcgs.patch | 320 +++ ...-09-mm-multigenerational-lru-Kconfig.patch | 80 - ...v6.1-10-mm-multi-gen-LRU-kill-switch.patch | 513 +++++ ...-multigenerational-lru-documentation.patch | 161 -- ...m-multi-gen-LRU-thrashing-prevention.patch | 233 +++ ...2-mm-multi-gen-LRU-debugfs-interface.patch | 586 ++++++ ...on-t-sync-disk-for-each-aging-cycle.patch} | 15 +- ...-retry-pages-written-back-while-isol.patch | 129 ++ ...-move-lru_gen_add_mm-out-of-IRQ-off-.patch | 54 + ..._young-for-architectures-not-having-.patch | 111 ++ ...roduce-arch_has_hw_nonleaf_pmd_young.patch | 122 ++ ...RU-fix-crash-during-cgroup-migration.patch | 61 + .../020-v6.3-19-mm-add-vma_has_recency.patch | 207 ++ ...6.3-20-mm-support-POSIX_FADV_NOREUSE.patch | 134 ++ ...-rename-lru_gen_struct-to-lru_gen_pa.patch | 359 ++++ ...-rename-lrugen-lists-to-lrugen-pages.patch | 171 ++ ...U-remove-eviction-fairness-safeguard.patch | 193 ++ ...-LRU-remove-aging-fairness-safeguard.patch | 292 +++ ...lti-gen-LRU-shuffle-should_run_aging.patch | 166 ++ ...-gen-LRU-per-node-lru_gen_page-lists.patch | 884 +++++++++ ...i-gen-LRU-clarify-scan_control-flags.patch | 201 ++ ...-simplify-arch_has_hw_pte_young-chec.patch | 39 + ...m-multi-gen-LRU-avoid-futile-retries.patch | 93 + target/linux/generic/config-5.15 | 2 - 37 files changed, 9995 insertions(+), 4804 deletions(-) create mode 100644 target/linux/generic/backport-5.15/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch delete mode 100644 target/linux/generic/backport-5.15/020-v6.1-04-mm-multigenerational-lru-groundwork.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch delete mode 100644 target/linux/generic/backport-5.15/020-v6.1-05-mm-multigenerational-lru-mm_struct-list.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch delete mode 100644 target/linux/generic/backport-5.15/020-v6.1-06-mm-multigenerational-lru-aging.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch delete mode 100644 target/linux/generic/backport-5.15/020-v6.1-07-mm-multigenerational-lru-eviction.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch delete mode 100644 target/linux/generic/backport-5.15/020-v6.1-08-mm-multigenerational-lru-user-interface.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch delete mode 100644 target/linux/generic/backport-5.15/020-v6.1-09-mm-multigenerational-lru-Kconfig.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch delete mode 100644 target/linux/generic/backport-5.15/020-v6.1-10-mm-multigenerational-lru-documentation.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch rename target/linux/generic/backport-5.15/{021-v6.1-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch => 020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch} (67%) create mode 100644 target/linux/generic/backport-5.15/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-19-mm-add-vma_has_recency.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch create mode 100644 target/linux/generic/backport-5.15/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch diff --git a/target/linux/generic/backport-5.15/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch b/target/linux/generic/backport-5.15/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch index 2a4207c3b54..3bea44d8658 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch @@ -1,134 +1,396 @@ -From a8e6015d9534f39abc08e6804566af059e498a60 Mon Sep 17 00:00:00 2001 +From a4103262b01a1b8704b37c01c7c813df91b7b119 Mon Sep 17 00:00:00 2001 From: Yu Zhao -Date: Wed, 4 Aug 2021 01:31:34 -0600 -Subject: [PATCH 01/10] mm: x86, arm64: add arch_has_hw_pte_young() +Date: Sun, 18 Sep 2022 01:59:58 -0600 +Subject: [PATCH 01/29] mm: x86, arm64: add arch_has_hw_pte_young() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit -Some architectures automatically set the accessed bit in PTEs, e.g., -x86 and arm64 v8.2. On architectures that do not have this capability, -clearing the accessed bit in a PTE triggers a page fault following the -TLB miss of this PTE. +Patch series "Multi-Gen LRU Framework", v14. -Being aware of this capability can help make better decisions, i.e., -whether to limit the size of each batch of PTEs and the burst of -batches when clearing the accessed bit. +What's new +========== +1. OpenWrt, in addition to Android, Arch Linux Zen, Armbian, ChromeOS, + Liquorix, post-factum and XanMod, is now shipping MGLRU on 5.15. +2. Fixed long-tailed direct reclaim latency seen on high-memory (TBs) + machines. The old direct reclaim backoff, which tries to enforce a + minimum fairness among all eligible memcgs, over-swapped by about + (total_mem>>DEF_PRIORITY)-nr_to_reclaim. The new backoff, which + pulls the plug on swapping once the target is met, trades some + fairness for curtailed latency: + https://lore.kernel.org/r/20220918080010.2920238-10-yuzhao@google.com/ +3. Fixed minior build warnings and conflicts. More comments and nits. +TLDR +==== +The current page reclaim is too expensive in terms of CPU usage and it +often makes poor choices about what to evict. This patchset offers an +alternative solution that is performant, versatile and +straightforward. + +Patchset overview +================= +The design and implementation overview is in patch 14: +https://lore.kernel.org/r/20220918080010.2920238-15-yuzhao@google.com/ + +01. mm: x86, arm64: add arch_has_hw_pte_young() +02. mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +Take advantage of hardware features when trying to clear the accessed +bit in many PTEs. + +03. mm/vmscan.c: refactor shrink_node() +04. Revert "include/linux/mm_inline.h: fold __update_lru_size() into + its sole caller" +Minor refactors to improve readability for the following patches. + +05. mm: multi-gen LRU: groundwork +Adds the basic data structure and the functions that insert pages to +and remove pages from the multi-gen LRU (MGLRU) lists. + +06. mm: multi-gen LRU: minimal implementation +A minimal implementation without optimizations. + +07. mm: multi-gen LRU: exploit locality in rmap +Exploits spatial locality to improve efficiency when using the rmap. + +08. mm: multi-gen LRU: support page table walks +Further exploits spatial locality by optionally scanning page tables. + +09. mm: multi-gen LRU: optimize multiple memcgs +Optimizes the overall performance for multiple memcgs running mixed +types of workloads. + +10. mm: multi-gen LRU: kill switch +Adds a kill switch to enable or disable MGLRU at runtime. + +11. mm: multi-gen LRU: thrashing prevention +12. mm: multi-gen LRU: debugfs interface +Provide userspace with features like thrashing prevention, working set +estimation and proactive reclaim. + +13. mm: multi-gen LRU: admin guide +14. mm: multi-gen LRU: design doc +Add an admin guide and a design doc. + +Benchmark results +================= +Independent lab results +----------------------- +Based on the popularity of searches [01] and the memory usage in +Google's public cloud, the most popular open-source memory-hungry +applications, in alphabetical order, are: + Apache Cassandra Memcached + Apache Hadoop MongoDB + Apache Spark PostgreSQL + MariaDB (MySQL) Redis + +An independent lab evaluated MGLRU with the most widely used benchmark +suites for the above applications. They posted 960 data points along +with kernel metrics and perf profiles collected over more than 500 +hours of total benchmark time. Their final reports show that, with 95% +confidence intervals (CIs), the above applications all performed +significantly better for at least part of their benchmark matrices. + +On 5.14: +1. Apache Spark [02] took 95% CIs [9.28, 11.19]% and [12.20, 14.93]% + less wall time to sort three billion random integers, respectively, + under the medium- and the high-concurrency conditions, when + overcommitting memory. There were no statistically significant + changes in wall time for the rest of the benchmark matrix. +2. MariaDB [03] achieved 95% CIs [5.24, 10.71]% and [20.22, 25.97]% + more transactions per minute (TPM), respectively, under the medium- + and the high-concurrency conditions, when overcommitting memory. + There were no statistically significant changes in TPM for the rest + of the benchmark matrix. +3. Memcached [04] achieved 95% CIs [23.54, 32.25]%, [20.76, 41.61]% + and [21.59, 30.02]% more operations per second (OPS), respectively, + for sequential access, random access and Gaussian (distribution) + access, when THP=always; 95% CIs [13.85, 15.97]% and + [23.94, 29.92]% more OPS, respectively, for random access and + Gaussian access, when THP=never. There were no statistically + significant changes in OPS for the rest of the benchmark matrix. +4. MongoDB [05] achieved 95% CIs [2.23, 3.44]%, [6.97, 9.73]% and + [2.16, 3.55]% more operations per second (OPS), respectively, for + exponential (distribution) access, random access and Zipfian + (distribution) access, when underutilizing memory; 95% CIs + [8.83, 10.03]%, [21.12, 23.14]% and [5.53, 6.46]% more OPS, + respectively, for exponential access, random access and Zipfian + access, when overcommitting memory. + +On 5.15: +5. Apache Cassandra [06] achieved 95% CIs [1.06, 4.10]%, [1.94, 5.43]% + and [4.11, 7.50]% more operations per second (OPS), respectively, + for exponential (distribution) access, random access and Zipfian + (distribution) access, when swap was off; 95% CIs [0.50, 2.60]%, + [6.51, 8.77]% and [3.29, 6.75]% more OPS, respectively, for + exponential access, random access and Zipfian access, when swap was + on. +6. Apache Hadoop [07] took 95% CIs [5.31, 9.69]% and [2.02, 7.86]% + less average wall time to finish twelve parallel TeraSort jobs, + respectively, under the medium- and the high-concurrency + conditions, when swap was on. There were no statistically + significant changes in average wall time for the rest of the + benchmark matrix. +7. PostgreSQL [08] achieved 95% CI [1.75, 6.42]% more transactions per + minute (TPM) under the high-concurrency condition, when swap was + off; 95% CIs [12.82, 18.69]% and [22.70, 46.86]% more TPM, + respectively, under the medium- and the high-concurrency + conditions, when swap was on. There were no statistically + significant changes in TPM for the rest of the benchmark matrix. +8. Redis [09] achieved 95% CIs [0.58, 5.94]%, [6.55, 14.58]% and + [11.47, 19.36]% more total operations per second (OPS), + respectively, for sequential access, random access and Gaussian + (distribution) access, when THP=always; 95% CIs [1.27, 3.54]%, + [10.11, 14.81]% and [8.75, 13.64]% more total OPS, respectively, + for sequential access, random access and Gaussian access, when + THP=never. + +Our lab results +--------------- +To supplement the above results, we ran the following benchmark suites +on 5.16-rc7 and found no regressions [10]. + fs_fio_bench_hdd_mq pft + fs_lmbench pgsql-hammerdb + fs_parallelio redis + fs_postmark stream + hackbench sysbenchthread + kernbench tpcc_spark + memcached unixbench + multichase vm-scalability + mutilate will-it-scale + nginx + +[01] https://trends.google.com +[02] https://lore.kernel.org/r/20211102002002.92051-1-bot@edi.works/ +[03] https://lore.kernel.org/r/20211009054315.47073-1-bot@edi.works/ +[04] https://lore.kernel.org/r/20211021194103.65648-1-bot@edi.works/ +[05] https://lore.kernel.org/r/20211109021346.50266-1-bot@edi.works/ +[06] https://lore.kernel.org/r/20211202062806.80365-1-bot@edi.works/ +[07] https://lore.kernel.org/r/20211209072416.33606-1-bot@edi.works/ +[08] https://lore.kernel.org/r/20211218071041.24077-1-bot@edi.works/ +[09] https://lore.kernel.org/r/20211122053248.57311-1-bot@edi.works/ +[10] https://lore.kernel.org/r/20220104202247.2903702-1-yuzhao@google.com/ + +Read-world applications +======================= +Third-party testimonials +------------------------ +Konstantin reported [11]: + I have Archlinux with 8G RAM + zswap + swap. While developing, I + have lots of apps opened such as multiple LSP-servers for different + langs, chats, two browsers, etc... Usually, my system gets quickly + to a point of SWAP-storms, where I have to kill LSP-servers, + restart browsers to free memory, etc, otherwise the system lags + heavily and is barely usable. + + 1.5 day ago I migrated from 5.11.15 kernel to 5.12 + the LRU + patchset, and I started up by opening lots of apps to create memory + pressure, and worked for a day like this. Till now I had not a + single SWAP-storm, and mind you I got 3.4G in SWAP. I was never + getting to the point of 3G in SWAP before without a single + SWAP-storm. + +Vaibhav from IBM reported [12]: + In a synthetic MongoDB Benchmark, seeing an average of ~19% + throughput improvement on POWER10(Radix MMU + 64K Page Size) with + MGLRU patches on top of 5.16 kernel for MongoDB + YCSB across + three different request distributions, namely, Exponential, Uniform + and Zipfan. + +Shuang from U of Rochester reported [13]: + With the MGLRU, fio achieved 95% CIs [38.95, 40.26]%, [4.12, 6.64]% + and [9.26, 10.36]% higher throughput, respectively, for random + access, Zipfian (distribution) access and Gaussian (distribution) + access, when the average number of jobs per CPU is 1; 95% CIs + [42.32, 49.15]%, [9.44, 9.89]% and [20.99, 22.86]% higher + throughput, respectively, for random access, Zipfian access and + Gaussian access, when the average number of jobs per CPU is 2. + +Daniel from Michigan Tech reported [14]: + With Memcached allocating ~100GB of byte-addressable Optante, + performance improvement in terms of throughput (measured as queries + per second) was about 10% for a series of workloads. + +Large-scale deployments +----------------------- +We've rolled out MGLRU to tens of millions of ChromeOS users and +about a million Android users. Google's fleetwide profiling [15] shows +an overall 40% decrease in kswapd CPU usage, in addition to +improvements in other UX metrics, e.g., an 85% decrease in the number +of low-memory kills at the 75th percentile and an 18% decrease in +app launch time at the 50th percentile. + +The downstream kernels that have been using MGLRU include: +1. Android [16] +2. Arch Linux Zen [17] +3. Armbian [18] +4. ChromeOS [19] +5. Liquorix [20] +6. OpenWrt [21] +7. post-factum [22] +8. XanMod [23] + +[11] https://lore.kernel.org/r/140226722f2032c86301fbd326d91baefe3d7d23.camel@yandex.ru/ +[12] https://lore.kernel.org/r/87czj3mux0.fsf@vajain21.in.ibm.com/ +[13] https://lore.kernel.org/r/20220105024423.26409-1-szhai2@cs.rochester.edu/ +[14] https://lore.kernel.org/r/CA+4-3vksGvKd18FgRinxhqHetBS1hQekJE2gwco8Ja-bJWKtFw@mail.gmail.com/ +[15] https://dl.acm.org/doi/10.1145/2749469.2750392 +[16] https://android.com +[17] https://archlinux.org +[18] https://armbian.com +[19] https://chromium.org +[20] https://liquorix.net +[21] https://openwrt.org +[22] https://codeberg.org/pf-kernel +[23] https://xanmod.org + +Summary +======= +The facts are: +1. The independent lab results and the real-world applications + indicate substantial improvements; there are no known regressions. +2. Thrashing prevention, working set estimation and proactive reclaim + work out of the box; there are no equivalent solutions. +3. There is a lot of new code; no smaller changes have been + demonstrated similar effects. + +Our options, accordingly, are: +1. Given the amount of evidence, the reported improvements will likely + materialize for a wide range of workloads. +2. Gauging the interest from the past discussions, the new features + will likely be put to use for both personal computers and data + centers. +3. Based on Google's track record, the new code will likely be well + maintained in the long term. It'd be more difficult if not + impossible to achieve similar effects with other approaches. + +This patch (of 14): + +Some architectures automatically set the accessed bit in PTEs, e.g., x86 +and arm64 v8.2. On architectures that do not have this capability, +clearing the accessed bit in a PTE usually triggers a page fault following +the TLB miss of this PTE (to emulate the accessed bit). + +Being aware of this capability can help make better decisions, e.g., +whether to spread the work out over a period of time to reduce bursty page +faults when trying to clear the accessed bit in many PTEs. + +Note that theoretically this capability can be unreliable, e.g., +hotplugged CPUs might be different from builtin ones. Therefore it should +not be used in architecture-independent code that involves correctness, +e.g., to determine whether TLB flushes are required (in combination with +the accessed bit). + +Link: https://lkml.kernel.org/r/20220918080010.2920238-1-yuzhao@google.com +Link: https://lkml.kernel.org/r/20220918080010.2920238-2-yuzhao@google.com Signed-off-by: Yu Zhao -Change-Id: Ib49b44fb56df3333a2ff1fcc496fb1980b976e7a +Reviewed-by: Barry Song +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Acked-by: Will Deacon +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: linux-arm-kernel@lists.infradead.org +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Miaohe Lin +Cc: Mike Rapoport +Cc: Qi Zheng +Signed-off-by: Andrew Morton --- - arch/arm64/include/asm/cpufeature.h | 5 +++++ - arch/arm64/include/asm/pgtable.h | 13 ++++++++----- - arch/arm64/kernel/cpufeature.c | 10 ++++++++++ - arch/arm64/tools/cpucaps | 1 + - arch/x86/include/asm/pgtable.h | 6 +++--- - include/linux/pgtable.h | 13 +++++++++++++ - mm/memory.c | 14 +------------- - 7 files changed, 41 insertions(+), 21 deletions(-) + arch/arm64/include/asm/pgtable.h | 14 ++------------ + arch/x86/include/asm/pgtable.h | 6 +++--- + include/linux/pgtable.h | 13 +++++++++++++ + mm/memory.c | 14 +------------- + 4 files changed, 19 insertions(+), 28 deletions(-) ---- a/arch/arm64/include/asm/cpufeature.h -+++ b/arch/arm64/include/asm/cpufeature.h -@@ -808,6 +808,11 @@ static inline bool system_supports_tlb_r - cpus_have_const_cap(ARM64_HAS_TLB_RANGE); - } - -+static inline bool system_has_hw_af(void) -+{ -+ return IS_ENABLED(CONFIG_ARM64_HW_AFDBM) && cpus_have_const_cap(ARM64_HW_AF); -+} -+ - extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); - - static inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange) +diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h +index ed57717cd004..874827fc7bc6 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h -@@ -999,13 +999,16 @@ static inline void update_mmu_cache(stru +@@ -999,23 +999,13 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, * page after fork() + CoW for pfn mappings. We don't always have a * hardware-managed access flag on arm64. */ -static inline bool arch_faults_on_old_pte(void) -+static inline bool arch_has_hw_pte_young(bool local) - { +-{ - WARN_ON(preemptible()); -+ if (local) { -+ WARN_ON(preemptible()); -+ return cpu_has_hw_af(); -+ } - +- - return !cpu_has_hw_af(); -+ return system_has_hw_af(); - } +-} -#define arch_faults_on_old_pte arch_faults_on_old_pte -+#define arch_has_hw_pte_young arch_has_hw_pte_young ++#define arch_has_hw_pte_young cpu_has_hw_af /* * Experimentally, it's cheap to set the access flag in hardware and we -@@ -1013,7 +1016,7 @@ static inline bool arch_faults_on_old_pt + * benefit from prefaulting mappings as 'old' to start with. */ - static inline bool arch_wants_old_prefaulted_pte(void) - { +-static inline bool arch_wants_old_prefaulted_pte(void) +-{ - return !arch_faults_on_old_pte(); -+ return arch_has_hw_pte_young(true); - } - #define arch_wants_old_prefaulted_pte arch_wants_old_prefaulted_pte +-} +-#define arch_wants_old_prefaulted_pte arch_wants_old_prefaulted_pte ++#define arch_wants_old_prefaulted_pte cpu_has_hw_af ---- a/arch/arm64/kernel/cpufeature.c -+++ b/arch/arm64/kernel/cpufeature.c -@@ -2197,6 +2197,16 @@ static const struct arm64_cpu_capabiliti - .matches = has_hw_dbm, - .cpu_enable = cpu_enable_hw_dbm, - }, -+ { -+ .desc = "Hardware update of the Access flag", -+ .type = ARM64_CPUCAP_SYSTEM_FEATURE, -+ .capability = ARM64_HW_AF, -+ .sys_reg = SYS_ID_AA64MMFR1_EL1, -+ .sign = FTR_UNSIGNED, -+ .field_pos = ID_AA64MMFR1_HADBS_SHIFT, -+ .min_field_value = 1, -+ .matches = has_cpuid_feature, -+ }, - #endif - { - .desc = "CRC32 instructions", ---- a/arch/arm64/tools/cpucaps -+++ b/arch/arm64/tools/cpucaps -@@ -35,6 +35,7 @@ HAS_STAGE2_FWB - HAS_SYSREG_GIC_CPUIF - HAS_TLB_RANGE - HAS_VIRT_HOST_EXTN -+HW_AF - HW_DBM - KVM_PROTECTED_MODE - MISMATCHED_CACHE_TYPE + #endif /* !__ASSEMBLY__ */ + +diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h +index 448cd01eb3ec..3908780fc408 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h -@@ -1397,10 +1397,10 @@ static inline bool arch_has_pfn_modify_c +@@ -1397,10 +1397,10 @@ static inline bool arch_has_pfn_modify_check(void) return boot_cpu_has_bug(X86_BUG_L1TF); } -#define arch_faults_on_old_pte arch_faults_on_old_pte -static inline bool arch_faults_on_old_pte(void) +#define arch_has_hw_pte_young arch_has_hw_pte_young -+static inline bool arch_has_hw_pte_young(bool local) ++static inline bool arch_has_hw_pte_young(void) { - return false; + return true; } #endif /* __ASSEMBLY__ */ +diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h +index d468efcf48f4..2f1188980baf 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h -@@ -259,6 +259,19 @@ static inline int pmdp_clear_flush_young +@@ -259,6 +259,19 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif +#ifndef arch_has_hw_pte_young +/* -+ * Return whether the accessed bit is supported by the local CPU or all CPUs. ++ * Return whether the accessed bit is supported on the local CPU. + * -+ * Those arches which have hw access flag feature need to implement their own -+ * helper. By default, "false" means pagefault will be hit on old pte. ++ * This stub assumes accessing through an old PTE triggers a page fault. ++ * Architectures that automatically set the access bit should overwrite it. + */ -+static inline bool arch_has_hw_pte_young(bool local) ++static inline bool arch_has_hw_pte_young(void) +{ + return false; +} @@ -137,6 +399,8 @@ Change-Id: Ib49b44fb56df3333a2ff1fcc496fb1980b976e7a #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long address, +diff --git a/mm/memory.c b/mm/memory.c +index a4d0f744a458..392b7326a2d2 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -121,18 +121,6 @@ int randomize_va_space __read_mostly = @@ -158,12 +422,15 @@ Change-Id: Ib49b44fb56df3333a2ff1fcc496fb1980b976e7a #ifndef arch_wants_old_prefaulted_pte static inline bool arch_wants_old_prefaulted_pte(void) { -@@ -2782,7 +2770,7 @@ static inline bool cow_user_page(struct +@@ -2782,7 +2770,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src, * On architectures with software "accessed" bits, we would * take a double page fault, so mark it accessed here. */ - if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) { -+ if (!arch_has_hw_pte_young(true) && !pte_young(vmf->orig_pte)) { ++ if (!arch_has_hw_pte_young() && !pte_young(vmf->orig_pte)) { pte_t entry; vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch b/target/linux/generic/backport-5.15/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch index 785af275f50..60ce9c07cc0 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch @@ -1,64 +1,112 @@ -From f8b663bbfa30af5515e222fd74df20ea4e8393a2 Mon Sep 17 00:00:00 2001 +From 493de1c4b0f2cd909169401da8c445f6c8a7e29d Mon Sep 17 00:00:00 2001 From: Yu Zhao -Date: Sat, 26 Sep 2020 21:17:18 -0600 -Subject: [PATCH 02/10] mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +Date: Sun, 18 Sep 2022 01:59:59 -0600 +Subject: [PATCH 02/29] mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit -Some architectures support the accessed bit on non-leaf PMD entries, -e.g., x86_64 sets the accessed bit on a non-leaf PMD entry when using -it as part of linear address translation [1]. As an optimization, page -table walkers who are interested in the accessed bit can skip the PTEs -under a non-leaf PMD entry if the accessed bit is cleared on this PMD -entry. +Some architectures support the accessed bit in non-leaf PMD entries, e.g., +x86 sets the accessed bit in a non-leaf PMD entry when using it as part of +linear address translation [1]. Page table walkers that clear the +accessed bit may use this capability to reduce their search space. -Although an inline function may be preferable, this capability is -added as a configuration option to look consistent when used with the -existing macros. +Note that: +1. Although an inline function is preferable, this capability is added + as a configuration option for consistency with the existing macros. +2. Due to the little interest in other varieties, this capability was + only tested on Intel and AMD CPUs. + +Thanks to the following developers for their efforts [2][3]. + Randy Dunlap + Stephen Rothwell [1]: Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3 (June 2021), section 4.8 +[2] https://lore.kernel.org/r/bfdcc7c8-922f-61a9-aa15-7e7250f04af7@infradead.org/ +[3] https://lore.kernel.org/r/20220413151513.5a0d7a7e@canb.auug.org.au/ +Link: https://lkml.kernel.org/r/20220918080010.2920238-3-yuzhao@google.com Signed-off-by: Yu Zhao +Reviewed-by: Barry Song +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte Tested-by: Konstantin Kharlamov -Change-Id: I1a17be3ae926f721f7b17ea1539e5c39e8c4f9a8 +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton --- - arch/Kconfig | 9 +++++++++ + arch/Kconfig | 8 ++++++++ arch/x86/Kconfig | 1 + arch/x86/include/asm/pgtable.h | 3 ++- arch/x86/mm/pgtable.c | 5 ++++- include/linux/pgtable.h | 4 ++-- - 5 files changed, 18 insertions(+), 4 deletions(-) + 5 files changed, 17 insertions(+), 4 deletions(-) +diff --git a/arch/Kconfig b/arch/Kconfig +index 5987363b41c2..62d55b7ccca1 100644 --- a/arch/Kconfig +++ b/arch/Kconfig -@@ -1295,6 +1295,15 @@ config ARCH_HAS_ELFCORE_COMPAT +@@ -1295,6 +1295,14 @@ config ARCH_HAS_ELFCORE_COMPAT config ARCH_HAS_PARANOID_L1D_FLUSH bool +config ARCH_HAS_NONLEAF_PMD_YOUNG + bool -+ depends on PGTABLE_LEVELS > 2 + help -+ Architectures that select this are able to set the accessed bit on -+ non-leaf PMD entries in addition to leaf PTE entries where pages are -+ mapped. For them, page table walkers that clear the accessed bit may -+ stop at non-leaf PMD entries if they do not see the accessed bit. ++ Architectures that select this option are capable of setting the ++ accessed bit in non-leaf PMD entries when using them as part of linear ++ address translations. Page table walkers that clear the accessed bit ++ may use this capability to reduce their search space. + source "kernel/gcov/Kconfig" source "scripts/gcc-plugins/Kconfig" +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index a08ce6360382..38e1d231d52a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -84,6 +84,7 @@ config X86 select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_PTE_DEVMAP if X86_64 select ARCH_HAS_PTE_SPECIAL -+ select ARCH_HAS_NONLEAF_PMD_YOUNG if X86_64 ++ select ARCH_HAS_NONLEAF_PMD_YOUNG if PGTABLE_LEVELS > 2 select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 select ARCH_HAS_COPY_MC if X86_64 select ARCH_HAS_SET_MEMORY +diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h +index 3908780fc408..01a1763123ff 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h -@@ -817,7 +817,8 @@ static inline unsigned long pmd_page_vad +@@ -817,7 +817,8 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) static inline int pmd_bad(pmd_t pmd) { @@ -68,9 +116,11 @@ Change-Id: I1a17be3ae926f721f7b17ea1539e5c39e8c4f9a8 } static inline unsigned long pages_to_mb(unsigned long npg) +diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c +index 3481b35cb4ec..a224193d84bf 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c -@@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_ +@@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma, return ret; } @@ -79,7 +129,7 @@ Change-Id: I1a17be3ae926f721f7b17ea1539e5c39e8c4f9a8 int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmdp) { -@@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_ +@@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma, return ret; } @@ -89,9 +139,11 @@ Change-Id: I1a17be3ae926f721f7b17ea1539e5c39e8c4f9a8 int pudp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pud_t *pudp) { +diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h +index 2f1188980baf..e6889556e0bf 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h -@@ -212,7 +212,7 @@ static inline int ptep_test_and_clear_yo +@@ -212,7 +212,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, #endif #ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG @@ -100,7 +152,7 @@ Change-Id: I1a17be3ae926f721f7b17ea1539e5c39e8c4f9a8 static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) -@@ -233,7 +233,7 @@ static inline int pmdp_test_and_clear_yo +@@ -233,7 +233,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, BUILD_BUG(); return 0; } @@ -109,3 +161,6 @@ Change-Id: I1a17be3ae926f721f7b17ea1539e5c39e8c4f9a8 #endif #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch b/target/linux/generic/backport-5.15/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch index 31161e2a0f5..1b9a70dbc12 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch @@ -1,21 +1,60 @@ -From a810f8e2f1bdd0707eaf05c8b4ba84a3ff2801bd Mon Sep 17 00:00:00 2001 +From 9e17efd11450d3d2069adaa3c58db9ac8ebd1c66 Mon Sep 17 00:00:00 2001 From: Yu Zhao -Date: Sun, 27 Sep 2020 20:49:08 -0600 -Subject: [PATCH 03/10] mm/vmscan.c: refactor shrink_node() +Date: Sun, 18 Sep 2022 02:00:00 -0600 +Subject: [PATCH 03/29] mm/vmscan.c: refactor shrink_node() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit -This patch refactors shrink_node(). This will make the upcoming -changes to mm/vmscan.c more readable. +This patch refactors shrink_node() to improve readability for the upcoming +changes to mm/vmscan.c. +Link: https://lkml.kernel.org/r/20220918080010.2920238-4-yuzhao@google.com Signed-off-by: Yu Zhao +Reviewed-by: Barry Song +Reviewed-by: Miaohe Lin +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte Tested-by: Konstantin Kharlamov -Change-Id: Iae734b5b4030205b7db6e8c841f747b6f6ae1a04 +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton --- - mm/vmscan.c | 186 +++++++++++++++++++++++++++------------------------- - 1 file changed, 98 insertions(+), 88 deletions(-) + mm/vmscan.c | 198 +++++++++++++++++++++++++++------------------------- + 1 file changed, 104 insertions(+), 94 deletions(-) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 201acea81804..dc5f0381513f 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -2497,6 +2497,103 @@ enum scan_balance { +@@ -2497,6 +2497,109 @@ enum scan_balance { SCAN_FILE, }; @@ -27,6 +66,12 @@ Change-Id: Iae734b5b4030205b7db6e8c841f747b6f6ae1a04 + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); + + /* ++ * Flush the memory cgroup stats, so that we read accurate per-memcg ++ * lruvec stats for heuristics. ++ */ ++ mem_cgroup_flush_stats(); ++ ++ /* + * Determine the scan balance between anon and file LRUs. + */ + spin_lock_irq(&target_lruvec->lru_lock); @@ -119,7 +164,7 @@ Change-Id: Iae734b5b4030205b7db6e8c841f747b6f6ae1a04 /* * Determine how aggressively the anon and file LRU lists should be * scanned. The relative value of each set of LRU lists is determined -@@ -2965,7 +3062,6 @@ static void shrink_node(pg_data_t *pgdat +@@ -2965,109 +3068,16 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc) unsigned long nr_reclaimed, nr_scanned; struct lruvec *target_lruvec; bool reclaimable = false; @@ -127,7 +172,15 @@ Change-Id: Iae734b5b4030205b7db6e8c841f747b6f6ae1a04 target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); -@@ -2981,93 +3077,7 @@ again: + again: +- /* +- * Flush the memory cgroup stats, so that we read accurate per-memcg +- * lruvec stats for heuristics. +- */ +- mem_cgroup_flush_stats(); +- + memset(&sc->nr, 0, sizeof(sc->nr)); + nr_reclaimed = sc->nr_reclaimed; nr_scanned = sc->nr_scanned; @@ -222,3 +275,6 @@ Change-Id: Iae734b5b4030205b7db6e8c841f747b6f6ae1a04 shrink_node_memcgs(pgdat, sc); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch b/target/linux/generic/backport-5.15/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch new file mode 100644 index 00000000000..24b5c8f7970 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch @@ -0,0 +1,87 @@ +From 03705be42114db7cc5bd6eb7bf7e8703c94d4880 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:01 -0600 +Subject: [PATCH 04/29] Revert "include/linux/mm_inline.h: fold + __update_lru_size() into its sole caller" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch undoes the following refactor: commit 289ccba18af4 +("include/linux/mm_inline.h: fold __update_lru_size() into its sole +caller") + +The upcoming changes to include/linux/mm_inline.h will reuse +__update_lru_size(). + +Link: https://lkml.kernel.org/r/20220918080010.2920238-5-yuzhao@google.com +Signed-off-by: Yu Zhao +Reviewed-by: Miaohe Lin +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index 355ea1ee32bd..a822d6b690a5 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -24,7 +24,7 @@ static inline int page_is_file_lru(struct page *page) + return !PageSwapBacked(page); + } + +-static __always_inline void update_lru_size(struct lruvec *lruvec, ++static __always_inline void __update_lru_size(struct lruvec *lruvec, + enum lru_list lru, enum zone_type zid, + int nr_pages) + { +@@ -33,6 +33,13 @@ static __always_inline void update_lru_size(struct lruvec *lruvec, + __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); + __mod_zone_page_state(&pgdat->node_zones[zid], + NR_ZONE_LRU_BASE + lru, nr_pages); ++} ++ ++static __always_inline void update_lru_size(struct lruvec *lruvec, ++ enum lru_list lru, enum zone_type zid, ++ long nr_pages) ++{ ++ __update_lru_size(lruvec, lru, zid, nr_pages); + #ifdef CONFIG_MEMCG + mem_cgroup_update_lru_size(lruvec, lru, zid, nr_pages); + #endif +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-04-mm-multigenerational-lru-groundwork.patch b/target/linux/generic/backport-5.15/020-v6.1-04-mm-multigenerational-lru-groundwork.patch deleted file mode 100644 index aec67c23eb2..00000000000 --- a/target/linux/generic/backport-5.15/020-v6.1-04-mm-multigenerational-lru-groundwork.patch +++ /dev/null @@ -1,996 +0,0 @@ -From 05f366c941ae2bb8ba21c79fafcb747a5a6b967b Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Mon, 25 Jan 2021 21:12:33 -0700 -Subject: [PATCH 04/10] mm: multigenerational lru: groundwork - -For each lruvec, evictable pages are divided into multiple -generations. The youngest generation number is stored in -lrugen->max_seq for both anon and file types as they are aged on an -equal footing. The oldest generation numbers are stored in -lrugen->min_seq[] separately for anon and file types as clean file -pages can be evicted regardless of swap constraints. These three -variables are monotonically increasing. Generation numbers are -truncated into order_base_2(MAX_NR_GENS+1) bits in order to fit into -page->flags. The sliding window technique is used to prevent truncated -generation numbers from overlapping. Each truncated generation number -is an index to -lrugen->lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]. - -The framework comprises two conceptually independent components: the -aging, which produces young generations, and the eviction, which -consumes old generations. Both can be invoked independently from user -space for the purpose of working set estimation and proactive reclaim. - -The protection of hot pages and the selection of cold pages are based -on page access types and patterns. There are two access types: one via -page tables and the other via file descriptors. The protection of the -former type is by design stronger because: - 1) The uncertainty in determining the access patterns of the former - type is higher due to the coalesced nature of the accessed bit. - 2) The cost of evicting the former type is higher due to the TLB - flushes required and the likelihood of involving I/O. - 3) The penalty of under-protecting the former type is higher because - applications usually do not prepare themselves for major faults like - they do for blocked I/O. For example, client applications commonly - dedicate blocked I/O to separate threads to avoid UI janks that - negatively affect user experience. - -There are also two access patterns: one with temporal locality and the -other without. The latter pattern, e.g., random and sequential, needs -to be explicitly excluded to avoid weakening the protection of the -former pattern. Generally the former type follows the former pattern -unless MADV_SEQUENTIAL is specified and the latter type follows the -latter pattern unless outlying refaults have been observed. - -Upon faulting, a page is added to the youngest generation, which -provides the strongest protection as the eviction will not consider -this page before the aging has scanned it at least twice. The first -scan clears the accessed bit set during the initial fault. And the -second scan makes sure this page has not been used since the first -scan. A page from any other generations is brought back to the -youngest generation whenever the aging finds the accessed bit set on -any of the PTEs mapping this page. - -Unmapped pages are initially added to the oldest generation and then -conditionally protected by tiers. This is done later [PATCH 07/10]. - -Signed-off-by: Yu Zhao -Tested-by: Konstantin Kharlamov -Change-Id: I71de7cd15b8dfa6f9fdd838023474693c4fee0a7 ---- - fs/fuse/dev.c | 3 +- - include/linux/cgroup.h | 15 +- - include/linux/mm.h | 36 ++++ - include/linux/mm_inline.h | 182 ++++++++++++++++++++ - include/linux/mmzone.h | 70 ++++++++ - include/linux/page-flags-layout.h | 19 ++- - include/linux/page-flags.h | 4 +- - include/linux/sched.h | 3 + - kernel/bounds.c | 3 + - kernel/cgroup/cgroup-internal.h | 1 - - mm/huge_memory.c | 3 +- - mm/memcontrol.c | 1 + - mm/memory.c | 7 + - mm/mm_init.c | 6 +- - mm/page_alloc.c | 1 + - mm/swap.c | 9 +- - mm/swapfile.c | 2 + - mm/vmscan.c | 268 ++++++++++++++++++++++++++++++ - 18 files changed, 618 insertions(+), 15 deletions(-) - ---- a/fs/fuse/dev.c -+++ b/fs/fuse/dev.c -@@ -785,7 +785,8 @@ static int fuse_check_page(struct page * - 1 << PG_active | - 1 << PG_workingset | - 1 << PG_reclaim | -- 1 << PG_waiters))) { -+ 1 << PG_waiters | -+ LRU_GEN_MASK | LRU_REFS_MASK))) { - dump_page(page, "fuse: trying to steal weird page"); - return 1; - } ---- a/include/linux/cgroup.h -+++ b/include/linux/cgroup.h -@@ -433,6 +433,18 @@ static inline void cgroup_put(struct cgr - css_put(&cgrp->self); - } - -+extern struct mutex cgroup_mutex; -+ -+static inline void cgroup_lock(void) -+{ -+ mutex_lock(&cgroup_mutex); -+} -+ -+static inline void cgroup_unlock(void) -+{ -+ mutex_unlock(&cgroup_mutex); -+} -+ - /** - * task_css_set_check - obtain a task's css_set with extra access conditions - * @task: the task to obtain css_set for -@@ -447,7 +459,6 @@ static inline void cgroup_put(struct cgr - * as locks used during the cgroup_subsys::attach() methods. - */ - #ifdef CONFIG_PROVE_RCU --extern struct mutex cgroup_mutex; - extern spinlock_t css_set_lock; - #define task_css_set_check(task, __c) \ - rcu_dereference_check((task)->cgroups, \ -@@ -708,6 +719,8 @@ struct cgroup; - static inline u64 cgroup_id(const struct cgroup *cgrp) { return 1; } - static inline void css_get(struct cgroup_subsys_state *css) {} - static inline void css_put(struct cgroup_subsys_state *css) {} -+static inline void cgroup_lock(void) {} -+static inline void cgroup_unlock(void) {} - static inline int cgroup_attach_task_all(struct task_struct *from, - struct task_struct *t) { return 0; } - static inline int cgroupstats_build(struct cgroupstats *stats, ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -1093,6 +1093,8 @@ vm_fault_t finish_mkwrite_fault(struct v - #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) - #define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) - #define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH) -+#define LRU_GEN_PGOFF (KASAN_TAG_PGOFF - LRU_GEN_WIDTH) -+#define LRU_REFS_PGOFF (LRU_GEN_PGOFF - LRU_REFS_WIDTH) - - /* - * Define the bit shifts to access each section. For non-existent -@@ -1807,6 +1809,40 @@ static inline void unmap_mapping_range(s - loff_t const holebegin, loff_t const holelen, int even_cows) { } - #endif - -+#ifdef CONFIG_LRU_GEN -+static inline void task_enter_nonseq_fault(void) -+{ -+ WARN_ON(current->in_nonseq_fault); -+ -+ current->in_nonseq_fault = 1; -+} -+ -+static inline void task_exit_nonseq_fault(void) -+{ -+ WARN_ON(!current->in_nonseq_fault); -+ -+ current->in_nonseq_fault = 0; -+} -+ -+static inline bool task_in_nonseq_fault(void) -+{ -+ return current->in_nonseq_fault; -+} -+#else -+static inline void task_enter_nonseq_fault(void) -+{ -+} -+ -+static inline void task_exit_nonseq_fault(void) -+{ -+} -+ -+static inline bool task_in_nonseq_fault(void) -+{ -+ return false; -+} -+#endif /* CONFIG_LRU_GEN */ -+ - static inline void unmap_shared_mapping_range(struct address_space *mapping, - loff_t const holebegin, loff_t const holelen) - { ---- a/include/linux/mm_inline.h -+++ b/include/linux/mm_inline.h -@@ -79,11 +79,187 @@ static __always_inline enum lru_list pag - return lru; - } - -+#ifdef CONFIG_LRU_GEN -+ -+static inline bool lru_gen_enabled(void) -+{ -+#ifdef CONFIG_LRU_GEN_ENABLED -+ DECLARE_STATIC_KEY_TRUE(lru_gen_static_key); -+ -+ return static_branch_likely(&lru_gen_static_key); -+#else -+ DECLARE_STATIC_KEY_FALSE(lru_gen_static_key); -+ -+ return static_branch_unlikely(&lru_gen_static_key); -+#endif -+} -+ -+/* Return an index within the sliding window that tracks MAX_NR_GENS generations. */ -+static inline int lru_gen_from_seq(unsigned long seq) -+{ -+ return seq % MAX_NR_GENS; -+} -+ -+/* The youngest and the second youngest generations are counted as active. */ -+static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) -+{ -+ unsigned long max_seq = lruvec->evictable.max_seq; -+ -+ VM_BUG_ON(gen >= MAX_NR_GENS); -+ -+ return gen == lru_gen_from_seq(max_seq) || gen == lru_gen_from_seq(max_seq - 1); -+} -+ -+/* Update the sizes of the multigenerational lru lists. */ -+static inline void lru_gen_update_size(struct page *page, struct lruvec *lruvec, -+ int old_gen, int new_gen) -+{ -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ int delta = thp_nr_pages(page); -+ enum lru_list lru = type * LRU_FILE; -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ lockdep_assert_held(&lruvec->lru_lock); -+ VM_BUG_ON(old_gen != -1 && old_gen >= MAX_NR_GENS); -+ VM_BUG_ON(new_gen != -1 && new_gen >= MAX_NR_GENS); -+ VM_BUG_ON(old_gen == -1 && new_gen == -1); -+ -+ if (old_gen >= 0) -+ WRITE_ONCE(lrugen->sizes[old_gen][type][zone], -+ lrugen->sizes[old_gen][type][zone] - delta); -+ if (new_gen >= 0) -+ WRITE_ONCE(lrugen->sizes[new_gen][type][zone], -+ lrugen->sizes[new_gen][type][zone] + delta); -+ -+ if (old_gen < 0) { -+ if (lru_gen_is_active(lruvec, new_gen)) -+ lru += LRU_ACTIVE; -+ update_lru_size(lruvec, lru, zone, delta); -+ return; -+ } -+ -+ if (new_gen < 0) { -+ if (lru_gen_is_active(lruvec, old_gen)) -+ lru += LRU_ACTIVE; -+ update_lru_size(lruvec, lru, zone, -delta); -+ return; -+ } -+ -+ if (!lru_gen_is_active(lruvec, old_gen) && lru_gen_is_active(lruvec, new_gen)) { -+ update_lru_size(lruvec, lru, zone, -delta); -+ update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta); -+ } -+ -+ VM_BUG_ON(lru_gen_is_active(lruvec, old_gen) && !lru_gen_is_active(lruvec, new_gen)); -+} -+ -+/* Add a page to one of the multigenerational lru lists. Return true on success. */ -+static inline bool lru_gen_add_page(struct page *page, struct lruvec *lruvec, bool reclaiming) -+{ -+ int gen; -+ unsigned long old_flags, new_flags; -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ if (PageUnevictable(page) || !lrugen->enabled[type]) -+ return false; -+ /* -+ * If a page shouldn't be considered for eviction, i.e., a page mapped -+ * upon fault during which the accessed bit is set, add it to the -+ * youngest generation. -+ * -+ * If a page can't be evicted immediately, i.e., an anon page not in -+ * swap cache or a dirty page pending writeback, add it to the second -+ * oldest generation. -+ * -+ * If a page could be evicted immediately, e.g., a clean page, add it to -+ * the oldest generation. -+ */ -+ if (PageActive(page)) -+ gen = lru_gen_from_seq(lrugen->max_seq); -+ else if ((!type && !PageSwapCache(page)) || -+ (PageReclaim(page) && (PageDirty(page) || PageWriteback(page)))) -+ gen = lru_gen_from_seq(lrugen->min_seq[type] + 1); -+ else -+ gen = lru_gen_from_seq(lrugen->min_seq[type]); -+ -+ do { -+ new_flags = old_flags = READ_ONCE(page->flags); -+ VM_BUG_ON_PAGE(new_flags & LRU_GEN_MASK, page); -+ -+ new_flags &= ~(LRU_GEN_MASK | BIT(PG_active)); -+ new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; -+ } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); -+ -+ lru_gen_update_size(page, lruvec, -1, gen); -+ /* for rotate_reclaimable_page() */ -+ if (reclaiming) -+ list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); -+ else -+ list_add(&page->lru, &lrugen->lists[gen][type][zone]); -+ -+ return true; -+} -+ -+/* Delete a page from one of the multigenerational lru lists. Return true on success. */ -+static inline bool lru_gen_del_page(struct page *page, struct lruvec *lruvec, bool reclaiming) -+{ -+ int gen; -+ unsigned long old_flags, new_flags; -+ -+ do { -+ new_flags = old_flags = READ_ONCE(page->flags); -+ if (!(new_flags & LRU_GEN_MASK)) -+ return false; -+ -+ VM_BUG_ON_PAGE(PageActive(page), page); -+ VM_BUG_ON_PAGE(PageUnevictable(page), page); -+ -+ gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; -+ -+ new_flags &= ~LRU_GEN_MASK; -+ /* for shrink_page_list() */ -+ if (reclaiming) -+ new_flags &= ~(BIT(PG_referenced) | BIT(PG_reclaim)); -+ else if (lru_gen_is_active(lruvec, gen)) -+ new_flags |= BIT(PG_active); -+ } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); -+ -+ lru_gen_update_size(page, lruvec, gen, -1); -+ list_del(&page->lru); -+ -+ return true; -+} -+ -+#else -+ -+static inline bool lru_gen_enabled(void) -+{ -+ return false; -+} -+ -+static inline bool lru_gen_add_page(struct page *page, struct lruvec *lruvec, bool reclaiming) -+{ -+ return false; -+} -+ -+static inline bool lru_gen_del_page(struct page *page, struct lruvec *lruvec, bool reclaiming) -+{ -+ return false; -+} -+ -+#endif /* CONFIG_LRU_GEN */ -+ - static __always_inline void add_page_to_lru_list(struct page *page, - struct lruvec *lruvec) - { - enum lru_list lru = page_lru(page); - -+ if (lru_gen_add_page(page, lruvec, false)) -+ return; -+ - update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); - list_add(&page->lru, &lruvec->lists[lru]); - } -@@ -93,6 +269,9 @@ static __always_inline void add_page_to_ - { - enum lru_list lru = page_lru(page); - -+ if (lru_gen_add_page(page, lruvec, true)) -+ return; -+ - update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); - list_add_tail(&page->lru, &lruvec->lists[lru]); - } -@@ -100,6 +279,9 @@ static __always_inline void add_page_to_ - static __always_inline void del_page_from_lru_list(struct page *page, - struct lruvec *lruvec) - { -+ if (lru_gen_del_page(page, lruvec, false)) -+ return; -+ - list_del(&page->lru); - update_lru_size(lruvec, page_lru(page), page_zonenum(page), - -thp_nr_pages(page)); ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -294,6 +294,72 @@ enum lruvec_flags { - */ - }; - -+struct lruvec; -+ -+#define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) -+#define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) -+ -+#ifdef CONFIG_LRU_GEN -+ -+/* -+ * For each lruvec, evictable pages are divided into multiple generations. The -+ * youngest and the oldest generation numbers, AKA max_seq and min_seq, are -+ * monotonically increasing. The sliding window technique is used to track at -+ * least MIN_NR_GENS and at most MAX_NR_GENS generations. An offset within the -+ * window, AKA gen, indexes an array of per-type and per-zone lists for the -+ * corresponding generation. The counter in page->flags stores gen+1 while a -+ * page is on one of the multigenerational lru lists. Otherwise, it stores 0. -+ * -+ * After a page is faulted in, the aging must check the accessed bit at least -+ * twice before the eviction would consider it. The first check clears the -+ * accessed bit set during the initial fault. The second check makes sure this -+ * page hasn't been used since then. -+ */ -+#define MIN_NR_GENS 2 -+#define MAX_NR_GENS ((unsigned int)CONFIG_NR_LRU_GENS) -+ -+struct lrugen { -+ /* the aging increments the max generation number */ -+ unsigned long max_seq; -+ /* the eviction increments the min generation numbers */ -+ unsigned long min_seq[ANON_AND_FILE]; -+ /* the birth time of each generation in jiffies */ -+ unsigned long timestamps[MAX_NR_GENS]; -+ /* the multigenerational lru lists */ -+ struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+ /* the sizes of the multigenerational lru lists in pages */ -+ unsigned long sizes[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+ /* whether the multigenerational lru is enabled */ -+ bool enabled[ANON_AND_FILE]; -+}; -+ -+#define MAX_BATCH_SIZE 8192 -+ -+void lru_gen_init_state(struct mem_cgroup *memcg, struct lruvec *lruvec); -+void lru_gen_change_state(bool enable, bool main, bool swap); -+ -+#ifdef CONFIG_MEMCG -+void lru_gen_init_memcg(struct mem_cgroup *memcg); -+#endif -+ -+#else /* !CONFIG_LRU_GEN */ -+ -+static inline void lru_gen_init_state(struct mem_cgroup *memcg, struct lruvec *lruvec) -+{ -+} -+ -+static inline void lru_gen_change_state(bool enable, bool main, bool swap) -+{ -+} -+ -+#ifdef CONFIG_MEMCG -+static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) -+{ -+} -+#endif -+ -+#endif /* CONFIG_LRU_GEN */ -+ - struct lruvec { - struct list_head lists[NR_LRU_LISTS]; - /* per lruvec lru_lock for memcg */ -@@ -311,6 +377,10 @@ struct lruvec { - unsigned long refaults[ANON_AND_FILE]; - /* Various lruvec state flags (enum lruvec_flags) */ - unsigned long flags; -+#ifdef CONFIG_LRU_GEN -+ /* unevictable pages are on LRU_UNEVICTABLE */ -+ struct lrugen evictable; -+#endif - #ifdef CONFIG_MEMCG - struct pglist_data *pgdat; - #endif ---- a/include/linux/page-flags-layout.h -+++ b/include/linux/page-flags-layout.h -@@ -26,6 +26,14 @@ - - #define ZONES_WIDTH ZONES_SHIFT - -+#ifdef CONFIG_LRU_GEN -+/* LRU_GEN_WIDTH is generated from order_base_2(CONFIG_NR_LRU_GENS + 1). */ -+#define LRU_REFS_WIDTH (CONFIG_TIERS_PER_GEN - 2) -+#else -+#define LRU_GEN_WIDTH 0 -+#define LRU_REFS_WIDTH 0 -+#endif /* CONFIG_LRU_GEN */ -+ - #ifdef CONFIG_SPARSEMEM - #include - #define SECTIONS_SHIFT (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS) -@@ -55,7 +63,8 @@ - #define SECTIONS_WIDTH 0 - #endif - --#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS -+#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_SHIFT \ -+ <= BITS_PER_LONG - NR_PAGEFLAGS - #define NODES_WIDTH NODES_SHIFT - #elif defined(CONFIG_SPARSEMEM_VMEMMAP) - #error "Vmemmap: No space for nodes field in page flags" -@@ -89,8 +98,8 @@ - #define LAST_CPUPID_SHIFT 0 - #endif - --#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT \ -- <= BITS_PER_LONG - NR_PAGEFLAGS -+#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ -+ KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS - #define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT - #else - #define LAST_CPUPID_WIDTH 0 -@@ -100,8 +109,8 @@ - #define LAST_CPUPID_NOT_IN_PAGE_FLAGS - #endif - --#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH \ -- > BITS_PER_LONG - NR_PAGEFLAGS -+#if ZONES_WIDTH + LRU_GEN_WIDTH + LRU_REFS_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ -+ KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS - #error "Not enough bits in page flags" - #endif - ---- a/include/linux/page-flags.h -+++ b/include/linux/page-flags.h -@@ -845,7 +845,7 @@ static inline void ClearPageSlabPfmemall - 1UL << PG_private | 1UL << PG_private_2 | \ - 1UL << PG_writeback | 1UL << PG_reserved | \ - 1UL << PG_slab | 1UL << PG_active | \ -- 1UL << PG_unevictable | __PG_MLOCKED) -+ 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) - - /* - * Flags checked when a page is prepped for return by the page allocator. -@@ -856,7 +856,7 @@ static inline void ClearPageSlabPfmemall - * alloc-free cycle to prevent from reusing the page. - */ - #define PAGE_FLAGS_CHECK_AT_PREP \ -- (PAGEFLAGS_MASK & ~__PG_HWPOISON) -+ ((PAGEFLAGS_MASK & ~__PG_HWPOISON) | LRU_GEN_MASK | LRU_REFS_MASK) - - #define PAGE_FLAGS_PRIVATE \ - (1UL << PG_private | 1UL << PG_private_2) ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -911,6 +911,9 @@ struct task_struct { - #ifdef CONFIG_MEMCG - unsigned in_user_fault:1; - #endif -+#ifdef CONFIG_LRU_GEN -+ unsigned in_nonseq_fault:1; -+#endif - #ifdef CONFIG_COMPAT_BRK - unsigned brk_randomized:1; - #endif ---- a/kernel/bounds.c -+++ b/kernel/bounds.c -@@ -22,6 +22,9 @@ int main(void) - DEFINE(NR_CPUS_BITS, ilog2(CONFIG_NR_CPUS)); - #endif - DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); -+#ifdef CONFIG_LRU_GEN -+ DEFINE(LRU_GEN_WIDTH, order_base_2(CONFIG_NR_LRU_GENS + 1)); -+#endif - /* End of constants */ - - return 0; ---- a/kernel/cgroup/cgroup-internal.h -+++ b/kernel/cgroup/cgroup-internal.h -@@ -165,7 +165,6 @@ struct cgroup_mgctx { - #define DEFINE_CGROUP_MGCTX(name) \ - struct cgroup_mgctx name = CGROUP_MGCTX_INIT(name) - --extern struct mutex cgroup_mutex; - extern spinlock_t css_set_lock; - extern struct cgroup_subsys *cgroup_subsys[]; - extern struct list_head cgroup_roots; ---- a/mm/huge_memory.c -+++ b/mm/huge_memory.c -@@ -2366,7 +2366,8 @@ static void __split_huge_page_tail(struc - #ifdef CONFIG_64BIT - (1L << PG_arch_2) | - #endif -- (1L << PG_dirty))); -+ (1L << PG_dirty) | -+ LRU_GEN_MASK | LRU_REFS_MASK)); - - /* ->mapping in first tail page is compound_mapcount */ - VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING, ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -5241,6 +5241,7 @@ static struct mem_cgroup *mem_cgroup_all - memcg->deferred_split_queue.split_queue_len = 0; - #endif - idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); -+ lru_gen_init_memcg(memcg); - return memcg; - fail: - mem_cgroup_id_remove(memcg); ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -4788,6 +4788,7 @@ vm_fault_t handle_mm_fault(struct vm_are - unsigned int flags, struct pt_regs *regs) - { - vm_fault_t ret; -+ bool nonseq_fault = !(vma->vm_flags & VM_SEQ_READ); - - __set_current_state(TASK_RUNNING); - -@@ -4809,11 +4810,17 @@ vm_fault_t handle_mm_fault(struct vm_are - if (flags & FAULT_FLAG_USER) - mem_cgroup_enter_user_fault(); - -+ if (nonseq_fault) -+ task_enter_nonseq_fault(); -+ - if (unlikely(is_vm_hugetlb_page(vma))) - ret = hugetlb_fault(vma->vm_mm, vma, address, flags); - else - ret = __handle_mm_fault(vma, address, flags); - -+ if (nonseq_fault) -+ task_exit_nonseq_fault(); -+ - if (flags & FAULT_FLAG_USER) { - mem_cgroup_exit_user_fault(); - /* ---- a/mm/mm_init.c -+++ b/mm/mm_init.c -@@ -65,14 +65,16 @@ void __init mminit_verify_pageflags_layo - - shift = 8 * sizeof(unsigned long); - width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH -- - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH; -+ - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH - LRU_GEN_WIDTH - LRU_REFS_WIDTH; - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", -- "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Flags %d\n", -+ "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Gen %d Tier %d Flags %d\n", - SECTIONS_WIDTH, - NODES_WIDTH, - ZONES_WIDTH, - LAST_CPUPID_WIDTH, - KASAN_TAG_WIDTH, -+ LRU_GEN_WIDTH, -+ LRU_REFS_WIDTH, - NR_PAGEFLAGS); - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", - "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d\n", ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -7459,6 +7459,7 @@ static void __meminit pgdat_init_interna - - pgdat_page_ext_init(pgdat); - lruvec_init(&pgdat->__lruvec); -+ lru_gen_init_state(NULL, &pgdat->__lruvec); - } - - static void __meminit zone_init_internals(struct zone *zone, enum zone_type idx, int nid, ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -446,6 +446,11 @@ void lru_cache_add(struct page *page) - VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); - VM_BUG_ON_PAGE(PageLRU(page), page); - -+ /* see the comment in lru_gen_add_page() */ -+ if (lru_gen_enabled() && !PageUnevictable(page) && -+ task_in_nonseq_fault() && !(current->flags & PF_MEMALLOC)) -+ SetPageActive(page); -+ - get_page(page); - local_lock(&lru_pvecs.lock); - pvec = this_cpu_ptr(&lru_pvecs.lru_add); -@@ -547,7 +552,7 @@ static void lru_deactivate_file_fn(struc - - static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec) - { -- if (PageActive(page) && !PageUnevictable(page)) { -+ if (!PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { - int nr_pages = thp_nr_pages(page); - - del_page_from_lru_list(page, lruvec); -@@ -661,7 +666,7 @@ void deactivate_file_page(struct page *p - */ - void deactivate_page(struct page *page) - { -- if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { -+ if (PageLRU(page) && !PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { - struct pagevec *pvec; - - local_lock(&lru_pvecs.lock); ---- a/mm/swapfile.c -+++ b/mm/swapfile.c -@@ -2689,6 +2689,7 @@ SYSCALL_DEFINE1(swapoff, const char __us - err = 0; - atomic_inc(&proc_poll_event); - wake_up_interruptible(&proc_poll_wait); -+ lru_gen_change_state(false, false, true); - - out_dput: - filp_close(victim, NULL); -@@ -3350,6 +3351,7 @@ SYSCALL_DEFINE2(swapon, const char __use - mutex_unlock(&swapon_mutex); - atomic_inc(&proc_poll_event); - wake_up_interruptible(&proc_poll_wait); -+ lru_gen_change_state(true, false, true); - - error = 0; - goto out; ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -50,6 +50,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -2815,6 +2816,273 @@ static bool can_age_anon_pages(struct pg - return can_demote(pgdat->node_id, sc); - } - -+#ifdef CONFIG_LRU_GEN -+ -+/****************************************************************************** -+ * shorthand helpers -+ ******************************************************************************/ -+ -+#define for_each_gen_type_zone(gen, type, zone) \ -+ for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ -+ for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ -+ for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) -+ -+static int page_lru_gen(struct page *page) -+{ -+ unsigned long flags = READ_ONCE(page->flags); -+ -+ return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; -+} -+ -+static struct lruvec *get_lruvec(int nid, struct mem_cgroup *memcg) -+{ -+ struct pglist_data *pgdat = NODE_DATA(nid); -+ -+#ifdef CONFIG_MEMCG -+ if (memcg) { -+ struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; -+ -+ if (lruvec->pgdat != pgdat) -+ lruvec->pgdat = pgdat; -+ -+ return lruvec; -+ } -+#endif -+ return pgdat ? &pgdat->__lruvec : NULL; -+} -+ -+static int get_nr_gens(struct lruvec *lruvec, int type) -+{ -+ return lruvec->evictable.max_seq - lruvec->evictable.min_seq[type] + 1; -+} -+ -+static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) -+{ -+ return get_nr_gens(lruvec, 1) >= MIN_NR_GENS && -+ get_nr_gens(lruvec, 1) <= get_nr_gens(lruvec, 0) && -+ get_nr_gens(lruvec, 0) <= MAX_NR_GENS; -+} -+ -+/****************************************************************************** -+ * state change -+ ******************************************************************************/ -+ -+#ifdef CONFIG_LRU_GEN_ENABLED -+DEFINE_STATIC_KEY_TRUE(lru_gen_static_key); -+#else -+DEFINE_STATIC_KEY_FALSE(lru_gen_static_key); -+#endif -+ -+static int lru_gen_nr_swapfiles; -+ -+static bool __maybe_unused state_is_valid(struct lruvec *lruvec) -+{ -+ int gen, type, zone; -+ enum lru_list lru; -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ for_each_evictable_lru(lru) { -+ type = is_file_lru(lru); -+ -+ if (lrugen->enabled[type] && !list_empty(&lruvec->lists[lru])) -+ return false; -+ } -+ -+ for_each_gen_type_zone(gen, type, zone) { -+ if (!lrugen->enabled[type] && !list_empty(&lrugen->lists[gen][type][zone])) -+ return false; -+ -+ /* unlikely but not a bug when reset_batch_size() is pending */ -+ VM_WARN_ON(!lrugen->enabled[type] && lrugen->sizes[gen][type][zone]); -+ } -+ -+ return true; -+} -+ -+static bool fill_lists(struct lruvec *lruvec) -+{ -+ enum lru_list lru; -+ int remaining = MAX_BATCH_SIZE; -+ -+ for_each_evictable_lru(lru) { -+ int type = is_file_lru(lru); -+ bool active = is_active_lru(lru); -+ struct list_head *head = &lruvec->lists[lru]; -+ -+ if (!lruvec->evictable.enabled[type]) -+ continue; -+ -+ while (!list_empty(head)) { -+ bool success; -+ struct page *page = lru_to_page(head); -+ -+ VM_BUG_ON_PAGE(PageTail(page), page); -+ VM_BUG_ON_PAGE(PageUnevictable(page), page); -+ VM_BUG_ON_PAGE(PageActive(page) != active, page); -+ VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); -+ VM_BUG_ON_PAGE(page_lru_gen(page) < MAX_NR_GENS, page); -+ -+ prefetchw_prev_lru_page(page, head, flags); -+ -+ del_page_from_lru_list(page, lruvec); -+ success = lru_gen_add_page(page, lruvec, false); -+ VM_BUG_ON(!success); -+ -+ if (!--remaining) -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+static bool drain_lists(struct lruvec *lruvec) -+{ -+ int gen, type, zone; -+ int remaining = MAX_BATCH_SIZE; -+ -+ for_each_gen_type_zone(gen, type, zone) { -+ struct list_head *head = &lruvec->evictable.lists[gen][type][zone]; -+ -+ if (lruvec->evictable.enabled[type]) -+ continue; -+ -+ while (!list_empty(head)) { -+ bool success; -+ struct page *page = lru_to_page(head); -+ -+ VM_BUG_ON_PAGE(PageTail(page), page); -+ VM_BUG_ON_PAGE(PageUnevictable(page), page); -+ VM_BUG_ON_PAGE(PageActive(page), page); -+ VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); -+ VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); -+ -+ prefetchw_prev_lru_page(page, head, flags); -+ -+ success = lru_gen_del_page(page, lruvec, false); -+ VM_BUG_ON(!success); -+ add_page_to_lru_list(page, lruvec); -+ -+ if (!--remaining) -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+/* -+ * For file page tracking, we enable/disable it according to the main switch. -+ * For anon page tracking, we only enabled it when the main switch is on and -+ * there is at least one swapfile; we disable it when there are no swapfiles -+ * regardless of the value of the main switch. Otherwise, we will eventually -+ * reach the max size of the sliding window and have to call inc_min_seq(). -+ */ -+void lru_gen_change_state(bool enable, bool main, bool swap) -+{ -+ static DEFINE_MUTEX(state_mutex); -+ -+ struct mem_cgroup *memcg; -+ -+ mem_hotplug_begin(); -+ cgroup_lock(); -+ mutex_lock(&state_mutex); -+ -+ if (swap) { -+ if (enable) -+ swap = !lru_gen_nr_swapfiles++; -+ else -+ swap = !--lru_gen_nr_swapfiles; -+ } -+ -+ if (main && enable != lru_gen_enabled()) { -+ if (enable) -+ static_branch_enable(&lru_gen_static_key); -+ else -+ static_branch_disable(&lru_gen_static_key); -+ } else if (!swap || !lru_gen_enabled()) -+ goto unlock; -+ -+ memcg = mem_cgroup_iter(NULL, NULL, NULL); -+ do { -+ int nid; -+ -+ for_each_node(nid) { -+ struct lruvec *lruvec = get_lruvec(nid, memcg); -+ -+ if (!lruvec) -+ continue; -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ -+ VM_BUG_ON(!seq_is_valid(lruvec)); -+ VM_BUG_ON(!state_is_valid(lruvec)); -+ -+ lruvec->evictable.enabled[0] = lru_gen_enabled() && lru_gen_nr_swapfiles; -+ lruvec->evictable.enabled[1] = lru_gen_enabled(); -+ -+ while (!(enable ? fill_lists(lruvec) : drain_lists(lruvec))) { -+ spin_unlock_irq(&lruvec->lru_lock); -+ cond_resched(); -+ spin_lock_irq(&lruvec->lru_lock); -+ } -+ -+ spin_unlock_irq(&lruvec->lru_lock); -+ } -+ -+ cond_resched(); -+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); -+unlock: -+ mutex_unlock(&state_mutex); -+ cgroup_unlock(); -+ mem_hotplug_done(); -+} -+ -+/****************************************************************************** -+ * initialization -+ ******************************************************************************/ -+ -+void lru_gen_init_state(struct mem_cgroup *memcg, struct lruvec *lruvec) -+{ -+ int i; -+ int gen, type, zone; -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ lrugen->max_seq = MIN_NR_GENS + 1; -+ lrugen->enabled[0] = lru_gen_enabled() && lru_gen_nr_swapfiles; -+ lrugen->enabled[1] = lru_gen_enabled(); -+ -+ for (i = 0; i <= MIN_NR_GENS + 1; i++) -+ lrugen->timestamps[i] = jiffies; -+ -+ for_each_gen_type_zone(gen, type, zone) -+ INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); -+} -+ -+#ifdef CONFIG_MEMCG -+void lru_gen_init_memcg(struct mem_cgroup *memcg) -+{ -+ int nid; -+ -+ for_each_node(nid) { -+ struct lruvec *lruvec = get_lruvec(nid, memcg); -+ -+ lru_gen_init_state(memcg, lruvec); -+ } -+} -+#endif -+ -+static int __init init_lru_gen(void) -+{ -+ BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); -+ BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); -+ -+ return 0; -+}; -+late_initcall(init_lru_gen); -+ -+#endif /* CONFIG_LRU_GEN */ -+ - static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) - { - unsigned long nr[NR_LRU_LISTS]; diff --git a/target/linux/generic/backport-5.15/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch b/target/linux/generic/backport-5.15/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch new file mode 100644 index 00000000000..5c143f3cfab --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch @@ -0,0 +1,842 @@ +From a9b328add8422921a0dbbef162730800e16e8cfd Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:02 -0600 +Subject: [PATCH 05/29] mm: multi-gen LRU: groundwork +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Evictable pages are divided into multiple generations for each lruvec. +The youngest generation number is stored in lrugen->max_seq for both +anon and file types as they are aged on an equal footing. The oldest +generation numbers are stored in lrugen->min_seq[] separately for anon +and file types as clean file pages can be evicted regardless of swap +constraints. These three variables are monotonically increasing. + +Generation numbers are truncated into order_base_2(MAX_NR_GENS+1) bits +in order to fit into the gen counter in page->flags. Each truncated +generation number is an index to lrugen->lists[]. The sliding window +technique is used to track at least MIN_NR_GENS and at most +MAX_NR_GENS generations. The gen counter stores a value within [1, +MAX_NR_GENS] while a page is on one of lrugen->lists[]. Otherwise it +stores 0. + +There are two conceptually independent procedures: "the aging", which +produces young generations, and "the eviction", which consumes old +generations. They form a closed-loop system, i.e., "the page reclaim". +Both procedures can be invoked from userspace for the purposes of working +set estimation and proactive reclaim. These techniques are commonly used +to optimize job scheduling (bin packing) in data centers [1][2]. + +To avoid confusion, the terms "hot" and "cold" will be applied to the +multi-gen LRU, as a new convention; the terms "active" and "inactive" will +be applied to the active/inactive LRU, as usual. + +The protection of hot pages and the selection of cold pages are based +on page access channels and patterns. There are two access channels: +one through page tables and the other through file descriptors. The +protection of the former channel is by design stronger because: +1. The uncertainty in determining the access patterns of the former + channel is higher due to the approximation of the accessed bit. +2. The cost of evicting the former channel is higher due to the TLB + flushes required and the likelihood of encountering the dirty bit. +3. The penalty of underprotecting the former channel is higher because + applications usually do not prepare themselves for major page + faults like they do for blocked I/O. E.g., GUI applications + commonly use dedicated I/O threads to avoid blocking rendering + threads. + +There are also two access patterns: one with temporal locality and the +other without. For the reasons listed above, the former channel is +assumed to follow the former pattern unless VM_SEQ_READ or VM_RAND_READ is +present; the latter channel is assumed to follow the latter pattern unless +outlying refaults have been observed [3][4]. + +The next patch will address the "outlying refaults". Three macros, i.e., +LRU_REFS_WIDTH, LRU_REFS_PGOFF and LRU_REFS_MASK, used later are added in +this patch to make the entire patchset less diffy. + +A page is added to the youngest generation on faulting. The aging needs +to check the accessed bit at least twice before handing this page over to +the eviction. The first check takes care of the accessed bit set on the +initial fault; the second check makes sure this page has not been used +since then. This protocol, AKA second chance, requires a minimum of two +generations, hence MIN_NR_GENS. + +[1] https://dl.acm.org/doi/10.1145/3297858.3304053 +[2] https://dl.acm.org/doi/10.1145/3503222.3507731 +[3] https://lwn.net/Articles/495543/ +[4] https://lwn.net/Articles/815342/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-6-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + fs/fuse/dev.c | 3 +- + include/linux/mm.h | 2 + + include/linux/mm_inline.h | 177 +++++++++++++++++++++++++++++- + include/linux/mmzone.h | 100 +++++++++++++++++ + include/linux/page-flags-layout.h | 13 ++- + include/linux/page-flags.h | 4 +- + include/linux/sched.h | 4 + + kernel/bounds.c | 5 + + mm/Kconfig | 8 ++ + mm/huge_memory.c | 3 +- + mm/memcontrol.c | 2 + + mm/memory.c | 25 +++++ + mm/mm_init.c | 6 +- + mm/mmzone.c | 2 + + mm/swap.c | 10 +- + mm/vmscan.c | 75 +++++++++++++ + 16 files changed, 425 insertions(+), 14 deletions(-) + +diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c +index d6b5339c56e2..4ec08f7c3e75 100644 +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -785,7 +785,8 @@ static int fuse_check_page(struct page *page) + 1 << PG_active | + 1 << PG_workingset | + 1 << PG_reclaim | +- 1 << PG_waiters))) { ++ 1 << PG_waiters | ++ LRU_GEN_MASK | LRU_REFS_MASK))) { + dump_page(page, "fuse: trying to steal weird page"); + return 1; + } +diff --git a/include/linux/mm.h b/include/linux/mm.h +index e4e1817bb3b8..699068f39aa0 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1093,6 +1093,8 @@ vm_fault_t finish_mkwrite_fault(struct vm_fault *vmf); + #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) + #define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) + #define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH) ++#define LRU_GEN_PGOFF (KASAN_TAG_PGOFF - LRU_GEN_WIDTH) ++#define LRU_REFS_PGOFF (LRU_GEN_PGOFF - LRU_REFS_WIDTH) + + /* + * Define the bit shifts to access each section. For non-existent +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index a822d6b690a5..65320d2b8f60 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -26,10 +26,13 @@ static inline int page_is_file_lru(struct page *page) + + static __always_inline void __update_lru_size(struct lruvec *lruvec, + enum lru_list lru, enum zone_type zid, +- int nr_pages) ++ long nr_pages) + { + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + ++ lockdep_assert_held(&lruvec->lru_lock); ++ WARN_ON_ONCE(nr_pages != (int)nr_pages); ++ + __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); + __mod_zone_page_state(&pgdat->node_zones[zid], + NR_ZONE_LRU_BASE + lru, nr_pages); +@@ -86,11 +89,177 @@ static __always_inline enum lru_list page_lru(struct page *page) + return lru; + } + ++#ifdef CONFIG_LRU_GEN ++ ++static inline bool lru_gen_enabled(void) ++{ ++ return true; ++} ++ ++static inline bool lru_gen_in_fault(void) ++{ ++ return current->in_lru_fault; ++} ++ ++static inline int lru_gen_from_seq(unsigned long seq) ++{ ++ return seq % MAX_NR_GENS; ++} ++ ++static inline int page_lru_gen(struct page *page) ++{ ++ unsigned long flags = READ_ONCE(page->flags); ++ ++ return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; ++} ++ ++static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) ++{ ++ unsigned long max_seq = lruvec->lrugen.max_seq; ++ ++ VM_WARN_ON_ONCE(gen >= MAX_NR_GENS); ++ ++ /* see the comment on MIN_NR_GENS */ ++ return gen == lru_gen_from_seq(max_seq) || gen == lru_gen_from_seq(max_seq - 1); ++} ++ ++static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, ++ int old_gen, int new_gen) ++{ ++ int type = page_is_file_lru(page); ++ int zone = page_zonenum(page); ++ int delta = thp_nr_pages(page); ++ enum lru_list lru = type * LRU_INACTIVE_FILE; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); ++ VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); ++ VM_WARN_ON_ONCE(old_gen == -1 && new_gen == -1); ++ ++ if (old_gen >= 0) ++ WRITE_ONCE(lrugen->nr_pages[old_gen][type][zone], ++ lrugen->nr_pages[old_gen][type][zone] - delta); ++ if (new_gen >= 0) ++ WRITE_ONCE(lrugen->nr_pages[new_gen][type][zone], ++ lrugen->nr_pages[new_gen][type][zone] + delta); ++ ++ /* addition */ ++ if (old_gen < 0) { ++ if (lru_gen_is_active(lruvec, new_gen)) ++ lru += LRU_ACTIVE; ++ __update_lru_size(lruvec, lru, zone, delta); ++ return; ++ } ++ ++ /* deletion */ ++ if (new_gen < 0) { ++ if (lru_gen_is_active(lruvec, old_gen)) ++ lru += LRU_ACTIVE; ++ __update_lru_size(lruvec, lru, zone, -delta); ++ return; ++ } ++} ++ ++static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ unsigned long seq; ++ unsigned long flags; ++ int gen = page_lru_gen(page); ++ int type = page_is_file_lru(page); ++ int zone = page_zonenum(page); ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ VM_WARN_ON_ONCE_PAGE(gen != -1, page); ++ ++ if (PageUnevictable(page)) ++ return false; ++ /* ++ * There are three common cases for this page: ++ * 1. If it's hot, e.g., freshly faulted in or previously hot and ++ * migrated, add it to the youngest generation. ++ * 2. If it's cold but can't be evicted immediately, i.e., an anon page ++ * not in swapcache or a dirty page pending writeback, add it to the ++ * second oldest generation. ++ * 3. Everything else (clean, cold) is added to the oldest generation. ++ */ ++ if (PageActive(page)) ++ seq = lrugen->max_seq; ++ else if ((type == LRU_GEN_ANON && !PageSwapCache(page)) || ++ (PageReclaim(page) && ++ (PageDirty(page) || PageWriteback(page)))) ++ seq = lrugen->min_seq[type] + 1; ++ else ++ seq = lrugen->min_seq[type]; ++ ++ gen = lru_gen_from_seq(seq); ++ flags = (gen + 1UL) << LRU_GEN_PGOFF; ++ /* see the comment on MIN_NR_GENS about PG_active */ ++ set_mask_bits(&page->flags, LRU_GEN_MASK | BIT(PG_active), flags); ++ ++ lru_gen_update_size(lruvec, page, -1, gen); ++ /* for rotate_reclaimable_page() */ ++ if (reclaiming) ++ list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); ++ else ++ list_add(&page->lru, &lrugen->lists[gen][type][zone]); ++ ++ return true; ++} ++ ++static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ unsigned long flags; ++ int gen = page_lru_gen(page); ++ ++ if (gen < 0) ++ return false; ++ ++ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ ++ /* for migrate_page_states() */ ++ flags = !reclaiming && lru_gen_is_active(lruvec, gen) ? BIT(PG_active) : 0; ++ flags = set_mask_bits(&page->flags, LRU_GEN_MASK, flags); ++ gen = ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; ++ ++ lru_gen_update_size(lruvec, page, gen, -1); ++ list_del(&page->lru); ++ ++ return true; ++} ++ ++#else /* !CONFIG_LRU_GEN */ ++ ++static inline bool lru_gen_enabled(void) ++{ ++ return false; ++} ++ ++static inline bool lru_gen_in_fault(void) ++{ ++ return false; ++} ++ ++static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ return false; ++} ++ ++static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ return false; ++} ++ ++#endif /* CONFIG_LRU_GEN */ ++ + static __always_inline void add_page_to_lru_list(struct page *page, + struct lruvec *lruvec) + { + enum lru_list lru = page_lru(page); + ++ if (lru_gen_add_page(lruvec, page, false)) ++ return; ++ + update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); + list_add(&page->lru, &lruvec->lists[lru]); + } +@@ -100,6 +269,9 @@ static __always_inline void add_page_to_lru_list_tail(struct page *page, + { + enum lru_list lru = page_lru(page); + ++ if (lru_gen_add_page(lruvec, page, true)) ++ return; ++ + update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); + list_add_tail(&page->lru, &lruvec->lists[lru]); + } +@@ -107,6 +279,9 @@ static __always_inline void add_page_to_lru_list_tail(struct page *page, + static __always_inline void del_page_from_lru_list(struct page *page, + struct lruvec *lruvec) + { ++ if (lru_gen_del_page(lruvec, page, false)) ++ return; ++ + list_del(&page->lru); + update_lru_size(lruvec, page_lru(page), page_zonenum(page), + -thp_nr_pages(page)); +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 6ba100216530..0c39f72184d0 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -294,6 +294,102 @@ enum lruvec_flags { + */ + }; + ++#endif /* !__GENERATING_BOUNDS_H */ ++ ++/* ++ * Evictable pages are divided into multiple generations. The youngest and the ++ * oldest generation numbers, max_seq and min_seq, are monotonically increasing. ++ * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An ++ * offset within MAX_NR_GENS, i.e., gen, indexes the LRU list of the ++ * corresponding generation. The gen counter in page->flags stores gen+1 while ++ * a page is on one of lrugen->lists[]. Otherwise it stores 0. ++ * ++ * A page is added to the youngest generation on faulting. The aging needs to ++ * check the accessed bit at least twice before handing this page over to the ++ * eviction. The first check takes care of the accessed bit set on the initial ++ * fault; the second check makes sure this page hasn't been used since then. ++ * This process, AKA second chance, requires a minimum of two generations, ++ * hence MIN_NR_GENS. And to maintain ABI compatibility with the active/inactive ++ * LRU, e.g., /proc/vmstat, these two generations are considered active; the ++ * rest of generations, if they exist, are considered inactive. See ++ * lru_gen_is_active(). ++ * ++ * PG_active is always cleared while a page is on one of lrugen->lists[] so that ++ * the aging needs not to worry about it. And it's set again when a page ++ * considered active is isolated for non-reclaiming purposes, e.g., migration. ++ * See lru_gen_add_page() and lru_gen_del_page(). ++ * ++ * MAX_NR_GENS is set to 4 so that the multi-gen LRU can support twice the ++ * number of categories of the active/inactive LRU when keeping track of ++ * accesses through page tables. This requires order_base_2(MAX_NR_GENS+1) bits ++ * in page->flags. ++ */ ++#define MIN_NR_GENS 2U ++#define MAX_NR_GENS 4U ++ ++#ifndef __GENERATING_BOUNDS_H ++ ++struct lruvec; ++ ++#define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) ++#define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) ++ ++#ifdef CONFIG_LRU_GEN ++ ++enum { ++ LRU_GEN_ANON, ++ LRU_GEN_FILE, ++}; ++ ++/* ++ * The youngest generation number is stored in max_seq for both anon and file ++ * types as they are aged on an equal footing. The oldest generation numbers are ++ * stored in min_seq[] separately for anon and file types as clean file pages ++ * can be evicted regardless of swap constraints. ++ * ++ * Normally anon and file min_seq are in sync. But if swapping is constrained, ++ * e.g., out of swap space, file min_seq is allowed to advance and leave anon ++ * min_seq behind. ++ * ++ * The number of pages in each generation is eventually consistent and therefore ++ * can be transiently negative. ++ */ ++struct lru_gen_struct { ++ /* the aging increments the youngest generation number */ ++ unsigned long max_seq; ++ /* the eviction increments the oldest generation numbers */ ++ unsigned long min_seq[ANON_AND_FILE]; ++ /* the multi-gen LRU lists, lazily sorted on eviction */ ++ struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ /* the multi-gen LRU sizes, eventually consistent */ ++ long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++}; ++ ++void lru_gen_init_lruvec(struct lruvec *lruvec); ++ ++#ifdef CONFIG_MEMCG ++void lru_gen_init_memcg(struct mem_cgroup *memcg); ++void lru_gen_exit_memcg(struct mem_cgroup *memcg); ++#endif ++ ++#else /* !CONFIG_LRU_GEN */ ++ ++static inline void lru_gen_init_lruvec(struct lruvec *lruvec) ++{ ++} ++ ++#ifdef CONFIG_MEMCG ++static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) ++{ ++} ++#endif ++ ++#endif /* CONFIG_LRU_GEN */ ++ + struct lruvec { + struct list_head lists[NR_LRU_LISTS]; + /* per lruvec lru_lock for memcg */ +@@ -311,6 +407,10 @@ struct lruvec { + unsigned long refaults[ANON_AND_FILE]; + /* Various lruvec state flags (enum lruvec_flags) */ + unsigned long flags; ++#ifdef CONFIG_LRU_GEN ++ /* evictable pages divided into generations */ ++ struct lru_gen_struct lrugen; ++#endif + #ifdef CONFIG_MEMCG + struct pglist_data *pgdat; + #endif +diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h +index ef1e3e736e14..240905407a18 100644 +--- a/include/linux/page-flags-layout.h ++++ b/include/linux/page-flags-layout.h +@@ -55,7 +55,8 @@ + #define SECTIONS_WIDTH 0 + #endif + +-#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS ++#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_SHIFT \ ++ <= BITS_PER_LONG - NR_PAGEFLAGS + #define NODES_WIDTH NODES_SHIFT + #elif defined(CONFIG_SPARSEMEM_VMEMMAP) + #error "Vmemmap: No space for nodes field in page flags" +@@ -89,8 +90,8 @@ + #define LAST_CPUPID_SHIFT 0 + #endif + +-#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT \ +- <= BITS_PER_LONG - NR_PAGEFLAGS ++#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ ++ KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS + #define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT + #else + #define LAST_CPUPID_WIDTH 0 +@@ -100,10 +101,12 @@ + #define LAST_CPUPID_NOT_IN_PAGE_FLAGS + #endif + +-#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH \ +- > BITS_PER_LONG - NR_PAGEFLAGS ++#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ ++ KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS + #error "Not enough bits in page flags" + #endif + ++#define LRU_REFS_WIDTH 0 ++ + #endif + #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ +diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h +index fbfd3fad48f2..a7d7ff4c621d 100644 +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -845,7 +845,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) + 1UL << PG_private | 1UL << PG_private_2 | \ + 1UL << PG_writeback | 1UL << PG_reserved | \ + 1UL << PG_slab | 1UL << PG_active | \ +- 1UL << PG_unevictable | __PG_MLOCKED) ++ 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) + + /* + * Flags checked when a page is prepped for return by the page allocator. +@@ -856,7 +856,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) + * alloc-free cycle to prevent from reusing the page. + */ + #define PAGE_FLAGS_CHECK_AT_PREP \ +- (PAGEFLAGS_MASK & ~__PG_HWPOISON) ++ ((PAGEFLAGS_MASK & ~__PG_HWPOISON) | LRU_GEN_MASK | LRU_REFS_MASK) + + #define PAGE_FLAGS_PRIVATE \ + (1UL << PG_private | 1UL << PG_private_2) +diff --git a/include/linux/sched.h b/include/linux/sched.h +index e418935f8db6..545f6b1ccd50 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -911,6 +911,10 @@ struct task_struct { + #ifdef CONFIG_MEMCG + unsigned in_user_fault:1; + #endif ++#ifdef CONFIG_LRU_GEN ++ /* whether the LRU algorithm may apply to this access */ ++ unsigned in_lru_fault:1; ++#endif + #ifdef CONFIG_COMPAT_BRK + unsigned brk_randomized:1; + #endif +diff --git a/kernel/bounds.c b/kernel/bounds.c +index 9795d75b09b2..5ee60777d8e4 100644 +--- a/kernel/bounds.c ++++ b/kernel/bounds.c +@@ -22,6 +22,11 @@ int main(void) + DEFINE(NR_CPUS_BITS, ilog2(CONFIG_NR_CPUS)); + #endif + DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); ++#ifdef CONFIG_LRU_GEN ++ DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); ++#else ++ DEFINE(LRU_GEN_WIDTH, 0); ++#endif + /* End of constants */ + + return 0; +diff --git a/mm/Kconfig b/mm/Kconfig +index c048dea7e342..0eeb27397884 100644 +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -897,6 +897,14 @@ config IO_MAPPING + config SECRETMEM + def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED + ++config LRU_GEN ++ bool "Multi-Gen LRU" ++ depends on MMU ++ # make sure page->flags has enough spare bits ++ depends on 64BIT || !SPARSEMEM || SPARSEMEM_VMEMMAP ++ help ++ A high performance LRU implementation to overcommit memory. ++ + source "mm/damon/Kconfig" + + endmenu +diff --git a/mm/huge_memory.c b/mm/huge_memory.c +index 98ff57c8eda6..f260ef82f03a 100644 +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -2366,7 +2366,8 @@ static void __split_huge_page_tail(struct page *head, int tail, + #ifdef CONFIG_64BIT + (1L << PG_arch_2) | + #endif +- (1L << PG_dirty))); ++ (1L << PG_dirty) | ++ LRU_GEN_MASK | LRU_REFS_MASK)); + + /* ->mapping in first tail page is compound_mapcount */ + VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING, +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index b68b2fe639fd..8b634dc72e7f 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -5178,6 +5178,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg) + + static void mem_cgroup_free(struct mem_cgroup *memcg) + { ++ lru_gen_exit_memcg(memcg); + memcg_wb_domain_exit(memcg); + __mem_cgroup_free(memcg); + } +@@ -5241,6 +5242,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void) + memcg->deferred_split_queue.split_queue_len = 0; + #endif + idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); ++ lru_gen_init_memcg(memcg); + return memcg; + fail: + mem_cgroup_id_remove(memcg); +diff --git a/mm/memory.c b/mm/memory.c +index 392b7326a2d2..7d5be951de9e 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -4778,6 +4778,27 @@ static inline void mm_account_fault(struct pt_regs *regs, + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); + } + ++#ifdef CONFIG_LRU_GEN ++static void lru_gen_enter_fault(struct vm_area_struct *vma) ++{ ++ /* the LRU algorithm doesn't apply to sequential or random reads */ ++ current->in_lru_fault = !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)); ++} ++ ++static void lru_gen_exit_fault(void) ++{ ++ current->in_lru_fault = false; ++} ++#else ++static void lru_gen_enter_fault(struct vm_area_struct *vma) ++{ ++} ++ ++static void lru_gen_exit_fault(void) ++{ ++} ++#endif /* CONFIG_LRU_GEN */ ++ + /* + * By the time we get here, we already hold the mm semaphore + * +@@ -4809,11 +4830,15 @@ vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address, + if (flags & FAULT_FLAG_USER) + mem_cgroup_enter_user_fault(); + ++ lru_gen_enter_fault(vma); ++ + if (unlikely(is_vm_hugetlb_page(vma))) + ret = hugetlb_fault(vma->vm_mm, vma, address, flags); + else + ret = __handle_mm_fault(vma, address, flags); + ++ lru_gen_exit_fault(); ++ + if (flags & FAULT_FLAG_USER) { + mem_cgroup_exit_user_fault(); + /* +diff --git a/mm/mm_init.c b/mm/mm_init.c +index 9ddaf0e1b0ab..0d7b2bd2454a 100644 +--- a/mm/mm_init.c ++++ b/mm/mm_init.c +@@ -65,14 +65,16 @@ void __init mminit_verify_pageflags_layout(void) + + shift = 8 * sizeof(unsigned long); + width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH +- - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH; ++ - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH - LRU_GEN_WIDTH - LRU_REFS_WIDTH; + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", +- "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Flags %d\n", ++ "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Gen %d Tier %d Flags %d\n", + SECTIONS_WIDTH, + NODES_WIDTH, + ZONES_WIDTH, + LAST_CPUPID_WIDTH, + KASAN_TAG_WIDTH, ++ LRU_GEN_WIDTH, ++ LRU_REFS_WIDTH, + NR_PAGEFLAGS); + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", + "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d\n", +diff --git a/mm/mmzone.c b/mm/mmzone.c +index eb89d6e018e2..2ec0d7793424 100644 +--- a/mm/mmzone.c ++++ b/mm/mmzone.c +@@ -81,6 +81,8 @@ void lruvec_init(struct lruvec *lruvec) + + for_each_lru(lru) + INIT_LIST_HEAD(&lruvec->lists[lru]); ++ ++ lru_gen_init_lruvec(lruvec); + } + + #if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) +diff --git a/mm/swap.c b/mm/swap.c +index af3cad4e5378..0bdc96661fb6 100644 +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -446,6 +446,11 @@ void lru_cache_add(struct page *page) + VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageLRU(page), page); + ++ /* see the comment in lru_gen_add_page() */ ++ if (lru_gen_enabled() && !PageUnevictable(page) && ++ lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) ++ SetPageActive(page); ++ + get_page(page); + local_lock(&lru_pvecs.lock); + pvec = this_cpu_ptr(&lru_pvecs.lru_add); +@@ -547,7 +552,7 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec) + + static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec) + { +- if (PageActive(page) && !PageUnevictable(page)) { ++ if (!PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { + int nr_pages = thp_nr_pages(page); + + del_page_from_lru_list(page, lruvec); +@@ -661,7 +666,8 @@ void deactivate_file_page(struct page *page) + */ + void deactivate_page(struct page *page) + { +- if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { ++ if (PageLRU(page) && !PageUnevictable(page) && ++ (PageActive(page) || lru_gen_enabled())) { + struct pagevec *pvec; + + local_lock(&lru_pvecs.lock); +diff --git a/mm/vmscan.c b/mm/vmscan.c +index dc5f0381513f..41826fe17eb3 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2821,6 +2821,81 @@ static bool can_age_anon_pages(struct pglist_data *pgdat, + return can_demote(pgdat->node_id, sc); + } + ++#ifdef CONFIG_LRU_GEN ++ ++/****************************************************************************** ++ * shorthand helpers ++ ******************************************************************************/ ++ ++#define for_each_gen_type_zone(gen, type, zone) \ ++ for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ ++ for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ ++ for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) ++ ++static struct lruvec __maybe_unused *get_lruvec(struct mem_cgroup *memcg, int nid) ++{ ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ ++#ifdef CONFIG_MEMCG ++ if (memcg) { ++ struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; ++ ++ /* for hotadd_new_pgdat() */ ++ if (!lruvec->pgdat) ++ lruvec->pgdat = pgdat; ++ ++ return lruvec; ++ } ++#endif ++ VM_WARN_ON_ONCE(!mem_cgroup_disabled()); ++ ++ return pgdat ? &pgdat->__lruvec : NULL; ++} ++ ++/****************************************************************************** ++ * initialization ++ ******************************************************************************/ ++ ++void lru_gen_init_lruvec(struct lruvec *lruvec) ++{ ++ int gen, type, zone; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ lrugen->max_seq = MIN_NR_GENS + 1; ++ ++ for_each_gen_type_zone(gen, type, zone) ++ INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); ++} ++ ++#ifdef CONFIG_MEMCG ++void lru_gen_init_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++void lru_gen_exit_memcg(struct mem_cgroup *memcg) ++{ ++ int nid; ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, ++ sizeof(lruvec->lrugen.nr_pages))); ++ } ++} ++#endif ++ ++static int __init init_lru_gen(void) ++{ ++ BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); ++ BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); ++ ++ return 0; ++}; ++late_initcall(init_lru_gen); ++ ++#endif /* CONFIG_LRU_GEN */ ++ + static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { + unsigned long nr[NR_LRU_LISTS]; +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-05-mm-multigenerational-lru-mm_struct-list.patch b/target/linux/generic/backport-5.15/020-v6.1-05-mm-multigenerational-lru-mm_struct-list.patch deleted file mode 100644 index a1c6e0f75d9..00000000000 --- a/target/linux/generic/backport-5.15/020-v6.1-05-mm-multigenerational-lru-mm_struct-list.patch +++ /dev/null @@ -1,760 +0,0 @@ -From 534bcc4a0bb5b24600891ce793f0295a142e9dae Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Mon, 5 Apr 2021 04:17:41 -0600 -Subject: [PATCH 05/10] mm: multigenerational lru: mm_struct list - -To scan PTEs for accessed pages, a mm_struct list is maintained for -each memcg. When multiple threads traverse the same memcg->mm_list, -each of them gets a unique mm_struct and therefore they can run -walk_page_range() concurrently to reach page tables of all processes -of this memcg. - -This infrastructure also provides the following optimizations: - 1) it allows walkers to skip processes that have been sleeping since - the last walk by tracking the usage of mm_struct between context - switches. - 2) it allows walkers to add interesting items they find during a - walk to a Bloom filter so that they can skip uninteresting items - during the next walk by testing whether an item is in this Bloom - filter. - -Signed-off-by: Yu Zhao -Tested-by: Konstantin Kharlamov -Change-Id: I25d9eda8c6bdc7c3653b9f210a159d6c247c81e8 ---- - fs/exec.c | 2 + - include/linux/memcontrol.h | 4 + - include/linux/mm_inline.h | 6 + - include/linux/mm_types.h | 75 +++++++++ - include/linux/mmzone.h | 63 +++++++ - kernel/exit.c | 1 + - kernel/fork.c | 9 + - kernel/sched/core.c | 1 + - mm/memcontrol.c | 25 +++ - mm/vmscan.c | 331 +++++++++++++++++++++++++++++++++++++ - 10 files changed, 517 insertions(+) - ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -1013,6 +1013,7 @@ static int exec_mmap(struct mm_struct *m - active_mm = tsk->active_mm; - tsk->active_mm = mm; - tsk->mm = mm; -+ lru_gen_add_mm(mm); - /* - * This prevents preemption while active_mm is being loaded and - * it and mm are being updated, which could cause problems for -@@ -1023,6 +1024,7 @@ static int exec_mmap(struct mm_struct *m - if (!IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) - local_irq_enable(); - activate_mm(active_mm, mm); -+ lru_gen_activate_mm(mm); - if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) - local_irq_enable(); - tsk->mm->vmacache_seqnum = 0; ---- a/include/linux/memcontrol.h -+++ b/include/linux/memcontrol.h -@@ -348,6 +348,10 @@ struct mem_cgroup { - struct deferred_split deferred_split_queue; - #endif - -+#ifdef CONFIG_LRU_GEN -+ struct lru_gen_mm_list mm_list; -+#endif -+ - struct mem_cgroup_per_node *nodeinfo[]; - }; - ---- a/include/linux/mm_inline.h -+++ b/include/linux/mm_inline.h -@@ -100,6 +100,12 @@ static inline int lru_gen_from_seq(unsig - return seq % MAX_NR_GENS; - } - -+/* Return a proper index regardless whether we keep stats for historical generations. */ -+static inline int lru_hist_from_seq(unsigned long seq) -+{ -+ return seq % NR_HIST_GENS; -+} -+ - /* The youngest and the second youngest generations are counted as active. */ - static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) - { ---- a/include/linux/mm_types.h -+++ b/include/linux/mm_types.h -@@ -3,6 +3,7 @@ - #define _LINUX_MM_TYPES_H - - #include -+#include - - #include - #include -@@ -15,6 +16,8 @@ - #include - #include - #include -+#include -+#include - - #include - -@@ -580,6 +583,18 @@ struct mm_struct { - #ifdef CONFIG_IOMMU_SUPPORT - u32 pasid; - #endif -+#ifdef CONFIG_LRU_GEN -+ struct { -+ /* the node of a global or per-memcg mm_struct list */ -+ struct list_head list; -+#ifdef CONFIG_MEMCG -+ /* points to the memcg of the owner task above */ -+ struct mem_cgroup *memcg; -+#endif -+ /* whether this mm_struct has been used since the last walk */ -+ nodemask_t nodes; -+ } lrugen; -+#endif /* CONFIG_LRU_GEN */ - } __randomize_layout; - - /* -@@ -606,6 +621,66 @@ static inline cpumask_t *mm_cpumask(stru - return (struct cpumask *)&mm->cpu_bitmap; - } - -+#ifdef CONFIG_LRU_GEN -+ -+struct lru_gen_mm_list { -+ /* a global or per-memcg mm_struct list */ -+ struct list_head fifo; -+ /* protects the list above */ -+ spinlock_t lock; -+}; -+ -+void lru_gen_add_mm(struct mm_struct *mm); -+void lru_gen_del_mm(struct mm_struct *mm); -+#ifdef CONFIG_MEMCG -+void lru_gen_migrate_mm(struct mm_struct *mm); -+#endif -+ -+static inline void lru_gen_init_mm(struct mm_struct *mm) -+{ -+ INIT_LIST_HEAD(&mm->lrugen.list); -+#ifdef CONFIG_MEMCG -+ mm->lrugen.memcg = NULL; -+#endif -+ nodes_clear(mm->lrugen.nodes); -+} -+ -+/* Track the usage of each mm_struct so that we can skip inactive ones. */ -+static inline void lru_gen_activate_mm(struct mm_struct *mm) -+{ -+ /* unlikely but not a bug when racing with lru_gen_migrate_mm() */ -+ VM_WARN_ON(list_empty(&mm->lrugen.list)); -+ -+ if (!(current->flags & PF_KTHREAD) && !nodes_full(mm->lrugen.nodes)) -+ nodes_setall(mm->lrugen.nodes); -+} -+ -+#else /* !CONFIG_LRU_GEN */ -+ -+static inline void lru_gen_add_mm(struct mm_struct *mm) -+{ -+} -+ -+static inline void lru_gen_del_mm(struct mm_struct *mm) -+{ -+} -+ -+#ifdef CONFIG_MEMCG -+static inline void lru_gen_migrate_mm(struct mm_struct *mm) -+{ -+} -+#endif -+ -+static inline void lru_gen_init_mm(struct mm_struct *mm) -+{ -+} -+ -+static inline void lru_gen_activate_mm(struct mm_struct *mm) -+{ -+} -+ -+#endif /* CONFIG_LRU_GEN */ -+ - struct mmu_gather; - extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm); - extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm); ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -318,6 +318,13 @@ struct lruvec; - #define MIN_NR_GENS 2 - #define MAX_NR_GENS ((unsigned int)CONFIG_NR_LRU_GENS) - -+/* Whether to keep stats for historical generations. */ -+#ifdef CONFIG_LRU_GEN_STATS -+#define NR_HIST_GENS ((unsigned int)CONFIG_NR_LRU_GENS) -+#else -+#define NR_HIST_GENS 1U -+#endif -+ - struct lrugen { - /* the aging increments the max generation number */ - unsigned long max_seq; -@@ -333,13 +340,63 @@ struct lrugen { - bool enabled[ANON_AND_FILE]; - }; - -+enum { -+ MM_LEAF_TOTAL, /* total leaf entries */ -+ MM_LEAF_OLD, /* old leaf entries */ -+ MM_LEAF_YOUNG, /* young leaf entries */ -+ MM_NONLEAF_TOTAL, /* total non-leaf entries */ -+ MM_NONLEAF_PREV, /* previously worthy non-leaf entries */ -+ MM_NONLEAF_CUR, /* currently worthy non-leaf entries */ -+ NR_MM_STATS -+}; -+ -+/* mnemonic codes for the stats above */ -+#define MM_STAT_CODES "toydpc" -+ -+/* double buffering bloom filters */ -+#define NR_BLOOM_FILTERS 2 -+ -+struct lru_gen_mm_walk { -+ /* set to max_seq after each round of walk */ -+ unsigned long seq; -+ /* the next mm_struct on the list to walk */ -+ struct list_head *head; -+ /* the first mm_struct never walked before */ -+ struct list_head *tail; -+ /* to wait for the last walker to finish */ -+ struct wait_queue_head wait; -+ /* bloom filters flip after each round of walk */ -+ unsigned long *filters[NR_BLOOM_FILTERS]; -+ /* page table stats for debugging */ -+ unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; -+ /* the number of concurrent walkers */ -+ int nr_walkers; -+}; -+ -+#define MIN_BATCH_SIZE 64 - #define MAX_BATCH_SIZE 8192 - -+struct mm_walk_args { -+ struct mem_cgroup *memcg; -+ unsigned long max_seq; -+ unsigned long start_pfn; -+ unsigned long end_pfn; -+ unsigned long next_addr; -+ unsigned long bitmap[BITS_TO_LONGS(MIN_BATCH_SIZE)]; -+ int node_id; -+ int swappiness; -+ int batch_size; -+ int nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+ int mm_stats[NR_MM_STATS]; -+ bool use_filter; -+}; -+ - void lru_gen_init_state(struct mem_cgroup *memcg, struct lruvec *lruvec); - void lru_gen_change_state(bool enable, bool main, bool swap); - - #ifdef CONFIG_MEMCG - void lru_gen_init_memcg(struct mem_cgroup *memcg); -+void lru_gen_free_memcg(struct mem_cgroup *memcg); - #endif - - #else /* !CONFIG_LRU_GEN */ -@@ -356,6 +413,10 @@ static inline void lru_gen_change_state( - static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) - { - } -+ -+static inline void lru_gen_free_memcg(struct mem_cgroup *memcg) -+{ -+} - #endif - - #endif /* CONFIG_LRU_GEN */ -@@ -380,6 +441,8 @@ struct lruvec { - #ifdef CONFIG_LRU_GEN - /* unevictable pages are on LRU_UNEVICTABLE */ - struct lrugen evictable; -+ /* state for mm list and page table walks */ -+ struct lru_gen_mm_walk mm_walk; - #endif - #ifdef CONFIG_MEMCG - struct pglist_data *pgdat; ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -469,6 +469,7 @@ assign_new_owner: - goto retry; - } - WRITE_ONCE(mm->owner, c); -+ lru_gen_migrate_mm(mm); - task_unlock(c); - put_task_struct(c); - } ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -1083,6 +1083,7 @@ static struct mm_struct *mm_init(struct - goto fail_nocontext; - - mm->user_ns = get_user_ns(user_ns); -+ lru_gen_init_mm(mm); - return mm; - - fail_nocontext: -@@ -1125,6 +1126,7 @@ static inline void __mmput(struct mm_str - } - if (mm->binfmt) - module_put(mm->binfmt->module); -+ lru_gen_del_mm(mm); - mmdrop(mm); - } - -@@ -2622,6 +2624,13 @@ pid_t kernel_clone(struct kernel_clone_a - get_task_struct(p); - } - -+ if (IS_ENABLED(CONFIG_LRU_GEN) && !(clone_flags & CLONE_VM)) { -+ /* lock the task to synchronize with memcg migration */ -+ task_lock(p); -+ lru_gen_add_mm(p->mm); -+ task_unlock(p); -+ } -+ - wake_up_new_task(p); - - /* forking complete and child started to run, tell ptracer */ ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -5007,6 +5007,7 @@ context_switch(struct rq *rq, struct tas - * finish_task_switch()'s mmdrop(). - */ - switch_mm_irqs_off(prev->active_mm, next->mm, next); -+ lru_gen_activate_mm(next->mm); - - if (!prev->mm) { // from kernel - /* will mmdrop() in finish_task_switch(). */ ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -5178,6 +5178,7 @@ static void __mem_cgroup_free(struct mem - - static void mem_cgroup_free(struct mem_cgroup *memcg) - { -+ lru_gen_free_memcg(memcg); - memcg_wb_domain_exit(memcg); - __mem_cgroup_free(memcg); - } -@@ -6210,6 +6211,29 @@ static void mem_cgroup_move_task(void) - } - #endif - -+#ifdef CONFIG_LRU_GEN -+static void mem_cgroup_attach(struct cgroup_taskset *tset) -+{ -+ struct cgroup_subsys_state *css; -+ struct task_struct *task = NULL; -+ -+ cgroup_taskset_for_each_leader(task, css, tset) -+ break; -+ -+ if (!task) -+ return; -+ -+ task_lock(task); -+ if (task->mm && task->mm->owner == task) -+ lru_gen_migrate_mm(task->mm); -+ task_unlock(task); -+} -+#else -+static void mem_cgroup_attach(struct cgroup_taskset *tset) -+{ -+} -+#endif /* CONFIG_LRU_GEN */ -+ - static int seq_puts_memcg_tunable(struct seq_file *m, unsigned long value) - { - if (value == PAGE_COUNTER_MAX) -@@ -6553,6 +6577,7 @@ struct cgroup_subsys memory_cgrp_subsys - .css_reset = mem_cgroup_css_reset, - .css_rstat_flush = mem_cgroup_css_rstat_flush, - .can_attach = mem_cgroup_can_attach, -+ .attach = mem_cgroup_attach, - .cancel_attach = mem_cgroup_cancel_attach, - .post_attach = mem_cgroup_move_task, - .dfl_cftypes = memory_files, ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -2864,6 +2864,306 @@ static bool __maybe_unused seq_is_valid( - } - - /****************************************************************************** -+ * mm_struct list -+ ******************************************************************************/ -+ -+static struct lru_gen_mm_list *get_mm_list(struct mem_cgroup *memcg) -+{ -+ static struct lru_gen_mm_list mm_list = { -+ .fifo = LIST_HEAD_INIT(mm_list.fifo), -+ .lock = __SPIN_LOCK_UNLOCKED(mm_list.lock), -+ }; -+ -+#ifdef CONFIG_MEMCG -+ if (memcg) -+ return &memcg->mm_list; -+#endif -+ return &mm_list; -+} -+ -+void lru_gen_add_mm(struct mm_struct *mm) -+{ -+ int nid; -+ struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm); -+ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); -+ -+ VM_BUG_ON_MM(!list_empty(&mm->lrugen.list), mm); -+#ifdef CONFIG_MEMCG -+ VM_BUG_ON_MM(mm->lrugen.memcg, mm); -+ mm->lrugen.memcg = memcg; -+#endif -+ spin_lock(&mm_list->lock); -+ -+ list_add_tail(&mm->lrugen.list, &mm_list->fifo); -+ -+ for_each_node(nid) { -+ struct lruvec *lruvec = get_lruvec(nid, memcg); -+ -+ if (!lruvec) -+ continue; -+ -+ if (lruvec->mm_walk.tail == &mm_list->fifo) -+ lruvec->mm_walk.tail = lruvec->mm_walk.tail->prev; -+ } -+ -+ spin_unlock(&mm_list->lock); -+} -+ -+void lru_gen_del_mm(struct mm_struct *mm) -+{ -+ int nid; -+ struct lru_gen_mm_list *mm_list; -+ struct mem_cgroup *memcg = NULL; -+ -+ if (list_empty(&mm->lrugen.list)) -+ return; -+ -+#ifdef CONFIG_MEMCG -+ memcg = mm->lrugen.memcg; -+#endif -+ mm_list = get_mm_list(memcg); -+ -+ spin_lock(&mm_list->lock); -+ -+ for_each_node(nid) { -+ struct lruvec *lruvec = get_lruvec(nid, memcg); -+ -+ if (!lruvec) -+ continue; -+ -+ if (lruvec->mm_walk.tail == &mm->lrugen.list) -+ lruvec->mm_walk.tail = lruvec->mm_walk.tail->next; -+ -+ if (lruvec->mm_walk.head != &mm->lrugen.list) -+ continue; -+ -+ lruvec->mm_walk.head = lruvec->mm_walk.head->next; -+ if (lruvec->mm_walk.head == &mm_list->fifo) -+ WRITE_ONCE(lruvec->mm_walk.seq, lruvec->mm_walk.seq + 1); -+ } -+ -+ list_del_init(&mm->lrugen.list); -+ -+ spin_unlock(&mm_list->lock); -+ -+#ifdef CONFIG_MEMCG -+ mem_cgroup_put(mm->lrugen.memcg); -+ mm->lrugen.memcg = NULL; -+#endif -+} -+ -+#ifdef CONFIG_MEMCG -+void lru_gen_migrate_mm(struct mm_struct *mm) -+{ -+ struct mem_cgroup *memcg; -+ -+ lockdep_assert_held(&mm->owner->alloc_lock); -+ -+ if (mem_cgroup_disabled()) -+ return; -+ -+ rcu_read_lock(); -+ memcg = mem_cgroup_from_task(mm->owner); -+ rcu_read_unlock(); -+ if (memcg == mm->lrugen.memcg) -+ return; -+ -+ VM_BUG_ON_MM(!mm->lrugen.memcg, mm); -+ VM_BUG_ON_MM(list_empty(&mm->lrugen.list), mm); -+ -+ lru_gen_del_mm(mm); -+ lru_gen_add_mm(mm); -+} -+#endif -+ -+#define BLOOM_FILTER_SHIFT 15 -+ -+static inline int filter_gen_from_seq(unsigned long seq) -+{ -+ return seq % NR_BLOOM_FILTERS; -+} -+ -+static void get_item_key(void *item, int *key) -+{ -+ u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); -+ -+ BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); -+ -+ key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); -+ key[1] = hash >> BLOOM_FILTER_SHIFT; -+} -+ -+static void clear_bloom_filter(struct lruvec *lruvec, unsigned long seq) -+{ -+ unsigned long *filter; -+ int gen = filter_gen_from_seq(seq); -+ -+ lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); -+ -+ filter = lruvec->mm_walk.filters[gen]; -+ if (filter) { -+ bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); -+ return; -+ } -+ -+ filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), GFP_ATOMIC); -+ WRITE_ONCE(lruvec->mm_walk.filters[gen], filter); -+} -+ -+static void set_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) -+{ -+ int key[2]; -+ unsigned long *filter; -+ int gen = filter_gen_from_seq(seq); -+ -+ filter = READ_ONCE(lruvec->mm_walk.filters[gen]); -+ if (!filter) -+ return; -+ -+ get_item_key(item, key); -+ -+ if (!test_bit(key[0], filter)) -+ set_bit(key[0], filter); -+ if (!test_bit(key[1], filter)) -+ set_bit(key[1], filter); -+} -+ -+static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) -+{ -+ int key[2]; -+ unsigned long *filter; -+ int gen = filter_gen_from_seq(seq); -+ -+ filter = READ_ONCE(lruvec->mm_walk.filters[gen]); -+ if (!filter) -+ return false; -+ -+ get_item_key(item, key); -+ -+ return test_bit(key[0], filter) && test_bit(key[1], filter); -+} -+ -+static void reset_mm_stats(struct lruvec *lruvec, bool last, struct mm_walk_args *args) -+{ -+ int i; -+ int hist = lru_hist_from_seq(args->max_seq); -+ -+ lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); -+ -+ for (i = 0; i < NR_MM_STATS; i++) { -+ WRITE_ONCE(lruvec->mm_walk.stats[hist][i], -+ lruvec->mm_walk.stats[hist][i] + args->mm_stats[i]); -+ args->mm_stats[i] = 0; -+ } -+ -+ if (!last || NR_HIST_GENS == 1) -+ return; -+ -+ hist = lru_hist_from_seq(args->max_seq + 1); -+ for (i = 0; i < NR_MM_STATS; i++) -+ WRITE_ONCE(lruvec->mm_walk.stats[hist][i], 0); -+} -+ -+static bool should_skip_mm(struct mm_struct *mm, struct mm_walk_args *args) -+{ -+ int type; -+ unsigned long size = 0; -+ -+ if (cpumask_empty(mm_cpumask(mm)) && !node_isset(args->node_id, mm->lrugen.nodes)) -+ return true; -+ -+ if (mm_is_oom_victim(mm)) -+ return true; -+ -+ for (type = !args->swappiness; type < ANON_AND_FILE; type++) { -+ size += type ? get_mm_counter(mm, MM_FILEPAGES) : -+ get_mm_counter(mm, MM_ANONPAGES) + -+ get_mm_counter(mm, MM_SHMEMPAGES); -+ } -+ -+ if (size < MIN_BATCH_SIZE) -+ return true; -+ -+ if (!mmget_not_zero(mm)) -+ return true; -+ -+ node_clear(args->node_id, mm->lrugen.nodes); -+ -+ return false; -+} -+ -+/* To support multiple walkers that concurrently walk an mm_struct list. */ -+static bool get_next_mm(struct lruvec *lruvec, struct mm_walk_args *args, -+ struct mm_struct **iter) -+{ -+ bool first = false; -+ bool last = true; -+ struct mm_struct *mm = NULL; -+ struct lru_gen_mm_walk *mm_walk = &lruvec->mm_walk; -+ struct lru_gen_mm_list *mm_list = get_mm_list(args->memcg); -+ -+ if (*iter) -+ mmput_async(*iter); -+ else if (args->max_seq <= READ_ONCE(mm_walk->seq)) -+ return false; -+ -+ spin_lock(&mm_list->lock); -+ -+ VM_BUG_ON(args->max_seq > mm_walk->seq + 1); -+ VM_BUG_ON(*iter && args->max_seq < mm_walk->seq); -+ VM_BUG_ON(*iter && !mm_walk->nr_walkers); -+ -+ if (args->max_seq <= mm_walk->seq) { -+ if (!*iter) -+ last = false; -+ goto done; -+ } -+ -+ if (mm_walk->head == &mm_list->fifo) { -+ VM_BUG_ON(mm_walk->nr_walkers); -+ mm_walk->head = mm_walk->head->next; -+ first = true; -+ } -+ -+ while (!mm && mm_walk->head != &mm_list->fifo) { -+ mm = list_entry(mm_walk->head, struct mm_struct, lrugen.list); -+ -+ mm_walk->head = mm_walk->head->next; -+ -+ if (mm_walk->tail == &mm->lrugen.list) { -+ mm_walk->tail = mm_walk->tail->next; -+ args->use_filter = false; -+ } -+ -+ if (should_skip_mm(mm, args)) -+ mm = NULL; -+ } -+ -+ if (mm_walk->head == &mm_list->fifo) -+ WRITE_ONCE(mm_walk->seq, mm_walk->seq + 1); -+done: -+ if (*iter && !mm) -+ mm_walk->nr_walkers--; -+ if (!*iter && mm) -+ mm_walk->nr_walkers++; -+ -+ if (mm_walk->nr_walkers) -+ last = false; -+ -+ if (mm && first) -+ clear_bloom_filter(lruvec, args->max_seq + 1); -+ -+ if (*iter || last) -+ reset_mm_stats(lruvec, last, args); -+ -+ spin_unlock(&mm_list->lock); -+ -+ *iter = mm; -+ -+ return last; -+} -+ -+/****************************************************************************** - * state change - ******************************************************************************/ - -@@ -3047,6 +3347,7 @@ void lru_gen_init_state(struct mem_cgrou - int i; - int gen, type, zone; - struct lrugen *lrugen = &lruvec->evictable; -+ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); - - lrugen->max_seq = MIN_NR_GENS + 1; - lrugen->enabled[0] = lru_gen_enabled() && lru_gen_nr_swapfiles; -@@ -3057,6 +3358,17 @@ void lru_gen_init_state(struct mem_cgrou - - for_each_gen_type_zone(gen, type, zone) - INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); -+ -+ if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG) && !memcg) -+ spin_lock(&mm_list->lock); -+ -+ lruvec->mm_walk.seq = MIN_NR_GENS; -+ lruvec->mm_walk.head = &mm_list->fifo; -+ lruvec->mm_walk.tail = &mm_list->fifo; -+ init_waitqueue_head(&lruvec->mm_walk.wait); -+ -+ if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG) && !memcg) -+ spin_unlock(&mm_list->lock); - } - - #ifdef CONFIG_MEMCG -@@ -3064,18 +3376,37 @@ void lru_gen_init_memcg(struct mem_cgrou - { - int nid; - -+ INIT_LIST_HEAD(&memcg->mm_list.fifo); -+ spin_lock_init(&memcg->mm_list.lock); -+ - for_each_node(nid) { - struct lruvec *lruvec = get_lruvec(nid, memcg); - - lru_gen_init_state(memcg, lruvec); - } - } -+ -+void lru_gen_free_memcg(struct mem_cgroup *memcg) -+{ -+ int nid; -+ -+ for_each_node(nid) { -+ int i; -+ struct lruvec *lruvec = get_lruvec(nid, memcg); -+ -+ for (i = 0; i < NR_BLOOM_FILTERS; i++) { -+ bitmap_free(lruvec->mm_walk.filters[i]); -+ lruvec->mm_walk.filters[i] = NULL; -+ } -+ } -+} - #endif - - static int __init init_lru_gen(void) - { - BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); - BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); -+ BUILD_BUG_ON(sizeof(MM_STAT_CODES) != NR_MM_STATS + 1); - - return 0; - }; diff --git a/target/linux/generic/backport-5.15/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch b/target/linux/generic/backport-5.15/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch new file mode 100644 index 00000000000..1e310ae2111 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch @@ -0,0 +1,1466 @@ +From b564b9471cd60ef1ee3961a224898ce4a9620d84 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:03 -0600 +Subject: [PATCH 06/29] mm: multi-gen LRU: minimal implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To avoid confusion, the terms "promotion" and "demotion" will be applied +to the multi-gen LRU, as a new convention; the terms "activation" and +"deactivation" will be applied to the active/inactive LRU, as usual. + +The aging produces young generations. Given an lruvec, it increments +max_seq when max_seq-min_seq+1 approaches MIN_NR_GENS. The aging promotes +hot pages to the youngest generation when it finds them accessed through +page tables; the demotion of cold pages happens consequently when it +increments max_seq. Promotion in the aging path does not involve any LRU +list operations, only the updates of the gen counter and +lrugen->nr_pages[]; demotion, unless as the result of the increment of +max_seq, requires LRU list operations, e.g., lru_deactivate_fn(). The +aging has the complexity O(nr_hot_pages), since it is only interested in +hot pages. + +The eviction consumes old generations. Given an lruvec, it increments +min_seq when lrugen->lists[] indexed by min_seq%MAX_NR_GENS becomes empty. +A feedback loop modeled after the PID controller monitors refaults over +anon and file types and decides which type to evict when both types are +available from the same generation. + +The protection of pages accessed multiple times through file descriptors +takes place in the eviction path. Each generation is divided into +multiple tiers. A page accessed N times through file descriptors is in +tier order_base_2(N). Tiers do not have dedicated lrugen->lists[], only +bits in page->flags. The aforementioned feedback loop also monitors +refaults over all tiers and decides when to protect pages in which tiers +(N>1), using the first tier (N=0,1) as a baseline. The first tier +contains single-use unmapped clean pages, which are most likely the best +choices. In contrast to promotion in the aging path, the protection of a +page in the eviction path is achieved by moving this page to the next +generation, i.e., min_seq+1, if the feedback loop decides so. This +approach has the following advantages: + +1. It removes the cost of activation in the buffered access path by + inferring whether pages accessed multiple times through file + descriptors are statistically hot and thus worth protecting in the + eviction path. +2. It takes pages accessed through page tables into account and avoids + overprotecting pages accessed multiple times through file + descriptors. (Pages accessed through page tables are in the first + tier, since N=0.) +3. More tiers provide better protection for pages accessed more than + twice through file descriptors, when under heavy buffered I/O + workloads. + +Server benchmark results: + Single workload: + fio (buffered I/O): +[30, 32]% + IOPS BW + 5.19-rc1: 2673k 10.2GiB/s + patch1-6: 3491k 13.3GiB/s + + Single workload: + memcached (anon): -[4, 6]% + Ops/sec KB/sec + 5.19-rc1: 1161501.04 45177.25 + patch1-6: 1106168.46 43025.04 + + Configurations: + CPU: two Xeon 6154 + Mem: total 256G + + Node 1 was only used as a ram disk to reduce the variance in the + results. + + patch drivers/block/brd.c < gfp_flags = GFP_NOIO | __GFP_ZERO | __GFP_HIGHMEM | __GFP_THISNODE; + > page = alloc_pages_node(1, gfp_flags, 0); + EOF + + cat >>/etc/systemd/system.conf <>/etc/memcached.conf </sys/fs/cgroup/user.slice/test/memory.max + echo $$ >/sys/fs/cgroup/user.slice/test/cgroup.procs + fio -name=mglru --numjobs=72 --directory=/mnt --size=1408m \ + --buffered=1 --ioengine=io_uring --iodepth=128 \ + --iodepth_batch_submit=32 --iodepth_batch_complete=32 \ + --rw=randread --random_distribution=random --norandommap \ + --time_based --ramp_time=10m --runtime=5m --group_reporting + + cat memcached.sh + modprobe brd rd_nr=1 rd_size=113246208 + swapoff -a + mkswap /dev/ram0 + swapon /dev/ram0 + + memtier_benchmark -S /var/run/memcached/memcached.sock \ + -P memcache_binary -n allkeys --key-minimum=1 \ + --key-maximum=65000000 --key-pattern=P:P -c 1 -t 36 \ + --ratio 1:0 --pipeline 8 -d 2000 + + memtier_benchmark -S /var/run/memcached/memcached.sock \ + -P memcache_binary -n allkeys --key-minimum=1 \ + --key-maximum=65000000 --key-pattern=R:R -c 1 -t 36 \ + --ratio 0:1 --pipeline 8 --randomize --distinct-client-seed + +Client benchmark results: + kswapd profiles: + 5.19-rc1 + 40.33% page_vma_mapped_walk (overhead) + 21.80% lzo1x_1_do_compress (real work) + 7.53% do_raw_spin_lock + 3.95% _raw_spin_unlock_irq + 2.52% vma_interval_tree_iter_next + 2.37% page_referenced_one + 2.28% vma_interval_tree_subtree_search + 1.97% anon_vma_interval_tree_iter_first + 1.60% ptep_clear_flush + 1.06% __zram_bvec_write + + patch1-6 + 39.03% lzo1x_1_do_compress (real work) + 18.47% page_vma_mapped_walk (overhead) + 6.74% _raw_spin_unlock_irq + 3.97% do_raw_spin_lock + 2.49% ptep_clear_flush + 2.48% anon_vma_interval_tree_iter_first + 1.92% page_referenced_one + 1.88% __zram_bvec_write + 1.48% memmove + 1.31% vma_interval_tree_iter_next + + Configurations: + CPU: single Snapdragon 7c + Mem: total 4G + + ChromeOS MemoryPressure [1] + +[1] https://chromium.googlesource.com/chromiumos/platform/tast-tests/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-7-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 36 ++ + include/linux/mmzone.h | 41 ++ + include/linux/page-flags-layout.h | 5 +- + kernel/bounds.c | 2 + + mm/Kconfig | 11 + + mm/swap.c | 39 ++ + mm/vmscan.c | 792 +++++++++++++++++++++++++++++- + mm/workingset.c | 110 ++++- + 8 files changed, 1025 insertions(+), 11 deletions(-) + +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index 65320d2b8f60..58aabb1ba020 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -106,6 +106,33 @@ static inline int lru_gen_from_seq(unsigned long seq) + return seq % MAX_NR_GENS; + } + ++static inline int lru_hist_from_seq(unsigned long seq) ++{ ++ return seq % NR_HIST_GENS; ++} ++ ++static inline int lru_tier_from_refs(int refs) ++{ ++ VM_WARN_ON_ONCE(refs > BIT(LRU_REFS_WIDTH)); ++ ++ /* see the comment in page_lru_refs() */ ++ return order_base_2(refs + 1); ++} ++ ++static inline int page_lru_refs(struct page *page) ++{ ++ unsigned long flags = READ_ONCE(page->flags); ++ bool workingset = flags & BIT(PG_workingset); ++ ++ /* ++ * Return the number of accesses beyond PG_referenced, i.e., N-1 if the ++ * total number of accesses is N>1, since N=0,1 both map to the first ++ * tier. lru_tier_from_refs() will account for this off-by-one. Also see ++ * the comment on MAX_NR_TIERS. ++ */ ++ return ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + workingset; ++} ++ + static inline int page_lru_gen(struct page *page) + { + unsigned long flags = READ_ONCE(page->flags); +@@ -158,6 +185,15 @@ static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, + __update_lru_size(lruvec, lru, zone, -delta); + return; + } ++ ++ /* promotion */ ++ if (!lru_gen_is_active(lruvec, old_gen) && lru_gen_is_active(lruvec, new_gen)) { ++ __update_lru_size(lruvec, lru, zone, -delta); ++ __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta); ++ } ++ ++ /* demotion requires isolation, e.g., lru_deactivate_fn() */ ++ VM_WARN_ON_ONCE(lru_gen_is_active(lruvec, old_gen) && !lru_gen_is_active(lruvec, new_gen)); + } + + static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 0c39f72184d0..fce8945c507c 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -327,6 +327,28 @@ enum lruvec_flags { + #define MIN_NR_GENS 2U + #define MAX_NR_GENS 4U + ++/* ++ * Each generation is divided into multiple tiers. A page accessed N times ++ * through file descriptors is in tier order_base_2(N). A page in the first tier ++ * (N=0,1) is marked by PG_referenced unless it was faulted in through page ++ * tables or read ahead. A page in any other tier (N>1) is marked by ++ * PG_referenced and PG_workingset. This implies a minimum of two tiers is ++ * supported without using additional bits in page->flags. ++ * ++ * In contrast to moving across generations which requires the LRU lock, moving ++ * across tiers only involves atomic operations on page->flags and therefore ++ * has a negligible cost in the buffered access path. In the eviction path, ++ * comparisons of refaulted/(evicted+protected) from the first tier and the ++ * rest infer whether pages accessed multiple times through file descriptors ++ * are statistically hot and thus worth protecting. ++ * ++ * MAX_NR_TIERS is set to 4 so that the multi-gen LRU can support twice the ++ * number of categories of the active/inactive LRU when keeping track of ++ * accesses through file descriptors. This uses MAX_NR_TIERS-2 spare bits in ++ * page->flags. ++ */ ++#define MAX_NR_TIERS 4U ++ + #ifndef __GENERATING_BOUNDS_H + + struct lruvec; +@@ -341,6 +363,16 @@ enum { + LRU_GEN_FILE, + }; + ++#define MIN_LRU_BATCH BITS_PER_LONG ++#define MAX_LRU_BATCH (MIN_LRU_BATCH * 64) ++ ++/* whether to keep historical stats from evicted generations */ ++#ifdef CONFIG_LRU_GEN_STATS ++#define NR_HIST_GENS MAX_NR_GENS ++#else ++#define NR_HIST_GENS 1U ++#endif ++ + /* + * The youngest generation number is stored in max_seq for both anon and file + * types as they are aged on an equal footing. The oldest generation numbers are +@@ -363,6 +395,15 @@ struct lru_gen_struct { + struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the multi-gen LRU sizes, eventually consistent */ + long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ /* the exponential moving average of refaulted */ ++ unsigned long avg_refaulted[ANON_AND_FILE][MAX_NR_TIERS]; ++ /* the exponential moving average of evicted+protected */ ++ unsigned long avg_total[ANON_AND_FILE][MAX_NR_TIERS]; ++ /* the first tier doesn't need protection, hence the minus one */ ++ unsigned long protected[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS - 1]; ++ /* can be modified without holding the LRU lock */ ++ atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; ++ atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + }; + + void lru_gen_init_lruvec(struct lruvec *lruvec); +diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h +index 240905407a18..7d79818dc065 100644 +--- a/include/linux/page-flags-layout.h ++++ b/include/linux/page-flags-layout.h +@@ -106,7 +106,10 @@ + #error "Not enough bits in page flags" + #endif + +-#define LRU_REFS_WIDTH 0 ++/* see the comment on MAX_NR_TIERS */ ++#define LRU_REFS_WIDTH min(__LRU_REFS_WIDTH, BITS_PER_LONG - NR_PAGEFLAGS - \ ++ ZONES_WIDTH - LRU_GEN_WIDTH - SECTIONS_WIDTH - \ ++ NODES_WIDTH - KASAN_TAG_WIDTH - LAST_CPUPID_WIDTH) + + #endif + #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ +diff --git a/kernel/bounds.c b/kernel/bounds.c +index 5ee60777d8e4..b529182e8b04 100644 +--- a/kernel/bounds.c ++++ b/kernel/bounds.c +@@ -24,8 +24,10 @@ int main(void) + DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); + #ifdef CONFIG_LRU_GEN + DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); ++ DEFINE(__LRU_REFS_WIDTH, MAX_NR_TIERS - 2); + #else + DEFINE(LRU_GEN_WIDTH, 0); ++ DEFINE(__LRU_REFS_WIDTH, 0); + #endif + /* End of constants */ + +diff --git a/mm/Kconfig b/mm/Kconfig +index 0eeb27397884..62433f3cd7ae 100644 +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -897,6 +897,7 @@ config IO_MAPPING + config SECRETMEM + def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED + ++# multi-gen LRU { + config LRU_GEN + bool "Multi-Gen LRU" + depends on MMU +@@ -905,6 +906,16 @@ config LRU_GEN + help + A high performance LRU implementation to overcommit memory. + ++config LRU_GEN_STATS ++ bool "Full stats for debugging" ++ depends on LRU_GEN ++ help ++ Do not enable this option unless you plan to look at historical stats ++ from evicted generations for debugging purpose. ++ ++ This option has a per-memcg and per-node memory overhead. ++# } ++ + source "mm/damon/Kconfig" + + endmenu +diff --git a/mm/swap.c b/mm/swap.c +index 0bdc96661fb6..5d227577b609 100644 +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -389,6 +389,40 @@ static void __lru_cache_activate_page(struct page *page) + local_unlock(&lru_pvecs.lock); + } + ++#ifdef CONFIG_LRU_GEN ++static void page_inc_refs(struct page *page) ++{ ++ unsigned long new_flags, old_flags = READ_ONCE(page->flags); ++ ++ if (PageUnevictable(page)) ++ return; ++ ++ if (!PageReferenced(page)) { ++ SetPageReferenced(page); ++ return; ++ } ++ ++ if (!PageWorkingset(page)) { ++ SetPageWorkingset(page); ++ return; ++ } ++ ++ /* see the comment on MAX_NR_TIERS */ ++ do { ++ new_flags = old_flags & LRU_REFS_MASK; ++ if (new_flags == LRU_REFS_MASK) ++ break; ++ ++ new_flags += BIT(LRU_REFS_PGOFF); ++ new_flags |= old_flags & ~LRU_REFS_MASK; ++ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); ++} ++#else ++static void page_inc_refs(struct page *page) ++{ ++} ++#endif /* CONFIG_LRU_GEN */ ++ + /* + * Mark a page as having seen activity. + * +@@ -403,6 +437,11 @@ void mark_page_accessed(struct page *page) + { + page = compound_head(page); + ++ if (lru_gen_enabled()) { ++ page_inc_refs(page); ++ return; ++ } ++ + if (!PageReferenced(page)) { + SetPageReferenced(page); + } else if (PageUnevictable(page)) { +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 41826fe17eb3..932abd24c1b3 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -1142,9 +1142,11 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, + + if (PageSwapCache(page)) { + swp_entry_t swap = { .val = page_private(page) }; +- mem_cgroup_swapout(page, swap); ++ ++ /* get a shadow entry before mem_cgroup_swapout() clears page_memcg() */ + if (reclaimed && !mapping_exiting(mapping)) + shadow = workingset_eviction(page, target_memcg); ++ mem_cgroup_swapout(page, swap); + __delete_from_swap_cache(page, swap, shadow); + xa_unlock_irq(&mapping->i_pages); + put_swap_page(page, swap); +@@ -2502,6 +2504,9 @@ static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc) + unsigned long file; + struct lruvec *target_lruvec; + ++ if (lru_gen_enabled()) ++ return; ++ + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); + + /* +@@ -2827,6 +2832,17 @@ static bool can_age_anon_pages(struct pglist_data *pgdat, + * shorthand helpers + ******************************************************************************/ + ++#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset)) ++ ++#define DEFINE_MAX_SEQ(lruvec) \ ++ unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq) ++ ++#define DEFINE_MIN_SEQ(lruvec) \ ++ unsigned long min_seq[ANON_AND_FILE] = { \ ++ READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_ANON]), \ ++ READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_FILE]), \ ++ } ++ + #define for_each_gen_type_zone(gen, type, zone) \ + for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ +@@ -2852,6 +2868,745 @@ static struct lruvec __maybe_unused *get_lruvec(struct mem_cgroup *memcg, int ni + return pgdat ? &pgdat->__lruvec : NULL; + } + ++static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ if (!can_demote(pgdat->node_id, sc) && ++ mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) ++ return 0; ++ ++ return mem_cgroup_swappiness(memcg); ++} ++ ++static int get_nr_gens(struct lruvec *lruvec, int type) ++{ ++ return lruvec->lrugen.max_seq - lruvec->lrugen.min_seq[type] + 1; ++} ++ ++static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) ++{ ++ /* see the comment on lru_gen_struct */ ++ return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && ++ get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && ++ get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; ++} ++ ++/****************************************************************************** ++ * refault feedback loop ++ ******************************************************************************/ ++ ++/* ++ * A feedback loop based on Proportional-Integral-Derivative (PID) controller. ++ * ++ * The P term is refaulted/(evicted+protected) from a tier in the generation ++ * currently being evicted; the I term is the exponential moving average of the ++ * P term over the generations previously evicted, using the smoothing factor ++ * 1/2; the D term isn't supported. ++ * ++ * The setpoint (SP) is always the first tier of one type; the process variable ++ * (PV) is either any tier of the other type or any other tier of the same ++ * type. ++ * ++ * The error is the difference between the SP and the PV; the correction is to ++ * turn off protection when SP>PV or turn on protection when SPlrugen; ++ int hist = lru_hist_from_seq(lrugen->min_seq[type]); ++ ++ pos->refaulted = lrugen->avg_refaulted[type][tier] + ++ atomic_long_read(&lrugen->refaulted[hist][type][tier]); ++ pos->total = lrugen->avg_total[type][tier] + ++ atomic_long_read(&lrugen->evicted[hist][type][tier]); ++ if (tier) ++ pos->total += lrugen->protected[hist][type][tier - 1]; ++ pos->gain = gain; ++} ++ ++static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) ++{ ++ int hist, tier; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; ++ unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; ++ ++ lockdep_assert_held(&lruvec->lru_lock); ++ ++ if (!carryover && !clear) ++ return; ++ ++ hist = lru_hist_from_seq(seq); ++ ++ for (tier = 0; tier < MAX_NR_TIERS; tier++) { ++ if (carryover) { ++ unsigned long sum; ++ ++ sum = lrugen->avg_refaulted[type][tier] + ++ atomic_long_read(&lrugen->refaulted[hist][type][tier]); ++ WRITE_ONCE(lrugen->avg_refaulted[type][tier], sum / 2); ++ ++ sum = lrugen->avg_total[type][tier] + ++ atomic_long_read(&lrugen->evicted[hist][type][tier]); ++ if (tier) ++ sum += lrugen->protected[hist][type][tier - 1]; ++ WRITE_ONCE(lrugen->avg_total[type][tier], sum / 2); ++ } ++ ++ if (clear) { ++ atomic_long_set(&lrugen->refaulted[hist][type][tier], 0); ++ atomic_long_set(&lrugen->evicted[hist][type][tier], 0); ++ if (tier) ++ WRITE_ONCE(lrugen->protected[hist][type][tier - 1], 0); ++ } ++ } ++} ++ ++static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) ++{ ++ /* ++ * Return true if the PV has a limited number of refaults or a lower ++ * refaulted/total than the SP. ++ */ ++ return pv->refaulted < MIN_LRU_BATCH || ++ pv->refaulted * (sp->total + MIN_LRU_BATCH) * sp->gain <= ++ (sp->refaulted + 1) * pv->total * pv->gain; ++} ++ ++/****************************************************************************** ++ * the aging ++ ******************************************************************************/ ++ ++/* protect pages accessed multiple times through file descriptors */ ++static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ int type = page_is_file_lru(page); ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); ++ unsigned long new_flags, old_flags = READ_ONCE(page->flags); ++ ++ VM_WARN_ON_ONCE_PAGE(!(old_flags & LRU_GEN_MASK), page); ++ ++ do { ++ new_gen = (old_gen + 1) % MAX_NR_GENS; ++ ++ new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); ++ new_flags |= (new_gen + 1UL) << LRU_GEN_PGOFF; ++ /* for end_page_writeback() */ ++ if (reclaiming) ++ new_flags |= BIT(PG_reclaim); ++ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); ++ ++ lru_gen_update_size(lruvec, page, old_gen, new_gen); ++ ++ return new_gen; ++} ++ ++static void inc_min_seq(struct lruvec *lruvec, int type) ++{ ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ reset_ctrl_pos(lruvec, type, true); ++ WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); ++} ++ ++static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) ++{ ++ int gen, type, zone; ++ bool success = false; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ DEFINE_MIN_SEQ(lruvec); ++ ++ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); ++ ++ /* find the oldest populated generation */ ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ while (min_seq[type] + MIN_NR_GENS <= lrugen->max_seq) { ++ gen = lru_gen_from_seq(min_seq[type]); ++ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) { ++ if (!list_empty(&lrugen->lists[gen][type][zone])) ++ goto next; ++ } ++ ++ min_seq[type]++; ++ } ++next: ++ ; ++ } ++ ++ /* see the comment on lru_gen_struct */ ++ if (can_swap) { ++ min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); ++ min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); ++ } ++ ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ if (min_seq[type] == lrugen->min_seq[type]) ++ continue; ++ ++ reset_ctrl_pos(lruvec, type, true); ++ WRITE_ONCE(lrugen->min_seq[type], min_seq[type]); ++ success = true; ++ } ++ ++ return success; ++} ++ ++static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_swap) ++{ ++ int prev, next; ++ int type, zone; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ ++ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); ++ ++ if (max_seq != lrugen->max_seq) ++ goto unlock; ++ ++ for (type = ANON_AND_FILE - 1; type >= 0; type--) { ++ if (get_nr_gens(lruvec, type) != MAX_NR_GENS) ++ continue; ++ ++ VM_WARN_ON_ONCE(type == LRU_GEN_FILE || can_swap); ++ ++ inc_min_seq(lruvec, type); ++ } ++ ++ /* ++ * Update the active/inactive LRU sizes for compatibility. Both sides of ++ * the current max_seq need to be covered, since max_seq+1 can overlap ++ * with min_seq[LRU_GEN_ANON] if swapping is constrained. And if they do ++ * overlap, cold/hot inversion happens. ++ */ ++ prev = lru_gen_from_seq(lrugen->max_seq - 1); ++ next = lru_gen_from_seq(lrugen->max_seq + 1); ++ ++ for (type = 0; type < ANON_AND_FILE; type++) { ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) { ++ enum lru_list lru = type * LRU_INACTIVE_FILE; ++ long delta = lrugen->nr_pages[prev][type][zone] - ++ lrugen->nr_pages[next][type][zone]; ++ ++ if (!delta) ++ continue; ++ ++ __update_lru_size(lruvec, lru, zone, delta); ++ __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, -delta); ++ } ++ } ++ ++ for (type = 0; type < ANON_AND_FILE; type++) ++ reset_ctrl_pos(lruvec, type, false); ++ ++ /* make sure preceding modifications appear */ ++ smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); ++unlock: ++ spin_unlock_irq(&lruvec->lru_lock); ++} ++ ++static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, ++ struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) ++{ ++ int gen, type, zone; ++ unsigned long old = 0; ++ unsigned long young = 0; ++ unsigned long total = 0; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ unsigned long seq; ++ ++ for (seq = min_seq[type]; seq <= max_seq; seq++) { ++ unsigned long size = 0; ++ ++ gen = lru_gen_from_seq(seq); ++ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); ++ ++ total += size; ++ if (seq == max_seq) ++ young += size; ++ else if (seq + MIN_NR_GENS == max_seq) ++ old += size; ++ } ++ } ++ ++ /* try to scrape all its memory if this memcg was deleted */ ++ *nr_to_scan = mem_cgroup_online(memcg) ? (total >> sc->priority) : total; ++ ++ /* ++ * The aging tries to be lazy to reduce the overhead, while the eviction ++ * stalls when the number of generations reaches MIN_NR_GENS. Hence, the ++ * ideal number of generations is MIN_NR_GENS+1. ++ */ ++ if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) ++ return true; ++ if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) ++ return false; ++ ++ /* ++ * It's also ideal to spread pages out evenly, i.e., 1/(MIN_NR_GENS+1) ++ * of the total number of pages for each generation. A reasonable range ++ * for this average portion is [1/MIN_NR_GENS, 1/(MIN_NR_GENS+2)]. The ++ * aging cares about the upper bound of hot pages, while the eviction ++ * cares about the lower bound of cold pages. ++ */ ++ if (young * MIN_NR_GENS > total) ++ return true; ++ if (old * (MIN_NR_GENS + 2) < total) ++ return true; ++ ++ return false; ++} ++ ++static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ bool need_aging; ++ unsigned long nr_to_scan; ++ int swappiness = get_swappiness(lruvec, sc); ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MAX_SEQ(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ VM_WARN_ON_ONCE(sc->memcg_low_reclaim); ++ ++ mem_cgroup_calculate_protection(NULL, memcg); ++ ++ if (mem_cgroup_below_min(memcg)) ++ return; ++ ++ need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); ++ if (need_aging) ++ inc_max_seq(lruvec, max_seq, swappiness); ++} ++ ++static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ struct mem_cgroup *memcg; ++ ++ VM_WARN_ON_ONCE(!current_is_kswapd()); ++ ++ memcg = mem_cgroup_iter(NULL, NULL, NULL); ++ do { ++ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); ++ ++ age_lruvec(lruvec, sc); ++ ++ cond_resched(); ++ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); ++} ++ ++/****************************************************************************** ++ * the eviction ++ ******************************************************************************/ ++ ++static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) ++{ ++ bool success; ++ int gen = page_lru_gen(page); ++ int type = page_is_file_lru(page); ++ int zone = page_zonenum(page); ++ int delta = thp_nr_pages(page); ++ int refs = page_lru_refs(page); ++ int tier = lru_tier_from_refs(refs); ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ VM_WARN_ON_ONCE_PAGE(gen >= MAX_NR_GENS, page); ++ ++ /* unevictable */ ++ if (!page_evictable(page)) { ++ success = lru_gen_del_page(lruvec, page, true); ++ VM_WARN_ON_ONCE_PAGE(!success, page); ++ SetPageUnevictable(page); ++ add_page_to_lru_list(page, lruvec); ++ __count_vm_events(UNEVICTABLE_PGCULLED, delta); ++ return true; ++ } ++ ++ /* dirty lazyfree */ ++ if (type == LRU_GEN_FILE && PageAnon(page) && PageDirty(page)) { ++ success = lru_gen_del_page(lruvec, page, true); ++ VM_WARN_ON_ONCE_PAGE(!success, page); ++ SetPageSwapBacked(page); ++ add_page_to_lru_list_tail(page, lruvec); ++ return true; ++ } ++ ++ /* protected */ ++ if (tier > tier_idx) { ++ int hist = lru_hist_from_seq(lrugen->min_seq[type]); ++ ++ gen = page_inc_gen(lruvec, page, false); ++ list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); ++ ++ WRITE_ONCE(lrugen->protected[hist][type][tier - 1], ++ lrugen->protected[hist][type][tier - 1] + delta); ++ __mod_lruvec_state(lruvec, WORKINGSET_ACTIVATE_BASE + type, delta); ++ return true; ++ } ++ ++ /* waiting for writeback */ ++ if (PageLocked(page) || PageWriteback(page) || ++ (type == LRU_GEN_FILE && PageDirty(page))) { ++ gen = page_inc_gen(lruvec, page, true); ++ list_move(&page->lru, &lrugen->lists[gen][type][zone]); ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool isolate_page(struct lruvec *lruvec, struct page *page, struct scan_control *sc) ++{ ++ bool success; ++ ++ /* unmapping inhibited */ ++ if (!sc->may_unmap && page_mapped(page)) ++ return false; ++ ++ /* swapping inhibited */ ++ if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && ++ (PageDirty(page) || ++ (PageAnon(page) && !PageSwapCache(page)))) ++ return false; ++ ++ /* raced with release_pages() */ ++ if (!get_page_unless_zero(page)) ++ return false; ++ ++ /* raced with another isolation */ ++ if (!TestClearPageLRU(page)) { ++ put_page(page); ++ return false; ++ } ++ ++ /* see the comment on MAX_NR_TIERS */ ++ if (!PageReferenced(page)) ++ set_mask_bits(&page->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, 0); ++ ++ /* for shrink_page_list() */ ++ ClearPageReclaim(page); ++ ClearPageReferenced(page); ++ ++ success = lru_gen_del_page(lruvec, page, true); ++ VM_WARN_ON_ONCE_PAGE(!success, page); ++ ++ return true; ++} ++ ++static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, ++ int type, int tier, struct list_head *list) ++{ ++ int gen, zone; ++ enum vm_event_item item; ++ int sorted = 0; ++ int scanned = 0; ++ int isolated = 0; ++ int remaining = MAX_LRU_BATCH; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ ++ VM_WARN_ON_ONCE(!list_empty(list)); ++ ++ if (get_nr_gens(lruvec, type) == MIN_NR_GENS) ++ return 0; ++ ++ gen = lru_gen_from_seq(lrugen->min_seq[type]); ++ ++ for (zone = sc->reclaim_idx; zone >= 0; zone--) { ++ LIST_HEAD(moved); ++ int skipped = 0; ++ struct list_head *head = &lrugen->lists[gen][type][zone]; ++ ++ while (!list_empty(head)) { ++ struct page *page = lru_to_page(head); ++ int delta = thp_nr_pages(page); ++ ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); ++ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); ++ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); ++ ++ scanned += delta; ++ ++ if (sort_page(lruvec, page, tier)) ++ sorted += delta; ++ else if (isolate_page(lruvec, page, sc)) { ++ list_add(&page->lru, list); ++ isolated += delta; ++ } else { ++ list_move(&page->lru, &moved); ++ skipped += delta; ++ } ++ ++ if (!--remaining || max(isolated, skipped) >= MIN_LRU_BATCH) ++ break; ++ } ++ ++ if (skipped) { ++ list_splice(&moved, head); ++ __count_zid_vm_events(PGSCAN_SKIP, zone, skipped); ++ } ++ ++ if (!remaining || isolated >= MIN_LRU_BATCH) ++ break; ++ } ++ ++ item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT; ++ if (!cgroup_reclaim(sc)) { ++ __count_vm_events(item, isolated); ++ __count_vm_events(PGREFILL, sorted); ++ } ++ __count_memcg_events(memcg, item, isolated); ++ __count_memcg_events(memcg, PGREFILL, sorted); ++ __count_vm_events(PGSCAN_ANON + type, isolated); ++ ++ /* ++ * There might not be eligible pages due to reclaim_idx, may_unmap and ++ * may_writepage. Check the remaining to prevent livelock if it's not ++ * making progress. ++ */ ++ return isolated || !remaining ? scanned : 0; ++} ++ ++static int get_tier_idx(struct lruvec *lruvec, int type) ++{ ++ int tier; ++ struct ctrl_pos sp, pv; ++ ++ /* ++ * To leave a margin for fluctuations, use a larger gain factor (1:2). ++ * This value is chosen because any other tier would have at least twice ++ * as many refaults as the first tier. ++ */ ++ read_ctrl_pos(lruvec, type, 0, 1, &sp); ++ for (tier = 1; tier < MAX_NR_TIERS; tier++) { ++ read_ctrl_pos(lruvec, type, tier, 2, &pv); ++ if (!positive_ctrl_err(&sp, &pv)) ++ break; ++ } ++ ++ return tier - 1; ++} ++ ++static int get_type_to_scan(struct lruvec *lruvec, int swappiness, int *tier_idx) ++{ ++ int type, tier; ++ struct ctrl_pos sp, pv; ++ int gain[ANON_AND_FILE] = { swappiness, 200 - swappiness }; ++ ++ /* ++ * Compare the first tier of anon with that of file to determine which ++ * type to scan. Also need to compare other tiers of the selected type ++ * with the first tier of the other type to determine the last tier (of ++ * the selected type) to evict. ++ */ ++ read_ctrl_pos(lruvec, LRU_GEN_ANON, 0, gain[LRU_GEN_ANON], &sp); ++ read_ctrl_pos(lruvec, LRU_GEN_FILE, 0, gain[LRU_GEN_FILE], &pv); ++ type = positive_ctrl_err(&sp, &pv); ++ ++ read_ctrl_pos(lruvec, !type, 0, gain[!type], &sp); ++ for (tier = 1; tier < MAX_NR_TIERS; tier++) { ++ read_ctrl_pos(lruvec, type, tier, gain[type], &pv); ++ if (!positive_ctrl_err(&sp, &pv)) ++ break; ++ } ++ ++ *tier_idx = tier - 1; ++ ++ return type; ++} ++ ++static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, ++ int *type_scanned, struct list_head *list) ++{ ++ int i; ++ int type; ++ int scanned; ++ int tier = -1; ++ DEFINE_MIN_SEQ(lruvec); ++ ++ /* ++ * Try to make the obvious choice first. When anon and file are both ++ * available from the same generation, interpret swappiness 1 as file ++ * first and 200 as anon first. ++ */ ++ if (!swappiness) ++ type = LRU_GEN_FILE; ++ else if (min_seq[LRU_GEN_ANON] < min_seq[LRU_GEN_FILE]) ++ type = LRU_GEN_ANON; ++ else if (swappiness == 1) ++ type = LRU_GEN_FILE; ++ else if (swappiness == 200) ++ type = LRU_GEN_ANON; ++ else ++ type = get_type_to_scan(lruvec, swappiness, &tier); ++ ++ for (i = !swappiness; i < ANON_AND_FILE; i++) { ++ if (tier < 0) ++ tier = get_tier_idx(lruvec, type); ++ ++ scanned = scan_pages(lruvec, sc, type, tier, list); ++ if (scanned) ++ break; ++ ++ type = !type; ++ tier = -1; ++ } ++ ++ *type_scanned = type; ++ ++ return scanned; ++} ++ ++static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) ++{ ++ int type; ++ int scanned; ++ int reclaimed; ++ LIST_HEAD(list); ++ struct page *page; ++ enum vm_event_item item; ++ struct reclaim_stat stat; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ ++ scanned = isolate_pages(lruvec, sc, swappiness, &type, &list); ++ ++ scanned += try_to_inc_min_seq(lruvec, swappiness); ++ ++ if (get_nr_gens(lruvec, !swappiness) == MIN_NR_GENS) ++ scanned = 0; ++ ++ spin_unlock_irq(&lruvec->lru_lock); ++ ++ if (list_empty(&list)) ++ return scanned; ++ ++ reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); ++ ++ list_for_each_entry(page, &list, lru) { ++ /* restore LRU_REFS_FLAGS cleared by isolate_page() */ ++ if (PageWorkingset(page)) ++ SetPageReferenced(page); ++ ++ /* don't add rejected pages to the oldest generation */ ++ if (PageReclaim(page) && ++ (PageDirty(page) || PageWriteback(page))) ++ ClearPageActive(page); ++ else ++ SetPageActive(page); ++ } ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ ++ move_pages_to_lru(lruvec, &list); ++ ++ item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; ++ if (!cgroup_reclaim(sc)) ++ __count_vm_events(item, reclaimed); ++ __count_memcg_events(memcg, item, reclaimed); ++ __count_vm_events(PGSTEAL_ANON + type, reclaimed); ++ ++ spin_unlock_irq(&lruvec->lru_lock); ++ ++ mem_cgroup_uncharge_list(&list); ++ free_unref_page_list(&list); ++ ++ sc->nr_reclaimed += reclaimed; ++ ++ return scanned; ++} ++ ++static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, ++ bool can_swap) ++{ ++ bool need_aging; ++ unsigned long nr_to_scan; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MAX_SEQ(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ if (mem_cgroup_below_min(memcg) || ++ (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) ++ return 0; ++ ++ need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); ++ if (!need_aging) ++ return nr_to_scan; ++ ++ /* skip the aging path at the default priority */ ++ if (sc->priority == DEF_PRIORITY) ++ goto done; ++ ++ /* leave the work to lru_gen_age_node() */ ++ if (current_is_kswapd()) ++ return 0; ++ ++ inc_max_seq(lruvec, max_seq, can_swap); ++done: ++ return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; ++} ++ ++static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ struct blk_plug plug; ++ unsigned long scanned = 0; ++ ++ lru_add_drain(); ++ ++ blk_start_plug(&plug); ++ ++ while (true) { ++ int delta; ++ int swappiness; ++ unsigned long nr_to_scan; ++ ++ if (sc->may_swap) ++ swappiness = get_swappiness(lruvec, sc); ++ else if (!cgroup_reclaim(sc) && get_swappiness(lruvec, sc)) ++ swappiness = 1; ++ else ++ swappiness = 0; ++ ++ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); ++ if (!nr_to_scan) ++ break; ++ ++ delta = evict_pages(lruvec, sc, swappiness); ++ if (!delta) ++ break; ++ ++ scanned += delta; ++ if (scanned >= nr_to_scan) ++ break; ++ ++ cond_resched(); ++ } ++ ++ blk_finish_plug(&plug); ++} ++ + /****************************************************************************** + * initialization + ******************************************************************************/ +@@ -2894,6 +3649,16 @@ static int __init init_lru_gen(void) + }; + late_initcall(init_lru_gen); + ++#else /* !CONFIG_LRU_GEN */ ++ ++static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++} ++ ++static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++} ++ + #endif /* CONFIG_LRU_GEN */ + + static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -2907,6 +3672,11 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + bool proportional_reclaim; + struct blk_plug plug; + ++ if (lru_gen_enabled()) { ++ lru_gen_shrink_lruvec(lruvec, sc); ++ return; ++ } ++ + get_scan_count(lruvec, sc, nr); + + /* Record the original scan target for proportional adjustments later */ +@@ -3372,6 +4142,9 @@ static void snapshot_refaults(struct mem_cgroup *target_memcg, pg_data_t *pgdat) + struct lruvec *target_lruvec; + unsigned long refaults; + ++ if (lru_gen_enabled()) ++ return; ++ + target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat); + refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_ANON); + target_lruvec->refaults[0] = refaults; +@@ -3736,12 +4509,16 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, + } + #endif + +-static void age_active_anon(struct pglist_data *pgdat, +- struct scan_control *sc) ++static void kswapd_age_node(struct pglist_data *pgdat, struct scan_control *sc) + { + struct mem_cgroup *memcg; + struct lruvec *lruvec; + ++ if (lru_gen_enabled()) { ++ lru_gen_age_node(pgdat, sc); ++ return; ++ } ++ + if (!can_age_anon_pages(pgdat, sc)) + return; + +@@ -4058,12 +4835,11 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx) + sc.may_swap = !nr_boost_reclaim; + + /* +- * Do some background aging of the anon list, to give +- * pages a chance to be referenced before reclaiming. All +- * pages are rotated regardless of classzone as this is +- * about consistent aging. ++ * Do some background aging, to give pages a chance to be ++ * referenced before reclaiming. All pages are rotated ++ * regardless of classzone as this is about consistent aging. + */ +- age_active_anon(pgdat, &sc); ++ kswapd_age_node(pgdat, &sc); + + /* + * If we're getting trouble reclaiming, start doing writepage +diff --git a/mm/workingset.c b/mm/workingset.c +index 880d882f3325..aeba62cebf8c 100644 +--- a/mm/workingset.c ++++ b/mm/workingset.c +@@ -187,7 +187,6 @@ static unsigned int bucket_order __read_mostly; + static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction, + bool workingset) + { +- eviction >>= bucket_order; + eviction &= EVICTION_MASK; + eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; + eviction = (eviction << NODES_SHIFT) | pgdat->node_id; +@@ -212,10 +211,107 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat, + + *memcgidp = memcgid; + *pgdat = NODE_DATA(nid); +- *evictionp = entry << bucket_order; ++ *evictionp = entry; + *workingsetp = workingset; + } + ++#ifdef CONFIG_LRU_GEN ++ ++static void *lru_gen_eviction(struct page *page) ++{ ++ int hist; ++ unsigned long token; ++ unsigned long min_seq; ++ struct lruvec *lruvec; ++ struct lru_gen_struct *lrugen; ++ int type = page_is_file_lru(page); ++ int delta = thp_nr_pages(page); ++ int refs = page_lru_refs(page); ++ int tier = lru_tier_from_refs(refs); ++ struct mem_cgroup *memcg = page_memcg(page); ++ struct pglist_data *pgdat = page_pgdat(page); ++ ++ BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_WIDTH > BITS_PER_LONG - EVICTION_SHIFT); ++ ++ lruvec = mem_cgroup_lruvec(memcg, pgdat); ++ lrugen = &lruvec->lrugen; ++ min_seq = READ_ONCE(lrugen->min_seq[type]); ++ token = (min_seq << LRU_REFS_WIDTH) | max(refs - 1, 0); ++ ++ hist = lru_hist_from_seq(min_seq); ++ atomic_long_add(delta, &lrugen->evicted[hist][type][tier]); ++ ++ return pack_shadow(mem_cgroup_id(memcg), pgdat, token, refs); ++} ++ ++static void lru_gen_refault(struct page *page, void *shadow) ++{ ++ int hist, tier, refs; ++ int memcg_id; ++ bool workingset; ++ unsigned long token; ++ unsigned long min_seq; ++ struct lruvec *lruvec; ++ struct lru_gen_struct *lrugen; ++ struct mem_cgroup *memcg; ++ struct pglist_data *pgdat; ++ int type = page_is_file_lru(page); ++ int delta = thp_nr_pages(page); ++ ++ unpack_shadow(shadow, &memcg_id, &pgdat, &token, &workingset); ++ ++ if (pgdat != page_pgdat(page)) ++ return; ++ ++ rcu_read_lock(); ++ ++ memcg = page_memcg_rcu(page); ++ if (memcg_id != mem_cgroup_id(memcg)) ++ goto unlock; ++ ++ lruvec = mem_cgroup_lruvec(memcg, pgdat); ++ lrugen = &lruvec->lrugen; ++ ++ min_seq = READ_ONCE(lrugen->min_seq[type]); ++ if ((token >> LRU_REFS_WIDTH) != (min_seq & (EVICTION_MASK >> LRU_REFS_WIDTH))) ++ goto unlock; ++ ++ hist = lru_hist_from_seq(min_seq); ++ /* see the comment in page_lru_refs() */ ++ refs = (token & (BIT(LRU_REFS_WIDTH) - 1)) + workingset; ++ tier = lru_tier_from_refs(refs); ++ ++ atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]); ++ mod_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + type, delta); ++ ++ /* ++ * Count the following two cases as stalls: ++ * 1. For pages accessed through page tables, hotter pages pushed out ++ * hot pages which refaulted immediately. ++ * 2. For pages accessed multiple times through file descriptors, ++ * numbers of accesses might have been out of the range. ++ */ ++ if (lru_gen_in_fault() || refs == BIT(LRU_REFS_WIDTH)) { ++ SetPageWorkingset(page); ++ mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + type, delta); ++ } ++unlock: ++ rcu_read_unlock(); ++} ++ ++#else /* !CONFIG_LRU_GEN */ ++ ++static void *lru_gen_eviction(struct page *page) ++{ ++ return NULL; ++} ++ ++static void lru_gen_refault(struct page *page, void *shadow) ++{ ++} ++ ++#endif /* CONFIG_LRU_GEN */ ++ + /** + * workingset_age_nonresident - age non-resident entries as LRU ages + * @lruvec: the lruvec that was aged +@@ -264,10 +360,14 @@ void *workingset_eviction(struct page *page, struct mem_cgroup *target_memcg) + VM_BUG_ON_PAGE(page_count(page), page); + VM_BUG_ON_PAGE(!PageLocked(page), page); + ++ if (lru_gen_enabled()) ++ return lru_gen_eviction(page); ++ + lruvec = mem_cgroup_lruvec(target_memcg, pgdat); + /* XXX: target_memcg can be NULL, go through lruvec */ + memcgid = mem_cgroup_id(lruvec_memcg(lruvec)); + eviction = atomic_long_read(&lruvec->nonresident_age); ++ eviction >>= bucket_order; + workingset_age_nonresident(lruvec, thp_nr_pages(page)); + return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); + } +@@ -296,7 +396,13 @@ void workingset_refault(struct page *page, void *shadow) + bool workingset; + int memcgid; + ++ if (lru_gen_enabled()) { ++ lru_gen_refault(page, shadow); ++ return; ++ } ++ + unpack_shadow(shadow, &memcgid, &pgdat, &eviction, &workingset); ++ eviction <<= bucket_order; + + rcu_read_lock(); + /* +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-06-mm-multigenerational-lru-aging.patch b/target/linux/generic/backport-5.15/020-v6.1-06-mm-multigenerational-lru-aging.patch deleted file mode 100644 index 2ff49681c7b..00000000000 --- a/target/linux/generic/backport-5.15/020-v6.1-06-mm-multigenerational-lru-aging.patch +++ /dev/null @@ -1,1176 +0,0 @@ -From 8217cd2238c40cf77208aa27a7cc09879e685890 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Mon, 5 Apr 2021 04:35:07 -0600 -Subject: [PATCH 06/10] mm: multigenerational lru: aging - -The aging produces young generations. Given an lruvec, the aging -traverses lruvec_memcg()->mm_list and calls walk_page_range() to scan -PTEs for accessed pages. Upon finding one, the aging updates its -generation number to max_seq (modulo MAX_NR_GENS). After each round of -traversal, the aging increments max_seq. The aging is due when -min_seq[] reaches max_seq-1. - -The aging uses the following optimizations when walking page tables: - 1) It skips non-leaf PMD entries that have the accessed bit cleared - when CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y. - 2) It does not zigzag between a PGD table and the same PMD or PTE - table spanning multiple VMAs. In other words, it finishes all the - VMAs within the range of the same PMD or PTE table before it returns - to this PGD table. This optimizes workloads that have large numbers - of tiny VMAs, especially when CONFIG_PGTABLE_LEVELS=5. - -Signed-off-by: Yu Zhao -Tested-by: Konstantin Kharlamov -Change-Id: I3ae8abc3100d023cecb3a699d86020ae6fc10a45 ---- - include/linux/memcontrol.h | 3 + - include/linux/mmzone.h | 9 + - include/linux/oom.h | 16 + - include/linux/swap.h | 3 + - mm/memcontrol.c | 5 + - mm/oom_kill.c | 4 +- - mm/rmap.c | 8 + - mm/vmscan.c | 948 +++++++++++++++++++++++++++++++++++++ - 8 files changed, 994 insertions(+), 2 deletions(-) - ---- a/include/linux/memcontrol.h -+++ b/include/linux/memcontrol.h -@@ -1367,10 +1367,13 @@ mem_cgroup_print_oom_meminfo(struct mem_ - - static inline void lock_page_memcg(struct page *page) - { -+ /* to match page_memcg_rcu() */ -+ rcu_read_lock(); - } - - static inline void unlock_page_memcg(struct page *page) - { -+ rcu_read_unlock(); - } - - static inline void mem_cgroup_handle_over_high(void) ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -295,6 +295,7 @@ enum lruvec_flags { - }; - - struct lruvec; -+struct page_vma_mapped_walk; - - #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) - #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) -@@ -393,6 +394,7 @@ struct mm_walk_args { - - void lru_gen_init_state(struct mem_cgroup *memcg, struct lruvec *lruvec); - void lru_gen_change_state(bool enable, bool main, bool swap); -+void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); - - #ifdef CONFIG_MEMCG - void lru_gen_init_memcg(struct mem_cgroup *memcg); -@@ -409,6 +411,10 @@ static inline void lru_gen_change_state( - { - } - -+static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) -+{ -+} -+ - #ifdef CONFIG_MEMCG - static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) - { -@@ -1028,6 +1034,9 @@ typedef struct pglist_data { - - unsigned long flags; - -+#ifdef CONFIG_LRU_GEN -+ struct mm_walk_args mm_walk_args; -+#endif - ZONE_PADDING(_pad2_) - - /* Per-node vmstats */ ---- a/include/linux/oom.h -+++ b/include/linux/oom.h -@@ -57,6 +57,22 @@ struct oom_control { - extern struct mutex oom_lock; - extern struct mutex oom_adj_mutex; - -+#ifdef CONFIG_MMU -+extern struct task_struct *oom_reaper_list; -+extern struct wait_queue_head oom_reaper_wait; -+ -+static inline bool oom_reaping_in_progress(void) -+{ -+ /* racy check to see if oom reaping could be in progress */ -+ return READ_ONCE(oom_reaper_list) || !waitqueue_active(&oom_reaper_wait); -+} -+#else -+static inline bool oom_reaping_in_progress(void) -+{ -+ return false; -+} -+#endif -+ - static inline void set_current_oom_origin(void) - { - current->signal->oom_flag_origin = true; ---- a/include/linux/swap.h -+++ b/include/linux/swap.h -@@ -137,6 +137,9 @@ union swap_header { - */ - struct reclaim_state { - unsigned long reclaimed_slab; -+#ifdef CONFIG_LRU_GEN -+ struct mm_walk_args *mm_walk_args; -+#endif - }; - - #ifdef __KERNEL__ ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -1304,12 +1304,17 @@ void mem_cgroup_update_lru_size(struct l - *lru_size += nr_pages; - - size = *lru_size; -+#ifdef CONFIG_LRU_GEN -+ /* unlikely but not a bug when reset_batch_size() is pending */ -+ VM_WARN_ON(size + MAX_BATCH_SIZE < 0); -+#else - if (WARN_ONCE(size < 0, - "%s(%p, %d, %d): lru_size %ld\n", - __func__, lruvec, lru, nr_pages, size)) { - VM_BUG_ON(1); - *lru_size = 0; - } -+#endif - - if (nr_pages > 0) - *lru_size += nr_pages; ---- a/mm/oom_kill.c -+++ b/mm/oom_kill.c -@@ -508,8 +508,8 @@ bool process_shares_mm(struct task_struc - * victim (if that is possible) to help the OOM killer to move on. - */ - static struct task_struct *oom_reaper_th; --static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait); --static struct task_struct *oom_reaper_list; -+DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait); -+struct task_struct *oom_reaper_list; - static DEFINE_SPINLOCK(oom_reaper_lock); - - bool __oom_reap_task_mm(struct mm_struct *mm) ---- a/mm/rmap.c -+++ b/mm/rmap.c -@@ -73,6 +73,7 @@ - #include - #include - #include -+#include - - #include - -@@ -793,6 +794,13 @@ static bool page_referenced_one(struct p - } - - if (pvmw.pte) { -+ /* the multigenerational lru exploits the spatial locality */ -+ if (lru_gen_enabled() && pte_young(*pvmw.pte) && -+ !(vma->vm_flags & VM_SEQ_READ)) { -+ lru_gen_look_around(&pvmw); -+ referenced++; -+ } -+ - if (ptep_clear_flush_young_notify(vma, address, - pvmw.pte)) { - /* ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -51,6 +51,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -2822,6 +2824,15 @@ static bool can_age_anon_pages(struct pg - * shorthand helpers - ******************************************************************************/ - -+#define DEFINE_MAX_SEQ(lruvec) \ -+ unsigned long max_seq = READ_ONCE((lruvec)->evictable.max_seq) -+ -+#define DEFINE_MIN_SEQ(lruvec) \ -+ unsigned long min_seq[ANON_AND_FILE] = { \ -+ READ_ONCE((lruvec)->evictable.min_seq[0]), \ -+ READ_ONCE((lruvec)->evictable.min_seq[1]), \ -+ } -+ - #define for_each_gen_type_zone(gen, type, zone) \ - for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ - for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ -@@ -2834,6 +2845,12 @@ static int page_lru_gen(struct page *pag - return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; - } - -+static int get_swappiness(struct mem_cgroup *memcg) -+{ -+ return mem_cgroup_get_nr_swap_pages(memcg) >= MIN_BATCH_SIZE ? -+ mem_cgroup_swappiness(memcg) : 0; -+} -+ - static struct lruvec *get_lruvec(int nid, struct mem_cgroup *memcg) - { - struct pglist_data *pgdat = NODE_DATA(nid); -@@ -3164,6 +3181,926 @@ done: - } - - /****************************************************************************** -+ * the aging -+ ******************************************************************************/ -+ -+static int page_update_gen(struct page *page, int gen) -+{ -+ unsigned long old_flags, new_flags; -+ -+ VM_BUG_ON(gen >= MAX_NR_GENS); -+ -+ do { -+ new_flags = old_flags = READ_ONCE(page->flags); -+ -+ if (!(new_flags & LRU_GEN_MASK)) { -+ new_flags |= BIT(PG_referenced); -+ continue; -+ } -+ -+ new_flags &= ~LRU_GEN_MASK; -+ new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; -+ } while (new_flags != old_flags && -+ cmpxchg(&page->flags, old_flags, new_flags) != old_flags); -+ -+ return ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; -+} -+ -+static void page_inc_gen(struct page *page, struct lruvec *lruvec, bool reclaiming) -+{ -+ int old_gen, new_gen; -+ unsigned long old_flags, new_flags; -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ old_gen = lru_gen_from_seq(lrugen->min_seq[type]); -+ -+ do { -+ new_flags = old_flags = READ_ONCE(page->flags); -+ VM_BUG_ON_PAGE(!(new_flags & LRU_GEN_MASK), page); -+ -+ new_gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; -+ /* page_update_gen() has updated this page? */ -+ if (new_gen >= 0 && new_gen != old_gen) { -+ list_move(&page->lru, &lrugen->lists[new_gen][type][zone]); -+ return; -+ } -+ -+ new_gen = (old_gen + 1) % MAX_NR_GENS; -+ -+ new_flags &= ~LRU_GEN_MASK; -+ new_flags |= (new_gen + 1UL) << LRU_GEN_PGOFF; -+ /* for end_page_writeback() */ -+ if (reclaiming) -+ new_flags |= BIT(PG_reclaim); -+ } while (cmpxchg(&page->flags, old_flags, new_flags) != old_flags); -+ -+ lru_gen_update_size(page, lruvec, old_gen, new_gen); -+ if (reclaiming) -+ list_move(&page->lru, &lrugen->lists[new_gen][type][zone]); -+ else -+ list_move_tail(&page->lru, &lrugen->lists[new_gen][type][zone]); -+} -+ -+static void update_batch_size(struct page *page, int old_gen, int new_gen, -+ struct mm_walk_args *args) -+{ -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ int delta = thp_nr_pages(page); -+ -+ VM_BUG_ON(old_gen >= MAX_NR_GENS); -+ VM_BUG_ON(new_gen >= MAX_NR_GENS); -+ -+ args->batch_size++; -+ -+ args->nr_pages[old_gen][type][zone] -= delta; -+ args->nr_pages[new_gen][type][zone] += delta; -+} -+ -+static void reset_batch_size(struct lruvec *lruvec, struct mm_walk_args *args) -+{ -+ int gen, type, zone; -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ args->batch_size = 0; -+ -+ for_each_gen_type_zone(gen, type, zone) { -+ enum lru_list lru = type * LRU_FILE; -+ int delta = args->nr_pages[gen][type][zone]; -+ -+ if (!delta) -+ continue; -+ -+ args->nr_pages[gen][type][zone] = 0; -+ WRITE_ONCE(lrugen->sizes[gen][type][zone], -+ lrugen->sizes[gen][type][zone] + delta); -+ -+ if (lru_gen_is_active(lruvec, gen)) -+ lru += LRU_ACTIVE; -+ update_lru_size(lruvec, lru, zone, delta); -+ } -+} -+ -+static int should_skip_vma(unsigned long start, unsigned long end, struct mm_walk *walk) -+{ -+ struct address_space *mapping; -+ struct vm_area_struct *vma = walk->vma; -+ struct mm_walk_args *args = walk->private; -+ -+ if (!vma_is_accessible(vma) || is_vm_hugetlb_page(vma) || -+ (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ))) -+ return true; -+ -+ if (vma_is_anonymous(vma)) -+ return !args->swappiness; -+ -+ if (WARN_ON_ONCE(!vma->vm_file || !vma->vm_file->f_mapping)) -+ return true; -+ -+ mapping = vma->vm_file->f_mapping; -+ if (!mapping->a_ops->writepage) -+ return true; -+ -+ return (shmem_mapping(mapping) && !args->swappiness) || mapping_unevictable(mapping); -+} -+ -+/* -+ * Some userspace memory allocators create many single-page VMAs. So instead of -+ * returning back to the PGD table for each of such VMAs, we finish at least an -+ * entire PMD table and therefore avoid many zigzags. -+ */ -+static bool get_next_vma(struct mm_walk *walk, unsigned long mask, unsigned long size, -+ unsigned long *start, unsigned long *end) -+{ -+ unsigned long next = round_up(*end, size); -+ -+ VM_BUG_ON(mask & size); -+ VM_BUG_ON(*start >= *end); -+ VM_BUG_ON((next & mask) != (*start & mask)); -+ -+ while (walk->vma) { -+ if (next >= walk->vma->vm_end) { -+ walk->vma = walk->vma->vm_next; -+ continue; -+ } -+ -+ if ((next & mask) != (walk->vma->vm_start & mask)) -+ return false; -+ -+ if (should_skip_vma(walk->vma->vm_start, walk->vma->vm_end, walk)) { -+ walk->vma = walk->vma->vm_next; -+ continue; -+ } -+ -+ *start = max(next, walk->vma->vm_start); -+ next = (next | ~mask) + 1; -+ /* rounded-up boundaries can wrap to 0 */ -+ *end = next && next < walk->vma->vm_end ? next : walk->vma->vm_end; -+ -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, -+ struct mm_walk *walk) -+{ -+ int i; -+ pte_t *pte; -+ spinlock_t *ptl; -+ unsigned long addr; -+ int worth = 0; -+ struct mm_walk_args *args = walk->private; -+ int old_gen, new_gen = lru_gen_from_seq(args->max_seq); -+ -+ VM_BUG_ON(pmd_leaf(*pmd)); -+ -+ pte = pte_offset_map_lock(walk->mm, pmd, start & PMD_MASK, &ptl); -+ arch_enter_lazy_mmu_mode(); -+restart: -+ for (i = pte_index(start), addr = start; addr != end; i++, addr += PAGE_SIZE) { -+ struct page *page; -+ unsigned long pfn = pte_pfn(pte[i]); -+ -+ args->mm_stats[MM_LEAF_TOTAL]++; -+ -+ if (!pte_present(pte[i]) || is_zero_pfn(pfn)) -+ continue; -+ -+ if (WARN_ON_ONCE(pte_devmap(pte[i]) || pte_special(pte[i]))) -+ continue; -+ -+ if (!pte_young(pte[i])) { -+ args->mm_stats[MM_LEAF_OLD]++; -+ continue; -+ } -+ -+ VM_BUG_ON(!pfn_valid(pfn)); -+ if (pfn < args->start_pfn || pfn >= args->end_pfn) -+ continue; -+ -+ page = compound_head(pfn_to_page(pfn)); -+ if (page_to_nid(page) != args->node_id) -+ continue; -+ -+ if (page_memcg_rcu(page) != args->memcg) -+ continue; -+ -+ VM_BUG_ON(addr < walk->vma->vm_start || addr >= walk->vma->vm_end); -+ if (!ptep_test_and_clear_young(walk->vma, addr, pte + i)) -+ continue; -+ -+ args->mm_stats[MM_LEAF_YOUNG]++; -+ -+ if (pte_dirty(pte[i]) && !PageDirty(page) && -+ !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) -+ set_page_dirty(page); -+ -+ old_gen = page_update_gen(page, new_gen); -+ if (old_gen >= 0 && old_gen != new_gen) -+ update_batch_size(page, old_gen, new_gen, args); -+ -+ worth++; -+ } -+ -+ if (i < PTRS_PER_PTE && get_next_vma(walk, PMD_MASK, PAGE_SIZE, &start, &end)) -+ goto restart; -+ -+ arch_leave_lazy_mmu_mode(); -+ pte_unmap_unlock(pte, ptl); -+ -+ return worth >= MIN_BATCH_SIZE / 2; -+} -+ -+/* -+ * We scan PMD entries in two passes. The first pass reaches to PTE tables and -+ * doesn't take the PMD lock. The second pass clears the accessed bit on PMD -+ * entries and needs to take the PMD lock. -+ */ -+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) -+static void walk_pmd_range_locked(pud_t *pud, unsigned long start, int offset, -+ struct vm_area_struct *vma, struct mm_walk *walk) -+{ -+ int i; -+ pmd_t *pmd; -+ spinlock_t *ptl; -+ struct mm_walk_args *args = walk->private; -+ int old_gen, new_gen = lru_gen_from_seq(args->max_seq); -+ -+ VM_BUG_ON(pud_leaf(*pud)); -+ -+ start = (start & PUD_MASK) + offset * PMD_SIZE; -+ pmd = pmd_offset(pud, start); -+ ptl = pmd_lock(walk->mm, pmd); -+ arch_enter_lazy_mmu_mode(); -+ -+ for_each_set_bit(i, args->bitmap, MIN_BATCH_SIZE) { -+ struct page *page; -+ unsigned long pfn = pmd_pfn(pmd[i]); -+ unsigned long addr = start + i * PMD_SIZE; -+ -+ if (!pmd_present(pmd[i]) || is_huge_zero_pmd(pmd[i])) -+ continue; -+ -+ if (WARN_ON_ONCE(pmd_devmap(pmd[i]))) -+ continue; -+ -+ if (!pmd_trans_huge(pmd[i])) { -+ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG)) -+ pmdp_test_and_clear_young(vma, addr, pmd + i); -+ continue; -+ } -+ -+ VM_BUG_ON(!pfn_valid(pfn)); -+ if (pfn < args->start_pfn || pfn >= args->end_pfn) -+ continue; -+ -+ page = pfn_to_page(pfn); -+ VM_BUG_ON_PAGE(PageTail(page), page); -+ if (page_to_nid(page) != args->node_id) -+ continue; -+ -+ if (page_memcg_rcu(page) != args->memcg) -+ continue; -+ -+ VM_BUG_ON(addr < vma->vm_start || addr >= vma->vm_end); -+ if (!pmdp_test_and_clear_young(vma, addr, pmd + i)) -+ continue; -+ -+ args->mm_stats[MM_LEAF_YOUNG]++; -+ -+ if (pmd_dirty(pmd[i]) && !PageDirty(page) && -+ !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) -+ set_page_dirty(page); -+ -+ old_gen = page_update_gen(page, new_gen); -+ if (old_gen >= 0 && old_gen != new_gen) -+ update_batch_size(page, old_gen, new_gen, args); -+ } -+ -+ arch_leave_lazy_mmu_mode(); -+ spin_unlock(ptl); -+ -+ bitmap_zero(args->bitmap, MIN_BATCH_SIZE); -+} -+#else -+static void walk_pmd_range_locked(pud_t *pud, unsigned long start, int offset, -+ struct vm_area_struct *vma, struct mm_walk *walk) -+{ -+} -+#endif -+ -+static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, -+ struct mm_walk *walk) -+{ -+ int i; -+ pmd_t *pmd; -+ unsigned long next; -+ unsigned long addr; -+ struct vm_area_struct *vma; -+ int offset = -1; -+ bool reset = false; -+ struct mm_walk_args *args = walk->private; -+ struct lruvec *lruvec = get_lruvec(args->node_id, args->memcg); -+ -+ VM_BUG_ON(pud_leaf(*pud)); -+ -+ pmd = pmd_offset(pud, start & PUD_MASK); -+restart: -+ vma = walk->vma; -+ for (i = pmd_index(start), addr = start; addr != end; i++, addr = next) { -+ pmd_t val = pmd_read_atomic(pmd + i); -+ -+ /* for pmd_read_atomic() */ -+ barrier(); -+ -+ next = pmd_addr_end(addr, end); -+ -+ if (!pmd_present(val)) { -+ args->mm_stats[MM_LEAF_TOTAL]++; -+ continue; -+ } -+ -+#ifdef CONFIG_TRANSPARENT_HUGEPAGE -+ if (pmd_trans_huge(val)) { -+ unsigned long pfn = pmd_pfn(val); -+ -+ args->mm_stats[MM_LEAF_TOTAL]++; -+ -+ if (is_huge_zero_pmd(val)) -+ continue; -+ -+ if (!pmd_young(val)) { -+ args->mm_stats[MM_LEAF_OLD]++; -+ continue; -+ } -+ -+ if (pfn < args->start_pfn || pfn >= args->end_pfn) -+ continue; -+ -+ if (offset < 0) -+ offset = i; -+ else if (i - offset >= MIN_BATCH_SIZE) { -+ walk_pmd_range_locked(pud, start, offset, vma, walk); -+ offset = i; -+ } -+ __set_bit(i - offset, args->bitmap); -+ reset = true; -+ continue; -+ } -+#endif -+ args->mm_stats[MM_NONLEAF_TOTAL]++; -+ -+#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG -+ if (!pmd_young(val)) -+ continue; -+ -+ if (offset < 0) -+ offset = i; -+ else if (i - offset >= MIN_BATCH_SIZE) { -+ walk_pmd_range_locked(pud, start, offset, vma, walk); -+ offset = i; -+ reset = false; -+ } -+ __set_bit(i - offset, args->bitmap); -+#endif -+ if (args->use_filter && !test_bloom_filter(lruvec, args->max_seq, pmd + i)) -+ continue; -+ -+ args->mm_stats[MM_NONLEAF_PREV]++; -+ -+ if (!walk_pte_range(&val, addr, next, walk)) -+ continue; -+ -+ args->mm_stats[MM_NONLEAF_CUR]++; -+ -+ set_bloom_filter(lruvec, args->max_seq + 1, pmd + i); -+ } -+ -+ if (reset) { -+ walk_pmd_range_locked(pud, start, offset, vma, walk); -+ offset = -1; -+ reset = false; -+ } -+ -+ if (i < PTRS_PER_PMD && get_next_vma(walk, PUD_MASK, PMD_SIZE, &start, &end)) -+ goto restart; -+ -+ if (offset >= 0) -+ walk_pmd_range_locked(pud, start, offset, vma, walk); -+} -+ -+static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, -+ struct mm_walk *walk) -+{ -+ int i; -+ pud_t *pud; -+ unsigned long addr; -+ unsigned long next; -+ struct mm_walk_args *args = walk->private; -+ -+ VM_BUG_ON(p4d_leaf(*p4d)); -+ -+ pud = pud_offset(p4d, start & P4D_MASK); -+restart: -+ for (i = pud_index(start), addr = start; addr != end; i++, addr = next) { -+ pud_t val = READ_ONCE(pud[i]); -+ -+ next = pud_addr_end(addr, end); -+ -+ if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val))) -+ continue; -+ -+ walk_pmd_range(&val, addr, next, walk); -+ -+ if (args->batch_size >= MAX_BATCH_SIZE) { -+ end = (addr | ~PUD_MASK) + 1; -+ goto done; -+ } -+ } -+ -+ if (i < PTRS_PER_PUD && get_next_vma(walk, P4D_MASK, PUD_SIZE, &start, &end)) -+ goto restart; -+ -+ end = round_up(end, P4D_SIZE); -+done: -+ /* rounded-up boundaries can wrap to 0 */ -+ args->next_addr = end && walk->vma ? max(end, walk->vma->vm_start) : 0; -+ -+ return -EAGAIN; -+} -+ -+static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct mm_walk_args *args) -+{ -+ static const struct mm_walk_ops mm_walk_ops = { -+ .test_walk = should_skip_vma, -+ .p4d_entry = walk_pud_range, -+ }; -+ -+ int err; -+ -+ args->next_addr = FIRST_USER_ADDRESS; -+ -+ do { -+ unsigned long start = args->next_addr; -+ unsigned long end = mm->highest_vm_end; -+ -+ err = -EBUSY; -+ -+ rcu_read_lock(); -+#ifdef CONFIG_MEMCG -+ if (args->memcg && atomic_read(&args->memcg->moving_account)) -+ goto contended; -+#endif -+ if (!mmap_read_trylock(mm)) -+ goto contended; -+ -+ err = walk_page_range(mm, start, end, &mm_walk_ops, args); -+ -+ mmap_read_unlock(mm); -+ -+ if (args->batch_size) { -+ spin_lock_irq(&lruvec->lru_lock); -+ reset_batch_size(lruvec, args); -+ spin_unlock_irq(&lruvec->lru_lock); -+ } -+contended: -+ rcu_read_unlock(); -+ -+ cond_resched(); -+ } while (err == -EAGAIN && args->next_addr && !mm_is_oom_victim(mm)); -+} -+ -+static struct mm_walk_args *alloc_mm_walk_args(void) -+{ -+ if (!current->reclaim_state || !current->reclaim_state->mm_walk_args) -+ return kvzalloc(sizeof(struct mm_walk_args), GFP_KERNEL); -+ -+ return current->reclaim_state->mm_walk_args; -+} -+ -+static void free_mm_walk_args(struct mm_walk_args *args) -+{ -+ if (!current->reclaim_state || !current->reclaim_state->mm_walk_args) -+ kvfree(args); -+} -+ -+static bool inc_min_seq(struct lruvec *lruvec, int type) -+{ -+ int gen, zone; -+ int remaining = MAX_BATCH_SIZE; -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ VM_BUG_ON(!seq_is_valid(lruvec)); -+ -+ if (get_nr_gens(lruvec, type) != MAX_NR_GENS) -+ return true; -+ -+ gen = lru_gen_from_seq(lrugen->min_seq[type]); -+ -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) { -+ struct list_head *head = &lrugen->lists[gen][type][zone]; -+ -+ while (!list_empty(head)) { -+ struct page *page = lru_to_page(head); -+ -+ VM_BUG_ON_PAGE(PageTail(page), page); -+ VM_BUG_ON_PAGE(PageUnevictable(page), page); -+ VM_BUG_ON_PAGE(PageActive(page), page); -+ VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); -+ VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); -+ -+ prefetchw_prev_lru_page(page, head, flags); -+ -+ page_inc_gen(page, lruvec, false); -+ -+ if (!--remaining) -+ return false; -+ } -+ } -+ -+ WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); -+ -+ return true; -+} -+ -+static bool try_to_inc_min_seq(struct lruvec *lruvec, int swappiness) -+{ -+ int gen, type, zone; -+ bool success = false; -+ struct lrugen *lrugen = &lruvec->evictable; -+ DEFINE_MIN_SEQ(lruvec); -+ -+ VM_BUG_ON(!seq_is_valid(lruvec)); -+ -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ while (lrugen->max_seq - min_seq[type] >= MIN_NR_GENS) { -+ gen = lru_gen_from_seq(min_seq[type]); -+ -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) { -+ if (!list_empty(&lrugen->lists[gen][type][zone])) -+ goto next; -+ } -+ -+ min_seq[type]++; -+ } -+next: -+ ; -+ } -+ -+ min_seq[0] = min(min_seq[0], min_seq[1]); -+ if (swappiness) -+ min_seq[1] = max(min_seq[0], lrugen->min_seq[1]); -+ -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ if (min_seq[type] == lrugen->min_seq[type]) -+ continue; -+ -+ WRITE_ONCE(lrugen->min_seq[type], min_seq[type]); -+ success = true; -+ } -+ -+ return success; -+} -+ -+static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq) -+{ -+ int gen, type, zone; -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ -+ VM_BUG_ON(!seq_is_valid(lruvec)); -+ -+ if (max_seq != lrugen->max_seq) -+ goto unlock; -+ -+ if (!try_to_inc_min_seq(lruvec, true)) { -+ for (type = ANON_AND_FILE - 1; type >= 0; type--) { -+ while (!inc_min_seq(lruvec, type)) { -+ spin_unlock_irq(&lruvec->lru_lock); -+ cond_resched(); -+ spin_lock_irq(&lruvec->lru_lock); -+ } -+ } -+ } -+ -+ gen = lru_gen_from_seq(lrugen->max_seq - 1); -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) { -+ enum lru_list lru = type * LRU_FILE; -+ long delta = lrugen->sizes[gen][type][zone]; -+ -+ if (!delta) -+ continue; -+ -+ WARN_ON_ONCE(delta != (int)delta); -+ -+ update_lru_size(lruvec, lru, zone, delta); -+ update_lru_size(lruvec, lru + LRU_ACTIVE, zone, -delta); -+ } -+ } -+ -+ gen = lru_gen_from_seq(lrugen->max_seq + 1); -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) { -+ enum lru_list lru = type * LRU_FILE; -+ long delta = lrugen->sizes[gen][type][zone]; -+ -+ if (!delta) -+ continue; -+ -+ WARN_ON_ONCE(delta != (int)delta); -+ -+ update_lru_size(lruvec, lru, zone, -delta); -+ update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta); -+ } -+ } -+ -+ WRITE_ONCE(lrugen->timestamps[gen], jiffies); -+ /* make sure all preceding modifications appear first */ -+ smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); -+unlock: -+ spin_unlock_irq(&lruvec->lru_lock); -+} -+ -+/* Main function used by the foreground, the background and the user-triggered aging. */ -+static bool try_to_inc_max_seq(struct lruvec *lruvec, struct scan_control *sc, int swappiness, -+ unsigned long max_seq, bool use_filter) -+{ -+ bool last; -+ struct mm_walk_args *args; -+ struct mm_struct *mm = NULL; -+ struct lrugen *lrugen = &lruvec->evictable; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ struct pglist_data *pgdat = lruvec_pgdat(lruvec); -+ int nid = pgdat->node_id; -+ -+ VM_BUG_ON(max_seq > READ_ONCE(lrugen->max_seq)); -+ -+ /* -+ * If we are not from run_aging() and clearing the accessed bit may -+ * trigger page faults, then don't proceed to clearing all accessed -+ * PTEs. Instead, fallback to lru_gen_look_around(), which only clears a -+ * handful of accessed PTEs. This is less efficient but causes fewer -+ * page faults on CPUs that don't have the capability. -+ */ -+ if ((current->flags & PF_MEMALLOC) && !arch_has_hw_pte_young(false)) { -+ inc_max_seq(lruvec, max_seq); -+ return true; -+ } -+ -+ args = alloc_mm_walk_args(); -+ if (!args) -+ return false; -+ -+ args->memcg = memcg; -+ args->max_seq = max_seq; -+ args->start_pfn = pgdat->node_start_pfn; -+ args->end_pfn = pgdat_end_pfn(pgdat); -+ args->node_id = nid; -+ args->swappiness = swappiness; -+ args->use_filter = use_filter; -+ -+ do { -+ last = get_next_mm(lruvec, args, &mm); -+ if (mm) -+ walk_mm(lruvec, mm, args); -+ -+ cond_resched(); -+ } while (mm); -+ -+ free_mm_walk_args(args); -+ -+ if (!last) { -+ /* don't wait unless we may have trouble reclaiming */ -+ if (!current_is_kswapd() && sc->priority < DEF_PRIORITY - 2) -+ wait_event_killable(lruvec->mm_walk.wait, -+ max_seq < READ_ONCE(lrugen->max_seq)); -+ -+ return max_seq < READ_ONCE(lrugen->max_seq); -+ } -+ -+ VM_BUG_ON(max_seq != READ_ONCE(lrugen->max_seq)); -+ -+ inc_max_seq(lruvec, max_seq); -+ /* either we see any waiters or they will see updated max_seq */ -+ if (wq_has_sleeper(&lruvec->mm_walk.wait)) -+ wake_up_all(&lruvec->mm_walk.wait); -+ -+ wakeup_flusher_threads(WB_REASON_VMSCAN); -+ -+ return true; -+} -+ -+static long get_nr_evictable(struct lruvec *lruvec, struct scan_control *sc, int swappiness, -+ unsigned long max_seq, unsigned long *min_seq, bool *low) -+{ -+ int gen, type, zone; -+ long max = 0; -+ long min = 0; -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ for (type = !swappiness; type < ANON_AND_FILE; type++) { -+ unsigned long seq; -+ -+ for (seq = min_seq[type]; seq <= max_seq; seq++) { -+ long size = 0; -+ -+ gen = lru_gen_from_seq(seq); -+ -+ for (zone = 0; zone <= sc->reclaim_idx; zone++) -+ size += READ_ONCE(lrugen->sizes[gen][type][zone]); -+ -+ max += size; -+ if (type && max_seq - seq >= MIN_NR_GENS) -+ min += size; -+ } -+ } -+ -+ *low = max_seq - min_seq[1] <= MIN_NR_GENS && min < MIN_BATCH_SIZE; -+ -+ return max > 0 ? max : 0; -+} -+ -+static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, -+ unsigned long min_ttl) -+{ -+ bool low; -+ long nr_to_scan; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ int swappiness = get_swappiness(memcg); -+ DEFINE_MAX_SEQ(lruvec); -+ DEFINE_MIN_SEQ(lruvec); -+ -+ if (mem_cgroup_below_min(memcg)) -+ return false; -+ -+ if (min_ttl) { -+ int gen = lru_gen_from_seq(min_seq[1]); -+ unsigned long birth = READ_ONCE(lruvec->evictable.timestamps[gen]); -+ -+ if (time_is_after_jiffies(birth + min_ttl)) -+ return false; -+ } -+ -+ nr_to_scan = get_nr_evictable(lruvec, sc, swappiness, max_seq, min_seq, &low); -+ if (!nr_to_scan) -+ return false; -+ -+ nr_to_scan >>= sc->priority; -+ -+ if (!mem_cgroup_online(memcg)) -+ nr_to_scan++; -+ -+ if (nr_to_scan && low && (!mem_cgroup_below_low(memcg) || sc->memcg_low_reclaim)) -+ try_to_inc_max_seq(lruvec, sc, swappiness, max_seq, true); -+ -+ return true; -+} -+ -+/* Protect the working set accessed within the last N milliseconds. */ -+static unsigned long lru_gen_min_ttl __read_mostly; -+ -+static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) -+{ -+ struct mem_cgroup *memcg; -+ bool success = false; -+ unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); -+ -+ VM_BUG_ON(!current_is_kswapd()); -+ -+ if (!sc->force_deactivate) { -+ sc->force_deactivate = 1; -+ return; -+ } -+ -+ current->reclaim_state->mm_walk_args = &pgdat->mm_walk_args; -+ -+ memcg = mem_cgroup_iter(NULL, NULL, NULL); -+ do { -+ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); -+ -+ if (age_lruvec(lruvec, sc, min_ttl)) -+ success = true; -+ -+ cond_resched(); -+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); -+ -+ if (!success && mutex_trylock(&oom_lock)) { -+ struct oom_control oc = { -+ .gfp_mask = sc->gfp_mask, -+ .order = sc->order, -+ }; -+ -+ /* to avoid overkilling */ -+ if (!oom_reaping_in_progress()) -+ out_of_memory(&oc); -+ -+ mutex_unlock(&oom_lock); -+ } -+ -+ current->reclaim_state->mm_walk_args = NULL; -+} -+ -+/* Scan the vicinity of an accessed PTE when shrink_page_list() uses the rmap. */ -+void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) -+{ -+ int i; -+ pte_t *pte; -+ struct page *page; -+ int old_gen, new_gen; -+ unsigned long start; -+ unsigned long end; -+ unsigned long addr; -+ struct mm_walk_args *args; -+ int worth = 0; -+ struct mem_cgroup *memcg = page_memcg(pvmw->page); -+ struct pglist_data *pgdat = page_pgdat(pvmw->page); -+ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); -+ DEFINE_MAX_SEQ(lruvec); -+ -+ lockdep_assert_held(pvmw->ptl); -+ VM_BUG_ON_PAGE(PageLRU(pvmw->page), pvmw->page); -+ -+ args = current->reclaim_state ? current->reclaim_state->mm_walk_args : NULL; -+ if (!args) -+ return; -+ -+ start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); -+ end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; -+ -+ if (end - start > MIN_BATCH_SIZE * PAGE_SIZE) { -+ if (pvmw->address - start < MIN_BATCH_SIZE * PAGE_SIZE / 2) -+ end = start + MIN_BATCH_SIZE * PAGE_SIZE; -+ else if (end - pvmw->address < MIN_BATCH_SIZE * PAGE_SIZE / 2) -+ start = end - MIN_BATCH_SIZE * PAGE_SIZE; -+ else { -+ start = pvmw->address - MIN_BATCH_SIZE * PAGE_SIZE / 2; -+ end = pvmw->address + MIN_BATCH_SIZE * PAGE_SIZE / 2; -+ } -+ } -+ -+ pte = pvmw->pte - (pvmw->address - start) / PAGE_SIZE; -+ new_gen = lru_gen_from_seq(max_seq); -+ -+ lock_page_memcg(pvmw->page); -+ arch_enter_lazy_mmu_mode(); -+ -+ for (i = 0, addr = start; addr != end; i++, addr += PAGE_SIZE) { -+ unsigned long pfn = pte_pfn(pte[i]); -+ -+ if (!pte_present(pte[i]) || is_zero_pfn(pfn)) -+ continue; -+ -+ if (WARN_ON_ONCE(pte_devmap(pte[i]) || pte_special(pte[i]))) -+ continue; -+ -+ VM_BUG_ON(!pfn_valid(pfn)); -+ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) -+ continue; -+ -+ worth++; -+ -+ if (!pte_young(pte[i])) -+ continue; -+ -+ page = compound_head(pfn_to_page(pfn)); -+ if (page_to_nid(page) != pgdat->node_id) -+ continue; -+ -+ if (page_memcg_rcu(page) != memcg) -+ continue; -+ -+ VM_BUG_ON(addr < pvmw->vma->vm_start || addr >= pvmw->vma->vm_end); -+ if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) -+ continue; -+ -+ if (pte_dirty(pte[i]) && !PageDirty(page) && -+ !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) -+ __set_bit(i, args->bitmap); -+ -+ old_gen = page_update_gen(page, new_gen); -+ if (old_gen >= 0 && old_gen != new_gen) -+ update_batch_size(page, old_gen, new_gen, args); -+ } -+ -+ arch_leave_lazy_mmu_mode(); -+ unlock_page_memcg(pvmw->page); -+ -+ if (worth >= MIN_BATCH_SIZE / 2) -+ set_bloom_filter(lruvec, max_seq, pvmw->pmd); -+ -+ for_each_set_bit(i, args->bitmap, MIN_BATCH_SIZE) -+ set_page_dirty(pte_page(pte[i])); -+ -+ bitmap_zero(args->bitmap, MIN_BATCH_SIZE); -+} -+ -+/****************************************************************************** - * state change - ******************************************************************************/ - -@@ -3412,6 +4349,12 @@ static int __init init_lru_gen(void) - }; - late_initcall(init_lru_gen); - -+#else -+ -+static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) -+{ -+} -+ - #endif /* CONFIG_LRU_GEN */ - - static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -@@ -4266,6 +5209,11 @@ static void age_active_anon(struct pglis - struct mem_cgroup *memcg; - struct lruvec *lruvec; - -+ if (lru_gen_enabled()) { -+ lru_gen_age_node(pgdat, sc); -+ return; -+ } -+ - if (!can_age_anon_pages(pgdat, sc)) - return; - diff --git a/target/linux/generic/backport-5.15/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch b/target/linux/generic/backport-5.15/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch new file mode 100644 index 00000000000..e0c6380b5f7 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch @@ -0,0 +1,508 @@ +From e4277535f6d6708bb19b88c4bad155832671d69b Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:04 -0600 +Subject: [PATCH 07/29] mm: multi-gen LRU: exploit locality in rmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Searching the rmap for PTEs mapping each page on an LRU list (to test and +clear the accessed bit) can be expensive because pages from different VMAs +(PA space) are not cache friendly to the rmap (VA space). For workloads +mostly using mapped pages, searching the rmap can incur the highest CPU +cost in the reclaim path. + +This patch exploits spatial locality to reduce the trips into the rmap. +When shrink_page_list() walks the rmap and finds a young PTE, a new +function lru_gen_look_around() scans at most BITS_PER_LONG-1 adjacent +PTEs. On finding another young PTE, it clears the accessed bit and +updates the gen counter of the page mapped by this PTE to +(max_seq%MAX_NR_GENS)+1. + +Server benchmark results: + Single workload: + fio (buffered I/O): no change + + Single workload: + memcached (anon): +[3, 5]% + Ops/sec KB/sec + patch1-6: 1106168.46 43025.04 + patch1-7: 1147696.57 44640.29 + + Configurations: + no change + +Client benchmark results: + kswapd profiles: + patch1-6 + 39.03% lzo1x_1_do_compress (real work) + 18.47% page_vma_mapped_walk (overhead) + 6.74% _raw_spin_unlock_irq + 3.97% do_raw_spin_lock + 2.49% ptep_clear_flush + 2.48% anon_vma_interval_tree_iter_first + 1.92% page_referenced_one + 1.88% __zram_bvec_write + 1.48% memmove + 1.31% vma_interval_tree_iter_next + + patch1-7 + 48.16% lzo1x_1_do_compress (real work) + 8.20% page_vma_mapped_walk (overhead) + 7.06% _raw_spin_unlock_irq + 2.92% ptep_clear_flush + 2.53% __zram_bvec_write + 2.11% do_raw_spin_lock + 2.02% memmove + 1.93% lru_gen_look_around + 1.56% free_unref_page_list + 1.40% memset + + Configurations: + no change + +Link: https://lkml.kernel.org/r/20220918080010.2920238-8-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Barry Song +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/memcontrol.h | 31 +++++++ + include/linux/mmzone.h | 6 ++ + mm/internal.h | 1 + + mm/memcontrol.c | 1 + + mm/rmap.c | 7 ++ + mm/swap.c | 4 +- + mm/vmscan.c | 184 +++++++++++++++++++++++++++++++++++++ + 7 files changed, 232 insertions(+), 2 deletions(-) + +diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h +index 4f189b17dafc..8d6a0329bc59 100644 +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -442,6 +442,7 @@ static inline struct obj_cgroup *__page_objcg(struct page *page) + * - LRU isolation + * - lock_page_memcg() + * - exclusive reference ++ * - mem_cgroup_trylock_pages() + * + * For a kmem page a caller should hold an rcu read lock to protect memcg + * associated with a kmem page from being released. +@@ -497,6 +498,7 @@ static inline struct mem_cgroup *page_memcg_rcu(struct page *page) + * - LRU isolation + * - lock_page_memcg() + * - exclusive reference ++ * - mem_cgroup_trylock_pages() + * + * For a kmem page a caller should hold an rcu read lock to protect memcg + * associated with a kmem page from being released. +@@ -953,6 +955,23 @@ void unlock_page_memcg(struct page *page); + + void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val); + ++/* try to stablize page_memcg() for all the pages in a memcg */ ++static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) ++{ ++ rcu_read_lock(); ++ ++ if (mem_cgroup_disabled() || !atomic_read(&memcg->moving_account)) ++ return true; ++ ++ rcu_read_unlock(); ++ return false; ++} ++ ++static inline void mem_cgroup_unlock_pages(void) ++{ ++ rcu_read_unlock(); ++} ++ + /* idx can be of type enum memcg_stat_item or node_stat_item */ + static inline void mod_memcg_state(struct mem_cgroup *memcg, + int idx, int val) +@@ -1369,6 +1388,18 @@ static inline void unlock_page_memcg(struct page *page) + { + } + ++static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) ++{ ++ /* to match page_memcg_rcu() */ ++ rcu_read_lock(); ++ return true; ++} ++ ++static inline void mem_cgroup_unlock_pages(void) ++{ ++ rcu_read_unlock(); ++} ++ + static inline void mem_cgroup_handle_over_high(void) + { + } +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index fce8945c507c..4db2b877fcf9 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -352,6 +352,7 @@ enum lruvec_flags { + #ifndef __GENERATING_BOUNDS_H + + struct lruvec; ++struct page_vma_mapped_walk; + + #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) + #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) +@@ -407,6 +408,7 @@ struct lru_gen_struct { + }; + + void lru_gen_init_lruvec(struct lruvec *lruvec); ++void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + + #ifdef CONFIG_MEMCG + void lru_gen_init_memcg(struct mem_cgroup *memcg); +@@ -419,6 +421,10 @@ static inline void lru_gen_init_lruvec(struct lruvec *lruvec) + { + } + ++static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) ++{ ++} ++ + #ifdef CONFIG_MEMCG + static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) + { +diff --git a/mm/internal.h b/mm/internal.h +index cf3cb933eba3..5c73246a092e 100644 +--- a/mm/internal.h ++++ b/mm/internal.h +@@ -35,6 +35,7 @@ + void page_writeback_init(void); + + vm_fault_t do_swap_page(struct vm_fault *vmf); ++void activate_page(struct page *page); + + void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma, + unsigned long floor, unsigned long ceiling); +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index 8b634dc72e7f..cc3431c5d9ba 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -2798,6 +2798,7 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg) + * - LRU isolation + * - lock_page_memcg() + * - exclusive reference ++ * - mem_cgroup_trylock_pages() + */ + page->memcg_data = (unsigned long)memcg; + } +diff --git a/mm/rmap.c b/mm/rmap.c +index 330b361a460e..22a86122732e 100644 +--- a/mm/rmap.c ++++ b/mm/rmap.c +@@ -73,6 +73,7 @@ + #include + #include + #include ++#include + + #include + +@@ -793,6 +794,12 @@ static bool page_referenced_one(struct page *page, struct vm_area_struct *vma, + } + + if (pvmw.pte) { ++ if (lru_gen_enabled() && pte_young(*pvmw.pte) && ++ !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) { ++ lru_gen_look_around(&pvmw); ++ referenced++; ++ } ++ + if (ptep_clear_flush_young_notify(vma, address, + pvmw.pte)) { + /* +diff --git a/mm/swap.c b/mm/swap.c +index 5d227577b609..966ff2d83343 100644 +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -325,7 +325,7 @@ static bool need_activate_page_drain(int cpu) + return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0; + } + +-static void activate_page(struct page *page) ++void activate_page(struct page *page) + { + page = compound_head(page); + if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { +@@ -345,7 +345,7 @@ static inline void activate_page_drain(int cpu) + { + } + +-static void activate_page(struct page *page) ++void activate_page(struct page *page) + { + struct lruvec *lruvec; + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 932abd24c1b3..1d0b25ae378c 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -1409,6 +1409,11 @@ static unsigned int shrink_page_list(struct list_head *page_list, + if (!sc->may_unmap && page_mapped(page)) + goto keep_locked; + ++ /* page_update_gen() tried to promote this page? */ ++ if (lru_gen_enabled() && !ignore_references && ++ page_mapped(page) && PageReferenced(page)) ++ goto keep_locked; ++ + may_enter_fs = (sc->gfp_mask & __GFP_FS) || + (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); + +@@ -2990,6 +2995,29 @@ static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) + * the aging + ******************************************************************************/ + ++/* promote pages accessed through page tables */ ++static int page_update_gen(struct page *page, int gen) ++{ ++ unsigned long new_flags, old_flags = READ_ONCE(page->flags); ++ ++ VM_WARN_ON_ONCE(gen >= MAX_NR_GENS); ++ VM_WARN_ON_ONCE(!rcu_read_lock_held()); ++ ++ do { ++ /* lru_gen_del_page() has isolated this page? */ ++ if (!(old_flags & LRU_GEN_MASK)) { ++ /* for shrink_page_list() */ ++ new_flags = old_flags | BIT(PG_referenced); ++ continue; ++ } ++ ++ new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); ++ new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; ++ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); ++ ++ return ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; ++} ++ + /* protect pages accessed multiple times through file descriptors */ + static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) + { +@@ -3001,6 +3029,11 @@ static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaimin + VM_WARN_ON_ONCE_PAGE(!(old_flags & LRU_GEN_MASK), page); + + do { ++ new_gen = ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; ++ /* page_update_gen() has promoted this page? */ ++ if (new_gen >= 0 && new_gen != old_gen) ++ return new_gen; ++ + new_gen = (old_gen + 1) % MAX_NR_GENS; + + new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); +@@ -3015,6 +3048,43 @@ static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaimin + return new_gen; + } + ++static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr) ++{ ++ unsigned long pfn = pte_pfn(pte); ++ ++ VM_WARN_ON_ONCE(addr < vma->vm_start || addr >= vma->vm_end); ++ ++ if (!pte_present(pte) || is_zero_pfn(pfn)) ++ return -1; ++ ++ if (WARN_ON_ONCE(pte_devmap(pte) || pte_special(pte))) ++ return -1; ++ ++ if (WARN_ON_ONCE(!pfn_valid(pfn))) ++ return -1; ++ ++ return pfn; ++} ++ ++static struct page *get_pfn_page(unsigned long pfn, struct mem_cgroup *memcg, ++ struct pglist_data *pgdat) ++{ ++ struct page *page; ++ ++ /* try to avoid unnecessary memory loads */ ++ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) ++ return NULL; ++ ++ page = compound_head(pfn_to_page(pfn)); ++ if (page_to_nid(page) != pgdat->node_id) ++ return NULL; ++ ++ if (page_memcg_rcu(page) != memcg) ++ return NULL; ++ ++ return page; ++} ++ + static void inc_min_seq(struct lruvec *lruvec, int type) + { + struct lru_gen_struct *lrugen = &lruvec->lrugen; +@@ -3214,6 +3284,114 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + } + ++/* ++ * This function exploits spatial locality when shrink_page_list() walks the ++ * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. ++ */ ++void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) ++{ ++ int i; ++ pte_t *pte; ++ unsigned long start; ++ unsigned long end; ++ unsigned long addr; ++ unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; ++ struct page *page = pvmw->page; ++ struct mem_cgroup *memcg = page_memcg(page); ++ struct pglist_data *pgdat = page_pgdat(page); ++ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); ++ DEFINE_MAX_SEQ(lruvec); ++ int old_gen, new_gen = lru_gen_from_seq(max_seq); ++ ++ lockdep_assert_held(pvmw->ptl); ++ VM_WARN_ON_ONCE_PAGE(PageLRU(page), page); ++ ++ if (spin_is_contended(pvmw->ptl)) ++ return; ++ ++ start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); ++ end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; ++ ++ if (end - start > MIN_LRU_BATCH * PAGE_SIZE) { ++ if (pvmw->address - start < MIN_LRU_BATCH * PAGE_SIZE / 2) ++ end = start + MIN_LRU_BATCH * PAGE_SIZE; ++ else if (end - pvmw->address < MIN_LRU_BATCH * PAGE_SIZE / 2) ++ start = end - MIN_LRU_BATCH * PAGE_SIZE; ++ else { ++ start = pvmw->address - MIN_LRU_BATCH * PAGE_SIZE / 2; ++ end = pvmw->address + MIN_LRU_BATCH * PAGE_SIZE / 2; ++ } ++ } ++ ++ pte = pvmw->pte - (pvmw->address - start) / PAGE_SIZE; ++ ++ rcu_read_lock(); ++ arch_enter_lazy_mmu_mode(); ++ ++ for (i = 0, addr = start; addr != end; i++, addr += PAGE_SIZE) { ++ unsigned long pfn; ++ ++ pfn = get_pte_pfn(pte[i], pvmw->vma, addr); ++ if (pfn == -1) ++ continue; ++ ++ if (!pte_young(pte[i])) ++ continue; ++ ++ page = get_pfn_page(pfn, memcg, pgdat); ++ if (!page) ++ continue; ++ ++ if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) ++ VM_WARN_ON_ONCE(true); ++ ++ if (pte_dirty(pte[i]) && !PageDirty(page) && ++ !(PageAnon(page) && PageSwapBacked(page) && ++ !PageSwapCache(page))) ++ set_page_dirty(page); ++ ++ old_gen = page_lru_gen(page); ++ if (old_gen < 0) ++ SetPageReferenced(page); ++ else if (old_gen != new_gen) ++ __set_bit(i, bitmap); ++ } ++ ++ arch_leave_lazy_mmu_mode(); ++ rcu_read_unlock(); ++ ++ if (bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { ++ for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { ++ page = pte_page(pte[i]); ++ activate_page(page); ++ } ++ return; ++ } ++ ++ /* page_update_gen() requires stable page_memcg() */ ++ if (!mem_cgroup_trylock_pages(memcg)) ++ return; ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); ++ ++ for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { ++ page = compound_head(pte_page(pte[i])); ++ if (page_memcg_rcu(page) != memcg) ++ continue; ++ ++ old_gen = page_update_gen(page, new_gen); ++ if (old_gen < 0 || old_gen == new_gen) ++ continue; ++ ++ lru_gen_update_size(lruvec, page, old_gen, new_gen); ++ } ++ ++ spin_unlock_irq(&lruvec->lru_lock); ++ ++ mem_cgroup_unlock_pages(); ++} ++ + /****************************************************************************** + * the eviction + ******************************************************************************/ +@@ -3250,6 +3428,12 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) + return true; + } + ++ /* promoted */ ++ if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { ++ list_move(&page->lru, &lrugen->lists[gen][type][zone]); ++ return true; ++ } ++ + /* protected */ + if (tier > tier_idx) { + int hist = lru_hist_from_seq(lrugen->min_seq[type]); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-07-mm-multigenerational-lru-eviction.patch b/target/linux/generic/backport-5.15/020-v6.1-07-mm-multigenerational-lru-eviction.patch deleted file mode 100644 index a75fedecaaa..00000000000 --- a/target/linux/generic/backport-5.15/020-v6.1-07-mm-multigenerational-lru-eviction.patch +++ /dev/null @@ -1,1002 +0,0 @@ -From f4b881ce07ccb2a519f664afaa2a68225b612ca3 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Tue, 29 Jun 2021 20:46:47 -0600 -Subject: [PATCH 07/10] mm: multigenerational lru: eviction - -The eviction consumes old generations. Given an lruvec, the eviction -scans pages on lrugen->lists indexed by anon and file min_seq[] -(modulo MAX_NR_GENS). It first tries to select a type based on the -values of min_seq[]. If they are equal, it selects the type that has -a lower refaulted %. The eviction sorts a page according to its -updated generation number if the aging has found this page accessed. -It also moves a page to the next generation if this page is from an -upper tier that has a higher refaulted % than the base tier. The -eviction increments min_seq[] of a selected type when it finds -lrugen->lists indexed by min_seq[] of this selected type are empty. - -Each generation is divided into multiple tiers. Tiers represent -different ranges of numbers of accesses from file descriptors only. -Pages accessed N times via file descriptors belong to tier -order_base_2(N). Each generation contains at most MAX_NR_TIERS tiers, -and they require additional MAX_NR_TIERS-2 bits in page->flags. In -contrast to moving between generations which requires list operations, -moving between tiers only involves operations on page->flags and -therefore has a negligible cost. A feedback loop modeled after the PID -controller monitors refaulted % across all tiers and decides when to -protect pages from which tiers. - -Unmapped pages are initially added to the oldest generation and then -conditionally protected by tiers. Each tier keeps track of how many -pages from it have refaulted. Tier 0 is the base tier and pages from -it are evicted unconditionally because there are no better candidates. -Pages from an upper tier are either evicted or moved to the next -generation, depending on whether this upper tier has a higher -refaulted % than the base tier. This model has the following -advantages: - 1) It removes the cost in the buffered access path and reduces the - overall cost of protection because pages are conditionally protected - in the reclaim path. - 2) It takes mapped pages into account and avoids overprotecting - pages accessed multiple times via file descriptors. - 3 Additional tiers improve the protection of pages accessed more - than twice. - -Signed-off-by: Yu Zhao -Tested-by: Konstantin Kharlamov -Change-Id: I64c06d8f2cdb83ac7d56c7e1d07f043483956cac ---- - include/linux/mm_inline.h | 10 + - include/linux/mmzone.h | 33 +++ - mm/swap.c | 42 +++ - mm/vmscan.c | 555 +++++++++++++++++++++++++++++++++++++- - mm/workingset.c | 120 ++++++++- - 5 files changed, 757 insertions(+), 3 deletions(-) - ---- a/include/linux/mm_inline.h -+++ b/include/linux/mm_inline.h -@@ -106,6 +106,14 @@ static inline int lru_hist_from_seq(unsi - return seq % NR_HIST_GENS; - } - -+/* Convert the number of accesses to a tier. See the comment on MAX_NR_TIERS. */ -+static inline int lru_tier_from_refs(int refs) -+{ -+ VM_BUG_ON(refs > BIT(LRU_REFS_WIDTH)); -+ -+ return order_base_2(refs + 1); -+} -+ - /* The youngest and the second youngest generations are counted as active. */ - static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) - { -@@ -226,6 +234,8 @@ static inline bool lru_gen_del_page(stru - gen = ((new_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; - - new_flags &= ~LRU_GEN_MASK; -+ if ((new_flags & LRU_REFS_FLAGS) != LRU_REFS_FLAGS) -+ new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); - /* for shrink_page_list() */ - if (reclaiming) - new_flags &= ~(BIT(PG_referenced) | BIT(PG_reclaim)); ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -319,6 +319,30 @@ struct page_vma_mapped_walk; - #define MIN_NR_GENS 2 - #define MAX_NR_GENS ((unsigned int)CONFIG_NR_LRU_GENS) - -+/* -+ * Each generation is divided into multiple tiers. Tiers represent different -+ * ranges of numbers of accesses from file descriptors, i.e., -+ * mark_page_accessed(). In contrast to moving between generations which -+ * requires the lru lock, moving between tiers only involves an atomic -+ * operation on page->flags and therefore has a negligible cost. -+ * -+ * The purposes of tiers are to: -+ * 1) estimate whether pages accessed multiple times via file descriptors are -+ * more active than pages accessed only via page tables by separating the two -+ * access types into upper tiers and the base tier, and comparing refaulted % -+ * across all tiers. -+ * 2) improve buffered io performance by deferring the protection of pages -+ * accessed multiple times until the eviction. That is the protection happens -+ * in the reclaim path, not the access path. -+ * -+ * Pages accessed N times via file descriptors belong to tier order_base_2(N). -+ * The base tier may be marked by PageReferenced(). All upper tiers are marked -+ * by PageReferenced() && PageWorkingset(). Additional bits from page->flags are -+ * used to support more than one upper tier. -+ */ -+#define MAX_NR_TIERS ((unsigned int)CONFIG_TIERS_PER_GEN) -+#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset)) -+ - /* Whether to keep stats for historical generations. */ - #ifdef CONFIG_LRU_GEN_STATS - #define NR_HIST_GENS ((unsigned int)CONFIG_NR_LRU_GENS) -@@ -337,6 +361,15 @@ struct lrugen { - struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; - /* the sizes of the multigenerational lru lists in pages */ - unsigned long sizes[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+ /* the exponential moving average of refaulted */ -+ unsigned long avg_refaulted[ANON_AND_FILE][MAX_NR_TIERS]; -+ /* the exponential moving average of protected+evicted */ -+ unsigned long avg_total[ANON_AND_FILE][MAX_NR_TIERS]; -+ /* the base tier isn't protected, hence the minus one */ -+ unsigned long protected[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS - 1]; -+ /* incremented without holding the lru lock */ -+ atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; -+ atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; - /* whether the multigenerational lru is enabled */ - bool enabled[ANON_AND_FILE]; - }; ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -389,6 +389,43 @@ static void __lru_cache_activate_page(st - local_unlock(&lru_pvecs.lock); - } - -+#ifdef CONFIG_LRU_GEN -+static void page_inc_refs(struct page *page) -+{ -+ unsigned long refs; -+ unsigned long old_flags, new_flags; -+ -+ if (PageUnevictable(page)) -+ return; -+ -+ /* see the comment on MAX_NR_TIERS */ -+ do { -+ new_flags = old_flags = READ_ONCE(page->flags); -+ -+ if (!(new_flags & BIT(PG_referenced))) { -+ new_flags |= BIT(PG_referenced); -+ continue; -+ } -+ -+ if (!(new_flags & BIT(PG_workingset))) { -+ new_flags |= BIT(PG_workingset); -+ continue; -+ } -+ -+ refs = new_flags & LRU_REFS_MASK; -+ refs = min(refs + BIT(LRU_REFS_PGOFF), LRU_REFS_MASK); -+ -+ new_flags &= ~LRU_REFS_MASK; -+ new_flags |= refs; -+ } while (new_flags != old_flags && -+ cmpxchg(&page->flags, old_flags, new_flags) != old_flags); -+} -+#else -+static void page_inc_refs(struct page *page) -+{ -+} -+#endif /* CONFIG_LRU_GEN */ -+ - /* - * Mark a page as having seen activity. - * -@@ -403,6 +440,11 @@ void mark_page_accessed(struct page *pag - { - page = compound_head(page); - -+ if (lru_gen_enabled()) { -+ page_inc_refs(page); -+ return; -+ } -+ - if (!PageReferenced(page)) { - SetPageReferenced(page); - } else if (PageUnevictable(page)) { ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -1145,9 +1145,11 @@ static int __remove_mapping(struct addre - - if (PageSwapCache(page)) { - swp_entry_t swap = { .val = page_private(page) }; -- mem_cgroup_swapout(page, swap); -+ -+ /* get a shadow entry before page_memcg() is cleared */ - if (reclaimed && !mapping_exiting(mapping)) - shadow = workingset_eviction(page, target_memcg); -+ mem_cgroup_swapout(page, swap); - __delete_from_swap_cache(page, swap, shadow); - xa_unlock_irq(&mapping->i_pages); - put_swap_page(page, swap); -@@ -1410,6 +1412,11 @@ retry: - if (!sc->may_unmap && page_mapped(page)) - goto keep_locked; - -+ /* lru_gen_look_around() has updated this page? */ -+ if (lru_gen_enabled() && !ignore_references && -+ page_mapped(page) && PageReferenced(page)) -+ goto keep_locked; -+ - may_enter_fs = (sc->gfp_mask & __GFP_FS) || - (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); - -@@ -2505,6 +2512,9 @@ static void prepare_scan_count(pg_data_t - unsigned long file; - struct lruvec *target_lruvec; - -+ if (lru_gen_enabled()) -+ return; -+ - target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); - - /* -@@ -2845,6 +2855,17 @@ static int page_lru_gen(struct page *pag - return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; - } - -+static int page_lru_tier(struct page *page) -+{ -+ int refs; -+ unsigned long flags = READ_ONCE(page->flags); -+ -+ refs = (flags & LRU_REFS_FLAGS) == LRU_REFS_FLAGS ? -+ ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + 1 : 0; -+ -+ return lru_tier_from_refs(refs); -+} -+ - static int get_swappiness(struct mem_cgroup *memcg) - { - return mem_cgroup_get_nr_swap_pages(memcg) >= MIN_BATCH_SIZE ? -@@ -3181,6 +3202,91 @@ done: - } - - /****************************************************************************** -+ * refault feedback loop -+ ******************************************************************************/ -+ -+/* -+ * A feedback loop modeled after the PID controller. Currently supports the -+ * proportional (P) and the integral (I) terms; the derivative (D) term can be -+ * added if necessary. The setpoint (SP) is the desired position; the process -+ * variable (PV) is the measured position. The error is the difference between -+ * the SP and the PV. A positive error results in a positive control output -+ * correction, which, in our case, is to allow eviction. -+ * -+ * The P term is refaulted % of the current generation being evicted. The I -+ * term is the exponential moving average of refaulted % of previously evicted -+ * generations, using the smoothing factor 1/2. -+ * -+ * Our goal is to maintain proportional refaulted % across all tiers. -+ */ -+struct ctrl_pos { -+ unsigned long refaulted; -+ unsigned long total; -+ int gain; -+}; -+ -+static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain, -+ struct ctrl_pos *pos) -+{ -+ struct lrugen *lrugen = &lruvec->evictable; -+ int hist = lru_hist_from_seq(lrugen->min_seq[type]); -+ -+ pos->refaulted = lrugen->avg_refaulted[type][tier] + -+ atomic_long_read(&lrugen->refaulted[hist][type][tier]); -+ pos->total = lrugen->avg_total[type][tier] + -+ atomic_long_read(&lrugen->evicted[hist][type][tier]); -+ if (tier) -+ pos->total += lrugen->protected[hist][type][tier - 1]; -+ pos->gain = gain; -+} -+ -+static void reset_ctrl_pos(struct lruvec *lruvec, int gen, int type) -+{ -+ int tier; -+ int hist = lru_hist_from_seq(gen); -+ struct lrugen *lrugen = &lruvec->evictable; -+ bool carryover = gen == lru_gen_from_seq(lrugen->min_seq[type]); -+ bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; -+ -+ if (!carryover && !clear) -+ return; -+ -+ for (tier = 0; tier < MAX_NR_TIERS; tier++) { -+ if (carryover) { -+ unsigned long sum; -+ -+ sum = lrugen->avg_refaulted[type][tier] + -+ atomic_long_read(&lrugen->refaulted[hist][type][tier]); -+ WRITE_ONCE(lrugen->avg_refaulted[type][tier], sum / 2); -+ -+ sum = lrugen->avg_total[type][tier] + -+ atomic_long_read(&lrugen->evicted[hist][type][tier]); -+ if (tier) -+ sum += lrugen->protected[hist][type][tier - 1]; -+ WRITE_ONCE(lrugen->avg_total[type][tier], sum / 2); -+ } -+ -+ if (clear) { -+ atomic_long_set(&lrugen->refaulted[hist][type][tier], 0); -+ atomic_long_set(&lrugen->evicted[hist][type][tier], 0); -+ if (tier) -+ WRITE_ONCE(lrugen->protected[hist][type][tier - 1], 0); -+ } -+ } -+} -+ -+static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) -+{ -+ /* -+ * Allow eviction if the PV has a limited number of refaulted pages or a -+ * lower refaulted % than the SP. -+ */ -+ return pv->refaulted < MIN_BATCH_SIZE || -+ pv->refaulted * max(sp->total, 1UL) * sp->gain <= -+ sp->refaulted * max(pv->total, 1UL) * pv->gain; -+} -+ -+/****************************************************************************** - * the aging - ******************************************************************************/ - -@@ -3200,6 +3306,7 @@ static int page_update_gen(struct page * - - new_flags &= ~LRU_GEN_MASK; - new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; -+ new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); - } while (new_flags != old_flags && - cmpxchg(&page->flags, old_flags, new_flags) != old_flags); - -@@ -3231,6 +3338,7 @@ static void page_inc_gen(struct page *pa - - new_flags &= ~LRU_GEN_MASK; - new_flags |= (new_gen + 1UL) << LRU_GEN_PGOFF; -+ new_flags &= ~(LRU_REFS_MASK | LRU_REFS_FLAGS); - /* for end_page_writeback() */ - if (reclaiming) - new_flags |= BIT(PG_reclaim); -@@ -3722,6 +3830,7 @@ static bool inc_min_seq(struct lruvec *l - } - } - -+ reset_ctrl_pos(lruvec, gen, type); - WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); - - return true; -@@ -3759,6 +3868,8 @@ next: - if (min_seq[type] == lrugen->min_seq[type]) - continue; - -+ gen = lru_gen_from_seq(lrugen->min_seq[type]); -+ reset_ctrl_pos(lruvec, gen, type); - WRITE_ONCE(lrugen->min_seq[type], min_seq[type]); - success = true; - } -@@ -3820,6 +3931,9 @@ static void inc_max_seq(struct lruvec *l - } - } - -+ for (type = 0; type < ANON_AND_FILE; type++) -+ reset_ctrl_pos(lruvec, gen, type); -+ - WRITE_ONCE(lrugen->timestamps[gen], jiffies); - /* make sure all preceding modifications appear first */ - smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); -@@ -4101,6 +4215,433 @@ void lru_gen_look_around(struct page_vma - } - - /****************************************************************************** -+ * the eviction -+ ******************************************************************************/ -+ -+static bool sort_page(struct page *page, struct lruvec *lruvec, int tier_idx) -+{ -+ bool success; -+ int gen = page_lru_gen(page); -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ int tier = page_lru_tier(page); -+ int delta = thp_nr_pages(page); -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ VM_BUG_ON_PAGE(gen >= MAX_NR_GENS, page); -+ -+ /* an mlocked page? */ -+ if (!page_evictable(page)) { -+ success = lru_gen_del_page(page, lruvec, true); -+ VM_BUG_ON_PAGE(!success, page); -+ SetPageUnevictable(page); -+ add_page_to_lru_list(page, lruvec); -+ __count_vm_events(UNEVICTABLE_PGCULLED, delta); -+ return true; -+ } -+ -+ /* a lazy-free page that has been written into? */ -+ if (type && PageDirty(page) && PageAnon(page)) { -+ success = lru_gen_del_page(page, lruvec, true); -+ VM_BUG_ON_PAGE(!success, page); -+ SetPageSwapBacked(page); -+ add_page_to_lru_list_tail(page, lruvec); -+ return true; -+ } -+ -+ /* page_update_gen() has updated this page? */ -+ if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { -+ list_move(&page->lru, &lrugen->lists[gen][type][zone]); -+ return true; -+ } -+ -+ /* protect this page if its tier has a higher refaulted % */ -+ if (tier > tier_idx) { -+ int hist = lru_hist_from_seq(gen); -+ -+ page_inc_gen(page, lruvec, false); -+ WRITE_ONCE(lrugen->protected[hist][type][tier - 1], -+ lrugen->protected[hist][type][tier - 1] + delta); -+ __mod_lruvec_state(lruvec, WORKINGSET_ACTIVATE_BASE + type, delta); -+ return true; -+ } -+ -+ /* mark this page for reclaim if it's pending writeback */ -+ if (PageWriteback(page) || (type && PageDirty(page))) { -+ page_inc_gen(page, lruvec, true); -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool isolate_page(struct page *page, struct lruvec *lruvec, struct scan_control *sc) -+{ -+ bool success; -+ -+ if (!sc->may_unmap && page_mapped(page)) -+ return false; -+ -+ if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && -+ (PageDirty(page) || (PageAnon(page) && !PageSwapCache(page)))) -+ return false; -+ -+ if (!get_page_unless_zero(page)) -+ return false; -+ -+ if (!TestClearPageLRU(page)) { -+ put_page(page); -+ return false; -+ } -+ -+ success = lru_gen_del_page(page, lruvec, true); -+ VM_BUG_ON_PAGE(!success, page); -+ -+ return true; -+} -+ -+static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, -+ int type, int tier, struct list_head *list) -+{ -+ int gen, zone; -+ enum vm_event_item item; -+ int sorted = 0; -+ int scanned = 0; -+ int isolated = 0; -+ int remaining = MAX_BATCH_SIZE; -+ struct lrugen *lrugen = &lruvec->evictable; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ -+ VM_BUG_ON(!list_empty(list)); -+ -+ if (get_nr_gens(lruvec, type) == MIN_NR_GENS) -+ return 0; -+ -+ gen = lru_gen_from_seq(lrugen->min_seq[type]); -+ -+ for (zone = sc->reclaim_idx; zone >= 0; zone--) { -+ LIST_HEAD(moved); -+ int skipped = 0; -+ struct list_head *head = &lrugen->lists[gen][type][zone]; -+ -+ while (!list_empty(head)) { -+ struct page *page = lru_to_page(head); -+ int delta = thp_nr_pages(page); -+ -+ VM_BUG_ON_PAGE(PageTail(page), page); -+ VM_BUG_ON_PAGE(PageUnevictable(page), page); -+ VM_BUG_ON_PAGE(PageActive(page), page); -+ VM_BUG_ON_PAGE(page_is_file_lru(page) != type, page); -+ VM_BUG_ON_PAGE(page_zonenum(page) != zone, page); -+ -+ prefetchw_prev_lru_page(page, head, flags); -+ -+ scanned += delta; -+ -+ if (sort_page(page, lruvec, tier)) -+ sorted += delta; -+ else if (isolate_page(page, lruvec, sc)) { -+ list_add(&page->lru, list); -+ isolated += delta; -+ } else { -+ list_move(&page->lru, &moved); -+ skipped += delta; -+ } -+ -+ if (!--remaining || max(isolated, skipped) >= MIN_BATCH_SIZE) -+ break; -+ } -+ -+ if (skipped) { -+ list_splice(&moved, head); -+ __count_zid_vm_events(PGSCAN_SKIP, zone, skipped); -+ } -+ -+ if (!remaining || isolated >= MIN_BATCH_SIZE) -+ break; -+ } -+ -+ item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT; -+ if (!cgroup_reclaim(sc)) { -+ __count_vm_events(item, isolated); -+ __count_vm_events(PGREFILL, sorted); -+ } -+ __count_memcg_events(memcg, item, isolated); -+ __count_memcg_events(memcg, PGREFILL, sorted); -+ __count_vm_events(PGSCAN_ANON + type, isolated); -+ -+ /* -+ * We may have trouble finding eligible pages due to reclaim_idx, -+ * may_unmap and may_writepage. Check `remaining` to make sure we won't -+ * be stuck if we aren't making enough progress. -+ */ -+ return isolated || !remaining ? scanned : 0; -+} -+ -+static int get_tier_idx(struct lruvec *lruvec, int type) -+{ -+ int tier; -+ struct ctrl_pos sp, pv; -+ -+ /* -+ * Ideally we don't want to evict upper tiers that have higher refaulted -+ * %. However, we need to leave a margin for the fluctuation in -+ * refaulted %. So we use a larger gain factor to make sure upper tiers -+ * are indeed more active. We choose 2 because the lowest upper tier -+ * would have twice of refaulted % of the base tier, according to their -+ * numbers of accesses. -+ */ -+ read_ctrl_pos(lruvec, type, 0, 1, &sp); -+ for (tier = 1; tier < MAX_NR_TIERS; tier++) { -+ read_ctrl_pos(lruvec, type, tier, 2, &pv); -+ if (!positive_ctrl_err(&sp, &pv)) -+ break; -+ } -+ -+ return tier - 1; -+} -+ -+static int get_type_to_scan(struct lruvec *lruvec, int swappiness, int *tier_idx) -+{ -+ int type, tier; -+ struct ctrl_pos sp, pv; -+ int gain[ANON_AND_FILE] = { swappiness, 200 - swappiness }; -+ -+ /* -+ * Compare refaulted % between the base tiers of anon and file to -+ * determine which type to evict. Also need to compare refaulted % of -+ * the upper tiers of the selected type with that of the base tier of -+ * the other type to determine which tier of the selected type to evict. -+ */ -+ read_ctrl_pos(lruvec, 0, 0, gain[0], &sp); -+ read_ctrl_pos(lruvec, 1, 0, gain[1], &pv); -+ type = positive_ctrl_err(&sp, &pv); -+ -+ read_ctrl_pos(lruvec, !type, 0, gain[!type], &sp); -+ for (tier = 1; tier < MAX_NR_TIERS; tier++) { -+ read_ctrl_pos(lruvec, type, tier, gain[type], &pv); -+ if (!positive_ctrl_err(&sp, &pv)) -+ break; -+ } -+ -+ *tier_idx = tier - 1; -+ -+ return type; -+} -+ -+static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, -+ int *type_scanned, struct list_head *list) -+{ -+ int i; -+ int type; -+ int scanned; -+ int tier = -1; -+ DEFINE_MIN_SEQ(lruvec); -+ -+ VM_BUG_ON(!seq_is_valid(lruvec)); -+ -+ /* -+ * Try to select a type based on generations and swappiness, and if that -+ * fails, fall back to get_type_to_scan(). When anon and file are both -+ * available from the same generation, swappiness 200 is interpreted as -+ * anon first and swappiness 1 is interpreted as file first. -+ */ -+ if (!swappiness) -+ type = 1; -+ else if (min_seq[0] < min_seq[1]) -+ type = 0; -+ else if (swappiness == 1) -+ type = 1; -+ else if (swappiness == 200) -+ type = 0; -+ else -+ type = get_type_to_scan(lruvec, swappiness, &tier); -+ -+ for (i = !swappiness; i < ANON_AND_FILE; i++) { -+ if (tier < 0) -+ tier = get_tier_idx(lruvec, type); -+ -+ scanned = scan_pages(lruvec, sc, type, tier, list); -+ if (scanned) -+ break; -+ -+ type = !type; -+ tier = -1; -+ } -+ -+ *type_scanned = type; -+ -+ return scanned; -+} -+ -+/* Main function used by the foreground, the background and the user-triggered eviction. */ -+static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) -+{ -+ int type; -+ int scanned; -+ int reclaimed; -+ LIST_HEAD(list); -+ struct page *page; -+ enum vm_event_item item; -+ struct reclaim_stat stat; -+ struct mm_walk_args *args; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ struct pglist_data *pgdat = lruvec_pgdat(lruvec); -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ -+ scanned = isolate_pages(lruvec, sc, swappiness, &type, &list); -+ -+ if (try_to_inc_min_seq(lruvec, swappiness)) -+ scanned++; -+ -+ if (get_nr_gens(lruvec, 1) == MIN_NR_GENS) -+ scanned = 0; -+ -+ spin_unlock_irq(&lruvec->lru_lock); -+ -+ if (list_empty(&list)) -+ return scanned; -+ -+ reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); -+ /* -+ * We need to prevent rejected pages from being added back to the same -+ * lists they were isolated from. Otherwise we may risk looping on them -+ * forever. -+ */ -+ list_for_each_entry(page, &list, lru) { -+ if (!PageReclaim(page) || !(PageDirty(page) || PageWriteback(page))) -+ SetPageActive(page); -+ -+ ClearPageReferenced(page); -+ ClearPageWorkingset(page); -+ } -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ -+ move_pages_to_lru(lruvec, &list); -+ -+ args = current->reclaim_state ? current->reclaim_state->mm_walk_args : NULL; -+ if (args && args->batch_size) -+ reset_batch_size(lruvec, args); -+ -+ item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; -+ if (!cgroup_reclaim(sc)) -+ __count_vm_events(item, reclaimed); -+ __count_memcg_events(memcg, item, reclaimed); -+ __count_vm_events(PGSTEAL_ANON + type, reclaimed); -+ -+ spin_unlock_irq(&lruvec->lru_lock); -+ -+ mem_cgroup_uncharge_list(&list); -+ free_unref_page_list(&list); -+ -+ sc->nr_reclaimed += reclaimed; -+ -+ return scanned; -+} -+ -+static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, int swappiness) -+{ -+ bool low; -+ long nr_to_scan; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ int priority = sc->priority; -+ DEFINE_MAX_SEQ(lruvec); -+ DEFINE_MIN_SEQ(lruvec); -+ -+ if (mem_cgroup_below_min(memcg) || -+ (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) -+ return 0; -+ -+ if (sc->nr_reclaimed >= sc->nr_to_reclaim) { -+ priority = DEF_PRIORITY; -+ sc->force_deactivate = 0; -+ } -+ -+ nr_to_scan = get_nr_evictable(lruvec, sc, swappiness, max_seq, min_seq, &low); -+ if (!nr_to_scan) -+ return 0; -+ -+ nr_to_scan >>= priority; -+ -+ if (!mem_cgroup_online(memcg)) -+ nr_to_scan++; -+ -+ if (!nr_to_scan) -+ return 0; -+ -+ if (current_is_kswapd()) { -+ /* leave the work to lru_gen_age_node() */ -+ if (max_seq - min_seq[1] < MIN_NR_GENS) -+ return 0; -+ -+ if (!low) -+ sc->force_deactivate = 0; -+ -+ return nr_to_scan; -+ } -+ -+ if (max_seq - min_seq[1] >= MIN_NR_GENS) -+ return nr_to_scan; -+ -+ /* move onto slab and other memcgs if we haven't tried them all */ -+ if (!sc->force_deactivate) { -+ sc->skipped_deactivate = 1; -+ return 0; -+ } -+ -+ return try_to_inc_max_seq(lruvec, sc, swappiness, max_seq, true) ? nr_to_scan : 0; -+} -+ -+static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -+{ -+ struct blk_plug plug; -+ long scanned = 0; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ struct pglist_data *pgdat = lruvec_pgdat(lruvec); -+ -+ lru_add_drain(); -+ -+ if (current_is_kswapd()) -+ current->reclaim_state->mm_walk_args = &pgdat->mm_walk_args; -+ -+ blk_start_plug(&plug); -+ -+ while (true) { -+ int delta; -+ int swappiness; -+ long nr_to_scan; -+ -+ if (sc->may_swap) -+ swappiness = get_swappiness(memcg); -+ else if (!cgroup_reclaim(sc) && get_swappiness(memcg)) -+ swappiness = 1; -+ else -+ swappiness = 0; -+ -+ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); -+ if (!nr_to_scan) -+ break; -+ -+ delta = evict_pages(lruvec, sc, swappiness); -+ if (!delta) -+ break; -+ -+ scanned += delta; -+ if (scanned >= nr_to_scan) -+ break; -+ -+ cond_resched(); -+ } -+ -+ blk_finish_plug(&plug); -+ -+ if (current_is_kswapd()) -+ current->reclaim_state->mm_walk_args = NULL; -+} -+ -+/****************************************************************************** - * state change - ******************************************************************************/ - -@@ -4355,6 +4896,10 @@ static void lru_gen_age_node(struct pgli - { - } - -+static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -+{ -+} -+ - #endif /* CONFIG_LRU_GEN */ - - static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -@@ -4368,6 +4913,11 @@ static void shrink_lruvec(struct lruvec - bool proportional_reclaim; - struct blk_plug plug; - -+ if (lru_gen_enabled()) { -+ lru_gen_shrink_lruvec(lruvec, sc); -+ return; -+ } -+ - get_scan_count(lruvec, sc, nr); - - /* Record the original scan target for proportional adjustments later */ -@@ -4839,6 +5389,9 @@ static void snapshot_refaults(struct mem - struct lruvec *target_lruvec; - unsigned long refaults; - -+ if (lru_gen_enabled()) -+ return; -+ - target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat); - refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_ANON); - target_lruvec->refaults[0] = refaults; ---- a/mm/workingset.c -+++ b/mm/workingset.c -@@ -187,7 +187,6 @@ static unsigned int bucket_order __read_ - static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction, - bool workingset) - { -- eviction >>= bucket_order; - eviction &= EVICTION_MASK; - eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; - eviction = (eviction << NODES_SHIFT) | pgdat->node_id; -@@ -212,10 +211,117 @@ static void unpack_shadow(void *shadow, - - *memcgidp = memcgid; - *pgdat = NODE_DATA(nid); -- *evictionp = entry << bucket_order; -+ *evictionp = entry; - *workingsetp = workingset; - } - -+#ifdef CONFIG_LRU_GEN -+ -+static int page_lru_refs(struct page *page) -+{ -+ unsigned long flags = READ_ONCE(page->flags); -+ -+ BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_WIDTH > BITS_PER_LONG - EVICTION_SHIFT); -+ -+ /* see the comment on MAX_NR_TIERS */ -+ return flags & BIT(PG_workingset) ? (flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF : 0; -+} -+ -+/* Return a token to be stored in the shadow entry of a page being evicted. */ -+static void *lru_gen_eviction(struct page *page) -+{ -+ int hist, tier; -+ unsigned long token; -+ unsigned long min_seq; -+ struct lruvec *lruvec; -+ struct lrugen *lrugen; -+ int type = page_is_file_lru(page); -+ int refs = page_lru_refs(page); -+ int delta = thp_nr_pages(page); -+ bool workingset = PageWorkingset(page); -+ struct mem_cgroup *memcg = page_memcg(page); -+ struct pglist_data *pgdat = page_pgdat(page); -+ -+ lruvec = mem_cgroup_lruvec(memcg, pgdat); -+ lrugen = &lruvec->evictable; -+ min_seq = READ_ONCE(lrugen->min_seq[type]); -+ token = (min_seq << LRU_REFS_WIDTH) | refs; -+ -+ hist = lru_hist_from_seq(min_seq); -+ tier = lru_tier_from_refs(refs + workingset); -+ atomic_long_add(delta, &lrugen->evicted[hist][type][tier]); -+ -+ return pack_shadow(mem_cgroup_id(memcg), pgdat, token, workingset); -+} -+ -+/* Count a refaulted page based on the token stored in its shadow entry. */ -+static void lru_gen_refault(struct page *page, void *shadow) -+{ -+ int hist, tier, refs; -+ int memcg_id; -+ bool workingset; -+ unsigned long token; -+ unsigned long min_seq; -+ struct lruvec *lruvec; -+ struct lrugen *lrugen; -+ struct mem_cgroup *memcg; -+ struct pglist_data *pgdat; -+ int type = page_is_file_lru(page); -+ int delta = thp_nr_pages(page); -+ -+ unpack_shadow(shadow, &memcg_id, &pgdat, &token, &workingset); -+ if (page_pgdat(page) != pgdat) -+ return; -+ -+ rcu_read_lock(); -+ memcg = page_memcg_rcu(page); -+ if (mem_cgroup_id(memcg) != memcg_id) -+ goto unlock; -+ -+ refs = token & (BIT(LRU_REFS_WIDTH) - 1); -+ if (refs && !workingset) -+ goto unlock; -+ -+ token >>= LRU_REFS_WIDTH; -+ lruvec = mem_cgroup_lruvec(memcg, pgdat); -+ lrugen = &lruvec->evictable; -+ min_seq = READ_ONCE(lrugen->min_seq[type]); -+ if (token != (min_seq & (EVICTION_MASK >> LRU_REFS_WIDTH))) -+ goto unlock; -+ -+ hist = lru_hist_from_seq(min_seq); -+ tier = lru_tier_from_refs(refs + workingset); -+ atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]); -+ mod_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + type, delta); -+ -+ /* -+ * Tiers don't offer any protection to pages accessed via page tables. -+ * That's what generations do. Tiers can't fully protect pages after -+ * their numbers of accesses has exceeded the max value. Conservatively -+ * count these two conditions as stalls even though they might not -+ * indicate any real memory pressure. -+ */ -+ if (task_in_nonseq_fault() || refs + workingset == BIT(LRU_REFS_WIDTH)) { -+ SetPageWorkingset(page); -+ mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + type, delta); -+ } -+unlock: -+ rcu_read_unlock(); -+} -+ -+#else -+ -+static void *lru_gen_eviction(struct page *page) -+{ -+ return NULL; -+} -+ -+static void lru_gen_refault(struct page *page, void *shadow) -+{ -+} -+ -+#endif /* CONFIG_LRU_GEN */ -+ - /** - * workingset_age_nonresident - age non-resident entries as LRU ages - * @lruvec: the lruvec that was aged -@@ -264,10 +370,14 @@ void *workingset_eviction(struct page *p - VM_BUG_ON_PAGE(page_count(page), page); - VM_BUG_ON_PAGE(!PageLocked(page), page); - -+ if (lru_gen_enabled()) -+ return lru_gen_eviction(page); -+ - lruvec = mem_cgroup_lruvec(target_memcg, pgdat); - /* XXX: target_memcg can be NULL, go through lruvec */ - memcgid = mem_cgroup_id(lruvec_memcg(lruvec)); - eviction = atomic_long_read(&lruvec->nonresident_age); -+ eviction >>= bucket_order; - workingset_age_nonresident(lruvec, thp_nr_pages(page)); - return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); - } -@@ -296,7 +406,13 @@ void workingset_refault(struct page *pag - bool workingset; - int memcgid; - -+ if (lru_gen_enabled()) { -+ lru_gen_refault(page, shadow); -+ return; -+ } -+ - unpack_shadow(shadow, &memcgid, &pgdat, &eviction, &workingset); -+ eviction <<= bucket_order; - - rcu_read_lock(); - /* diff --git a/target/linux/generic/backport-5.15/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch b/target/linux/generic/backport-5.15/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch new file mode 100644 index 00000000000..64de2c0c828 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch @@ -0,0 +1,1710 @@ +From 05223c4e80b34e29f2255c04ffebc2c4475e7593 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:05 -0600 +Subject: [PATCH 08/29] mm: multi-gen LRU: support page table walks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To further exploit spatial locality, the aging prefers to walk page tables +to search for young PTEs and promote hot pages. A kill switch will be +added in the next patch to disable this behavior. When disabled, the +aging relies on the rmap only. + +NB: this behavior has nothing similar with the page table scanning in the +2.4 kernel [1], which searches page tables for old PTEs, adds cold pages +to swapcache and unmaps them. + +To avoid confusion, the term "iteration" specifically means the traversal +of an entire mm_struct list; the term "walk" will be applied to page +tables and the rmap, as usual. + +An mm_struct list is maintained for each memcg, and an mm_struct follows +its owner task to the new memcg when this task is migrated. Given an +lruvec, the aging iterates lruvec_memcg()->mm_list and calls +walk_page_range() with each mm_struct on this list to promote hot pages +before it increments max_seq. + +When multiple page table walkers iterate the same list, each of them gets +a unique mm_struct; therefore they can run concurrently. Page table +walkers ignore any misplaced pages, e.g., if an mm_struct was migrated, +pages it left in the previous memcg will not be promoted when its current +memcg is under reclaim. Similarly, page table walkers will not promote +pages from nodes other than the one under reclaim. + +This patch uses the following optimizations when walking page tables: +1. It tracks the usage of mm_struct's between context switches so that + page table walkers can skip processes that have been sleeping since + the last iteration. +2. It uses generational Bloom filters to record populated branches so + that page table walkers can reduce their search space based on the + query results, e.g., to skip page tables containing mostly holes or + misplaced pages. +3. It takes advantage of the accessed bit in non-leaf PMD entries when + CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y. +4. It does not zigzag between a PGD table and the same PMD table + spanning multiple VMAs. IOW, it finishes all the VMAs within the + range of the same PMD table before it returns to a PGD table. This + improves the cache performance for workloads that have large + numbers of tiny VMAs [2], especially when CONFIG_PGTABLE_LEVELS=5. + +Server benchmark results: + Single workload: + fio (buffered I/O): no change + + Single workload: + memcached (anon): +[8, 10]% + Ops/sec KB/sec + patch1-7: 1147696.57 44640.29 + patch1-8: 1245274.91 48435.66 + + Configurations: + no change + +Client benchmark results: + kswapd profiles: + patch1-7 + 48.16% lzo1x_1_do_compress (real work) + 8.20% page_vma_mapped_walk (overhead) + 7.06% _raw_spin_unlock_irq + 2.92% ptep_clear_flush + 2.53% __zram_bvec_write + 2.11% do_raw_spin_lock + 2.02% memmove + 1.93% lru_gen_look_around + 1.56% free_unref_page_list + 1.40% memset + + patch1-8 + 49.44% lzo1x_1_do_compress (real work) + 6.19% page_vma_mapped_walk (overhead) + 5.97% _raw_spin_unlock_irq + 3.13% get_pfn_page + 2.85% ptep_clear_flush + 2.42% __zram_bvec_write + 2.08% do_raw_spin_lock + 1.92% memmove + 1.44% alloc_zspage + 1.36% memset + + Configurations: + no change + +Thanks to the following developers for their efforts [3]. + kernel test robot + +[1] https://lwn.net/Articles/23732/ +[2] https://llvm.org/docs/ScudoHardenedAllocator.html +[3] https://lore.kernel.org/r/202204160827.ekEARWQo-lkp@intel.com/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-9-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + fs/exec.c | 2 + + include/linux/memcontrol.h | 5 + + include/linux/mm_types.h | 76 +++ + include/linux/mmzone.h | 56 +- + include/linux/swap.h | 4 + + kernel/exit.c | 1 + + kernel/fork.c | 9 + + kernel/sched/core.c | 1 + + mm/memcontrol.c | 25 + + mm/vmscan.c | 1010 +++++++++++++++++++++++++++++++++++- + 10 files changed, 1172 insertions(+), 17 deletions(-) + +diff --git a/fs/exec.c b/fs/exec.c +index 881390b44cfd..1afa15a07d26 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1013,6 +1013,7 @@ static int exec_mmap(struct mm_struct *mm) + active_mm = tsk->active_mm; + tsk->active_mm = mm; + tsk->mm = mm; ++ lru_gen_add_mm(mm); + /* + * This prevents preemption while active_mm is being loaded and + * it and mm are being updated, which could cause problems for +@@ -1028,6 +1029,7 @@ static int exec_mmap(struct mm_struct *mm) + tsk->mm->vmacache_seqnum = 0; + vmacache_flush(tsk); + task_unlock(tsk); ++ lru_gen_use_mm(mm); + if (old_mm) { + mmap_read_unlock(old_mm); + BUG_ON(active_mm != old_mm); +diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h +index 8d6a0329bc59..3736405cbcf6 100644 +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -348,6 +348,11 @@ struct mem_cgroup { + struct deferred_split deferred_split_queue; + #endif + ++#ifdef CONFIG_LRU_GEN ++ /* per-memcg mm_struct list */ ++ struct lru_gen_mm_list mm_list; ++#endif ++ + struct mem_cgroup_per_node *nodeinfo[]; + }; + +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 7f8ee09c711f..33c142d31261 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -580,6 +580,22 @@ struct mm_struct { + #ifdef CONFIG_IOMMU_SUPPORT + u32 pasid; + #endif ++#ifdef CONFIG_LRU_GEN ++ struct { ++ /* this mm_struct is on lru_gen_mm_list */ ++ struct list_head list; ++ /* ++ * Set when switching to this mm_struct, as a hint of ++ * whether it has been used since the last time per-node ++ * page table walkers cleared the corresponding bits. ++ */ ++ unsigned long bitmap; ++#ifdef CONFIG_MEMCG ++ /* points to the memcg of "owner" above */ ++ struct mem_cgroup *memcg; ++#endif ++ } lru_gen; ++#endif /* CONFIG_LRU_GEN */ + } __randomize_layout; + + /* +@@ -606,6 +622,66 @@ static inline cpumask_t *mm_cpumask(struct mm_struct *mm) + return (struct cpumask *)&mm->cpu_bitmap; + } + ++#ifdef CONFIG_LRU_GEN ++ ++struct lru_gen_mm_list { ++ /* mm_struct list for page table walkers */ ++ struct list_head fifo; ++ /* protects the list above */ ++ spinlock_t lock; ++}; ++ ++void lru_gen_add_mm(struct mm_struct *mm); ++void lru_gen_del_mm(struct mm_struct *mm); ++#ifdef CONFIG_MEMCG ++void lru_gen_migrate_mm(struct mm_struct *mm); ++#endif ++ ++static inline void lru_gen_init_mm(struct mm_struct *mm) ++{ ++ INIT_LIST_HEAD(&mm->lru_gen.list); ++ mm->lru_gen.bitmap = 0; ++#ifdef CONFIG_MEMCG ++ mm->lru_gen.memcg = NULL; ++#endif ++} ++ ++static inline void lru_gen_use_mm(struct mm_struct *mm) ++{ ++ /* ++ * When the bitmap is set, page reclaim knows this mm_struct has been ++ * used since the last time it cleared the bitmap. So it might be worth ++ * walking the page tables of this mm_struct to clear the accessed bit. ++ */ ++ WRITE_ONCE(mm->lru_gen.bitmap, -1); ++} ++ ++#else /* !CONFIG_LRU_GEN */ ++ ++static inline void lru_gen_add_mm(struct mm_struct *mm) ++{ ++} ++ ++static inline void lru_gen_del_mm(struct mm_struct *mm) ++{ ++} ++ ++#ifdef CONFIG_MEMCG ++static inline void lru_gen_migrate_mm(struct mm_struct *mm) ++{ ++} ++#endif ++ ++static inline void lru_gen_init_mm(struct mm_struct *mm) ++{ ++} ++ ++static inline void lru_gen_use_mm(struct mm_struct *mm) ++{ ++} ++ ++#endif /* CONFIG_LRU_GEN */ ++ + struct mmu_gather; + extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm); + extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm); +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 4db2b877fcf9..659bab633bdf 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -385,7 +385,7 @@ enum { + * min_seq behind. + * + * The number of pages in each generation is eventually consistent and therefore +- * can be transiently negative. ++ * can be transiently negative when reset_batch_size() is pending. + */ + struct lru_gen_struct { + /* the aging increments the youngest generation number */ +@@ -407,6 +407,53 @@ struct lru_gen_struct { + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + }; + ++enum { ++ MM_LEAF_TOTAL, /* total leaf entries */ ++ MM_LEAF_OLD, /* old leaf entries */ ++ MM_LEAF_YOUNG, /* young leaf entries */ ++ MM_NONLEAF_TOTAL, /* total non-leaf entries */ ++ MM_NONLEAF_FOUND, /* non-leaf entries found in Bloom filters */ ++ MM_NONLEAF_ADDED, /* non-leaf entries added to Bloom filters */ ++ NR_MM_STATS ++}; ++ ++/* double-buffering Bloom filters */ ++#define NR_BLOOM_FILTERS 2 ++ ++struct lru_gen_mm_state { ++ /* set to max_seq after each iteration */ ++ unsigned long seq; ++ /* where the current iteration continues (inclusive) */ ++ struct list_head *head; ++ /* where the last iteration ended (exclusive) */ ++ struct list_head *tail; ++ /* to wait for the last page table walker to finish */ ++ struct wait_queue_head wait; ++ /* Bloom filters flip after each iteration */ ++ unsigned long *filters[NR_BLOOM_FILTERS]; ++ /* the mm stats for debugging */ ++ unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; ++ /* the number of concurrent page table walkers */ ++ int nr_walkers; ++}; ++ ++struct lru_gen_mm_walk { ++ /* the lruvec under reclaim */ ++ struct lruvec *lruvec; ++ /* unstable max_seq from lru_gen_struct */ ++ unsigned long max_seq; ++ /* the next address within an mm to scan */ ++ unsigned long next_addr; ++ /* to batch promoted pages */ ++ int nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ /* to batch the mm stats */ ++ int mm_stats[NR_MM_STATS]; ++ /* total batched items */ ++ int batched; ++ bool can_swap; ++ bool force_scan; ++}; ++ + void lru_gen_init_lruvec(struct lruvec *lruvec); + void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + +@@ -457,6 +504,8 @@ struct lruvec { + #ifdef CONFIG_LRU_GEN + /* evictable pages divided into generations */ + struct lru_gen_struct lrugen; ++ /* to concurrently iterate lru_gen_mm_list */ ++ struct lru_gen_mm_state mm_state; + #endif + #ifdef CONFIG_MEMCG + struct pglist_data *pgdat; +@@ -1042,6 +1091,11 @@ typedef struct pglist_data { + + unsigned long flags; + ++#ifdef CONFIG_LRU_GEN ++ /* kswap mm walk data */ ++ struct lru_gen_mm_walk mm_walk; ++#endif ++ + ZONE_PADDING(_pad2_) + + /* Per-node vmstats */ +diff --git a/include/linux/swap.h b/include/linux/swap.h +index 4efd267e2937..e970fca4f178 100644 +--- a/include/linux/swap.h ++++ b/include/linux/swap.h +@@ -137,6 +137,10 @@ union swap_header { + */ + struct reclaim_state { + unsigned long reclaimed_slab; ++#ifdef CONFIG_LRU_GEN ++ /* per-thread mm walk data */ ++ struct lru_gen_mm_walk *mm_walk; ++#endif + }; + + #ifdef __KERNEL__ +diff --git a/kernel/exit.c b/kernel/exit.c +index 80efdfda6662..06b477395012 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -469,6 +469,7 @@ void mm_update_next_owner(struct mm_struct *mm) + goto retry; + } + WRITE_ONCE(mm->owner, c); ++ lru_gen_migrate_mm(mm); + task_unlock(c); + put_task_struct(c); + } +diff --git a/kernel/fork.c b/kernel/fork.c +index 68eab6ce3085..d8f37ecdde87 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -1083,6 +1083,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, + goto fail_nocontext; + + mm->user_ns = get_user_ns(user_ns); ++ lru_gen_init_mm(mm); + return mm; + + fail_nocontext: +@@ -1125,6 +1126,7 @@ static inline void __mmput(struct mm_struct *mm) + } + if (mm->binfmt) + module_put(mm->binfmt->module); ++ lru_gen_del_mm(mm); + mmdrop(mm); + } + +@@ -2622,6 +2624,13 @@ pid_t kernel_clone(struct kernel_clone_args *args) + get_task_struct(p); + } + ++ if (IS_ENABLED(CONFIG_LRU_GEN) && !(clone_flags & CLONE_VM)) { ++ /* lock the task to synchronize with memcg migration */ ++ task_lock(p); ++ lru_gen_add_mm(p->mm); ++ task_unlock(p); ++ } ++ + wake_up_new_task(p); + + /* forking complete and child started to run, tell ptracer */ +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index c1458fa8beb3..fe4d60474d4a 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -5007,6 +5007,7 @@ context_switch(struct rq *rq, struct task_struct *prev, + * finish_task_switch()'s mmdrop(). + */ + switch_mm_irqs_off(prev->active_mm, next->mm, next); ++ lru_gen_use_mm(next->mm); + + if (!prev->mm) { // from kernel + /* will mmdrop() in finish_task_switch(). */ +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index cc3431c5d9ba..ed87d1256f0e 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -6212,6 +6212,30 @@ static void mem_cgroup_move_task(void) + } + #endif + ++#ifdef CONFIG_LRU_GEN ++static void mem_cgroup_attach(struct cgroup_taskset *tset) ++{ ++ struct task_struct *task; ++ struct cgroup_subsys_state *css; ++ ++ /* find the first leader if there is any */ ++ cgroup_taskset_for_each_leader(task, css, tset) ++ break; ++ ++ if (!task) ++ return; ++ ++ task_lock(task); ++ if (task->mm && READ_ONCE(task->mm->owner) == task) ++ lru_gen_migrate_mm(task->mm); ++ task_unlock(task); ++} ++#else ++static void mem_cgroup_attach(struct cgroup_taskset *tset) ++{ ++} ++#endif /* CONFIG_LRU_GEN */ ++ + static int seq_puts_memcg_tunable(struct seq_file *m, unsigned long value) + { + if (value == PAGE_COUNTER_MAX) +@@ -6555,6 +6579,7 @@ struct cgroup_subsys memory_cgrp_subsys = { + .css_reset = mem_cgroup_css_reset, + .css_rstat_flush = mem_cgroup_css_rstat_flush, + .can_attach = mem_cgroup_can_attach, ++ .attach = mem_cgroup_attach, + .cancel_attach = mem_cgroup_cancel_attach, + .post_attach = mem_cgroup_move_task, + .dfl_cftypes = memory_files, +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 1d0b25ae378c..a7844c689522 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -50,6 +50,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -2853,7 +2855,7 @@ static bool can_age_anon_pages(struct pglist_data *pgdat, + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ + for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) + +-static struct lruvec __maybe_unused *get_lruvec(struct mem_cgroup *memcg, int nid) ++static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) + { + struct pglist_data *pgdat = NODE_DATA(nid); + +@@ -2898,6 +2900,371 @@ static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) + get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; + } + ++/****************************************************************************** ++ * mm_struct list ++ ******************************************************************************/ ++ ++static struct lru_gen_mm_list *get_mm_list(struct mem_cgroup *memcg) ++{ ++ static struct lru_gen_mm_list mm_list = { ++ .fifo = LIST_HEAD_INIT(mm_list.fifo), ++ .lock = __SPIN_LOCK_UNLOCKED(mm_list.lock), ++ }; ++ ++#ifdef CONFIG_MEMCG ++ if (memcg) ++ return &memcg->mm_list; ++#endif ++ VM_WARN_ON_ONCE(!mem_cgroup_disabled()); ++ ++ return &mm_list; ++} ++ ++void lru_gen_add_mm(struct mm_struct *mm) ++{ ++ int nid; ++ struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm); ++ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); ++ ++ VM_WARN_ON_ONCE(!list_empty(&mm->lru_gen.list)); ++#ifdef CONFIG_MEMCG ++ VM_WARN_ON_ONCE(mm->lru_gen.memcg); ++ mm->lru_gen.memcg = memcg; ++#endif ++ spin_lock(&mm_list->lock); ++ ++ for_each_node_state(nid, N_MEMORY) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ if (!lruvec) ++ continue; ++ ++ /* the first addition since the last iteration */ ++ if (lruvec->mm_state.tail == &mm_list->fifo) ++ lruvec->mm_state.tail = &mm->lru_gen.list; ++ } ++ ++ list_add_tail(&mm->lru_gen.list, &mm_list->fifo); ++ ++ spin_unlock(&mm_list->lock); ++} ++ ++void lru_gen_del_mm(struct mm_struct *mm) ++{ ++ int nid; ++ struct lru_gen_mm_list *mm_list; ++ struct mem_cgroup *memcg = NULL; ++ ++ if (list_empty(&mm->lru_gen.list)) ++ return; ++ ++#ifdef CONFIG_MEMCG ++ memcg = mm->lru_gen.memcg; ++#endif ++ mm_list = get_mm_list(memcg); ++ ++ spin_lock(&mm_list->lock); ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ if (!lruvec) ++ continue; ++ ++ /* where the last iteration ended (exclusive) */ ++ if (lruvec->mm_state.tail == &mm->lru_gen.list) ++ lruvec->mm_state.tail = lruvec->mm_state.tail->next; ++ ++ /* where the current iteration continues (inclusive) */ ++ if (lruvec->mm_state.head != &mm->lru_gen.list) ++ continue; ++ ++ lruvec->mm_state.head = lruvec->mm_state.head->next; ++ /* the deletion ends the current iteration */ ++ if (lruvec->mm_state.head == &mm_list->fifo) ++ WRITE_ONCE(lruvec->mm_state.seq, lruvec->mm_state.seq + 1); ++ } ++ ++ list_del_init(&mm->lru_gen.list); ++ ++ spin_unlock(&mm_list->lock); ++ ++#ifdef CONFIG_MEMCG ++ mem_cgroup_put(mm->lru_gen.memcg); ++ mm->lru_gen.memcg = NULL; ++#endif ++} ++ ++#ifdef CONFIG_MEMCG ++void lru_gen_migrate_mm(struct mm_struct *mm) ++{ ++ struct mem_cgroup *memcg; ++ struct task_struct *task = rcu_dereference_protected(mm->owner, true); ++ ++ VM_WARN_ON_ONCE(task->mm != mm); ++ lockdep_assert_held(&task->alloc_lock); ++ ++ /* for mm_update_next_owner() */ ++ if (mem_cgroup_disabled()) ++ return; ++ ++ rcu_read_lock(); ++ memcg = mem_cgroup_from_task(task); ++ rcu_read_unlock(); ++ if (memcg == mm->lru_gen.memcg) ++ return; ++ ++ VM_WARN_ON_ONCE(!mm->lru_gen.memcg); ++ VM_WARN_ON_ONCE(list_empty(&mm->lru_gen.list)); ++ ++ lru_gen_del_mm(mm); ++ lru_gen_add_mm(mm); ++} ++#endif ++ ++/* ++ * Bloom filters with m=1<<15, k=2 and the false positive rates of ~1/5 when ++ * n=10,000 and ~1/2 when n=20,000, where, conventionally, m is the number of ++ * bits in a bitmap, k is the number of hash functions and n is the number of ++ * inserted items. ++ * ++ * Page table walkers use one of the two filters to reduce their search space. ++ * To get rid of non-leaf entries that no longer have enough leaf entries, the ++ * aging uses the double-buffering technique to flip to the other filter each ++ * time it produces a new generation. For non-leaf entries that have enough ++ * leaf entries, the aging carries them over to the next generation in ++ * walk_pmd_range(); the eviction also report them when walking the rmap ++ * in lru_gen_look_around(). ++ * ++ * For future optimizations: ++ * 1. It's not necessary to keep both filters all the time. The spare one can be ++ * freed after the RCU grace period and reallocated if needed again. ++ * 2. And when reallocating, it's worth scaling its size according to the number ++ * of inserted entries in the other filter, to reduce the memory overhead on ++ * small systems and false positives on large systems. ++ * 3. Jenkins' hash function is an alternative to Knuth's. ++ */ ++#define BLOOM_FILTER_SHIFT 15 ++ ++static inline int filter_gen_from_seq(unsigned long seq) ++{ ++ return seq % NR_BLOOM_FILTERS; ++} ++ ++static void get_item_key(void *item, int *key) ++{ ++ u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); ++ ++ BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); ++ ++ key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); ++ key[1] = hash >> BLOOM_FILTER_SHIFT; ++} ++ ++static void reset_bloom_filter(struct lruvec *lruvec, unsigned long seq) ++{ ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = lruvec->mm_state.filters[gen]; ++ if (filter) { ++ bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); ++ return; ++ } ++ ++ filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), ++ __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); ++ WRITE_ONCE(lruvec->mm_state.filters[gen], filter); ++} ++ ++static void update_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) ++{ ++ int key[2]; ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = READ_ONCE(lruvec->mm_state.filters[gen]); ++ if (!filter) ++ return; ++ ++ get_item_key(item, key); ++ ++ if (!test_bit(key[0], filter)) ++ set_bit(key[0], filter); ++ if (!test_bit(key[1], filter)) ++ set_bit(key[1], filter); ++} ++ ++static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) ++{ ++ int key[2]; ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = READ_ONCE(lruvec->mm_state.filters[gen]); ++ if (!filter) ++ return true; ++ ++ get_item_key(item, key); ++ ++ return test_bit(key[0], filter) && test_bit(key[1], filter); ++} ++ ++static void reset_mm_stats(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, bool last) ++{ ++ int i; ++ int hist; ++ ++ lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); ++ ++ if (walk) { ++ hist = lru_hist_from_seq(walk->max_seq); ++ ++ for (i = 0; i < NR_MM_STATS; i++) { ++ WRITE_ONCE(lruvec->mm_state.stats[hist][i], ++ lruvec->mm_state.stats[hist][i] + walk->mm_stats[i]); ++ walk->mm_stats[i] = 0; ++ } ++ } ++ ++ if (NR_HIST_GENS > 1 && last) { ++ hist = lru_hist_from_seq(lruvec->mm_state.seq + 1); ++ ++ for (i = 0; i < NR_MM_STATS; i++) ++ WRITE_ONCE(lruvec->mm_state.stats[hist][i], 0); ++ } ++} ++ ++static bool should_skip_mm(struct mm_struct *mm, struct lru_gen_mm_walk *walk) ++{ ++ int type; ++ unsigned long size = 0; ++ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); ++ int key = pgdat->node_id % BITS_PER_TYPE(mm->lru_gen.bitmap); ++ ++ if (!walk->force_scan && !test_bit(key, &mm->lru_gen.bitmap)) ++ return true; ++ ++ clear_bit(key, &mm->lru_gen.bitmap); ++ ++ for (type = !walk->can_swap; type < ANON_AND_FILE; type++) { ++ size += type ? get_mm_counter(mm, MM_FILEPAGES) : ++ get_mm_counter(mm, MM_ANONPAGES) + ++ get_mm_counter(mm, MM_SHMEMPAGES); ++ } ++ ++ if (size < MIN_LRU_BATCH) ++ return true; ++ ++ return !mmget_not_zero(mm); ++} ++ ++static bool iterate_mm_list(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, ++ struct mm_struct **iter) ++{ ++ bool first = false; ++ bool last = true; ++ struct mm_struct *mm = NULL; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); ++ struct lru_gen_mm_state *mm_state = &lruvec->mm_state; ++ ++ /* ++ * There are four interesting cases for this page table walker: ++ * 1. It tries to start a new iteration of mm_list with a stale max_seq; ++ * there is nothing left to do. ++ * 2. It's the first of the current generation, and it needs to reset ++ * the Bloom filter for the next generation. ++ * 3. It reaches the end of mm_list, and it needs to increment ++ * mm_state->seq; the iteration is done. ++ * 4. It's the last of the current generation, and it needs to reset the ++ * mm stats counters for the next generation. ++ */ ++ spin_lock(&mm_list->lock); ++ ++ VM_WARN_ON_ONCE(mm_state->seq + 1 < walk->max_seq); ++ VM_WARN_ON_ONCE(*iter && mm_state->seq > walk->max_seq); ++ VM_WARN_ON_ONCE(*iter && !mm_state->nr_walkers); ++ ++ if (walk->max_seq <= mm_state->seq) { ++ if (!*iter) ++ last = false; ++ goto done; ++ } ++ ++ if (!mm_state->nr_walkers) { ++ VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); ++ ++ mm_state->head = mm_list->fifo.next; ++ first = true; ++ } ++ ++ while (!mm && mm_state->head != &mm_list->fifo) { ++ mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); ++ ++ mm_state->head = mm_state->head->next; ++ ++ /* force scan for those added after the last iteration */ ++ if (!mm_state->tail || mm_state->tail == &mm->lru_gen.list) { ++ mm_state->tail = mm_state->head; ++ walk->force_scan = true; ++ } ++ ++ if (should_skip_mm(mm, walk)) ++ mm = NULL; ++ } ++ ++ if (mm_state->head == &mm_list->fifo) ++ WRITE_ONCE(mm_state->seq, mm_state->seq + 1); ++done: ++ if (*iter && !mm) ++ mm_state->nr_walkers--; ++ if (!*iter && mm) ++ mm_state->nr_walkers++; ++ ++ if (mm_state->nr_walkers) ++ last = false; ++ ++ if (*iter || last) ++ reset_mm_stats(lruvec, walk, last); ++ ++ spin_unlock(&mm_list->lock); ++ ++ if (mm && first) ++ reset_bloom_filter(lruvec, walk->max_seq + 1); ++ ++ if (*iter) ++ mmput_async(*iter); ++ ++ *iter = mm; ++ ++ return last; ++} ++ ++static bool iterate_mm_list_nowalk(struct lruvec *lruvec, unsigned long max_seq) ++{ ++ bool success = false; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); ++ struct lru_gen_mm_state *mm_state = &lruvec->mm_state; ++ ++ spin_lock(&mm_list->lock); ++ ++ VM_WARN_ON_ONCE(mm_state->seq + 1 < max_seq); ++ ++ if (max_seq > mm_state->seq && !mm_state->nr_walkers) { ++ VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); ++ ++ WRITE_ONCE(mm_state->seq, mm_state->seq + 1); ++ reset_mm_stats(lruvec, NULL, true); ++ success = true; ++ } ++ ++ spin_unlock(&mm_list->lock); ++ ++ return success; ++} ++ + /****************************************************************************** + * refault feedback loop + ******************************************************************************/ +@@ -3048,6 +3415,118 @@ static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaimin + return new_gen; + } + ++static void update_batch_size(struct lru_gen_mm_walk *walk, struct page *page, ++ int old_gen, int new_gen) ++{ ++ int type = page_is_file_lru(page); ++ int zone = page_zonenum(page); ++ int delta = thp_nr_pages(page); ++ ++ VM_WARN_ON_ONCE(old_gen >= MAX_NR_GENS); ++ VM_WARN_ON_ONCE(new_gen >= MAX_NR_GENS); ++ ++ walk->batched++; ++ ++ walk->nr_pages[old_gen][type][zone] -= delta; ++ walk->nr_pages[new_gen][type][zone] += delta; ++} ++ ++static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) ++{ ++ int gen, type, zone; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ walk->batched = 0; ++ ++ for_each_gen_type_zone(gen, type, zone) { ++ enum lru_list lru = type * LRU_INACTIVE_FILE; ++ int delta = walk->nr_pages[gen][type][zone]; ++ ++ if (!delta) ++ continue; ++ ++ walk->nr_pages[gen][type][zone] = 0; ++ WRITE_ONCE(lrugen->nr_pages[gen][type][zone], ++ lrugen->nr_pages[gen][type][zone] + delta); ++ ++ if (lru_gen_is_active(lruvec, gen)) ++ lru += LRU_ACTIVE; ++ __update_lru_size(lruvec, lru, zone, delta); ++ } ++} ++ ++static int should_skip_vma(unsigned long start, unsigned long end, struct mm_walk *args) ++{ ++ struct address_space *mapping; ++ struct vm_area_struct *vma = args->vma; ++ struct lru_gen_mm_walk *walk = args->private; ++ ++ if (!vma_is_accessible(vma)) ++ return true; ++ ++ if (is_vm_hugetlb_page(vma)) ++ return true; ++ ++ if (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ | VM_RAND_READ)) ++ return true; ++ ++ if (vma == get_gate_vma(vma->vm_mm)) ++ return true; ++ ++ if (vma_is_anonymous(vma)) ++ return !walk->can_swap; ++ ++ if (WARN_ON_ONCE(!vma->vm_file || !vma->vm_file->f_mapping)) ++ return true; ++ ++ mapping = vma->vm_file->f_mapping; ++ if (mapping_unevictable(mapping)) ++ return true; ++ ++ if (shmem_mapping(mapping)) ++ return !walk->can_swap; ++ ++ /* to exclude special mappings like dax, etc. */ ++ return !mapping->a_ops->readpage; ++} ++ ++/* ++ * Some userspace memory allocators map many single-page VMAs. Instead of ++ * returning back to the PGD table for each of such VMAs, finish an entire PMD ++ * table to reduce zigzags and improve cache performance. ++ */ ++static bool get_next_vma(unsigned long mask, unsigned long size, struct mm_walk *args, ++ unsigned long *vm_start, unsigned long *vm_end) ++{ ++ unsigned long start = round_up(*vm_end, size); ++ unsigned long end = (start | ~mask) + 1; ++ ++ VM_WARN_ON_ONCE(mask & size); ++ VM_WARN_ON_ONCE((start & mask) != (*vm_start & mask)); ++ ++ while (args->vma) { ++ if (start >= args->vma->vm_end) { ++ args->vma = args->vma->vm_next; ++ continue; ++ } ++ ++ if (end && end <= args->vma->vm_start) ++ return false; ++ ++ if (should_skip_vma(args->vma->vm_start, args->vma->vm_end, args)) { ++ args->vma = args->vma->vm_next; ++ continue; ++ } ++ ++ *vm_start = max(start, args->vma->vm_start); ++ *vm_end = min(end - 1, args->vma->vm_end - 1) + 1; ++ ++ return true; ++ } ++ ++ return false; ++} ++ + static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr) + { + unsigned long pfn = pte_pfn(pte); +@@ -3066,8 +3545,28 @@ static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned + return pfn; + } + ++#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) ++static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned long addr) ++{ ++ unsigned long pfn = pmd_pfn(pmd); ++ ++ VM_WARN_ON_ONCE(addr < vma->vm_start || addr >= vma->vm_end); ++ ++ if (!pmd_present(pmd) || is_huge_zero_pmd(pmd)) ++ return -1; ++ ++ if (WARN_ON_ONCE(pmd_devmap(pmd))) ++ return -1; ++ ++ if (WARN_ON_ONCE(!pfn_valid(pfn))) ++ return -1; ++ ++ return pfn; ++} ++#endif ++ + static struct page *get_pfn_page(unsigned long pfn, struct mem_cgroup *memcg, +- struct pglist_data *pgdat) ++ struct pglist_data *pgdat, bool can_swap) + { + struct page *page; + +@@ -3082,9 +3581,375 @@ static struct page *get_pfn_page(unsigned long pfn, struct mem_cgroup *memcg, + if (page_memcg_rcu(page) != memcg) + return NULL; + ++ /* file VMAs can contain anon pages from COW */ ++ if (!page_is_file_lru(page) && !can_swap) ++ return NULL; ++ + return page; + } + ++static bool suitable_to_scan(int total, int young) ++{ ++ int n = clamp_t(int, cache_line_size() / sizeof(pte_t), 2, 8); ++ ++ /* suitable if the average number of young PTEs per cacheline is >=1 */ ++ return young * n >= total; ++} ++ ++static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, ++ struct mm_walk *args) ++{ ++ int i; ++ pte_t *pte; ++ spinlock_t *ptl; ++ unsigned long addr; ++ int total = 0; ++ int young = 0; ++ struct lru_gen_mm_walk *walk = args->private; ++ struct mem_cgroup *memcg = lruvec_memcg(walk->lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); ++ int old_gen, new_gen = lru_gen_from_seq(walk->max_seq); ++ ++ VM_WARN_ON_ONCE(pmd_leaf(*pmd)); ++ ++ ptl = pte_lockptr(args->mm, pmd); ++ if (!spin_trylock(ptl)) ++ return false; ++ ++ arch_enter_lazy_mmu_mode(); ++ ++ pte = pte_offset_map(pmd, start & PMD_MASK); ++restart: ++ for (i = pte_index(start), addr = start; addr != end; i++, addr += PAGE_SIZE) { ++ unsigned long pfn; ++ struct page *page; ++ ++ total++; ++ walk->mm_stats[MM_LEAF_TOTAL]++; ++ ++ pfn = get_pte_pfn(pte[i], args->vma, addr); ++ if (pfn == -1) ++ continue; ++ ++ if (!pte_young(pte[i])) { ++ walk->mm_stats[MM_LEAF_OLD]++; ++ continue; ++ } ++ ++ page = get_pfn_page(pfn, memcg, pgdat, walk->can_swap); ++ if (!page) ++ continue; ++ ++ if (!ptep_test_and_clear_young(args->vma, addr, pte + i)) ++ VM_WARN_ON_ONCE(true); ++ ++ young++; ++ walk->mm_stats[MM_LEAF_YOUNG]++; ++ ++ if (pte_dirty(pte[i]) && !PageDirty(page) && ++ !(PageAnon(page) && PageSwapBacked(page) && ++ !PageSwapCache(page))) ++ set_page_dirty(page); ++ ++ old_gen = page_update_gen(page, new_gen); ++ if (old_gen >= 0 && old_gen != new_gen) ++ update_batch_size(walk, page, old_gen, new_gen); ++ } ++ ++ if (i < PTRS_PER_PTE && get_next_vma(PMD_MASK, PAGE_SIZE, args, &start, &end)) ++ goto restart; ++ ++ pte_unmap(pte); ++ ++ arch_leave_lazy_mmu_mode(); ++ spin_unlock(ptl); ++ ++ return suitable_to_scan(total, young); ++} ++ ++#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) ++static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, ++ struct mm_walk *args, unsigned long *bitmap, unsigned long *start) ++{ ++ int i; ++ pmd_t *pmd; ++ spinlock_t *ptl; ++ struct lru_gen_mm_walk *walk = args->private; ++ struct mem_cgroup *memcg = lruvec_memcg(walk->lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); ++ int old_gen, new_gen = lru_gen_from_seq(walk->max_seq); ++ ++ VM_WARN_ON_ONCE(pud_leaf(*pud)); ++ ++ /* try to batch at most 1+MIN_LRU_BATCH+1 entries */ ++ if (*start == -1) { ++ *start = next; ++ return; ++ } ++ ++ i = next == -1 ? 0 : pmd_index(next) - pmd_index(*start); ++ if (i && i <= MIN_LRU_BATCH) { ++ __set_bit(i - 1, bitmap); ++ return; ++ } ++ ++ pmd = pmd_offset(pud, *start); ++ ++ ptl = pmd_lockptr(args->mm, pmd); ++ if (!spin_trylock(ptl)) ++ goto done; ++ ++ arch_enter_lazy_mmu_mode(); ++ ++ do { ++ unsigned long pfn; ++ struct page *page; ++ unsigned long addr = i ? (*start & PMD_MASK) + i * PMD_SIZE : *start; ++ ++ pfn = get_pmd_pfn(pmd[i], vma, addr); ++ if (pfn == -1) ++ goto next; ++ ++ if (!pmd_trans_huge(pmd[i])) { ++ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG)) ++ pmdp_test_and_clear_young(vma, addr, pmd + i); ++ goto next; ++ } ++ ++ page = get_pfn_page(pfn, memcg, pgdat, walk->can_swap); ++ if (!page) ++ goto next; ++ ++ if (!pmdp_test_and_clear_young(vma, addr, pmd + i)) ++ goto next; ++ ++ walk->mm_stats[MM_LEAF_YOUNG]++; ++ ++ if (pmd_dirty(pmd[i]) && !PageDirty(page) && ++ !(PageAnon(page) && PageSwapBacked(page) && ++ !PageSwapCache(page))) ++ set_page_dirty(page); ++ ++ old_gen = page_update_gen(page, new_gen); ++ if (old_gen >= 0 && old_gen != new_gen) ++ update_batch_size(walk, page, old_gen, new_gen); ++next: ++ i = i > MIN_LRU_BATCH ? 0 : find_next_bit(bitmap, MIN_LRU_BATCH, i) + 1; ++ } while (i <= MIN_LRU_BATCH); ++ ++ arch_leave_lazy_mmu_mode(); ++ spin_unlock(ptl); ++done: ++ *start = -1; ++ bitmap_zero(bitmap, MIN_LRU_BATCH); ++} ++#else ++static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, ++ struct mm_walk *args, unsigned long *bitmap, unsigned long *start) ++{ ++} ++#endif ++ ++static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, ++ struct mm_walk *args) ++{ ++ int i; ++ pmd_t *pmd; ++ unsigned long next; ++ unsigned long addr; ++ struct vm_area_struct *vma; ++ unsigned long pos = -1; ++ struct lru_gen_mm_walk *walk = args->private; ++ unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; ++ ++ VM_WARN_ON_ONCE(pud_leaf(*pud)); ++ ++ /* ++ * Finish an entire PMD in two passes: the first only reaches to PTE ++ * tables to avoid taking the PMD lock; the second, if necessary, takes ++ * the PMD lock to clear the accessed bit in PMD entries. ++ */ ++ pmd = pmd_offset(pud, start & PUD_MASK); ++restart: ++ /* walk_pte_range() may call get_next_vma() */ ++ vma = args->vma; ++ for (i = pmd_index(start), addr = start; addr != end; i++, addr = next) { ++ pmd_t val = pmd_read_atomic(pmd + i); ++ ++ /* for pmd_read_atomic() */ ++ barrier(); ++ ++ next = pmd_addr_end(addr, end); ++ ++ if (!pmd_present(val) || is_huge_zero_pmd(val)) { ++ walk->mm_stats[MM_LEAF_TOTAL]++; ++ continue; ++ } ++ ++#ifdef CONFIG_TRANSPARENT_HUGEPAGE ++ if (pmd_trans_huge(val)) { ++ unsigned long pfn = pmd_pfn(val); ++ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); ++ ++ walk->mm_stats[MM_LEAF_TOTAL]++; ++ ++ if (!pmd_young(val)) { ++ walk->mm_stats[MM_LEAF_OLD]++; ++ continue; ++ } ++ ++ /* try to avoid unnecessary memory loads */ ++ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) ++ continue; ++ ++ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++ continue; ++ } ++#endif ++ walk->mm_stats[MM_NONLEAF_TOTAL]++; ++ ++#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG ++ if (!pmd_young(val)) ++ continue; ++ ++ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++#endif ++ if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) ++ continue; ++ ++ walk->mm_stats[MM_NONLEAF_FOUND]++; ++ ++ if (!walk_pte_range(&val, addr, next, args)) ++ continue; ++ ++ walk->mm_stats[MM_NONLEAF_ADDED]++; ++ ++ /* carry over to the next generation */ ++ update_bloom_filter(walk->lruvec, walk->max_seq + 1, pmd + i); ++ } ++ ++ walk_pmd_range_locked(pud, -1, vma, args, bitmap, &pos); ++ ++ if (i < PTRS_PER_PMD && get_next_vma(PUD_MASK, PMD_SIZE, args, &start, &end)) ++ goto restart; ++} ++ ++static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, ++ struct mm_walk *args) ++{ ++ int i; ++ pud_t *pud; ++ unsigned long addr; ++ unsigned long next; ++ struct lru_gen_mm_walk *walk = args->private; ++ ++ VM_WARN_ON_ONCE(p4d_leaf(*p4d)); ++ ++ pud = pud_offset(p4d, start & P4D_MASK); ++restart: ++ for (i = pud_index(start), addr = start; addr != end; i++, addr = next) { ++ pud_t val = READ_ONCE(pud[i]); ++ ++ next = pud_addr_end(addr, end); ++ ++ if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val))) ++ continue; ++ ++ walk_pmd_range(&val, addr, next, args); ++ ++ /* a racy check to curtail the waiting time */ ++ if (wq_has_sleeper(&walk->lruvec->mm_state.wait)) ++ return 1; ++ ++ if (need_resched() || walk->batched >= MAX_LRU_BATCH) { ++ end = (addr | ~PUD_MASK) + 1; ++ goto done; ++ } ++ } ++ ++ if (i < PTRS_PER_PUD && get_next_vma(P4D_MASK, PUD_SIZE, args, &start, &end)) ++ goto restart; ++ ++ end = round_up(end, P4D_SIZE); ++done: ++ if (!end || !args->vma) ++ return 1; ++ ++ walk->next_addr = max(end, args->vma->vm_start); ++ ++ return -EAGAIN; ++} ++ ++static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_mm_walk *walk) ++{ ++ static const struct mm_walk_ops mm_walk_ops = { ++ .test_walk = should_skip_vma, ++ .p4d_entry = walk_pud_range, ++ }; ++ ++ int err; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ ++ walk->next_addr = FIRST_USER_ADDRESS; ++ ++ do { ++ err = -EBUSY; ++ ++ /* page_update_gen() requires stable page_memcg() */ ++ if (!mem_cgroup_trylock_pages(memcg)) ++ break; ++ ++ /* the caller might be holding the lock for write */ ++ if (mmap_read_trylock(mm)) { ++ err = walk_page_range(mm, walk->next_addr, ULONG_MAX, &mm_walk_ops, walk); ++ ++ mmap_read_unlock(mm); ++ } ++ ++ mem_cgroup_unlock_pages(); ++ ++ if (walk->batched) { ++ spin_lock_irq(&lruvec->lru_lock); ++ reset_batch_size(lruvec, walk); ++ spin_unlock_irq(&lruvec->lru_lock); ++ } ++ ++ cond_resched(); ++ } while (err == -EAGAIN); ++} ++ ++static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat) ++{ ++ struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; ++ ++ if (pgdat && current_is_kswapd()) { ++ VM_WARN_ON_ONCE(walk); ++ ++ walk = &pgdat->mm_walk; ++ } else if (!pgdat && !walk) { ++ VM_WARN_ON_ONCE(current_is_kswapd()); ++ ++ walk = kzalloc(sizeof(*walk), __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); ++ } ++ ++ current->reclaim_state->mm_walk = walk; ++ ++ return walk; ++} ++ ++static void clear_mm_walk(void) ++{ ++ struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; ++ ++ VM_WARN_ON_ONCE(walk && memchr_inv(walk->nr_pages, 0, sizeof(walk->nr_pages))); ++ VM_WARN_ON_ONCE(walk && memchr_inv(walk->mm_stats, 0, sizeof(walk->mm_stats))); ++ ++ current->reclaim_state->mm_walk = NULL; ++ ++ if (!current_is_kswapd()) ++ kfree(walk); ++} ++ + static void inc_min_seq(struct lruvec *lruvec, int type) + { + struct lru_gen_struct *lrugen = &lruvec->lrugen; +@@ -3136,7 +4001,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) + return success; + } + +-static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_swap) ++static void inc_max_seq(struct lruvec *lruvec, bool can_swap) + { + int prev, next; + int type, zone; +@@ -3146,9 +4011,6 @@ static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_s + + VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); + +- if (max_seq != lrugen->max_seq) +- goto unlock; +- + for (type = ANON_AND_FILE - 1; type >= 0; type--) { + if (get_nr_gens(lruvec, type) != MAX_NR_GENS) + continue; +@@ -3186,10 +4048,76 @@ static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_s + + /* make sure preceding modifications appear */ + smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); +-unlock: ++ + spin_unlock_irq(&lruvec->lru_lock); + } + ++static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, ++ struct scan_control *sc, bool can_swap) ++{ ++ bool success; ++ struct lru_gen_mm_walk *walk; ++ struct mm_struct *mm = NULL; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); ++ ++ /* see the comment in iterate_mm_list() */ ++ if (max_seq <= READ_ONCE(lruvec->mm_state.seq)) { ++ success = false; ++ goto done; ++ } ++ ++ /* ++ * If the hardware doesn't automatically set the accessed bit, fallback ++ * to lru_gen_look_around(), which only clears the accessed bit in a ++ * handful of PTEs. Spreading the work out over a period of time usually ++ * is less efficient, but it avoids bursty page faults. ++ */ ++ if (!arch_has_hw_pte_young()) { ++ success = iterate_mm_list_nowalk(lruvec, max_seq); ++ goto done; ++ } ++ ++ walk = set_mm_walk(NULL); ++ if (!walk) { ++ success = iterate_mm_list_nowalk(lruvec, max_seq); ++ goto done; ++ } ++ ++ walk->lruvec = lruvec; ++ walk->max_seq = max_seq; ++ walk->can_swap = can_swap; ++ walk->force_scan = false; ++ ++ do { ++ success = iterate_mm_list(lruvec, walk, &mm); ++ if (mm) ++ walk_mm(lruvec, mm, walk); ++ ++ cond_resched(); ++ } while (mm); ++done: ++ if (!success) { ++ if (sc->priority <= DEF_PRIORITY - 2) ++ wait_event_killable(lruvec->mm_state.wait, ++ max_seq < READ_ONCE(lrugen->max_seq)); ++ ++ return max_seq < READ_ONCE(lrugen->max_seq); ++ } ++ ++ VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); ++ ++ inc_max_seq(lruvec, can_swap); ++ /* either this sees any waiters or they will see updated max_seq */ ++ if (wq_has_sleeper(&lruvec->mm_state.wait)) ++ wake_up_all(&lruvec->mm_state.wait); ++ ++ wakeup_flusher_threads(WB_REASON_VMSCAN); ++ ++ return true; ++} ++ + static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, + struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) + { +@@ -3265,7 +4193,7 @@ static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) + + need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); + if (need_aging) +- inc_max_seq(lruvec, max_seq, swappiness); ++ try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); + } + + static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +@@ -3274,6 +4202,8 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + + VM_WARN_ON_ONCE(!current_is_kswapd()); + ++ set_mm_walk(pgdat); ++ + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); +@@ -3282,11 +4212,16 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); ++ ++ clear_mm_walk(); + } + + /* + * This function exploits spatial locality when shrink_page_list() walks the +- * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. ++ * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. If ++ * the scan was done cacheline efficiently, it adds the PMD entry pointing to ++ * the PTE table to the Bloom filter. This forms a feedback loop between the ++ * eviction and the aging. + */ + void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + { +@@ -3295,6 +4230,8 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + unsigned long start; + unsigned long end; + unsigned long addr; ++ struct lru_gen_mm_walk *walk; ++ int young = 0; + unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; + struct page *page = pvmw->page; + struct mem_cgroup *memcg = page_memcg(page); +@@ -3309,6 +4246,9 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + if (spin_is_contended(pvmw->ptl)) + return; + ++ /* avoid taking the LRU lock under the PTL when possible */ ++ walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; ++ + start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); + end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; + +@@ -3338,13 +4278,15 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + if (!pte_young(pte[i])) + continue; + +- page = get_pfn_page(pfn, memcg, pgdat); ++ page = get_pfn_page(pfn, memcg, pgdat, !walk || walk->can_swap); + if (!page) + continue; + + if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) + VM_WARN_ON_ONCE(true); + ++ young++; ++ + if (pte_dirty(pte[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && + !PageSwapCache(page))) +@@ -3360,7 +4302,11 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + arch_leave_lazy_mmu_mode(); + rcu_read_unlock(); + +- if (bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { ++ /* feedback from rmap walkers to page table walkers */ ++ if (suitable_to_scan(i, young)) ++ update_bloom_filter(lruvec, max_seq, pvmw->pmd); ++ ++ if (!walk && bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { + page = pte_page(pte[i]); + activate_page(page); +@@ -3372,8 +4318,10 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + if (!mem_cgroup_trylock_pages(memcg)) + return; + +- spin_lock_irq(&lruvec->lru_lock); +- new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); ++ if (!walk) { ++ spin_lock_irq(&lruvec->lru_lock); ++ new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); ++ } + + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { + page = compound_head(pte_page(pte[i])); +@@ -3384,10 +4332,14 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + if (old_gen < 0 || old_gen == new_gen) + continue; + +- lru_gen_update_size(lruvec, page, old_gen, new_gen); ++ if (walk) ++ update_batch_size(walk, page, old_gen, new_gen); ++ else ++ lru_gen_update_size(lruvec, page, old_gen, new_gen); + } + +- spin_unlock_irq(&lruvec->lru_lock); ++ if (!walk) ++ spin_unlock_irq(&lruvec->lru_lock); + + mem_cgroup_unlock_pages(); + } +@@ -3670,6 +4622,7 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + struct page *page; + enum vm_event_item item; + struct reclaim_stat stat; ++ struct lru_gen_mm_walk *walk; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + +@@ -3706,6 +4659,10 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + + move_pages_to_lru(lruvec, &list); + ++ walk = current->reclaim_state->mm_walk; ++ if (walk && walk->batched) ++ reset_batch_size(lruvec, walk); ++ + item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; + if (!cgroup_reclaim(sc)) + __count_vm_events(item, reclaimed); +@@ -3722,6 +4679,11 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + return scanned; + } + ++/* ++ * For future optimizations: ++ * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg ++ * reclaim. ++ */ + static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, + bool can_swap) + { +@@ -3747,7 +4709,8 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * + if (current_is_kswapd()) + return 0; + +- inc_max_seq(lruvec, max_seq, can_swap); ++ if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap)) ++ return nr_to_scan; + done: + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; + } +@@ -3761,6 +4724,8 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + + blk_start_plug(&plug); + ++ set_mm_walk(lruvec_pgdat(lruvec)); ++ + while (true) { + int delta; + int swappiness; +@@ -3788,6 +4753,8 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + cond_resched(); + } + ++ clear_mm_walk(); ++ + blk_finish_plug(&plug); + } + +@@ -3804,15 +4771,21 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) + + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); ++ ++ lruvec->mm_state.seq = MIN_NR_GENS; ++ init_waitqueue_head(&lruvec->mm_state.wait); + } + + #ifdef CONFIG_MEMCG + void lru_gen_init_memcg(struct mem_cgroup *memcg) + { ++ INIT_LIST_HEAD(&memcg->mm_list.fifo); ++ spin_lock_init(&memcg->mm_list.lock); + } + + void lru_gen_exit_memcg(struct mem_cgroup *memcg) + { ++ int i; + int nid; + + for_each_node(nid) { +@@ -3820,6 +4793,11 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) + + VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, + sizeof(lruvec->lrugen.nr_pages))); ++ ++ for (i = 0; i < NR_BLOOM_FILTERS; i++) { ++ bitmap_free(lruvec->mm_state.filters[i]); ++ lruvec->mm_state.filters[i] = NULL; ++ } + } + } + #endif +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-08-mm-multigenerational-lru-user-interface.patch b/target/linux/generic/backport-5.15/020-v6.1-08-mm-multigenerational-lru-user-interface.patch deleted file mode 100644 index f0753ea8028..00000000000 --- a/target/linux/generic/backport-5.15/020-v6.1-08-mm-multigenerational-lru-user-interface.patch +++ /dev/null @@ -1,496 +0,0 @@ -From 5cc7fdec54e87e32b4fb0f07d84b21769d5f8d92 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Mon, 25 Jan 2021 21:38:02 -0700 -Subject: [PATCH 08/10] mm: multigenerational lru: user interface - -Add /sys/kernel/mm/lru_gen/enabled to enable and disable the -multigenerational lru at runtime. - -Add /sys/kernel/mm/lru_gen/min_ttl_ms to protect the working set of a -given number of milliseconds. The OOM killer is invoked if this -working set cannot be kept in memory. - -Add /sys/kernel/debug/lru_gen to monitor the multigenerational lru and -invoke the aging and the eviction. This file has the following output: - memcg memcg_id memcg_path - node node_id - min_gen birth_time anon_size file_size - ... - max_gen birth_time anon_size file_size - -min_gen is the oldest generation number and max_gen is the youngest -generation number. birth_time is in milliseconds. anon_size and -file_size are in pages. - -This file takes the following input: - + memcg_id node_id max_gen [swappiness] [use_bloom_filter] - - memcg_id node_id min_gen [swappiness] [nr_to_reclaim] - -The first command line invokes the aging, which scans PTEs for -accessed pages and then creates the next generation max_gen+1. A swap -file and a non-zero swappiness, which overrides vm.swappiness, are -required to scan PTEs mapping anon pages. The second command line -invokes the eviction, which evicts generations less than or equal to -min_gen. min_gen should be less than max_gen-1 as max_gen and -max_gen-1 are not fully aged and therefore cannot be evicted. -Setting nr_to_reclaim to N limits the number of pages to evict. -Setting use_bloom_filter to 0 overrides the default behavior which -only scans PTE tables found populated. Multiple command lines are -supported, as is concatenation with delimiters "," and ";". - -Signed-off-by: Yu Zhao -Tested-by: Konstantin Kharlamov -Change-Id: I4448e60029badbe347aa3b624f429b280cc3a3d3 ---- - include/linux/nodemask.h | 1 + - mm/vmscan.c | 415 +++++++++++++++++++++++++++++++++++++++ - 2 files changed, 416 insertions(+) - ---- a/include/linux/nodemask.h -+++ b/include/linux/nodemask.h -@@ -485,6 +485,7 @@ static inline int num_node_state(enum no - #define first_online_node 0 - #define first_memory_node 0 - #define next_online_node(nid) (MAX_NUMNODES) -+#define next_memory_node(nid) (MAX_NUMNODES) - #define nr_node_ids 1U - #define nr_online_nodes 1U - ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -53,6 +53,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -4817,6 +4819,413 @@ unlock: - } - - /****************************************************************************** -+ * sysfs interface -+ ******************************************************************************/ -+ -+static ssize_t show_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%u\n", jiffies_to_msecs(READ_ONCE(lru_gen_min_ttl))); -+} -+ -+static ssize_t store_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t len) -+{ -+ unsigned int msecs; -+ -+ if (kstrtouint(buf, 10, &msecs)) -+ return -EINVAL; -+ -+ WRITE_ONCE(lru_gen_min_ttl, msecs_to_jiffies(msecs)); -+ -+ return len; -+} -+ -+static struct kobj_attribute lru_gen_min_ttl_attr = __ATTR( -+ min_ttl_ms, 0644, show_min_ttl, store_min_ttl -+); -+ -+static ssize_t show_enable(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -+{ -+ return snprintf(buf, PAGE_SIZE, "%d\n", lru_gen_enabled()); -+} -+ -+static ssize_t store_enable(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool enable; -+ -+ if (kstrtobool(buf, &enable)) -+ return -EINVAL; -+ -+ lru_gen_change_state(enable, true, false); -+ -+ return len; -+} -+ -+static struct kobj_attribute lru_gen_enabled_attr = __ATTR( -+ enabled, 0644, show_enable, store_enable -+); -+ -+static struct attribute *lru_gen_attrs[] = { -+ &lru_gen_min_ttl_attr.attr, -+ &lru_gen_enabled_attr.attr, -+ NULL -+}; -+ -+static struct attribute_group lru_gen_attr_group = { -+ .name = "lru_gen", -+ .attrs = lru_gen_attrs, -+}; -+ -+/****************************************************************************** -+ * debugfs interface -+ ******************************************************************************/ -+ -+static void *lru_gen_seq_start(struct seq_file *m, loff_t *pos) -+{ -+ struct mem_cgroup *memcg; -+ loff_t nr_to_skip = *pos; -+ -+ m->private = kvmalloc(PATH_MAX, GFP_KERNEL); -+ if (!m->private) -+ return ERR_PTR(-ENOMEM); -+ -+ memcg = mem_cgroup_iter(NULL, NULL, NULL); -+ do { -+ int nid; -+ -+ for_each_node_state(nid, N_MEMORY) { -+ if (!nr_to_skip--) -+ return get_lruvec(nid, memcg); -+ } -+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); -+ -+ return NULL; -+} -+ -+static void lru_gen_seq_stop(struct seq_file *m, void *v) -+{ -+ if (!IS_ERR_OR_NULL(v)) -+ mem_cgroup_iter_break(NULL, lruvec_memcg(v)); -+ -+ kvfree(m->private); -+ m->private = NULL; -+} -+ -+static void *lru_gen_seq_next(struct seq_file *m, void *v, loff_t *pos) -+{ -+ int nid = lruvec_pgdat(v)->node_id; -+ struct mem_cgroup *memcg = lruvec_memcg(v); -+ -+ ++*pos; -+ -+ nid = next_memory_node(nid); -+ if (nid == MAX_NUMNODES) { -+ memcg = mem_cgroup_iter(NULL, memcg, NULL); -+ if (!memcg) -+ return NULL; -+ -+ nid = first_memory_node; -+ } -+ -+ return get_lruvec(nid, memcg); -+} -+ -+static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, -+ unsigned long max_seq, unsigned long *min_seq, -+ unsigned long seq) -+{ -+ int i; -+ int type, tier; -+ int hist = lru_hist_from_seq(seq); -+ struct lrugen *lrugen = &lruvec->evictable; -+ -+ for (tier = 0; tier < MAX_NR_TIERS; tier++) { -+ seq_printf(m, " %10d", tier); -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ unsigned long n[3] = {}; -+ -+ if (seq == max_seq) { -+ n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]); -+ n[1] = READ_ONCE(lrugen->avg_total[type][tier]); -+ -+ seq_printf(m, " %10luR %10luT %10lu ", n[0], n[1], n[2]); -+ } else if (seq == min_seq[type] || NR_HIST_GENS > 1) { -+ n[0] = atomic_long_read(&lrugen->refaulted[hist][type][tier]); -+ n[1] = atomic_long_read(&lrugen->evicted[hist][type][tier]); -+ if (tier) -+ n[2] = READ_ONCE(lrugen->protected[hist][type][tier - 1]); -+ -+ seq_printf(m, " %10lur %10lue %10lup", n[0], n[1], n[2]); -+ } else -+ seq_puts(m, " 0 0 0 "); -+ } -+ seq_putc(m, '\n'); -+ } -+ -+ seq_puts(m, " "); -+ for (i = 0; i < NR_MM_STATS; i++) { -+ if (seq == max_seq && NR_HIST_GENS == 1) -+ seq_printf(m, " %10lu%c", READ_ONCE(lruvec->mm_walk.stats[hist][i]), -+ toupper(MM_STAT_CODES[i])); -+ else if (seq != max_seq && NR_HIST_GENS > 1) -+ seq_printf(m, " %10lu%c", READ_ONCE(lruvec->mm_walk.stats[hist][i]), -+ MM_STAT_CODES[i]); -+ else -+ seq_puts(m, " 0 "); -+ } -+ seq_putc(m, '\n'); -+} -+ -+static int lru_gen_seq_show(struct seq_file *m, void *v) -+{ -+ unsigned long seq; -+ bool full = !debugfs_real_fops(m->file)->write; -+ struct lruvec *lruvec = v; -+ struct lrugen *lrugen = &lruvec->evictable; -+ int nid = lruvec_pgdat(lruvec)->node_id; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ DEFINE_MAX_SEQ(lruvec); -+ DEFINE_MIN_SEQ(lruvec); -+ -+ if (nid == first_memory_node) { -+ const char *path = memcg ? m->private : ""; -+ -+#ifdef CONFIG_MEMCG -+ if (memcg) -+ cgroup_path(memcg->css.cgroup, m->private, PATH_MAX); -+#endif -+ seq_printf(m, "memcg %5hu %s\n", mem_cgroup_id(memcg), path); -+ } -+ -+ seq_printf(m, " node %5d\n", nid); -+ -+ if (!full) -+ seq = min_seq[0]; -+ else if (max_seq >= MAX_NR_GENS) -+ seq = max_seq - MAX_NR_GENS + 1; -+ else -+ seq = 0; -+ -+ for (; seq <= max_seq; seq++) { -+ int gen, type, zone; -+ unsigned int msecs; -+ -+ gen = lru_gen_from_seq(seq); -+ msecs = jiffies_to_msecs(jiffies - READ_ONCE(lrugen->timestamps[gen])); -+ -+ seq_printf(m, " %10lu %10u", seq, msecs); -+ -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ long size = 0; -+ -+ if (seq < min_seq[type]) { -+ seq_puts(m, " -0 "); -+ continue; -+ } -+ -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) -+ size += READ_ONCE(lrugen->sizes[gen][type][zone]); -+ -+ seq_printf(m, " %10lu ", max(size, 0L)); -+ } -+ -+ seq_putc(m, '\n'); -+ -+ if (full) -+ lru_gen_seq_show_full(m, lruvec, max_seq, min_seq, seq); -+ } -+ -+ return 0; -+} -+ -+static const struct seq_operations lru_gen_seq_ops = { -+ .start = lru_gen_seq_start, -+ .stop = lru_gen_seq_stop, -+ .next = lru_gen_seq_next, -+ .show = lru_gen_seq_show, -+}; -+ -+static int run_aging(struct lruvec *lruvec, struct scan_control *sc, int swappiness, -+ unsigned long seq, bool use_filter) -+{ -+ DEFINE_MAX_SEQ(lruvec); -+ -+ if (seq == max_seq) -+ try_to_inc_max_seq(lruvec, sc, swappiness, max_seq, use_filter); -+ -+ return seq > max_seq ? -EINVAL : 0; -+} -+ -+static int run_eviction(struct lruvec *lruvec, struct scan_control *sc, int swappiness, -+ unsigned long seq, unsigned long nr_to_reclaim) -+{ -+ struct blk_plug plug; -+ int err = -EINTR; -+ DEFINE_MAX_SEQ(lruvec); -+ -+ if (seq >= max_seq - 1) -+ return -EINVAL; -+ -+ sc->nr_reclaimed = 0; -+ -+ blk_start_plug(&plug); -+ -+ while (!signal_pending(current)) { -+ DEFINE_MIN_SEQ(lruvec); -+ -+ if (seq < min_seq[!swappiness] || sc->nr_reclaimed >= nr_to_reclaim || -+ !evict_pages(lruvec, sc, swappiness)) { -+ err = 0; -+ break; -+ } -+ -+ cond_resched(); -+ } -+ -+ blk_finish_plug(&plug); -+ -+ return err; -+} -+ -+static int run_cmd(char cmd, int memcg_id, int nid, struct scan_control *sc, -+ int swappiness, unsigned long seq, unsigned long opt) -+{ -+ struct lruvec *lruvec; -+ int err = -EINVAL; -+ struct mem_cgroup *memcg = NULL; -+ -+ if (!mem_cgroup_disabled()) { -+ rcu_read_lock(); -+ memcg = mem_cgroup_from_id(memcg_id); -+#ifdef CONFIG_MEMCG -+ if (memcg && !css_tryget(&memcg->css)) -+ memcg = NULL; -+#endif -+ rcu_read_unlock(); -+ -+ if (!memcg) -+ goto done; -+ } -+ if (memcg_id != mem_cgroup_id(memcg)) -+ goto done; -+ -+ if (nid < 0 || nid >= MAX_NUMNODES || !node_state(nid, N_MEMORY)) -+ goto done; -+ -+ lruvec = get_lruvec(nid, memcg); -+ -+ if (swappiness < 0) -+ swappiness = get_swappiness(memcg); -+ else if (swappiness > 200) -+ goto done; -+ -+ switch (cmd) { -+ case '+': -+ err = run_aging(lruvec, sc, swappiness, seq, opt); -+ break; -+ case '-': -+ err = run_eviction(lruvec, sc, swappiness, seq, opt); -+ break; -+ } -+done: -+ mem_cgroup_put(memcg); -+ -+ return err; -+} -+ -+static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, -+ size_t len, loff_t *pos) -+{ -+ void *buf; -+ char *cur, *next; -+ unsigned int flags; -+ int err = 0; -+ struct scan_control sc = { -+ .may_writepage = 1, -+ .may_unmap = 1, -+ .may_swap = 1, -+ .reclaim_idx = MAX_NR_ZONES - 1, -+ .gfp_mask = GFP_KERNEL, -+ }; -+ -+ buf = kvmalloc(len + 1, GFP_KERNEL); -+ if (!buf) -+ return -ENOMEM; -+ -+ if (copy_from_user(buf, src, len)) { -+ kvfree(buf); -+ return -EFAULT; -+ } -+ -+ next = buf; -+ next[len] = '\0'; -+ -+ sc.reclaim_state.mm_walk_args = alloc_mm_walk_args(); -+ if (!sc.reclaim_state.mm_walk_args) { -+ kvfree(buf); -+ return -ENOMEM; -+ } -+ -+ flags = memalloc_noreclaim_save(); -+ set_task_reclaim_state(current, &sc.reclaim_state); -+ -+ while ((cur = strsep(&next, ",;\n"))) { -+ int n; -+ int end; -+ char cmd; -+ unsigned int memcg_id; -+ unsigned int nid; -+ unsigned long seq; -+ unsigned int swappiness = -1; -+ unsigned long opt = -1; -+ -+ cur = skip_spaces(cur); -+ if (!*cur) -+ continue; -+ -+ n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid, -+ &seq, &end, &swappiness, &end, &opt, &end); -+ if (n < 4 || cur[end]) { -+ err = -EINVAL; -+ break; -+ } -+ -+ err = run_cmd(cmd, memcg_id, nid, &sc, swappiness, seq, opt); -+ if (err) -+ break; -+ } -+ -+ set_task_reclaim_state(current, NULL); -+ memalloc_noreclaim_restore(flags); -+ -+ free_mm_walk_args(sc.reclaim_state.mm_walk_args); -+ kvfree(buf); -+ -+ return err ? : len; -+} -+ -+static int lru_gen_seq_open(struct inode *inode, struct file *file) -+{ -+ return seq_open(file, &lru_gen_seq_ops); -+} -+ -+static const struct file_operations lru_gen_rw_fops = { -+ .open = lru_gen_seq_open, -+ .read = seq_read, -+ .write = lru_gen_seq_write, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+static const struct file_operations lru_gen_ro_fops = { -+ .open = lru_gen_seq_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+/****************************************************************************** - * initialization - ******************************************************************************/ - -@@ -4886,6 +5295,12 @@ static int __init init_lru_gen(void) - BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); - BUILD_BUG_ON(sizeof(MM_STAT_CODES) != NR_MM_STATS + 1); - -+ if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) -+ pr_err("lru_gen: failed to create sysfs group\n"); -+ -+ debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_rw_fops); -+ debugfs_create_file("lru_gen_full", 0444, NULL, NULL, &lru_gen_ro_fops); -+ - return 0; - }; - late_initcall(init_lru_gen); diff --git a/target/linux/generic/backport-5.15/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch b/target/linux/generic/backport-5.15/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch new file mode 100644 index 00000000000..e47bfc36d46 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch @@ -0,0 +1,320 @@ +From 36a18a68ea458e8f4db2ca86b00091daf32c6c74 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:06 -0600 +Subject: [PATCH 09/29] mm: multi-gen LRU: optimize multiple memcgs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When multiple memcgs are available, it is possible to use generations as a +frame of reference to make better choices and improve overall performance +under global memory pressure. This patch adds a basic optimization to +select memcgs that can drop single-use unmapped clean pages first. Doing +so reduces the chance of going into the aging path or swapping, which can +be costly. + +A typical example that benefits from this optimization is a server running +mixed types of workloads, e.g., heavy anon workload in one memcg and heavy +buffered I/O workload in the other. + +Though this optimization can be applied to both kswapd and direct reclaim, +it is only added to kswapd to keep the patchset manageable. Later +improvements may cover the direct reclaim path. + +While ensuring certain fairness to all eligible memcgs, proportional scans +of individual memcgs also require proper backoff to avoid overshooting +their aggregate reclaim target by too much. Otherwise it can cause high +direct reclaim latency. The conditions for backoff are: + +1. At low priorities, for direct reclaim, if aging fairness or direct + reclaim latency is at risk, i.e., aging one memcg multiple times or + swapping after the target is met. +2. At high priorities, for global reclaim, if per-zone free pages are + above respective watermarks. + +Server benchmark results: + Mixed workloads: + fio (buffered I/O): +[19, 21]% + IOPS BW + patch1-8: 1880k 7343MiB/s + patch1-9: 2252k 8796MiB/s + + memcached (anon): +[119, 123]% + Ops/sec KB/sec + patch1-8: 862768.65 33514.68 + patch1-9: 1911022.12 74234.54 + + Mixed workloads: + fio (buffered I/O): +[75, 77]% + IOPS BW + 5.19-rc1: 1279k 4996MiB/s + patch1-9: 2252k 8796MiB/s + + memcached (anon): +[13, 15]% + Ops/sec KB/sec + 5.19-rc1: 1673524.04 65008.87 + patch1-9: 1911022.12 74234.54 + + Configurations: + (changes since patch 6) + + cat mixed.sh + modprobe brd rd_nr=2 rd_size=56623104 + + swapoff -a + mkswap /dev/ram0 + swapon /dev/ram0 + + mkfs.ext4 /dev/ram1 + mount -t ext4 /dev/ram1 /mnt + + memtier_benchmark -S /var/run/memcached/memcached.sock \ + -P memcache_binary -n allkeys --key-minimum=1 \ + --key-maximum=50000000 --key-pattern=P:P -c 1 -t 36 \ + --ratio 1:0 --pipeline 8 -d 2000 + + fio -name=mglru --numjobs=36 --directory=/mnt --size=1408m \ + --buffered=1 --ioengine=io_uring --iodepth=128 \ + --iodepth_batch_submit=32 --iodepth_batch_complete=32 \ + --rw=randread --random_distribution=random --norandommap \ + --time_based --ramp_time=10m --runtime=90m --group_reporting & + pid=$! + + sleep 200 + + memtier_benchmark -S /var/run/memcached/memcached.sock \ + -P memcache_binary -n allkeys --key-minimum=1 \ + --key-maximum=50000000 --key-pattern=R:R -c 1 -t 36 \ + --ratio 0:1 --pipeline 8 --randomize --distinct-client-seed + + kill -INT $pid + wait + +Client benchmark results: + no change (CONFIG_MEMCG=n) + +Link: https://lkml.kernel.org/r/20220918080010.2920238-10-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 96 insertions(+), 9 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index a7844c689522..b6f6fc2585e1 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -127,6 +127,12 @@ struct scan_control { + /* Always discard instead of demoting to lower tier memory */ + unsigned int no_demotion:1; + ++#ifdef CONFIG_LRU_GEN ++ /* help kswapd make better choices among multiple memcgs */ ++ unsigned int memcgs_need_aging:1; ++ unsigned long last_reclaimed; ++#endif ++ + /* Allocation order */ + s8 order; + +@@ -4202,6 +4208,19 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + + VM_WARN_ON_ONCE(!current_is_kswapd()); + ++ sc->last_reclaimed = sc->nr_reclaimed; ++ ++ /* ++ * To reduce the chance of going into the aging path, which can be ++ * costly, optimistically skip it if the flag below was cleared in the ++ * eviction path. This improves the overall performance when multiple ++ * memcgs are available. ++ */ ++ if (!sc->memcgs_need_aging) { ++ sc->memcgs_need_aging = true; ++ return; ++ } ++ + set_mm_walk(pgdat); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); +@@ -4613,7 +4632,8 @@ static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swa + return scanned; + } + +-static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) ++static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, ++ bool *need_swapping) + { + int type; + int scanned; +@@ -4676,6 +4696,9 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + + sc->nr_reclaimed += reclaimed; + ++ if (need_swapping && type == LRU_GEN_ANON) ++ *need_swapping = true; ++ + return scanned; + } + +@@ -4685,9 +4708,8 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + * reclaim. + */ + static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, +- bool can_swap) ++ bool can_swap, bool *need_aging) + { +- bool need_aging; + unsigned long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); +@@ -4697,8 +4719,8 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * + (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) + return 0; + +- need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); +- if (!need_aging) ++ *need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); ++ if (!*need_aging) + return nr_to_scan; + + /* skip the aging path at the default priority */ +@@ -4715,10 +4737,68 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; + } + ++static bool should_abort_scan(struct lruvec *lruvec, unsigned long seq, ++ struct scan_control *sc, bool need_swapping) ++{ ++ int i; ++ DEFINE_MAX_SEQ(lruvec); ++ ++ if (!current_is_kswapd()) { ++ /* age each memcg once to ensure fairness */ ++ if (max_seq - seq > 1) ++ return true; ++ ++ /* over-swapping can increase allocation latency */ ++ if (sc->nr_reclaimed >= sc->nr_to_reclaim && need_swapping) ++ return true; ++ ++ /* give this thread a chance to exit and free its memory */ ++ if (fatal_signal_pending(current)) { ++ sc->nr_reclaimed += MIN_LRU_BATCH; ++ return true; ++ } ++ ++ if (cgroup_reclaim(sc)) ++ return false; ++ } else if (sc->nr_reclaimed - sc->last_reclaimed < sc->nr_to_reclaim) ++ return false; ++ ++ /* keep scanning at low priorities to ensure fairness */ ++ if (sc->priority > DEF_PRIORITY - 2) ++ return false; ++ ++ /* ++ * A minimum amount of work was done under global memory pressure. For ++ * kswapd, it may be overshooting. For direct reclaim, the target isn't ++ * met, and yet the allocation may still succeed, since kswapd may have ++ * caught up. In either case, it's better to stop now, and restart if ++ * necessary. ++ */ ++ for (i = 0; i <= sc->reclaim_idx; i++) { ++ unsigned long wmark; ++ struct zone *zone = lruvec_pgdat(lruvec)->node_zones + i; ++ ++ if (!managed_zone(zone)) ++ continue; ++ ++ wmark = current_is_kswapd() ? high_wmark_pages(zone) : low_wmark_pages(zone); ++ if (wmark > zone_page_state(zone, NR_FREE_PAGES)) ++ return false; ++ } ++ ++ sc->nr_reclaimed += MIN_LRU_BATCH; ++ ++ return true; ++} ++ + static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { + struct blk_plug plug; ++ bool need_aging = false; ++ bool need_swapping = false; + unsigned long scanned = 0; ++ unsigned long reclaimed = sc->nr_reclaimed; ++ DEFINE_MAX_SEQ(lruvec); + + lru_add_drain(); + +@@ -4738,21 +4818,28 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + else + swappiness = 0; + +- nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); ++ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness, &need_aging); + if (!nr_to_scan) +- break; ++ goto done; + +- delta = evict_pages(lruvec, sc, swappiness); ++ delta = evict_pages(lruvec, sc, swappiness, &need_swapping); + if (!delta) +- break; ++ goto done; + + scanned += delta; + if (scanned >= nr_to_scan) + break; + ++ if (should_abort_scan(lruvec, max_seq, sc, need_swapping)) ++ break; ++ + cond_resched(); + } + ++ /* see the comment in lru_gen_age_node() */ ++ if (sc->nr_reclaimed - reclaimed >= MIN_LRU_BATCH && !need_aging) ++ sc->memcgs_need_aging = false; ++done: + clear_mm_walk(); + + blk_finish_plug(&plug); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-09-mm-multigenerational-lru-Kconfig.patch b/target/linux/generic/backport-5.15/020-v6.1-09-mm-multigenerational-lru-Kconfig.patch deleted file mode 100644 index 4462549f99b..00000000000 --- a/target/linux/generic/backport-5.15/020-v6.1-09-mm-multigenerational-lru-Kconfig.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 3008095eb835d207dd7e5b60899aad17f32aa9f7 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Mon, 25 Jan 2021 21:47:24 -0700 -Subject: [PATCH 09/10] mm: multigenerational lru: Kconfig - -Add configuration options for the multigenerational lru. - -Signed-off-by: Yu Zhao -Tested-by: Konstantin Kharlamov -Change-Id: Ic74ea07f8fb5f56e6904a1b80c3c286bc2911635 ---- - mm/Kconfig | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 59 insertions(+) - ---- a/mm/Kconfig -+++ b/mm/Kconfig -@@ -899,4 +899,63 @@ config SECRETMEM - - source "mm/damon/Kconfig" - -+# the multigenerational lru { -+config LRU_GEN -+ bool "Multigenerational LRU" -+ depends on MMU -+ # the following options may leave not enough spare bits in page->flags -+ depends on !MAXSMP && (64BIT || !SPARSEMEM || SPARSEMEM_VMEMMAP) -+ help -+ A high performance LRU implementation to heavily overcommit workloads -+ that are not IO bound. See Documentation/vm/multigen_lru.rst for -+ details. -+ -+ Warning: do not enable this option unless you plan to use it because -+ it introduces a small per-process and per-memcg and per-node memory -+ overhead. -+ -+config LRU_GEN_ENABLED -+ bool "Turn on by default" -+ depends on LRU_GEN -+ help -+ The default value of /sys/kernel/mm/lru_gen/enabled is 0. This option -+ changes it to 1. -+ -+ Warning: the default value is the fast path. See -+ Documentation/static-keys.txt for details. -+ -+config LRU_GEN_STATS -+ bool "Full stats for debugging" -+ depends on LRU_GEN -+ help -+ This option keeps full stats for each generation, which can be read -+ from /sys/kernel/debug/lru_gen_full. -+ -+ Warning: do not enable this option unless you plan to use it because -+ it introduces an additional small per-process and per-memcg and -+ per-node memory overhead. -+ -+config NR_LRU_GENS -+ int "Max number of generations" -+ depends on LRU_GEN -+ range 4 31 -+ default 7 -+ help -+ This will use order_base_2(N+1) spare bits from page flags. -+ -+ Warning: do not use numbers larger than necessary because each -+ generation introduces a small per-node and per-memcg memory overhead. -+ -+config TIERS_PER_GEN -+ int "Number of tiers per generation" -+ depends on LRU_GEN -+ range 2 5 -+ default 4 -+ help -+ This will use N-2 spare bits from page flags. -+ -+ Larger values generally offer better protection to active pages under -+ heavy buffered I/O workloads. -+# } -+ - endmenu diff --git a/target/linux/generic/backport-5.15/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch b/target/linux/generic/backport-5.15/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch new file mode 100644 index 00000000000..0adb15f5e24 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch @@ -0,0 +1,513 @@ +From 640db3a029dca909af47157ca18f52b29d34a1b9 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:07 -0600 +Subject: [PATCH 10/29] mm: multi-gen LRU: kill switch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add /sys/kernel/mm/lru_gen/enabled as a kill switch. Components that +can be disabled include: + 0x0001: the multi-gen LRU core + 0x0002: walking page table, when arch_has_hw_pte_young() returns + true + 0x0004: clearing the accessed bit in non-leaf PMD entries, when + CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y + [yYnN]: apply to all the components above +E.g., + echo y >/sys/kernel/mm/lru_gen/enabled + cat /sys/kernel/mm/lru_gen/enabled + 0x0007 + echo 5 >/sys/kernel/mm/lru_gen/enabled + cat /sys/kernel/mm/lru_gen/enabled + 0x0005 + +NB: the page table walks happen on the scale of seconds under heavy memory +pressure, in which case the mmap_lock contention is a lesser concern, +compared with the LRU lock contention and the I/O congestion. So far the +only well-known case of the mmap_lock contention happens on Android, due +to Scudo [1] which allocates several thousand VMAs for merely a few +hundred MBs. The SPF and the Maple Tree also have provided their own +assessments [2][3]. However, if walking page tables does worsen the +mmap_lock contention, the kill switch can be used to disable it. In this +case the multi-gen LRU will suffer a minor performance degradation, as +shown previously. + +Clearing the accessed bit in non-leaf PMD entries can also be disabled, +since this behavior was not tested on x86 varieties other than Intel and +AMD. + +[1] https://source.android.com/devices/tech/debug/scudo +[2] https://lore.kernel.org/r/20220128131006.67712-1-michel@lespinasse.org/ +[3] https://lore.kernel.org/r/20220426150616.3937571-1-Liam.Howlett@oracle.com/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-11-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/cgroup.h | 15 ++- + include/linux/mm_inline.h | 15 ++- + include/linux/mmzone.h | 9 ++ + kernel/cgroup/cgroup-internal.h | 1 - + mm/Kconfig | 6 + + mm/vmscan.c | 228 +++++++++++++++++++++++++++++++- + 6 files changed, 265 insertions(+), 9 deletions(-) + +diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h +index 45cdb12243e3..f9a5d6a81101 100644 +--- a/include/linux/cgroup.h ++++ b/include/linux/cgroup.h +@@ -433,6 +433,18 @@ static inline void cgroup_put(struct cgroup *cgrp) + css_put(&cgrp->self); + } + ++extern struct mutex cgroup_mutex; ++ ++static inline void cgroup_lock(void) ++{ ++ mutex_lock(&cgroup_mutex); ++} ++ ++static inline void cgroup_unlock(void) ++{ ++ mutex_unlock(&cgroup_mutex); ++} ++ + /** + * task_css_set_check - obtain a task's css_set with extra access conditions + * @task: the task to obtain css_set for +@@ -447,7 +459,6 @@ static inline void cgroup_put(struct cgroup *cgrp) + * as locks used during the cgroup_subsys::attach() methods. + */ + #ifdef CONFIG_PROVE_RCU +-extern struct mutex cgroup_mutex; + extern spinlock_t css_set_lock; + #define task_css_set_check(task, __c) \ + rcu_dereference_check((task)->cgroups, \ +@@ -708,6 +719,8 @@ struct cgroup; + static inline u64 cgroup_id(const struct cgroup *cgrp) { return 1; } + static inline void css_get(struct cgroup_subsys_state *css) {} + static inline void css_put(struct cgroup_subsys_state *css) {} ++static inline void cgroup_lock(void) {} ++static inline void cgroup_unlock(void) {} + static inline int cgroup_attach_task_all(struct task_struct *from, + struct task_struct *t) { return 0; } + static inline int cgroupstats_build(struct cgroupstats *stats, +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index 58aabb1ba020..e095c1c24311 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -91,10 +91,21 @@ static __always_inline enum lru_list page_lru(struct page *page) + + #ifdef CONFIG_LRU_GEN + ++#ifdef CONFIG_LRU_GEN_ENABLED + static inline bool lru_gen_enabled(void) + { +- return true; ++ DECLARE_STATIC_KEY_TRUE(lru_gen_caps[NR_LRU_GEN_CAPS]); ++ ++ return static_branch_likely(&lru_gen_caps[LRU_GEN_CORE]); ++} ++#else ++static inline bool lru_gen_enabled(void) ++{ ++ DECLARE_STATIC_KEY_FALSE(lru_gen_caps[NR_LRU_GEN_CAPS]); ++ ++ return static_branch_unlikely(&lru_gen_caps[LRU_GEN_CORE]); + } ++#endif + + static inline bool lru_gen_in_fault(void) + { +@@ -207,7 +218,7 @@ static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bo + + VM_WARN_ON_ONCE_PAGE(gen != -1, page); + +- if (PageUnevictable(page)) ++ if (PageUnevictable(page) || !lrugen->enabled) + return false; + /* + * There are three common cases for this page: +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 659bab633bdf..edaf035503ed 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -364,6 +364,13 @@ enum { + LRU_GEN_FILE, + }; + ++enum { ++ LRU_GEN_CORE, ++ LRU_GEN_MM_WALK, ++ LRU_GEN_NONLEAF_YOUNG, ++ NR_LRU_GEN_CAPS ++}; ++ + #define MIN_LRU_BATCH BITS_PER_LONG + #define MAX_LRU_BATCH (MIN_LRU_BATCH * 64) + +@@ -405,6 +412,8 @@ struct lru_gen_struct { + /* can be modified without holding the LRU lock */ + atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; ++ /* whether the multi-gen LRU is enabled */ ++ bool enabled; + }; + + enum { +diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h +index d8fcc139ac05..28c32a01da7d 100644 +--- a/kernel/cgroup/cgroup-internal.h ++++ b/kernel/cgroup/cgroup-internal.h +@@ -165,7 +165,6 @@ struct cgroup_mgctx { + #define DEFINE_CGROUP_MGCTX(name) \ + struct cgroup_mgctx name = CGROUP_MGCTX_INIT(name) + +-extern struct mutex cgroup_mutex; + extern spinlock_t css_set_lock; + extern struct cgroup_subsys *cgroup_subsys[]; + extern struct list_head cgroup_roots; +diff --git a/mm/Kconfig b/mm/Kconfig +index 62433f3cd7ae..4a7d0af3c39b 100644 +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -906,6 +906,12 @@ config LRU_GEN + help + A high performance LRU implementation to overcommit memory. + ++config LRU_GEN_ENABLED ++ bool "Enable by default" ++ depends on LRU_GEN ++ help ++ This option enables the multi-gen LRU by default. ++ + config LRU_GEN_STATS + bool "Full stats for debugging" + depends on LRU_GEN +diff --git a/mm/vmscan.c b/mm/vmscan.c +index b6f6fc2585e1..be37d996bc92 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -52,6 +52,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -2841,6 +2842,14 @@ static bool can_age_anon_pages(struct pglist_data *pgdat, + + #ifdef CONFIG_LRU_GEN + ++#ifdef CONFIG_LRU_GEN_ENABLED ++DEFINE_STATIC_KEY_ARRAY_TRUE(lru_gen_caps, NR_LRU_GEN_CAPS); ++#define get_cap(cap) static_branch_likely(&lru_gen_caps[cap]) ++#else ++DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); ++#define get_cap(cap) static_branch_unlikely(&lru_gen_caps[cap]) ++#endif ++ + /****************************************************************************** + * shorthand helpers + ******************************************************************************/ +@@ -3717,7 +3726,8 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area + goto next; + + if (!pmd_trans_huge(pmd[i])) { +- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG)) ++ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && ++ get_cap(LRU_GEN_NONLEAF_YOUNG)) + pmdp_test_and_clear_young(vma, addr, pmd + i); + goto next; + } +@@ -3815,10 +3825,12 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, + walk->mm_stats[MM_NONLEAF_TOTAL]++; + + #ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +- if (!pmd_young(val)) +- continue; ++ if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { ++ if (!pmd_young(val)) ++ continue; + +- walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++ } + #endif + if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) + continue; +@@ -4080,7 +4092,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ +- if (!arch_has_hw_pte_young()) { ++ if (!(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } +@@ -4845,6 +4857,208 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + blk_finish_plug(&plug); + } + ++/****************************************************************************** ++ * state change ++ ******************************************************************************/ ++ ++static bool __maybe_unused state_is_valid(struct lruvec *lruvec) ++{ ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ if (lrugen->enabled) { ++ enum lru_list lru; ++ ++ for_each_evictable_lru(lru) { ++ if (!list_empty(&lruvec->lists[lru])) ++ return false; ++ } ++ } else { ++ int gen, type, zone; ++ ++ for_each_gen_type_zone(gen, type, zone) { ++ if (!list_empty(&lrugen->lists[gen][type][zone])) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static bool fill_evictable(struct lruvec *lruvec) ++{ ++ enum lru_list lru; ++ int remaining = MAX_LRU_BATCH; ++ ++ for_each_evictable_lru(lru) { ++ int type = is_file_lru(lru); ++ bool active = is_active_lru(lru); ++ struct list_head *head = &lruvec->lists[lru]; ++ ++ while (!list_empty(head)) { ++ bool success; ++ struct page *page = lru_to_page(head); ++ ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageActive(page) != active, page); ++ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); ++ VM_WARN_ON_ONCE_PAGE(page_lru_gen(page) != -1, page); ++ ++ del_page_from_lru_list(page, lruvec); ++ success = lru_gen_add_page(lruvec, page, false); ++ VM_WARN_ON_ONCE(!success); ++ ++ if (!--remaining) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static bool drain_evictable(struct lruvec *lruvec) ++{ ++ int gen, type, zone; ++ int remaining = MAX_LRU_BATCH; ++ ++ for_each_gen_type_zone(gen, type, zone) { ++ struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; ++ ++ while (!list_empty(head)) { ++ bool success; ++ struct page *page = lru_to_page(head); ++ ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); ++ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); ++ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); ++ ++ success = lru_gen_del_page(lruvec, page, false); ++ VM_WARN_ON_ONCE(!success); ++ add_page_to_lru_list(page, lruvec); ++ ++ if (!--remaining) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static void lru_gen_change_state(bool enabled) ++{ ++ static DEFINE_MUTEX(state_mutex); ++ ++ struct mem_cgroup *memcg; ++ ++ cgroup_lock(); ++ cpus_read_lock(); ++ get_online_mems(); ++ mutex_lock(&state_mutex); ++ ++ if (enabled == lru_gen_enabled()) ++ goto unlock; ++ ++ if (enabled) ++ static_branch_enable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); ++ else ++ static_branch_disable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); ++ ++ memcg = mem_cgroup_iter(NULL, NULL, NULL); ++ do { ++ int nid; ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ if (!lruvec) ++ continue; ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ ++ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); ++ VM_WARN_ON_ONCE(!state_is_valid(lruvec)); ++ ++ lruvec->lrugen.enabled = enabled; ++ ++ while (!(enabled ? fill_evictable(lruvec) : drain_evictable(lruvec))) { ++ spin_unlock_irq(&lruvec->lru_lock); ++ cond_resched(); ++ spin_lock_irq(&lruvec->lru_lock); ++ } ++ ++ spin_unlock_irq(&lruvec->lru_lock); ++ } ++ ++ cond_resched(); ++ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); ++unlock: ++ mutex_unlock(&state_mutex); ++ put_online_mems(); ++ cpus_read_unlock(); ++ cgroup_unlock(); ++} ++ ++/****************************************************************************** ++ * sysfs interface ++ ******************************************************************************/ ++ ++static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ unsigned int caps = 0; ++ ++ if (get_cap(LRU_GEN_CORE)) ++ caps |= BIT(LRU_GEN_CORE); ++ ++ if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) ++ caps |= BIT(LRU_GEN_MM_WALK); ++ ++ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) ++ caps |= BIT(LRU_GEN_NONLEAF_YOUNG); ++ ++ return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); ++} ++ ++static ssize_t store_enabled(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int i; ++ unsigned int caps; ++ ++ if (tolower(*buf) == 'n') ++ caps = 0; ++ else if (tolower(*buf) == 'y') ++ caps = -1; ++ else if (kstrtouint(buf, 0, &caps)) ++ return -EINVAL; ++ ++ for (i = 0; i < NR_LRU_GEN_CAPS; i++) { ++ bool enabled = caps & BIT(i); ++ ++ if (i == LRU_GEN_CORE) ++ lru_gen_change_state(enabled); ++ else if (enabled) ++ static_branch_enable(&lru_gen_caps[i]); ++ else ++ static_branch_disable(&lru_gen_caps[i]); ++ } ++ ++ return len; ++} ++ ++static struct kobj_attribute lru_gen_enabled_attr = __ATTR( ++ enabled, 0644, show_enabled, store_enabled ++); ++ ++static struct attribute *lru_gen_attrs[] = { ++ &lru_gen_enabled_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group lru_gen_attr_group = { ++ .name = "lru_gen", ++ .attrs = lru_gen_attrs, ++}; ++ + /****************************************************************************** + * initialization + ******************************************************************************/ +@@ -4855,6 +5069,7 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; ++ lrugen->enabled = lru_gen_enabled(); + + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); +@@ -4894,6 +5109,9 @@ static int __init init_lru_gen(void) + BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); + BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); + ++ if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) ++ pr_err("lru_gen: failed to create sysfs group\n"); ++ + return 0; + }; + late_initcall(init_lru_gen); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-10-mm-multigenerational-lru-documentation.patch b/target/linux/generic/backport-5.15/020-v6.1-10-mm-multigenerational-lru-documentation.patch deleted file mode 100644 index f4716fb68d6..00000000000 --- a/target/linux/generic/backport-5.15/020-v6.1-10-mm-multigenerational-lru-documentation.patch +++ /dev/null @@ -1,161 +0,0 @@ -From f59c618ed70a1e48accc4cad91a200966f2569c9 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Tue, 2 Feb 2021 01:27:45 -0700 -Subject: [PATCH 10/10] mm: multigenerational lru: documentation - -Add Documentation/vm/multigen_lru.rst. - -Signed-off-by: Yu Zhao -Tested-by: Konstantin Kharlamov -Change-Id: I1902178bcbb5adfa0a748c4d284a6456059bdd7e ---- - Documentation/vm/index.rst | 1 + - Documentation/vm/multigen_lru.rst | 132 ++++++++++++++++++++++++++++++ - 2 files changed, 133 insertions(+) - create mode 100644 Documentation/vm/multigen_lru.rst - ---- a/Documentation/vm/index.rst -+++ b/Documentation/vm/index.rst -@@ -17,6 +17,7 @@ various features of the Linux memory man - - swap_numa - zswap -+ multigen_lru - - Kernel developers MM documentation - ================================== ---- /dev/null -+++ b/Documentation/vm/multigen_lru.rst -@@ -0,0 +1,132 @@ -+.. SPDX-License-Identifier: GPL-2.0 -+ -+===================== -+Multigenerational LRU -+===================== -+ -+Quick Start -+=========== -+Build Configurations -+-------------------- -+:Required: Set ``CONFIG_LRU_GEN=y``. -+ -+:Optional: Set ``CONFIG_LRU_GEN_ENABLED=y`` to turn the feature on by -+ default. -+ -+Runtime Configurations -+---------------------- -+:Required: Write ``1`` to ``/sys/kernel/mm/lru_gen/enable`` if the -+ feature was not turned on by default. -+ -+:Optional: Write ``N`` to ``/sys/kernel/mm/lru_gen/min_ttl_ms`` to -+ protect the working set of ``N`` milliseconds. The OOM killer is -+ invoked if this working set cannot be kept in memory. -+ -+:Optional: Read ``/sys/kernel/debug/lru_gen`` to confirm the feature -+ is turned on. This file has the following output: -+ -+:: -+ -+ memcg memcg_id memcg_path -+ node node_id -+ min_gen birth_time anon_size file_size -+ ... -+ max_gen birth_time anon_size file_size -+ -+``min_gen`` is the oldest generation number and ``max_gen`` is the -+youngest generation number. ``birth_time`` is in milliseconds. -+``anon_size`` and ``file_size`` are in pages. -+ -+Phones/Laptops/Workstations -+--------------------------- -+No additional configurations required. -+ -+Servers/Data Centers -+-------------------- -+:To support more generations: Change ``CONFIG_NR_LRU_GENS`` to a -+ larger number. -+ -+:To support more tiers: Change ``CONFIG_TIERS_PER_GEN`` to a larger -+ number. -+ -+:To support full stats: Set ``CONFIG_LRU_GEN_STATS=y``. -+ -+:Working set estimation: Write ``+ memcg_id node_id max_gen -+ [swappiness] [use_bloom_filter]`` to ``/sys/kernel/debug/lru_gen`` to -+ invoke the aging, which scans PTEs for accessed pages and then -+ creates the next generation ``max_gen+1``. A swap file and a non-zero -+ ``swappiness``, which overrides ``vm.swappiness``, are required to -+ scan PTEs mapping anon pages. Set ``use_bloom_filter`` to 0 to -+ override the default behavior which only scans PTE tables found -+ populated. -+ -+:Proactive reclaim: Write ``- memcg_id node_id min_gen [swappiness] -+ [nr_to_reclaim]`` to ``/sys/kernel/debug/lru_gen`` to invoke the -+ eviction, which evicts generations less than or equal to ``min_gen``. -+ ``min_gen`` should be less than ``max_gen-1`` as ``max_gen`` and -+ ``max_gen-1`` are not fully aged and therefore cannot be evicted. -+ Use ``nr_to_reclaim`` to limit the number of pages to evict. Multiple -+ command lines are supported, so does concatenation with delimiters -+ ``,`` and ``;``. -+ -+Framework -+========= -+For each ``lruvec``, evictable pages are divided into multiple -+generations. The youngest generation number is stored in -+``lrugen->max_seq`` for both anon and file types as they are aged on -+an equal footing. The oldest generation numbers are stored in -+``lrugen->min_seq[]`` separately for anon and file types as clean -+file pages can be evicted regardless of swap and writeback -+constraints. These three variables are monotonically increasing. -+Generation numbers are truncated into -+``order_base_2(CONFIG_NR_LRU_GENS+1)`` bits in order to fit into -+``page->flags``. The sliding window technique is used to prevent -+truncated generation numbers from overlapping. Each truncated -+generation number is an index to an array of per-type and per-zone -+lists ``lrugen->lists``. -+ -+Each generation is divided into multiple tiers. Tiers represent -+different ranges of numbers of accesses from file descriptors only. -+Pages accessed ``N`` times via file descriptors belong to tier -+``order_base_2(N)``. Each generation contains at most -+``CONFIG_TIERS_PER_GEN`` tiers, and they require additional -+``CONFIG_TIERS_PER_GEN-2`` bits in ``page->flags``. In contrast to -+moving between generations which requires list operations, moving -+between tiers only involves operations on ``page->flags`` and -+therefore has a negligible cost. A feedback loop modeled after the PID -+controller monitors refaulted % across all tiers and decides when to -+protect pages from which tiers. -+ -+The framework comprises two conceptually independent components: the -+aging and the eviction, which can be invoked separately from user -+space for the purpose of working set estimation and proactive reclaim. -+ -+Aging -+----- -+The aging produces young generations. Given an ``lruvec``, the aging -+traverses ``lruvec_memcg()->mm_list`` and calls ``walk_page_range()`` -+to scan PTEs for accessed pages (a ``mm_struct`` list is maintained -+for each ``memcg``). Upon finding one, the aging updates its -+generation number to ``max_seq`` (modulo ``CONFIG_NR_LRU_GENS``). -+After each round of traversal, the aging increments ``max_seq``. The -+aging is due when ``min_seq[]`` reaches ``max_seq-1``. -+ -+Eviction -+-------- -+The eviction consumes old generations. Given an ``lruvec``, the -+eviction scans pages on the per-zone lists indexed by anon and file -+``min_seq[]`` (modulo ``CONFIG_NR_LRU_GENS``). It first tries to -+select a type based on the values of ``min_seq[]``. If they are -+equal, it selects the type that has a lower refaulted %. The eviction -+sorts a page according to its updated generation number if the aging -+has found this page accessed. It also moves a page to the next -+generation if this page is from an upper tier that has a higher -+refaulted % than the base tier. The eviction increments ``min_seq[]`` -+of a selected type when it finds all the per-zone lists indexed by -+``min_seq[]`` of this selected type are empty. -+ -+To-do List -+========== -+KVM Optimization -+---------------- -+Support shadow page table walk. diff --git a/target/linux/generic/backport-5.15/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch b/target/linux/generic/backport-5.15/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch new file mode 100644 index 00000000000..5b1ed03ca92 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch @@ -0,0 +1,233 @@ +From 73d1ff551760f0c79c47ab70faa4c2ca91413f5c Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:08 -0600 +Subject: [PATCH 11/29] mm: multi-gen LRU: thrashing prevention +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add /sys/kernel/mm/lru_gen/min_ttl_ms for thrashing prevention, as +requested by many desktop users [1]. + +When set to value N, it prevents the working set of N milliseconds from +getting evicted. The OOM killer is triggered if this working set cannot +be kept in memory. Based on the average human detectable lag (~100ms), +N=1000 usually eliminates intolerable lags due to thrashing. Larger +values like N=3000 make lags less noticeable at the risk of premature OOM +kills. + +Compared with the size-based approach [2], this time-based approach +has the following advantages: + +1. It is easier to configure because it is agnostic to applications + and memory sizes. +2. It is more reliable because it is directly wired to the OOM killer. + +[1] https://lore.kernel.org/r/Ydza%2FzXKY9ATRoh6@google.com/ +[2] https://lore.kernel.org/r/20101028191523.GA14972@google.com/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-12-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/mmzone.h | 2 ++ + mm/vmscan.c | 74 ++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 73 insertions(+), 3 deletions(-) + +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index edaf035503ed..6b85ba1f4e18 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -399,6 +399,8 @@ struct lru_gen_struct { + unsigned long max_seq; + /* the eviction increments the oldest generation numbers */ + unsigned long min_seq[ANON_AND_FILE]; ++ /* the birth time of each generation in jiffies */ ++ unsigned long timestamps[MAX_NR_GENS]; + /* the multi-gen LRU lists, lazily sorted on eviction */ + struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the multi-gen LRU sizes, eventually consistent */ +diff --git a/mm/vmscan.c b/mm/vmscan.c +index be37d996bc92..642ee7bef61d 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4064,6 +4064,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap) + for (type = 0; type < ANON_AND_FILE; type++) + reset_ctrl_pos(lruvec, type, false); + ++ WRITE_ONCE(lrugen->timestamps[next], jiffies); + /* make sure preceding modifications appear */ + smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); + +@@ -4193,7 +4194,7 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig + return false; + } + +-static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, unsigned long min_ttl) + { + bool need_aging; + unsigned long nr_to_scan; +@@ -4207,16 +4208,36 @@ static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) + mem_cgroup_calculate_protection(NULL, memcg); + + if (mem_cgroup_below_min(memcg)) +- return; ++ return false; + + need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); ++ ++ if (min_ttl) { ++ int gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); ++ unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); ++ ++ if (time_is_after_jiffies(birth + min_ttl)) ++ return false; ++ ++ /* the size is likely too small to be helpful */ ++ if (!nr_to_scan && sc->priority != DEF_PRIORITY) ++ return false; ++ } ++ + if (need_aging) + try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); ++ ++ return true; + } + ++/* to protect the working set of the last N jiffies */ ++static unsigned long lru_gen_min_ttl __read_mostly; ++ + static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + { + struct mem_cgroup *memcg; ++ bool success = false; ++ unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); + + VM_WARN_ON_ONCE(!current_is_kswapd()); + +@@ -4239,12 +4260,32 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + +- age_lruvec(lruvec, sc); ++ if (age_lruvec(lruvec, sc, min_ttl)) ++ success = true; + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + + clear_mm_walk(); ++ ++ /* check the order to exclude compaction-induced reclaim */ ++ if (success || !min_ttl || sc->order) ++ return; ++ ++ /* ++ * The main goal is to OOM kill if every generation from all memcgs is ++ * younger than min_ttl. However, another possibility is all memcgs are ++ * either below min or empty. ++ */ ++ if (mutex_trylock(&oom_lock)) { ++ struct oom_control oc = { ++ .gfp_mask = sc->gfp_mask, ++ }; ++ ++ out_of_memory(&oc); ++ ++ mutex_unlock(&oom_lock); ++ } + } + + /* +@@ -5002,6 +5043,28 @@ static void lru_gen_change_state(bool enabled) + * sysfs interface + ******************************************************************************/ + ++static ssize_t show_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%u\n", jiffies_to_msecs(READ_ONCE(lru_gen_min_ttl))); ++} ++ ++static ssize_t store_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t len) ++{ ++ unsigned int msecs; ++ ++ if (kstrtouint(buf, 0, &msecs)) ++ return -EINVAL; ++ ++ WRITE_ONCE(lru_gen_min_ttl, msecs_to_jiffies(msecs)); ++ ++ return len; ++} ++ ++static struct kobj_attribute lru_gen_min_ttl_attr = __ATTR( ++ min_ttl_ms, 0644, show_min_ttl, store_min_ttl ++); ++ + static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { + unsigned int caps = 0; +@@ -5050,6 +5113,7 @@ static struct kobj_attribute lru_gen_enabled_attr = __ATTR( + ); + + static struct attribute *lru_gen_attrs[] = { ++ &lru_gen_min_ttl_attr.attr, + &lru_gen_enabled_attr.attr, + NULL + }; +@@ -5065,12 +5129,16 @@ static struct attribute_group lru_gen_attr_group = { + + void lru_gen_init_lruvec(struct lruvec *lruvec) + { ++ int i; + int gen, type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; + lrugen->enabled = lru_gen_enabled(); + ++ for (i = 0; i <= MIN_NR_GENS + 1; i++) ++ lrugen->timestamps[i] = jiffies; ++ + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); + +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch b/target/linux/generic/backport-5.15/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch new file mode 100644 index 00000000000..ae9d76faa45 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch @@ -0,0 +1,586 @@ +From 530716d008ca26315f246cd70dc1cefc636beaa4 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:09 -0600 +Subject: [PATCH 12/29] mm: multi-gen LRU: debugfs interface +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add /sys/kernel/debug/lru_gen for working set estimation and proactive +reclaim. These techniques are commonly used to optimize job scheduling +(bin packing) in data centers [1][2]. + +Compared with the page table-based approach and the PFN-based +approach, this lruvec-based approach has the following advantages: +1. It offers better choices because it is aware of memcgs, NUMA nodes, + shared mappings and unmapped page cache. +2. It is more scalable because it is O(nr_hot_pages), whereas the + PFN-based approach is O(nr_total_pages). + +Add /sys/kernel/debug/lru_gen_full for debugging. + +[1] https://dl.acm.org/doi/10.1145/3297858.3304053 +[2] https://dl.acm.org/doi/10.1145/3503222.3507731 + +Link: https://lkml.kernel.org/r/20220918080010.2920238-13-yuzhao@google.com +Signed-off-by: Yu Zhao +Reviewed-by: Qi Zheng +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/nodemask.h | 1 + + mm/vmscan.c | 411 ++++++++++++++++++++++++++++++++++++++- + 2 files changed, 402 insertions(+), 10 deletions(-) + +diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h +index 0f233b76c9ce..292ec0ce0d63 100644 +--- a/include/linux/nodemask.h ++++ b/include/linux/nodemask.h +@@ -485,6 +485,7 @@ static inline int num_node_state(enum node_states state) + #define first_online_node 0 + #define first_memory_node 0 + #define next_online_node(nid) (MAX_NUMNODES) ++#define next_memory_node(nid) (MAX_NUMNODES) + #define nr_node_ids 1U + #define nr_online_nodes 1U + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 642ee7bef61d..b74b334488d8 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -53,6 +53,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -3968,12 +3969,40 @@ static void clear_mm_walk(void) + kfree(walk); + } + +-static void inc_min_seq(struct lruvec *lruvec, int type) ++static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) + { ++ int zone; ++ int remaining = MAX_LRU_BATCH; + struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); ++ ++ if (type == LRU_GEN_ANON && !can_swap) ++ goto done; ++ ++ /* prevent cold/hot inversion if force_scan is true */ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) { ++ struct list_head *head = &lrugen->lists[old_gen][type][zone]; ++ ++ while (!list_empty(head)) { ++ struct page *page = lru_to_page(head); ++ ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); ++ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); ++ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); + ++ new_gen = page_inc_gen(lruvec, page, false); ++ list_move_tail(&page->lru, &lrugen->lists[new_gen][type][zone]); ++ ++ if (!--remaining) ++ return false; ++ } ++ } ++done: + reset_ctrl_pos(lruvec, type, true); + WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); ++ ++ return true; + } + + static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +@@ -4019,7 +4048,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) + return success; + } + +-static void inc_max_seq(struct lruvec *lruvec, bool can_swap) ++static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan) + { + int prev, next; + int type, zone; +@@ -4033,9 +4062,13 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap) + if (get_nr_gens(lruvec, type) != MAX_NR_GENS) + continue; + +- VM_WARN_ON_ONCE(type == LRU_GEN_FILE || can_swap); ++ VM_WARN_ON_ONCE(!force_scan && (type == LRU_GEN_FILE || can_swap)); + +- inc_min_seq(lruvec, type); ++ while (!inc_min_seq(lruvec, type, can_swap)) { ++ spin_unlock_irq(&lruvec->lru_lock); ++ cond_resched(); ++ spin_lock_irq(&lruvec->lru_lock); ++ } + } + + /* +@@ -4072,7 +4105,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap) + } + + static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +- struct scan_control *sc, bool can_swap) ++ struct scan_control *sc, bool can_swap, bool force_scan) + { + bool success; + struct lru_gen_mm_walk *walk; +@@ -4093,7 +4126,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ +- if (!(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { ++ if (!force_scan && !(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } +@@ -4107,7 +4140,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + walk->lruvec = lruvec; + walk->max_seq = max_seq; + walk->can_swap = can_swap; +- walk->force_scan = false; ++ walk->force_scan = force_scan; + + do { + success = iterate_mm_list(lruvec, walk, &mm); +@@ -4127,7 +4160,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + + VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); + +- inc_max_seq(lruvec, can_swap); ++ inc_max_seq(lruvec, can_swap, force_scan); + /* either this sees any waiters or they will see updated max_seq */ + if (wq_has_sleeper(&lruvec->mm_state.wait)) + wake_up_all(&lruvec->mm_state.wait); +@@ -4225,7 +4258,7 @@ static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, unsigned + } + + if (need_aging) +- try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); ++ try_to_inc_max_seq(lruvec, max_seq, sc, swappiness, false); + + return true; + } +@@ -4784,7 +4817,7 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * + if (current_is_kswapd()) + return 0; + +- if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap)) ++ if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false)) + return nr_to_scan; + done: + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; +@@ -5123,6 +5156,361 @@ static struct attribute_group lru_gen_attr_group = { + .attrs = lru_gen_attrs, + }; + ++/****************************************************************************** ++ * debugfs interface ++ ******************************************************************************/ ++ ++static void *lru_gen_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct mem_cgroup *memcg; ++ loff_t nr_to_skip = *pos; ++ ++ m->private = kvmalloc(PATH_MAX, GFP_KERNEL); ++ if (!m->private) ++ return ERR_PTR(-ENOMEM); ++ ++ memcg = mem_cgroup_iter(NULL, NULL, NULL); ++ do { ++ int nid; ++ ++ for_each_node_state(nid, N_MEMORY) { ++ if (!nr_to_skip--) ++ return get_lruvec(memcg, nid); ++ } ++ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); ++ ++ return NULL; ++} ++ ++static void lru_gen_seq_stop(struct seq_file *m, void *v) ++{ ++ if (!IS_ERR_OR_NULL(v)) ++ mem_cgroup_iter_break(NULL, lruvec_memcg(v)); ++ ++ kvfree(m->private); ++ m->private = NULL; ++} ++ ++static void *lru_gen_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ int nid = lruvec_pgdat(v)->node_id; ++ struct mem_cgroup *memcg = lruvec_memcg(v); ++ ++ ++*pos; ++ ++ nid = next_memory_node(nid); ++ if (nid == MAX_NUMNODES) { ++ memcg = mem_cgroup_iter(NULL, memcg, NULL); ++ if (!memcg) ++ return NULL; ++ ++ nid = first_memory_node; ++ } ++ ++ return get_lruvec(memcg, nid); ++} ++ ++static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, ++ unsigned long max_seq, unsigned long *min_seq, ++ unsigned long seq) ++{ ++ int i; ++ int type, tier; ++ int hist = lru_hist_from_seq(seq); ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ for (tier = 0; tier < MAX_NR_TIERS; tier++) { ++ seq_printf(m, " %10d", tier); ++ for (type = 0; type < ANON_AND_FILE; type++) { ++ const char *s = " "; ++ unsigned long n[3] = {}; ++ ++ if (seq == max_seq) { ++ s = "RT "; ++ n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]); ++ n[1] = READ_ONCE(lrugen->avg_total[type][tier]); ++ } else if (seq == min_seq[type] || NR_HIST_GENS > 1) { ++ s = "rep"; ++ n[0] = atomic_long_read(&lrugen->refaulted[hist][type][tier]); ++ n[1] = atomic_long_read(&lrugen->evicted[hist][type][tier]); ++ if (tier) ++ n[2] = READ_ONCE(lrugen->protected[hist][type][tier - 1]); ++ } ++ ++ for (i = 0; i < 3; i++) ++ seq_printf(m, " %10lu%c", n[i], s[i]); ++ } ++ seq_putc(m, '\n'); ++ } ++ ++ seq_puts(m, " "); ++ for (i = 0; i < NR_MM_STATS; i++) { ++ const char *s = " "; ++ unsigned long n = 0; ++ ++ if (seq == max_seq && NR_HIST_GENS == 1) { ++ s = "LOYNFA"; ++ n = READ_ONCE(lruvec->mm_state.stats[hist][i]); ++ } else if (seq != max_seq && NR_HIST_GENS > 1) { ++ s = "loynfa"; ++ n = READ_ONCE(lruvec->mm_state.stats[hist][i]); ++ } ++ ++ seq_printf(m, " %10lu%c", n, s[i]); ++ } ++ seq_putc(m, '\n'); ++} ++ ++static int lru_gen_seq_show(struct seq_file *m, void *v) ++{ ++ unsigned long seq; ++ bool full = !debugfs_real_fops(m->file)->write; ++ struct lruvec *lruvec = v; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ int nid = lruvec_pgdat(lruvec)->node_id; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MAX_SEQ(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ if (nid == first_memory_node) { ++ const char *path = memcg ? m->private : ""; ++ ++#ifdef CONFIG_MEMCG ++ if (memcg) ++ cgroup_path(memcg->css.cgroup, m->private, PATH_MAX); ++#endif ++ seq_printf(m, "memcg %5hu %s\n", mem_cgroup_id(memcg), path); ++ } ++ ++ seq_printf(m, " node %5d\n", nid); ++ ++ if (!full) ++ seq = min_seq[LRU_GEN_ANON]; ++ else if (max_seq >= MAX_NR_GENS) ++ seq = max_seq - MAX_NR_GENS + 1; ++ else ++ seq = 0; ++ ++ for (; seq <= max_seq; seq++) { ++ int type, zone; ++ int gen = lru_gen_from_seq(seq); ++ unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); ++ ++ seq_printf(m, " %10lu %10u", seq, jiffies_to_msecs(jiffies - birth)); ++ ++ for (type = 0; type < ANON_AND_FILE; type++) { ++ unsigned long size = 0; ++ char mark = full && seq < min_seq[type] ? 'x' : ' '; ++ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); ++ ++ seq_printf(m, " %10lu%c", size, mark); ++ } ++ ++ seq_putc(m, '\n'); ++ ++ if (full) ++ lru_gen_seq_show_full(m, lruvec, max_seq, min_seq, seq); ++ } ++ ++ return 0; ++} ++ ++static const struct seq_operations lru_gen_seq_ops = { ++ .start = lru_gen_seq_start, ++ .stop = lru_gen_seq_stop, ++ .next = lru_gen_seq_next, ++ .show = lru_gen_seq_show, ++}; ++ ++static int run_aging(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, ++ bool can_swap, bool force_scan) ++{ ++ DEFINE_MAX_SEQ(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ if (seq < max_seq) ++ return 0; ++ ++ if (seq > max_seq) ++ return -EINVAL; ++ ++ if (!force_scan && min_seq[!can_swap] + MAX_NR_GENS - 1 <= max_seq) ++ return -ERANGE; ++ ++ try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, force_scan); ++ ++ return 0; ++} ++ ++static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, ++ int swappiness, unsigned long nr_to_reclaim) ++{ ++ DEFINE_MAX_SEQ(lruvec); ++ ++ if (seq + MIN_NR_GENS > max_seq) ++ return -EINVAL; ++ ++ sc->nr_reclaimed = 0; ++ ++ while (!signal_pending(current)) { ++ DEFINE_MIN_SEQ(lruvec); ++ ++ if (seq < min_seq[!swappiness]) ++ return 0; ++ ++ if (sc->nr_reclaimed >= nr_to_reclaim) ++ return 0; ++ ++ if (!evict_pages(lruvec, sc, swappiness, NULL)) ++ return 0; ++ ++ cond_resched(); ++ } ++ ++ return -EINTR; ++} ++ ++static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, ++ struct scan_control *sc, int swappiness, unsigned long opt) ++{ ++ struct lruvec *lruvec; ++ int err = -EINVAL; ++ struct mem_cgroup *memcg = NULL; ++ ++ if (nid < 0 || nid >= MAX_NUMNODES || !node_state(nid, N_MEMORY)) ++ return -EINVAL; ++ ++ if (!mem_cgroup_disabled()) { ++ rcu_read_lock(); ++ memcg = mem_cgroup_from_id(memcg_id); ++#ifdef CONFIG_MEMCG ++ if (memcg && !css_tryget(&memcg->css)) ++ memcg = NULL; ++#endif ++ rcu_read_unlock(); ++ ++ if (!memcg) ++ return -EINVAL; ++ } ++ ++ if (memcg_id != mem_cgroup_id(memcg)) ++ goto done; ++ ++ lruvec = get_lruvec(memcg, nid); ++ ++ if (swappiness < 0) ++ swappiness = get_swappiness(lruvec, sc); ++ else if (swappiness > 200) ++ goto done; ++ ++ switch (cmd) { ++ case '+': ++ err = run_aging(lruvec, seq, sc, swappiness, opt); ++ break; ++ case '-': ++ err = run_eviction(lruvec, seq, sc, swappiness, opt); ++ break; ++ } ++done: ++ mem_cgroup_put(memcg); ++ ++ return err; ++} ++ ++static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, ++ size_t len, loff_t *pos) ++{ ++ void *buf; ++ char *cur, *next; ++ unsigned int flags; ++ struct blk_plug plug; ++ int err = -EINVAL; ++ struct scan_control sc = { ++ .may_writepage = true, ++ .may_unmap = true, ++ .may_swap = true, ++ .reclaim_idx = MAX_NR_ZONES - 1, ++ .gfp_mask = GFP_KERNEL, ++ }; ++ ++ buf = kvmalloc(len + 1, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ if (copy_from_user(buf, src, len)) { ++ kvfree(buf); ++ return -EFAULT; ++ } ++ ++ set_task_reclaim_state(current, &sc.reclaim_state); ++ flags = memalloc_noreclaim_save(); ++ blk_start_plug(&plug); ++ if (!set_mm_walk(NULL)) { ++ err = -ENOMEM; ++ goto done; ++ } ++ ++ next = buf; ++ next[len] = '\0'; ++ ++ while ((cur = strsep(&next, ",;\n"))) { ++ int n; ++ int end; ++ char cmd; ++ unsigned int memcg_id; ++ unsigned int nid; ++ unsigned long seq; ++ unsigned int swappiness = -1; ++ unsigned long opt = -1; ++ ++ cur = skip_spaces(cur); ++ if (!*cur) ++ continue; ++ ++ n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid, ++ &seq, &end, &swappiness, &end, &opt, &end); ++ if (n < 4 || cur[end]) { ++ err = -EINVAL; ++ break; ++ } ++ ++ err = run_cmd(cmd, memcg_id, nid, seq, &sc, swappiness, opt); ++ if (err) ++ break; ++ } ++done: ++ clear_mm_walk(); ++ blk_finish_plug(&plug); ++ memalloc_noreclaim_restore(flags); ++ set_task_reclaim_state(current, NULL); ++ ++ kvfree(buf); ++ ++ return err ? : len; ++} ++ ++static int lru_gen_seq_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &lru_gen_seq_ops); ++} ++ ++static const struct file_operations lru_gen_rw_fops = { ++ .open = lru_gen_seq_open, ++ .read = seq_read, ++ .write = lru_gen_seq_write, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++static const struct file_operations lru_gen_ro_fops = { ++ .open = lru_gen_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ + /****************************************************************************** + * initialization + ******************************************************************************/ +@@ -5180,6 +5568,9 @@ static int __init init_lru_gen(void) + if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) + pr_err("lru_gen: failed to create sysfs group\n"); + ++ debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_rw_fops); ++ debugfs_create_file("lru_gen_full", 0444, NULL, NULL, &lru_gen_ro_fops); ++ + return 0; + }; + late_initcall(init_lru_gen); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/021-v6.1-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch b/target/linux/generic/backport-5.15/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch similarity index 67% rename from target/linux/generic/backport-5.15/021-v6.1-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch rename to target/linux/generic/backport-5.15/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch index 6cc4b3368f3..a2318499e79 100644 --- a/target/linux/generic/backport-5.15/021-v6.1-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch @@ -1,7 +1,7 @@ -From 14aa8b2d5c2ebead01b542f62d68029023054774 Mon Sep 17 00:00:00 2001 +From 92d430e8955c976eacb7cc91d7ff849c0dd009af Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 28 Sep 2022 13:36:58 -0600 -Subject: [PATCH 1/1] mm/mglru: don't sync disk for each aging cycle +Subject: [PATCH 13/29] mm/mglru: don't sync disk for each aging cycle wakeup_flusher_threads() was added under the assumption that if a system runs out of clean cold pages, it might want to write back dirty pages more @@ -19,14 +19,19 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 2 -- 1 file changed, 2 deletions(-) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index b74b334488d8..1c0875e6514a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4007,8 +4007,6 @@ static bool try_to_inc_max_seq(struct lr - if (wq_has_sleeper(&lruvec->mm_walk.wait)) - wake_up_all(&lruvec->mm_walk.wait); +@@ -4165,8 +4165,6 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + if (wq_has_sleeper(&lruvec->mm_state.wait)) + wake_up_all(&lruvec->mm_state.wait); - wakeup_flusher_threads(WB_REASON_VMSCAN); - return true; } +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch b/target/linux/generic/backport-5.15/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch new file mode 100644 index 00000000000..ffdebafa2ce --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch @@ -0,0 +1,129 @@ +From 6f315879ad750391a0b1fab8c9170bc054a5f5d7 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Tue, 15 Nov 2022 18:38:07 -0700 +Subject: [PATCH 14/29] mm: multi-gen LRU: retry pages written back while + isolated + +The page reclaim isolates a batch of pages from the tail of one of the +LRU lists and works on those pages one by one. For a suitable +swap-backed page, if the swap device is async, it queues that page for +writeback. After the page reclaim finishes an entire batch, it puts back +the pages it queued for writeback to the head of the original LRU list. + +In the meantime, the page writeback flushes the queued pages also by +batches. Its batching logic is independent from that of the page reclaim. +For each of the pages it writes back, the page writeback calls +rotate_reclaimable_page() which tries to rotate a page to the tail. + +rotate_reclaimable_page() only works for a page after the page reclaim +has put it back. If an async swap device is fast enough, the page +writeback can finish with that page while the page reclaim is still +working on the rest of the batch containing it. In this case, that page +will remain at the head and the page reclaim will not retry it before +reaching there. + +This patch adds a retry to evict_pages(). After evict_pages() has +finished an entire batch and before it puts back pages it cannot free +immediately, it retries those that may have missed the rotation. + +Before this patch, ~60% of pages swapped to an Intel Optane missed +rotate_reclaimable_page(). After this patch, ~99% of missed pages were +reclaimed upon retry. + +This problem affects relatively slow async swap devices like Samsung 980 +Pro much less and does not affect sync swap devices like zram or zswap at +all. + +Link: https://lkml.kernel.org/r/20221116013808.3995280-1-yuzhao@google.com +Fixes: ac35a4902374 ("mm: multi-gen LRU: minimal implementation") +Signed-off-by: Yu Zhao +Cc: "Yin, Fengwei" +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 48 +++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 37 insertions(+), 11 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 1c0875e6514a..27bc525380f9 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4723,10 +4723,13 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + int scanned; + int reclaimed; + LIST_HEAD(list); ++ LIST_HEAD(clean); + struct page *page; ++ struct page *next; + enum vm_event_item item; + struct reclaim_stat stat; + struct lru_gen_mm_walk *walk; ++ bool skip_retry = false; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + +@@ -4743,20 +4746,37 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + + if (list_empty(&list)) + return scanned; +- ++retry: + reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); ++ sc->nr_reclaimed += reclaimed; + +- list_for_each_entry(page, &list, lru) { +- /* restore LRU_REFS_FLAGS cleared by isolate_page() */ +- if (PageWorkingset(page)) +- SetPageReferenced(page); ++ list_for_each_entry_safe_reverse(page, next, &list, lru) { ++ if (!page_evictable(page)) { ++ list_del(&page->lru); ++ putback_lru_page(page); ++ continue; ++ } + +- /* don't add rejected pages to the oldest generation */ + if (PageReclaim(page) && +- (PageDirty(page) || PageWriteback(page))) +- ClearPageActive(page); +- else +- SetPageActive(page); ++ (PageDirty(page) || PageWriteback(page))) { ++ /* restore LRU_REFS_FLAGS cleared by isolate_page() */ ++ if (PageWorkingset(page)) ++ SetPageReferenced(page); ++ continue; ++ } ++ ++ if (skip_retry || PageActive(page) || PageReferenced(page) || ++ page_mapped(page) || PageLocked(page) || ++ PageDirty(page) || PageWriteback(page)) { ++ /* don't add rejected pages to the oldest generation */ ++ set_mask_bits(&page->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, ++ BIT(PG_active)); ++ continue; ++ } ++ ++ /* retry pages that may have missed rotate_reclaimable_page() */ ++ list_move(&page->lru, &clean); ++ sc->nr_scanned -= thp_nr_pages(page); + } + + spin_lock_irq(&lruvec->lru_lock); +@@ -4778,7 +4798,13 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + mem_cgroup_uncharge_list(&list); + free_unref_page_list(&list); + +- sc->nr_reclaimed += reclaimed; ++ INIT_LIST_HEAD(&list); ++ list_splice_init(&clean, &list); ++ ++ if (!list_empty(&list)) { ++ skip_retry = true; ++ goto retry; ++ } + + if (need_swapping && type == LRU_GEN_ANON) + *need_swapping = true; +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch b/target/linux/generic/backport-5.15/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch new file mode 100644 index 00000000000..7dc296b5b35 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch @@ -0,0 +1,54 @@ +From 255bb0ac393f1c2818cd75af45a9226300ab3daf Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Wed, 26 Oct 2022 15:48:30 +0200 +Subject: [PATCH 15/29] mm: multi-gen LRU: move lru_gen_add_mm() out of IRQ-off + region + +lru_gen_add_mm() has been added within an IRQ-off region in the commit +mentioned below. The other invocations of lru_gen_add_mm() are not within +an IRQ-off region. + +The invocation within IRQ-off region is problematic on PREEMPT_RT because +the function is using a spin_lock_t which must not be used within +IRQ-disabled regions. + +The other invocations of lru_gen_add_mm() occur while +task_struct::alloc_lock is acquired. Move lru_gen_add_mm() after +interrupts are enabled and before task_unlock(). + +Link: https://lkml.kernel.org/r/20221026134830.711887-1-bigeasy@linutronix.de +Fixes: bd74fdaea1460 ("mm: multi-gen LRU: support page table walks") +Signed-off-by: Sebastian Andrzej Siewior +Acked-by: Yu Zhao +Cc: Al Viro +Cc: "Eric W . Biederman" +Cc: Kees Cook +Cc: Thomas Gleixner +Signed-off-by: Andrew Morton +--- + fs/exec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/exec.c b/fs/exec.c +index 1afa15a07d26..718c58947be1 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1013,7 +1013,6 @@ static int exec_mmap(struct mm_struct *mm) + active_mm = tsk->active_mm; + tsk->active_mm = mm; + tsk->mm = mm; +- lru_gen_add_mm(mm); + /* + * This prevents preemption while active_mm is being loaded and + * it and mm are being updated, which could cause problems for +@@ -1028,6 +1027,7 @@ static int exec_mmap(struct mm_struct *mm) + local_irq_enable(); + tsk->mm->vmacache_seqnum = 0; + vmacache_flush(tsk); ++ lru_gen_add_mm(mm); + task_unlock(tsk); + lru_gen_use_mm(mm); + if (old_mm) { +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch b/target/linux/generic/backport-5.15/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch new file mode 100644 index 00000000000..4e11e821153 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch @@ -0,0 +1,111 @@ +From c5ec455ebd2b488d91de9d8915a0c8036a2a04dd Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Wed, 30 Nov 2022 14:49:41 -0800 +Subject: [PATCH 17/29] mm: add dummy pmd_young() for architectures not having + it + +In order to avoid #ifdeffery add a dummy pmd_young() implementation as a +fallback. This is required for the later patch "mm: introduce +arch_has_hw_nonleaf_pmd_young()". + +Link: https://lkml.kernel.org/r/fd3ac3cd-7349-6bbd-890a-71a9454ca0b3@suse.com +Signed-off-by: Juergen Gross +Acked-by: Yu Zhao +Cc: Borislav Petkov +Cc: Dave Hansen +Cc: Geert Uytterhoeven +Cc: "H. Peter Anvin" +Cc: Ingo Molnar +Cc: Sander Eikelenboom +Cc: Thomas Gleixner +Signed-off-by: Andrew Morton +--- + arch/mips/include/asm/pgtable.h | 1 + + arch/riscv/include/asm/pgtable.h | 1 + + arch/s390/include/asm/pgtable.h | 1 + + arch/sparc/include/asm/pgtable_64.h | 1 + + arch/x86/include/asm/pgtable.h | 1 + + include/linux/pgtable.h | 7 +++++++ + 6 files changed, 12 insertions(+) + +diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h +index 804889b70965..89ab8b4cf971 100644 +--- a/arch/mips/include/asm/pgtable.h ++++ b/arch/mips/include/asm/pgtable.h +@@ -632,6 +632,7 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd) + return pmd; + } + ++#define pmd_young pmd_young + static inline int pmd_young(pmd_t pmd) + { + return !!(pmd_val(pmd) & _PAGE_ACCESSED); +diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h +index 39b550310ec6..4a64e03dcdd4 100644 +--- a/arch/riscv/include/asm/pgtable.h ++++ b/arch/riscv/include/asm/pgtable.h +@@ -531,6 +531,7 @@ static inline int pmd_dirty(pmd_t pmd) + return pte_dirty(pmd_pte(pmd)); + } + ++#define pmd_young pmd_young + static inline int pmd_young(pmd_t pmd) + { + return pte_young(pmd_pte(pmd)); +diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h +index b61426c9ef17..55ff4f22da2d 100644 +--- a/arch/s390/include/asm/pgtable.h ++++ b/arch/s390/include/asm/pgtable.h +@@ -748,6 +748,7 @@ static inline int pmd_dirty(pmd_t pmd) + return (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) != 0; + } + ++#define pmd_young pmd_young + static inline int pmd_young(pmd_t pmd) + { + return (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) != 0; +diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h +index 4679e45c8348..bfd10179c137 100644 +--- a/arch/sparc/include/asm/pgtable_64.h ++++ b/arch/sparc/include/asm/pgtable_64.h +@@ -712,6 +712,7 @@ static inline unsigned long pmd_dirty(pmd_t pmd) + return pte_dirty(pte); + } + ++#define pmd_young pmd_young + static inline unsigned long pmd_young(pmd_t pmd) + { + pte_t pte = __pte(pmd_val(pmd)); +diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h +index 01a1763123ff..c4b64ee357fd 100644 +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -136,6 +136,7 @@ static inline int pmd_dirty(pmd_t pmd) + return pmd_flags(pmd) & _PAGE_DIRTY; + } + ++#define pmd_young pmd_young + static inline int pmd_young(pmd_t pmd) + { + return pmd_flags(pmd) & _PAGE_ACCESSED; +diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h +index e6889556e0bf..dec3d890e814 100644 +--- a/include/linux/pgtable.h ++++ b/include/linux/pgtable.h +@@ -164,6 +164,13 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr) + return pmd_none(*pmd) ? NULL : pte_offset_kernel(pmd, vaddr); + } + ++#ifndef pmd_young ++static inline int pmd_young(pmd_t pmd) ++{ ++ return 0; ++} ++#endif ++ + #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS + extern int ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch b/target/linux/generic/backport-5.15/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch new file mode 100644 index 00000000000..4c4a2d11f2b --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch @@ -0,0 +1,122 @@ +From 46cbda7b65998a5af4493f745d94417af697bd68 Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Wed, 23 Nov 2022 07:45:10 +0100 +Subject: [PATCH 18/29] mm: introduce arch_has_hw_nonleaf_pmd_young() + +When running as a Xen PV guests commit eed9a328aa1a ("mm: x86: add +CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") can cause a protection violation in +pmdp_test_and_clear_young(): + + BUG: unable to handle page fault for address: ffff8880083374d0 + #PF: supervisor write access in kernel mode + #PF: error_code(0x0003) - permissions violation + PGD 3026067 P4D 3026067 PUD 3027067 PMD 7fee5067 PTE 8010000008337065 + Oops: 0003 [#1] PREEMPT SMP NOPTI + CPU: 7 PID: 158 Comm: kswapd0 Not tainted 6.1.0-rc5-20221118-doflr+ #1 + RIP: e030:pmdp_test_and_clear_young+0x25/0x40 + +This happens because the Xen hypervisor can't emulate direct writes to +page table entries other than PTEs. + +This can easily be fixed by introducing arch_has_hw_nonleaf_pmd_young() +similar to arch_has_hw_pte_young() and test that instead of +CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG. + +Link: https://lkml.kernel.org/r/20221123064510.16225-1-jgross@suse.com +Fixes: eed9a328aa1a ("mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") +Signed-off-by: Juergen Gross +Reported-by: Sander Eikelenboom +Acked-by: Yu Zhao +Tested-by: Sander Eikelenboom +Acked-by: David Hildenbrand [core changes] +Signed-off-by: Andrew Morton +--- + arch/x86/include/asm/pgtable.h | 8 ++++++++ + include/linux/pgtable.h | 11 +++++++++++ + mm/vmscan.c | 10 +++++----- + 3 files changed, 24 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h +index c4b64ee357fd..d8363c676496 100644 +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -1405,6 +1405,14 @@ static inline bool arch_has_hw_pte_young(void) + return true; + } + ++#ifdef CONFIG_XEN_PV ++#define arch_has_hw_nonleaf_pmd_young arch_has_hw_nonleaf_pmd_young ++static inline bool arch_has_hw_nonleaf_pmd_young(void) ++{ ++ return !cpu_feature_enabled(X86_FEATURE_XENPV); ++} ++#endif ++ + #endif /* __ASSEMBLY__ */ + + #endif /* _ASM_X86_PGTABLE_H */ +diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h +index dec3d890e814..562b4cc82b33 100644 +--- a/include/linux/pgtable.h ++++ b/include/linux/pgtable.h +@@ -266,6 +266,17 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + #endif + ++#ifndef arch_has_hw_nonleaf_pmd_young ++/* ++ * Return whether the accessed bit in non-leaf PMD entries is supported on the ++ * local CPU. ++ */ ++static inline bool arch_has_hw_nonleaf_pmd_young(void) ++{ ++ return IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG); ++} ++#endif ++ + #ifndef arch_has_hw_pte_young + /* + * Return whether the accessed bit is supported on the local CPU. +diff --git a/mm/vmscan.c b/mm/vmscan.c +index d310e0b9e520..96f1af44bb77 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3730,7 +3730,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area + goto next; + + if (!pmd_trans_huge(pmd[i])) { +- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && ++ if (arch_has_hw_nonleaf_pmd_young() && + get_cap(LRU_GEN_NONLEAF_YOUNG)) + pmdp_test_and_clear_young(vma, addr, pmd + i); + goto next; +@@ -3828,14 +3828,14 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, + #endif + walk->mm_stats[MM_NONLEAF_TOTAL]++; + +-#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +- if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { ++ if (arch_has_hw_nonleaf_pmd_young() && ++ get_cap(LRU_GEN_NONLEAF_YOUNG)) { + if (!pmd_young(val)) + continue; + + walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); + } +-#endif ++ + if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) + continue; + +@@ -5135,7 +5135,7 @@ static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, c + if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) + caps |= BIT(LRU_GEN_MM_WALK); + +- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) ++ if (arch_has_hw_nonleaf_pmd_young() && get_cap(LRU_GEN_NONLEAF_YOUNG)) + caps |= BIT(LRU_GEN_NONLEAF_YOUNG); + + return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch b/target/linux/generic/backport-5.15/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch new file mode 100644 index 00000000000..a8cd1fca1b0 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch @@ -0,0 +1,61 @@ +From c7dfefd4bdfba3d5171038d1cc2d4160288e6ee4 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 15 Jan 2023 20:44:05 -0700 +Subject: [PATCH 16/29] mm: multi-gen LRU: fix crash during cgroup migration + +lru_gen_migrate_mm() assumes lru_gen_add_mm() runs prior to itself. This +isn't true for the following scenario: + + CPU 1 CPU 2 + + clone() + cgroup_can_fork() + cgroup_procs_write() + cgroup_post_fork() + task_lock() + lru_gen_migrate_mm() + task_unlock() + task_lock() + lru_gen_add_mm() + task_unlock() + +And when the above happens, kernel crashes because of linked list +corruption (mm_struct->lru_gen.list). + +Link: https://lore.kernel.org/r/20230115134651.30028-1-msizanoen@qtmlabs.xyz/ +Link: https://lkml.kernel.org/r/20230116034405.2960276-1-yuzhao@google.com +Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks") +Signed-off-by: Yu Zhao +Reported-by: msizanoen +Tested-by: msizanoen +Cc: [6.1+] +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 27bc525380f9..d310e0b9e520 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3024,13 +3024,16 @@ void lru_gen_migrate_mm(struct mm_struct *mm) + if (mem_cgroup_disabled()) + return; + ++ /* migration can happen before addition */ ++ if (!mm->lru_gen.memcg) ++ return; ++ + rcu_read_lock(); + memcg = mem_cgroup_from_task(task); + rcu_read_unlock(); + if (memcg == mm->lru_gen.memcg) + return; + +- VM_WARN_ON_ONCE(!mm->lru_gen.memcg); + VM_WARN_ON_ONCE(list_empty(&mm->lru_gen.list)); + + lru_gen_del_mm(mm); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-19-mm-add-vma_has_recency.patch b/target/linux/generic/backport-5.15/020-v6.3-19-mm-add-vma_has_recency.patch new file mode 100644 index 00000000000..542bb0c3a83 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-19-mm-add-vma_has_recency.patch @@ -0,0 +1,207 @@ +From 6c7f552a48b49a8612786a28a2239fbc24fac289 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Fri, 30 Dec 2022 14:52:51 -0700 +Subject: [PATCH 19/29] mm: add vma_has_recency() + +Add vma_has_recency() to indicate whether a VMA may exhibit temporal +locality that the LRU algorithm relies on. + +This function returns false for VMAs marked by VM_SEQ_READ or +VM_RAND_READ. While the former flag indicates linear access, i.e., a +special case of spatial locality, both flags indicate a lack of temporal +locality, i.e., the reuse of an area within a relatively small duration. + +"Recency" is chosen over "locality" to avoid confusion between temporal +and spatial localities. + +Before this patch, the active/inactive LRU only ignored the accessed bit +from VMAs marked by VM_SEQ_READ. After this patch, the active/inactive +LRU and MGLRU share the same logic: they both ignore the accessed bit if +vma_has_recency() returns false. + +For the active/inactive LRU, the following fio test showed a [6, 8]% +increase in IOPS when randomly accessing mapped files under memory +pressure. + + kb=$(awk '/MemTotal/ { print $2 }' /proc/meminfo) + kb=$((kb - 8*1024*1024)) + + modprobe brd rd_nr=1 rd_size=$kb + dd if=/dev/zero of=/dev/ram0 bs=1M + + mkfs.ext4 /dev/ram0 + mount /dev/ram0 /mnt/ + swapoff -a + + fio --name=test --directory=/mnt/ --ioengine=mmap --numjobs=8 \ + --size=8G --rw=randrw --time_based --runtime=10m \ + --group_reporting + +The discussion that led to this patch is here [1]. Additional test +results are available in that thread. + +[1] https://lore.kernel.org/r/Y31s%2FK8T85jh05wH@google.com/ + +Link: https://lkml.kernel.org/r/20221230215252.2628425-1-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Alexander Viro +Cc: Andrea Righi +Cc: Johannes Weiner +Cc: Michael Larabel +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 9 +++++++++ + mm/memory.c | 8 ++++---- + mm/rmap.c | 42 +++++++++++++++++---------------------- + mm/vmscan.c | 5 ++++- + 4 files changed, 35 insertions(+), 29 deletions(-) + +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index e095c1c24311..e8c723053a52 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -333,4 +333,13 @@ static __always_inline void del_page_from_lru_list(struct page *page, + update_lru_size(lruvec, page_lru(page), page_zonenum(page), + -thp_nr_pages(page)); + } ++ ++static inline bool vma_has_recency(struct vm_area_struct *vma) ++{ ++ if (vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)) ++ return false; ++ ++ return true; ++} ++ + #endif +diff --git a/mm/memory.c b/mm/memory.c +index 7d5be951de9e..1306b1ff0c10 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -41,6 +41,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -1353,8 +1354,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb, + force_flush = 1; + set_page_dirty(page); + } +- if (pte_young(ptent) && +- likely(!(vma->vm_flags & VM_SEQ_READ))) ++ if (pte_young(ptent) && likely(vma_has_recency(vma))) + mark_page_accessed(page); + } + rss[mm_counter(page)]--; +@@ -4781,8 +4781,8 @@ static inline void mm_account_fault(struct pt_regs *regs, + #ifdef CONFIG_LRU_GEN + static void lru_gen_enter_fault(struct vm_area_struct *vma) + { +- /* the LRU algorithm doesn't apply to sequential or random reads */ +- current->in_lru_fault = !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)); ++ /* the LRU algorithm only applies to accesses with recency */ ++ current->in_lru_fault = vma_has_recency(vma); + } + + static void lru_gen_exit_fault(void) +diff --git a/mm/rmap.c b/mm/rmap.c +index 22a86122732e..53df47753f3c 100644 +--- a/mm/rmap.c ++++ b/mm/rmap.c +@@ -794,25 +794,14 @@ static bool page_referenced_one(struct page *page, struct vm_area_struct *vma, + } + + if (pvmw.pte) { +- if (lru_gen_enabled() && pte_young(*pvmw.pte) && +- !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) { ++ if (lru_gen_enabled() && pte_young(*pvmw.pte)) { + lru_gen_look_around(&pvmw); + referenced++; + } + + if (ptep_clear_flush_young_notify(vma, address, +- pvmw.pte)) { +- /* +- * Don't treat a reference through +- * a sequentially read mapping as such. +- * If the page has been used in another mapping, +- * we will catch it; if this other mapping is +- * already gone, the unmap path will have set +- * PG_referenced or activated the page. +- */ +- if (likely(!(vma->vm_flags & VM_SEQ_READ))) +- referenced++; +- } ++ pvmw.pte)) ++ referenced++; + } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { + if (pmdp_clear_flush_young_notify(vma, address, + pvmw.pmd)) +@@ -846,7 +835,20 @@ static bool invalid_page_referenced_vma(struct vm_area_struct *vma, void *arg) + struct page_referenced_arg *pra = arg; + struct mem_cgroup *memcg = pra->memcg; + +- if (!mm_match_cgroup(vma->vm_mm, memcg)) ++ /* ++ * Ignore references from this mapping if it has no recency. If the ++ * page has been used in another mapping, we will catch it; if this ++ * other mapping is already gone, the unmap path will have set the ++ * referenced flag or activated the page in zap_pte_range(). ++ */ ++ if (!vma_has_recency(vma)) ++ return true; ++ ++ /* ++ * If we are reclaiming on behalf of a cgroup, skip counting on behalf ++ * of references from different cgroups. ++ */ ++ if (memcg && !mm_match_cgroup(vma->vm_mm, memcg)) + return true; + + return false; +@@ -876,6 +878,7 @@ int page_referenced(struct page *page, + .rmap_one = page_referenced_one, + .arg = (void *)&pra, + .anon_lock = page_lock_anon_vma_read, ++ .invalid_vma = invalid_page_referenced_vma, + }; + + *vm_flags = 0; +@@ -891,15 +894,6 @@ int page_referenced(struct page *page, + return 1; + } + +- /* +- * If we are reclaiming on behalf of a cgroup, skip +- * counting on behalf of references from different +- * cgroups +- */ +- if (memcg) { +- rwc.invalid_vma = invalid_page_referenced_vma; +- } +- + rmap_walk(page, &rwc); + *vm_flags = pra.vm_flags; + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 96f1af44bb77..4ab376abeaae 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3486,7 +3486,10 @@ static int should_skip_vma(unsigned long start, unsigned long end, struct mm_wal + if (is_vm_hugetlb_page(vma)) + return true; + +- if (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ | VM_RAND_READ)) ++ if (!vma_has_recency(vma)) ++ return true; ++ ++ if (vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) + return true; + + if (vma == get_gate_vma(vma->vm_mm)) +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch b/target/linux/generic/backport-5.15/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch new file mode 100644 index 00000000000..75f74114c67 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch @@ -0,0 +1,134 @@ +From 686c3d4f71de9e0e7a27f03a5617a712385f90cd Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Fri, 30 Dec 2022 14:52:52 -0700 +Subject: [PATCH 20/29] mm: support POSIX_FADV_NOREUSE + +This patch adds POSIX_FADV_NOREUSE to vma_has_recency() so that the LRU +algorithm can ignore access to mapped files marked by this flag. + +The advantages of POSIX_FADV_NOREUSE are: +1. Unlike MADV_SEQUENTIAL and MADV_RANDOM, it does not alter the + default readahead behavior. +2. Unlike MADV_SEQUENTIAL and MADV_RANDOM, it does not split VMAs and + therefore does not take mmap_lock. +3. Unlike MADV_COLD, setting it has a negligible cost, regardless of + how many pages it affects. + +Its limitations are: +1. Like POSIX_FADV_RANDOM and POSIX_FADV_SEQUENTIAL, it currently does + not support range. IOW, its scope is the entire file. +2. It currently does not ignore access through file descriptors. + Specifically, for the active/inactive LRU, given a file page shared + by two users and one of them having set POSIX_FADV_NOREUSE on the + file, this page will be activated upon the second user accessing + it. This corner case can be covered by checking POSIX_FADV_NOREUSE + before calling mark_page_accessed() on the read path. But it is + considered not worth the effort. + +There have been a few attempts to support POSIX_FADV_NOREUSE, e.g., [1]. +This time the goal is to fill a niche: a few desktop applications, e.g., +large file transferring and video encoding/decoding, want fast file +streaming with mmap() rather than direct IO. Among those applications, an +SVT-AV1 regression was reported when running with MGLRU [2]. The +following test can reproduce that regression. + + kb=$(awk '/MemTotal/ { print $2 }' /proc/meminfo) + kb=$((kb - 8*1024*1024)) + + modprobe brd rd_nr=1 rd_size=$kb + dd if=/dev/zero of=/dev/ram0 bs=1M + + mkfs.ext4 /dev/ram0 + mount /dev/ram0 /mnt/ + swapoff -a + + fallocate -l 8G /mnt/swapfile + mkswap /mnt/swapfile + swapon /mnt/swapfile + + wget http://ultravideo.cs.tut.fi/video/Bosphorus_3840x2160_120fps_420_8bit_YUV_Y4M.7z + 7z e -o/mnt/ Bosphorus_3840x2160_120fps_420_8bit_YUV_Y4M.7z + SvtAv1EncApp --preset 12 -w 3840 -h 2160 \ + -i /mnt/Bosphorus_3840x2160.y4m + +For MGLRU, the following change showed a [9-11]% increase in FPS, +which makes it on par with the active/inactive LRU. + + patch Source/App/EncApp/EbAppMain.c < #include + 35d35 + < #include /* _O_BINARY */ + 117a118 + > posix_fadvise(config->mmap.fd, 0, 0, POSIX_FADV_NOREUSE); + EOF + +[1] https://lore.kernel.org/r/1308923350-7932-1-git-send-email-andrea@betterlinux.com/ +[2] https://openbenchmarking.org/result/2209259-PTS-MGLRU8GB57 + +Link: https://lkml.kernel.org/r/20221230215252.2628425-2-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Alexander Viro +Cc: Andrea Righi +Cc: Johannes Weiner +Cc: Michael Larabel +Signed-off-by: Andrew Morton +--- + include/linux/fs.h | 2 ++ + include/linux/mm_inline.h | 3 +++ + mm/fadvise.c | 5 ++++- + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 23ecfecdc450..601e52991f4a 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -167,6 +167,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, + /* File is stream-like */ + #define FMODE_STREAM ((__force fmode_t)0x200000) + ++#define FMODE_NOREUSE ((__force fmode_t)0x400000) ++ + /* File was opened by fanotify and shouldn't generate fanotify events */ + #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) + +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index e8c723053a52..8a6a2a23f9b6 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -339,6 +339,9 @@ static inline bool vma_has_recency(struct vm_area_struct *vma) + if (vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)) + return false; + ++ if (vma->vm_file && (vma->vm_file->f_mode & FMODE_NOREUSE)) ++ return false; ++ + return true; + } + +diff --git a/mm/fadvise.c b/mm/fadvise.c +index d6baa4f451c5..e8023c69f219 100644 +--- a/mm/fadvise.c ++++ b/mm/fadvise.c +@@ -80,7 +80,7 @@ int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice) + case POSIX_FADV_NORMAL: + file->f_ra.ra_pages = bdi->ra_pages; + spin_lock(&file->f_lock); +- file->f_mode &= ~FMODE_RANDOM; ++ file->f_mode &= ~(FMODE_RANDOM | FMODE_NOREUSE); + spin_unlock(&file->f_lock); + break; + case POSIX_FADV_RANDOM: +@@ -107,6 +107,9 @@ int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice) + force_page_cache_readahead(mapping, file, start_index, nrpages); + break; + case POSIX_FADV_NOREUSE: ++ spin_lock(&file->f_lock); ++ file->f_mode |= FMODE_NOREUSE; ++ spin_unlock(&file->f_lock); + break; + case POSIX_FADV_DONTNEED: + if (!inode_write_congested(mapping->host)) +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch b/target/linux/generic/backport-5.15/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch new file mode 100644 index 00000000000..836a16b8c77 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch @@ -0,0 +1,359 @@ +From 348fdbada9fb3f0bf1a53651be46319105af187f Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:18:59 -0700 +Subject: [PATCH 21/29] mm: multi-gen LRU: rename lru_gen_struct to + lru_gen_page + +Patch series "mm: multi-gen LRU: memcg LRU", v3. + +Overview +======== + +An memcg LRU is a per-node LRU of memcgs. It is also an LRU of LRUs, +since each node and memcg combination has an LRU of pages (see +mem_cgroup_lruvec()). + +Its goal is to improve the scalability of global reclaim, which is +critical to system-wide memory overcommit in data centers. Note that +memcg reclaim is currently out of scope. + +Its memory bloat is a pointer to each lruvec and negligible to each +pglist_data. In terms of traversing memcgs during global reclaim, it +improves the best-case complexity from O(n) to O(1) and does not affect +the worst-case complexity O(n). Therefore, on average, it has a sublinear +complexity in contrast to the current linear complexity. + +The basic structure of an memcg LRU can be understood by an analogy to +the active/inactive LRU (of pages): +1. It has the young and the old (generations), i.e., the counterparts + to the active and the inactive; +2. The increment of max_seq triggers promotion, i.e., the counterpart + to activation; +3. Other events trigger similar operations, e.g., offlining an memcg + triggers demotion, i.e., the counterpart to deactivation. + +In terms of global reclaim, it has two distinct features: +1. Sharding, which allows each thread to start at a random memcg (in + the old generation) and improves parallelism; +2. Eventual fairness, which allows direct reclaim to bail out at will + and reduces latency without affecting fairness over some time. + +The commit message in patch 6 details the workflow: +https://lore.kernel.org/r/20221222041905.2431096-7-yuzhao@google.com/ + +The following is a simple test to quickly verify its effectiveness. + + Test design: + 1. Create multiple memcgs. + 2. Each memcg contains a job (fio). + 3. All jobs access the same amount of memory randomly. + 4. The system does not experience global memory pressure. + 5. Periodically write to the root memory.reclaim. + + Desired outcome: + 1. All memcgs have similar pgsteal counts, i.e., stddev(pgsteal) + over mean(pgsteal) is close to 0%. + 2. The total pgsteal is close to the total requested through + memory.reclaim, i.e., sum(pgsteal) over sum(requested) is close + to 100%. + + Actual outcome [1]: + MGLRU off MGLRU on + stddev(pgsteal) / mean(pgsteal) 75% 20% + sum(pgsteal) / sum(requested) 425% 95% + + #################################################################### + MEMCGS=128 + + for ((memcg = 0; memcg < $MEMCGS; memcg++)); do + mkdir /sys/fs/cgroup/memcg$memcg + done + + start() { + echo $BASHPID > /sys/fs/cgroup/memcg$memcg/cgroup.procs + + fio -name=memcg$memcg --numjobs=1 --ioengine=mmap \ + --filename=/dev/zero --size=1920M --rw=randrw \ + --rate=64m,64m --random_distribution=random \ + --fadvise_hint=0 --time_based --runtime=10h \ + --group_reporting --minimal + } + + for ((memcg = 0; memcg < $MEMCGS; memcg++)); do + start & + done + + sleep 600 + + for ((i = 0; i < 600; i++)); do + echo 256m >/sys/fs/cgroup/memory.reclaim + sleep 6 + done + + for ((memcg = 0; memcg < $MEMCGS; memcg++)); do + grep "pgsteal " /sys/fs/cgroup/memcg$memcg/memory.stat + done + #################################################################### + +[1]: This was obtained from running the above script (touches less + than 256GB memory) on an EPYC 7B13 with 512GB DRAM for over an + hour. + +This patch (of 8): + +The new name lru_gen_page will be more distinct from the coming +lru_gen_memcg. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-1-yuzhao@google.com +Link: https://lkml.kernel.org/r/20221222041905.2431096-2-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 4 ++-- + include/linux/mmzone.h | 6 +++--- + mm/vmscan.c | 34 +++++++++++++++++----------------- + mm/workingset.c | 4 ++-- + 4 files changed, 24 insertions(+), 24 deletions(-) + +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index 8a6a2a23f9b6..27c4890503c5 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -168,7 +168,7 @@ static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, + int zone = page_zonenum(page); + int delta = thp_nr_pages(page); + enum lru_list lru = type * LRU_INACTIVE_FILE; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); + VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); +@@ -214,7 +214,7 @@ static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bo + int gen = page_lru_gen(page); + int type = page_is_file_lru(page); + int zone = page_zonenum(page); +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + VM_WARN_ON_ONCE_PAGE(gen != -1, page); + +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 6b85ba1f4e18..5856b026c089 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -394,7 +394,7 @@ enum { + * The number of pages in each generation is eventually consistent and therefore + * can be transiently negative when reset_batch_size() is pending. + */ +-struct lru_gen_struct { ++struct lru_gen_page { + /* the aging increments the youngest generation number */ + unsigned long max_seq; + /* the eviction increments the oldest generation numbers */ +@@ -451,7 +451,7 @@ struct lru_gen_mm_state { + struct lru_gen_mm_walk { + /* the lruvec under reclaim */ + struct lruvec *lruvec; +- /* unstable max_seq from lru_gen_struct */ ++ /* unstable max_seq from lru_gen_page */ + unsigned long max_seq; + /* the next address within an mm to scan */ + unsigned long next_addr; +@@ -514,7 +514,7 @@ struct lruvec { + unsigned long flags; + #ifdef CONFIG_LRU_GEN + /* evictable pages divided into generations */ +- struct lru_gen_struct lrugen; ++ struct lru_gen_page lrugen; + /* to concurrently iterate lru_gen_mm_list */ + struct lru_gen_mm_state mm_state; + #endif +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 4ab376abeaae..3b1b5bd9736a 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2910,7 +2910,7 @@ static int get_nr_gens(struct lruvec *lruvec, int type) + + static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) + { +- /* see the comment on lru_gen_struct */ ++ /* see the comment on lru_gen_page */ + return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && + get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && + get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; +@@ -3316,7 +3316,7 @@ struct ctrl_pos { + static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain, + struct ctrl_pos *pos) + { +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + pos->refaulted = lrugen->avg_refaulted[type][tier] + +@@ -3331,7 +3331,7 @@ static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain, + static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) + { + int hist, tier; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; + unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; + +@@ -3408,7 +3408,7 @@ static int page_update_gen(struct page *page, int gen) + static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) + { + int type = page_is_file_lru(page); +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); + unsigned long new_flags, old_flags = READ_ONCE(page->flags); + +@@ -3453,7 +3453,7 @@ static void update_batch_size(struct lru_gen_mm_walk *walk, struct page *page, + static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) + { + int gen, type, zone; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + walk->batched = 0; + +@@ -3979,7 +3979,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) + { + int zone; + int remaining = MAX_LRU_BATCH; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); + + if (type == LRU_GEN_ANON && !can_swap) +@@ -4015,7 +4015,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) + { + int gen, type, zone; + bool success = false; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + DEFINE_MIN_SEQ(lruvec); + + VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); +@@ -4036,7 +4036,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) + ; + } + +- /* see the comment on lru_gen_struct */ ++ /* see the comment on lru_gen_page */ + if (can_swap) { + min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); + min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); +@@ -4058,7 +4058,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan) + { + int prev, next; + int type, zone; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + spin_lock_irq(&lruvec->lru_lock); + +@@ -4116,7 +4116,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + bool success; + struct lru_gen_mm_walk *walk; + struct mm_struct *mm = NULL; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); + +@@ -4181,7 +4181,7 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig + unsigned long old = 0; + unsigned long young = 0; + unsigned long total = 0; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + + for (type = !can_swap; type < ANON_AND_FILE; type++) { +@@ -4466,7 +4466,7 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) + int delta = thp_nr_pages(page); + int refs = page_lru_refs(page); + int tier = lru_tier_from_refs(refs); +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + VM_WARN_ON_ONCE_PAGE(gen >= MAX_NR_GENS, page); + +@@ -4566,7 +4566,7 @@ static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, + int scanned = 0; + int isolated = 0; + int remaining = MAX_LRU_BATCH; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + + VM_WARN_ON_ONCE(!list_empty(list)); +@@ -4967,7 +4967,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + + static bool __maybe_unused state_is_valid(struct lruvec *lruvec) + { +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + if (lrugen->enabled) { + enum lru_list lru; +@@ -5247,7 +5247,7 @@ static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, + int i; + int type, tier; + int hist = lru_hist_from_seq(seq); +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + for (tier = 0; tier < MAX_NR_TIERS; tier++) { + seq_printf(m, " %10d", tier); +@@ -5296,7 +5296,7 @@ static int lru_gen_seq_show(struct seq_file *m, void *v) + unsigned long seq; + bool full = !debugfs_real_fops(m->file)->write; + struct lruvec *lruvec = v; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + int nid = lruvec_pgdat(lruvec)->node_id; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); +@@ -5549,7 +5549,7 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) + { + int i; + int gen, type, zone; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; + lrugen->enabled = lru_gen_enabled(); +diff --git a/mm/workingset.c b/mm/workingset.c +index aeba62cebf8c..a5e1798c6d60 100644 +--- a/mm/workingset.c ++++ b/mm/workingset.c +@@ -223,7 +223,7 @@ static void *lru_gen_eviction(struct page *page) + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; +- struct lru_gen_struct *lrugen; ++ struct lru_gen_page *lrugen; + int type = page_is_file_lru(page); + int delta = thp_nr_pages(page); + int refs = page_lru_refs(page); +@@ -252,7 +252,7 @@ static void lru_gen_refault(struct page *page, void *shadow) + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; +- struct lru_gen_struct *lrugen; ++ struct lru_gen_page *lrugen; + struct mem_cgroup *memcg; + struct pglist_data *pgdat; + int type = page_is_file_lru(page); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch b/target/linux/generic/backport-5.15/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch new file mode 100644 index 00000000000..2e1783661dd --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch @@ -0,0 +1,171 @@ +From afd37e73db04c7e6b47411120ac5f6a7eca51fec Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:00 -0700 +Subject: [PATCH 22/29] mm: multi-gen LRU: rename lrugen->lists[] to + lrugen->pages[] + +lru_gen_page will be chained into per-node lists by the coming +lrugen->list. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-3-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 4 ++-- + include/linux/mmzone.h | 8 ++++---- + mm/vmscan.c | 20 ++++++++++---------- + 3 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index 27c4890503c5..4adc9ba59569 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -246,9 +246,9 @@ static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bo + lru_gen_update_size(lruvec, page, -1, gen); + /* for rotate_reclaimable_page() */ + if (reclaiming) +- list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_add_tail(&page->lru, &lrugen->pages[gen][type][zone]); + else +- list_add(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_add(&page->lru, &lrugen->pages[gen][type][zone]); + + return true; + } +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 5856b026c089..7b8a26aaf381 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -302,7 +302,7 @@ enum lruvec_flags { + * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An + * offset within MAX_NR_GENS, i.e., gen, indexes the LRU list of the + * corresponding generation. The gen counter in page->flags stores gen+1 while +- * a page is on one of lrugen->lists[]. Otherwise it stores 0. ++ * a page is on one of lrugen->pages[]. Otherwise it stores 0. + * + * A page is added to the youngest generation on faulting. The aging needs to + * check the accessed bit at least twice before handing this page over to the +@@ -314,8 +314,8 @@ enum lruvec_flags { + * rest of generations, if they exist, are considered inactive. See + * lru_gen_is_active(). + * +- * PG_active is always cleared while a page is on one of lrugen->lists[] so that +- * the aging needs not to worry about it. And it's set again when a page ++ * PG_active is always cleared while a page is on one of lrugen->pages[] so ++ * that the aging needs not to worry about it. And it's set again when a page + * considered active is isolated for non-reclaiming purposes, e.g., migration. + * See lru_gen_add_page() and lru_gen_del_page(). + * +@@ -402,7 +402,7 @@ struct lru_gen_page { + /* the birth time of each generation in jiffies */ + unsigned long timestamps[MAX_NR_GENS]; + /* the multi-gen LRU lists, lazily sorted on eviction */ +- struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ struct list_head pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the multi-gen LRU sizes, eventually consistent */ + long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the exponential moving average of refaulted */ +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 3b1b5bd9736a..2322c913aa64 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3987,7 +3987,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) + + /* prevent cold/hot inversion if force_scan is true */ + for (zone = 0; zone < MAX_NR_ZONES; zone++) { +- struct list_head *head = &lrugen->lists[old_gen][type][zone]; ++ struct list_head *head = &lrugen->pages[old_gen][type][zone]; + + while (!list_empty(head)) { + struct page *page = lru_to_page(head); +@@ -3998,7 +3998,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) + VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); + + new_gen = page_inc_gen(lruvec, page, false); +- list_move_tail(&page->lru, &lrugen->lists[new_gen][type][zone]); ++ list_move_tail(&page->lru, &lrugen->pages[new_gen][type][zone]); + + if (!--remaining) + return false; +@@ -4026,7 +4026,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) + gen = lru_gen_from_seq(min_seq[type]); + + for (zone = 0; zone < MAX_NR_ZONES; zone++) { +- if (!list_empty(&lrugen->lists[gen][type][zone])) ++ if (!list_empty(&lrugen->pages[gen][type][zone])) + goto next; + } + +@@ -4491,7 +4491,7 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) + + /* promoted */ + if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { +- list_move(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_move(&page->lru, &lrugen->pages[gen][type][zone]); + return true; + } + +@@ -4500,7 +4500,7 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + gen = page_inc_gen(lruvec, page, false); +- list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_move_tail(&page->lru, &lrugen->pages[gen][type][zone]); + + WRITE_ONCE(lrugen->protected[hist][type][tier - 1], + lrugen->protected[hist][type][tier - 1] + delta); +@@ -4512,7 +4512,7 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) + if (PageLocked(page) || PageWriteback(page) || + (type == LRU_GEN_FILE && PageDirty(page))) { + gen = page_inc_gen(lruvec, page, true); +- list_move(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_move(&page->lru, &lrugen->pages[gen][type][zone]); + return true; + } + +@@ -4579,7 +4579,7 @@ static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, + for (zone = sc->reclaim_idx; zone >= 0; zone--) { + LIST_HEAD(moved); + int skipped = 0; +- struct list_head *head = &lrugen->lists[gen][type][zone]; ++ struct list_head *head = &lrugen->pages[gen][type][zone]; + + while (!list_empty(head)) { + struct page *page = lru_to_page(head); +@@ -4980,7 +4980,7 @@ static bool __maybe_unused state_is_valid(struct lruvec *lruvec) + int gen, type, zone; + + for_each_gen_type_zone(gen, type, zone) { +- if (!list_empty(&lrugen->lists[gen][type][zone])) ++ if (!list_empty(&lrugen->pages[gen][type][zone])) + return false; + } + } +@@ -5025,7 +5025,7 @@ static bool drain_evictable(struct lruvec *lruvec) + int remaining = MAX_LRU_BATCH; + + for_each_gen_type_zone(gen, type, zone) { +- struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; ++ struct list_head *head = &lruvec->lrugen.pages[gen][type][zone]; + + while (!list_empty(head)) { + bool success; +@@ -5558,7 +5558,7 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) + lrugen->timestamps[i] = jiffies; + + for_each_gen_type_zone(gen, type, zone) +- INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); ++ INIT_LIST_HEAD(&lrugen->pages[gen][type][zone]); + + lruvec->mm_state.seq = MIN_NR_GENS; + init_waitqueue_head(&lruvec->mm_state.wait); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch b/target/linux/generic/backport-5.15/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch new file mode 100644 index 00000000000..1490f9d4bc5 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch @@ -0,0 +1,193 @@ +From ce45f1c4b32cf69b166f56ef5bc6c761e06ed4e5 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:01 -0700 +Subject: [PATCH 23/29] mm: multi-gen LRU: remove eviction fairness safeguard + +Recall that the eviction consumes the oldest generation: first it +bucket-sorts pages whose gen counters were updated by the aging and +reclaims the rest; then it increments lrugen->min_seq. + +The current eviction fairness safeguard for global reclaim has a +dilemma: when there are multiple eligible memcgs, should it continue +or stop upon meeting the reclaim goal? If it continues, it overshoots +and increases direct reclaim latency; if it stops, it loses fairness +between memcgs it has taken memory away from and those it has yet to. + +With memcg LRU, the eviction, while ensuring eventual fairness, will +stop upon meeting its goal. Therefore the current eviction fairness +safeguard for global reclaim will not be needed. + +Note that memcg LRU only applies to global reclaim. For memcg reclaim, +the eviction will continue, even if it is overshooting. This becomes +unconditional due to code simplification. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-4-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 82 +++++++++++++++-------------------------------------- + 1 file changed, 23 insertions(+), 59 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 2322c913aa64..40e7a947c5c7 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -443,6 +443,11 @@ static bool cgroup_reclaim(struct scan_control *sc) + return sc->target_mem_cgroup; + } + ++static bool global_reclaim(struct scan_control *sc) ++{ ++ return !sc->target_mem_cgroup || mem_cgroup_is_root(sc->target_mem_cgroup); ++} ++ + /** + * writeback_throttling_sane - is the usual dirty throttling mechanism available? + * @sc: scan_control in question +@@ -493,6 +498,11 @@ static bool cgroup_reclaim(struct scan_control *sc) + return false; + } + ++static bool global_reclaim(struct scan_control *sc) ++{ ++ return true; ++} ++ + static bool writeback_throttling_sane(struct scan_control *sc) + { + return true; +@@ -4722,8 +4732,7 @@ static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swa + return scanned; + } + +-static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, +- bool *need_swapping) ++static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) + { + int type; + int scanned; +@@ -4812,9 +4821,6 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + goto retry; + } + +- if (need_swapping && type == LRU_GEN_ANON) +- *need_swapping = true; +- + return scanned; + } + +@@ -4853,68 +4859,26 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; + } + +-static bool should_abort_scan(struct lruvec *lruvec, unsigned long seq, +- struct scan_control *sc, bool need_swapping) ++static unsigned long get_nr_to_reclaim(struct scan_control *sc) + { +- int i; +- DEFINE_MAX_SEQ(lruvec); +- +- if (!current_is_kswapd()) { +- /* age each memcg once to ensure fairness */ +- if (max_seq - seq > 1) +- return true; +- +- /* over-swapping can increase allocation latency */ +- if (sc->nr_reclaimed >= sc->nr_to_reclaim && need_swapping) +- return true; +- +- /* give this thread a chance to exit and free its memory */ +- if (fatal_signal_pending(current)) { +- sc->nr_reclaimed += MIN_LRU_BATCH; +- return true; +- } +- +- if (cgroup_reclaim(sc)) +- return false; +- } else if (sc->nr_reclaimed - sc->last_reclaimed < sc->nr_to_reclaim) +- return false; +- +- /* keep scanning at low priorities to ensure fairness */ +- if (sc->priority > DEF_PRIORITY - 2) +- return false; +- +- /* +- * A minimum amount of work was done under global memory pressure. For +- * kswapd, it may be overshooting. For direct reclaim, the target isn't +- * met, and yet the allocation may still succeed, since kswapd may have +- * caught up. In either case, it's better to stop now, and restart if +- * necessary. +- */ +- for (i = 0; i <= sc->reclaim_idx; i++) { +- unsigned long wmark; +- struct zone *zone = lruvec_pgdat(lruvec)->node_zones + i; +- +- if (!managed_zone(zone)) +- continue; +- +- wmark = current_is_kswapd() ? high_wmark_pages(zone) : low_wmark_pages(zone); +- if (wmark > zone_page_state(zone, NR_FREE_PAGES)) +- return false; +- } ++ /* don't abort memcg reclaim to ensure fairness */ ++ if (!global_reclaim(sc)) ++ return -1; + +- sc->nr_reclaimed += MIN_LRU_BATCH; ++ /* discount the previous progress for kswapd */ ++ if (current_is_kswapd()) ++ return sc->nr_to_reclaim + sc->last_reclaimed; + +- return true; ++ return max(sc->nr_to_reclaim, compact_gap(sc->order)); + } + + static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { + struct blk_plug plug; + bool need_aging = false; +- bool need_swapping = false; + unsigned long scanned = 0; + unsigned long reclaimed = sc->nr_reclaimed; +- DEFINE_MAX_SEQ(lruvec); ++ unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + + lru_add_drain(); + +@@ -4938,7 +4902,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + if (!nr_to_scan) + goto done; + +- delta = evict_pages(lruvec, sc, swappiness, &need_swapping); ++ delta = evict_pages(lruvec, sc, swappiness); + if (!delta) + goto done; + +@@ -4946,7 +4910,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + if (scanned >= nr_to_scan) + break; + +- if (should_abort_scan(lruvec, max_seq, sc, need_swapping)) ++ if (sc->nr_reclaimed >= nr_to_reclaim) + break; + + cond_resched(); +@@ -5393,7 +5357,7 @@ static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_co + if (sc->nr_reclaimed >= nr_to_reclaim) + return 0; + +- if (!evict_pages(lruvec, sc, swappiness, NULL)) ++ if (!evict_pages(lruvec, sc, swappiness)) + return 0; + + cond_resched(); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch b/target/linux/generic/backport-5.15/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch new file mode 100644 index 00000000000..82ba77dec20 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch @@ -0,0 +1,292 @@ +From e20b7386fccc18c791796eb1dc1a91eee3ccf801 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:02 -0700 +Subject: [PATCH 24/29] mm: multi-gen LRU: remove aging fairness safeguard + +Recall that the aging produces the youngest generation: first it scans +for accessed pages and updates their gen counters; then it increments +lrugen->max_seq. + +The current aging fairness safeguard for kswapd uses two passes to +ensure the fairness to multiple eligible memcgs. On the first pass, +which is shared with the eviction, it checks whether all eligible +memcgs are low on cold pages. If so, it requires a second pass, on +which it ages all those memcgs at the same time. + +With memcg LRU, the aging, while ensuring eventual fairness, will run +when necessary. Therefore the current aging fairness safeguard for +kswapd will not be needed. + +Note that memcg LRU only applies to global reclaim. For memcg reclaim, +the aging can be unfair to different memcgs, i.e., their +lrugen->max_seq can be incremented at different paces. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-5-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 126 ++++++++++++++++++++++++---------------------------- + 1 file changed, 59 insertions(+), 67 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 40e7a947c5c7..7159436872ba 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -131,7 +131,6 @@ struct scan_control { + + #ifdef CONFIG_LRU_GEN + /* help kswapd make better choices among multiple memcgs */ +- unsigned int memcgs_need_aging:1; + unsigned long last_reclaimed; + #endif + +@@ -4184,7 +4183,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + return true; + } + +-static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, ++static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, + struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) + { + int gen, type, zone; +@@ -4193,6 +4192,13 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig + unsigned long total = 0; + struct lru_gen_page *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ /* whether this lruvec is completely out of cold pages */ ++ if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { ++ *nr_to_scan = 0; ++ return true; ++ } + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + unsigned long seq; +@@ -4221,8 +4227,6 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig + * stalls when the number of generations reaches MIN_NR_GENS. Hence, the + * ideal number of generations is MIN_NR_GENS+1. + */ +- if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) +- return true; + if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) + return false; + +@@ -4241,40 +4245,54 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig + return false; + } + +-static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, unsigned long min_ttl) ++static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) + { +- bool need_aging; +- unsigned long nr_to_scan; +- int swappiness = get_swappiness(lruvec, sc); ++ int gen, type, zone; ++ unsigned long total = 0; ++ bool can_swap = get_swappiness(lruvec, sc); ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + +- VM_WARN_ON_ONCE(sc->memcg_low_reclaim); ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ unsigned long seq; + +- mem_cgroup_calculate_protection(NULL, memcg); ++ for (seq = min_seq[type]; seq <= max_seq; seq++) { ++ gen = lru_gen_from_seq(seq); + +- if (mem_cgroup_below_min(memcg)) +- return false; ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ total += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); ++ } ++ } + +- need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); ++ /* whether the size is big enough to be helpful */ ++ return mem_cgroup_online(memcg) ? (total >> sc->priority) : total; ++} + +- if (min_ttl) { +- int gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); +- unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); ++static bool lruvec_is_reclaimable(struct lruvec *lruvec, struct scan_control *sc, ++ unsigned long min_ttl) ++{ ++ int gen; ++ unsigned long birth; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MIN_SEQ(lruvec); + +- if (time_is_after_jiffies(birth + min_ttl)) +- return false; ++ VM_WARN_ON_ONCE(sc->memcg_low_reclaim); + +- /* the size is likely too small to be helpful */ +- if (!nr_to_scan && sc->priority != DEF_PRIORITY) +- return false; +- } ++ /* see the comment on lru_gen_page */ ++ gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); ++ birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); + +- if (need_aging) +- try_to_inc_max_seq(lruvec, max_seq, sc, swappiness, false); ++ if (time_is_after_jiffies(birth + min_ttl)) ++ return false; + +- return true; ++ if (!lruvec_is_sizable(lruvec, sc)) ++ return false; ++ ++ mem_cgroup_calculate_protection(NULL, memcg); ++ ++ return !mem_cgroup_below_min(memcg); + } + + /* to protect the working set of the last N jiffies */ +@@ -4283,46 +4301,32 @@ static unsigned long lru_gen_min_ttl __read_mostly; + static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + { + struct mem_cgroup *memcg; +- bool success = false; + unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); + + VM_WARN_ON_ONCE(!current_is_kswapd()); + + sc->last_reclaimed = sc->nr_reclaimed; + +- /* +- * To reduce the chance of going into the aging path, which can be +- * costly, optimistically skip it if the flag below was cleared in the +- * eviction path. This improves the overall performance when multiple +- * memcgs are available. +- */ +- if (!sc->memcgs_need_aging) { +- sc->memcgs_need_aging = true; ++ /* check the order to exclude compaction-induced reclaim */ ++ if (!min_ttl || sc->order || sc->priority == DEF_PRIORITY) + return; +- } +- +- set_mm_walk(pgdat); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + +- if (age_lruvec(lruvec, sc, min_ttl)) +- success = true; ++ if (lruvec_is_reclaimable(lruvec, sc, min_ttl)) { ++ mem_cgroup_iter_break(NULL, memcg); ++ return; ++ } + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + +- clear_mm_walk(); +- +- /* check the order to exclude compaction-induced reclaim */ +- if (success || !min_ttl || sc->order) +- return; +- + /* + * The main goal is to OOM kill if every generation from all memcgs is + * younger than min_ttl. However, another possibility is all memcgs are +- * either below min or empty. ++ * either too small or below min. + */ + if (mutex_trylock(&oom_lock)) { + struct oom_control oc = { +@@ -4830,33 +4834,27 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + * reclaim. + */ + static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, +- bool can_swap, bool *need_aging) ++ bool can_swap) + { + unsigned long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); +- DEFINE_MIN_SEQ(lruvec); + + if (mem_cgroup_below_min(memcg) || + (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) + return 0; + +- *need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); +- if (!*need_aging) ++ if (!should_run_aging(lruvec, max_seq, sc, can_swap, &nr_to_scan)) + return nr_to_scan; + + /* skip the aging path at the default priority */ + if (sc->priority == DEF_PRIORITY) +- goto done; ++ return nr_to_scan; + +- /* leave the work to lru_gen_age_node() */ +- if (current_is_kswapd()) +- return 0; ++ try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false); + +- if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false)) +- return nr_to_scan; +-done: +- return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; ++ /* skip this lruvec as it's low on cold pages */ ++ return 0; + } + + static unsigned long get_nr_to_reclaim(struct scan_control *sc) +@@ -4875,9 +4873,7 @@ static unsigned long get_nr_to_reclaim(struct scan_control *sc) + static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { + struct blk_plug plug; +- bool need_aging = false; + unsigned long scanned = 0; +- unsigned long reclaimed = sc->nr_reclaimed; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + + lru_add_drain(); +@@ -4898,13 +4894,13 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + else + swappiness = 0; + +- nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness, &need_aging); ++ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); + if (!nr_to_scan) +- goto done; ++ break; + + delta = evict_pages(lruvec, sc, swappiness); + if (!delta) +- goto done; ++ break; + + scanned += delta; + if (scanned >= nr_to_scan) +@@ -4916,10 +4912,6 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + cond_resched(); + } + +- /* see the comment in lru_gen_age_node() */ +- if (sc->nr_reclaimed - reclaimed >= MIN_LRU_BATCH && !need_aging) +- sc->memcgs_need_aging = false; +-done: + clear_mm_walk(); + + blk_finish_plug(&plug); +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch b/target/linux/generic/backport-5.15/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch new file mode 100644 index 00000000000..bb5402a3f2a --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch @@ -0,0 +1,166 @@ +From 107d54931df3c28d81648122e219bf0034ef4e99 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:03 -0700 +Subject: [PATCH 25/29] mm: multi-gen LRU: shuffle should_run_aging() + +Move should_run_aging() next to its only caller left. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-6-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 124 ++++++++++++++++++++++++++-------------------------- + 1 file changed, 62 insertions(+), 62 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 7159436872ba..cb026e2714d7 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4183,68 +4183,6 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + return true; + } + +-static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, +- struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) +-{ +- int gen, type, zone; +- unsigned long old = 0; +- unsigned long young = 0; +- unsigned long total = 0; +- struct lru_gen_page *lrugen = &lruvec->lrugen; +- struct mem_cgroup *memcg = lruvec_memcg(lruvec); +- DEFINE_MIN_SEQ(lruvec); +- +- /* whether this lruvec is completely out of cold pages */ +- if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { +- *nr_to_scan = 0; +- return true; +- } +- +- for (type = !can_swap; type < ANON_AND_FILE; type++) { +- unsigned long seq; +- +- for (seq = min_seq[type]; seq <= max_seq; seq++) { +- unsigned long size = 0; +- +- gen = lru_gen_from_seq(seq); +- +- for (zone = 0; zone < MAX_NR_ZONES; zone++) +- size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); +- +- total += size; +- if (seq == max_seq) +- young += size; +- else if (seq + MIN_NR_GENS == max_seq) +- old += size; +- } +- } +- +- /* try to scrape all its memory if this memcg was deleted */ +- *nr_to_scan = mem_cgroup_online(memcg) ? (total >> sc->priority) : total; +- +- /* +- * The aging tries to be lazy to reduce the overhead, while the eviction +- * stalls when the number of generations reaches MIN_NR_GENS. Hence, the +- * ideal number of generations is MIN_NR_GENS+1. +- */ +- if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) +- return false; +- +- /* +- * It's also ideal to spread pages out evenly, i.e., 1/(MIN_NR_GENS+1) +- * of the total number of pages for each generation. A reasonable range +- * for this average portion is [1/MIN_NR_GENS, 1/(MIN_NR_GENS+2)]. The +- * aging cares about the upper bound of hot pages, while the eviction +- * cares about the lower bound of cold pages. +- */ +- if (young * MIN_NR_GENS > total) +- return true; +- if (old * (MIN_NR_GENS + 2) < total) +- return true; +- +- return false; +-} +- + static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) + { + int gen, type, zone; +@@ -4828,6 +4766,68 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp + return scanned; + } + ++static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, ++ struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) ++{ ++ int gen, type, zone; ++ unsigned long old = 0; ++ unsigned long young = 0; ++ unsigned long total = 0; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ /* whether this lruvec is completely out of cold pages */ ++ if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { ++ *nr_to_scan = 0; ++ return true; ++ } ++ ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ unsigned long seq; ++ ++ for (seq = min_seq[type]; seq <= max_seq; seq++) { ++ unsigned long size = 0; ++ ++ gen = lru_gen_from_seq(seq); ++ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); ++ ++ total += size; ++ if (seq == max_seq) ++ young += size; ++ else if (seq + MIN_NR_GENS == max_seq) ++ old += size; ++ } ++ } ++ ++ /* try to scrape all its memory if this memcg was deleted */ ++ *nr_to_scan = mem_cgroup_online(memcg) ? (total >> sc->priority) : total; ++ ++ /* ++ * The aging tries to be lazy to reduce the overhead, while the eviction ++ * stalls when the number of generations reaches MIN_NR_GENS. Hence, the ++ * ideal number of generations is MIN_NR_GENS+1. ++ */ ++ if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) ++ return false; ++ ++ /* ++ * It's also ideal to spread pages out evenly, i.e., 1/(MIN_NR_GENS+1) ++ * of the total number of pages for each generation. A reasonable range ++ * for this average portion is [1/MIN_NR_GENS, 1/(MIN_NR_GENS+2)]. The ++ * aging cares about the upper bound of hot pages, while the eviction ++ * cares about the lower bound of cold pages. ++ */ ++ if (young * MIN_NR_GENS > total) ++ return true; ++ if (old * (MIN_NR_GENS + 2) < total) ++ return true; ++ ++ return false; ++} ++ + /* + * For future optimizations: + * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch b/target/linux/generic/backport-5.15/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch new file mode 100644 index 00000000000..2a625703465 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch @@ -0,0 +1,884 @@ +From fa6363828d314e837c5f79e97ea5e8c0d2f7f062 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:04 -0700 +Subject: [PATCH 26/29] mm: multi-gen LRU: per-node lru_gen_page lists + +For each node, memcgs are divided into two generations: the old and +the young. For each generation, memcgs are randomly sharded into +multiple bins to improve scalability. For each bin, an RCU hlist_nulls +is virtually divided into three segments: the head, the tail and the +default. + +An onlining memcg is added to the tail of a random bin in the old +generation. The eviction starts at the head of a random bin in the old +generation. The per-node memcg generation counter, whose reminder (mod +2) indexes the old generation, is incremented when all its bins become +empty. + +There are four operations: +1. MEMCG_LRU_HEAD, which moves an memcg to the head of a random bin in + its current generation (old or young) and updates its "seg" to + "head"; +2. MEMCG_LRU_TAIL, which moves an memcg to the tail of a random bin in + its current generation (old or young) and updates its "seg" to + "tail"; +3. MEMCG_LRU_OLD, which moves an memcg to the head of a random bin in + the old generation, updates its "gen" to "old" and resets its "seg" + to "default"; +4. MEMCG_LRU_YOUNG, which moves an memcg to the tail of a random bin + in the young generation, updates its "gen" to "young" and resets + its "seg" to "default". + +The events that trigger the above operations are: +1. Exceeding the soft limit, which triggers MEMCG_LRU_HEAD; +2. The first attempt to reclaim an memcg below low, which triggers + MEMCG_LRU_TAIL; +3. The first attempt to reclaim an memcg below reclaimable size + threshold, which triggers MEMCG_LRU_TAIL; +4. The second attempt to reclaim an memcg below reclaimable size + threshold, which triggers MEMCG_LRU_YOUNG; +5. Attempting to reclaim an memcg below min, which triggers + MEMCG_LRU_YOUNG; +6. Finishing the aging on the eviction path, which triggers + MEMCG_LRU_YOUNG; +7. Offlining an memcg, which triggers MEMCG_LRU_OLD. + +Note that memcg LRU only applies to global reclaim, and the +round-robin incrementing of their max_seq counters ensures the +eventual fairness to all eligible memcgs. For memcg reclaim, it still +relies on mem_cgroup_iter(). + +Link: https://lkml.kernel.org/r/20221222041905.2431096-7-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + include/linux/memcontrol.h | 10 + + include/linux/mm_inline.h | 17 ++ + include/linux/mmzone.h | 117 +++++++++++- + mm/memcontrol.c | 16 ++ + mm/page_alloc.c | 1 + + mm/vmscan.c | 373 +++++++++++++++++++++++++++++++++---- + 6 files changed, 499 insertions(+), 35 deletions(-) + +diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h +index 3736405cbcf6..2e405fd88846 100644 +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -818,6 +818,11 @@ static inline void obj_cgroup_put(struct obj_cgroup *objcg) + percpu_ref_put(&objcg->refcnt); + } + ++static inline bool mem_cgroup_tryget(struct mem_cgroup *memcg) ++{ ++ return !memcg || css_tryget(&memcg->css); ++} ++ + static inline void mem_cgroup_put(struct mem_cgroup *memcg) + { + if (memcg) +@@ -1283,6 +1288,11 @@ struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css) + return NULL; + } + ++static inline bool mem_cgroup_tryget(struct mem_cgroup *memcg) ++{ ++ return true; ++} ++ + static inline void mem_cgroup_put(struct mem_cgroup *memcg) + { + } +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index 4adc9ba59569..9138c2e638ce 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -112,6 +112,18 @@ static inline bool lru_gen_in_fault(void) + return current->in_lru_fault; + } + ++#ifdef CONFIG_MEMCG ++static inline int lru_gen_memcg_seg(struct lruvec *lruvec) ++{ ++ return READ_ONCE(lruvec->lrugen.seg); ++} ++#else ++static inline int lru_gen_memcg_seg(struct lruvec *lruvec) ++{ ++ return 0; ++} ++#endif ++ + static inline int lru_gen_from_seq(unsigned long seq) + { + return seq % MAX_NR_GENS; +@@ -287,6 +299,11 @@ static inline bool lru_gen_in_fault(void) + return false; + } + ++static inline int lru_gen_memcg_seg(struct lruvec *lruvec) ++{ ++ return 0; ++} ++ + static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) + { + return false; +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 7b8a26aaf381..4bbf191517e2 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -7,6 +7,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -357,6 +358,15 @@ struct page_vma_mapped_walk; + #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) + #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) + ++/* see the comment on MEMCG_NR_GENS */ ++enum { ++ MEMCG_LRU_NOP, ++ MEMCG_LRU_HEAD, ++ MEMCG_LRU_TAIL, ++ MEMCG_LRU_OLD, ++ MEMCG_LRU_YOUNG, ++}; ++ + #ifdef CONFIG_LRU_GEN + + enum { +@@ -416,6 +426,14 @@ struct lru_gen_page { + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + /* whether the multi-gen LRU is enabled */ + bool enabled; ++#ifdef CONFIG_MEMCG ++ /* the memcg generation this lru_gen_page belongs to */ ++ u8 gen; ++ /* the list segment this lru_gen_page belongs to */ ++ u8 seg; ++ /* per-node lru_gen_page list for global reclaim */ ++ struct hlist_nulls_node list; ++#endif + }; + + enum { +@@ -469,12 +487,87 @@ void lru_gen_init_lruvec(struct lruvec *lruvec); + void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + + #ifdef CONFIG_MEMCG ++ ++/* ++ * For each node, memcgs are divided into two generations: the old and the ++ * young. For each generation, memcgs are randomly sharded into multiple bins ++ * to improve scalability. For each bin, the hlist_nulls is virtually divided ++ * into three segments: the head, the tail and the default. ++ * ++ * An onlining memcg is added to the tail of a random bin in the old generation. ++ * The eviction starts at the head of a random bin in the old generation. The ++ * per-node memcg generation counter, whose reminder (mod MEMCG_NR_GENS) indexes ++ * the old generation, is incremented when all its bins become empty. ++ * ++ * There are four operations: ++ * 1. MEMCG_LRU_HEAD, which moves an memcg to the head of a random bin in its ++ * current generation (old or young) and updates its "seg" to "head"; ++ * 2. MEMCG_LRU_TAIL, which moves an memcg to the tail of a random bin in its ++ * current generation (old or young) and updates its "seg" to "tail"; ++ * 3. MEMCG_LRU_OLD, which moves an memcg to the head of a random bin in the old ++ * generation, updates its "gen" to "old" and resets its "seg" to "default"; ++ * 4. MEMCG_LRU_YOUNG, which moves an memcg to the tail of a random bin in the ++ * young generation, updates its "gen" to "young" and resets its "seg" to ++ * "default". ++ * ++ * The events that trigger the above operations are: ++ * 1. Exceeding the soft limit, which triggers MEMCG_LRU_HEAD; ++ * 2. The first attempt to reclaim an memcg below low, which triggers ++ * MEMCG_LRU_TAIL; ++ * 3. The first attempt to reclaim an memcg below reclaimable size threshold, ++ * which triggers MEMCG_LRU_TAIL; ++ * 4. The second attempt to reclaim an memcg below reclaimable size threshold, ++ * which triggers MEMCG_LRU_YOUNG; ++ * 5. Attempting to reclaim an memcg below min, which triggers MEMCG_LRU_YOUNG; ++ * 6. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG; ++ * 7. Offlining an memcg, which triggers MEMCG_LRU_OLD. ++ * ++ * Note that memcg LRU only applies to global reclaim, and the round-robin ++ * incrementing of their max_seq counters ensures the eventual fairness to all ++ * eligible memcgs. For memcg reclaim, it still relies on mem_cgroup_iter(). ++ */ ++#define MEMCG_NR_GENS 2 ++#define MEMCG_NR_BINS 8 ++ ++struct lru_gen_memcg { ++ /* the per-node memcg generation counter */ ++ unsigned long seq; ++ /* each memcg has one lru_gen_page per node */ ++ unsigned long nr_memcgs[MEMCG_NR_GENS]; ++ /* per-node lru_gen_page list for global reclaim */ ++ struct hlist_nulls_head fifo[MEMCG_NR_GENS][MEMCG_NR_BINS]; ++ /* protects the above */ ++ spinlock_t lock; ++}; ++ ++void lru_gen_init_pgdat(struct pglist_data *pgdat); ++ + void lru_gen_init_memcg(struct mem_cgroup *memcg); + void lru_gen_exit_memcg(struct mem_cgroup *memcg); +-#endif ++void lru_gen_online_memcg(struct mem_cgroup *memcg); ++void lru_gen_offline_memcg(struct mem_cgroup *memcg); ++void lru_gen_release_memcg(struct mem_cgroup *memcg); ++void lru_gen_rotate_memcg(struct lruvec *lruvec, int op); ++ ++#else /* !CONFIG_MEMCG */ ++ ++#define MEMCG_NR_GENS 1 ++ ++struct lru_gen_memcg { ++}; ++ ++static inline void lru_gen_init_pgdat(struct pglist_data *pgdat) ++{ ++} ++ ++#endif /* CONFIG_MEMCG */ + + #else /* !CONFIG_LRU_GEN */ + ++static inline void lru_gen_init_pgdat(struct pglist_data *pgdat) ++{ ++} ++ + static inline void lru_gen_init_lruvec(struct lruvec *lruvec) + { + } +@@ -484,6 +577,7 @@ static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + } + + #ifdef CONFIG_MEMCG ++ + static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) + { + } +@@ -491,7 +585,24 @@ static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) + static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) + { + } +-#endif ++ ++static inline void lru_gen_online_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++static inline void lru_gen_offline_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++static inline void lru_gen_release_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++static inline void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) ++{ ++} ++ ++#endif /* CONFIG_MEMCG */ + + #endif /* CONFIG_LRU_GEN */ + +@@ -1105,6 +1216,8 @@ typedef struct pglist_data { + #ifdef CONFIG_LRU_GEN + /* kswap mm walk data */ + struct lru_gen_mm_walk mm_walk; ++ /* lru_gen_page list */ ++ struct lru_gen_memcg memcg_lru; + #endif + + ZONE_PADDING(_pad2_) +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index ed87d1256f0e..172adfbee06e 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -549,6 +549,16 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) + struct mem_cgroup_per_node *mz; + struct mem_cgroup_tree_per_node *mctz; + ++ if (lru_gen_enabled()) { ++ struct lruvec *lruvec = &mem_cgroup_page_nodeinfo(memcg, page)->lruvec; ++ ++ /* see the comment on MEMCG_NR_GENS */ ++ if (soft_limit_excess(memcg) && lru_gen_memcg_seg(lruvec) != MEMCG_LRU_HEAD) ++ lru_gen_rotate_memcg(lruvec, MEMCG_LRU_HEAD); ++ ++ return; ++ } ++ + mctz = soft_limit_tree_from_page(page); + if (!mctz) + return; +@@ -3433,6 +3443,9 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order, + unsigned long excess; + unsigned long nr_scanned; + ++ if (lru_gen_enabled()) ++ return 0; ++ + if (order > 0) + return 0; + +@@ -5321,6 +5334,7 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) + if (unlikely(mem_cgroup_is_root(memcg))) + queue_delayed_work(system_unbound_wq, &stats_flush_dwork, + 2UL*HZ); ++ lru_gen_online_memcg(memcg); + return 0; + } + +@@ -5347,6 +5361,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) + memcg_offline_kmem(memcg); + reparent_shrinker_deferred(memcg); + wb_memcg_offline(memcg); ++ lru_gen_offline_memcg(memcg); + + drain_all_stock(memcg); + +@@ -5358,6 +5373,7 @@ static void mem_cgroup_css_released(struct cgroup_subsys_state *css) + struct mem_cgroup *memcg = mem_cgroup_from_css(css); + + invalidate_reclaim_iterators(memcg); ++ lru_gen_release_memcg(memcg); + } + + static void mem_cgroup_css_free(struct cgroup_subsys_state *css) +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index c929357fbefe..6459d9c018be 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -7645,6 +7645,7 @@ static void __init free_area_init_node(int nid) + pgdat_set_deferred_range(pgdat); + + free_area_init_core(pgdat); ++ lru_gen_init_pgdat(pgdat); + } + + void __init free_area_init_memoryless_node(int nid) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index cb026e2714d7..3d8e0665186c 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -54,6 +54,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -129,11 +131,6 @@ struct scan_control { + /* Always discard instead of demoting to lower tier memory */ + unsigned int no_demotion:1; + +-#ifdef CONFIG_LRU_GEN +- /* help kswapd make better choices among multiple memcgs */ +- unsigned long last_reclaimed; +-#endif +- + /* Allocation order */ + s8 order; + +@@ -2880,6 +2877,9 @@ DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ + for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) + ++#define get_memcg_gen(seq) ((seq) % MEMCG_NR_GENS) ++#define get_memcg_bin(bin) ((bin) % MEMCG_NR_BINS) ++ + static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) + { + struct pglist_data *pgdat = NODE_DATA(nid); +@@ -4169,8 +4169,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + if (sc->priority <= DEF_PRIORITY - 2) + wait_event_killable(lruvec->mm_state.wait, + max_seq < READ_ONCE(lrugen->max_seq)); +- +- return max_seq < READ_ONCE(lrugen->max_seq); ++ return false; + } + + VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); +@@ -4243,8 +4242,6 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + + VM_WARN_ON_ONCE(!current_is_kswapd()); + +- sc->last_reclaimed = sc->nr_reclaimed; +- + /* check the order to exclude compaction-induced reclaim */ + if (!min_ttl || sc->order || sc->priority == DEF_PRIORITY) + return; +@@ -4833,8 +4830,7 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, + * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg + * reclaim. + */ +-static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, +- bool can_swap) ++static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool can_swap) + { + unsigned long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); +@@ -4851,10 +4847,8 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * + if (sc->priority == DEF_PRIORITY) + return nr_to_scan; + +- try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false); +- + /* skip this lruvec as it's low on cold pages */ +- return 0; ++ return try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false) ? -1 : 0; + } + + static unsigned long get_nr_to_reclaim(struct scan_control *sc) +@@ -4863,29 +4857,18 @@ static unsigned long get_nr_to_reclaim(struct scan_control *sc) + if (!global_reclaim(sc)) + return -1; + +- /* discount the previous progress for kswapd */ +- if (current_is_kswapd()) +- return sc->nr_to_reclaim + sc->last_reclaimed; +- + return max(sc->nr_to_reclaim, compact_gap(sc->order)); + } + +-static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { +- struct blk_plug plug; ++ long nr_to_scan; + unsigned long scanned = 0; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + +- lru_add_drain(); +- +- blk_start_plug(&plug); +- +- set_mm_walk(lruvec_pgdat(lruvec)); +- + while (true) { + int delta; + int swappiness; +- unsigned long nr_to_scan; + + if (sc->may_swap) + swappiness = get_swappiness(lruvec, sc); +@@ -4895,7 +4878,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + swappiness = 0; + + nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); +- if (!nr_to_scan) ++ if (nr_to_scan <= 0) + break; + + delta = evict_pages(lruvec, sc, swappiness); +@@ -4912,11 +4895,251 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + cond_resched(); + } + ++ /* whether try_to_inc_max_seq() was successful */ ++ return nr_to_scan < 0; ++} ++ ++static int shrink_one(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ bool success; ++ unsigned long scanned = sc->nr_scanned; ++ unsigned long reclaimed = sc->nr_reclaimed; ++ int seg = lru_gen_memcg_seg(lruvec); ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ /* see the comment on MEMCG_NR_GENS */ ++ if (!lruvec_is_sizable(lruvec, sc)) ++ return seg != MEMCG_LRU_TAIL ? MEMCG_LRU_TAIL : MEMCG_LRU_YOUNG; ++ ++ mem_cgroup_calculate_protection(NULL, memcg); ++ ++ if (mem_cgroup_below_min(memcg)) ++ return MEMCG_LRU_YOUNG; ++ ++ if (mem_cgroup_below_low(memcg)) { ++ /* see the comment on MEMCG_NR_GENS */ ++ if (seg != MEMCG_LRU_TAIL) ++ return MEMCG_LRU_TAIL; ++ ++ memcg_memory_event(memcg, MEMCG_LOW); ++ } ++ ++ success = try_to_shrink_lruvec(lruvec, sc); ++ ++ shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, sc->priority); ++ ++ vmpressure(sc->gfp_mask, memcg, false, sc->nr_scanned - scanned, ++ sc->nr_reclaimed - reclaimed); ++ ++ sc->nr_reclaimed += current->reclaim_state->reclaimed_slab; ++ current->reclaim_state->reclaimed_slab = 0; ++ ++ return success ? MEMCG_LRU_YOUNG : 0; ++} ++ ++#ifdef CONFIG_MEMCG ++ ++static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ int gen; ++ int bin; ++ int first_bin; ++ struct lruvec *lruvec; ++ struct lru_gen_page *lrugen; ++ const struct hlist_nulls_node *pos; ++ int op = 0; ++ struct mem_cgroup *memcg = NULL; ++ unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); ++ ++ bin = first_bin = prandom_u32_max(MEMCG_NR_BINS); ++restart: ++ gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq)); ++ ++ rcu_read_lock(); ++ ++ hlist_nulls_for_each_entry_rcu(lrugen, pos, &pgdat->memcg_lru.fifo[gen][bin], list) { ++ if (op) ++ lru_gen_rotate_memcg(lruvec, op); ++ ++ mem_cgroup_put(memcg); ++ ++ lruvec = container_of(lrugen, struct lruvec, lrugen); ++ memcg = lruvec_memcg(lruvec); ++ ++ if (!mem_cgroup_tryget(memcg)) { ++ op = 0; ++ memcg = NULL; ++ continue; ++ } ++ ++ rcu_read_unlock(); ++ ++ op = shrink_one(lruvec, sc); ++ ++ if (sc->nr_reclaimed >= nr_to_reclaim) ++ goto success; ++ ++ rcu_read_lock(); ++ } ++ ++ rcu_read_unlock(); ++ ++ /* restart if raced with lru_gen_rotate_memcg() */ ++ if (gen != get_nulls_value(pos)) ++ goto restart; ++ ++ /* try the rest of the bins of the current generation */ ++ bin = get_memcg_bin(bin + 1); ++ if (bin != first_bin) ++ goto restart; ++success: ++ if (op) ++ lru_gen_rotate_memcg(lruvec, op); ++ ++ mem_cgroup_put(memcg); ++} ++ ++static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ struct blk_plug plug; ++ ++ VM_WARN_ON_ONCE(global_reclaim(sc)); ++ ++ lru_add_drain(); ++ ++ blk_start_plug(&plug); ++ ++ set_mm_walk(lruvec_pgdat(lruvec)); ++ ++ if (try_to_shrink_lruvec(lruvec, sc)) ++ lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); ++ ++ clear_mm_walk(); ++ ++ blk_finish_plug(&plug); ++} ++ ++#else /* !CONFIG_MEMCG */ ++ ++static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ BUILD_BUG(); ++} ++ ++static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ BUILD_BUG(); ++} ++ ++#endif ++ ++static void set_initial_priority(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ int priority; ++ unsigned long reclaimable; ++ struct lruvec *lruvec = mem_cgroup_lruvec(NULL, pgdat); ++ ++ if (sc->priority != DEF_PRIORITY || sc->nr_to_reclaim < MIN_LRU_BATCH) ++ return; ++ /* ++ * Determine the initial priority based on ((total / MEMCG_NR_GENS) >> ++ * priority) * reclaimed_to_scanned_ratio = nr_to_reclaim, where the ++ * estimated reclaimed_to_scanned_ratio = inactive / total. ++ */ ++ reclaimable = node_page_state(pgdat, NR_INACTIVE_FILE); ++ if (get_swappiness(lruvec, sc)) ++ reclaimable += node_page_state(pgdat, NR_INACTIVE_ANON); ++ ++ reclaimable /= MEMCG_NR_GENS; ++ ++ /* round down reclaimable and round up sc->nr_to_reclaim */ ++ priority = fls_long(reclaimable) - 1 - fls_long(sc->nr_to_reclaim - 1); ++ ++ sc->priority = clamp(priority, 0, DEF_PRIORITY); ++} ++ ++static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ struct blk_plug plug; ++ unsigned long reclaimed = sc->nr_reclaimed; ++ ++ VM_WARN_ON_ONCE(!global_reclaim(sc)); ++ ++ lru_add_drain(); ++ ++ blk_start_plug(&plug); ++ ++ set_mm_walk(pgdat); ++ ++ set_initial_priority(pgdat, sc); ++ ++ if (current_is_kswapd()) ++ sc->nr_reclaimed = 0; ++ ++ if (mem_cgroup_disabled()) ++ shrink_one(&pgdat->__lruvec, sc); ++ else ++ shrink_many(pgdat, sc); ++ ++ if (current_is_kswapd()) ++ sc->nr_reclaimed += reclaimed; ++ + clear_mm_walk(); + + blk_finish_plug(&plug); ++ ++ /* kswapd should never fail */ ++ pgdat->kswapd_failures = 0; + } + ++#ifdef CONFIG_MEMCG ++void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) ++{ ++ int seg; ++ int old, new; ++ int bin = prandom_u32_max(MEMCG_NR_BINS); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ seg = 0; ++ new = old = lruvec->lrugen.gen; ++ ++ /* see the comment on MEMCG_NR_GENS */ ++ if (op == MEMCG_LRU_HEAD) ++ seg = MEMCG_LRU_HEAD; ++ else if (op == MEMCG_LRU_TAIL) ++ seg = MEMCG_LRU_TAIL; ++ else if (op == MEMCG_LRU_OLD) ++ new = get_memcg_gen(pgdat->memcg_lru.seq); ++ else if (op == MEMCG_LRU_YOUNG) ++ new = get_memcg_gen(pgdat->memcg_lru.seq + 1); ++ else ++ VM_WARN_ON_ONCE(true); ++ ++ hlist_nulls_del_rcu(&lruvec->lrugen.list); ++ ++ if (op == MEMCG_LRU_HEAD || op == MEMCG_LRU_OLD) ++ hlist_nulls_add_head_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]); ++ else ++ hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]); ++ ++ pgdat->memcg_lru.nr_memcgs[old]--; ++ pgdat->memcg_lru.nr_memcgs[new]++; ++ ++ lruvec->lrugen.gen = new; ++ WRITE_ONCE(lruvec->lrugen.seg, seg); ++ ++ if (!pgdat->memcg_lru.nr_memcgs[old] && old == get_memcg_gen(pgdat->memcg_lru.seq)) ++ WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); ++ ++ spin_unlock(&pgdat->memcg_lru.lock); ++} ++#endif ++ + /****************************************************************************** + * state change + ******************************************************************************/ +@@ -5370,11 +5593,11 @@ static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, + + if (!mem_cgroup_disabled()) { + rcu_read_lock(); ++ + memcg = mem_cgroup_from_id(memcg_id); +-#ifdef CONFIG_MEMCG +- if (memcg && !css_tryget(&memcg->css)) ++ if (!mem_cgroup_tryget(memcg)) + memcg = NULL; +-#endif ++ + rcu_read_unlock(); + + if (!memcg) +@@ -5521,6 +5744,19 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) + } + + #ifdef CONFIG_MEMCG ++ ++void lru_gen_init_pgdat(struct pglist_data *pgdat) ++{ ++ int i, j; ++ ++ spin_lock_init(&pgdat->memcg_lru.lock); ++ ++ for (i = 0; i < MEMCG_NR_GENS; i++) { ++ for (j = 0; j < MEMCG_NR_BINS; j++) ++ INIT_HLIST_NULLS_HEAD(&pgdat->memcg_lru.fifo[i][j], i); ++ } ++} ++ + void lru_gen_init_memcg(struct mem_cgroup *memcg) + { + INIT_LIST_HEAD(&memcg->mm_list.fifo); +@@ -5544,7 +5780,69 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) + } + } + } +-#endif ++ ++void lru_gen_online_memcg(struct mem_cgroup *memcg) ++{ ++ int gen; ++ int nid; ++ int bin = prandom_u32_max(MEMCG_NR_BINS); ++ ++ for_each_node(nid) { ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(!hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ gen = get_memcg_gen(pgdat->memcg_lru.seq); ++ ++ hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[gen][bin]); ++ pgdat->memcg_lru.nr_memcgs[gen]++; ++ ++ lruvec->lrugen.gen = gen; ++ ++ spin_unlock(&pgdat->memcg_lru.lock); ++ } ++} ++ ++void lru_gen_offline_memcg(struct mem_cgroup *memcg) ++{ ++ int nid; ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ lru_gen_rotate_memcg(lruvec, MEMCG_LRU_OLD); ++ } ++} ++ ++void lru_gen_release_memcg(struct mem_cgroup *memcg) ++{ ++ int gen; ++ int nid; ++ ++ for_each_node(nid) { ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ gen = lruvec->lrugen.gen; ++ ++ hlist_nulls_del_rcu(&lruvec->lrugen.list); ++ pgdat->memcg_lru.nr_memcgs[gen]--; ++ ++ if (!pgdat->memcg_lru.nr_memcgs[gen] && gen == get_memcg_gen(pgdat->memcg_lru.seq)) ++ WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); ++ ++ spin_unlock(&pgdat->memcg_lru.lock); ++ } ++} ++ ++#endif /* CONFIG_MEMCG */ + + static int __init init_lru_gen(void) + { +@@ -5571,6 +5869,10 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + { + } + ++static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++} ++ + #endif /* CONFIG_LRU_GEN */ + + static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -5584,7 +5886,7 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + bool proportional_reclaim; + struct blk_plug plug; + +- if (lru_gen_enabled()) { ++ if (lru_gen_enabled() && !global_reclaim(sc)) { + lru_gen_shrink_lruvec(lruvec, sc); + return; + } +@@ -5826,6 +6128,11 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc) + struct lruvec *target_lruvec; + bool reclaimable = false; + ++ if (lru_gen_enabled() && global_reclaim(sc)) { ++ lru_gen_shrink_node(pgdat, sc); ++ return; ++ } ++ + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); + + again: +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch b/target/linux/generic/backport-5.15/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch new file mode 100644 index 00000000000..59d2c82b564 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch @@ -0,0 +1,201 @@ +From 93147736b5b3a21bea24313bfc7a696829932009 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:05 -0700 +Subject: [PATCH 27/29] mm: multi-gen LRU: clarify scan_control flags + +Among the flags in scan_control: +1. sc->may_swap, which indicates swap constraint due to memsw.max, is + supported as usual. +2. sc->proactive, which indicates reclaim by memory.reclaim, may not + opportunistically skip the aging path, since it is considered less + latency sensitive. +3. !(sc->gfp_mask & __GFP_IO), which indicates IO constraint, lowers + swappiness to prioritize file LRU, since clean file pages are more + likely to exist. +4. sc->may_writepage and sc->may_unmap, which indicates opportunistic + reclaim, are rejected, since unmapped clean pages are already + prioritized. Scanning for more of them is likely futile and can + cause high reclaim latency when there is a large number of memcgs. + +The rest are handled by the existing code. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-8-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 55 +++++++++++++++++++++++++++-------------------------- + 1 file changed, 28 insertions(+), 27 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 3d8e0665186c..4bcb93df316c 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2905,6 +2905,9 @@ static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + ++ if (!sc->may_swap) ++ return 0; ++ + if (!can_demote(pgdat->node_id, sc) && + mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) + return 0; +@@ -3952,7 +3955,7 @@ static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_ + } while (err == -EAGAIN); + } + +-static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat) ++static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat, bool force_alloc) + { + struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; + +@@ -3960,7 +3963,7 @@ static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat) + VM_WARN_ON_ONCE(walk); + + walk = &pgdat->mm_walk; +- } else if (!pgdat && !walk) { ++ } else if (!walk && force_alloc) { + VM_WARN_ON_ONCE(current_is_kswapd()); + + walk = kzalloc(sizeof(*walk), __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); +@@ -4146,7 +4149,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + goto done; + } + +- walk = set_mm_walk(NULL); ++ walk = set_mm_walk(NULL, true); + if (!walk) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; +@@ -4215,8 +4218,6 @@ static bool lruvec_is_reclaimable(struct lruvec *lruvec, struct scan_control *sc + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MIN_SEQ(lruvec); + +- VM_WARN_ON_ONCE(sc->memcg_low_reclaim); +- + /* see the comment on lru_gen_page */ + gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); + birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); +@@ -4472,12 +4473,8 @@ static bool isolate_page(struct lruvec *lruvec, struct page *page, struct scan_c + { + bool success; + +- /* unmapping inhibited */ +- if (!sc->may_unmap && page_mapped(page)) +- return false; +- + /* swapping inhibited */ +- if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && ++ if (!(sc->gfp_mask & __GFP_IO) && + (PageDirty(page) || + (PageAnon(page) && !PageSwapCache(page)))) + return false; +@@ -4574,9 +4571,8 @@ static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, + __count_vm_events(PGSCAN_ANON + type, isolated); + + /* +- * There might not be eligible pages due to reclaim_idx, may_unmap and +- * may_writepage. Check the remaining to prevent livelock if it's not +- * making progress. ++ * There might not be eligible pages due to reclaim_idx. Check the ++ * remaining to prevent livelock if it's not making progress. + */ + return isolated || !remaining ? scanned : 0; + } +@@ -4836,8 +4832,7 @@ static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + +- if (mem_cgroup_below_min(memcg) || +- (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) ++ if (mem_cgroup_below_min(memcg)) + return 0; + + if (!should_run_aging(lruvec, max_seq, sc, can_swap, &nr_to_scan)) +@@ -4865,17 +4860,14 @@ static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + long nr_to_scan; + unsigned long scanned = 0; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); ++ int swappiness = get_swappiness(lruvec, sc); ++ ++ /* clean file pages are more likely to exist */ ++ if (swappiness && !(sc->gfp_mask & __GFP_IO)) ++ swappiness = 1; + + while (true) { + int delta; +- int swappiness; +- +- if (sc->may_swap) +- swappiness = get_swappiness(lruvec, sc); +- else if (!cgroup_reclaim(sc) && get_swappiness(lruvec, sc)) +- swappiness = 1; +- else +- swappiness = 0; + + nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); + if (nr_to_scan <= 0) +@@ -5005,12 +4997,13 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc + struct blk_plug plug; + + VM_WARN_ON_ONCE(global_reclaim(sc)); ++ VM_WARN_ON_ONCE(!sc->may_writepage || !sc->may_unmap); + + lru_add_drain(); + + blk_start_plug(&plug); + +- set_mm_walk(lruvec_pgdat(lruvec)); ++ set_mm_walk(NULL, false); + + if (try_to_shrink_lruvec(lruvec, sc)) + lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); +@@ -5066,11 +5059,19 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control * + + VM_WARN_ON_ONCE(!global_reclaim(sc)); + ++ /* ++ * Unmapped clean pages are already prioritized. Scanning for more of ++ * them is likely futile and can cause high reclaim latency when there ++ * is a large number of memcgs. ++ */ ++ if (!sc->may_writepage || !sc->may_unmap) ++ goto done; ++ + lru_add_drain(); + + blk_start_plug(&plug); + +- set_mm_walk(pgdat); ++ set_mm_walk(pgdat, false); + + set_initial_priority(pgdat, sc); + +@@ -5088,7 +5089,7 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control * + clear_mm_walk(); + + blk_finish_plug(&plug); +- ++done: + /* kswapd should never fail */ + pgdat->kswapd_failures = 0; + } +@@ -5656,7 +5657,7 @@ static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, + set_task_reclaim_state(current, &sc.reclaim_state); + flags = memalloc_noreclaim_save(); + blk_start_plug(&plug); +- if (!set_mm_walk(NULL)) { ++ if (!set_mm_walk(NULL, true)) { + err = -ENOMEM; + goto done; + } +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch b/target/linux/generic/backport-5.15/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch new file mode 100644 index 00000000000..a6c7b019ced --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch @@ -0,0 +1,39 @@ +From cf3297e4c7a928da8b2b2f0baff2f9c69ea57952 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:06 -0700 +Subject: [PATCH 28/29] mm: multi-gen LRU: simplify arch_has_hw_pte_young() + check + +Scanning page tables when hardware does not set the accessed bit has +no real use cases. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-9-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 4bcb93df316c..3f6874a69886 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4144,7 +4144,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ +- if (!force_scan && !(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { ++ if (!arch_has_hw_pte_young() || !get_cap(LRU_GEN_MM_WALK)) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } +-- +2.40.0 + diff --git a/target/linux/generic/backport-5.15/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch b/target/linux/generic/backport-5.15/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch new file mode 100644 index 00000000000..14e1aff1776 --- /dev/null +++ b/target/linux/generic/backport-5.15/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch @@ -0,0 +1,93 @@ +From cc67f962cc53f6e1dfa92eb85b7b26fe83a3c66f Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Mon, 13 Feb 2023 00:53:22 -0700 +Subject: [PATCH 29/29] mm: multi-gen LRU: avoid futile retries + +Recall that the per-node memcg LRU has two generations and they alternate +when the last memcg (of a given node) is moved from one to the other. +Each generation is also sharded into multiple bins to improve scalability. +A reclaimer starts with a random bin (in the old generation) and, if it +fails, it will retry, i.e., to try the rest of the bins. + +If a reclaimer fails with the last memcg, it should move this memcg to the +young generation first, which causes the generations to alternate, and +then retry. Otherwise, the retries will be futile because all other bins +are empty. + +Link: https://lkml.kernel.org/r/20230213075322.1416966-1-yuzhao@google.com +Fixes: e4dde56cd208 ("mm: multi-gen LRU: per-node lru_gen_folio lists") +Signed-off-by: Yu Zhao +Reported-by: T.J. Mercier +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 3f6874a69886..0b76774963ff 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4934,18 +4934,20 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc) + + static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) + { ++ int op; + int gen; + int bin; + int first_bin; + struct lruvec *lruvec; + struct lru_gen_page *lrugen; ++ struct mem_cgroup *memcg; + const struct hlist_nulls_node *pos; +- int op = 0; +- struct mem_cgroup *memcg = NULL; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + + bin = first_bin = prandom_u32_max(MEMCG_NR_BINS); + restart: ++ op = 0; ++ memcg = NULL; + gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq)); + + rcu_read_lock(); +@@ -4969,14 +4971,22 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) + + op = shrink_one(lruvec, sc); + +- if (sc->nr_reclaimed >= nr_to_reclaim) +- goto success; +- + rcu_read_lock(); ++ ++ if (sc->nr_reclaimed >= nr_to_reclaim) ++ break; + } + + rcu_read_unlock(); + ++ if (op) ++ lru_gen_rotate_memcg(lruvec, op); ++ ++ mem_cgroup_put(memcg); ++ ++ if (sc->nr_reclaimed >= nr_to_reclaim) ++ return; ++ + /* restart if raced with lru_gen_rotate_memcg() */ + if (gen != get_nulls_value(pos)) + goto restart; +@@ -4985,11 +4995,6 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) + bin = get_memcg_bin(bin + 1); + if (bin != first_bin) + goto restart; +-success: +- if (op) +- lru_gen_rotate_memcg(lruvec, op); +- +- mem_cgroup_put(memcg); + } + + static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +-- +2.40.0 + diff --git a/target/linux/generic/config-5.15 b/target/linux/generic/config-5.15 index b41de9cc288..c9581ba5d4a 100644 --- a/target/linux/generic/config-5.15 +++ b/target/linux/generic/config-5.15 @@ -4425,7 +4425,6 @@ CONFIG_NMI_LOG_BUF_SHIFT=13 # CONFIG_NO_HZ is not set # CONFIG_NO_HZ_FULL is not set # CONFIG_NO_HZ_IDLE is not set -CONFIG_NR_LRU_GENS=7 # CONFIG_NS83820 is not set # CONFIG_NTB is not set # CONFIG_NTFS3_64BIT_CLUSTER is not set @@ -6529,7 +6528,6 @@ CONFIG_THIN_ARCHIVES=y # CONFIG_THUNDER_NIC_VF is not set # CONFIG_TICK_CPU_ACCOUNTING is not set CONFIG_TICK_ONESHOT=y -CONFIG_TIERS_PER_GEN=4 # CONFIG_TIFM_CORE is not set # CONFIG_TIGON3 is not set # CONFIG_TIMB_DMA is not set From 708a507af00d618fd91eadf1f2a03e2f7e86b6ea Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 25 Mar 2023 17:24:27 +0100 Subject: [PATCH 33/53] generic: 5.15: refresh kernel patches Refresh kernel patches for generic kernel 5.15 due to new backport version of MGLRU patchset. Signed-off-by: Christian Marangi --- ...-x86-arm64-add-arch_has_hw_pte_young.patch | 19 +--- ...dd-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch | 23 +---- ...-03-mm-vmscan.c-refactor-shrink_node.patch | 7 +- ...inux-mm_inline.h-fold-__update_lru_s.patch | 9 +- ...-v6.1-05-mm-multi-gen-LRU-groundwork.patch | 69 ++++--------- ...multi-gen-LRU-minimal-implementation.patch | 51 +++------- ...lti-gen-LRU-exploit-locality-in-rmap.patch | 47 +++------ ...lti-gen-LRU-support-page-table-walks.patch | 97 +++++++------------ ...lti-gen-LRU-optimize-multiple-memcgs.patch | 19 ++-- ...v6.1-10-mm-multi-gen-LRU-kill-switch.patch | 41 +++----- ...m-multi-gen-LRU-thrashing-prevention.patch | 21 ++-- ...2-mm-multi-gen-LRU-debugfs-interface.patch | 33 +++---- ...don-t-sync-disk-for-each-aging-cycle.patch | 7 +- ...-retry-pages-written-back-while-isol.patch | 11 +-- ...-move-lru_gen_add_mm-out-of-IRQ-off-.patch | 9 +- ..._young-for-architectures-not-having-.patch | 21 +--- ...roduce-arch_has_hw_nonleaf_pmd_young.patch | 19 +--- ...RU-fix-crash-during-cgroup-migration.patch | 7 +- .../020-v6.3-19-mm-add-vma_has_recency.patch | 23 ++--- ...6.3-20-mm-support-POSIX_FADV_NOREUSE.patch | 17 +--- ...-rename-lru_gen_struct-to-lru_gen_pa.patch | 51 ++++------ ...-rename-lrugen-lists-to-lrugen-pages.patch | 31 +++--- ...U-remove-eviction-fairness-safeguard.patch | 21 ++-- ...-LRU-remove-aging-fairness-safeguard.patch | 23 ++--- ...lti-gen-LRU-shuffle-should_run_aging.patch | 9 +- ...-gen-LRU-per-node-lru_gen_page-lists.patch | 78 ++++++--------- ...i-gen-LRU-clarify-scan_control-flags.patch | 31 +++--- ...-simplify-arch_has_hw_pte_young-chec.patch | 7 +- ...m-multi-gen-LRU-avoid-futile-retries.patch | 11 +-- ...e_mem_map-with-ARCH_PFN_OFFSET-calcu.patch | 2 +- 30 files changed, 261 insertions(+), 553 deletions(-) diff --git a/target/linux/generic/backport-5.15/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch b/target/linux/generic/backport-5.15/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch index 3bea44d8658..df854ffd3d8 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch @@ -327,11 +327,9 @@ Signed-off-by: Andrew Morton mm/memory.c | 14 +------------- 4 files changed, 19 insertions(+), 28 deletions(-) -diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h -index ed57717cd004..874827fc7bc6 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h -@@ -999,23 +999,13 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, +@@ -999,23 +999,13 @@ static inline void update_mmu_cache(stru * page after fork() + CoW for pfn mappings. We don't always have a * hardware-managed access flag on arm64. */ @@ -357,11 +355,9 @@ index ed57717cd004..874827fc7bc6 100644 #endif /* !__ASSEMBLY__ */ -diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h -index 448cd01eb3ec..3908780fc408 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h -@@ -1397,10 +1397,10 @@ static inline bool arch_has_pfn_modify_check(void) +@@ -1397,10 +1397,10 @@ static inline bool arch_has_pfn_modify_c return boot_cpu_has_bug(X86_BUG_L1TF); } @@ -375,11 +371,9 @@ index 448cd01eb3ec..3908780fc408 100644 } #endif /* __ASSEMBLY__ */ -diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h -index d468efcf48f4..2f1188980baf 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h -@@ -259,6 +259,19 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, +@@ -259,6 +259,19 @@ static inline int pmdp_clear_flush_young #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif @@ -399,8 +393,6 @@ index d468efcf48f4..2f1188980baf 100644 #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long address, -diff --git a/mm/memory.c b/mm/memory.c -index a4d0f744a458..392b7326a2d2 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -121,18 +121,6 @@ int randomize_va_space __read_mostly = @@ -422,7 +414,7 @@ index a4d0f744a458..392b7326a2d2 100644 #ifndef arch_wants_old_prefaulted_pte static inline bool arch_wants_old_prefaulted_pte(void) { -@@ -2782,7 +2770,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src, +@@ -2782,7 +2770,7 @@ static inline bool cow_user_page(struct * On architectures with software "accessed" bits, we would * take a double page fault, so mark it accessed here. */ @@ -431,6 +423,3 @@ index a4d0f744a458..392b7326a2d2 100644 pte_t entry; vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch b/target/linux/generic/backport-5.15/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch index 60ce9c07cc0..9e0430ea2aa 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch @@ -71,8 +71,6 @@ Signed-off-by: Andrew Morton include/linux/pgtable.h | 4 ++-- 5 files changed, 17 insertions(+), 4 deletions(-) -diff --git a/arch/Kconfig b/arch/Kconfig -index 5987363b41c2..62d55b7ccca1 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1295,6 +1295,14 @@ config ARCH_HAS_ELFCORE_COMPAT @@ -90,8 +88,6 @@ index 5987363b41c2..62d55b7ccca1 100644 source "kernel/gcov/Kconfig" source "scripts/gcc-plugins/Kconfig" -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index a08ce6360382..38e1d231d52a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -84,6 +84,7 @@ config X86 @@ -102,11 +98,9 @@ index a08ce6360382..38e1d231d52a 100644 select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 select ARCH_HAS_COPY_MC if X86_64 select ARCH_HAS_SET_MEMORY -diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h -index 3908780fc408..01a1763123ff 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h -@@ -817,7 +817,8 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) +@@ -817,7 +817,8 @@ static inline unsigned long pmd_page_vad static inline int pmd_bad(pmd_t pmd) { @@ -116,11 +110,9 @@ index 3908780fc408..01a1763123ff 100644 } static inline unsigned long pages_to_mb(unsigned long npg) -diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c -index 3481b35cb4ec..a224193d84bf 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c -@@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma, +@@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_ return ret; } @@ -129,7 +121,7 @@ index 3481b35cb4ec..a224193d84bf 100644 int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmdp) { -@@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma, +@@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_ return ret; } @@ -139,11 +131,9 @@ index 3481b35cb4ec..a224193d84bf 100644 int pudp_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pud_t *pudp) { -diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h -index 2f1188980baf..e6889556e0bf 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h -@@ -212,7 +212,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, +@@ -212,7 +212,7 @@ static inline int ptep_test_and_clear_yo #endif #ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG @@ -152,7 +142,7 @@ index 2f1188980baf..e6889556e0bf 100644 static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) -@@ -233,7 +233,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, +@@ -233,7 +233,7 @@ static inline int pmdp_test_and_clear_yo BUILD_BUG(); return 0; } @@ -161,6 +151,3 @@ index 2f1188980baf..e6889556e0bf 100644 #endif #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch b/target/linux/generic/backport-5.15/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch index 1b9a70dbc12..b8d2917d26c 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch @@ -50,8 +50,6 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 198 +++++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 94 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 201acea81804..dc5f0381513f 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2497,6 +2497,109 @@ enum scan_balance { @@ -164,7 +162,7 @@ index 201acea81804..dc5f0381513f 100644 /* * Determine how aggressively the anon and file LRU lists should be * scanned. The relative value of each set of LRU lists is determined -@@ -2965,109 +3068,16 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc) +@@ -2965,109 +3068,16 @@ static void shrink_node(pg_data_t *pgdat unsigned long nr_reclaimed, nr_scanned; struct lruvec *target_lruvec; bool reclaimable = false; @@ -275,6 +273,3 @@ index 201acea81804..dc5f0381513f 100644 shrink_node_memcgs(pgdat, sc); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch b/target/linux/generic/backport-5.15/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch index 24b5c8f7970..2f277a56e1c 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch @@ -55,11 +55,9 @@ Signed-off-by: Andrew Morton include/linux/mm_inline.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index 355ea1ee32bd..a822d6b690a5 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -24,7 +24,7 @@ static inline int page_is_file_lru(struct page *page) +@@ -24,7 +24,7 @@ static inline int page_is_file_lru(struc return !PageSwapBacked(page); } @@ -68,7 +66,7 @@ index 355ea1ee32bd..a822d6b690a5 100644 enum lru_list lru, enum zone_type zid, int nr_pages) { -@@ -33,6 +33,13 @@ static __always_inline void update_lru_size(struct lruvec *lruvec, +@@ -33,6 +33,13 @@ static __always_inline void update_lru_s __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); __mod_zone_page_state(&pgdat->node_zones[zid], NR_ZONE_LRU_BASE + lru, nr_pages); @@ -82,6 +80,3 @@ index 355ea1ee32bd..a822d6b690a5 100644 #ifdef CONFIG_MEMCG mem_cgroup_update_lru_size(lruvec, lru, zid, nr_pages); #endif --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch b/target/linux/generic/backport-5.15/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch index 5c143f3cfab..577c2817daa 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch @@ -124,11 +124,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 75 +++++++++++++ 16 files changed, 425 insertions(+), 14 deletions(-) -diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c -index d6b5339c56e2..4ec08f7c3e75 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c -@@ -785,7 +785,8 @@ static int fuse_check_page(struct page *page) +@@ -785,7 +785,8 @@ static int fuse_check_page(struct page * 1 << PG_active | 1 << PG_workingset | 1 << PG_reclaim | @@ -138,11 +136,9 @@ index d6b5339c56e2..4ec08f7c3e75 100644 dump_page(page, "fuse: trying to steal weird page"); return 1; } -diff --git a/include/linux/mm.h b/include/linux/mm.h -index e4e1817bb3b8..699068f39aa0 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h -@@ -1093,6 +1093,8 @@ vm_fault_t finish_mkwrite_fault(struct vm_fault *vmf); +@@ -1093,6 +1093,8 @@ vm_fault_t finish_mkwrite_fault(struct v #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) #define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) #define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH) @@ -151,11 +147,9 @@ index e4e1817bb3b8..699068f39aa0 100644 /* * Define the bit shifts to access each section. For non-existent -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index a822d6b690a5..65320d2b8f60 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -26,10 +26,13 @@ static inline int page_is_file_lru(struct page *page) +@@ -26,10 +26,13 @@ static inline int page_is_file_lru(struc static __always_inline void __update_lru_size(struct lruvec *lruvec, enum lru_list lru, enum zone_type zid, @@ -170,7 +164,7 @@ index a822d6b690a5..65320d2b8f60 100644 __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); __mod_zone_page_state(&pgdat->node_zones[zid], NR_ZONE_LRU_BASE + lru, nr_pages); -@@ -86,11 +89,177 @@ static __always_inline enum lru_list page_lru(struct page *page) +@@ -86,11 +89,177 @@ static __always_inline enum lru_list pag return lru; } @@ -348,7 +342,7 @@ index a822d6b690a5..65320d2b8f60 100644 update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); list_add(&page->lru, &lruvec->lists[lru]); } -@@ -100,6 +269,9 @@ static __always_inline void add_page_to_lru_list_tail(struct page *page, +@@ -100,6 +269,9 @@ static __always_inline void add_page_to_ { enum lru_list lru = page_lru(page); @@ -358,7 +352,7 @@ index a822d6b690a5..65320d2b8f60 100644 update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); list_add_tail(&page->lru, &lruvec->lists[lru]); } -@@ -107,6 +279,9 @@ static __always_inline void add_page_to_lru_list_tail(struct page *page, +@@ -107,6 +279,9 @@ static __always_inline void add_page_to_ static __always_inline void del_page_from_lru_list(struct page *page, struct lruvec *lruvec) { @@ -368,8 +362,6 @@ index a822d6b690a5..65320d2b8f60 100644 list_del(&page->lru); update_lru_size(lruvec, page_lru(page), page_zonenum(page), -thp_nr_pages(page)); -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index 6ba100216530..0c39f72184d0 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -294,6 +294,102 @@ enum lruvec_flags { @@ -486,8 +478,6 @@ index 6ba100216530..0c39f72184d0 100644 #ifdef CONFIG_MEMCG struct pglist_data *pgdat; #endif -diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h -index ef1e3e736e14..240905407a18 100644 --- a/include/linux/page-flags-layout.h +++ b/include/linux/page-flags-layout.h @@ -55,7 +55,8 @@ @@ -526,11 +516,9 @@ index ef1e3e736e14..240905407a18 100644 + #endif #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ -diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h -index fbfd3fad48f2..a7d7ff4c621d 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h -@@ -845,7 +845,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) +@@ -845,7 +845,7 @@ static inline void ClearPageSlabPfmemall 1UL << PG_private | 1UL << PG_private_2 | \ 1UL << PG_writeback | 1UL << PG_reserved | \ 1UL << PG_slab | 1UL << PG_active | \ @@ -539,7 +527,7 @@ index fbfd3fad48f2..a7d7ff4c621d 100644 /* * Flags checked when a page is prepped for return by the page allocator. -@@ -856,7 +856,7 @@ static inline void ClearPageSlabPfmemalloc(struct page *page) +@@ -856,7 +856,7 @@ static inline void ClearPageSlabPfmemall * alloc-free cycle to prevent from reusing the page. */ #define PAGE_FLAGS_CHECK_AT_PREP \ @@ -548,8 +536,6 @@ index fbfd3fad48f2..a7d7ff4c621d 100644 #define PAGE_FLAGS_PRIVATE \ (1UL << PG_private | 1UL << PG_private_2) -diff --git a/include/linux/sched.h b/include/linux/sched.h -index e418935f8db6..545f6b1ccd50 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -911,6 +911,10 @@ struct task_struct { @@ -563,8 +549,6 @@ index e418935f8db6..545f6b1ccd50 100644 #ifdef CONFIG_COMPAT_BRK unsigned brk_randomized:1; #endif -diff --git a/kernel/bounds.c b/kernel/bounds.c -index 9795d75b09b2..5ee60777d8e4 100644 --- a/kernel/bounds.c +++ b/kernel/bounds.c @@ -22,6 +22,11 @@ int main(void) @@ -579,8 +563,6 @@ index 9795d75b09b2..5ee60777d8e4 100644 /* End of constants */ return 0; -diff --git a/mm/Kconfig b/mm/Kconfig -index c048dea7e342..0eeb27397884 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -897,6 +897,14 @@ config IO_MAPPING @@ -598,11 +580,9 @@ index c048dea7e342..0eeb27397884 100644 source "mm/damon/Kconfig" endmenu -diff --git a/mm/huge_memory.c b/mm/huge_memory.c -index 98ff57c8eda6..f260ef82f03a 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c -@@ -2366,7 +2366,8 @@ static void __split_huge_page_tail(struct page *head, int tail, +@@ -2366,7 +2366,8 @@ static void __split_huge_page_tail(struc #ifdef CONFIG_64BIT (1L << PG_arch_2) | #endif @@ -612,11 +592,9 @@ index 98ff57c8eda6..f260ef82f03a 100644 /* ->mapping in first tail page is compound_mapcount */ VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING, -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index b68b2fe639fd..8b634dc72e7f 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -5178,6 +5178,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg) +@@ -5178,6 +5178,7 @@ static void __mem_cgroup_free(struct mem static void mem_cgroup_free(struct mem_cgroup *memcg) { @@ -624,7 +602,7 @@ index b68b2fe639fd..8b634dc72e7f 100644 memcg_wb_domain_exit(memcg); __mem_cgroup_free(memcg); } -@@ -5241,6 +5242,7 @@ static struct mem_cgroup *mem_cgroup_alloc(void) +@@ -5241,6 +5242,7 @@ static struct mem_cgroup *mem_cgroup_all memcg->deferred_split_queue.split_queue_len = 0; #endif idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); @@ -632,11 +610,9 @@ index b68b2fe639fd..8b634dc72e7f 100644 return memcg; fail: mem_cgroup_id_remove(memcg); -diff --git a/mm/memory.c b/mm/memory.c -index 392b7326a2d2..7d5be951de9e 100644 --- a/mm/memory.c +++ b/mm/memory.c -@@ -4778,6 +4778,27 @@ static inline void mm_account_fault(struct pt_regs *regs, +@@ -4778,6 +4778,27 @@ static inline void mm_account_fault(stru perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); } @@ -664,7 +640,7 @@ index 392b7326a2d2..7d5be951de9e 100644 /* * By the time we get here, we already hold the mm semaphore * -@@ -4809,11 +4830,15 @@ vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address, +@@ -4809,11 +4830,15 @@ vm_fault_t handle_mm_fault(struct vm_are if (flags & FAULT_FLAG_USER) mem_cgroup_enter_user_fault(); @@ -680,11 +656,9 @@ index 392b7326a2d2..7d5be951de9e 100644 if (flags & FAULT_FLAG_USER) { mem_cgroup_exit_user_fault(); /* -diff --git a/mm/mm_init.c b/mm/mm_init.c -index 9ddaf0e1b0ab..0d7b2bd2454a 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c -@@ -65,14 +65,16 @@ void __init mminit_verify_pageflags_layout(void) +@@ -65,14 +65,16 @@ void __init mminit_verify_pageflags_layo shift = 8 * sizeof(unsigned long); width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH @@ -703,8 +677,6 @@ index 9ddaf0e1b0ab..0d7b2bd2454a 100644 NR_PAGEFLAGS); mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d\n", -diff --git a/mm/mmzone.c b/mm/mmzone.c -index eb89d6e018e2..2ec0d7793424 100644 --- a/mm/mmzone.c +++ b/mm/mmzone.c @@ -81,6 +81,8 @@ void lruvec_init(struct lruvec *lruvec) @@ -716,8 +688,6 @@ index eb89d6e018e2..2ec0d7793424 100644 } #if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) -diff --git a/mm/swap.c b/mm/swap.c -index af3cad4e5378..0bdc96661fb6 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -446,6 +446,11 @@ void lru_cache_add(struct page *page) @@ -732,7 +702,7 @@ index af3cad4e5378..0bdc96661fb6 100644 get_page(page); local_lock(&lru_pvecs.lock); pvec = this_cpu_ptr(&lru_pvecs.lru_add); -@@ -547,7 +552,7 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec) +@@ -547,7 +552,7 @@ static void lru_deactivate_file_fn(struc static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec) { @@ -741,7 +711,7 @@ index af3cad4e5378..0bdc96661fb6 100644 int nr_pages = thp_nr_pages(page); del_page_from_lru_list(page, lruvec); -@@ -661,7 +666,8 @@ void deactivate_file_page(struct page *page) +@@ -661,7 +666,8 @@ void deactivate_file_page(struct page *p */ void deactivate_page(struct page *page) { @@ -751,11 +721,9 @@ index af3cad4e5378..0bdc96661fb6 100644 struct pagevec *pvec; local_lock(&lru_pvecs.lock); -diff --git a/mm/vmscan.c b/mm/vmscan.c -index dc5f0381513f..41826fe17eb3 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -2821,6 +2821,81 @@ static bool can_age_anon_pages(struct pglist_data *pgdat, +@@ -2821,6 +2821,81 @@ static bool can_age_anon_pages(struct pg return can_demote(pgdat->node_id, sc); } @@ -837,6 +805,3 @@ index dc5f0381513f..41826fe17eb3 100644 static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) { unsigned long nr[NR_LRU_LISTS]; --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch b/target/linux/generic/backport-5.15/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch index 1e310ae2111..f8a7d9bd7f6 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch @@ -208,11 +208,9 @@ Signed-off-by: Andrew Morton mm/workingset.c | 110 ++++- 8 files changed, 1025 insertions(+), 11 deletions(-) -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index 65320d2b8f60..58aabb1ba020 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -106,6 +106,33 @@ static inline int lru_gen_from_seq(unsigned long seq) +@@ -106,6 +106,33 @@ static inline int lru_gen_from_seq(unsig return seq % MAX_NR_GENS; } @@ -246,7 +244,7 @@ index 65320d2b8f60..58aabb1ba020 100644 static inline int page_lru_gen(struct page *page) { unsigned long flags = READ_ONCE(page->flags); -@@ -158,6 +185,15 @@ static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, +@@ -158,6 +185,15 @@ static inline void lru_gen_update_size(s __update_lru_size(lruvec, lru, zone, -delta); return; } @@ -262,8 +260,6 @@ index 65320d2b8f60..58aabb1ba020 100644 } static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index 0c39f72184d0..fce8945c507c 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -327,6 +327,28 @@ enum lruvec_flags { @@ -328,8 +324,6 @@ index 0c39f72184d0..fce8945c507c 100644 }; void lru_gen_init_lruvec(struct lruvec *lruvec); -diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h -index 240905407a18..7d79818dc065 100644 --- a/include/linux/page-flags-layout.h +++ b/include/linux/page-flags-layout.h @@ -106,7 +106,10 @@ @@ -344,8 +338,6 @@ index 240905407a18..7d79818dc065 100644 #endif #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ -diff --git a/kernel/bounds.c b/kernel/bounds.c -index 5ee60777d8e4..b529182e8b04 100644 --- a/kernel/bounds.c +++ b/kernel/bounds.c @@ -24,8 +24,10 @@ int main(void) @@ -359,8 +351,6 @@ index 5ee60777d8e4..b529182e8b04 100644 #endif /* End of constants */ -diff --git a/mm/Kconfig b/mm/Kconfig -index 0eeb27397884..62433f3cd7ae 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -897,6 +897,7 @@ config IO_MAPPING @@ -388,11 +378,9 @@ index 0eeb27397884..62433f3cd7ae 100644 source "mm/damon/Kconfig" endmenu -diff --git a/mm/swap.c b/mm/swap.c -index 0bdc96661fb6..5d227577b609 100644 --- a/mm/swap.c +++ b/mm/swap.c -@@ -389,6 +389,40 @@ static void __lru_cache_activate_page(struct page *page) +@@ -389,6 +389,40 @@ static void __lru_cache_activate_page(st local_unlock(&lru_pvecs.lock); } @@ -433,7 +421,7 @@ index 0bdc96661fb6..5d227577b609 100644 /* * Mark a page as having seen activity. * -@@ -403,6 +437,11 @@ void mark_page_accessed(struct page *page) +@@ -403,6 +437,11 @@ void mark_page_accessed(struct page *pag { page = compound_head(page); @@ -445,11 +433,9 @@ index 0bdc96661fb6..5d227577b609 100644 if (!PageReferenced(page)) { SetPageReferenced(page); } else if (PageUnevictable(page)) { -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 41826fe17eb3..932abd24c1b3 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -1142,9 +1142,11 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, +@@ -1142,9 +1142,11 @@ static int __remove_mapping(struct addre if (PageSwapCache(page)) { swp_entry_t swap = { .val = page_private(page) }; @@ -462,7 +448,7 @@ index 41826fe17eb3..932abd24c1b3 100644 __delete_from_swap_cache(page, swap, shadow); xa_unlock_irq(&mapping->i_pages); put_swap_page(page, swap); -@@ -2502,6 +2504,9 @@ static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc) +@@ -2502,6 +2504,9 @@ static void prepare_scan_count(pg_data_t unsigned long file; struct lruvec *target_lruvec; @@ -472,7 +458,7 @@ index 41826fe17eb3..932abd24c1b3 100644 target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); /* -@@ -2827,6 +2832,17 @@ static bool can_age_anon_pages(struct pglist_data *pgdat, +@@ -2827,6 +2832,17 @@ static bool can_age_anon_pages(struct pg * shorthand helpers ******************************************************************************/ @@ -490,7 +476,7 @@ index 41826fe17eb3..932abd24c1b3 100644 #define for_each_gen_type_zone(gen, type, zone) \ for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ -@@ -2852,6 +2868,745 @@ static struct lruvec __maybe_unused *get_lruvec(struct mem_cgroup *memcg, int ni +@@ -2852,6 +2868,745 @@ static struct lruvec __maybe_unused *get return pgdat ? &pgdat->__lruvec : NULL; } @@ -1253,7 +1239,7 @@ index 41826fe17eb3..932abd24c1b3 100644 #endif /* CONFIG_LRU_GEN */ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -@@ -2907,6 +3672,11 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -2907,6 +3672,11 @@ static void shrink_lruvec(struct lruvec bool proportional_reclaim; struct blk_plug plug; @@ -1265,7 +1251,7 @@ index 41826fe17eb3..932abd24c1b3 100644 get_scan_count(lruvec, sc, nr); /* Record the original scan target for proportional adjustments later */ -@@ -3372,6 +4142,9 @@ static void snapshot_refaults(struct mem_cgroup *target_memcg, pg_data_t *pgdat) +@@ -3372,6 +4142,9 @@ static void snapshot_refaults(struct mem struct lruvec *target_lruvec; unsigned long refaults; @@ -1275,7 +1261,7 @@ index 41826fe17eb3..932abd24c1b3 100644 target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat); refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_ANON); target_lruvec->refaults[0] = refaults; -@@ -3736,12 +4509,16 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, +@@ -3736,12 +4509,16 @@ unsigned long try_to_free_mem_cgroup_pag } #endif @@ -1294,7 +1280,7 @@ index 41826fe17eb3..932abd24c1b3 100644 if (!can_age_anon_pages(pgdat, sc)) return; -@@ -4058,12 +4835,11 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx) +@@ -4058,12 +4835,11 @@ restart: sc.may_swap = !nr_boost_reclaim; /* @@ -1311,11 +1297,9 @@ index 41826fe17eb3..932abd24c1b3 100644 /* * If we're getting trouble reclaiming, start doing writepage -diff --git a/mm/workingset.c b/mm/workingset.c -index 880d882f3325..aeba62cebf8c 100644 --- a/mm/workingset.c +++ b/mm/workingset.c -@@ -187,7 +187,6 @@ static unsigned int bucket_order __read_mostly; +@@ -187,7 +187,6 @@ static unsigned int bucket_order __read_ static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction, bool workingset) { @@ -1323,7 +1307,7 @@ index 880d882f3325..aeba62cebf8c 100644 eviction &= EVICTION_MASK; eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; eviction = (eviction << NODES_SHIFT) | pgdat->node_id; -@@ -212,10 +211,107 @@ static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat, +@@ -212,10 +211,107 @@ static void unpack_shadow(void *shadow, *memcgidp = memcgid; *pgdat = NODE_DATA(nid); @@ -1432,7 +1416,7 @@ index 880d882f3325..aeba62cebf8c 100644 /** * workingset_age_nonresident - age non-resident entries as LRU ages * @lruvec: the lruvec that was aged -@@ -264,10 +360,14 @@ void *workingset_eviction(struct page *page, struct mem_cgroup *target_memcg) +@@ -264,10 +360,14 @@ void *workingset_eviction(struct page *p VM_BUG_ON_PAGE(page_count(page), page); VM_BUG_ON_PAGE(!PageLocked(page), page); @@ -1447,7 +1431,7 @@ index 880d882f3325..aeba62cebf8c 100644 workingset_age_nonresident(lruvec, thp_nr_pages(page)); return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); } -@@ -296,7 +396,13 @@ void workingset_refault(struct page *page, void *shadow) +@@ -296,7 +396,13 @@ void workingset_refault(struct page *pag bool workingset; int memcgid; @@ -1461,6 +1445,3 @@ index 880d882f3325..aeba62cebf8c 100644 rcu_read_lock(); /* --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch b/target/linux/generic/backport-5.15/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch index e0c6380b5f7..5cd6e03dc60 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch @@ -108,11 +108,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 184 +++++++++++++++++++++++++++++++++++++ 7 files changed, 232 insertions(+), 2 deletions(-) -diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h -index 4f189b17dafc..8d6a0329bc59 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h -@@ -442,6 +442,7 @@ static inline struct obj_cgroup *__page_objcg(struct page *page) +@@ -442,6 +442,7 @@ static inline struct obj_cgroup *__page_ * - LRU isolation * - lock_page_memcg() * - exclusive reference @@ -120,7 +118,7 @@ index 4f189b17dafc..8d6a0329bc59 100644 * * For a kmem page a caller should hold an rcu read lock to protect memcg * associated with a kmem page from being released. -@@ -497,6 +498,7 @@ static inline struct mem_cgroup *page_memcg_rcu(struct page *page) +@@ -497,6 +498,7 @@ static inline struct mem_cgroup *page_me * - LRU isolation * - lock_page_memcg() * - exclusive reference @@ -128,7 +126,7 @@ index 4f189b17dafc..8d6a0329bc59 100644 * * For a kmem page a caller should hold an rcu read lock to protect memcg * associated with a kmem page from being released. -@@ -953,6 +955,23 @@ void unlock_page_memcg(struct page *page); +@@ -953,6 +955,23 @@ void unlock_page_memcg(struct page *page void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val); @@ -152,7 +150,7 @@ index 4f189b17dafc..8d6a0329bc59 100644 /* idx can be of type enum memcg_stat_item or node_stat_item */ static inline void mod_memcg_state(struct mem_cgroup *memcg, int idx, int val) -@@ -1369,6 +1388,18 @@ static inline void unlock_page_memcg(struct page *page) +@@ -1369,6 +1388,18 @@ static inline void unlock_page_memcg(str { } @@ -171,8 +169,6 @@ index 4f189b17dafc..8d6a0329bc59 100644 static inline void mem_cgroup_handle_over_high(void) { } -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index fce8945c507c..4db2b877fcf9 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -352,6 +352,7 @@ enum lruvec_flags { @@ -191,7 +187,7 @@ index fce8945c507c..4db2b877fcf9 100644 #ifdef CONFIG_MEMCG void lru_gen_init_memcg(struct mem_cgroup *memcg); -@@ -419,6 +421,10 @@ static inline void lru_gen_init_lruvec(struct lruvec *lruvec) +@@ -419,6 +421,10 @@ static inline void lru_gen_init_lruvec(s { } @@ -202,8 +198,6 @@ index fce8945c507c..4db2b877fcf9 100644 #ifdef CONFIG_MEMCG static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) { -diff --git a/mm/internal.h b/mm/internal.h -index cf3cb933eba3..5c73246a092e 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -35,6 +35,7 @@ @@ -214,11 +208,9 @@ index cf3cb933eba3..5c73246a092e 100644 void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma, unsigned long floor, unsigned long ceiling); -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 8b634dc72e7f..cc3431c5d9ba 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -2798,6 +2798,7 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg) +@@ -2798,6 +2798,7 @@ static void commit_charge(struct page *p * - LRU isolation * - lock_page_memcg() * - exclusive reference @@ -226,8 +218,6 @@ index 8b634dc72e7f..cc3431c5d9ba 100644 */ page->memcg_data = (unsigned long)memcg; } -diff --git a/mm/rmap.c b/mm/rmap.c -index 330b361a460e..22a86122732e 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -73,6 +73,7 @@ @@ -238,7 +228,7 @@ index 330b361a460e..22a86122732e 100644 #include -@@ -793,6 +794,12 @@ static bool page_referenced_one(struct page *page, struct vm_area_struct *vma, +@@ -793,6 +794,12 @@ static bool page_referenced_one(struct p } if (pvmw.pte) { @@ -251,11 +241,9 @@ index 330b361a460e..22a86122732e 100644 if (ptep_clear_flush_young_notify(vma, address, pvmw.pte)) { /* -diff --git a/mm/swap.c b/mm/swap.c -index 5d227577b609..966ff2d83343 100644 --- a/mm/swap.c +++ b/mm/swap.c -@@ -325,7 +325,7 @@ static bool need_activate_page_drain(int cpu) +@@ -325,7 +325,7 @@ static bool need_activate_page_drain(int return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0; } @@ -264,7 +252,7 @@ index 5d227577b609..966ff2d83343 100644 { page = compound_head(page); if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { -@@ -345,7 +345,7 @@ static inline void activate_page_drain(int cpu) +@@ -345,7 +345,7 @@ static inline void activate_page_drain(i { } @@ -273,11 +261,9 @@ index 5d227577b609..966ff2d83343 100644 { struct lruvec *lruvec; -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 932abd24c1b3..1d0b25ae378c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -1409,6 +1409,11 @@ static unsigned int shrink_page_list(struct list_head *page_list, +@@ -1409,6 +1409,11 @@ retry: if (!sc->may_unmap && page_mapped(page)) goto keep_locked; @@ -289,7 +275,7 @@ index 932abd24c1b3..1d0b25ae378c 100644 may_enter_fs = (sc->gfp_mask & __GFP_FS) || (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); -@@ -2990,6 +2995,29 @@ static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) +@@ -2990,6 +2995,29 @@ static bool positive_ctrl_err(struct ctr * the aging ******************************************************************************/ @@ -319,7 +305,7 @@ index 932abd24c1b3..1d0b25ae378c 100644 /* protect pages accessed multiple times through file descriptors */ static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) { -@@ -3001,6 +3029,11 @@ static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaimin +@@ -3001,6 +3029,11 @@ static int page_inc_gen(struct lruvec *l VM_WARN_ON_ONCE_PAGE(!(old_flags & LRU_GEN_MASK), page); do { @@ -331,7 +317,7 @@ index 932abd24c1b3..1d0b25ae378c 100644 new_gen = (old_gen + 1) % MAX_NR_GENS; new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); -@@ -3015,6 +3048,43 @@ static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaimin +@@ -3015,6 +3048,43 @@ static int page_inc_gen(struct lruvec *l return new_gen; } @@ -375,7 +361,7 @@ index 932abd24c1b3..1d0b25ae378c 100644 static void inc_min_seq(struct lruvec *lruvec, int type) { struct lru_gen_struct *lrugen = &lruvec->lrugen; -@@ -3214,6 +3284,114 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +@@ -3214,6 +3284,114 @@ static void lru_gen_age_node(struct pgli } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); } @@ -490,7 +476,7 @@ index 932abd24c1b3..1d0b25ae378c 100644 /****************************************************************************** * the eviction ******************************************************************************/ -@@ -3250,6 +3428,12 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) +@@ -3250,6 +3428,12 @@ static bool sort_page(struct lruvec *lru return true; } @@ -503,6 +489,3 @@ index 932abd24c1b3..1d0b25ae378c 100644 /* protected */ if (tier > tier_idx) { int hist = lru_hist_from_seq(lrugen->min_seq[type]); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch b/target/linux/generic/backport-5.15/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch index 64de2c0c828..b0df223b7c4 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch @@ -147,11 +147,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 1010 +++++++++++++++++++++++++++++++++++- 10 files changed, 1172 insertions(+), 17 deletions(-) -diff --git a/fs/exec.c b/fs/exec.c -index 881390b44cfd..1afa15a07d26 100644 --- a/fs/exec.c +++ b/fs/exec.c -@@ -1013,6 +1013,7 @@ static int exec_mmap(struct mm_struct *mm) +@@ -1013,6 +1013,7 @@ static int exec_mmap(struct mm_struct *m active_mm = tsk->active_mm; tsk->active_mm = mm; tsk->mm = mm; @@ -159,7 +157,7 @@ index 881390b44cfd..1afa15a07d26 100644 /* * This prevents preemption while active_mm is being loaded and * it and mm are being updated, which could cause problems for -@@ -1028,6 +1029,7 @@ static int exec_mmap(struct mm_struct *mm) +@@ -1028,6 +1029,7 @@ static int exec_mmap(struct mm_struct *m tsk->mm->vmacache_seqnum = 0; vmacache_flush(tsk); task_unlock(tsk); @@ -167,8 +165,6 @@ index 881390b44cfd..1afa15a07d26 100644 if (old_mm) { mmap_read_unlock(old_mm); BUG_ON(active_mm != old_mm); -diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h -index 8d6a0329bc59..3736405cbcf6 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -348,6 +348,11 @@ struct mem_cgroup { @@ -183,8 +179,6 @@ index 8d6a0329bc59..3736405cbcf6 100644 struct mem_cgroup_per_node *nodeinfo[]; }; -diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h -index 7f8ee09c711f..33c142d31261 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -580,6 +580,22 @@ struct mm_struct { @@ -210,7 +204,7 @@ index 7f8ee09c711f..33c142d31261 100644 } __randomize_layout; /* -@@ -606,6 +622,66 @@ static inline cpumask_t *mm_cpumask(struct mm_struct *mm) +@@ -606,6 +622,66 @@ static inline cpumask_t *mm_cpumask(stru return (struct cpumask *)&mm->cpu_bitmap; } @@ -277,8 +271,6 @@ index 7f8ee09c711f..33c142d31261 100644 struct mmu_gather; extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm); extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm); -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index 4db2b877fcf9..659bab633bdf 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -385,7 +385,7 @@ enum { @@ -365,8 +357,6 @@ index 4db2b877fcf9..659bab633bdf 100644 ZONE_PADDING(_pad2_) /* Per-node vmstats */ -diff --git a/include/linux/swap.h b/include/linux/swap.h -index 4efd267e2937..e970fca4f178 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -137,6 +137,10 @@ union swap_header { @@ -380,11 +370,9 @@ index 4efd267e2937..e970fca4f178 100644 }; #ifdef __KERNEL__ -diff --git a/kernel/exit.c b/kernel/exit.c -index 80efdfda6662..06b477395012 100644 --- a/kernel/exit.c +++ b/kernel/exit.c -@@ -469,6 +469,7 @@ void mm_update_next_owner(struct mm_struct *mm) +@@ -469,6 +469,7 @@ assign_new_owner: goto retry; } WRITE_ONCE(mm->owner, c); @@ -392,11 +380,9 @@ index 80efdfda6662..06b477395012 100644 task_unlock(c); put_task_struct(c); } -diff --git a/kernel/fork.c b/kernel/fork.c -index 68eab6ce3085..d8f37ecdde87 100644 --- a/kernel/fork.c +++ b/kernel/fork.c -@@ -1083,6 +1083,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, +@@ -1083,6 +1083,7 @@ static struct mm_struct *mm_init(struct goto fail_nocontext; mm->user_ns = get_user_ns(user_ns); @@ -404,7 +390,7 @@ index 68eab6ce3085..d8f37ecdde87 100644 return mm; fail_nocontext: -@@ -1125,6 +1126,7 @@ static inline void __mmput(struct mm_struct *mm) +@@ -1125,6 +1126,7 @@ static inline void __mmput(struct mm_str } if (mm->binfmt) module_put(mm->binfmt->module); @@ -412,7 +398,7 @@ index 68eab6ce3085..d8f37ecdde87 100644 mmdrop(mm); } -@@ -2622,6 +2624,13 @@ pid_t kernel_clone(struct kernel_clone_args *args) +@@ -2622,6 +2624,13 @@ pid_t kernel_clone(struct kernel_clone_a get_task_struct(p); } @@ -426,11 +412,9 @@ index 68eab6ce3085..d8f37ecdde87 100644 wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index c1458fa8beb3..fe4d60474d4a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c -@@ -5007,6 +5007,7 @@ context_switch(struct rq *rq, struct task_struct *prev, +@@ -5007,6 +5007,7 @@ context_switch(struct rq *rq, struct tas * finish_task_switch()'s mmdrop(). */ switch_mm_irqs_off(prev->active_mm, next->mm, next); @@ -438,8 +422,6 @@ index c1458fa8beb3..fe4d60474d4a 100644 if (!prev->mm) { // from kernel /* will mmdrop() in finish_task_switch(). */ -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index cc3431c5d9ba..ed87d1256f0e 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -6212,6 +6212,30 @@ static void mem_cgroup_move_task(void) @@ -473,7 +455,7 @@ index cc3431c5d9ba..ed87d1256f0e 100644 static int seq_puts_memcg_tunable(struct seq_file *m, unsigned long value) { if (value == PAGE_COUNTER_MAX) -@@ -6555,6 +6579,7 @@ struct cgroup_subsys memory_cgrp_subsys = { +@@ -6555,6 +6579,7 @@ struct cgroup_subsys memory_cgrp_subsys .css_reset = mem_cgroup_css_reset, .css_rstat_flush = mem_cgroup_css_rstat_flush, .can_attach = mem_cgroup_can_attach, @@ -481,8 +463,6 @@ index cc3431c5d9ba..ed87d1256f0e 100644 .cancel_attach = mem_cgroup_cancel_attach, .post_attach = mem_cgroup_move_task, .dfl_cftypes = memory_files, -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 1d0b25ae378c..a7844c689522 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -50,6 +50,8 @@ @@ -494,7 +474,7 @@ index 1d0b25ae378c..a7844c689522 100644 #include #include -@@ -2853,7 +2855,7 @@ static bool can_age_anon_pages(struct pglist_data *pgdat, +@@ -2853,7 +2855,7 @@ static bool can_age_anon_pages(struct pg for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) @@ -503,11 +483,10 @@ index 1d0b25ae378c..a7844c689522 100644 { struct pglist_data *pgdat = NODE_DATA(nid); -@@ -2898,6 +2900,371 @@ static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) - get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; +@@ -2899,6 +2901,371 @@ static bool __maybe_unused seq_is_valid( } -+/****************************************************************************** + /****************************************************************************** + * mm_struct list + ******************************************************************************/ + @@ -872,10 +851,11 @@ index 1d0b25ae378c..a7844c689522 100644 + return success; +} + - /****************************************************************************** ++/****************************************************************************** * refault feedback loop ******************************************************************************/ -@@ -3048,6 +3415,118 @@ static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaimin + +@@ -3048,6 +3415,118 @@ static int page_inc_gen(struct lruvec *l return new_gen; } @@ -994,7 +974,7 @@ index 1d0b25ae378c..a7844c689522 100644 static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr) { unsigned long pfn = pte_pfn(pte); -@@ -3066,8 +3545,28 @@ static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned +@@ -3066,8 +3545,28 @@ static unsigned long get_pte_pfn(pte_t p return pfn; } @@ -1024,7 +1004,7 @@ index 1d0b25ae378c..a7844c689522 100644 { struct page *page; -@@ -3082,9 +3581,375 @@ static struct page *get_pfn_page(unsigned long pfn, struct mem_cgroup *memcg, +@@ -3082,9 +3581,375 @@ static struct page *get_pfn_page(unsigne if (page_memcg_rcu(page) != memcg) return NULL; @@ -1400,7 +1380,7 @@ index 1d0b25ae378c..a7844c689522 100644 static void inc_min_seq(struct lruvec *lruvec, int type) { struct lru_gen_struct *lrugen = &lruvec->lrugen; -@@ -3136,7 +4001,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +@@ -3136,7 +4001,7 @@ next: return success; } @@ -1409,7 +1389,7 @@ index 1d0b25ae378c..a7844c689522 100644 { int prev, next; int type, zone; -@@ -3146,9 +4011,6 @@ static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_s +@@ -3146,9 +4011,6 @@ static void inc_max_seq(struct lruvec *l VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); @@ -1419,7 +1399,7 @@ index 1d0b25ae378c..a7844c689522 100644 for (type = ANON_AND_FILE - 1; type >= 0; type--) { if (get_nr_gens(lruvec, type) != MAX_NR_GENS) continue; -@@ -3186,10 +4048,76 @@ static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_s +@@ -3186,10 +4048,76 @@ static void inc_max_seq(struct lruvec *l /* make sure preceding modifications appear */ smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); @@ -1497,7 +1477,7 @@ index 1d0b25ae378c..a7844c689522 100644 static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) { -@@ -3265,7 +4193,7 @@ static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -3265,7 +4193,7 @@ static void age_lruvec(struct lruvec *lr need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); if (need_aging) @@ -1506,7 +1486,7 @@ index 1d0b25ae378c..a7844c689522 100644 } static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) -@@ -3274,6 +4202,8 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +@@ -3274,6 +4202,8 @@ static void lru_gen_age_node(struct pgli VM_WARN_ON_ONCE(!current_is_kswapd()); @@ -1515,7 +1495,7 @@ index 1d0b25ae378c..a7844c689522 100644 memcg = mem_cgroup_iter(NULL, NULL, NULL); do { struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); -@@ -3282,11 +4212,16 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +@@ -3282,11 +4212,16 @@ static void lru_gen_age_node(struct pgli cond_resched(); } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); @@ -1533,7 +1513,7 @@ index 1d0b25ae378c..a7844c689522 100644 */ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) { -@@ -3295,6 +4230,8 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +@@ -3295,6 +4230,8 @@ void lru_gen_look_around(struct page_vma unsigned long start; unsigned long end; unsigned long addr; @@ -1542,7 +1522,7 @@ index 1d0b25ae378c..a7844c689522 100644 unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; struct page *page = pvmw->page; struct mem_cgroup *memcg = page_memcg(page); -@@ -3309,6 +4246,9 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +@@ -3309,6 +4246,9 @@ void lru_gen_look_around(struct page_vma if (spin_is_contended(pvmw->ptl)) return; @@ -1552,7 +1532,7 @@ index 1d0b25ae378c..a7844c689522 100644 start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; -@@ -3338,13 +4278,15 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +@@ -3338,13 +4278,15 @@ void lru_gen_look_around(struct page_vma if (!pte_young(pte[i])) continue; @@ -1569,7 +1549,7 @@ index 1d0b25ae378c..a7844c689522 100644 if (pte_dirty(pte[i]) && !PageDirty(page) && !(PageAnon(page) && PageSwapBacked(page) && !PageSwapCache(page))) -@@ -3360,7 +4302,11 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +@@ -3360,7 +4302,11 @@ void lru_gen_look_around(struct page_vma arch_leave_lazy_mmu_mode(); rcu_read_unlock(); @@ -1582,7 +1562,7 @@ index 1d0b25ae378c..a7844c689522 100644 for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { page = pte_page(pte[i]); activate_page(page); -@@ -3372,8 +4318,10 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +@@ -3372,8 +4318,10 @@ void lru_gen_look_around(struct page_vma if (!mem_cgroup_trylock_pages(memcg)) return; @@ -1595,7 +1575,7 @@ index 1d0b25ae378c..a7844c689522 100644 for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { page = compound_head(pte_page(pte[i])); -@@ -3384,10 +4332,14 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +@@ -3384,10 +4332,14 @@ void lru_gen_look_around(struct page_vma if (old_gen < 0 || old_gen == new_gen) continue; @@ -1612,7 +1592,7 @@ index 1d0b25ae378c..a7844c689522 100644 mem_cgroup_unlock_pages(); } -@@ -3670,6 +4622,7 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -3670,6 +4622,7 @@ static int evict_pages(struct lruvec *lr struct page *page; enum vm_event_item item; struct reclaim_stat stat; @@ -1620,7 +1600,7 @@ index 1d0b25ae378c..a7844c689522 100644 struct mem_cgroup *memcg = lruvec_memcg(lruvec); struct pglist_data *pgdat = lruvec_pgdat(lruvec); -@@ -3706,6 +4659,10 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -3706,6 +4659,10 @@ static int evict_pages(struct lruvec *lr move_pages_to_lru(lruvec, &list); @@ -1631,7 +1611,7 @@ index 1d0b25ae378c..a7844c689522 100644 item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; if (!cgroup_reclaim(sc)) __count_vm_events(item, reclaimed); -@@ -3722,6 +4679,11 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -3722,6 +4679,11 @@ static int evict_pages(struct lruvec *lr return scanned; } @@ -1643,7 +1623,7 @@ index 1d0b25ae378c..a7844c689522 100644 static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool can_swap) { -@@ -3747,7 +4709,8 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * +@@ -3747,7 +4709,8 @@ static unsigned long get_nr_to_scan(stru if (current_is_kswapd()) return 0; @@ -1653,7 +1633,7 @@ index 1d0b25ae378c..a7844c689522 100644 done: return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; } -@@ -3761,6 +4724,8 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -3761,6 +4724,8 @@ static void lru_gen_shrink_lruvec(struct blk_start_plug(&plug); @@ -1662,7 +1642,7 @@ index 1d0b25ae378c..a7844c689522 100644 while (true) { int delta; int swappiness; -@@ -3788,6 +4753,8 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -3788,6 +4753,8 @@ static void lru_gen_shrink_lruvec(struct cond_resched(); } @@ -1671,7 +1651,7 @@ index 1d0b25ae378c..a7844c689522 100644 blk_finish_plug(&plug); } -@@ -3804,15 +4771,21 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) +@@ -3804,15 +4771,21 @@ void lru_gen_init_lruvec(struct lruvec * for_each_gen_type_zone(gen, type, zone) INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); @@ -1693,7 +1673,7 @@ index 1d0b25ae378c..a7844c689522 100644 int nid; for_each_node(nid) { -@@ -3820,6 +4793,11 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) +@@ -3820,6 +4793,11 @@ void lru_gen_exit_memcg(struct mem_cgrou VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, sizeof(lruvec->lrugen.nr_pages))); @@ -1705,6 +1685,3 @@ index 1d0b25ae378c..a7844c689522 100644 } } #endif --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch b/target/linux/generic/backport-5.15/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch index e47bfc36d46..b5fb1951514 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch @@ -134,8 +134,6 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 9 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index a7844c689522..b6f6fc2585e1 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -127,6 +127,12 @@ struct scan_control { @@ -151,7 +149,7 @@ index a7844c689522..b6f6fc2585e1 100644 /* Allocation order */ s8 order; -@@ -4202,6 +4208,19 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +@@ -4202,6 +4208,19 @@ static void lru_gen_age_node(struct pgli VM_WARN_ON_ONCE(!current_is_kswapd()); @@ -171,7 +169,7 @@ index a7844c689522..b6f6fc2585e1 100644 set_mm_walk(pgdat); memcg = mem_cgroup_iter(NULL, NULL, NULL); -@@ -4613,7 +4632,8 @@ static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swa +@@ -4613,7 +4632,8 @@ static int isolate_pages(struct lruvec * return scanned; } @@ -181,7 +179,7 @@ index a7844c689522..b6f6fc2585e1 100644 { int type; int scanned; -@@ -4676,6 +4696,9 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -4676,6 +4696,9 @@ static int evict_pages(struct lruvec *lr sc->nr_reclaimed += reclaimed; @@ -191,7 +189,7 @@ index a7844c689522..b6f6fc2585e1 100644 return scanned; } -@@ -4685,9 +4708,8 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -4685,9 +4708,8 @@ static int evict_pages(struct lruvec *lr * reclaim. */ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, @@ -202,7 +200,7 @@ index a7844c689522..b6f6fc2585e1 100644 unsigned long nr_to_scan; struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); -@@ -4697,8 +4719,8 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * +@@ -4697,8 +4719,8 @@ static unsigned long get_nr_to_scan(stru (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) return 0; @@ -213,7 +211,7 @@ index a7844c689522..b6f6fc2585e1 100644 return nr_to_scan; /* skip the aging path at the default priority */ -@@ -4715,10 +4737,68 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * +@@ -4715,10 +4737,68 @@ done: return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; } @@ -282,7 +280,7 @@ index a7844c689522..b6f6fc2585e1 100644 lru_add_drain(); -@@ -4738,21 +4818,28 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -4738,21 +4818,28 @@ static void lru_gen_shrink_lruvec(struct else swappiness = 0; @@ -315,6 +313,3 @@ index a7844c689522..b6f6fc2585e1 100644 clear_mm_walk(); blk_finish_plug(&plug); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch b/target/linux/generic/backport-5.15/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch index 0adb15f5e24..cf5b8f0e9f7 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch @@ -87,11 +87,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 228 +++++++++++++++++++++++++++++++- 6 files changed, 265 insertions(+), 9 deletions(-) -diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h -index 45cdb12243e3..f9a5d6a81101 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h -@@ -433,6 +433,18 @@ static inline void cgroup_put(struct cgroup *cgrp) +@@ -433,6 +433,18 @@ static inline void cgroup_put(struct cgr css_put(&cgrp->self); } @@ -110,7 +108,7 @@ index 45cdb12243e3..f9a5d6a81101 100644 /** * task_css_set_check - obtain a task's css_set with extra access conditions * @task: the task to obtain css_set for -@@ -447,7 +459,6 @@ static inline void cgroup_put(struct cgroup *cgrp) +@@ -447,7 +459,6 @@ static inline void cgroup_put(struct cgr * as locks used during the cgroup_subsys::attach() methods. */ #ifdef CONFIG_PROVE_RCU @@ -127,11 +125,9 @@ index 45cdb12243e3..f9a5d6a81101 100644 static inline int cgroup_attach_task_all(struct task_struct *from, struct task_struct *t) { return 0; } static inline int cgroupstats_build(struct cgroupstats *stats, -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index 58aabb1ba020..e095c1c24311 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -91,10 +91,21 @@ static __always_inline enum lru_list page_lru(struct page *page) +@@ -91,10 +91,21 @@ static __always_inline enum lru_list pag #ifdef CONFIG_LRU_GEN @@ -154,7 +150,7 @@ index 58aabb1ba020..e095c1c24311 100644 static inline bool lru_gen_in_fault(void) { -@@ -207,7 +218,7 @@ static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bo +@@ -207,7 +218,7 @@ static inline bool lru_gen_add_page(stru VM_WARN_ON_ONCE_PAGE(gen != -1, page); @@ -163,8 +159,6 @@ index 58aabb1ba020..e095c1c24311 100644 return false; /* * There are three common cases for this page: -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index 659bab633bdf..edaf035503ed 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -364,6 +364,13 @@ enum { @@ -190,8 +184,6 @@ index 659bab633bdf..edaf035503ed 100644 }; enum { -diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h -index d8fcc139ac05..28c32a01da7d 100644 --- a/kernel/cgroup/cgroup-internal.h +++ b/kernel/cgroup/cgroup-internal.h @@ -165,7 +165,6 @@ struct cgroup_mgctx { @@ -202,8 +194,6 @@ index d8fcc139ac05..28c32a01da7d 100644 extern spinlock_t css_set_lock; extern struct cgroup_subsys *cgroup_subsys[]; extern struct list_head cgroup_roots; -diff --git a/mm/Kconfig b/mm/Kconfig -index 62433f3cd7ae..4a7d0af3c39b 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -906,6 +906,12 @@ config LRU_GEN @@ -219,8 +209,6 @@ index 62433f3cd7ae..4a7d0af3c39b 100644 config LRU_GEN_STATS bool "Full stats for debugging" depends on LRU_GEN -diff --git a/mm/vmscan.c b/mm/vmscan.c -index b6f6fc2585e1..be37d996bc92 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -52,6 +52,7 @@ @@ -231,7 +219,7 @@ index b6f6fc2585e1..be37d996bc92 100644 #include #include -@@ -2841,6 +2842,14 @@ static bool can_age_anon_pages(struct pglist_data *pgdat, +@@ -2841,6 +2842,14 @@ static bool can_age_anon_pages(struct pg #ifdef CONFIG_LRU_GEN @@ -246,7 +234,7 @@ index b6f6fc2585e1..be37d996bc92 100644 /****************************************************************************** * shorthand helpers ******************************************************************************/ -@@ -3717,7 +3726,8 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area +@@ -3717,7 +3726,8 @@ static void walk_pmd_range_locked(pud_t goto next; if (!pmd_trans_huge(pmd[i])) { @@ -256,7 +244,7 @@ index b6f6fc2585e1..be37d996bc92 100644 pmdp_test_and_clear_young(vma, addr, pmd + i); goto next; } -@@ -3815,10 +3825,12 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, +@@ -3815,10 +3825,12 @@ restart: walk->mm_stats[MM_NONLEAF_TOTAL]++; #ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG @@ -272,7 +260,7 @@ index b6f6fc2585e1..be37d996bc92 100644 #endif if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) continue; -@@ -4080,7 +4092,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4080,7 +4092,7 @@ static bool try_to_inc_max_seq(struct lr * handful of PTEs. Spreading the work out over a period of time usually * is less efficient, but it avoids bursty page faults. */ @@ -281,11 +269,10 @@ index b6f6fc2585e1..be37d996bc92 100644 success = iterate_mm_list_nowalk(lruvec, max_seq); goto done; } -@@ -4845,6 +4857,208 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc - blk_finish_plug(&plug); +@@ -4846,6 +4858,208 @@ done: } -+/****************************************************************************** + /****************************************************************************** + * state change + ******************************************************************************/ + @@ -487,10 +474,11 @@ index b6f6fc2585e1..be37d996bc92 100644 + .attrs = lru_gen_attrs, +}; + - /****************************************************************************** ++/****************************************************************************** * initialization ******************************************************************************/ -@@ -4855,6 +5069,7 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) + +@@ -4855,6 +5069,7 @@ void lru_gen_init_lruvec(struct lruvec * struct lru_gen_struct *lrugen = &lruvec->lrugen; lrugen->max_seq = MIN_NR_GENS + 1; @@ -508,6 +496,3 @@ index b6f6fc2585e1..be37d996bc92 100644 return 0; }; late_initcall(init_lru_gen); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch b/target/linux/generic/backport-5.15/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch index 5b1ed03ca92..30e20aff6ed 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch @@ -68,8 +68,6 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 74 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 3 deletions(-) -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index edaf035503ed..6b85ba1f4e18 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -399,6 +399,8 @@ struct lru_gen_struct { @@ -81,11 +79,9 @@ index edaf035503ed..6b85ba1f4e18 100644 /* the multi-gen LRU lists, lazily sorted on eviction */ struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; /* the multi-gen LRU sizes, eventually consistent */ -diff --git a/mm/vmscan.c b/mm/vmscan.c -index be37d996bc92..642ee7bef61d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4064,6 +4064,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap) +@@ -4064,6 +4064,7 @@ static void inc_max_seq(struct lruvec *l for (type = 0; type < ANON_AND_FILE; type++) reset_ctrl_pos(lruvec, type, false); @@ -93,7 +89,7 @@ index be37d996bc92..642ee7bef61d 100644 /* make sure preceding modifications appear */ smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); -@@ -4193,7 +4194,7 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig +@@ -4193,7 +4194,7 @@ static bool should_run_aging(struct lruv return false; } @@ -102,7 +98,7 @@ index be37d996bc92..642ee7bef61d 100644 { bool need_aging; unsigned long nr_to_scan; -@@ -4207,16 +4208,36 @@ static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -4207,16 +4208,36 @@ static void age_lruvec(struct lruvec *lr mem_cgroup_calculate_protection(NULL, memcg); if (mem_cgroup_below_min(memcg)) @@ -140,7 +136,7 @@ index be37d996bc92..642ee7bef61d 100644 VM_WARN_ON_ONCE(!current_is_kswapd()); -@@ -4239,12 +4260,32 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +@@ -4239,12 +4260,32 @@ static void lru_gen_age_node(struct pgli do { struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); @@ -174,7 +170,7 @@ index be37d996bc92..642ee7bef61d 100644 } /* -@@ -5002,6 +5043,28 @@ static void lru_gen_change_state(bool enabled) +@@ -5002,6 +5043,28 @@ unlock: * sysfs interface ******************************************************************************/ @@ -203,7 +199,7 @@ index be37d996bc92..642ee7bef61d 100644 static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { unsigned int caps = 0; -@@ -5050,6 +5113,7 @@ static struct kobj_attribute lru_gen_enabled_attr = __ATTR( +@@ -5050,6 +5113,7 @@ static struct kobj_attribute lru_gen_ena ); static struct attribute *lru_gen_attrs[] = { @@ -211,7 +207,7 @@ index be37d996bc92..642ee7bef61d 100644 &lru_gen_enabled_attr.attr, NULL }; -@@ -5065,12 +5129,16 @@ static struct attribute_group lru_gen_attr_group = { +@@ -5065,12 +5129,16 @@ static struct attribute_group lru_gen_at void lru_gen_init_lruvec(struct lruvec *lruvec) { @@ -228,6 +224,3 @@ index be37d996bc92..642ee7bef61d 100644 for_each_gen_type_zone(gen, type, zone) INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch b/target/linux/generic/backport-5.15/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch index ae9d76faa45..482e714bb6a 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch @@ -64,11 +64,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 411 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 402 insertions(+), 10 deletions(-) -diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h -index 0f233b76c9ce..292ec0ce0d63 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h -@@ -485,6 +485,7 @@ static inline int num_node_state(enum node_states state) +@@ -485,6 +485,7 @@ static inline int num_node_state(enum no #define first_online_node 0 #define first_memory_node 0 #define next_online_node(nid) (MAX_NUMNODES) @@ -76,8 +74,6 @@ index 0f233b76c9ce..292ec0ce0d63 100644 #define nr_node_ids 1U #define nr_online_nodes 1U -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 642ee7bef61d..b74b334488d8 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -53,6 +53,7 @@ @@ -130,7 +126,7 @@ index 642ee7bef61d..b74b334488d8 100644 } static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) -@@ -4019,7 +4048,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +@@ -4019,7 +4048,7 @@ next: return success; } @@ -139,7 +135,7 @@ index 642ee7bef61d..b74b334488d8 100644 { int prev, next; int type, zone; -@@ -4033,9 +4062,13 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap) +@@ -4033,9 +4062,13 @@ static void inc_max_seq(struct lruvec *l if (get_nr_gens(lruvec, type) != MAX_NR_GENS) continue; @@ -155,7 +151,7 @@ index 642ee7bef61d..b74b334488d8 100644 } /* -@@ -4072,7 +4105,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap) +@@ -4072,7 +4105,7 @@ static void inc_max_seq(struct lruvec *l } static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, @@ -164,7 +160,7 @@ index 642ee7bef61d..b74b334488d8 100644 { bool success; struct lru_gen_mm_walk *walk; -@@ -4093,7 +4126,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4093,7 +4126,7 @@ static bool try_to_inc_max_seq(struct lr * handful of PTEs. Spreading the work out over a period of time usually * is less efficient, but it avoids bursty page faults. */ @@ -173,7 +169,7 @@ index 642ee7bef61d..b74b334488d8 100644 success = iterate_mm_list_nowalk(lruvec, max_seq); goto done; } -@@ -4107,7 +4140,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4107,7 +4140,7 @@ static bool try_to_inc_max_seq(struct lr walk->lruvec = lruvec; walk->max_seq = max_seq; walk->can_swap = can_swap; @@ -182,7 +178,7 @@ index 642ee7bef61d..b74b334488d8 100644 do { success = iterate_mm_list(lruvec, walk, &mm); -@@ -4127,7 +4160,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4127,7 +4160,7 @@ done: VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); @@ -191,7 +187,7 @@ index 642ee7bef61d..b74b334488d8 100644 /* either this sees any waiters or they will see updated max_seq */ if (wq_has_sleeper(&lruvec->mm_state.wait)) wake_up_all(&lruvec->mm_state.wait); -@@ -4225,7 +4258,7 @@ static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, unsigned +@@ -4225,7 +4258,7 @@ static bool age_lruvec(struct lruvec *lr } if (need_aging) @@ -200,7 +196,7 @@ index 642ee7bef61d..b74b334488d8 100644 return true; } -@@ -4784,7 +4817,7 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * +@@ -4784,7 +4817,7 @@ static unsigned long get_nr_to_scan(stru if (current_is_kswapd()) return 0; @@ -209,11 +205,10 @@ index 642ee7bef61d..b74b334488d8 100644 return nr_to_scan; done: return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; -@@ -5123,6 +5156,361 @@ static struct attribute_group lru_gen_attr_group = { - .attrs = lru_gen_attrs, +@@ -5124,6 +5157,361 @@ static struct attribute_group lru_gen_at }; -+/****************************************************************************** + /****************************************************************************** + * debugfs interface + ******************************************************************************/ + @@ -568,9 +563,10 @@ index 642ee7bef61d..b74b334488d8 100644 + .release = seq_release, +}; + - /****************************************************************************** ++/****************************************************************************** * initialization ******************************************************************************/ + @@ -5180,6 +5568,9 @@ static int __init init_lru_gen(void) if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) pr_err("lru_gen: failed to create sysfs group\n"); @@ -581,6 +577,3 @@ index 642ee7bef61d..b74b334488d8 100644 return 0; }; late_initcall(init_lru_gen); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch b/target/linux/generic/backport-5.15/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch index a2318499e79..fd4aa727473 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch @@ -19,11 +19,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 2 -- 1 file changed, 2 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index b74b334488d8..1c0875e6514a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4165,8 +4165,6 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4165,8 +4165,6 @@ done: if (wq_has_sleeper(&lruvec->mm_state.wait)) wake_up_all(&lruvec->mm_state.wait); @@ -32,6 +30,3 @@ index b74b334488d8..1c0875e6514a 100644 return true; } --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch b/target/linux/generic/backport-5.15/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch index ffdebafa2ce..31b35cbc4b6 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch @@ -43,11 +43,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 1c0875e6514a..27bc525380f9 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4723,10 +4723,13 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -4723,10 +4723,13 @@ static int evict_pages(struct lruvec *lr int scanned; int reclaimed; LIST_HEAD(list); @@ -61,7 +59,7 @@ index 1c0875e6514a..27bc525380f9 100644 struct mem_cgroup *memcg = lruvec_memcg(lruvec); struct pglist_data *pgdat = lruvec_pgdat(lruvec); -@@ -4743,20 +4746,37 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -4743,20 +4746,37 @@ static int evict_pages(struct lruvec *lr if (list_empty(&list)) return scanned; @@ -109,7 +107,7 @@ index 1c0875e6514a..27bc525380f9 100644 } spin_lock_irq(&lruvec->lru_lock); -@@ -4778,7 +4798,13 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -4778,7 +4798,13 @@ static int evict_pages(struct lruvec *lr mem_cgroup_uncharge_list(&list); free_unref_page_list(&list); @@ -124,6 +122,3 @@ index 1c0875e6514a..27bc525380f9 100644 if (need_swapping && type == LRU_GEN_ANON) *need_swapping = true; --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch b/target/linux/generic/backport-5.15/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch index 7dc296b5b35..5b1d378504a 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch @@ -29,11 +29,9 @@ Signed-off-by: Andrew Morton fs/exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/fs/exec.c b/fs/exec.c -index 1afa15a07d26..718c58947be1 100644 --- a/fs/exec.c +++ b/fs/exec.c -@@ -1013,7 +1013,6 @@ static int exec_mmap(struct mm_struct *mm) +@@ -1013,7 +1013,6 @@ static int exec_mmap(struct mm_struct *m active_mm = tsk->active_mm; tsk->active_mm = mm; tsk->mm = mm; @@ -41,7 +39,7 @@ index 1afa15a07d26..718c58947be1 100644 /* * This prevents preemption while active_mm is being loaded and * it and mm are being updated, which could cause problems for -@@ -1028,6 +1027,7 @@ static int exec_mmap(struct mm_struct *mm) +@@ -1028,6 +1027,7 @@ static int exec_mmap(struct mm_struct *m local_irq_enable(); tsk->mm->vmacache_seqnum = 0; vmacache_flush(tsk); @@ -49,6 +47,3 @@ index 1afa15a07d26..718c58947be1 100644 task_unlock(tsk); lru_gen_use_mm(mm); if (old_mm) { --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch b/target/linux/generic/backport-5.15/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch index 4e11e821153..c91252eb6b2 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch @@ -28,11 +28,9 @@ Signed-off-by: Andrew Morton include/linux/pgtable.h | 7 +++++++ 6 files changed, 12 insertions(+) -diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h -index 804889b70965..89ab8b4cf971 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h -@@ -632,6 +632,7 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd) +@@ -632,6 +632,7 @@ static inline pmd_t pmd_mkdirty(pmd_t pm return pmd; } @@ -40,8 +38,6 @@ index 804889b70965..89ab8b4cf971 100644 static inline int pmd_young(pmd_t pmd) { return !!(pmd_val(pmd) & _PAGE_ACCESSED); -diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h -index 39b550310ec6..4a64e03dcdd4 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -531,6 +531,7 @@ static inline int pmd_dirty(pmd_t pmd) @@ -52,8 +48,6 @@ index 39b550310ec6..4a64e03dcdd4 100644 static inline int pmd_young(pmd_t pmd) { return pte_young(pmd_pte(pmd)); -diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h -index b61426c9ef17..55ff4f22da2d 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -748,6 +748,7 @@ static inline int pmd_dirty(pmd_t pmd) @@ -64,11 +58,9 @@ index b61426c9ef17..55ff4f22da2d 100644 static inline int pmd_young(pmd_t pmd) { return (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) != 0; -diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h -index 4679e45c8348..bfd10179c137 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h -@@ -712,6 +712,7 @@ static inline unsigned long pmd_dirty(pmd_t pmd) +@@ -712,6 +712,7 @@ static inline unsigned long pmd_dirty(pm return pte_dirty(pte); } @@ -76,8 +68,6 @@ index 4679e45c8348..bfd10179c137 100644 static inline unsigned long pmd_young(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); -diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h -index 01a1763123ff..c4b64ee357fd 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -136,6 +136,7 @@ static inline int pmd_dirty(pmd_t pmd) @@ -88,11 +78,9 @@ index 01a1763123ff..c4b64ee357fd 100644 static inline int pmd_young(pmd_t pmd) { return pmd_flags(pmd) & _PAGE_ACCESSED; -diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h -index e6889556e0bf..dec3d890e814 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h -@@ -164,6 +164,13 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr) +@@ -164,6 +164,13 @@ static inline pte_t *virt_to_kpte(unsign return pmd_none(*pmd) ? NULL : pte_offset_kernel(pmd, vaddr); } @@ -106,6 +94,3 @@ index e6889556e0bf..dec3d890e814 100644 #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, pte_t *ptep, --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch b/target/linux/generic/backport-5.15/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch index 4c4a2d11f2b..9a1f9bead6c 100644 --- a/target/linux/generic/backport-5.15/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch +++ b/target/linux/generic/backport-5.15/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch @@ -36,11 +36,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 10 +++++----- 3 files changed, 24 insertions(+), 5 deletions(-) -diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h -index c4b64ee357fd..d8363c676496 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h -@@ -1405,6 +1405,14 @@ static inline bool arch_has_hw_pte_young(void) +@@ -1405,6 +1405,14 @@ static inline bool arch_has_hw_pte_young return true; } @@ -55,11 +53,9 @@ index c4b64ee357fd..d8363c676496 100644 #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_PGTABLE_H */ -diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h -index dec3d890e814..562b4cc82b33 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h -@@ -266,6 +266,17 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, +@@ -266,6 +266,17 @@ static inline int pmdp_clear_flush_young #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif @@ -77,11 +73,9 @@ index dec3d890e814..562b4cc82b33 100644 #ifndef arch_has_hw_pte_young /* * Return whether the accessed bit is supported on the local CPU. -diff --git a/mm/vmscan.c b/mm/vmscan.c -index d310e0b9e520..96f1af44bb77 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3730,7 +3730,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area +@@ -3727,7 +3727,7 @@ static void walk_pmd_range_locked(pud_t goto next; if (!pmd_trans_huge(pmd[i])) { @@ -90,7 +84,7 @@ index d310e0b9e520..96f1af44bb77 100644 get_cap(LRU_GEN_NONLEAF_YOUNG)) pmdp_test_and_clear_young(vma, addr, pmd + i); goto next; -@@ -3828,14 +3828,14 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, +@@ -3825,14 +3825,14 @@ restart: #endif walk->mm_stats[MM_NONLEAF_TOTAL]++; @@ -108,7 +102,7 @@ index d310e0b9e520..96f1af44bb77 100644 if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) continue; -@@ -5135,7 +5135,7 @@ static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, c +@@ -5132,7 +5132,7 @@ static ssize_t show_enabled(struct kobje if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) caps |= BIT(LRU_GEN_MM_WALK); @@ -117,6 +111,3 @@ index d310e0b9e520..96f1af44bb77 100644 caps |= BIT(LRU_GEN_NONLEAF_YOUNG); return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch b/target/linux/generic/backport-5.15/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch index a8cd1fca1b0..e37386abdf1 100644 --- a/target/linux/generic/backport-5.15/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch +++ b/target/linux/generic/backport-5.15/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch @@ -34,11 +34,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 27bc525380f9..d310e0b9e520 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3024,13 +3024,16 @@ void lru_gen_migrate_mm(struct mm_struct *mm) +@@ -3024,13 +3024,16 @@ void lru_gen_migrate_mm(struct mm_struct if (mem_cgroup_disabled()) return; @@ -56,6 +54,3 @@ index 27bc525380f9..d310e0b9e520 100644 VM_WARN_ON_ONCE(list_empty(&mm->lru_gen.list)); lru_gen_del_mm(mm); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-19-mm-add-vma_has_recency.patch b/target/linux/generic/backport-5.15/020-v6.3-19-mm-add-vma_has_recency.patch index 542bb0c3a83..6154bbe3528 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-19-mm-add-vma_has_recency.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-19-mm-add-vma_has_recency.patch @@ -56,11 +56,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 5 ++++- 4 files changed, 35 insertions(+), 29 deletions(-) -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index e095c1c24311..e8c723053a52 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -333,4 +333,13 @@ static __always_inline void del_page_from_lru_list(struct page *page, +@@ -333,4 +333,13 @@ static __always_inline void del_page_fro update_lru_size(lruvec, page_lru(page), page_zonenum(page), -thp_nr_pages(page)); } @@ -74,8 +72,6 @@ index e095c1c24311..e8c723053a52 100644 +} + #endif -diff --git a/mm/memory.c b/mm/memory.c -index 7d5be951de9e..1306b1ff0c10 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -41,6 +41,7 @@ @@ -86,7 +82,7 @@ index 7d5be951de9e..1306b1ff0c10 100644 #include #include #include -@@ -1353,8 +1354,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb, +@@ -1353,8 +1354,7 @@ again: force_flush = 1; set_page_dirty(page); } @@ -96,7 +92,7 @@ index 7d5be951de9e..1306b1ff0c10 100644 mark_page_accessed(page); } rss[mm_counter(page)]--; -@@ -4781,8 +4781,8 @@ static inline void mm_account_fault(struct pt_regs *regs, +@@ -4781,8 +4781,8 @@ static inline void mm_account_fault(stru #ifdef CONFIG_LRU_GEN static void lru_gen_enter_fault(struct vm_area_struct *vma) { @@ -107,11 +103,9 @@ index 7d5be951de9e..1306b1ff0c10 100644 } static void lru_gen_exit_fault(void) -diff --git a/mm/rmap.c b/mm/rmap.c -index 22a86122732e..53df47753f3c 100644 --- a/mm/rmap.c +++ b/mm/rmap.c -@@ -794,25 +794,14 @@ static bool page_referenced_one(struct page *page, struct vm_area_struct *vma, +@@ -794,25 +794,14 @@ static bool page_referenced_one(struct p } if (pvmw.pte) { @@ -140,7 +134,7 @@ index 22a86122732e..53df47753f3c 100644 } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { if (pmdp_clear_flush_young_notify(vma, address, pvmw.pmd)) -@@ -846,7 +835,20 @@ static bool invalid_page_referenced_vma(struct vm_area_struct *vma, void *arg) +@@ -846,7 +835,20 @@ static bool invalid_page_referenced_vma( struct page_referenced_arg *pra = arg; struct mem_cgroup *memcg = pra->memcg; @@ -186,11 +180,9 @@ index 22a86122732e..53df47753f3c 100644 rmap_walk(page, &rwc); *vm_flags = pra.vm_flags; -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 96f1af44bb77..4ab376abeaae 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3486,7 +3486,10 @@ static int should_skip_vma(unsigned long start, unsigned long end, struct mm_wal +@@ -3486,7 +3486,10 @@ static int should_skip_vma(unsigned long if (is_vm_hugetlb_page(vma)) return true; @@ -202,6 +194,3 @@ index 96f1af44bb77..4ab376abeaae 100644 return true; if (vma == get_gate_vma(vma->vm_mm)) --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch b/target/linux/generic/backport-5.15/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch index 75f74114c67..3bb075bf367 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch @@ -79,11 +79,9 @@ Signed-off-by: Andrew Morton mm/fadvise.c | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 23ecfecdc450..601e52991f4a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -167,6 +167,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, +@@ -167,6 +167,8 @@ typedef int (dio_iodone_t)(struct kiocb /* File is stream-like */ #define FMODE_STREAM ((__force fmode_t)0x200000) @@ -92,11 +90,9 @@ index 23ecfecdc450..601e52991f4a 100644 /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index e8c723053a52..8a6a2a23f9b6 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -339,6 +339,9 @@ static inline bool vma_has_recency(struct vm_area_struct *vma) +@@ -339,6 +339,9 @@ static inline bool vma_has_recency(struc if (vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)) return false; @@ -106,11 +102,9 @@ index e8c723053a52..8a6a2a23f9b6 100644 return true; } -diff --git a/mm/fadvise.c b/mm/fadvise.c -index d6baa4f451c5..e8023c69f219 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c -@@ -80,7 +80,7 @@ int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice) +@@ -80,7 +80,7 @@ int generic_fadvise(struct file *file, l case POSIX_FADV_NORMAL: file->f_ra.ra_pages = bdi->ra_pages; spin_lock(&file->f_lock); @@ -119,7 +113,7 @@ index d6baa4f451c5..e8023c69f219 100644 spin_unlock(&file->f_lock); break; case POSIX_FADV_RANDOM: -@@ -107,6 +107,9 @@ int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice) +@@ -107,6 +107,9 @@ int generic_fadvise(struct file *file, l force_page_cache_readahead(mapping, file, start_index, nrpages); break; case POSIX_FADV_NOREUSE: @@ -129,6 +123,3 @@ index d6baa4f451c5..e8023c69f219 100644 break; case POSIX_FADV_DONTNEED: if (!inode_write_congested(mapping->host)) --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch b/target/linux/generic/backport-5.15/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch index 836a16b8c77..4e09173681f 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch @@ -122,11 +122,9 @@ Signed-off-by: Andrew Morton mm/workingset.c | 4 ++-- 4 files changed, 24 insertions(+), 24 deletions(-) -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index 8a6a2a23f9b6..27c4890503c5 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -168,7 +168,7 @@ static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, +@@ -168,7 +168,7 @@ static inline void lru_gen_update_size(s int zone = page_zonenum(page); int delta = thp_nr_pages(page); enum lru_list lru = type * LRU_INACTIVE_FILE; @@ -135,7 +133,7 @@ index 8a6a2a23f9b6..27c4890503c5 100644 VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); -@@ -214,7 +214,7 @@ static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bo +@@ -214,7 +214,7 @@ static inline bool lru_gen_add_page(stru int gen = page_lru_gen(page); int type = page_is_file_lru(page); int zone = page_zonenum(page); @@ -144,8 +142,6 @@ index 8a6a2a23f9b6..27c4890503c5 100644 VM_WARN_ON_ONCE_PAGE(gen != -1, page); -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index 6b85ba1f4e18..5856b026c089 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -394,7 +394,7 @@ enum { @@ -175,11 +171,9 @@ index 6b85ba1f4e18..5856b026c089 100644 /* to concurrently iterate lru_gen_mm_list */ struct lru_gen_mm_state mm_state; #endif -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 4ab376abeaae..3b1b5bd9736a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -2910,7 +2910,7 @@ static int get_nr_gens(struct lruvec *lruvec, int type) +@@ -2910,7 +2910,7 @@ static int get_nr_gens(struct lruvec *lr static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) { @@ -197,7 +191,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 int hist = lru_hist_from_seq(lrugen->min_seq[type]); pos->refaulted = lrugen->avg_refaulted[type][tier] + -@@ -3331,7 +3331,7 @@ static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain, +@@ -3331,7 +3331,7 @@ static void read_ctrl_pos(struct lruvec static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) { int hist, tier; @@ -206,7 +200,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; -@@ -3408,7 +3408,7 @@ static int page_update_gen(struct page *page, int gen) +@@ -3408,7 +3408,7 @@ static int page_update_gen(struct page * static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) { int type = page_is_file_lru(page); @@ -215,7 +209,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); unsigned long new_flags, old_flags = READ_ONCE(page->flags); -@@ -3453,7 +3453,7 @@ static void update_batch_size(struct lru_gen_mm_walk *walk, struct page *page, +@@ -3453,7 +3453,7 @@ static void update_batch_size(struct lru static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) { int gen, type, zone; @@ -224,7 +218,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 walk->batched = 0; -@@ -3979,7 +3979,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) +@@ -3979,7 +3979,7 @@ static bool inc_min_seq(struct lruvec *l { int zone; int remaining = MAX_LRU_BATCH; @@ -233,7 +227,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); if (type == LRU_GEN_ANON && !can_swap) -@@ -4015,7 +4015,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +@@ -4015,7 +4015,7 @@ static bool try_to_inc_min_seq(struct lr { int gen, type, zone; bool success = false; @@ -242,7 +236,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 DEFINE_MIN_SEQ(lruvec); VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); -@@ -4036,7 +4036,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +@@ -4036,7 +4036,7 @@ next: ; } @@ -251,7 +245,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 if (can_swap) { min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); -@@ -4058,7 +4058,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan) +@@ -4058,7 +4058,7 @@ static void inc_max_seq(struct lruvec *l { int prev, next; int type, zone; @@ -260,7 +254,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 spin_lock_irq(&lruvec->lru_lock); -@@ -4116,7 +4116,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4116,7 +4116,7 @@ static bool try_to_inc_max_seq(struct lr bool success; struct lru_gen_mm_walk *walk; struct mm_struct *mm = NULL; @@ -269,7 +263,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); -@@ -4181,7 +4181,7 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig +@@ -4181,7 +4181,7 @@ static bool should_run_aging(struct lruv unsigned long old = 0; unsigned long young = 0; unsigned long total = 0; @@ -278,7 +272,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 struct mem_cgroup *memcg = lruvec_memcg(lruvec); for (type = !can_swap; type < ANON_AND_FILE; type++) { -@@ -4466,7 +4466,7 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) +@@ -4466,7 +4466,7 @@ static bool sort_page(struct lruvec *lru int delta = thp_nr_pages(page); int refs = page_lru_refs(page); int tier = lru_tier_from_refs(refs); @@ -287,7 +281,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 VM_WARN_ON_ONCE_PAGE(gen >= MAX_NR_GENS, page); -@@ -4566,7 +4566,7 @@ static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, +@@ -4566,7 +4566,7 @@ static int scan_pages(struct lruvec *lru int scanned = 0; int isolated = 0; int remaining = MAX_LRU_BATCH; @@ -296,7 +290,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 struct mem_cgroup *memcg = lruvec_memcg(lruvec); VM_WARN_ON_ONCE(!list_empty(list)); -@@ -4967,7 +4967,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -4967,7 +4967,7 @@ done: static bool __maybe_unused state_is_valid(struct lruvec *lruvec) { @@ -305,7 +299,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 if (lrugen->enabled) { enum lru_list lru; -@@ -5247,7 +5247,7 @@ static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, +@@ -5247,7 +5247,7 @@ static void lru_gen_seq_show_full(struct int i; int type, tier; int hist = lru_hist_from_seq(seq); @@ -314,7 +308,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 for (tier = 0; tier < MAX_NR_TIERS; tier++) { seq_printf(m, " %10d", tier); -@@ -5296,7 +5296,7 @@ static int lru_gen_seq_show(struct seq_file *m, void *v) +@@ -5296,7 +5296,7 @@ static int lru_gen_seq_show(struct seq_f unsigned long seq; bool full = !debugfs_real_fops(m->file)->write; struct lruvec *lruvec = v; @@ -323,7 +317,7 @@ index 4ab376abeaae..3b1b5bd9736a 100644 int nid = lruvec_pgdat(lruvec)->node_id; struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); -@@ -5549,7 +5549,7 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) +@@ -5549,7 +5549,7 @@ void lru_gen_init_lruvec(struct lruvec * { int i; int gen, type, zone; @@ -332,11 +326,9 @@ index 4ab376abeaae..3b1b5bd9736a 100644 lrugen->max_seq = MIN_NR_GENS + 1; lrugen->enabled = lru_gen_enabled(); -diff --git a/mm/workingset.c b/mm/workingset.c -index aeba62cebf8c..a5e1798c6d60 100644 --- a/mm/workingset.c +++ b/mm/workingset.c -@@ -223,7 +223,7 @@ static void *lru_gen_eviction(struct page *page) +@@ -223,7 +223,7 @@ static void *lru_gen_eviction(struct pag unsigned long token; unsigned long min_seq; struct lruvec *lruvec; @@ -345,7 +337,7 @@ index aeba62cebf8c..a5e1798c6d60 100644 int type = page_is_file_lru(page); int delta = thp_nr_pages(page); int refs = page_lru_refs(page); -@@ -252,7 +252,7 @@ static void lru_gen_refault(struct page *page, void *shadow) +@@ -252,7 +252,7 @@ static void lru_gen_refault(struct page unsigned long token; unsigned long min_seq; struct lruvec *lruvec; @@ -354,6 +346,3 @@ index aeba62cebf8c..a5e1798c6d60 100644 struct mem_cgroup *memcg; struct pglist_data *pgdat; int type = page_is_file_lru(page); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch b/target/linux/generic/backport-5.15/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch index 2e1783661dd..b548c1c8b3d 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch @@ -23,11 +23,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index 27c4890503c5..4adc9ba59569 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -246,9 +246,9 @@ static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bo +@@ -246,9 +246,9 @@ static inline bool lru_gen_add_page(stru lru_gen_update_size(lruvec, page, -1, gen); /* for rotate_reclaimable_page() */ if (reclaiming) @@ -39,8 +37,6 @@ index 27c4890503c5..4adc9ba59569 100644 return true; } -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index 5856b026c089..7b8a26aaf381 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -302,7 +302,7 @@ enum lruvec_flags { @@ -72,11 +68,9 @@ index 5856b026c089..7b8a26aaf381 100644 /* the multi-gen LRU sizes, eventually consistent */ long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; /* the exponential moving average of refaulted */ -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 3b1b5bd9736a..2322c913aa64 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3987,7 +3987,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) +@@ -3987,7 +3987,7 @@ static bool inc_min_seq(struct lruvec *l /* prevent cold/hot inversion if force_scan is true */ for (zone = 0; zone < MAX_NR_ZONES; zone++) { @@ -85,7 +79,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 while (!list_empty(head)) { struct page *page = lru_to_page(head); -@@ -3998,7 +3998,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) +@@ -3998,7 +3998,7 @@ static bool inc_min_seq(struct lruvec *l VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); new_gen = page_inc_gen(lruvec, page, false); @@ -94,7 +88,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 if (!--remaining) return false; -@@ -4026,7 +4026,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +@@ -4026,7 +4026,7 @@ static bool try_to_inc_min_seq(struct lr gen = lru_gen_from_seq(min_seq[type]); for (zone = 0; zone < MAX_NR_ZONES; zone++) { @@ -103,7 +97,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 goto next; } -@@ -4491,7 +4491,7 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) +@@ -4491,7 +4491,7 @@ static bool sort_page(struct lruvec *lru /* promoted */ if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { @@ -112,7 +106,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 return true; } -@@ -4500,7 +4500,7 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) +@@ -4500,7 +4500,7 @@ static bool sort_page(struct lruvec *lru int hist = lru_hist_from_seq(lrugen->min_seq[type]); gen = page_inc_gen(lruvec, page, false); @@ -121,7 +115,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 WRITE_ONCE(lrugen->protected[hist][type][tier - 1], lrugen->protected[hist][type][tier - 1] + delta); -@@ -4512,7 +4512,7 @@ static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) +@@ -4512,7 +4512,7 @@ static bool sort_page(struct lruvec *lru if (PageLocked(page) || PageWriteback(page) || (type == LRU_GEN_FILE && PageDirty(page))) { gen = page_inc_gen(lruvec, page, true); @@ -130,7 +124,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 return true; } -@@ -4579,7 +4579,7 @@ static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, +@@ -4579,7 +4579,7 @@ static int scan_pages(struct lruvec *lru for (zone = sc->reclaim_idx; zone >= 0; zone--) { LIST_HEAD(moved); int skipped = 0; @@ -139,7 +133,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 while (!list_empty(head)) { struct page *page = lru_to_page(head); -@@ -4980,7 +4980,7 @@ static bool __maybe_unused state_is_valid(struct lruvec *lruvec) +@@ -4980,7 +4980,7 @@ static bool __maybe_unused state_is_vali int gen, type, zone; for_each_gen_type_zone(gen, type, zone) { @@ -148,7 +142,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 return false; } } -@@ -5025,7 +5025,7 @@ static bool drain_evictable(struct lruvec *lruvec) +@@ -5025,7 +5025,7 @@ static bool drain_evictable(struct lruve int remaining = MAX_LRU_BATCH; for_each_gen_type_zone(gen, type, zone) { @@ -157,7 +151,7 @@ index 3b1b5bd9736a..2322c913aa64 100644 while (!list_empty(head)) { bool success; -@@ -5558,7 +5558,7 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) +@@ -5558,7 +5558,7 @@ void lru_gen_init_lruvec(struct lruvec * lrugen->timestamps[i] = jiffies; for_each_gen_type_zone(gen, type, zone) @@ -166,6 +160,3 @@ index 3b1b5bd9736a..2322c913aa64 100644 lruvec->mm_state.seq = MIN_NR_GENS; init_waitqueue_head(&lruvec->mm_state.wait); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch b/target/linux/generic/backport-5.15/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch index 1490f9d4bc5..2bb6e12a5ae 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch @@ -35,11 +35,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 82 +++++++++++++++-------------------------------------- 1 file changed, 23 insertions(+), 59 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 2322c913aa64..40e7a947c5c7 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -443,6 +443,11 @@ static bool cgroup_reclaim(struct scan_control *sc) +@@ -443,6 +443,11 @@ static bool cgroup_reclaim(struct scan_c return sc->target_mem_cgroup; } @@ -51,7 +49,7 @@ index 2322c913aa64..40e7a947c5c7 100644 /** * writeback_throttling_sane - is the usual dirty throttling mechanism available? * @sc: scan_control in question -@@ -493,6 +498,11 @@ static bool cgroup_reclaim(struct scan_control *sc) +@@ -493,6 +498,11 @@ static bool cgroup_reclaim(struct scan_c return false; } @@ -63,7 +61,7 @@ index 2322c913aa64..40e7a947c5c7 100644 static bool writeback_throttling_sane(struct scan_control *sc) { return true; -@@ -4722,8 +4732,7 @@ static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swa +@@ -4722,8 +4732,7 @@ static int isolate_pages(struct lruvec * return scanned; } @@ -73,7 +71,7 @@ index 2322c913aa64..40e7a947c5c7 100644 { int type; int scanned; -@@ -4812,9 +4821,6 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -4812,9 +4821,6 @@ retry: goto retry; } @@ -83,7 +81,7 @@ index 2322c913aa64..40e7a947c5c7 100644 return scanned; } -@@ -4853,68 +4859,26 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * +@@ -4853,68 +4859,26 @@ done: return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; } @@ -161,7 +159,7 @@ index 2322c913aa64..40e7a947c5c7 100644 lru_add_drain(); -@@ -4938,7 +4902,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -4938,7 +4902,7 @@ static void lru_gen_shrink_lruvec(struct if (!nr_to_scan) goto done; @@ -170,7 +168,7 @@ index 2322c913aa64..40e7a947c5c7 100644 if (!delta) goto done; -@@ -4946,7 +4910,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -4946,7 +4910,7 @@ static void lru_gen_shrink_lruvec(struct if (scanned >= nr_to_scan) break; @@ -179,7 +177,7 @@ index 2322c913aa64..40e7a947c5c7 100644 break; cond_resched(); -@@ -5393,7 +5357,7 @@ static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_co +@@ -5393,7 +5357,7 @@ static int run_eviction(struct lruvec *l if (sc->nr_reclaimed >= nr_to_reclaim) return 0; @@ -188,6 +186,3 @@ index 2322c913aa64..40e7a947c5c7 100644 return 0; cond_resched(); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch b/target/linux/generic/backport-5.15/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch index 82ba77dec20..316217ed028 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch @@ -35,8 +35,6 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 126 ++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 67 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 40e7a947c5c7..7159436872ba 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -131,7 +131,6 @@ struct scan_control { @@ -47,7 +45,7 @@ index 40e7a947c5c7..7159436872ba 100644 unsigned long last_reclaimed; #endif -@@ -4184,7 +4183,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4184,7 +4183,7 @@ done: return true; } @@ -56,7 +54,7 @@ index 40e7a947c5c7..7159436872ba 100644 struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) { int gen, type, zone; -@@ -4193,6 +4192,13 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig +@@ -4193,6 +4192,13 @@ static bool should_run_aging(struct lruv unsigned long total = 0; struct lru_gen_page *lrugen = &lruvec->lrugen; struct mem_cgroup *memcg = lruvec_memcg(lruvec); @@ -70,7 +68,7 @@ index 40e7a947c5c7..7159436872ba 100644 for (type = !can_swap; type < ANON_AND_FILE; type++) { unsigned long seq; -@@ -4221,8 +4227,6 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig +@@ -4221,8 +4227,6 @@ static bool should_run_aging(struct lruv * stalls when the number of generations reaches MIN_NR_GENS. Hence, the * ideal number of generations is MIN_NR_GENS+1. */ @@ -79,7 +77,7 @@ index 40e7a947c5c7..7159436872ba 100644 if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) return false; -@@ -4241,40 +4245,54 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig +@@ -4241,40 +4245,54 @@ static bool should_run_aging(struct lruv return false; } @@ -155,7 +153,7 @@ index 40e7a947c5c7..7159436872ba 100644 } /* to protect the working set of the last N jiffies */ -@@ -4283,46 +4301,32 @@ static unsigned long lru_gen_min_ttl __read_mostly; +@@ -4283,46 +4301,32 @@ static unsigned long lru_gen_min_ttl __r static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) { struct mem_cgroup *memcg; @@ -209,7 +207,7 @@ index 40e7a947c5c7..7159436872ba 100644 */ if (mutex_trylock(&oom_lock)) { struct oom_control oc = { -@@ -4830,33 +4834,27 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -4830,33 +4834,27 @@ retry: * reclaim. */ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, @@ -249,7 +247,7 @@ index 40e7a947c5c7..7159436872ba 100644 } static unsigned long get_nr_to_reclaim(struct scan_control *sc) -@@ -4875,9 +4873,7 @@ static unsigned long get_nr_to_reclaim(struct scan_control *sc) +@@ -4875,9 +4873,7 @@ static unsigned long get_nr_to_reclaim(s static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) { struct blk_plug plug; @@ -259,7 +257,7 @@ index 40e7a947c5c7..7159436872ba 100644 unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); lru_add_drain(); -@@ -4898,13 +4894,13 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -4898,13 +4894,13 @@ static void lru_gen_shrink_lruvec(struct else swappiness = 0; @@ -276,7 +274,7 @@ index 40e7a947c5c7..7159436872ba 100644 scanned += delta; if (scanned >= nr_to_scan) -@@ -4916,10 +4912,6 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -4916,10 +4912,6 @@ static void lru_gen_shrink_lruvec(struct cond_resched(); } @@ -287,6 +285,3 @@ index 40e7a947c5c7..7159436872ba 100644 clear_mm_walk(); blk_finish_plug(&plug); --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch b/target/linux/generic/backport-5.15/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch index bb5402a3f2a..391ee6e67ce 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch @@ -19,11 +19,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 124 ++++++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 62 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 7159436872ba..cb026e2714d7 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4183,68 +4183,6 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4183,68 +4183,6 @@ done: return true; } @@ -92,7 +90,7 @@ index 7159436872ba..cb026e2714d7 100644 static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) { int gen, type, zone; -@@ -4828,6 +4766,68 @@ static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swapp +@@ -4828,6 +4766,68 @@ retry: return scanned; } @@ -161,6 +159,3 @@ index 7159436872ba..cb026e2714d7 100644 /* * For future optimizations: * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch b/target/linux/generic/backport-5.15/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch index 2a625703465..cf01c3997a2 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch @@ -67,11 +67,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 373 +++++++++++++++++++++++++++++++++---- 6 files changed, 499 insertions(+), 35 deletions(-) -diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h -index 3736405cbcf6..2e405fd88846 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h -@@ -818,6 +818,11 @@ static inline void obj_cgroup_put(struct obj_cgroup *objcg) +@@ -818,6 +818,11 @@ static inline void obj_cgroup_put(struct percpu_ref_put(&objcg->refcnt); } @@ -83,7 +81,7 @@ index 3736405cbcf6..2e405fd88846 100644 static inline void mem_cgroup_put(struct mem_cgroup *memcg) { if (memcg) -@@ -1283,6 +1288,11 @@ struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css) +@@ -1283,6 +1288,11 @@ struct mem_cgroup *mem_cgroup_from_css(s return NULL; } @@ -95,11 +93,9 @@ index 3736405cbcf6..2e405fd88846 100644 static inline void mem_cgroup_put(struct mem_cgroup *memcg) { } -diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h -index 4adc9ba59569..9138c2e638ce 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -112,6 +112,18 @@ static inline bool lru_gen_in_fault(void) +@@ -112,6 +112,18 @@ static inline bool lru_gen_in_fault(void return current->in_lru_fault; } @@ -118,7 +114,7 @@ index 4adc9ba59569..9138c2e638ce 100644 static inline int lru_gen_from_seq(unsigned long seq) { return seq % MAX_NR_GENS; -@@ -287,6 +299,11 @@ static inline bool lru_gen_in_fault(void) +@@ -287,6 +299,11 @@ static inline bool lru_gen_in_fault(void return false; } @@ -130,8 +126,6 @@ index 4adc9ba59569..9138c2e638ce 100644 static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) { return false; -diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h -index 7b8a26aaf381..4bbf191517e2 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -7,6 +7,7 @@ @@ -173,7 +167,7 @@ index 7b8a26aaf381..4bbf191517e2 100644 }; enum { -@@ -469,12 +487,87 @@ void lru_gen_init_lruvec(struct lruvec *lruvec); +@@ -469,12 +487,87 @@ void lru_gen_init_lruvec(struct lruvec * void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); #ifdef CONFIG_MEMCG @@ -262,7 +256,7 @@ index 7b8a26aaf381..4bbf191517e2 100644 static inline void lru_gen_init_lruvec(struct lruvec *lruvec) { } -@@ -484,6 +577,7 @@ static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) +@@ -484,6 +577,7 @@ static inline void lru_gen_look_around(s } #ifdef CONFIG_MEMCG @@ -270,7 +264,7 @@ index 7b8a26aaf381..4bbf191517e2 100644 static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) { } -@@ -491,7 +585,24 @@ static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) +@@ -491,7 +585,24 @@ static inline void lru_gen_init_memcg(st static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) { } @@ -305,11 +299,9 @@ index 7b8a26aaf381..4bbf191517e2 100644 #endif ZONE_PADDING(_pad2_) -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index ed87d1256f0e..172adfbee06e 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -549,6 +549,16 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page) +@@ -549,6 +549,16 @@ static void mem_cgroup_update_tree(struc struct mem_cgroup_per_node *mz; struct mem_cgroup_tree_per_node *mctz; @@ -326,7 +318,7 @@ index ed87d1256f0e..172adfbee06e 100644 mctz = soft_limit_tree_from_page(page); if (!mctz) return; -@@ -3433,6 +3443,9 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order, +@@ -3433,6 +3443,9 @@ unsigned long mem_cgroup_soft_limit_recl unsigned long excess; unsigned long nr_scanned; @@ -336,7 +328,7 @@ index ed87d1256f0e..172adfbee06e 100644 if (order > 0) return 0; -@@ -5321,6 +5334,7 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) +@@ -5321,6 +5334,7 @@ static int mem_cgroup_css_online(struct if (unlikely(mem_cgroup_is_root(memcg))) queue_delayed_work(system_unbound_wq, &stats_flush_dwork, 2UL*HZ); @@ -344,7 +336,7 @@ index ed87d1256f0e..172adfbee06e 100644 return 0; } -@@ -5347,6 +5361,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) +@@ -5347,6 +5361,7 @@ static void mem_cgroup_css_offline(struc memcg_offline_kmem(memcg); reparent_shrinker_deferred(memcg); wb_memcg_offline(memcg); @@ -352,7 +344,7 @@ index ed87d1256f0e..172adfbee06e 100644 drain_all_stock(memcg); -@@ -5358,6 +5373,7 @@ static void mem_cgroup_css_released(struct cgroup_subsys_state *css) +@@ -5358,6 +5373,7 @@ static void mem_cgroup_css_released(stru struct mem_cgroup *memcg = mem_cgroup_from_css(css); invalidate_reclaim_iterators(memcg); @@ -360,11 +352,9 @@ index ed87d1256f0e..172adfbee06e 100644 } static void mem_cgroup_css_free(struct cgroup_subsys_state *css) -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index c929357fbefe..6459d9c018be 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -7645,6 +7645,7 @@ static void __init free_area_init_node(int nid) +@@ -7645,6 +7645,7 @@ static void __init free_area_init_node(i pgdat_set_deferred_range(pgdat); free_area_init_core(pgdat); @@ -372,8 +362,6 @@ index c929357fbefe..6459d9c018be 100644 } void __init free_area_init_memoryless_node(int nid) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index cb026e2714d7..3d8e0665186c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -54,6 +54,8 @@ @@ -397,7 +385,7 @@ index cb026e2714d7..3d8e0665186c 100644 /* Allocation order */ s8 order; -@@ -2880,6 +2877,9 @@ DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); +@@ -2880,6 +2877,9 @@ DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_ca for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) @@ -407,7 +395,7 @@ index cb026e2714d7..3d8e0665186c 100644 static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) { struct pglist_data *pgdat = NODE_DATA(nid); -@@ -4169,8 +4169,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4169,8 +4169,7 @@ done: if (sc->priority <= DEF_PRIORITY - 2) wait_event_killable(lruvec->mm_state.wait, max_seq < READ_ONCE(lrugen->max_seq)); @@ -417,7 +405,7 @@ index cb026e2714d7..3d8e0665186c 100644 } VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); -@@ -4243,8 +4242,6 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +@@ -4243,8 +4242,6 @@ static void lru_gen_age_node(struct pgli VM_WARN_ON_ONCE(!current_is_kswapd()); @@ -426,7 +414,7 @@ index cb026e2714d7..3d8e0665186c 100644 /* check the order to exclude compaction-induced reclaim */ if (!min_ttl || sc->order || sc->priority == DEF_PRIORITY) return; -@@ -4833,8 +4830,7 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, +@@ -4833,8 +4830,7 @@ static bool should_run_aging(struct lruv * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg * reclaim. */ @@ -436,7 +424,7 @@ index cb026e2714d7..3d8e0665186c 100644 { unsigned long nr_to_scan; struct mem_cgroup *memcg = lruvec_memcg(lruvec); -@@ -4851,10 +4847,8 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * +@@ -4851,10 +4847,8 @@ static unsigned long get_nr_to_scan(stru if (sc->priority == DEF_PRIORITY) return nr_to_scan; @@ -448,7 +436,7 @@ index cb026e2714d7..3d8e0665186c 100644 } static unsigned long get_nr_to_reclaim(struct scan_control *sc) -@@ -4863,29 +4857,18 @@ static unsigned long get_nr_to_reclaim(struct scan_control *sc) +@@ -4863,29 +4857,18 @@ static unsigned long get_nr_to_reclaim(s if (!global_reclaim(sc)) return -1; @@ -480,7 +468,7 @@ index cb026e2714d7..3d8e0665186c 100644 if (sc->may_swap) swappiness = get_swappiness(lruvec, sc); -@@ -4895,7 +4878,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -4895,7 +4878,7 @@ static void lru_gen_shrink_lruvec(struct swappiness = 0; nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); @@ -489,7 +477,7 @@ index cb026e2714d7..3d8e0665186c 100644 break; delta = evict_pages(lruvec, sc, swappiness); -@@ -4912,11 +4895,251 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -4912,10 +4895,250 @@ static void lru_gen_shrink_lruvec(struct cond_resched(); } @@ -689,8 +677,8 @@ index cb026e2714d7..3d8e0665186c 100644 + + /* kswapd should never fail */ + pgdat->kswapd_failures = 0; - } - ++} ++ +#ifdef CONFIG_MEMCG +void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) +{ @@ -735,13 +723,12 @@ index cb026e2714d7..3d8e0665186c 100644 + WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); + + spin_unlock(&pgdat->memcg_lru.lock); -+} + } +#endif -+ + /****************************************************************************** * state change - ******************************************************************************/ -@@ -5370,11 +5593,11 @@ static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, +@@ -5370,11 +5593,11 @@ static int run_cmd(char cmd, int memcg_i if (!mem_cgroup_disabled()) { rcu_read_lock(); @@ -756,7 +743,7 @@ index cb026e2714d7..3d8e0665186c 100644 rcu_read_unlock(); if (!memcg) -@@ -5521,6 +5744,19 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) +@@ -5521,6 +5744,19 @@ void lru_gen_init_lruvec(struct lruvec * } #ifdef CONFIG_MEMCG @@ -776,7 +763,7 @@ index cb026e2714d7..3d8e0665186c 100644 void lru_gen_init_memcg(struct mem_cgroup *memcg) { INIT_LIST_HEAD(&memcg->mm_list.fifo); -@@ -5544,7 +5780,69 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) +@@ -5544,7 +5780,69 @@ void lru_gen_exit_memcg(struct mem_cgrou } } } @@ -847,7 +834,7 @@ index cb026e2714d7..3d8e0665186c 100644 static int __init init_lru_gen(void) { -@@ -5571,6 +5869,10 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -5571,6 +5869,10 @@ static void lru_gen_shrink_lruvec(struct { } @@ -858,7 +845,7 @@ index cb026e2714d7..3d8e0665186c 100644 #endif /* CONFIG_LRU_GEN */ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -@@ -5584,7 +5886,7 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -5584,7 +5886,7 @@ static void shrink_lruvec(struct lruvec bool proportional_reclaim; struct blk_plug plug; @@ -867,7 +854,7 @@ index cb026e2714d7..3d8e0665186c 100644 lru_gen_shrink_lruvec(lruvec, sc); return; } -@@ -5826,6 +6128,11 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc) +@@ -5826,6 +6128,11 @@ static void shrink_node(pg_data_t *pgdat struct lruvec *target_lruvec; bool reclaimable = false; @@ -879,6 +866,3 @@ index cb026e2714d7..3d8e0665186c 100644 target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); again: --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch b/target/linux/generic/backport-5.15/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch index 59d2c82b564..882f29e9892 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch @@ -33,11 +33,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 55 +++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 3d8e0665186c..4bcb93df316c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -2905,6 +2905,9 @@ static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) +@@ -2905,6 +2905,9 @@ static int get_swappiness(struct lruvec struct mem_cgroup *memcg = lruvec_memcg(lruvec); struct pglist_data *pgdat = lruvec_pgdat(lruvec); @@ -47,7 +45,7 @@ index 3d8e0665186c..4bcb93df316c 100644 if (!can_demote(pgdat->node_id, sc) && mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) return 0; -@@ -3952,7 +3955,7 @@ static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_ +@@ -3952,7 +3955,7 @@ static void walk_mm(struct lruvec *lruve } while (err == -EAGAIN); } @@ -56,7 +54,7 @@ index 3d8e0665186c..4bcb93df316c 100644 { struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; -@@ -3960,7 +3963,7 @@ static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat) +@@ -3960,7 +3963,7 @@ static struct lru_gen_mm_walk *set_mm_wa VM_WARN_ON_ONCE(walk); walk = &pgdat->mm_walk; @@ -65,7 +63,7 @@ index 3d8e0665186c..4bcb93df316c 100644 VM_WARN_ON_ONCE(current_is_kswapd()); walk = kzalloc(sizeof(*walk), __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); -@@ -4146,7 +4149,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4146,7 +4149,7 @@ static bool try_to_inc_max_seq(struct lr goto done; } @@ -74,7 +72,7 @@ index 3d8e0665186c..4bcb93df316c 100644 if (!walk) { success = iterate_mm_list_nowalk(lruvec, max_seq); goto done; -@@ -4215,8 +4218,6 @@ static bool lruvec_is_reclaimable(struct lruvec *lruvec, struct scan_control *sc +@@ -4215,8 +4218,6 @@ static bool lruvec_is_reclaimable(struct struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MIN_SEQ(lruvec); @@ -83,7 +81,7 @@ index 3d8e0665186c..4bcb93df316c 100644 /* see the comment on lru_gen_page */ gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); -@@ -4472,12 +4473,8 @@ static bool isolate_page(struct lruvec *lruvec, struct page *page, struct scan_c +@@ -4472,12 +4473,8 @@ static bool isolate_page(struct lruvec * { bool success; @@ -97,7 +95,7 @@ index 3d8e0665186c..4bcb93df316c 100644 (PageDirty(page) || (PageAnon(page) && !PageSwapCache(page)))) return false; -@@ -4574,9 +4571,8 @@ static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, +@@ -4574,9 +4571,8 @@ static int scan_pages(struct lruvec *lru __count_vm_events(PGSCAN_ANON + type, isolated); /* @@ -109,7 +107,7 @@ index 3d8e0665186c..4bcb93df316c 100644 */ return isolated || !remaining ? scanned : 0; } -@@ -4836,8 +4832,7 @@ static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool +@@ -4836,8 +4832,7 @@ static long get_nr_to_scan(struct lruvec struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); @@ -119,7 +117,7 @@ index 3d8e0665186c..4bcb93df316c 100644 return 0; if (!should_run_aging(lruvec, max_seq, sc, can_swap, &nr_to_scan)) -@@ -4865,17 +4860,14 @@ static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -4865,17 +4860,14 @@ static bool try_to_shrink_lruvec(struct long nr_to_scan; unsigned long scanned = 0; unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); @@ -142,7 +140,7 @@ index 3d8e0665186c..4bcb93df316c 100644 nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); if (nr_to_scan <= 0) -@@ -5005,12 +4997,13 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc +@@ -5005,12 +4997,13 @@ static void lru_gen_shrink_lruvec(struct struct blk_plug plug; VM_WARN_ON_ONCE(global_reclaim(sc)); @@ -157,7 +155,7 @@ index 3d8e0665186c..4bcb93df316c 100644 if (try_to_shrink_lruvec(lruvec, sc)) lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); -@@ -5066,11 +5059,19 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control * +@@ -5066,11 +5059,19 @@ static void lru_gen_shrink_node(struct p VM_WARN_ON_ONCE(!global_reclaim(sc)); @@ -178,7 +176,7 @@ index 3d8e0665186c..4bcb93df316c 100644 set_initial_priority(pgdat, sc); -@@ -5088,7 +5089,7 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control * +@@ -5088,7 +5089,7 @@ static void lru_gen_shrink_node(struct p clear_mm_walk(); blk_finish_plug(&plug); @@ -187,7 +185,7 @@ index 3d8e0665186c..4bcb93df316c 100644 /* kswapd should never fail */ pgdat->kswapd_failures = 0; } -@@ -5656,7 +5657,7 @@ static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, +@@ -5656,7 +5657,7 @@ static ssize_t lru_gen_seq_write(struct set_task_reclaim_state(current, &sc.reclaim_state); flags = memalloc_noreclaim_save(); blk_start_plug(&plug); @@ -196,6 +194,3 @@ index 3d8e0665186c..4bcb93df316c 100644 err = -ENOMEM; goto done; } --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch b/target/linux/generic/backport-5.15/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch index a6c7b019ced..38d0e5496cc 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch @@ -21,11 +21,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 4bcb93df316c..3f6874a69886 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4144,7 +4144,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +@@ -4144,7 +4144,7 @@ static bool try_to_inc_max_seq(struct lr * handful of PTEs. Spreading the work out over a period of time usually * is less efficient, but it avoids bursty page faults. */ @@ -34,6 +32,3 @@ index 4bcb93df316c..3f6874a69886 100644 success = iterate_mm_list_nowalk(lruvec, max_seq); goto done; } --- -2.40.0 - diff --git a/target/linux/generic/backport-5.15/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch b/target/linux/generic/backport-5.15/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch index 14e1aff1776..2d19d0d7da1 100644 --- a/target/linux/generic/backport-5.15/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch +++ b/target/linux/generic/backport-5.15/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch @@ -23,11 +23,9 @@ Signed-off-by: Andrew Morton mm/vmscan.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 3f6874a69886..0b76774963ff 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4934,18 +4934,20 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc) +@@ -4934,18 +4934,20 @@ static int shrink_one(struct lruvec *lru static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) { @@ -50,7 +48,7 @@ index 3f6874a69886..0b76774963ff 100644 gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq)); rcu_read_lock(); -@@ -4969,14 +4971,22 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) +@@ -4969,14 +4971,22 @@ restart: op = shrink_one(lruvec, sc); @@ -76,7 +74,7 @@ index 3f6874a69886..0b76774963ff 100644 /* restart if raced with lru_gen_rotate_memcg() */ if (gen != get_nulls_value(pos)) goto restart; -@@ -4985,11 +4995,6 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) +@@ -4985,11 +4995,6 @@ restart: bin = get_memcg_bin(bin + 1); if (bin != first_bin) goto restart; @@ -88,6 +86,3 @@ index 3f6874a69886..0b76774963ff 100644 } static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) --- -2.40.0 - diff --git a/target/linux/generic/pending-5.15/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/target/linux/generic/pending-5.15/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch index 4865659c04b..c1313c82f4d 100644 --- a/target/linux/generic/pending-5.15/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch +++ b/target/linux/generic/pending-5.15/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch @@ -71,7 +71,7 @@ Signed-off-by: Tobias Wolf --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -7605,7 +7605,7 @@ static void __init alloc_node_mem_map(st +@@ -7604,7 +7604,7 @@ static void __init alloc_node_mem_map(st if (pgdat == NODE_DATA(0)) { mem_map = NODE_DATA(0)->node_mem_map; if (page_to_pfn(mem_map) != pgdat->node_start_pfn) From 42a59177868a304e8047bf8e8c51219d1b35fec7 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 27 Mar 2023 18:15:13 +0200 Subject: [PATCH 34/53] ipq-wifi: bump to latest git HEAD ccd7e46 ipq40xx: add support for Wallystech DR40x9 2ce60e1 Revert "ipq40xx: add support for Wallystech DR40x9" ea962ca ipq40xx: add Emplus WAP551 BDF Signed-off-by: Christian Marangi --- package/firmware/ipq-wifi/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile index f3bf1185f82..8eea981191e 100644 --- a/package/firmware/ipq-wifi/Makefile +++ b/package/firmware/ipq-wifi/Makefile @@ -6,9 +6,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/firmware/qca-wireless.git -PKG_SOURCE_DATE:=2023-03-20 -PKG_SOURCE_VERSION:=f9cece02724b8ca2c1a166a46f0afa89e632d431 -PKG_MIRROR_HASH:=89c20798c7ec83114aa69467f2467fe32cbb74ebeca277c60a033af960ca6c04 +PKG_SOURCE_DATE:=2023-03-27 +PKG_SOURCE_VERSION:=ccd7e460cc798d90148a10539b6d94a5fd761004 +PKG_MIRROR_HASH:=e51d28c741aeb0867493a7bfc801b8b1977c942ed5d51d62c1aa8729c91cce32 PKG_FLAGS:=nonshared From 027586ae8ecacff49757ed854c020f35d24a599c Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 11 Mar 2023 03:44:41 +0000 Subject: [PATCH 35/53] generic: backport some phylink helper functions It isn't feasible to literally backport all upstream phylink_pcs changes down to Linux 5.15: It's just too many patches, and many downstream drivers and hacks are likely to break. We are too close to branching off to risk this, and it's also just too much work. Instead just add helper functions used by modern PCS drivers while keeping the original functions instact as well. While this may add a kilobyte or two of extra kernel size, it has the advantage that we get the best of both worlds: None of the existing codepaths are touched, but yet we have the option to backport singular improvements to Ethernet drivers where needed. Signed-off-by: Daniel Golle --- .../795-backport-phylink_pcs-helpers.patch | 150 ++++++++++++++++++ ...y-simplify-phy_link_change-arguments.patch | 2 +- 2 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 target/linux/generic/hack-5.15/795-backport-phylink_pcs-helpers.patch diff --git a/target/linux/generic/hack-5.15/795-backport-phylink_pcs-helpers.patch b/target/linux/generic/hack-5.15/795-backport-phylink_pcs-helpers.patch new file mode 100644 index 00000000000..2ccdc905a5c --- /dev/null +++ b/target/linux/generic/hack-5.15/795-backport-phylink_pcs-helpers.patch @@ -0,0 +1,150 @@ +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -584,10 +584,37 @@ int phylink_speed_up(struct phylink *pl) + #define phylink_test(bm, mode) __phylink_do_bit(test_bit, bm, mode) + + void phylink_set_port_modes(unsigned long *bits); ++ ++/** ++ * phylink_get_link_timer_ns - return the PCS link timer value ++ * @interface: link &typedef phy_interface_t mode ++ * ++ * Return the PCS link timer setting in nanoseconds for the PHY @interface ++ * mode, or -EINVAL if not appropriate. ++ */ ++static inline int phylink_get_link_timer_ns(phy_interface_t interface) ++{ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_SGMII: ++ return 1600000; ++ ++ case PHY_INTERFACE_MODE_1000BASEX: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ return 10000000; ++ ++ default: ++ return -EINVAL; ++ } ++} ++ + void phylink_helper_basex_speed(struct phylink_link_state *state); + ++void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, ++ u16 bmsr, u16 lpa); + void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, + struct phylink_link_state *state); ++int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, ++ const unsigned long *advertising); + int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, + phy_interface_t interface, + const unsigned long *advertising); +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -885,7 +885,6 @@ static int phylink_change_inband_advert( + + return 0; + } +- + static void phylink_mac_pcs_get_state(struct phylink *pl, + struct phylink_link_state *state) + { +@@ -2966,6 +2965,52 @@ void phylink_mii_c22_pcs_get_state(struc + EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); + + /** ++ * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers ++ * @state: a pointer to a &struct phylink_link_state. ++ * @bmsr: The value of the %MII_BMSR register ++ * @lpa: The value of the %MII_LPA register ++ * ++ * Helper for MAC PCS supporting the 802.3 clause 22 register set for ++ * clause 37 negotiation and/or SGMII control. ++ * ++ * Parse the Clause 37 or Cisco SGMII link partner negotiation word into ++ * the phylink @state structure. This is suitable to be used for implementing ++ * the mac_pcs_get_state() member of the struct phylink_mac_ops structure if ++ * accessing @bmsr and @lpa cannot be done with MDIO directly. ++ */ ++void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, ++ u16 bmsr, u16 lpa) ++{ ++ state->link = !!(bmsr & BMSR_LSTATUS); ++ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); ++ /* If there is no link or autonegotiation is disabled, the LP advertisement ++ * data is not meaningful, so don't go any further. ++ */ ++ if (!state->link || !state->an_enabled) ++ return; ++ ++ switch (state->interface) { ++ case PHY_INTERFACE_MODE_1000BASEX: ++ phylink_decode_c37_word(state, lpa, SPEED_1000); ++ break; ++ ++ case PHY_INTERFACE_MODE_2500BASEX: ++ phylink_decode_c37_word(state, lpa, SPEED_2500); ++ break; ++ ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_QSGMII: ++ phylink_decode_sgmii_word(state, lpa); ++ break; ++ ++ default: ++ state->link = false; ++ break; ++ } ++} ++EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state); ++ ++/** + * phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS + * advertisement + * @pcs: a pointer to a &struct mdio_device. +@@ -3037,6 +3082,46 @@ int phylink_mii_c22_pcs_set_advertisemen + EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement); + + /** ++ * phylink_mii_c22_pcs_encode_advertisement() - configure the clause 37 PCS ++ * advertisement ++ * @interface: the PHY interface mode being configured ++ * @advertising: the ethtool advertisement mask ++ * ++ * Helper for MAC PCS supporting the 802.3 clause 22 register set for ++ * clause 37 negotiation and/or SGMII control. ++ * ++ * Encode the clause 37 PCS advertisement as specified by @interface and ++ * @advertising. ++ * ++ * Return: The new value for @adv, or ``-EINVAL`` if it should not be changed. ++ */ ++int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, ++ const unsigned long *advertising) ++{ ++ u16 adv; ++ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_1000BASEX: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ adv = ADVERTISE_1000XFULL; ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, ++ advertising)) ++ adv |= ADVERTISE_1000XPAUSE; ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, ++ advertising)) ++ adv |= ADVERTISE_1000XPSE_ASYM; ++ return adv; ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_QSGMII: ++ return 0x0001; ++ default: ++ /* Nothing to do for other modes */ ++ return -EINVAL; ++ } ++} ++EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement); ++ ++/** + * phylink_mii_c22_pcs_config() - configure clause 22 PCS + * @pcs: a pointer to a &struct mdio_device. + * @mode: link autonegotiation mode diff --git a/target/linux/ramips/patches-5.15/720-Revert-net-phy-simplify-phy_link_change-arguments.patch b/target/linux/ramips/patches-5.15/720-Revert-net-phy-simplify-phy_link_change-arguments.patch index d53a8c2d792..9283900edf8 100644 --- a/target/linux/ramips/patches-5.15/720-Revert-net-phy-simplify-phy_link_change-arguments.patch +++ b/target/linux/ramips/patches-5.15/720-Revert-net-phy-simplify-phy_link_change-arguments.patch @@ -95,7 +95,7 @@ still required by target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c phydev->mii_ts->link_state(phydev->mii_ts, phydev); --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c -@@ -1323,7 +1323,8 @@ void phylink_destroy(struct phylink *pl) +@@ -1322,7 +1322,8 @@ void phylink_destroy(struct phylink *pl) } EXPORT_SYMBOL_GPL(phylink_destroy); From 2f663cab46dd20a3372d206d02876326012904bf Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 27 Mar 2023 16:02:44 +0100 Subject: [PATCH 36/53] generic: replace mtk_sgmii patches with versions accepted upstream Replace patches for MediaTek Ethernet driver SGMII/SerDes unit with their corresponding upstream patches. Not all of the patches in our tree went upstream as-is, some are slightly different implementations, and they require the phylink_pcs helpers now made available. Signed-off-by: Daniel Golle --- ...-mtk_eth_soc-add-definitions-for-PCS.patch | 55 ++++++++ ...eliminate-unnecessary-error-handling.patch | 74 ++++++++++ ...soc-add-pcs_get_state-implementation.patch | 46 ++++++ ...convert-mtk_sgmii-to-use-regmap_upda.patch | 130 +++++++++++++++++ ...add-out-of-band-forcing-of-speed-and.patch | 52 +++++++ ...07-net-mtk_eth_soc-move-PHY-power-up.patch | 48 +++++++ ...h_soc-move-interface-speed-selection.patch | 48 +++++++ ...th_soc-add-advertisement-programming.patch | 52 +++++++ ...move-and-correct-link-timer-programm.patch | 63 +++++++++ ...add-support-for-in-band-802.3z-negot.patch | 132 ++++++++++++++++++ ...i-ensure-the-SGMII-PHY-is-powered-d.patch} | 87 ++++++------ ...atek-sgmii-fix-duplex-configuration.patch} | 36 ++--- ...nable-PCS-polling-to-allow-SFP-work.patch} | 4 +- ...thernet-mtk_eth_soc-reset-PCS-state.patch} | 22 +-- ..._eth_soc-only-write-values-if-needed.patch | 103 ++++++++++++++ ...-net-mtk_sgmii-implement-mtk_pcs_ops.patch | 46 ------ ...k_pcs_setup_mode_an-don-t-rely-on-re.patch | 31 ---- ...t-the-speed-according-to-the-phy-int.patch | 41 ------ .../729-net-mtk_eth_soc-improve-comment.patch | 22 --- ...iatek-ppe-add-support-for-flow-accou.patch | 4 +- ..._eth_soc-add-code-for-offloading-flo.patch | 2 +- 21 files changed, 875 insertions(+), 223 deletions(-) create mode 100644 target/linux/generic/backport-5.15/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-03-net-mtk_eth_soc-eliminate-unnecessary-error-handling.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-04-net-mtk_eth_soc-add-pcs_get_state-implementation.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-05-net-mtk_eth_soc-convert-mtk_sgmii-to-use-regmap_upda.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-06-net-mtk_eth_soc-add-out-of-band-forcing-of-speed-and.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-07-net-mtk_eth_soc-move-PHY-power-up.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-08-net-mtk_eth_soc-move-interface-speed-selection.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-09-net-mtk_eth_soc-add-advertisement-programming.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-10-net-mtk_eth_soc-move-and-correct-link-timer-programm.patch create mode 100644 target/linux/generic/backport-5.15/733-v6.2-11-net-mtk_eth_soc-add-support-for-in-band-802.3z-negot.patch rename target/linux/generic/backport-5.15/{733-v6.2-02-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch => 733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch} (66%) rename target/linux/generic/backport-5.15/{733-v6.2-03-net-mediatek-sgmii-fix-duplex-configuration.patch => 733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch} (63%) rename target/linux/generic/backport-5.15/{733-v6.2-04-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch => 733-v6.2-14-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch} (89%) rename target/linux/generic/{pending-5.15/733-01-net-ethernet-mtk_eth_soc-reset-PCS-state.patch => backport-5.15/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch} (65%) create mode 100644 target/linux/generic/backport-5.15/733-v6.3-16-net-ethernet-mtk_eth_soc-only-write-values-if-needed.patch delete mode 100644 target/linux/generic/pending-5.15/724-net-mtk_sgmii-implement-mtk_pcs_ops.patch delete mode 100644 target/linux/generic/pending-5.15/727-net-mtk_sgmii-mtk_pcs_setup_mode_an-don-t-rely-on-re.patch delete mode 100644 target/linux/generic/pending-5.15/728-net-mtk_sgmii-set-the-speed-according-to-the-phy-int.patch delete mode 100644 target/linux/generic/pending-5.15/729-net-mtk_eth_soc-improve-comment.patch diff --git a/target/linux/generic/backport-5.15/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch b/target/linux/generic/backport-5.15/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch new file mode 100644 index 00000000000..68f3659367a --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch @@ -0,0 +1,55 @@ +From b6a709cb51f7bdc55c01cec886098a9753ce8c28 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:10:42 +0100 +Subject: [PATCH 01/10] net: mtk_eth_soc: add definitions for PCS + +As a result of help from Frank Wunderlich to investigate and test, we +know a bit more about the PCS on the Mediatek platforms. Update the +definitions from this investigation. + +This PCS appears similar, but not identical to the Lynx PCS. + +Although not included in this patch, but for future reference, the PHY +ID registers at offset 4 read as 0x4d544950 'MTIP'. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -501,8 +501,10 @@ + #define ETHSYS_DMA_AG_MAP_PPE BIT(2) + + /* SGMII subsystem config registers */ +-/* Register to auto-negotiation restart */ ++/* BMCR (low 16) BMSR (high 16) */ + #define SGMSYS_PCS_CONTROL_1 0x0 ++#define SGMII_BMCR GENMASK(15, 0) ++#define SGMII_BMSR GENMASK(31, 16) + #define SGMII_AN_RESTART BIT(9) + #define SGMII_ISOLATE BIT(10) + #define SGMII_AN_ENABLE BIT(12) +@@ -512,13 +514,18 @@ + #define SGMII_PCS_FAULT BIT(23) + #define SGMII_AN_EXPANSION_CLR BIT(30) + ++#define SGMSYS_PCS_ADVERTISE 0x8 ++#define SGMII_ADVERTISE GENMASK(15, 0) ++#define SGMII_LPA GENMASK(31, 16) ++ + /* Register to programmable link timer, the unit in 2 * 8ns */ + #define SGMSYS_PCS_LINK_TIMER 0x18 +-#define SGMII_LINK_TIMER_DEFAULT (0x186a0 & GENMASK(19, 0)) ++#define SGMII_LINK_TIMER_MASK GENMASK(19, 0) ++#define SGMII_LINK_TIMER_DEFAULT (0x186a0 & SGMII_LINK_TIMER_MASK) + + /* Register to control remote fault */ + #define SGMSYS_SGMII_MODE 0x20 +-#define SGMII_IF_MODE_BIT0 BIT(0) ++#define SGMII_IF_MODE_SGMII BIT(0) + #define SGMII_SPEED_DUPLEX_AN BIT(1) + #define SGMII_SPEED_MASK GENMASK(3, 2) + #define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) diff --git a/target/linux/generic/backport-5.15/733-v6.2-03-net-mtk_eth_soc-eliminate-unnecessary-error-handling.patch b/target/linux/generic/backport-5.15/733-v6.2-03-net-mtk_eth_soc-eliminate-unnecessary-error-handling.patch new file mode 100644 index 00000000000..4ea428c9d6b --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-03-net-mtk_eth_soc-eliminate-unnecessary-error-handling.patch @@ -0,0 +1,74 @@ +From 5cf7797526ee81bea0f627bccaa3d887f48f53e0 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:10:47 +0100 +Subject: [PATCH 02/10] net: mtk_eth_soc: eliminate unnecessary error handling + +The functions called by the pcs_config() method always return zero, so +there is no point trying to handle an error from these functions. Make +these functions void, eliminate the "err" variable and simply return +zero from the pcs_config() function itself. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -20,7 +20,7 @@ static struct mtk_pcs *pcs_to_mtk_pcs(st + } + + /* For SGMII interface mode */ +-static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) ++static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { + unsigned int val; + +@@ -39,16 +39,13 @@ static int mtk_pcs_setup_mode_an(struct + regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); + val &= ~SGMII_PHYA_PWD; + regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); +- +- return 0; +- + } + + /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a + * fixed speed. + */ +-static int mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, +- phy_interface_t interface) ++static void mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, ++ phy_interface_t interface) + { + unsigned int val; + +@@ -73,8 +70,6 @@ static int mtk_pcs_setup_mode_force(stru + regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); + val &= ~SGMII_PHYA_PWD; + regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); +- +- return 0; + } + + static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -83,15 +78,14 @@ static int mtk_pcs_config(struct phylink + bool permit_pause_to_mac) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- int err = 0; + + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) +- err = mtk_pcs_setup_mode_force(mpcs, interface); ++ mtk_pcs_setup_mode_force(mpcs, interface); + else if (phylink_autoneg_inband(mode)) +- err = mtk_pcs_setup_mode_an(mpcs); ++ mtk_pcs_setup_mode_an(mpcs); + +- return err; ++ return 0; + } + + static void mtk_pcs_restart_an(struct phylink_pcs *pcs) diff --git a/target/linux/generic/backport-5.15/733-v6.2-04-net-mtk_eth_soc-add-pcs_get_state-implementation.patch b/target/linux/generic/backport-5.15/733-v6.2-04-net-mtk_eth_soc-add-pcs_get_state-implementation.patch new file mode 100644 index 00000000000..64a4a72fa6a --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-04-net-mtk_eth_soc-add-pcs_get_state-implementation.patch @@ -0,0 +1,46 @@ +From c000dca098002da193b98099df051c9ead0cacb4 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:10:52 +0100 +Subject: [PATCH 03/10] net: mtk_eth_soc: add pcs_get_state() implementation + +Add a pcs_get_state() implementation which uses the advertisements +to compute the resulting link modes, and BMSR contents to determine +negotiation and link status. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -19,6 +19,20 @@ static struct mtk_pcs *pcs_to_mtk_pcs(st + return container_of(pcs, struct mtk_pcs, pcs); + } + ++static void mtk_pcs_get_state(struct phylink_pcs *pcs, ++ struct phylink_link_state *state) ++{ ++ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); ++ unsigned int bm, adv; ++ ++ /* Read the BMSR and LPA */ ++ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); ++ regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ ++ phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), ++ FIELD_GET(SGMII_LPA, adv)); ++} ++ + /* For SGMII interface mode */ + static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { +@@ -117,6 +131,7 @@ static void mtk_pcs_link_up(struct phyli + } + + static const struct phylink_pcs_ops mtk_pcs_ops = { ++ .pcs_get_state = mtk_pcs_get_state, + .pcs_config = mtk_pcs_config, + .pcs_an_restart = mtk_pcs_restart_an, + .pcs_link_up = mtk_pcs_link_up, diff --git a/target/linux/generic/backport-5.15/733-v6.2-05-net-mtk_eth_soc-convert-mtk_sgmii-to-use-regmap_upda.patch b/target/linux/generic/backport-5.15/733-v6.2-05-net-mtk_eth_soc-convert-mtk_sgmii-to-use-regmap_upda.patch new file mode 100644 index 00000000000..24610fe11e1 --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-05-net-mtk_eth_soc-convert-mtk_sgmii-to-use-regmap_upda.patch @@ -0,0 +1,130 @@ +From 0d2351dc2768061689abd4de1529fa206bbd574e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:10:58 +0100 +Subject: [PATCH 04/10] net: mtk_eth_soc: convert mtk_sgmii to use + regmap_update_bits() + +mtk_sgmii does a lot of read-modify-write operations, for which there +is a specific regmap function. Use this function instead of open-coding +the operations. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 61 ++++++++++------------- + 1 file changed, 26 insertions(+), 35 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -36,23 +36,18 @@ static void mtk_pcs_get_state(struct phy + /* For SGMII interface mode */ + static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { +- unsigned int val; +- + /* Setup the link timer and QPHY power up inside SGMIISYS */ + regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, + SGMII_LINK_TIMER_DEFAULT); + +- regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); +- val |= SGMII_REMOTE_FAULT_DIS; +- regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); +- +- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); +- val |= SGMII_AN_RESTART; +- regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); +- +- regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); +- val &= ~SGMII_PHYA_PWD; +- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_REMOTE_FAULT_DIS, SGMII_REMOTE_FAULT_DIS); ++ ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_RESTART, SGMII_AN_RESTART); ++ ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, 0); + } + + /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a +@@ -61,29 +56,26 @@ static void mtk_pcs_setup_mode_an(struct + static void mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, + phy_interface_t interface) + { +- unsigned int val; ++ unsigned int rgc3; + +- regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); +- val &= ~RG_PHY_SPEED_MASK; + if (interface == PHY_INTERFACE_MODE_2500BASEX) +- val |= RG_PHY_SPEED_3_125G; +- regmap_write(mpcs->regmap, mpcs->ana_rgc3, val); ++ rgc3 = RG_PHY_SPEED_3_125G; ++ ++ regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, ++ RG_PHY_SPEED_3_125G, rgc3); + + /* Disable SGMII AN */ +- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); +- val &= ~SGMII_AN_ENABLE; +- regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_ENABLE, 0); + + /* Set the speed etc but leave the duplex unchanged */ +- regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); +- val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK; +- val |= SGMII_SPEED_1000; +- regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_IF_MODE_MASK & ~SGMII_DUPLEX_FULL, ++ SGMII_SPEED_1000); + + /* Release PHYA power down state */ +- regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); +- val &= ~SGMII_PHYA_PWD; +- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, 0); + } + + static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -105,29 +97,28 @@ static int mtk_pcs_config(struct phylink + static void mtk_pcs_restart_an(struct phylink_pcs *pcs) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int val; + +- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); +- val |= SGMII_AN_RESTART; +- regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_RESTART, SGMII_AN_RESTART); + } + + static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, int speed, int duplex) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int val; ++ unsigned int sgm_mode; + + if (!phy_interface_mode_is_8023z(interface)) + return; + + /* SGMII force duplex setting */ +- regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); +- val &= ~SGMII_DUPLEX_FULL; + if (duplex == DUPLEX_FULL) +- val |= SGMII_DUPLEX_FULL; ++ sgm_mode = SGMII_DUPLEX_FULL; ++ else ++ sgm_mode = 0; + +- regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_DUPLEX_FULL, sgm_mode); + } + + static const struct phylink_pcs_ops mtk_pcs_ops = { diff --git a/target/linux/generic/backport-5.15/733-v6.2-06-net-mtk_eth_soc-add-out-of-band-forcing-of-speed-and.patch b/target/linux/generic/backport-5.15/733-v6.2-06-net-mtk_eth_soc-add-out-of-band-forcing-of-speed-and.patch new file mode 100644 index 00000000000..ba76ca40ffa --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-06-net-mtk_eth_soc-add-out-of-band-forcing-of-speed-and.patch @@ -0,0 +1,52 @@ +From 12198c3a410fe69843e335c1bbf6d4c2a4d48e4e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:03 +0100 +Subject: [PATCH 05/10] net: mtk_eth_soc: add out of band forcing of speed and + duplex in pcs_link_up + +Add support for forcing the link speed and duplex setting in the +pcs_link_up() method for out of band modes, which will be useful when +we finish converting the pcs_config() method. Until then, we still have +to force duplex for 802.3z modes to work correctly. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 28 ++++++++++++++--------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -108,17 +108,23 @@ static void mtk_pcs_link_up(struct phyli + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int sgm_mode; + +- if (!phy_interface_mode_is_8023z(interface)) +- return; ++ if (!phylink_autoneg_inband(mode) || ++ phy_interface_mode_is_8023z(interface)) { ++ /* Force the speed and duplex setting */ ++ if (speed == SPEED_10) ++ sgm_mode = SGMII_SPEED_10; ++ else if (speed == SPEED_100) ++ sgm_mode = SGMII_SPEED_100; ++ else ++ sgm_mode = SGMII_SPEED_1000; + +- /* SGMII force duplex setting */ +- if (duplex == DUPLEX_FULL) +- sgm_mode = SGMII_DUPLEX_FULL; +- else +- sgm_mode = 0; ++ if (duplex == DUPLEX_FULL) ++ sgm_mode |= SGMII_DUPLEX_FULL; + +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_DUPLEX_FULL, sgm_mode); ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_DUPLEX_FULL | SGMII_SPEED_MASK, ++ sgm_mode); ++ } + } + + static const struct phylink_pcs_ops mtk_pcs_ops = { diff --git a/target/linux/generic/backport-5.15/733-v6.2-07-net-mtk_eth_soc-move-PHY-power-up.patch b/target/linux/generic/backport-5.15/733-v6.2-07-net-mtk_eth_soc-move-PHY-power-up.patch new file mode 100644 index 00000000000..b76e1592750 --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-07-net-mtk_eth_soc-move-PHY-power-up.patch @@ -0,0 +1,48 @@ +From 6f38fffe2179dd29612aea2c67c46ed6682b4e46 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:08 +0100 +Subject: [PATCH 06/10] net: mtk_eth_soc: move PHY power up + +The PHY power up is common to both configuration paths, so move it into +the parent function. We need to do this for all serdes modes. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -45,9 +45,6 @@ static void mtk_pcs_setup_mode_an(struct + + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, + SGMII_AN_RESTART, SGMII_AN_RESTART); +- +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, 0); + } + + /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a +@@ -72,10 +69,6 @@ static void mtk_pcs_setup_mode_force(str + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, + SGMII_IF_MODE_MASK & ~SGMII_DUPLEX_FULL, + SGMII_SPEED_1000); +- +- /* Release PHYA power down state */ +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, 0); + } + + static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -91,6 +84,10 @@ static int mtk_pcs_config(struct phylink + else if (phylink_autoneg_inband(mode)) + mtk_pcs_setup_mode_an(mpcs); + ++ /* Release PHYA power down state */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, 0); ++ + return 0; + } + diff --git a/target/linux/generic/backport-5.15/733-v6.2-08-net-mtk_eth_soc-move-interface-speed-selection.patch b/target/linux/generic/backport-5.15/733-v6.2-08-net-mtk_eth_soc-move-interface-speed-selection.patch new file mode 100644 index 00000000000..cd9f0699b3e --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-08-net-mtk_eth_soc-move-interface-speed-selection.patch @@ -0,0 +1,48 @@ +From f752c0df13dfeb721c11d3debb79f08cf437344f Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:13 +0100 +Subject: [PATCH 07/10] net: mtk_eth_soc: move interface speed selection + +Move the selection of the underlying interface speed to the pcs_config +function, so we always program the interface speed. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -53,14 +53,6 @@ static void mtk_pcs_setup_mode_an(struct + static void mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, + phy_interface_t interface) + { +- unsigned int rgc3; +- +- if (interface == PHY_INTERFACE_MODE_2500BASEX) +- rgc3 = RG_PHY_SPEED_3_125G; +- +- regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, +- RG_PHY_SPEED_3_125G, rgc3); +- + /* Disable SGMII AN */ + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, + SGMII_AN_ENABLE, 0); +@@ -77,6 +69,16 @@ static int mtk_pcs_config(struct phylink + bool permit_pause_to_mac) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); ++ unsigned int rgc3; ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ rgc3 = RG_PHY_SPEED_3_125G; ++ else ++ rgc3 = 0; ++ ++ /* Configure the underlying interface speed */ ++ regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, ++ RG_PHY_SPEED_3_125G, rgc3); + + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) diff --git a/target/linux/generic/backport-5.15/733-v6.2-09-net-mtk_eth_soc-add-advertisement-programming.patch b/target/linux/generic/backport-5.15/733-v6.2-09-net-mtk_eth_soc-add-advertisement-programming.patch new file mode 100644 index 00000000000..f08358e963d --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-09-net-mtk_eth_soc-add-advertisement-programming.patch @@ -0,0 +1,52 @@ +From c125c66ea71b9377ae2478c4f1b87b180cc5c6ef Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:18 +0100 +Subject: [PATCH 08/10] net: mtk_eth_soc: add advertisement programming + +Program the advertisement into the mtk PCS block. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -70,16 +70,27 @@ static int mtk_pcs_config(struct phylink + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int rgc3; ++ int advertise; ++ bool changed; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + rgc3 = RG_PHY_SPEED_3_125G; + else + rgc3 = 0; + ++ advertise = phylink_mii_c22_pcs_encode_advertisement(interface, ++ advertising); ++ if (advertise < 0) ++ return advertise; ++ + /* Configure the underlying interface speed */ + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); + ++ /* Update the advertisement, noting whether it has changed */ ++ regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, ++ SGMII_ADVERTISE, advertise, &changed); ++ + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) + mtk_pcs_setup_mode_force(mpcs, interface); +@@ -90,7 +101,7 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, 0); + +- return 0; ++ return changed; + } + + static void mtk_pcs_restart_an(struct phylink_pcs *pcs) diff --git a/target/linux/generic/backport-5.15/733-v6.2-10-net-mtk_eth_soc-move-and-correct-link-timer-programm.patch b/target/linux/generic/backport-5.15/733-v6.2-10-net-mtk_eth_soc-move-and-correct-link-timer-programm.patch new file mode 100644 index 00000000000..602d52c6f46 --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-10-net-mtk_eth_soc-move-and-correct-link-timer-programm.patch @@ -0,0 +1,63 @@ +From 3027d89f87707e7f3e5b683e0d37a32afb5bde96 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:23 +0100 +Subject: [PATCH 09/10] net: mtk_eth_soc: move and correct link timer + programming + +Program the link timer appropriately for the interface mode being +used, using the newly introduced phylink helper that provides the +nanosecond link timer interval. + +The intervals are 1.6ms for SGMII based protocols and 10ms for +802.3z based protocols. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -36,10 +36,6 @@ static void mtk_pcs_get_state(struct phy + /* For SGMII interface mode */ + static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { +- /* Setup the link timer and QPHY power up inside SGMIISYS */ +- regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, +- SGMII_LINK_TIMER_DEFAULT); +- + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, + SGMII_REMOTE_FAULT_DIS, SGMII_REMOTE_FAULT_DIS); + +@@ -69,8 +65,8 @@ static int mtk_pcs_config(struct phylink + bool permit_pause_to_mac) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); ++ int advertise, link_timer; + unsigned int rgc3; +- int advertise; + bool changed; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) +@@ -83,6 +79,10 @@ static int mtk_pcs_config(struct phylink + if (advertise < 0) + return advertise; + ++ link_timer = phylink_get_link_timer_ns(interface); ++ if (link_timer < 0) ++ return link_timer; ++ + /* Configure the underlying interface speed */ + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); +@@ -91,6 +91,9 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, + SGMII_ADVERTISE, advertise, &changed); + ++ /* Setup the link timer and QPHY power up inside SGMIISYS */ ++ regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); ++ + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) + mtk_pcs_setup_mode_force(mpcs, interface); diff --git a/target/linux/generic/backport-5.15/733-v6.2-11-net-mtk_eth_soc-add-support-for-in-band-802.3z-negot.patch b/target/linux/generic/backport-5.15/733-v6.2-11-net-mtk_eth_soc-add-support-for-in-band-802.3z-negot.patch new file mode 100644 index 00000000000..0e9a0535a7b --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.2-11-net-mtk_eth_soc-add-support-for-in-band-802.3z-negot.patch @@ -0,0 +1,132 @@ +From 81b0f12a2a8a1699a7d49c3995e5f71e4ec018e6 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:28 +0100 +Subject: [PATCH 10/10] net: mtk_eth_soc: add support for in-band 802.3z + negotiation + +As a result of help from Frank Wunderlich to investigate and test, we +now know how to program this PCS for in-band 802.3z negotiation. Add +support for this by moving the contents of the two functions into the +common mtk_pcs_config() function and adding the register settings for +802.3z negotiation. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 77 ++++++++++++----------- + 1 file changed, 42 insertions(+), 35 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -33,41 +33,15 @@ static void mtk_pcs_get_state(struct phy + FIELD_GET(SGMII_LPA, adv)); + } + +-/* For SGMII interface mode */ +-static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) +-{ +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_REMOTE_FAULT_DIS, SGMII_REMOTE_FAULT_DIS); +- +- regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_RESTART, SGMII_AN_RESTART); +-} +- +-/* For 1000BASE-X and 2500BASE-X interface modes, which operate at a +- * fixed speed. +- */ +-static void mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, +- phy_interface_t interface) +-{ +- /* Disable SGMII AN */ +- regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_ENABLE, 0); +- +- /* Set the speed etc but leave the duplex unchanged */ +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_IF_MODE_MASK & ~SGMII_DUPLEX_FULL, +- SGMII_SPEED_1000); +-} +- + static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); ++ unsigned int rgc3, sgm_mode, bmcr; + int advertise, link_timer; +- unsigned int rgc3; +- bool changed; ++ bool changed, use_an; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + rgc3 = RG_PHY_SPEED_3_125G; +@@ -83,6 +57,37 @@ static int mtk_pcs_config(struct phylink + if (link_timer < 0) + return link_timer; + ++ /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and ++ * we assume that fixes it's speed at bitrate = line rate (in ++ * other words, 1000Mbps or 2500Mbps). ++ */ ++ if (interface == PHY_INTERFACE_MODE_SGMII) { ++ sgm_mode = SGMII_IF_MODE_SGMII; ++ if (phylink_autoneg_inband(mode)) { ++ sgm_mode |= SGMII_REMOTE_FAULT_DIS | ++ SGMII_SPEED_DUPLEX_AN; ++ use_an = true; ++ } else { ++ use_an = false; ++ } ++ } else if (phylink_autoneg_inband(mode)) { ++ /* 1000base-X or 2500base-X autoneg */ ++ sgm_mode = SGMII_REMOTE_FAULT_DIS; ++ use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, ++ advertising); ++ } else { ++ /* 1000base-X or 2500base-X without autoneg */ ++ sgm_mode = 0; ++ use_an = false; ++ } ++ ++ if (use_an) { ++ /* FIXME: Do we need to set AN_RESTART here? */ ++ bmcr = SGMII_AN_RESTART | SGMII_AN_ENABLE; ++ } else { ++ bmcr = 0; ++ } ++ + /* Configure the underlying interface speed */ + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); +@@ -94,11 +99,14 @@ static int mtk_pcs_config(struct phylink + /* Setup the link timer and QPHY power up inside SGMIISYS */ + regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); + +- /* Setup SGMIISYS with the determined property */ +- if (interface != PHY_INTERFACE_MODE_SGMII) +- mtk_pcs_setup_mode_force(mpcs, interface); +- else if (phylink_autoneg_inband(mode)) +- mtk_pcs_setup_mode_an(mpcs); ++ /* Update the sgmsys mode register */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | ++ SGMII_IF_MODE_SGMII, sgm_mode); ++ ++ /* Update the BMCR */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr); + + /* Release PHYA power down state */ + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +@@ -121,8 +129,7 @@ static void mtk_pcs_link_up(struct phyli + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int sgm_mode; + +- if (!phylink_autoneg_inband(mode) || +- phy_interface_mode_is_8023z(interface)) { ++ if (!phylink_autoneg_inband(mode)) { + /* Force the speed and duplex setting */ + if (speed == SPEED_10) + sgm_mode = SGMII_SPEED_10; diff --git a/target/linux/generic/backport-5.15/733-v6.2-02-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch b/target/linux/generic/backport-5.15/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch similarity index 66% rename from target/linux/generic/backport-5.15/733-v6.2-02-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch rename to target/linux/generic/backport-5.15/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch index 62830ebf106..8d2991f4500 100644 --- a/target/linux/generic/backport-5.15/733-v6.2-02-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch +++ b/target/linux/generic/backport-5.15/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch @@ -1,8 +1,8 @@ From 7ff82416de8295c61423ef6fd75f052d3837d2f7 Mon Sep 17 00:00:00 2001 From: Alexander Couzens Date: Wed, 1 Feb 2023 19:23:29 +0100 -Subject: [PATCH] net: mediatek: sgmii: ensure the SGMII PHY is powered down on - configuration +Subject: [PATCH 11/13] net: mediatek: sgmii: ensure the SGMII PHY is powered + down on configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -34,7 +34,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1063,11 +1063,13 @@ struct mtk_soc_data { +@@ -1070,11 +1070,13 @@ struct mtk_soc_data { * @regmap: The register map pointing at the range used to setup * SGMII modes * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap @@ -50,57 +50,51 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_sgmii.c +++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -24,6 +24,10 @@ static int mtk_pcs_setup_mode_an(struct - { - unsigned int val; +@@ -43,11 +43,6 @@ static int mtk_pcs_config(struct phylink + int advertise, link_timer; + bool changed, use_an; -+ regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); -+ val &= ~RG_PHY_SPEED_MASK; -+ regmap_write(mpcs->regmap, mpcs->ana_rgc3, val); -+ - /* Setup the link timer and QPHY power up inside SGMIISYS */ - regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, - SGMII_LINK_TIMER_DEFAULT); -@@ -36,9 +40,6 @@ static int mtk_pcs_setup_mode_an(struct - val |= SGMII_AN_RESTART; - regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); - -- regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); -- val &= ~SGMII_PHYA_PWD; -- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); - - return 0; - -@@ -69,11 +70,6 @@ static int mtk_pcs_setup_mode_force(stru - val |= SGMII_SPEED_1000; - regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); - -- /* Release PHYA power down state */ -- regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); -- val &= ~SGMII_PHYA_PWD; -- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); +- if (interface == PHY_INTERFACE_MODE_2500BASEX) +- rgc3 = RG_PHY_SPEED_3_125G; +- else +- rgc3 = 0; - - return 0; - } - -@@ -85,12 +81,32 @@ static int mtk_pcs_config(struct phylink - struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); - int err = 0; + advertise = phylink_mii_c22_pcs_encode_advertisement(interface, + advertising); + if (advertise < 0) +@@ -88,9 +83,22 @@ static int mtk_pcs_config(struct phylink + bmcr = 0; + } +- /* Configure the underlying interface speed */ +- regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, +- RG_PHY_SPEED_3_125G, rgc3); + if (mpcs->interface != interface) { + /* PHYA power down */ + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, SGMII_PHYA_PWD); + ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ rgc3 = RG_PHY_SPEED_3_125G; ++ else ++ rgc3 = 0; ++ ++ /* Configure the underlying interface speed */ ++ regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, ++ RG_PHY_SPEED_3_125G, rgc3); ++ + mpcs->interface = interface; + } -+ - /* Setup SGMIISYS with the determined property */ - if (interface != PHY_INTERFACE_MODE_SGMII) - err = mtk_pcs_setup_mode_force(mpcs, interface); - else if (phylink_autoneg_inband(mode)) - err = mtk_pcs_setup_mode_an(mpcs); + /* Update the advertisement, noting whether it has changed */ + regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, +@@ -108,9 +116,17 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, + SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr); + +- /* Release PHYA power down state */ +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, 0); + /* Release PHYA power down state + * Only removing bit SGMII_PHYA_PWD isn't enough. + * There are cases when the SGMII_PHYA_PWD register contains 0x9 which @@ -112,11 +106,10 @@ Signed-off-by: Jakub Kicinski + */ + usleep_range(50, 100); + regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); -+ - return err; - } -@@ -145,6 +161,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + return changed; + } +@@ -171,6 +187,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, return PTR_ERR(ss->pcs[i].regmap); ss->pcs[i].pcs.ops = &mtk_pcs_ops; diff --git a/target/linux/generic/backport-5.15/733-v6.2-03-net-mediatek-sgmii-fix-duplex-configuration.patch b/target/linux/generic/backport-5.15/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch similarity index 63% rename from target/linux/generic/backport-5.15/733-v6.2-03-net-mediatek-sgmii-fix-duplex-configuration.patch rename to target/linux/generic/backport-5.15/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch index eb6837f47a0..79e5ad147ce 100644 --- a/target/linux/generic/backport-5.15/733-v6.2-03-net-mediatek-sgmii-fix-duplex-configuration.patch +++ b/target/linux/generic/backport-5.15/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch @@ -1,7 +1,7 @@ From 9d32637122de88f1ef614c29703f0e050cad342e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 1 Feb 2023 19:23:30 +0100 -Subject: [PATCH] net: mediatek: sgmii: fix duplex configuration +Subject: [PATCH 12/13] net: mediatek: sgmii: fix duplex configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -24,7 +24,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -524,7 +524,7 @@ +@@ -531,7 +531,7 @@ #define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) #define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) #define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) @@ -35,26 +35,18 @@ Signed-off-by: Jakub Kicinski #define SGMII_CODE_SYNC_SET_VAL BIT(9) --- a/drivers/net/ethernet/mediatek/mtk_sgmii.c +++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -66,7 +66,7 @@ static int mtk_pcs_setup_mode_force(stru +@@ -154,11 +154,11 @@ static void mtk_pcs_link_up(struct phyli + else + sgm_mode = SGMII_SPEED_1000; - /* Set the speed etc but leave the duplex unchanged */ - regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); -- val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK; -+ val &= SGMII_DUPLEX_HALF | ~SGMII_IF_MODE_MASK; - val |= SGMII_SPEED_1000; - regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); +- if (duplex == DUPLEX_FULL) +- sgm_mode |= SGMII_DUPLEX_FULL; ++ if (duplex != DUPLEX_FULL) ++ sgm_mode |= SGMII_DUPLEX_HALF; -@@ -131,9 +131,10 @@ static void mtk_pcs_link_up(struct phyli - - /* SGMII force duplex setting */ - regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); -- val &= ~SGMII_DUPLEX_FULL; -- if (duplex == DUPLEX_FULL) -- val |= SGMII_DUPLEX_FULL; -+ -+ val &= ~SGMII_DUPLEX_HALF; -+ if (duplex != DUPLEX_FULL) -+ val |= SGMII_DUPLEX_HALF; - - regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_DUPLEX_FULL | SGMII_SPEED_MASK, ++ SGMII_DUPLEX_HALF | SGMII_SPEED_MASK, + sgm_mode); + } } diff --git a/target/linux/generic/backport-5.15/733-v6.2-04-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch b/target/linux/generic/backport-5.15/733-v6.2-14-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch similarity index 89% rename from target/linux/generic/backport-5.15/733-v6.2-04-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch rename to target/linux/generic/backport-5.15/733-v6.2-14-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch index ace8aa075b3..56d7a1348fb 100644 --- a/target/linux/generic/backport-5.15/733-v6.2-04-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch +++ b/target/linux/generic/backport-5.15/733-v6.2-14-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch @@ -1,7 +1,7 @@ From 3337a6e04ddf2923a1bdcf3d31b3b52412bf82dd Mon Sep 17 00:00:00 2001 From: Alexander Couzens Date: Wed, 1 Feb 2023 19:23:31 +0100 -Subject: [PATCH] mtk_sgmii: enable PCS polling to allow SFP work +Subject: [PATCH 13/13] mtk_sgmii: enable PCS polling to allow SFP work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -23,7 +23,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_sgmii.c +++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -162,6 +162,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, +@@ -187,6 +187,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, return PTR_ERR(ss->pcs[i].regmap); ss->pcs[i].pcs.ops = &mtk_pcs_ops; diff --git a/target/linux/generic/pending-5.15/733-01-net-ethernet-mtk_eth_soc-reset-PCS-state.patch b/target/linux/generic/backport-5.15/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch similarity index 65% rename from target/linux/generic/pending-5.15/733-01-net-ethernet-mtk_eth_soc-reset-PCS-state.patch rename to target/linux/generic/backport-5.15/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch index 4d52d7be393..a63b110914b 100644 --- a/target/linux/generic/pending-5.15/733-01-net-ethernet-mtk_eth_soc-reset-PCS-state.patch +++ b/target/linux/generic/backport-5.15/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch @@ -1,16 +1,20 @@ -From b66105968b8c37c26a75b9da9281cbc1c8f73594 Mon Sep 17 00:00:00 2001 +From 611e2dabb4b3243d176739fd6a5a34d007fa3f86 Mon Sep 17 00:00:00 2001 From: Daniel Golle -Date: Sun, 22 Jan 2023 23:58:36 +0000 -Subject: [PATCH] net: ethernet: mtk_eth_soc: reset PCS state +Date: Tue, 14 Mar 2023 00:34:26 +0000 +Subject: [PATCH 1/2] net: ethernet: mtk_eth_soc: reset PCS state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -Reset PCS state when changing interface mode. +Reset the internal PCS state machine when changing interface mode. +This prevents confusing the state machine when changing interface +modes, e.g. from SGMII to 2500Base-X or vice-versa. +Fixes: 7e538372694b ("net: ethernet: mediatek: Re-add support SGMII") Reviewed-by: Russell King (Oracle) Tested-by: Bjørn Mork Signed-off-by: Daniel Golle +Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++ drivers/net/ethernet/mediatek/mtk_sgmii.c | 4 ++++ @@ -18,7 +22,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -530,6 +530,10 @@ +@@ -539,6 +539,10 @@ #define SGMII_SEND_AN_ERROR_EN BIT(11) #define SGMII_IF_MODE_MASK GENMASK(5, 1) @@ -31,7 +35,7 @@ Signed-off-by: Daniel Golle #define RG_PHY_SPEED_MASK (BIT(2) | BIT(3)) --- a/drivers/net/ethernet/mediatek/mtk_sgmii.c +++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -90,6 +90,10 @@ static int mtk_pcs_config(struct phylink +@@ -88,6 +88,10 @@ static int mtk_pcs_config(struct phylink regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD, SGMII_PHYA_PWD); @@ -39,6 +43,6 @@ Signed-off-by: Daniel Golle + regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0, + SGMII_SW_RESET, SGMII_SW_RESET); + - mpcs->interface = interface; - } - + if (interface == PHY_INTERFACE_MODE_2500BASEX) + rgc3 = RG_PHY_SPEED_3_125G; + else diff --git a/target/linux/generic/backport-5.15/733-v6.3-16-net-ethernet-mtk_eth_soc-only-write-values-if-needed.patch b/target/linux/generic/backport-5.15/733-v6.3-16-net-ethernet-mtk_eth_soc-only-write-values-if-needed.patch new file mode 100644 index 00000000000..0fabeea20c0 --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.3-16-net-ethernet-mtk_eth_soc-only-write-values-if-needed.patch @@ -0,0 +1,103 @@ +From 6e933a804c7db8be64f367f33e63cd7dcc302ebb Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 14 Mar 2023 00:34:45 +0000 +Subject: [PATCH 2/2] net: ethernet: mtk_eth_soc: only write values if needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only restart auto-negotiation and write link timer if actually +necessary. This prevents losing the link in case of minor +changes. + +Fixes: 7e538372694b ("net: ethernet: mediatek: Re-add support SGMII") +Reviewed-by: Russell King (Oracle) +Tested-by: Bjørn Mork +Signed-off-by: Daniel Golle +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 24 +++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -38,20 +38,16 @@ static int mtk_pcs_config(struct phylink + const unsigned long *advertising, + bool permit_pause_to_mac) + { ++ bool mode_changed = false, changed, use_an; + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int rgc3, sgm_mode, bmcr; + int advertise, link_timer; +- bool changed, use_an; + + advertise = phylink_mii_c22_pcs_encode_advertisement(interface, + advertising); + if (advertise < 0) + return advertise; + +- link_timer = phylink_get_link_timer_ns(interface); +- if (link_timer < 0) +- return link_timer; +- + /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and + * we assume that fixes it's speed at bitrate = line rate (in + * other words, 1000Mbps or 2500Mbps). +@@ -77,13 +73,16 @@ static int mtk_pcs_config(struct phylink + } + + if (use_an) { +- /* FIXME: Do we need to set AN_RESTART here? */ +- bmcr = SGMII_AN_RESTART | SGMII_AN_ENABLE; ++ bmcr = SGMII_AN_ENABLE; + } else { + bmcr = 0; + } + + if (mpcs->interface != interface) { ++ link_timer = phylink_get_link_timer_ns(interface); ++ if (link_timer < 0) ++ return link_timer; ++ + /* PHYA power down */ + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, SGMII_PHYA_PWD); +@@ -101,16 +100,17 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); + ++ /* Setup the link timer */ ++ regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); ++ + mpcs->interface = interface; ++ mode_changed = true; + } + + /* Update the advertisement, noting whether it has changed */ + regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, + SGMII_ADVERTISE, advertise, &changed); + +- /* Setup the link timer and QPHY power up inside SGMIISYS */ +- regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); +- + /* Update the sgmsys mode register */ + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, + SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | +@@ -118,7 +118,7 @@ static int mtk_pcs_config(struct phylink + + /* Update the BMCR */ + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr); ++ SGMII_AN_ENABLE, bmcr); + + /* Release PHYA power down state + * Only removing bit SGMII_PHYA_PWD isn't enough. +@@ -132,7 +132,7 @@ static int mtk_pcs_config(struct phylink + usleep_range(50, 100); + regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); + +- return changed; ++ return changed || mode_changed; + } + + static void mtk_pcs_restart_an(struct phylink_pcs *pcs) diff --git a/target/linux/generic/pending-5.15/724-net-mtk_sgmii-implement-mtk_pcs_ops.patch b/target/linux/generic/pending-5.15/724-net-mtk_sgmii-implement-mtk_pcs_ops.patch deleted file mode 100644 index 9a6b228a272..00000000000 --- a/target/linux/generic/pending-5.15/724-net-mtk_sgmii-implement-mtk_pcs_ops.patch +++ /dev/null @@ -1,46 +0,0 @@ -From cbfed00575d15eafd85efd9619b7ecc0836a4aa7 Mon Sep 17 00:00:00 2001 -From: Alexander Couzens -Date: Sat, 13 Aug 2022 14:42:12 +0200 -Subject: [PATCH 04/10] net: mtk_sgmii: implement mtk_pcs_ops - -Implement mtk_pcs_ops for the SGMII pcs to read the current state -of the hardware. - -Signed-off-by: Alexander Couzens -[added DUPLEX_FULL] -Signed-off-by: Daniel Golle ---- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -139,10 +139,28 @@ static void mtk_pcs_link_up(struct phyli - regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); - } - -+static void mtk_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state) -+{ -+ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); -+ unsigned int val; -+ -+ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); -+ state->an_complete = !!(val & SGMII_AN_COMPLETE); -+ state->link = !!(val & SGMII_LINK_STATYS); -+ if (!state->link) -+ return; -+ -+ regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); -+ state->speed = val & RG_PHY_SPEED_3_125G ? SPEED_2500 : SPEED_1000; -+ state->duplex = DUPLEX_FULL; -+ state->pause = 0; -+} -+ - static const struct phylink_pcs_ops mtk_pcs_ops = { - .pcs_config = mtk_pcs_config, - .pcs_an_restart = mtk_pcs_restart_an, - .pcs_link_up = mtk_pcs_link_up, -+ .pcs_get_state = mtk_pcs_get_state, - }; - - int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) diff --git a/target/linux/generic/pending-5.15/727-net-mtk_sgmii-mtk_pcs_setup_mode_an-don-t-rely-on-re.patch b/target/linux/generic/pending-5.15/727-net-mtk_sgmii-mtk_pcs_setup_mode_an-don-t-rely-on-re.patch deleted file mode 100644 index fd68ce22f69..00000000000 --- a/target/linux/generic/pending-5.15/727-net-mtk_sgmii-mtk_pcs_setup_mode_an-don-t-rely-on-re.patch +++ /dev/null @@ -1,31 +0,0 @@ -From e4dca7affb8c03438b63bdb5fddefd6ad2431cfd Mon Sep 17 00:00:00 2001 -From: Alexander Couzens -Date: Mon, 15 Aug 2022 14:59:29 +0200 -Subject: [PATCH 07/10] net: mtk_sgmii: mtk_pcs_setup_mode_an: don't rely on - register defaults - -Ensure autonegotiation is enabled. - -Signed-off-by: Alexander Couzens ---- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -32,12 +32,13 @@ static int mtk_pcs_setup_mode_an(struct - regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, - SGMII_LINK_TIMER_DEFAULT); - -+ /* disable remote fault & enable auto neg */ - regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); -- val |= SGMII_REMOTE_FAULT_DIS; -+ val |= SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN; - regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); - - regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); -- val |= SGMII_AN_RESTART; -+ val |= SGMII_AN_RESTART | SGMII_AN_ENABLE; - regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); - - diff --git a/target/linux/generic/pending-5.15/728-net-mtk_sgmii-set-the-speed-according-to-the-phy-int.patch b/target/linux/generic/pending-5.15/728-net-mtk_sgmii-set-the-speed-according-to-the-phy-int.patch deleted file mode 100644 index 1649a64551d..00000000000 --- a/target/linux/generic/pending-5.15/728-net-mtk_sgmii-set-the-speed-according-to-the-phy-int.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 952b64575613d26163a5afa5ff8bfdb57840091b Mon Sep 17 00:00:00 2001 -From: Alexander Couzens -Date: Mon, 15 Aug 2022 15:00:14 +0200 -Subject: [PATCH 08/10] net: mtk_sgmii: set the speed according to the phy - interface in AN - -The non auto-negotioting code path is setting the correct speed for the -interface. Ensure auto-negotiation code path is doing it as well. - -Signed-off-by: Alexander Couzens ---- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -20,12 +20,14 @@ static struct mtk_pcs *pcs_to_mtk_pcs(st - } - - /* For SGMII interface mode */ --static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) -+static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs, phy_interface_t interface) - { - unsigned int val; - - regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); - val &= ~RG_PHY_SPEED_MASK; -+ if (interface == PHY_INTERFACE_MODE_2500BASEX) -+ val |= RG_PHY_SPEED_3_125G; - regmap_write(mpcs->regmap, mpcs->ana_rgc3, val); - - /* Setup the link timer and QPHY power up inside SGMIISYS */ -@@ -94,7 +96,7 @@ static int mtk_pcs_config(struct phylink - if (interface != PHY_INTERFACE_MODE_SGMII) - err = mtk_pcs_setup_mode_force(mpcs, interface); - else if (phylink_autoneg_inband(mode)) -- err = mtk_pcs_setup_mode_an(mpcs); -+ err = mtk_pcs_setup_mode_an(mpcs, interface); - - /* Release PHYA power down state - * Only removing bit SGMII_PHYA_PWD isn't enough. diff --git a/target/linux/generic/pending-5.15/729-net-mtk_eth_soc-improve-comment.patch b/target/linux/generic/pending-5.15/729-net-mtk_eth_soc-improve-comment.patch deleted file mode 100644 index cd64c6147ad..00000000000 --- a/target/linux/generic/pending-5.15/729-net-mtk_eth_soc-improve-comment.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 06773f19cffd6c9d34dcbc8320169afef5ab60ba Mon Sep 17 00:00:00 2001 -From: Alexander Couzens -Date: Mon, 15 Aug 2022 13:58:07 +0200 -Subject: [PATCH 09/10] net: mtk_eth_soc: improve comment - -Signed-off-by: Alexander Couzens ---- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -67,7 +67,8 @@ static int mtk_pcs_setup_mode_force(stru - val &= ~SGMII_AN_ENABLE; - regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); - -- /* Set the speed etc but leave the duplex unchanged */ -+ /* Set the speed etc but leave the duplex unchanged. -+ * The SGMII mode for 2.5gbit is the same as for 1gbit, expect the speed in ANA_RGC3 */ - regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); - val &= SGMII_DUPLEX_HALF | ~SGMII_IF_MODE_MASK; - val |= SGMII_SPEED_1000; diff --git a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch index 9268d3e428f..67bd504da14 100644 --- a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch +++ b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch @@ -90,7 +90,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .rxd_size = sizeof(struct mtk_rx_dma_v2), --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1026,6 +1026,8 @@ struct mtk_reg_map { +@@ -1037,6 +1037,8 @@ struct mtk_reg_map { * the extra setup for those pins used by GMAC. * @hash_offset Flow table hash offset. * @foe_entry_size Foe table entry size. @@ -99,7 +99,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov * @txd_size Tx DMA descriptor size. * @rxd_size Rx DMA descriptor size. * @rx_irq_done_mask Rx irq done register mask. -@@ -1043,6 +1045,7 @@ struct mtk_soc_data { +@@ -1054,6 +1056,7 @@ struct mtk_soc_data { u8 hash_offset; u16 foe_entry_size; netdev_features_t hw_features; diff --git a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch index 0496752f780..4017e2beac8 100644 --- a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch +++ b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1319,6 +1319,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk +@@ -1326,6 +1326,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk int mtk_eth_offload_init(struct mtk_eth *eth); int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data); From 658c4dd43f63d6cab0d7e33800002471fd5dc49b Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 10 Mar 2023 19:36:12 +0000 Subject: [PATCH 37/53] mediatek: backport clk driver for MT7981 SoC Backport driver for common clocks in MT7981 SoC. The driver has also been submitted upstream and became part of Linux 6.3. Signed-off-by: Daniel Golle --- .../drivers/clk/mediatek/clk-mt7981-apmixed.c | 102 ++++ .../drivers/clk/mediatek/clk-mt7981-eth.c | 139 ++++++ .../clk/mediatek/clk-mt7981-infracfg.c | 235 +++++++++ .../clk/mediatek/clk-mt7981-topckgen.c | 450 ++++++++++++++++++ .../dt-bindings/clock/mediatek,mt7981-clk.h | 215 +++++++++ target/linux/mediatek/filogic/config-5.15 | 2 + target/linux/mediatek/mt7622/config-5.15 | 1 + target/linux/mediatek/mt7623/config-5.15 | 1 + target/linux/mediatek/mt7629/config-5.15 | 1 + ...lk-mediatek-add-mt7981-clock-support.patch | 39 ++ 10 files changed, 1185 insertions(+) create mode 100644 target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-apmixed.c create mode 100644 target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-eth.c create mode 100644 target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-infracfg.c create mode 100644 target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-topckgen.c create mode 100644 target/linux/mediatek/files-5.15/include/dt-bindings/clock/mediatek,mt7981-clk.h create mode 100644 target/linux/mediatek/patches-5.15/214-v6.3-clk-mediatek-add-mt7981-clock-support.patch diff --git a/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-apmixed.c b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-apmixed.c new file mode 100644 index 00000000000..1647021de88 --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-apmixed.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Sam Shih + * Author: Wenzhen Yu + * Author: Jianhui Zhao + * Author: Daniel Golle + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" + +#include +#include + +#define MT7981_PLL_FMAX (2500UL * MHZ) +#define CON0_MT7981_RST_BAR BIT(27) + +#define PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ + _div_table, _parent_name) \ + { \ + .id = _id, .name = _name, .reg = _reg, .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, .flags = _flags, \ + .rst_bar_mask = CON0_MT7981_RST_BAR, .fmax = MT7981_PLL_FMAX, \ + .pcwbits = _pcwbits, .pd_reg = _pd_reg, .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, .div_table = _div_table, \ + .parent_name = _parent_name, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \ + _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) \ + PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, NULL, \ + "clkxtal") + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x00000001, PLL_AO, + 32, 0x0200, 4, 0, 0x0204, 0), + PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0210, 0x021C, 0x00000001, 0, 32, + 0x0210, 4, 0, 0x0214, 0), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0220, 0x022C, 0x00000001, 0, 32, + 0x0220, 4, 0, 0x0224, 0), + PLL(CLK_APMIXED_SGMPLL, "sgmpll", 0x0230, 0x023C, 0x00000001, 0, 32, + 0x0230, 4, 0, 0x0234, 0), + PLL(CLK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0240, 0x024C, 0x00000001, 0, 32, + 0x0240, 4, 0, 0x0244, 0), + PLL(CLK_APMIXED_NET1PLL, "net1pll", 0x0250, 0x025C, 0x00000001, 0, 32, + 0x0250, 4, 0, 0x0254, 0), + PLL(CLK_APMIXED_MPLL, "mpll", 0x0260, 0x0270, 0x00000001, 0, 32, + 0x0260, 4, 0, 0x0264, 0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x0278, 0x0288, 0x00000001, 0, 32, + 0x0278, 4, 0, 0x027C, 0), +}; + +static const struct of_device_id of_match_clk_mt7981_apmixed[] = { + { .compatible = "mediatek,mt7981-apmixedsys", }, + {} +}; + +static int clk_mt7981_apmixed_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls)); + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + + clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMPLL]); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_apmixed_data; + } + return r; + +free_apmixed_data: + mtk_free_clk_data(clk_data); + return r; +} + +static struct platform_driver clk_mt7981_apmixed_drv = { + .probe = clk_mt7981_apmixed_probe, + .driver = { + .name = "clk-mt7981-apmixed", + .of_match_table = of_match_clk_mt7981_apmixed, + }, +}; +builtin_platform_driver(clk_mt7981_apmixed_drv); diff --git a/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-eth.c b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-eth.c new file mode 100644 index 00000000000..4aba657aa6f --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-eth.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Sam Shih + * Author: Wenzhen Yu + * Author: Jianhui Zhao + * Author: Daniel Golle + */ + +#include +#include +#include +#include +#include + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include + +static const struct mtk_gate_regs sgmii0_cg_regs = { + .set_ofs = 0xE4, + .clr_ofs = 0xE4, + .sta_ofs = 0xE4, +}; + +#define GATE_SGMII0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &sgmii0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate sgmii0_clks[] __initconst = { + GATE_SGMII0(CLK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2), + GATE_SGMII0(CLK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3), + GATE_SGMII0(CLK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4), + GATE_SGMII0(CLK_SGM0_CDR_CK0_EN, "sgm0_cdr_ck0_en", "usb_cdr", 5), +}; + +static const struct mtk_gate_regs sgmii1_cg_regs = { + .set_ofs = 0xE4, + .clr_ofs = 0xE4, + .sta_ofs = 0xE4, +}; + +#define GATE_SGMII1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &sgmii1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate sgmii1_clks[] __initconst = { + GATE_SGMII1(CLK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2), + GATE_SGMII1(CLK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3), + GATE_SGMII1(CLK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4), + GATE_SGMII1(CLK_SGM1_CDR_CK1_EN, "sgm1_cdr_ck1_en", "usb_cdr", 5), +}; + +static const struct mtk_gate_regs eth_cg_regs = { + .set_ofs = 0x30, + .clr_ofs = 0x30, + .sta_ofs = 0x30, +}; + +#define GATE_ETH(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = ð_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate eth_clks[] __initconst = { + GATE_ETH(CLK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6), + GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7), + GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8), + GATE_ETH(CLK_ETH_WOCPU0_EN, "eth_wocpu0_en", "netsys_wed_mcu", 15), +}; + +static void __init mtk_sgmiisys_0_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + int r; + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii0_clks)); + + mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); +} +CLK_OF_DECLARE(mtk_sgmiisys_0, "mediatek,mt7981-sgmiisys_0", + mtk_sgmiisys_0_init); + +static void __init mtk_sgmiisys_1_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + int r; + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii1_clks)); + + mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); +} +CLK_OF_DECLARE(mtk_sgmiisys_1, "mediatek,mt7981-sgmiisys_1", + mtk_sgmiisys_1_init); + +static void __init mtk_ethsys_init(struct device_node *node) +{ + struct clk_onecell_data *clk_data; + int r; + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(eth_clks)); + + mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); +} +CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt7981-ethsys", mtk_ethsys_init); diff --git a/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-infracfg.c b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-infracfg.c new file mode 100644 index 00000000000..8416829e358 --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-infracfg.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Sam Shih + * Author: Wenzhen Yu + * Author: Jianhui Zhao + * Author: Daniel Golle + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" + +#include +#include + +static DEFINE_SPINLOCK(mt7981_clk_lock); + +static const struct mtk_fixed_factor infra_divs[] = { + FACTOR(CLK_INFRA_66M_MCK, "infra_66m_mck", "sysaxi_sel", 1, 2), +}; + +static const char *const infra_uart_parent[] __initconst = { "csw_f26m_sel", + "uart_sel" }; + +static const char *const infra_spi0_parents[] __initconst = { "i2c_sel", + "spi_sel" }; + +static const char *const infra_spi1_parents[] __initconst = { "i2c_sel", + "spim_mst_sel" }; + +static const char *const infra_pwm1_parents[] __initconst = { "pwm_sel" }; + +static const char *const infra_pwm_bsel_parents[] __initconst = { + "cb_rtc_32p7k", "csw_f26m_sel", "infra_66m_mck", "pwm_sel" +}; + +static const char *const infra_pcie_parents[] __initconst = { + "cb_rtc_32p7k", "csw_f26m_sel", "cb_cksq_40m", "pextp_tl_ck_sel" +}; + +static const struct mtk_mux infra_muxes[] = { + /* MODULE_CLK_SEL_0 */ + MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART0_SEL, "infra_uart0_sel", + infra_uart_parent, 0x0018, 0x0010, 0x0014, 0, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART1_SEL, "infra_uart1_sel", + infra_uart_parent, 0x0018, 0x0010, 0x0014, 1, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_UART2_SEL, "infra_uart2_sel", + infra_uart_parent, 0x0018, 0x0010, 0x0014, 2, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI0_SEL, "infra_spi0_sel", + infra_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI1_SEL, "infra_spi1_sel", + infra_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_SPI2_SEL, "infra_spi2_sel", + infra_spi0_parents, 0x0018, 0x0010, 0x0014, 6, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM1_SEL, "infra_pwm1_sel", + infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 9, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM2_SEL, "infra_pwm2_sel", + infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 11, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM3_SEL, "infra_pwm3_sel", + infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 15, 1, + -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_BSEL, "infra_pwm_bsel", + infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13, + 2, -1, -1, -1), + /* MODULE_CLK_SEL_1 */ + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_SEL, "infra_pcie_sel", + infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2, + -1, -1, -1), +}; + +static const struct mtk_gate_regs infra0_cg_regs = { + .set_ofs = 0x40, + .clr_ofs = 0x44, + .sta_ofs = 0x48, +}; + +static const struct mtk_gate_regs infra1_cg_regs = { + .set_ofs = 0x50, + .clr_ofs = 0x54, + .sta_ofs = 0x58, +}; + +static const struct mtk_gate_regs infra2_cg_regs = { + .set_ofs = 0x60, + .clr_ofs = 0x64, + .sta_ofs = 0x68, +}; + +#define GATE_INFRA0(_id, _name, _parent, _shift) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &infra0_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_INFRA1(_id, _name, _parent, _shift) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &infra1_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_INFRA2(_id, _name, _parent, _shift) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &infra2_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate infra_clks[] = { + /* INFRA0 */ + GATE_INFRA0(CLK_INFRA_GPT_STA, "infra_gpt_sta", "infra_66m_mck", 0), + GATE_INFRA0(CLK_INFRA_PWM_HCK, "infra_pwm_hck", "infra_66m_mck", 1), + GATE_INFRA0(CLK_INFRA_PWM_STA, "infra_pwm_sta", "infra_pwm_bsel", 2), + GATE_INFRA0(CLK_INFRA_PWM1_CK, "infra_pwm1", "infra_pwm1_sel", 3), + GATE_INFRA0(CLK_INFRA_PWM2_CK, "infra_pwm2", "infra_pwm2_sel", 4), + GATE_INFRA0(CLK_INFRA_CQ_DMA_CK, "infra_cq_dma", "sysaxi", 6), + + GATE_INFRA0(CLK_INFRA_AUD_BUS_CK, "infra_aud_bus", "sysaxi", 8), + GATE_INFRA0(CLK_INFRA_AUD_26M_CK, "infra_aud_26m", "csw_f26m_sel", 9), + GATE_INFRA0(CLK_INFRA_AUD_L_CK, "infra_aud_l", "aud_l", 10), + GATE_INFRA0(CLK_INFRA_AUD_AUD_CK, "infra_aud_aud", "a1sys", 11), + GATE_INFRA0(CLK_INFRA_AUD_EG2_CK, "infra_aud_eg2", "a_tuner", 13), + GATE_INFRA0(CLK_INFRA_DRAMC_26M_CK, "infra_dramc_26m", "csw_f26m_sel", + 14), + GATE_INFRA0(CLK_INFRA_DBG_CK, "infra_dbg", "infra_66m_mck", 15), + GATE_INFRA0(CLK_INFRA_AP_DMA_CK, "infra_ap_dma", "infra_66m_mck", 16), + GATE_INFRA0(CLK_INFRA_SEJ_CK, "infra_sej", "infra_66m_mck", 24), + GATE_INFRA0(CLK_INFRA_SEJ_13M_CK, "infra_sej_13m", "csw_f26m_sel", 25), + GATE_INFRA0(CLK_INFRA_PWM3_CK, "infra_pwm3", "infra_pwm3_sel", 27), + /* INFRA1 */ + GATE_INFRA1(CLK_INFRA_THERM_CK, "infra_therm", "csw_f26m_sel", 0), + GATE_INFRA1(CLK_INFRA_I2C0_CK, "infra_i2c0", "i2c_bck", 1), + GATE_INFRA1(CLK_INFRA_UART0_CK, "infra_uart0", "infra_uart0_sel", 2), + GATE_INFRA1(CLK_INFRA_UART1_CK, "infra_uart1", "infra_uart1_sel", 3), + GATE_INFRA1(CLK_INFRA_UART2_CK, "infra_uart2", "infra_uart2_sel", 4), + GATE_INFRA1(CLK_INFRA_SPI2_CK, "infra_spi2", "infra_spi2_sel", 6), + GATE_INFRA1(CLK_INFRA_SPI2_HCK_CK, "infra_spi2_hck", "infra_66m_mck", 7), + GATE_INFRA1(CLK_INFRA_NFI1_CK, "infra_nfi1", "nfi1x", 8), + GATE_INFRA1(CLK_INFRA_SPINFI1_CK, "infra_spinfi1", "spinfi_bck", 9), + GATE_INFRA1(CLK_INFRA_NFI_HCK_CK, "infra_nfi_hck", "infra_66m_mck", 10), + GATE_INFRA1(CLK_INFRA_SPI0_CK, "infra_spi0", "infra_spi0_sel", 11), + GATE_INFRA1(CLK_INFRA_SPI1_CK, "infra_spi1", "infra_spi1_sel", 12), + GATE_INFRA1(CLK_INFRA_SPI0_HCK_CK, "infra_spi0_hck", "infra_66m_mck", + 13), + GATE_INFRA1(CLK_INFRA_SPI1_HCK_CK, "infra_spi1_hck", "infra_66m_mck", + 14), + GATE_INFRA1(CLK_INFRA_FRTC_CK, "infra_frtc", "cb_rtc_32k", 15), + GATE_INFRA1(CLK_INFRA_MSDC_CK, "infra_msdc", "emmc_400m", 16), + GATE_INFRA1(CLK_INFRA_MSDC_HCK_CK, "infra_msdc_hck", "emmc_208m", 17), + GATE_INFRA1(CLK_INFRA_MSDC_133M_CK, "infra_msdc_133m", "sysaxi", 18), + GATE_INFRA1(CLK_INFRA_MSDC_66M_CK, "infra_msdc_66m", "sysaxi", 19), + GATE_INFRA1(CLK_INFRA_ADC_26M_CK, "infra_adc_26m", "infra_adc_frc", 20), + GATE_INFRA1(CLK_INFRA_ADC_FRC_CK, "infra_adc_frc", "csw_f26m", 21), + GATE_INFRA1(CLK_INFRA_FBIST2FPC_CK, "infra_fbist2fpc", "nfi1x", 23), + GATE_INFRA1(CLK_INFRA_I2C_MCK_CK, "infra_i2c_mck", "sysaxi", 25), + GATE_INFRA1(CLK_INFRA_I2C_PCK_CK, "infra_i2c_pck", "infra_66m_mck", 26), + /* INFRA2 */ + GATE_INFRA2(CLK_INFRA_IUSB_133_CK, "infra_iusb_133", "sysaxi", 0), + GATE_INFRA2(CLK_INFRA_IUSB_66M_CK, "infra_iusb_66m", "sysaxi", 1), + GATE_INFRA2(CLK_INFRA_IUSB_SYS_CK, "infra_iusb_sys", "u2u3_sys", 2), + GATE_INFRA2(CLK_INFRA_IUSB_CK, "infra_iusb", "u2u3_ref", 3), + GATE_INFRA2(CLK_INFRA_IPCIE_CK, "infra_ipcie", "pextp_tl", 12), + GATE_INFRA2(CLK_INFRA_IPCIE_PIPE_CK, "infra_ipcie_pipe", "cb_cksq_40m", + 13), + GATE_INFRA2(CLK_INFRA_IPCIER_CK, "infra_ipcier", "csw_f26m", 14), + GATE_INFRA2(CLK_INFRA_IPCIEB_CK, "infra_ipcieb", "sysaxi", 15), +}; + +static int clk_mt7981_infracfg_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + int nr = ARRAY_SIZE(infra_divs) + ARRAY_SIZE(infra_muxes) + + ARRAY_SIZE(infra_clks); + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(nr); + + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data); + mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node, + &mt7981_clk_lock, clk_data); + mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_infracfg_data; + } + return r; + +free_infracfg_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const struct of_device_id of_match_clk_mt7981_infracfg[] = { + { .compatible = "mediatek,mt7981-infracfg", }, + {} +}; + +static struct platform_driver clk_mt7981_infracfg_drv = { + .probe = clk_mt7981_infracfg_probe, + .driver = { + .name = "clk-mt7981-infracfg", + .of_match_table = of_match_clk_mt7981_infracfg, + }, +}; +builtin_platform_driver(clk_mt7981_infracfg_drv); diff --git a/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-topckgen.c b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-topckgen.c new file mode 100644 index 00000000000..ce6dc186726 --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7981-topckgen.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Sam Shih + * Author: Wenzhen Yu + * Author: Jianhui Zhao + */ + + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" + +#include +#include + +static DEFINE_SPINLOCK(mt7981_clk_lock); + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_CB_CKSQ_40M, "cb_cksq_40m", "clkxtal", 1, 1), + FACTOR(CLK_TOP_CB_M_416M, "cb_m_416m", "mpll", 1, 1), + FACTOR(CLK_TOP_CB_M_D2, "cb_m_d2", "mpll", 1, 2), + FACTOR(CLK_TOP_CB_M_D3, "cb_m_d3", "mpll", 1, 3), + FACTOR(CLK_TOP_M_D3_D2, "m_d3_d2", "mpll", 1, 2), + FACTOR(CLK_TOP_CB_M_D4, "cb_m_d4", "mpll", 1, 4), + FACTOR(CLK_TOP_CB_M_D8, "cb_m_d8", "mpll", 1, 8), + FACTOR(CLK_TOP_M_D8_D2, "m_d8_d2", "mpll", 1, 16), + FACTOR(CLK_TOP_CB_MM_720M, "cb_mm_720m", "mmpll", 1, 1), + FACTOR(CLK_TOP_CB_MM_D2, "cb_mm_d2", "mmpll", 1, 2), + FACTOR(CLK_TOP_CB_MM_D3, "cb_mm_d3", "mmpll", 1, 3), + FACTOR(CLK_TOP_CB_MM_D3_D5, "cb_mm_d3_d5", "mmpll", 1, 15), + FACTOR(CLK_TOP_CB_MM_D4, "cb_mm_d4", "mmpll", 1, 4), + FACTOR(CLK_TOP_CB_MM_D6, "cb_mm_d6", "mmpll", 1, 6), + FACTOR(CLK_TOP_MM_D6_D2, "mm_d6_d2", "mmpll", 1, 12), + FACTOR(CLK_TOP_CB_MM_D8, "cb_mm_d8", "mmpll", 1, 8), + FACTOR(CLK_TOP_CB_APLL2_196M, "cb_apll2_196m", "apll2", 1, 1), + FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2", 1, 2), + FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4), + FACTOR(CLK_TOP_NET1_2500M, "net1_2500m", "net1pll", 1, 1), + FACTOR(CLK_TOP_CB_NET1_D4, "cb_net1_d4", "net1pll", 1, 4), + FACTOR(CLK_TOP_CB_NET1_D5, "cb_net1_d5", "net1pll", 1, 5), + FACTOR(CLK_TOP_NET1_D5_D2, "net1_d5_d2", "net1pll", 1, 10), + FACTOR(CLK_TOP_NET1_D5_D4, "net1_d5_d4", "net1pll", 1, 20), + FACTOR(CLK_TOP_CB_NET1_D8, "cb_net1_d8", "net1pll", 1, 8), + FACTOR(CLK_TOP_NET1_D8_D2, "net1_d8_d2", "net1pll", 1, 16), + FACTOR(CLK_TOP_NET1_D8_D4, "net1_d8_d4", "net1pll", 1, 32), + FACTOR(CLK_TOP_CB_NET2_800M, "cb_net2_800m", "net2pll", 1, 1), + FACTOR(CLK_TOP_CB_NET2_D2, "cb_net2_d2", "net2pll", 1, 2), + FACTOR(CLK_TOP_CB_NET2_D4, "cb_net2_d4", "net2pll", 1, 4), + FACTOR(CLK_TOP_NET2_D4_D2, "net2_d4_d2", "net2pll", 1, 8), + FACTOR(CLK_TOP_NET2_D4_D4, "net2_d4_d4", "net2pll", 1, 16), + FACTOR(CLK_TOP_CB_NET2_D6, "cb_net2_d6", "net2pll", 1, 6), + FACTOR(CLK_TOP_CB_WEDMCU_208M, "cb_wedmcu_208m", "wedmcupll", 1, 1), + FACTOR(CLK_TOP_CB_SGM_325M, "cb_sgm_325m", "sgmpll", 1, 1), + FACTOR(CLK_TOP_CKSQ_40M_D2, "cksq_40m_d2", "cb_cksq_40m", 1, 2), + FACTOR(CLK_TOP_CB_RTC_32K, "cb_rtc_32k", "cb_cksq_40m", 1, 1250), + FACTOR(CLK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", "cb_cksq_40m", 1, 1220), + FACTOR(CLK_TOP_USB_TX250M, "usb_tx250m", "cb_cksq_40m", 1, 1), + FACTOR(CLK_TOP_FAUD, "faud", "aud_sel", 1, 1), + FACTOR(CLK_TOP_NFI1X, "nfi1x", "nfi1x_sel", 1, 1), + FACTOR(CLK_TOP_USB_EQ_RX250M, "usb_eq_rx250m", "cb_cksq_40m", 1, 1), + FACTOR(CLK_TOP_USB_CDR_CK, "usb_cdr", "cb_cksq_40m", 1, 1), + FACTOR(CLK_TOP_USB_LN0_CK, "usb_ln0", "cb_cksq_40m", 1, 1), + FACTOR(CLK_TOP_SPINFI_BCK, "spinfi_bck", "spinfi_sel", 1, 1), + FACTOR(CLK_TOP_SPI, "spi", "spi_sel", 1, 1), + FACTOR(CLK_TOP_SPIM_MST, "spim_mst", "spim_mst_sel", 1, 1), + FACTOR(CLK_TOP_UART_BCK, "uart_bck", "uart_sel", 1, 1), + FACTOR(CLK_TOP_PWM_BCK, "pwm_bck", "pwm_sel", 1, 1), + FACTOR(CLK_TOP_I2C_BCK, "i2c_bck", "i2c_sel", 1, 1), + FACTOR(CLK_TOP_PEXTP_TL, "pextp_tl", "pextp_tl_ck_sel", 1, 1), + FACTOR(CLK_TOP_EMMC_208M, "emmc_208m", "emmc_208m_sel", 1, 1), + FACTOR(CLK_TOP_EMMC_400M, "emmc_400m", "emmc_400m_sel", 1, 1), + FACTOR(CLK_TOP_DRAMC_REF, "dramc_ref", "dramc_sel", 1, 1), + FACTOR(CLK_TOP_DRAMC_MD32, "dramc_md32", "dramc_md32_sel", 1, 1), + FACTOR(CLK_TOP_SYSAXI, "sysaxi", "sysaxi_sel", 1, 1), + FACTOR(CLK_TOP_SYSAPB, "sysapb", "sysapb_sel", 1, 1), + FACTOR(CLK_TOP_ARM_DB_MAIN, "arm_db_main", "arm_db_main_sel", 1, 1), + FACTOR(CLK_TOP_AP2CNN_HOST, "ap2cnn_host", "ap2cnn_host_sel", 1, 1), + FACTOR(CLK_TOP_NETSYS, "netsys", "netsys_sel", 1, 1), + FACTOR(CLK_TOP_NETSYS_500M, "netsys_500m", "netsys_500m_sel", 1, 1), + FACTOR(CLK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu", "netsys_mcu_sel", 1, 1), + FACTOR(CLK_TOP_NETSYS_2X, "netsys_2x", "netsys_2x_sel", 1, 1), + FACTOR(CLK_TOP_SGM_325M, "sgm_325m", "sgm_325m_sel", 1, 1), + FACTOR(CLK_TOP_SGM_REG, "sgm_reg", "sgm_reg_sel", 1, 1), + FACTOR(CLK_TOP_F26M, "csw_f26m", "csw_f26m_sel", 1, 1), + FACTOR(CLK_TOP_EIP97B, "eip97b", "eip97b_sel", 1, 1), + FACTOR(CLK_TOP_USB3_PHY, "usb3_phy", "usb3_phy_sel", 1, 1), + FACTOR(CLK_TOP_AUD, "aud", "faud", 1, 1), + FACTOR(CLK_TOP_A1SYS, "a1sys", "a1sys_sel", 1, 1), + FACTOR(CLK_TOP_AUD_L, "aud_l", "aud_l_sel", 1, 1), + FACTOR(CLK_TOP_A_TUNER, "a_tuner", "a_tuner_sel", 1, 1), + FACTOR(CLK_TOP_U2U3_REF, "u2u3_ref", "u2u3_sel", 1, 1), + FACTOR(CLK_TOP_U2U3_SYS, "u2u3_sys", "u2u3_sys_sel", 1, 1), + FACTOR(CLK_TOP_U2U3_XHCI, "u2u3_xhci", "u2u3_xhci_sel", 1, 1), + FACTOR(CLK_TOP_USB_FRMCNT, "usb_frmcnt", "usb_frmcnt_sel", 1, 1), +}; + +static const char * const nfi1x_parents[] __initconst = { + "cb_cksq_40m", + "cb_mm_d4", + "net1_d8_d2", + "cb_net2_d6", + "cb_m_d4", + "cb_mm_d8", + "net1_d8_d4", + "cb_m_d8" +}; + +static const char * const spinfi_parents[] __initconst = { + "cksq_40m_d2", + "cb_cksq_40m", + "net1_d5_d4", + "cb_m_d4", + "cb_mm_d8", + "net1_d8_d4", + "mm_d6_d2", + "cb_m_d8" +}; + +static const char * const spi_parents[] __initconst = { + "cb_cksq_40m", + "cb_m_d2", + "cb_mm_d4", + "net1_d8_d2", + "cb_net2_d6", + "net1_d5_d4", + "cb_m_d4", + "net1_d8_d4" +}; + +static const char * const uart_parents[] __initconst = { + "cb_cksq_40m", + "cb_m_d8", + "m_d8_d2" +}; + +static const char * const pwm_parents[] __initconst = { + "cb_cksq_40m", + "net1_d8_d2", + "net1_d5_d4", + "cb_m_d4", + "m_d8_d2", + "cb_rtc_32k" +}; + +static const char * const i2c_parents[] __initconst = { + "cb_cksq_40m", + "net1_d5_d4", + "cb_m_d4", + "net1_d8_d4" +}; + +static const char * const pextp_tl_ck_parents[] __initconst = { + "cb_cksq_40m", + "net1_d5_d4", + "cb_m_d4", + "cb_rtc_32k" +}; + +static const char * const emmc_208m_parents[] __initconst = { + "cb_cksq_40m", + "cb_m_d2", + "cb_net2_d4", + "cb_apll2_196m", + "cb_mm_d4", + "net1_d8_d2", + "cb_mm_d6" +}; + +static const char * const emmc_400m_parents[] __initconst = { + "cb_cksq_40m", + "cb_net2_d2", + "cb_mm_d2", + "cb_net2_d2" +}; + +static const char * const csw_f26m_parents[] __initconst = { + "cksq_40m_d2", + "m_d8_d2" +}; + +static const char * const dramc_md32_parents[] __initconst = { + "cb_cksq_40m", + "cb_m_d2", + "cb_wedmcu_208m" +}; + +static const char * const sysaxi_parents[] __initconst = { + "cb_cksq_40m", + "net1_d8_d2" +}; + +static const char * const sysapb_parents[] __initconst = { + "cb_cksq_40m", + "m_d3_d2" +}; + +static const char * const arm_db_main_parents[] __initconst = { + "cb_cksq_40m", + "cb_net2_d6" +}; + +static const char * const ap2cnn_host_parents[] __initconst = { + "cb_cksq_40m", + "net1_d8_d4" +}; + +static const char * const netsys_parents[] __initconst = { + "cb_cksq_40m", + "cb_mm_d2" +}; + +static const char * const netsys_500m_parents[] __initconst = { + "cb_cksq_40m", + "cb_net1_d5" +}; + +static const char * const netsys_mcu_parents[] __initconst = { + "cb_cksq_40m", + "cb_mm_720m", + "cb_net1_d4", + "cb_net1_d5", + "cb_m_416m" +}; + +static const char * const netsys_2x_parents[] __initconst = { + "cb_cksq_40m", + "cb_net2_800m", + "cb_mm_720m" +}; + +static const char * const sgm_325m_parents[] __initconst = { + "cb_cksq_40m", + "cb_sgm_325m" +}; + +static const char * const sgm_reg_parents[] __initconst = { + "cb_cksq_40m", + "cb_net2_d4" +}; + +static const char * const eip97b_parents[] __initconst = { + "cb_cksq_40m", + "cb_net1_d5", + "cb_m_416m", + "cb_mm_d2", + "net1_d5_d2" +}; + +static const char * const aud_parents[] __initconst = { + "cb_cksq_40m", + "cb_apll2_196m" +}; + +static const char * const a1sys_parents[] __initconst = { + "cb_cksq_40m", + "apll2_d4" +}; + +static const char * const aud_l_parents[] __initconst = { + "cb_cksq_40m", + "cb_apll2_196m", + "m_d8_d2" +}; + +static const char * const a_tuner_parents[] __initconst = { + "cb_cksq_40m", + "apll2_d4", + "m_d8_d2" +}; + +static const char * const u2u3_parents[] __initconst = { + "cb_cksq_40m", + "m_d8_d2" +}; + +static const char * const u2u3_sys_parents[] __initconst = { + "cb_cksq_40m", + "net1_d5_d4" +}; + +static const char * const usb_frmcnt_parents[] __initconst = { + "cb_cksq_40m", + "cb_mm_d3_d5" +}; + +static const struct mtk_mux top_muxes[] = { + /* CLK_CFG_0 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents, + 0x000, 0x004, 0x008, 0, 3, 7, 0x1C0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents, + 0x000, 0x004, 0x008, 8, 3, 15, 0x1C0, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, + 0x000, 0x004, 0x008, 16, 3, 23, 0x1C0, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents, + 0x000, 0x004, 0x008, 24, 3, 31, 0x1C0, 3), + /* CLK_CFG_1 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_parents, + 0x010, 0x014, 0x018, 0, 2, 7, 0x1C0, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, + 0x010, 0x014, 0x018, 8, 3, 15, 0x1C0, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents, + 0x010, 0x014, 0x018, 16, 2, 23, 0x1C0, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel", + pextp_tl_ck_parents, 0x010, 0x014, 0x018, 24, 2, 31, + 0x1C0, 7), + /* CLK_CFG_2 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_208M_SEL, "emmc_208m_sel", + emmc_208m_parents, 0x020, 0x024, 0x028, 0, 3, 7, + 0x1C0, 8), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_400M_SEL, "emmc_400m_sel", + emmc_400m_parents, 0x020, 0x024, 0x028, 8, 2, 15, + 0x1C0, 9), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_F26M_SEL, "csw_f26m_sel", + csw_f26m_parents, 0x020, 0x024, 0x028, 16, 1, 23, + 0x1C0, 10, + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel", + csw_f26m_parents, 0x020, 0x024, 0x028, 24, 1, + 31, 0x1C0, 11, + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), + /* CLK_CFG_3 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel", + dramc_md32_parents, 0x030, 0x034, 0x038, 0, 2, + 7, 0x1C0, 12, + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel", + sysaxi_parents, 0x030, 0x034, 0x038, 8, 1, 15, + 0x1C0, 13, + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel", + sysapb_parents, 0x030, 0x034, 0x038, 16, 1, + 23, 0x1C0, 14, + CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel", + arm_db_main_parents, 0x030, 0x034, 0x038, 24, 1, 31, + 0x1C0, 15), + /* CLK_CFG_4 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_AP2CNN_HOST_SEL, "ap2cnn_host_sel", + ap2cnn_host_parents, 0x040, 0x044, 0x048, 0, 1, 7, + 0x1C0, 16), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents, + 0x040, 0x044, 0x048, 8, 1, 15, 0x1C0, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_500M_SEL, "netsys_500m_sel", + netsys_500m_parents, 0x040, 0x044, 0x048, 16, 1, 23, + 0x1C0, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel", + netsys_mcu_parents, 0x040, 0x044, 0x048, 24, 3, 31, + 0x1C0, 19), + /* CLK_CFG_5 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_2X_SEL, "netsys_2x_sel", + netsys_2x_parents, 0x050, 0x054, 0x058, 0, 2, 7, + 0x1C0, 20), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_325M_SEL, "sgm_325m_sel", + sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15, + 0x1C0, 21), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents, + 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP97B_SEL, "eip97b_sel", eip97b_parents, + 0x050, 0x054, 0x058, 24, 3, 31, 0x1C0, 23), + /* CLK_CFG_6 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB3_PHY_SEL, "usb3_phy_sel", + csw_f26m_parents, 0x060, 0x064, 0x068, 0, 1, + 7, 0x1C0, 24), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x060, + 0x064, 0x068, 8, 1, 15, 0x1C0, 25), + MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents, + 0x060, 0x064, 0x068, 16, 1, 23, 0x1C0, 26), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents, + 0x060, 0x064, 0x068, 24, 2, 31, 0x1C0, 27), + /* CLK_CFG_7 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel", + a_tuner_parents, 0x070, 0x074, 0x078, 0, 2, 7, + 0x1C0, 28), + MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_SEL, "u2u3_sel", u2u3_parents, 0x070, + 0x074, 0x078, 8, 1, 15, 0x1C0, 29), + MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_SYS_SEL, "u2u3_sys_sel", + u2u3_sys_parents, 0x070, 0x074, 0x078, 16, 1, 23, + 0x1C0, 30), + MUX_GATE_CLR_SET_UPD(CLK_TOP_U2U3_XHCI_SEL, "u2u3_xhci_sel", + u2u3_sys_parents, 0x070, 0x074, 0x078, 24, 1, 31, + 0x1C4, 0), + /* CLK_CFG_8 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel", + usb_frmcnt_parents, 0x080, 0x084, 0x088, 0, 1, 7, + 0x1C4, 1), +}; + +static struct mtk_composite top_aud_divs[] = { + DIV_GATE(CLK_TOP_AUD_I2S_M, "aud_i2s_m", "aud", + 0x0420, 0, 0x0420, 8, 8), +}; + +static int clk_mt7981_topckgen_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + int nr = ARRAY_SIZE(top_divs) + ARRAY_SIZE(top_muxes) + + ARRAY_SIZE(top_aud_divs); + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(nr); + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); + mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node, + &mt7981_clk_lock, clk_data); + mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs), base, + &mt7981_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_topckgen_data; + } + return r; + +free_topckgen_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const struct of_device_id of_match_clk_mt7981_topckgen[] = { + { .compatible = "mediatek,mt7981-topckgen", }, + {} +}; + +static struct platform_driver clk_mt7981_topckgen_drv = { + .probe = clk_mt7981_topckgen_probe, + .driver = { + .name = "clk-mt7981-topckgen", + .of_match_table = of_match_clk_mt7981_topckgen, + }, +}; +builtin_platform_driver(clk_mt7981_topckgen_drv); diff --git a/target/linux/mediatek/files-5.15/include/dt-bindings/clock/mediatek,mt7981-clk.h b/target/linux/mediatek/files-5.15/include/dt-bindings/clock/mediatek,mt7981-clk.h new file mode 100644 index 00000000000..192f8cefb58 --- /dev/null +++ b/target/linux/mediatek/files-5.15/include/dt-bindings/clock/mediatek,mt7981-clk.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Wenzhen.Yu + * Author: Jianhui Zhao + * Author: Daniel Golle + */ + +#ifndef _DT_BINDINGS_CLK_MT7981_H +#define _DT_BINDINGS_CLK_MT7981_H + +/* TOPCKGEN */ +#define CLK_TOP_CB_CKSQ_40M 0 +#define CLK_TOP_CB_M_416M 1 +#define CLK_TOP_CB_M_D2 2 +#define CLK_TOP_CB_M_D3 3 +#define CLK_TOP_M_D3_D2 4 +#define CLK_TOP_CB_M_D4 5 +#define CLK_TOP_CB_M_D8 6 +#define CLK_TOP_M_D8_D2 7 +#define CLK_TOP_CB_MM_720M 8 +#define CLK_TOP_CB_MM_D2 9 +#define CLK_TOP_CB_MM_D3 10 +#define CLK_TOP_CB_MM_D3_D5 11 +#define CLK_TOP_CB_MM_D4 12 +#define CLK_TOP_CB_MM_D6 13 +#define CLK_TOP_MM_D6_D2 14 +#define CLK_TOP_CB_MM_D8 15 +#define CLK_TOP_CB_APLL2_196M 16 +#define CLK_TOP_APLL2_D2 17 +#define CLK_TOP_APLL2_D4 18 +#define CLK_TOP_NET1_2500M 19 +#define CLK_TOP_CB_NET1_D4 20 +#define CLK_TOP_CB_NET1_D5 21 +#define CLK_TOP_NET1_D5_D2 22 +#define CLK_TOP_NET1_D5_D4 23 +#define CLK_TOP_CB_NET1_D8 24 +#define CLK_TOP_NET1_D8_D2 25 +#define CLK_TOP_NET1_D8_D4 26 +#define CLK_TOP_CB_NET2_800M 27 +#define CLK_TOP_CB_NET2_D2 28 +#define CLK_TOP_CB_NET2_D4 29 +#define CLK_TOP_NET2_D4_D2 30 +#define CLK_TOP_NET2_D4_D4 31 +#define CLK_TOP_CB_NET2_D6 32 +#define CLK_TOP_CB_WEDMCU_208M 33 +#define CLK_TOP_CB_SGM_325M 34 +#define CLK_TOP_CKSQ_40M_D2 35 +#define CLK_TOP_CB_RTC_32K 36 +#define CLK_TOP_CB_RTC_32P7K 37 +#define CLK_TOP_USB_TX250M 38 +#define CLK_TOP_FAUD 39 +#define CLK_TOP_NFI1X 40 +#define CLK_TOP_USB_EQ_RX250M 41 +#define CLK_TOP_USB_CDR_CK 42 +#define CLK_TOP_USB_LN0_CK 43 +#define CLK_TOP_SPINFI_BCK 44 +#define CLK_TOP_SPI 45 +#define CLK_TOP_SPIM_MST 46 +#define CLK_TOP_UART_BCK 47 +#define CLK_TOP_PWM_BCK 48 +#define CLK_TOP_I2C_BCK 49 +#define CLK_TOP_PEXTP_TL 50 +#define CLK_TOP_EMMC_208M 51 +#define CLK_TOP_EMMC_400M 52 +#define CLK_TOP_DRAMC_REF 53 +#define CLK_TOP_DRAMC_MD32 54 +#define CLK_TOP_SYSAXI 55 +#define CLK_TOP_SYSAPB 56 +#define CLK_TOP_ARM_DB_MAIN 57 +#define CLK_TOP_AP2CNN_HOST 58 +#define CLK_TOP_NETSYS 59 +#define CLK_TOP_NETSYS_500M 60 +#define CLK_TOP_NETSYS_WED_MCU 61 +#define CLK_TOP_NETSYS_2X 62 +#define CLK_TOP_SGM_325M 63 +#define CLK_TOP_SGM_REG 64 +#define CLK_TOP_F26M 65 +#define CLK_TOP_EIP97B 66 +#define CLK_TOP_USB3_PHY 67 +#define CLK_TOP_AUD 68 +#define CLK_TOP_A1SYS 69 +#define CLK_TOP_AUD_L 70 +#define CLK_TOP_A_TUNER 71 +#define CLK_TOP_U2U3_REF 72 +#define CLK_TOP_U2U3_SYS 73 +#define CLK_TOP_U2U3_XHCI 74 +#define CLK_TOP_USB_FRMCNT 75 +#define CLK_TOP_NFI1X_SEL 76 +#define CLK_TOP_SPINFI_SEL 77 +#define CLK_TOP_SPI_SEL 78 +#define CLK_TOP_SPIM_MST_SEL 79 +#define CLK_TOP_UART_SEL 80 +#define CLK_TOP_PWM_SEL 81 +#define CLK_TOP_I2C_SEL 82 +#define CLK_TOP_PEXTP_TL_SEL 83 +#define CLK_TOP_EMMC_208M_SEL 84 +#define CLK_TOP_EMMC_400M_SEL 85 +#define CLK_TOP_F26M_SEL 86 +#define CLK_TOP_DRAMC_SEL 87 +#define CLK_TOP_DRAMC_MD32_SEL 88 +#define CLK_TOP_SYSAXI_SEL 89 +#define CLK_TOP_SYSAPB_SEL 90 +#define CLK_TOP_ARM_DB_MAIN_SEL 91 +#define CLK_TOP_AP2CNN_HOST_SEL 92 +#define CLK_TOP_NETSYS_SEL 93 +#define CLK_TOP_NETSYS_500M_SEL 94 +#define CLK_TOP_NETSYS_MCU_SEL 95 +#define CLK_TOP_NETSYS_2X_SEL 96 +#define CLK_TOP_SGM_325M_SEL 97 +#define CLK_TOP_SGM_REG_SEL 98 +#define CLK_TOP_EIP97B_SEL 99 +#define CLK_TOP_USB3_PHY_SEL 100 +#define CLK_TOP_AUD_SEL 101 +#define CLK_TOP_A1SYS_SEL 102 +#define CLK_TOP_AUD_L_SEL 103 +#define CLK_TOP_A_TUNER_SEL 104 +#define CLK_TOP_U2U3_SEL 105 +#define CLK_TOP_U2U3_SYS_SEL 106 +#define CLK_TOP_U2U3_XHCI_SEL 107 +#define CLK_TOP_USB_FRMCNT_SEL 108 +#define CLK_TOP_AUD_I2S_M 109 + +/* INFRACFG */ +#define CLK_INFRA_66M_MCK 0 +#define CLK_INFRA_UART0_SEL 1 +#define CLK_INFRA_UART1_SEL 2 +#define CLK_INFRA_UART2_SEL 3 +#define CLK_INFRA_SPI0_SEL 4 +#define CLK_INFRA_SPI1_SEL 5 +#define CLK_INFRA_SPI2_SEL 6 +#define CLK_INFRA_PWM1_SEL 7 +#define CLK_INFRA_PWM2_SEL 8 +#define CLK_INFRA_PWM3_SEL 9 +#define CLK_INFRA_PWM_BSEL 10 +#define CLK_INFRA_PCIE_SEL 11 +#define CLK_INFRA_GPT_STA 12 +#define CLK_INFRA_PWM_HCK 13 +#define CLK_INFRA_PWM_STA 14 +#define CLK_INFRA_PWM1_CK 15 +#define CLK_INFRA_PWM2_CK 16 +#define CLK_INFRA_PWM3_CK 17 +#define CLK_INFRA_CQ_DMA_CK 18 +#define CLK_INFRA_AUD_BUS_CK 19 +#define CLK_INFRA_AUD_26M_CK 20 +#define CLK_INFRA_AUD_L_CK 21 +#define CLK_INFRA_AUD_AUD_CK 22 +#define CLK_INFRA_AUD_EG2_CK 23 +#define CLK_INFRA_DRAMC_26M_CK 24 +#define CLK_INFRA_DBG_CK 25 +#define CLK_INFRA_AP_DMA_CK 26 +#define CLK_INFRA_SEJ_CK 27 +#define CLK_INFRA_SEJ_13M_CK 28 +#define CLK_INFRA_THERM_CK 29 +#define CLK_INFRA_I2C0_CK 30 +#define CLK_INFRA_UART0_CK 31 +#define CLK_INFRA_UART1_CK 32 +#define CLK_INFRA_UART2_CK 33 +#define CLK_INFRA_SPI2_CK 34 +#define CLK_INFRA_SPI2_HCK_CK 35 +#define CLK_INFRA_NFI1_CK 36 +#define CLK_INFRA_SPINFI1_CK 37 +#define CLK_INFRA_NFI_HCK_CK 38 +#define CLK_INFRA_SPI0_CK 39 +#define CLK_INFRA_SPI1_CK 40 +#define CLK_INFRA_SPI0_HCK_CK 41 +#define CLK_INFRA_SPI1_HCK_CK 42 +#define CLK_INFRA_FRTC_CK 43 +#define CLK_INFRA_MSDC_CK 44 +#define CLK_INFRA_MSDC_HCK_CK 45 +#define CLK_INFRA_MSDC_133M_CK 46 +#define CLK_INFRA_MSDC_66M_CK 47 +#define CLK_INFRA_ADC_26M_CK 48 +#define CLK_INFRA_ADC_FRC_CK 49 +#define CLK_INFRA_FBIST2FPC_CK 50 +#define CLK_INFRA_I2C_MCK_CK 51 +#define CLK_INFRA_I2C_PCK_CK 52 +#define CLK_INFRA_IUSB_133_CK 53 +#define CLK_INFRA_IUSB_66M_CK 54 +#define CLK_INFRA_IUSB_SYS_CK 55 +#define CLK_INFRA_IUSB_CK 56 +#define CLK_INFRA_IPCIE_CK 57 +#define CLK_INFRA_IPCIE_PIPE_CK 58 +#define CLK_INFRA_IPCIER_CK 59 +#define CLK_INFRA_IPCIEB_CK 60 + +/* APMIXEDSYS */ +#define CLK_APMIXED_ARMPLL 0 +#define CLK_APMIXED_NET2PLL 1 +#define CLK_APMIXED_MMPLL 2 +#define CLK_APMIXED_SGMPLL 3 +#define CLK_APMIXED_WEDMCUPLL 4 +#define CLK_APMIXED_NET1PLL 5 +#define CLK_APMIXED_MPLL 6 +#define CLK_APMIXED_APLL2 7 + +/* SGMIISYS_0 */ +#define CLK_SGM0_TX_EN 0 +#define CLK_SGM0_RX_EN 1 +#define CLK_SGM0_CK0_EN 2 +#define CLK_SGM0_CDR_CK0_EN 3 + +/* SGMIISYS_1 */ +#define CLK_SGM1_TX_EN 0 +#define CLK_SGM1_RX_EN 1 +#define CLK_SGM1_CK1_EN 2 +#define CLK_SGM1_CDR_CK1_EN 3 + +/* ETHSYS */ +#define CLK_ETH_FE_EN 0 +#define CLK_ETH_GP2_EN 1 +#define CLK_ETH_GP1_EN 2 +#define CLK_ETH_WOCPU0_EN 3 + +#endif /* _DT_BINDINGS_CLK_MT7981_H */ diff --git a/target/linux/mediatek/filogic/config-5.15 b/target/linux/mediatek/filogic/config-5.15 index a1c2e64acd4..6883a5b54b0 100644 --- a/target/linux/mediatek/filogic/config-5.15 +++ b/target/linux/mediatek/filogic/config-5.15 @@ -57,6 +57,8 @@ CONFIG_COMMON_CLK_MEDIATEK=y # CONFIG_COMMON_CLK_MT6779 is not set # CONFIG_COMMON_CLK_MT6797 is not set # CONFIG_COMMON_CLK_MT7622 is not set +CONFIG_COMMON_CLK_MT7981=y +CONFIG_COMMON_CLK_MT7981_ETHSYS=y CONFIG_COMMON_CLK_MT7986=y CONFIG_COMMON_CLK_MT7986_ETHSYS=y # CONFIG_COMMON_CLK_MT8173 is not set diff --git a/target/linux/mediatek/mt7622/config-5.15 b/target/linux/mediatek/mt7622/config-5.15 index 3f99221c212..3168c2deda1 100644 --- a/target/linux/mediatek/mt7622/config-5.15 +++ b/target/linux/mediatek/mt7622/config-5.15 @@ -71,6 +71,7 @@ CONFIG_COMMON_CLK_MT7622=y CONFIG_COMMON_CLK_MT7622_AUDSYS=y CONFIG_COMMON_CLK_MT7622_ETHSYS=y CONFIG_COMMON_CLK_MT7622_HIFSYS=y +# CONFIG_COMMON_CLK_MT7981 is not set # CONFIG_COMMON_CLK_MT7986 is not set # CONFIG_COMMON_CLK_MT8173 is not set # CONFIG_COMMON_CLK_MT8183 is not set diff --git a/target/linux/mediatek/mt7623/config-5.15 b/target/linux/mediatek/mt7623/config-5.15 index 984e85aba0b..26d037ff003 100644 --- a/target/linux/mediatek/mt7623/config-5.15 +++ b/target/linux/mediatek/mt7623/config-5.15 @@ -68,6 +68,7 @@ CONFIG_COMMON_CLK_MT2701_MMSYS=y CONFIG_COMMON_CLK_MT2701_VDECSYS=y # CONFIG_COMMON_CLK_MT7622 is not set # CONFIG_COMMON_CLK_MT7629 is not set +# CONFIG_COMMON_CLK_MT7981 is not set # CONFIG_COMMON_CLK_MT7986 is not set # CONFIG_COMMON_CLK_MT8135 is not set # CONFIG_COMMON_CLK_MT8173 is not set diff --git a/target/linux/mediatek/mt7629/config-5.15 b/target/linux/mediatek/mt7629/config-5.15 index fc53bec882e..32f75d6528b 100644 --- a/target/linux/mediatek/mt7629/config-5.15 +++ b/target/linux/mediatek/mt7629/config-5.15 @@ -52,6 +52,7 @@ CONFIG_COMMON_CLK_MEDIATEK=y CONFIG_COMMON_CLK_MT7629=y CONFIG_COMMON_CLK_MT7629_ETHSYS=y CONFIG_COMMON_CLK_MT7629_HIFSYS=y +# CONFIG_COMMON_CLK_MT7981 is not set # CONFIG_COMMON_CLK_MT7986 is not set # CONFIG_COMMON_CLK_MT8135 is not set # CONFIG_COMMON_CLK_MT8173 is not set diff --git a/target/linux/mediatek/patches-5.15/214-v6.3-clk-mediatek-add-mt7981-clock-support.patch b/target/linux/mediatek/patches-5.15/214-v6.3-clk-mediatek-add-mt7981-clock-support.patch new file mode 100644 index 00000000000..631eb04092d --- /dev/null +++ b/target/linux/mediatek/patches-5.15/214-v6.3-clk-mediatek-add-mt7981-clock-support.patch @@ -0,0 +1,39 @@ +--- a/drivers/clk/mediatek/Kconfig ++++ b/drivers/clk/mediatek/Kconfig +@@ -344,6 +344,23 @@ config COMMON_CLK_MT7629_HIFSYS + This driver supports MediaTek MT7629 HIFSYS clocks providing + to PCI-E and USB. + ++config COMMON_CLK_MT7981 ++ bool "Clock driver for MediaTek MT7981" ++ depends on ARCH_MEDIATEK || COMPILE_TEST ++ select COMMON_CLK_MEDIATEK ++ default ARCH_MEDIATEK ++ help ++ This driver supports MediaTek MT7981 basic clocks and clocks ++ required for various periperals found on MediaTek. ++ ++config COMMON_CLK_MT7981_ETHSYS ++ bool "Clock driver for MediaTek MT7981 ETHSYS" ++ depends on COMMON_CLK_MT7981 ++ default COMMON_CLK_MT7981 ++ help ++ This driver add support for clocks for Ethernet and SGMII ++ required on MediaTek MT7981 SoC. ++ + config COMMON_CLK_MT7986 + bool "Clock driver for MediaTek MT7986" + depends on ARCH_MEDIATEK || COMPILE_TEST +--- a/drivers/clk/mediatek/Makefile ++++ b/drivers/clk/mediatek/Makefile +@@ -46,6 +46,10 @@ obj-$(CONFIG_COMMON_CLK_MT7622_AUDSYS) + + obj-$(CONFIG_COMMON_CLK_MT7629) += clk-mt7629.o + obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o + obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o ++obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-apmixed.o ++obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-topckgen.o ++obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981-infracfg.o ++obj-$(CONFIG_COMMON_CLK_MT7981_ETHSYS) += clk-mt7981-eth.o + obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-apmixed.o + obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-topckgen.o + obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-infracfg.o From 18a9ae56e98a2b81832f3c68d634bd935a797c5a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 10 Mar 2023 19:40:37 +0000 Subject: [PATCH 38/53] mediatek: backport pinctrl driver for MT7981 SoC Backport the pinctrl driver for the MT7981 SoC. The driver has also been submitted upstream and is part of Linux 6.3. Signed-off-by: Daniel Golle --- .../drivers/pinctrl/mediatek/pinctrl-mt7981.c | 993 ++++++++++++++++++ target/linux/mediatek/filogic/config-5.15 | 1 + target/linux/mediatek/mt7622/config-5.15 | 1 + ...-mediatek-add-support-for-MT7981-SoC.patch | 26 + 4 files changed, 1021 insertions(+) create mode 100644 target/linux/mediatek/files-5.15/drivers/pinctrl/mediatek/pinctrl-mt7981.c create mode 100644 target/linux/mediatek/patches-5.15/215-v6.3-pinctrl-mediatek-add-support-for-MT7981-SoC.patch diff --git a/target/linux/mediatek/files-5.15/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/target/linux/mediatek/files-5.15/drivers/pinctrl/mediatek/pinctrl-mt7981.c new file mode 100644 index 00000000000..35125f93a44 --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/pinctrl/mediatek/pinctrl-mt7981.c @@ -0,0 +1,993 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The MT7981 driver based on Linux generic pinctrl binding. + * + * Copyright (C) 2020 MediaTek Inc. + * Author: Sam Shih + */ + +#include "pinctrl-moore.h" + +#define MT7981_PIN(_number, _name) \ + MTK_PIN(_number, _name, 0, _number, DRV_GRP4) + +#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 0) + +#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 1) + +static const struct mtk_pin_field_calc mt7981_pin_mode_range[] = { + PIN_FIELD(0, 56, 0x300, 0x10, 0, 4), +}; + +static const struct mtk_pin_field_calc mt7981_pin_dir_range[] = { + PIN_FIELD(0, 56, 0x0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_di_range[] = { + PIN_FIELD(0, 56, 0x200, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_do_range[] = { + PIN_FIELD(0, 56, 0x100, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_ies_range[] = { + PIN_FIELD_BASE(0, 0, 1, 0x10, 0x10, 1, 1), + PIN_FIELD_BASE(1, 1, 1, 0x10, 0x10, 0, 1), + PIN_FIELD_BASE(2, 2, 5, 0x20, 0x10, 6, 1), + PIN_FIELD_BASE(3, 3, 4, 0x20, 0x10, 6, 1), + PIN_FIELD_BASE(4, 4, 4, 0x20, 0x10, 2, 1), + PIN_FIELD_BASE(5, 5, 4, 0x20, 0x10, 1, 1), + PIN_FIELD_BASE(6, 6, 4, 0x20, 0x10, 3, 1), + PIN_FIELD_BASE(7, 7, 4, 0x20, 0x10, 0, 1), + PIN_FIELD_BASE(8, 8, 4, 0x20, 0x10, 4, 1), + + PIN_FIELD_BASE(9, 9, 5, 0x20, 0x10, 9, 1), + PIN_FIELD_BASE(10, 10, 5, 0x20, 0x10, 8, 1), + PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1), + PIN_FIELD_BASE(12, 12, 5, 0x20, 0x10, 7, 1), + PIN_FIELD_BASE(13, 13, 5, 0x20, 0x10, 11, 1), + + PIN_FIELD_BASE(14, 14, 4, 0x20, 0x10, 8, 1), + + PIN_FIELD_BASE(15, 15, 2, 0x20, 0x10, 0, 1), + PIN_FIELD_BASE(16, 16, 2, 0x20, 0x10, 1, 1), + PIN_FIELD_BASE(17, 17, 2, 0x20, 0x10, 5, 1), + PIN_FIELD_BASE(18, 18, 2, 0x20, 0x10, 4, 1), + PIN_FIELD_BASE(19, 19, 2, 0x20, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 2, 0x20, 0x10, 3, 1), + PIN_FIELD_BASE(21, 21, 2, 0x20, 0x10, 6, 1), + PIN_FIELD_BASE(22, 22, 2, 0x20, 0x10, 7, 1), + PIN_FIELD_BASE(23, 23, 2, 0x20, 0x10, 10, 1), + PIN_FIELD_BASE(24, 24, 2, 0x20, 0x10, 9, 1), + PIN_FIELD_BASE(25, 25, 2, 0x20, 0x10, 8, 1), + + PIN_FIELD_BASE(26, 26, 5, 0x20, 0x10, 0, 1), + PIN_FIELD_BASE(27, 27, 5, 0x20, 0x10, 4, 1), + PIN_FIELD_BASE(28, 28, 5, 0x20, 0x10, 3, 1), + PIN_FIELD_BASE(29, 29, 5, 0x20, 0x10, 1, 1), + PIN_FIELD_BASE(30, 30, 5, 0x20, 0x10, 2, 1), + PIN_FIELD_BASE(31, 31, 5, 0x20, 0x10, 5, 1), + + PIN_FIELD_BASE(32, 32, 1, 0x10, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 1, 0x10, 0x10, 3, 1), + + PIN_FIELD_BASE(34, 34, 4, 0x20, 0x10, 5, 1), + PIN_FIELD_BASE(35, 35, 4, 0x20, 0x10, 7, 1), + + PIN_FIELD_BASE(36, 36, 3, 0x10, 0x10, 2, 1), + PIN_FIELD_BASE(37, 37, 3, 0x10, 0x10, 3, 1), + PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 0, 1), + PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 1, 1), + + PIN_FIELD_BASE(40, 40, 7, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(41, 41, 7, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 7, 0x30, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 7, 0x30, 0x10, 7, 1), + PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1), + PIN_FIELD_BASE(45, 45, 7, 0x30, 0x10, 3, 1), + PIN_FIELD_BASE(46, 46, 7, 0x30, 0x10, 4, 1), + PIN_FIELD_BASE(47, 47, 7, 0x30, 0x10, 5, 1), + PIN_FIELD_BASE(48, 48, 7, 0x30, 0x10, 6, 1), + PIN_FIELD_BASE(49, 49, 7, 0x30, 0x10, 2, 1), + + PIN_FIELD_BASE(50, 50, 6, 0x10, 0x10, 0, 1), + PIN_FIELD_BASE(51, 51, 6, 0x10, 0x10, 2, 1), + PIN_FIELD_BASE(52, 52, 6, 0x10, 0x10, 3, 1), + PIN_FIELD_BASE(53, 53, 6, 0x10, 0x10, 4, 1), + PIN_FIELD_BASE(54, 54, 6, 0x10, 0x10, 5, 1), + PIN_FIELD_BASE(55, 55, 6, 0x10, 0x10, 6, 1), + PIN_FIELD_BASE(56, 56, 6, 0x10, 0x10, 1, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_smt_range[] = { + PIN_FIELD_BASE(0, 0, 1, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(1, 1, 1, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(2, 2, 5, 0x90, 0x10, 6, 1), + PIN_FIELD_BASE(3, 3, 4, 0x80, 0x10, 6, 1), + PIN_FIELD_BASE(4, 4, 4, 0x80, 0x10, 2, 1), + PIN_FIELD_BASE(5, 5, 4, 0x80, 0x10, 1, 1), + PIN_FIELD_BASE(6, 6, 4, 0x80, 0x10, 3, 1), + PIN_FIELD_BASE(7, 7, 4, 0x80, 0x10, 0, 1), + PIN_FIELD_BASE(8, 8, 4, 0x80, 0x10, 4, 1), + + PIN_FIELD_BASE(9, 9, 5, 0x90, 0x10, 9, 1), + PIN_FIELD_BASE(10, 10, 5, 0x90, 0x10, 8, 1), + PIN_FIELD_BASE(11, 11, 5, 0x90, 0x10, 10, 1), + PIN_FIELD_BASE(12, 12, 5, 0x90, 0x10, 7, 1), + PIN_FIELD_BASE(13, 13, 5, 0x90, 0x10, 11, 1), + + PIN_FIELD_BASE(14, 14, 4, 0x80, 0x10, 8, 1), + + PIN_FIELD_BASE(15, 15, 2, 0x90, 0x10, 0, 1), + PIN_FIELD_BASE(16, 16, 2, 0x90, 0x10, 1, 1), + PIN_FIELD_BASE(17, 17, 2, 0x90, 0x10, 5, 1), + PIN_FIELD_BASE(18, 18, 2, 0x90, 0x10, 4, 1), + PIN_FIELD_BASE(19, 19, 2, 0x90, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1), + PIN_FIELD_BASE(21, 21, 2, 0x90, 0x10, 6, 1), + PIN_FIELD_BASE(22, 22, 2, 0x90, 0x10, 7, 1), + PIN_FIELD_BASE(23, 23, 2, 0x90, 0x10, 10, 1), + PIN_FIELD_BASE(24, 24, 2, 0x90, 0x10, 9, 1), + PIN_FIELD_BASE(25, 25, 2, 0x90, 0x10, 8, 1), + + PIN_FIELD_BASE(26, 26, 5, 0x90, 0x10, 0, 1), + PIN_FIELD_BASE(27, 27, 5, 0x90, 0x10, 4, 1), + PIN_FIELD_BASE(28, 28, 5, 0x90, 0x10, 3, 1), + PIN_FIELD_BASE(29, 29, 5, 0x90, 0x10, 1, 1), + PIN_FIELD_BASE(30, 30, 5, 0x90, 0x10, 2, 1), + PIN_FIELD_BASE(31, 31, 5, 0x90, 0x10, 5, 1), + + PIN_FIELD_BASE(32, 32, 1, 0x60, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 1, 0x60, 0x10, 3, 1), + + PIN_FIELD_BASE(34, 34, 4, 0x80, 0x10, 5, 1), + PIN_FIELD_BASE(35, 35, 4, 0x80, 0x10, 7, 1), + + PIN_FIELD_BASE(36, 36, 3, 0x60, 0x10, 2, 1), + PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 3, 1), + PIN_FIELD_BASE(38, 38, 3, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(39, 39, 3, 0x60, 0x10, 1, 1), + + PIN_FIELD_BASE(40, 40, 7, 0x70, 0x10, 1, 1), + PIN_FIELD_BASE(41, 41, 7, 0x70, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 7, 0x70, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 7, 0x70, 0x10, 7, 1), + PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1), + PIN_FIELD_BASE(45, 45, 7, 0x70, 0x10, 3, 1), + PIN_FIELD_BASE(46, 46, 7, 0x70, 0x10, 4, 1), + PIN_FIELD_BASE(47, 47, 7, 0x70, 0x10, 5, 1), + PIN_FIELD_BASE(48, 48, 7, 0x70, 0x10, 6, 1), + PIN_FIELD_BASE(49, 49, 7, 0x70, 0x10, 2, 1), + + PIN_FIELD_BASE(50, 50, 6, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(51, 51, 6, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(52, 52, 6, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(53, 53, 6, 0x50, 0x10, 4, 1), + PIN_FIELD_BASE(54, 54, 6, 0x50, 0x10, 5, 1), + PIN_FIELD_BASE(55, 55, 6, 0x50, 0x10, 6, 1), + PIN_FIELD_BASE(56, 56, 6, 0x50, 0x10, 1, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_pu_range[] = { + PIN_FIELD_BASE(40, 40, 7, 0x50, 0x10, 1, 1), + PIN_FIELD_BASE(41, 41, 7, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 7, 0x50, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 7, 0x50, 0x10, 7, 1), + PIN_FIELD_BASE(44, 44, 7, 0x50, 0x10, 8, 1), + PIN_FIELD_BASE(45, 45, 7, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(46, 46, 7, 0x50, 0x10, 4, 1), + PIN_FIELD_BASE(47, 47, 7, 0x50, 0x10, 5, 1), + PIN_FIELD_BASE(48, 48, 7, 0x50, 0x10, 6, 1), + PIN_FIELD_BASE(49, 49, 7, 0x50, 0x10, 2, 1), + + PIN_FIELD_BASE(50, 50, 6, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(51, 51, 6, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(52, 52, 6, 0x30, 0x10, 3, 1), + PIN_FIELD_BASE(53, 53, 6, 0x30, 0x10, 4, 1), + PIN_FIELD_BASE(54, 54, 6, 0x30, 0x10, 5, 1), + PIN_FIELD_BASE(55, 55, 6, 0x30, 0x10, 6, 1), + PIN_FIELD_BASE(56, 56, 6, 0x30, 0x10, 1, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_pd_range[] = { + PIN_FIELD_BASE(40, 40, 7, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(41, 41, 7, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 7, 0x40, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 7, 0x40, 0x10, 7, 1), + PIN_FIELD_BASE(44, 44, 7, 0x40, 0x10, 8, 1), + PIN_FIELD_BASE(45, 45, 7, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(46, 46, 7, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(47, 47, 7, 0x40, 0x10, 5, 1), + PIN_FIELD_BASE(48, 48, 7, 0x40, 0x10, 6, 1), + PIN_FIELD_BASE(49, 49, 7, 0x40, 0x10, 2, 1), + + PIN_FIELD_BASE(50, 50, 6, 0x20, 0x10, 0, 1), + PIN_FIELD_BASE(51, 51, 6, 0x20, 0x10, 2, 1), + PIN_FIELD_BASE(52, 52, 6, 0x20, 0x10, 3, 1), + PIN_FIELD_BASE(53, 53, 6, 0x20, 0x10, 4, 1), + PIN_FIELD_BASE(54, 54, 6, 0x20, 0x10, 5, 1), + PIN_FIELD_BASE(55, 55, 6, 0x20, 0x10, 6, 1), + PIN_FIELD_BASE(56, 56, 6, 0x20, 0x10, 1, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = { + PIN_FIELD_BASE(0, 0, 1, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(1, 1, 1, 0x00, 0x10, 0, 3), + + PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 18, 3), + + PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 1), + PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 1), + PIN_FIELD_BASE(5, 5, 4, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(6, 6, 4, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 12, 3), + + PIN_FIELD_BASE(9, 9, 5, 0x00, 0x10, 27, 3), + PIN_FIELD_BASE(10, 10, 5, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(11, 11, 5, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(12, 12, 5, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(13, 13, 5, 0x00, 0x10, 3, 3), + + PIN_FIELD_BASE(14, 14, 4, 0x00, 0x10, 27, 3), + + PIN_FIELD_BASE(15, 15, 2, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(16, 16, 2, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(17, 17, 2, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(18, 18, 2, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(19, 19, 2, 0x00, 0x10, 6, 3), + PIN_FIELD_BASE(20, 20, 2, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(21, 21, 2, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(22, 22, 2, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(23, 23, 2, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(24, 24, 2, 0x00, 0x10, 27, 3), + PIN_FIELD_BASE(25, 25, 2, 0x00, 0x10, 24, 3), + + PIN_FIELD_BASE(26, 26, 5, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(27, 27, 5, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(28, 28, 5, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(29, 29, 5, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(30, 30, 5, 0x00, 0x10, 6, 3), + PIN_FIELD_BASE(31, 31, 5, 0x00, 0x10, 15, 3), + + PIN_FIELD_BASE(32, 32, 1, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(33, 33, 1, 0x00, 0x10, 12, 3), + + PIN_FIELD_BASE(34, 34, 4, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(35, 35, 4, 0x00, 0x10, 21, 3), + + PIN_FIELD_BASE(36, 36, 3, 0x00, 0x10, 6, 3), + PIN_FIELD_BASE(37, 37, 3, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(38, 38, 3, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(39, 39, 3, 0x00, 0x10, 3, 3), + + PIN_FIELD_BASE(40, 40, 7, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(41, 41, 7, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(42, 42, 7, 0x00, 0x10, 27, 3), + PIN_FIELD_BASE(43, 43, 7, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(44, 44, 7, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(45, 45, 7, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(46, 46, 7, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(47, 47, 7, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(48, 48, 7, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(49, 49, 7, 0x00, 0x10, 6, 3), + + PIN_FIELD_BASE(50, 50, 6, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(51, 51, 6, 0x00, 0x10, 6, 3), + PIN_FIELD_BASE(52, 52, 6, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(53, 53, 6, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(54, 54, 6, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(55, 55, 6, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(56, 56, 6, 0x00, 0x10, 3, 3), +}; + +static const struct mtk_pin_field_calc mt7981_pin_pupd_range[] = { + PIN_FIELD_BASE(0, 0, 1, 0x20, 0x10, 1, 1), + PIN_FIELD_BASE(1, 1, 1, 0x20, 0x10, 0, 1), + PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 6, 1), + PIN_FIELD_BASE(3, 3, 4, 0x30, 0x10, 6, 1), + PIN_FIELD_BASE(4, 4, 4, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(5, 5, 4, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(6, 6, 4, 0x30, 0x10, 3, 1), + PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 4, 1), + + PIN_FIELD_BASE(9, 9, 5, 0x30, 0x10, 9, 1), + PIN_FIELD_BASE(10, 10, 5, 0x30, 0x10, 8, 1), + PIN_FIELD_BASE(11, 11, 5, 0x30, 0x10, 10, 1), + PIN_FIELD_BASE(12, 12, 5, 0x30, 0x10, 7, 1), + PIN_FIELD_BASE(13, 13, 5, 0x30, 0x10, 11, 1), + + PIN_FIELD_BASE(14, 14, 4, 0x30, 0x10, 8, 1), + + PIN_FIELD_BASE(15, 15, 2, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(16, 16, 2, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(17, 17, 2, 0x30, 0x10, 5, 1), + PIN_FIELD_BASE(18, 18, 2, 0x30, 0x10, 4, 1), + PIN_FIELD_BASE(19, 19, 2, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1), + PIN_FIELD_BASE(21, 21, 2, 0x30, 0x10, 6, 1), + PIN_FIELD_BASE(22, 22, 2, 0x30, 0x10, 7, 1), + PIN_FIELD_BASE(23, 23, 2, 0x30, 0x10, 10, 1), + PIN_FIELD_BASE(24, 24, 2, 0x30, 0x10, 9, 1), + PIN_FIELD_BASE(25, 25, 2, 0x30, 0x10, 8, 1), + + PIN_FIELD_BASE(26, 26, 5, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(27, 27, 5, 0x30, 0x10, 4, 1), + PIN_FIELD_BASE(28, 28, 5, 0x30, 0x10, 3, 1), + PIN_FIELD_BASE(29, 29, 5, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(30, 30, 5, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(31, 31, 5, 0x30, 0x10, 5, 1), + + PIN_FIELD_BASE(32, 32, 1, 0x20, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 1, 0x20, 0x10, 3, 1), + + PIN_FIELD_BASE(34, 34, 4, 0x30, 0x10, 5, 1), + PIN_FIELD_BASE(35, 35, 4, 0x30, 0x10, 7, 1), + + PIN_FIELD_BASE(36, 36, 3, 0x20, 0x10, 2, 1), + PIN_FIELD_BASE(37, 37, 3, 0x20, 0x10, 3, 1), + PIN_FIELD_BASE(38, 38, 3, 0x20, 0x10, 0, 1), + PIN_FIELD_BASE(39, 39, 3, 0x20, 0x10, 1, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_r0_range[] = { + PIN_FIELD_BASE(0, 0, 1, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(1, 1, 1, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(2, 2, 5, 0x40, 0x10, 6, 1), + PIN_FIELD_BASE(3, 3, 4, 0x40, 0x10, 6, 1), + PIN_FIELD_BASE(4, 4, 4, 0x40, 0x10, 2, 1), + PIN_FIELD_BASE(5, 5, 4, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(6, 6, 4, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1), + + PIN_FIELD_BASE(9, 9, 5, 0x40, 0x10, 9, 1), + PIN_FIELD_BASE(10, 10, 5, 0x40, 0x10, 8, 1), + PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1), + PIN_FIELD_BASE(12, 12, 5, 0x40, 0x10, 7, 1), + PIN_FIELD_BASE(13, 13, 5, 0x40, 0x10, 11, 1), + + PIN_FIELD_BASE(14, 14, 4, 0x40, 0x10, 8, 1), + + PIN_FIELD_BASE(15, 15, 2, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(16, 16, 2, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(17, 17, 2, 0x40, 0x10, 5, 1), + PIN_FIELD_BASE(18, 18, 2, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(19, 19, 2, 0x40, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 2, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(21, 21, 2, 0x40, 0x10, 6, 1), + PIN_FIELD_BASE(22, 22, 2, 0x40, 0x10, 7, 1), + PIN_FIELD_BASE(23, 23, 2, 0x40, 0x10, 10, 1), + PIN_FIELD_BASE(24, 24, 2, 0x40, 0x10, 9, 1), + PIN_FIELD_BASE(25, 25, 2, 0x40, 0x10, 8, 1), + + PIN_FIELD_BASE(26, 26, 5, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(27, 27, 5, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(28, 28, 5, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(29, 29, 5, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(30, 30, 5, 0x40, 0x10, 2, 1), + PIN_FIELD_BASE(31, 31, 5, 0x40, 0x10, 5, 1), + + PIN_FIELD_BASE(32, 32, 1, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 1, 0x30, 0x10, 3, 1), + + PIN_FIELD_BASE(34, 34, 4, 0x40, 0x10, 5, 1), + PIN_FIELD_BASE(35, 35, 4, 0x40, 0x10, 7, 1), + + PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 3, 1), + PIN_FIELD_BASE(38, 38, 3, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(39, 39, 3, 0x30, 0x10, 1, 1), +}; + +static const struct mtk_pin_field_calc mt7981_pin_r1_range[] = { + PIN_FIELD_BASE(0, 0, 1, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(1, 1, 1, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 6, 1), + PIN_FIELD_BASE(3, 3, 4, 0x50, 0x10, 6, 1), + PIN_FIELD_BASE(4, 4, 4, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(5, 5, 4, 0x50, 0x10, 1, 1), + PIN_FIELD_BASE(6, 6, 4, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(7, 7, 4, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(8, 8, 4, 0x50, 0x10, 4, 1), + + PIN_FIELD_BASE(9, 9, 5, 0x50, 0x10, 9, 1), + PIN_FIELD_BASE(10, 10, 5, 0x50, 0x10, 8, 1), + PIN_FIELD_BASE(11, 11, 5, 0x50, 0x10, 10, 1), + PIN_FIELD_BASE(12, 12, 5, 0x50, 0x10, 7, 1), + PIN_FIELD_BASE(13, 13, 5, 0x50, 0x10, 11, 1), + + PIN_FIELD_BASE(14, 14, 4, 0x50, 0x10, 8, 1), + + PIN_FIELD_BASE(15, 15, 2, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(16, 16, 2, 0x50, 0x10, 1, 1), + PIN_FIELD_BASE(17, 17, 2, 0x50, 0x10, 5, 1), + PIN_FIELD_BASE(18, 18, 2, 0x50, 0x10, 4, 1), + PIN_FIELD_BASE(19, 19, 2, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 2, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(21, 21, 2, 0x50, 0x10, 6, 1), + PIN_FIELD_BASE(22, 22, 2, 0x50, 0x10, 7, 1), + PIN_FIELD_BASE(23, 23, 2, 0x50, 0x10, 10, 1), + PIN_FIELD_BASE(24, 24, 2, 0x50, 0x10, 9, 1), + PIN_FIELD_BASE(25, 25, 2, 0x50, 0x10, 8, 1), + + PIN_FIELD_BASE(26, 26, 5, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(27, 27, 5, 0x50, 0x10, 4, 1), + PIN_FIELD_BASE(28, 28, 5, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(29, 29, 5, 0x50, 0x10, 1, 1), + PIN_FIELD_BASE(30, 30, 5, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(31, 31, 5, 0x50, 0x10, 5, 1), + + PIN_FIELD_BASE(32, 32, 1, 0x40, 0x10, 2, 1), + PIN_FIELD_BASE(33, 33, 1, 0x40, 0x10, 3, 1), + + PIN_FIELD_BASE(34, 34, 4, 0x50, 0x10, 5, 1), + PIN_FIELD_BASE(35, 35, 4, 0x50, 0x10, 7, 1), + + PIN_FIELD_BASE(36, 36, 3, 0x40, 0x10, 2, 1), + PIN_FIELD_BASE(37, 37, 3, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(38, 38, 3, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(39, 39, 3, 0x40, 0x10, 1, 1), +}; + +static const struct mtk_pin_reg_calc mt7981_reg_cals[] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7981_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7981_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7981_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7981_pin_do_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7981_pin_smt_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7981_pin_ies_range), + [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7981_pin_pu_range), + [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7981_pin_pd_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7981_pin_drv_range), + [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7981_pin_pupd_range), + [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7981_pin_r0_range), + [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7981_pin_r1_range), +}; + +static const struct mtk_pin_desc mt7981_pins[] = { + MT7981_PIN(0, "GPIO_WPS"), + MT7981_PIN(1, "GPIO_RESET"), + MT7981_PIN(2, "SYS_WATCHDOG"), + MT7981_PIN(3, "PCIE_PERESET_N"), + MT7981_PIN(4, "JTAG_JTDO"), + MT7981_PIN(5, "JTAG_JTDI"), + MT7981_PIN(6, "JTAG_JTMS"), + MT7981_PIN(7, "JTAG_JTCLK"), + MT7981_PIN(8, "JTAG_JTRST_N"), + MT7981_PIN(9, "WO_JTAG_JTDO"), + MT7981_PIN(10, "WO_JTAG_JTDI"), + MT7981_PIN(11, "WO_JTAG_JTMS"), + MT7981_PIN(12, "WO_JTAG_JTCLK"), + MT7981_PIN(13, "WO_JTAG_JTRST_N"), + MT7981_PIN(14, "USB_VBUS"), + MT7981_PIN(15, "PWM0"), + MT7981_PIN(16, "SPI0_CLK"), + MT7981_PIN(17, "SPI0_MOSI"), + MT7981_PIN(18, "SPI0_MISO"), + MT7981_PIN(19, "SPI0_CS"), + MT7981_PIN(20, "SPI0_HOLD"), + MT7981_PIN(21, "SPI0_WP"), + MT7981_PIN(22, "SPI1_CLK"), + MT7981_PIN(23, "SPI1_MOSI"), + MT7981_PIN(24, "SPI1_MISO"), + MT7981_PIN(25, "SPI1_CS"), + MT7981_PIN(26, "SPI2_CLK"), + MT7981_PIN(27, "SPI2_MOSI"), + MT7981_PIN(28, "SPI2_MISO"), + MT7981_PIN(29, "SPI2_CS"), + MT7981_PIN(30, "SPI2_HOLD"), + MT7981_PIN(31, "SPI2_WP"), + MT7981_PIN(32, "UART0_RXD"), + MT7981_PIN(33, "UART0_TXD"), + MT7981_PIN(34, "PCIE_CLK_REQ"), + MT7981_PIN(35, "PCIE_WAKE_N"), + MT7981_PIN(36, "SMI_MDC"), + MT7981_PIN(37, "SMI_MDIO"), + MT7981_PIN(38, "GBE_INT"), + MT7981_PIN(39, "GBE_RESET"), + MT7981_PIN(40, "WF_DIG_RESETB"), + MT7981_PIN(41, "WF_CBA_RESETB"), + MT7981_PIN(42, "WF_XO_REQ"), + MT7981_PIN(43, "WF_TOP_CLK"), + MT7981_PIN(44, "WF_TOP_DATA"), + MT7981_PIN(45, "WF_HB1"), + MT7981_PIN(46, "WF_HB2"), + MT7981_PIN(47, "WF_HB3"), + MT7981_PIN(48, "WF_HB4"), + MT7981_PIN(49, "WF_HB0"), + MT7981_PIN(50, "WF_HB0_B"), + MT7981_PIN(51, "WF_HB5"), + MT7981_PIN(52, "WF_HB6"), + MT7981_PIN(53, "WF_HB7"), + MT7981_PIN(54, "WF_HB8"), + MT7981_PIN(55, "WF_HB9"), + MT7981_PIN(56, "WF_HB10"), +}; + +/* List all groups consisting of these pins dedicated to the enablement of + * certain hardware block and the corresponding mode for all of the pins. + * The hardware probably has multiple combinations of these pinouts. + */ + +/* WA_AICE */ +static int mt7981_wa_aice1_pins[] = { 0, 1, }; +static int mt7981_wa_aice1_funcs[] = { 2, 2, }; + +static int mt7981_wa_aice2_pins[] = { 0, 1, }; +static int mt7981_wa_aice2_funcs[] = { 3, 3, }; + +static int mt7981_wa_aice3_pins[] = { 28, 29, }; +static int mt7981_wa_aice3_funcs[] = { 3, 3, }; + +static int mt7981_wm_aice1_pins[] = { 9, 10, }; +static int mt7981_wm_aice1_funcs[] = { 2, 2, }; + +static int mt7981_wm_aice2_pins[] = { 30, 31, }; +static int mt7981_wm_aice2_funcs[] = { 5, 5, }; + +/* WM_UART */ +static int mt7981_wm_uart_0_pins[] = { 0, 1, }; +static int mt7981_wm_uart_0_funcs[] = { 5, 5, }; + +static int mt7981_wm_uart_1_pins[] = { 20, 21, }; +static int mt7981_wm_uart_1_funcs[] = { 4, 4, }; + +static int mt7981_wm_uart_2_pins[] = { 30, 31, }; +static int mt7981_wm_uart_2_funcs[] = { 3, 3, }; + +/* DFD */ +static int mt7981_dfd_pins[] = { 0, 1, 4, 5, }; +static int mt7981_dfd_funcs[] = { 5, 5, 6, 6, }; + +/* SYS_WATCHDOG */ +static int mt7981_watchdog_pins[] = { 2, }; +static int mt7981_watchdog_funcs[] = { 1, }; + +static int mt7981_watchdog1_pins[] = { 13, }; +static int mt7981_watchdog1_funcs[] = { 5, }; + +/* PCIE_PERESET_N */ +static int mt7981_pcie_pereset_pins[] = { 3, }; +static int mt7981_pcie_pereset_funcs[] = { 1, }; + +/* JTAG */ +static int mt7981_jtag_pins[] = { 4, 5, 6, 7, 8, }; +static int mt7981_jtag_funcs[] = { 1, 1, 1, 1, 1, }; + +/* WM_JTAG */ +static int mt7981_wm_jtag_0_pins[] = { 4, 5, 6, 7, 8, }; +static int mt7981_wm_jtag_0_funcs[] = { 2, 2, 2, 2, 2, }; + +static int mt7981_wm_jtag_1_pins[] = { 20, 21, 22, 23, 24, }; +static int mt7981_wm_jtag_1_funcs[] = { 5, 5, 5, 5, 5, }; + +/* WO0_JTAG */ +static int mt7981_wo0_jtag_0_pins[] = { 9, 10, 11, 12, 13, }; +static int mt7981_wo0_jtag_0_funcs[] = { 1, 1, 1, 1, 1, }; + +static int mt7981_wo0_jtag_1_pins[] = { 25, 26, 27, 28, 29, }; +static int mt7981_wo0_jtag_1_funcs[] = { 5, 5, 5, 5, 5, }; + +/* UART2 */ +static int mt7981_uart2_0_pins[] = { 4, 5, 6, 7, }; +static int mt7981_uart2_0_funcs[] = { 3, 3, 3, 3, }; + +/* GBE_LED0 */ +static int mt7981_gbe_led0_pins[] = { 8, }; +static int mt7981_gbe_led0_funcs[] = { 3, }; + +/* PTA_EXT */ +static int mt7981_pta_ext_0_pins[] = { 4, 5, 6, }; +static int mt7981_pta_ext_0_funcs[] = { 4, 4, 4, }; + +static int mt7981_pta_ext_1_pins[] = { 22, 23, 24, }; +static int mt7981_pta_ext_1_funcs[] = { 4, 4, 4, }; + +/* PWM2 */ +static int mt7981_pwm2_pins[] = { 7, }; +static int mt7981_pwm2_funcs[] = { 4, }; + +/* NET_WO0_UART_TXD */ +static int mt7981_net_wo0_uart_txd_0_pins[] = { 8, }; +static int mt7981_net_wo0_uart_txd_0_funcs[] = { 4, }; + +static int mt7981_net_wo0_uart_txd_1_pins[] = { 14, }; +static int mt7981_net_wo0_uart_txd_1_funcs[] = { 3, }; + +static int mt7981_net_wo0_uart_txd_2_pins[] = { 15, }; +static int mt7981_net_wo0_uart_txd_2_funcs[] = { 4, }; + +/* SPI1 */ +static int mt7981_spi1_0_pins[] = { 4, 5, 6, 7, }; +static int mt7981_spi1_0_funcs[] = { 5, 5, 5, 5, }; + +/* I2C */ +static int mt7981_i2c0_0_pins[] = { 6, 7, }; +static int mt7981_i2c0_0_funcs[] = { 6, 6, }; + +static int mt7981_i2c0_1_pins[] = { 30, 31, }; +static int mt7981_i2c0_1_funcs[] = { 4, 4, }; + +static int mt7981_i2c0_2_pins[] = { 36, 37, }; +static int mt7981_i2c0_2_funcs[] = { 2, 2, }; + +static int mt7981_u2_phy_i2c_pins[] = { 30, 31, }; +static int mt7981_u2_phy_i2c_funcs[] = { 6, 6, }; + +static int mt7981_u3_phy_i2c_pins[] = { 32, 33, }; +static int mt7981_u3_phy_i2c_funcs[] = { 3, 3, }; + +static int mt7981_sgmii1_phy_i2c_pins[] = { 32, 33, }; +static int mt7981_sgmii1_phy_i2c_funcs[] = { 2, 2, }; + +static int mt7981_sgmii0_phy_i2c_pins[] = { 32, 33, }; +static int mt7981_sgmii0_phy_i2c_funcs[] = { 5, 5, }; + +/* DFD_NTRST */ +static int mt7981_dfd_ntrst_pins[] = { 8, }; +static int mt7981_dfd_ntrst_funcs[] = { 6, }; + +/* PWM0 */ +static int mt7981_pwm0_0_pins[] = { 13, }; +static int mt7981_pwm0_0_funcs[] = { 2, }; + +static int mt7981_pwm0_1_pins[] = { 15, }; +static int mt7981_pwm0_1_funcs[] = { 1, }; + +/* PWM1 */ +static int mt7981_pwm1_0_pins[] = { 14, }; +static int mt7981_pwm1_0_funcs[] = { 2, }; + +static int mt7981_pwm1_1_pins[] = { 15, }; +static int mt7981_pwm1_1_funcs[] = { 3, }; + +/* GBE_LED1 */ +static int mt7981_gbe_led1_pins[] = { 13, }; +static int mt7981_gbe_led1_funcs[] = { 3, }; + +/* PCM */ +static int mt7981_pcm_pins[] = { 9, 10, 11, 12, 13, 25 }; +static int mt7981_pcm_funcs[] = { 4, 4, 4, 4, 4, 4, }; + +/* UDI */ +static int mt7981_udi_pins[] = { 9, 10, 11, 12, 13, }; +static int mt7981_udi_funcs[] = { 6, 6, 6, 6, 6, }; + +/* DRV_VBUS */ +static int mt7981_drv_vbus_pins[] = { 14, }; +static int mt7981_drv_vbus_funcs[] = { 1, }; + +/* EMMC */ +static int mt7981_emmc_45_pins[] = { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, }; +static int mt7981_emmc_45_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }; + +/* SNFI */ +static int mt7981_snfi_pins[] = { 16, 17, 18, 19, 20, 21, }; +static int mt7981_snfi_funcs[] = { 3, 3, 3, 3, 3, 3, }; + +/* SPI0 */ +static int mt7981_spi0_pins[] = { 16, 17, 18, 19, }; +static int mt7981_spi0_funcs[] = { 1, 1, 1, 1, }; + +/* SPI0 */ +static int mt7981_spi0_wp_hold_pins[] = { 20, 21, }; +static int mt7981_spi0_wp_hold_funcs[] = { 1, 1, }; + +/* SPI1 */ +static int mt7981_spi1_1_pins[] = { 22, 23, 24, 25, }; +static int mt7981_spi1_1_funcs[] = { 1, 1, 1, 1, }; + +/* SPI2 */ +static int mt7981_spi2_pins[] = { 26, 27, 28, 29, }; +static int mt7981_spi2_funcs[] = { 1, 1, 1, 1, }; + +/* SPI2 */ +static int mt7981_spi2_wp_hold_pins[] = { 30, 31, }; +static int mt7981_spi2_wp_hold_funcs[] = { 1, 1, }; + +/* UART1 */ +static int mt7981_uart1_0_pins[] = { 16, 17, 18, 19, }; +static int mt7981_uart1_0_funcs[] = { 4, 4, 4, 4, }; + +static int mt7981_uart1_1_pins[] = { 26, 27, 28, 29, }; +static int mt7981_uart1_1_funcs[] = { 2, 2, 2, 2, }; + +/* UART2 */ +static int mt7981_uart2_1_pins[] = { 22, 23, 24, 25, }; +static int mt7981_uart2_1_funcs[] = { 3, 3, 3, 3, }; + +/* UART0 */ +static int mt7981_uart0_pins[] = { 32, 33, }; +static int mt7981_uart0_funcs[] = { 1, 1, }; + +/* PCIE_CLK_REQ */ +static int mt7981_pcie_clk_pins[] = { 34, }; +static int mt7981_pcie_clk_funcs[] = { 2, }; + +/* PCIE_WAKE_N */ +static int mt7981_pcie_wake_pins[] = { 35, }; +static int mt7981_pcie_wake_funcs[] = { 2, }; + +/* MDC_MDIO */ +static int mt7981_smi_mdc_mdio_pins[] = { 36, 37, }; +static int mt7981_smi_mdc_mdio_funcs[] = { 1, 1, }; + +static int mt7981_gbe_ext_mdc_mdio_pins[] = { 36, 37, }; +static int mt7981_gbe_ext_mdc_mdio_funcs[] = { 3, 3, }; + +/* WF0_MODE1 */ +static int mt7981_wf0_mode1_pins[] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 }; +static int mt7981_wf0_mode1_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + +/* WF0_MODE3 */ +static int mt7981_wf0_mode3_pins[] = { 45, 46, 47, 48, 49, 51 }; +static int mt7981_wf0_mode3_funcs[] = { 2, 2, 2, 2, 2, 2 }; + +/* WF2G_LED */ +static int mt7981_wf2g_led0_pins[] = { 30, }; +static int mt7981_wf2g_led0_funcs[] = { 2, }; + +static int mt7981_wf2g_led1_pins[] = { 34, }; +static int mt7981_wf2g_led1_funcs[] = { 1, }; + +/* WF5G_LED */ +static int mt7981_wf5g_led0_pins[] = { 31, }; +static int mt7981_wf5g_led0_funcs[] = { 2, }; + +static int mt7981_wf5g_led1_pins[] = { 35, }; +static int mt7981_wf5g_led1_funcs[] = { 1, }; + +/* MT7531_INT */ +static int mt7981_mt7531_int_pins[] = { 38, }; +static int mt7981_mt7531_int_funcs[] = { 1, }; + +/* ANT_SEL */ +static int mt7981_ant_sel_pins[] = { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 34, 35 }; +static int mt7981_ant_sel_funcs[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }; + +static const struct group_desc mt7981_groups[] = { + /* @GPIO(0,1): WA_AICE(2) */ + PINCTRL_PIN_GROUP("wa_aice1", mt7981_wa_aice1), + /* @GPIO(0,1): WA_AICE(3) */ + PINCTRL_PIN_GROUP("wa_aice2", mt7981_wa_aice2), + /* @GPIO(0,1): WM_UART(5) */ + PINCTRL_PIN_GROUP("wm_uart_0", mt7981_wm_uart_0), + /* @GPIO(0,1,4,5): DFD(6) */ + PINCTRL_PIN_GROUP("dfd", mt7981_dfd), + /* @GPIO(2): SYS_WATCHDOG(1) */ + PINCTRL_PIN_GROUP("watchdog", mt7981_watchdog), + /* @GPIO(3): PCIE_PERESET_N(1) */ + PINCTRL_PIN_GROUP("pcie_pereset", mt7981_pcie_pereset), + /* @GPIO(4,8) JTAG(1) */ + PINCTRL_PIN_GROUP("jtag", mt7981_jtag), + /* @GPIO(4,8) WM_JTAG(2) */ + PINCTRL_PIN_GROUP("wm_jtag_0", mt7981_wm_jtag_0), + /* @GPIO(9,13) WO0_JTAG(1) */ + PINCTRL_PIN_GROUP("wo0_jtag_0", mt7981_wo0_jtag_0), + /* @GPIO(4,7) WM_JTAG(3) */ + PINCTRL_PIN_GROUP("uart2_0", mt7981_uart2_0), + /* @GPIO(8) GBE_LED0(3) */ + PINCTRL_PIN_GROUP("gbe_led0", mt7981_gbe_led0), + /* @GPIO(4,6) PTA_EXT(4) */ + PINCTRL_PIN_GROUP("pta_ext_0", mt7981_pta_ext_0), + /* @GPIO(7) PWM2(4) */ + PINCTRL_PIN_GROUP("pwm2", mt7981_pwm2), + /* @GPIO(8) NET_WO0_UART_TXD(4) */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7981_net_wo0_uart_txd_0), + /* @GPIO(4,7) SPI1(5) */ + PINCTRL_PIN_GROUP("spi1_0", mt7981_spi1_0), + /* @GPIO(6,7) I2C(5) */ + PINCTRL_PIN_GROUP("i2c0_0", mt7981_i2c0_0), + /* @GPIO(0,1,4,5): DFD_NTRST(6) */ + PINCTRL_PIN_GROUP("dfd_ntrst", mt7981_dfd_ntrst), + /* @GPIO(9,10): WM_AICE(2) */ + PINCTRL_PIN_GROUP("wm_aice1", mt7981_wm_aice1), + /* @GPIO(13): PWM0(2) */ + PINCTRL_PIN_GROUP("pwm0_0", mt7981_pwm0_0), + /* @GPIO(15): PWM0(1) */ + PINCTRL_PIN_GROUP("pwm0_1", mt7981_pwm0_1), + /* @GPIO(14): PWM1(2) */ + PINCTRL_PIN_GROUP("pwm1_0", mt7981_pwm1_0), + /* @GPIO(15): PWM1(3) */ + PINCTRL_PIN_GROUP("pwm1_1", mt7981_pwm1_1), + /* @GPIO(14) NET_WO0_UART_TXD(3) */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7981_net_wo0_uart_txd_1), + /* @GPIO(15) NET_WO0_UART_TXD(4) */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_2", mt7981_net_wo0_uart_txd_2), + /* @GPIO(13) GBE_LED0(3) */ + PINCTRL_PIN_GROUP("gbe_led1", mt7981_gbe_led1), + /* @GPIO(9,13) PCM(4) */ + PINCTRL_PIN_GROUP("pcm", mt7981_pcm), + /* @GPIO(13): SYS_WATCHDOG1(5) */ + PINCTRL_PIN_GROUP("watchdog1", mt7981_watchdog1), + /* @GPIO(9,13) UDI(4) */ + PINCTRL_PIN_GROUP("udi", mt7981_udi), + /* @GPIO(14) DRV_VBUS(1) */ + PINCTRL_PIN_GROUP("drv_vbus", mt7981_drv_vbus), + /* @GPIO(15,25): EMMC(2) */ + PINCTRL_PIN_GROUP("emmc_45", mt7981_emmc_45), + /* @GPIO(16,21): SNFI(3) */ + PINCTRL_PIN_GROUP("snfi", mt7981_snfi), + /* @GPIO(16,19): SPI0(1) */ + PINCTRL_PIN_GROUP("spi0", mt7981_spi0), + /* @GPIO(20,21): SPI0(1) */ + PINCTRL_PIN_GROUP("spi0_wp_hold", mt7981_spi0_wp_hold), + /* @GPIO(22,25) SPI1(1) */ + PINCTRL_PIN_GROUP("spi1_1", mt7981_spi1_1), + /* @GPIO(26,29): SPI2(1) */ + PINCTRL_PIN_GROUP("spi2", mt7981_spi2), + /* @GPIO(30,31): SPI0(1) */ + PINCTRL_PIN_GROUP("spi2_wp_hold", mt7981_spi2_wp_hold), + /* @GPIO(16,19): UART1(4) */ + PINCTRL_PIN_GROUP("uart1_0", mt7981_uart1_0), + /* @GPIO(26,29): UART1(2) */ + PINCTRL_PIN_GROUP("uart1_1", mt7981_uart1_1), + /* @GPIO(22,25): UART1(3) */ + PINCTRL_PIN_GROUP("uart2_1", mt7981_uart2_1), + /* @GPIO(22,24) PTA_EXT(4) */ + PINCTRL_PIN_GROUP("pta_ext_1", mt7981_pta_ext_1), + /* @GPIO(20,21): WM_UART(4) */ + PINCTRL_PIN_GROUP("wm_aurt_1", mt7981_wm_uart_1), + /* @GPIO(30,31): WM_UART(3) */ + PINCTRL_PIN_GROUP("wm_aurt_2", mt7981_wm_uart_2), + /* @GPIO(20,24) WM_JTAG(5) */ + PINCTRL_PIN_GROUP("wm_jtag_1", mt7981_wm_jtag_1), + /* @GPIO(25,29) WO0_JTAG(5) */ + PINCTRL_PIN_GROUP("wo0_jtag_1", mt7981_wo0_jtag_1), + /* @GPIO(28,29): WA_AICE(3) */ + PINCTRL_PIN_GROUP("wa_aice3", mt7981_wa_aice3), + /* @GPIO(30,31): WM_AICE(5) */ + PINCTRL_PIN_GROUP("wm_aice2", mt7981_wm_aice2), + /* @GPIO(30,31): I2C(4) */ + PINCTRL_PIN_GROUP("i2c0_1", mt7981_i2c0_1), + /* @GPIO(30,31): I2C(6) */ + PINCTRL_PIN_GROUP("u2_phy_i2c", mt7981_u2_phy_i2c), + /* @GPIO(32,33): I2C(1) */ + PINCTRL_PIN_GROUP("uart0", mt7981_uart0), + /* @GPIO(32,33): I2C(2) */ + PINCTRL_PIN_GROUP("sgmii1_phy_i2c", mt7981_sgmii1_phy_i2c), + /* @GPIO(32,33): I2C(3) */ + PINCTRL_PIN_GROUP("u3_phy_i2c", mt7981_u3_phy_i2c), + /* @GPIO(32,33): I2C(5) */ + PINCTRL_PIN_GROUP("sgmii0_phy_i2c", mt7981_sgmii0_phy_i2c), + /* @GPIO(34): PCIE_CLK_REQ(2) */ + PINCTRL_PIN_GROUP("pcie_clk", mt7981_pcie_clk), + /* @GPIO(35): PCIE_WAKE_N(2) */ + PINCTRL_PIN_GROUP("pcie_wake", mt7981_pcie_wake), + /* @GPIO(36,37): I2C(2) */ + PINCTRL_PIN_GROUP("i2c0_2", mt7981_i2c0_2), + /* @GPIO(36,37): MDC_MDIO(1) */ + PINCTRL_PIN_GROUP("smi_mdc_mdio", mt7981_smi_mdc_mdio), + /* @GPIO(36,37): MDC_MDIO(3) */ + PINCTRL_PIN_GROUP("gbe_ext_mdc_mdio", mt7981_gbe_ext_mdc_mdio), + /* @GPIO(69,85): WF0_MODE1(1) */ + PINCTRL_PIN_GROUP("wf0_mode1", mt7981_wf0_mode1), + /* @GPIO(74,80): WF0_MODE3(3) */ + PINCTRL_PIN_GROUP("wf0_mode3", mt7981_wf0_mode3), + /* @GPIO(30): WF2G_LED(2) */ + PINCTRL_PIN_GROUP("wf2g_led0", mt7981_wf2g_led0), + /* @GPIO(34): WF2G_LED(1) */ + PINCTRL_PIN_GROUP("wf2g_led1", mt7981_wf2g_led1), + /* @GPIO(31): WF5G_LED(2) */ + PINCTRL_PIN_GROUP("wf5g_led0", mt7981_wf5g_led0), + /* @GPIO(35): WF5G_LED(1) */ + PINCTRL_PIN_GROUP("wf5g_led1", mt7981_wf5g_led1), + /* @GPIO(38): MT7531_INT(1) */ + PINCTRL_PIN_GROUP("mt7531_int", mt7981_mt7531_int), + /* @GPIO(14,15,26,17,18,19,20,21,22,23,24,25,34,35): ANT_SEL(1) */ + PINCTRL_PIN_GROUP("ant_sel", mt7981_ant_sel), +}; + +/* Joint those groups owning the same capability in user point of view which + * allows that people tend to use through the device tree. + */ +static const char *mt7981_wa_aice_groups[] = { "wa_aice1", "wa_aice2", "wm_aice1_1", + "wa_aice3", "wm_aice1_2", }; +static const char *mt7981_uart_groups[] = { "wm_uart_0", "uart2_0", + "net_wo0_uart_txd_0", "net_wo0_uart_txd_1", "net_wo0_uart_txd_2", + "uart1_0", "uart1_1", "uart2_1", "wm_aurt_1", "wm_aurt_2", "uart0", }; +static const char *mt7981_dfd_groups[] = { "dfd", "dfd_ntrst", }; +static const char *mt7981_wdt_groups[] = { "watchdog", "watchdog1", }; +static const char *mt7981_pcie_groups[] = { "pcie_pereset", "pcie_clk", "pcie_wake", }; +static const char *mt7981_jtag_groups[] = { "jtag", "wm_jtag_0", "wo0_jtag_0", + "wo0_jtag_1", "wm_jtag_1", }; +static const char *mt7981_led_groups[] = { "gbe_led0", "gbe_led1", "wf2g_led0", + "wf2g_led1", "wf5g_led0", "wf5g_led1", }; +static const char *mt7981_pta_groups[] = { "pta_ext_0", "pta_ext_1", }; +static const char *mt7981_pwm_groups[] = { "pwm2", "pwm0_0", "pwm0_1", + "pwm1_0", "pwm1_1", }; +static const char *mt7981_spi_groups[] = { "spi1_0", "spi0", "spi0_wp_hold", "spi1_1", "spi2", + "spi2_wp_hold", }; +static const char *mt7981_i2c_groups[] = { "i2c0_0", "i2c0_1", "u2_phy_i2c", + "sgmii1_phy_i2c", "u3_phy_i2c", "sgmii0_phy_i2c", "i2c0_2", }; +static const char *mt7981_pcm_groups[] = { "pcm", }; +static const char *mt7981_udi_groups[] = { "udi", }; +static const char *mt7981_usb_groups[] = { "drv_vbus", }; +static const char *mt7981_flash_groups[] = { "emmc_45", "snfi", }; +static const char *mt7981_ethernet_groups[] = { "smi_mdc_mdio", "gbe_ext_mdc_mdio", + "wf0_mode1", "wf0_mode3", "mt7531_int", }; +static const char *mt7981_ant_groups[] = { "ant_sel", }; + +static const struct function_desc mt7981_functions[] = { + {"wa_aice", mt7981_wa_aice_groups, ARRAY_SIZE(mt7981_wa_aice_groups)}, + {"dfd", mt7981_dfd_groups, ARRAY_SIZE(mt7981_dfd_groups)}, + {"jtag", mt7981_jtag_groups, ARRAY_SIZE(mt7981_jtag_groups)}, + {"pta", mt7981_pta_groups, ARRAY_SIZE(mt7981_pta_groups)}, + {"pcm", mt7981_pcm_groups, ARRAY_SIZE(mt7981_pcm_groups)}, + {"udi", mt7981_udi_groups, ARRAY_SIZE(mt7981_udi_groups)}, + {"usb", mt7981_usb_groups, ARRAY_SIZE(mt7981_usb_groups)}, + {"ant", mt7981_ant_groups, ARRAY_SIZE(mt7981_ant_groups)}, + {"eth", mt7981_ethernet_groups, ARRAY_SIZE(mt7981_ethernet_groups)}, + {"i2c", mt7981_i2c_groups, ARRAY_SIZE(mt7981_i2c_groups)}, + {"led", mt7981_led_groups, ARRAY_SIZE(mt7981_led_groups)}, + {"pwm", mt7981_pwm_groups, ARRAY_SIZE(mt7981_pwm_groups)}, + {"spi", mt7981_spi_groups, ARRAY_SIZE(mt7981_spi_groups)}, + {"uart", mt7981_uart_groups, ARRAY_SIZE(mt7981_uart_groups)}, + {"watchdog", mt7981_wdt_groups, ARRAY_SIZE(mt7981_wdt_groups)}, + {"flash", mt7981_flash_groups, ARRAY_SIZE(mt7981_flash_groups)}, + {"pcie", mt7981_pcie_groups, ARRAY_SIZE(mt7981_pcie_groups)}, +}; + +static const struct mtk_eint_hw mt7981_eint_hw = { + .port_mask = 7, + .ports = 7, + .ap_num = ARRAY_SIZE(mt7981_pins), + .db_cnt = 16, +}; + +static const char * const mt7981_pinctrl_register_base_names[] = { + "gpio", "iocfg_rt", "iocfg_rm", "iocfg_rb", + "iocfg_lb", "iocfg_bl", "iocfg_tm", "iocfg_tl", +}; + +static struct mtk_pin_soc mt7981_data = { + .reg_cal = mt7981_reg_cals, + .pins = mt7981_pins, + .npins = ARRAY_SIZE(mt7981_pins), + .grps = mt7981_groups, + .ngrps = ARRAY_SIZE(mt7981_groups), + .funcs = mt7981_functions, + .nfuncs = ARRAY_SIZE(mt7981_functions), + .eint_hw = &mt7981_eint_hw, + .gpio_m = 0, + .ies_present = false, + .base_names = mt7981_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt7981_pinctrl_register_base_names), + .bias_set_combo = mtk_pinconf_bias_set_combo, + .bias_get_combo = mtk_pinconf_bias_get_combo, + .drive_set = mtk_pinconf_drive_set_rev1, + .drive_get = mtk_pinconf_drive_get_rev1, + .adv_pull_get = mtk_pinconf_adv_pull_get, + .adv_pull_set = mtk_pinconf_adv_pull_set, +}; + +static const struct of_device_id mt7981_pinctrl_of_match[] = { + { .compatible = "mediatek,mt7981-pinctrl", }, + {} +}; + +static int mt7981_pinctrl_probe(struct platform_device *pdev) +{ + return mtk_moore_pinctrl_probe(pdev, &mt7981_data); +} + +static struct platform_driver mt7981_pinctrl_driver = { + .driver = { + .name = "mt7981-pinctrl", + .of_match_table = mt7981_pinctrl_of_match, + }, + .probe = mt7981_pinctrl_probe, +}; + +static int __init mt7981_pinctrl_init(void) +{ + return platform_driver_register(&mt7981_pinctrl_driver); +} +arch_initcall(mt7981_pinctrl_init); diff --git a/target/linux/mediatek/filogic/config-5.15 b/target/linux/mediatek/filogic/config-5.15 index 6883a5b54b0..7e91f070658 100644 --- a/target/linux/mediatek/filogic/config-5.15 +++ b/target/linux/mediatek/filogic/config-5.15 @@ -308,6 +308,7 @@ CONFIG_PINCTRL=y # CONFIG_PINCTRL_MT6765 is not set # CONFIG_PINCTRL_MT6797 is not set # CONFIG_PINCTRL_MT7622 is not set +CONFIG_PINCTRL_MT7981=y CONFIG_PINCTRL_MT7986=y # CONFIG_PINCTRL_MT8173 is not set # CONFIG_PINCTRL_MT8183 is not set diff --git a/target/linux/mediatek/mt7622/config-5.15 b/target/linux/mediatek/mt7622/config-5.15 index 3168c2deda1..933de930990 100644 --- a/target/linux/mediatek/mt7622/config-5.15 +++ b/target/linux/mediatek/mt7622/config-5.15 @@ -333,6 +333,7 @@ CONFIG_PINCTRL=y # CONFIG_PINCTRL_MT6765 is not set # CONFIG_PINCTRL_MT6797 is not set CONFIG_PINCTRL_MT7622=y +# CONFIG_PINCTRL_MT7981 is not set # CONFIG_PINCTRL_MT7986 is not set # CONFIG_PINCTRL_MT8173 is not set # CONFIG_PINCTRL_MT8183 is not set diff --git a/target/linux/mediatek/patches-5.15/215-v6.3-pinctrl-mediatek-add-support-for-MT7981-SoC.patch b/target/linux/mediatek/patches-5.15/215-v6.3-pinctrl-mediatek-add-support-for-MT7981-SoC.patch new file mode 100644 index 00000000000..ae99685df4c --- /dev/null +++ b/target/linux/mediatek/patches-5.15/215-v6.3-pinctrl-mediatek-add-support-for-MT7981-SoC.patch @@ -0,0 +1,26 @@ +--- a/drivers/pinctrl/mediatek/Kconfig ++++ b/drivers/pinctrl/mediatek/Kconfig +@@ -120,6 +120,13 @@ config PINCTRL_MT7622 + default ARM64 && ARCH_MEDIATEK + select PINCTRL_MTK_MOORE + ++config PINCTRL_MT7981 ++ bool "Mediatek MT7981 pin control" ++ depends on OF ++ depends on ARM64 || COMPILE_TEST ++ default ARM64 && ARCH_MEDIATEK ++ select PINCTRL_MTK_MOORE ++ + config PINCTRL_MT7986 + bool "Mediatek MT7986 pin control" + depends on OF +--- a/drivers/pinctrl/mediatek/Makefile ++++ b/drivers/pinctrl/mediatek/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_MT6797) += pinctrl- + obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o + obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o + obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o ++obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7981.o + obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o + obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o + obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o From 18a3cd2062ebb8a914e7e5559e18ddb4735992e5 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 10 Mar 2023 19:41:51 +0000 Subject: [PATCH 39/53] generic: backport support for MT7981 Ethernet Backport support for the MT7981 SoC to mtk_eth_soc. Signed-off-by: Daniel Golle --- ...t-mtk_eth_soc-add-support-for-MT7981.patch | 183 ++++++++++++++++++ ..._eth_soc-add-code-for-offloading-flo.patch | 2 +- 2 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 target/linux/generic/backport-5.15/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch diff --git a/target/linux/generic/backport-5.15/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch b/target/linux/generic/backport-5.15/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch new file mode 100644 index 00000000000..bfa0df30534 --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch @@ -0,0 +1,183 @@ +--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c +@@ -96,12 +96,20 @@ static int set_mux_gmac2_gmac0_to_gephy( + + static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) + { +- unsigned int val = 0; ++ unsigned int val = 0, mask = 0, reg = 0; + bool updated = true; + + switch (path) { + case MTK_ETH_PATH_GMAC2_SGMII: +- val = CO_QPHY_SEL; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) { ++ reg = USB_PHY_SWITCH_REG; ++ val = SGMII_QPHY_SEL; ++ mask = QPHY_SEL_MASK; ++ } else { ++ reg = INFRA_MISC2; ++ val = CO_QPHY_SEL; ++ mask = val; ++ } + break; + default: + updated = false; +@@ -109,7 +117,7 @@ static int set_mux_u3_gmac2_to_qphy(stru + } + + if (updated) +- regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val); ++ regmap_update_bits(eth->infra, reg, mask, val); + + dev_dbg(eth->dev, "path %s in %s updated = %d\n", + mtk_eth_path_name(path), __func__, updated); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4757,6 +4757,26 @@ static const struct mtk_soc_data mt7629_ + }, + }; + ++static const struct mtk_soc_data mt7981_data = { ++ .reg_map = &mt7986_reg_map, ++ .ana_rgc3 = 0x128, ++ .caps = MT7981_CAPS, ++ .hw_features = MTK_HW_FEATURES, ++ .required_clks = MT7981_CLKS_BITMAP, ++ .required_pctl = false, ++ .offload_version = 2, ++ .hash_offset = 4, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma_v2), ++ .rxd_size = sizeof(struct mtk_rx_dma_v2), ++ .rx_irq_done_mask = MTK_RX_DONE_INT_V2, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID_V2, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, ++ .dma_len_offset = 8, ++ }, ++}; ++ + static const struct mtk_soc_data mt7986_data = { + .reg_map = &mt7986_reg_map, + .ana_rgc3 = 0x128, +@@ -4799,6 +4819,7 @@ const struct of_device_id of_mtk_match[] + { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, + { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, + { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, ++ { .compatible = "mediatek,mt7981-eth", .data = &mt7981_data}, + { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data}, + { .compatible = "ralink,rt5350-eth", .data = &rt5350_data}, + {}, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -553,11 +553,22 @@ + #define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 + #define SGMII_PHYA_PWD BIT(4) + ++/* Register to QPHY wrapper control */ ++#define SGMSYS_QPHY_WRAP_CTRL 0xec ++#define SGMII_PN_SWAP_MASK GENMASK(1, 0) ++#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) ++#define MTK_SGMII_FLAG_PN_SWAP BIT(0) ++ + /* Infrasys subsystem config registers */ + #define INFRA_MISC2 0x70c + #define CO_QPHY_SEL BIT(0) + #define GEPHY_MAC_SEL BIT(1) + ++/* Top misc registers */ ++#define USB_PHY_SWITCH_REG 0x218 ++#define QPHY_SEL_MASK GENMASK(1, 0) ++#define SGMII_QPHY_SEL 0x2 ++ + /* MT7628/88 specific stuff */ + #define MT7628_PDMA_OFFSET 0x0800 + #define MT7628_SDM_OFFSET 0x0c00 +@@ -738,6 +749,17 @@ enum mtk_clks_map { + BIT(MTK_CLK_SGMII2_CDR_FB) | \ + BIT(MTK_CLK_SGMII_CK) | \ + BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) ++#define MT7981_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ ++ BIT(MTK_CLK_WOCPU0) | \ ++ BIT(MTK_CLK_SGMII_TX_250M) | \ ++ BIT(MTK_CLK_SGMII_RX_250M) | \ ++ BIT(MTK_CLK_SGMII_CDR_REF) | \ ++ BIT(MTK_CLK_SGMII_CDR_FB) | \ ++ BIT(MTK_CLK_SGMII2_TX_250M) | \ ++ BIT(MTK_CLK_SGMII2_RX_250M) | \ ++ BIT(MTK_CLK_SGMII2_CDR_REF) | \ ++ BIT(MTK_CLK_SGMII2_CDR_FB) | \ ++ BIT(MTK_CLK_SGMII_CK)) + #define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ + BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \ + BIT(MTK_CLK_SGMII_TX_250M) | \ +@@ -851,6 +873,7 @@ enum mkt_eth_capabilities { + MTK_NETSYS_V2_BIT, + MTK_SOC_MT7628_BIT, + MTK_RSTCTRL_PPE1_BIT, ++ MTK_U3_COPHY_V2_BIT, + + /* MUX BITS*/ + MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, +@@ -885,6 +908,7 @@ enum mkt_eth_capabilities { + #define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) + #define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) + #define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) ++#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT) + + #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ + BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) +@@ -963,6 +987,11 @@ enum mkt_eth_capabilities { + MTK_MUX_U3_GMAC2_TO_QPHY | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) + ++#define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ ++ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ ++ MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \ ++ MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) ++ + #define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ + MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) +@@ -1076,12 +1105,14 @@ struct mtk_soc_data { + * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap + * @interface: Currently configured interface mode + * @pcs: Phylink PCS structure ++ * @flags: Flags indicating hardware properties + */ + struct mtk_pcs { + struct regmap *regmap; + u32 ana_rgc3; + phy_interface_t interface; + struct phylink_pcs pcs; ++ u32 flags; + }; + + /* struct mtk_sgmii - This is the structure holding sgmii regmap and its +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -87,6 +87,11 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, SGMII_PHYA_PWD); + ++ if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP) ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, ++ SGMII_PN_SWAP_MASK, ++ SGMII_PN_SWAP_TX_RX); ++ + /* Reset SGMII PCS state */ + regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0, + SGMII_SW_RESET, SGMII_SW_RESET); +@@ -186,6 +191,11 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + + ss->pcs[i].ana_rgc3 = ana_rgc3; + ss->pcs[i].regmap = syscon_node_to_regmap(np); ++ ++ ss->pcs[i].flags = 0; ++ if (of_property_read_bool(np, "mediatek,pnswap")) ++ ss->pcs[i].flags |= MTK_SGMII_FLAG_PN_SWAP; ++ + of_node_put(np); + if (IS_ERR(ss->pcs[i].regmap)) + return PTR_ERR(ss->pcs[i].regmap); diff --git a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch index 4017e2beac8..0a7f6706553 100644 --- a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch +++ b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1326,6 +1326,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk +@@ -1357,6 +1357,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk int mtk_eth_offload_init(struct mtk_eth *eth); int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data); From a438a805ebe3f1aa6f25e31ee2152c60e3223343 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 10 Mar 2023 19:44:52 +0000 Subject: [PATCH 40/53] mediatek: add support for built-in GE PHYs of newer SoCs MT7981 and the upcoming MT7988 have built-in Gigabit Ethernet PHYs. While they share some design properties with the PHYs present in MT753x, they do need calibration data from the SoC's efuse. Add driver to support them. Upstreaming it is planned, but there are still some ongoing discussions with MediaTek. Signed-off-by: Daniel Golle --- target/linux/mediatek/filogic/config-5.15 | 1 + target/linux/mediatek/mt7622/config-5.15 | 1 + target/linux/mediatek/mt7623/config-5.15 | 1 + ...er-for-MediaTek-SoC-built-in-GE-PHYs.patch | 1443 +++++++++++++++++ 4 files changed, 1446 insertions(+) create mode 100644 target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch diff --git a/target/linux/mediatek/filogic/config-5.15 b/target/linux/mediatek/filogic/config-5.15 index 7e91f070658..ef528818b36 100644 --- a/target/linux/mediatek/filogic/config-5.15 +++ b/target/linux/mediatek/filogic/config-5.15 @@ -206,6 +206,7 @@ CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVRES=y CONFIG_MEDIATEK_GE_PHY=y +CONFIG_MEDIATEK_GE_PHY_SOC=y CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEMFD_CREATE=y CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7 diff --git a/target/linux/mediatek/mt7622/config-5.15 b/target/linux/mediatek/mt7622/config-5.15 index 933de930990..14a0bec31a5 100644 --- a/target/linux/mediatek/mt7622/config-5.15 +++ b/target/linux/mediatek/mt7622/config-5.15 @@ -232,6 +232,7 @@ CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVRES=y CONFIG_MEDIATEK_GE_PHY=y +# CONFIG_MEDIATEK_GE_PHY_SOC is not set CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEMFD_CREATE=y CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7 diff --git a/target/linux/mediatek/mt7623/config-5.15 b/target/linux/mediatek/mt7623/config-5.15 index 26d037ff003..fa99dd50bb0 100644 --- a/target/linux/mediatek/mt7623/config-5.15 +++ b/target/linux/mediatek/mt7623/config-5.15 @@ -321,6 +321,7 @@ CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVRES=y CONFIG_MDIO_GPIO=y CONFIG_MEDIATEK_GE_PHY=y +# CONFIG_MEDIATEK_GE_PHY_SOC is not set CONFIG_MEDIATEK_MT6577_AUXADC=y CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEMFD_CREATE=y diff --git a/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch b/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch new file mode 100644 index 00000000000..4909d9e9229 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch @@ -0,0 +1,1443 @@ +From a6f143af419bfc3f52d82e88ac033d9833e720af Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 13 Feb 2023 02:33:14 +0000 +Subject: [PATCH] net: phy: add driver for MediaTek SoC built-in GE PHYs + +Some of MediaTek's Filogic SoCs come with built-in gigabit Ethernet +PHYs which require calibration data from the SoC's efuse. +Add support for these PHYs to the mediatek-ge driver if built for +MediaTek's ARM64 SoCs. + +Signed-off-by: Daniel Golle +--- + MAINTAINERS | 8 + + drivers/net/phy/Kconfig | 12 + + drivers/net/phy/mediatek-ge.c | 1351 +++++++++++++++++++++++++++++++++ + 3 files changed, 1371 insertions(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -11790,6 +11790,14 @@ L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/ethernet/mediatek/ + ++MEDIATEK ETHERNET PHY DRIVERS ++M: Daniel Golle ++M: Qingfang Deng ++M: SkyLake Huang ++L: netdev@vger.kernel.org ++S: Maintained ++F: drivers/net/phy/mediatek-ge.c ++ + MEDIATEK I2C CONTROLLER DRIVER + M: Qii Wang + L: linux-i2c@vger.kernel.org +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -292,6 +292,18 @@ config MEDIATEK_GE_PHY + help + Supports the MediaTek Gigabit Ethernet PHYs. + ++config MEDIATEK_GE_PHY_SOC ++ bool "MediaTek SoC Ethernet PHYs" ++ depends on (ARM64 && ARCH_MEDIATEK && MEDIATEK_GE_PHY) || COMPILE_TEST ++ select NVMEM_MTK_EFUSE ++ help ++ Supports MediaTek SoC built-in Gigabit Ethernet PHYs. ++ ++ Include support for built-in Ethernet PHYs which are present in ++ the MT7981 and MT7988 SoCs. These PHYs need calibration data ++ present in the SoCs efuse and will dynamically calibrate VCM ++ (common-mode voltage) during startup. ++ + config MICREL_PHY + tristate "Micrel PHYs" + help +--- a/drivers/net/phy/mediatek-ge.c ++++ b/drivers/net/phy/mediatek-ge.c +@@ -1,6 +1,9 @@ + // SPDX-License-Identifier: GPL-2.0+ + #include + #include ++#include ++#include ++#include + #include + + #define MTK_EXT_PAGE_ACCESS 0x1f +@@ -11,6 +14,275 @@ + #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 + #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + ++#define ANALOG_INTERNAL_OPERATION_MAX_US (20) ++#define ZCAL_CTRL_MIN (0) ++#define ZCAL_CTRL_MAX (63) ++#define TXRESERVE_MIN (0) ++#define TXRESERVE_MAX (7) ++ ++#define MTK_PHY_ANARG_RG (0x10) ++#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8) ++ ++/* Registers on MDIO_MMD_VEND1 */ ++enum { ++ MTK_PHY_MIDDLE_LEVEL_SHAPPER_0TO1 = 0, ++ MTK_PHY_1st_OVERSHOOT_LEVEL_0TO1, ++ MTK_PHY_2nd_OVERSHOOT_LEVEL_0TO1, ++ MTK_PHY_MIDDLE_LEVEL_SHAPPER_1TO0, ++ MTK_PHY_1st_OVERSHOOT_LEVEL_1TO0, ++ MTK_PHY_2nd_OVERSHOOT_LEVEL_1TO0, ++ MTK_PHY_MIDDLE_LEVEL_SHAPPER_0TON1, /* N means negative */ ++ MTK_PHY_1st_OVERSHOOT_LEVEL_0TON1, ++ MTK_PHY_2nd_OVERSHOOT_LEVEL_0TON1, ++ MTK_PHY_MIDDLE_LEVEL_SHAPPER_N1TO0, ++ MTK_PHY_1st_OVERSHOOT_LEVEL_N1TO0, ++ MTK_PHY_2nd_OVERSHOOT_LEVEL_N1TO0, ++ MTK_PHY_TX_MLT3_END, ++}; ++ ++#define MTK_PHY_TXVLD_DA_RG (0x12) ++#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10) ++#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 (0x16) ++#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10) ++#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 (0x17) ++#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8) ++#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 (0x18) ++#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8) ++#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 (0x19) ++#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8) ++#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 (0x20) ++#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8) ++#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 (0x21) ++#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8) ++#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 (0x22) ++#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8) ++#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_TANA_CAL_MODE (0xc1) ++#define MTK_PHY_TANA_CAL_MODE_SHIFT (8) ++ ++#define MTK_PHY_RXADC_CTRL_RG7 (0xc6) ++#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) ++ ++#define MTK_PHY_RXADC_CTRL_RG9 (0xc8) ++#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12) ++#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8) ++#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4) ++#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0) ++ ++#define MTK_PHY_LDO_OUTPUT_V (0xd7) ++ ++#define MTK_PHY_RG_ANA_CAL_RG0 (0xdb) ++#define MTK_PHY_RG_CAL_CKINV BIT(12) ++#define MTK_PHY_RG_ANA_CALEN BIT(8) ++#define MTK_PHY_RG_REXT_CALEN BIT(4) ++#define MTK_PHY_RG_ZCALEN_A BIT(0) ++ ++#define MTK_PHY_RG_ANA_CAL_RG1 (0xdc) ++#define MTK_PHY_RG_ZCALEN_B BIT(12) ++#define MTK_PHY_RG_ZCALEN_C BIT(8) ++#define MTK_PHY_RG_ZCALEN_D BIT(4) ++#define MTK_PHY_RG_TXVOS_CALEN BIT(0) ++ ++#define MTK_PHY_RG_ANA_CAL_RG2 (0xdd) ++#define MTK_PHY_RG_TXG_CALEN_A BIT(12) ++#define MTK_PHY_RG_TXG_CALEN_B BIT(8) ++#define MTK_PHY_RG_TXG_CALEN_C BIT(4) ++#define MTK_PHY_RG_TXG_CALEN_D BIT(0) ++ ++#define MTK_PHY_RG_ANA_CAL_RG5 (0xe0) ++#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8) ++#define MTK_PHY_RG_ZCAL_CTRL_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_RG_TX_FILTER (0xfe) ++ ++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B (0x172) ++#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8) ++#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0) ++ ++#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D (0x173) ++#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8) ++#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) ++ ++#define MTK_PHY_RG_AD_CAL_COMP (0x17a) ++#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) ++ ++#define MTK_PHY_RG_AD_CAL_CLK (0x17b) ++#define MTK_PHY_DA_CAL_CLK BIT(0) ++ ++#define MTK_PHY_RG_AD_CALIN (0x17c) ++#define MTK_PHY_DA_CALIN_FLAG BIT(0) ++ ++#define MTK_PHY_RG_DASN_DAC_IN0_A (0x17d) ++#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0) ++ ++#define MTK_PHY_RG_DASN_DAC_IN0_B (0x17e) ++#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0) ++ ++#define MTK_PHY_RG_DASN_DAC_IN0_C (0x17f) ++#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0) ++ ++#define MTK_PHY_RG_DASN_DAC_IN0_D (0x180) ++#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0) ++ ++#define MTK_PHY_RG_DASN_DAC_IN1_A (0x181) ++#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0) ++ ++#define MTK_PHY_RG_DASN_DAC_IN1_B (0x182) ++#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0) ++ ++#define MTK_PHY_RG_DASN_DAC_IN1_C (0x183) ++#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0) ++ ++#define MTK_PHY_RG_DASN_DAC_IN1_D (0x180) ++#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0) ++ ++#define MTK_PHY_RG_LP_IIR2_K1_L (0x22a) ++#define MTK_PHY_RG_LP_IIR2_K1_U (0x22b) ++#define MTK_PHY_RG_LP_IIR2_K2_L (0x22c) ++#define MTK_PHY_RG_LP_IIR2_K2_U (0x22d) ++#define MTK_PHY_RG_LP_IIR2_K3_L (0x22e) ++#define MTK_PHY_RG_LP_IIR2_K3_U (0x22f) ++#define MTK_PHY_RG_LP_IIR2_K4_L (0x230) ++#define MTK_PHY_RG_LP_IIR2_K4_U (0x231) ++#define MTK_PHY_RG_LP_IIR2_K5_L (0x232) ++#define MTK_PHY_RG_LP_IIR2_K5_U (0x233) ++ ++#define MTK_PHY_RG_DEV1E_REG234 (0x234) ++#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0) ++#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4) ++ ++#define MTK_PHY_RG_LPF_CNT_VAL (0x235) ++ ++#define MTK_PHY_RG_DEV1E_REG27C (0x27c) ++#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8) ++#define MTK_PHY_RG_DEV1E_REG27D (0x27d) ++#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0) ++ ++#define MTK_PHY_LDO_PUMP_EN_PAIRAB (0x502) ++#define MTK_PHY_LDO_PUMP_EN_PAIRCD (0x503) ++ ++#define MTK_PHY_DA_TX_R50_PAIR_A (0x53d) ++#define MTK_PHY_DA_TX_R50_PAIR_B (0x53e) ++#define MTK_PHY_DA_TX_R50_PAIR_C (0x53f) ++#define MTK_PHY_DA_TX_R50_PAIR_D (0x540) ++ ++/* Registers on MDIO_MMD_VEND2 */ ++#define MTK_PHY_LED0_ON_CTRL (0x24) ++#define MTK_PHY_LED0_ON_MASK GENMASK(6, 0) ++#define MTK_PHY_LED0_ON_LINK1000 BIT(0) ++#define MTK_PHY_LED0_ON_LINK100 BIT(1) ++#define MTK_PHY_LED0_ON_LINK10 BIT(2) ++#define MTK_PHY_LED0_ON_LINKDOWN BIT(3) ++#define MTK_PHY_LED0_ON_FDX BIT(4) /* Full duplex */ ++#define MTK_PHY_LED0_ON_HDX BIT(5) /* Half duplex */ ++#define MTK_PHY_LED0_FORCE_ON BIT(6) ++#define MTK_PHY_LED0_POLARITY BIT(14) ++#define MTK_PHY_LED0_ENABLE BIT(15) ++ ++#define MTK_PHY_LED0_BLINK_CTRL (0x25) ++#define MTK_PHY_LED0_1000TX BIT(0) ++#define MTK_PHY_LED0_1000RX BIT(1) ++#define MTK_PHY_LED0_100TX BIT(2) ++#define MTK_PHY_LED0_100RX BIT(3) ++#define MTK_PHY_LED0_10TX BIT(4) ++#define MTK_PHY_LED0_10RX BIT(5) ++#define MTK_PHY_LED0_COLLISION BIT(6) ++#define MTK_PHY_LED0_RX_CRC_ERR BIT(7) ++#define MTK_PHY_LED0_RX_IDLE_ERR BIT(8) ++#define MTK_PHY_LED0_FORCE_BLINK BIT(9) ++ ++#define MTK_PHY_ANA_TEST_BUS_CTRL_RG (0x100) ++#define MTK_PHY_ANA_TEST_MODE_MASK GENMASK(15, 8) ++ ++#define MTK_PHY_RG_DASN_TXT_DMY2 (0x110) ++#define MTK_PHY_TST_DMY2_MASK GENMASK(5, 0) ++ ++#define MTK_PHY_RG_BG_RASEL (0x115) ++#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0) ++ ++/* These macro privides efuse parsing for internal phy. */ ++#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0)) ++#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0)) ++#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0)) ++#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0)) ++#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0)) ++ ++#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0)) ++#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0)) ++#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0)) ++#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0)) ++#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0)) ++ ++#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0)) ++#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0)) ++#define EFS_DA_TX_R50_A_10M(x) (((x) >> 12) & GENMASK(5, 0)) ++#define EFS_DA_TX_R50_B_10M(x) (((x) >> 18) & GENMASK(5, 0)) ++ ++#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0)) ++#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0)) ++ ++enum { ++ NO_PAIR, ++ PAIR_A, ++ PAIR_B, ++ PAIR_C, ++ PAIR_D, ++}; ++ ++enum { ++ GPHY_PORT0, ++ GPHY_PORT1, ++ GPHY_PORT2, ++ GPHY_PORT3, ++}; ++ ++enum calibration_mode { ++ EFUSE_K, ++ SW_K ++}; ++ ++enum CAL_ITEM { ++ REXT, ++ TX_OFFSET, ++ TX_AMP, ++ TX_R50, ++ TX_VCM ++}; ++ ++enum CAL_MODE { ++ SW_EFUSE_M, ++ EFUSE_M, ++ SW_M ++}; ++ ++const u8 mt798x_zcal_to_r50[64] = { ++ 7, 8, 9, 9, 10, 10, 11, 11, ++ 12, 13, 13, 14, 14, 15, 16, 16, ++ 17, 18, 18, 19, 20, 21, 21, 22, ++ 23, 24, 24, 25, 26, 27, 28, 29, ++ 30, 31, 32, 33, 34, 35, 36, 37, ++ 38, 40, 41, 42, 43, 45, 46, 48, ++ 49, 51, 52, 54, 55, 57, 59, 61, ++ 62, 63, 63, 63, 63, 63, 63, 63 ++}; ++ ++const char pair[4] = {'A', 'B', 'C', 'D'}; ++ + static int mtk_gephy_read_page(struct phy_device *phydev) + { + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +@@ -68,6 +340,1059 @@ static int mt7531_phy_config_init(struct + return 0; + } + ++#ifdef CONFIG_MEDIATEK_GE_PHY_SOC ++/* One calibration cycle consists of: ++ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high ++ * until AD_CAL_COMP is ready to output calibration result. ++ * 2.Wait until DA_CAL_CLK is available. ++ * 3.Fetch AD_CAL_COMP_OUT. ++ */ ++static int cal_cycle(struct phy_device *phydev, int devad, ++ u32 regnum, u16 mask, u16 cal_val) ++{ ++ unsigned long timeout; ++ int reg_val; ++ int ret; ++ ++ phy_modify_mmd(phydev, devad, regnum, ++ mask, cal_val); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, ++ MTK_PHY_DA_CALIN_FLAG); ++ ++ timeout = jiffies + usecs_to_jiffies(ANALOG_INTERNAL_OPERATION_MAX_US); ++ do { ++ reg_val = phy_read_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_AD_CAL_CLK); ++ } while (time_before(jiffies, timeout) && !(reg_val & BIT(0))); ++ ++ if (!(reg_val & BIT(0))) { ++ dev_err(&phydev->mdio.dev, "Calibration cycle timeout\n"); ++ return -ETIMEDOUT; ++ } ++ ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, ++ MTK_PHY_DA_CALIN_FLAG); ++ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >> ++ MTK_PHY_AD_CAL_COMP_OUT_SHIFT; ++ dev_dbg(&phydev->mdio.dev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); ++ ++ return ret; ++} ++ ++static int rext_fill_result(struct phy_device *phydev, u16 *buf) ++{ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL, ++ MTK_PHY_RG_BG_RASEL_MASK, buf[1]); ++ ++ return 0; ++} ++ ++static int rext_cal_efuse(struct phy_device *phydev, u32 *buf) ++{ ++ u16 rext_cal_val[2]; ++ ++ rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]); ++ rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]); ++ rext_fill_result(phydev, rext_cal_val); ++ ++ return 0; ++} ++ ++static int rext_cal_sw(struct phy_device *phydev) ++{ ++ u8 rg_zcal_ctrl_def; ++ u8 zcal_lower, zcal_upper, rg_zcal_ctrl; ++ u8 lower_ret, upper_ret; ++ u16 rext_cal_val[2]; ++ int ret; ++ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, ++ MTK_PHY_ANA_TEST_MODE_MASK, MTK_PHY_TANA_CAL_MODE << 8); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, ++ MTK_PHY_RG_TXVOS_CALEN); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN | ++ MTK_PHY_RG_REXT_CALEN); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DASN_TXT_DMY2, ++ MTK_PHY_TST_DMY2_MASK, 0x1); ++ ++ rg_zcal_ctrl_def = phy_read_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG5) & ++ MTK_PHY_RG_ZCAL_CTRL_MASK; ++ zcal_lower = ZCAL_CTRL_MIN; ++ zcal_upper = ZCAL_CTRL_MAX; ++ ++ dev_dbg(&phydev->mdio.dev, "Start REXT SW cal.\n"); ++ while ((zcal_upper - zcal_lower) > 1) { ++ rg_zcal_ctrl = DIV_ROUND_CLOSEST(zcal_lower + zcal_upper, 2); ++ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl); ++ if (ret == 1) { ++ zcal_upper = rg_zcal_ctrl; ++ upper_ret = ret; ++ } else if (ret == 0) { ++ zcal_lower = rg_zcal_ctrl; ++ lower_ret = ret; ++ } else { ++ goto restore; ++ } ++ } ++ ++ if (zcal_lower == ZCAL_CTRL_MIN) { ++ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_lower); ++ ret = lower_ret; ++ } else if (zcal_upper == ZCAL_CTRL_MAX) { ++ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_upper); ++ ret = upper_ret; ++ } ++ if (ret < 0) ++ goto restore; ++ ++ ret = upper_ret - lower_ret; ++ if (ret == 1) { ++ rext_cal_val[0] = zcal_upper; ++ rext_cal_val[1] = zcal_upper >> 3; ++ rext_fill_result(phydev, rext_cal_val); ++ dev_info(&phydev->mdio.dev, "REXT SW cal result: 0x%x\n", ++ zcal_upper); ++ ret = 0; ++ } else { ++ ret = -EINVAL; ++ } ++ ++restore: ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, ++ MTK_PHY_ANA_TEST_BUS_CTRL_RG, ++ MTK_PHY_ANA_TEST_MODE_MASK); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN | ++ MTK_PHY_RG_REXT_CALEN); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DASN_TXT_DMY2, ++ MTK_PHY_TST_DMY2_MASK); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl_def); ++ ++ return ret; ++} ++ ++static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf) ++{ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, ++ MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, ++ MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, ++ MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, ++ MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]); ++ ++ return 0; ++} ++ ++static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) ++{ ++ u16 tx_offset_cal_val[4]; ++ ++ tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]); ++ tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]); ++ tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]); ++ tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]); ++ ++ tx_offset_fill_result(phydev, tx_offset_cal_val); ++ ++ return 0; ++} ++ ++static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) ++{ ++ int i; ++ int bias[16] = {0}; ++ const int vals_9461[16] = { 7, 1, 4, 7, ++ 7, 1, 4, 7, ++ 7, 1, 4, 7, ++ 7, 1, 4, 7 }; ++ const int vals_9481[16] = { 10, 6, 6, 10, ++ 10, 6, 6, 10, ++ 10, 6, 6, 10, ++ 10, 6, 6, 10 }; ++ ++ switch (phydev->drv->phy_id) { ++ case 0x03a29461: ++ /* We add some calibration to efuse values ++ * due to board level influence. ++ * GBE: +7, TBT: +1, HBT: +4, TST: +7 ++ */ ++ memcpy(bias, (const void *)vals_9461, sizeof(bias)); ++ for (i = 0; i <= 12; i += 4) { ++ if (likely(buf[i >> 2] + bias[i] >= 32)) { ++ bias[i] -= 13; ++ } else { ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, ++ 0x5c, 0x7 << i, bias[i] << i); ++ bias[i + 1] += 13; ++ bias[i + 2] += 13; ++ bias[i + 3] += 13; ++ } ++ } ++ break; ++ case 0x03a29481: ++ memcpy(bias, (const void *)vals_9481, sizeof(bias)); ++ break; ++ default: ++ break; ++ } ++ ++ /* Prevent overflow */ ++ for (i = 0; i < 12; i++) { ++ if (buf[i >> 2] + bias[i] > 63) { ++ buf[i >> 2] = 63; ++ bias[i] = 0; ++ } else if (buf[i >> 2] + bias[i] < 0) { ++ /* Bias caused by board design may change in the future. ++ * So check negative cases, too. ++ */ ++ buf[i >> 2] = 0; ++ bias[i] = 0; ++ } ++ } ++ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, ++ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, ++ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, ++ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, ++ MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]); ++ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, ++ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, ++ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, ++ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, ++ MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]); ++ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, ++ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, ++ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, ++ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, ++ MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]); ++ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, ++ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, ++ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, ++ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, ++ MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]); ++ ++ return 0; ++} ++ ++static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf) ++{ ++ u16 tx_amp_cal_val[4]; ++ ++ tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]); ++ tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]); ++ tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]); ++ tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]); ++ tx_amp_fill_result(phydev, tx_amp_cal_val); ++ ++ return 0; ++} ++ ++static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val, ++ u8 txg_calen_x) ++{ ++ int bias = 0; ++ u16 reg, val; ++ ++ switch (phydev->drv->phy_id) { ++ case 0x03a29481: ++ { ++ bias = -2; ++ break; ++ } ++ /* 0x03a29461 enters default case */ ++ default: ++ break; ++ } ++ ++ val = clamp_val(bias + tx_r50_cal_val, 0, 63); ++ ++ switch (txg_calen_x) { ++ case PAIR_A: ++ reg = MTK_PHY_DA_TX_R50_PAIR_A; ++ break; ++ case PAIR_B: ++ reg = MTK_PHY_DA_TX_R50_PAIR_B; ++ break; ++ case PAIR_C: ++ reg = MTK_PHY_DA_TX_R50_PAIR_C; ++ break; ++ case PAIR_D: ++ reg = MTK_PHY_DA_TX_R50_PAIR_D; ++ break; ++ } ++ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8); ++ ++ return 0; ++} ++ ++static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf, ++ u8 txg_calen_x) ++{ ++ u16 tx_r50_cal_val; ++ ++ switch (txg_calen_x) { ++ case PAIR_A: ++ tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]); ++ break; ++ case PAIR_B: ++ tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]); ++ break; ++ case PAIR_C: ++ tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]); ++ break; ++ case PAIR_D: ++ tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]); ++ break; ++ } ++ tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); ++ ++ return 0; ++} ++ ++static int tx_r50_cal_sw(struct phy_device *phydev, u8 txg_calen_x) ++{ ++ u8 zcal_lower, zcal_upper, rg_zcal_ctrl; ++ u8 lower_ret, upper_ret; ++ u8 rg_zcal_ctrl_def; ++ u16 tx_r50_cal_val; ++ int ret; ++ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, ++ MTK_PHY_ANA_TEST_MODE_MASK, MTK_PHY_TANA_CAL_MODE << 8); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, ++ MTK_PHY_RG_TXVOS_CALEN); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG2, ++ BIT(txg_calen_x * 4)); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DASN_TXT_DMY2, ++ MTK_PHY_TST_DMY2_MASK, 0x1); ++ ++ rg_zcal_ctrl_def = phy_read_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG5) & ++ MTK_PHY_RG_ZCAL_CTRL_MASK; ++ zcal_lower = ZCAL_CTRL_MIN; ++ zcal_upper = ZCAL_CTRL_MAX; ++ ++ dev_dbg(&phydev->mdio.dev, "Start TX-R50 Pair%c SW cal.\n", ++ pair[txg_calen_x]); ++ while ((zcal_upper - zcal_lower) > 1) { ++ rg_zcal_ctrl = DIV_ROUND_CLOSEST(zcal_lower + zcal_upper, 2); ++ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl); ++ if (ret == 1) { ++ zcal_upper = rg_zcal_ctrl; ++ upper_ret = ret; ++ } else if (ret == 0) { ++ zcal_lower = rg_zcal_ctrl; ++ lower_ret = ret; ++ } else { ++ goto restore; ++ } ++ } ++ ++ if (zcal_lower == ZCAL_CTRL_MIN) { ++ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_lower); ++ ret = lower_ret; ++ } else if (zcal_upper == ZCAL_CTRL_MAX) { ++ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_upper); ++ ret = upper_ret; ++ } ++ if (ret < 0) ++ goto restore; ++ ++ ret = upper_ret - lower_ret; ++ if (ret == 1) { ++ tx_r50_cal_val = mt798x_zcal_to_r50[zcal_upper]; ++ tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); ++ dev_info(&phydev->mdio.dev, ++ "TX-R50 Pair%c SW cal result: 0x%x\n", ++ pair[txg_calen_x], zcal_lower); ++ ret = 0; ++ } else { ++ ret = -EINVAL; ++ } ++ ++restore: ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, ++ MTK_PHY_ANA_TEST_MODE_MASK); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG2, ++ BIT(txg_calen_x * 4)); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DASN_TXT_DMY2, ++ MTK_PHY_TST_DMY2_MASK); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, ++ MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl_def); ++ ++ return ret; ++} ++ ++static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) ++{ ++ u8 lower_idx, upper_idx, txreserve_val; ++ u8 lower_ret, upper_ret; ++ int ret; ++ ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_ANA_CALEN); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_CAL_CKINV); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, ++ MTK_PHY_RG_TXVOS_CALEN); ++ ++ switch (rg_txreserve_x) { ++ case PAIR_A: ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_DASN_DAC_IN0_A, ++ MTK_PHY_DASN_DAC_IN0_A_MASK); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_DASN_DAC_IN1_A, ++ MTK_PHY_DASN_DAC_IN1_A_MASK); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_ZCALEN_A); ++ break; ++ case PAIR_B: ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_DASN_DAC_IN0_B, ++ MTK_PHY_DASN_DAC_IN0_B_MASK); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_DASN_DAC_IN1_B, ++ MTK_PHY_DASN_DAC_IN1_B_MASK); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG1, ++ MTK_PHY_RG_ZCALEN_B); ++ break; ++ case PAIR_C: ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_DASN_DAC_IN0_C, ++ MTK_PHY_DASN_DAC_IN0_C_MASK); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_DASN_DAC_IN1_C, ++ MTK_PHY_DASN_DAC_IN1_C_MASK); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG1, ++ MTK_PHY_RG_ZCALEN_C); ++ break; ++ case PAIR_D: ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_DASN_DAC_IN0_D, ++ MTK_PHY_DASN_DAC_IN0_D_MASK); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_DASN_DAC_IN1_D, ++ MTK_PHY_DASN_DAC_IN1_D_MASK); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RG_ANA_CAL_RG1, ++ MTK_PHY_RG_ZCALEN_D); ++ break; ++ default: ++ ret = -EINVAL; ++ goto restore; ++ } ++ ++ lower_idx = TXRESERVE_MIN; ++ upper_idx = TXRESERVE_MAX; ++ ++ dev_dbg(&phydev->mdio.dev, "Start TX-VCM SW cal.\n"); ++ while ((upper_idx - lower_idx) > 1) { ++ txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2); ++ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, ++ MTK_PHY_DA_RX_PSBN_TBT_MASK | ++ MTK_PHY_DA_RX_PSBN_HBT_MASK | ++ MTK_PHY_DA_RX_PSBN_GBE_MASK | ++ MTK_PHY_DA_RX_PSBN_LP_MASK, ++ txreserve_val << 12 | txreserve_val << 8 | ++ txreserve_val << 4 | txreserve_val); ++ if (ret == 1) { ++ upper_idx = txreserve_val; ++ upper_ret = ret; ++ } else if (ret == 0) { ++ lower_idx = txreserve_val; ++ lower_ret = ret; ++ } else { ++ goto restore; ++ } ++ } ++ ++ if (lower_idx == TXRESERVE_MIN) { ++ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RXADC_CTRL_RG9, ++ MTK_PHY_DA_RX_PSBN_TBT_MASK | ++ MTK_PHY_DA_RX_PSBN_HBT_MASK | ++ MTK_PHY_DA_RX_PSBN_GBE_MASK | ++ MTK_PHY_DA_RX_PSBN_LP_MASK, ++ lower_idx << 12 | lower_idx << 8 | ++ lower_idx << 4 | lower_idx); ++ ret = lower_ret; ++ } else if (upper_idx == TXRESERVE_MAX) { ++ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, ++ MTK_PHY_RXADC_CTRL_RG9, ++ MTK_PHY_DA_RX_PSBN_TBT_MASK | ++ MTK_PHY_DA_RX_PSBN_HBT_MASK | ++ MTK_PHY_DA_RX_PSBN_GBE_MASK | ++ MTK_PHY_DA_RX_PSBN_LP_MASK, ++ upper_idx << 12 | upper_idx << 8 | ++ upper_idx << 4 | upper_idx); ++ ret = upper_ret; ++ } ++ if (ret < 0) ++ goto restore; ++ ++ /* We calibrate TX-VCM in different logic. Check upper index and then ++ * lower index. If this calibration is valid, apply lower index's result. ++ */ ++ ret = upper_ret - lower_ret; ++ if (ret == 1) { ++ ret = 0; ++ /* Make sure we use upper_idx in our calibration system */ ++ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, ++ MTK_PHY_DA_RX_PSBN_TBT_MASK | ++ MTK_PHY_DA_RX_PSBN_HBT_MASK | ++ MTK_PHY_DA_RX_PSBN_GBE_MASK | ++ MTK_PHY_DA_RX_PSBN_LP_MASK, ++ upper_idx << 12 | upper_idx << 8 | ++ upper_idx << 4 | upper_idx); ++ dev_info(&phydev->mdio.dev, "TX-VCM SW cal result: 0x%x\n", ++ upper_idx); ++ } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && ++ lower_ret == 1) { ++ ret = 0; ++ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, ++ MTK_PHY_DA_RX_PSBN_TBT_MASK | ++ MTK_PHY_DA_RX_PSBN_HBT_MASK | ++ MTK_PHY_DA_RX_PSBN_GBE_MASK | ++ MTK_PHY_DA_RX_PSBN_LP_MASK, ++ lower_idx << 12 | lower_idx << 8 | ++ lower_idx << 4 | lower_idx); ++ dev_warn(&phydev->mdio.dev, ++ "TX-VCM SW cal result at low margin 0x%x\n", ++ lower_idx); ++ } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && ++ lower_ret == 0) { ++ ret = 0; ++ dev_warn(&phydev->mdio.dev, ++ "TX-VCM SW cal result at high margin 0x%x\n", ++ upper_idx); ++ } else { ++ ret = -EINVAL; ++ } ++ ++restore: ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_ANA_CALEN); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, ++ MTK_PHY_RG_TXVOS_CALEN); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, ++ MTK_PHY_RG_ZCALEN_A); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, ++ MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | ++ MTK_PHY_RG_ZCALEN_D); ++ ++ return ret; ++} ++ ++static inline void mt7981_phy_finetune(struct phy_device *phydev) ++{ ++ u32 i; ++ ++ /* 100M eye finetune: ++ * Keep middle level of TX MLT3 shapper as default. ++ * Only change TX MLT3 overshoot level here. ++ */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_0TO1, ++ 0x1ce); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_0TO1, ++ 0x1c1); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_1TO0, ++ 0x20f); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_1TO0, ++ 0x202); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_0TON1, ++ 0x3d0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_0TON1, ++ 0x3c0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_N1TO0, ++ 0x13); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_N1TO0, ++ 0x5); ++ ++ /* TX-AMP finetune: ++ * 100M +4, 1000M +6 to default value. ++ * If efuse values aren't valid, TX-AMP uses the below values. ++ */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, 0x9824); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, ++ 0x9026); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, ++ 0x2624); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, ++ 0x2426); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, ++ 0x2624); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, ++ 0x2426); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, ++ 0x2624); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, ++ 0x2426); ++ ++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); ++ /* EnabRandUpdTrig = 1 */ ++ __phy_write(phydev, 0x11, 0x2f00); ++ __phy_write(phydev, 0x12, 0xe); ++ __phy_write(phydev, 0x10, 0x8fb0); ++ ++ /* SlvDSPreadyTime = 0xc */ ++ __phy_write(phydev, 0x11, 0x671); ++ __phy_write(phydev, 0x12, 0xc); ++ __phy_write(phydev, 0x10, 0x8fae); ++ ++ /* NormMseLoThresh = 85 */ ++ __phy_write(phydev, 0x11, 0x55a0); ++ __phy_write(phydev, 0x12, 0x0); ++ __phy_write(phydev, 0x10, 0x83aa); ++ ++ /* InhibitDisableDfeTail1000 = 1 */ ++ __phy_write(phydev, 0x11, 0x2b); ++ __phy_write(phydev, 0x12, 0x0); ++ __phy_write(phydev, 0x10, 0x8f80); ++ ++ /* SSTr related */ ++ __phy_write(phydev, 0x11, 0xbaef); ++ __phy_write(phydev, 0x12, 0x2e); ++ __phy_write(phydev, 0x10, 0x968c); ++ ++ /* VcoSlicerThreshBitsHigh */ ++ __phy_write(phydev, 0x11, 0x5555); ++ __phy_write(phydev, 0x12, 0x55); ++ __phy_write(phydev, 0x10, 0x8ec0); ++ ++ /* ResetSyncOffset = 6 */ ++ __phy_write(phydev, 0x11, 0x600); ++ __phy_write(phydev, 0x12, 0x0); ++ __phy_write(phydev, 0x10, 0x8fc0); ++ ++ /* VgaDecRate = 1 */ ++ __phy_write(phydev, 0x11, 0x4c2a); ++ __phy_write(phydev, 0x12, 0x3e); ++ __phy_write(phydev, 0x10, 0x8fa4); ++ ++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); ++ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, ++ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, ++ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); ++ ++ /* rg_tr_lpf_cnt_val = 512 */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); ++ ++ /* IIR2 related */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); ++ ++ /* FFE peaking */ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, ++ MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, ++ MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); ++ ++ /* TX shape */ ++ /* 10/100/1000 TX shaper is enabled by default */ ++ for (i = 0x202; i < 0x230; i += 2) { ++ if (i == 0x20c || i == 0x218 || i == 0x224) ++ continue; ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, i, 0x2219); ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, i + 1, 0x23); ++ } ++} ++ ++static inline void mt7988_phy_finetune(struct phy_device *phydev) ++{ ++ u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182, ++ 0x020d, 0x0206, 0x0384, 0x03d0, ++ 0x03c6, 0x030a, 0x0011, 0x0005 }; ++ int i; ++ ++ for (i = 0; i < MTK_PHY_TX_MLT3_END; i++) ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]); ++ ++ /* TCT finetune */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); ++ ++ /* Disable TX power saving */ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, ++ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); ++ ++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); ++ /* EnabRandUpdTrig = 1 */ ++ __phy_write(phydev, 0x11, 0x2f00); ++ __phy_write(phydev, 0x12, 0xe); ++ __phy_write(phydev, 0x10, 0x8fb0); ++ ++ /* SlvDSPreadyTime = 0xc */ ++ __phy_write(phydev, 0x11, 0x671); ++ __phy_write(phydev, 0x12, 0xc); ++ __phy_write(phydev, 0x10, 0x8fae); ++ ++ /* NormMseLoThresh = 85 */ ++ __phy_write(phydev, 0x11, 0x55a0); ++ __phy_write(phydev, 0x12, 0x0); ++ __phy_write(phydev, 0x10, 0x83aa); ++ ++ /* InhibitDisableDfeTail1000 = 1 */ ++ __phy_write(phydev, 0x11, 0x2b); ++ __phy_write(phydev, 0x12, 0x0); ++ __phy_write(phydev, 0x10, 0x8f80); ++ ++ /* SSTr related */ ++ __phy_write(phydev, 0x11, 0xbaef); ++ __phy_write(phydev, 0x12, 0x2e); ++ __phy_write(phydev, 0x10, 0x968c); ++ ++ /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, ++ * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 ++ */ ++ __phy_write(phydev, 0x11, 0xd10a); ++ __phy_write(phydev, 0x12, 0x34); ++ __phy_write(phydev, 0x10, 0x8f82); ++ ++ /* VcoSlicerThreshBitsHigh */ ++ __phy_write(phydev, 0x11, 0x5555); ++ __phy_write(phydev, 0x12, 0x55); ++ __phy_write(phydev, 0x10, 0x8ec0); ++ ++ /* ResetSyncOffset = 5 */ ++ __phy_write(phydev, 0x11, 0x500); ++ __phy_write(phydev, 0x12, 0x0); ++ __phy_write(phydev, 0x10, 0x8fc0); ++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); ++ ++ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30); ++ /* TxClkOffset = 2 */ ++ __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK, ++ FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2)); ++ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); ++ ++ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, ++ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, ++ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); ++ ++ /* rg_tr_lpf_cnt_val = 512 */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); ++ ++ /* IIR2 related */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); ++ ++ /* FFE peaking */ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, ++ MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, ++ MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); ++ ++ /* TX shape */ ++ /* 10/100/1000 TX shaper is enabled by default */ ++ for (i = 0x202; i < 0x230; i += 2) { ++ if (i == 0x20c || i == 0x218 || i == 0x224) ++ continue; ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, i, 0x2219); ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, i + 1, 0x23); ++ } ++ ++ /* Disable LDO pump */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0); ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0); ++ ++ /* Adjust LDO output voltage */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222); ++} ++ ++static inline int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item, ++ u8 start_pair, u8 end_pair) ++{ ++ u8 pair_n; ++ int ret; ++ ++ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { ++ /* TX_OFFSET & TX_AMP have no SW calibration. */ ++ switch (cal_item) { ++ case REXT: ++ ret = rext_cal_sw(phydev); ++ break; ++ case TX_R50: ++ ret = tx_r50_cal_sw(phydev, pair_n); ++ break; ++ case TX_VCM: ++ ret = tx_vcm_cal_sw(phydev, pair_n); ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++static inline int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item, ++ u8 start_pair, u8 end_pair, u32 *buf) ++{ ++ u8 pair_n; ++ int ret; ++ ++ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { ++ /* TX_VCM has no efuse calibration. */ ++ switch (cal_item) { ++ case REXT: ++ ret = rext_cal_efuse(phydev, buf); ++ break; ++ case TX_OFFSET: ++ ret = tx_offset_cal_efuse(phydev, buf); ++ break; ++ case TX_AMP: ++ ret = tx_amp_cal_efuse(phydev, buf); ++ break; ++ case TX_R50: ++ ret = tx_r50_cal_efuse(phydev, buf, pair_n); ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item, ++ bool efs_valid, enum CAL_MODE cal_mode, u8 start_pair, ++ u8 end_pair, u32 *buf) ++{ ++ char cal_prop[5][20] = { "mediatek,rext", "mediatek,tx_offset", ++ "mediatek,tx_amp", "mediatek,tx_r50", ++ "mediatek,tx_vcm" }; ++ const char *dts_cal_mode; ++ u8 final_cal_mode = 0; ++ bool is_cal = true; ++ int ret, cal_ret; ++ ++ ret = of_property_read_string(phydev->mdio.dev.of_node, ++ cal_prop[cal_item], &dts_cal_mode); ++ ++ switch (cal_mode) { ++ case SW_EFUSE_M: ++ if ((efs_valid && ret) || ++ (efs_valid && !ret && strcmp("efuse", dts_cal_mode) == 0)) { ++ cal_ret = cal_efuse(phydev, cal_item, start_pair, ++ end_pair, buf); ++ final_cal_mode = EFUSE_K; ++ } else if ((!efs_valid && ret) || ++ (!ret && strcmp("sw", dts_cal_mode) == 0)) { ++ cal_ret = cal_sw(phydev, cal_item, start_pair, end_pair); ++ final_cal_mode = SW_K; ++ } else { ++ is_cal = false; ++ } ++ break; ++ case EFUSE_M: ++ if ((efs_valid && ret) || ++ (efs_valid && !ret && strcmp("efuse", dts_cal_mode) == 0)) { ++ cal_ret = cal_efuse(phydev, cal_item, start_pair, ++ end_pair, buf); ++ final_cal_mode = EFUSE_K; ++ } else { ++ is_cal = false; ++ } ++ break; ++ case SW_M: ++ if (ret || (!ret && strcmp("sw", dts_cal_mode) == 0)) { ++ cal_ret = cal_sw(phydev, cal_item, start_pair, end_pair); ++ final_cal_mode = SW_K; ++ } else { ++ is_cal = false; ++ } ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (cal_ret) { ++ dev_err(&phydev->mdio.dev, "[%s]cal failed\n", cal_prop[cal_item]); ++ return -EIO; ++ } ++ ++ if (!is_cal) { ++ dev_dbg(&phydev->mdio.dev, "[%s]K mode: %s(not supported)\n", ++ cal_prop[cal_item], dts_cal_mode); ++ return -EIO; ++ } ++ ++ dev_dbg(&phydev->mdio.dev, "[%s]K mode: %s(dts: %s), efs-valid: %s\n", ++ cal_prop[cal_item], ++ final_cal_mode ? "SW" : "EFUSE", ++ ret ? "not set" : dts_cal_mode, ++ efs_valid ? "yes" : "no"); ++ return 0; ++} ++ ++static int mt798x_phy_calibration(struct phy_device *phydev) ++{ ++ int ret = 0; ++ u32 *buf; ++ bool efs_valid = true; ++ size_t len; ++ struct nvmem_cell *cell; ++ ++ if (phydev->interface != PHY_INTERFACE_MODE_GMII) ++ return -EINVAL; ++ ++ cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); ++ if (IS_ERR(cell)) { ++ if (PTR_ERR(cell) == -EPROBE_DEFER) ++ return PTR_ERR(cell); ++ return 0; ++ } ++ ++ buf = (u32 *)nvmem_cell_read(cell, &len); ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ nvmem_cell_put(cell); ++ ++ if (!buf[0] || !buf[1] || !buf[2] || !buf[3]) ++ efs_valid = false; ++ ++ if (len < 4 * sizeof(u32)) { ++ dev_err(&phydev->mdio.dev, "invalid calibration data\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ ret = start_cal(phydev, REXT, efs_valid, SW_EFUSE_M, ++ NO_PAIR, NO_PAIR, buf); ++ if (ret) ++ goto out; ++ ret = start_cal(phydev, TX_OFFSET, efs_valid, EFUSE_M, ++ NO_PAIR, NO_PAIR, buf); ++ if (ret) ++ goto out; ++ ret = start_cal(phydev, TX_AMP, efs_valid, EFUSE_M, ++ NO_PAIR, NO_PAIR, buf); ++ if (ret) ++ goto out; ++ ret = start_cal(phydev, TX_R50, efs_valid, EFUSE_M, ++ PAIR_A, PAIR_D, buf); ++ if (ret) ++ goto out; ++ ret = start_cal(phydev, TX_VCM, efs_valid, SW_M, ++ PAIR_A, PAIR_A, buf); ++ if (ret) ++ goto out; ++ ++out: ++ kfree(buf); ++ return ret; ++} ++ ++static int mt7981_phy_probe(struct phy_device *phydev) ++{ ++ mt7981_phy_finetune(phydev); ++ ++ return mt798x_phy_calibration(phydev); ++} ++ ++static int mt7988_phy_probe(struct phy_device *phydev) ++{ ++ struct device_node *np; ++ void __iomem *boottrap; ++ u32 reg; ++ int port; ++ ++ /* Setup LED polarity according to boottrap's polarity */ ++ np = of_find_compatible_node(NULL, NULL, "mediatek,boottrap"); ++ if (!np) ++ return -ENOENT; ++ boottrap = of_iomap(np, 0); ++ if (!boottrap) ++ return -ENOMEM; ++ reg = readl(boottrap); ++ port = phydev->mdio.addr; ++ if ((port == GPHY_PORT0 && reg & BIT(8)) || ++ (port == GPHY_PORT1 && reg & BIT(9)) || ++ (port == GPHY_PORT2 && reg & BIT(10)) || ++ (port == GPHY_PORT3 && reg & BIT(11))) { ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, ++ MTK_PHY_LED0_ENABLE | MTK_PHY_LED0_ON_LINK10 | ++ MTK_PHY_LED0_ON_LINK100 | ++ MTK_PHY_LED0_ON_LINK1000); ++ } else { ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, ++ MTK_PHY_LED0_ENABLE | MTK_PHY_LED0_POLARITY | ++ MTK_PHY_LED0_ON_LINK10 | ++ MTK_PHY_LED0_ON_LINK100 | ++ MTK_PHY_LED0_ON_LINK1000); ++ } ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_BLINK_CTRL, ++ MTK_PHY_LED0_1000TX | MTK_PHY_LED0_1000RX | ++ MTK_PHY_LED0_100TX | MTK_PHY_LED0_100RX | ++ MTK_PHY_LED0_10TX | MTK_PHY_LED0_10RX); ++ ++ mt7988_phy_finetune(phydev); ++ ++ return mt798x_phy_calibration(phydev); ++} ++#endif ++ + static struct phy_driver mtk_gephy_driver[] = { + { + PHY_ID_MATCH_EXACT(0x03a29412), +@@ -97,6 +1422,30 @@ static struct phy_driver mtk_gephy_drive + .read_page = mtk_gephy_read_page, + .write_page = mtk_gephy_write_page, + }, ++#ifdef CONFIG_MEDIATEK_GE_PHY_SOC ++ { ++ PHY_ID_MATCH_EXACT(0x03a29461), ++ .name = "MediaTek MT7981 PHY", ++ .probe = mt7981_phy_probe, ++ .config_intr = genphy_no_config_intr, ++ .handle_interrupt = genphy_handle_interrupt_no_ack, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = mtk_gephy_read_page, ++ .write_page = mtk_gephy_write_page, ++ }, ++ { ++ PHY_ID_MATCH_EXACT(0x03a29481), ++ .name = "MediaTek MT7988 PHY", ++ .probe = mt7988_phy_probe, ++ .config_intr = genphy_no_config_intr, ++ .handle_interrupt = genphy_handle_interrupt_no_ack, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = mtk_gephy_read_page, ++ .write_page = mtk_gephy_write_page, ++ }, ++#endif + }; + + module_phy_driver(mtk_gephy_driver); +@@ -107,6 +1456,8 @@ static struct mdio_device_id __maybe_unu + }; + + MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver"); ++MODULE_AUTHOR("Daniel Golle "); ++MODULE_AUTHOR("SkyLake Huang "); + MODULE_AUTHOR("DENG, Qingfang "); + MODULE_LICENSE("GPL"); + From 5b972d7272c06d17cc0a5a8374dbfb9a9dd33fe1 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 27 Mar 2023 17:50:54 +0100 Subject: [PATCH 41/53] generic: mtk_eth_soc: allow setting MDIO clock frequency Backport patch allowing to set the MDIO bus clock frequency. By default the MDIO bus clock runs on 2.5 MHz, allow increasing it up to 25 MHz. Signed-off-by: Daniel Golle --- ..._eth_soc-set-MDIO-bus-clock-frequenc.patch | 76 +++++++++++++++++++ ...net-mtk_eth_soc-enable-threaded-NAPI.patch | 6 +- ...e-all-MACs-are-powered-down-before-r.patch | 2 +- ...iatek-ppe-add-support-for-flow-accou.patch | 12 +-- ..._eth_soc-drop-generic-vlan-rx-offloa.patch | 14 ++-- ..._eth_soc-work-around-issue-with-send.patch | 6 +- ..._eth_soc-add-code-for-offloading-flo.patch | 2 +- ..._eth_soc-implement-Clause-45-MDIO-ac.patch | 4 +- 8 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 target/linux/generic/backport-5.15/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch diff --git a/target/linux/generic/backport-5.15/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch b/target/linux/generic/backport-5.15/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch new file mode 100644 index 00000000000..df7ee081f79 --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch @@ -0,0 +1,76 @@ +From c0a440031d4314d1023c1b87f43a4233634eebdb Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 19 Mar 2023 12:57:15 +0000 +Subject: [PATCH] net: ethernet: mtk_eth_soc: set MDIO bus clock frequency +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Set MDIO bus clock frequency and allow setting a custom maximum +frequency from device tree. + +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Tested-by: Bjørn Mork +Signed-off-by: Daniel Golle +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 21 +++++++++++++++++++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 7 +++++++ + 2 files changed, 28 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -704,8 +704,10 @@ static const struct phylink_mac_ops mtk_ + + static int mtk_mdio_init(struct mtk_eth *eth) + { ++ unsigned int max_clk = 2500000, divider; + struct device_node *mii_np; + int ret; ++ u32 val; + + mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus"); + if (!mii_np) { +@@ -731,6 +733,25 @@ static int mtk_mdio_init(struct mtk_eth + eth->mii_bus->parent = eth->dev; + + snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np); ++ ++ if (!of_property_read_u32(mii_np, "clock-frequency", &val)) { ++ if (val > MDC_MAX_FREQ || val < MDC_MAX_FREQ / MDC_MAX_DIVIDER) { ++ dev_err(eth->dev, "MDIO clock frequency out of range"); ++ ret = -EINVAL; ++ goto err_put_node; ++ } ++ max_clk = val; ++ } ++ divider = min_t(unsigned int, DIV_ROUND_UP(MDC_MAX_FREQ, max_clk), 63); ++ ++ /* Configure MDC Divider */ ++ val = mtk_r32(eth, MTK_PPSC); ++ val &= ~PPSC_MDC_CFG; ++ val |= FIELD_PREP(PPSC_MDC_CFG, divider) | PPSC_MDC_TURBO; ++ mtk_w32(eth, val, MTK_PPSC); ++ ++ dev_dbg(eth->dev, "MDC is running on %d Hz\n", MDC_MAX_FREQ / divider); ++ + ret = of_mdiobus_register(eth->mii_bus, mii_np); + + err_put_node: +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -363,6 +363,13 @@ + #define RX_DMA_VTAG_V2 BIT(0) + #define RX_DMA_L4_VALID_V2 BIT(2) + ++/* PHY Polling and SMI Master Control registers */ ++#define MTK_PPSC 0x10000 ++#define PPSC_MDC_CFG GENMASK(29, 24) ++#define PPSC_MDC_TURBO BIT(20) ++#define MDC_MAX_FREQ 25000000 ++#define MDC_MAX_DIVIDER 63 ++ + /* PHY Indirect Access Control registers */ + #define MTK_PHY_IAC 0x10004 + #define PHY_IAC_ACCESS BIT(31) diff --git a/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch b/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch index 6cde5d8589c..75393bcce70 100644 --- a/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch +++ b/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2972,8 +2972,8 @@ static irqreturn_t mtk_handle_irq_rx(int +@@ -2993,8 +2993,8 @@ static irqreturn_t mtk_handle_irq_rx(int eth->rx_events++; if (likely(napi_schedule_prep(ð->rx_napi))) { @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -2985,8 +2985,8 @@ static irqreturn_t mtk_handle_irq_tx(int +@@ -3006,8 +3006,8 @@ static irqreturn_t mtk_handle_irq_tx(int eth->tx_events++; if (likely(napi_schedule_prep(ð->tx_napi))) { @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -4617,6 +4617,8 @@ static int mtk_probe(struct platform_dev +@@ -4638,6 +4638,8 @@ static int mtk_probe(struct platform_dev * for NAPI to work */ init_dummy_netdev(ð->dummy_dev); diff --git a/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch b/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch index 01cc5fd18ef..0226cef8c3f 100644 --- a/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch +++ b/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch @@ -15,7 +15,7 @@ Signed-off-by: Alexander Couzens --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2341,6 +2341,10 @@ mt7531_setup(struct dsa_switch *ds) +@@ -2342,6 +2342,10 @@ mt7531_setup(struct dsa_switch *ds) return -ENODEV; } diff --git a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch index 67bd504da14..c6572214fb8 100644 --- a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch +++ b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch @@ -53,7 +53,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4586,8 +4586,8 @@ static int mtk_probe(struct platform_dev +@@ -4607,8 +4607,8 @@ static int mtk_probe(struct platform_dev for (i = 0; i < num_ppe; i++) { u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; @@ -64,7 +64,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov if (!eth->ppe[i]) { err = -ENOMEM; goto err_free_dev; -@@ -4712,6 +4712,7 @@ static const struct mtk_soc_data mt7622_ +@@ -4733,6 +4733,7 @@ static const struct mtk_soc_data mt7622_ .required_pctl = false, .offload_version = 2, .hash_offset = 2, @@ -72,7 +72,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), -@@ -4749,6 +4750,7 @@ static const struct mtk_soc_data mt7629_ +@@ -4770,6 +4771,7 @@ static const struct mtk_soc_data mt7629_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7629_CLKS_BITMAP, .required_pctl = false, @@ -80,7 +80,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4769,6 +4771,7 @@ static const struct mtk_soc_data mt7986_ +@@ -4790,6 +4792,7 @@ static const struct mtk_soc_data mt7986_ .offload_version = 2, .hash_offset = 4, .foe_entry_size = sizeof(struct mtk_foe_entry), @@ -90,7 +90,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .rxd_size = sizeof(struct mtk_rx_dma_v2), --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1037,6 +1037,8 @@ struct mtk_reg_map { +@@ -1044,6 +1044,8 @@ struct mtk_reg_map { * the extra setup for those pins used by GMAC. * @hash_offset Flow table hash offset. * @foe_entry_size Foe table entry size. @@ -99,7 +99,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov * @txd_size Tx DMA descriptor size. * @rxd_size Rx DMA descriptor size. * @rx_irq_done_mask Rx irq done register mask. -@@ -1054,6 +1056,7 @@ struct mtk_soc_data { +@@ -1061,6 +1063,7 @@ struct mtk_soc_data { u8 hash_offset; u16 foe_entry_size; netdev_features_t hw_features; diff --git a/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch b/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch index c2b411d2e9d..84afb3f46a8 100644 --- a/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch +++ b/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch @@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1830,9 +1830,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1851,9 +1851,7 @@ static int mtk_poll_rx(struct napi_struc while (done < budget) { unsigned int pktlen, *rxdcsum; @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau dma_addr_t dma_addr; u32 hash, reason; int mac = 0; -@@ -1967,36 +1965,21 @@ static int mtk_poll_rx(struct napi_struc +@@ -1988,36 +1986,21 @@ static int mtk_poll_rx(struct napi_struc skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); @@ -70,7 +70,7 @@ Signed-off-by: Felix Fietkau skb_record_rx_queue(skb, 0); napi_gro_receive(napi, skb); -@@ -2811,29 +2794,11 @@ static netdev_features_t mtk_fix_feature +@@ -2832,29 +2815,11 @@ static netdev_features_t mtk_fix_feature static int mtk_set_features(struct net_device *dev, netdev_features_t features) { @@ -100,7 +100,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3147,30 +3112,6 @@ static int mtk_open(struct net_device *d +@@ -3168,30 +3133,6 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; int i, err; @@ -131,7 +131,7 @@ Signed-off-by: Felix Fietkau err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); if (err) { netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, -@@ -3211,6 +3152,35 @@ static int mtk_open(struct net_device *d +@@ -3232,6 +3173,35 @@ static int mtk_open(struct net_device *d phylink_start(mac->phylink); netif_tx_start_all_queues(dev); @@ -167,7 +167,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3695,10 +3665,9 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3716,10 +3686,9 @@ static int mtk_hw_init(struct mtk_eth *e if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { val = mtk_r32(eth, MTK_CDMP_IG_CTRL); mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); @@ -180,7 +180,7 @@ Signed-off-by: Felix Fietkau /* set interrupt delays based on current Net DIM sample */ mtk_dim_rx(ð->rx_dim.work); -@@ -4336,7 +4305,7 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4357,7 +4326,7 @@ static int mtk_add_mac(struct mtk_eth *e eth->netdev[id]->hw_features |= NETIF_F_LRO; eth->netdev[id]->vlan_features = eth->soc->hw_features & diff --git a/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch b/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch index 961d970c4d2..0ed8c695e92 100644 --- a/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch +++ b/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch @@ -16,7 +16,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1403,12 +1403,28 @@ static void mtk_wake_queue(struct mtk_et +@@ -1424,12 +1424,28 @@ static void mtk_wake_queue(struct mtk_et } } @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau bool gso = false; int tx_num; -@@ -1430,6 +1446,18 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1451,6 +1467,18 @@ static netdev_tx_t mtk_start_xmit(struct return NETDEV_TX_BUSY; } @@ -64,7 +64,7 @@ Signed-off-by: Felix Fietkau /* TSO: fill MSS info in tcp checksum field */ if (skb_is_gso(skb)) { if (skb_cow_head(skb, 0)) { -@@ -1445,8 +1473,14 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1466,8 +1494,14 @@ static netdev_tx_t mtk_start_xmit(struct } } diff --git a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch index 0a7f6706553..f6919dc19ef 100644 --- a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch +++ b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1357,6 +1357,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk +@@ -1364,6 +1364,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk int mtk_eth_offload_init(struct mtk_eth *eth); int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data); diff --git a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch index 554619c0179..d72776d9c46 100644 --- a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch +++ b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch @@ -103,7 +103,7 @@ Signed-off-by: David S. Miller ret = mtk_mdio_busy_wait(eth); if (ret < 0) -@@ -727,6 +770,7 @@ static int mtk_mdio_init(struct mtk_eth +@@ -729,6 +772,7 @@ static int mtk_mdio_init(struct mtk_eth eth->mii_bus->name = "mdio"; eth->mii_bus->read = mtk_mdio_read; eth->mii_bus->write = mtk_mdio_write; @@ -113,7 +113,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -369,9 +369,12 @@ +@@ -376,9 +376,12 @@ #define PHY_IAC_ADDR_MASK GENMASK(24, 20) #define PHY_IAC_ADDR(x) FIELD_PREP(PHY_IAC_ADDR_MASK, (x)) #define PHY_IAC_CMD_MASK GENMASK(19, 18) From 72094f74a6d855d9146df9dec2d73355c9c434be Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 27 Mar 2023 18:14:21 +0100 Subject: [PATCH 42/53] generic: net: pcs: add driver for MediaTek SGMII PCS Backport dedicated PCS driver for MediaTek LynxI SGMII/SerDes unit. Signed-off-by: Daniel Golle --- ...2c-Add-driver-for-Sony-IMX477-sensor.patch | 2 +- ...vicetree-Add-documentation-for-imx37.patch | 2 +- ...a-i2c-Add-IMX519-CMOS-sensor-binding.patch | 2 +- ...cs-add-driver-for-MediaTek-SGMII-PCS.patch | 394 ++++++++++++++++++ ...d-driver-for-OCOTP-in-Sunplus-SP7021.patch | 2 +- ...001-nvmem-microchip-otpc-add-support.patch | 2 +- ...er-for-MediaTek-SoC-built-in-GE-PHYs.patch | 6 +- ...hdog-add-realtek-otto-watchdog-timer.patch | 2 +- ...t-dsa-add-support-for-rtl838x-switch.patch | 2 +- ...vers-net-phy-eee-support-for-rtl838x.patch | 6 +- 10 files changed, 407 insertions(+), 13 deletions(-) create mode 100644 target/linux/generic/backport-5.15/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch diff --git a/target/linux/bcm27xx/patches-5.15/950-0281-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch b/target/linux/bcm27xx/patches-5.15/950-0281-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch index 7690153d3db..e756fa2fff6 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0281-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0281-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch @@ -25,7 +25,7 @@ Signed-off-by: Naushir Patuck --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -17530,6 +17530,14 @@ T: git git://linuxtv.org/media_tree.git +@@ -17538,6 +17538,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml F: drivers/media/i2c/imx412.c diff --git a/target/linux/bcm27xx/patches-5.15/950-0413-Documentation-devicetree-Add-documentation-for-imx37.patch b/target/linux/bcm27xx/patches-5.15/950-0413-Documentation-devicetree-Add-documentation-for-imx37.patch index d60c0f372cc..27fd0e57938 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0413-Documentation-devicetree-Add-documentation-for-imx37.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0413-Documentation-devicetree-Add-documentation-for-imx37.patch @@ -132,7 +132,7 @@ Signed-off-by: David Plowman +... --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -17544,6 +17544,7 @@ M: Raspberry Pi Kernel Maintenance +... --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -17548,6 +17548,14 @@ F: Documentation/devicetree/bindings/med +@@ -17556,6 +17556,14 @@ F: Documentation/devicetree/bindings/med F: Documentation/devicetree/bindings/media/i2c/imx477.yaml F: drivers/media/i2c/imx477.c diff --git a/target/linux/generic/backport-5.15/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch b/target/linux/generic/backport-5.15/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch new file mode 100644 index 00000000000..1f2a3ee140f --- /dev/null +++ b/target/linux/generic/backport-5.15/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch @@ -0,0 +1,394 @@ +From 4765a9722e09765866e131ec31f7b9cf4c1f4854 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 19 Mar 2023 12:57:50 +0000 +Subject: [PATCH] net: pcs: add driver for MediaTek SGMII PCS + +The SGMII core found in several MediaTek SoCs is identical to what can +also be found in MediaTek's MT7531 Ethernet switch IC. +As this has not always been clear, both drivers developed different +implementations to deal with the PCS. +Recently Alexander Couzens pointed out this fact which lead to the +development of this shared driver. + +Add a dedicated driver, mostly by copying the code now found in the +Ethernet driver. The now redundant code will be removed by a follow-up +commit. + +Suggested-by: Alexander Couzens +Suggested-by: Russell King (Oracle) +Signed-off-by: Daniel Golle +Tested-by: Frank Wunderlich +Reviewed-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + MAINTAINERS | 8 + + drivers/net/pcs/Kconfig | 7 + + drivers/net/pcs/Makefile | 1 + + drivers/net/pcs/pcs-mtk-lynxi.c | 305 ++++++++++++++++++++++++++++++ + include/linux/pcs/pcs-mtk-lynxi.h | 13 ++ + 5 files changed, 334 insertions(+) + create mode 100644 drivers/net/pcs/pcs-mtk-lynxi.c + create mode 100644 include/linux/pcs/pcs-mtk-lynxi.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -11790,6 +11790,14 @@ L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/ethernet/mediatek/ + ++MEDIATEK ETHERNET PCS DRIVER ++M: Alexander Couzens ++M: Daniel Golle ++L: netdev@vger.kernel.org ++S: Maintained ++F: drivers/net/pcs/pcs-mtk-lynxi.c ++F: include/linux/pcs/pcs-mtk-lynxi.h ++ + MEDIATEK I2C CONTROLLER DRIVER + M: Qii Wang + L: linux-i2c@vger.kernel.org +--- a/drivers/net/pcs/Kconfig ++++ b/drivers/net/pcs/Kconfig +@@ -18,4 +18,11 @@ config PCS_LYNX + This module provides helpers to phylink for managing the Lynx PCS + which is part of the Layerscape and QorIQ Ethernet SERDES. + ++config PCS_MTK_LYNXI ++ tristate ++ select REGMAP ++ help ++ This module provides helpers to phylink for managing the LynxI PCS ++ which is part of MediaTek's SoC and Ethernet switch ICs. ++ + endmenu +--- a/drivers/net/pcs/Makefile ++++ b/drivers/net/pcs/Makefile +@@ -5,3 +5,4 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs. + + obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o + obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o ++obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o +--- /dev/null ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -0,0 +1,305 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 MediaTek Inc. ++/* A library for MediaTek SGMII circuit ++ * ++ * Author: Sean Wang ++ * Author: Alexander Couzens ++ * Author: Daniel Golle ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* SGMII subsystem config registers */ ++/* BMCR (low 16) BMSR (high 16) */ ++#define SGMSYS_PCS_CONTROL_1 0x0 ++#define SGMII_BMCR GENMASK(15, 0) ++#define SGMII_BMSR GENMASK(31, 16) ++ ++#define SGMSYS_PCS_DEVICE_ID 0x4 ++#define SGMII_LYNXI_DEV_ID 0x4d544950 ++ ++#define SGMSYS_PCS_ADVERTISE 0x8 ++#define SGMII_ADVERTISE GENMASK(15, 0) ++#define SGMII_LPA GENMASK(31, 16) ++ ++#define SGMSYS_PCS_SCRATCH 0x14 ++#define SGMII_DEV_VERSION GENMASK(31, 16) ++ ++/* Register to programmable link timer, the unit in 2 * 8ns */ ++#define SGMSYS_PCS_LINK_TIMER 0x18 ++#define SGMII_LINK_TIMER_MASK GENMASK(19, 0) ++#define SGMII_LINK_TIMER_VAL(ns) FIELD_PREP(SGMII_LINK_TIMER_MASK, \ ++ ((ns) / 2 / 8)) ++ ++/* Register to control remote fault */ ++#define SGMSYS_SGMII_MODE 0x20 ++#define SGMII_IF_MODE_SGMII BIT(0) ++#define SGMII_SPEED_DUPLEX_AN BIT(1) ++#define SGMII_SPEED_MASK GENMASK(3, 2) ++#define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) ++#define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) ++#define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) ++#define SGMII_DUPLEX_HALF BIT(4) ++#define SGMII_REMOTE_FAULT_DIS BIT(8) ++ ++/* Register to reset SGMII design */ ++#define SGMSYS_RESERVED_0 0x34 ++#define SGMII_SW_RESET BIT(0) ++ ++/* Register to set SGMII speed, ANA RG_ Control Signals III */ ++#define SGMII_PHY_SPEED_MASK GENMASK(3, 2) ++#define SGMII_PHY_SPEED_1_25G FIELD_PREP(SGMII_PHY_SPEED_MASK, 0) ++#define SGMII_PHY_SPEED_3_125G FIELD_PREP(SGMII_PHY_SPEED_MASK, 1) ++ ++/* Register to power up QPHY */ ++#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 ++#define SGMII_PHYA_PWD BIT(4) ++ ++/* Register to QPHY wrapper control */ ++#define SGMSYS_QPHY_WRAP_CTRL 0xec ++#define SGMII_PN_SWAP_MASK GENMASK(1, 0) ++#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) ++ ++/* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated ++ * data ++ * @regmap: The register map pointing at the range used to setup ++ * SGMII modes ++ * @dev: Pointer to device owning the PCS ++ * @ana_rgc3: The offset of register ANA_RGC3 relative to regmap ++ * @interface: Currently configured interface mode ++ * @pcs: Phylink PCS structure ++ * @flags: Flags indicating hardware properties ++ */ ++struct mtk_pcs_lynxi { ++ struct regmap *regmap; ++ u32 ana_rgc3; ++ phy_interface_t interface; ++ struct phylink_pcs pcs; ++ u32 flags; ++}; ++ ++static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs) ++{ ++ return container_of(pcs, struct mtk_pcs_lynxi, pcs); ++} ++ ++static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, ++ struct phylink_link_state *state) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ unsigned int bm, adv; ++ ++ /* Read the BMSR and LPA */ ++ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); ++ regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ ++ phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), ++ FIELD_GET(SGMII_LPA, adv)); ++} ++ ++static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode, ++ phy_interface_t interface, ++ const unsigned long *advertising, ++ bool permit_pause_to_mac) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ bool mode_changed = false, changed, use_an; ++ unsigned int rgc3, sgm_mode, bmcr; ++ int advertise, link_timer; ++ ++ advertise = phylink_mii_c22_pcs_encode_advertisement(interface, ++ advertising); ++ if (advertise < 0) ++ return advertise; ++ ++ /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and ++ * we assume that fixes it's speed at bitrate = line rate (in ++ * other words, 1000Mbps or 2500Mbps). ++ */ ++ if (interface == PHY_INTERFACE_MODE_SGMII) { ++ sgm_mode = SGMII_IF_MODE_SGMII; ++ if (phylink_autoneg_inband(mode)) { ++ sgm_mode |= SGMII_REMOTE_FAULT_DIS | ++ SGMII_SPEED_DUPLEX_AN; ++ use_an = true; ++ } else { ++ use_an = false; ++ } ++ } else if (phylink_autoneg_inband(mode)) { ++ /* 1000base-X or 2500base-X autoneg */ ++ sgm_mode = SGMII_REMOTE_FAULT_DIS; ++ use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, ++ advertising); ++ } else { ++ /* 1000base-X or 2500base-X without autoneg */ ++ sgm_mode = 0; ++ use_an = false; ++ } ++ ++ if (use_an) ++ bmcr = BMCR_ANENABLE; ++ else ++ bmcr = 0; ++ ++ if (mpcs->interface != interface) { ++ link_timer = phylink_get_link_timer_ns(interface); ++ if (link_timer < 0) ++ return link_timer; ++ ++ /* PHYA power down */ ++ regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD); ++ ++ /* Reset SGMII PCS state */ ++ regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0, ++ SGMII_SW_RESET); ++ ++ if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP) ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, ++ SGMII_PN_SWAP_MASK, ++ SGMII_PN_SWAP_TX_RX); ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ rgc3 = SGMII_PHY_SPEED_3_125G; ++ else ++ rgc3 = SGMII_PHY_SPEED_1_25G; ++ ++ /* Configure the underlying interface speed */ ++ regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, ++ SGMII_PHY_SPEED_MASK, rgc3); ++ ++ /* Setup the link timer */ ++ regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, ++ SGMII_LINK_TIMER_VAL(link_timer)); ++ ++ mpcs->interface = interface; ++ mode_changed = true; ++ } ++ ++ /* Update the advertisement, noting whether it has changed */ ++ regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, ++ SGMII_ADVERTISE, advertise, &changed); ++ ++ /* Update the sgmsys mode register */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | ++ SGMII_IF_MODE_SGMII, sgm_mode); ++ ++ /* Update the BMCR */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ BMCR_ANENABLE, bmcr); ++ ++ /* Release PHYA power down state ++ * Only removing bit SGMII_PHYA_PWD isn't enough. ++ * There are cases when the SGMII_PHYA_PWD register contains 0x9 which ++ * prevents SGMII from working. The SGMII still shows link but no traffic ++ * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was ++ * taken from a good working state of the SGMII interface. ++ * Unknown how much the QPHY needs but it is racy without a sleep. ++ * Tested on mt7622 & mt7986. ++ */ ++ usleep_range(50, 100); ++ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); ++ ++ return changed || mode_changed; ++} ++ ++static void mtk_pcs_lynxi_restart_an(struct phylink_pcs *pcs) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ ++ regmap_set_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, BMCR_ANRESTART); ++} ++ ++static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, unsigned int mode, ++ phy_interface_t interface, int speed, ++ int duplex) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ unsigned int sgm_mode; ++ ++ if (!phylink_autoneg_inband(mode)) { ++ /* Force the speed and duplex setting */ ++ if (speed == SPEED_10) ++ sgm_mode = SGMII_SPEED_10; ++ else if (speed == SPEED_100) ++ sgm_mode = SGMII_SPEED_100; ++ else ++ sgm_mode = SGMII_SPEED_1000; ++ ++ if (duplex != DUPLEX_FULL) ++ sgm_mode |= SGMII_DUPLEX_HALF; ++ ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_DUPLEX_HALF | SGMII_SPEED_MASK, ++ sgm_mode); ++ } ++} ++ ++static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = { ++ .pcs_get_state = mtk_pcs_lynxi_get_state, ++ .pcs_config = mtk_pcs_lynxi_config, ++ .pcs_an_restart = mtk_pcs_lynxi_restart_an, ++ .pcs_link_up = mtk_pcs_lynxi_link_up, ++}; ++ ++struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, ++ struct regmap *regmap, u32 ana_rgc3, ++ u32 flags) ++{ ++ struct mtk_pcs_lynxi *mpcs; ++ u32 id, ver; ++ int ret; ++ ++ ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id); ++ if (ret < 0) ++ return NULL; ++ ++ if (id != SGMII_LYNXI_DEV_ID) { ++ dev_err(dev, "unknown PCS device id %08x\n", id); ++ return NULL; ++ } ++ ++ ret = regmap_read(regmap, SGMSYS_PCS_SCRATCH, &ver); ++ if (ret < 0) ++ return NULL; ++ ++ ver = FIELD_GET(SGMII_DEV_VERSION, ver); ++ if (ver != 0x1) { ++ dev_err(dev, "unknown PCS device version %04x\n", ver); ++ return NULL; ++ } ++ ++ dev_dbg(dev, "MediaTek LynxI SGMII PCS (id 0x%08x, ver 0x%04x)\n", id, ++ ver); ++ ++ mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL); ++ if (!mpcs) ++ return NULL; ++ ++ mpcs->ana_rgc3 = ana_rgc3; ++ mpcs->regmap = regmap; ++ mpcs->flags = flags; ++ mpcs->pcs.ops = &mtk_pcs_lynxi_ops; ++ mpcs->pcs.poll = true; ++ mpcs->interface = PHY_INTERFACE_MODE_NA; ++ ++ return &mpcs->pcs; ++} ++EXPORT_SYMBOL(mtk_pcs_lynxi_create); ++ ++void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs) ++{ ++ if (!pcs) ++ return; ++ ++ kfree(pcs_to_mtk_pcs_lynxi(pcs)); ++} ++EXPORT_SYMBOL(mtk_pcs_lynxi_destroy); ++ ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/include/linux/pcs/pcs-mtk-lynxi.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __LINUX_PCS_MTK_LYNXI_H ++#define __LINUX_PCS_MTK_LYNXI_H ++ ++#include ++#include ++ ++#define MTK_SGMII_FLAG_PN_SWAP BIT(0) ++struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, ++ struct regmap *regmap, ++ u32 ana_rgc3, u32 flags); ++void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs); ++#endif diff --git a/target/linux/generic/backport-5.15/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch b/target/linux/generic/backport-5.15/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch index a4c1b66c9e3..2a9dc749478 100644 --- a/target/linux/generic/backport-5.15/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch +++ b/target/linux/generic/backport-5.15/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch @@ -19,7 +19,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -17954,6 +17954,11 @@ L: netdev@vger.kernel.org +@@ -17962,6 +17962,11 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/dlink/sundance.c diff --git a/target/linux/generic/backport-5.15/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch b/target/linux/generic/backport-5.15/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch index 6503c7aa3b1..cec66ec383e 100644 --- a/target/linux/generic/backport-5.15/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch +++ b/target/linux/generic/backport-5.15/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch @@ -57,7 +57,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -12354,6 +12354,14 @@ S: Supported +@@ -12362,6 +12362,14 @@ S: Supported F: Documentation/devicetree/bindings/mtd/atmel-nand.txt F: drivers/mtd/nand/raw/atmel/* diff --git a/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch b/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch index 4909d9e9229..f2145dbc16f 100644 --- a/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch +++ b/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch @@ -17,9 +17,9 @@ Signed-off-by: Daniel Golle --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -11790,6 +11790,14 @@ L: netdev@vger.kernel.org - S: Maintained - F: drivers/net/ethernet/mediatek/ +@@ -11798,6 +11798,14 @@ S: Maintained + F: drivers/net/pcs/pcs-mtk-lynxi.c + F: include/linux/pcs/pcs-mtk-lynxi.h +MEDIATEK ETHERNET PHY DRIVERS +M: Daniel Golle diff --git a/target/linux/realtek/patches-5.15/008-5.17-watchdog-add-realtek-otto-watchdog-timer.patch b/target/linux/realtek/patches-5.15/008-5.17-watchdog-add-realtek-otto-watchdog-timer.patch index 93f0fe5cf47..e562dd8396c 100644 --- a/target/linux/realtek/patches-5.15/008-5.17-watchdog-add-realtek-otto-watchdog-timer.patch +++ b/target/linux/realtek/patches-5.15/008-5.17-watchdog-add-realtek-otto-watchdog-timer.patch @@ -32,7 +32,7 @@ Signed-off-by: Guenter Roeck --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -15891,6 +15891,13 @@ S: Maintained +@@ -15899,6 +15899,13 @@ S: Maintained F: include/sound/rt*.h F: sound/soc/codecs/rt* diff --git a/target/linux/realtek/patches-5.15/700-net-dsa-add-support-for-rtl838x-switch.patch b/target/linux/realtek/patches-5.15/700-net-dsa-add-support-for-rtl838x-switch.patch index 71724034d4c..8f400012635 100644 --- a/target/linux/realtek/patches-5.15/700-net-dsa-add-support-for-rtl838x-switch.patch +++ b/target/linux/realtek/patches-5.15/700-net-dsa-add-support-for-rtl838x-switch.patch @@ -22,7 +22,7 @@ Submitted-by: John Crispin --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig -@@ -60,6 +60,8 @@ source "drivers/net/dsa/sja1105/Kconfig" +@@ -61,6 +61,8 @@ source "drivers/net/dsa/sja1105/Kconfig" source "drivers/net/dsa/xrs700x/Kconfig" diff --git a/target/linux/realtek/patches-5.15/704-drivers-net-phy-eee-support-for-rtl838x.patch b/target/linux/realtek/patches-5.15/704-drivers-net-phy-eee-support-for-rtl838x.patch index 1cea91e0d13..591f0cea13a 100644 --- a/target/linux/realtek/patches-5.15/704-drivers-net-phy-eee-support-for-rtl838x.patch +++ b/target/linux/realtek/patches-5.15/704-drivers-net-phy-eee-support-for-rtl838x.patch @@ -21,7 +21,7 @@ Submitted-by: John Crispin --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c -@@ -1943,6 +1943,11 @@ int phylink_ethtool_ksettings_set(struct +@@ -1942,6 +1942,11 @@ int phylink_ethtool_ksettings_set(struct * the presence of a PHY, this should not be changed as that * should be determined from the media side advertisement. */ @@ -33,7 +33,7 @@ Submitted-by: John Crispin return phy_ethtool_ksettings_set(pl->phydev, kset); } -@@ -2246,8 +2251,11 @@ int phylink_ethtool_get_eee(struct phyli +@@ -2245,8 +2250,11 @@ int phylink_ethtool_get_eee(struct phyli ASSERT_RTNL(); @@ -46,7 +46,7 @@ Submitted-by: John Crispin return ret; } -@@ -2264,8 +2272,11 @@ int phylink_ethtool_set_eee(struct phyli +@@ -2263,8 +2271,11 @@ int phylink_ethtool_set_eee(struct phyli ASSERT_RTNL(); From 880d1311335120f64447ca9d11933872d734e19a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 27 Mar 2023 18:41:54 +0100 Subject: [PATCH 43/53] generic: pcs-mtk-lynxi: add hack to use 2500Base-X without AN Using 2500Base-T SFP modules e.g. on the BananaPi R3 requires manually disabling auto-negotiation, e.g. using ethtool. While a proper fix using SFP quirks is being discussed upstream, bring a work-around to restore user experience to what it was before the switch to the dedicated SGMII PCS driver. Signed-off-by: Daniel Golle --- ...mtk-lynxi-workaround-2500BaseX-no-an.patch | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 target/linux/generic/hack-5.15/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch diff --git a/target/linux/generic/hack-5.15/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch b/target/linux/generic/hack-5.15/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch new file mode 100644 index 00000000000..b03f0feab27 --- /dev/null +++ b/target/linux/generic/hack-5.15/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch @@ -0,0 +1,40 @@ +--- a/drivers/net/pcs/pcs-mtk-lynxi.c ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -92,14 +92,23 @@ static void mtk_pcs_lynxi_get_state(stru + struct phylink_link_state *state) + { + struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); +- unsigned int bm, adv; ++ unsigned int bm, bmsr, adv; + + /* Read the BMSR and LPA */ + regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); +- regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ bmsr = FIELD_GET(SGMII_BMSR, bm); ++ ++ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { ++ state->link = !!(bmsr & BMSR_LSTATUS); ++ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); ++ state->speed = SPEED_2500; ++ state->duplex = DUPLEX_FULL; + +- phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), +- FIELD_GET(SGMII_LPA, adv)); ++ return; ++ } ++ ++ regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ phylink_mii_c22_pcs_decode_state(state, bmsr, FIELD_GET(SGMII_LPA, adv)); + } + + static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -134,7 +143,8 @@ static int mtk_pcs_lynxi_config(struct p + /* 1000base-X or 2500base-X autoneg */ + sgm_mode = SGMII_REMOTE_FAULT_DIS; + use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +- advertising); ++ advertising) && ++ !(interface == PHY_INTERFACE_MODE_2500BASEX); + } else { + /* 1000base-X or 2500base-X without autoneg */ + sgm_mode = 0; From 53dc9a60c05642e9596b25e5cfba1136a5d9e09e Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 27 Mar 2023 18:15:13 +0100 Subject: [PATCH 44/53] generic: mtk_eth_soc: switch to external PCS driver Backport patch to make use of the new PCS driver in mtk_eth_soc. Signed-off-by: Daniel Golle --- ..._eth_soc-switch-to-external-PCS-driv.patch | 512 ++++++++++++++++++ ...net-mtk_eth_soc-enable-threaded-NAPI.patch | 6 +- ...iatek-ppe-add-support-for-flow-accou.patch | 12 +- ..._eth_soc-drop-generic-vlan-rx-offloa.patch | 14 +- ..._eth_soc-work-around-issue-with-send.patch | 6 +- ..._eth_soc-add-code-for-offloading-flo.patch | 2 +- ..._eth_soc-implement-Clause-45-MDIO-ac.patch | 6 +- ...ethernet-mediatek-support-net-labels.patch | 4 +- 8 files changed, 537 insertions(+), 25 deletions(-) create mode 100644 target/linux/generic/backport-5.15/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch diff --git a/target/linux/generic/backport-5.15/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch b/target/linux/generic/backport-5.15/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch new file mode 100644 index 00000000000..1eca7dfeaf5 --- /dev/null +++ b/target/linux/generic/backport-5.15/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch @@ -0,0 +1,512 @@ +From 2a3ec7ae313310c1092e4256208cc04d1958e469 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 19 Mar 2023 12:58:02 +0000 +Subject: [PATCH] net: ethernet: mtk_eth_soc: switch to external PCS driver + +Now that we got a PCS driver, use it and remove the now redundant +PCS code and it's header macros from the Ethernet driver. + +Signed-off-by: Daniel Golle +Tested-by: Frank Wunderlich +Reviewed-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/Kconfig | 2 + + drivers/net/ethernet/mediatek/Makefile | 2 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 61 +++++- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 93 +-------- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 217 -------------------- + 5 files changed, 56 insertions(+), 319 deletions(-) + delete mode 100644 drivers/net/ethernet/mediatek/mtk_sgmii.c + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -18,6 +18,8 @@ config NET_MEDIATEK_SOC + select DIMLIB + select PAGE_POOL + select PAGE_POOL_STATS ++ select PCS_MTK_LYNXI ++ select REGMAP_MMIO + help + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -4,7 +4,7 @@ + # + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o +-mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o ++mtk_eth-y := mtk_eth_soc.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o + mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o + ifdef CONFIG_DEBUG_FS + mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -357,7 +358,7 @@ static struct phylink_pcs *mtk_mac_selec + sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? + 0 : mac->id; + +- return mtk_sgmii_select_pcs(eth->sgmii, sid); ++ return eth->sgmii_pcs[sid]; + } + + return NULL; +@@ -3979,8 +3980,17 @@ static int mtk_unreg_dev(struct mtk_eth + return 0; + } + ++static void mtk_sgmii_destroy(struct mtk_eth *eth) ++{ ++ int i; ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) ++ mtk_pcs_lynxi_destroy(eth->sgmii_pcs[i]); ++} ++ + static int mtk_cleanup(struct mtk_eth *eth) + { ++ mtk_sgmii_destroy(eth); + mtk_unreg_dev(eth); + mtk_free_dev(eth); + cancel_work_sync(ð->pending_work); +@@ -4410,6 +4420,36 @@ void mtk_eth_set_dma_device(struct mtk_e + rtnl_unlock(); + } + ++static int mtk_sgmii_init(struct mtk_eth *eth) ++{ ++ struct device_node *np; ++ struct regmap *regmap; ++ u32 flags; ++ int i; ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) { ++ np = of_parse_phandle(eth->dev->of_node, "mediatek,sgmiisys", i); ++ if (!np) ++ break; ++ ++ regmap = syscon_node_to_regmap(np); ++ flags = 0; ++ if (of_property_read_bool(np, "mediatek,pnswap")) ++ flags |= MTK_SGMII_FLAG_PN_SWAP; ++ ++ of_node_put(np); ++ ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ eth->sgmii_pcs[i] = mtk_pcs_lynxi_create(eth->dev, regmap, ++ eth->soc->ana_rgc3, ++ flags); ++ } ++ ++ return 0; ++} ++ + static int mtk_probe(struct platform_device *pdev) + { + struct resource *res = NULL; +@@ -4473,13 +4513,7 @@ static int mtk_probe(struct platform_dev + } + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { +- eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), +- GFP_KERNEL); +- if (!eth->sgmii) +- return -ENOMEM; +- +- err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node, +- eth->soc->ana_rgc3); ++ err = mtk_sgmii_init(eth); + + if (err) + return err; +@@ -4490,14 +4524,17 @@ static int mtk_probe(struct platform_dev + "mediatek,pctl"); + if (IS_ERR(eth->pctl)) { + dev_err(&pdev->dev, "no pctl regmap found\n"); +- return PTR_ERR(eth->pctl); ++ err = PTR_ERR(eth->pctl); ++ goto err_destroy_sgmii; + } + } + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) +- return -EINVAL; ++ if (!res) { ++ err = -EINVAL; ++ goto err_destroy_sgmii; ++ } + } + + if (eth->soc->offload_version) { +@@ -4657,6 +4694,8 @@ err_deinit_hw: + mtk_hw_deinit(eth); + err_wed_exit: + mtk_wed_exit(); ++err_destroy_sgmii: ++ mtk_sgmii_destroy(eth); + + return err; + } +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -507,65 +507,6 @@ + #define ETHSYS_DMA_AG_MAP_QDMA BIT(1) + #define ETHSYS_DMA_AG_MAP_PPE BIT(2) + +-/* SGMII subsystem config registers */ +-/* BMCR (low 16) BMSR (high 16) */ +-#define SGMSYS_PCS_CONTROL_1 0x0 +-#define SGMII_BMCR GENMASK(15, 0) +-#define SGMII_BMSR GENMASK(31, 16) +-#define SGMII_AN_RESTART BIT(9) +-#define SGMII_ISOLATE BIT(10) +-#define SGMII_AN_ENABLE BIT(12) +-#define SGMII_LINK_STATYS BIT(18) +-#define SGMII_AN_ABILITY BIT(19) +-#define SGMII_AN_COMPLETE BIT(21) +-#define SGMII_PCS_FAULT BIT(23) +-#define SGMII_AN_EXPANSION_CLR BIT(30) +- +-#define SGMSYS_PCS_ADVERTISE 0x8 +-#define SGMII_ADVERTISE GENMASK(15, 0) +-#define SGMII_LPA GENMASK(31, 16) +- +-/* Register to programmable link timer, the unit in 2 * 8ns */ +-#define SGMSYS_PCS_LINK_TIMER 0x18 +-#define SGMII_LINK_TIMER_MASK GENMASK(19, 0) +-#define SGMII_LINK_TIMER_DEFAULT (0x186a0 & SGMII_LINK_TIMER_MASK) +- +-/* Register to control remote fault */ +-#define SGMSYS_SGMII_MODE 0x20 +-#define SGMII_IF_MODE_SGMII BIT(0) +-#define SGMII_SPEED_DUPLEX_AN BIT(1) +-#define SGMII_SPEED_MASK GENMASK(3, 2) +-#define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) +-#define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) +-#define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) +-#define SGMII_DUPLEX_HALF BIT(4) +-#define SGMII_IF_MODE_BIT5 BIT(5) +-#define SGMII_REMOTE_FAULT_DIS BIT(8) +-#define SGMII_CODE_SYNC_SET_VAL BIT(9) +-#define SGMII_CODE_SYNC_SET_EN BIT(10) +-#define SGMII_SEND_AN_ERROR_EN BIT(11) +-#define SGMII_IF_MODE_MASK GENMASK(5, 1) +- +-/* Register to reset SGMII design */ +-#define SGMII_RESERVED_0 0x34 +-#define SGMII_SW_RESET BIT(0) +- +-/* Register to set SGMII speed, ANA RG_ Control Signals III*/ +-#define SGMSYS_ANA_RG_CS3 0x2028 +-#define RG_PHY_SPEED_MASK (BIT(2) | BIT(3)) +-#define RG_PHY_SPEED_1_25G 0x0 +-#define RG_PHY_SPEED_3_125G BIT(2) +- +-/* Register to power up QPHY */ +-#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 +-#define SGMII_PHYA_PWD BIT(4) +- +-/* Register to QPHY wrapper control */ +-#define SGMSYS_QPHY_WRAP_CTRL 0xec +-#define SGMII_PN_SWAP_MASK GENMASK(1, 0) +-#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) +-#define MTK_SGMII_FLAG_PN_SWAP BIT(0) +- + /* Infrasys subsystem config registers */ + #define INFRA_MISC2 0x70c + #define CO_QPHY_SEL BIT(0) +@@ -1105,31 +1046,6 @@ struct mtk_soc_data { + /* currently no SoC has more than 2 macs */ + #define MTK_MAX_DEVS 2 + +-/* struct mtk_pcs - This structure holds each sgmii regmap and associated +- * data +- * @regmap: The register map pointing at the range used to setup +- * SGMII modes +- * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap +- * @interface: Currently configured interface mode +- * @pcs: Phylink PCS structure +- * @flags: Flags indicating hardware properties +- */ +-struct mtk_pcs { +- struct regmap *regmap; +- u32 ana_rgc3; +- phy_interface_t interface; +- struct phylink_pcs pcs; +- u32 flags; +-}; +- +-/* struct mtk_sgmii - This is the structure holding sgmii regmap and its +- * characteristics +- * @pcs Array of individual PCS structures +- */ +-struct mtk_sgmii { +- struct mtk_pcs pcs[MTK_MAX_DEVS]; +-}; +- + /* struct mtk_eth - This is the main datasructure for holding the state + * of the driver + * @dev: The device pointer +@@ -1149,6 +1065,7 @@ struct mtk_sgmii { + * MII modes + * @infra: The register map pointing at the range used to setup + * SGMII and GePHY path ++ * @sgmii_pcs: Pointers to mtk-pcs-lynxi phylink_pcs instances + * @pctl: The register map pointing at the range used to setup + * GMAC port drive/slew values + * @dma_refcnt: track how many netdevs are using the DMA engine +@@ -1189,8 +1106,8 @@ struct mtk_eth { + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; +- struct regmap *infra; +- struct mtk_sgmii *sgmii; ++ struct regmap *infra; ++ struct phylink_pcs *sgmii_pcs[MTK_MAX_DEVS]; + struct regmap *pctl; + bool hwlro; + refcount_t dma_refcnt; +@@ -1352,10 +1269,6 @@ void mtk_stats_update_mac(struct mtk_mac + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); + u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + +-struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id); +-int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, +- u32 ana_rgc3); +- + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ /dev/null +@@ -1,217 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018-2019 MediaTek Inc. +- +-/* A library for MediaTek SGMII circuit +- * +- * Author: Sean Wang +- * +- */ +- +-#include +-#include +-#include +-#include +- +-#include "mtk_eth_soc.h" +- +-static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs) +-{ +- return container_of(pcs, struct mtk_pcs, pcs); +-} +- +-static void mtk_pcs_get_state(struct phylink_pcs *pcs, +- struct phylink_link_state *state) +-{ +- struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int bm, adv; +- +- /* Read the BMSR and LPA */ +- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); +- regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); +- +- phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), +- FIELD_GET(SGMII_LPA, adv)); +-} +- +-static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +- phy_interface_t interface, +- const unsigned long *advertising, +- bool permit_pause_to_mac) +-{ +- bool mode_changed = false, changed, use_an; +- struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int rgc3, sgm_mode, bmcr; +- int advertise, link_timer; +- +- advertise = phylink_mii_c22_pcs_encode_advertisement(interface, +- advertising); +- if (advertise < 0) +- return advertise; +- +- /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and +- * we assume that fixes it's speed at bitrate = line rate (in +- * other words, 1000Mbps or 2500Mbps). +- */ +- if (interface == PHY_INTERFACE_MODE_SGMII) { +- sgm_mode = SGMII_IF_MODE_SGMII; +- if (phylink_autoneg_inband(mode)) { +- sgm_mode |= SGMII_REMOTE_FAULT_DIS | +- SGMII_SPEED_DUPLEX_AN; +- use_an = true; +- } else { +- use_an = false; +- } +- } else if (phylink_autoneg_inband(mode)) { +- /* 1000base-X or 2500base-X autoneg */ +- sgm_mode = SGMII_REMOTE_FAULT_DIS; +- use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +- advertising); +- } else { +- /* 1000base-X or 2500base-X without autoneg */ +- sgm_mode = 0; +- use_an = false; +- } +- +- if (use_an) { +- bmcr = SGMII_AN_ENABLE; +- } else { +- bmcr = 0; +- } +- +- if (mpcs->interface != interface) { +- link_timer = phylink_get_link_timer_ns(interface); +- if (link_timer < 0) +- return link_timer; +- +- /* PHYA power down */ +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, SGMII_PHYA_PWD); +- +- if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP) +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, +- SGMII_PN_SWAP_MASK, +- SGMII_PN_SWAP_TX_RX); +- +- /* Reset SGMII PCS state */ +- regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0, +- SGMII_SW_RESET, SGMII_SW_RESET); +- +- if (interface == PHY_INTERFACE_MODE_2500BASEX) +- rgc3 = RG_PHY_SPEED_3_125G; +- else +- rgc3 = 0; +- +- /* Configure the underlying interface speed */ +- regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, +- RG_PHY_SPEED_3_125G, rgc3); +- +- /* Setup the link timer */ +- regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); +- +- mpcs->interface = interface; +- mode_changed = true; +- } +- +- /* Update the advertisement, noting whether it has changed */ +- regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, +- SGMII_ADVERTISE, advertise, &changed); +- +- /* Update the sgmsys mode register */ +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | +- SGMII_IF_MODE_SGMII, sgm_mode); +- +- /* Update the BMCR */ +- regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_ENABLE, bmcr); +- +- /* Release PHYA power down state +- * Only removing bit SGMII_PHYA_PWD isn't enough. +- * There are cases when the SGMII_PHYA_PWD register contains 0x9 which +- * prevents SGMII from working. The SGMII still shows link but no traffic +- * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was +- * taken from a good working state of the SGMII interface. +- * Unknown how much the QPHY needs but it is racy without a sleep. +- * Tested on mt7622 & mt7986. +- */ +- usleep_range(50, 100); +- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); +- +- return changed || mode_changed; +-} +- +-static void mtk_pcs_restart_an(struct phylink_pcs *pcs) +-{ +- struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- +- regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_RESTART, SGMII_AN_RESTART); +-} +- +-static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +- phy_interface_t interface, int speed, int duplex) +-{ +- struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int sgm_mode; +- +- if (!phylink_autoneg_inband(mode)) { +- /* Force the speed and duplex setting */ +- if (speed == SPEED_10) +- sgm_mode = SGMII_SPEED_10; +- else if (speed == SPEED_100) +- sgm_mode = SGMII_SPEED_100; +- else +- sgm_mode = SGMII_SPEED_1000; +- +- if (duplex != DUPLEX_FULL) +- sgm_mode |= SGMII_DUPLEX_HALF; +- +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_DUPLEX_HALF | SGMII_SPEED_MASK, +- sgm_mode); +- } +-} +- +-static const struct phylink_pcs_ops mtk_pcs_ops = { +- .pcs_get_state = mtk_pcs_get_state, +- .pcs_config = mtk_pcs_config, +- .pcs_an_restart = mtk_pcs_restart_an, +- .pcs_link_up = mtk_pcs_link_up, +-}; +- +-int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) +-{ +- struct device_node *np; +- int i; +- +- for (i = 0; i < MTK_MAX_DEVS; i++) { +- np = of_parse_phandle(r, "mediatek,sgmiisys", i); +- if (!np) +- break; +- +- ss->pcs[i].ana_rgc3 = ana_rgc3; +- ss->pcs[i].regmap = syscon_node_to_regmap(np); +- +- ss->pcs[i].flags = 0; +- if (of_property_read_bool(np, "mediatek,pnswap")) +- ss->pcs[i].flags |= MTK_SGMII_FLAG_PN_SWAP; +- +- of_node_put(np); +- if (IS_ERR(ss->pcs[i].regmap)) +- return PTR_ERR(ss->pcs[i].regmap); +- +- ss->pcs[i].pcs.ops = &mtk_pcs_ops; +- ss->pcs[i].pcs.poll = true; +- ss->pcs[i].interface = PHY_INTERFACE_MODE_NA; +- } +- +- return 0; +-} +- +-struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id) +-{ +- if (!ss->pcs[id].regmap) +- return NULL; +- +- return &ss->pcs[id].pcs; +-} diff --git a/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch b/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch index 75393bcce70..5dcbc6c46a2 100644 --- a/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch +++ b/target/linux/generic/pending-5.15/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2993,8 +2993,8 @@ static irqreturn_t mtk_handle_irq_rx(int +@@ -2994,8 +2994,8 @@ static irqreturn_t mtk_handle_irq_rx(int eth->rx_events++; if (likely(napi_schedule_prep(ð->rx_napi))) { @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -3006,8 +3006,8 @@ static irqreturn_t mtk_handle_irq_tx(int +@@ -3007,8 +3007,8 @@ static irqreturn_t mtk_handle_irq_tx(int eth->tx_events++; if (likely(napi_schedule_prep(ð->tx_napi))) { @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -4638,6 +4638,8 @@ static int mtk_probe(struct platform_dev +@@ -4675,6 +4675,8 @@ static int mtk_probe(struct platform_dev * for NAPI to work */ init_dummy_netdev(ð->dummy_dev); diff --git a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch index c6572214fb8..c7e1d3f6f08 100644 --- a/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch +++ b/target/linux/generic/pending-5.15/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch @@ -53,7 +53,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4607,8 +4607,8 @@ static int mtk_probe(struct platform_dev +@@ -4644,8 +4644,8 @@ static int mtk_probe(struct platform_dev for (i = 0; i < num_ppe; i++) { u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; @@ -64,7 +64,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov if (!eth->ppe[i]) { err = -ENOMEM; goto err_free_dev; -@@ -4733,6 +4733,7 @@ static const struct mtk_soc_data mt7622_ +@@ -4772,6 +4772,7 @@ static const struct mtk_soc_data mt7622_ .required_pctl = false, .offload_version = 2, .hash_offset = 2, @@ -72,7 +72,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), -@@ -4770,6 +4771,7 @@ static const struct mtk_soc_data mt7629_ +@@ -4809,6 +4810,7 @@ static const struct mtk_soc_data mt7629_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7629_CLKS_BITMAP, .required_pctl = false, @@ -80,7 +80,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4790,6 +4792,7 @@ static const struct mtk_soc_data mt7986_ +@@ -4829,6 +4831,7 @@ static const struct mtk_soc_data mt7981_ .offload_version = 2, .hash_offset = 4, .foe_entry_size = sizeof(struct mtk_foe_entry), @@ -90,7 +90,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .rxd_size = sizeof(struct mtk_rx_dma_v2), --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1044,6 +1044,8 @@ struct mtk_reg_map { +@@ -1014,6 +1014,8 @@ struct mtk_reg_map { * the extra setup for those pins used by GMAC. * @hash_offset Flow table hash offset. * @foe_entry_size Foe table entry size. @@ -99,7 +99,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov * @txd_size Tx DMA descriptor size. * @rxd_size Rx DMA descriptor size. * @rx_irq_done_mask Rx irq done register mask. -@@ -1061,6 +1063,7 @@ struct mtk_soc_data { +@@ -1031,6 +1033,7 @@ struct mtk_soc_data { u8 hash_offset; u16 foe_entry_size; netdev_features_t hw_features; diff --git a/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch b/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch index 84afb3f46a8..b5e118f9fab 100644 --- a/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch +++ b/target/linux/generic/pending-5.15/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch @@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1851,9 +1851,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1852,9 +1852,7 @@ static int mtk_poll_rx(struct napi_struc while (done < budget) { unsigned int pktlen, *rxdcsum; @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau dma_addr_t dma_addr; u32 hash, reason; int mac = 0; -@@ -1988,36 +1986,21 @@ static int mtk_poll_rx(struct napi_struc +@@ -1989,36 +1987,21 @@ static int mtk_poll_rx(struct napi_struc skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); @@ -70,7 +70,7 @@ Signed-off-by: Felix Fietkau skb_record_rx_queue(skb, 0); napi_gro_receive(napi, skb); -@@ -2832,29 +2815,11 @@ static netdev_features_t mtk_fix_feature +@@ -2833,29 +2816,11 @@ static netdev_features_t mtk_fix_feature static int mtk_set_features(struct net_device *dev, netdev_features_t features) { @@ -100,7 +100,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3168,30 +3133,6 @@ static int mtk_open(struct net_device *d +@@ -3169,30 +3134,6 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; int i, err; @@ -131,7 +131,7 @@ Signed-off-by: Felix Fietkau err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); if (err) { netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, -@@ -3232,6 +3173,35 @@ static int mtk_open(struct net_device *d +@@ -3233,6 +3174,35 @@ static int mtk_open(struct net_device *d phylink_start(mac->phylink); netif_tx_start_all_queues(dev); @@ -167,7 +167,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3716,10 +3686,9 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3717,10 +3687,9 @@ static int mtk_hw_init(struct mtk_eth *e if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { val = mtk_r32(eth, MTK_CDMP_IG_CTRL); mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); @@ -180,7 +180,7 @@ Signed-off-by: Felix Fietkau /* set interrupt delays based on current Net DIM sample */ mtk_dim_rx(ð->rx_dim.work); -@@ -4357,7 +4326,7 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4367,7 +4336,7 @@ static int mtk_add_mac(struct mtk_eth *e eth->netdev[id]->hw_features |= NETIF_F_LRO; eth->netdev[id]->vlan_features = eth->soc->hw_features & diff --git a/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch b/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch index 0ed8c695e92..72bad79c138 100644 --- a/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch +++ b/target/linux/generic/pending-5.15/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch @@ -16,7 +16,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1424,12 +1424,28 @@ static void mtk_wake_queue(struct mtk_et +@@ -1425,12 +1425,28 @@ static void mtk_wake_queue(struct mtk_et } } @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau bool gso = false; int tx_num; -@@ -1451,6 +1467,18 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1452,6 +1468,18 @@ static netdev_tx_t mtk_start_xmit(struct return NETDEV_TX_BUSY; } @@ -64,7 +64,7 @@ Signed-off-by: Felix Fietkau /* TSO: fill MSS info in tcp checksum field */ if (skb_is_gso(skb)) { if (skb_cow_head(skb, 0)) { -@@ -1466,8 +1494,14 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1467,8 +1495,14 @@ static netdev_tx_t mtk_start_xmit(struct } } diff --git a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch index f6919dc19ef..4f765c5c145 100644 --- a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch +++ b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1364,6 +1364,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk +@@ -1277,6 +1277,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk int mtk_eth_offload_init(struct mtk_eth *eth); int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data); diff --git a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch index d72776d9c46..ffa98e3f0d9 100644 --- a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch +++ b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch @@ -20,7 +20,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -230,13 +230,35 @@ static int _mtk_mdio_write(struct mtk_et +@@ -231,13 +231,35 @@ static int _mtk_mdio_write(struct mtk_et if (ret < 0) return ret; @@ -63,7 +63,7 @@ Signed-off-by: David S. Miller ret = mtk_mdio_busy_wait(eth); if (ret < 0) -@@ -253,12 +275,33 @@ static int _mtk_mdio_read(struct mtk_eth +@@ -254,12 +276,33 @@ static int _mtk_mdio_read(struct mtk_eth if (ret < 0) return ret; @@ -103,7 +103,7 @@ Signed-off-by: David S. Miller ret = mtk_mdio_busy_wait(eth); if (ret < 0) -@@ -729,6 +772,7 @@ static int mtk_mdio_init(struct mtk_eth +@@ -730,6 +773,7 @@ static int mtk_mdio_init(struct mtk_eth eth->mii_bus->name = "mdio"; eth->mii_bus->read = mtk_mdio_read; eth->mii_bus->write = mtk_mdio_write; diff --git a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch index 72faba8a9ee..c3e0a342a19 100644 --- a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch +++ b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch @@ -14,7 +14,7 @@ Signed-off-by: René van Dorst --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4228,6 +4228,7 @@ static const struct net_device_ops mtk_n +@@ -4259,6 +4259,7 @@ static const struct net_device_ops mtk_n static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) { @@ -22,7 +22,7 @@ Signed-off-by: René van Dorst const __be32 *_id = of_get_property(np, "reg", NULL); phy_interface_t phy_mode; struct phylink *phylink; -@@ -4356,6 +4357,9 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4387,6 +4388,9 @@ static int mtk_add_mac(struct mtk_eth *e register_netdevice_notifier(&mac->device_notifier); } From d308479d10f7c40ccff725f6c2252f6c94df0829 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 11 Mar 2023 17:55:56 +0000 Subject: [PATCH 45/53] generic: backport regmap reg_base and downshift features Backport new regmap features from Linux 5.18 which are needed to let mt7530 use pcs-mtk-lynxi. Signed-off-by: Daniel Golle --- ...configurable-downshift-for-addresses.patch | 90 ++++++++++++++++++ ...efined-reg_base-to-be-added-to-every.patch | 95 +++++++++++++++++++ ..._base-and-reg_downshift-for-single-r.patch | 57 +++++++++++ .../hack-5.15/259-regmap_dynamic.patch | 2 +- 4 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 target/linux/generic/backport-5.15/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch create mode 100644 target/linux/generic/backport-5.15/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch create mode 100644 target/linux/generic/backport-5.15/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch diff --git a/target/linux/generic/backport-5.15/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch b/target/linux/generic/backport-5.15/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch new file mode 100644 index 00000000000..99cd89ea002 --- /dev/null +++ b/target/linux/generic/backport-5.15/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch @@ -0,0 +1,90 @@ +From 86fc59ef818beb0e1945d17f8e734898baba7e4e Mon Sep 17 00:00:00 2001 +From: Colin Foster +Date: Sun, 13 Mar 2022 15:45:23 -0700 +Subject: [PATCH 1/2] regmap: add configurable downshift for addresses + +Add an additional reg_downshift to be applied to register addresses before +any register accesses. An example of a device that uses this is a VSC7514 +chip, which require each register address to be downshifted by two if the +access is performed over a SPI bus. + +Signed-off-by: Colin Foster +Link: https://lore.kernel.org/r/20220313224524.399947-2-colin.foster@in-advantage.com +Signed-off-by: Mark Brown +--- + drivers/base/regmap/internal.h | 1 + + drivers/base/regmap/regmap.c | 5 +++++ + include/linux/regmap.h | 3 +++ + 3 files changed, 9 insertions(+) + +--- a/drivers/base/regmap/internal.h ++++ b/drivers/base/regmap/internal.h +@@ -31,6 +31,7 @@ struct regmap_format { + size_t buf_size; + size_t reg_bytes; + size_t pad_bytes; ++ size_t reg_downshift; + size_t val_bytes; + void (*format_write)(struct regmap *map, + unsigned int reg, unsigned int val); +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -823,6 +823,7 @@ struct regmap *__regmap_init(struct devi + + map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); + map->format.pad_bytes = config->pad_bits / 8; ++ map->format.reg_downshift = config->reg_downshift; + map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); + map->format.buf_size = DIV_ROUND_UP(config->reg_bits + + config->val_bits + config->pad_bits, 8); +@@ -1735,6 +1736,7 @@ static int _regmap_raw_write_impl(struct + return ret; + } + ++ reg >>= map->format.reg_downshift; + map->format.format_reg(map->work_buf, reg, map->reg_shift); + regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, + map->write_flag_mask); +@@ -1905,6 +1907,7 @@ static int _regmap_bus_formatted_write(v + return ret; + } + ++ reg >>= map->format.reg_downshift; + map->format.format_write(map, reg, val); + + trace_regmap_hw_write_start(map, reg, 1); +@@ -2346,6 +2349,7 @@ static int _regmap_raw_multi_reg_write(s + unsigned int reg = regs[i].reg; + unsigned int val = regs[i].def; + trace_regmap_hw_write_start(map, reg, 1); ++ reg >>= map->format.reg_downshift; + map->format.format_reg(u8, reg, map->reg_shift); + u8 += reg_bytes + pad_bytes; + map->format.format_val(u8, val, 0); +@@ -2673,6 +2677,7 @@ static int _regmap_raw_read(struct regma + return ret; + } + ++ reg >>= map->format.reg_downshift; + map->format.format_reg(map->work_buf, reg, map->reg_shift); + regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, + map->read_flag_mask); +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -237,6 +237,8 @@ typedef void (*regmap_unlock)(void *); + * @reg_stride: The register address stride. Valid register addresses are a + * multiple of this value. If set to 0, a value of 1 will be + * used. ++ * @reg_downshift: The number of bits to downshift the register before ++ * performing any operations. + * @pad_bits: Number of bits of padding between register and value. + * @val_bits: Number of bits in a register value, mandatory. + * +@@ -360,6 +362,7 @@ struct regmap_config { + + int reg_bits; + int reg_stride; ++ int reg_downshift; + int pad_bits; + int val_bits; + diff --git a/target/linux/generic/backport-5.15/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch b/target/linux/generic/backport-5.15/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch new file mode 100644 index 00000000000..0f32288fcab --- /dev/null +++ b/target/linux/generic/backport-5.15/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch @@ -0,0 +1,95 @@ +From 0074f3f2b1e43d3cedd97e47fb6980db6d2ba79e Mon Sep 17 00:00:00 2001 +From: Colin Foster +Date: Sun, 13 Mar 2022 15:45:24 -0700 +Subject: [PATCH 2/2] regmap: allow a defined reg_base to be added to every + address + +There's an inconsistency that arises when a register set can be accessed +internally via MMIO, or externally via SPI. The VSC7514 chip allows both +modes of operation. When internally accessed, the system utilizes __iomem, +devm_ioremap_resource, and devm_regmap_init_mmio. + +For SPI it isn't possible to utilize memory-mapped IO. To properly operate, +the resource base must be added to the register before every operation. + +Signed-off-by: Colin Foster +Link: https://lore.kernel.org/r/20220313224524.399947-3-colin.foster@in-advantage.com +Signed-off-by: Mark Brown +--- + drivers/base/regmap/internal.h | 1 + + drivers/base/regmap/regmap.c | 6 ++++++ + include/linux/regmap.h | 3 +++ + 3 files changed, 10 insertions(+) + +--- a/drivers/base/regmap/internal.h ++++ b/drivers/base/regmap/internal.h +@@ -63,6 +63,7 @@ struct regmap { + regmap_unlock unlock; + void *lock_arg; /* This is passed to lock/unlock functions */ + gfp_t alloc_flags; ++ unsigned int reg_base; + + struct device *dev; /* Device we do I/O on */ + void *work_buf; /* Scratch buffer used to format I/O */ +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -821,6 +821,8 @@ struct regmap *__regmap_init(struct devi + else + map->alloc_flags = GFP_KERNEL; + ++ map->reg_base = config->reg_base; ++ + map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); + map->format.pad_bytes = config->pad_bits / 8; + map->format.reg_downshift = config->reg_downshift; +@@ -1736,6 +1738,7 @@ static int _regmap_raw_write_impl(struct + return ret; + } + ++ reg += map->reg_base; + reg >>= map->format.reg_downshift; + map->format.format_reg(map->work_buf, reg, map->reg_shift); + regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, +@@ -1907,6 +1910,7 @@ static int _regmap_bus_formatted_write(v + return ret; + } + ++ reg += map->reg_base; + reg >>= map->format.reg_downshift; + map->format.format_write(map, reg, val); + +@@ -2349,6 +2353,7 @@ static int _regmap_raw_multi_reg_write(s + unsigned int reg = regs[i].reg; + unsigned int val = regs[i].def; + trace_regmap_hw_write_start(map, reg, 1); ++ reg += map->reg_base; + reg >>= map->format.reg_downshift; + map->format.format_reg(u8, reg, map->reg_shift); + u8 += reg_bytes + pad_bytes; +@@ -2677,6 +2682,7 @@ static int _regmap_raw_read(struct regma + return ret; + } + ++ reg += map->reg_base; + reg >>= map->format.reg_downshift; + map->format.format_reg(map->work_buf, reg, map->reg_shift); + regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -239,6 +239,8 @@ typedef void (*regmap_unlock)(void *); + * used. + * @reg_downshift: The number of bits to downshift the register before + * performing any operations. ++ * @reg_base: Value to be added to every register address before performing any ++ * operation. + * @pad_bits: Number of bits of padding between register and value. + * @val_bits: Number of bits in a register value, mandatory. + * +@@ -363,6 +365,7 @@ struct regmap_config { + int reg_bits; + int reg_stride; + int reg_downshift; ++ unsigned int reg_base; + int pad_bits; + int val_bits; + diff --git a/target/linux/generic/backport-5.15/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch b/target/linux/generic/backport-5.15/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch new file mode 100644 index 00000000000..804f68d23c5 --- /dev/null +++ b/target/linux/generic/backport-5.15/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch @@ -0,0 +1,57 @@ +From 697c3892d825fb78f42ec8e53bed065dd728db3e Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 30 Jan 2023 02:04:57 +0000 +Subject: [PATCH] regmap: apply reg_base and reg_downshift for single register + ops + +reg_base and reg_downshift currently don't have any effect if used with +a regmap_bus or regmap_config which only offers single register +operations (ie. reg_read, reg_write and optionally reg_update_bits). + +Fix that and take them into account also for regmap_bus with only +reg_read and read_write operations by applying reg_base and +reg_downshift in _regmap_bus_reg_write, _regmap_bus_reg_read. + +Also apply reg_base and reg_downshift in _regmap_update_bits, but only +in case the operation is carried out with a reg_update_bits call +defined in either regmap_bus or regmap_config. + +Fixes: 0074f3f2b1e43d ("regmap: allow a defined reg_base to be added to every address") +Fixes: 86fc59ef818beb ("regmap: add configurable downshift for addresses") +Signed-off-by: Daniel Golle +Tested-by: Colin Foster +Link: https://lore.kernel.org/r/Y9clyVS3tQEHlUhA@makrotopia.org +Signed-off-by: Mark Brown +--- + drivers/base/regmap/regmap.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -1929,6 +1929,8 @@ static int _regmap_bus_reg_write(void *c + { + struct regmap *map = context; + ++ reg += map->reg_base; ++ reg >>= map->format.reg_downshift; + return map->bus->reg_write(map->bus_context, reg, val); + } + +@@ -2703,6 +2705,8 @@ static int _regmap_bus_reg_read(void *co + { + struct regmap *map = context; + ++ reg += map->reg_base; ++ reg >>= map->format.reg_downshift; + return map->bus->reg_read(map->bus_context, reg, val); + } + +@@ -3078,6 +3082,8 @@ static int _regmap_update_bits(struct re + *change = false; + + if (regmap_volatile(map, reg) && map->reg_update_bits) { ++ reg += map->reg_base; ++ reg >>= map->format.reg_downshift; + ret = map->reg_update_bits(map->bus_context, reg, mask, val); + if (ret == 0 && change) + *change = true; diff --git a/target/linux/generic/hack-5.15/259-regmap_dynamic.patch b/target/linux/generic/hack-5.15/259-regmap_dynamic.patch index 6be5875177c..76a5ace6f31 100644 --- a/target/linux/generic/hack-5.15/259-regmap_dynamic.patch +++ b/target/linux/generic/hack-5.15/259-regmap_dynamic.patch @@ -125,7 +125,7 @@ Signed-off-by: Felix Fietkau #include #include #include -@@ -3341,3 +3342,5 @@ static int __init regmap_initcall(void) +@@ -3358,3 +3359,5 @@ static int __init regmap_initcall(void) return 0; } postcore_initcall(regmap_initcall); From b62f58891ae1b3013720b6c8e4b9dec2b0491edf Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 11 Mar 2023 17:58:12 +0000 Subject: [PATCH 46/53] generic: dsa: make use of pcs-mtk-lynxi also for mt7530 The MT7531 switch IC comes with SerDes ports with PCS identical to what is also used in MediaTek's SoCs. Make use of the shared driver to ease maintainance and reduce code duplication. Signed-off-by: Daniel Golle --- ...t-dsa-mt7530-use-external-PCS-driver.patch | 514 ++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 target/linux/generic/backport-5.15/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch diff --git a/target/linux/generic/backport-5.15/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch b/target/linux/generic/backport-5.15/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch new file mode 100644 index 00000000000..f55b7aa8ea8 --- /dev/null +++ b/target/linux/generic/backport-5.15/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch @@ -0,0 +1,514 @@ +From patchwork Thu Mar 9 10:57:44 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 13167235 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +Date: Thu, 9 Mar 2023 10:57:44 +0000 +From: Daniel Golle +To: netdev@vger.kernel.org, linux-mediatek@lists.infradead.org, + linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, + Russell King , + Heiner Kallweit , + Lorenzo Bianconi , + Mark Lee , + John Crispin , Felix Fietkau , + AngeloGioacchino Del Regno + , + Matthias Brugger , + DENG Qingfang , + Landen Chao , + Sean Wang , + Paolo Abeni , + Jakub Kicinski , + Eric Dumazet , + "David S. Miller" , + Vladimir Oltean , + Florian Fainelli , + Andrew Lunn , + Vladimir Oltean +Cc: =?iso-8859-1?q?Bj=F8rn?= Mork , + Frank Wunderlich , + Alexander Couzens +Subject: [PATCH net-next v13 11/16] net: dsa: mt7530: use external PCS driver +Message-ID: + <2ac2ee40d3b0e705461b50613fda6a7edfdbc4b3.1678357225.git.daniel@makrotopia.org> +References: +MIME-Version: 1.0 +Content-Disposition: inline +In-Reply-To: +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +Implement regmap access wrappers, for now only to be used by the +pcs-mtk driver. +Make use of external PCS driver and drop the reduntant implementation +in mt7530.c. +As a nice side effect the SGMII registers can now also more easily be +inspected for debugging via /sys/kernel/debug/regmap. + +Reviewed-by: Russell King (Oracle) +Tested-by: Bjørn Mork +Signed-off-by: Daniel Golle +Tested-by: Frank Wunderlich +--- + drivers/net/dsa/Kconfig | 1 + + drivers/net/dsa/mt7530.c | 277 ++++++++++----------------------------- + drivers/net/dsa/mt7530.h | 47 +------ + 3 files changed, 71 insertions(+), 254 deletions(-) + +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -37,6 +37,7 @@ config NET_DSA_MT7530 + tristate "MediaTek MT753x and MT7621 Ethernet switch support" + select NET_DSA_TAG_MTK + select MEDIATEK_GE_PHY ++ select PCS_MTK_LYNXI + help + This enables support for the MediaTek MT7530, MT7531, and MT7621 + Ethernet switch chips. +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2568,128 +2569,11 @@ static int mt7531_rgmii_setup(struct mt7 + return 0; + } + +-static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +- phy_interface_t interface, int speed, int duplex) +-{ +- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; +- int port = pcs_to_mt753x_pcs(pcs)->port; +- unsigned int val; +- +- /* For adjusting speed and duplex of SGMII force mode. */ +- if (interface != PHY_INTERFACE_MODE_SGMII || +- phylink_autoneg_inband(mode)) +- return; +- +- /* SGMII force mode setting */ +- val = mt7530_read(priv, MT7531_SGMII_MODE(port)); +- val &= ~MT7531_SGMII_IF_MODE_MASK; +- +- switch (speed) { +- case SPEED_10: +- val |= MT7531_SGMII_FORCE_SPEED_10; +- break; +- case SPEED_100: +- val |= MT7531_SGMII_FORCE_SPEED_100; +- break; +- case SPEED_1000: +- val |= MT7531_SGMII_FORCE_SPEED_1000; +- break; +- } +- +- /* MT7531 SGMII 1G force mode can only work in full duplex mode, +- * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. +- * +- * The speed check is unnecessary as the MAC capabilities apply +- * this restriction. --rmk +- */ +- if ((speed == SPEED_10 || speed == SPEED_100) && +- duplex != DUPLEX_FULL) +- val |= MT7531_SGMII_FORCE_HALF_DUPLEX; +- +- mt7530_write(priv, MT7531_SGMII_MODE(port), val); +-} +- + static bool mt753x_is_mac_port(u32 port) + { + return (port == 5 || port == 6); + } + +-static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port, +- phy_interface_t interface) +-{ +- u32 val; +- +- if (!mt753x_is_mac_port(port)) +- return -EINVAL; +- +- mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), +- MT7531_SGMII_PHYA_PWD); +- +- val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port)); +- val &= ~MT7531_RG_TPHY_SPEED_MASK; +- /* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B +- * encoding. +- */ +- val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ? +- MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G; +- mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val); +- +- mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); +- +- /* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex +- * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. +- */ +- mt7530_rmw(priv, MT7531_SGMII_MODE(port), +- MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS, +- MT7531_SGMII_FORCE_SPEED_1000); +- +- mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); +- +- return 0; +-} +- +-static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port, +- phy_interface_t interface) +-{ +- if (!mt753x_is_mac_port(port)) +- return -EINVAL; +- +- mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), +- MT7531_SGMII_PHYA_PWD); +- +- mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), +- MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G); +- +- mt7530_set(priv, MT7531_SGMII_MODE(port), +- MT7531_SGMII_REMOTE_FAULT_DIS | +- MT7531_SGMII_SPEED_DUPLEX_AN); +- +- mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port), +- MT7531_SGMII_TX_CONFIG_MASK, 1); +- +- mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); +- +- mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART); +- +- mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); +- +- return 0; +-} +- +-static void mt7531_pcs_an_restart(struct phylink_pcs *pcs) +-{ +- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; +- int port = pcs_to_mt753x_pcs(pcs)->port; +- u32 val; +- +- /* Only restart AN when AN is enabled */ +- val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); +- if (val & MT7531_SGMII_AN_ENABLE) { +- val |= MT7531_SGMII_AN_RESTART; +- mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val); +- } +-} +- + static int + mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, + phy_interface_t interface) +@@ -2712,11 +2596,11 @@ mt7531_mac_config(struct dsa_switch *ds, + phydev = dp->slave->phydev; + return mt7531_rgmii_setup(priv, port, interface, phydev); + case PHY_INTERFACE_MODE_SGMII: +- return mt7531_sgmii_setup_mode_an(priv, port, interface); + case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: +- return mt7531_sgmii_setup_mode_force(priv, port, interface); ++ /* handled in SGMII PCS driver */ ++ return 0; + default: + return -EINVAL; + } +@@ -2741,11 +2625,11 @@ mt753x_phylink_mac_select_pcs(struct dsa + + switch (interface) { + case PHY_INTERFACE_MODE_TRGMII: ++ return &priv->pcs[port].pcs; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: +- return &priv->pcs[port].pcs; +- ++ return priv->ports[port].sgmii_pcs; + default: + return NULL; + } +@@ -2986,86 +2870,6 @@ static void mt7530_pcs_get_state(struct + state->pause |= MLO_PAUSE_TX; + } + +-static int +-mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, +- struct phylink_link_state *state) +-{ +- u32 status, val; +- u16 config_reg; +- +- status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); +- state->link = !!(status & MT7531_SGMII_LINK_STATUS); +- state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE); +- if (state->interface == PHY_INTERFACE_MODE_SGMII && +- (status & MT7531_SGMII_AN_ENABLE)) { +- val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); +- config_reg = val >> 16; +- +- switch (config_reg & LPA_SGMII_SPD_MASK) { +- case LPA_SGMII_1000: +- state->speed = SPEED_1000; +- break; +- case LPA_SGMII_100: +- state->speed = SPEED_100; +- break; +- case LPA_SGMII_10: +- state->speed = SPEED_10; +- break; +- default: +- dev_err(priv->dev, "invalid sgmii PHY speed\n"); +- state->link = false; +- return -EINVAL; +- } +- +- if (config_reg & LPA_SGMII_FULL_DUPLEX) +- state->duplex = DUPLEX_FULL; +- else +- state->duplex = DUPLEX_HALF; +- } +- +- return 0; +-} +- +-static void +-mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, +- struct phylink_link_state *state) +-{ +- unsigned int val; +- +- val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); +- state->link = !!(val & MT7531_SGMII_LINK_STATUS); +- if (!state->link) +- return; +- +- state->an_complete = state->link; +- +- if (state->interface == PHY_INTERFACE_MODE_2500BASEX) +- state->speed = SPEED_2500; +- else +- state->speed = SPEED_1000; +- +- state->duplex = DUPLEX_FULL; +- state->pause = MLO_PAUSE_NONE; +-} +- +-static void mt7531_pcs_get_state(struct phylink_pcs *pcs, +- struct phylink_link_state *state) +-{ +- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; +- int port = pcs_to_mt753x_pcs(pcs)->port; +- +- if (state->interface == PHY_INTERFACE_MODE_SGMII) { +- mt7531_sgmii_pcs_get_state_an(priv, port, state); +- return; +- } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) || +- (state->interface == PHY_INTERFACE_MODE_2500BASEX)) { +- mt7531_sgmii_pcs_get_state_inband(priv, port, state); +- return; +- } +- +- state->link = false; +-} +- + static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, +@@ -3085,18 +2889,57 @@ static const struct phylink_pcs_ops mt75 + .pcs_an_restart = mt7530_pcs_an_restart, + }; + +-static const struct phylink_pcs_ops mt7531_pcs_ops = { +- .pcs_validate = mt753x_pcs_validate, +- .pcs_get_state = mt7531_pcs_get_state, +- .pcs_config = mt753x_pcs_config, +- .pcs_an_restart = mt7531_pcs_an_restart, +- .pcs_link_up = mt7531_pcs_link_up, ++static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val) ++{ ++ struct mt7530_priv *priv = context; ++ ++ *val = mt7530_read(priv, reg); ++ return 0; ++}; ++ ++static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val) ++{ ++ struct mt7530_priv *priv = context; ++ ++ mt7530_write(priv, reg, val); ++ return 0; ++}; ++ ++static int mt7530_regmap_update_bits(void *context, unsigned int reg, ++ unsigned int mask, unsigned int val) ++{ ++ struct mt7530_priv *priv = context; ++ ++ mt7530_rmw(priv, reg, mask, val); ++ return 0; ++}; ++ ++static const struct regmap_bus mt7531_regmap_bus = { ++ .reg_write = mt7530_regmap_write, ++ .reg_read = mt7530_regmap_read, ++ .reg_update_bits = mt7530_regmap_update_bits, ++}; ++ ++#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \ ++ { \ ++ .name = _name, \ ++ .reg_bits = 16, \ ++ .val_bits = 32, \ ++ .reg_stride = 4, \ ++ .reg_base = _reg_base, \ ++ .max_register = 0x17c, \ ++ } ++ ++static const struct regmap_config mt7531_pcs_config[] = { ++ MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)), ++ MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)), + }; + + static int + mt753x_setup(struct dsa_switch *ds) + { + struct mt7530_priv *priv = ds->priv; ++ struct regmap *regmap; + int i, ret; + + /* Initialise the PCS devices */ +@@ -3104,8 +2947,6 @@ mt753x_setup(struct dsa_switch *ds) + priv->pcs[i].pcs.ops = priv->info->pcs_ops; + priv->pcs[i].priv = priv; + priv->pcs[i].port = i; +- if (mt753x_is_mac_port(i)) +- priv->pcs[i].pcs.poll = 1; + } + + ret = priv->info->sw_setup(ds); +@@ -3120,6 +2961,16 @@ mt753x_setup(struct dsa_switch *ds) + if (ret && priv->irq) + mt7530_free_irq_common(priv); + ++ if (priv->id == ID_MT7531) ++ for (i = 0; i < 2; i++) { ++ regmap = devm_regmap_init(ds->dev, ++ &mt7531_regmap_bus, priv, ++ &mt7531_pcs_config[i]); ++ priv->ports[5 + i].sgmii_pcs = ++ mtk_pcs_lynxi_create(ds->dev, regmap, ++ MT7531_PHYA_CTRL_SIGNAL3, 0); ++ } ++ + return ret; + } + +@@ -3211,7 +3062,7 @@ static const struct mt753x_info mt753x_t + }, + [ID_MT7531] = { + .id = ID_MT7531, +- .pcs_ops = &mt7531_pcs_ops, ++ .pcs_ops = &mt7530_pcs_ops, + .sw_setup = mt7531_setup, + .phy_read = mt7531_ind_phy_read, + .phy_write = mt7531_ind_phy_write, +@@ -3319,7 +3170,7 @@ static void + mt7530_remove(struct mdio_device *mdiodev) + { + struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); +- int ret = 0; ++ int ret = 0, i; + + if (!priv) + return; +@@ -3338,6 +3189,10 @@ mt7530_remove(struct mdio_device *mdiode + mt7530_free_irq(priv); + + dsa_unregister_switch(priv->ds); ++ ++ for (i = 0; i < 2; ++i) ++ mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs); ++ + mutex_destroy(&priv->reg_mutex); + + dev_set_drvdata(&mdiodev->dev, NULL); +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -364,47 +364,8 @@ enum mt7530_vlan_port_acc_frm { + CCR_TX_OCT_CNT_BAD) + + /* MT7531 SGMII register group */ +-#define MT7531_SGMII_REG_BASE 0x5000 +-#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \ +- ((p) - 5) * 0x1000 + (r)) +- +-/* Register forSGMII PCS_CONTROL_1 */ +-#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(p, 0x00) +-#define MT7531_SGMII_LINK_STATUS BIT(18) +-#define MT7531_SGMII_AN_ENABLE BIT(12) +-#define MT7531_SGMII_AN_RESTART BIT(9) +-#define MT7531_SGMII_AN_COMPLETE BIT(21) +- +-/* Register for SGMII PCS_SPPED_ABILITY */ +-#define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08) +-#define MT7531_SGMII_TX_CONFIG_MASK GENMASK(15, 0) +-#define MT7531_SGMII_TX_CONFIG BIT(0) +- +-/* Register for SGMII_MODE */ +-#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(p, 0x20) +-#define MT7531_SGMII_REMOTE_FAULT_DIS BIT(8) +-#define MT7531_SGMII_IF_MODE_MASK GENMASK(5, 1) +-#define MT7531_SGMII_FORCE_DUPLEX BIT(4) +-#define MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2) +-#define MT7531_SGMII_FORCE_SPEED_1000 BIT(3) +-#define MT7531_SGMII_FORCE_SPEED_100 BIT(2) +-#define MT7531_SGMII_FORCE_SPEED_10 0 +-#define MT7531_SGMII_SPEED_DUPLEX_AN BIT(1) +- +-enum mt7531_sgmii_force_duplex { +- MT7531_SGMII_FORCE_FULL_DUPLEX = 0, +- MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10, +-}; +- +-/* Fields of QPHY_PWR_STATE_CTRL */ +-#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(p, 0xe8) +-#define MT7531_SGMII_PHYA_PWD BIT(4) +- +-/* Values of SGMII SPEED */ +-#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(p, 0x128) +-#define MT7531_RG_TPHY_SPEED_MASK (BIT(2) | BIT(3)) +-#define MT7531_RG_TPHY_SPEED_1_25G 0x0 +-#define MT7531_RG_TPHY_SPEED_3_125G BIT(2) ++#define MT7531_SGMII_REG_BASE(p) (0x5000 + ((p) - 5) * 0x1000) ++#define MT7531_PHYA_CTRL_SIGNAL3 0x128 + + /* Register for system reset */ + #define MT7530_SYS_CTRL 0x7000 +@@ -703,13 +664,13 @@ struct mt7530_fdb { + * @pm: The matrix used to show all connections with the port. + * @pvid: The VLAN specified is to be considered a PVID at ingress. Any + * untagged frames will be assigned to the related VLAN. +- * @vlan_filtering: The flags indicating whether the port that can recognize +- * VLAN-tagged frames. ++ * @sgmii_pcs: Pointer to PCS instance for SerDes ports + */ + struct mt7530_port { + bool enable; + u32 pm; + u16 pvid; ++ struct phylink_pcs *sgmii_pcs; + }; + + /* Port 5 interface select definitions */ From ad962c90c3b48f6cfa93bbd838526ab855f1c773 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 11 Mar 2023 03:51:00 +0000 Subject: [PATCH 47/53] mediatek: simplify MaxLinear GPY PHY driver The mxl-gpy driver apparently was built in the assumption that SGMII auto-negotiation is always switched on at the MAC. This may be true for few rather recent drivers (why?), but certainly isn't for most drivers unless 'managed = "in-band-status"' is set in device tree. Add patch to the mediatek target which reduces mxl-gpy to behave more like an ordinary PHY driver using out-of-band status. This allows to use these PHYs without rate-adaptation which seems to be at least partially broken/racy in some revisions of the PHY and/or internal PHY firmware. Signed-off-by: Daniel Golle --- ...et-phy-hack-mxl-gpy-disable-sgmii-an.patch | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 target/linux/mediatek/patches-5.15/731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch diff --git a/target/linux/mediatek/patches-5.15/731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch b/target/linux/mediatek/patches-5.15/731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch new file mode 100644 index 00000000000..2e39ca3c26a --- /dev/null +++ b/target/linux/mediatek/patches-5.15/731-net-phy-hack-mxl-gpy-disable-sgmii-an.patch @@ -0,0 +1,166 @@ +--- a/drivers/net/phy/mxl-gpy.c ++++ b/drivers/net/phy/mxl-gpy.c +@@ -126,6 +126,12 @@ static int gpy_config_init(struct phy_de + if (ret < 0) + return ret; + ++ /* Disable SGMII auto-negotiation */ ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, ++ VSPEC1_SGMII_CTRL_ANEN, 0); ++ if (ret < 0) ++ return ret; ++ + return gpy_led_write(phydev); + } + +@@ -151,65 +157,6 @@ static int gpy_probe(struct phy_device * + return 0; + } + +-static bool gpy_sgmii_need_reaneg(struct phy_device *phydev) +-{ +- int fw_ver, fw_type, fw_minor; +- size_t i; +- +- fw_ver = phy_read(phydev, PHY_FWV); +- if (fw_ver < 0) +- return true; +- +- fw_type = FIELD_GET(PHY_FWV_TYPE_MASK, fw_ver); +- fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, fw_ver); +- +- for (i = 0; i < ARRAY_SIZE(ver_need_sgmii_reaneg); i++) { +- if (fw_type != ver_need_sgmii_reaneg[i].type) +- continue; +- if (fw_minor < ver_need_sgmii_reaneg[i].minor) +- return true; +- break; +- } +- +- return false; +-} +- +-static bool gpy_2500basex_chk(struct phy_device *phydev) +-{ +- int ret; +- +- ret = phy_read(phydev, PHY_MIISTAT); +- if (ret < 0) { +- phydev_err(phydev, "Error: MDIO register access failed: %d\n", +- ret); +- return false; +- } +- +- if (!(ret & PHY_MIISTAT_LS) || +- FIELD_GET(PHY_MIISTAT_SPD_MASK, ret) != PHY_MIISTAT_SPD_2500) +- return false; +- +- phydev->speed = SPEED_2500; +- phydev->interface = PHY_INTERFACE_MODE_2500BASEX; +- phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, +- VSPEC1_SGMII_CTRL_ANEN, 0); +- return true; +-} +- +-static bool gpy_sgmii_aneg_en(struct phy_device *phydev) +-{ +- int ret; +- +- ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL); +- if (ret < 0) { +- phydev_err(phydev, "Error: MMD register access failed: %d\n", +- ret); +- return true; +- } +- +- return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false; +-} +- + static int gpy_config_aneg(struct phy_device *phydev) + { + bool changed = false; +@@ -248,53 +195,11 @@ static int gpy_config_aneg(struct phy_de + phydev->interface == PHY_INTERFACE_MODE_INTERNAL) + return 0; + +- /* No need to trigger re-ANEG if link speed is 2.5G or SGMII ANEG is +- * disabled. +- */ +- if (!gpy_sgmii_need_reaneg(phydev) || gpy_2500basex_chk(phydev) || +- !gpy_sgmii_aneg_en(phydev)) +- return 0; +- +- /* There is a design constraint in GPY2xx device where SGMII AN is +- * only triggered when there is change of speed. If, PHY link +- * partner`s speed is still same even after PHY TPI is down and up +- * again, SGMII AN is not triggered and hence no new in-band message +- * from GPY to MAC side SGMII. +- * This could cause an issue during power up, when PHY is up prior to +- * MAC. At this condition, once MAC side SGMII is up, MAC side SGMII +- * wouldn`t receive new in-band message from GPY with correct link +- * status, speed and duplex info. +- * +- * 1) If PHY is already up and TPI link status is still down (such as +- * hard reboot), TPI link status is polled for 4 seconds before +- * retriggerring SGMII AN. +- * 2) If PHY is already up and TPI link status is also up (such as soft +- * reboot), polling of TPI link status is not needed and SGMII AN is +- * immediately retriggered. +- * 3) Other conditions such as PHY is down, speed change etc, skip +- * retriggering SGMII AN. Note: in case of speed change, GPY FW will +- * initiate SGMII AN. +- */ +- +- if (phydev->state != PHY_UP) +- return 0; +- +- ret = phy_read_poll_timeout(phydev, MII_BMSR, ret, ret & BMSR_LSTATUS, +- 20000, 4000000, false); +- if (ret == -ETIMEDOUT) +- return 0; +- else if (ret < 0) +- return ret; +- +- /* Trigger SGMII AN. */ +- return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, +- VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS); ++ return 0; + } + + static void gpy_update_interface(struct phy_device *phydev) + { +- int ret; +- + /* Interface mode is fixed for USXGMII and integrated PHY */ + if (phydev->interface == PHY_INTERFACE_MODE_USXGMII || + phydev->interface == PHY_INTERFACE_MODE_INTERNAL) +@@ -306,29 +211,11 @@ static void gpy_update_interface(struct + switch (phydev->speed) { + case SPEED_2500: + phydev->interface = PHY_INTERFACE_MODE_2500BASEX; +- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, +- VSPEC1_SGMII_CTRL_ANEN, 0); +- if (ret < 0) +- phydev_err(phydev, +- "Error: Disable of SGMII ANEG failed: %d\n", +- ret); + break; + case SPEED_1000: + case SPEED_100: + case SPEED_10: + phydev->interface = PHY_INTERFACE_MODE_SGMII; +- if (gpy_sgmii_aneg_en(phydev)) +- break; +- /* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed +- * if ANEG is disabled (in 2500-BaseX mode). +- */ +- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, +- VSPEC1_SGMII_ANEN_ANRS, +- VSPEC1_SGMII_ANEN_ANRS); +- if (ret < 0) +- phydev_err(phydev, +- "Error: Enable of SGMII ANEG failed: %d\n", +- ret); + break; + } + } From be6bbd94845575302fc7e96b30d8f9dab0f62ddc Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 10 Mar 2023 19:55:09 +0000 Subject: [PATCH 48/53] mediatek: add I2C for MT7981 SoC Add patch to support I2C on the MT7981 SoC. This change will also be submitted to upstream Linux soon. Signed-off-by: Daniel Golle --- ...-mediatek-add-support-for-MT7981-SoC.patch | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 target/linux/mediatek/patches-5.15/810-i2c-mediatek-add-support-for-MT7981-SoC.patch diff --git a/target/linux/mediatek/patches-5.15/810-i2c-mediatek-add-support-for-MT7981-SoC.patch b/target/linux/mediatek/patches-5.15/810-i2c-mediatek-add-support-for-MT7981-SoC.patch new file mode 100644 index 00000000000..f9ad79c4430 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/810-i2c-mediatek-add-support-for-MT7981-SoC.patch @@ -0,0 +1,74 @@ +From bd4f7dae6a1f2fd65bb2112783c92ffe0839bc77 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 28 Feb 2023 23:53:56 +0000 +Subject: [PATCH] i2c: mediatek: add support for MT7981 SoC + +Signed-off-by: Daniel Golle +--- + drivers/i2c/busses/i2c-mt65xx.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/i2c/busses/i2c-mt65xx.c ++++ b/drivers/i2c/busses/i2c-mt65xx.c +@@ -202,6 +202,34 @@ static const u16 mt_i2c_regs_v2[] = { + [OFFSET_DCM_EN] = 0xf88, + }; + ++static const u16 mt_i2c_regs_v3[] = { ++ [OFFSET_DATA_PORT] = 0x0, ++ [OFFSET_INTR_MASK] = 0x8, ++ [OFFSET_INTR_STAT] = 0xc, ++ [OFFSET_CONTROL] = 0x10, ++ [OFFSET_TRANSFER_LEN] = 0x14, ++ [OFFSET_TRANSAC_LEN] = 0x18, ++ [OFFSET_DELAY_LEN] = 0x1c, ++ [OFFSET_TIMING] = 0x20, ++ [OFFSET_START] = 0x24, ++ [OFFSET_EXT_CONF] = 0x28, ++ [OFFSET_LTIMING] = 0x2c, ++ [OFFSET_HS] = 0x30, ++ [OFFSET_IO_CONFIG] = 0x34, ++ [OFFSET_FIFO_ADDR_CLR] = 0x38, ++ [OFFSET_SDA_TIMING] = 0x3c, ++ [OFFSET_TRANSFER_LEN_AUX] = 0x44, ++ [OFFSET_CLOCK_DIV] = 0x48, ++ [OFFSET_SOFTRESET] = 0x50, ++ [OFFSET_SCL_MIS_COMP_POINT] = 0x90, ++ [OFFSET_SLAVE_ADDR] = 0x94, ++ [OFFSET_DEBUGSTAT] = 0xe4, ++ [OFFSET_DEBUGCTRL] = 0xe8, ++ [OFFSET_FIFO_STAT] = 0xf4, ++ [OFFSET_FIFO_THRESH] = 0xf8, ++ [OFFSET_DCM_EN] = 0xf88, ++}; ++ + struct mtk_i2c_compatible { + const struct i2c_adapter_quirks *quirks; + const u16 *regs; +@@ -365,6 +393,18 @@ static const struct mtk_i2c_compatible m + .max_dma_support = 32, + }; + ++static const struct mtk_i2c_compatible mt7981_compat = { ++ .regs = mt_i2c_regs_v3, ++ .pmic_i2c = 0, ++ .dcm = 0, ++ .auto_restart = 1, ++ .aux_len_reg = 1, ++ .timing_adjust = 1, ++ .dma_sync = 1, ++ .ltiming_adjust = 1, ++ .max_dma_support = 33 ++}; ++ + static const struct mtk_i2c_compatible mt7986_compat = { + .quirks = &mt7622_i2c_quirks, + .regs = mt_i2c_regs_v1, +@@ -424,6 +464,7 @@ static const struct of_device_id mtk_i2c + { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat }, + { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat }, + { .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat }, ++ { .compatible = "mediatek,mt7981-i2c", .data = &mt7981_compat }, + { .compatible = "mediatek,mt7986-i2c", .data = &mt7986_compat }, + { .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat }, + { .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat }, From 3542ee9d1f463fd39912548515dbb8ca48414a77 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 10 Mar 2023 19:57:18 +0000 Subject: [PATCH 49/53] mediatek: add PWM support for MT7981 SoC Add patch to support PWM on the MT7981 SoC. This patch will also be submitted to upstream Linux soon. Signed-off-by: Daniel Golle --- ...-pwm-mediatek-Add-support-for-MT7981.patch | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 target/linux/mediatek/patches-5.15/811-pwm-mediatek-Add-support-for-MT7981.patch diff --git a/target/linux/mediatek/patches-5.15/811-pwm-mediatek-Add-support-for-MT7981.patch b/target/linux/mediatek/patches-5.15/811-pwm-mediatek-Add-support-for-MT7981.patch new file mode 100644 index 00000000000..ab465a7582f --- /dev/null +++ b/target/linux/mediatek/patches-5.15/811-pwm-mediatek-Add-support-for-MT7981.patch @@ -0,0 +1,212 @@ +From 947b535ebfe161e1725f1030a09de10d1460371c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 23 Jan 2023 20:47:34 +0000 +Subject: [PATCH] pwm: mediatek: Add support for MT7981 + +The PWM unit on MT7981 uses different register offsets than previous +MediaTek PWM units. Add support for these new offsets and add support +for PWM on MT7981 which has 3 PWM channels, one of them is typically +used for a temperature controlled fan. + +Signed-off-by: Daniel Golle +--- + drivers/pwm/pwm-mediatek.c | 54 ++++++++++++++++++++++++++++++++------ + 1 file changed, 46 insertions(+), 8 deletions(-) + +--- a/drivers/pwm/pwm-mediatek.c ++++ b/drivers/pwm/pwm-mediatek.c +@@ -34,10 +34,14 @@ + + #define PWM_CLK_DIV_MAX 7 + ++#define REG_V1 1 ++#define REG_V2 2 ++ + struct pwm_mediatek_of_data { + unsigned int num_pwms; + bool pwm45_fixup; + bool has_ck_26m_sel; ++ u8 reg_ver; + }; + + /** +@@ -59,10 +63,14 @@ struct pwm_mediatek_chip { + const struct pwm_mediatek_of_data *soc; + }; + +-static const unsigned int pwm_mediatek_reg_offset[] = { ++static const unsigned int mtk_pwm_reg_offset_v1[] = { + 0x0010, 0x0050, 0x0090, 0x00d0, 0x0110, 0x0150, 0x0190, 0x0220 + }; + ++static const unsigned int mtk_pwm_reg_offset_v2[] = { ++ 0x0080, 0x00c0, 0x0100, 0x0140, 0x0180, 0x1c0, 0x200, 0x0240 ++}; ++ + static inline struct pwm_mediatek_chip * + to_pwm_mediatek_chip(struct pwm_chip *chip) + { +@@ -111,7 +119,19 @@ static inline void pwm_mediatek_writel(s + unsigned int num, unsigned int offset, + u32 value) + { +- writel(value, chip->regs + pwm_mediatek_reg_offset[num] + offset); ++ u32 pwm_offset; ++ ++ switch (chip->soc->reg_ver) { ++ case REG_V2: ++ pwm_offset = mtk_pwm_reg_offset_v2[num]; ++ break; ++ ++ case REG_V1: ++ default: ++ pwm_offset = mtk_pwm_reg_offset_v1[num]; ++ } ++ ++ writel(value, chip->regs + pwm_offset + offset); + } + + static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm, +@@ -146,7 +166,7 @@ static int pwm_mediatek_config(struct pw + + if (clkdiv > PWM_CLK_DIV_MAX) { + pwm_mediatek_clk_disable(chip, pwm); +- dev_err(chip->dev, "period %d not supported\n", period_ns); ++ dev_err(chip->dev, "period of %d ns not supported\n", period_ns); + return -EINVAL; + } + +@@ -221,24 +241,20 @@ static int pwm_mediatek_probe(struct pla + if (IS_ERR(pc->regs)) + return PTR_ERR(pc->regs); + +- pc->clk_pwms = devm_kcalloc(&pdev->dev, pc->soc->num_pwms, ++ pc->clk_pwms = devm_kmalloc_array(&pdev->dev, pc->soc->num_pwms, + sizeof(*pc->clk_pwms), GFP_KERNEL); + if (!pc->clk_pwms) + return -ENOMEM; + + pc->clk_top = devm_clk_get(&pdev->dev, "top"); +- if (IS_ERR(pc->clk_top)) { +- dev_err(&pdev->dev, "clock: top fail: %ld\n", +- PTR_ERR(pc->clk_top)); +- return PTR_ERR(pc->clk_top); +- } ++ if (IS_ERR(pc->clk_top)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_top), ++ "Failed to get top clock\n"); + + pc->clk_main = devm_clk_get(&pdev->dev, "main"); +- if (IS_ERR(pc->clk_main)) { +- dev_err(&pdev->dev, "clock: main fail: %ld\n", +- PTR_ERR(pc->clk_main)); +- return PTR_ERR(pc->clk_main); +- } ++ if (IS_ERR(pc->clk_main)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_main), ++ "Failed to get main clock\n"); + + for (i = 0; i < pc->soc->num_pwms; i++) { + char name[8]; +@@ -246,11 +262,9 @@ static int pwm_mediatek_probe(struct pla + snprintf(name, sizeof(name), "pwm%d", i + 1); + + pc->clk_pwms[i] = devm_clk_get(&pdev->dev, name); +- if (IS_ERR(pc->clk_pwms[i])) { +- dev_err(&pdev->dev, "clock: %s fail: %ld\n", +- name, PTR_ERR(pc->clk_pwms[i])); +- return PTR_ERR(pc->clk_pwms[i]); +- } ++ if (IS_ERR(pc->clk_pwms[i])) ++ return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_pwms[i]), ++ "Failed to get %s clock\n", name); + } + + pc->chip.dev = &pdev->dev; +@@ -258,10 +272,8 @@ static int pwm_mediatek_probe(struct pla + pc->chip.npwm = pc->soc->num_pwms; + + ret = devm_pwmchip_add(&pdev->dev, &pc->chip); +- if (ret < 0) { +- dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); +- return ret; +- } ++ if (ret < 0) ++ return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n"); + + return 0; + } +@@ -270,48 +282,63 @@ static const struct pwm_mediatek_of_data + .num_pwms = 8, + .pwm45_fixup = false, + .has_ck_26m_sel = false, ++ .reg_ver = REG_V1, + }; + + static const struct pwm_mediatek_of_data mt7622_pwm_data = { + .num_pwms = 6, + .pwm45_fixup = false, + .has_ck_26m_sel = true, ++ .reg_ver = REG_V1, + }; + + static const struct pwm_mediatek_of_data mt7623_pwm_data = { + .num_pwms = 5, + .pwm45_fixup = true, + .has_ck_26m_sel = false, ++ .reg_ver = REG_V1, + }; + + static const struct pwm_mediatek_of_data mt7628_pwm_data = { + .num_pwms = 4, + .pwm45_fixup = true, + .has_ck_26m_sel = false, ++ .reg_ver = REG_V1, + }; + + static const struct pwm_mediatek_of_data mt7629_pwm_data = { + .num_pwms = 1, + .pwm45_fixup = false, + .has_ck_26m_sel = false, ++ .reg_ver = REG_V1, + }; + +-static const struct pwm_mediatek_of_data mt8183_pwm_data = { +- .num_pwms = 4, ++static const struct pwm_mediatek_of_data mt7981_pwm_data = { ++ .num_pwms = 3, + .pwm45_fixup = false, + .has_ck_26m_sel = true, ++ .reg_ver = REG_V2, + }; + + static const struct pwm_mediatek_of_data mt7986_pwm_data = { + .num_pwms = 2, + .pwm45_fixup = false, + .has_ck_26m_sel = true, ++ .reg_ver = REG_V1, ++}; ++ ++static const struct pwm_mediatek_of_data mt8183_pwm_data = { ++ .num_pwms = 4, ++ .pwm45_fixup = false, ++ .has_ck_26m_sel = true, ++ .reg_ver = REG_V1, + }; + + static const struct pwm_mediatek_of_data mt8516_pwm_data = { + .num_pwms = 5, + .pwm45_fixup = false, + .has_ck_26m_sel = true, ++ .reg_ver = REG_V1, + }; + + static const struct of_device_id pwm_mediatek_of_match[] = { +@@ -320,6 +347,7 @@ static const struct of_device_id pwm_med + { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, + { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, + { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data }, ++ { .compatible = "mediatek,mt7981-pwm", .data = &mt7981_pwm_data }, + { .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data }, + { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data }, + { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data }, From 540377010532d9840ebe0778c2af991bd4b67052 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 10 Mar 2023 23:53:54 +0000 Subject: [PATCH 50/53] mediatek: add support for SPI calibration Newer MediaTek's SoCs need SPI calibration routines for SPI to work reliably. Import patches for that from MediaTek's SDK. Signed-off-by: Daniel Golle --- ...xx-Move-chip_config-to-driver-s-priv.patch | 130 ++++++++++ ...-Add-support-for-dynamic-calibration.patch | 236 ++++++++++++++++++ ...ers-spi-mem-Add-spi-calibration-hook.patch | 41 +++ ...xx-Add-controller-s-calibration-para.patch | 43 ++++ ...and-Add-calibration-support-for-spin.patch | 81 ++++++ ...nor-Add-calibration-support-for-spi-.patch | 57 +++++ .../930-spi-mt65xx-enable-sel-clk.patch | 4 +- 7 files changed, 590 insertions(+), 2 deletions(-) create mode 100644 target/linux/mediatek/patches-5.15/431-drivers-spi-mt65xx-Move-chip_config-to-driver-s-priv.patch create mode 100644 target/linux/mediatek/patches-5.15/432-drivers-spi-Add-support-for-dynamic-calibration.patch create mode 100644 target/linux/mediatek/patches-5.15/433-drivers-spi-mem-Add-spi-calibration-hook.patch create mode 100644 target/linux/mediatek/patches-5.15/434-drivers-spi-mt65xx-Add-controller-s-calibration-para.patch create mode 100644 target/linux/mediatek/patches-5.15/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch create mode 100644 target/linux/mediatek/patches-5.15/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch diff --git a/target/linux/mediatek/patches-5.15/431-drivers-spi-mt65xx-Move-chip_config-to-driver-s-priv.patch b/target/linux/mediatek/patches-5.15/431-drivers-spi-mt65xx-Move-chip_config-to-driver-s-priv.patch new file mode 100644 index 00000000000..a57ee253938 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/431-drivers-spi-mt65xx-Move-chip_config-to-driver-s-priv.patch @@ -0,0 +1,130 @@ +From bfd3acc428085742d754a6d328d1a93ebf9451df Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:29:51 +0800 +Subject: [PATCH 1/6] drivers: spi-mt65xx: Move chip_config to driver's private + data + +Signed-off-by: SkyLake.Huang +--- + drivers/spi/spi-mt65xx.c | 29 +++++++++--------------- + include/linux/platform_data/spi-mt65xx.h | 17 -------------- + 2 files changed, 11 insertions(+), 35 deletions(-) + delete mode 100644 include/linux/platform_data/spi-mt65xx.h + +--- a/drivers/spi/spi-mt65xx.c ++++ b/drivers/spi/spi-mt65xx.c +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -142,6 +141,8 @@ struct mtk_spi { + struct device *dev; + dma_addr_t tx_dma; + dma_addr_t rx_dma; ++ u32 sample_sel; ++ u32 get_tick_dly; + }; + + static const struct mtk_spi_compatible mtk_common_compat; +@@ -187,15 +188,6 @@ static const struct mtk_spi_compatible m + .no_need_unprepare = true, + }; + +-/* +- * A piece of default chip info unless the platform +- * supplies it. +- */ +-static const struct mtk_chip_config mtk_default_chip_info = { +- .sample_sel = 0, +- .tick_delay = 0, +-}; +- + static const struct of_device_id mtk_spi_of_match[] = { + { .compatible = "mediatek,spi-ipm", + .data = (void *)&mtk_ipm_compat, +@@ -323,7 +315,6 @@ static int mtk_spi_hw_init(struct spi_ma + { + u16 cpha, cpol; + u32 reg_val; +- struct mtk_chip_config *chip_config = spi->controller_data; + struct mtk_spi *mdata = spi_master_get_devdata(master); + + cpha = spi->mode & SPI_CPHA ? 1 : 0; +@@ -373,7 +364,7 @@ static int mtk_spi_hw_init(struct spi_ma + else + reg_val &= ~SPI_CMD_CS_POL; + +- if (chip_config->sample_sel) ++ if (mdata->sample_sel) + reg_val |= SPI_CMD_SAMPLE_SEL; + else + reg_val &= ~SPI_CMD_SAMPLE_SEL; +@@ -400,20 +391,20 @@ static int mtk_spi_hw_init(struct spi_ma + if (mdata->dev_comp->ipm_design) { + reg_val = readl(mdata->base + SPI_CMD_REG); + reg_val &= ~SPI_CMD_IPM_GET_TICKDLY_MASK; +- reg_val |= ((chip_config->tick_delay & 0x7) ++ reg_val |= ((mdata->get_tick_dly & 0x7) + << SPI_CMD_IPM_GET_TICKDLY_OFFSET); + writel(reg_val, mdata->base + SPI_CMD_REG); + } else { + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK; +- reg_val |= ((chip_config->tick_delay & 0x7) ++ reg_val |= ((mdata->get_tick_dly & 0x7) + << SPI_CFG1_GET_TICK_DLY_OFFSET); + writel(reg_val, mdata->base + SPI_CFG1_REG); + } + } else { + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK_V1; +- reg_val |= ((chip_config->tick_delay & 0x3) ++ reg_val |= ((mdata->get_tick_dly & 0x3) + << SPI_CFG1_GET_TICK_DLY_OFFSET_V1); + writel(reg_val, mdata->base + SPI_CFG1_REG); + } +@@ -700,9 +691,6 @@ static int mtk_spi_setup(struct spi_devi + { + struct mtk_spi *mdata = spi_master_get_devdata(spi->master); + +- if (!spi->controller_data) +- spi->controller_data = (void *)&mtk_default_chip_info; +- + if (mdata->dev_comp->need_pad_sel && spi->cs_gpiod) + /* CS de-asserted, gpiolib will handle inversion */ + gpiod_direction_output(spi->cs_gpiod, 0); +@@ -1115,6 +1103,10 @@ static int mtk_spi_probe(struct platform + mdata = spi_master_get_devdata(master); + mdata->dev_comp = of_id->data; + ++ /* Set device configs to default first. Calibrate it later. */ ++ mdata->sample_sel = 0; ++ mdata->get_tick_dly = 2; ++ + if (mdata->dev_comp->enhance_timing) + master->mode_bits |= SPI_CS_HIGH; + +--- a/include/linux/platform_data/spi-mt65xx.h ++++ /dev/null +@@ -1,17 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * MTK SPI bus driver definitions +- * +- * Copyright (c) 2015 MediaTek Inc. +- * Author: Leilk Liu +- */ +- +-#ifndef ____LINUX_PLATFORM_DATA_SPI_MTK_H +-#define ____LINUX_PLATFORM_DATA_SPI_MTK_H +- +-/* Board specific platform_data */ +-struct mtk_chip_config { +- u32 sample_sel; +- u32 tick_delay; +-}; +-#endif diff --git a/target/linux/mediatek/patches-5.15/432-drivers-spi-Add-support-for-dynamic-calibration.patch b/target/linux/mediatek/patches-5.15/432-drivers-spi-Add-support-for-dynamic-calibration.patch new file mode 100644 index 00000000000..4c980e9438d --- /dev/null +++ b/target/linux/mediatek/patches-5.15/432-drivers-spi-Add-support-for-dynamic-calibration.patch @@ -0,0 +1,236 @@ +From 2ade0172154e50c8a2bfd8634c6eff943cffea29 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:35:52 +0800 +Subject: [PATCH 2/6] drivers: spi: Add support for dynamic calibration + +Signed-off-by: SkyLake.Huang +--- + drivers/spi/spi.c | 137 ++++++++++++++++++++++++++++++++++++++++ + include/linux/spi/spi.h | 42 ++++++++++++ + 2 files changed, 179 insertions(+) + +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -1234,6 +1234,70 @@ static int spi_transfer_wait(struct spi_ + return 0; + } + ++int spi_do_calibration(struct spi_controller *ctlr, struct spi_device *spi, ++ int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), void *drv_priv) ++{ ++ int datalen = ctlr->cal_rule->datalen; ++ int addrlen = ctlr->cal_rule->addrlen; ++ u8 *buf; ++ int ret; ++ int i; ++ struct list_head *cal_head, *listptr; ++ struct spi_cal_target *target; ++ ++ /* Calculate calibration result */ ++ int hit_val, total_hit, origin; ++ bool hit; ++ ++ /* Make sure we can start calibration */ ++ if(!ctlr->cal_target || !ctlr->cal_rule || !ctlr->append_caldata) ++ return 0; ++ ++ buf = kzalloc(datalen * sizeof(u8), GFP_KERNEL); ++ if(!buf) ++ return -ENOMEM; ++ ++ ret = ctlr->append_caldata(ctlr); ++ if (ret) ++ goto cal_end; ++ ++ cal_head = ctlr->cal_target; ++ list_for_each(listptr, cal_head) { ++ target = list_entry(listptr, struct spi_cal_target, list); ++ ++ hit = false; ++ hit_val = 0; ++ total_hit = 0; ++ origin = *target->cal_item; ++ ++ for(i=target->cal_min; i<=target->cal_max; i+=target->step) { ++ *target->cal_item = i; ++ ret = (*cal_read)(drv_priv, ctlr->cal_rule->addr, addrlen, buf, datalen); ++ if(ret) ++ break; ++ dev_dbg(&spi->dev, "controller cal item value: 0x%x\n", i); ++ if(memcmp(ctlr->cal_rule->match_data, buf, datalen * sizeof(u8)) == 0) { ++ hit = true; ++ hit_val += i; ++ total_hit++; ++ dev_dbg(&spi->dev, "golden data matches data read!\n"); ++ } ++ } ++ if(hit) { ++ *target->cal_item = DIV_ROUND_CLOSEST(hit_val, total_hit); ++ dev_info(&spi->dev, "calibration result: 0x%x", *target->cal_item); ++ } else { ++ *target->cal_item = origin; ++ dev_warn(&spi->dev, "calibration failed, fallback to default: 0x%x", origin); ++ } ++ } ++ ++cal_end: ++ kfree(buf); ++ return ret? ret: 0; ++} ++EXPORT_SYMBOL_GPL(spi_do_calibration); ++ + static void _spi_transfer_delay_ns(u32 ns) + { + if (!ns) +@@ -2021,6 +2085,75 @@ void spi_flush_queue(struct spi_controll + /*-------------------------------------------------------------------------*/ + + #if defined(CONFIG_OF) ++static inline void alloc_cal_data(struct list_head **cal_target, ++ struct spi_cal_rule **cal_rule, bool enable) ++{ ++ if(enable) { ++ *cal_target = kmalloc(sizeof(struct list_head), GFP_KERNEL); ++ INIT_LIST_HEAD(*cal_target); ++ *cal_rule = kmalloc(sizeof(struct spi_cal_rule), GFP_KERNEL); ++ } else { ++ kfree(*cal_target); ++ kfree(*cal_rule); ++ } ++} ++ ++static int of_spi_parse_cal_dt(struct spi_controller *ctlr, struct spi_device *spi, ++ struct device_node *nc) ++{ ++ u32 value; ++ int rc; ++ const char *cal_mode; ++ ++ rc = of_property_read_bool(nc, "spi-cal-enable"); ++ if (rc) ++ alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, true); ++ else ++ return 0; ++ ++ rc = of_property_read_string(nc, "spi-cal-mode", &cal_mode); ++ if(!rc) { ++ if(strcmp("read-data", cal_mode) == 0){ ++ ctlr->cal_rule->mode = SPI_CAL_READ_DATA; ++ } else if(strcmp("read-pp", cal_mode) == 0) { ++ ctlr->cal_rule->mode = SPI_CAL_READ_PP; ++ return 0; ++ } else if(strcmp("read-sfdp", cal_mode) == 0){ ++ ctlr->cal_rule->mode = SPI_CAL_READ_SFDP; ++ return 0; ++ } ++ } else ++ goto err; ++ ++ ctlr->cal_rule->datalen = 0; ++ rc = of_property_read_u32(nc, "spi-cal-datalen", &value); ++ if(!rc && value > 0) { ++ ctlr->cal_rule->datalen = value; ++ ++ ctlr->cal_rule->match_data = kzalloc(value * sizeof(u8), GFP_KERNEL); ++ rc = of_property_read_u8_array(nc, "spi-cal-data", ++ ctlr->cal_rule->match_data, value); ++ if(rc) ++ kfree(ctlr->cal_rule->match_data); ++ } ++ ++ rc = of_property_read_u32(nc, "spi-cal-addrlen", &value); ++ if(!rc && value > 0) { ++ ctlr->cal_rule->addrlen = value; ++ ++ ctlr->cal_rule->addr = kzalloc(value * sizeof(u32), GFP_KERNEL); ++ rc = of_property_read_u32_array(nc, "spi-cal-addr", ++ ctlr->cal_rule->addr, value); ++ if(rc) ++ kfree(ctlr->cal_rule->addr); ++ } ++ return 0; ++ ++err: ++ alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, false); ++ return 0; ++} ++ + static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, + struct device_node *nc) + { +@@ -2139,6 +2272,10 @@ of_register_spi_device(struct spi_contro + if (rc) + goto err_out; + ++ rc = of_spi_parse_cal_dt(ctlr, spi, nc); ++ if (rc) ++ goto err_out; ++ + /* Store a pointer to the node in the device structure */ + of_node_get(nc); + spi->dev.of_node = nc; +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -290,6 +290,40 @@ struct spi_driver { + struct device_driver driver; + }; + ++enum { ++ SPI_CAL_READ_DATA = 0, ++ SPI_CAL_READ_PP = 1, /* only for SPI-NAND */ ++ SPI_CAL_READ_SFDP = 2, /* only for SPI-NOR */ ++}; ++ ++struct nand_addr { ++ unsigned int lun; ++ unsigned int plane; ++ unsigned int eraseblock; ++ unsigned int page; ++ unsigned int dataoffs; ++}; ++ ++/** ++ * Read calibration rule from device dts node. ++ * Once calibration result matches the rule, we regard is as success. ++ */ ++struct spi_cal_rule { ++ int datalen; ++ u8 *match_data; ++ int addrlen; ++ u32 *addr; ++ int mode; ++}; ++ ++struct spi_cal_target { ++ u32 *cal_item; ++ int cal_min; /* min of cal_item */ ++ int cal_max; /* max of cal_item */ ++ int step; /* Increase/decrease cal_item */ ++ struct list_head list; ++}; ++ + static inline struct spi_driver *to_spi_driver(struct device_driver *drv) + { + return drv ? container_of(drv, struct spi_driver, driver) : NULL; +@@ -665,6 +699,11 @@ struct spi_controller { + void *dummy_rx; + void *dummy_tx; + ++ /* For calibration */ ++ int (*append_caldata)(struct spi_controller *ctlr); ++ struct list_head *cal_target; ++ struct spi_cal_rule *cal_rule; ++ + int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs); + + /* +@@ -1477,6 +1516,9 @@ spi_register_board_info(struct spi_board + { return 0; } + #endif + ++extern int spi_do_calibration(struct spi_controller *ctlr, ++ struct spi_device *spi, int (*cal_read)(void *, u32 *, int, u8 *, int), void *drv_priv); ++ + /* If you're hotplugging an adapter with devices (parport, usb, etc) + * use spi_new_device() to describe each device. You can also call + * spi_unregister_device() to start making that device vanish, but diff --git a/target/linux/mediatek/patches-5.15/433-drivers-spi-mem-Add-spi-calibration-hook.patch b/target/linux/mediatek/patches-5.15/433-drivers-spi-mem-Add-spi-calibration-hook.patch new file mode 100644 index 00000000000..aaacab01312 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/433-drivers-spi-mem-Add-spi-calibration-hook.patch @@ -0,0 +1,41 @@ +From 06640a5da2973318c06e516da16a5b579622e7c5 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:37:55 +0800 +Subject: [PATCH 3/6] drivers: spi-mem: Add spi calibration hook + +Signed-off-by: SkyLake.Huang +--- + drivers/spi/spi-mem.c | 8 ++++++++ + include/linux/spi/spi-mem.h | 4 ++++ + 2 files changed, 12 insertions(+) + +--- a/drivers/spi/spi-mem.c ++++ b/drivers/spi/spi-mem.c +@@ -410,6 +410,14 @@ int spi_mem_exec_op(struct spi_mem *mem, + } + EXPORT_SYMBOL_GPL(spi_mem_exec_op); + ++int spi_mem_do_calibration(struct spi_mem *mem, ++ int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), ++ void *priv) ++{ ++ return spi_do_calibration(mem->spi->controller, mem->spi, cal_read, priv); ++} ++EXPORT_SYMBOL_GPL(spi_mem_do_calibration); ++ + /** + * spi_mem_get_name() - Return the SPI mem device name to be used by the + * upper layer if necessary +--- a/include/linux/spi/spi-mem.h ++++ b/include/linux/spi/spi-mem.h +@@ -366,6 +366,10 @@ bool spi_mem_supports_op(struct spi_mem + int spi_mem_exec_op(struct spi_mem *mem, + const struct spi_mem_op *op); + ++int spi_mem_do_calibration(struct spi_mem *mem, ++ int (*cal_read)(void *, u32 *, int, u8 *, int), ++ void *priv); ++ + const char *spi_mem_get_name(struct spi_mem *mem); + + struct spi_mem_dirmap_desc * diff --git a/target/linux/mediatek/patches-5.15/434-drivers-spi-mt65xx-Add-controller-s-calibration-para.patch b/target/linux/mediatek/patches-5.15/434-drivers-spi-mt65xx-Add-controller-s-calibration-para.patch new file mode 100644 index 00000000000..a64d6229819 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/434-drivers-spi-mt65xx-Add-controller-s-calibration-para.patch @@ -0,0 +1,43 @@ +From d278c7a0bf730318a7ccf8d0a8b434c813e23fd0 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:39:03 +0800 +Subject: [PATCH 4/6] drivers: spi-mt65xx: Add controller's calibration + paramter + +Signed-off-by: SkyLake.Huang +--- + drivers/spi/spi-mt65xx.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/spi/spi-mt65xx.c ++++ b/drivers/spi/spi-mt65xx.c +@@ -800,6 +800,21 @@ static irqreturn_t mtk_spi_interrupt(int + return IRQ_HANDLED; + } + ++static int mtk_spi_append_caldata(struct spi_controller *ctlr) ++{ ++ struct spi_cal_target *cal_target = kmalloc(sizeof(*cal_target), GFP_KERNEL); ++ struct mtk_spi *mdata = spi_master_get_devdata(ctlr); ++ ++ cal_target->cal_item = &mdata->get_tick_dly; ++ cal_target->cal_min = 0; ++ cal_target->cal_max = 7; ++ cal_target->step = 1; ++ ++ list_add(&cal_target->list, ctlr->cal_target); ++ ++ return 0; ++} ++ + static int mtk_spi_mem_adjust_op_size(struct spi_mem *mem, + struct spi_mem_op *op) + { +@@ -1092,6 +1107,7 @@ static int mtk_spi_probe(struct platform + master->setup = mtk_spi_setup; + master->set_cs_timing = mtk_spi_set_hw_cs_timing; + master->use_gpio_descriptors = true; ++ master->append_caldata = mtk_spi_append_caldata; + + of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node); + if (!of_id) { diff --git a/target/linux/mediatek/patches-5.15/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch b/target/linux/mediatek/patches-5.15/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch new file mode 100644 index 00000000000..f71a1d2d589 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/435-drivers-mtd-spinand-Add-calibration-support-for-spin.patch @@ -0,0 +1,81 @@ +From 7670ec4a14891a1a182b98a9c403ffbf6b49e4b1 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:39:56 +0800 +Subject: [PATCH 5/6] drivers: mtd: spinand: Add calibration support for + spinand + +Signed-off-by: SkyLake.Huang +--- + drivers/mtd/nand/spi/core.c | 54 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 54 insertions(+) + +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -967,6 +967,56 @@ static int spinand_manufacturer_match(st + return -ENOTSUPP; + } + ++int spinand_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) { ++ struct spinand_device *spinand = (struct spinand_device *)priv; ++ struct device *dev = &spinand->spimem->spi->dev; ++ struct spi_mem_op op = SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, buf, readlen); ++ struct nand_pos pos; ++ struct nand_page_io_req req; ++ u8 status; ++ int ret; ++ ++ if(addrlen != sizeof(struct nand_addr)/sizeof(unsigned int)) { ++ dev_err(dev, "Must provide correct addr(length) for spinand calibration\n"); ++ return -EINVAL; ++ } ++ ++ ret = spinand_reset_op(spinand); ++ if (ret) ++ return ret; ++ ++ /* We should store our golden data in first target because ++ * we can't switch target at this moment. ++ */ ++ pos = (struct nand_pos){ ++ .target = 0, ++ .lun = *addr, ++ .plane = *(addr+1), ++ .eraseblock = *(addr+2), ++ .page = *(addr+3), ++ }; ++ ++ req = (struct nand_page_io_req){ ++ .pos = pos, ++ .dataoffs = *(addr+4), ++ .datalen = readlen, ++ .databuf.in = buf, ++ .mode = MTD_OPS_AUTO_OOB, ++ }; ++ ++ ret = spinand_load_page_op(spinand, &req); ++ if (ret) ++ return ret; ++ ++ ret = spinand_wait(spinand, &status); ++ if (ret < 0) ++ return ret; ++ ++ ret = spi_mem_exec_op(spinand->spimem, &op); ++ ++ return 0; ++} ++ + static int spinand_id_detect(struct spinand_device *spinand) + { + u8 *id = spinand->id.data; +@@ -1217,6 +1267,10 @@ static int spinand_init(struct spinand_d + if (!spinand->scratchbuf) + return -ENOMEM; + ++ ret = spi_mem_do_calibration(spinand->spimem, spinand_cal_read, spinand); ++ if (ret) ++ dev_err(dev, "Failed to calibrate SPI-NAND (err = %d)\n", ret); ++ + ret = spinand_detect(spinand); + if (ret) + goto err_free_bufs; diff --git a/target/linux/mediatek/patches-5.15/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch b/target/linux/mediatek/patches-5.15/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch new file mode 100644 index 00000000000..a08b19870cc --- /dev/null +++ b/target/linux/mediatek/patches-5.15/436-drivers-mtd-spi-nor-Add-calibration-support-for-spi-.patch @@ -0,0 +1,57 @@ +From f3fe3b15eca7908eaac57f9b8387a5dbc45ec5b2 Mon Sep 17 00:00:00 2001 +From: "SkyLake.Huang" +Date: Thu, 23 Jun 2022 18:40:59 +0800 +Subject: [PATCH 6/6] drivers: mtd: spi-nor: Add calibration support for + spi-nor + +Signed-off-by: SkyLake.Huang +--- + drivers/mtd/nand/spi/core.c | 5 ++++- + drivers/mtd/spi-nor/core.c | 15 +++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -1008,7 +1008,10 @@ int spinand_cal_read(void *priv, u32 *ad + if (ret) + return ret; + +- ret = spinand_wait(spinand, &status); ++ ret = spinand_wait(spinand, ++ SPINAND_READ_INITIAL_DELAY_US, ++ SPINAND_READ_POLL_DELAY_US, ++ &status); + if (ret < 0) + return ret; + +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -3060,6 +3060,18 @@ static void spi_nor_debugfs_init(struct + info->id_len, info->id); + } + ++static int spi_nor_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) ++{ ++ struct spi_nor *nor = (struct spi_nor *)priv; ++ ++ nor->reg_proto = SNOR_PROTO_1_1_1; ++ nor->read_proto = SNOR_PROTO_1_1_1; ++ nor->read_opcode = SPINOR_OP_READ; ++ nor->read_dummy = 0; ++ ++ return nor->controller_ops->read(nor, *addr, readlen, buf); ++} ++ + static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, + const char *name) + { +@@ -3133,6 +3145,9 @@ int spi_nor_scan(struct spi_nor *nor, co + if (!nor->bouncebuf) + return -ENOMEM; + ++ if(nor->spimem) ++ spi_mem_do_calibration(nor->spimem, spi_nor_cal_read, nor); ++ + info = spi_nor_get_flash_info(nor, name); + if (IS_ERR(info)) + return PTR_ERR(info); diff --git a/target/linux/mediatek/patches-5.15/930-spi-mt65xx-enable-sel-clk.patch b/target/linux/mediatek/patches-5.15/930-spi-mt65xx-enable-sel-clk.patch index 904f2ef3a2f..ebb6c060b54 100644 --- a/target/linux/mediatek/patches-5.15/930-spi-mt65xx-enable-sel-clk.patch +++ b/target/linux/mediatek/patches-5.15/930-spi-mt65xx-enable-sel-clk.patch @@ -1,6 +1,6 @@ --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c -@@ -1223,10 +1223,16 @@ static int mtk_spi_probe(struct platform +@@ -1231,10 +1231,16 @@ static int mtk_spi_probe(struct platform goto err_disable_spi_hclk; } @@ -18,7 +18,7 @@ } mdata->spi_clk_hz = clk_get_rate(mdata->spi_clk); -@@ -1277,6 +1283,8 @@ static int mtk_spi_probe(struct platform +@@ -1285,6 +1291,8 @@ static int mtk_spi_probe(struct platform err_disable_runtime_pm: pm_runtime_disable(&pdev->dev); From 5f898483af574699783ed81a7a7895414c94de07 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 11 Mar 2023 02:38:59 +0000 Subject: [PATCH 51/53] generic: fix Macronix SPI-NAND driver Use scratch buffer for DMA operetations. Passing a pointer to a stack variable won't work and results in bogus bit flips being reported. Patch was submitted upstream and is part of Linux 6.3. Signed-off-by: Daniel Golle --- ...onix-use-scratch-buffer-for-DMA-oper.patch | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 target/linux/generic/backport-5.15/423-v6.3-mtd-spinand-macronix-use-scratch-buffer-for-DMA-oper.patch diff --git a/target/linux/generic/backport-5.15/423-v6.3-mtd-spinand-macronix-use-scratch-buffer-for-DMA-oper.patch b/target/linux/generic/backport-5.15/423-v6.3-mtd-spinand-macronix-use-scratch-buffer-for-DMA-oper.patch new file mode 100644 index 00000000000..7dbc2717250 --- /dev/null +++ b/target/linux/generic/backport-5.15/423-v6.3-mtd-spinand-macronix-use-scratch-buffer-for-DMA-oper.patch @@ -0,0 +1,35 @@ +From ebed787a0becb9354f0a23620a5130cccd6c730c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 19 Jan 2023 03:45:43 +0000 +Subject: [PATCH] mtd: spinand: macronix: use scratch buffer for DMA operation + +The mx35lf1ge4ab_get_eccsr() function uses an SPI DMA operation to +read the eccsr, hence the buffer should not be on stack. Since commit +380583227c0c7f ("spi: spi-mem: Add extra sanity checks on the op param") +the kernel emmits a warning and blocks such operations. + +Use the scratch buffer to get eccsr instead of trying to directly read +into a stack-allocated variable. + +Signed-off-by: Daniel Golle +Reviewed-by: Dhruva Gole +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/Y8i85zM0u4XdM46z@makrotopia.org +--- + drivers/mtd/nand/spi/macronix.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/nand/spi/macronix.c ++++ b/drivers/mtd/nand/spi/macronix.c +@@ -83,9 +83,10 @@ static int mx35lf1ge4ab_ecc_get_status(s + * in order to avoid forcing the wear-leveling layer to move + * data around if it's not necessary. + */ +- if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr)) ++ if (mx35lf1ge4ab_get_eccsr(spinand, spinand->scratchbuf)) + return nanddev_get_ecc_conf(nand)->strength; + ++ eccsr = *spinand->scratchbuf; + if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength || + !eccsr)) + return nanddev_get_ecc_conf(nand)->strength; From 397c706cba55201dcbddb4f42c92ba455968cd9a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 11 Mar 2023 03:55:52 +0000 Subject: [PATCH 52/53] mediatek: add device tree include for the MT7981 SoC Add mt7981.dtsi so we can start adding MT7981 devices. Signed-off-by: Daniel Golle --- .../arch/arm64/boot/dts/mediatek/mt7981.dtsi | 766 ++++++++++++++++++ 1 file changed, 766 insertions(+) create mode 100644 target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi diff --git a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi new file mode 100644 index 00000000000..279bce14e86 --- /dev/null +++ b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi @@ -0,0 +1,766 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2020 MediaTek Inc. + * Author: Sam.Shih + * Author: Jianhui Zhao + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + compatible = "mediatek,mt7981"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + enable-method = "psci"; + reg = <0x0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + enable-method = "psci"; + reg = <0x1>; + }; + }; + + pwm: pwm@10048000 { + compatible = "mediatek,mt7981-pwm"; + reg = <0 0x10048000 0 0x1000>; + #pwm-cells = <2>; + clocks = <&infracfg CLK_INFRA_PWM_STA>, + <&infracfg CLK_INFRA_PWM_HCK>, + <&infracfg CLK_INFRA_PWM1_CK>, + <&infracfg CLK_INFRA_PWM2_CK>, + <&infracfg CLK_INFRA_PWM3_CK>; + clock-names = "top", "main", "pwm1", "pwm2", "pwm3"; + }; + + fan: pwm-fan { + compatible = "pwm-fan"; + /* cooling level (0, 1, 2, 3) : (0% duty, 50% duty, 75% duty, 100% duty) */ + cooling-levels = <0 128 192 255>; + #cooling-cells = <2>; + status = "disabled"; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <1000>; + thermal-sensors = <&thermal 0>; + trips { + cpu_trip_crit: crit { + temperature = <125000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu_trip_hot: hot { + temperature = <120000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpu_trip_active_high: active-high { + temperature = <115000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_trip_active_med: active-med { + temperature = <85000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_trip_active_low: active-low { + temperature = <60000>; + hysteresis = <2000>; + type = "active"; + }; + }; + + cooling-maps { + cpu-active-high { + /* active: set fan to cooling level 3 */ + cooling-device = <&fan 3 3>; + trip = <&cpu_trip_active_high>; + }; + + cpu-active-med { + /* active: set fan to cooling level 2 */ + cooling-device = <&fan 2 2>; + trip = <&cpu_trip_active_med>; + }; + + cpu-active-low { + /* passive: set fan to cooling level 1 */ + cooling-device = <&fan 1 1>; + trip = <&cpu_trip_active_low>; + }; + }; + }; + }; + + thermal: thermal@1100c800 { + #thermal-sensor-cells = <1>; + compatible = "mediatek,mt7981-thermal", "mediatek,mt7986-thermal"; + reg = <0 0x1100c800 0 0x800>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_THERM_CK>, + <&infracfg CLK_INFRA_ADC_26M_CK>; + clock-names = "therm", "auxadc"; + mediatek,auxadc = <&auxadc>; + mediatek,apmixedsys = <&apmixedsys>; + nvmem-cells = <&thermal_calibration>; + nvmem-cell-names = "calibration-data"; + }; + + auxadc: adc@1100d000 { + compatible = "mediatek,mt7981-auxadc", + "mediatek,mt7986-auxadc", + "mediatek,mt7622-auxadc"; + reg = <0 0x1100d000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_ADC_26M_CK>, + <&infracfg CLK_INFRA_ADC_FRC_CK>; + clock-names = "main", "32k"; + #io-channel-cells = <1>; + }; + + wdma: wdma@15104800 { + compatible = "mediatek,wed-wdma"; + reg = <0 0x15104800 0 0x400>, + <0 0x15104c00 0 0x400>; + }; + + ap2woccif: ap2woccif@151a5000 { + compatible = "mediatek,ap2woccif"; + reg = <0 0x151a5000 0 0x1000>, + <0 0x151ad000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = , + ; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@43000000 { + reg = <0 0x43000000 0 0x30000>; + no-map; + }; + + wmcpu_emi: wmcpu-reserved@47c80000 { + reg = <0 0x47c80000 0 0x100000>; + no-map; + }; + + wo_emi0: wo-emi@47d80000 { + reg = <0 0x47d80000 0 0x40000>; + no-map; + }; + + wo_data: wo-data@47dc0000 { + reg = <0 0x47dc0000 0 0x240000>; + no-map; + }; + + wo_ilm0: wo-ilm@151e0000 { + reg = <0 0x151e0000 0 0x8000>; + no-map; + }; + + wo_dlm0: wo-dlm@151e8000 { + reg = <0 0x151e8000 0 0x2000>; + no-map; + }; + + wo_boot: wo-boot@15194000 { + reg = <0 0x15194000 0 0x1000>; + no-map; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + trng { + compatible = "mediatek,mt7981-rng"; + }; + + clk40m: oscillator@0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <40000000>; + clock-output-names = "clkxtal"; + }; + + infracfg: infracfg@10001000 { + compatible = "mediatek,mt7981-infracfg", "syscon"; + reg = <0 0x10001000 0 0x1000>; + #clock-cells = <1>; + }; + + topckgen: topckgen@1001B000 { + compatible = "mediatek,mt7981-topckgen", "syscon"; + reg = <0 0x1001B000 0 0x1000>; + #clock-cells = <1>; + }; + + apmixedsys: apmixedsys@1001E000 { + compatible = "mediatek,mt7981-apmixedsys", "mediatek,mt7986-apmixedsys", "syscon"; + reg = <0 0x1001E000 0 0x1000>; + #clock-cells = <1>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + clock-frequency = <13000000>; + interrupts = , + , + , + ; + + }; + + watchdog: watchdog@1001c000 { + compatible = "mediatek,mt7986-wdt", + "mediatek,mt6589-wdt"; + reg = <0 0x1001c000 0 0x1000>; + interrupts = ; + #reset-cells = <1>; + status = "disabled"; + }; + + gic: interrupt-controller@c000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + interrupt-controller; + reg = <0 0x0c000000 0 0x40000>, /* GICD */ + <0 0x0c080000 0 0x200000>; /* GICR */ + + interrupts = ; + }; + + uart0: serial@11002000 { + compatible = "mediatek,mt6577-uart"; + reg = <0 0x11002000 0 0x400>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_UART0_SEL>, + <&infracfg CLK_INFRA_UART0_CK>; + clock-names = "baud", "bus"; + assigned-clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_UART0_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_CKSQ_40M>, + <&topckgen CLK_TOP_UART_SEL>; + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart1: serial@11003000 { + compatible = "mediatek,mt6577-uart"; + reg = <0 0x11003000 0 0x400>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_UART1_SEL>, + <&infracfg CLK_INFRA_UART1_CK>; + clock-names = "baud", "bus"; + assigned-clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_UART1_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_CKSQ_40M>, + <&topckgen CLK_TOP_UART_SEL>; + status = "disabled"; + }; + + uart2: serial@11004000 { + compatible = "mediatek,mt6577-uart"; + reg = <0 0x11004000 0 0x400>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_UART2_SEL>, + <&infracfg CLK_INFRA_UART2_CK>; + clock-names = "baud", "bus"; + assigned-clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_UART2_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_CKSQ_40M>, + <&topckgen CLK_TOP_UART_SEL>; + status = "disabled"; + }; + + i2c0: i2c@11007000 { + compatible = "mediatek,mt7981-i2c"; + reg = <0 0x11007000 0 0x1000>, + <0 0x10217080 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&infracfg CLK_INFRA_I2C0_CK>, + <&infracfg CLK_INFRA_AP_DMA_CK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + pcie: pcie@11280000 { + compatible = "mediatek,mt7981-pcie", + "mediatek,mt7986-pcie"; + device_type = "pci"; + reg = <0 0x11280000 0 0x4000>; + reg-names = "pcie-mac"; + #address-cells = <3>; + #size-cells = <2>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 + 0x0 0x20000000 0 0x10000000>; + status = "disabled"; + + clocks = <&infracfg CLK_INFRA_IPCIE_CK>, + <&infracfg CLK_INFRA_IPCIE_PIPE_CK>, + <&infracfg CLK_INFRA_IPCIER_CK>, + <&infracfg CLK_INFRA_IPCIEB_CK>; + + phys = <&u3port0 PHY_TYPE_PCIE>; + phy-names = "pcie-phy"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc 0>, + <0 0 0 2 &pcie_intc 1>, + <0 0 0 3 &pcie_intc 2>, + <0 0 0 4 &pcie_intc 3>; + pcie_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + crypto: crypto@10320000 { + compatible = "inside-secure,safexcel-eip97"; + reg = <0 0x10320000 0 0x40000>; + interrupts = , + , + , + ; + interrupt-names = "ring0", "ring1", "ring2", "ring3"; + clocks = <&topckgen CLK_TOP_EIP97B>; + clock-names = "top_eip97_ck"; + assigned-clocks = <&topckgen CLK_TOP_EIP97B_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_NET1_D5>; + }; + + pio: pinctrl@11d00000 { + compatible = "mediatek,mt7981-pinctrl"; + reg = <0 0x11d00000 0 0x1000>, + <0 0x11c00000 0 0x1000>, + <0 0x11c10000 0 0x1000>, + <0 0x11d20000 0 0x1000>, + <0 0x11e00000 0 0x1000>, + <0 0x11e20000 0 0x1000>, + <0 0x11f00000 0 0x1000>, + <0 0x11f10000 0 0x1000>, + <0 0x1000b000 0 0x1000>; + reg-names = "gpio", "iocfg_rt", "iocfg_rm", + "iocfg_rb", "iocfg_lb", "iocfg_bl", + "iocfg_tm", "iocfg_tl", "eint"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pio 0 0 56>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; + #interrupt-cells = <2>; + + mdio_pins: mdc-mdio-pins { + mux { + function = "eth"; + groups = "smi_mdc_mdio"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0"; + }; + }; + + wifi_dbdc_pins: wifi-dbdc-pins { + mux { + function = "eth"; + groups = "wf0_mode1"; + }; + conf { + pins = "WF_HB1", "WF_HB2", "WF_HB3", "WF_HB4", + "WF_HB0", "WF_HB0_B", "WF_HB5", "WF_HB6", + "WF_HB7", "WF_HB8", "WF_HB9", "WF_HB10", + "WF_TOP_CLK", "WF_TOP_DATA", "WF_XO_REQ", + "WF_CBA_RESETB", "WF_DIG_RESETB"; + drive-strength = <4>; + }; + }; + }; + + ethsys: syscon@15000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mediatek,mt7981-ethsys", + "mediatek,mt7986-ethsys", + "syscon"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + wed: wed@15010000 { + compatible = "mediatek,mt7981-wed", + "mediatek,mt7986-wed", + "syscon"; + reg = <0 0x15010000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>, + <&wo_data>, <&wo_boot>; + memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", + "wo-data", "wo-boot"; + mediatek,wo-ccif = <&wo_ccif0>; + }; + + eth: ethernet@15100000 { + compatible = "mediatek,mt7981-eth"; + reg = <0 0x15100000 0 0x80000>; + interrupts = , + , + , + ; + clocks = <ðsys CLK_ETH_FE_EN>, + <ðsys CLK_ETH_GP2_EN>, + <ðsys CLK_ETH_GP1_EN>, + <ðsys CLK_ETH_WOCPU0_EN>, + <&sgmiisys0 CLK_SGM0_TX_EN>, + <&sgmiisys0 CLK_SGM0_RX_EN>, + <&sgmiisys0 CLK_SGM0_CK0_EN>, + <&sgmiisys0 CLK_SGM0_CDR_CK0_EN>, + <&sgmiisys1 CLK_SGM1_TX_EN>, + <&sgmiisys1 CLK_SGM1_RX_EN>, + <&sgmiisys1 CLK_SGM1_CK1_EN>, + <&sgmiisys1 CLK_SGM1_CDR_CK1_EN>, + <&topckgen CLK_TOP_SGM_REG>, + <&topckgen CLK_TOP_NETSYS_SEL>, + <&topckgen CLK_TOP_NETSYS_500M_SEL>; + clock-names = "fe", "gp2", "gp1", "wocpu0", + "sgmii_tx250m", "sgmii_rx250m", + "sgmii_cdr_ref", "sgmii_cdr_fb", + "sgmii2_tx250m", "sgmii2_rx250m", + "sgmii2_cdr_ref", "sgmii2_cdr_fb", + "sgmii_ck", "netsys0", "netsys1"; + assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>, + <&topckgen CLK_TOP_SGM_325M_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_NET2_800M>, + <&topckgen CLK_TOP_CB_SGM_325M>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; + mediatek,infracfg = <&topmisc>; + mediatek,wed = <&wed>; + #reset-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + mdio_bus: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + int_gbe_phy: ethernet-phy@0 { + reg = <0>; + compatible = "ethernet-phy-ieee802.3-c22"; + phy-mode = "gmii"; + phy-is-integrated; + nvmem-cells = <&phy_calibration>; + nvmem-cell-names = "phy-cal-data"; + }; + }; + }; + + wo_ccif0: syscon@151a5000 { + compatible = "mediatek,mt7986-wo-ccif", "syscon"; + reg = <0 0x151a5000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + }; + + sgmiisys0: syscon@10060000 { + compatible = "mediatek,mt7981-sgmiisys_0", "mediatek,mt7986-sgmiisys_0", "syscon"; + reg = <0 0x10060000 0 0x1000>; + mediatek,pnswap; + #clock-cells = <1>; + }; + + sgmiisys1: syscon@10070000 { + compatible = "mediatek,mt7981-sgmiisys_1", "mediatek,mt7986-sgmiisys_1", "syscon"; + reg = <0 0x10070000 0 0x1000>; + #clock-cells = <1>; + }; + + topmisc: topmisc@11d10000 { + compatible = "mediatek,mt7981-topmisc", "syscon"; + reg = <0 0x11d10000 0 0x10000>; + #clock-cells = <1>; + }; + + snand: snfi@11005000 { + compatible = "mediatek,mt7986-snand"; + reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>; + reg-names = "nfi", "ecc"; + interrupts = ; + clocks = <&infracfg CLK_INFRA_SPINFI1_CK>, + <&infracfg CLK_INFRA_NFI1_CK>, + <&infracfg CLK_INFRA_NFI_HCK_CK>; + clock-names = "pad_clk", "nfi_clk", "nfi_hclk"; + assigned-clocks = <&topckgen CLK_TOP_SPINFI_SEL>, + <&topckgen CLK_TOP_NFI1X_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D8>, + <&topckgen CLK_TOP_CB_M_D8>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + mmc0: mmc@11230000 { + compatible = "mediatek,mt7986-mmc", + "mediatek,mt7981-mmc"; + reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_EMMC_208M>, + <&topckgen CLK_TOP_EMMC_400M>, + <&infracfg CLK_INFRA_MSDC_CK>; + assigned-clocks = <&topckgen CLK_TOP_EMMC_208M_SEL>, + <&topckgen CLK_TOP_EMMC_400M_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D2>, + <&topckgen CLK_TOP_CB_NET2_D2>; + clock-names = "source", "hclk", "source_cg"; + status = "disabled"; + }; + + wed_pcie: wed_pcie@10003000 { + compatible = "mediatek,wed_pcie"; + reg = <0 0x10003000 0 0x10>; + }; + + spi0: spi@1100a000 { + compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x1100a000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_CB_M_D2>, + <&topckgen CLK_TOP_SPI_SEL>, + <&infracfg CLK_INFRA_SPI0_CK>, + <&infracfg CLK_INFRA_SPI0_HCK_CK>; + + clock-names = "parent-clk", "sel-clk", "spi-clk", "hclk"; + status = "disabled"; + }; + + spi1: spi@1100b000 { + compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x1100b000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_CB_M_D2>, + <&topckgen CLK_TOP_SPIM_MST_SEL>, + <&infracfg CLK_INFRA_SPI1_CK>, + <&infracfg CLK_INFRA_SPI1_HCK_CK>; + clock-names = "parent-clk", "sel-clk", "spi-clk", "hclk"; + status = "disabled"; + }; + + spi2: spi@11009000 { + compatible = "mediatek,mt7986-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x11009000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_CB_M_D2>, + <&topckgen CLK_TOP_SPI_SEL>, + <&infracfg CLK_INFRA_SPI2_CK>, + <&infracfg CLK_INFRA_SPI2_HCK_CK>; + clock-names = "parent-clk", "sel-clk", "spi-clk", "hclk"; + status = "disabled"; + }; + + consys: consys@10000000 { + compatible = "mediatek,mt7981-consys"; + reg = <0 0x10000000 0 0x8600000>; + memory-region = <&wmcpu_emi>; + }; + + xhci: usb@11200000 { + compatible = "mediatek,mt7986-xhci", + "mediatek,mtk-xhci"; + reg = <0 0x11200000 0 0x2e00>, + <0 0x11203e00 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + clocks = <&infracfg CLK_INFRA_IUSB_SYS_CK>, + <&infracfg CLK_INFRA_IUSB_CK>, + <&infracfg CLK_INFRA_IUSB_133_CK>, + <&infracfg CLK_INFRA_IUSB_66M_CK>, + <&topckgen CLK_TOP_U2U3_XHCI_SEL>; + clock-names = "sys_ck", + "ref_ck", + "mcu_ck", + "dma_ck", + "xhci_ck"; + phys = <&u2port0 PHY_TYPE_USB2>, + <&u3port0 PHY_TYPE_USB3>; + vusb33-supply = <®_3p3v>; + mediatek,u3p-dis-msk = <0x01>; + status = "disabled"; + }; + + usb_phy: usb-phy@11e10000 { + compatible = "mediatek,mt7981", + "mediatek,generic-tphy-v2"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x11e10000 0x1700>; + status = "disabled"; + + u2port0: usb-phy@0 { + reg = <0x0 0x700>; + clocks = <&topckgen CLK_TOP_USB_FRMCNT_SEL>; + clock-names = "ref"; + #phy-cells = <1>; + }; + + u3port0: usb-phy@700 { + reg = <0x700 0x900>; + clocks = <&topckgen CLK_TOP_USB3_PHY_SEL>; + clock-names = "ref"; + #phy-cells = <1>; + mediatek,syscon-type = <&topmisc 0x218 0>; + status = "okay"; + }; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + efuse: efuse@11f20000 { + compatible = "mediatek,mt7981-efuse", + "mediatek,efuse"; + reg = <0 0x11f20000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + + thermal_calibration: thermal-calib@274 { + reg = <0x274 0xc>; + }; + + phy_calibration: phy-calib@8dc { + reg = <0x8dc 0x10>; + }; + + comb_rx_imp_p0: usb3-rx-imp@8c8 { + reg = <0x8c8 1>; + bits = <0 5>; + }; + + comb_tx_imp_p0: usb3-tx-imp@8c8 { + reg = <0x8c8 2>; + bits = <5 5>; + }; + + comb_intr_p0: usb3-intr@8c9 { + reg = <0x8c9 1>; + bits = <2 6>; + }; + }; + + afe: audio-controller@11210000 { + compatible = "mediatek,mt79xx-audio"; + reg = <0 0x11210000 0 0x9000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_AUD_BUS_CK>, + <&infracfg CLK_INFRA_AUD_26M_CK>, + <&infracfg CLK_INFRA_AUD_L_CK>, + <&infracfg CLK_INFRA_AUD_AUD_CK>, + <&infracfg CLK_INFRA_AUD_EG2_CK>, + <&topckgen CLK_TOP_AUD_SEL>; + clock-names = "aud_bus_ck", + "aud_26m_ck", + "aud_l_ck", + "aud_aud_ck", + "aud_eg2_ck", + "aud_sel"; + assigned-clocks = <&topckgen CLK_TOP_AUD_SEL>, + <&topckgen CLK_TOP_A1SYS_SEL>, + <&topckgen CLK_TOP_AUD_L_SEL>, + <&topckgen CLK_TOP_A_TUNER_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_APLL2_196M>, + <&topckgen CLK_TOP_APLL2_D4>, + <&topckgen CLK_TOP_CB_APLL2_196M>, + <&topckgen CLK_TOP_APLL2_D4>; + status = "disabled"; + }; + + ice: ice_debug { + compatible = "mediatek,mt7981-ice_debug", + "mediatek,mt2701-ice_debug"; + clocks = <&infracfg CLK_INFRA_DBG_CK>; + clock-names = "ice_dbg"; + }; + + wifi: wifi@18000000 { + compatible = "mediatek,mt7981-wmac"; + resets = <&watchdog MT7986_TOPRGU_CONSYS_RST>; + reset-names = "consys"; + pinctrl-0 = <&wifi_dbdc_pins>; + pinctrl-names = "dbdc"; + clocks = <&topckgen CLK_TOP_NETSYS_MCU_SEL>, + <&topckgen CLK_TOP_AP2CNN_HOST_SEL>; + clock-names = "mcu", "ap2conn"; + reg = <0 0x18000000 0 0x1000000>, + <0 0x10003000 0 0x1000>, + <0 0x11d10000 0 0x1000>; + interrupts = , + , + , + ; + memory-region = <&wmcpu_emi>; + status = "disabled"; + }; +}; From d98c4fb8bfabe86d4cfdb8bb5497ec6791d1e36d Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 10 Mar 2023 20:05:18 +0000 Subject: [PATCH 53/53] mediatek: broaden filogic target description The filogic subtarget now also supports MT7981 and will in future also support MT7988. Reflect that in the target description. Signed-off-by: Daniel Golle --- target/linux/mediatek/filogic/target.mk | 4 ++-- target/linux/mediatek/image/filogic.mk | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/target/linux/mediatek/filogic/target.mk b/target/linux/mediatek/filogic/target.mk index 44bc47dceac..dd4c4c14483 100644 --- a/target/linux/mediatek/filogic/target.mk +++ b/target/linux/mediatek/filogic/target.mk @@ -1,8 +1,8 @@ ARCH:=aarch64 SUBTARGET:=filogic -BOARDNAME:=Filogic 830 (MT7986) +BOARDNAME:=Filogic 8x0 (MT798x) CPU_TYPE:=cortex-a53 -DEFAULT_PACKAGES += kmod-crypto-hw-safexcel kmod-mt7915e kmod-mt7986-firmware wpad-basic-mbedtls uboot-envtools mt7986-wo-firmware +DEFAULT_PACKAGES += kmod-crypto-hw-safexcel kmod-mt7915e wpad-basic-mbedtls uboot-envtools KERNELNAME:=Image dtbs define Target/Description diff --git a/target/linux/mediatek/image/filogic.mk b/target/linux/mediatek/image/filogic.mk index 2e9becb241e..318052a03c9 100644 --- a/target/linux/mediatek/image/filogic.mk +++ b/target/linux/mediatek/image/filogic.mk @@ -63,7 +63,7 @@ define Device/bananapi_bpi-r3 DEVICE_DTS_CONFIG := config-mt7986a-bananapi-bpi-r3 DEVICE_DTS_OVERLAY:= mt7986a-bananapi-bpi-r3-nor mt7986a-bananapi-bpi-r3-emmc-nor mt7986a-bananapi-bpi-r3-emmc-snand mt7986a-bananapi-bpi-r3-snand DEVICE_DTS_DIR := ../dts - DEVICE_PACKAGES := kmod-hwmon-pwmfan kmod-i2c-gpio kmod-sfp kmod-usb3 e2fsprogs f2fsck mkf2fs + DEVICE_PACKAGES := kmod-hwmon-pwmfan kmod-i2c-gpio kmod-mt7986-firmware kmod-sfp kmod-usb3 e2fsprogs f2fsck mkf2fs mt7986-wo-firmware IMAGES := sysupgrade.itb KERNEL_INITRAMFS_SUFFIX := -recovery.itb ARTIFACTS := \ @@ -107,6 +107,7 @@ define Device/mediatek_mt7986a-rfb-nand DEVICE_MODEL := MT7986 rfba AP (NAND) DEVICE_DTS := mt7986a-rfb-spim-nand DEVICE_DTS_DIR := $(DTS_DIR)/ + DEVICE_PACKAGES := kmod-mt7986-firmware mt7986-wo-firmware KERNEL_LOADADDR := 0x48000000 SUPPORTED_DEVICES := mediatek,mt7986a-rfb-snand UBINIZE_OPTS := -E 5 @@ -130,6 +131,7 @@ define Device/mediatek_mt7986b-rfb DEVICE_MODEL := MTK7986 rfbb AP DEVICE_DTS := mt7986b-rfb DEVICE_DTS_DIR := $(DTS_DIR)/ + DEVICE_PACKAGES := kmod-mt7986-firmware mt7986-wo-firmware KERNEL_LOADADDR := 0x48000000 SUPPORTED_DEVICES := mediatek,mt7986b-rfb UBINIZE_OPTS := -E 5 @@ -148,7 +150,7 @@ define Device/xiaomi_redmi-router-ax6000-stock DEVICE_MODEL := Redmi Router AX6000 (stock layout) DEVICE_DTS := mt7986a-xiaomi-redmi-router-ax6000-stock DEVICE_DTS_DIR := ../dts - DEVICE_PACKAGES := kmod-leds-ws2812b + DEVICE_PACKAGES := kmod-leds-ws2812b kmod-mt7986-firmware mt7986-wo-firmware KERNEL_LOADADDR := 0x48000000 UBINIZE_OPTS := -E 5 BLOCKSIZE := 128k @@ -166,7 +168,7 @@ define Device/xiaomi_redmi-router-ax6000-ubootmod DEVICE_MODEL := Redmi Router AX6000 (OpenWrt U-Boot layout) DEVICE_DTS := mt7986a-xiaomi-redmi-router-ax6000-ubootmod DEVICE_DTS_DIR := ../dts - DEVICE_PACKAGES := kmod-leds-ws2812b + DEVICE_PACKAGES := kmod-leds-ws2812b kmod-mt7986-firmware mt7986-wo-firmware KERNEL_INITRAMFS_SUFFIX := -recovery.itb IMAGES := sysupgrade.itb KERNEL_LOADADDR := 0x48000000