From 6f0b8b4a859850c7be88df38f2c0db61052d79e3 Mon Sep 17 00:00:00 2001 From: "github-action[bot]" Date: Fri, 20 Mar 2026 20:03:30 +0100 Subject: [PATCH] Update On Fri Mar 20 20:03:30 CET 2026 --- .github/update.log | 1 + .../golang/clash/.github/workflows/build.yml | 6 +- .../golang/clash/adapter/outbound/sudoku.go | 2 +- .../golang/clash/adapter/outbound/trojan.go | 20 +- .../golang/clash/adapter/outbound/vless.go | 18 +- .../golang/clash/adapter/outbound/vmess.go | 19 +- .../clash/adapter/outboundgroup/fallback.go | 10 +- .../clash/adapter/outboundgroup/groupbase.go | 24 +- .../adapter/outboundgroup/loadbalance.go | 10 +- .../clash/adapter/outboundgroup/selector.go | 10 +- .../clash/adapter/outboundgroup/urltest.go | 10 +- .../clash/adapter/outboundgroup/util.go | 3 + .../golang/clash/adapter/provider/parser.go | 4 +- .../src/foss/golang/clash/docs/config.yaml | 7 +- .../core/src/foss/golang/clash/go.mod | 1 + .../core/src/foss/golang/clash/go.sum | 2 + .../golang/clash/listener/inbound/sudoku.go | 2 +- .../foss/golang/clash/listener/mixed/mixed.go | 1 + .../clash/listener/shadowsocks/utils.go | 5 +- .../clash/listener/shadowsocks/utils_test.go | 22 + .../clash/listener/sing_vmess/server.go | 4 +- .../clash/listener/sing_vmess/server_test.go | 22 + .../foss/golang/clash/transport/gun/gun.go | 47 +- .../golang/clash/transport/gun/transport.go | 13 +- .../clash/transport/gun/transport_close.go | 2 +- .../transport/sudoku/crypto/record_conn.go | 152 +++- .../sudoku/crypto/record_conn_test.go | 86 +++ .../clash/transport/sudoku/early_handshake.go | 345 +++++++++ .../clash/transport/sudoku/handshake.go | 3 + .../clash/transport/sudoku/httpmask_tunnel.go | 56 +- .../transport/sudoku/httpmask_tunnel_test.go | 62 ++ .../sudoku/obfs/httpmask/early_handshake.go | 174 +++++ .../transport/sudoku/obfs/httpmask/tunnel.go | 170 +++-- .../sudoku/obfs/httpmask/tunnel_ws.go | 31 +- .../sudoku/obfs/httpmask/tunnel_ws_server.go | 36 +- .../transport/sudoku/obfs/sudoku/packed.go | 192 +++-- .../sudoku/obfs/sudoku/packed_prefix_test.go | 91 +++ .../clash/transport/trusttunnel/client.go | 91 +-- .../transport/trusttunnel/force_close.go | 2 +- .../clash/transport/trusttunnel/protocol.go | 4 + .../core/src/foss/golang/go.mod | 1 + .../core/src/foss/golang/go.sum | 2 + .../core/src/main/golang/go.mod | 1 + .../core/src/main/golang/go.sum | 2 + .../src/main/golang/native/tunnel/proxies.go | 5 +- clash-meta/adapter/outboundgroup/fallback.go | 10 +- clash-meta/adapter/outboundgroup/groupbase.go | 24 +- .../adapter/outboundgroup/loadbalance.go | 10 +- clash-meta/adapter/outboundgroup/selector.go | 10 +- clash-meta/adapter/outboundgroup/urltest.go | 10 +- clash-meta/adapter/outboundgroup/util.go | 3 + clash-meta/go.mod | 3 +- clash-meta/go.sum | 2 + clash-meta/listener/shadowsocks/utils.go | 5 +- clash-meta/listener/shadowsocks/utils_test.go | 22 + clash-meta/listener/sing_tun/server.go | 2 - .../listener/sing_tun/server_android.go | 25 - .../listener/sing_tun/server_notandroid.go | 1 - clash-meta/listener/sing_vmess/server.go | 4 +- clash-meta/listener/sing_vmess/server_test.go | 22 + clash-nyanpasu/backend/Cargo.lock | 6 +- .../frontend/interface/package.json | 2 +- clash-nyanpasu/frontend/nyanpasu/package.json | 4 +- clash-nyanpasu/manifest/version.json | 4 +- clash-nyanpasu/package.json | 2 +- clash-nyanpasu/pnpm-lock.yaml | 189 +++-- clash-nyanpasu/scripts/package.json | 4 +- hysteria/app/cmd/server.go | 4 + hysteria/app/cmd/server_test.go | 1 + hysteria/app/cmd/server_test.yaml | 1 + lede/package/kernel/mac80211/Makefile | 19 +- .../ath/070-ath_common_config.patch | 10 + .../ath/400-ath_move_debug_code.patch | 31 + .../ath/402-ath_regd_optional.patch | 92 +++ .../ath/403-world_regd_fixup.patch | 84 ++ .../ath/404-regd_no_assoc_hints.patch | 19 + .../patches-6.18/ath/405-ath_regd_us.patch | 26 + .../ath/406-ath_relax_default_regd.patch | 51 ++ ...add_platform_eeprom_support_to_ath5k.patch | 56 ++ .../ath10k/080-ath10k_thermal_config.patch | 47 ++ ...21-ath10k_init_devices_synchronously.patch | 33 + .../930-ath10k_add_tpt_led_trigger.patch | 37 + ...75-ath10k-use-tpt-trigger-by-default.patch | 51 ++ ...-power-reduction-for-US-regulatory-d.patch | 101 +++ ...h10k-Try-to-get-mac-address-from-dts.patch | 37 + ...k-always-use-mac80211-loss-detection.patch | 28 + .../ath10k/990-ath10k-small-buffers.patch | 64 ++ .../991-ath10k-support-flush_sta-method.patch | 70 ++ ...i-ath11k-use-unique-QRTR-instance-ID.patch | 164 ++++ ...wrong-usage-of-resource_size-causing.patch | 69 ++ ...ort-setting-bdf-addr-and-caldb-addr-.patch | 62 ++ ...k_mac_op_flush_sta-to-properly-flush.patch | 65 ++ ...k-control-thermal-support-via-symbol.patch | 66 ++ ...upport-setting-FW-memory-mode-via-DT.patch | 75 ++ ...tersection-support-for-regulatory-ru.patch | 332 ++++++++ ...-ath11k-disable-coldboot-for-ipq6018.patch | 26 + ...ble-coldboot-calibration-for-ipq5018.patch | 27 + ...apped-ce-accessing-issue-on-64bit-OS.patch | 153 ++++ ...ifi-ath11k-add-hw-params-for-QCN6122.patch | 120 +++ ...wifi-ath11k-add-hal-regs-for-QCN6122.patch | 114 +++ ...-ath11k-add-hw-ring-mask-for-QCN6122.patch | 74 ++ ...k-update-hif_and-pci_ops-for-QCN6122.patch | 102 +++ ...h11k-add-multipd-support-for-QCN6122.patch | 110 +++ ...fi-ath11k-add-QCN6122-device-support.patch | 55 ++ ...11k-Support-to-assign-m3-dump-memory.patch | 31 + ...rssi-station-dump-for-IPQ5018-and-QC.patch | 32 + ...8-wifi-ath11k-Fix-the-WMM-param-type.patch | 24 + ...dd-basic-hwmon-temperature-reporting.patch | 380 +++++++++ ...0-ath12k-prevent-ltssm-startup-crash.patch | 17 + ...k-limit-WMI_SCAN_CHAN_LIST_CMDID-arg.patch | 153 ++++ ...k-fix-5GHz-operation-on-wideband-QCN.patch | 137 ++++ ...2k-convert-tasklet-to-BH-workqueue-f.patch | 82 ++ ...k-control-thermal-support-via-symbol.patch | 62 ++ .../201-ath5k-WAR-for-AR71xx-PCI-bug.patch | 38 + .../ath5k/411-ath5k_allow_adhoc_and_ap.patch | 46 ++ .../ath5k/420-ath5k_disable_fast_cc.patch | 18 + .../ath5k/430-add_ath5k_platform.patch | 33 + .../ath5k/440-ath5k_channel_bw_debugfs.patch | 142 ++++ .../341-wifi-ath9k-obtain-system-gpios.patch | 273 +++++++ ...w-reset-AHB-WMAC-interface-on-AR91xx.patch | 25 + ..._hw-issue-external-reset-for-QCA955x.patch | 129 ++++ ...h9k-force-rx_clear-when-disabling-rx.patch | 35 + ...erpret-requested-txpower-in-EIRP-dom.patch | 36 + ...power-reduction-for-US-regulatory-do.patch | 24 + .../ath9k/401-ath9k_blink_default.patch | 11 + .../ath9k/410-ath9k_allow_adhoc_and_ap.patch | 10 + ...abled-MFP-capability-unconditionally.patch | 34 + .../ath9k/500-ath9k_eeprom_debugfs.patch | 92 +++ .../ath9k/501-ath9k_ahb_init.patch | 34 + .../510-ath9k_intr_mitigation_tweak.patch | 18 + .../ath9k/511-ath9k_reduce_rxbuf.patch | 11 + .../ath9k/512-ath9k_channelbw_debugfs.patch | 191 +++++ .../ath9k/513-ath9k_add_pci_ids.patch | 30 + .../ath9k/530-ath9k_extra_leds.patch | 267 +++++++ .../ath9k/540-ath9k_reduce_ani_interval.patch | 11 + .../ath9k/542-ath9k_debugfs_diag.patch | 139 ++++ .../ath9k/543-ath9k_entropy_from_adc.patch | 186 +++++ ...544-ath9k-ar933x-usb-hang-workaround.patch | 79 ++ .../ath9k/545-ath9k_ani_ws_detect.patch | 155 ++++ .../ath9k/547-ath9k_led_defstate_fix.patch | 29 + .../ath9k/548-ath9k_enable_gpio_chip.patch | 210 +++++ .../patches-6.18/ath9k/550-ath9k-of.patch | 166 ++++ .../ath9k/551-ath9k_ubnt_uap_plus_hsr.patch | 406 ++++++++++ .../brcm/040-brcmutil_option.patch | 10 + .../810-b43-gpio-mask-module-option.patch | 37 + .../patches-6.18/brcm/811-b43_no_pio.patch | 86 +++ .../brcm/812-b43-add-antenna-control.patch | 133 ++++ .../813-b43-reduce-number-of-RX-slots.patch | 11 + .../814-b43-only-use-gpio-0-1-for-led.patch | 17 + ...815-b43-always-take-overlapping-devs.patch | 11 + ...-remove-extra-regulation-restriction.patch | 27 + ...und-bug-with-some-inconsistent-BSSes.patch | 49 ++ ...mfmac-adds-support-for-BCM43341-wifi.patch | 29 + ...fer-a-ccode-from-OTP-over-nvram-file.patch | 130 ++++ ...ac-Increase-power-saving-delay-to-2s.patch | 24 + ...upport-DS1-exit-firmware-re-download.patch | 721 ++++++++++++++++++ ...eroperating-DPP-and-other-encryption.patch | 129 ++++ ...c-Include-modinfo-for-43456-CLM-blob.patch | 26 + ...mfmac-disable-dump_survey-on-bcm2835.patch | 38 + .../patches-6.18/build/000-fix_kconfig.patch | 14 + .../patches-6.18/build/001-fix_build.patch | 168 ++++ .../build/002-change_allconfig.patch | 64 ++ .../build/003-remove_bogus_modparams.patch | 34 + .../build/004-fix-kconf-compiling.patch | 47 ++ .../build/005-fix-kconf-warnings.patch | 76 ++ .../build/012-kernel_build_check.patch | 11 + .../build/020-intel-mld-compile.patch | 54 ++ .../100-backports-drop-QRTR-and-MHI.patch | 76 ++ ...port-fix-unaligned.h-header-location.patch | 26 + .../build/140-trace_backport.patch | 694 +++++++++++++++++ .../150-ath_iommu_paging_domain_revert.patch | 32 + .../build/200-iwlwifi_thermal_backport.patch | 40 + .../210-wireless_netns_local_backport.patch | 54 ++ .../220-brcmfmac_usb_driver_backport.patch | 14 + ...x-init_vqs-build-error-on-kernel-6.6.patch | 30 + .../240-realtek-rtw88-BH-workqueue.patch | 14 + ...-genlmsg_multicast_allns-upstream-ba.patch | 121 +++ .../build/400-restore-old-debugfs_fops.patch | 252 ++++++ ...-convert-short-fops-to-debugfs-files.patch | 210 +++++ ...01-wifi-mt7601u-update-firmware-path.patch | 55 ++ ...700-mwl8k-missing-pci-id-for-WNR854T.patch | 10 + .../801-libertas-configure-sysfs-links.patch | 21 + .../802-libertas-set-wireless-macaddr.patch | 11 + ...crease-the-global-limit-up-to-4-SSID.patch | 41 + ...940-mwl8k_init_devices_synchronously.patch | 20 + ...ringified-name-of-command-in-error-l.patch | 177 +++++ .../rt2x00/100-rt2x00_options.patch | 42 + ...to-build-rt2800soc-module-for-RT3883.patch | 21 + ...support-for-loading-EEPROM-from-user.patch | 225 ++++++ ...-support-for-loading-EEPROM-from-MTD.patch | 107 +++ ...i-rt2x00-Support-EEPROM-swap-binding.patch | 44 ++ ...port-loading-eeprom-from-NVMEM-cells.patch | 95 +++ ...EEPROM-from-devicetree-embedded-data.patch | 76 ++ ...00-allow_disabling_bands_through_dts.patch | 17 + ...0-rt2x00-change-led-polarity-from-OF.patch | 40 + .../611-rt2x00-add-AP+STA-support.patch | 11 + ...spect-rt2800-hardware-TX-queue-index.patch | 257 +++++++ ...ease-the-watchdog-sampling-frequency.patch | 74 ++ ...librate-MT7620-when-switching-channe.patch | 77 ++ ...-rt2x00-rework-link-tuner-for-MT7620.patch | 48 ++ ...rrect-MT7620-SDM-mode-register-value.patch | 25 + ...gister-operation-on-RXIQ-calibration.patch | 26 + ...FCSR-register-init-values-for-RT5592.patch | 230 ++++++ ...-BBP-register-init-values-for-RT5592.patch | 119 +++ ...t-support-for-external-LNA-on-MT7620.patch | 121 +++ ...duce-accessors-for-CHIP_VER-register.patch | 139 ++++ ...-differentiate-based-on-SoC-CHIP_VER.patch | 437 +++++++++++ .../110-mac80211_keep_keys_on_stop_ap.patch | 24 + .../120-cfg80211_allow_perm_addr_change.patch | 52 ++ .../subsys/130-disable_auto_vif.patch | 27 + .../patches-6.18/subsys/210-ap_scan.patch | 19 + .../subsys/220-allow-ibss-mixed.patch | 40 + .../230-avoid-crashing-missing-band.patch | 34 + ...domize-BA-session-dialog-token-alloc.patch | 38 + ...-minstrel_ht-fix-MINSTREL_FRAC-macro.patch | 21 + ...l_ht-reduce-fluctuations-in-rate-pro.patch | 30 + ...l_ht-rework-rate-downgrade-code-and-.patch | 151 ++++ ...crease-quantum-for-airtime-scheduler.patch | 53 ++ ...race-period-for-DFS-available-after-.patch | 153 ++++ ...dd-AQL-support-for-broadcast-packets.patch | 293 +++++++ ...sh-in-ieee80211_chan_bw_change-for-A.patch | 39 + ...llow-scanning-while-on-radar-channel.patch | 399 ++++++++++ ...out-part-of-ieee80211_calc_expected_.patch | 140 ++++ ...e-expected-throughput-if-not-provide.patch | 53 ++ ...d-MLO-support-to-ieee80211_probe_cli.patch | 64 ++ ...d-eMLSR-eMLMR-action-frame-parsing-s.patch | 412 ++++++++++ lede/package/kernel/mt76/Makefile | 28 + ...-Introduce-MT7992-WED-support-to-MT7.patch | 116 +++ ...e-proper-wed-reference-in-mt76-wed-d.patch | 79 ++ ...dma-mask-limitation-and-GFP_DMA32-fo.patch | 50 ++ ...a-faux-bus-for-use-when-a-simple-dev.patch | 386 ++++++++++ .../dts/mt7987a-glinet-gl-mt3600be.dts | 292 +++++++ .../filogic/base-files/etc/board.d/02_network | 1 + lede/target/linux/mediatek/image/filogic.mk | 21 + mihomo/adapter/outboundgroup/fallback.go | 10 +- mihomo/adapter/outboundgroup/groupbase.go | 24 +- mihomo/adapter/outboundgroup/loadbalance.go | 10 +- mihomo/adapter/outboundgroup/selector.go | 10 +- mihomo/adapter/outboundgroup/urltest.go | 10 +- mihomo/adapter/outboundgroup/util.go | 3 + mihomo/go.mod | 3 +- mihomo/go.sum | 2 + mihomo/listener/shadowsocks/utils.go | 5 +- mihomo/listener/shadowsocks/utils_test.go | 22 + mihomo/listener/sing_tun/server.go | 2 - mihomo/listener/sing_tun/server_android.go | 25 - mihomo/listener/sing_tun/server_notandroid.go | 1 - mihomo/listener/sing_vmess/server.go | 4 +- mihomo/listener/sing_vmess/server_test.go | 22 + openclash/luci-app-openclash/Makefile | 2 +- .../luasrc/controller/openclash.lua | 76 +- .../model/cbi/openclash/config-subscribe.lua | 8 + .../luasrc/model/cbi/openclash/settings.lua | 4 +- .../luasrc/view/openclash/config_edit.htm | 2 - .../luasrc/view/openclash/status.htm | 73 +- .../luasrc/view/openclash/sub_info_show.htm | 239 +++--- .../luci-app-openclash/po/es/openclash.es.po | 3 - .../po/zh-cn/openclash.zh-cn.po | 3 - .../root/etc/init.d/openclash | 9 +- .../root/usr/share/openclash/YAML.rb | 19 +- .../root/usr/share/openclash/openclash.sh | 14 +- .../usr/share/openclash/openclash_update.sh | 4 +- .../usr/share/openclash/openclash_watchdog.sh | 2 + .../root/usr/share/openclash/uci.sh | 8 +- small/.github/workflows/T2 build.yml | 44 +- small/.github/workflows/T9 build.yml | 44 +- small/README.md | 13 +- small/dns2socks/Makefile | 26 +- small/luci-app-openclash/Makefile | 2 +- .../luasrc/controller/openclash.lua | 76 +- .../model/cbi/openclash/config-subscribe.lua | 8 + .../luasrc/model/cbi/openclash/settings.lua | 4 +- .../luasrc/view/openclash/config_edit.htm | 2 - .../luasrc/view/openclash/status.htm | 73 +- .../luasrc/view/openclash/sub_info_show.htm | 239 +++--- .../luci-app-openclash/po/es/openclash.es.po | 3 - .../po/zh-cn/openclash.zh-cn.po | 3 - .../root/etc/init.d/openclash | 9 +- .../root/usr/share/openclash/YAML.rb | 19 +- .../root/usr/share/openclash/openclash.sh | 14 +- .../usr/share/openclash/openclash_update.sh | 4 +- .../usr/share/openclash/openclash_watchdog.sh | 2 + .../root/usr/share/openclash/uci.sh | 8 +- small/nikki/Makefile | 2 +- small/nikki/files/nikki.init | 2 +- small/nikki/files/ucode/include.uc | 2 +- small/v2ray-geodata/Makefile | 4 +- v2rayn/.github/workflows/build-linux.yml | 79 +- v2rayn/package-debian.sh | 641 ++++++++++++++-- v2rayn/package-rhel.sh | 59 +- v2rayn/v2rayN/Directory.Build.props | 2 +- v2rayn/v2rayN/Directory.Packages.props | 2 +- .../v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 36 + .../v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 12 + v2rayn/v2rayN/ServiceLib/Resx/ResUI.fr.resx | 12 + v2rayn/v2rayN/ServiceLib/Resx/ResUI.hu.resx | 12 + v2rayn/v2rayN/ServiceLib/Resx/ResUI.resx | 12 + v2rayn/v2rayN/ServiceLib/Resx/ResUI.ru.resx | 154 ++-- .../v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 12 + .../v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 12 + .../Views/AddServerWindow.axaml | 16 +- .../Views/DNSSettingWindow.axaml | 22 +- .../Views/FullConfigTemplateWindow.axaml | 22 +- .../v2rayN.Desktop/Views/JsonEditor.axaml | 23 + .../v2rayN.Desktop/Views/JsonEditor.axaml.cs | 96 +++ .../v2rayN/v2rayN.Desktop/Views/MsgView.axaml | 4 +- 306 files changed, 18701 insertions(+), 1246 deletions(-) create mode 100644 clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/utils_test.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server_test.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/crypto/record_conn_test.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/early_handshake.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/early_handshake.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/sudoku/packed_prefix_test.go create mode 100644 clash-meta/listener/shadowsocks/utils_test.go create mode 100644 clash-meta/listener/sing_vmess/server_test.go create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath/070-ath_common_config.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath/400-ath_move_debug_code.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath/402-ath_regd_optional.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath/403-world_regd_fixup.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath/404-regd_no_assoc_hints.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath/405-ath_regd_us.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath/406-ath_relax_default_regd.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath/431-add_platform_eeprom_support_to_ath5k.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/080-ath10k_thermal_config.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/921-ath10k_init_devices_synchronously.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/930-ath10k_add_tpt_led_trigger.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/975-ath10k-use-tpt-trigger-by-default.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/981-ath10k-adjust-tx-power-reduction-for-US-regulatory-d.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/988-ath10k-always-use-mac80211-loss-detection.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/990-ath10k-small-buffers.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath10k/991-ath10k-support-flush_sta-method.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/100-wifi-ath11k-use-unique-QRTR-instance-ID.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/101-wifi-ath11k-fix-wrong-usage-of-resource_size-causing.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/201-wifi-ath11k-Support-setting-bdf-addr-and-caldb-addr-.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/453-ath11k-add-ath11k_mac_op_flush_sta-to-properly-flush.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/900-ath11k-control-thermal-support-via-symbol.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/903-ath11k-support-setting-FW-memory-mode-via-DT.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/905-ath11k-remove-intersection-support-for-regulatory-ru.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/906-wifi-ath11k-disable-coldboot-for-ipq6018.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/907-wifi-ath11k-disable-coldboot-calibration-for-ipq5018.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/910-ath11k-fix-remapped-ce-accessing-issue-on-64bit-OS.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/920-wifi-ath11k-add-hw-params-for-QCN6122.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/921-wifi-ath11k-add-hal-regs-for-QCN6122.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/922-wifi-ath11k-add-hw-ring-mask-for-QCN6122.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/923-wifi-ath11k-update-hif_and-pci_ops-for-QCN6122.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/924-wifi-ath11k-add-multipd-support-for-QCN6122.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/925-wifi-ath11k-add-QCN6122-device-support.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/931-wifi-ath11k-Support-to-assign-m3-dump-memory.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/947-wifi-ath11k-fix-rssi-station-dump-for-IPQ5018-and-QC.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath11k/948-wifi-ath11k-Fix-the-WMM-param-type.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath12k/001-v7.1-wifi-ath12k-add-basic-hwmon-temperature-reporting.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath12k/100-ath12k-prevent-ltssm-startup-crash.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath12k/102-wifi-ath12k-limit-WMI_SCAN_CHAN_LIST_CMDID-arg.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath12k/103-wifi-ath12k-fix-5GHz-operation-on-wideband-QCN.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath12k/200-Revert-wifi-ath12k-convert-tasklet-to-BH-workqueue-f.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath12k/300-ath12k-control-thermal-support-via-symbol.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath5k/201-ath5k-WAR-for-AR71xx-PCI-bug.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath5k/411-ath5k_allow_adhoc_and_ap.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath5k/420-ath5k_disable_fast_cc.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath5k/430-add_ath5k_platform.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath5k/440-ath5k_channel_bw_debugfs.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/341-wifi-ath9k-obtain-system-gpios.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/350-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/351-ath9k_hw-issue-external-reset-for-QCA955x.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/354-ath9k-force-rx_clear-when-disabling-rx.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/356-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/365-ath9k-adjust-tx-power-reduction-for-US-regulatory-do.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/401-ath9k_blink_default.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/410-ath9k_allow_adhoc_and_ap.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/450-ath9k-enabled-MFP-capability-unconditionally.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/500-ath9k_eeprom_debugfs.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/501-ath9k_ahb_init.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/510-ath9k_intr_mitigation_tweak.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/511-ath9k_reduce_rxbuf.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/512-ath9k_channelbw_debugfs.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/513-ath9k_add_pci_ids.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/530-ath9k_extra_leds.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/540-ath9k_reduce_ani_interval.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/542-ath9k_debugfs_diag.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/543-ath9k_entropy_from_adc.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/544-ath9k-ar933x-usb-hang-workaround.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/545-ath9k_ani_ws_detect.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/547-ath9k_led_defstate_fix.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/548-ath9k_enable_gpio_chip.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/550-ath9k-of.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/040-brcmutil_option.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/810-b43-gpio-mask-module-option.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/811-b43_no_pio.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/812-b43-add-antenna-control.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/813-b43-reduce-number-of-RX-slots.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/814-b43-only-use-gpio-0-1-for-led.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/815-b43-always-take-overlapping-devs.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/850-brcmsmac-remove-extra-regulation-restriction.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/860-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/870-01-rpi-6.12-brcmfmac-adds-support-for-BCM43341-wifi.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/870-02-rpi-6.12-brcmfmac-Prefer-a-ccode-from-OTP-over-nvram-file.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/870-03-rpi-6.12-brcmfmac-Increase-power-saving-delay-to-2s.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/870-04-rpi-6.12-brcmfmac-non-upstream-support-DS1-exit-firmware-re-download.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/870-05-rpi-6.12-brcmfmac-Fix-interoperating-DPP-and-other-encryption.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/870-06-rpi-6.12-brcmfmac-Include-modinfo-for-43456-CLM-blob.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/brcm/871-brcmfmac-disable-dump_survey-on-bcm2835.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/000-fix_kconfig.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/001-fix_build.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/002-change_allconfig.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/003-remove_bogus_modparams.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/004-fix-kconf-compiling.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/005-fix-kconf-warnings.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/012-kernel_build_check.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/020-intel-mld-compile.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/100-backports-drop-QRTR-and-MHI.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/120-backport-fix-unaligned.h-header-location.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/140-trace_backport.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/150-ath_iommu_paging_domain_revert.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/200-iwlwifi_thermal_backport.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/210-wireless_netns_local_backport.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/220-brcmfmac_usb_driver_backport.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/230-fix-init_vqs-build-error-on-kernel-6.6.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/240-realtek-rtw88-BH-workqueue.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/300-backports-handle-genlmsg_multicast_allns-upstream-ba.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/400-restore-old-debugfs_fops.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/build/410-mac80211-convert-short-fops-to-debugfs-files.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/mt7601u/001-wifi-mt7601u-update-firmware-path.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/mwl/801-libertas-configure-sysfs-links.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/mwl/802-libertas-set-wireless-macaddr.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/mwl/940-mwl8k_init_devices_synchronously.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/100-rt2x00_options.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/501-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/602-01-wifi-rt2x00-Add-support-for-loading-EEPROM-from-user.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/602-03-wifi-rt2x00-Add-support-for-loading-EEPROM-from-MTD.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/602-04-wifi-rt2x00-Support-EEPROM-swap-binding.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/602-05-wifi-rt2x00-support-loading-eeprom-from-NVMEM-cells.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/603-wifi-rt2x00-Add-support-for-loading-EEPROM-from-devicetree-embedded-data.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/611-rt2x00-add-AP+STA-support.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/620-01-rt2x00-respect-rt2800-hardware-TX-queue-index.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/620-02-rt2x00-increase-the-watchdog-sampling-frequency.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/621-01-rt2x00-always-calibrate-MT7620-when-switching-channe.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/621-02-rt2x00-rework-link-tuner-for-MT7620.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/621-03-rt2x00-correct-MT7620-SDM-mode-register-value.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/621-04-rt2x00-fix-register-operation-on-RXIQ-calibration.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/622-01-rt2x00-fix-RFCSR-register-init-values-for-RT5592.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/622-02-rt2x00-fix-BBP-register-init-values-for-RT5592.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/110-mac80211_keep_keys_on_stop_ap.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/120-cfg80211_allow_perm_addr_change.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/130-disable_auto_vif.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/210-ap_scan.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/220-allow-ibss-mixed.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/230-avoid-crashing-missing-band.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/302-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/310-cfg80211-allow-grace-period-for-DFS-available-after-.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/320-mac80211-add-AQL-support-for-broadcast-packets.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/330-mac80211-fix-crash-in-ieee80211_chan_bw_change-for-A.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/350-mac80211-allow-scanning-while-on-radar-channel.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/360-mac80211-factor-out-part-of-ieee80211_calc_expected_.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/361-mac80211-estimate-expected-throughput-if-not-provide.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/370-wifi-mac80211-add-MLO-support-to-ieee80211_probe_cli.patch create mode 100644 lede/package/kernel/mac80211/patches-6.18/subsys/371-wifi-mac80211-Add-eMLSR-eMLMR-action-frame-parsing-s.patch create mode 100644 lede/target/linux/generic/backport-6.12/731-v6.18-net-mediatek-wed-Introduce-MT7992-WED-support-to-MT7.patch create mode 100644 lede/target/linux/generic/backport-6.12/732-v6.18-wifi-mt76-wed-use-proper-wed-reference-in-mt76-wed-d.patch create mode 100644 lede/target/linux/generic/backport-6.12/733-v6.18-net-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-fo.patch create mode 100644 lede/target/linux/generic/backport-6.12/900-v6.14-driver-core-add-a-faux-bus-for-use-when-a-simple-dev.patch create mode 100644 lede/target/linux/mediatek/dts/mt7987a-glinet-gl-mt3600be.dts create mode 100644 mihomo/listener/shadowsocks/utils_test.go create mode 100644 mihomo/listener/sing_vmess/server_test.go create mode 100644 v2rayn/v2rayN/v2rayN.Desktop/Views/JsonEditor.axaml create mode 100644 v2rayn/v2rayN/v2rayN.Desktop/Views/JsonEditor.axaml.cs diff --git a/.github/update.log b/.github/update.log index 913b0400b7..0fb9e65aa5 100644 --- a/.github/update.log +++ b/.github/update.log @@ -1304,3 +1304,4 @@ Update On Mon Mar 16 20:17:53 CET 2026 Update On Tue Mar 17 20:16:34 CET 2026 Update On Wed Mar 18 20:13:21 CET 2026 Update On Thu Mar 19 20:11:34 CET 2026 +Update On Fri Mar 20 20:03:22 CET 2026 diff --git a/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml b/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml index 48ef8d5f6b..461a400911 100644 --- a/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml +++ b/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml @@ -53,7 +53,7 @@ jobs: - { goos: linux, goarch: mipsle, gomips: softfloat, output: mipsle-softfloat } - { goos: linux, goarch: mips64, output: mips64 } - { goos: linux, goarch: mips64le, output: mips64le, debian: mips64el, rpm: mips64el } - - { goos: linux, goarch: loong64, output: loong64-abi1, abi: '1', debian: loongarch64, rpm: loongarch64 } + - { goos: linux, goarch: loong64, output: loong64-abi1, abi: '1', debian: loongarch64, rpm: loongarch64, goversion: 'custom' } - { goos: linux, goarch: loong64, output: loong64-abi2, abi: '2', debian: loong64, rpm: loong64 } - { goos: linux, goarch: riscv64, output: riscv64, debian: riscv64, rpm: riscv64 } - { goos: linux, goarch: s390x, output: s390x, debian: s390x, rpm: s390x } @@ -158,14 +158,14 @@ jobs: - uses: actions/checkout@v5 - name: Set up Go - if: ${{ matrix.jobs.goversion == '' && matrix.jobs.abi != '1' }} + if: ${{ matrix.jobs.goversion == '' }} uses: actions/setup-go@v6 with: go-version: '1.26' check-latest: true # Always check for the latest patch release - name: Set up Go - if: ${{ matrix.jobs.goversion != '' && matrix.jobs.abi != '1' }} + if: ${{ matrix.jobs.goversion != '' && matrix.jobs.goversion != 'custom' }} uses: actions/setup-go@v6 with: go-version: ${{ matrix.jobs.goversion }} diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/sudoku.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/sudoku.go index d8550bf430..cf845821ce 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/sudoku.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/sudoku.go @@ -54,7 +54,7 @@ type SudokuHTTPMaskOptions struct { Mode string `proxy:"mode,omitempty"` TLS bool `proxy:"tls,omitempty"` Host string `proxy:"host,omitempty"` - PathRoot string `proxy:"path_root,omitempty"` + PathRoot string `proxy:"path-root,omitempty"` Multiplex string `proxy:"multiplex,omitempty"` } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/trojan.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/trojan.go index b691ff0080..497ff05b1f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/trojan.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/trojan.go @@ -27,8 +27,7 @@ type Trojan struct { hexPassword [trojan.KeyLength]byte // for gun mux - gunConfig *gun.Config - gunTransport *gun.TransportWrap + gunTransport *gun.Transport realityConfig *tlsC.RealityConfig echConfig *ech.Config @@ -178,7 +177,7 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con var c net.Conn // gun transport if t.gunTransport != nil { - c, err = gun.StreamGunWithTransport(t.gunTransport, t.gunConfig) + c, err = t.gunTransport.Dial() } else { c, err = t.dialer.DialContext(ctx, "tcp", t.addr) } @@ -206,7 +205,7 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata) var c net.Conn // grpc transport if t.gunTransport != nil { - c, err = gun.StreamGunWithTransport(t.gunTransport, t.gunConfig) + c, err = t.gunTransport.Dial() } else { c, err = t.dialer.DialContext(ctx, "tcp", t.addr) } @@ -317,13 +316,14 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { Reality: t.realityConfig, } - t.gunTransport = gun.NewHTTP2Client(dialFn, tlsConfig) - - t.gunConfig = &gun.Config{ - ServiceName: option.GrpcOpts.GrpcServiceName, - UserAgent: option.GrpcOpts.GrpcUserAgent, - Host: option.SNI, + gunConfig := &gun.Config{ + ServiceName: option.GrpcOpts.GrpcServiceName, + UserAgent: option.GrpcOpts.GrpcUserAgent, + Host: option.SNI, + PingInterval: option.GrpcOpts.PingInterval, } + + t.gunTransport = gun.NewTransport(dialFn, tlsConfig, gunConfig) } return t, nil diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vless.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vless.go index bd060b185d..78ccb6676f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vless.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vless.go @@ -33,8 +33,7 @@ type Vless struct { encryption *encryption.ClientInstance // for gun mux - gunConfig *gun.Config - gunTransport *gun.TransportWrap + gunTransport *gun.Transport realityConfig *tlsC.RealityConfig echConfig *ech.Config @@ -234,7 +233,7 @@ func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn var c net.Conn // gun transport if v.gunTransport != nil { - c, err = gun.StreamGunWithTransport(v.gunTransport, v.gunConfig) + c, err = v.gunTransport.Dial() } else { c, err = v.dialer.DialContext(ctx, "tcp", v.addr) } @@ -260,7 +259,7 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata) ( var c net.Conn // gun transport if v.gunTransport != nil { - c, err = gun.StreamGunWithTransport(v.gunTransport, v.gunConfig) + c, err = v.gunTransport.Dial() } else { c, err = v.dialer.DialContext(ctx, "tcp", v.addr) } @@ -431,9 +430,10 @@ func NewVless(option VlessOption) (*Vless, error) { } gunConfig := &gun.Config{ - ServiceName: option.GrpcOpts.GrpcServiceName, - UserAgent: option.GrpcOpts.GrpcUserAgent, - Host: option.ServerName, + ServiceName: option.GrpcOpts.GrpcServiceName, + UserAgent: option.GrpcOpts.GrpcUserAgent, + Host: option.ServerName, + PingInterval: option.GrpcOpts.PingInterval, } if option.ServerName == "" { gunConfig.Host = v.addr @@ -457,9 +457,7 @@ func NewVless(option VlessOption) (*Vless, error) { } } - v.gunConfig = gunConfig - - v.gunTransport = gun.NewHTTP2Client(dialFn, tlsConfig) + v.gunTransport = gun.NewTransport(dialFn, tlsConfig, gunConfig) } return v, nil diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vmess.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vmess.go index 29ed63fde2..0de06b7c17 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vmess.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vmess.go @@ -34,8 +34,7 @@ type Vmess struct { option *VmessOption // for gun mux - gunConfig *gun.Config - gunTransport *gun.TransportWrap + gunTransport *gun.Transport realityConfig *tlsC.RealityConfig echConfig *ech.Config @@ -86,6 +85,7 @@ type HTTP2Options struct { type GrpcOptions struct { GrpcServiceName string `proxy:"grpc-service-name,omitempty"` GrpcUserAgent string `proxy:"grpc-user-agent,omitempty"` + PingInterval int `proxy:"ping-interval,omitempty"` } type WSOptions struct { @@ -295,7 +295,7 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn var c net.Conn // gun transport if v.gunTransport != nil { - c, err = gun.StreamGunWithTransport(v.gunTransport, v.gunConfig) + c, err = v.gunTransport.Dial() } else { c, err = v.dialer.DialContext(ctx, "tcp", v.addr) } @@ -318,7 +318,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) ( var c net.Conn // gun transport if v.gunTransport != nil { - c, err = gun.StreamGunWithTransport(v.gunTransport, v.gunConfig) + c, err = v.gunTransport.Dial() } else { c, err = v.dialer.DialContext(ctx, "tcp", v.addr) } @@ -437,9 +437,10 @@ func NewVmess(option VmessOption) (*Vmess, error) { } gunConfig := &gun.Config{ - ServiceName: option.GrpcOpts.GrpcServiceName, - UserAgent: option.GrpcOpts.GrpcUserAgent, - Host: option.ServerName, + ServiceName: option.GrpcOpts.GrpcServiceName, + UserAgent: option.GrpcOpts.GrpcUserAgent, + Host: option.ServerName, + PingInterval: option.GrpcOpts.PingInterval, } if option.ServerName == "" { gunConfig.Host = v.addr @@ -463,9 +464,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { } } - v.gunConfig = gunConfig - - v.gunTransport = gun.NewHTTP2Client(dialFn, tlsConfig) + v.gunTransport = gun.NewTransport(dialFn, tlsConfig, gunConfig) } return v, nil diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/fallback.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/fallback.go index 0174a7b944..ef4a74c37f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/fallback.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/fallback.go @@ -19,8 +19,6 @@ type Fallback struct { testUrl string selected string expectedStatus string - Hidden bool - Icon string } func (f *Fallback) Now() string { @@ -90,8 +88,8 @@ func (f *Fallback) MarshalJSON() ([]byte, error) { "testUrl": f.testUrl, "expectedStatus": f.expectedStatus, "fixed": f.selected, - "hidden": f.Hidden, - "icon": f.Icon, + "hidden": f.Hidden(), + "icon": f.Icon(), }) } @@ -163,6 +161,8 @@ func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallba GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.Fallback, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -173,7 +173,5 @@ func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallba disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, } } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/groupbase.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/groupbase.go index 1a1b3cfd0b..7dd085c033 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/groupbase.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/groupbase.go @@ -22,6 +22,8 @@ import ( type GroupBase struct { *outbound.Base + hidden bool + icon string filterRegs []*regexp2.Regexp excludeFilterRegs []*regexp2.Regexp excludeTypeArray []string @@ -30,7 +32,7 @@ type GroupBase struct { failedTimes int failedTime time.Time failedTesting atomic.Bool - TestTimeout int + testTimeout int maxFailedTimes int // for GetProxies @@ -42,6 +44,8 @@ type GroupBase struct { type GroupBaseOption struct { Name string Type C.AdapterType + Hidden bool + Icon string Filter string ExcludeFilter string ExcludeType string @@ -74,17 +78,19 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { gb := &GroupBase{ Base: outbound.NewBase(outbound.BaseOption{Name: opt.Name, Type: opt.Type}), + hidden: opt.Hidden, + icon: opt.Icon, filterRegs: filterRegs, excludeFilterRegs: excludeFilterRegs, excludeTypeArray: excludeTypeArray, providers: opt.Providers, failedTesting: atomic.NewBool(false), - TestTimeout: opt.TestTimeout, + testTimeout: opt.TestTimeout, maxFailedTimes: opt.MaxFailedTimes, } - if gb.TestTimeout == 0 { - gb.TestTimeout = 5000 + if gb.testTimeout == 0 { + gb.testTimeout = 5000 } if gb.maxFailedTimes == 0 { gb.maxFailedTimes = 5 @@ -93,6 +99,14 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { return gb } +func (gb *GroupBase) Hidden() bool { + return gb.hidden +} + +func (gb *GroupBase) Icon() string { + return gb.icon +} + func (gb *GroupBase) Touch() { for _, pd := range gb.providers { pd.Touch() @@ -265,7 +279,7 @@ func (gb *GroupBase) onDialFailed(adapterType C.AdapterType, err error, fn func( log.Debugln("ProxyGroup: %s first failed", gb.Name()) gb.failedTime = time.Now() } else { - if time.Since(gb.failedTime) > time.Duration(gb.TestTimeout)*time.Millisecond { + if time.Since(gb.failedTime) > time.Duration(gb.testTimeout)*time.Millisecond { gb.failedTimes = 0 return } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/loadbalance.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/loadbalance.go index 19ee38c7de..8d68af3d5b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/loadbalance.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/loadbalance.go @@ -27,8 +27,6 @@ type LoadBalance struct { strategyFn strategyFn testUrl string expectedStatus string - Hidden bool - Icon string } var errStrategy = errors.New("unsupported strategy") @@ -234,8 +232,8 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) { "all": all, "testUrl": lb.testUrl, "expectedStatus": lb.expectedStatus, - "hidden": lb.Hidden, - "icon": lb.Icon, + "hidden": lb.Hidden(), + "icon": lb.Icon(), }) } @@ -267,6 +265,8 @@ func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, stra GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.LoadBalance, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -278,7 +278,5 @@ func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, stra disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, }, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/selector.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/selector.go index 7bc138fdc7..b0272f6c1a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/selector.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/selector.go @@ -14,8 +14,6 @@ type Selector struct { disableUDP bool selected string testUrl string - Hidden bool - Icon string } // DialContext implements C.ProxyAdapter @@ -68,8 +66,8 @@ func (s *Selector) MarshalJSON() ([]byte, error) { "now": s.Now(), "all": all, "testUrl": url, - "hidden": s.Hidden, - "icon": s.Icon, + "hidden": s.Hidden(), + "icon": s.Icon(), }) } @@ -121,6 +119,8 @@ func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Select GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.Selector, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -131,7 +131,5 @@ func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Select selected: "COMPATIBLE", disableUDP: option.DisableUDP, testUrl: option.URL, - Hidden: option.Hidden, - Icon: option.Icon, } } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/urltest.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/urltest.go index 49ea12aa0b..640c840c8e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/urltest.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/urltest.go @@ -29,8 +29,6 @@ type URLTest struct { expectedStatus string tolerance uint16 disableUDP bool - Hidden bool - Icon string fastNode C.Proxy fastSingle *singledo.Single[C.Proxy] } @@ -180,8 +178,8 @@ func (u *URLTest) MarshalJSON() ([]byte, error) { "testUrl": u.testUrl, "expectedStatus": u.expectedStatus, "fixed": u.selected, - "hidden": u.Hidden, - "icon": u.Icon, + "hidden": u.Hidden(), + "icon": u.Icon(), }) } @@ -215,6 +213,8 @@ func NewURLTest(option *GroupCommonOption, providers []P.ProxyProvider, options GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.URLTest, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -226,8 +226,6 @@ func NewURLTest(option *GroupCommonOption, providers []P.ProxyProvider, options disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, } for _, option := range options { diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/util.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/util.go index d35ea66f15..22d6b1890b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/util.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/util.go @@ -16,6 +16,9 @@ type ProxyGroup interface { Now() string Touch() + Hidden() bool + Icon() string + URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (mp map[string]uint16, err error) } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go index f6200fdde2..1668ccf99f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go @@ -18,8 +18,8 @@ var ( type healthCheckSchema struct { Enable bool `provider:"enable"` - URL string `provider:"url"` - Interval int `provider:"interval"` + URL string `provider:"url,omitempty"` + Interval int `provider:"interval,omitempty"` TestTimeout int `provider:"timeout,omitempty"` Lazy bool `provider:"lazy,omitempty"` ExpectedStatus string `provider:"expected-status,omitempty"` diff --git a/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml b/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml index 6368f5ede4..efaa9ede90 100644 --- a/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml +++ b/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml @@ -669,6 +669,7 @@ proxies: # socks5 grpc-opts: grpc-service-name: "example" # grpc-user-agent: "grpc-go/1.36.0" + # ping-interval: 0 # 默认关闭,单位为秒 # ip-version: ipv4 # vless @@ -759,6 +760,7 @@ proxies: # socks5 grpc-opts: grpc-service-name: "grpc" # grpc-user-agent: "grpc-go/1.36.0" + # ping-interval: 0 # 默认关闭,单位为秒 reality-opts: public-key: CrrQSjAG_YkHLwvM2M-7XkKJilgL5upBKCp0od0tLhE @@ -830,6 +832,7 @@ proxies: # socks5 grpc-opts: grpc-service-name: "example" # grpc-user-agent: "grpc-go/1.36.0" + # ping-interval: 0 # 默认关闭,单位为秒 - name: trojan-ws server: server @@ -1098,7 +1101,7 @@ proxies: # socks5 mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll)、ws(WebSocket 隧道) # tls: true # 可选:仅在 mode 为 stream/poll/auto/ws 时生效;true 强制 https/wss;false 强制 http/ws(不会根据端口自动推断) # host: "" # 可选:覆盖 Host/SNI(支持 example.com 或 example.com:443);仅在 mode 为 stream/poll/auto/ws 时生效 - # path_root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws + # path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws # multiplex: off # 可选:off(默认)、auto(复用底层 HTTP 连接,减少建链 RTT)、on(Sudoku mux 单隧道多目标;仅在 mode=stream/poll/auto 生效;ws 强制 off) # # 向后兼容旧写法: @@ -1677,7 +1680,7 @@ listeners: httpmask: disable: false # true 禁用所有 HTTP 伪装/隧道 mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll)、ws(WebSocket 隧道) - # path_root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws + # path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws # # 可选:当启用 HTTPMask 且识别到“像 HTTP 但不符合 tunnel/auth”的请求时,将原始字节透传给 fallback(常用于与其他服务共端口): # fallback: "127.0.0.1:80" diff --git a/clash-meta-android/core/src/foss/golang/clash/go.mod b/clash-meta-android/core/src/foss/golang/clash/go.mod index 7e82371848..65b09f4750 100644 --- a/clash-meta-android/core/src/foss/golang/clash/go.mod +++ b/clash-meta-android/core/src/foss/golang/clash/go.mod @@ -23,6 +23,7 @@ require ( github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/http v0.1.0 github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 + github.com/metacubex/mhurl v0.1.0 github.com/metacubex/mlkem v0.1.0 github.com/metacubex/quic-go v0.59.1-0.20260213014310-4df8f0de5b56 github.com/metacubex/randv2 v0.2.0 diff --git a/clash-meta-android/core/src/foss/golang/clash/go.sum b/clash-meta-android/core/src/foss/golang/clash/go.sum index 91b61d786e..e295e21651 100644 --- a/clash-meta-android/core/src/foss/golang/clash/go.sum +++ b/clash-meta-android/core/src/foss/golang/clash/go.sum @@ -107,6 +107,8 @@ github.com/metacubex/http v0.1.0 h1:Jcy0I9zKjYijSUaksZU34XEe2xNdoFkgUTB7z7K5q0o= github.com/metacubex/http v0.1.0/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 h1:hJwCVlE3ojViC35MGHB+FBr8TuIf3BUFn2EQ1VIamsI= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604/go.mod h1:lpmN3m269b3V5jFCWtffqBLS4U3QQoIid9ugtO+OhVc= +github.com/metacubex/mhurl v0.1.0 h1:ZdW4Zxe3j3uJ89gNytOazHu6kbHn5owutN/VfXOI8GE= +github.com/metacubex/mhurl v0.1.0/go.mod h1:2qpQImCbXoUs6GwJrjuEXKelPyoimsIXr07eNKZdS00= github.com/metacubex/mlkem v0.1.0 h1:wFClitonSFcmipzzQvax75beLQU+D7JuC+VK1RzSL8I= github.com/metacubex/mlkem v0.1.0/go.mod h1:amhaXZVeYNShuy9BILcR7P0gbeo/QLZsnqCdL8U2PDQ= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku.go index 02ef5a34a4..5c7099ae63 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku.go @@ -35,7 +35,7 @@ type SudokuOption struct { type SudokuHTTPMaskOptions struct { Disable bool `inbound:"disable,omitempty"` Mode string `inbound:"mode,omitempty"` - PathRoot string `inbound:"path_root,omitempty"` + PathRoot string `inbound:"path-root,omitempty"` } func (o SudokuOption) Equal(config C.InboundConfig) bool { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go b/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go index bc67a476e2..200d095a31 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go @@ -148,6 +148,7 @@ func handleConn(conn net.Conn, tunnel C.Tunnel, store auth.AuthStore, additions bufConn := N.NewBufferedConn(conn) head, err := bufConn.Peek(1) if err != nil { + conn.Close() return } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/utils.go b/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/utils.go index 5d6a2977ee..6bdddb232b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/utils.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/utils.go @@ -4,9 +4,10 @@ import ( "bytes" "errors" "net" - "net/url" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/mhurl" ) type packet struct { @@ -48,7 +49,7 @@ func (c *packet) InAddr() net.Addr { } func ParseSSURL(s string) (addr, cipher, password string, err error) { - u, err := url.Parse(s) + u, err := mhurl.Parse(s) // we need multiple hosts url supports if err != nil { return } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/utils_test.go b/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/utils_test.go new file mode 100644 index 0000000000..b2b7739f00 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/shadowsocks/utils_test.go @@ -0,0 +1,22 @@ +package shadowsocks + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseSSURL(t *testing.T) { + for _, test := range []struct{ method, passwd, hosts string }{ + {method: "aes-256-gcm", passwd: "password", hosts: ":1000,:2000,:3000"}, + {method: "aes-256-gcm", passwd: "password", hosts: "127.0.0.1:1000,127.0.0.1:2000,127.0.0.1:3000"}, + {method: "aes-256-gcm", passwd: "password", hosts: "[::1]:1000,[::1]:2000,[::1]:3000"}, + } { + addr, cipher, password, err := ParseSSURL(fmt.Sprintf("ss://%s:%s@%s", test.method, test.passwd, test.hosts)) + require.NoError(t, err) + require.Equal(t, test.hosts, addr) + require.Equal(t, test.method, cipher) + require.Equal(t, test.passwd, password) + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go index 7dd0a163ba..5604700f63 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go @@ -4,7 +4,6 @@ import ( "context" "errors" "net" - "net/url" "strings" "github.com/metacubex/mihomo/adapter/inbound" @@ -19,6 +18,7 @@ import ( mihomoVMess "github.com/metacubex/mihomo/transport/vmess" "github.com/metacubex/http" + "github.com/metacubex/mhurl" vmess "github.com/metacubex/sing-vmess" "github.com/metacubex/sing/common" "github.com/metacubex/sing/common/metadata" @@ -230,7 +230,7 @@ func HandleVmess(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) } func ParseVmessURL(s string) (addr, username, password string, err error) { - u, err := url.Parse(s) + u, err := mhurl.Parse(s) // we need multiple hosts url supports if err != nil { return } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server_test.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server_test.go new file mode 100644 index 0000000000..36b2ab14ba --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server_test.go @@ -0,0 +1,22 @@ +package sing_vmess + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseVmessURL(t *testing.T) { + for _, test := range []struct{ username, passwd, hosts string }{ + {username: "username", passwd: "password", hosts: ":1000,:2000,:3000"}, + {username: "username", passwd: "password", hosts: "127.0.0.1:1000,127.0.0.1:2000,127.0.0.1:3000"}, + {username: "username", passwd: "password", hosts: "[::1]:1000,[::1]:2000,[::1]:3000"}, + } { + addr, username, password, err := ParseVmessURL(fmt.Sprintf("vmess://%s:%s@%s", test.username, test.passwd, test.hosts)) + require.NoError(t, err) + require.Equal(t, test.hosts, addr) + require.Equal(t, test.username, username) + require.Equal(t, test.passwd, password) + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go index 27c0cbbbe2..0a760affe2 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go @@ -33,8 +33,8 @@ var ( ) var defaultHeader = http.Header{ - "content-type": []string{"application/grpc"}, - "user-agent": []string{"grpc-go/1.36.0"}, + "Content-Type": []string{"application/grpc"}, + "User-Agent": []string{"grpc-go/1.36.0"}, } type DialFn = func(ctx context.Context, network, addr string) (net.Conn, error) @@ -59,9 +59,10 @@ type Conn struct { } type Config struct { - ServiceName string - UserAgent string - Host string + ServiceName string + UserAgent string + Host string + PingInterval int } func (g *Conn) initReader() { @@ -246,7 +247,7 @@ func (g *Conn) SetDeadline(t time.Time) error { return nil } -func NewHTTP2Client(dialFn DialFn, tlsConfig *vmess.TLSConfig) *TransportWrap { +func NewTransport(dialFn DialFn, tlsConfig *vmess.TLSConfig, gunCfg *Config) *Transport { dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout) defer cancel() @@ -288,14 +289,16 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *vmess.TLSConfig) *TransportWrap { DialTLSContext: dialFunc, AllowHTTP: false, DisableCompression: true, + ReadIdleTimeout: time.Duration(gunCfg.PingInterval) * time.Second, // If zero, no health check is performed PingTimeout: 0, } ctx, cancel := context.WithCancel(context.Background()) - wrap := &TransportWrap{ - Http2Transport: transport, - ctx: ctx, - cancel: cancel, + wrap := &Transport{ + transport: transport, + cfg: gunCfg, + ctx: ctx, + cancel: cancel, } return wrap } @@ -307,18 +310,18 @@ func ServiceNameToPath(serviceName string) string { return "/" + serviceName + "/Tun" } -func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, error) { +func (t *Transport) Dial() (net.Conn, error) { serviceName := "GunService" - if cfg.ServiceName != "" { - serviceName = cfg.ServiceName + if t.cfg.ServiceName != "" { + serviceName = t.cfg.ServiceName } path := ServiceNameToPath(serviceName) reader, writer := io.Pipe() header := defaultHeader.Clone() - if cfg.UserAgent != "" { - header.Set("User-Agent", cfg.UserAgent) + if t.cfg.UserAgent != "" { + header.Set("User-Agent", t.cfg.UserAgent) } request := &http.Request{ @@ -326,17 +329,17 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er Body: reader, URL: &url.URL{ Scheme: "https", - Host: cfg.Host, + Host: t.cfg.Host, Path: path, // for unescape path - Opaque: "//" + cfg.Host + path, + Opaque: "//" + t.cfg.Host + path, }, Proto: "HTTP/2", ProtoMajor: 2, ProtoMinor: 0, Header: header, } - request = request.WithContext(transport.ctx) + request = request.WithContext(t.ctx) conn := &Conn{ initFn: func() (io.ReadCloser, NetAddr, error) { @@ -348,7 +351,7 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er }, } request = request.WithContext(httptrace.WithClientTrace(request.Context(), trace)) - response, err := transport.RoundTrip(request) + response, err := t.transport.RoundTrip(request) if err != nil { return nil, nAddr, err } @@ -361,13 +364,13 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er return conn, nil } -func StreamGunWithConn(conn net.Conn, tlsConfig *vmess.TLSConfig, cfg *Config) (net.Conn, error) { +func StreamGunWithConn(conn net.Conn, tlsConfig *vmess.TLSConfig, gunCfg *Config) (net.Conn, error) { dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) { return conn, nil } - transport := NewHTTP2Client(dialFn, tlsConfig) - c, err := StreamGunWithTransport(transport, cfg) + transport := NewTransport(dialFn, tlsConfig, gunCfg) + c, err := transport.Dial() if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go index 4b9da971f3..80c0af1537 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go @@ -10,17 +10,18 @@ import ( "github.com/metacubex/http" ) -type TransportWrap struct { - *http.Http2Transport +type Transport struct { + transport *http.Http2Transport + cfg *Config ctx context.Context cancel context.CancelFunc closeOnce sync.Once } -func (tw *TransportWrap) Close() error { - tw.closeOnce.Do(func() { - tw.cancel() - CloseTransport(tw.Http2Transport) +func (t *Transport) Close() error { + t.closeOnce.Do(func() { + t.cancel() + CloseHttp2Transport(t.transport) }) return nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport_close.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport_close.go index 44fefd7c12..add4906e46 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport_close.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport_close.go @@ -44,7 +44,7 @@ func closeClientConn(cc *http.Http2ClientConn) { // like forceCloseConn() in htt _ = cc.Close() } -func CloseTransport(tr *http.Http2Transport) { +func CloseHttp2Transport(tr *http.Http2Transport) { connPool := transportConnPool(tr) p := (*clientConnPool)((*efaceWords)(unsafe.Pointer(&connPool)).data) p.mu.Lock() diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/crypto/record_conn.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/crypto/record_conn.go index 7a80c7f5f3..7c0357151b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/crypto/record_conn.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/crypto/record_conn.go @@ -5,6 +5,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/hmac" + "crypto/rand" "crypto/sha256" "encoding/binary" "errors" @@ -12,6 +13,7 @@ import ( "io" "net" "sync" + "sync/atomic" "golang.org/x/crypto/chacha20poly1305" ) @@ -55,13 +57,15 @@ type RecordConn struct { recvAEADEpoch uint32 // Send direction state. - sendEpoch uint32 - sendSeq uint64 - sendBytes int64 + sendEpoch uint32 + sendSeq uint64 + sendBytes int64 + sendEpochUpdates uint32 // Receive direction state. - recvEpoch uint32 - recvSeq uint64 + recvEpoch uint32 + recvSeq uint64 + recvInitialized bool readBuf bytes.Buffer @@ -105,6 +109,9 @@ func NewRecordConn(conn net.Conn, method string, baseSend, baseRecv []byte) (*Re } rc := &RecordConn{Conn: conn, method: method} rc.keys = recordKeys{baseSend: cloneBytes(baseSend), baseRecv: cloneBytes(baseRecv)} + if err := rc.resetTrafficState(); err != nil { + return nil, err + } return rc, nil } @@ -127,11 +134,9 @@ func (c *RecordConn) Rekey(baseSend, baseRecv []byte) error { defer c.writeMu.Unlock() c.keys = recordKeys{baseSend: cloneBytes(baseSend), baseRecv: cloneBytes(baseRecv)} - c.sendEpoch = 0 - c.sendSeq = 0 - c.sendBytes = 0 - c.recvEpoch = 0 - c.recvSeq = 0 + if err := c.resetTrafficState(); err != nil { + return err + } c.readBuf.Reset() c.sendAEAD = nil @@ -141,6 +146,21 @@ func (c *RecordConn) Rekey(baseSend, baseRecv []byte) error { return nil } +func (c *RecordConn) resetTrafficState() error { + sendEpoch, sendSeq, err := randomRecordCounters() + if err != nil { + return fmt.Errorf("initialize record counters: %w", err) + } + c.sendEpoch = sendEpoch + c.sendSeq = sendSeq + c.sendBytes = 0 + c.sendEpochUpdates = 0 + c.recvEpoch = 0 + c.recvSeq = 0 + c.recvInitialized = false + return nil +} + func normalizeAEADMethod(method string) string { switch method { case "", "chacha20-poly1305": @@ -166,6 +186,44 @@ func cloneBytes(b []byte) []byte { return append([]byte(nil), b...) } +func randomRecordCounters() (uint32, uint64, error) { + epoch, err := randomNonZeroUint32() + if err != nil { + return 0, 0, err + } + seq, err := randomNonZeroUint64() + if err != nil { + return 0, 0, err + } + return epoch, seq, nil +} + +func randomNonZeroUint32() (uint32, error) { + var b [4]byte + for { + if _, err := io.ReadFull(rand.Reader, b[:]); err != nil { + return 0, err + } + v := binary.BigEndian.Uint32(b[:]) + if v != 0 && v != ^uint32(0) { + return v, nil + } + } +} + +func randomNonZeroUint64() (uint64, error) { + var b [8]byte + for { + if _, err := io.ReadFull(rand.Reader, b[:]); err != nil { + return 0, err + } + v := binary.BigEndian.Uint64(b[:]) + if v != 0 && v != ^uint64(0) { + return v, nil + } + } +} + func (c *RecordConn) newAEADFor(base []byte, epoch uint32) (cipher.AEAD, error) { if c.method == "none" { return nil, nil @@ -209,17 +267,49 @@ func deriveEpochKey(base []byte, epoch uint32, method string) []byte { return mac.Sum(nil) } -func (c *RecordConn) maybeBumpSendEpochLocked(addedPlain int) { - if KeyUpdateAfterBytes <= 0 || c.method == "none" { - return +func (c *RecordConn) maybeBumpSendEpochLocked(addedPlain int) error { + ku := atomic.LoadInt64(&KeyUpdateAfterBytes) + if ku <= 0 || c.method == "none" { + return nil } c.sendBytes += int64(addedPlain) - threshold := KeyUpdateAfterBytes * int64(c.sendEpoch+1) + threshold := ku * int64(c.sendEpochUpdates+1) if c.sendBytes < threshold { - return + return nil } c.sendEpoch++ - c.sendSeq = 0 + c.sendEpochUpdates++ + nextSeq, err := randomNonZeroUint64() + if err != nil { + return fmt.Errorf("rotate record seq: %w", err) + } + c.sendSeq = nextSeq + return nil +} + +func (c *RecordConn) validateRecvPosition(epoch uint32, seq uint64) error { + if !c.recvInitialized { + return nil + } + if epoch < c.recvEpoch { + return fmt.Errorf("replayed epoch: got %d want >=%d", epoch, c.recvEpoch) + } + if epoch == c.recvEpoch && seq != c.recvSeq { + return fmt.Errorf("out of order: epoch=%d got=%d want=%d", epoch, seq, c.recvSeq) + } + if epoch > c.recvEpoch { + const maxJump = 8 + if epoch-c.recvEpoch > maxJump { + return fmt.Errorf("epoch jump too large: got=%d want<=%d", epoch-c.recvEpoch, maxJump) + } + } + return nil +} + +func (c *RecordConn) markRecvPosition(epoch uint32, seq uint64) { + c.recvEpoch = epoch + c.recvSeq = seq + 1 + c.recvInitialized = true } func (c *RecordConn) Write(p []byte) (int, error) { @@ -282,7 +372,9 @@ func (c *RecordConn) Write(p []byte) (int, error) { } total += n - c.maybeBumpSendEpochLocked(n) + if err := c.maybeBumpSendEpochLocked(n); err != nil { + return total, err + } } return total, nil } @@ -324,31 +416,17 @@ func (c *RecordConn) Read(p []byte) (int, error) { epoch := binary.BigEndian.Uint32(header[:4]) seq := binary.BigEndian.Uint64(header[4:]) - if epoch < c.recvEpoch { - return 0, fmt.Errorf("replayed epoch: got %d want >=%d", epoch, c.recvEpoch) - } - if epoch == c.recvEpoch && seq != c.recvSeq { - return 0, fmt.Errorf("out of order: epoch=%d got=%d want=%d", epoch, seq, c.recvSeq) - } - if epoch > c.recvEpoch { - const maxJump = 8 - if epoch-c.recvEpoch > maxJump { - return 0, fmt.Errorf("epoch jump too large: got=%d want<=%d", epoch-c.recvEpoch, maxJump) - } - c.recvEpoch = epoch - c.recvSeq = 0 - if seq != 0 { - return 0, fmt.Errorf("out of order: epoch advanced to %d but seq=%d", epoch, seq) - } + if err := c.validateRecvPosition(epoch, seq); err != nil { + return 0, err } - if c.recvAEAD == nil || c.recvAEADEpoch != c.recvEpoch { - a, err := c.newAEADFor(c.keys.baseRecv, c.recvEpoch) + if c.recvAEAD == nil || c.recvAEADEpoch != epoch { + a, err := c.newAEADFor(c.keys.baseRecv, epoch) if err != nil { return 0, err } c.recvAEAD = a - c.recvAEADEpoch = c.recvEpoch + c.recvAEADEpoch = epoch } aead := c.recvAEAD @@ -356,7 +434,7 @@ func (c *RecordConn) Read(p []byte) (int, error) { if err != nil { return 0, fmt.Errorf("decryption failed: epoch=%d seq=%d: %w", epoch, seq, err) } - c.recvSeq++ + c.markRecvPosition(epoch, seq) c.readBuf.Write(plaintext) return c.readBuf.Read(p) diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/crypto/record_conn_test.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/crypto/record_conn_test.go new file mode 100644 index 0000000000..4ea0b9b88e --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/crypto/record_conn_test.go @@ -0,0 +1,86 @@ +package crypto + +import ( + "bytes" + "crypto/sha256" + "encoding/binary" + "io" + "net" + "testing" + "time" +) + +type captureConn struct { + bytes.Buffer +} + +func (c *captureConn) Read(_ []byte) (int, error) { return 0, io.EOF } +func (c *captureConn) Write(p []byte) (int, error) { return c.Buffer.Write(p) } +func (c *captureConn) Close() error { return nil } +func (c *captureConn) LocalAddr() net.Addr { return nil } +func (c *captureConn) RemoteAddr() net.Addr { return nil } +func (c *captureConn) SetDeadline(time.Time) error { return nil } +func (c *captureConn) SetReadDeadline(time.Time) error { return nil } +func (c *captureConn) SetWriteDeadline(time.Time) error { return nil } + +type replayConn struct { + reader *bytes.Reader +} + +func (c *replayConn) Read(p []byte) (int, error) { return c.reader.Read(p) } +func (c *replayConn) Write(p []byte) (int, error) { return len(p), nil } +func (c *replayConn) Close() error { return nil } +func (c *replayConn) LocalAddr() net.Addr { return nil } +func (c *replayConn) RemoteAddr() net.Addr { return nil } +func (c *replayConn) SetDeadline(time.Time) error { return nil } +func (c *replayConn) SetReadDeadline(time.Time) error { return nil } +func (c *replayConn) SetWriteDeadline(time.Time) error { return nil } + +func TestRecordConn_FirstFrameUsesRandomizedCounters(t *testing.T) { + pskSend := sha256.Sum256([]byte("record-send")) + pskRecv := sha256.Sum256([]byte("record-recv")) + + raw := &captureConn{} + writer, err := NewRecordConn(raw, "chacha20-poly1305", pskSend[:], pskRecv[:]) + if err != nil { + t.Fatalf("new writer: %v", err) + } + + if writer.sendEpoch == 0 || writer.sendSeq == 0 { + t.Fatalf("expected non-zero randomized counters, got epoch=%d seq=%d", writer.sendEpoch, writer.sendSeq) + } + + want := []byte("record prefix camouflage") + if _, err := writer.Write(want); err != nil { + t.Fatalf("write: %v", err) + } + + wire := raw.Bytes() + if len(wire) < 2+recordHeaderSize { + t.Fatalf("short frame: %d", len(wire)) + } + + bodyLen := int(binary.BigEndian.Uint16(wire[:2])) + if bodyLen != len(wire)-2 { + t.Fatalf("body len mismatch: got %d want %d", bodyLen, len(wire)-2) + } + + epoch := binary.BigEndian.Uint32(wire[2:6]) + seq := binary.BigEndian.Uint64(wire[6:14]) + if epoch == 0 || seq == 0 { + t.Fatalf("wire header still starts from zero: epoch=%d seq=%d", epoch, seq) + } + + reader, err := NewRecordConn(&replayConn{reader: bytes.NewReader(wire)}, "chacha20-poly1305", pskRecv[:], pskSend[:]) + if err != nil { + t.Fatalf("new reader: %v", err) + } + + got := make([]byte, len(want)) + if _, err := io.ReadFull(reader, got); err != nil { + t.Fatalf("read: %v", err) + } + if !bytes.Equal(got, want) { + t.Fatalf("plaintext mismatch: got %q want %q", got, want) + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/early_handshake.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/early_handshake.go new file mode 100644 index 0000000000..803a5293a8 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/early_handshake.go @@ -0,0 +1,345 @@ +package sudoku + +import ( + "bytes" + "crypto/ecdh" + "crypto/rand" + "encoding/hex" + "fmt" + "net" + "time" + + "github.com/metacubex/mihomo/transport/sudoku/crypto" + httpmaskobfs "github.com/metacubex/mihomo/transport/sudoku/obfs/httpmask" + sudokuobfs "github.com/metacubex/mihomo/transport/sudoku/obfs/sudoku" +) + +const earlyKIPHandshakeTTL = 60 * time.Second + +type EarlyCodecConfig struct { + PSK string + AEAD string + EnablePureDownlink bool + PaddingMin int + PaddingMax int +} + +type EarlyClientState struct { + RequestPayload []byte + + cfg EarlyCodecConfig + table *sudokuobfs.Table + nonce [kipHelloNonceSize]byte + ephemeral *ecdh.PrivateKey + sessionC2S []byte + sessionS2C []byte + responseSet bool +} + +type EarlyServerState struct { + ResponsePayload []byte + UserHash string + + cfg EarlyCodecConfig + table *sudokuobfs.Table + sessionC2S []byte + sessionS2C []byte +} + +type ReplayAllowFunc func(userHash string, nonce [kipHelloNonceSize]byte, now time.Time) bool + +type earlyMemoryConn struct { + reader *bytes.Reader + write bytes.Buffer +} + +func newEarlyMemoryConn(readBuf []byte) *earlyMemoryConn { + return &earlyMemoryConn{reader: bytes.NewReader(readBuf)} +} + +func (c *earlyMemoryConn) Read(p []byte) (int, error) { + if c == nil || c.reader == nil { + return 0, net.ErrClosed + } + return c.reader.Read(p) +} + +func (c *earlyMemoryConn) Write(p []byte) (int, error) { + if c == nil { + return 0, net.ErrClosed + } + return c.write.Write(p) +} + +func (c *earlyMemoryConn) Close() error { return nil } +func (c *earlyMemoryConn) LocalAddr() net.Addr { return earlyDummyAddr("local") } +func (c *earlyMemoryConn) RemoteAddr() net.Addr { return earlyDummyAddr("remote") } +func (c *earlyMemoryConn) SetDeadline(time.Time) error { return nil } +func (c *earlyMemoryConn) SetReadDeadline(time.Time) error { return nil } +func (c *earlyMemoryConn) SetWriteDeadline(time.Time) error { return nil } +func (c *earlyMemoryConn) Written() []byte { return append([]byte(nil), c.write.Bytes()...) } + +type earlyDummyAddr string + +func (a earlyDummyAddr) Network() string { return string(a) } +func (a earlyDummyAddr) String() string { return string(a) } + +func buildEarlyClientObfsConn(raw net.Conn, cfg EarlyCodecConfig, table *sudokuobfs.Table) net.Conn { + base := sudokuobfs.NewConn(raw, table, cfg.PaddingMin, cfg.PaddingMax, false) + if cfg.EnablePureDownlink { + return base + } + packed := sudokuobfs.NewPackedConn(raw, table, cfg.PaddingMin, cfg.PaddingMax) + return newDirectionalConn(raw, packed, base) +} + +func buildEarlyServerObfsConn(raw net.Conn, cfg EarlyCodecConfig, table *sudokuobfs.Table) net.Conn { + uplink := sudokuobfs.NewConn(raw, table, cfg.PaddingMin, cfg.PaddingMax, false) + if cfg.EnablePureDownlink { + return uplink + } + packed := sudokuobfs.NewPackedConn(raw, table, cfg.PaddingMin, cfg.PaddingMax) + return newDirectionalConn(raw, uplink, packed, packed.Flush) +} + +func NewEarlyClientState(cfg EarlyCodecConfig, table *sudokuobfs.Table, userHash [kipHelloUserHashSize]byte, feats uint32) (*EarlyClientState, error) { + if table == nil { + return nil, fmt.Errorf("nil table") + } + + curve := ecdh.X25519() + ephemeral, err := curve.GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("ecdh generate failed: %w", err) + } + + var nonce [kipHelloNonceSize]byte + if _, err := rand.Read(nonce[:]); err != nil { + return nil, fmt.Errorf("nonce generate failed: %w", err) + } + + var clientPub [kipHelloPubSize]byte + copy(clientPub[:], ephemeral.PublicKey().Bytes()) + hello := &KIPClientHello{ + Timestamp: time.Now(), + UserHash: userHash, + Nonce: nonce, + ClientPub: clientPub, + Features: feats, + } + + mem := newEarlyMemoryConn(nil) + obfsConn := buildEarlyClientObfsConn(mem, cfg, table) + pskC2S, pskS2C := derivePSKDirectionalBases(cfg.PSK) + rc, err := crypto.NewRecordConn(obfsConn, cfg.AEAD, pskC2S, pskS2C) + if err != nil { + return nil, fmt.Errorf("client early crypto setup failed: %w", err) + } + if err := WriteKIPMessage(rc, KIPTypeClientHello, hello.EncodePayload()); err != nil { + return nil, fmt.Errorf("write early client hello failed: %w", err) + } + + return &EarlyClientState{ + RequestPayload: mem.Written(), + cfg: cfg, + table: table, + nonce: nonce, + ephemeral: ephemeral, + }, nil +} + +func (s *EarlyClientState) ProcessResponse(payload []byte) error { + if s == nil { + return fmt.Errorf("nil client state") + } + + mem := newEarlyMemoryConn(payload) + obfsConn := buildEarlyClientObfsConn(mem, s.cfg, s.table) + pskC2S, pskS2C := derivePSKDirectionalBases(s.cfg.PSK) + rc, err := crypto.NewRecordConn(obfsConn, s.cfg.AEAD, pskC2S, pskS2C) + if err != nil { + return fmt.Errorf("client early crypto setup failed: %w", err) + } + + msg, err := ReadKIPMessage(rc) + if err != nil { + return fmt.Errorf("read early server hello failed: %w", err) + } + if msg.Type != KIPTypeServerHello { + return fmt.Errorf("unexpected early handshake message: %d", msg.Type) + } + sh, err := DecodeKIPServerHelloPayload(msg.Payload) + if err != nil { + return fmt.Errorf("decode early server hello failed: %w", err) + } + if sh.Nonce != s.nonce { + return fmt.Errorf("early handshake nonce mismatch") + } + + shared, err := x25519SharedSecret(s.ephemeral, sh.ServerPub[:]) + if err != nil { + return fmt.Errorf("ecdh failed: %w", err) + } + s.sessionC2S, s.sessionS2C, err = deriveSessionDirectionalBases(s.cfg.PSK, shared, s.nonce) + if err != nil { + return fmt.Errorf("derive session keys failed: %w", err) + } + s.responseSet = true + return nil +} + +func (s *EarlyClientState) WrapConn(raw net.Conn) (net.Conn, error) { + if s == nil { + return nil, fmt.Errorf("nil client state") + } + if !s.responseSet { + return nil, fmt.Errorf("early handshake not completed") + } + + obfsConn := buildEarlyClientObfsConn(raw, s.cfg, s.table) + rc, err := crypto.NewRecordConn(obfsConn, s.cfg.AEAD, s.sessionC2S, s.sessionS2C) + if err != nil { + return nil, fmt.Errorf("setup client session crypto failed: %w", err) + } + return rc, nil +} + +func (s *EarlyClientState) Ready() bool { + return s != nil && s.responseSet +} + +func NewHTTPMaskClientEarlyHandshake(cfg EarlyCodecConfig, table *sudokuobfs.Table, userHash [kipHelloUserHashSize]byte, feats uint32) (*httpmaskobfs.ClientEarlyHandshake, error) { + state, err := NewEarlyClientState(cfg, table, userHash, feats) + if err != nil { + return nil, err + } + return &httpmaskobfs.ClientEarlyHandshake{ + RequestPayload: state.RequestPayload, + HandleResponse: state.ProcessResponse, + Ready: state.Ready, + WrapConn: state.WrapConn, + }, nil +} + +func ProcessEarlyClientPayload(cfg EarlyCodecConfig, tables []*sudokuobfs.Table, payload []byte, allowReplay ReplayAllowFunc) (*EarlyServerState, error) { + if len(payload) == 0 { + return nil, fmt.Errorf("empty early payload") + } + if len(tables) == 0 { + return nil, fmt.Errorf("no tables configured") + } + + var firstErr error + for _, table := range tables { + state, err := processEarlyClientPayloadForTable(cfg, table, payload, allowReplay) + if err == nil { + return state, nil + } + if firstErr == nil { + firstErr = err + } + } + if firstErr == nil { + firstErr = fmt.Errorf("early handshake probe failed") + } + return nil, firstErr +} + +func processEarlyClientPayloadForTable(cfg EarlyCodecConfig, table *sudokuobfs.Table, payload []byte, allowReplay ReplayAllowFunc) (*EarlyServerState, error) { + mem := newEarlyMemoryConn(payload) + obfsConn := buildEarlyServerObfsConn(mem, cfg, table) + pskC2S, pskS2C := derivePSKDirectionalBases(cfg.PSK) + rc, err := crypto.NewRecordConn(obfsConn, cfg.AEAD, pskS2C, pskC2S) + if err != nil { + return nil, err + } + + msg, err := ReadKIPMessage(rc) + if err != nil { + return nil, err + } + if msg.Type != KIPTypeClientHello { + return nil, fmt.Errorf("unexpected handshake message: %d", msg.Type) + } + ch, err := DecodeKIPClientHelloPayload(msg.Payload) + if err != nil { + return nil, err + } + if absInt64(time.Now().Unix()-ch.Timestamp.Unix()) > int64(earlyKIPHandshakeTTL.Seconds()) { + return nil, fmt.Errorf("time skew/replay") + } + + userHash := hex.EncodeToString(ch.UserHash[:]) + if allowReplay != nil && !allowReplay(userHash, ch.Nonce, time.Now()) { + return nil, fmt.Errorf("replay detected") + } + + curve := ecdh.X25519() + serverEphemeral, err := curve.GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("ecdh generate failed: %w", err) + } + shared, err := x25519SharedSecret(serverEphemeral, ch.ClientPub[:]) + if err != nil { + return nil, fmt.Errorf("ecdh failed: %w", err) + } + sessionC2S, sessionS2C, err := deriveSessionDirectionalBases(cfg.PSK, shared, ch.Nonce) + if err != nil { + return nil, fmt.Errorf("derive session keys failed: %w", err) + } + + var serverPub [kipHelloPubSize]byte + copy(serverPub[:], serverEphemeral.PublicKey().Bytes()) + serverHello := &KIPServerHello{ + Nonce: ch.Nonce, + ServerPub: serverPub, + SelectedFeats: ch.Features & KIPFeatAll, + } + + respMem := newEarlyMemoryConn(nil) + respObfs := buildEarlyServerObfsConn(respMem, cfg, table) + respConn, err := crypto.NewRecordConn(respObfs, cfg.AEAD, pskS2C, pskC2S) + if err != nil { + return nil, fmt.Errorf("server early crypto setup failed: %w", err) + } + if err := WriteKIPMessage(respConn, KIPTypeServerHello, serverHello.EncodePayload()); err != nil { + return nil, fmt.Errorf("write early server hello failed: %w", err) + } + + return &EarlyServerState{ + ResponsePayload: respMem.Written(), + UserHash: userHash, + cfg: cfg, + table: table, + sessionC2S: sessionC2S, + sessionS2C: sessionS2C, + }, nil +} + +func (s *EarlyServerState) WrapConn(raw net.Conn) (net.Conn, error) { + if s == nil { + return nil, fmt.Errorf("nil server state") + } + obfsConn := buildEarlyServerObfsConn(raw, s.cfg, s.table) + rc, err := crypto.NewRecordConn(obfsConn, s.cfg.AEAD, s.sessionS2C, s.sessionC2S) + if err != nil { + return nil, fmt.Errorf("setup server session crypto failed: %w", err) + } + return rc, nil +} + +func NewHTTPMaskServerEarlyHandshake(cfg EarlyCodecConfig, tables []*sudokuobfs.Table, allowReplay ReplayAllowFunc) *httpmaskobfs.TunnelServerEarlyHandshake { + return &httpmaskobfs.TunnelServerEarlyHandshake{ + Prepare: func(payload []byte) (*httpmaskobfs.PreparedServerEarlyHandshake, error) { + state, err := ProcessEarlyClientPayload(cfg, tables, payload, allowReplay) + if err != nil { + return nil, err + } + return &httpmaskobfs.PreparedServerEarlyHandshake{ + ResponsePayload: state.ResponsePayload, + WrapConn: state.WrapConn, + UserHash: state.UserHash, + }, nil + }, + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake.go index 971d47fd8b..bac688e8f5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake.go @@ -337,6 +337,9 @@ func ServerHandshake(rawConn net.Conn, cfg *ProtocolConfig) (net.Conn, *Handshak if err := cfg.Validate(); err != nil { return nil, nil, fmt.Errorf("invalid config: %w", err) } + if userHash, ok := httpmask.EarlyHandshakeUserHash(rawConn); ok { + return rawConn, &HandshakeMeta{UserHash: userHash}, nil + } handshakeTimeout := time.Duration(cfg.HandshakeTimeoutSeconds) * time.Second if handshakeTimeout <= 0 { diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_tunnel.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_tunnel.go index 1ff2bb3883..c066eb1c65 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_tunnel.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_tunnel.go @@ -14,6 +14,30 @@ type HTTPMaskTunnelServer struct { ts *httpmask.TunnelServer } +func newHTTPMaskEarlyCodecConfig(cfg *ProtocolConfig, psk string) EarlyCodecConfig { + return EarlyCodecConfig{ + PSK: psk, + AEAD: cfg.AEADMethod, + EnablePureDownlink: cfg.EnablePureDownlink, + PaddingMin: cfg.PaddingMin, + PaddingMax: cfg.PaddingMax, + } +} + +func newClientHTTPMaskEarlyHandshake(cfg *ProtocolConfig) (*httpmask.ClientEarlyHandshake, error) { + table, err := pickClientTable(cfg) + if err != nil { + return nil, err + } + + return NewHTTPMaskClientEarlyHandshake( + newHTTPMaskEarlyCodecConfig(cfg, ClientAEADSeed(cfg.Key)), + table, + kipUserHashFromKey(cfg.Key), + KIPFeatAll, + ) +} + func NewHTTPMaskTunnelServer(cfg *ProtocolConfig) *HTTPMaskTunnelServer { return newHTTPMaskTunnelServer(cfg, false) } @@ -35,6 +59,11 @@ func newHTTPMaskTunnelServer(cfg *ProtocolConfig, passThroughOnReject bool) *HTT Mode: cfg.HTTPMaskMode, PathRoot: cfg.HTTPMaskPathRoot, AuthKey: ServerAEADSeed(cfg.Key), + EarlyHandshake: NewHTTPMaskServerEarlyHandshake( + newHTTPMaskEarlyCodecConfig(cfg, ServerAEADSeed(cfg.Key)), + cfg.tableCandidates(), + globalHandshakeReplay.allow, + ), // When upstream fallback is enabled, preserve rejected HTTP requests for the caller. PassThroughOnReject: passThroughOnReject, }) @@ -101,14 +130,25 @@ func DialHTTPMaskTunnel(ctx context.Context, serverAddress string, cfg *Protocol default: return nil, fmt.Errorf("http-mask-mode=%q does not use http tunnel", cfg.HTTPMaskMode) } + var ( + earlyHandshake *httpmask.ClientEarlyHandshake + err error + ) + if upgrade != nil { + earlyHandshake, err = newClientHTTPMaskEarlyHandshake(cfg) + if err != nil { + return nil, err + } + } return httpmask.DialTunnel(ctx, serverAddress, httpmask.TunnelDialOptions{ - Mode: cfg.HTTPMaskMode, - TLSEnabled: cfg.HTTPMaskTLSEnabled, - HostOverride: cfg.HTTPMaskHost, - PathRoot: cfg.HTTPMaskPathRoot, - AuthKey: ClientAEADSeed(cfg.Key), - Upgrade: upgrade, - Multiplex: cfg.HTTPMaskMultiplex, - DialContext: dial, + Mode: cfg.HTTPMaskMode, + TLSEnabled: cfg.HTTPMaskTLSEnabled, + HostOverride: cfg.HTTPMaskHost, + PathRoot: cfg.HTTPMaskPathRoot, + AuthKey: ClientAEADSeed(cfg.Key), + EarlyHandshake: earlyHandshake, + Upgrade: upgrade, + Multiplex: cfg.HTTPMaskMultiplex, + DialContext: dial, }) } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_tunnel_test.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_tunnel_test.go index 8894882ef9..01eb3a5078 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_tunnel_test.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_tunnel_test.go @@ -389,6 +389,68 @@ func TestHTTPMaskTunnel_WS_TCPRoundTrip(t *testing.T) { } } +func TestHTTPMaskTunnel_EarlyHandshake_TCPRoundTrip(t *testing.T) { + modes := []string{"stream", "poll", "ws"} + for _, mode := range modes { + t.Run(mode, func(t *testing.T) { + key := "tunnel-early-" + mode + target := "1.1.1.1:80" + + serverCfg := newTunnelTestTable(t, key) + serverCfg.HTTPMaskMode = mode + + addr, stop, errCh := startTunnelServer(t, serverCfg, func(s *ServerSession) error { + if s.Type != SessionTypeTCP { + return fmt.Errorf("unexpected session type: %v", s.Type) + } + if s.Target != target { + return fmt.Errorf("target mismatch: %s", s.Target) + } + _, _ = s.Conn.Write([]byte("ok")) + return nil + }) + defer stop() + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + clientCfg := *serverCfg + clientCfg.ServerAddress = addr + + handshakeCfg := clientCfg + handshakeCfg.DisableHTTPMask = true + tunnelConn, err := DialHTTPMaskTunnel(ctx, clientCfg.ServerAddress, &clientCfg, (&net.Dialer{}).DialContext, func(raw net.Conn) (net.Conn, error) { + return ClientHandshake(raw, &handshakeCfg) + }) + if err != nil { + t.Fatalf("dial tunnel: %v", err) + } + defer tunnelConn.Close() + + addrBuf, err := EncodeAddress(target) + if err != nil { + t.Fatalf("encode addr: %v", err) + } + if err := WriteKIPMessage(tunnelConn, KIPTypeOpenTCP, addrBuf); err != nil { + t.Fatalf("write addr: %v", err) + } + + buf := make([]byte, 2) + if _, err := io.ReadFull(tunnelConn, buf); err != nil { + t.Fatalf("read: %v", err) + } + if string(buf) != "ok" { + t.Fatalf("unexpected payload: %q", buf) + } + + stop() + for err := range errCh { + t.Fatalf("server error: %v", err) + } + }) + } +} + func TestHTTPMaskTunnel_Validation(t *testing.T) { cfg := DefaultConfig() cfg.Key = "k" diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/early_handshake.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/early_handshake.go new file mode 100644 index 0000000000..54158577bc --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/early_handshake.go @@ -0,0 +1,174 @@ +package httpmask + +import ( + "encoding/base64" + "errors" + "fmt" + "net" + "net/url" + "strings" +) + +const ( + tunnelEarlyDataQueryKey = "ed" + tunnelEarlyDataHeader = "X-Sudoku-Early" +) + +type ClientEarlyHandshake struct { + RequestPayload []byte + HandleResponse func(payload []byte) error + Ready func() bool + WrapConn func(raw net.Conn) (net.Conn, error) +} + +type TunnelServerEarlyHandshake struct { + Prepare func(payload []byte) (*PreparedServerEarlyHandshake, error) +} + +type PreparedServerEarlyHandshake struct { + ResponsePayload []byte + WrapConn func(raw net.Conn) (net.Conn, error) + UserHash string +} + +type earlyHandshakeMeta interface { + HTTPMaskEarlyHandshakeUserHash() string +} + +type earlyHandshakeConn struct { + net.Conn + userHash string +} + +func (c *earlyHandshakeConn) HTTPMaskEarlyHandshakeUserHash() string { + if c == nil { + return "" + } + return c.userHash +} + +func wrapEarlyHandshakeConn(conn net.Conn, userHash string) net.Conn { + if conn == nil { + return nil + } + return &earlyHandshakeConn{Conn: conn, userHash: userHash} +} + +func EarlyHandshakeUserHash(conn net.Conn) (string, bool) { + if conn == nil { + return "", false + } + v, ok := conn.(earlyHandshakeMeta) + if !ok { + return "", false + } + return v.HTTPMaskEarlyHandshakeUserHash(), true +} + +type authorizeResponse struct { + token string + earlyPayload []byte +} + +func isTunnelTokenByte(c byte) bool { + return (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || + c == '_' +} + +func parseAuthorizeResponse(body []byte) (*authorizeResponse, error) { + s := strings.TrimSpace(string(body)) + idx := strings.Index(s, "token=") + if idx < 0 { + return nil, errors.New("missing token") + } + s = s[idx+len("token="):] + if s == "" { + return nil, errors.New("empty token") + } + + var b strings.Builder + for i := 0; i < len(s); i++ { + c := s[i] + if isTunnelTokenByte(c) { + b.WriteByte(c) + continue + } + break + } + token := b.String() + if token == "" { + return nil, errors.New("empty token") + } + + out := &authorizeResponse{token: token} + if earlyLine := findAuthorizeField(body, "ed="); earlyLine != "" { + decoded, err := base64.RawURLEncoding.DecodeString(earlyLine) + if err != nil { + return nil, fmt.Errorf("decode early authorize payload failed: %w", err) + } + out.earlyPayload = decoded + } + return out, nil +} + +func findAuthorizeField(body []byte, prefix string) string { + for _, line := range strings.Split(strings.TrimSpace(string(body)), "\n") { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, prefix) { + return strings.TrimSpace(strings.TrimPrefix(line, prefix)) + } + } + return "" +} + +func setEarlyDataQuery(rawURL string, payload []byte) (string, error) { + if len(payload) == 0 { + return rawURL, nil + } + u, err := url.Parse(rawURL) + if err != nil { + return "", err + } + q := u.Query() + q.Set(tunnelEarlyDataQueryKey, base64.RawURLEncoding.EncodeToString(payload)) + u.RawQuery = q.Encode() + return u.String(), nil +} + +func parseEarlyDataQuery(u *url.URL) ([]byte, error) { + if u == nil { + return nil, nil + } + val := strings.TrimSpace(u.Query().Get(tunnelEarlyDataQueryKey)) + if val == "" { + return nil, nil + } + return base64.RawURLEncoding.DecodeString(val) +} + +func applyEarlyHandshakeOrUpgrade(raw net.Conn, opts TunnelDialOptions) (net.Conn, error) { + out := raw + if opts.EarlyHandshake != nil && opts.EarlyHandshake.WrapConn != nil && (opts.EarlyHandshake.Ready == nil || opts.EarlyHandshake.Ready()) { + wrapped, err := opts.EarlyHandshake.WrapConn(raw) + if err != nil { + return nil, err + } + if wrapped != nil { + out = wrapped + } + return out, nil + } + if opts.Upgrade != nil { + wrapped, err := opts.Upgrade(raw) + if err != nil { + return nil, err + } + if wrapped != nil { + out = wrapped + } + } + return out, nil +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel.go index 20981c3906..a100c6202e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel.go @@ -72,6 +72,10 @@ type TunnelDialOptions struct { // AuthKey enables short-term HMAC auth for HTTP tunnel requests (anti-probing). // When set (non-empty), each HTTP request carries an Authorization bearer token derived from AuthKey. AuthKey string + // EarlyHandshake folds the protocol handshake into the HTTP/WS setup round trip. + // When the server accepts the early payload, DialTunnel returns a conn that is already post-handshake. + // When the server does not echo early data, DialTunnel falls back to Upgrade. + EarlyHandshake *ClientEarlyHandshake // Upgrade optionally wraps the raw tunnel conn and/or writes a small prelude before DialTunnel returns. // It is called with the raw tunnel conn; if it returns a non-nil conn, that conn is returned by DialTunnel. Upgrade func(raw net.Conn) (net.Conn, error) @@ -225,30 +229,11 @@ func canonicalHeaderHost(urlHost, scheme string) string { } func parseTunnelToken(body []byte) (string, error) { - s := strings.TrimSpace(string(body)) - idx := strings.Index(s, "token=") - if idx < 0 { - return "", errors.New("missing token") + resp, err := parseAuthorizeResponse(body) + if err != nil { + return "", err } - s = s[idx+len("token="):] - if s == "" { - return "", errors.New("empty token") - } - // Token is base64.RawURLEncoding (A-Z a-z 0-9 - _). Strip any trailing bytes (e.g. from CDN compression). - var b strings.Builder - for i := 0; i < len(s); i++ { - c := s[i] - if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' { - b.WriteByte(c) - continue - } - break - } - token := b.String() - if token == "" { - return "", errors.New("empty token") - } - return token, nil + return resp.token, nil } type httpClientTarget struct { @@ -353,6 +338,13 @@ func dialSessionWithClient(ctx context.Context, client *http.Client, target http auth := newTunnelAuth(opts.AuthKey, 0) authorizeURL := (&url.URL{Scheme: target.scheme, Host: target.urlHost, Path: joinPathRoot(opts.PathRoot, "/session")}).String() + if opts.EarlyHandshake != nil && len(opts.EarlyHandshake.RequestPayload) > 0 { + var err error + authorizeURL, err = setEarlyDataQuery(authorizeURL, opts.EarlyHandshake.RequestPayload) + if err != nil { + return nil, err + } + } var bodyBytes []byte for attempt := 0; ; attempt++ { @@ -410,13 +402,19 @@ func dialSessionWithClient(ctx context.Context, client *http.Client, target http break } - token, err := parseTunnelToken(bodyBytes) + authResp, err := parseAuthorizeResponse(bodyBytes) if err != nil { return nil, fmt.Errorf("%s authorize failed: %q", mode, strings.TrimSpace(string(bodyBytes))) } + token := authResp.token if token == "" { return nil, fmt.Errorf("%s authorize empty token", mode) } + if opts.EarlyHandshake != nil && len(authResp.earlyPayload) > 0 && opts.EarlyHandshake.HandleResponse != nil { + if err := opts.EarlyHandshake.HandleResponse(authResp.earlyPayload); err != nil { + return nil, err + } + } pushURL := (&url.URL{Scheme: target.scheme, Host: target.urlHost, Path: joinPathRoot(opts.PathRoot, "/api/v1/upload"), RawQuery: "token=" + url.QueryEscape(token)}).String() pullURL := (&url.URL{Scheme: target.scheme, Host: target.urlHost, Path: joinPathRoot(opts.PathRoot, "/stream"), RawQuery: "token=" + url.QueryEscape(token)}).String() @@ -671,16 +669,10 @@ func dialStreamSplitWithClient(ctx context.Context, client *http.Client, target if c == nil { return nil, fmt.Errorf("failed to build stream split conn") } - outConn := net.Conn(c) - if opts.Upgrade != nil { - upgraded, err := opts.Upgrade(c) - if err != nil { - _ = c.Close() - return nil, err - } - if upgraded != nil { - outConn = upgraded - } + outConn, err := applyEarlyHandshakeOrUpgrade(c, opts) + if err != nil { + _ = c.Close() + return nil, err } return outConn, nil } @@ -694,16 +686,10 @@ func dialStreamSplit(ctx context.Context, serverAddress string, opts TunnelDialO if c == nil { return nil, fmt.Errorf("failed to build stream split conn") } - outConn := net.Conn(c) - if opts.Upgrade != nil { - upgraded, err := opts.Upgrade(c) - if err != nil { - _ = c.Close() - return nil, err - } - if upgraded != nil { - outConn = upgraded - } + outConn, err := applyEarlyHandshakeOrUpgrade(c, opts) + if err != nil { + _ = c.Close() + return nil, err } return outConn, nil } @@ -1120,16 +1106,10 @@ func dialPollWithClient(ctx context.Context, client *http.Client, target httpCli if c == nil { return nil, fmt.Errorf("failed to build poll conn") } - outConn := net.Conn(c) - if opts.Upgrade != nil { - upgraded, err := opts.Upgrade(c) - if err != nil { - _ = c.Close() - return nil, err - } - if upgraded != nil { - outConn = upgraded - } + outConn, err := applyEarlyHandshakeOrUpgrade(c, opts) + if err != nil { + _ = c.Close() + return nil, err } return outConn, nil } @@ -1143,16 +1123,10 @@ func dialPoll(ctx context.Context, serverAddress string, opts TunnelDialOptions) if c == nil { return nil, fmt.Errorf("failed to build poll conn") } - outConn := net.Conn(c) - if opts.Upgrade != nil { - upgraded, err := opts.Upgrade(c) - if err != nil { - _ = c.Close() - return nil, err - } - if upgraded != nil { - outConn = upgraded - } + outConn, err := applyEarlyHandshakeOrUpgrade(c, opts) + if err != nil { + _ = c.Close() + return nil, err } return outConn, nil } @@ -1528,6 +1502,8 @@ type TunnelServerOptions struct { PullReadTimeout time.Duration // SessionTTL is a best-effort TTL to prevent leaked sessions. 0 uses a conservative default. SessionTTL time.Duration + // EarlyHandshake optionally folds the protocol handshake into the initial HTTP/WS round trip. + EarlyHandshake *TunnelServerEarlyHandshake } type TunnelServer struct { @@ -1538,6 +1514,7 @@ type TunnelServer struct { pullReadTimeout time.Duration sessionTTL time.Duration + earlyHandshake *TunnelServerEarlyHandshake mu sync.Mutex sessions map[string]*tunnelSession @@ -1570,6 +1547,7 @@ func NewTunnelServer(opts TunnelServerOptions) *TunnelServer { passThroughOnReject: opts.PassThroughOnReject, pullReadTimeout: timeout, sessionTTL: ttl, + earlyHandshake: opts.EarlyHandshake, sessions: make(map[string]*tunnelSession), } } @@ -1925,9 +1903,12 @@ func (s *TunnelServer) handleStream(rawConn net.Conn, req *httpRequestHeader, he switch strings.ToUpper(req.method) { case http.MethodGet: - // Stream split-session: GET /session (no token) => token + start tunnel on a server-side pipe. if token == "" && path == "/session" { - return s.sessionAuthorize(rawConn) + earlyPayload, err := parseEarlyDataQuery(u) + if err != nil { + return rejectOrReply(http.StatusBadRequest, "bad request") + } + return s.sessionAuthorize(rawConn, earlyPayload) } // Stream split-session: GET /stream?token=... => downlink poll. if token != "" && path == "/stream" { @@ -2045,10 +2026,18 @@ func writeSimpleHTTPResponse(w io.Writer, code int, body string) error { func writeTokenHTTPResponse(w io.Writer, token string) error { token = strings.TrimRight(token, "\r\n") - // Use application/octet-stream to avoid CDN auto-compression (e.g. brotli) breaking clients that expect a plain token string. + return writeTokenHTTPResponseWithEarlyData(w, token, nil) +} + +func writeTokenHTTPResponseWithEarlyData(w io.Writer, token string, earlyPayload []byte) error { + token = strings.TrimRight(token, "\r\n") + body := "token=" + token + if len(earlyPayload) > 0 { + body += "\ned=" + base64.RawURLEncoding.EncodeToString(earlyPayload) + } _, err := io.WriteString(w, - fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nCache-Control: no-store\r\nPragma: no-cache\r\nContent-Length: %d\r\nConnection: close\r\n\r\ntoken=%s", - len("token=")+len(token), token)) + fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nCache-Control: no-store\r\nPragma: no-cache\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s", + len(body), body)) return err } @@ -2088,7 +2077,11 @@ func (s *TunnelServer) handlePoll(rawConn net.Conn, req *httpRequestHeader, head switch strings.ToUpper(req.method) { case http.MethodGet: if token == "" && path == "/session" { - return s.sessionAuthorize(rawConn) + earlyPayload, err := parseEarlyDataQuery(u) + if err != nil { + return rejectOrReply(http.StatusBadRequest, "bad request") + } + return s.sessionAuthorize(rawConn, earlyPayload) } if token != "" && path == "/stream" { if s.passThroughOnReject && !s.sessionHas(token) { @@ -2128,7 +2121,7 @@ func (s *TunnelServer) handlePoll(rawConn net.Conn, req *httpRequestHeader, head } } -func (s *TunnelServer) sessionAuthorize(rawConn net.Conn) (HandleResult, net.Conn, error) { +func (s *TunnelServer) sessionAuthorize(rawConn net.Conn, earlyPayload []byte) (HandleResult, net.Conn, error) { token, err := newSessionToken() if err != nil { _ = writeSimpleHTTPResponse(rawConn, http.StatusInternalServerError, "internal error") @@ -2137,6 +2130,37 @@ func (s *TunnelServer) sessionAuthorize(rawConn net.Conn) (HandleResult, net.Con } c1, c2 := newHalfPipe() + outConn := net.Conn(c1) + var responsePayload []byte + var userHash string + if len(earlyPayload) > 0 && s.earlyHandshake != nil && s.earlyHandshake.Prepare != nil { + prepared, err := s.earlyHandshake.Prepare(earlyPayload) + if err != nil { + _ = c1.Close() + _ = c2.Close() + if s.passThroughOnReject { + return HandlePassThrough, newRejectedPreBufferedConn(rawConn, nil), nil + } + _ = writeSimpleHTTPResponse(rawConn, http.StatusNotFound, "not found") + _ = rawConn.Close() + return HandleDone, nil, nil + } + responsePayload = prepared.ResponsePayload + userHash = prepared.UserHash + if prepared.WrapConn != nil { + wrapped, err := prepared.WrapConn(c1) + if err != nil { + _ = c1.Close() + _ = c2.Close() + _ = writeSimpleHTTPResponse(rawConn, http.StatusInternalServerError, "internal error") + _ = rawConn.Close() + return HandleDone, nil, nil + } + if wrapped != nil { + outConn = wrapEarlyHandshakeConn(wrapped, userHash) + } + } + } s.mu.Lock() s.sessions[token] = &tunnelSession{conn: c2, lastActive: time.Now()} @@ -2144,9 +2168,9 @@ func (s *TunnelServer) sessionAuthorize(rawConn net.Conn) (HandleResult, net.Con go s.reapLater(token) - _ = writeTokenHTTPResponse(rawConn, token) + _ = writeTokenHTTPResponseWithEarlyData(rawConn, token, responsePayload) _ = rawConn.Close() - return HandleStartTunnel, c1, nil + return HandleStartTunnel, outConn, nil } func newSessionToken() (string, error) { diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel_ws.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel_ws.go index e1299e3da1..8ef8d5c3af 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel_ws.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel_ws.go @@ -2,6 +2,7 @@ package httpmask import ( "context" + "encoding/base64" "fmt" "io" mrand "math/rand" @@ -115,6 +116,16 @@ func dialWS(ctx context.Context, serverAddress string, opts TunnelDialOptions) ( Host: urlHost, Path: joinPathRoot(opts.PathRoot, "/ws"), } + if opts.EarlyHandshake != nil && len(opts.EarlyHandshake.RequestPayload) > 0 { + rawURL, err := setEarlyDataQuery(u.String(), opts.EarlyHandshake.RequestPayload) + if err != nil { + return nil, err + } + u, err = url.Parse(rawURL) + if err != nil { + return nil, err + } + } header := make(stdhttp.Header) applyWSHeaders(header, headerHost) @@ -132,6 +143,16 @@ func dialWS(ctx context.Context, serverAddress string, opts TunnelDialOptions) ( d := ws.Dialer{ Host: headerHost, Header: ws.HandshakeHeaderHTTP(header), + OnHeader: func(key, value []byte) error { + if !strings.EqualFold(string(key), tunnelEarlyDataHeader) || opts.EarlyHandshake == nil || opts.EarlyHandshake.HandleResponse == nil { + return nil + } + decoded, err := base64.RawURLEncoding.DecodeString(strings.TrimSpace(string(value))) + if err != nil { + return err + } + return opts.EarlyHandshake.HandleResponse(decoded) + }, NetDial: func(dialCtx context.Context, network, addr string) (net.Conn, error) { if addr == urlHost { addr = dialAddr @@ -161,16 +182,10 @@ func dialWS(ctx context.Context, serverAddress string, opts TunnelDialOptions) ( } wsConn := newWSStreamConn(conn, ws.StateClientSide) - if opts.Upgrade == nil { - return wsConn, nil - } - upgraded, err := opts.Upgrade(wsConn) + upgraded, err := applyEarlyHandshakeOrUpgrade(wsConn, opts) if err != nil { _ = wsConn.Close() return nil, err } - if upgraded != nil { - return upgraded, nil - } - return wsConn, nil + return upgraded, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel_ws_server.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel_ws_server.go index 3e79e58aff..b17b1ded3d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel_ws_server.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/httpmask/tunnel_ws_server.go @@ -1,6 +1,7 @@ package httpmask import ( + "encoding/base64" "net" "net/http" "net/url" @@ -63,15 +64,46 @@ func (s *TunnelServer) handleWS(rawConn net.Conn, req *httpRequestHeader, header return rejectOrReply(http.StatusNotFound, "not found") } + earlyPayload, err := parseEarlyDataQuery(u) + if err != nil { + return rejectOrReply(http.StatusBadRequest, "bad request") + } + var prepared *PreparedServerEarlyHandshake + if len(earlyPayload) > 0 && s.earlyHandshake != nil && s.earlyHandshake.Prepare != nil { + prepared, err = s.earlyHandshake.Prepare(earlyPayload) + if err != nil { + return rejectOrReply(http.StatusNotFound, "not found") + } + } + prefix := make([]byte, 0, len(headerBytes)+len(buffered)) prefix = append(prefix, headerBytes...) prefix = append(prefix, buffered...) wsConnRaw := newPreBufferedConn(rawConn, prefix) - if _, err := ws.Upgrade(wsConnRaw); err != nil { + upgrader := ws.Upgrader{} + if prepared != nil && len(prepared.ResponsePayload) > 0 { + upgrader.OnBeforeUpgrade = func() (ws.HandshakeHeader, error) { + h := http.Header{} + h.Set(tunnelEarlyDataHeader, base64.RawURLEncoding.EncodeToString(prepared.ResponsePayload)) + return ws.HandshakeHeaderHTTP(h), nil + } + } + if _, err := upgrader.Upgrade(wsConnRaw); err != nil { _ = rawConn.Close() return HandleDone, nil, nil } - return HandleStartTunnel, newWSStreamConn(wsConnRaw, ws.StateServerSide), nil + outConn := net.Conn(newWSStreamConn(wsConnRaw, ws.StateServerSide)) + if prepared != nil && prepared.WrapConn != nil { + wrapped, err := prepared.WrapConn(outConn) + if err != nil { + _ = outConn.Close() + return HandleDone, nil, nil + } + if wrapped != nil { + outConn = wrapEarlyHandshakeConn(wrapped, prepared.UserHash) + } + } + return HandleStartTunnel, outConn, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/sudoku/packed.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/sudoku/packed.go index 346314a32d..0edf4f32b4 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/sudoku/packed.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/sudoku/packed.go @@ -11,35 +11,35 @@ import ( ) const ( - // 每次从 RNG 获取批量随机数的缓存大小,减少 RNG 函数调用开销 RngBatchSize = 128 + + packedProtectedPrefixBytes = 14 ) -// 1. 使用 12字节->16组 的块处理优化 Write (减少循环开销) -// 2. 使用整数阈值随机概率判断 Padding,与纯 Sudoku 保持流量特征一致 -// 3. Read 使用 copy 移动避免底层数组泄漏 +// PackedConn encodes traffic with the packed Sudoku layout while preserving +// the same padding model as the regular connection. type PackedConn struct { net.Conn table *Table reader *bufio.Reader - // 读缓冲 + // Read-side buffers. rawBuf []byte - pendingData []byte // 解码后尚未被 Read 取走的字节 + pendingData []byte - // 写缓冲与状态 + // Write-side state. writeMu sync.Mutex writeBuf []byte - bitBuf uint64 // 暂存的位数据 - bitCount int // 暂存的位数 + bitBuf uint64 + bitCount int - // 读状态 + // Read-side bit accumulator. readBitBuf uint64 readBits int - // 随机数与填充控制 - 使用整数阈值随机,与 Conn 一致 + // Padding selection matches Conn's threshold-based model. rng *rand.Rand - paddingThreshold uint64 // 与 Conn 保持一致的随机概率模型 + paddingThreshold uint64 padMarker byte padPool []byte } @@ -95,7 +95,6 @@ func NewPackedConn(c net.Conn, table *Table, pMin, pMax int) *PackedConn { return pc } -// maybeAddPadding 内联辅助:根据概率阈值插入 padding func (pc *PackedConn) maybeAddPadding(out []byte) []byte { if shouldPad(pc.rng, pc.paddingThreshold) { out = append(out, pc.getPaddingByte()) @@ -103,7 +102,73 @@ func (pc *PackedConn) maybeAddPadding(out []byte) []byte { return out } -// Write 极致优化版 - 批量处理 12 字节 +func (pc *PackedConn) appendGroup(out []byte, group byte) []byte { + out = pc.maybeAddPadding(out) + return append(out, pc.encodeGroup(group)) +} + +func (pc *PackedConn) appendForcedPadding(out []byte) []byte { + return append(out, pc.getPaddingByte()) +} + +func (pc *PackedConn) nextProtectedPrefixGap() int { + return 1 + pc.rng.Intn(2) +} + +func (pc *PackedConn) writeProtectedPrefix(out []byte, p []byte) ([]byte, int) { + if len(p) == 0 { + return out, 0 + } + + limit := len(p) + if limit > packedProtectedPrefixBytes { + limit = packedProtectedPrefixBytes + } + + for padCount := 0; padCount < 1+pc.rng.Intn(2); padCount++ { + out = pc.appendForcedPadding(out) + } + + gap := pc.nextProtectedPrefixGap() + effective := 0 + for i := 0; i < limit; i++ { + pc.bitBuf = (pc.bitBuf << 8) | uint64(p[i]) + pc.bitCount += 8 + for pc.bitCount >= 6 { + pc.bitCount -= 6 + group := byte(pc.bitBuf >> pc.bitCount) + if pc.bitCount == 0 { + pc.bitBuf = 0 + } else { + pc.bitBuf &= (1 << pc.bitCount) - 1 + } + out = pc.appendGroup(out, group&0x3F) + } + + effective++ + if effective >= gap { + out = pc.appendForcedPadding(out) + effective = 0 + gap = pc.nextProtectedPrefixGap() + } + } + + return out, limit +} + +func (pc *PackedConn) drainPendingData(dst []byte) int { + n := copy(dst, pc.pendingData) + if n == len(pc.pendingData) { + pc.pendingData = pc.pendingData[:0] + return n + } + + remaining := len(pc.pendingData) - n + copy(pc.pendingData, pc.pendingData[n:]) + pc.pendingData = pc.pendingData[:remaining] + return n +} + func (pc *PackedConn) Write(p []byte) (int, error) { if len(p) == 0 { return 0, nil @@ -112,20 +177,19 @@ func (pc *PackedConn) Write(p []byte) (int, error) { pc.writeMu.Lock() defer pc.writeMu.Unlock() - // 1. 预分配内存,避免 append 导致的多次扩容 - // 预估:原数据 * 1.5 (4/3 + padding 余量) needed := len(p)*3/2 + 32 if cap(pc.writeBuf) < needed { pc.writeBuf = make([]byte, 0, needed) } out := pc.writeBuf[:0] - i := 0 + var prefixN int + out, prefixN = pc.writeProtectedPrefix(out, p) + + i := prefixN n := len(p) - // 2. 头部对齐处理 (Slow Path) for pc.bitCount > 0 && i < n { - out = pc.maybeAddPadding(out) b := p[i] i++ pc.bitBuf = (pc.bitBuf << 8) | uint64(b) @@ -138,14 +202,11 @@ func (pc *PackedConn) Write(p []byte) (int, error) { } else { pc.bitBuf &= (1 << pc.bitCount) - 1 } - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(group&0x3F)) + out = pc.appendGroup(out, group&0x3F) } } - // 3. 极速批量处理 (Fast Path) - 每次处理 12 字节 → 生成 16 个编码组 for i+11 < n { - // 处理 4 组,每组 3 字节 for batch := 0; batch < 4; batch++ { b1, b2, b3 := p[i], p[i+1], p[i+2] i += 3 @@ -155,19 +216,13 @@ func (pc *PackedConn) Write(p []byte) (int, error) { g3 := ((b2 & 0x0F) << 2) | ((b3 >> 6) & 0x03) g4 := b3 & 0x3F - // 每个组之前都有概率插入 padding - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(g1)) - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(g2)) - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(g3)) - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(g4)) + out = pc.appendGroup(out, g1) + out = pc.appendGroup(out, g2) + out = pc.appendGroup(out, g3) + out = pc.appendGroup(out, g4) } } - // 4. 处理剩余的 3 字节块 for i+2 < n { b1, b2, b3 := p[i], p[i+1], p[i+2] i += 3 @@ -177,17 +232,12 @@ func (pc *PackedConn) Write(p []byte) (int, error) { g3 := ((b2 & 0x0F) << 2) | ((b3 >> 6) & 0x03) g4 := b3 & 0x3F - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(g1)) - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(g2)) - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(g3)) - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(g4)) + out = pc.appendGroup(out, g1) + out = pc.appendGroup(out, g2) + out = pc.appendGroup(out, g3) + out = pc.appendGroup(out, g4) } - // 5. 尾部处理 (Tail Path) - 处理剩余的 1 或 2 个字节 for ; i < n; i++ { b := p[i] pc.bitBuf = (pc.bitBuf << 8) | uint64(b) @@ -200,35 +250,28 @@ func (pc *PackedConn) Write(p []byte) (int, error) { } else { pc.bitBuf &= (1 << pc.bitCount) - 1 } - out = pc.maybeAddPadding(out) - out = append(out, pc.encodeGroup(group&0x3F)) + out = pc.appendGroup(out, group&0x3F) } } - // 6. 处理残留位 if pc.bitCount > 0 { - out = pc.maybeAddPadding(out) group := byte(pc.bitBuf << (6 - pc.bitCount)) pc.bitBuf = 0 pc.bitCount = 0 - out = append(out, pc.encodeGroup(group&0x3F)) + out = pc.appendGroup(out, group&0x3F) out = append(out, pc.padMarker) } - // 尾部可能添加 padding out = pc.maybeAddPadding(out) - // 发送数据 if len(out) > 0 { - _, err := pc.Conn.Write(out) pc.writeBuf = out[:0] - return len(p), err + return len(p), writeFull(pc.Conn, out) } pc.writeBuf = out[:0] return len(p), nil } -// Flush 处理最后不足 6 bit 的情况 func (pc *PackedConn) Flush() error { pc.writeMu.Lock() defer pc.writeMu.Unlock() @@ -243,38 +286,34 @@ func (pc *PackedConn) Flush() error { out = append(out, pc.padMarker) } - // 尾部随机添加 padding out = pc.maybeAddPadding(out) if len(out) > 0 { - _, err := pc.Conn.Write(out) pc.writeBuf = out[:0] - return err + return writeFull(pc.Conn, out) } return nil } -// Read 优化版:减少切片操作,避免内存泄漏 -func (pc *PackedConn) Read(p []byte) (int, error) { - // 1. 优先返回待处理区的数据 - if len(pc.pendingData) > 0 { - n := copy(p, pc.pendingData) - if n == len(pc.pendingData) { - pc.pendingData = pc.pendingData[:0] - } else { - // 优化:移动剩余数据到数组头部,避免切片指向中间导致内存泄漏 - remaining := len(pc.pendingData) - n - copy(pc.pendingData, pc.pendingData[n:]) - pc.pendingData = pc.pendingData[:remaining] +func writeFull(w io.Writer, b []byte) error { + for len(b) > 0 { + n, err := w.Write(b) + if err != nil { + return err } - return n, nil + b = b[n:] + } + return nil +} + +func (pc *PackedConn) Read(p []byte) (int, error) { + if len(pc.pendingData) > 0 { + return pc.drainPendingData(p), nil } - // 2. 循环读取直到解出数据或出错 for { nr, rErr := pc.reader.Read(pc.rawBuf) if nr > 0 { - // 缓存频繁访问的变量 rBuf := pc.readBitBuf rBits := pc.readBits padMarker := pc.padMarker @@ -324,24 +363,13 @@ func (pc *PackedConn) Read(p []byte) (int, error) { } } - // 3. 返回解码后的数据 - 优化:避免底层数组泄漏 - n := copy(p, pc.pendingData) - if n == len(pc.pendingData) { - pc.pendingData = pc.pendingData[:0] - } else { - remaining := len(pc.pendingData) - n - copy(pc.pendingData, pc.pendingData[n:]) - pc.pendingData = pc.pendingData[:remaining] - } - return n, nil + return pc.drainPendingData(p), nil } -// getPaddingByte 从 Pool 中随机取 Padding 字节 func (pc *PackedConn) getPaddingByte() byte { return pc.padPool[pc.rng.Intn(len(pc.padPool))] } -// encodeGroup 编码 6-bit 组 func (pc *PackedConn) encodeGroup(group byte) byte { return pc.table.layout.encodeGroup(group) } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/sudoku/packed_prefix_test.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/sudoku/packed_prefix_test.go new file mode 100644 index 0000000000..f041c0f561 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs/sudoku/packed_prefix_test.go @@ -0,0 +1,91 @@ +package sudoku + +import ( + "bytes" + "io" + "math/rand" + "net" + "testing" + "time" +) + +type mockConn struct { + readBuf []byte + writeBuf []byte +} + +func (c *mockConn) Read(p []byte) (int, error) { + if len(c.readBuf) == 0 { + return 0, io.EOF + } + n := copy(p, c.readBuf) + c.readBuf = c.readBuf[n:] + return n, nil +} + +func (c *mockConn) Write(p []byte) (int, error) { + c.writeBuf = append(c.writeBuf, p...) + return len(p), nil +} + +func (c *mockConn) Close() error { return nil } +func (c *mockConn) LocalAddr() net.Addr { return nil } +func (c *mockConn) RemoteAddr() net.Addr { return nil } +func (c *mockConn) SetDeadline(time.Time) error { return nil } +func (c *mockConn) SetReadDeadline(time.Time) error { return nil } +func (c *mockConn) SetWriteDeadline(time.Time) error { return nil } + +func TestPackedConn_ProtectedPrefixPadding(t *testing.T) { + table := NewTable("packed-prefix-seed", "prefer_ascii") + mock := &mockConn{} + writer := NewPackedConn(mock, table, 0, 0) + writer.rng = rand.New(rand.NewSource(1)) + + payload := bytes.Repeat([]byte{0}, 32) + if _, err := writer.Write(payload); err != nil { + t.Fatalf("write: %v", err) + } + + wire := append([]byte(nil), mock.writeBuf...) + if len(wire) < 20 { + t.Fatalf("wire too short: %d", len(wire)) + } + + firstHint := -1 + nonHintCount := 0 + maxHintRun := 0 + currentHintRun := 0 + for i, b := range wire[:20] { + if table.layout.isHint(b) { + if firstHint == -1 { + firstHint = i + } + currentHintRun++ + if currentHintRun > maxHintRun { + maxHintRun = currentHintRun + } + continue + } + nonHintCount++ + currentHintRun = 0 + } + + if firstHint < 1 || firstHint > 2 { + t.Fatalf("expected 1-2 leading padding bytes, first hint index=%d", firstHint) + } + if nonHintCount < 6 { + t.Fatalf("expected dense prefix padding, got only %d non-hint bytes in first 20", nonHintCount) + } + if maxHintRun > 3 { + t.Fatalf("prefix still exposes long hint run: %d", maxHintRun) + } + + reader := NewPackedConn(&mockConn{readBuf: wire}, table, 0, 0) + decoded := make([]byte, len(payload)) + if _, err := io.ReadFull(reader, decoded); err != nil { + t.Fatalf("read back: %v", err) + } + if !bytes.Equal(decoded, payload) { + t.Fatalf("roundtrip mismatch") + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/client.go b/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/client.go index d2d25ea089..a4c4c728ba 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/client.go @@ -131,34 +131,45 @@ func (c *Client) resetHealthCheckTimer() { c.healthCheckTimer.Reset(DefaultHealthCheckTimeout) } -func (c *Client) dial(ctx context.Context, request *http.Request, conn *httpConn, pipeReader *io.PipeReader, pipeWriter *io.PipeWriter) { +func (c *Client) roundTrip(request *http.Request, conn *httpConn) { c.startOnce.Do(c.start) - trace := &httptrace.ClientTrace{ - GotConn: func(connInfo httptrace.GotConnInfo) { - conn.SetLocalAddr(connInfo.Conn.LocalAddr()) - conn.SetRemoteAddr(connInfo.Conn.RemoteAddr()) - }, - } - request = request.WithContext(httptrace.WithClientTrace(ctx, trace)) - response, err := c.roundTripper.RoundTrip(request) - if err != nil { - _ = pipeWriter.CloseWithError(err) - _ = pipeReader.CloseWithError(err) - conn.setUp(nil, err) - } else if response.StatusCode != http.StatusOK { - _ = response.Body.Close() - err = fmt.Errorf("unexpected status code: %d", response.StatusCode) - _ = pipeWriter.CloseWithError(err) - _ = pipeReader.CloseWithError(err) - conn.setUp(nil, err) - } else { - c.resetHealthCheckTimer() - conn.setUp(response.Body, nil) + pipeReader, pipeWriter := io.Pipe() + request.Body = pipeReader + *conn = httpConn{ + writer: pipeWriter, + created: make(chan struct{}), } + ctx, cancel := context.WithCancel(c.ctx) // requestCtx must alive during conn not closed + conn.cancelFn = cancel // cancel ctx when conn closed + go func() { + timeout := time.AfterFunc(C.DefaultTCPTimeout, cancel) // only cancel when RoundTrip timeout + defer timeout.Stop() // RoundTrip already returned, stop the timer + trace := &httptrace.ClientTrace{ + GotConn: func(connInfo httptrace.GotConnInfo) { + conn.SetLocalAddr(connInfo.Conn.LocalAddr()) + conn.SetRemoteAddr(connInfo.Conn.RemoteAddr()) + }, + } + request = request.WithContext(httptrace.WithClientTrace(ctx, trace)) + response, err := c.roundTripper.RoundTrip(request) + if err != nil { + _ = pipeWriter.CloseWithError(err) + _ = pipeReader.CloseWithError(err) + conn.setUp(nil, err) + } else if response.StatusCode != http.StatusOK { + _ = response.Body.Close() + err = fmt.Errorf("unexpected status code: %d", response.StatusCode) + _ = pipeWriter.CloseWithError(err) + _ = pipeReader.CloseWithError(err) + conn.setUp(nil, err) + } else { + c.resetHealthCheckTimer() + conn.setUp(response.Body, nil) + } + }() } func (c *Client) Dial(ctx context.Context, host string) (net.Conn, error) { - pipeReader, pipeWriter := io.Pipe() request := &http.Request{ Method: http.MethodConnect, URL: &url.URL{ @@ -166,23 +177,16 @@ func (c *Client) Dial(ctx context.Context, host string) (net.Conn, error) { Host: host, }, Header: make(http.Header), - Body: pipeReader, Host: host, } request.Header.Add("User-Agent", TCPUserAgent) request.Header.Add("Proxy-Authorization", c.auth) - conn := &tcpConn{ - httpConn: httpConn{ - writer: pipeWriter, - created: make(chan struct{}), - }, - } - go c.dial(ctx, request, &conn.httpConn, pipeReader, pipeWriter) + conn := &tcpConn{} + c.roundTrip(request, &conn.httpConn) return conn, nil } func (c *Client) ListenPacket(ctx context.Context) (net.PacketConn, error) { - pipeReader, pipeWriter := io.Pipe() request := &http.Request{ Method: http.MethodConnect, URL: &url.URL{ @@ -190,25 +194,16 @@ func (c *Client) ListenPacket(ctx context.Context) (net.PacketConn, error) { Host: UDPMagicAddress, }, Header: make(http.Header), - Body: pipeReader, Host: UDPMagicAddress, } request.Header.Add("User-Agent", UDPUserAgent) request.Header.Add("Proxy-Authorization", c.auth) - conn := &clientPacketConn{ - packetConn: packetConn{ - httpConn: httpConn{ - writer: pipeWriter, - created: make(chan struct{}), - }, - }, - } - go c.dial(ctx, request, &conn.httpConn, pipeReader, pipeWriter) + conn := &clientPacketConn{} + c.roundTrip(request, &conn.httpConn) return conn, nil } func (c *Client) ListenICMP(ctx context.Context) (*IcmpConn, error) { - pipeReader, pipeWriter := io.Pipe() request := &http.Request{ Method: http.MethodConnect, URL: &url.URL{ @@ -216,18 +211,12 @@ func (c *Client) ListenICMP(ctx context.Context) (*IcmpConn, error) { Host: ICMPMagicAddress, }, Header: make(http.Header), - Body: pipeReader, Host: ICMPMagicAddress, } request.Header.Add("User-Agent", ICMPUserAgent) request.Header.Add("Proxy-Authorization", c.auth) - conn := &IcmpConn{ - httpConn{ - writer: pipeWriter, - created: make(chan struct{}), - }, - } - go c.dial(ctx, request, &conn.httpConn, pipeReader, pipeWriter) + conn := &IcmpConn{} + c.roundTrip(request, &conn.httpConn) return conn, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/force_close.go b/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/force_close.go index 3253b6c64c..d34b9376df 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/force_close.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/force_close.go @@ -11,7 +11,7 @@ func forceCloseAllConnections(roundTripper RoundTripper) { roundTripper.CloseIdleConnections() switch tr := roundTripper.(type) { case *http.Http2Transport: - gun.CloseTransport(tr) + gun.CloseHttp2Transport(tr) case *http3.Transport: _ = tr.Close() } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/protocol.go b/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/protocol.go index f541d6872d..a78ecb1e01 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/protocol.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/trusttunnel/protocol.go @@ -97,6 +97,7 @@ type httpConn struct { body io.ReadCloser created chan struct{} createErr error + cancelFn func() gun.NetAddr // deadlines @@ -125,6 +126,9 @@ func (h *httpConn) Close() error { if h.body != nil { errorArr = append(errorArr, h.body.Close()) } + if h.cancelFn != nil { + h.cancelFn() + } return errors.Join(errorArr...) } diff --git a/clash-meta-android/core/src/foss/golang/go.mod b/clash-meta-android/core/src/foss/golang/go.mod index e19f1adf95..a80947f9f4 100644 --- a/clash-meta-android/core/src/foss/golang/go.mod +++ b/clash-meta-android/core/src/foss/golang/go.mod @@ -53,6 +53,7 @@ require ( github.com/metacubex/hpke v0.1.0 // indirect github.com/metacubex/http v0.1.0 // indirect github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 // indirect + github.com/metacubex/mhurl v0.1.0 // indirect github.com/metacubex/mihomo v1.7.0 // indirect github.com/metacubex/mlkem v0.1.0 // indirect github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect diff --git a/clash-meta-android/core/src/foss/golang/go.sum b/clash-meta-android/core/src/foss/golang/go.sum index 93108fc610..4cdce78935 100644 --- a/clash-meta-android/core/src/foss/golang/go.sum +++ b/clash-meta-android/core/src/foss/golang/go.sum @@ -102,6 +102,8 @@ github.com/metacubex/http v0.1.0 h1:Jcy0I9zKjYijSUaksZU34XEe2xNdoFkgUTB7z7K5q0o= github.com/metacubex/http v0.1.0/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 h1:hJwCVlE3ojViC35MGHB+FBr8TuIf3BUFn2EQ1VIamsI= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604/go.mod h1:lpmN3m269b3V5jFCWtffqBLS4U3QQoIid9ugtO+OhVc= +github.com/metacubex/mhurl v0.1.0 h1:ZdW4Zxe3j3uJ89gNytOazHu6kbHn5owutN/VfXOI8GE= +github.com/metacubex/mhurl v0.1.0/go.mod h1:2qpQImCbXoUs6GwJrjuEXKelPyoimsIXr07eNKZdS00= github.com/metacubex/mlkem v0.1.0 h1:wFClitonSFcmipzzQvax75beLQU+D7JuC+VK1RzSL8I= github.com/metacubex/mlkem v0.1.0/go.mod h1:amhaXZVeYNShuy9BILcR7P0gbeo/QLZsnqCdL8U2PDQ= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= diff --git a/clash-meta-android/core/src/main/golang/go.mod b/clash-meta-android/core/src/main/golang/go.mod index a551b07cc6..a83a37a3c8 100644 --- a/clash-meta-android/core/src/main/golang/go.mod +++ b/clash-meta-android/core/src/main/golang/go.mod @@ -58,6 +58,7 @@ require ( github.com/metacubex/hpke v0.1.0 // indirect github.com/metacubex/http v0.1.0 // indirect github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 // indirect + github.com/metacubex/mhurl v0.1.0 // indirect github.com/metacubex/mlkem v0.1.0 // indirect github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect github.com/metacubex/qpack v0.6.0 // indirect diff --git a/clash-meta-android/core/src/main/golang/go.sum b/clash-meta-android/core/src/main/golang/go.sum index 93108fc610..4cdce78935 100644 --- a/clash-meta-android/core/src/main/golang/go.sum +++ b/clash-meta-android/core/src/main/golang/go.sum @@ -102,6 +102,8 @@ github.com/metacubex/http v0.1.0 h1:Jcy0I9zKjYijSUaksZU34XEe2xNdoFkgUTB7z7K5q0o= github.com/metacubex/http v0.1.0/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 h1:hJwCVlE3ojViC35MGHB+FBr8TuIf3BUFn2EQ1VIamsI= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604/go.mod h1:lpmN3m269b3V5jFCWtffqBLS4U3QQoIid9ugtO+OhVc= +github.com/metacubex/mhurl v0.1.0 h1:ZdW4Zxe3j3uJ89gNytOazHu6kbHn5owutN/VfXOI8GE= +github.com/metacubex/mhurl v0.1.0/go.mod h1:2qpQImCbXoUs6GwJrjuEXKelPyoimsIXr07eNKZdS00= github.com/metacubex/mlkem v0.1.0 h1:wFClitonSFcmipzzQvax75beLQU+D7JuC+VK1RzSL8I= github.com/metacubex/mlkem v0.1.0/go.mod h1:amhaXZVeYNShuy9BILcR7P0gbeo/QLZsnqCdL8U2PDQ= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= diff --git a/clash-meta-android/core/src/main/golang/native/tunnel/proxies.go b/clash-meta-android/core/src/main/golang/native/tunnel/proxies.go index 83ad15ecc0..3357d5046e 100644 --- a/clash-meta-android/core/src/main/golang/native/tunnel/proxies.go +++ b/clash-meta-android/core/src/main/golang/native/tunnel/proxies.go @@ -68,8 +68,11 @@ func QueryProxyGroupNames(excludeNotSelectable bool) []string { } for _, p := range proxies { - if _, ok := p.Adapter().(outboundgroup.ProxyGroup); ok { + if g, ok := p.Adapter().(outboundgroup.ProxyGroup); ok { if !excludeNotSelectable || p.Type() == C.Selector { + if g.Hidden() { + continue + } result = append(result, p.Name()) } } diff --git a/clash-meta/adapter/outboundgroup/fallback.go b/clash-meta/adapter/outboundgroup/fallback.go index 0174a7b944..ef4a74c37f 100644 --- a/clash-meta/adapter/outboundgroup/fallback.go +++ b/clash-meta/adapter/outboundgroup/fallback.go @@ -19,8 +19,6 @@ type Fallback struct { testUrl string selected string expectedStatus string - Hidden bool - Icon string } func (f *Fallback) Now() string { @@ -90,8 +88,8 @@ func (f *Fallback) MarshalJSON() ([]byte, error) { "testUrl": f.testUrl, "expectedStatus": f.expectedStatus, "fixed": f.selected, - "hidden": f.Hidden, - "icon": f.Icon, + "hidden": f.Hidden(), + "icon": f.Icon(), }) } @@ -163,6 +161,8 @@ func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallba GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.Fallback, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -173,7 +173,5 @@ func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallba disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, } } diff --git a/clash-meta/adapter/outboundgroup/groupbase.go b/clash-meta/adapter/outboundgroup/groupbase.go index 1a1b3cfd0b..7dd085c033 100644 --- a/clash-meta/adapter/outboundgroup/groupbase.go +++ b/clash-meta/adapter/outboundgroup/groupbase.go @@ -22,6 +22,8 @@ import ( type GroupBase struct { *outbound.Base + hidden bool + icon string filterRegs []*regexp2.Regexp excludeFilterRegs []*regexp2.Regexp excludeTypeArray []string @@ -30,7 +32,7 @@ type GroupBase struct { failedTimes int failedTime time.Time failedTesting atomic.Bool - TestTimeout int + testTimeout int maxFailedTimes int // for GetProxies @@ -42,6 +44,8 @@ type GroupBase struct { type GroupBaseOption struct { Name string Type C.AdapterType + Hidden bool + Icon string Filter string ExcludeFilter string ExcludeType string @@ -74,17 +78,19 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { gb := &GroupBase{ Base: outbound.NewBase(outbound.BaseOption{Name: opt.Name, Type: opt.Type}), + hidden: opt.Hidden, + icon: opt.Icon, filterRegs: filterRegs, excludeFilterRegs: excludeFilterRegs, excludeTypeArray: excludeTypeArray, providers: opt.Providers, failedTesting: atomic.NewBool(false), - TestTimeout: opt.TestTimeout, + testTimeout: opt.TestTimeout, maxFailedTimes: opt.MaxFailedTimes, } - if gb.TestTimeout == 0 { - gb.TestTimeout = 5000 + if gb.testTimeout == 0 { + gb.testTimeout = 5000 } if gb.maxFailedTimes == 0 { gb.maxFailedTimes = 5 @@ -93,6 +99,14 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { return gb } +func (gb *GroupBase) Hidden() bool { + return gb.hidden +} + +func (gb *GroupBase) Icon() string { + return gb.icon +} + func (gb *GroupBase) Touch() { for _, pd := range gb.providers { pd.Touch() @@ -265,7 +279,7 @@ func (gb *GroupBase) onDialFailed(adapterType C.AdapterType, err error, fn func( log.Debugln("ProxyGroup: %s first failed", gb.Name()) gb.failedTime = time.Now() } else { - if time.Since(gb.failedTime) > time.Duration(gb.TestTimeout)*time.Millisecond { + if time.Since(gb.failedTime) > time.Duration(gb.testTimeout)*time.Millisecond { gb.failedTimes = 0 return } diff --git a/clash-meta/adapter/outboundgroup/loadbalance.go b/clash-meta/adapter/outboundgroup/loadbalance.go index 19ee38c7de..8d68af3d5b 100644 --- a/clash-meta/adapter/outboundgroup/loadbalance.go +++ b/clash-meta/adapter/outboundgroup/loadbalance.go @@ -27,8 +27,6 @@ type LoadBalance struct { strategyFn strategyFn testUrl string expectedStatus string - Hidden bool - Icon string } var errStrategy = errors.New("unsupported strategy") @@ -234,8 +232,8 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) { "all": all, "testUrl": lb.testUrl, "expectedStatus": lb.expectedStatus, - "hidden": lb.Hidden, - "icon": lb.Icon, + "hidden": lb.Hidden(), + "icon": lb.Icon(), }) } @@ -267,6 +265,8 @@ func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, stra GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.LoadBalance, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -278,7 +278,5 @@ func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, stra disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, }, nil } diff --git a/clash-meta/adapter/outboundgroup/selector.go b/clash-meta/adapter/outboundgroup/selector.go index 7bc138fdc7..b0272f6c1a 100644 --- a/clash-meta/adapter/outboundgroup/selector.go +++ b/clash-meta/adapter/outboundgroup/selector.go @@ -14,8 +14,6 @@ type Selector struct { disableUDP bool selected string testUrl string - Hidden bool - Icon string } // DialContext implements C.ProxyAdapter @@ -68,8 +66,8 @@ func (s *Selector) MarshalJSON() ([]byte, error) { "now": s.Now(), "all": all, "testUrl": url, - "hidden": s.Hidden, - "icon": s.Icon, + "hidden": s.Hidden(), + "icon": s.Icon(), }) } @@ -121,6 +119,8 @@ func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Select GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.Selector, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -131,7 +131,5 @@ func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Select selected: "COMPATIBLE", disableUDP: option.DisableUDP, testUrl: option.URL, - Hidden: option.Hidden, - Icon: option.Icon, } } diff --git a/clash-meta/adapter/outboundgroup/urltest.go b/clash-meta/adapter/outboundgroup/urltest.go index 49ea12aa0b..640c840c8e 100644 --- a/clash-meta/adapter/outboundgroup/urltest.go +++ b/clash-meta/adapter/outboundgroup/urltest.go @@ -29,8 +29,6 @@ type URLTest struct { expectedStatus string tolerance uint16 disableUDP bool - Hidden bool - Icon string fastNode C.Proxy fastSingle *singledo.Single[C.Proxy] } @@ -180,8 +178,8 @@ func (u *URLTest) MarshalJSON() ([]byte, error) { "testUrl": u.testUrl, "expectedStatus": u.expectedStatus, "fixed": u.selected, - "hidden": u.Hidden, - "icon": u.Icon, + "hidden": u.Hidden(), + "icon": u.Icon(), }) } @@ -215,6 +213,8 @@ func NewURLTest(option *GroupCommonOption, providers []P.ProxyProvider, options GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.URLTest, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -226,8 +226,6 @@ func NewURLTest(option *GroupCommonOption, providers []P.ProxyProvider, options disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, } for _, option := range options { diff --git a/clash-meta/adapter/outboundgroup/util.go b/clash-meta/adapter/outboundgroup/util.go index d35ea66f15..22d6b1890b 100644 --- a/clash-meta/adapter/outboundgroup/util.go +++ b/clash-meta/adapter/outboundgroup/util.go @@ -16,6 +16,9 @@ type ProxyGroup interface { Now() string Touch() + Hidden() bool + Icon() string + URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (mp map[string]uint16, err error) } diff --git a/clash-meta/go.mod b/clash-meta/go.mod index 7e82371848..f1b15792ab 100644 --- a/clash-meta/go.mod +++ b/clash-meta/go.mod @@ -23,6 +23,7 @@ require ( github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/http v0.1.0 github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 + github.com/metacubex/mhurl v0.1.0 github.com/metacubex/mlkem v0.1.0 github.com/metacubex/quic-go v0.59.1-0.20260213014310-4df8f0de5b56 github.com/metacubex/randv2 v0.2.0 @@ -43,7 +44,6 @@ require ( github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 - github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a github.com/samber/lo v1.53.0 github.com/sirupsen/logrus v1.9.4 github.com/stretchr/testify v1.11.1 @@ -104,6 +104,7 @@ require ( github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect diff --git a/clash-meta/go.sum b/clash-meta/go.sum index 91b61d786e..e295e21651 100644 --- a/clash-meta/go.sum +++ b/clash-meta/go.sum @@ -107,6 +107,8 @@ github.com/metacubex/http v0.1.0 h1:Jcy0I9zKjYijSUaksZU34XEe2xNdoFkgUTB7z7K5q0o= github.com/metacubex/http v0.1.0/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 h1:hJwCVlE3ojViC35MGHB+FBr8TuIf3BUFn2EQ1VIamsI= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604/go.mod h1:lpmN3m269b3V5jFCWtffqBLS4U3QQoIid9ugtO+OhVc= +github.com/metacubex/mhurl v0.1.0 h1:ZdW4Zxe3j3uJ89gNytOazHu6kbHn5owutN/VfXOI8GE= +github.com/metacubex/mhurl v0.1.0/go.mod h1:2qpQImCbXoUs6GwJrjuEXKelPyoimsIXr07eNKZdS00= github.com/metacubex/mlkem v0.1.0 h1:wFClitonSFcmipzzQvax75beLQU+D7JuC+VK1RzSL8I= github.com/metacubex/mlkem v0.1.0/go.mod h1:amhaXZVeYNShuy9BILcR7P0gbeo/QLZsnqCdL8U2PDQ= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= diff --git a/clash-meta/listener/shadowsocks/utils.go b/clash-meta/listener/shadowsocks/utils.go index 5d6a2977ee..6bdddb232b 100644 --- a/clash-meta/listener/shadowsocks/utils.go +++ b/clash-meta/listener/shadowsocks/utils.go @@ -4,9 +4,10 @@ import ( "bytes" "errors" "net" - "net/url" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/mhurl" ) type packet struct { @@ -48,7 +49,7 @@ func (c *packet) InAddr() net.Addr { } func ParseSSURL(s string) (addr, cipher, password string, err error) { - u, err := url.Parse(s) + u, err := mhurl.Parse(s) // we need multiple hosts url supports if err != nil { return } diff --git a/clash-meta/listener/shadowsocks/utils_test.go b/clash-meta/listener/shadowsocks/utils_test.go new file mode 100644 index 0000000000..b2b7739f00 --- /dev/null +++ b/clash-meta/listener/shadowsocks/utils_test.go @@ -0,0 +1,22 @@ +package shadowsocks + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseSSURL(t *testing.T) { + for _, test := range []struct{ method, passwd, hosts string }{ + {method: "aes-256-gcm", passwd: "password", hosts: ":1000,:2000,:3000"}, + {method: "aes-256-gcm", passwd: "password", hosts: "127.0.0.1:1000,127.0.0.1:2000,127.0.0.1:3000"}, + {method: "aes-256-gcm", passwd: "password", hosts: "[::1]:1000,[::1]:2000,[::1]:3000"}, + } { + addr, cipher, password, err := ParseSSURL(fmt.Sprintf("ss://%s:%s@%s", test.method, test.passwd, test.hosts)) + require.NoError(t, err) + require.Equal(t, test.hosts, addr) + require.Equal(t, test.method, cipher) + require.Equal(t, test.passwd, password) + } +} diff --git a/clash-meta/listener/sing_tun/server.go b/clash-meta/listener/sing_tun/server.go index e873bff861..0c7778c82d 100644 --- a/clash-meta/listener/sing_tun/server.go +++ b/clash-meta/listener/sing_tun/server.go @@ -506,8 +506,6 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis } } - //l.openAndroidHotspot(tunOptions) - if !l.options.AutoDetectInterface { resolver.ResetConnection() } diff --git a/clash-meta/listener/sing_tun/server_android.go b/clash-meta/listener/sing_tun/server_android.go index d8240534ed..f180bd3051 100644 --- a/clash-meta/listener/sing_tun/server_android.go +++ b/clash-meta/listener/sing_tun/server_android.go @@ -4,7 +4,6 @@ package sing_tun import ( "errors" - "runtime" "sync" "github.com/metacubex/mihomo/component/process" @@ -13,8 +12,6 @@ import ( "github.com/metacubex/mihomo/log" "github.com/metacubex/sing-tun" - "github.com/sagernet/netlink" - "golang.org/x/sys/unix" ) type packageManagerCallback struct{} @@ -78,25 +75,3 @@ func init() { process.DefaultPackageNameResolver = findPackageName } } - -func (l *Listener) openAndroidHotspot(tunOptions tun.Options) { - if runtime.GOOS == "android" && tunOptions.AutoRoute { - priority := 9000 - if len(tunOptions.ExcludedRanges()) > 0 { - priority++ - } - if tunOptions.InterfaceMonitor.AndroidVPNEnabled() { - priority++ - } - it := netlink.NewRule() - it.Priority = priority - it.IifName = tunOptions.Name - it.Table = 254 //main - it.Family = unix.AF_INET - it.SuppressPrefixlen = 0 - err := netlink.RuleAdd(it) - if err != nil { - log.Warnln("[TUN] add AndroidHotspot rule error") - } - } -} diff --git a/clash-meta/listener/sing_tun/server_notandroid.go b/clash-meta/listener/sing_tun/server_notandroid.go index 10fd3997b4..e393d4ca0d 100644 --- a/clash-meta/listener/sing_tun/server_notandroid.go +++ b/clash-meta/listener/sing_tun/server_notandroid.go @@ -9,4 +9,3 @@ import ( func (l *Listener) buildAndroidRules(tunOptions *tun.Options) error { return nil } -func (l *Listener) openAndroidHotspot(tunOptions tun.Options) {} diff --git a/clash-meta/listener/sing_vmess/server.go b/clash-meta/listener/sing_vmess/server.go index 7dd0a163ba..5604700f63 100644 --- a/clash-meta/listener/sing_vmess/server.go +++ b/clash-meta/listener/sing_vmess/server.go @@ -4,7 +4,6 @@ import ( "context" "errors" "net" - "net/url" "strings" "github.com/metacubex/mihomo/adapter/inbound" @@ -19,6 +18,7 @@ import ( mihomoVMess "github.com/metacubex/mihomo/transport/vmess" "github.com/metacubex/http" + "github.com/metacubex/mhurl" vmess "github.com/metacubex/sing-vmess" "github.com/metacubex/sing/common" "github.com/metacubex/sing/common/metadata" @@ -230,7 +230,7 @@ func HandleVmess(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) } func ParseVmessURL(s string) (addr, username, password string, err error) { - u, err := url.Parse(s) + u, err := mhurl.Parse(s) // we need multiple hosts url supports if err != nil { return } diff --git a/clash-meta/listener/sing_vmess/server_test.go b/clash-meta/listener/sing_vmess/server_test.go new file mode 100644 index 0000000000..36b2ab14ba --- /dev/null +++ b/clash-meta/listener/sing_vmess/server_test.go @@ -0,0 +1,22 @@ +package sing_vmess + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseVmessURL(t *testing.T) { + for _, test := range []struct{ username, passwd, hosts string }{ + {username: "username", passwd: "password", hosts: ":1000,:2000,:3000"}, + {username: "username", passwd: "password", hosts: "127.0.0.1:1000,127.0.0.1:2000,127.0.0.1:3000"}, + {username: "username", passwd: "password", hosts: "[::1]:1000,[::1]:2000,[::1]:3000"}, + } { + addr, username, password, err := ParseVmessURL(fmt.Sprintf("vmess://%s:%s@%s", test.username, test.passwd, test.hosts)) + require.NoError(t, err) + require.Equal(t, test.hosts, addr) + require.Equal(t, test.username, username) + require.Equal(t, test.passwd, password) + } +} diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index 167ca04ee9..8015265208 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -1692,7 +1692,7 @@ dependencies = [ "windows-registry 0.5.3", "windows-sys 0.60.2", "winreg 0.55.0", - "zip 8.2.0", + "zip 8.3.0", "zip-extensions", ] @@ -12802,9 +12802,9 @@ dependencies = [ [[package]] name = "zip" -version = "8.2.0" +version = "8.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b680f2a0cd479b4cff6e1233c483fdead418106eae419dc60200ae9850f6d004" +checksum = "4a243cfad17427fc077f529da5a95abe4e94fd2bfdb601611870a6557cc67657" dependencies = [ "aes", "bzip2", diff --git a/clash-nyanpasu/frontend/interface/package.json b/clash-nyanpasu/frontend/interface/package.json index e5aba2b756..0152d524a5 100644 --- a/clash-nyanpasu/frontend/interface/package.json +++ b/clash-nyanpasu/frontend/interface/package.json @@ -11,7 +11,7 @@ "build": "tsc" }, "dependencies": { - "@tanstack/react-query": "5.91.2", + "@tanstack/react-query": "5.91.3", "@tauri-apps/api": "2.10.1", "ahooks": "3.9.6", "dayjs": "1.11.20", diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index c57d18b0df..db361f37bb 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -43,7 +43,7 @@ "country-emoji": "1.5.6", "dayjs": "1.11.20", "framer-motion": "12.38.0", - "i18next": "25.8.19", + "i18next": "25.8.20", "jotai": "2.18.1", "json-schema": "0.4.0", "material-react-table": "3.2.1", @@ -71,7 +71,7 @@ "@emotion/react": "11.14.0", "@iconify/json": "2.2.452", "@monaco-editor/react": "4.7.0", - "@tanstack/react-query": "5.91.2", + "@tanstack/react-query": "5.91.3", "@tanstack/react-router": "1.167.5", "@tanstack/react-router-devtools": "1.166.9", "@tanstack/router-plugin": "1.166.14", diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index e2590179b7..246a888056 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -5,7 +5,7 @@ "mihomo_alpha": "alpha-dd4eb63", "clash_rs": "v0.9.6", "clash_premium": "2023-09-05-gdcc8d87", - "clash_rs_alpha": "0.9.6-alpha+sha.489d5d9" + "clash_rs_alpha": "0.9.6-alpha+sha.b17ba0a" }, "arch_template": { "mihomo": { @@ -69,5 +69,5 @@ "linux-armv7hf": "clash-rs-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2026-03-18T22:23:38.730Z" + "updated_at": "2026-03-19T22:22:44.922Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index 6823059526..7cbe4214cd 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -80,7 +80,7 @@ "prettier-plugin-ember-template-tag": "2.1.3", "prettier-plugin-tailwindcss": "0.7.2", "prettier-plugin-toml": "2.0.6", - "stylelint": "17.4.0", + "stylelint": "17.5.0", "stylelint-config-html": "1.1.0", "stylelint-config-recess-order": "7.7.0", "stylelint-config-standard": "40.0.0", diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 72826a47fe..3f8c0c07b2 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -95,26 +95,26 @@ importers: specifier: 2.0.6 version: 2.0.6(prettier@3.8.1) stylelint: - specifier: 17.4.0 - version: 17.4.0(typescript@5.9.3) + specifier: 17.5.0 + version: 17.5.0(typescript@5.9.3) stylelint-config-html: specifier: 1.1.0 - version: 1.1.0(postcss-html@1.8.1)(stylelint@17.4.0(typescript@5.9.3)) + version: 1.1.0(postcss-html@1.8.1)(stylelint@17.5.0(typescript@5.9.3)) stylelint-config-recess-order: specifier: 7.7.0 - version: 7.7.0(stylelint-order@8.1.1(stylelint@17.4.0(typescript@5.9.3)))(stylelint@17.4.0(typescript@5.9.3)) + version: 7.7.0(stylelint-order@8.1.1(stylelint@17.5.0(typescript@5.9.3)))(stylelint@17.5.0(typescript@5.9.3)) stylelint-config-standard: specifier: 40.0.0 - version: 40.0.0(stylelint@17.4.0(typescript@5.9.3)) + version: 40.0.0(stylelint@17.5.0(typescript@5.9.3)) stylelint-declaration-block-no-ignored-properties: specifier: 3.0.0 - version: 3.0.0(stylelint@17.4.0(typescript@5.9.3)) + version: 3.0.0(stylelint@17.5.0(typescript@5.9.3)) stylelint-order: specifier: 8.1.1 - version: 8.1.1(stylelint@17.4.0(typescript@5.9.3)) + version: 8.1.1(stylelint@17.5.0(typescript@5.9.3)) stylelint-scss: specifier: 7.0.0 - version: 7.0.0(stylelint@17.4.0(typescript@5.9.3)) + version: 7.0.0(stylelint@17.5.0(typescript@5.9.3)) tailwindcss: specifier: 4.2.2 version: 4.2.2 @@ -128,8 +128,8 @@ importers: frontend/interface: dependencies: '@tanstack/react-query': - specifier: 5.91.2 - version: 5.91.2(react@19.2.4) + specifier: 5.91.3 + version: 5.91.3(react@19.2.4) '@tauri-apps/api': specifier: 2.10.1 version: 2.10.1 @@ -261,8 +261,8 @@ importers: specifier: 12.38.0 version: 12.38.0(@emotion/is-prop-valid@1.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) i18next: - specifier: 25.8.19 - version: 25.8.19(typescript@5.9.3) + specifier: 25.8.20 + version: 25.8.20(typescript@5.9.3) jotai: specifier: 2.18.1 version: 2.18.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.4) @@ -301,7 +301,7 @@ importers: version: 8.2.0(e309558cb1df3652b39c2e76ceb9cee4) react-i18next: specifier: 15.7.4 - version: 15.7.4(i18next@25.8.19(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + version: 15.7.4(i18next@25.8.20(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) react-markdown: specifier: 10.1.0 version: 10.1.0(@types/react@19.2.14)(react@19.2.4) @@ -340,8 +340,8 @@ importers: specifier: 4.7.0 version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-query': - specifier: 5.91.2 - version: 5.91.2(react@19.2.4) + specifier: 5.91.3 + version: 5.91.3(react@19.2.4) '@tanstack/react-router': specifier: 1.167.5 version: 1.167.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -500,7 +500,7 @@ importers: version: 6.0.0(react@19.2.4) react-i18next: specifier: 15.7.4 - version: 15.7.4(i18next@25.8.19(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + version: 15.7.4(i18next@25.8.20(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) react-use: specifier: 17.6.0 version: 17.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -594,14 +594,14 @@ importers: specifier: 1.1.1 version: 1.1.1 tar: - specifier: 7.5.11 - version: 7.5.11 + specifier: 7.5.12 + version: 7.5.12 telegram: specifier: 2.26.22 version: 2.26.22 undici: - specifier: 7.24.4 - version: 7.24.4 + specifier: 7.24.5 + version: 7.24.5 yargs: specifier: 18.0.0 version: 18.0.0 @@ -3852,8 +3852,8 @@ packages: '@tanstack/query-core@5.91.2': resolution: {integrity: sha512-Uz2pTgPC1mhqrrSGg18RKCWT/pkduAYtxbcyIyKBhw7dTWjXZIzqmpzO2lBkyWr4hlImQgpu1m1pei3UnkFRWw==} - '@tanstack/react-query@5.91.2': - resolution: {integrity: sha512-GClLPzbM57iFXv+FlvOUL56XVe00PxuTaVEyj1zAObhRiKF008J5vedmaq7O6ehs+VmPHe8+PUQhMuEyv8d9wQ==} + '@tanstack/react-query@5.91.3': + resolution: {integrity: sha512-D8jsCexxS5crZxAeiH6VlLHOUzmHOxeW5c11y8rZu0c34u/cy18hUKQXA/gn1Ila3ZIFzP+Pzv76YnliC0EtZQ==} peerDependencies: react: ^18 || ^19 @@ -4575,6 +4575,10 @@ packages: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -4959,15 +4963,6 @@ packages: typescript: optional: true - cosmiconfig@9.0.0: - resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - cosmiconfig@9.0.1: resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} engines: {node: '>=14'} @@ -5010,6 +5005,10 @@ packages: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -5528,6 +5527,10 @@ packages: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} + get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} @@ -5568,8 +5571,8 @@ packages: resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==} engines: {node: '>=18'} - globby@16.1.0: - resolution: {integrity: sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==} + globby@16.1.1: + resolution: {integrity: sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==} engines: {node: '>=20'} globjoin@0.1.4: @@ -5661,8 +5664,8 @@ packages: hyphenate-style-name@1.1.0: resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} - i18next@25.8.19: - resolution: {integrity: sha512-Szzho7sXdv9Do6TvZIyYu+H+94xCrh60cq01DKcYH/gDjpcHimrQApUEQycxw37U7guwbTEJ07CWScGGbgs96w==} + i18next@25.8.20: + resolution: {integrity: sha512-xjo9+lbX/P1tQt3xpO2rfJiBppNfUnNIPKgCvNsTKsvTOCro1Qr/geXVg1N47j5ScOSaXAPq8ET93raK3Rr06A==} peerDependencies: typescript: ^5 peerDependenciesMeta: @@ -6169,6 +6172,9 @@ packages: mdn-data@2.25.0: resolution: {integrity: sha512-T2LPsjgUE/tgMmRXREVmwsux89DwWfNjiynOeXuLd2mX6jphGQ2YE3Ukz7LQ2VOFKiVZU/Ee1GqzHiipZCjymw==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -6177,8 +6183,8 @@ packages: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} - meow@14.0.0: - resolution: {integrity: sha512-JhC3R1f6dbspVtmF3vKjAWz1EVIvwFrGGPLSdU6rK79xBwHWTuHoLnRX/t1/zHS1Ch1Y2UtIrih7DAHuH9JFJA==} + meow@14.1.0: + resolution: {integrity: sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==} engines: {node: '>=20'} merge2@1.4.1: @@ -7339,6 +7345,10 @@ packages: resolution: {integrity: sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==} engines: {node: '>=20'} + string-width@8.2.0: + resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + engines: {node: '>=20'} + stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} @@ -7350,6 +7360,10 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -7411,8 +7425,8 @@ packages: peerDependencies: stylelint: ^16.8.2 || ^17.0.0 - stylelint@17.4.0: - resolution: {integrity: sha512-3kQ2/cHv3Zt8OBg+h2B8XCx9evEABQIrv4hh3uXahGz/ZEHrTR80zxBiK2NfXNaSoyBzxO1pjsz1Vhdzwn5XSw==} + stylelint@17.5.0: + resolution: {integrity: sha512-o/NS6zhsPZFmgUm5tXX4pVNg1XDOZSlucLdf2qow/lVn4JIyzZIQ5b3kad1ugqUj3GSIgr2u5lQw7X8rjqw33g==} engines: {node: '>=20.19.0'} hasBin: true @@ -7482,8 +7496,8 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} - tar@7.5.11: - resolution: {integrity: sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==} + tar@7.5.12: + resolution: {integrity: sha512-9TsuLcdhOn4XztcQqhNyq1KOwOOED/3k58JAvtULiYqbO8B/0IBAAIE1hj0Svmm58k27TmcigyDI0deMlgG3uw==} engines: {node: '>=18'} telegram@2.26.22: @@ -7612,8 +7626,8 @@ packages: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} - undici@7.24.4: - resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==} + undici@7.24.5: + resolution: {integrity: sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -11362,7 +11376,7 @@ snapshots: '@tanstack/query-core@5.91.2': {} - '@tanstack/react-query@5.91.2(react@19.2.4)': + '@tanstack/react-query@5.91.3(react@19.2.4)': dependencies: '@tanstack/query-core': 5.91.2 react: 19.2.4 @@ -12201,6 +12215,8 @@ snapshots: ansi-regex@6.0.1: {} + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -12565,15 +12581,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - cosmiconfig@9.0.0(typescript@5.9.3): - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.0 - js-yaml: 4.1.1 - parse-json: 5.2.0 - optionalDependencies: - typescript: 5.9.3 - cosmiconfig@9.0.1(typescript@5.9.3): dependencies: env-paths: 2.2.1 @@ -12622,6 +12629,11 @@ snapshots: mdn-data: 2.12.2 source-map-js: 1.2.1 + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + css-what@6.1.0: {} cssesc@3.0.0: {} @@ -13135,6 +13147,8 @@ snapshots: get-east-asian-width@1.4.0: {} + get-east-asian-width@1.5.0: {} + get-nonce@1.0.1: {} get-tsconfig@4.10.1: @@ -13182,7 +13196,7 @@ snapshots: globals@17.4.0: {} - globby@16.1.0: + globby@16.1.1: dependencies: '@sindresorhus/merge-streams': 4.0.0 fast-glob: 3.3.3 @@ -13301,7 +13315,7 @@ snapshots: hyphenate-style-name@1.1.0: {} - i18next@25.8.19(typescript@5.9.3): + i18next@25.8.20(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.6 optionalDependencies: @@ -13787,11 +13801,13 @@ snapshots: mdn-data@2.25.0: {} + mdn-data@2.27.1: {} + memorystream@0.3.1: {} meow@13.2.0: {} - meow@14.0.0: {} + meow@14.1.0: {} merge2@1.4.1: {} @@ -14530,11 +14546,11 @@ snapshots: dependencies: react: 19.2.4 - react-i18next@15.7.4(i18next@25.8.19(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + react-i18next@15.7.4(i18next@25.8.20(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.3 html-parse-stringify: 3.0.1 - i18next: 25.8.19(typescript@5.9.3) + i18next: 25.8.20(typescript@5.9.3) react: 19.2.4 optionalDependencies: react-dom: 19.2.4(react@19.2.4) @@ -15060,6 +15076,11 @@ snapshots: get-east-asian-width: 1.4.0 strip-ansi: 7.1.0 + string-width@8.2.0: + dependencies: + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 + stringify-entities@4.0.4: dependencies: character-entities-html4: 2.1.0 @@ -15073,6 +15094,10 @@ snapshots: dependencies: ansi-regex: 6.0.1 + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + strip-bom@3.0.0: {} strip-json-comments@3.1.1: {} @@ -15087,36 +15112,36 @@ snapshots: dependencies: inline-style-parser: 0.2.3 - stylelint-config-html@1.1.0(postcss-html@1.8.1)(stylelint@17.4.0(typescript@5.9.3)): + stylelint-config-html@1.1.0(postcss-html@1.8.1)(stylelint@17.5.0(typescript@5.9.3)): dependencies: postcss-html: 1.8.1 - stylelint: 17.4.0(typescript@5.9.3) + stylelint: 17.5.0(typescript@5.9.3) - stylelint-config-recess-order@7.7.0(stylelint-order@8.1.1(stylelint@17.4.0(typescript@5.9.3)))(stylelint@17.4.0(typescript@5.9.3)): + stylelint-config-recess-order@7.7.0(stylelint-order@8.1.1(stylelint@17.5.0(typescript@5.9.3)))(stylelint@17.5.0(typescript@5.9.3)): dependencies: - stylelint: 17.4.0(typescript@5.9.3) - stylelint-order: 8.1.1(stylelint@17.4.0(typescript@5.9.3)) + stylelint: 17.5.0(typescript@5.9.3) + stylelint-order: 8.1.1(stylelint@17.5.0(typescript@5.9.3)) - stylelint-config-recommended@18.0.0(stylelint@17.4.0(typescript@5.9.3)): + stylelint-config-recommended@18.0.0(stylelint@17.5.0(typescript@5.9.3)): dependencies: - stylelint: 17.4.0(typescript@5.9.3) + stylelint: 17.5.0(typescript@5.9.3) - stylelint-config-standard@40.0.0(stylelint@17.4.0(typescript@5.9.3)): + stylelint-config-standard@40.0.0(stylelint@17.5.0(typescript@5.9.3)): dependencies: - stylelint: 17.4.0(typescript@5.9.3) - stylelint-config-recommended: 18.0.0(stylelint@17.4.0(typescript@5.9.3)) + stylelint: 17.5.0(typescript@5.9.3) + stylelint-config-recommended: 18.0.0(stylelint@17.5.0(typescript@5.9.3)) - stylelint-declaration-block-no-ignored-properties@3.0.0(stylelint@17.4.0(typescript@5.9.3)): + stylelint-declaration-block-no-ignored-properties@3.0.0(stylelint@17.5.0(typescript@5.9.3)): dependencies: - stylelint: 17.4.0(typescript@5.9.3) + stylelint: 17.5.0(typescript@5.9.3) - stylelint-order@8.1.1(stylelint@17.4.0(typescript@5.9.3)): + stylelint-order@8.1.1(stylelint@17.5.0(typescript@5.9.3)): dependencies: postcss: 8.5.8 postcss-sorting: 10.0.0(postcss@8.5.8) - stylelint: 17.4.0(typescript@5.9.3) + stylelint: 17.5.0(typescript@5.9.3) - stylelint-scss@7.0.0(stylelint@17.4.0(typescript@5.9.3)): + stylelint-scss@7.0.0(stylelint@17.5.0(typescript@5.9.3)): dependencies: css-tree: 3.1.0 is-plain-object: 5.0.0 @@ -15126,9 +15151,9 @@ snapshots: postcss-resolve-nested-selector: 0.1.6 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - stylelint: 17.4.0(typescript@5.9.3) + stylelint: 17.5.0(typescript@5.9.3) - stylelint@17.4.0(typescript@5.9.3): + stylelint@17.5.0(typescript@5.9.3): dependencies: '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) @@ -15138,15 +15163,15 @@ snapshots: '@csstools/selector-resolve-nested': 4.0.0(postcss-selector-parser@7.1.1) '@csstools/selector-specificity': 6.0.0(postcss-selector-parser@7.1.1) colord: 2.9.3 - cosmiconfig: 9.0.0(typescript@5.9.3) + cosmiconfig: 9.0.1(typescript@5.9.3) css-functions-list: 3.3.3 - css-tree: 3.1.0 + css-tree: 3.2.1 debug: 4.4.3 fast-glob: 3.3.3 fastest-levenshtein: 1.0.16 file-entry-cache: 11.1.2 global-modules: 2.0.0 - globby: 16.1.0 + globby: 16.1.1 globjoin: 0.1.4 html-tags: 5.1.0 ignore: 7.0.5 @@ -15154,7 +15179,7 @@ snapshots: imurmurhash: 0.1.4 is-plain-object: 5.0.0 mathml-tag-names: 4.0.0 - meow: 14.0.0 + meow: 14.1.0 micromatch: 4.0.8 normalize-path: 3.0.0 picocolors: 1.1.1 @@ -15162,7 +15187,7 @@ snapshots: postcss-safe-parser: 7.0.1(postcss@8.5.8) postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - string-width: 8.1.1 + string-width: 8.2.0 supports-hyperlinks: 4.4.0 svg-tags: 1.0.0 table: 6.9.0 @@ -15235,7 +15260,7 @@ snapshots: tapable@2.3.0: {} - tar@7.5.11: + tar@7.5.12: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 @@ -15375,7 +15400,7 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - undici@7.24.4: {} + undici@7.24.5: {} unicode-canonical-property-names-ecmascript@2.0.1: {} diff --git a/clash-nyanpasu/scripts/package.json b/clash-nyanpasu/scripts/package.json index ba869d498c..2a0d6fb298 100644 --- a/clash-nyanpasu/scripts/package.json +++ b/clash-nyanpasu/scripts/package.json @@ -22,9 +22,9 @@ "fs-extra": "11.3.4", "octokit": "5.0.5", "picocolors": "1.1.1", - "tar": "7.5.11", + "tar": "7.5.12", "telegram": "2.26.22", - "undici": "7.24.4", + "undici": "7.24.5", "yargs": "18.0.0" } } diff --git a/hysteria/app/cmd/server.go b/hysteria/app/cmd/server.go index 301f706a34..79417b135a 100644 --- a/hysteria/app/cmd/server.go +++ b/hysteria/app/cmd/server.go @@ -240,6 +240,7 @@ type serverConfigMasqueradeFile struct { type serverConfigMasqueradeProxy struct { URL string `mapstructure:"url"` RewriteHost bool `mapstructure:"rewriteHost"` + XForwarded bool `mapstructure:"xForwarded"` Insecure bool `mapstructure:"insecure"` } @@ -852,6 +853,9 @@ func (c *serverConfig) fillMasqHandler(hyConfig *server.Config) error { if !c.Masquerade.Proxy.RewriteHost { r.Out.Host = r.In.Host } + if c.Masquerade.Proxy.XForwarded { + r.SetXForwarded() + } }, Transport: transport, ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) { diff --git a/hysteria/app/cmd/server_test.go b/hysteria/app/cmd/server_test.go index b2e3a77d32..c610c7b60c 100644 --- a/hysteria/app/cmd/server_test.go +++ b/hysteria/app/cmd/server_test.go @@ -172,6 +172,7 @@ func TestServerConfig(t *testing.T) { Proxy: serverConfigMasqueradeProxy{ URL: "https://some.site.net", RewriteHost: true, + XForwarded: true, Insecure: true, }, String: serverConfigMasqueradeString{ diff --git a/hysteria/app/cmd/server_test.yaml b/hysteria/app/cmd/server_test.yaml index 0aa9e3ffc1..e04ad48074 100644 --- a/hysteria/app/cmd/server_test.yaml +++ b/hysteria/app/cmd/server_test.yaml @@ -133,6 +133,7 @@ masquerade: proxy: url: https://some.site.net rewriteHost: true + xForwarded: true insecure: true string: content: aint nothin here diff --git a/lede/package/kernel/mac80211/Makefile b/lede/package/kernel/mac80211/Makefile index c2594b7c2d..b2258874db 100644 --- a/lede/package/kernel/mac80211/Makefile +++ b/lede/package/kernel/mac80211/Makefile @@ -10,15 +10,24 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mac80211 +ifdef CONFIG_LINUX_6_12 +PKG_VERSION:=6.18.7 +PKG_HASH:=623e5cf46ca8e81fd413f4f465e2580a0143e24929f9c22ce1ba7c34f2872989 +PKG_SOURCE_URL:=https://github.com/openwrt/backports/releases/download/backports-v$(PKG_VERSION) +PKG_SOURCE:=backports-$(PKG_VERSION).tar.zst +PATCH_DIR:=./patches-6.18 +else PKG_VERSION:=6.6.15 +PKG_HASH:=3bbc461121134fda9089c084a5eed577d05e7837a157edf9a3797937172a3ece +PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources/ +PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz +PATCH_DIR:=./patches +endif + PKG_RELEASE:=1 PKG_LICENSE:=GPL-2.0-only PKG_LICENSE_FILES:=COPYING -PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources/ -PKG_HASH:=3bbc461121134fda9089c084a5eed577d05e7837a157edf9a3797937172a3ece - -PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(if $(BUILD_VARIANT),$(PKG_NAME)-$(BUILD_VARIANT)/)backports-$(PKG_VERSION) PKG_BUILD_PARALLEL:=1 @@ -333,9 +342,7 @@ endif ifeq ($(strip $(CONFIG_EXTERNAL_KERNEL_TREE)),"") ifeq ($(strip $(CONFIG_KERNEL_GIT_CLONE_URI)),"") define Build/Configure - cmp $(PKG_BUILD_DIR)/include/linux/ath9k_platform.h $(LINUX_DIR)/include/linux/ath9k_platform.h cmp $(PKG_BUILD_DIR)/include/linux/ath5k_platform.h $(LINUX_DIR)/include/linux/ath5k_platform.h - cmp $(PKG_BUILD_DIR)/include/linux/rt2x00_platform.h $(LINUX_DIR)/include/linux/rt2x00_platform.h endef endif endif diff --git a/lede/package/kernel/mac80211/patches-6.18/ath/070-ath_common_config.patch b/lede/package/kernel/mac80211/patches-6.18/ath/070-ath_common_config.patch new file mode 100644 index 0000000000..3d0b4d6b1a --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath/070-ath_common_config.patch @@ -0,0 +1,10 @@ +--- a/drivers/net/wireless/ath/Kconfig ++++ b/drivers/net/wireless/ath/Kconfig +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: ISC + config ATH_COMMON +- tristate ++ tristate "ath.ko" + depends on m + + config WLAN_VENDOR_ATH diff --git a/lede/package/kernel/mac80211/patches-6.18/ath/400-ath_move_debug_code.patch b/lede/package/kernel/mac80211/patches-6.18/ath/400-ath_move_debug_code.patch new file mode 100644 index 0000000000..23b7340e25 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath/400-ath_move_debug_code.patch @@ -0,0 +1,31 @@ +--- a/drivers/net/wireless/ath/Makefile ++++ b/drivers/net/wireless/ath/Makefile +@@ -16,10 +16,10 @@ ath-objs := main.o \ + regd.o \ + hw.o \ + key.o \ ++ debug.o \ + dfs_pattern_detector.o \ + dfs_pri_detector.o + +-ath-$(CPTCFG_ATH_DEBUG) += debug.o + ath-$(CPTCFG_ATH_TRACEPOINTS) += trace.o + + CFLAGS_trace.o := -I$(src) +--- a/drivers/net/wireless/ath/ath.h ++++ b/drivers/net/wireless/ath/ath.h +@@ -321,14 +321,7 @@ void _ath_dbg(struct ath_common *common, + #endif /* CPTCFG_ATH_DEBUG */ + + /** Returns string describing opmode, or NULL if unknown mode. */ +-#ifdef CPTCFG_ATH_DEBUG + const char *ath_opmode_to_string(enum nl80211_iftype opmode); +-#else +-static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode) +-{ +- return "UNKNOWN"; +-} +-#endif + + extern const char *ath_bus_type_strings[]; + static inline const char *ath_bus_type_to_string(enum ath_bus_type bustype) diff --git a/lede/package/kernel/mac80211/patches-6.18/ath/402-ath_regd_optional.patch b/lede/package/kernel/mac80211/patches-6.18/ath/402-ath_regd_optional.patch new file mode 100644 index 0000000000..1d7ccdcaea --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath/402-ath_regd_optional.patch @@ -0,0 +1,92 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -24,6 +24,7 @@ + #include "regd_common.h" + + static int __ath_regd_init(struct ath_regulatory *reg); ++static struct reg_dmn_pair_mapping *ath_get_regpair(int regdmn); + + /* + * This is a set of common rules used by our world regulatory domains. +@@ -116,6 +117,9 @@ static const struct ieee80211_regdomain + + static bool dynamic_country_user_possible(struct ath_regulatory *reg) + { ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return true; ++ + if (IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) + return true; + +@@ -188,6 +192,8 @@ static bool dynamic_country_user_possibl + + static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg) + { ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return true; + if (!IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_REG_HINTS)) + return false; + if (!dynamic_country_user_possible(reg)) +@@ -345,6 +351,9 @@ ath_reg_apply_beaconing_flags(struct wip + struct ieee80211_channel *ch; + unsigned int i; + ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return; ++ + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!wiphy->bands[band]) + continue; +@@ -379,6 +388,9 @@ ath_reg_apply_ir_flags(struct wiphy *wip + { + struct ieee80211_supported_band *sband; + ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return; ++ + sband = wiphy->bands[NL80211_BAND_2GHZ]; + if (!sband) + return; +@@ -408,6 +420,9 @@ static void ath_reg_apply_radar_flags(st + struct ieee80211_channel *ch; + unsigned int i; + ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return; ++ + if (!wiphy->bands[NL80211_BAND_5GHZ]) + return; + +@@ -640,6 +655,10 @@ ath_regd_init_wiphy(struct ath_regulator + const struct ieee80211_regdomain *regd; + + wiphy->reg_notifier = reg_notifier; ++ ++ if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) ++ return 0; ++ + wiphy->regulatory_flags |= REGULATORY_STRICT_REG | + REGULATORY_CUSTOM_REG; + +--- a/drivers/net/wireless/ath/Kconfig ++++ b/drivers/net/wireless/ath/Kconfig +@@ -24,6 +24,9 @@ config WLAN_VENDOR_ATH + + if WLAN_VENDOR_ATH + ++config ATH_USER_REGD ++ bool "Do not enforce EEPROM regulatory restrictions" ++ + config ATH_DEBUG + bool "Atheros wireless debugging" + help +--- a/local-symbols ++++ b/local-symbols +@@ -91,6 +91,7 @@ ADM8211= + ATH_COMMON= + WLAN_VENDOR_ATH= + ATH_DEBUG= ++ATH_USER_REGD= + ATH_TRACEPOINTS= + ATH_REG_DYNAMIC_USER_REG_HINTS= + ATH_REG_DYNAMIC_USER_CERT_TESTING= diff --git a/lede/package/kernel/mac80211/patches-6.18/ath/403-world_regd_fixup.patch b/lede/package/kernel/mac80211/patches-6.18/ath/403-world_regd_fixup.patch new file mode 100644 index 0000000000..ed616b7532 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath/403-world_regd_fixup.patch @@ -0,0 +1,84 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -44,7 +44,8 @@ static struct reg_dmn_pair_mapping *ath_ + NL80211_RRF_NO_OFDM) + + /* We allow IBSS on these on a case by case basis by regulatory domain */ +-#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ ++#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\ ++ REG_RULE(5260-10, 5350+10, 80, 0, 30,\ + NL80211_RRF_NO_IR) + #define ATH_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ + NL80211_RRF_NO_IR) +@@ -62,57 +63,56 @@ static struct reg_dmn_pair_mapping *ath_ + #define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \ + ATH_5GHZ_5725_5850 + ++#define REGD_RULES(...) \ ++ .reg_rules = { __VA_ARGS__ }, \ ++ .n_reg_rules = ARRAY_SIZE(((struct ieee80211_reg_rule[]) { __VA_ARGS__ })) ++ + /* Can be used for: + * 0x60, 0x61, 0x62 */ + static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = { +- .n_reg_rules = 5, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH_2GHZ_ALL, + ATH_5GHZ_ALL, +- } ++ ) + }; + + /* Can be used by 0x63 and 0x65 */ + static const struct ieee80211_regdomain ath_world_regdom_63_65 = { +- .n_reg_rules = 4, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH_2GHZ_CH01_11, + ATH_2GHZ_CH12_13, + ATH_5GHZ_NO_MIDBAND, +- } ++ ) + }; + + /* Can be used by 0x64 only */ + static const struct ieee80211_regdomain ath_world_regdom_64 = { +- .n_reg_rules = 3, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH_2GHZ_CH01_11, + ATH_5GHZ_NO_MIDBAND, +- } ++ ) + }; + + /* Can be used by 0x66 and 0x69 */ + static const struct ieee80211_regdomain ath_world_regdom_66_69 = { +- .n_reg_rules = 3, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH_2GHZ_CH01_11, + ATH_5GHZ_ALL, +- } ++ ) + }; + + /* Can be used by 0x67, 0x68, 0x6A and 0x6C */ + static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { +- .n_reg_rules = 4, + .alpha2 = "99", +- .reg_rules = { ++ REGD_RULES( + ATH_2GHZ_CH01_11, + ATH_2GHZ_CH12_13, + ATH_5GHZ_ALL, +- } ++ ) + }; + + static bool dynamic_country_user_possible(struct ath_regulatory *reg) diff --git a/lede/package/kernel/mac80211/patches-6.18/ath/404-regd_no_assoc_hints.patch b/lede/package/kernel/mac80211/patches-6.18/ath/404-regd_no_assoc_hints.patch new file mode 100644 index 0000000000..57c9c7b0d9 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath/404-regd_no_assoc_hints.patch @@ -0,0 +1,19 @@ +--- a/net/wireless/reg.c ++++ b/net/wireless/reg.c +@@ -3335,6 +3335,8 @@ void regulatory_hint_country_ie(struct w + enum environment_cap env = ENVIRON_ANY; + struct regulatory_request *request = NULL, *lr; + ++ return; ++ + /* IE len must be evenly divisible by 2 */ + if (country_ie_len & 0x01) + return; +@@ -3584,6 +3586,7 @@ static bool is_wiphy_all_set_reg_flag(en + + void regulatory_hint_disconnect(void) + { ++ return; + /* Restore of regulatory settings is not required when wiphy(s) + * ignore IE from connected access point but clearance of beacon hints + * is required when wiphy(s) supports beacon hints. diff --git a/lede/package/kernel/mac80211/patches-6.18/ath/405-ath_regd_us.patch b/lede/package/kernel/mac80211/patches-6.18/ath/405-ath_regd_us.patch new file mode 100644 index 0000000000..6723721a47 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath/405-ath_regd_us.patch @@ -0,0 +1,26 @@ +--- a/drivers/net/wireless/ath/regd_common.h ++++ b/drivers/net/wireless/ath/regd_common.h +@@ -32,6 +32,7 @@ enum EnumRd { + FCC2_WORLD = 0x21, + FCC2_ETSIC = 0x22, + FCC6_WORLD = 0x23, ++ FCC3_FCCA_2 = 0x2A, + FRANCE_RES = 0x31, + FCC3_FCCA = 0x3A, + FCC3_WORLD = 0x3B, +@@ -173,6 +174,7 @@ static struct reg_dmn_pair_mapping regDo + {FCC2_WORLD, CTL_FCC, CTL_ETSI}, + {FCC2_ETSIC, CTL_FCC, CTL_ETSI}, + {FCC3_FCCA, CTL_FCC, CTL_FCC}, ++ {FCC3_FCCA_2, CTL_FCC, CTL_FCC}, + {FCC3_WORLD, CTL_FCC, CTL_ETSI}, + {FCC3_ETSIC, CTL_FCC, CTL_ETSI}, + {FCC4_FCCA, CTL_FCC, CTL_FCC}, +@@ -486,6 +488,7 @@ static struct country_code_to_enum_rd al + {CTRY_UAE, NULL1_WORLD, "AE"}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, + {CTRY_UNITED_STATES, FCC3_FCCA, "US"}, ++ {CTRY_UNITED_STATES, FCC3_FCCA_2, "US"}, + {CTRY_UNITED_STATES2, FCC3_FCCA, "US"}, + {CTRY_UNITED_STATES3, FCC3_FCCA, "US"}, + /* This "PS" is for US public safety actually... to support this we diff --git a/lede/package/kernel/mac80211/patches-6.18/ath/406-ath_relax_default_regd.patch b/lede/package/kernel/mac80211/patches-6.18/ath/406-ath_relax_default_regd.patch new file mode 100644 index 0000000000..ee4e461342 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath/406-ath_relax_default_regd.patch @@ -0,0 +1,51 @@ +--- a/drivers/net/wireless/ath/regd.c ++++ b/drivers/net/wireless/ath/regd.c +@@ -115,6 +115,16 @@ static const struct ieee80211_regdomain + ) + }; + ++static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) ++{ ++ return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; ++} ++ ++static bool is_default_regd(struct ath_regulatory *reg) ++{ ++ return ath_regd_get_eepromRD(reg) == CTRY_DEFAULT; ++} ++ + static bool dynamic_country_user_possible(struct ath_regulatory *reg) + { + if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) +@@ -123,6 +133,9 @@ static bool dynamic_country_user_possibl + if (IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) + return true; + ++ if (is_default_regd(reg)) ++ return true; ++ + switch (reg->country_code) { + case CTRY_UNITED_STATES: + case CTRY_JAPAN1: +@@ -208,11 +221,6 @@ static inline bool is_wwr_sku(u16 regd) + (regd == WORLD)); + } + +-static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) +-{ +- return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; +-} +- + bool ath_is_world_regd(struct ath_regulatory *reg) + { + return is_wwr_sku(ath_regd_get_eepromRD(reg)); +@@ -659,6 +667,9 @@ ath_regd_init_wiphy(struct ath_regulator + if (IS_ENABLED(CPTCFG_ATH_USER_REGD)) + return 0; + ++ if (is_default_regd(reg)) ++ return 0; ++ + wiphy->regulatory_flags |= REGULATORY_STRICT_REG | + REGULATORY_CUSTOM_REG; + diff --git a/lede/package/kernel/mac80211/patches-6.18/ath/431-add_platform_eeprom_support_to_ath5k.patch b/lede/package/kernel/mac80211/patches-6.18/ath/431-add_platform_eeprom_support_to_ath5k.patch new file mode 100644 index 0000000000..abadadf856 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath/431-add_platform_eeprom_support_to_ath5k.patch @@ -0,0 +1,56 @@ +--- a/drivers/net/wireless/ath/ath5k/pci.c ++++ b/drivers/net/wireless/ath/ath5k/pci.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include "../ath.h" + #include "ath5k.h" + #include "debug.h" +@@ -73,7 +74,7 @@ static void ath5k_pci_read_cachesize(str + } + + /* +- * Read from eeprom ++ * Read from eeprom or platform_data + */ + static bool + ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data) +@@ -81,6 +82,19 @@ ath5k_pci_eeprom_read(struct ath_common + struct ath5k_hw *ah = common->ah; + u32 status, timeout; + ++ struct ath5k_platform_data *pdata = NULL; ++ ++ if (ah->pdev) ++ pdata = ah->pdev->dev.platform_data; ++ ++ if (pdata && pdata->eeprom_data && pdata->eeprom_data[61] == AR5K_EEPROM_MAGIC_VALUE) { ++ if (offset >= ATH5K_PLAT_EEP_MAX_WORDS) ++ return false; ++ ++ *data = pdata->eeprom_data[offset]; ++ return true; ++ } ++ + /* + * Initialize EEPROM access + */ +@@ -124,6 +138,16 @@ static int ath5k_pci_eeprom_read_mac(str + u16 data; + int octet; + ++ struct ath5k_platform_data *pdata = NULL; ++ ++ if (ah->pdev) ++ pdata = ah->pdev->dev.platform_data; ++ ++ if (pdata && pdata->macaddr) { ++ memcpy(mac, pdata->macaddr, ETH_ALEN); ++ return 0; ++ } ++ + AR5K_EEPROM_READ(0x20, data); + + for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/080-ath10k_thermal_config.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/080-ath10k_thermal_config.patch new file mode 100644 index 0000000000..fbba682877 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/080-ath10k_thermal_config.patch @@ -0,0 +1,47 @@ +--- a/drivers/net/wireless/ath/ath10k/Kconfig ++++ b/drivers/net/wireless/ath/ath10k/Kconfig +@@ -94,6 +94,12 @@ config ATH10K_TRACING + help + Select this to ath10k use tracing infrastructure. + ++config ATH10K_THERMAL ++ bool "Atheros ath10k thermal monitoring support" ++ depends on THERMAL ++ ---help--- ++ Select this to ath10k use hwmon for thermal measurement. ++ + config ATH10K_DFS_CERTIFIED + bool "Atheros DFS support for certified platforms" + depends on ATH10K && CFG80211_CERTIFICATION_ONUS +--- a/drivers/net/wireless/ath/ath10k/Makefile ++++ b/drivers/net/wireless/ath/ath10k/Makefile +@@ -18,7 +18,7 @@ ath10k_core-y += mac.o \ + ath10k_core-$(CPTCFG_ATH10K_SPECTRAL) += spectral.o + ath10k_core-$(CPTCFG_NL80211_TESTMODE) += testmode.o + ath10k_core-$(CPTCFG_ATH10K_TRACING) += trace.o +-ath10k_core-$(CONFIG_THERMAL) += thermal.o ++ath10k_core-$(CPTCFG_ATH10K_THERMAL) += thermal.o + ath10k_core-$(CPTCFG_ATH10K_LEDS) += leds.o + ath10k_core-$(CPTCFG_MAC80211_DEBUGFS) += debugfs_sta.o + ath10k_core-$(CONFIG_PM) += wow.o +--- a/drivers/net/wireless/ath/ath10k/thermal.h ++++ b/drivers/net/wireless/ath/ath10k/thermal.h +@@ -25,7 +25,7 @@ struct ath10k_thermal { + int temperature; + }; + +-#if IS_REACHABLE(CONFIG_THERMAL) ++#if IS_REACHABLE(CPTCFG_ATH10K_THERMAL) + int ath10k_thermal_register(struct ath10k *ar); + void ath10k_thermal_unregister(struct ath10k *ar); + void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature); +--- a/local-symbols ++++ b/local-symbols +@@ -151,6 +151,7 @@ ATH10K_DEBUG= + ATH10K_DEBUGFS= + ATH10K_LEDS= + ATH10K_SPECTRAL= ++ATH10K_THERMAL= + ATH10K_TRACING= + ATH10K_DFS_CERTIFIED= + WCN36XX= diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/921-ath10k_init_devices_synchronously.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/921-ath10k_init_devices_synchronously.patch new file mode 100644 index 0000000000..217901cc00 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/921-ath10k_init_devices_synchronously.patch @@ -0,0 +1,33 @@ +From: Sven Eckelmann +Date: Tue, 18 Nov 2014 12:29:28 +0100 +Subject: [PATCH] ath10k: Don't initialize devices asynchronously + +OpenWrt requires all PHYs to be initialized to create the configuration files +during bootup. ath10k violates this because it delays the creation of the PHY +to a not well defined point in the future. + +Forcing the work to be done immediately works around this problem but may also +delay the boot when firmware images cannot be found. + +Signed-off-by: Sven Eckelmann +--- + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -3583,6 +3583,16 @@ int ath10k_core_register(struct ath10k * + + queue_work(ar->workqueue, &ar->register_work); + ++ /* OpenWrt requires all PHYs to be initialized to create the ++ * configuration files during bootup. ath10k violates this ++ * because it delays the creation of the PHY to a not well defined ++ * point in the future. ++ * ++ * Forcing the work to be done immediately works around this problem ++ * but may also delay the boot when firmware images cannot be found. ++ */ ++ flush_workqueue(ar->workqueue); ++ + return 0; + } + EXPORT_SYMBOL(ath10k_core_register); diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/930-ath10k_add_tpt_led_trigger.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/930-ath10k_add_tpt_led_trigger.patch new file mode 100644 index 0000000000..66883bf13b --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/930-ath10k_add_tpt_led_trigger.patch @@ -0,0 +1,37 @@ +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -9970,6 +9970,21 @@ static int ath10k_mac_init_rd(struct ath + return 0; + } + ++#ifdef CPTCFG_MAC80211_LEDS ++static const struct ieee80211_tpt_blink ath10k_tpt_blink[] = { ++ { .throughput = 0 * 1024, .blink_time = 334 }, ++ { .throughput = 1 * 1024, .blink_time = 260 }, ++ { .throughput = 2 * 1024, .blink_time = 220 }, ++ { .throughput = 5 * 1024, .blink_time = 190 }, ++ { .throughput = 10 * 1024, .blink_time = 170 }, ++ { .throughput = 25 * 1024, .blink_time = 150 }, ++ { .throughput = 54 * 1024, .blink_time = 130 }, ++ { .throughput = 120 * 1024, .blink_time = 110 }, ++ { .throughput = 265 * 1024, .blink_time = 80 }, ++ { .throughput = 586 * 1024, .blink_time = 50 }, ++}; ++#endif ++ + int ath10k_mac_register(struct ath10k *ar) + { + static const u32 cipher_suites[] = { +@@ -10332,6 +10347,12 @@ int ath10k_mac_register(struct ath10k *a + + ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER; + ++#ifdef CPTCFG_MAC80211_LEDS ++ ieee80211_create_tpt_led_trigger(ar->hw, ++ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath10k_tpt_blink, ++ ARRAY_SIZE(ath10k_tpt_blink)); ++#endif ++ + ret = ieee80211_register_hw(ar->hw); + if (ret) { + ath10k_err(ar, "failed to register ieee80211: %d\n", ret); diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/975-ath10k-use-tpt-trigger-by-default.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/975-ath10k-use-tpt-trigger-by-default.patch new file mode 100644 index 0000000000..ce4196689b --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/975-ath10k-use-tpt-trigger-by-default.patch @@ -0,0 +1,51 @@ +From 79c9d7aabae1d1da9eea97d83b61e1517a8a2221 Mon Sep 17 00:00:00 2001 +From: Mathias Kresin +Date: Fri, 22 Jun 2018 18:59:44 +0200 +Subject: [PATCH] ath10k: use tpt LED trigger by default + +Use the tpt LED trigger for each created phy led. Ths way LEDs attached +to the ath10k GPIO pins are indicating the phy status and blink on +traffic. + +Signed-off-by: Mathias Kresin +--- + drivers/net/wireless/ath/ath10k/core.h | 4 ++++ + drivers/net/wireless/ath/ath10k/leds.c | 4 +--- + drivers/net/wireless/ath/ath10k/mac.c | 2 +- + 3 files changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath10k/core.h ++++ b/drivers/net/wireless/ath/ath10k/core.h +@@ -1320,6 +1320,10 @@ struct ath10k { + s32 tx_power_2g_limit; + s32 tx_power_5g_limit; + ++#ifdef CPTCFG_MAC80211_LEDS ++ const char *led_default_trigger; ++#endif ++ + /* must be last */ + u8 drv_priv[] __aligned(sizeof(void *)); + }; +--- a/drivers/net/wireless/ath/ath10k/leds.c ++++ b/drivers/net/wireless/ath/ath10k/leds.c +@@ -69,7 +69,7 @@ int ath10k_leds_register(struct ath10k * + + ar->leds.cdev.name = ar->leds.label; + ar->leds.cdev.brightness_set_blocking = ath10k_leds_set_brightness_blocking; +- ar->leds.cdev.default_trigger = ar->leds.wifi_led.default_trigger; ++ ar->leds.cdev.default_trigger = ar->led_default_trigger; + + ret = led_classdev_register(wiphy_dev(ar->hw->wiphy), &ar->leds.cdev); + if (ret) +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -10348,7 +10348,7 @@ int ath10k_mac_register(struct ath10k *a + ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER; + + #ifdef CPTCFG_MAC80211_LEDS +- ieee80211_create_tpt_led_trigger(ar->hw, ++ ar->led_default_trigger = ieee80211_create_tpt_led_trigger(ar->hw, + IEEE80211_TPT_LEDTRIG_FL_RADIO, ath10k_tpt_blink, + ARRAY_SIZE(ath10k_tpt_blink)); + #endif diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/981-ath10k-adjust-tx-power-reduction-for-US-regulatory-d.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/981-ath10k-adjust-tx-power-reduction-for-US-regulatory-d.patch new file mode 100644 index 0000000000..8fab4c742e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/981-ath10k-adjust-tx-power-reduction-for-US-regulatory-d.patch @@ -0,0 +1,101 @@ +From: Sven Eckelmann +Date: Wed, 28 Nov 2018 16:16:27 +0100 +Subject: ath10k: adjust tx power reduction for US regulatory domain + +FCC allows maximum antenna gain of 6 dBi. 15.247(b)(4): + +> (4) The conducted output power limit +> specified in paragraph (b) of this section +> is based on the use of antennas +> with directional gains that do not exceed +> 6 dBi. Except as shown in paragraph +> (c) of this section, if transmitting +> antennas of directional gain greater +> than 6 dBi are used, the conducted +> output power from the intentional radiator +> shall be reduced below the stated +> values in paragraphs (b)(1), (b)(2), +> and (b)(3) of this section, as appropriate, +> by the amount in dB that the +> directional gain of the antenna exceeds +> 6 dBi. + +https://www.gpo.gov/fdsys/pkg/CFR-2013-title47-vol1/pdf/CFR-2013-title47-vol1-sec15-247.pdf + +Signed-off-by: Sven Eckelmann + +Forwarded: no + +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -1051,6 +1051,40 @@ static inline int ath10k_vdev_delete_syn + return 0; + } + ++static u32 ath10k_get_max_antenna_gain(struct ath10k *ar, ++ u32 ch_max_antenna_gain) ++{ ++ u32 max_antenna_gain; ++ ++ if (ar->dfs_detector && ar->dfs_detector->region == NL80211_DFS_FCC) { ++ /* FCC allows maximum antenna gain of 6 dBi. 15.247(b)(4): ++ * ++ * > (4) The conducted output power limit ++ * > specified in paragraph (b) of this section ++ * > is based on the use of antennas ++ * > with directional gains that do not exceed ++ * > 6 dBi. Except as shown in paragraph ++ * > (c) of this section, if transmitting ++ * > antennas of directional gain greater ++ * > than 6 dBi are used, the conducted ++ * > output power from the intentional radiator ++ * > shall be reduced below the stated ++ * > values in paragraphs (b)(1), (b)(2), ++ * > and (b)(3) of this section, as appropriate, ++ * > by the amount in dB that the ++ * > directional gain of the antenna exceeds ++ * > 6 dBi. ++ * ++ * https://www.gpo.gov/fdsys/pkg/CFR-2013-title47-vol1/pdf/CFR-2013-title47-vol1-sec15-247.pdf ++ */ ++ max_antenna_gain = 6; ++ } else { ++ max_antenna_gain = 0; ++ } ++ ++ return max(ch_max_antenna_gain, max_antenna_gain); ++} ++ + static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) + { + struct cfg80211_chan_def *chandef = NULL; +@@ -1083,7 +1117,8 @@ static int ath10k_monitor_vdev_start(str + arg.channel.min_power = 0; + arg.channel.max_power = channel->max_power * 2; + arg.channel.max_reg_power = channel->max_reg_power * 2; +- arg.channel.max_antenna_gain = channel->max_antenna_gain; ++ arg.channel.max_antenna_gain = ath10k_get_max_antenna_gain(ar, ++ channel->max_antenna_gain); + + reinit_completion(&ar->vdev_setup_done); + reinit_completion(&ar->vdev_delete_done); +@@ -1529,7 +1564,8 @@ static int ath10k_vdev_start_restart(str + arg.channel.min_power = 0; + arg.channel.max_power = chandef->chan->max_power * 2; + arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; +- arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain; ++ arg.channel.max_antenna_gain = ath10k_get_max_antenna_gain(ar, ++ chandef->chan->max_antenna_gain); + + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + arg.ssid = arvif->u.ap.ssid; +@@ -3460,7 +3496,8 @@ static int ath10k_update_channel_list(st + ch->min_power = 0; + ch->max_power = channel->max_power * 2; + ch->max_reg_power = channel->max_reg_power * 2; +- ch->max_antenna_gain = channel->max_antenna_gain; ++ ch->max_antenna_gain = ath10k_get_max_antenna_gain(ar, ++ channel->max_antenna_gain); + ch->reg_class_id = 0; /* FIXME */ + + /* FIXME: why use only legacy modes, why not any diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch new file mode 100644 index 0000000000..5f59ac20ff --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch @@ -0,0 +1,37 @@ +From 22fb5991a44c78ff18ec0082dc90c809356eb893 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 27 Sep 2020 19:23:35 +0200 +Subject: [PATCH 1/2] ath10k: Try to get mac-address from dts + +Most of embedded device that have the ath10k wifi integrated store the +mac-address in nvmem partitions. Try to fetch the mac-address using the +standard 'of_get_mac_address' than in all the check also try to fetch the +address using the nvmem api searching for a defined 'mac-address' cell. +Mac-address defined in the dts have priority than any other address found. + +Tested-on: QCA9984 hw1.0 PCI 10.4 + +Signed-off-by: Ansuel Smith +--- + drivers/net/wireless/ath/ath10k/core.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -3455,6 +3456,8 @@ static int ath10k_core_probe_fw(struct a + + device_get_mac_address(ar->dev, ar->mac_addr); + ++ of_get_mac_address(ar->dev->of_node, ar->mac_addr); ++ + ret = ath10k_core_init_firmware_features(ar); + if (ret) { + ath10k_err(ar, "fatal problem with firmware features: %d\n", diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/988-ath10k-always-use-mac80211-loss-detection.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/988-ath10k-always-use-mac80211-loss-detection.patch new file mode 100644 index 0000000000..eabab8cb81 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/988-ath10k-always-use-mac80211-loss-detection.patch @@ -0,0 +1,28 @@ +From f7d6edafe4358e3880a26775cfde4cd5c71ba063 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Wed, 5 Jul 2023 01:30:29 +0200 +Subject: [PATCH] ath10k: always use mac80211 loss detection + +ath10k does not report excessive loss in case of broken block-ack +sessions. The loss is communicated to the host-os, but ath10k does not +trigger a low-ack events by itself. + +The mac80211 framework for loss detection however detects this +circumstance well in case of ath10k. So use it regardless of ath10k's +own loss detection mechanism. + +Signed-off-by: David Bauer +--- + drivers/net/wireless/ath/ath10k/mac.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -10140,7 +10140,6 @@ int ath10k_mac_register(struct ath10k *a + ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); + ieee80211_hw_set(ar->hw, QUEUE_CONTROL); + ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); +- ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); + + if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) + ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/990-ath10k-small-buffers.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/990-ath10k-small-buffers.patch new file mode 100644 index 0000000000..a65e5525c2 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/990-ath10k-small-buffers.patch @@ -0,0 +1,64 @@ +--- a/drivers/net/wireless/ath/ath10k/htt.h ++++ b/drivers/net/wireless/ath/ath10k/htt.h +@@ -236,7 +236,11 @@ enum htt_rx_ring_flags { + }; + + #define HTT_RX_RING_SIZE_MIN 128 ++#ifndef CONFIG_ATH10K_SMALLBUFFERS + #define HTT_RX_RING_SIZE_MAX 2048 ++#else ++#define HTT_RX_RING_SIZE_MAX 512 ++#endif + #define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX + #define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1) + #define HTT_RX_RING_FILL_LEVEL_DUAL_MAC (HTT_RX_RING_SIZE - 1) +--- a/drivers/net/wireless/ath/ath10k/pci.c ++++ b/drivers/net/wireless/ath/ath10k/pci.c +@@ -133,7 +133,11 @@ static const struct ce_attr pci_host_ce_ + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, ++#ifndef CONFIG_ATH10K_SMALLBUFFERS + .dest_nentries = 512, ++#else ++ .dest_nentries = 128, ++#endif + .recv_cb = ath10k_pci_htt_htc_rx_cb, + }, + +@@ -142,7 +146,11 @@ static const struct ce_attr pci_host_ce_ + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, ++#ifndef CONFIG_ATH10K_SMALLBUFFERS + .dest_nentries = 128, ++#else ++ .dest_nentries = 64, ++#endif + .recv_cb = ath10k_pci_htc_rx_cb, + }, + +@@ -169,7 +177,11 @@ static const struct ce_attr pci_host_ce_ + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 512, ++#ifndef CONFIG_ATH10K_SMALLBUFFERS + .dest_nentries = 512, ++#else ++ .dest_nentries = 128, ++#endif + .recv_cb = ath10k_pci_htt_rx_cb, + }, + +@@ -194,7 +206,11 @@ static const struct ce_attr pci_host_ce_ + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, ++#ifndef CONFIG_ATH10K_SMALLBUFFERS + .dest_nentries = 128, ++#else ++ .dest_nentries = 96, ++#endif + .recv_cb = ath10k_pci_pktlog_rx_cb, + }, + diff --git a/lede/package/kernel/mac80211/patches-6.18/ath10k/991-ath10k-support-flush_sta-method.patch b/lede/package/kernel/mac80211/patches-6.18/ath10k/991-ath10k-support-flush_sta-method.patch new file mode 100644 index 0000000000..1d368a1114 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath10k/991-ath10k-support-flush_sta-method.patch @@ -0,0 +1,70 @@ +From: Zhi-Jun You +Date: Wed, 6 Aug 2025 15:00:05 +0800 +Subject: [RFC PATCH] wifi: ath10k: support flush_sta method + + +When a STA is marked as no longer authorized, if the driver doesn't +implement flush_sta(), mac80211 calls ieee80211_flush_queues() to +flush hardware queues to avoid sending unencrypted frames. + +This has became a problem for ath10k because ieee80211_flush_queues() +will stop all traffic and call ath10k_flush, which waits until the +whole HW queue is empty. In a busy environment this will trigger a +timeout warning and stalls other STAs. + +Fix this by implementing flush_sta method using WMI command to flush +frames of a specific STA. +Flushed frames will be marked as discard in tx complete indication. + +ops->flush_sta will be set to NULL if htt.disable_tx_comp is set to +true. + +Tested-on: QCA9984 hw1.0 PCI 10.4-3.9.0.2-00157 + +Signed-off-by: Zhi-Jun You +Tested-by: Florian Maurer +--- + drivers/net/wireless/ath/ath10k/mac.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/net/wireless/ath/ath10k/mac.c ++++ b/drivers/net/wireless/ath/ath10k/mac.c +@@ -8180,6 +8180,20 @@ static void ath10k_flush(struct ieee8021 + mutex_unlock(&ar->conf_mutex); + } + ++static void ath10k_mac_op_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) ++{ ++ struct ath10k_vif *arvif = (void *)vif->drv_priv; ++ struct ath10k *ar = hw->priv; ++ u32 bitmap = 0xFFFFFFFF; ++ int ret = 0; ++ ++ ret = ath10k_wmi_peer_flush(ar, arvif->vdev_id, sta->addr, bitmap); ++ if (ret) ++ ath10k_warn(ar, "failed to flush sta (sta %pM)\n", ++ sta->addr); ++} ++ + /* TODO: Implement this function properly + * For now it is needed to reply to Probe Requests in IBSS mode. + * Probably we need this information from FW. +@@ -9532,6 +9546,7 @@ static const struct ieee80211_ops ath10k + .set_rts_threshold = ath10k_set_rts_threshold, + .set_frag_threshold = ath10k_mac_op_set_frag_threshold, + .flush = ath10k_flush, ++ .flush_sta = ath10k_mac_op_flush_sta, + .tx_last_beacon = ath10k_tx_last_beacon, + .set_antenna = ath10k_set_antenna, + .get_antenna = ath10k_get_antenna, +@@ -10353,6 +10368,9 @@ int ath10k_mac_register(struct ath10k *a + if (!ar->hw_params.hw_ops->set_coverage_class) + ar->ops->set_coverage_class = NULL; + ++ if (ar->htt.disable_tx_comp) ++ ar->ops->flush_sta = NULL; ++ + ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, + ath10k_reg_notifier); + if (ret) { diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/100-wifi-ath11k-use-unique-QRTR-instance-ID.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/100-wifi-ath11k-use-unique-QRTR-instance-ID.patch new file mode 100644 index 0000000000..87f8000ec6 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/100-wifi-ath11k-use-unique-QRTR-instance-ID.patch @@ -0,0 +1,164 @@ +From 534a5f99d589cfa6b244b4433c192b6a278a67ff Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sat, 5 Nov 2022 20:15:40 +0100 +Subject: [PATCH] wifi: ath11k: use unique QRTR instance ID + +Currently, trying to use AHB + PCI/MHI cards or multiple PCI/MHI cards +will cause a clash in the QRTR instance node ID and prevent the driver +from talking via QMI to the card and thus initializing it with: +[ 9.836329] ath11k c000000.wifi: host capability request failed: 1 90 +[ 9.842047] ath11k c000000.wifi: failed to send qmi host cap: -22 + +So, in order to allow for this combination of cards, especially AHB + PCI +cards like IPQ8074 + QCN9074 (Used by me and tested on) set the desired +QRTR instance ID offset by calculating a unique one based on PCI domain +and bus ID-s and writing it to bits 7-0 of BHI_ERRDBG2 MHI register by +using the SBL state callback that is added as part of the series. +We also have to make sure that new QRTR offset is added on top of the +default QRTR instance ID-s that are currently used in the driver. + +This finally allows using AHB + PCI or multiple PCI cards on the same +system. + +Since this is not supported on QCA6390 and like, its limited to QCN9074 +which is known to support changing QRTR instance ID. + +Before: +root@OpenWrt:/# qrtr-lookup + Service Version Instance Node Port + 1054 1 0 7 1 + 69 1 2 7 3 ATH10k WLAN firmware service + +After: +root@OpenWrt:/# qrtr-lookup + Service Version Instance Node Port + 1054 1 0 7 1 + 69 1 2 7 3 ATH10k WLAN firmware service + 15 1 0 8 1 Test service + 69 1 8 8 2 ATH10k WLAN firmware service + +Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1 +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Robert Marko +--- + drivers/net/wireless/ath/ath11k/mhi.c | 49 ++++++++++++++++++--------- + drivers/net/wireless/ath/ath11k/mhi.h | 3 ++ + drivers/net/wireless/ath/ath11k/pci.c | 9 ++++- + 3 files changed, 44 insertions(+), 17 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/mhi.c ++++ b/drivers/net/wireless/ath/ath11k/mhi.c +@@ -239,6 +239,34 @@ static void ath11k_mhi_op_runtime_put(st + { + } + ++static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, ++ void __iomem *addr, ++ u32 *out) ++{ ++ *out = readl(addr); ++ ++ return 0; ++} ++ ++static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl, ++ void __iomem *addr, ++ u32 val) ++{ ++ writel(val, addr); ++} ++ ++static void ath11k_mhi_qrtr_instance_set(struct mhi_controller *mhi_cntrl) ++{ ++ struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev); ++ ++ if (ab->hw_rev == ATH11K_HW_QCN9074_HW10) { ++ ath11k_mhi_op_write_reg(mhi_cntrl, ++ mhi_cntrl->bhi + BHI_ERRDBG2, ++ FIELD_PREP(QRTR_INSTANCE_MASK, ++ ab->qmi.service_ins_id - ab->hw_params.qmi_service_ins_id)); ++ } ++} ++ + static char *ath11k_mhi_op_callback_to_str(enum mhi_callback reason) + { + switch (reason) { +@@ -260,6 +288,8 @@ static char *ath11k_mhi_op_callback_to_s + return "MHI_CB_FATAL_ERROR"; + case MHI_CB_BW_REQ: + return "MHI_CB_BW_REQ"; ++ case MHI_CB_EE_SBL_MODE: ++ return "MHI_CB_EE_SBL_MODE"; + default: + return "UNKNOWN"; + } +@@ -290,6 +320,9 @@ static void ath11k_mhi_op_status_cb(stru + queue_work(ab->workqueue_aux, &ab->reset_work); + + break; ++ case MHI_CB_EE_SBL_MODE: ++ ath11k_mhi_qrtr_instance_set(mhi_cntrl); ++ break; + default: + break; + } +@@ -297,22 +330,6 @@ static void ath11k_mhi_op_status_cb(stru + ab_pci->mhi_pre_cb = cb; + } + +-static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, +- void __iomem *addr, +- u32 *out) +-{ +- *out = readl(addr); +- +- return 0; +-} +- +-static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl, +- void __iomem *addr, +- u32 val) +-{ +- writel(val, addr); +-} +- + static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl) + { + struct device_node *np; +--- a/drivers/net/wireless/ath/ath11k/mhi.h ++++ b/drivers/net/wireless/ath/ath11k/mhi.h +@@ -17,6 +17,9 @@ + #define MHICTRL 0x38 + #define MHICTRL_RESET_MASK 0x2 + ++#define BHI_ERRDBG2 0x38 ++#define QRTR_INSTANCE_MASK GENMASK(7, 0) ++ + int ath11k_mhi_start(struct ath11k_pci *ar_pci); + void ath11k_mhi_stop(struct ath11k_pci *ar_pci, bool is_suspend); + int ath11k_mhi_register(struct ath11k_pci *ar_pci); +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -394,13 +394,20 @@ static void ath11k_pci_sw_reset(struct a + static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) + { + struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; ++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ++ struct pci_bus *bus = ab_pci->pdev->bus; + + cfg->tgt_ce = ab->hw_params.target_ce_config; + cfg->tgt_ce_len = ab->hw_params.target_ce_count; + + cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; + cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; +- ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; ++ ++ if (ab->hw_rev == ATH11K_HW_QCN9074_HW10) { ++ ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id + ++ (((pci_domain_nr(bus) & 0xF) << 4) | (bus->number & 0xF)); ++ } else ++ ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; + + ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, + &cfg->shadow_reg_v2_len); diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/101-wifi-ath11k-fix-wrong-usage-of-resource_size-causing.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/101-wifi-ath11k-fix-wrong-usage-of-resource_size-causing.patch new file mode 100644 index 0000000000..ea3f64cbc4 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/101-wifi-ath11k-fix-wrong-usage-of-resource_size-causing.patch @@ -0,0 +1,69 @@ +From 88f17c87ddc9ee7467acdc322d383e5a443a55ab Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 8 Dec 2025 20:50:47 +0100 +Subject: [PATCH 1/2] wifi: ath11k: fix wrong usage of resource_size() causing + firmware panic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On converting to the of_reserved_mem_region_to_resource() helper with +commit 900730dc4705 ("wifi: ath: Use +of_reserved_mem_region_to_resource() for "memory-region"") a logic error +was introduced in the ath11k_core_coldboot_cal_support() if condition. + +The original code checked for hremote_node presence and skipped +ath11k_core_coldboot_cal_support() in the other switch case but now +everything is driven entirely on the values of the resource struct. + +resource_size() (in this case) is wrongly assumed to return a size of +zero if the passed resource struct is init to zero. This is not the case +as a resource struct should be always init with correct values (or at +best set the end value to -1 to signal it's not configured) +(the return value of resource_size() for a resource struct with start +and end set to zero is 1) + +On top of this, using resource_size() to check if a resource struct is +initialized or not is generally wrong and other measure should be used +instead. + +To better handle this, use the DEFINE_RES macro to initialize the +resource struct and set the IORESOURCE_UNSET flag by default. + +Replace the resource_size() check with checking for the resource struct +flags and check if it's IORESOURCE_UNSET. + +This change effectively restore the original logic and restore correct +loading of the ath11k firmware (restoring correct functionality of +Wi-Fi) + +Cc: stable@vger.kernel.org +Fixes: 900730dc4705 ("wifi: ath: Use of_reserved_mem_region_to_resource() for "memory-region"") +Link: https://lore.kernel.org/all/20251207215359.28895-1-ansuelsmth@gmail.com/T/#m990492684913c5a158ff0e5fc90697d8ad95351b +Cc: Ilpo Järvinen +Signed-off-by: Christian Marangi +--- + drivers/net/wireless/ath/ath11k/qmi.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2039,8 +2039,8 @@ static int ath11k_qmi_alloc_target_mem_c + + static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) + { ++ struct resource res = DEFINE_RES_NAMED(0, 0, NULL, IORESOURCE_UNSET); + struct device *dev = ab->dev; +- struct resource res = {}; + u32 host_ddr_sz; + int i, idx, ret; + +@@ -2086,7 +2086,7 @@ static int ath11k_qmi_assign_target_mem_ + } + + if (ath11k_core_coldboot_cal_support(ab)) { +- if (resource_size(&res)) { ++ if (res.flags != IORESOURCE_UNSET) { + ab->qmi.target_mem[idx].paddr = + res.start + host_ddr_sz; + ab->qmi.target_mem[idx].iaddr = diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/201-wifi-ath11k-Support-setting-bdf-addr-and-caldb-addr-.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/201-wifi-ath11k-Support-setting-bdf-addr-and-caldb-addr-.patch new file mode 100644 index 0000000000..721b521887 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/201-wifi-ath11k-Support-setting-bdf-addr-and-caldb-addr-.patch @@ -0,0 +1,62 @@ +From 824dde8652815aa67b4e2bf2d8a9455a8ef82b8f Mon Sep 17 00:00:00 2001 +From: Ziyang Huang +Date: Thu, 29 Jun 2023 06:12:45 +0000 +Subject: [PATCH] wifi: ath11k: Support setting bdf-addr and caldb-addr via DT + +Signed-off-by: Ziyang Huang +--- + drivers/net/wireless/ath/ath11k/qmi.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2042,6 +2042,7 @@ static int ath11k_qmi_assign_target_mem_ + struct resource res = DEFINE_RES_NAMED(0, 0, NULL, IORESOURCE_UNSET); + struct device *dev = ab->dev; + u32 host_ddr_sz; ++ u32 addr; + int i, idx, ret; + + for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { +@@ -2073,7 +2074,9 @@ static int ath11k_qmi_assign_target_mem_ + idx++; + break; + case BDF_MEM_REGION_TYPE: +- ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr; ++ if (of_property_read_u32(dev->of_node, "qcom,bdf-addr", &addr)) ++ addr = ab->hw_params.bdf_addr; ++ ab->qmi.target_mem[idx].paddr = addr; + ab->qmi.target_mem[idx].iaddr = NULL; + ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; + ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; +@@ -2095,8 +2098,9 @@ static int ath11k_qmi_assign_target_mem_ + if (!ab->qmi.target_mem[idx].iaddr) + return -EIO; + } else { +- ab->qmi.target_mem[idx].paddr = +- ATH11K_QMI_CALDB_ADDRESS; ++ if (of_property_read_u32(dev->of_node, "qcom,caldb-addr", &addr)) ++ addr = ATH11K_QMI_CALDB_ADDRESS; ++ ab->qmi.target_mem[idx].paddr = addr; + ab->qmi.target_mem[idx].iaddr = NULL; + } + } else { +@@ -2302,6 +2306,7 @@ static int ath11k_qmi_load_file_target_m + struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; + struct qmi_txn txn; + const u8 *temp = data; ++ u32 addr; + void __iomem *bdf_addr = NULL; + int ret = 0; + u32 remaining = len; +@@ -2313,7 +2318,9 @@ static int ath11k_qmi_load_file_target_m + memset(&resp, 0, sizeof(resp)); + + if (ab->hw_params.fixed_bdf_addr) { +- bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size); ++ if(of_property_read_u32(ab->dev->of_node, "qcom,bdf-addr", &addr)) ++ addr = ab->hw_params.bdf_addr; ++ bdf_addr = ioremap(addr, ab->hw_params.fw.board_size); + if (!bdf_addr) { + ath11k_warn(ab, "qmi ioremap error for bdf_addr\n"); + ret = -EIO; diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/453-ath11k-add-ath11k_mac_op_flush_sta-to-properly-flush.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/453-ath11k-add-ath11k_mac_op_flush_sta-to-properly-flush.patch new file mode 100644 index 0000000000..c198fad1bc --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/453-ath11k-add-ath11k_mac_op_flush_sta-to-properly-flush.patch @@ -0,0 +1,65 @@ +From b5ade0e0e1c1622a85fbfd2c93b41caff479f305 Mon Sep 17 00:00:00 2001 +From: Florian Maurer +Date: Fri, 3 Oct 2025 12:56:13 +0200 +Subject: [PATCH] ath11k: add ath11k_mac_op_flush_sta to properly flush pending + packets + +When a STA is marked as no longer authorized, if the driver doesn't +implement flush_sta(), mac80211 calls ieee80211_flush_queues() to +flush hardware queues to avoid sending unencrypted frames. + +This has became a problem for ath11k because ieee80211_flush_queues() +will stop all traffic and call ath11k_flush, which waits until the +whole HW queue is empty. In a busy environment this will trigger a +timeout warning and stalls other STAs. + +Fix this by implementing flush_sta method using WMI command to flush +frames of a specific STA. +Flushed frames will be marked as discard in tx complete indication. + +warning print "ath11k c000000.wifi: failed to flush transmit queue 0" +was observed on various openwrt devices, and is fixed through this patch. + +Tested-by: Florian Maurer +Tested-by: Flole +Co-developed-by: Benjamin Berg +Signed-off-by: Benjamin Berg +Signed-off-by: Florian Maurer +--- + drivers/net/wireless/ath/ath11k/mac.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -8330,6 +8330,23 @@ static void ath11k_mac_op_flush(struct i + ath11k_mac_flush_tx_complete(ar); + } + ++static void ath11k_mac_op_flush_sta(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) ++{ ++ struct ath11k_vif *arvif = (void *)vif->drv_priv; ++ struct ath11k *ar = hw->priv; ++ struct peer_flush_params params = { ++ .peer_tid_bitmap = 0xFF, ++ .vdev_id = arvif->vdev_id, ++ }; ++ int ret; ++ ++ ret = ath11k_wmi_send_peer_flush_tids_cmd(ar, sta->addr, ¶ms); ++ if (ret) ++ ath11k_warn(ar->ab, "failed to flush sta %pM: %d\n", sta->addr, ret); ++} ++ + static bool + ath11k_mac_has_single_legacy_rate(struct ath11k *ar, + enum nl80211_band band, +@@ -9920,6 +9937,7 @@ static const struct ieee80211_ops ath11k + .set_bitrate_mask = ath11k_mac_op_set_bitrate_mask, + .get_survey = ath11k_mac_op_get_survey, + .flush = ath11k_mac_op_flush, ++ .flush_sta = ath11k_mac_op_flush_sta, + .sta_statistics = ath11k_mac_op_sta_statistics, + CFG80211_TESTMODE_CMD(ath11k_tm_cmd) + diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/900-ath11k-control-thermal-support-via-symbol.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/900-ath11k-control-thermal-support-via-symbol.patch new file mode 100644 index 0000000000..0e5d451f9b --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/900-ath11k-control-thermal-support-via-symbol.patch @@ -0,0 +1,66 @@ +From 703d6551f71e7290619d6effe2a25a64e10538b7 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Thu, 15 Dec 2022 12:20:52 +0100 +Subject: [PATCH] ath11k: control thermal support via symbol + +Currently, thermal support will get built if CONFIG_THERMAL is reachable, +however this is not suitable for OpenWrt as with ALL_KMODS being set to y +ATH11K_THERMAL wont get selected and so hwmon and thermal kmods wont get +pulled in resulting in a build-failure. + +So, to avoid that, lets do what is already done for ath10k and add a +config symbol into backports for enabling thermal support. + +Signed-off-by: Robert Marko +--- + drivers/net/wireless/ath/ath11k/Kconfig | 7 +++++++ + drivers/net/wireless/ath/ath11k/Makefile | 2 +- + drivers/net/wireless/ath/ath11k/thermal.h | 2 +- + local-symbols | 1 + + 4 files changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/Kconfig ++++ b/drivers/net/wireless/ath/ath11k/Kconfig +@@ -62,3 +62,10 @@ config ATH11K_SPECTRAL + Enable ath11k spectral scan support + + Say Y to enable access to the FFT/spectral data via debugfs. ++ ++config ATH11K_THERMAL ++ bool "ath11k thermal sensors and throttling support" ++ depends on ATH11K ++ depends on THERMAL ++ help ++ Enable ath11k thermal sensors and throttling support. +--- a/drivers/net/wireless/ath/ath11k/Makefile ++++ b/drivers/net/wireless/ath/ath11k/Makefile +@@ -24,7 +24,7 @@ ath11k-y += core.o \ + ath11k-$(CPTCFG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o + ath11k-$(CPTCFG_NL80211_TESTMODE) += testmode.o + ath11k-$(CPTCFG_ATH11K_TRACING) += trace.o +-ath11k-$(CONFIG_THERMAL) += thermal.o ++ath11k-$(CPTCFG_ATH11K_THERMAL) += thermal.o + ath11k-$(CPTCFG_ATH11K_SPECTRAL) += spectral.o + ath11k-$(CONFIG_PM) += wow.o + ath11k-$(CONFIG_DEV_COREDUMP) += coredump.o +--- a/drivers/net/wireless/ath/ath11k/thermal.h ++++ b/drivers/net/wireless/ath/ath11k/thermal.h +@@ -26,7 +26,7 @@ struct ath11k_thermal { + int temperature; + }; + +-#if IS_REACHABLE(CONFIG_THERMAL) ++#if IS_REACHABLE(CPTCFG_ATH11K_THERMAL) + int ath11k_thermal_register(struct ath11k_base *ab); + void ath11k_thermal_unregister(struct ath11k_base *ab); + int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state); +--- a/local-symbols ++++ b/local-symbols +@@ -163,6 +163,7 @@ ATH11K_DEBUG= + ATH11K_DEBUGFS= + ATH11K_TRACING= + ATH11K_SPECTRAL= ++ATH11K_THERMAL= + ATH12K= + ATH12K_AHB= + ATH12K_DEBUG= diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/903-ath11k-support-setting-FW-memory-mode-via-DT.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/903-ath11k-support-setting-FW-memory-mode-via-DT.patch new file mode 100644 index 0000000000..ab915fef4a --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/903-ath11k-support-setting-FW-memory-mode-via-DT.patch @@ -0,0 +1,75 @@ +From fb1c40c225cbc413d82c872dd8c8af3469b2b921 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Fri, 16 Dec 2022 17:17:52 +0100 +Subject: [PATCH] ath11k: support setting FW memory mode via DT + +ath11k is really memory intensive for devices with less that 1GB of RAM, +so lets allow saving a significant amount of memory by setting the FW to +Mode-1 via DTS for devices that need it. + +However the drawback is reduced number of VDEV-s and peers which is a +reasonable tradeoff. + +Mode-2 allows for further reduction, but it has further restrictions. + +While we are here, lets add a print to be able to easily determine what +FW memory mode is being used. + +Signed-off-by: Robert Marko +--- + drivers/net/wireless/ath/ath11k/core.c | 28 ++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -39,7 +39,7 @@ bool ath11k_ftm_mode; + module_param_named(ftm_mode, ath11k_ftm_mode, bool, 0444); + MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode"); + +-static const struct ath11k_hw_params ath11k_hw_params[] = { ++static struct ath11k_hw_params ath11k_hw_params[] = { + { + .hw_rev = ATH11K_HW_IPQ8074, + .name = "ipq8074 hw2.0", +@@ -2521,7 +2521,8 @@ static void ath11k_core_reset(struct wor + static int ath11k_init_hw_params(struct ath11k_base *ab) + { + const struct ath11k_hw_params *hw_params = NULL; +- int i; ++ u32 fw_mem_mode; ++ int i, ret; + + for (i = 0; i < ARRAY_SIZE(ath11k_hw_params); i++) { + hw_params = &ath11k_hw_params[i]; +@@ -2537,7 +2538,31 @@ static int ath11k_init_hw_params(struct + + ab->hw_params = *hw_params; + ++ ret = of_property_read_u32(ab->dev->of_node, ++ "qcom,ath11k-fw-memory-mode", ++ &fw_mem_mode); ++ if (!ret) { ++ if (fw_mem_mode == 0) { ++ ab->hw_params.fw_mem_mode = 0; ++ ab->hw_params.num_vdevs = 16 + 1; ++ ab->hw_params.num_peers = 512; ++ } ++ else if (fw_mem_mode == 1) { ++ ab->hw_params.fw_mem_mode = 1; ++ ab->hw_params.num_vdevs = 8; ++ ab->hw_params.num_peers = 128; ++ } else if (fw_mem_mode == 2) { ++ ab->hw_params.fw_mem_mode = 2; ++ ab->hw_params.num_vdevs = 8; ++ ab->hw_params.num_peers = 128; ++ ab->hw_params.coldboot_cal_mm = false; ++ ab->hw_params.coldboot_cal_ftm = false; ++ } else ++ ath11k_info(ab, "Unsupported FW memory mode: %u\n", fw_mem_mode); ++ } ++ + ath11k_info(ab, "%s\n", ab->hw_params.name); ++ ath11k_info(ab, "FW memory mode: %d\n", ab->hw_params.fw_mem_mode); + + return 0; + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/905-ath11k-remove-intersection-support-for-regulatory-ru.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/905-ath11k-remove-intersection-support-for-regulatory-ru.patch new file mode 100644 index 0000000000..59a2165c0c --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/905-ath11k-remove-intersection-support-for-regulatory-ru.patch @@ -0,0 +1,332 @@ +From abdd0985a36189ef2cc0e393b027276e86137ace Mon Sep 17 00:00:00 2001 +From: Aditya Kumar Singh +Date: Tue, 11 Apr 2023 20:08:49 +0200 +Subject: [PATCH] ath11k: remove intersection support for regulatory rules + +Currently, regulatory rules from new country settings is intersected with +rules from default country settings(during initialisation) in order to prevent +users to bypass their default country settings such as power limits, channel +flags, etc. + +However, the country setting in the BDF will take higher higher precendence +and FW will protect it. Therefore, there is no need to handle intersection +on the driver side now. + +Remove regulatory rules intersection logic support. + +Signed-off-by: Aditya Kumar Singh +--- + drivers/net/wireless/ath/ath11k/reg.c | 168 +++----------------------- + drivers/net/wireless/ath/ath11k/reg.h | 2 +- + drivers/net/wireless/ath/ath11k/wmi.c | 24 +--- + 3 files changed, 16 insertions(+), 178 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -353,134 +353,6 @@ static u32 ath11k_map_fw_phy_flags(u32 p + return flags; + } + +-static bool +-ath11k_reg_can_intersect(struct ieee80211_reg_rule *rule1, +- struct ieee80211_reg_rule *rule2) +-{ +- u32 start_freq1, end_freq1; +- u32 start_freq2, end_freq2; +- +- start_freq1 = rule1->freq_range.start_freq_khz; +- start_freq2 = rule2->freq_range.start_freq_khz; +- +- end_freq1 = rule1->freq_range.end_freq_khz; +- end_freq2 = rule2->freq_range.end_freq_khz; +- +- if ((start_freq1 >= start_freq2 && +- start_freq1 < end_freq2) || +- (start_freq2 > start_freq1 && +- start_freq2 < end_freq1)) +- return true; +- +- /* TODO: Should we restrict intersection feasibility +- * based on min bandwidth of the intersected region also, +- * say the intersected rule should have a min bandwidth +- * of 20MHz? +- */ +- +- return false; +-} +- +-static void ath11k_reg_intersect_rules(struct ieee80211_reg_rule *rule1, +- struct ieee80211_reg_rule *rule2, +- struct ieee80211_reg_rule *new_rule) +-{ +- u32 start_freq1, end_freq1; +- u32 start_freq2, end_freq2; +- u32 freq_diff, max_bw; +- +- start_freq1 = rule1->freq_range.start_freq_khz; +- start_freq2 = rule2->freq_range.start_freq_khz; +- +- end_freq1 = rule1->freq_range.end_freq_khz; +- end_freq2 = rule2->freq_range.end_freq_khz; +- +- new_rule->freq_range.start_freq_khz = max_t(u32, start_freq1, +- start_freq2); +- new_rule->freq_range.end_freq_khz = min_t(u32, end_freq1, end_freq2); +- +- freq_diff = new_rule->freq_range.end_freq_khz - +- new_rule->freq_range.start_freq_khz; +- max_bw = min_t(u32, rule1->freq_range.max_bandwidth_khz, +- rule2->freq_range.max_bandwidth_khz); +- new_rule->freq_range.max_bandwidth_khz = min_t(u32, max_bw, freq_diff); +- +- new_rule->power_rule.max_antenna_gain = +- min_t(u32, rule1->power_rule.max_antenna_gain, +- rule2->power_rule.max_antenna_gain); +- +- new_rule->power_rule.max_eirp = min_t(u32, rule1->power_rule.max_eirp, +- rule2->power_rule.max_eirp); +- +- /* Use the flags of both the rules */ +- new_rule->flags = rule1->flags | rule2->flags; +- +- if ((rule1->flags & NL80211_RRF_PSD) && (rule2->flags & NL80211_RRF_PSD)) +- new_rule->psd = min_t(s8, rule1->psd, rule2->psd); +- else +- new_rule->flags &= ~NL80211_RRF_PSD; +- +- /* To be safe, lts use the max cac timeout of both rules */ +- new_rule->dfs_cac_ms = max_t(u32, rule1->dfs_cac_ms, +- rule2->dfs_cac_ms); +-} +- +-static struct ieee80211_regdomain * +-ath11k_regd_intersect(struct ieee80211_regdomain *default_regd, +- struct ieee80211_regdomain *curr_regd) +-{ +- u8 num_old_regd_rules, num_curr_regd_rules, num_new_regd_rules; +- struct ieee80211_reg_rule *old_rule, *curr_rule, *new_rule; +- struct ieee80211_regdomain *new_regd = NULL; +- u8 i, j, k; +- +- num_old_regd_rules = default_regd->n_reg_rules; +- num_curr_regd_rules = curr_regd->n_reg_rules; +- num_new_regd_rules = 0; +- +- /* Find the number of intersecting rules to allocate new regd memory */ +- for (i = 0; i < num_old_regd_rules; i++) { +- old_rule = default_regd->reg_rules + i; +- for (j = 0; j < num_curr_regd_rules; j++) { +- curr_rule = curr_regd->reg_rules + j; +- +- if (ath11k_reg_can_intersect(old_rule, curr_rule)) +- num_new_regd_rules++; +- } +- } +- +- if (!num_new_regd_rules) +- return NULL; +- +- new_regd = kzalloc(sizeof(*new_regd) + (num_new_regd_rules * +- sizeof(struct ieee80211_reg_rule)), +- GFP_ATOMIC); +- +- if (!new_regd) +- return NULL; +- +- /* We set the new country and dfs region directly and only trim +- * the freq, power, antenna gain by intersecting with the +- * default regdomain. Also MAX of the dfs cac timeout is selected. +- */ +- new_regd->n_reg_rules = num_new_regd_rules; +- memcpy(new_regd->alpha2, curr_regd->alpha2, sizeof(new_regd->alpha2)); +- new_regd->dfs_region = curr_regd->dfs_region; +- new_rule = new_regd->reg_rules; +- +- for (i = 0, k = 0; i < num_old_regd_rules; i++) { +- old_rule = default_regd->reg_rules + i; +- for (j = 0; j < num_curr_regd_rules; j++) { +- curr_rule = curr_regd->reg_rules + j; +- +- if (ath11k_reg_can_intersect(old_rule, curr_rule)) +- ath11k_reg_intersect_rules(old_rule, curr_rule, +- (new_rule + k++)); +- } +- } +- return new_regd; +-} +- + static const char * + ath11k_reg_get_regdom_str(enum nl80211_dfs_regions dfs_region) + { +@@ -631,11 +503,11 @@ ath11k_reg_ap_pwr_convert(enum ieee80211 + + struct ieee80211_regdomain * + ath11k_reg_build_regd(struct ath11k_base *ab, +- struct cur_regulatory_info *reg_info, bool intersect, ++ struct cur_regulatory_info *reg_info, + enum wmi_vdev_type vdev_type, + enum ieee80211_ap_reg_power power_type) + { +- struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL; ++ struct ieee80211_regdomain *new_regd = NULL; + struct cur_reg_rule *reg_rule, *reg_rule_6ghz; + u8 i = 0, j = 0, k = 0; + u8 num_rules; +@@ -678,26 +550,26 @@ ath11k_reg_build_regd(struct ath11k_base + } + + if (!num_rules) +- goto ret; ++ return new_regd; + + /* Add max additional rules to accommodate weather radar band */ + if (reg_info->dfs_region == ATH11K_DFS_REG_ETSI) + num_rules += 2; + +- tmp_regd = kzalloc(sizeof(*tmp_regd) + ++ new_regd = kzalloc(sizeof(*new_regd) + + (num_rules * sizeof(struct ieee80211_reg_rule)), + GFP_ATOMIC); +- if (!tmp_regd) +- goto ret; ++ if (!new_regd) ++ return new_regd; + +- memcpy(tmp_regd->alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1); ++ memcpy(new_regd->alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1); + memcpy(alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1); + alpha2[2] = '\0'; +- tmp_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region); ++ new_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region); + + ath11k_dbg(ab, ATH11K_DBG_REG, + "Country %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n", +- alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region), ++ alpha2, ath11k_reg_get_regdom_str(new_regd->dfs_region), + reg_info->dfs_region, num_rules); + /* Update reg_rules[] below. Firmware is expected to + * send these rules in order(2 GHz rules first and then 5 GHz) +@@ -736,7 +608,7 @@ ath11k_reg_build_regd(struct ath11k_base + flags |= ath11k_map_fw_reg_flags(reg_rule->flags); + flags |= ath11k_map_fw_phy_flags(reg_info->phybitmap); + +- ath11k_reg_update_rule(tmp_regd->reg_rules + i, ++ ath11k_reg_update_rule(new_regd->reg_rules + i, + reg_rule->start_freq, + reg_rule->end_freq, max_bw, + reg_rule->ant_gain, reg_rule->reg_power, +@@ -751,7 +623,7 @@ ath11k_reg_build_regd(struct ath11k_base + reg_info->dfs_region == ATH11K_DFS_REG_ETSI && + (reg_rule->end_freq > ETSI_WEATHER_RADAR_BAND_LOW && + reg_rule->start_freq < ETSI_WEATHER_RADAR_BAND_HIGH)){ +- ath11k_reg_update_weather_radar_band(ab, tmp_regd, ++ ath11k_reg_update_weather_radar_band(ab, new_regd, + reg_rule, &i, + flags, max_bw); + continue; +@@ -762,37 +634,20 @@ ath11k_reg_build_regd(struct ath11k_base + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d) (%d, %d)\n", + i + 1, reg_rule->start_freq, reg_rule->end_freq, + max_bw, reg_rule->ant_gain, reg_rule->reg_power, +- tmp_regd->reg_rules[i].dfs_cac_ms, flags, ++ new_regd->reg_rules[i].dfs_cac_ms, flags, + reg_rule->psd_flag, reg_rule->psd_eirp); + } else { + ath11k_dbg(ab, ATH11K_DBG_REG, + "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n", + i + 1, reg_rule->start_freq, reg_rule->end_freq, + max_bw, reg_rule->ant_gain, reg_rule->reg_power, +- tmp_regd->reg_rules[i].dfs_cac_ms, ++ new_regd->reg_rules[i].dfs_cac_ms, + flags); + } + } + +- tmp_regd->n_reg_rules = i; ++ new_regd->n_reg_rules = i; + +- if (intersect) { +- default_regd = ab->default_regd[reg_info->phy_id]; +- +- /* Get a new regd by intersecting the received regd with +- * our default regd. +- */ +- new_regd = ath11k_regd_intersect(default_regd, tmp_regd); +- kfree(tmp_regd); +- if (!new_regd) { +- ath11k_warn(ab, "Unable to create intersected regdomain\n"); +- goto ret; +- } +- } else { +- new_regd = tmp_regd; +- } +- +-ret: + return new_regd; + } + +@@ -844,17 +699,6 @@ void ath11k_regd_update_chan_list_work(s + } + } + +-static bool ath11k_reg_is_world_alpha(char *alpha) +-{ +- if (alpha[0] == '0' && alpha[1] == '0') +- return true; +- +- if (alpha[0] == 'n' && alpha[1] == 'a') +- return true; +- +- return false; +-} +- + static enum wmi_vdev_type ath11k_reg_get_ar_vdev_type(struct ath11k *ar) + { + struct ath11k_vif *arvif; +@@ -877,7 +721,6 @@ int ath11k_reg_handle_chan_list(struct a + enum ieee80211_ap_reg_power power_type) + { + struct ieee80211_regdomain *regd; +- bool intersect = false; + int pdev_idx; + struct ath11k *ar; + enum wmi_vdev_type vdev_type; +@@ -929,24 +772,14 @@ int ath11k_reg_handle_chan_list(struct a + (char *)reg_info->alpha2, 2)) + goto retfail; + +- /* Intersect new rules with default regd if a new country setting was +- * requested, i.e a default regd was already set during initialization +- * and the regd coming from this event has a valid country info. +- */ +- if (ab->default_regd[pdev_idx] && +- !ath11k_reg_is_world_alpha((char *) +- ab->default_regd[pdev_idx]->alpha2) && +- !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) +- intersect = true; +- + ar = ab->pdevs[pdev_idx].ar; + vdev_type = ath11k_reg_get_ar_vdev_type(ar); + + ath11k_dbg(ab, ATH11K_DBG_WMI, +- "wmi handle chan list power type %d vdev type %d intersect %d\n", +- power_type, vdev_type, intersect); ++ "wmi handle chan list power type %d vdev type %d\n", ++ power_type, vdev_type); + +- regd = ath11k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type); ++ regd = ath11k_reg_build_regd(ab, reg_info, vdev_type, power_type); + if (!regd) { + ath11k_warn(ab, "failed to build regd from reg_info\n"); + goto fallback; +--- a/drivers/net/wireless/ath/ath11k/reg.h ++++ b/drivers/net/wireless/ath/ath11k/reg.h +@@ -36,7 +36,7 @@ void ath11k_regd_update_work(struct work + void ath11k_regd_update_chan_list_work(struct work_struct *work); + struct ieee80211_regdomain * + ath11k_reg_build_regd(struct ath11k_base *ab, +- struct cur_regulatory_info *reg_info, bool intersect, ++ struct cur_regulatory_info *reg_info, + enum wmi_vdev_type vdev_type, + enum ieee80211_ap_reg_power power_type); + int ath11k_regd_update(struct ath11k *ar); diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/906-wifi-ath11k-disable-coldboot-for-ipq6018.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/906-wifi-ath11k-disable-coldboot-for-ipq6018.patch new file mode 100644 index 0000000000..003efc3016 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/906-wifi-ath11k-disable-coldboot-for-ipq6018.patch @@ -0,0 +1,26 @@ +From a3be23672b4a81256d275af31afc6edcce5c5a26 Mon Sep 17 00:00:00 2001 +From: Mantas Pucka +Date: Mon, 22 Jan 2024 11:38:28 +0200 +Subject: [PATCH] wifi: ath11k: disable coldboot for ipq6018 + +Coldboot calibration does not work at the moment and causes failure during +wifi startup. + +Signed-off-by: Mantas Pucka +--- + drivers/net/wireless/ath/ath11k/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -173,8 +173,8 @@ static struct ath11k_hw_params ath11k_hw + .supports_shadow_regs = false, + .idle_ps = false, + .supports_sta_ps = false, +- .coldboot_cal_mm = true, +- .coldboot_cal_ftm = true, ++ .coldboot_cal_mm = false, ++ .coldboot_cal_ftm = false, + .cbcal_restart_fw = true, + .fw_mem_mode = 0, + .num_vdevs = 16 + 1, diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/907-wifi-ath11k-disable-coldboot-calibration-for-ipq5018.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/907-wifi-ath11k-disable-coldboot-calibration-for-ipq5018.patch new file mode 100644 index 0000000000..a6449d8d43 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/907-wifi-ath11k-disable-coldboot-calibration-for-ipq5018.patch @@ -0,0 +1,27 @@ +From b2d16b688ce04b67f2033f90f49f4add7ebd3fe8 Mon Sep 17 00:00:00 2001 +From: George Moussalem +Date: Tue, 10 Jun 2025 14:34:37 +0400 +Subject: [PATCH] wifi: ath11k: disable coldboot calibration for ipq5018 + +Coldboot calibration does not work causes the firmware to crash during +wifi startup. So let's disable coldboot calibration until a solution is +found. + +Signed-off-by: George Moussalem +--- + drivers/net/wireless/ath/ath11k/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -700,8 +700,8 @@ static struct ath11k_hw_params ath11k_hw + .supports_suspend = false, + .hal_params = &ath11k_hw_hal_params_ipq8074, + .single_pdev_only = false, +- .coldboot_cal_mm = true, +- .coldboot_cal_ftm = true, ++ .coldboot_cal_mm = false, ++ .coldboot_cal_ftm = false, + .cbcal_restart_fw = true, + .fix_l1ss = true, + .supports_dynamic_smps_6ghz = false, diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/910-ath11k-fix-remapped-ce-accessing-issue-on-64bit-OS.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/910-ath11k-fix-remapped-ce-accessing-issue-on-64bit-OS.patch new file mode 100644 index 0000000000..254b9c438b --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/910-ath11k-fix-remapped-ce-accessing-issue-on-64bit-OS.patch @@ -0,0 +1,153 @@ +From: Ziyang Huang +Date: Thu, 2 May 2024 00:14:31 +0800 +Subject: [PATCH] wifi: ath11k: fix remapped ce accessing issue on 64bit OS + +On 64bit OS, when ab->mem_ce is lower than or 4G far away from ab->mem, +u32 is not enough to store the offsets, which makes ath11k_ahb_read32() +and ath11k_ahb_write32() access incorrect address and causes Data Abort +Exception. + +Let's use the high bits of offsets to decide where to access, which is +similar as ath11k_pci_get_window_start() done. In the future, we can merge +these functions for unified regs accessing. + +Signed-off-by: Ziyang Huang +--- + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -198,12 +198,18 @@ static const struct ath11k_pci_ops ath11 + + static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset) + { +- return ioread32(ab->mem + offset); ++ if ((offset & ATH11K_REG_TYPE_MASK) == ATH11K_REG_TYPE_CE) ++ return ioread32(ab->mem_ce + FIELD_GET(ATH11K_REG_OFFSET_MASK, offset)); ++ else ++ return ioread32(ab->mem + FIELD_GET(ATH11K_REG_OFFSET_MASK, offset)); + } + + static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value) + { +- iowrite32(value, ab->mem + offset); ++ if ((offset & ATH11K_REG_TYPE_MASK) == ATH11K_REG_TYPE_CE) ++ iowrite32(value, ab->mem_ce + FIELD_GET(ATH11K_REG_OFFSET_MASK, offset)); ++ else ++ iowrite32(value, ab->mem + FIELD_GET(ATH11K_REG_OFFSET_MASK, offset)); + } + + static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab) +@@ -275,9 +281,9 @@ static void ath11k_ahb_ce_irq_enable(str + const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr; + u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr; + +- ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab); +- ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab); +- ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab); ++ ie1_reg_addr = ce_ie_addr->ie1_reg_addr; ++ ie2_reg_addr = ce_ie_addr->ie2_reg_addr; ++ ie3_reg_addr = ce_ie_addr->ie3_reg_addr; + + ce_attr = &ab->hw_params.host_ce_config[ce_id]; + if (ce_attr->src_nentries) +@@ -296,9 +302,9 @@ static void ath11k_ahb_ce_irq_disable(st + const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr; + u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr; + +- ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab); +- ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab); +- ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab); ++ ie1_reg_addr = ce_ie_addr->ie1_reg_addr; ++ ie2_reg_addr = ce_ie_addr->ie2_reg_addr; ++ ie3_reg_addr = ce_ie_addr->ie3_reg_addr; + + ce_attr = &ab->hw_params.host_ce_config[ce_id]; + if (ce_attr->src_nentries) +--- a/drivers/net/wireless/ath/ath11k/hal.c ++++ b/drivers/net/wireless/ath/ath11k/hal.c +@@ -1274,20 +1274,16 @@ static int ath11k_hal_srng_create_config + s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP; + + s = &hal->srng_config[HAL_CE_SRC]; +- s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_BASE_LSB + +- ATH11K_CE_OFFSET(ab); +- s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_HP + +- ATH11K_CE_OFFSET(ab); ++ s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_BASE_LSB; ++ s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_HP; + s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab); + s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab); + + s = &hal->srng_config[HAL_CE_DST]; +- s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_BASE_LSB + +- ATH11K_CE_OFFSET(ab); +- s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_HP + +- ATH11K_CE_OFFSET(ab); ++ s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_BASE_LSB; ++ s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_HP; + s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab); + s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) - +@@ -1295,9 +1291,8 @@ static int ath11k_hal_srng_create_config + + s = &hal->srng_config[HAL_CE_DST_STATUS]; + s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + +- HAL_CE_DST_STATUS_RING_BASE_LSB + ATH11K_CE_OFFSET(ab); +- s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_STATUS_RING_HP + +- ATH11K_CE_OFFSET(ab); ++ HAL_CE_DST_STATUS_RING_BASE_LSB; ++ s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_STATUS_RING_HP; + s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) - + HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab); + s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) - +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -2268,9 +2268,9 @@ const struct ce_ie_addr ath11k_ce_ie_add + }; + + const struct ce_ie_addr ath11k_ce_ie_addr_ipq5018 = { +- .ie1_reg_addr = CE_HOST_IPQ5018_IE_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE, +- .ie2_reg_addr = CE_HOST_IPQ5018_IE_2_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE, +- .ie3_reg_addr = CE_HOST_IPQ5018_IE_3_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE, ++ .ie1_reg_addr = ATH11K_REG_TYPE_CE + CE_HOST_IPQ5018_IE_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE, ++ .ie2_reg_addr = ATH11K_REG_TYPE_CE + CE_HOST_IPQ5018_IE_2_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE, ++ .ie3_reg_addr = ATH11K_REG_TYPE_CE + CE_HOST_IPQ5018_IE_3_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE, + }; + + const struct ce_remap ath11k_ce_remap_ipq5018 = { +@@ -2801,13 +2801,13 @@ const struct ath11k_hw_regs ipq5018_regs + .hal_reo_status_hp = 0x00003070, + + /* WCSS relative address */ +- .hal_seq_wcss_umac_ce0_src_reg = 0x08400000 ++ .hal_seq_wcss_umac_ce0_src_reg = ATH11K_REG_TYPE_CE + 0x08400000 + - HAL_IPQ5018_CE_WFSS_REG_BASE, +- .hal_seq_wcss_umac_ce0_dst_reg = 0x08401000 ++ .hal_seq_wcss_umac_ce0_dst_reg = ATH11K_REG_TYPE_CE + 0x08401000 + - HAL_IPQ5018_CE_WFSS_REG_BASE, +- .hal_seq_wcss_umac_ce1_src_reg = 0x08402000 ++ .hal_seq_wcss_umac_ce1_src_reg = ATH11K_REG_TYPE_CE + 0x08402000 + - HAL_IPQ5018_CE_WFSS_REG_BASE, +- .hal_seq_wcss_umac_ce1_dst_reg = 0x08403000 ++ .hal_seq_wcss_umac_ce1_dst_reg = ATH11K_REG_TYPE_CE + 0x08403000 + - HAL_IPQ5018_CE_WFSS_REG_BASE, + + /* WBM Idle address */ +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -81,7 +81,12 @@ + #define ATH11K_M3_FILE "m3.bin" + #define ATH11K_REGDB_FILE_NAME "regdb.bin" + +-#define ATH11K_CE_OFFSET(ab) (ab->mem_ce - ab->mem) ++#define ATH11K_REG_TYPE_MASK GENMASK(31, 28) ++#define ATH11K_REG_TYPE(x) FIELD_PREP_CONST(ATH11K_REG_TYPE_MASK, x) ++#define ATH11K_REG_TYPE_NORMAL ATH11K_REG_TYPE(0) ++#define ATH11K_REG_TYPE_DP ATH11K_REG_TYPE(1) ++#define ATH11K_REG_TYPE_CE ATH11K_REG_TYPE(2) ++#define ATH11K_REG_OFFSET_MASK GENMASK(27, 0) + + enum ath11k_hw_rate_cck { + ATH11K_HW_RATE_CCK_LP_11M = 0, diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/920-wifi-ath11k-add-hw-params-for-QCN6122.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/920-wifi-ath11k-add-hw-params-for-QCN6122.patch new file mode 100644 index 0000000000..4f4cef664e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/920-wifi-ath11k-add-hw-params-for-QCN6122.patch @@ -0,0 +1,120 @@ +From: George Moussalem +Date: Wed, 27 Oct 2024 16:34:11 +0400 +Subject: [PATCH] wifi: ath11k: add hw params for QCN6122 + +Add QCN6122 platform support. + +QCN6122 is a PCIe based solution that is attached to and enumerated +by the WPSS (Wireless Processor SubSystem) Q6 processor. + +Though it is a PCIe device, since it is not attached to APSS processor +(Application Processor SubSystem), APSS will be unaware of such a decice +and hence it is registered to the APSS processor as a platform device(AHB). +Because of this hybrid nature, it is called as a hybrid bus device. + +As such, QCN6122 is a hybrid bus type device and follows the same codepath +as for WCN6750. + +This is a heavily simplified version of below downstream patch: +Download from https://git.codelinaro.org/clo/qsdk/oss/system/feeds/wlan-open/-/blob/NHSS.QSDK.12.4.5.r2/mac80211/patches/232-ath11k-qcn6122-support.patch + +Co-developed-by: George Moussalem +Signed-off-by: Sowmiya Sree Elavalagan +Signed-off-by: George Moussalem +--- + +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -907,6 +907,67 @@ static struct ath11k_hw_params ath11k_hw + .support_dual_stations = true, + .pdev_suspend = false, + }, ++ { ++ .hw_rev = ATH11K_HW_QCN6122_HW10, ++ .name = "qcn6122 hw1.0", ++ .fw = { ++ .dir = "QCN6122/hw1.0", ++ .board_size = 256 * 1024, ++ .cal_offset = 128 * 1024, ++ }, ++ .hal_params = &ath11k_hw_hal_params_ipq8074, ++ .max_radios = MAX_RADIOS_5018, ++ .bdf_addr = 0x4D200000, ++ .hw_ops = &ipq5018_ops, ++ .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), ++ .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122, ++ .interface_modes = BIT(NL80211_IFTYPE_STATION) | ++ BIT(NL80211_IFTYPE_AP) | ++ BIT(NL80211_IFTYPE_MESH_POINT), ++ .spectral = { ++ .fft_sz = 2, ++ .fft_pad_sz = 0, ++ .summary_pad_sz = 16, ++ .fft_hdr_len = 24, ++ .max_fft_bins = 1024, ++ }, ++ .credit_flow = false, ++ .max_tx_ring = 1, ++ .supports_monitor = true, ++ .supports_shadow_regs = false, ++ .idle_ps = false, ++ .supports_suspend = false, ++ .host_ce_config = ath11k_host_ce_config_qcn9074, ++ .ce_count = CE_CNT_5018, ++ .target_ce_config = ath11k_target_ce_config_wlan_ipq5018, ++ .target_ce_count = TARGET_CE_CNT_5018, ++ .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq5018, ++ .svc_to_ce_map_len = SVC_CE_MAP_LEN_5018, ++ .single_pdev_only = false, ++ .rxdma1_enable = true, ++ .num_rxdma_per_pdev = RXDMA_PER_PDEV_5018, ++ .rx_mac_buf_ring = false, ++ .vdev_start_delay = false, ++ .htt_peer_map_v2 = true, ++ .coldboot_cal_mm = false, ++ .coldboot_cal_ftm = false, ++ .cbcal_restart_fw = true, ++ .fix_l1ss = true, ++ .alloc_cacheable_memory = true, ++ .m3_fw_support = false, ++ .fixed_bdf_addr = true, ++ .fixed_mem_region = true, ++ .static_window_map = true, ++ .hybrid_bus_type = true, ++ .fw_mem_mode = 1, ++ .supports_sta_ps = false, ++ .dbr_debug_support = true, ++ .bios_sar_capa = NULL, ++ .fixed_fw_mem = false, ++ .support_off_channel_tx = false, ++ .tcl_ring_retry = true, ++ .tx_ring_size = DP_TCL_DATA_RING_SIZE, ++ }, + }; + + static const struct dmi_system_id ath11k_pm_quirk_table[] = { +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -152,6 +152,7 @@ enum ath11k_hw_rev { + ATH11K_HW_IPQ5018_HW10, + ATH11K_HW_QCA2066_HW21, + ATH11K_HW_QCA6698AQ_HW21, ++ ATH11K_HW_QCN6122_HW10, + }; + + enum ath11k_firmware_mode { +--- a/drivers/net/wireless/ath/ath11k/qmi.h ++++ b/drivers/net/wireless/ath/ath11k/qmi.h +@@ -22,10 +22,11 @@ + #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074 0x02 + #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9074 0x07 + #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_WCN6750 0x03 ++#define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122 0x40 + #define ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 32 + #define ATH11K_QMI_RESP_LEN_MAX 8192 + #define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01 52 +-#define ATH11K_QMI_CALDB_SIZE 0x480000 ++#define ATH11K_QMI_CALDB_SIZE 0x500000 + #define ATH11K_QMI_BDF_EXT_STR_LENGTH 0x20 + #define ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT 5 + diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/921-wifi-ath11k-add-hal-regs-for-QCN6122.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/921-wifi-ath11k-add-hal-regs-for-QCN6122.patch new file mode 100644 index 0000000000..dc16385105 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/921-wifi-ath11k-add-hal-regs-for-QCN6122.patch @@ -0,0 +1,114 @@ +From: George Moussalem +Date: Wed, 27 Oct 2024 16:34:11 +0400 +Subject: [PATCH] wifi: ath11k: add hal regs for QCN6122 + +Add HAL changes required to support QCN6122. Offsets are similar to those of +WCN6750 but QCN6122 does not use the hal_shadow_base_addr, so add platform +specific ath11k_hw_regs and register them in hw params. + +Signed-off-by: George Moussalem +--- +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -920,6 +920,7 @@ static struct ath11k_hw_params ath11k_hw + .bdf_addr = 0x4D200000, + .hw_ops = &ipq5018_ops, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), ++ .regs = &qcn6122_regs, + .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122, + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -2822,6 +2822,81 @@ const struct ath11k_hw_regs ipq5018_regs + .hal_wbm1_release_ring_base_lsb = 0x0000097c, + }; + ++const struct ath11k_hw_regs qcn6122_regs = { ++ /* SW2TCL(x) R0 ring configuration address */ ++ .hal_tcl1_ring_base_lsb = 0x00000694, ++ .hal_tcl1_ring_base_msb = 0x00000698, ++ .hal_tcl1_ring_id = 0x0000069c, ++ .hal_tcl1_ring_misc = 0x000006a4, ++ .hal_tcl1_ring_tp_addr_lsb = 0x000006b0, ++ .hal_tcl1_ring_tp_addr_msb = 0x000006b4, ++ .hal_tcl1_ring_consumer_int_setup_ix0 = 0x000006c4, ++ .hal_tcl1_ring_consumer_int_setup_ix1 = 0x000006c8, ++ .hal_tcl1_ring_msi1_base_lsb = 0x000006dc, ++ .hal_tcl1_ring_msi1_base_msb = 0x000006e0, ++ .hal_tcl1_ring_msi1_data = 0x000006e4, ++ .hal_tcl2_ring_base_lsb = 0x000006ec, ++ .hal_tcl_ring_base_lsb = 0x0000079c, ++ ++ /* TCL STATUS ring address */ ++ .hal_tcl_status_ring_base_lsb = 0x000008a4, ++ ++ /* REO2SW(x) R0 ring configuration address */ ++ .hal_reo1_ring_base_lsb = 0x000001ec, ++ .hal_reo1_ring_base_msb = 0x000001f0, ++ .hal_reo1_ring_id = 0x000001f4, ++ .hal_reo1_ring_misc = 0x000001fc, ++ .hal_reo1_ring_hp_addr_lsb = 0x00000200, ++ .hal_reo1_ring_hp_addr_msb = 0x00000204, ++ .hal_reo1_ring_producer_int_setup = 0x00000210, ++ .hal_reo1_ring_msi1_base_lsb = 0x00000234, ++ .hal_reo1_ring_msi1_base_msb = 0x00000238, ++ .hal_reo1_ring_msi1_data = 0x0000023c, ++ .hal_reo2_ring_base_lsb = 0x00000244, ++ .hal_reo1_aging_thresh_ix_0 = 0x00000564, ++ .hal_reo1_aging_thresh_ix_1 = 0x00000568, ++ .hal_reo1_aging_thresh_ix_2 = 0x0000056c, ++ .hal_reo1_aging_thresh_ix_3 = 0x00000570, ++ ++ /* REO2SW(x) R2 ring pointers (head/tail) address */ ++ .hal_reo1_ring_hp = 0x00003028, ++ .hal_reo1_ring_tp = 0x0000302c, ++ .hal_reo2_ring_hp = 0x00003030, ++ ++ /* REO2TCL R0 ring configuration address */ ++ .hal_reo_tcl_ring_base_lsb = 0x000003fc, ++ .hal_reo_tcl_ring_hp = 0x00003058, ++ ++ /* SW2REO ring address */ ++ .hal_sw2reo_ring_base_lsb = 0x0000013c, ++ .hal_sw2reo_ring_hp = 0x00003018, ++ ++ /* REO CMD ring address */ ++ .hal_reo_cmd_ring_base_lsb = 0x000000e4, ++ .hal_reo_cmd_ring_hp = 0x00003010, ++ ++ /* REO status address */ ++ .hal_reo_status_ring_base_lsb = 0x00000504, ++ .hal_reo_status_hp = 0x00003070, ++ ++ /* WCSS relative address */ ++ .hal_seq_wcss_umac_ce0_src_reg = 0x01b80000, ++ .hal_seq_wcss_umac_ce0_dst_reg = 0x01b81000, ++ .hal_seq_wcss_umac_ce1_src_reg = 0x01b82000, ++ .hal_seq_wcss_umac_ce1_dst_reg = 0x01b83000, ++ ++ /* WBM Idle address */ ++ .hal_wbm_idle_link_ring_base_lsb = 0x00000874, ++ .hal_wbm_idle_link_ring_misc = 0x00000884, ++ ++ /* SW2WBM release address */ ++ .hal_wbm_release_ring_base_lsb = 0x000001ec, ++ ++ /* WBM2SW release address */ ++ .hal_wbm0_release_ring_base_lsb = 0x00000924, ++ .hal_wbm1_release_ring_base_lsb = 0x0000097c, ++}; ++ + const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = { + .rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM, + .tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_ipq8074, +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -426,6 +426,7 @@ extern const struct ath11k_hw_regs qcn90 + extern const struct ath11k_hw_regs wcn6855_regs; + extern const struct ath11k_hw_regs wcn6750_regs; + extern const struct ath11k_hw_regs ipq5018_regs; ++extern const struct ath11k_hw_regs qcn6122_regs; + + static inline const char *ath11k_bd_ie_type_str(enum ath11k_bd_ie_type type) + { diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/922-wifi-ath11k-add-hw-ring-mask-for-QCN6122.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/922-wifi-ath11k-add-hw-ring-mask-for-QCN6122.patch new file mode 100644 index 0000000000..509c27e15c --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/922-wifi-ath11k-add-hw-ring-mask-for-QCN6122.patch @@ -0,0 +1,74 @@ +From: George Moussalem +Date: Wed, 27 Oct 2024 16:34:11 +0400 +Subject: [PATCH] wifi: ath11k: add hw ring mask for QCN6122 + +Add ring mask for QCN6122 and register them in hw params. + +Signed-off-by: George Moussalem +--- +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -919,6 +919,7 @@ static struct ath11k_hw_params ath11k_hw + .max_radios = MAX_RADIOS_5018, + .bdf_addr = 0x4D200000, + .hw_ops = &ipq5018_ops, ++ .ring_mask = &ath11k_hw_ring_mask_qcn6122, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .regs = &qcn6122_regs, + .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122, +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -2070,6 +2070,43 @@ const struct ath11k_hw_ring_mask ath11k_ + }, + }; + ++const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn6122 = { ++ .tx = { ++ ATH11K_TX_RING_MASK_0, ++ ATH11K_TX_RING_MASK_1, ++ ATH11K_TX_RING_MASK_2, ++ }, ++ .rx_mon_status = { ++ 0, 0, 0, ++ ATH11K_RX_MON_STATUS_RING_MASK_0, ++ }, ++ .rx = { ++ 0, 0, 0, 0, ++ ATH11K_RX_RING_MASK_0, ++ ATH11K_RX_RING_MASK_1, ++ ATH11K_RX_RING_MASK_2, ++ ATH11K_RX_RING_MASK_3, ++ }, ++ .rx_err = { ++ 0, 0, 0, 0, 0, 0, 0, 0, ++ ATH11K_RX_ERR_RING_MASK_0, ++ }, ++ .rx_wbm_rel = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ ATH11K_RX_WBM_REL_RING_MASK_0, ++ }, ++ .reo_status = { ++ 0, 0, 0, ++ ATH11K_REO_STATUS_RING_MASK_0, ++ }, ++ .rxdma2host = { ++ ATH11K_RXDMA2HOST_RING_MASK_0, ++ }, ++ .host2rxdma = { ++ ATH11K_HOST2RXDMA_RING_MASK_0, ++ }, ++}; ++ + /* Target firmware's Copy Engine configuration for IPQ5018 */ + const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq5018[] = { + /* CE0: host->target HTC control and raw streams */ +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -290,6 +290,7 @@ extern const struct ath11k_hw_ring_mask + extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390; + extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074; + extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_wcn6750; ++extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn6122; + + extern const struct ce_ie_addr ath11k_ce_ie_addr_ipq8074; + extern const struct ce_ie_addr ath11k_ce_ie_addr_ipq5018; diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/923-wifi-ath11k-update-hif_and-pci_ops-for-QCN6122.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/923-wifi-ath11k-update-hif_and-pci_ops-for-QCN6122.patch new file mode 100644 index 0000000000..10648dda9e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/923-wifi-ath11k-update-hif_and-pci_ops-for-QCN6122.patch @@ -0,0 +1,102 @@ +From: George Moussalem +Date: Wed, 27 Oct 2024 16:34:11 +0400 +Subject: [PATCH] wifi: ath11k: update hif and pci ops for QCN6122 + +Add HIF and PCI ops for QCN6122. QCN6122 by default uses DP window 3. +However, this is configurable, so let's introduce a function to do that and +follow the existing register access code for (hybrid)AHB devices and use +DP window 1. + +Signed-off-by: George Moussalem +--- +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -768,6 +768,18 @@ static int ath11k_ahb_hif_resume(struct + return 0; + } + ++static void ath11k_ahb_config_static_window_qcn6122(struct ath11k_base *ab) ++{ ++ u32 umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); ++ u32 ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); ++ u32 window; ++ ++ window = (umac_window) | (ce_window << 6); ++ ++ iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, ++ ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); ++} ++ + static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = { + .start = ath11k_ahb_start, + .stop = ath11k_ahb_stop, +@@ -800,6 +812,24 @@ static const struct ath11k_hif_ops ath11 + .ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq, + }; + ++static const struct ath11k_hif_ops ath11k_ahb_hif_ops_qcn6122 = { ++ .start = ath11k_pcic_start, ++ .stop = ath11k_pcic_stop, ++ .read32 = ath11k_pcic_read32, ++ .write32 = ath11k_pcic_write32, ++ .read = NULL, ++ .irq_enable = ath11k_pcic_ext_irq_enable, ++ .irq_disable = ath11k_pcic_ext_irq_disable, ++ .get_msi_address = ath11k_pcic_get_msi_address, ++ .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment, ++ .map_service_to_pipe = ath11k_pcic_map_service_to_pipe, ++ .power_down = ath11k_ahb_power_down, ++ .power_up = ath11k_ahb_power_up, ++ .ce_irq_enable = ath11k_pci_enable_ce_irqs_except_wake_irq, ++ .ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq, ++ .config_static_window = ath11k_ahb_config_static_window_qcn6122, ++}; ++ + static int ath11k_core_get_rproc(struct ath11k_base *ab) + { + struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab); +@@ -1133,6 +1163,10 @@ static int ath11k_ahb_probe(struct platf + hif_ops = &ath11k_ahb_hif_ops_wcn6750; + pci_ops = &ath11k_ahb_pci_ops_wcn6750; + break; ++ case ATH11K_HW_QCN6122_HW10: ++ hif_ops = &ath11k_ahb_hif_ops_qcn6122; ++ pci_ops = &ath11k_ahb_pci_ops_wcn6750; ++ break; + default: + dev_err(&pdev->dev, "unsupported device type %d\n", hw_rev); + return -EOPNOTSUPP; +--- a/drivers/net/wireless/ath/ath11k/hif.h ++++ b/drivers/net/wireless/ath/ath11k/hif.h +@@ -32,6 +32,7 @@ struct ath11k_hif_ops { + void (*ce_irq_disable)(struct ath11k_base *ab); + void (*get_ce_msi_idx)(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx); + void (*coredump_download)(struct ath11k_base *ab); ++ void (*config_static_window)(struct ath11k_base *ab); + }; + + static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab) +@@ -159,4 +160,12 @@ static inline void ath11k_hif_coredump_d + ab->hif.ops->coredump_download(ab); + } + ++static inline void ath11k_hif_config_static_window(struct ath11k_base *ab) ++{ ++ if (!ab->hw_params.static_window_map || !ab->hif.ops->config_static_window) ++ return; ++ ++ ab->hif.ops->config_static_window(ab); ++} ++ + #endif /* _HIF_H_ */ +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2194,6 +2194,8 @@ static int ath11k_qmi_request_device_inf + if (!ab->hw_params.ce_remap) + ab->mem_ce = ab->mem; + ++ ath11k_hif_config_static_window(ab); ++ + return 0; + out: + return ret; diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/924-wifi-ath11k-add-multipd-support-for-QCN6122.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/924-wifi-ath11k-add-multipd-support-for-QCN6122.patch new file mode 100644 index 0000000000..d8a7191c82 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/924-wifi-ath11k-add-multipd-support-for-QCN6122.patch @@ -0,0 +1,110 @@ +From: George Moussalem +Date: Wed, 27 Oct 2024 16:34:11 +0400 +Subject: [PATCH] wifi: ath11k: add multipd support for QCN6122 + +IPQ5018/QCN6122 platforms use multi PD (protection domains) to avoid having +one instance of the running Q6 firmware crashing resulting in crashing the +others. See below patch for more info: +https://lore.kernel.org/all/20231110091939.3025413-1-quic_mmanikan@quicinc.com/ + +The IPQ5018 platform can have multiple (2) QCN6122 wifi cards. To differentiate +the two, the PD instance number (1 or 2) is added to the QMI service instance +ID, which the QCN6122 firmware also expects. IPQ5018 is always the first PD, so +the QCN6122 cards should be the second or third. + +Signed-off-by: George Moussalem +--- +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -435,6 +435,7 @@ static void ath11k_ahb_init_qmi_ce_confi + cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; + cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; + ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; ++ ab->qmi.service_ins_id += ab->userpd_id; + } + + static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab) +@@ -1107,6 +1108,27 @@ err_unregister: + return ret; + } + ++static int ath11k_get_userpd_id(struct device *dev) ++{ ++ int ret; ++ int userpd_id = 0; ++ const char *subsys_name; ++ ++ ret = of_property_read_string(dev->of_node, ++ "qcom,userpd-subsys-name", ++ &subsys_name); ++ if (ret) ++ return 0; ++ ++ if (strcmp(subsys_name, "q6v5_wcss_userpd2") == 0) ++ userpd_id = ATH11K_QCN6122_USERPD_2; ++ else if (strcmp(subsys_name, "q6v5_wcss_userpd3") == 0) ++ userpd_id = ATH11K_QCN6122_USERPD_3; ++ dev_info(dev, "Multipd architecture - userpd: %d\n", userpd_id + 1); ++ ++ return userpd_id; ++} ++ + static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab) + { + struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab); +@@ -1148,7 +1170,7 @@ static int ath11k_ahb_probe(struct platf + const struct ath11k_hif_ops *hif_ops; + const struct ath11k_pci_ops *pci_ops; + enum ath11k_hw_rev hw_rev; +- int ret; ++ int ret, userpd_id; + + hw_rev = (uintptr_t)device_get_match_data(&pdev->dev); + +@@ -1172,6 +1194,7 @@ static int ath11k_ahb_probe(struct platf + return -EOPNOTSUPP; + } + ++ userpd_id = ath11k_get_userpd_id(&pdev->dev); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n"); +@@ -1188,6 +1211,7 @@ static int ath11k_ahb_probe(struct platf + ab->hif.ops = hif_ops; + ab->pdev = pdev; + ab->hw_rev = hw_rev; ++ ab->userpd_id = userpd_id; + ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL; + platform_set_drvdata(pdev, ab); + +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -48,6 +48,9 @@ + #define ATH11K_INVALID_HW_MAC_ID 0xFF + #define ATH11K_CONNECTION_LOSS_HZ (3 * HZ) + ++#define ATH11K_QCN6122_USERPD_2 1 ++#define ATH11K_QCN6122_USERPD_3 2 ++ + /* SMBIOS type containing Board Data File Name Extension */ + #define ATH11K_SMBIOS_BDF_EXT_TYPE 0xF8 + +@@ -969,6 +972,7 @@ struct ath11k_base { + struct list_head peers; + wait_queue_head_t peer_mapping_wq; + u8 mac_addr[ETH_ALEN]; ++ int userpd_id; + int irq_num[ATH11K_IRQ_NUM_MAX]; + struct ath11k_ext_irq_grp ext_irq_grp[ATH11K_EXT_IRQ_GRP_NUM_MAX]; + struct ath11k_targ_cap target_caps; +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -409,6 +409,8 @@ static void ath11k_pci_init_qmi_ce_confi + } else + ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; + ++ ab->qmi.service_ins_id += ab->userpd_id; ++ + ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, + &cfg->shadow_reg_v2_len); + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/925-wifi-ath11k-add-QCN6122-device-support.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/925-wifi-ath11k-add-QCN6122-device-support.patch new file mode 100644 index 0000000000..4a35f145d2 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/925-wifi-ath11k-add-QCN6122-device-support.patch @@ -0,0 +1,55 @@ +From: George Moussalem +Date: Wed, 27 Oct 2024 16:34:11 +0400 +Subject: [PATCH] wifi: ath11k: add QCN6122 device support + +QCN6122 is a 2x2 11AX PCIe based chipset, but it is attached to the WPSS +(Wireless Processor SubSystem) Q6 processor, hence it is enumerated +by the Q6 processor. It is registered to the APSS processor +(Application Processor SubSystem) as a platform device (AHB) and remoteproc +APIs are used to boot up or shutdown the device like other AHB devices. + +Also, device information like BAR and its size is not known to the +APSS processor as the chip is enumerated by WPSS Q6. These details +are fetched over QMI. + +STA, AP, and MESH modes are supported. +Tested on: Linksys MX2000 and GLiNET B3000 access points for prolonged duration +tests spanning multiple days with multiple clients connected with firmware +WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 + +An important point to note is that though QCN6122 is a PCIe device, +it is an IPQ5018 SoC specific solution and cannot be attached to any other +platform. + +Signed-off-by: George Moussalem +--- +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -37,6 +37,9 @@ static const struct of_device_id ath11k_ + { .compatible = "qcom,ipq5018-wifi", + .data = (void *)ATH11K_HW_IPQ5018_HW10, + }, ++ { .compatible = "qcom,qcn6122-wifi", ++ .data = (void *)ATH11K_HW_QCN6122_HW10, ++ }, + { } + }; + +--- a/drivers/net/wireless/ath/ath11k/pcic.c ++++ b/drivers/net/wireless/ath/ath11k/pcic.c +@@ -139,6 +139,15 @@ static const struct ath11k_msi_config at + }, + .hw_rev = ATH11K_HW_QCA6698AQ_HW21, + }, ++ { ++ .total_vectors = 13, ++ .total_users = 2, ++ .users = (struct ath11k_msi_user[]) { ++ { .name = "CE", .num_vectors = 5, .base_vector = 0 }, ++ { .name = "DP", .num_vectors = 8, .base_vector = 5 }, ++ }, ++ .hw_rev = ATH11K_HW_QCN6122_HW10, ++ }, + }; + + int ath11k_pcic_init_msi_config(struct ath11k_base *ab) diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/931-wifi-ath11k-Support-to-assign-m3-dump-memory.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/931-wifi-ath11k-Support-to-assign-m3-dump-memory.patch new file mode 100644 index 0000000000..77c92fd777 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/931-wifi-ath11k-Support-to-assign-m3-dump-memory.patch @@ -0,0 +1,31 @@ +From 64f6f6cdde0b6b763181145a698207fad4536c06 Mon Sep 17 00:00:00 2001 +From: Ziyang Huang +Date: Wed, 9 Aug 2023 17:44:49 +0000 +Subject: [PATCH] wifi: ath11k: Support to assign m3 dump memory + +Signed-off-by: Ziyang Huang +--- + drivers/net/wireless/ath/ath11k/qmi.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -2111,6 +2111,18 @@ static int ath11k_qmi_assign_target_mem_ + ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; + idx++; + break; ++ case M3_DUMP_REGION_TYPE: ++ if (of_property_read_u32(dev->of_node, "qcom,m3-dump-addr", &addr)) { ++ ath11k_warn(ab, "qmi fail to get qcom,m3-dump-addr, ignore m3 dump mem req\n"); ++ break; ++ } ++ ++ ab->qmi.target_mem[idx].paddr = (phys_addr_t) addr; ++ ab->qmi.target_mem[idx].vaddr = NULL; ++ ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; ++ ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; ++ idx++; ++ break; + default: + ath11k_warn(ab, "qmi ignore invalid mem req type %d\n", + ab->qmi.target_mem[i].type); diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/947-wifi-ath11k-fix-rssi-station-dump-for-IPQ5018-and-QC.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/947-wifi-ath11k-fix-rssi-station-dump-for-IPQ5018-and-QC.patch new file mode 100644 index 0000000000..1caac86207 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/947-wifi-ath11k-fix-rssi-station-dump-for-IPQ5018-and-QC.patch @@ -0,0 +1,32 @@ +From 8fd48529849310a68500d1d546f246d44697bbed Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 25 Nov 2025 14:56:08 +0100 +Subject: [PATCH] wifi: ath11k: fix rssi station dump for IPQ5018 and QCN6122 + +Commit 031ffa6c2cd3 ("wifi: ath11k: fix rssi station dump not updated in +QCN9074") didn't account for IPQ5018 and QCN6122 WiFi card that are +based on QCN9074. + +Update the .mpdu_info_get_peerid to use the QCN9074 variant to correctly +receive consistent RSSI station data. + +Reported-by: Scott Mercer +Suggested-by: Scott Mercer +Tested-by: Scott Mercer +Fixes: 031ffa6c2cd3 ("wifi: ath11k: fix rssi station dump not updated in QCN9074") +Signed-off-by: Christian Marangi +--- + drivers/net/wireless/ath/ath11k/hw.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ath/ath11k/hw.c ++++ b/drivers/net/wireless/ath/ath11k/hw.c +@@ -1175,7 +1175,7 @@ const struct ath11k_hw_ops ipq5018_ops = + .rx_desc_get_attention = ath11k_hw_qcn9074_rx_desc_get_attention, + .reo_setup = ath11k_hw_ipq5018_reo_setup, + .rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload, +- .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, ++ .mpdu_info_get_peerid = ath11k_hw_qcn9074_mpdu_info_get_peerid, + .rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid, + .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2, + .get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector, diff --git a/lede/package/kernel/mac80211/patches-6.18/ath11k/948-wifi-ath11k-Fix-the-WMM-param-type.patch b/lede/package/kernel/mac80211/patches-6.18/ath11k/948-wifi-ath11k-Fix-the-WMM-param-type.patch new file mode 100644 index 0000000000..174f02be81 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath11k/948-wifi-ath11k-Fix-the-WMM-param-type.patch @@ -0,0 +1,24 @@ +From c420c1f66235b5ab4fc8d94da72bd5ae6397117f Mon Sep 17 00:00:00 2001 +From: Gautham Kumar Senthilkumaran +Date: Mon, 19 Jan 2026 11:55:51 +0100 +Subject: [PATCH] wifi: ath11k: Fix the WMM param type + +Since FW does not support the 11ax EDCA parameter in WMI TLV command. +FW was crashing as host was sending this parameter, now changed the +WMM parameter type as default zero before sending to FW. + +Fixes: b78c02f7c710 ("wifi: ath11k: add support for MU EDCA") +Signed-off-by: Gautham Kumar Senthilkumaran +Signed-off-by: Paweł Owoc + +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -2688,7 +2688,7 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(s + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = vdev_id; +- cmd->wmm_param_type = wmm_param_type; ++ cmd->wmm_param_type = WMI_WMM_PARAM_TYPE_LEGACY; + + for (ac = 0; ac < WME_NUM_AC; ac++) { + switch (ac) { diff --git a/lede/package/kernel/mac80211/patches-6.18/ath12k/001-v7.1-wifi-ath12k-add-basic-hwmon-temperature-reporting.patch b/lede/package/kernel/mac80211/patches-6.18/ath12k/001-v7.1-wifi-ath12k-add-basic-hwmon-temperature-reporting.patch new file mode 100644 index 0000000000..f861283ca7 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath12k/001-v7.1-wifi-ath12k-add-basic-hwmon-temperature-reporting.patch @@ -0,0 +1,380 @@ +From 151322bccdbdb132f5a73cc8ad5d3ab89b90ed52 Mon Sep 17 00:00:00 2001 +From: Maharaja Kennadyrajan +Date: Mon, 23 Feb 2026 18:56:22 +0530 +Subject: wifi: ath12k: add basic hwmon temperature reporting + +Add initial thermal support by wiring up a per-radio (pdev) hwmon temperature +sensor backed by the existing WMI pdev temperature command and event. +When userspace reads the sysfs file temp1_input, the driver sends +WMI_PDEV_GET_TEMPERATURE_CMDID (tag WMI_TAG_PDEV_GET_TEMPERATURE_CMD) and waits +for the corresponding WMI_PDEV_TEMPERATURE_EVENTID +(tag WMI_TAG_PDEV_TEMPERATURE_EVENT) to get the temperature and pdev_id. + +Export the reported value in millidegrees Celsius as required by hwmon. +The temperature reported is per-radio (pdev). In a multi-radio wiphy under a +single phy, a separate hwmon device is created for each radio. + +Sample command and output: +$ cat /sys/devices/pci0000:00/.../ieee80211/phyX/hwmonY/temp1_input +$ 50000 + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 +Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 + +Co-developed-by: Aishwarya R +Signed-off-by: Aishwarya R +Signed-off-by: Maharaja Kennadyrajan +Reviewed-by: Vasanthakumar Thiagarajan +Link: https://patch.msgid.link/20260223132622.43464-1-maharaja.kennadyrajan@oss.qualcomm.com +Signed-off-by: Jeff Johnson +--- + drivers/net/wireless/ath/ath12k/Makefile | 1 + + drivers/net/wireless/ath/ath12k/core.c | 13 ++++ + drivers/net/wireless/ath/ath12k/core.h | 3 + + drivers/net/wireless/ath/ath12k/mac.c | 4 + + drivers/net/wireless/ath/ath12k/thermal.c | 124 ++++++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath12k/thermal.h | 40 ++++++++++ + drivers/net/wireless/ath/ath12k/wmi.c | 57 +++++++------- + 7 files changed, 211 insertions(+), 31 deletions(-) + create mode 100644 drivers/net/wireless/ath/ath12k/thermal.c + create mode 100644 drivers/net/wireless/ath/ath12k/thermal.h + +--- a/drivers/net/wireless/ath/ath12k/core.c ++++ b/drivers/net/wireless/ath/ath12k/core.c +@@ -857,11 +857,22 @@ static int ath12k_core_pdev_create(struc + return ret; + } + ++ ret = ath12k_thermal_register(ab); ++ if (ret) { ++ ath12k_err(ab, "could not register thermal device: %d\n", ret); ++ goto err_dp_pdev_free; ++ } ++ + return 0; ++ ++err_dp_pdev_free: ++ ath12k_dp_pdev_free(ab); ++ return ret; + } + + static void ath12k_core_pdev_destroy(struct ath12k_base *ab) + { ++ ath12k_thermal_unregister(ab); + ath12k_dp_pdev_free(ab); + } + +@@ -1350,6 +1361,7 @@ static int ath12k_core_reconfigure_on_cr + int ret, total_vdev; + + mutex_lock(&ab->core_lock); ++ ath12k_thermal_unregister(ab); + ath12k_dp_pdev_free(ab); + ath12k_ce_cleanup_pipes(ab); + ath12k_wmi_detach(ab); +@@ -1491,6 +1503,7 @@ static void ath12k_core_pre_reconfigure_ + complete(&ar->vdev_delete_done); + complete(&ar->bss_survey_done); + complete_all(&ar->regd_update_completed); ++ complete_all(&ar->thermal.wmi_sync); + + wake_up(&ar->dp.tx_empty_waitq); + idr_for_each(&ar->txmgmt_idr, +--- a/drivers/net/wireless/ath/ath12k/core.h ++++ b/drivers/net/wireless/ath/ath12k/core.h +@@ -34,6 +34,7 @@ + #include "wow.h" + #include "debugfs_htt_stats.h" + #include "coredump.h" ++#include "thermal.h" + + #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) + +@@ -846,6 +847,8 @@ struct ath12k { + + s8 max_allowed_tx_power; + struct ath12k_pdev_rssi_offsets rssi_info; ++ ++ struct ath12k_thermal thermal; + }; + + struct ath12k_hw { +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -14057,6 +14057,10 @@ static void ath12k_mac_setup(struct ath1 + init_completion(&ar->mlo_setup_done); + init_completion(&ar->completed_11d_scan); + init_completion(&ar->regd_update_completed); ++ init_completion(&ar->thermal.wmi_sync); ++ ++ ar->thermal.temperature = 0; ++ ar->thermal.hwmon_dev = NULL; + + INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); + wiphy_work_init(&ar->scan.vdev_clean_wk, ath12k_scan_vdev_clean_work); +--- a/drivers/net/wireless/ath/ath12k/Makefile ++++ b/drivers/net/wireless/ath/ath12k/Makefile +@@ -30,6 +30,7 @@ ath12k-$(CPTCFG_ATH12K_TRACING) += trace + ath12k-$(CONFIG_PM) += wow.o + ath12k-$(CPTCFG_ATH12K_COREDUMP) += coredump.o + ath12k-$(CPTCFG_NL80211_TESTMODE) += testmode.o ++ath12k-$(CONFIG_THERMAL) += thermal.o + + # for tracing framework to find trace.h + CFLAGS_trace.o := -I$(src) +--- /dev/null ++++ b/drivers/net/wireless/ath/ath12k/thermal.c +@@ -0,0 +1,124 @@ ++// SPDX-License-Identifier: BSD-3-Clause-Clear ++/* ++ * Copyright (c) 2020 The Linux Foundation. All rights reserved. ++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "core.h" ++#include "debug.h" ++ ++static ssize_t ath12k_thermal_temp_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct ath12k *ar = dev_get_drvdata(dev); ++ unsigned long time_left; ++ int ret, temperature; ++ ++ guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy); ++ ++ if (ar->ah->state != ATH12K_HW_STATE_ON) ++ return -ENETDOWN; ++ ++ reinit_completion(&ar->thermal.wmi_sync); ++ ret = ath12k_wmi_send_pdev_temperature_cmd(ar); ++ if (ret) { ++ ath12k_warn(ar->ab, "failed to read temperature %d\n", ret); ++ return ret; ++ } ++ ++ if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) ++ return -ESHUTDOWN; ++ ++ time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync, ++ ATH12K_THERMAL_SYNC_TIMEOUT_HZ); ++ if (!time_left) { ++ ath12k_warn(ar->ab, "failed to synchronize thermal read\n"); ++ return -ETIMEDOUT; ++ } ++ ++ spin_lock_bh(&ar->data_lock); ++ temperature = ar->thermal.temperature; ++ spin_unlock_bh(&ar->data_lock); ++ ++ /* display in millidegree celsius */ ++ return sysfs_emit(buf, "%d\n", temperature * 1000); ++} ++ ++void ath12k_thermal_event_temperature(struct ath12k *ar, int temperature) ++{ ++ spin_lock_bh(&ar->data_lock); ++ ar->thermal.temperature = temperature; ++ spin_unlock_bh(&ar->data_lock); ++ complete_all(&ar->thermal.wmi_sync); ++} ++ ++static SENSOR_DEVICE_ATTR_RO(temp1_input, ath12k_thermal_temp, 0); ++ ++static struct attribute *ath12k_hwmon_attrs[] = { ++ &sensor_dev_attr_temp1_input.dev_attr.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(ath12k_hwmon); ++ ++int ath12k_thermal_register(struct ath12k_base *ab) ++{ ++ struct ath12k *ar; ++ int i, j, ret; ++ ++ if (!IS_REACHABLE(CONFIG_HWMON)) ++ return 0; ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ ar = ab->pdevs[i].ar; ++ if (!ar) ++ continue; ++ ++ ar->thermal.hwmon_dev = ++ hwmon_device_register_with_groups(&ar->ah->hw->wiphy->dev, ++ "ath12k_hwmon", ar, ++ ath12k_hwmon_groups); ++ if (IS_ERR(ar->thermal.hwmon_dev)) { ++ ret = PTR_ERR(ar->thermal.hwmon_dev); ++ ar->thermal.hwmon_dev = NULL; ++ ath12k_err(ar->ab, "failed to register hwmon device: %d\n", ++ ret); ++ for (j = i - 1; j >= 0; j--) { ++ ar = ab->pdevs[j].ar; ++ if (!ar) ++ continue; ++ ++ hwmon_device_unregister(ar->thermal.hwmon_dev); ++ ar->thermal.hwmon_dev = NULL; ++ } ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++void ath12k_thermal_unregister(struct ath12k_base *ab) ++{ ++ struct ath12k *ar; ++ int i; ++ ++ if (!IS_REACHABLE(CONFIG_HWMON)) ++ return; ++ ++ for (i = 0; i < ab->num_radios; i++) { ++ ar = ab->pdevs[i].ar; ++ if (!ar) ++ continue; ++ ++ if (ar->thermal.hwmon_dev) { ++ hwmon_device_unregister(ar->thermal.hwmon_dev); ++ ar->thermal.hwmon_dev = NULL; ++ } ++ } ++} +--- /dev/null ++++ b/drivers/net/wireless/ath/ath12k/thermal.h +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: BSD-3-Clause-Clear */ ++/* ++ * Copyright (c) 2020 The Linux Foundation. All rights reserved. ++ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. ++ */ ++ ++#ifndef _ATH12K_THERMAL_ ++#define _ATH12K_THERMAL_ ++ ++#define ATH12K_THERMAL_SYNC_TIMEOUT_HZ (5 * HZ) ++ ++struct ath12k_thermal { ++ struct completion wmi_sync; ++ ++ /* temperature value in Celsius degree protected by data_lock. */ ++ int temperature; ++ struct device *hwmon_dev; ++}; ++ ++#if IS_REACHABLE(CONFIG_THERMAL) ++int ath12k_thermal_register(struct ath12k_base *ab); ++void ath12k_thermal_unregister(struct ath12k_base *ab); ++void ath12k_thermal_event_temperature(struct ath12k *ar, int temperature); ++#else ++static inline int ath12k_thermal_register(struct ath12k_base *ab) ++{ ++ return 0; ++} ++ ++static inline void ath12k_thermal_unregister(struct ath12k_base *ab) ++{ ++} ++ ++static inline void ath12k_thermal_event_temperature(struct ath12k *ar, ++ int temperature) ++{ ++} ++ ++#endif ++#endif /* _ATH12K_THERMAL_ */ +--- a/drivers/net/wireless/ath/ath12k/wmi.c ++++ b/drivers/net/wireless/ath/ath12k/wmi.c +@@ -6674,31 +6674,6 @@ static int ath12k_pull_peer_assoc_conf_e + return 0; + } + +-static int +-ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, struct sk_buff *skb, +- const struct wmi_pdev_temperature_event *ev) +-{ +- const void **tb; +- int ret; +- +- tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); +- if (IS_ERR(tb)) { +- ret = PTR_ERR(tb); +- ath12k_warn(ab, "failed to parse tlv: %d\n", ret); +- return ret; +- } +- +- ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT]; +- if (!ev) { +- ath12k_warn(ab, "failed to fetch pdev temp ev"); +- kfree(tb); +- return -EPROTO; +- } +- +- kfree(tb); +- return 0; +-} +- + static void ath12k_wmi_op_ep_tx_credits(struct ath12k_base *ab) + { + /* try to send pending beacons first. they take priority */ +@@ -8713,25 +8688,45 @@ static void + ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab, + struct sk_buff *skb) + { ++ const struct wmi_pdev_temperature_event *ev; + struct ath12k *ar; +- struct wmi_pdev_temperature_event ev = {}; ++ const void **tb; ++ int temp; ++ u32 pdev_id; + +- if (ath12k_pull_pdev_temp_ev(ab, skb, &ev) != 0) { +- ath12k_warn(ab, "failed to extract pdev temperature event"); ++ tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); ++ if (IS_ERR(tb)) { ++ ath12k_warn(ab, "failed to parse tlv: %ld\n", PTR_ERR(tb)); + return; + } + ++ ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT]; ++ if (!ev) { ++ ath12k_warn(ab, "failed to fetch pdev temp ev\n"); ++ kfree(tb); ++ return; ++ } ++ ++ temp = a_sle32_to_cpu(ev->temp); ++ pdev_id = le32_to_cpu(ev->pdev_id); ++ ++ kfree(tb); ++ + ath12k_dbg(ab, ATH12K_DBG_WMI, +- "pdev temperature ev temp %d pdev_id %d\n", ev.temp, ev.pdev_id); ++ "pdev temperature ev temp %d pdev_id %u\n", ++ temp, pdev_id); + + rcu_read_lock(); + +- ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev.pdev_id)); ++ ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id); + if (!ar) { +- ath12k_warn(ab, "invalid pdev id in pdev temperature ev %d", ev.pdev_id); ++ ath12k_warn(ab, "invalid pdev id %u in pdev temperature ev\n", ++ pdev_id); + goto exit; + } + ++ ath12k_thermal_event_temperature(ar, temp); ++ + exit: + rcu_read_unlock(); + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath12k/100-ath12k-prevent-ltssm-startup-crash.patch b/lede/package/kernel/mac80211/patches-6.18/ath12k/100-ath12k-prevent-ltssm-startup-crash.patch new file mode 100644 index 0000000000..a98c82f818 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath12k/100-ath12k-prevent-ltssm-startup-crash.patch @@ -0,0 +1,17 @@ +Fix ltssm crashes on BPI-Rx boards. +Seems read32/write32 using wrong address which +is not a problem on x86/64 PCI controllers. +But have issues on BPI-Rx boards. + +--- a/drivers/net/wireless/ath/ath12k/pci.c ++++ b/drivers/net/wireless/ath/ath12k/pci.c +@@ -297,6 +297,9 @@ static void ath12k_pci_enable_ltssm(stru + u32 val; + int i; + ++ /* Prevent startup crash on BPI-Rx */ ++ return; ++ + val = ath12k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); + + /* PCIE link seems very unstable after the Hot Reset*/ diff --git a/lede/package/kernel/mac80211/patches-6.18/ath12k/102-wifi-ath12k-limit-WMI_SCAN_CHAN_LIST_CMDID-arg.patch b/lede/package/kernel/mac80211/patches-6.18/ath12k/102-wifi-ath12k-limit-WMI_SCAN_CHAN_LIST_CMDID-arg.patch new file mode 100644 index 0000000000..36d7d681b8 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath12k/102-wifi-ath12k-limit-WMI_SCAN_CHAN_LIST_CMDID-arg.patch @@ -0,0 +1,153 @@ +From patchwork Mon Mar 10 13:28:18 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Mantas +X-Patchwork-Id: 14010032 +X-Patchwork-Delegate: quic_jjohnson@quicinc.com +Received: from mail-lf1-f41.google.com (mail-lf1-f41.google.com + [209.85.167.41]) + (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) + (No client certificate requested) + by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2ADD522A4DA + for ; Mon, 10 Mar 2025 13:28:47 +0000 (UTC) +Authentication-Results: smtp.subspace.kernel.org; + arc=none smtp.client-ip=209.85.167.41 +ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; + t=1741613330; cv=none; + b=Vx8zckt7S92zrauuzzoNjX/1eXhlbq+4R3uNXCWPCBFXXHBuAHrmXrDOQILh1g+IfyWOgpyXyibTTkLg6IWREXcA/OjV+V9ehNaQaHJAt4D14uxuNW6uIDA56myF+bhdmiZnfGZfK3puVBjeCAMbZwGhc81dTR3RaEhKYP93Wcg= +ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; + s=arc-20240116; t=1741613330; c=relaxed/simple; + bh=yRMCaDQnvsF6vQ/w9rLRB/etZre1sSzpWUDTNGX0zAk=; + h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; + b=rFopB9f+nOXbmGbGXoo4SeBAV82xQ6nydiMDCiYAw7sELURejS0lK9xQZolnRGeyNtHnQgix39lrcilr6cdvGMhaziXzS6RYlY2WyoHTMxHwYGUIa9McnJ1AkCczdVv6SgeNUlVVEgAZBqH0Q2pmd5b91h/PMc/aPdQm9SQY8IU= +ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; + dmarc=pass (p=quarantine dis=none) header.from=8devices.com; + spf=pass smtp.mailfrom=8devices.com; + dkim=pass (2048-bit key) header.d=8devices.com header.i=@8devices.com + header.b=LitRbtOU; arc=none smtp.client-ip=209.85.167.41 +Authentication-Results: smtp.subspace.kernel.org; + dmarc=pass (p=quarantine dis=none) header.from=8devices.com +Authentication-Results: smtp.subspace.kernel.org; + spf=pass smtp.mailfrom=8devices.com +Authentication-Results: smtp.subspace.kernel.org; + dkim=pass (2048-bit key) header.d=8devices.com header.i=@8devices.com + header.b="LitRbtOU" +Received: by mail-lf1-f41.google.com with SMTP id + 2adb3069b0e04-5499c5d9691so1866539e87.2 + for ; + Mon, 10 Mar 2025 06:28:47 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=8devices.com; s=8devices; t=1741613326; x=1742218126; + darn=vger.kernel.org; + h=cc:to:message-id:content-transfer-encoding:mime-version:subject + :date:from:from:to:cc:subject:date:message-id:reply-to; + bh=6+w3029kfHch5SeD/z0zur2K64cd98za9hhmN/ji0MY=; + b=LitRbtOUxDhUPycKFo/pzuJu9Y11QmpYSvOmkgM9TcNEOsBvLk8z0EJ7+xy24ijRGJ + Xz16V9Z1kJGkXBK90klI6s3RjVBQf+dxf37t2kdQWdrgOE2VhXjnnV5zP7odCkMmOViw + 2UmKSvagsxc6KojE2OYyd+vR3hmL+4fCtegorXMaRrf0Brje8XJmViAUgbc+IAtfL0Ao + pnig300fAb4WbnmIJIRiOUKoTESjbJRkUehGJkhe1ztiPE1F86AVMXw5IrDBR/WtMin1 + 9nYYDqfSGvI7fOvfStfZ9hS0ShIhBNd5naccyQ7c0xSTvXJ51vUvNvdZuufm9OKsbQ99 + nh4g== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20230601; t=1741613326; x=1742218126; + h=cc:to:message-id:content-transfer-encoding:mime-version:subject + :date:from:x-gm-message-state:from:to:cc:subject:date:message-id + :reply-to; + bh=6+w3029kfHch5SeD/z0zur2K64cd98za9hhmN/ji0MY=; + b=Gx+AX3aIV66kzjGLGOToc2CuQrnfaWn43yZW2rgRpKJv03162undTbo+SdaI8s+8mY + aKrYsNOOqI4h6pHCZsVkBzqVh5ZOs+xJbJaHEETGzyBYA2sy0bdDwDUr0rIzJUD8ZYiw + 736zfMRE2rxfOLoVIcfBLXMUcR2d63n/4wxgr1s5HVV3o8uEZ5gxNDnz5p/QabiWbT3m + AMSVVaOBUTRnd9GcZhzYfKboT7SNrTJz0emqSWPKCWfm8dYIzH3TuIGULfRu5UA1/Y2H + Q6ZbLmcYu5+VDKCtQl4nSmun3WUNAyPoeg5PCB1YcuCpqKcjU8l5Kkn+JxNjYAG432us + Z5xQ== +X-Forwarded-Encrypted: i=1; + AJvYcCVigvWgctGNxtYGpBtNhTPBpQPHa7l14ZVktj/Oe1W8p1xwSIjIViAk2X3sDC23bbrmI41TVZbgJZDGCMFJ6g==@vger.kernel.org +X-Gm-Message-State: AOJu0YxJFjAixTwr8dSwTYmdvbVzm/jbyVk+gQV6pF/9Vep5xeVdJMWa + TE+4MHJDPdO8dA16Yn/y5c8pLBEYKqRlo8uDHNKV6e5ldbv18Xv6bR163j+rVCQ= +X-Gm-Gg: ASbGncsUwV1fquQPNOfmTge/yCSzRhyC7+A8STTBe3n+C2XDK1UV8IswQL5UEXlb268 + mumVPzu1Ex8+Nh+quKWT+CIR3WR0NRXm1oiG0N+Cu2Mm4cm4mipqrV9Yxd6x5OMsG32XKd6r0iQ + gr7joJETyo6k1TGc6i0LyoIabLOCc7Nkeu7BD+URUnBvoeQyXBdJpX0bbdvANKW5DrUeX1GkUA7 + 0o4dZYtRola31Z1W9xZMdSefhmI4zZE4uy/RyR/FkQq2Zqk9FGct8DOKoHpOPa0DHVMy0lQAiNI + KNg6OYtuJY+/6TpDoZzNpooiLi29WL6hqlpkmlZeluuCBG6HlSbZTQ== +X-Google-Smtp-Source: + AGHT+IGIixTut4yqDWp69RPz6EjMMq4lD94Ez1yhsRnow6NgvTk6WmKPLFavYgOJC+xGczTQmaocLw== +X-Received: by 2002:a05:6512:1112:b0:549:5850:f275 with SMTP id + 2adb3069b0e04-54990ec8e60mr4354451e87.50.1741613326121; + Mon, 10 Mar 2025 06:28:46 -0700 (PDT) +Received: from [127.0.1.1] ([78.62.132.154]) + by smtp.gmail.com with ESMTPSA id + 2adb3069b0e04-5498b1bcaecsm1460408e87.200.2025.03.10.06.28.45 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Mon, 10 Mar 2025 06:28:45 -0700 (PDT) +From: Mantas Pucka +Date: Mon, 10 Mar 2025 15:28:18 +0200 +Subject: [PATCH ath-next] wifi: ath12k: limit WMI_SCAN_CHAN_LIST_CMDID + argument size +Precedence: bulk +X-Mailing-List: linux-wireless@vger.kernel.org +List-Id: +List-Subscribe: +List-Unsubscribe: +MIME-Version: 1.0 +Message-Id: <20250310-limit-wmi-chanlist-v1-1-8f0fb45459a7@8devices.com> +X-B4-Tracking: v=1; b=H4sIAPHozmcC/x2MSwqEMBAFryK9tiGJ+MGriIuMtvpAM0MSHEG8u + 9FNQVG8d1IQDwnUZid52RHwdUl0ntGwWDcLY0xORplSFVrxig2R/xv46StCZF0Pn2Y0ibaiNPx + 5mXC8px3ZuLCTI1J/XTfUqQSebgAAAA== +X-Change-ID: 20250310-limit-wmi-chanlist-17cb8d27cba6 +To: ath12k@lists.infradead.org +Cc: Johannes Berg , + Jeff Johnson , linux-wireless@vger.kernel.org, + linux-kernel@vger.kernel.org, Mantas Pucka +X-Mailer: b4 0.14.2 + +When using BDF with both 5GHz and 6GHz bands enabled on QCN9274, interface +fails to start. It happens because FW fails to process +WMI_SCAN_CHAN_LIST_CMDID with argument size >2048, resulting in a command +timeout. The current code allows splitting channel list across multiple WMI +commands but uses WMI max_msg_len (4096) as chunk size, which is still too +large. + +Fix this by limiting the number of channels sent at once, using the value +specified in WMI interface description [1]. + +[1] https://git.codelinaro.org/clo/qsdk/platform/vendor/qcom-opensource/wlan/fw-api/-/blob/NHSS.QSDK.13.0.0.6/fw/wmi_unified.h#L6459 + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Mantas Pucka +--- + drivers/net/wireless/ath/ath12k/wmi.c | 3 +++ + drivers/net/wireless/ath/ath12k/wmi.h | 2 ++ + 2 files changed, 5 insertions(+) + + +--- +base-commit: 42aa76e608ca845c98e79f9e23af0bdb07b2eb1d +change-id: 20250310-limit-wmi-chanlist-17cb8d27cba6 + +Best regards, + +--- a/drivers/net/wireless/ath/ath12k/wmi.c ++++ b/drivers/net/wireless/ath/ath12k/wmi.c +@@ -2894,6 +2894,9 @@ int ath12k_wmi_send_scan_chan_list_cmd(s + max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) / + sizeof(*chan_info); + ++ if (max_chan_limit > WMI_MAX_NUM_CHAN_PER_WMI_CMD) ++ max_chan_limit = WMI_MAX_NUM_CHAN_PER_WMI_CMD; ++ + num_send_chans = min(arg->nallchans, max_chan_limit); + + arg->nallchans -= num_send_chans; +--- a/drivers/net/wireless/ath/ath12k/wmi.h ++++ b/drivers/net/wireless/ath/ath12k/wmi.h +@@ -4004,6 +4004,8 @@ struct wmi_stop_scan_cmd { + __le32 pdev_id; + } __packed; + ++#define WMI_MAX_NUM_CHAN_PER_WMI_CMD 58 ++ + struct ath12k_wmi_scan_chan_list_arg { + struct list_head list; + u32 pdev_id; diff --git a/lede/package/kernel/mac80211/patches-6.18/ath12k/103-wifi-ath12k-fix-5GHz-operation-on-wideband-QCN.patch b/lede/package/kernel/mac80211/patches-6.18/ath12k/103-wifi-ath12k-fix-5GHz-operation-on-wideband-QCN.patch new file mode 100644 index 0000000000..14f6fbb35e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath12k/103-wifi-ath12k-fix-5GHz-operation-on-wideband-QCN.patch @@ -0,0 +1,137 @@ +From patchwork Thu Mar 13 09:00:56 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Mantas +X-Patchwork-Id: 14014575 +X-Patchwork-Delegate: quic_jjohnson@quicinc.com +Received: from mail-lf1-f49.google.com (mail-lf1-f49.google.com + [209.85.167.49]) + (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) + (No client certificate requested) + by smtp.subspace.kernel.org (Postfix) with ESMTPS id F210C2641F0 + for ; Thu, 13 Mar 2025 09:01:28 +0000 (UTC) +Authentication-Results: smtp.subspace.kernel.org; + arc=none smtp.client-ip=209.85.167.49 +ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; + t=1741856491; cv=none; + b=CeFjBZstZXxg4oQQPPON0u0Mw9kvUaCubWSfpcWvN2italvlwccDBr+izqIzCXwxYaoAedVR6iHEQv+LBtIHOsMWHOCI9E6jYAPqjbEUEU0RMdvujKLVFvFXYR4UaRDAMzDGMlFF1qc0pY0sYR4FYfFBBQOarHn2sjZ/csIyj4k= +ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; + s=arc-20240116; t=1741856491; c=relaxed/simple; + bh=oLhlWw1tOovRHEGC4gsbi6BHKYXLNDYOrtVP3tTS5nE=; + h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; + b=baAfN8drFOEwQR9LVuWoVsd3jkMbQECK7Zuc68EzbbJwM4Zb0tbziTk1vvqED+f9JPOMbjRyjvV1hvy3svqZr7OuTZJdSM41D+DsbHvw0jEhaRlKwzpLWuOn9lu56ahcAsvx4A4JRawEK90smoYpejhxkdlSrxqRBh1ey3RwmQU= +ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; + dmarc=pass (p=quarantine dis=none) header.from=8devices.com; + spf=pass smtp.mailfrom=8devices.com; + dkim=pass (2048-bit key) header.d=8devices.com header.i=@8devices.com + header.b=FdBxu3P+; arc=none smtp.client-ip=209.85.167.49 +Authentication-Results: smtp.subspace.kernel.org; + dmarc=pass (p=quarantine dis=none) header.from=8devices.com +Authentication-Results: smtp.subspace.kernel.org; + spf=pass smtp.mailfrom=8devices.com +Authentication-Results: smtp.subspace.kernel.org; + dkim=pass (2048-bit key) header.d=8devices.com header.i=@8devices.com + header.b="FdBxu3P+" +Received: by mail-lf1-f49.google.com with SMTP id + 2adb3069b0e04-54943bb8006so648002e87.0 + for ; + Thu, 13 Mar 2025 02:01:28 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=8devices.com; s=8devices; t=1741856487; x=1742461287; + darn=vger.kernel.org; + h=cc:to:message-id:content-transfer-encoding:mime-version:subject + :date:from:from:to:cc:subject:date:message-id:reply-to; + bh=uj7GGUjO2Cb2hoHrzMda/fIIQwFl12ddzGuw5jrHW8M=; + b=FdBxu3P+gf3qNd4jxSOCYUJ1meLFYAm0ou6lnEyomeeXDBFwITM6FM0cgBdXgmkLWZ + ZKowNImwE9FKqNGxpg2tZ4obR9aM7HzzkxV3TE+1aIiocbr/5xyXQU+/AUvaM3vui/8d + SFiwhX9FwFKdrYi1Og4XFD2aBhA5Fzp0U27grJYGTLchEfkr9Om43y3vZ7w2ENEBU0SO + 7NFmSwx7BmflIybP2sGCUzjacGQzzec0zz256EY7GpZH9r19jgWiCe1YGWdlxDaRhWze + xV4okbZKydpYlUU/qGsgn23cRQuFCvMobvfkmTwsGYwlN4bAzq/cHw83YEFrUzYOngZK + z7bg== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20230601; t=1741856487; x=1742461287; + h=cc:to:message-id:content-transfer-encoding:mime-version:subject + :date:from:x-gm-message-state:from:to:cc:subject:date:message-id + :reply-to; + bh=uj7GGUjO2Cb2hoHrzMda/fIIQwFl12ddzGuw5jrHW8M=; + b=PhLIANoGtdl34d9fFH7uxPyg1K5yPGRwimsWPVhHon98V9QP64+qUbifocbfojxz8u + NEVzhOx0kfmsmkBxUzuRCu6xuTAF8LmjBpAJJxo3/4nqY67np8iZt/MITzx6egbMOUAs + txqj0rzXwr55N/9yAD/QuD6bBcd8PcNMPp0CjFAt39AyK6De3BEIcA7b/eLoY3lifaxJ + 9U5ZZ/dHXwSIr9xuE1EB6pT5FbHcI8iWJTDJ8NdBcmWC8qtGAAMzlzWqHU0nOAJEjwEc + T+oaJr8fTAgq4B5OvS1cNClscZHvoM3zlIoczwPPoBZCtUi2gThz9R4BrBxepdoZl1qq + NZQA== +X-Forwarded-Encrypted: i=1; + AJvYcCUSbJyRkEPLa3fw7FZX3Ci6+/o8dqI0hd6pkVT20pi6Ufgze7nBQXa+qdK3OM5Ng2TFBrym8JoyBo//MwDHng==@vger.kernel.org +X-Gm-Message-State: AOJu0Ywjzq2sFNyTMNPyxDt+721RyXdLbDPrF5PY3LnwpKaTfduyXkMF + K/7N3Cpb/71aQsMXwmIbXAOGeLVWLBQHdYnQLZlsCTjVNArIjgiX7tNB0Mq56+qYtR9PdMrBAt8 + m +X-Gm-Gg: ASbGncvDd0SdjhjPfzaKTXW4e0hclZuKu4pZ4d0XD5/Q6dnv09ZObgGjJbIRrAhYizp + zWc8CwidDk8UYPX/OhiAyDhS4XRKRy2QG03sZh17aHDhishhmCE+mcqe+YUM+F4ns/05sAR2MeP + wu/Rz6NS6UD4ihGNReTORGB3X4n9I5dgdNheFyqbrRX+Js4zXuvn1jgoEWawfovOu/4HAlnv+7p + 1ufgXBXJGVj6+OGzyNOyYloTB/Csok3zU9yBfrU+G19mpGaF86t/6yxmUIXCO+cWfbu2GIhVZp3 + RmSiDo/spnsvtYVGCPc6v9jALz83YcknTLkX8u+08AOkJKK7Mh8rKlCvbfZcB355 +X-Google-Smtp-Source: + AGHT+IE2NulrNIo+M5vahinpDWyI9BdSgzdREdo+l0AN7HhcxOd01ZBOpT3HYFht1EVpKj5T7Edrrw== +X-Received: by 2002:a05:6512:ba6:b0:549:8f21:bc0e with SMTP id + 2adb3069b0e04-54990eb1987mr9398593e87.32.1741856486697; + Thu, 13 Mar 2025 02:01:26 -0700 (PDT) +Received: from [127.0.1.1] ([78.62.132.154]) + by smtp.gmail.com with ESMTPSA id + 2adb3069b0e04-549ba88591csm142134e87.187.2025.03.13.02.01.25 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Thu, 13 Mar 2025 02:01:25 -0700 (PDT) +From: Mantas Pucka +Date: Thu, 13 Mar 2025 11:00:56 +0200 +Subject: [PATCH] wifi: ath12k: fix 5GHz operation on wideband QCN9274 + radios +Precedence: bulk +X-Mailing-List: linux-wireless@vger.kernel.org +List-Id: +List-Subscribe: +List-Unsubscribe: +MIME-Version: 1.0 +Message-Id: <20250313-ath12-wideband-caps-v1-1-23ac4247cd8a@8devices.com> +X-B4-Tracking: v=1; b=H4sIAMee0mcC/x3MQQqAIBBA0avErBvIsUi6SrSwHGs2FhoVhHdPW + r7F/y8kjsIJhuqFyJck2UOBqitYNhtWRnHFQA11jVYa7bkpwlsczzY4XOyRkNqZjOqNcZ6hlEd + kL89/HaecP+zWjGtlAAAA +X-Change-ID: 20250313-ath12-wideband-caps-24b281788dfe +To: ath12k@lists.infradead.org +Cc: Johannes Berg , + Jeff Johnson , linux-wireless@vger.kernel.org, + linux-kernel@vger.kernel.org, Mantas Pucka +X-Mailer: b4 0.14.2 + +Currently ath12k_mac_setup_ht_vht_cap() incorrectly assumes that QCN9274 +radios with 6GHz band can't support 5GHz as well. This prevents the +addition of HT and VHT capabilities for the 5GHz band. Since QCN9274 is +capable of operating in multiple bands, remove the 6GHz support check and +exception for single_pdev_only (i.e. WCN7850). + +Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 + +Signed-off-by: Mantas Pucka +--- + drivers/net/wireless/ath/ath12k/mac.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + + +--- +base-commit: 42aa76e608ca845c98e79f9e23af0bdb07b2eb1d +change-id: 20250313-ath12-wideband-caps-24b281788dfe + +Best regards, + +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -7724,9 +7724,7 @@ static void ath12k_mac_setup_ht_vht_cap( + rate_cap_rx_chainmask); + } + +- if (cap->supported_bands & WMI_HOST_WLAN_5GHZ_CAP && +- (ar->ab->hw_params->single_pdev_only || +- !ar->supports_6ghz)) { ++ if (cap->supported_bands & WMI_HOST_WLAN_5GHZ_CAP) { + band = &ar->mac.sbands[NL80211_BAND_5GHZ]; + ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info; + if (ht_cap_info) diff --git a/lede/package/kernel/mac80211/patches-6.18/ath12k/200-Revert-wifi-ath12k-convert-tasklet-to-BH-workqueue-f.patch b/lede/package/kernel/mac80211/patches-6.18/ath12k/200-Revert-wifi-ath12k-convert-tasklet-to-BH-workqueue-f.patch new file mode 100644 index 0000000000..6df26e0ddd --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath12k/200-Revert-wifi-ath12k-convert-tasklet-to-BH-workqueue-f.patch @@ -0,0 +1,82 @@ +From cd911185014f773f0e227cabfb760b30968c3bca Mon Sep 17 00:00:00 2001 +From: Mantas Pucka +Date: Tue, 27 May 2025 14:13:27 +0300 +Subject: [PATCH] Revert "wifi: ath12k: convert tasklet to BH workqueue for CE + interrupts" + +This reverts commit cdad737160571a98cc4933a62c9f2728e965ab27. +--- + drivers/net/wireless/ath/ath12k/ce.h | 2 +- + drivers/net/wireless/ath/ath12k/pci.c | 14 +++++++------- + 2 files changed, 8 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireless/ath/ath12k/ce.h ++++ b/drivers/net/wireless/ath/ath12k/ce.h +@@ -159,7 +159,7 @@ struct ath12k_ce_pipe { + void (*send_cb)(struct ath12k_ce_pipe *pipe); + void (*recv_cb)(struct ath12k_base *ab, struct sk_buff *skb); + +- struct work_struct intr_wq; ++ struct tasklet_struct intr_tq; + struct ath12k_ce_ring *src_ring; + struct ath12k_ce_ring *dest_ring; + struct ath12k_ce_ring *status_ring; +--- a/drivers/net/wireless/ath/ath12k/pci.c ++++ b/drivers/net/wireless/ath/ath12k/pci.c +@@ -448,9 +448,9 @@ static void ath12k_pci_sync_ce_irqs(stru + } + } + +-static void ath12k_pci_ce_workqueue(struct work_struct *work) ++static void ath12k_pci_ce_tasklet(struct tasklet_struct *t) + { +- struct ath12k_ce_pipe *ce_pipe = from_work(ce_pipe, work, intr_wq); ++ struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); + int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; + + ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); +@@ -472,7 +472,7 @@ static irqreturn_t ath12k_pci_ce_interru + + disable_irq_nosync(ab->irq_num[irq_idx]); + +- queue_work(system_bh_wq, &ce_pipe->intr_wq); ++ tasklet_schedule(&ce_pipe->intr_tq); + + return IRQ_HANDLED; + } +@@ -702,7 +702,7 @@ static int ath12k_pci_config_irq(struct + + irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i; + +- INIT_WORK(&ce_pipe->intr_wq, ath12k_pci_ce_workqueue); ++ tasklet_setup(&ce_pipe->intr_tq, ath12k_pci_ce_tasklet); + + ret = request_irq(irq, ath12k_pci_ce_interrupt_handler, + ab_pci->irq_flags, irq_name[irq_idx], +@@ -985,7 +985,7 @@ static void ath12k_pci_aspm_restore(stru + PCI_EXP_LNKCTL_ASPMC); + } + +-static void ath12k_pci_cancel_workqueue(struct ath12k_base *ab) ++static void ath12k_pci_kill_tasklets(struct ath12k_base *ab) + { + int i; + +@@ -995,7 +995,7 @@ static void ath12k_pci_cancel_workqueue( + if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) + continue; + +- cancel_work_sync(&ce_pipe->intr_wq); ++ tasklet_kill(&ce_pipe->intr_tq); + } + } + +@@ -1003,7 +1003,7 @@ static void ath12k_pci_ce_irq_disable_sy + { + ath12k_pci_ce_irqs_disable(ab); + ath12k_pci_sync_ce_irqs(ab); +- ath12k_pci_cancel_workqueue(ab); ++ ath12k_pci_kill_tasklets(ab); + } + + int ath12k_pci_map_service_to_pipe(struct ath12k_base *ab, u16 service_id, diff --git a/lede/package/kernel/mac80211/patches-6.18/ath12k/300-ath12k-control-thermal-support-via-symbol.patch b/lede/package/kernel/mac80211/patches-6.18/ath12k/300-ath12k-control-thermal-support-via-symbol.patch new file mode 100644 index 0000000000..8d7e2d8cc5 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath12k/300-ath12k-control-thermal-support-via-symbol.patch @@ -0,0 +1,62 @@ +From b6a3bb1561e98980b24f08bffe91327b29091c82 Mon Sep 17 00:00:00 2001 +From: Matt Merhar +Date: Wed, 4 Mar 2026 22:07:15 -0500 +Subject: [PATCH] ath12k: control thermal support via symbol + +As is already done for ath10k and ath11k, add a new ATH12K_THERMAL +symbol to decouple the enablement of thermal support from +CONFIG_THERMAL. + +Signed-off-by: Matt Merhar +--- + drivers/net/wireless/ath/ath12k/Kconfig | 7 +++++++ + drivers/net/wireless/ath/ath12k/Makefile | 2 +- + drivers/net/wireless/ath/ath12k/thermal.h | 2 +- + local-symbols | 1 + + 4 files changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath12k/Kconfig ++++ b/drivers/net/wireless/ath/ath12k/Kconfig +@@ -61,3 +61,10 @@ config ATH12K_COREDUMP + + If unsure, say Y to make it easier to debug problems. But if + dump collection not required choose N. ++ ++config ATH12K_THERMAL ++ bool "ath12k thermal sensor support" ++ depends on ATH12K ++ depends on THERMAL ++ help ++ Enable ath12k thermal sensor support. +--- a/drivers/net/wireless/ath/ath12k/Makefile ++++ b/drivers/net/wireless/ath/ath12k/Makefile +@@ -30,7 +30,7 @@ ath12k-$(CPTCFG_ATH12K_TRACING) += trace + ath12k-$(CONFIG_PM) += wow.o + ath12k-$(CPTCFG_ATH12K_COREDUMP) += coredump.o + ath12k-$(CPTCFG_NL80211_TESTMODE) += testmode.o +-ath12k-$(CONFIG_THERMAL) += thermal.o ++ath12k-$(CPTCFG_ATH12K_THERMAL) += thermal.o + + # for tracing framework to find trace.h + CFLAGS_trace.o := -I$(src) +--- a/drivers/net/wireless/ath/ath12k/thermal.h ++++ b/drivers/net/wireless/ath/ath12k/thermal.h +@@ -17,7 +17,7 @@ struct ath12k_thermal { + struct device *hwmon_dev; + }; + +-#if IS_REACHABLE(CONFIG_THERMAL) ++#if IS_REACHABLE(CPTCFG_ATH12K_THERMAL) + int ath12k_thermal_register(struct ath12k_base *ab); + void ath12k_thermal_unregister(struct ath12k_base *ab); + void ath12k_thermal_event_temperature(struct ath12k *ar, int temperature); +--- a/local-symbols ++++ b/local-symbols +@@ -170,6 +170,7 @@ ATH12K_DEBUG= + ATH12K_DEBUGFS= + ATH12K_TRACING= + ATH12K_COREDUMP= ++ATH12K_THERMAL= + WLAN_VENDOR_ATMEL= + AT76C50X_USB= + WLAN_VENDOR_BROADCOM= diff --git a/lede/package/kernel/mac80211/patches-6.18/ath5k/201-ath5k-WAR-for-AR71xx-PCI-bug.patch b/lede/package/kernel/mac80211/patches-6.18/ath5k/201-ath5k-WAR-for-AR71xx-PCI-bug.patch new file mode 100644 index 0000000000..4fc97dfaec --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath5k/201-ath5k-WAR-for-AR71xx-PCI-bug.patch @@ -0,0 +1,38 @@ +--- a/drivers/net/wireless/ath/ath5k/initvals.c ++++ b/drivers/net/wireless/ath/ath5k/initvals.c +@@ -62,8 +62,14 @@ static const struct ath5k_ini ar5210_ini + { AR5K_IMR, 0 }, + { AR5K_IER, AR5K_IER_DISABLE }, + { AR5K_BSR, 0, AR5K_INI_READ }, ++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79) + { AR5K_TXCFG, AR5K_DMASIZE_128B }, + { AR5K_RXCFG, AR5K_DMASIZE_128B }, ++#else ++ /* WAR for AR71xx PCI bug */ ++ { AR5K_TXCFG, AR5K_DMASIZE_128B }, ++ { AR5K_RXCFG, AR5K_DMASIZE_4B }, ++#endif + { AR5K_CFG, AR5K_INIT_CFG }, + { AR5K_TOPS, 8 }, + { AR5K_RXNOFRM, 8 }, +--- a/drivers/net/wireless/ath/ath5k/dma.c ++++ b/drivers/net/wireless/ath/ath5k/dma.c +@@ -854,10 +854,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah) + * guess we can tweak it and see how it goes ;-) + */ + if (ah->ah_version != AR5K_AR5210) { ++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79) + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); + AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, + AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B); ++#else ++ /* WAR for AR71xx PCI bug */ ++ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, ++ AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); ++ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, ++ AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_4B); ++#endif + } + + /* Pre-enable interrupts on 5211/5212*/ diff --git a/lede/package/kernel/mac80211/patches-6.18/ath5k/411-ath5k_allow_adhoc_and_ap.patch b/lede/package/kernel/mac80211/patches-6.18/ath5k/411-ath5k_allow_adhoc_and_ap.patch new file mode 100644 index 0000000000..1df4aab57e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath5k/411-ath5k_allow_adhoc_and_ap.patch @@ -0,0 +1,46 @@ +--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c ++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c +@@ -86,13 +86,8 @@ ath5k_add_interface(struct ieee80211_hw + goto end; + } + +- /* Don't allow other interfaces if one ad-hoc is configured. +- * TODO: Fix the problems with ad-hoc and multiple other interfaces. +- * We would need to operate the HW in ad-hoc mode to allow TSF updates +- * for the IBSS, but this breaks with additional AP or STA interfaces +- * at the moment. */ +- if (ah->num_adhoc_vifs || +- (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { ++ /* Don't allow more than one ad-hoc interface */ ++ if (ah->num_adhoc_vifs && vif->type == NL80211_IFTYPE_ADHOC) { + ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n"); + ret = -ELNRNG; + goto end; +--- a/drivers/net/wireless/ath/ath5k/base.c ++++ b/drivers/net/wireless/ath/ath5k/base.c +@@ -2009,7 +2009,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) + } + + if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + +- ah->num_mesh_vifs > 1) || ++ ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) || + ah->opmode == NL80211_IFTYPE_MESH_POINT) { + u64 tsf = ath5k_hw_get_tsf64(ah); + u32 tsftu = TSF_TO_TU(tsf); +@@ -2095,7 +2095,7 @@ ath5k_beacon_update_timers(struct ath5k_ + + intval = ah->bintval & AR5K_BEACON_PERIOD; + if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs +- + ah->num_mesh_vifs > 1) { ++ + ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) { + intval /= ATH_BCBUF; /* staggered multi-bss beacons */ + if (intval < 15) + ATH5K_WARN(ah, "intval %u is too low, min 15\n", +@@ -2561,6 +2561,7 @@ static const struct ieee80211_iface_limi + BIT(NL80211_IFTYPE_MESH_POINT) | + #endif + BIT(NL80211_IFTYPE_AP) }, ++ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + }; + + static const struct ieee80211_iface_combination if_comb = { diff --git a/lede/package/kernel/mac80211/patches-6.18/ath5k/420-ath5k_disable_fast_cc.patch b/lede/package/kernel/mac80211/patches-6.18/ath5k/420-ath5k_disable_fast_cc.patch new file mode 100644 index 0000000000..414f49508f --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath5k/420-ath5k_disable_fast_cc.patch @@ -0,0 +1,18 @@ +--- a/drivers/net/wireless/ath/ath5k/reset.c ++++ b/drivers/net/wireless/ath/ath5k/reset.c +@@ -1154,6 +1154,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum + tsf_lo = 0; + mode = 0; + ++#if 0 + /* + * Sanity check for fast flag + * Fast channel change only available +@@ -1161,6 +1162,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum + */ + if (fast && (ah->ah_radio != AR5K_RF2413) && + (ah->ah_radio != AR5K_RF5413)) ++#endif + fast = false; + + /* Disable sleep clock operation diff --git a/lede/package/kernel/mac80211/patches-6.18/ath5k/430-add_ath5k_platform.patch b/lede/package/kernel/mac80211/patches-6.18/ath5k/430-add_ath5k_platform.patch new file mode 100644 index 0000000000..b213e2a819 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath5k/430-add_ath5k_platform.patch @@ -0,0 +1,33 @@ +--- /dev/null ++++ b/include/linux/ath5k_platform.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2008 Atheros Communications Inc. ++ * Copyright (c) 2009 Gabor Juhos ++ * Copyright (c) 2009 Imre Kaloz ++ * Copyright (c) 2010 Daniel Golle ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _LINUX_ATH5K_PLATFORM_H ++#define _LINUX_ATH5K_PLATFORM_H ++ ++#define ATH5K_PLAT_EEP_MAX_WORDS 2048 ++ ++struct ath5k_platform_data { ++ u16 *eeprom_data; ++ u8 *macaddr; ++}; ++ ++#endif /* _LINUX_ATH5K_PLATFORM_H */ diff --git a/lede/package/kernel/mac80211/patches-6.18/ath5k/440-ath5k_channel_bw_debugfs.patch b/lede/package/kernel/mac80211/patches-6.18/ath5k/440-ath5k_channel_bw_debugfs.patch new file mode 100644 index 0000000000..6ff95f95a3 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath5k/440-ath5k_channel_bw_debugfs.patch @@ -0,0 +1,142 @@ +This adds a bwmode debugfs file which can be used to set alternate +channel operating bandwidths. Only tested with AR5413 and only at +5 and 20 mhz channels. + +Signed-off-by: Pat Erley +--- +Other devices will need to be added to the switch in write_file_bwmode + +drivers/net/wireless/ath/ath5k/debug.c | 86 ++++++++++++++++++++++++++++++++ + 1 files changed, 86 insertions(+), 0 deletions(-) + +--- a/drivers/net/wireless/ath/ath5k/debug.c ++++ b/drivers/net/wireless/ath/ath5k/debug.c +@@ -803,6 +803,97 @@ static const struct file_operations fops + .llseek = default_llseek, + }; + ++/* debugfs: bwmode */ ++ ++static ssize_t read_file_bwmode(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_hw *ah = file->private_data; ++ char buf[15]; ++ unsigned int len = 0; ++ ++ int cur_ah_bwmode = ah->ah_bwmode_debug; ++ ++#define print_selected(MODE, LABEL) \ ++ if (cur_ah_bwmode == MODE) \ ++ len += snprintf(buf+len, sizeof(buf)-len, "[%s]", LABEL); \ ++ else \ ++ len += snprintf(buf+len, sizeof(buf)-len, "%s", LABEL); \ ++ len += snprintf(buf+len, sizeof(buf)-len, " "); ++ ++ print_selected(AR5K_BWMODE_5MHZ, "5"); ++ print_selected(AR5K_BWMODE_10MHZ, "10"); ++ print_selected(AR5K_BWMODE_DEFAULT, "20"); ++ print_selected(AR5K_BWMODE_40MHZ, "40"); ++#undef print_selected ++ ++ len += snprintf(buf+len, sizeof(buf)-len, "\n"); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_bwmode(struct file *file, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath5k_hw *ah = file->private_data; ++ char buf[3]; ++ int bw = 20; ++ int tobwmode = AR5K_BWMODE_DEFAULT; ++ ++ if (copy_from_user(buf, userbuf, min(count, sizeof(buf)))) ++ return -EFAULT; ++ ++ /* TODO: Add check for active interface */ ++ ++ if(strncmp(buf, "5", 1) == 0 ) { ++ tobwmode = AR5K_BWMODE_5MHZ; ++ bw = 5; ++ } else if ( strncmp(buf, "10", 2) == 0 ) { ++ tobwmode = AR5K_BWMODE_10MHZ; ++ bw = 10; ++ } else if ( strncmp(buf, "20", 2) == 0 ) { ++ tobwmode = AR5K_BWMODE_DEFAULT; ++ bw = 20; ++ } else if ( strncmp(buf, "40", 2) == 0 ) { ++ tobwmode = AR5K_BWMODE_40MHZ; ++ bw = 40; ++ } else ++ return -EINVAL; ++ ++ ATH5K_INFO(ah, "Changing to %imhz channel width[%i]\n", ++ bw, tobwmode); ++ ++ switch (ah->ah_radio) { ++ /* TODO: only define radios that actually support 5/10mhz channels */ ++ case AR5K_RF5413: ++ case AR5K_RF5110: ++ case AR5K_RF5111: ++ case AR5K_RF5112: ++ case AR5K_RF2413: ++ case AR5K_RF2316: ++ case AR5K_RF2317: ++ case AR5K_RF2425: ++ if(ah->ah_bwmode_debug != tobwmode) { ++ mutex_lock(&ah->lock); ++ ah->ah_bwmode = tobwmode; ++ ah->ah_bwmode_debug = tobwmode; ++ mutex_unlock(&ah->lock); ++ } ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return count; ++} ++ ++static const struct file_operations fops_bwmode = { ++ .read = read_file_bwmode, ++ .write = write_file_bwmode, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; + + /* debugfs: queues etc */ + +@@ -995,6 +1086,8 @@ ath5k_debug_init_device(struct ath5k_hw + debugfs_create_file("queue", 0600, phydir, ah, &fops_queue); + debugfs_create_bool("32khz_clock", 0600, phydir, + &ah->ah_use_32khz_clock); ++ debugfs_create_file("bwmode", S_IWUSR | S_IRUSR, phydir, ah, ++ &fops_bwmode); + } + + /* functions used in other places */ +--- a/drivers/net/wireless/ath/ath5k/ath5k.h ++++ b/drivers/net/wireless/ath/ath5k/ath5k.h +@@ -1372,6 +1372,7 @@ struct ath5k_hw { + u8 ah_coverage_class; + bool ah_ack_bitrate_high; + u8 ah_bwmode; ++ u8 ah_bwmode_debug; + bool ah_short_slot; + + /* Antenna Control */ +--- a/drivers/net/wireless/ath/ath5k/base.c ++++ b/drivers/net/wireless/ath/ath5k/base.c +@@ -465,6 +465,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru + return -EINVAL; + } + ++ if (ah->ah_bwmode_debug != AR5K_BWMODE_DEFAULT) ++ ah->ah_bwmode = ah->ah_bwmode_debug; ++ + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/341-wifi-ath9k-obtain-system-gpios.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/341-wifi-ath9k-obtain-system-gpios.patch new file mode 100644 index 0000000000..9a235aeeb1 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/341-wifi-ath9k-obtain-system-gpios.patch @@ -0,0 +1,273 @@ +From patchwork Tue Apr 23 12:12:33 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Linus Walleij +X-Patchwork-Id: 1926515 +Return-Path: + +X-Original-To: incoming@patchwork.ozlabs.org +Delivered-To: patchwork-incoming@legolas.ozlabs.org +Authentication-Results: legolas.ozlabs.org; + dkim=pass (2048-bit key; + unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 + header.s=google header.b=qX99TQMM; + dkim-atps=neutral +Authentication-Results: legolas.ozlabs.org; + spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org + (client-ip=2604:1380:45e3:2400::1; helo=sv.mirrors.kernel.org; + envelope-from=linux-gpio+bounces-5755-incoming=patchwork.ozlabs.org@vger.kernel.org; + receiver=patchwork.ozlabs.org) +Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org + [IPv6:2604:1380:45e3:2400::1]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) + key-exchange X25519 server-signature ECDSA (secp384r1)) + (No client certificate requested) + by legolas.ozlabs.org (Postfix) with ESMTPS id 4VP1Gc6RZKz1yZP + for ; Tue, 23 Apr 2024 22:12:56 +1000 (AEST) +Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org + [52.25.139.140]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by sv.mirrors.kernel.org (Postfix) with ESMTPS id 5BB9C28522A + for ; Tue, 23 Apr 2024 12:12:55 +0000 (UTC) +Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) + by smtp.subspace.kernel.org (Postfix) with ESMTP id 2F83B8563D; + Tue, 23 Apr 2024 12:12:41 +0000 (UTC) +Authentication-Results: smtp.subspace.kernel.org; + dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org + header.b="qX99TQMM" +X-Original-To: linux-gpio@vger.kernel.org +Received: from mail-lj1-f179.google.com (mail-lj1-f179.google.com + [209.85.208.179]) + (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) + (No client certificate requested) + by smtp.subspace.kernel.org (Postfix) with ESMTPS id A8F3C82865 + for ; Tue, 23 Apr 2024 12:12:37 +0000 (UTC) +Authentication-Results: smtp.subspace.kernel.org; + arc=none smtp.client-ip=209.85.208.179 +ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; + t=1713874361; cv=none; + b=d6RcvcAu8hBYAK8Io489ZHQpJVXPwuokP6iMcAkbvElCerbXD6jAdqdi+RjDlo5C49GHGO4FQ19UwQn/VE//qSwiK1ulTSBp3OkvAmyb7yYAFnDs9AVNWRw+5/NxeFNn3fj5PyvqVymIbaJKabfrOVNwkz/5JMHxEIJtr6Crmog= +ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; + s=arc-20240116; t=1713874361; c=relaxed/simple; + bh=0eXJ5AIjzz1TBGZ8SlshIPrEHZaZwZfYEdof+dSpu4Y=; + h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; + b=EfFtruUxRIGy+jylEiJ2rPEyPCjGCc8ptT9FVxe6s0O/kW38Y6196xVQeiSV2tSKVCEOIO+9HoqmpgdKsJE7gU9++EcrasP96MYpsklYpc2zsWW3b8QEhfxfZ9Ai/idyYihE2u9dQ7a143P/Ij/twDrZTt24wO/mtHDrE5XcCFI= +ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; + dmarc=pass (p=none dis=none) header.from=linaro.org; + spf=pass smtp.mailfrom=linaro.org; + dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org + header.b=qX99TQMM; arc=none smtp.client-ip=209.85.208.179 +Authentication-Results: smtp.subspace.kernel.org; + dmarc=pass (p=none dis=none) header.from=linaro.org +Authentication-Results: smtp.subspace.kernel.org; + spf=pass smtp.mailfrom=linaro.org +Received: by mail-lj1-f179.google.com with SMTP id + 38308e7fff4ca-2dd041acff1so40839131fa.1 + for ; + Tue, 23 Apr 2024 05:12:37 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=linaro.org; s=google; t=1713874356; x=1714479156; + darn=vger.kernel.org; + h=cc:to:message-id:content-transfer-encoding:mime-version:subject + :date:from:from:to:cc:subject:date:message-id:reply-to; + bh=vysJsMiH5IVqdTs4yMwZxZ7nUmt2aG7eBhkn8qm8hvI=; + b=qX99TQMMdHbskFYUaw8c93sIJsUhKmj/WPdyahHcupUhwn5wol4aVoPczkOKYwJZhE + eoInxzjAHIl3UNKyvPPrD4MrbLcSoFT6mTFMsgRQYUghsLattmGcqIebu9XT556dBhsf + DydmpqGgnTOIa+IEknFxg24mo8Xn2LVmDC7LSGEYykUy1xLHd1NSq56YEaYXC7641xeZ + 9TOL0rZszeGld5cCS3013EmEeXQGCC3lAP83Eb48vbFXjPojkN0s40rZ2s8YpVsGT0iP + LeLVtP/E8XJqi4YipKryKSgbgOvQ1Bclle5+s+2qcJQNnSEjekMwR59BIRs3OZH2SRfN + gQdQ== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20230601; t=1713874356; x=1714479156; + h=cc:to:message-id:content-transfer-encoding:mime-version:subject + :date:from:x-gm-message-state:from:to:cc:subject:date:message-id + :reply-to; + bh=vysJsMiH5IVqdTs4yMwZxZ7nUmt2aG7eBhkn8qm8hvI=; + b=jEBH4NQ7SzFi2tnb1lgL06IchnBJoscNgKesjlorvou6X/9wDE/VbgxNFKR0zWwdTk + BEjG/ifFJxLmM9jdaCKu5cJc4yiDNXp7yZd48D71V34zJ4aINAGAx4hcOKqf95neFknx + nsFPpBFnTYFEpCLF0TebVoL6h6ehPzSojmkArzsrMppNvW2cwJ5gDlkqy2y4SezLanmM + 6iU0ksnwE0bb2iLkahhgo00Ejt33yqxwa+3xBfhOe9oYKSSZYnY7qVq055SSwt9IAq+H + REGyJN+GrvupTHagiioYe3LPXDPdOui9ZixXXDllw1t1yGUy+TkJu8xSqtvHEfg81FHP + AxtA== +X-Forwarded-Encrypted: i=1; + AJvYcCUbxzPklfPYrLgyY1I0ycuj7Dh04dcGVonYocA2mzxzlAEV107o0ELlFqr3O9Td+tV/t0eV9ly9YAbTY6n1XPnFXS5dsYYAZw6RHw== +X-Gm-Message-State: AOJu0YxsC7zdakTzntbiRFnN2A7yTrR0x+IpR6ce6eGn5kHeqIBi1km+ + zTVpRulbch3JsmzVDbCbbAAYoBkNgEA568YL6zdjVARnvFwNz1cqatOrR1AXUm0= +X-Google-Smtp-Source: + AGHT+IHBRMGvaJM98f86Z6m/RfVhK2XejjNGF3EvcRq/4x3oGM0DKpd2PbeCJdgmzHjLPVVbdsNzJg== +X-Received: by 2002:a2e:9852:0:b0:2d8:a98d:18e with SMTP id + e18-20020a2e9852000000b002d8a98d018emr7955886ljj.8.1713874355700; + Tue, 23 Apr 2024 05:12:35 -0700 (PDT) +Received: from [192.168.1.140] ([85.235.12.238]) + by smtp.gmail.com with ESMTPSA id + x6-20020a2e7c06000000b002da179d8d25sm1628982ljc.64.2024.04.23.05.12.33 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Tue, 23 Apr 2024 05:12:35 -0700 (PDT) +From: Linus Walleij +Date: Tue, 23 Apr 2024 14:12:33 +0200 +Subject: [PATCH v2] wifi: ath9k: Obtain system GPIOS from descriptors +Precedence: bulk +X-Mailing-List: linux-gpio@vger.kernel.org +List-Id: +List-Subscribe: +List-Unsubscribe: +MIME-Version: 1.0 +Message-Id: <20240423-descriptors-wireless-v2-1-6d1d03b30bfa@linaro.org> +X-B4-Tracking: v=1; b=H4sIALClJ2YC/22Nyw6CMBBFf4XM2hpanrLyPwyL0o4wCaFkxqCG9 + N+txKXLc5Nz7g6CTCjQZTswbiQUlgTmlIGb7DKiIp8YTG7KXBujPIpjWh+BRT2JcUYRNbTeXir + v7FBUkNSV8U6vI3vrE08kSXgfL5v+rr9gof8HN61yhdo1rvJ125T1dabFcjgHHqGPMX4Ao4iiN + LkAAAA= +To: Kalle Valo , + Andy Shevchenko , + Arnd Bergmann , Alban Bedel , + Bartosz Golaszewski , =?utf-8?q?Toke_H=C3=B8iland-J=C3=B8rg?= + =?utf-8?q?ensen?= +Cc: linux-wireless@vger.kernel.org, brcm80211-dev-list.pdl@broadcom.com, + linux-gpio@vger.kernel.org, Linus Walleij +X-Mailer: b4 0.13.0 + +The ath9k has an odd use of system-wide GPIOs: if the chip +does not have internal GPIO capability, it will try to obtain a +GPIO line from the system GPIO controller: + + if (BIT(gpio) & ah->caps.gpio_mask) + ath9k_hw_gpio_cfg_wmac(...); + else if (AR_SREV_SOC(ah)) + ath9k_hw_gpio_cfg_soc(ah, gpio, out, label); + +Where ath9k_hw_gpio_cfg_soc() will attempt to issue +gpio_request_one() passing the local GPIO number of the controller +(0..31) to gpio_request_one(). + +This is somewhat peculiar and possibly even dangerous: there is +nowadays no guarantee of the numbering of these system-wide +GPIOs, and assuming that GPIO 0..31 as used by ath9k would +correspond to GPIOs 0..31 on the system as a whole seems a bit +wild. + +Register all 32 GPIOs at index 0..31 directly in the ATH79K +GPIO driver and associate with WIFI if and only if we are probing +ATH79K wifi from the AHB bus (used for SoCs). + +Signed-off-by: Linus Walleij +--- +Changes in v2: +- Define all the descriptors directly in the ATH79K + GPIO driver in case the driver want to request them directly. +- Link to v1: https://lore.kernel.org/r/20240131-descriptors-wireless-v1-0-e1c7c5d68746@linaro.org +--- + drivers/net/wireless/ath/ath9k/hw.c | 29 ++++++++++++----------- + drivers/net/wireless/ath/ath9k/hw.h | 3 ++- + 2 files changed, 32 insertions(+), 15 deletions(-) + + +--- +base-commit: 4cece764965020c22cff7665b18a012006359095 +change-id: 20240122-descriptors-wireless-b8da95dcab35 + +Best regards, + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -21,7 +21,7 @@ + #include + #include + #include +-#include ++#include + #include + + #include "hw.h" +@@ -2719,19 +2719,25 @@ static void ath9k_hw_gpio_cfg_output_mux + static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out, + const char *label) + { ++ enum gpiod_flags flags = out ? GPIOD_OUT_LOW : GPIOD_IN; ++ struct gpio_desc *gpiod; + int err; + +- if (ah->caps.gpio_requested & BIT(gpio)) ++ if (ah->gpiods[gpio]) + return; + +- err = devm_gpio_request_one(ah->dev, gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label); +- if (err) { ++ /* Obtains a system specific GPIO descriptor from another GPIO controller */ ++ gpiod = gpiod_get_index(NULL, "ath9k", gpio, flags); ++ ++ if (IS_ERR(gpiod)) { ++ err = PTR_ERR(gpiod); + ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n", + gpio, err); + return; + } + +- ah->caps.gpio_requested |= BIT(gpio); ++ gpiod_set_consumer_name(gpiod, label); ++ ah->gpiods[gpio] = gpiod; + } + + static void ath9k_hw_gpio_cfg_wmac(struct ath_hw *ah, u32 gpio, bool out, +@@ -2793,8 +2799,10 @@ void ath9k_hw_gpio_free(struct ath_hw *a + + WARN_ON(gpio >= ah->caps.num_gpio_pins); + +- if (ah->caps.gpio_requested & BIT(gpio)) +- ah->caps.gpio_requested &= ~BIT(gpio); ++ if (ah->gpiods[gpio]) { ++ gpiod_put(ah->gpiods[gpio]); ++ ah->gpiods[gpio] = NULL; ++ } + } + EXPORT_SYMBOL(ath9k_hw_gpio_free); + +@@ -2822,8 +2830,8 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, + val = REG_READ(ah, AR_GPIO_IN(ah)) & BIT(gpio); + else + val = MS_REG_READ(AR, gpio); +- } else if (BIT(gpio) & ah->caps.gpio_requested) { +- val = gpio_get_value(gpio) & BIT(gpio); ++ } else if (ah->gpiods[gpio]) { ++ val = gpiod_get_value(ah->gpiods[gpio]); + } else { + WARN_ON(1); + } +@@ -2846,8 +2854,8 @@ void ath9k_hw_set_gpio(struct ath_hw *ah + AR7010_GPIO_OUT : AR_GPIO_IN_OUT(ah); + + REG_RMW(ah, out_addr, val << gpio, BIT(gpio)); +- } else if (BIT(gpio) & ah->caps.gpio_requested) { +- gpio_set_value(gpio, val); ++ } else if (ah->gpiods[gpio]) { ++ gpiod_set_value(ah->gpiods[gpio], val); + } else { + WARN_ON(1); + } +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -19,6 +19,7 @@ + + #include + #include ++#include + #include + #include + +@@ -302,7 +303,6 @@ struct ath9k_hw_capabilities { + u8 max_rxchains; + u8 num_gpio_pins; + u32 gpio_mask; +- u32 gpio_requested; + u8 rx_hp_qdepth; + u8 rx_lp_qdepth; + u8 rx_status_len; +@@ -783,6 +783,7 @@ struct ath_hw { + struct ath9k_hw_capabilities caps; + struct ath9k_channel channels[ATH9K_NUM_CHANNELS]; + struct ath9k_channel *curchan; ++ struct gpio_desc *gpiods[32]; + + union { + struct ar5416_eeprom_def def; diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/350-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/350-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch new file mode 100644 index 0000000000..d648a3a3e5 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/350-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau +Date: Sat, 9 Jul 2016 15:25:24 +0200 +Subject: [PATCH] ath9k_hw: reset AHB-WMAC interface on AR91xx + +Should fix a few stability issues + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1435,8 +1435,12 @@ static bool ath9k_hw_set_reset(struct at + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, 0); + +- if (AR_SREV_9100(ah)) ++ if (AR_SREV_9100(ah)) { ++ /* Reset the AHB-WMAC interface */ ++ if (ah->external_reset) ++ ah->external_reset(); + udelay(50); ++ } + + return true; + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/351-ath9k_hw-issue-external-reset-for-QCA955x.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/351-ath9k_hw-issue-external-reset-for-QCA955x.patch new file mode 100644 index 0000000000..79e24f6c23 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/351-ath9k_hw-issue-external-reset-for-QCA955x.patch @@ -0,0 +1,129 @@ +From: Felix Fietkau +Date: Sat, 9 Jul 2016 15:26:44 +0200 +Subject: [PATCH] ath9k_hw: issue external reset for QCA955x + +The RTC interface on the SoC needs to be reset along with the rest of +the WMAC. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1312,39 +1312,56 @@ void ath9k_hw_get_delta_slope_vals(struc + *coef_exponent = coef_exp - 16; + } + +-/* AR9330 WAR: +- * call external reset function to reset WMAC if: +- * - doing a cold reset +- * - we have pending frames in the TX queues. +- */ +-static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type) ++static bool ath9k_hw_need_external_reset(struct ath_hw *ah, int type) + { +- int i, npend = 0; ++ int i; + +- for (i = 0; i < AR_NUM_QCU; i++) { +- npend = ath9k_hw_numtxpending(ah, i); +- if (npend) +- break; +- } +- +- if (ah->external_reset && +- (npend || type == ATH9K_RESET_COLD)) { +- int reset_err = 0; +- +- ath_dbg(ath9k_hw_common(ah), RESET, +- "reset MAC via external reset\n"); +- +- reset_err = ah->external_reset(); +- if (reset_err) { +- ath_err(ath9k_hw_common(ah), +- "External reset failed, err=%d\n", +- reset_err); +- return false; ++ if (type == ATH9K_RESET_COLD) ++ return true; ++ ++ if (AR_SREV_9550(ah)) ++ return true; ++ ++ /* AR9330 WAR: ++ * call external reset function to reset WMAC if: ++ * - doing a cold reset ++ * - we have pending frames in the TX queues. ++ */ ++ if (AR_SREV_9330(ah)) { ++ for (i = 0; i < AR_NUM_QCU; i++) { ++ if (ath9k_hw_numtxpending(ah, i)) ++ return true; + } ++ } ++ ++ return false; ++} ++ ++static bool ath9k_hw_external_reset(struct ath_hw *ah, int type) ++{ ++ int err; ++ ++ if (!ah->external_reset || !ath9k_hw_need_external_reset(ah, type)) ++ return true; ++ ++ ath_dbg(ath9k_hw_common(ah), RESET, ++ "reset MAC via external reset\n"); + +- REG_WRITE(ah, AR_RTC_RESET(ah), 1); ++ err = ah->external_reset(); ++ if (err) { ++ ath_err(ath9k_hw_common(ah), ++ "External reset failed, err=%d\n", err); ++ return false; + } + ++ if (AR_SREV_9550(ah)) { ++ REG_WRITE(ah, AR_RTC_RESET(ah), 0); ++ udelay(10); ++ } ++ ++ REG_WRITE(ah, AR_RTC_RESET(ah), 1); ++ udelay(10); ++ + return true; + } + +@@ -1397,24 +1414,24 @@ static bool ath9k_hw_set_reset(struct at + rst_flags |= AR_RTC_RC_MAC_COLD; + } + +- if (AR_SREV_9330(ah)) { +- if (!ath9k_hw_ar9330_reset_war(ah, type)) +- return false; +- } +- + if (ath9k_hw_mci_is_enabled(ah)) + ar9003_mci_check_gpm_offset(ah); + + /* DMA HALT added to resolve ar9300 and ar9580 bus error during +- * RTC_RC reg read ++ * RTC_RC reg read. Also needed for AR9550 external reset + */ +- if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) { ++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) { + REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); + ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK, + 20 * AH_WAIT_TIMEOUT); +- REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); + } + ++ if (!AR_SREV_9100(ah)) ++ ath9k_hw_external_reset(ah, type); ++ ++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) ++ REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); ++ + REG_WRITE(ah, AR_RTC_RC(ah), rst_flags); + + REGWRITE_BUFFER_FLUSH(ah); diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/354-ath9k-force-rx_clear-when-disabling-rx.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/354-ath9k-force-rx_clear-when-disabling-rx.patch new file mode 100644 index 0000000000..8aaccf49b4 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/354-ath9k-force-rx_clear-when-disabling-rx.patch @@ -0,0 +1,35 @@ +From: Felix Fietkau +Date: Sun, 7 Jun 2015 13:53:35 +0200 +Subject: [PATCH] ath9k: force rx_clear when disabling rx + +This makes stopping Rx more reliable and should reduce the frequency of +Rx related DMA stop warnings. Don't use rx_clear in TX99 mode. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau +Signed-off-by: Helmut Schaa +--- + +--- a/drivers/net/wireless/ath/ath9k/mac.c ++++ b/drivers/net/wireless/ath/ath9k/mac.c +@@ -678,13 +678,18 @@ void ath9k_hw_startpcureceive(struct ath + + ath9k_ani_reset(ah, is_scanning); + +- REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); ++ REG_CLR_BIT(ah, AR_DIAG_SW, ++ AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR); + } + EXPORT_SYMBOL(ath9k_hw_startpcureceive); + + void ath9k_hw_abortpcurecv(struct ath_hw *ah) + { +- REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS); ++ u32 reg = AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT; ++ ++ if (!IS_ENABLED(CPTCFG_ATH9K_TX99)) ++ reg |= AR_DIAG_FORCE_RX_CLEAR; ++ REG_SET_BIT(ah, AR_DIAG_SW, reg); + + ath9k_hw_disable_mib_counters(ah); + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/356-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/356-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch new file mode 100644 index 0000000000..9016da963b --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/356-Revert-ath9k-interpret-requested-txpower-in-EIRP-dom.patch @@ -0,0 +1,36 @@ +From: Felix Fietkau +Date: Sat, 14 May 2016 14:51:02 +0200 +Subject: [PATCH] Revert "ath9k: interpret requested txpower in EIRP + domain" + +This reverts commit 71f5137bf010c6faffab50c0ec15374c59c4a411. +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -2975,7 +2975,8 @@ void ath9k_hw_apply_txpower(struct ath_h + { + struct ath_regulatory *reg = ath9k_hw_regulatory(ah); + struct ieee80211_channel *channel; +- int chan_pwr, new_pwr; ++ int chan_pwr, new_pwr, max_gain; ++ int ant_gain, ant_reduction = 0; + u16 ctl = NO_CTL; + + if (!chan) +@@ -2987,9 +2988,14 @@ void ath9k_hw_apply_txpower(struct ath_h + channel = chan->chan; + chan_pwr = min_t(int, channel->max_power * 2, MAX_COMBINED_POWER); + new_pwr = min_t(int, chan_pwr, reg->power_limit); ++ max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2; ++ ++ ant_gain = get_antenna_gain(ah, chan); ++ if (ant_gain > max_gain) ++ ant_reduction = ant_gain - max_gain; + + ah->eep_ops->set_txpower(ah, chan, ctl, +- get_antenna_gain(ah, chan), new_pwr, test); ++ ant_reduction, new_pwr, test); + } + + void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/365-ath9k-adjust-tx-power-reduction-for-US-regulatory-do.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/365-ath9k-adjust-tx-power-reduction-for-US-regulatory-do.patch new file mode 100644 index 0000000000..5e5f3e4f10 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/365-ath9k-adjust-tx-power-reduction-for-US-regulatory-do.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +Date: Wed, 19 Jul 2017 08:49:31 +0200 +Subject: [PATCH] ath9k: adjust tx power reduction for US regulatory + domain + +FCC regulatory rules allow for up to 6 dBi antenna gain. Account for +this in the EEPROM based tx power reduction code. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -2994,6 +2994,10 @@ void ath9k_hw_apply_txpower(struct ath_h + if (ant_gain > max_gain) + ant_reduction = ant_gain - max_gain; + ++ /* FCC allows maximum antenna gain of 6 dBi */ ++ if (reg->region == NL80211_DFS_FCC) ++ ant_reduction = max_t(int, ant_reduction - 12, 0); ++ + ah->eep_ops->set_txpower(ah, chan, ctl, + ant_reduction, new_pwr, test); + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/401-ath9k_blink_default.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/401-ath9k_blink_default.patch new file mode 100644 index 0000000000..7405e594fe --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/401-ath9k_blink_default.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -47,7 +47,7 @@ int ath9k_modparam_nohwcrypt; + module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); + MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); + +-int ath9k_led_blink; ++int ath9k_led_blink = 1; + module_param_named(blink, ath9k_led_blink, int, 0444); + MODULE_PARM_DESC(blink, "Enable LED blink on activity"); + diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/410-ath9k_allow_adhoc_and_ap.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/410-ath9k_allow_adhoc_and_ap.patch new file mode 100644 index 0000000000..978d915c54 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/410-ath9k_allow_adhoc_and_ap.patch @@ -0,0 +1,10 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -836,6 +836,7 @@ static const struct ieee80211_iface_limi + BIT(NL80211_IFTYPE_AP) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) }, ++ { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + }; + + #ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/450-ath9k-enabled-MFP-capability-unconditionally.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/450-ath9k-enabled-MFP-capability-unconditionally.patch new file mode 100644 index 0000000000..dffeb32611 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/450-ath9k-enabled-MFP-capability-unconditionally.patch @@ -0,0 +1,34 @@ +From d946085ff5a331de64e91a2e3c96b9ca79d740f5 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Mon, 15 Jun 2020 00:10:34 +0200 +Subject: [PATCH] ath9k: enabled MFP capability unconditionally + +ath9k will already fallback on software-crypto for chipsets not +supporting IEEE802.11w (MFP). So advertising MFP is not dependent +on disabling HW crypto for all traffic entirely. + +Signed-off-by: David Bauer +--- + drivers/net/wireless/ath/ath9k/init.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -917,6 +917,7 @@ static void ath9k_set_hw_capab(struct at + ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); + ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ++ ieee80211_hw_set(hw, MFP_CAPABLE); + + if (ath9k_ps_enable) + ieee80211_hw_set(hw, SUPPORTS_PS); +@@ -929,9 +930,6 @@ static void ath9k_set_hw_capab(struct at + IEEE80211_RADIOTAP_MCS_HAVE_STBC; + } + +- if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) +- ieee80211_hw_set(hw, MFP_CAPABLE); +- + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_P2P_GO_CTWIN; diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/500-ath9k_eeprom_debugfs.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/500-ath9k_eeprom_debugfs.patch new file mode 100644 index 0000000000..e9bcbebe7f --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/500-ath9k_eeprom_debugfs.patch @@ -0,0 +1,92 @@ +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1430,6 +1430,7 @@ int ath9k_init_debug(struct ath_hw *ah) + + ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah); + ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah); ++ ath9k_cmn_debug_eeprom(sc->debug.debugfs_phy, sc->sc_ah); + + debugfs_create_u32("gpio_mask", 0600, + sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); +--- a/drivers/net/wireless/ath/ath9k/common-debug.c ++++ b/drivers/net/wireless/ath/ath9k/common-debug.c +@@ -261,3 +261,58 @@ void ath9k_cmn_debug_phy_err(struct dent + &fops_phy_err); + } + EXPORT_SYMBOL(ath9k_cmn_debug_phy_err); ++ ++static ssize_t read_file_eeprom(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_hw *ah = file->private_data; ++ struct ath_common *common = ath9k_hw_common(ah); ++ int bytes = 0; ++ int pos = *ppos; ++ int size = 4096; ++ u16 val; ++ int i; ++ ++ if (AR_SREV_9300_20_OR_LATER(ah)) ++ size = 16384; ++ ++ if (*ppos < 0) ++ return -EINVAL; ++ ++ if (count > size - *ppos) ++ count = size - *ppos; ++ ++ for (i = *ppos / 2; count > 0; count -= bytes, *ppos += bytes, i++) { ++ void *from = &val; ++ ++ if (!common->bus_ops->eeprom_read(common, i, &val)) ++ val = 0xffff; ++ ++ if (*ppos % 2) { ++ from++; ++ bytes = 1; ++ } else if (count == 1) { ++ bytes = 1; ++ } else { ++ bytes = 2; ++ } ++ if (copy_to_user(user_buf, from, bytes)) ++ return -EFAULT; ++ user_buf += bytes; ++ } ++ return *ppos - pos; ++} ++ ++static const struct file_operations fops_eeprom = { ++ .read = read_file_eeprom, ++ .open = simple_open, ++ .owner = THIS_MODULE ++}; ++ ++void ath9k_cmn_debug_eeprom(struct dentry *debugfs_phy, ++ struct ath_hw *ah) ++{ ++ debugfs_create_file("eeprom", S_IRUSR, debugfs_phy, ah, ++ &fops_eeprom); ++} ++EXPORT_SYMBOL(ath9k_cmn_debug_eeprom); +--- a/drivers/net/wireless/ath/ath9k/common-debug.h ++++ b/drivers/net/wireless/ath/ath9k/common-debug.h +@@ -69,6 +69,8 @@ void ath9k_cmn_debug_modal_eeprom(struct + struct ath_hw *ah); + void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah); ++void ath9k_cmn_debug_eeprom(struct dentry *debugfs_phy, ++ struct ath_hw *ah); + void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, + struct ath_rx_status *rs); + void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, +--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +@@ -512,6 +512,7 @@ int ath9k_htc_init_debug(struct ath_hw * + + ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); + ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); ++ ath9k_cmn_debug_eeprom(priv->debug.debugfs_phy, priv->ah); + + return 0; + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/501-ath9k_ahb_init.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/501-ath9k_ahb_init.patch new file mode 100644 index 0000000000..2aee171608 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/501-ath9k_ahb_init.patch @@ -0,0 +1,34 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -1132,25 +1132,25 @@ static int __init ath9k_init(void) + { + int error; + +- error = ath_pci_init(); ++ error = ath_ahb_init(); + if (error < 0) { +- pr_err("No PCI devices found, driver not installed\n"); + error = -ENODEV; + goto err_out; + } + +- error = ath_ahb_init(); ++ error = ath_pci_init(); + if (error < 0) { ++ pr_err("No PCI devices found, driver not installed\n"); + error = -ENODEV; +- goto err_pci_exit; ++ goto err_ahb_exit; + } + + dmi_check_system(ath9k_quirks); + + return 0; + +- err_pci_exit: +- ath_pci_exit(); ++ err_ahb_exit: ++ ath_ahb_exit(); + err_out: + return error; + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/510-ath9k_intr_mitigation_tweak.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/510-ath9k_intr_mitigation_tweak.patch new file mode 100644 index 0000000000..75b48b480e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/510-ath9k_intr_mitigation_tweak.patch @@ -0,0 +1,18 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -403,13 +403,8 @@ static void ath9k_hw_init_config(struct + + ah->config.rx_intr_mitigation = true; + +- if (AR_SREV_9300_20_OR_LATER(ah)) { +- ah->config.rimt_last = 500; +- ah->config.rimt_first = 2000; +- } else { +- ah->config.rimt_last = 250; +- ah->config.rimt_first = 700; +- } ++ ah->config.rimt_last = 250; ++ ah->config.rimt_first = 500; + + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) + ah->config.pll_pwrsave = 7; diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/511-ath9k_reduce_rxbuf.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/511-ath9k_reduce_rxbuf.patch new file mode 100644 index 0000000000..d806782889 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/511-ath9k_reduce_rxbuf.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -90,7 +90,7 @@ int ath_descdma_setup(struct ath_softc * + (_l) &= ((_sz) - 1); \ + } while (0) + +-#define ATH_RXBUF 512 ++#define ATH_RXBUF 256 + #define ATH_TXBUF 512 + #define ATH_TXBUF_RESERVE 5 + #define ATH_TXMAXTRY 13 diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/512-ath9k_channelbw_debugfs.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/512-ath9k_channelbw_debugfs.patch new file mode 100644 index 0000000000..ebf8297d52 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/512-ath9k_channelbw_debugfs.patch @@ -0,0 +1,191 @@ +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1431,6 +1431,7 @@ int ath9k_init_debug(struct ath_hw *ah) + ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah); + ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah); + ath9k_cmn_debug_eeprom(sc->debug.debugfs_phy, sc->sc_ah); ++ ath9k_cmn_debug_chanbw(sc->debug.debugfs_phy, sc->sc_ah); + + debugfs_create_u32("gpio_mask", 0600, + sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); +--- a/drivers/net/wireless/ath/ath.h ++++ b/drivers/net/wireless/ath/ath.h +@@ -151,6 +151,7 @@ struct ath_common { + int debug_mask; + enum ath_device_state state; + unsigned long op_flags; ++ u32 chan_bw; + + struct ath_ani ani; + +@@ -181,6 +182,7 @@ struct ath_common { + const struct ath_ops *ops; + const struct ath_bus_ops *bus_ops; + const struct ath_ps_ops *ps_ops; ++ const struct ieee80211_ops *ieee_ops; + + bool btcoex_enabled; + bool disable_ani; +--- a/drivers/net/wireless/ath/ath9k/common.c ++++ b/drivers/net/wireless/ath/ath9k/common.c +@@ -298,11 +298,13 @@ EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_ke + /* + * Update internal channel flags. + */ +-static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, ++static void ath9k_cmn_update_ichannel(struct ath_common *common, ++ struct ath9k_channel *ichan, + struct cfg80211_chan_def *chandef) + { + struct ieee80211_channel *chan = chandef->chan; + u16 flags = 0; ++ int width; + + ichan->channel = chan->center_freq; + ichan->chan = chan; +@@ -310,7 +312,19 @@ static void ath9k_cmn_update_ichannel(st + if (chan->band == NL80211_BAND_5GHZ) + flags |= CHANNEL_5GHZ; + +- switch (chandef->width) { ++ switch (common->chan_bw) { ++ case 5: ++ width = NL80211_CHAN_WIDTH_5; ++ break; ++ case 10: ++ width = NL80211_CHAN_WIDTH_10; ++ break; ++ default: ++ width = chandef->width; ++ break; ++ } ++ ++ switch (width) { + case NL80211_CHAN_WIDTH_5: + flags |= CHANNEL_QUARTER; + break; +@@ -343,10 +357,11 @@ struct ath9k_channel *ath9k_cmn_get_chan + struct cfg80211_chan_def *chandef) + { + struct ieee80211_channel *curchan = chandef->chan; ++ struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_channel *channel; + + channel = &ah->channels[curchan->hw_value]; +- ath9k_cmn_update_ichannel(channel, chandef); ++ ath9k_cmn_update_ichannel(common, channel, chandef); + + return channel; + } +--- a/drivers/net/wireless/ath/ath9k/common-debug.c ++++ b/drivers/net/wireless/ath/ath9k/common-debug.c +@@ -316,3 +316,55 @@ void ath9k_cmn_debug_eeprom(struct dentr + &fops_eeprom); + } + EXPORT_SYMBOL(ath9k_cmn_debug_eeprom); ++ ++static ssize_t read_file_chan_bw(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_hw *ah = file->private_data; ++ struct ath_common *common = ath9k_hw_common(ah); ++ char buf[32]; ++ unsigned int len; ++ ++ len = sprintf(buf, "0x%08x\n", common->chan_bw); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_chan_bw(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_hw *ah = file->private_data; ++ struct ath_common *common = ath9k_hw_common(ah); ++ unsigned long chan_bw; ++ char buf[32]; ++ ssize_t len; ++ ++ len = min(count, sizeof(buf) - 1); ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ if (kstrtoul(buf, 0, &chan_bw)) ++ return -EINVAL; ++ ++ common->chan_bw = chan_bw; ++ if (!test_bit(ATH_OP_INVALID, &common->op_flags)) ++ common->ieee_ops->config(ah->hw, -1, IEEE80211_CONF_CHANGE_CHANNEL); ++ ++ return count; ++} ++ ++static const struct file_operations fops_chanbw = { ++ .read = read_file_chan_bw, ++ .write = write_file_chan_bw, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++void ath9k_cmn_debug_chanbw(struct dentry *debugfs_phy, ++ struct ath_hw *ah) ++{ ++ debugfs_create_file("chanbw", S_IRUSR | S_IWUSR, debugfs_phy, ah, ++ &fops_chanbw); ++} ++EXPORT_SYMBOL(ath9k_cmn_debug_chanbw); +--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +@@ -513,6 +513,7 @@ int ath9k_htc_init_debug(struct ath_hw * + ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); + ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); + ath9k_cmn_debug_eeprom(priv->debug.debugfs_phy, priv->ah); ++ ath9k_cmn_debug_chanbw(priv->debug.debugfs_phy, priv->ah); + + return 0; + } +--- a/drivers/net/wireless/ath/ath9k/common-debug.h ++++ b/drivers/net/wireless/ath/ath9k/common-debug.h +@@ -71,6 +71,8 @@ void ath9k_cmn_debug_base_eeprom(struct + struct ath_hw *ah); + void ath9k_cmn_debug_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah); ++void ath9k_cmn_debug_chanbw(struct dentry *debugfs_phy, ++ struct ath_hw *ah); + void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, + struct ath_rx_status *rs); + void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, +--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c +@@ -631,6 +631,7 @@ static int ath9k_init_priv(struct ath9k_ + priv->ah = ah; + + common = ath9k_hw_common(ah); ++ common->ieee_ops = &ath9k_htc_ops; + common->ops = &ah->reg_ops; + common->ps_ops = &ath9k_htc_ps_ops; + common->bus_ops = &ath9k_usb_bus_ops; +@@ -746,9 +747,9 @@ static void ath9k_set_hw_capab(struct at + + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | +- WIPHY_FLAG_HAS_CHANNEL_SWITCH; +- +- hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; ++ WIPHY_FLAG_HAS_CHANNEL_SWITCH | ++ WIPHY_FLAG_SUPPORTS_5_10_MHZ | ++ WIPHY_FLAG_SUPPORTS_TDLS; + + hw->queues = 4; + hw->max_listen_interval = 1; +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -691,6 +691,7 @@ static int ath9k_init_softc(u16 devid, s + if (!ath9k_is_chanctx_enabled()) + sc->cur_chan->hw_queue_base = 0; + ++ common->ieee_ops = &ath9k_ops; + common->ops = &ah->reg_ops; + common->bus_ops = bus_ops; + common->ps_ops = &ath9k_ps_ops; diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/513-ath9k_add_pci_ids.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/513-ath9k_add_pci_ids.patch new file mode 100644 index 0000000000..3adb2b2d02 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/513-ath9k_add_pci_ids.patch @@ -0,0 +1,30 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -663,6 +663,7 @@ int ath9k_hw_init(struct ath_hw *ah) + + /* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */ + switch (ah->hw_version.devid) { ++ case AR9300_DEVID_INVALID: + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR5416_AR9100_DEVID: +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -37,6 +37,7 @@ + + #define ATHEROS_VENDOR_ID 0x168c + ++#define AR9300_DEVID_INVALID 0xabcd + #define AR5416_DEVID_PCI 0x0023 + #define AR5416_DEVID_PCIE 0x0024 + #define AR9160_DEVID_PCI 0x0027 +--- a/drivers/net/wireless/ath/ath9k/pci.c ++++ b/drivers/net/wireless/ath/ath9k/pci.c +@@ -772,6 +772,7 @@ static const struct pci_device_id ath_pc + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + #endif + ++ { PCI_VDEVICE(ATHEROS, 0xabcd) }, /* PCI-E internal chip default ID */ + { 0 } + }; + diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/530-ath9k_extra_leds.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/530-ath9k_extra_leds.patch new file mode 100644 index 0000000000..b92c19849e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/530-ath9k_extra_leds.patch @@ -0,0 +1,267 @@ +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -844,6 +844,9 @@ static inline int ath9k_dump_btcoex(stru + #ifdef CPTCFG_MAC80211_LEDS + void ath_init_leds(struct ath_softc *sc); + void ath_deinit_leds(struct ath_softc *sc); ++int ath_create_gpio_led(struct ath_softc *sc, int gpio, const char *name, ++ const char *trigger, bool active_low); ++ + #else + static inline void ath_init_leds(struct ath_softc *sc) + { +@@ -980,6 +983,13 @@ void ath_ant_comb_scan(struct ath_softc + + #define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */ + ++struct ath_led { ++ struct list_head list; ++ struct ath_softc *sc; ++ const struct gpio_led *gpio; ++ struct led_classdev cdev; ++}; ++ + struct ath_softc { + struct ieee80211_hw *hw; + struct device *dev; +@@ -1035,9 +1045,8 @@ struct ath_softc { + spinlock_t chan_lock; + + #ifdef CPTCFG_MAC80211_LEDS +- bool led_registered; +- char led_name[32]; +- struct led_classdev led_cdev; ++ const char *led_default_trigger; ++ struct list_head leds; + #endif + + #ifdef CPTCFG_ATH9K_DEBUGFS +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -39,61 +39,111 @@ static void ath_fill_led_pin(struct ath_ + else + ah->led_pin = ATH_LED_PIN_DEF; + } ++} ++ ++static void ath_led_brightness(struct led_classdev *led_cdev, ++ enum led_brightness brightness) ++{ ++ struct ath_led *led = container_of(led_cdev, struct ath_led, cdev); ++ struct ath_softc *sc = led->sc; ++ ++ ath9k_ps_wakeup(sc); ++ ath9k_hw_set_gpio(sc->sc_ah, led->gpio->gpio, ++ (brightness != LED_OFF) ^ led->gpio->active_low); ++ ath9k_ps_restore(sc); ++} ++ ++static int ath_add_led(struct ath_softc *sc, struct ath_led *led) ++{ ++ const struct gpio_led *gpio = led->gpio; ++ int ret; ++ ++ led->cdev.name = gpio->name; ++ led->cdev.default_trigger = gpio->default_trigger; ++ led->cdev.brightness_set = ath_led_brightness; ++ ++ ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->cdev); ++ if (ret < 0) ++ return ret; ++ ++ led->sc = sc; ++ list_add(&led->list, &sc->leds); + + /* Configure gpio for output */ +- ath9k_hw_gpio_request_out(ah, ah->led_pin, "ath9k-led", ++ ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + +- /* LED off, active low */ +- ath9k_hw_set_gpio(ah, ah->led_pin, ah->config.led_active_high ? 0 : 1); ++ /* LED off */ ++ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low); ++ ++ return 0; + } + +-static void ath_led_brightness(struct led_classdev *led_cdev, +- enum led_brightness brightness) ++int ath_create_gpio_led(struct ath_softc *sc, int gpio_num, const char *name, ++ const char *trigger, bool active_low) + { +- struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); +- u32 val = (brightness == LED_OFF); ++ struct ath_led *led; ++ struct gpio_led *gpio; ++ char *_name; ++ int ret; + +- if (sc->sc_ah->config.led_active_high) +- val = !val; ++ led = kzalloc(sizeof(*led) + sizeof(*gpio) + strlen(name) + 1, ++ GFP_KERNEL); ++ if (!led) ++ return -ENOMEM; ++ ++ led->gpio = gpio = (struct gpio_led *) (led + 1); ++ _name = (char *) (led->gpio + 1); ++ ++ strcpy(_name, name); ++ gpio->name = _name; ++ gpio->gpio = gpio_num; ++ gpio->active_low = active_low; ++ gpio->default_trigger = trigger; ++ ++ ret = ath_add_led(sc, led); ++ if (unlikely(ret < 0)) ++ kfree(led); + +- ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val); ++ return ret; + } + + void ath_deinit_leds(struct ath_softc *sc) + { +- if (!sc->led_registered) +- return; ++ struct ath_led *led; + +- ath_led_brightness(&sc->led_cdev, LED_OFF); +- led_classdev_unregister(&sc->led_cdev); +- +- ath9k_hw_gpio_free(sc->sc_ah, sc->sc_ah->led_pin); ++ while (!list_empty(&sc->leds)) { ++ led = list_first_entry(&sc->leds, struct ath_led, list); ++ list_del(&led->list); ++ ath_led_brightness(&led->cdev, LED_OFF); ++ led_classdev_unregister(&led->cdev); ++ ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio); ++ kfree(led); ++ } + } + + void ath_init_leds(struct ath_softc *sc) + { +- int ret; ++ char led_name[32]; ++ const char *trigger; ++ ++ INIT_LIST_HEAD(&sc->leds); + + if (AR_SREV_9100(sc->sc_ah)) + return; + + ath_fill_led_pin(sc); + +- if (!ath9k_led_blink) +- sc->led_cdev.default_trigger = +- ieee80211_get_radio_led_name(sc->hw); +- +- snprintf(sc->led_name, sizeof(sc->led_name), +- "ath9k-%s", wiphy_name(sc->hw->wiphy)); +- sc->led_cdev.name = sc->led_name; +- sc->led_cdev.brightness_set = ath_led_brightness; ++ snprintf(led_name, sizeof(led_name), "ath9k-%s", ++ wiphy_name(sc->hw->wiphy)); + +- ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev); +- if (ret < 0) +- return; ++ if (ath9k_led_blink) ++ trigger = sc->led_default_trigger; ++ else ++ trigger = ieee80211_get_radio_led_name(sc->hw); + +- sc->led_registered = true; ++ ath_create_gpio_led(sc, sc->sc_ah->led_pin, led_name, trigger, ++ !sc->sc_ah->config.led_active_high); + } + #endif + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -1043,7 +1043,7 @@ int ath9k_init_device(u16 devid, struct + + #ifdef CPTCFG_MAC80211_LEDS + /* must be initialized before ieee80211_register_hw */ +- sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, ++ sc->led_default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, + IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink, + ARRAY_SIZE(ath9k_tpt_blink)); + #endif +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -123,6 +123,61 @@ static const struct file_operations fops + + #define DMA_BUF_LEN 1024 + ++#ifdef CONFIG_MAC80211_LEDS ++ ++static ssize_t write_file_gpio_led(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ char buf[32], *str, *name, *c; ++ ssize_t len; ++ unsigned int gpio; ++ bool active_low = false; ++ ++ len = min(count, sizeof(buf) - 1); ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ name = strchr(buf, ','); ++ if (!name) ++ return -EINVAL; ++ ++ *(name++) = 0; ++ if (!*name) ++ return -EINVAL; ++ ++ c = strchr(name, '\n'); ++ if (c) ++ *c = 0; ++ ++ str = buf; ++ if (*str == '!') { ++ str++; ++ active_low = true; ++ } ++ ++ if (kstrtouint(str, 0, &gpio) < 0) ++ return -EINVAL; ++ ++ if (gpio >= sc->sc_ah->caps.num_gpio_pins) ++ return -EINVAL; ++ ++ if (ath_create_gpio_led(sc, gpio, name, NULL, active_low) < 0) ++ return -EINVAL; ++ ++ return count; ++} ++ ++static const struct file_operations fops_gpio_led = { ++ .write = write_file_gpio_led, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++#endif ++ + + static ssize_t read_file_ani(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +@@ -1391,6 +1446,10 @@ int ath9k_init_debug(struct ath_hw *ah) + ath9k_tx99_init_debug(sc); + ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); + ++#ifdef CONFIG_MAC80211_LEDS ++ debugfs_create_file("gpio_led", S_IWUSR, ++ sc->debug.debugfs_phy, sc, &fops_gpio_led); ++#endif + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/540-ath9k_reduce_ani_interval.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/540-ath9k_reduce_ani_interval.patch new file mode 100644 index 0000000000..e899903478 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/540-ath9k_reduce_ani_interval.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ath/ath9k/ani.h ++++ b/drivers/net/wireless/ath/ath9k/ani.h +@@ -42,7 +42,7 @@ + #define ATH9K_ANI_PERIOD 300 + + /* in ms */ +-#define ATH9K_ANI_POLLINTERVAL 1000 ++#define ATH9K_ANI_POLLINTERVAL 300 + + #define ATH9K_SIG_FIRSTEP_SETTING_MIN 0 + #define ATH9K_SIG_FIRSTEP_SETTING_MAX 20 diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/542-ath9k_debugfs_diag.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/542-ath9k_debugfs_diag.patch new file mode 100644 index 0000000000..19b208a765 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/542-ath9k_debugfs_diag.patch @@ -0,0 +1,139 @@ +--- a/drivers/net/wireless/ath/ath9k/debug.c ++++ b/drivers/net/wireless/ath/ath9k/debug.c +@@ -1429,6 +1429,50 @@ void ath9k_deinit_debug(struct ath_softc + ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); + } + ++static ssize_t read_file_diag(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_hw *ah = sc->sc_ah; ++ char buf[32]; ++ unsigned int len; ++ ++ len = sprintf(buf, "0x%08lx\n", ah->diag); ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t write_file_diag(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ath_softc *sc = file->private_data; ++ struct ath_hw *ah = sc->sc_ah; ++ unsigned long diag; ++ char buf[32]; ++ ssize_t len; ++ ++ len = min(count, sizeof(buf) - 1); ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ if (kstrtoul(buf, 0, &diag)) ++ return -EINVAL; ++ ++ ah->diag = diag; ++ ath9k_hw_update_diag(ah); ++ ++ return count; ++} ++ ++static const struct file_operations fops_diag = { ++ .read = read_file_diag, ++ .write = write_file_diag, ++ .open = simple_open, ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++}; ++ ++ + int ath9k_init_debug(struct ath_hw *ah) + { + struct ath_common *common = ath9k_hw_common(ah); +@@ -1450,6 +1494,8 @@ int ath9k_init_debug(struct ath_hw *ah) + debugfs_create_file("gpio_led", S_IWUSR, + sc->debug.debugfs_phy, sc, &fops_gpio_led); + #endif ++ debugfs_create_file("diag", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++ sc, &fops_diag); + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -522,6 +522,12 @@ enum { + ATH9K_RESET_COLD, + }; + ++enum { ++ ATH_DIAG_DISABLE_RX, ++ ATH_DIAG_DISABLE_TX, ++ ATH_DIAG_TRIGGER_ERROR, ++}; ++ + struct ath9k_hw_version { + u32 magic; + u16 devid; +@@ -811,6 +817,8 @@ struct ath_hw { + u32 ah_flags; + s16 nf_override; + ++ unsigned long diag; ++ + bool reset_power_on; + bool htc_reset_init; + +@@ -1080,6 +1088,7 @@ void ath9k_hw_check_nav(struct ath_hw *a + bool ath9k_hw_check_alive(struct ath_hw *ah); + + bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); ++void ath9k_hw_update_diag(struct ath_hw *ah); + + /* Generic hw timer primitives */ + struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1873,6 +1873,20 @@ u32 ath9k_hw_get_tsf_offset(ktime_t last + } + EXPORT_SYMBOL(ath9k_hw_get_tsf_offset); + ++void ath9k_hw_update_diag(struct ath_hw *ah) ++{ ++ if (test_bit(ATH_DIAG_DISABLE_RX, &ah->diag)) ++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); ++ else ++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); ++ ++ if (test_bit(ATH_DIAG_DISABLE_TX, &ah->diag)) ++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK); ++ else ++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_LOOP_BACK); ++} ++EXPORT_SYMBOL(ath9k_hw_update_diag); ++ + int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, + struct ath9k_hw_cal_data *caldata, bool fastcc) + { +@@ -2081,6 +2095,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st + ar9003_hw_disable_phy_restart(ah); + + ath9k_hw_apply_gpio_override(ah); ++ ath9k_hw_update_diag(ah); + + if (AR_SREV_9565(ah) && common->bt_ant_diversity) + REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -537,6 +537,11 @@ irqreturn_t ath_isr(int irq, void *dev) + return IRQ_HANDLED; + } + ++ if (test_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag)) { ++ status |= ATH9K_INT_FATAL; ++ clear_bit(ATH_DIAG_TRIGGER_ERROR, &ah->diag); ++ } ++ + /* + * If there are no status bits set, then this interrupt was not + * for me (should have been caught above). diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/543-ath9k_entropy_from_adc.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/543-ath9k_entropy_from_adc.patch new file mode 100644 index 0000000000..8966cca2b6 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/543-ath9k_entropy_from_adc.patch @@ -0,0 +1,186 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -723,6 +723,7 @@ struct ath_spec_scan { + * @config_pci_powersave: + * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC + * ++ * @get_adc_entropy: get entropy from the raw ADC I/Q output + * @spectral_scan_config: set parameters for spectral scan and enable/disable it + * @spectral_scan_trigger: trigger a spectral scan run + * @spectral_scan_wait: wait for a spectral scan run to finish +@@ -745,6 +746,7 @@ struct ath_hw_ops { + struct ath_hw_antcomb_conf *antconf); + void (*antdiv_comb_conf_set)(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf); ++ void (*get_adc_entropy)(struct ath_hw *ah, u8 *buf, size_t len); + void (*spectral_scan_config)(struct ath_hw *ah, + struct ath_spec_scan *param); + void (*spectral_scan_trigger)(struct ath_hw *ah); +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -1915,6 +1915,26 @@ void ar9003_hw_init_rate_txpower(struct + } + } + ++static void ar9003_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len) ++{ ++ int i, j; ++ ++ REG_RMW_FIELD(ah, AR_PHY_TEST(ah), AR_PHY_TEST_BBB_OBS_SEL, 1); ++ REG_CLR_BIT(ah, AR_PHY_TEST(ah), AR_PHY_TEST_RX_OBS_SEL_BIT5); ++ REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS(ah), AR_PHY_TEST_CTL_RX_OBS_SEL, 0); ++ ++ memset(buf, 0, len); ++ for (i = 0; i < len; i++) { ++ for (j = 0; j < 4; j++) { ++ u32 regval = REG_READ(ah, AR_PHY_TST_ADC); ++ ++ buf[i] <<= 2; ++ buf[i] |= (regval & 1) | ((regval & BIT(10)) >> 9); ++ udelay(1); ++ } ++ } ++} ++ + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) + { + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); +@@ -1951,6 +1971,7 @@ void ar9003_hw_attach_phy_ops(struct ath + priv_ops->set_radar_params = ar9003_hw_set_radar_params; + priv_ops->fast_chan_change = ar9003_hw_fast_chan_change; + ++ ops->get_adc_entropy = ar9003_hw_get_adc_entropy; + ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; + ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; + ops->spectral_scan_config = ar9003_hw_spectral_scan_config; +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -825,7 +825,8 @@ static void ath9k_init_txpower_limits(st + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ); + +- ah->curchan = curchan; ++ if (curchan) ++ ah->curchan = curchan; + } + + static const struct ieee80211_iface_limit if_limits[] = { +@@ -1003,6 +1004,18 @@ static void ath9k_set_hw_capab(struct at + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); + } + ++static void ath_get_initial_entropy(struct ath_softc *sc) ++{ ++ struct ath_hw *ah = sc->sc_ah; ++ char buf[256]; ++ ++ /* reuse last channel initialized by the tx power test */ ++ ath9k_hw_reset(ah, ah->curchan, NULL, false); ++ ++ ath9k_hw_get_adc_entropy(ah, buf, sizeof(buf)); ++ add_device_randomness(buf, sizeof(buf)); ++} ++ + int ath9k_init_device(u16 devid, struct ath_softc *sc, + const struct ath_bus_ops *bus_ops) + { +@@ -1050,6 +1063,8 @@ int ath9k_init_device(u16 devid, struct + + wiphy_read_of_freq_limits(hw->wiphy); + ++ ath_get_initial_entropy(sc); ++ + /* Register with mac80211 */ + error = ieee80211_register_hw(hw); + if (error) +--- a/drivers/net/wireless/ath/ath9k/hw-ops.h ++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h +@@ -100,6 +100,12 @@ static inline void ath9k_hw_tx99_set_txp + ath9k_hw_ops(ah)->tx99_set_txpower(ah, power); + } + ++static inline void ath9k_hw_get_adc_entropy(struct ath_hw *ah, ++ u8 *buf, size_t len) ++{ ++ ath9k_hw_ops(ah)->get_adc_entropy(ah, buf, len); ++} ++ + #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT + + static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) +--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c +@@ -1340,9 +1340,30 @@ void ar5008_hw_init_rate_txpower(struct + } + } + ++static void ar5008_hw_get_adc_entropy(struct ath_hw *ah, u8 *buf, size_t len) ++{ ++ int i, j; ++ ++ REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1); ++ REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); ++ REG_RMW_FIELD(ah, AR_PHY_TEST2, AR_PHY_TEST2_RX_OBS_SEL, 0); ++ ++ memset(buf, 0, len); ++ for (i = 0; i < len; i++) { ++ for (j = 0; j < 4; j++) { ++ u32 regval = REG_READ(ah, AR_PHY_TST_ADC); ++ ++ buf[i] <<= 2; ++ buf[i] |= (regval & 1) | ((regval & BIT(9)) >> 8); ++ udelay(1); ++ } ++ } ++} ++ + int ar5008_hw_attach_phy_ops(struct ath_hw *ah) + { + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); ++ struct ath_hw_ops *ops = ath9k_hw_ops(ah); + static const u32 ar5416_cca_regs[6] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, +@@ -1357,6 +1378,8 @@ int ar5008_hw_attach_phy_ops(struct ath_ + if (ret) + return ret; + ++ ops->get_adc_entropy = ar5008_hw_get_adc_entropy; ++ + priv_ops->rf_set_freq = ar5008_hw_set_channel; + priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate; + +--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h ++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h +@@ -20,6 +20,12 @@ + #define PHY_AGC_CLR 0x10000000 + #define RFSILENT_BB 0x00002000 + ++#define AR_PHY_TEST_BBB_OBS_SEL 0x780000 ++#define AR_PHY_TEST_BBB_OBS_SEL_S 19 ++ ++#define AR_PHY_TEST_RX_OBS_SEL_BIT5_S 23 ++#define AR_PHY_TEST_RX_OBS_SEL_BIT5 (1 << AR_PHY_TEST_RX_OBS_SEL_BIT5_S) ++ + #define AR_PHY_TURBO 0x9804 + #define AR_PHY_FC_TURBO_MODE 0x00000001 + #define AR_PHY_FC_TURBO_SHORT 0x00000002 +@@ -36,6 +42,9 @@ + + #define AR_PHY_TEST2 0x9808 + ++#define AR_PHY_TEST2_RX_OBS_SEL 0x3C00 ++#define AR_PHY_TEST2_RX_OBS_SEL_S 10 ++ + #define AR_PHY_TIMING2 0x9810 + #define AR_PHY_TIMING3 0x9814 + #define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000 +@@ -393,6 +402,8 @@ + #define AR_PHY_RFBUS_GRANT 0x9C20 + #define AR_PHY_RFBUS_GRANT_EN 0x00000001 + ++#define AR_PHY_TST_ADC 0x9C24 ++ + #define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4 + #define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320 + diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/544-ath9k-ar933x-usb-hang-workaround.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/544-ath9k-ar933x-usb-hang-workaround.patch new file mode 100644 index 0000000000..29afe215f4 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/544-ath9k-ar933x-usb-hang-workaround.patch @@ -0,0 +1,79 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -248,6 +248,19 @@ void ath9k_hw_get_channel_centers(struct + centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT); + } + ++static inline void ath9k_hw_disable_pll_lock_detect(struct ath_hw *ah) ++{ ++ /* On AR9330 and AR9340 devices, some PHY registers must be ++ * tuned to gain better stability/performance. These registers ++ * might be changed while doing wlan reset so the registers must ++ * be reprogrammed after each reset. ++ */ ++ REG_CLR_BIT(ah, AR_PHY_USB_CTRL1, BIT(20)); ++ REG_RMW(ah, AR_PHY_USB_CTRL2, ++ (1 << 21) | (0xf << 22), ++ (1 << 21) | (0x3 << 22)); ++} ++ + /******************/ + /* Chip Revisions */ + /******************/ +@@ -1455,6 +1468,9 @@ static bool ath9k_hw_set_reset(struct at + udelay(50); + } + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return true; + } + +@@ -1554,6 +1570,9 @@ static bool ath9k_hw_chip_reset(struct a + ar9003_hw_internal_regulator_apply(ah); + ath9k_hw_init_pll(ah, chan); + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return true; + } + +@@ -1860,8 +1879,14 @@ static int ath9k_hw_do_fastcc(struct ath + if (AR_SREV_9271(ah)) + ar9002_hw_load_ani_reg(ah, chan); + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return 0; + fail: ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return -EINVAL; + } + +@@ -2106,6 +2131,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st + ath9k_hw_set_radar_params(ah); + } + ++ if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) ++ ath9k_hw_disable_pll_lock_detect(ah); ++ + return 0; + } + EXPORT_SYMBOL(ath9k_hw_reset); +--- a/drivers/net/wireless/ath/ath9k/phy.h ++++ b/drivers/net/wireless/ath/ath9k/phy.h +@@ -48,6 +48,9 @@ + #define AR_PHY_PLL_CONTROL 0x16180 + #define AR_PHY_PLL_MODE 0x16184 + ++#define AR_PHY_USB_CTRL1 0x16c84 ++#define AR_PHY_USB_CTRL2 0x16c88 ++ + enum ath9k_ant_div_comb_lna_conf { + ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2, + ATH_ANT_DIV_COMB_LNA2, diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/545-ath9k_ani_ws_detect.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/545-ath9k_ani_ws_detect.patch new file mode 100644 index 0000000000..6027741cd8 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/545-ath9k_ani_ws_detect.patch @@ -0,0 +1,155 @@ +--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c +@@ -969,55 +969,6 @@ static bool ar5008_hw_ani_control_new(st + * on == 0 means more noise imm + */ + u32 on = param ? 1 : 0; +- /* +- * make register setting for default +- * (weak sig detect ON) come from INI file +- */ +- int m1ThreshLow = on ? +- aniState->iniDef.m1ThreshLow : m1ThreshLow_off; +- int m2ThreshLow = on ? +- aniState->iniDef.m2ThreshLow : m2ThreshLow_off; +- int m1Thresh = on ? +- aniState->iniDef.m1Thresh : m1Thresh_off; +- int m2Thresh = on ? +- aniState->iniDef.m2Thresh : m2Thresh_off; +- int m2CountThr = on ? +- aniState->iniDef.m2CountThr : m2CountThr_off; +- int m2CountThrLow = on ? +- aniState->iniDef.m2CountThrLow : m2CountThrLow_off; +- int m1ThreshLowExt = on ? +- aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off; +- int m2ThreshLowExt = on ? +- aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off; +- int m1ThreshExt = on ? +- aniState->iniDef.m1ThreshExt : m1ThreshExt_off; +- int m2ThreshExt = on ? +- aniState->iniDef.m2ThreshExt : m2ThreshExt_off; +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M1_THRESH_LOW, +- m1ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2_THRESH_LOW, +- m2ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M1_THRESH, m1Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2_THRESH, m2Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2COUNT_THR, m2CountThr); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, +- m2CountThrLow); +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, +--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c +@@ -42,20 +42,6 @@ static const int cycpwrThr1_table[] = + /* level: 0 1 2 3 4 5 6 7 8 */ + { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */ + +-/* +- * register values to turn OFDM weak signal detection OFF +- */ +-static const int m1ThreshLow_off = 127; +-static const int m2ThreshLow_off = 127; +-static const int m1Thresh_off = 127; +-static const int m2Thresh_off = 127; +-static const int m2CountThr_off = 31; +-static const int m2CountThrLow_off = 63; +-static const int m1ThreshLowExt_off = 127; +-static const int m2ThreshLowExt_off = 127; +-static const int m1ThreshExt_off = 127; +-static const int m2ThreshExt_off = 127; +- + static const u8 ofdm2pwr[] = { + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_6_24, +@@ -1065,11 +1051,6 @@ static bool ar9003_hw_ani_control(struct + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_channel *chan = ah->curchan; + struct ar5416AniState *aniState = &ah->ani; +- int m1ThreshLow, m2ThreshLow; +- int m1Thresh, m2Thresh; +- int m2CountThr, m2CountThrLow; +- int m1ThreshLowExt, m2ThreshLowExt; +- int m1ThreshExt, m2ThreshExt; + s32 value, value2; + + switch (cmd & ah->ani_function) { +@@ -1083,61 +1064,6 @@ static bool ar9003_hw_ani_control(struct + */ + u32 on = param ? 1 : 0; + +- if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) +- goto skip_ws_det; +- +- m1ThreshLow = on ? +- aniState->iniDef.m1ThreshLow : m1ThreshLow_off; +- m2ThreshLow = on ? +- aniState->iniDef.m2ThreshLow : m2ThreshLow_off; +- m1Thresh = on ? +- aniState->iniDef.m1Thresh : m1Thresh_off; +- m2Thresh = on ? +- aniState->iniDef.m2Thresh : m2Thresh_off; +- m2CountThr = on ? +- aniState->iniDef.m2CountThr : m2CountThr_off; +- m2CountThrLow = on ? +- aniState->iniDef.m2CountThrLow : m2CountThrLow_off; +- m1ThreshLowExt = on ? +- aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off; +- m2ThreshLowExt = on ? +- aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off; +- m1ThreshExt = on ? +- aniState->iniDef.m1ThreshExt : m1ThreshExt_off; +- m2ThreshExt = on ? +- aniState->iniDef.m2ThreshExt : m2ThreshExt_off; +- +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M1_THRESH_LOW, +- m1ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2_THRESH_LOW, +- m2ThreshLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M1_THRESH, +- m1Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2_THRESH, +- m2Thresh); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR, +- AR_PHY_SFCORR_M2COUNT_THR, +- m2CountThr); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, +- AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, +- m2CountThrLow); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH_LOW, +- m1ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH_LOW, +- m2ThreshLowExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M1_THRESH, +- m1ThreshExt); +- REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, +- AR_PHY_SFCORR_EXT_M2_THRESH, +- m2ThreshExt); +-skip_ws_det: + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/547-ath9k_led_defstate_fix.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/547-ath9k_led_defstate_fix.patch new file mode 100644 index 0000000000..d633c051b0 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/547-ath9k_led_defstate_fix.patch @@ -0,0 +1,29 @@ +From: Michal Cieslakiewicz +Date: Sun, 31 Jan 2016 20:48:49 +0100 +Subject: [PATCH v4 2/8] mac80211: ath9k: set default state for platform LEDs + +Support default state for platform LEDs connected to ath9k device. +Now LEDs are correctly set on or off at ath9k module initialization. +Very useful if power LED is connected to wireless chip. + +Signed-off-by: Michal Cieslakiewicz +--- + gpio.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -73,8 +73,11 @@ static int ath_add_led(struct ath_softc + ath9k_hw_gpio_request_out(sc->sc_ah, gpio->gpio, gpio->name, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + +- /* LED off */ +- ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low); ++ /* Set default LED state */ ++ if (gpio->default_state == LEDS_GPIO_DEFSTATE_ON) ++ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, !gpio->active_low); ++ else ++ ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low); + + return 0; + } diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/548-ath9k_enable_gpio_chip.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/548-ath9k_enable_gpio_chip.patch new file mode 100644 index 0000000000..7b0dd850b1 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/548-ath9k_enable_gpio_chip.patch @@ -0,0 +1,210 @@ +From: Michal Cieslakiewicz +Date: Sun, 31 Jan 2016 21:01:31 +0100 +Subject: [PATCH v4 4/8] mac80211: ath9k: enable access to GPIO + +Enable access to GPIO chip and its pins for Atheros AR92xx +wireless devices. For now AR9285 and AR9287 are supported. + +Signed-off-by: Michal Cieslakiewicz +Signed-off-by: Felix Fietkau +--- +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -25,6 +25,8 @@ + #include + #include + #include ++#include ++#include + + #include "common.h" + #include "debug.h" +@@ -1047,6 +1049,10 @@ struct ath_softc { + #ifdef CPTCFG_MAC80211_LEDS + const char *led_default_trigger; + struct list_head leds; ++#ifdef CONFIG_GPIOLIB ++ struct gpio_chip *gpiochip; ++ struct gpio_desc *gpiodesc; ++#endif + #endif + + #ifdef CPTCFG_ATH9K_DEBUGFS +--- a/drivers/net/wireless/ath/ath9k/gpio.c ++++ b/drivers/net/wireless/ath/ath9k/gpio.c +@@ -16,12 +16,120 @@ + + #include "ath9k.h" + ++#ifdef CPTCFG_MAC80211_LEDS ++ ++#ifdef CONFIG_GPIOLIB ++ ++/***************/ ++/* GPIO Chip */ ++/***************/ ++ ++/* gpio_chip handler : set GPIO to input */ ++static int ath9k_gpio_pin_cfg_input(struct gpio_chip *chip, unsigned offset) ++{ ++ struct ath_softc *sc = gpiochip_get_data(chip); ++ ++ ath9k_hw_gpio_request_in(sc->sc_ah, offset, "ath9k-gpio"); ++ ++ return 0; ++} ++ ++/* gpio_chip handler : set GPIO to output */ ++static int ath9k_gpio_pin_cfg_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ struct ath_softc *sc = gpiochip_get_data(chip); ++ ++ ath9k_hw_gpio_request_out(sc->sc_ah, offset, "ath9k-gpio", ++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_set_gpio(sc->sc_ah, offset, value); ++ ++ return 0; ++} ++ ++/* gpio_chip handler : query GPIO direction (0=out, 1=in) */ ++static int ath9k_gpio_pin_get_dir(struct gpio_chip *chip, unsigned offset) ++{ ++ struct ath_softc *sc = gpiochip_get_data(chip); ++ struct ath_hw *ah = sc->sc_ah; ++ ++ return !((REG_READ(ah, AR_GPIO_OE_OUT(ah)) >> (offset * 2)) & 3); ++} ++ ++/* gpio_chip handler : get GPIO pin value */ ++static int ath9k_gpio_pin_get(struct gpio_chip *chip, unsigned offset) ++{ ++ struct ath_softc *sc = gpiochip_get_data(chip); ++ ++ return ath9k_hw_gpio_get(sc->sc_ah, offset); ++} ++ ++/* gpio_chip handler : set GPIO pin to value */ ++static void ath9k_gpio_pin_set(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ struct ath_softc *sc = gpiochip_get_data(chip); ++ ++ ath9k_hw_set_gpio(sc->sc_ah, offset, value); ++} ++ ++/* register GPIO chip */ ++static void ath9k_register_gpio_chip(struct ath_softc *sc) ++{ ++ struct gpio_chip *gc = sc->gpiochip; ++ struct ath_hw *ah = sc->sc_ah; ++ ++ gc = kzalloc(sizeof(struct gpio_chip), GFP_KERNEL); ++ if (!gc) ++ return; ++ ++ gc->label = kasprintf(GFP_KERNEL, "ath9k-%s", ++ wiphy_name(sc->hw->wiphy)); ++ gc->parent = sc->dev; ++ gc->base = -1; /* determine base automatically */ ++ gc->ngpio = ah->caps.num_gpio_pins; ++ gc->direction_input = ath9k_gpio_pin_cfg_input; ++ gc->direction_output = ath9k_gpio_pin_cfg_output; ++ gc->get_direction = ath9k_gpio_pin_get_dir; ++ gc->get = ath9k_gpio_pin_get; ++ gc->set = ath9k_gpio_pin_set; ++ ++ if (gpiochip_add_data(gc, sc)) { ++ kfree(gc->label); ++ kfree(gc); ++ return; ++ } ++} ++ ++/* remove GPIO chip */ ++static void ath9k_unregister_gpio_chip(struct ath_softc *sc) ++{ ++ struct gpio_chip *gc = sc->gpiochip; ++ ++ if (!gc) ++ return; ++ ++ gpiochip_remove(gc); ++ kfree(gc->label); ++ kfree(gc); ++} ++ ++#else /* CONFIG_GPIOLIB */ ++ ++static inline void ath9k_register_gpio_chip(struct ath_softc *sc) ++{ ++} ++ ++static inline void ath9k_unregister_gpio_chip(struct ath_softc *sc) ++{ ++} ++ ++#endif /* CONFIG_GPIOLIB */ ++ + /********************************/ + /* LED functions */ + /********************************/ + +-#ifdef CPTCFG_MAC80211_LEDS +- + static void ath_fill_led_pin(struct ath_softc *sc) + { + struct ath_hw *ah = sc->sc_ah; +@@ -79,6 +187,12 @@ static int ath_add_led(struct ath_softc + else + ath9k_hw_set_gpio(sc->sc_ah, gpio->gpio, gpio->active_low); + ++#ifdef CONFIG_GPIOLIB ++ /* If there is GPIO chip configured, reserve LED pin */ ++ if (sc->gpiochip) ++ sc->gpiodesc = gpiod_get(sc->dev, gpio->name, GPIOD_ASIS); ++#endif ++ + return 0; + } + +@@ -117,16 +231,23 @@ void ath_deinit_leds(struct ath_softc *s + + while (!list_empty(&sc->leds)) { + led = list_first_entry(&sc->leds, struct ath_led, list); ++#ifdef CONFIG_GPIOLIB ++ /* If there is GPIO chip configured, free LED pin */ ++ if (sc->gpiochip) ++ gpiod_put(sc->gpiodesc); ++#endif + list_del(&led->list); + ath_led_brightness(&led->cdev, LED_OFF); + led_classdev_unregister(&led->cdev); + ath9k_hw_gpio_free(sc->sc_ah, led->gpio->gpio); + kfree(led); + } ++ ath9k_unregister_gpio_chip(sc); + } + + void ath_init_leds(struct ath_softc *sc) + { ++ struct device_node *np = sc->dev->of_node; + char led_name[32]; + const char *trigger; + +@@ -135,6 +256,15 @@ void ath_init_leds(struct ath_softc *sc) + if (AR_SREV_9100(sc->sc_ah)) + return; + ++ if (!np) ++ ath9k_register_gpio_chip(sc); ++ ++ /* setup gpio controller only if requested and skip the led_pin setup */ ++ if (of_property_read_bool(np, "gpio-controller")) { ++ ath9k_register_gpio_chip(sc); ++ return; ++ } ++ + ath_fill_led_pin(sc); + + snprintf(led_name, sizeof(led_name), "ath9k-%s", diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/550-ath9k-of.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/550-ath9k-of.patch new file mode 100644 index 0000000000..2db6177b28 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/550-ath9k-of.patch @@ -0,0 +1,166 @@ +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -28,6 +28,11 @@ + + #include "ath9k.h" + ++#ifdef CONFIG_ATH79 ++#include ++#include ++#endif ++ + struct ath9k_eeprom_ctx { + struct completion complete; + struct ath_hw *ah; +@@ -242,6 +247,81 @@ static unsigned int ath9k_reg_rmw(void * + return val; + } + ++#ifdef CONFIG_ATH79 ++#define QCA955X_DDR_CTL_CONFIG 0x108 ++#define QCA955X_DDR_CTL_CONFIG_ACT_WMAC BIT(23) ++ ++static int ar913x_wmac_reset(void) ++{ ++ ath79_device_reset_set(AR913X_RESET_AMBA2WMAC); ++ mdelay(10); ++ ++ ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC); ++ mdelay(10); ++ ++ return 0; ++} ++ ++static int ar933x_wmac_reset(void) ++{ ++ int retries = 20; ++ ++ ath79_device_reset_set(AR933X_RESET_WMAC); ++ ath79_device_reset_clear(AR933X_RESET_WMAC); ++ ++ while (1) { ++ u32 bootstrap; ++ ++ bootstrap = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); ++ if ((bootstrap & AR933X_BOOTSTRAP_EEPBUSY) == 0) ++ return 0; ++ ++ if (retries-- == 0) ++ break; ++ ++ udelay(10000); ++ } ++ ++ pr_err("ar933x: WMAC reset timed out"); ++ return -ETIMEDOUT; ++} ++ ++static int qca955x_wmac_reset(void) ++{ ++ int i; ++ ++ /* Try to wait for WMAC DDR activity to stop */ ++ for (i = 0; i < 10; i++) { ++ if (!(__raw_readl(ath79_ddr_base + QCA955X_DDR_CTL_CONFIG) & ++ QCA955X_DDR_CTL_CONFIG_ACT_WMAC)) ++ break; ++ ++ udelay(10); ++ } ++ ++ ath79_device_reset_set(QCA955X_RESET_RTC); ++ udelay(10); ++ ath79_device_reset_clear(QCA955X_RESET_RTC); ++ udelay(10); ++ ++ return 0; ++} ++ ++ ++static int ar9330_get_soc_revision(void) ++{ ++ if (ath79_soc_rev == 1) ++ return ath79_soc_rev; ++ ++ return 0; ++} ++ ++static int ath79_get_soc_revision(void) ++{ ++ return ath79_soc_rev; ++} ++#endif ++ + /**************************/ + /* Initialization */ + /**************************/ +@@ -626,6 +706,7 @@ static int ath9k_of_init(struct ath_soft + struct ath_common *common = ath9k_hw_common(ah); + enum ath_bus_type bus_type = common->bus_ops->ath_bus_type; + char eeprom_name[100]; ++ u32 mask; + int ret; + + if (!of_device_is_available(np)) +@@ -633,6 +714,43 @@ static int ath9k_of_init(struct ath_soft + + ath_dbg(common, CONFIG, "parsing configuration from OF node\n"); + ++ if (!of_property_read_u32(np, "qca,gpio-mask", &mask)) ++ ah->caps.gpio_mask = mask; ++ ++ if (of_property_read_bool(np, "qca,tx-gain-buffalo")) ++ ah->config.tx_gain_buffalo = true; ++ ++#ifdef CONFIG_ATH79 ++ if (ah->hw_version.devid == AR5416_AR9100_DEVID) { ++ ah->external_reset = ar913x_wmac_reset; ++ } else if (ah->hw_version.devid == AR9300_DEVID_AR9330) { ++ ah->get_mac_revision = ar9330_get_soc_revision; ++ u32 t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); ++ ah->is_clk_25mhz = !(t & AR933X_BOOTSTRAP_REF_CLK_40); ++ ah->external_reset = ar933x_wmac_reset; ++ } else if (ah->hw_version.devid == AR9300_DEVID_AR9340) { ++ ah->get_mac_revision = ath79_get_soc_revision; ++ u32 t = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); ++ ah->is_clk_25mhz = !(t & AR934X_BOOTSTRAP_REF_CLK_40); ++ } else if (ah->hw_version.devid == AR9300_DEVID_AR953X) { ++ ah->get_mac_revision = ath79_get_soc_revision; ++ /* ++ * QCA953x only supports 25MHz refclk. ++ * Some vendors have an invalid bootstrap option ++ * set, which would break the WMAC here. ++ */ ++ ah->is_clk_25mhz = true; ++ } else if (ah->hw_version.devid == AR9300_DEVID_QCA955X) { ++ u32 t = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP); ++ ah->is_clk_25mhz = !(t & QCA955X_BOOTSTRAP_REF_CLK_40); ++ ah->external_reset = qca955x_wmac_reset; ++ } else if (ah->hw_version.devid == AR9300_DEVID_QCA956X) { ++ ah->get_mac_revision = ath79_get_soc_revision; ++ u32 t = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP); ++ ah->is_clk_25mhz = !(t & QCA956X_BOOTSTRAP_REF_CLK_40); ++ } ++#endif ++ + if (of_property_read_bool(np, "qca,no-eeprom")) { + /* ath9k-eeprom--.bin */ + scnprintf(eeprom_name, sizeof(eeprom_name), +@@ -651,6 +769,17 @@ static int ath9k_of_init(struct ath_soft + if (ret == -EPROBE_DEFER) + return ret; + ++ np = of_get_child_by_name(np, "led"); ++ if (np && of_device_is_available(np)) { ++ u32 led_pin; ++ ++ if (!of_property_read_u32(np, "led-sources", &led_pin)) ++ ah->led_pin = led_pin; ++ ++ ah->config.led_active_high = !of_property_read_bool(np, "led-active-low"); ++ of_node_put(np); ++ } ++ + return 0; + } + diff --git a/lede/package/kernel/mac80211/patches-6.18/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch b/lede/package/kernel/mac80211/patches-6.18/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch new file mode 100644 index 0000000000..8f762848ae --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch @@ -0,0 +1,406 @@ +--- a/drivers/net/wireless/ath/ath9k/channel.c ++++ b/drivers/net/wireless/ath/ath9k/channel.c +@@ -15,6 +15,7 @@ + */ + + #include "ath9k.h" ++#include "hsr.h" + + /* Set/change channels. If the channel is really being changed, it's done + * by resetting the chip. To accomplish this we must first cleanup any pending +@@ -22,6 +23,7 @@ + */ + static int ath_set_channel(struct ath_softc *sc) + { ++ struct device_node *np = sc->dev->of_node; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hw *hw = sc->hw; +@@ -42,6 +44,11 @@ static int ath_set_channel(struct ath_so + ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", + chan->center_freq, chandef->width); + ++ if (of_property_read_bool(np, "ubnt,hsr")) { ++ ath9k_hsr_enable(ah, chandef->width, chan->center_freq); ++ ath9k_hsr_status(ah); ++ } ++ + /* update survey stats for the old channel before switching */ + spin_lock_irqsave(&common->cc_lock, flags); + ath_update_survey_stats(sc); +--- /dev/null ++++ b/drivers/net/wireless/ath/ath9k/hsr.c +@@ -0,0 +1,248 @@ ++/* ++ * ++ * The MIT License (MIT) ++ * ++ * Copyright (c) 2015 Kirill Berezin ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hw.h" ++#include "ath9k.h" ++#include "hsr.h" ++ ++#define HSR_GPIO_CSN 8 ++#define HSR_GPIO_CLK 6 ++#define HSR_GPIO_DOUT 7 ++#define HSR_GPIO_DIN 5 ++ ++/* delays are in useconds */ ++#define HSR_DELAY_HALF_TICK 100 ++#define HSR_DELAY_PRE_WRITE 75 ++#define HSR_DELAY_FINAL 20000 ++#define HSR_DELAY_TRAILING 200 ++ ++void ath9k_hsr_init(struct ath_hw *ah) ++{ ++ ath9k_hw_gpio_request_in(ah, HSR_GPIO_DIN, NULL); ++ ath9k_hw_gpio_request_out(ah, HSR_GPIO_CSN, NULL, ++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_gpio_request_out(ah, HSR_GPIO_CLK, NULL, ++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_gpio_request_out(ah, HSR_GPIO_DOUT, NULL, ++ AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0); ++ ++ udelay(HSR_DELAY_TRAILING); ++} ++ ++static u32 ath9k_hsr_write_byte(struct ath_hw *ah, int delay, u32 value) ++{ ++ struct ath_common *common = ath9k_hw_common(ah); ++ int i; ++ u32 rval = 0; ++ ++ udelay(delay); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ for (i = 0; i < 8; ++i) { ++ rval = rval << 1; ++ ++ /* pattern is left to right, that is 7-th bit runs first */ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ } ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath_dbg(common, CONFIG, "ath9k_hsr_write_byte: write byte %d return value is %d %c\n", ++ value, rval, rval > 32 ? rval : '-'); ++ ++ return rval & 0xff; ++} ++ ++static int ath9k_hsr_write_a_chain(struct ath_hw *ah, char *chain, int items) ++{ ++ int status = 0; ++ int i = 0; ++ int err; ++ ++ /* a preamble */ ++ ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ ++ /* clear HSR's reply buffer */ ++ if (status) { ++ int loop = 0; ++ ++ for (loop = 0; (loop < 42) && status; ++loop) ++ status = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, ++ 0); ++ ++ if (loop >= 42) { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n"); ++ return -1; ++ } ++ } ++ ++ for (i = 0; (i < items) && (chain[i] != 0); ++i) ++ ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]); ++ ++ ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ mdelay(HSR_DELAY_FINAL / 1000); ++ ++ /* reply */ ++ memset(chain, 0, items); ++ ++ ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ udelay(HSR_DELAY_TRAILING); ++ ++ for (i = 0; i < (items - 1); ++i) { ++ u32 ret; ++ ++ ret = ath9k_hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ if (ret != 0) ++ chain[i] = (char)ret; ++ else ++ break; ++ ++ udelay(HSR_DELAY_TRAILING); ++ } ++ ++ if (i <= 1) ++ return 0; ++ ++ err = kstrtoint(chain + 1, 10, &i); ++ if (err) ++ return err; ++ ++ return i; ++} ++ ++int ath9k_hsr_disable(struct ath_hw *ah) ++{ ++ char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0}; ++ int ret; ++ ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ((ret > 0) && (*cmd == 'B')) ++ return 0; ++ ++ return -1; ++} ++ ++int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq) ++{ ++ char cmd[10]; ++ int ret; ++ ++ /* Bandwidth argument is 0 sometimes. Assume default 802.11bgn ++ * 20MHz on invalid values ++ */ ++ if ((bw != 5) && (bw != 10) && (bw != 20) && (bw != 40)) ++ bw = 20; ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'b'; ++ snprintf(cmd + 1, 3, "%02d", bw); ++ ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ((*cmd != 'B') || (ret != bw)) { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d)\n", ++ 'b', bw, *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'x'; ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if (*cmd != 'X') { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_enable: failed 'x' command -> reply (%d, %d)\n", ++ *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'm'; ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if (*cmd != 'M') { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_enable: failed 'm' command -> reply (%d, %d)\n", ++ *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'f'; ++ snprintf(cmd + 1, 6, "%05d", fq); ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ((*cmd != 'F') && (ret != fq)) { ++ ATH_DBG_WARN(1, ++ "ath9k_hsr_enable: failed set frequency -> reply (%d, %d)\n", ++ *cmd, ret); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int ath9k_hsr_status(struct ath_hw *ah) ++{ ++ char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ int ret; ++ ++ ret = ath9k_hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if (*cmd != 'S') { ++ ATH_DBG_WARN(1, "ath9k_hsr_status: returned %d,%d\n", *cmd, ++ ret); ++ return -1; ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/net/wireless/ath/ath9k/hsr.h +@@ -0,0 +1,50 @@ ++/* ++ * The MIT License (MIT) ++ * ++ * Copyright (c) 2015 Kirill Berezin ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef HSR_H ++#define HSR_H ++ ++ struct ath_hw; ++ ++#ifdef CPTCFG_ATH9K_UBNTHSR ++ ++void ath9k_hsr_init(struct ath_hw *ah); ++int ath9k_hsr_disable(struct ath_hw *ah); ++int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq); ++int ath9k_hsr_status(struct ath_hw *ah); ++ ++#else ++static inline void ath9k_hsr_init(struct ath_hw *ah) {} ++ ++static inline int ath9k_hsr_enable(struct ath_hw *ah, int bw, int fq) ++{ ++ return 0; ++} ++ ++static inline int ath9k_hsr_disable(struct ath_hw *ah) { return 0; } ++static inline int ath9k_hsr_status(struct ath_hw *ah) { return 0; } ++ ++#endif ++ ++#endif /* HSR_H */ +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -18,6 +18,7 @@ + #include + #include "ath9k.h" + #include "btcoex.h" ++#include "hsr.h" + + static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); +@@ -658,6 +659,7 @@ void ath_reset_work(struct work_struct * + static int ath9k_start(struct ieee80211_hw *hw) + { + struct ath_softc *sc = hw->priv; ++ struct device_node *np = sc->dev->of_node; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; +@@ -736,6 +738,11 @@ static int ath9k_start(struct ieee80211_ + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + } + ++ if (of_property_read_bool(np, "ubnt,hsr")) { ++ ath9k_hsr_init(ah); ++ ath9k_hsr_disable(ah); ++ } ++ + /* + * Reset key cache to sane defaults (all entries cleared) instead of + * semi-random values after suspend/resume. +--- a/drivers/net/wireless/ath/ath9k/Makefile ++++ b/drivers/net/wireless/ath/ath9k/Makefile +@@ -17,6 +17,7 @@ ath9k-$(CPTCFG_ATH9K_DFS_CERTIFIED) += d + ath9k-$(CPTCFG_ATH9K_TX99) += tx99.o + ath9k-$(CPTCFG_ATH9K_WOW) += wow.o + ath9k-$(CPTCFG_ATH9K_HWRNG) += rng.o ++ath9k-$(CPTCFG_ATH9K_UBNTHSR) += hsr.o + + ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o + +--- a/local-symbols ++++ b/local-symbols +@@ -118,6 +118,7 @@ ATH9K_WOW= + ATH9K_RFKILL= + ATH9K_CHANNEL_CONTEXT= + ATH9K_PCOEM= ++ATH9K_UBNTHSR= + ATH9K_PCI_NO_EEPROM= + ATH9K_HTC= + ATH9K_HTC_DEBUGFS= +--- a/drivers/net/wireless/ath/ath9k/Kconfig ++++ b/drivers/net/wireless/ath/ath9k/Kconfig +@@ -58,6 +58,19 @@ config ATH9K_AHB + Say Y, if you have a SoC with a compatible built-in + wireless MAC. Say N if unsure. + ++config ATH9K_UBNTHSR ++ bool "Ubiquiti UniFi Outdoor Plus HSR support" ++ depends on ATH9K ++ ---help--- ++ This options enables code to control the HSR RF ++ filter in the receive path of the Ubiquiti UniFi ++ Outdoor Plus access point. ++ ++ Say Y if you want to use the access point. The ++ code will only be used if the device is detected, ++ so it does not harm other setup other than occupying ++ a bit of memory. ++ + config ATH9K_DEBUGFS + bool "Atheros ath9k debugging" + depends on ATH9K && DEBUG_FS && MAC80211_DEBUGFS diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/040-brcmutil_option.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/040-brcmutil_option.patch new file mode 100644 index 0000000000..3e8505b5b4 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/040-brcmutil_option.patch @@ -0,0 +1,10 @@ +--- a/drivers/net/wireless/broadcom/brcm80211/Kconfig ++++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0-only + config BRCMUTIL +- tristate ++ tristate "Broadcom 802.11 driver utility functions" + depends on m + + config BRCMSMAC diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/810-b43-gpio-mask-module-option.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/810-b43-gpio-mask-module-option.patch new file mode 100644 index 0000000000..295a4cca73 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/810-b43-gpio-mask-module-option.patch @@ -0,0 +1,37 @@ +--- a/drivers/net/wireless/broadcom/b43/b43.h ++++ b/drivers/net/wireless/broadcom/b43/b43.h +@@ -840,6 +840,7 @@ struct b43_wldev { + bool qos_enabled; /* TRUE, if QoS is used. */ + bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ + bool use_pio; /* TRUE if next init should use PIO */ ++ int gpiomask; /* GPIO LED mask as a module parameter */ + + /* PHY/Radio device. */ + struct b43_phy phy; +--- a/drivers/net/wireless/broadcom/b43/main.c ++++ b/drivers/net/wireless/broadcom/b43/main.c +@@ -72,6 +72,11 @@ MODULE_FIRMWARE("b43/ucode40.fw"); + MODULE_FIRMWARE("b43/ucode42.fw"); + MODULE_FIRMWARE("b43/ucode9.fw"); + ++static int modparam_gpiomask = 0x000F; ++module_param_named(gpiomask, modparam_gpiomask, int, 0444); ++MODULE_PARM_DESC(gpiomask, ++ "GPIO mask for LED control (default 0x000F)"); ++ + static int modparam_bad_frames_preempt; + module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); + MODULE_PARM_DESC(bad_frames_preempt, +@@ -2870,10 +2875,10 @@ static int b43_gpio_init(struct b43_wlde + u32 mask, set; + + b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0); +- b43_maskset16(dev, B43_MMIO_GPIO_MASK, ~0, 0xF); ++ b43_maskset16(dev, B43_MMIO_GPIO_MASK, ~0, modparam_gpiomask); + + mask = 0x0000001F; +- set = 0x0000000F; ++ set = modparam_gpiomask; + if (dev->dev->chip_id == 0x4301) { + mask |= 0x0060; + set |= 0x0060; diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/811-b43_no_pio.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/811-b43_no_pio.patch new file mode 100644 index 0000000000..e395d48202 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/811-b43_no_pio.patch @@ -0,0 +1,86 @@ +--- a/drivers/net/wireless/broadcom/b43/Makefile ++++ b/drivers/net/wireless/broadcom/b43/Makefile +@@ -18,7 +18,7 @@ b43-$(CPTCFG_B43_PHY_AC) += phy_ac.o + b43-y += sysfs.o + b43-y += xmit.o + b43-y += dma.o +-b43-y += pio.o ++b43-$(CPTCFG_B43_PIO) += pio.o + b43-y += rfkill.o + b43-y += ppr.o + b43-$(CPTCFG_B43_LEDS) += leds.o +--- a/drivers/net/wireless/broadcom/b43/main.c ++++ b/drivers/net/wireless/broadcom/b43/main.c +@@ -2001,10 +2001,12 @@ static void b43_do_interrupt_thread(stru + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3], + dma_reason[4], dma_reason[5]); ++#ifdef CPTCFG_B43_PIO + b43err(dev->wl, "This device does not support DMA " + "on your system. It will now be switched to PIO.\n"); + /* Fall back to PIO transfers if we get fatal DMA errors! */ + dev->use_pio = true; ++#endif + b43_controller_restart(dev, "DMA error"); + return; + } +--- a/drivers/net/wireless/broadcom/b43/pio.h ++++ b/drivers/net/wireless/broadcom/b43/pio.h +@@ -151,7 +151,7 @@ static inline void b43_piorx_write32(str + b43_write32(q->dev, q->mmio_base + offset, value); + } + +- ++#ifdef CPTCFG_B43_PIO + int b43_pio_init(struct b43_wldev *dev); + void b43_pio_free(struct b43_wldev *dev); + +@@ -162,5 +162,37 @@ void b43_pio_rx(struct b43_pio_rxqueue * + + void b43_pio_tx_suspend(struct b43_wldev *dev); + void b43_pio_tx_resume(struct b43_wldev *dev); ++#else ++static inline int b43_pio_init(struct b43_wldev *dev) ++{ ++ return 0; ++} ++ ++static inline void b43_pio_free(struct b43_wldev *dev) ++{ ++} ++ ++static inline int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) ++{ ++ return 0; ++} ++ ++static inline void b43_pio_handle_txstatus(struct b43_wldev *dev, ++ const struct b43_txstatus *status) ++{ ++} ++ ++static inline void b43_pio_rx(struct b43_pio_rxqueue *q) ++{ ++} ++ ++static inline void b43_pio_tx_suspend(struct b43_wldev *dev) ++{ ++} ++ ++static inline void b43_pio_tx_resume(struct b43_wldev *dev) ++{ ++} ++#endif /* CPTCFG_B43_PIO */ + + #endif /* B43_PIO_H_ */ +--- a/drivers/net/wireless/broadcom/b43/Kconfig ++++ b/drivers/net/wireless/broadcom/b43/Kconfig +@@ -100,7 +100,7 @@ config B43_BCMA_PIO + default y + + config B43_PIO +- bool ++ bool "Broadcom 43xx PIO support" + depends on B43 && B43_SSB + depends on SSB_BLOCKIO + default y diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/812-b43-add-antenna-control.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/812-b43-add-antenna-control.patch new file mode 100644 index 0000000000..70d8f9129d --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/812-b43-add-antenna-control.patch @@ -0,0 +1,133 @@ +--- a/drivers/net/wireless/broadcom/b43/main.c ++++ b/drivers/net/wireless/broadcom/b43/main.c +@@ -1643,7 +1643,7 @@ static void b43_write_beacon_template(st + len, ram_offset, shm_size_offset, rate); + + /* Write the PHY TX control parameters. */ +- antenna = B43_ANTENNA_DEFAULT; ++ antenna = dev->tx_antenna; + antenna = b43_antenna_to_phyctl(antenna); + ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); + /* We can't send beacons with short preamble. Would get PHY errors. */ +@@ -3285,8 +3285,8 @@ static int b43_chip_init(struct b43_wlde + + /* Select the antennae */ + if (phy->ops->set_rx_antenna) +- phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT); +- b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT); ++ phy->ops->set_rx_antenna(dev, dev->rx_antenna); ++ b43_mgmtframe_txantenna(dev, dev->tx_antenna); + + if (phy->type == B43_PHYTYPE_B) { + value16 = b43_read16(dev, 0x005E); +@@ -3988,7 +3988,6 @@ static int b43_op_config(struct ieee8021 + struct b43_wldev *dev = wl->current_dev; + struct b43_phy *phy = &dev->phy; + struct ieee80211_conf *conf = &hw->conf; +- int antenna; + int err = 0; + + mutex_lock(&wl->mutex); +@@ -4031,11 +4030,9 @@ static int b43_op_config(struct ieee8021 + } + + /* Antennas for RX and management frame TX. */ +- antenna = B43_ANTENNA_DEFAULT; +- b43_mgmtframe_txantenna(dev, antenna); +- antenna = B43_ANTENNA_DEFAULT; ++ b43_mgmtframe_txantenna(dev, dev->tx_antenna); + if (phy->ops->set_rx_antenna) +- phy->ops->set_rx_antenna(dev, antenna); ++ phy->ops->set_rx_antenna(dev, dev->rx_antenna); + + if (wl->radio_enabled != phy->radio_on) { + if (wl->radio_enabled) { +@@ -5178,6 +5175,49 @@ static int b43_op_get_survey(struct ieee + return 0; + } + ++static int b43_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, ++ u32 tx_ant, u32 rx_ant) ++{ ++ struct b43_wl *wl = hw_to_b43_wl(hw); ++ struct b43_wldev *dev = wl->current_dev; ++ ++ if (tx_ant == 1 && rx_ant == 1) { ++ dev->tx_antenna = B43_ANTENNA0; ++ dev->rx_antenna = B43_ANTENNA0; ++ } ++ else if (tx_ant == 2 && rx_ant == 2) { ++ dev->tx_antenna = B43_ANTENNA1; ++ dev->rx_antenna = B43_ANTENNA1; ++ } ++ else if ((tx_ant & 3) == 3 && (rx_ant & 3) == 3) { ++ dev->tx_antenna = B43_ANTENNA_DEFAULT; ++ dev->rx_antenna = B43_ANTENNA_DEFAULT; ++ } ++ else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++ ++static int b43_op_get_antenna(struct ieee80211_hw *hw, int radio_idx, ++ u32 *tx_ant, u32 *rx_ant) ++{ ++ struct b43_wl *wl = hw_to_b43_wl(hw); ++ struct b43_wldev *dev = wl->current_dev; ++ ++ switch (dev->tx_antenna) { ++ case B43_ANTENNA0: ++ *tx_ant = 1; *rx_ant = 1; break; ++ case B43_ANTENNA1: ++ *tx_ant = 2; *rx_ant = 2; break; ++ case B43_ANTENNA_DEFAULT: ++ *tx_ant = 3; *rx_ant = 3; break; ++ } ++ return 0; ++} ++ + static const struct ieee80211_ops b43_hw_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, +@@ -5204,6 +5244,8 @@ static const struct ieee80211_ops b43_hw + .sw_scan_complete = b43_op_sw_scan_complete_notifier, + .get_survey = b43_op_get_survey, + .rfkill_poll = b43_rfkill_poll, ++ .set_antenna = b43_op_set_antenna, ++ .get_antenna = b43_op_get_antenna, + }; + + /* Hard-reset the chip. Do not call this directly. +@@ -5505,6 +5547,8 @@ static int b43_one_core_attach(struct b4 + if (!wldev) + goto out; + ++ wldev->rx_antenna = B43_ANTENNA_DEFAULT; ++ wldev->tx_antenna = B43_ANTENNA_DEFAULT; + wldev->use_pio = b43_modparam_pio; + wldev->dev = dev; + wldev->wl = wl; +@@ -5596,6 +5640,9 @@ static struct b43_wl *b43_wireless_init( + + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + ++ hw->wiphy->available_antennas_rx = 0x3; ++ hw->wiphy->available_antennas_tx = 0x3; ++ + wl->hw_registered = false; + hw->max_rates = 2; + SET_IEEE80211_DEV(hw, dev->dev); +--- a/drivers/net/wireless/broadcom/b43/b43.h ++++ b/drivers/net/wireless/broadcom/b43/b43.h +@@ -841,6 +841,8 @@ struct b43_wldev { + bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ + bool use_pio; /* TRUE if next init should use PIO */ + int gpiomask; /* GPIO LED mask as a module parameter */ ++ int rx_antenna; /* Used RX antenna (B43_ANTENNAxxx) */ ++ int tx_antenna; /* Used TX antenna (B43_ANTENNAxxx) */ + + /* PHY/Radio device. */ + struct b43_phy phy; diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/813-b43-reduce-number-of-RX-slots.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/813-b43-reduce-number-of-RX-slots.patch new file mode 100644 index 0000000000..85c52c0282 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/813-b43-reduce-number-of-RX-slots.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/broadcom/b43/dma.h ++++ b/drivers/net/wireless/broadcom/b43/dma.h +@@ -170,7 +170,7 @@ struct b43_dmadesc_generic { + + /* DMA engine tuning knobs */ + #define B43_TXRING_SLOTS 256 +-#define B43_RXRING_SLOTS 256 ++#define B43_RXRING_SLOTS 32 + #define B43_DMA0_RX_FW598_BUFSIZE (B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN) + #define B43_DMA0_RX_FW351_BUFSIZE (B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN) + diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/814-b43-only-use-gpio-0-1-for-led.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/814-b43-only-use-gpio-0-1-for-led.patch new file mode 100644 index 0000000000..f7aa413208 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/814-b43-only-use-gpio-0-1-for-led.patch @@ -0,0 +1,17 @@ +--- a/drivers/net/wireless/broadcom/b43/main.c ++++ b/drivers/net/wireless/broadcom/b43/main.c +@@ -2887,6 +2887,14 @@ static int b43_gpio_init(struct b43_wlde + } else if (dev->dev->chip_id == 0x5354) { + /* Don't allow overtaking buttons GPIOs */ + set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */ ++ } else if (dev->dev->chip_id == BCMA_CHIP_ID_BCM4716 || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM47162 || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM5356 || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM5357 || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM53572) { ++ /* just use gpio 0 and 1 for 2.4 GHz wifi led */ ++ set &= 0x3; ++ mask &= 0x3; + } + + if (0 /* FIXME: conditional unknown */ ) { diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/815-b43-always-take-overlapping-devs.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/815-b43-always-take-overlapping-devs.patch new file mode 100644 index 0000000000..3700eaa1a0 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/815-b43-always-take-overlapping-devs.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/broadcom/b43/main.c ++++ b/drivers/net/wireless/broadcom/b43/main.c +@@ -114,7 +114,7 @@ static int b43_modparam_pio; + module_param_named(pio, b43_modparam_pio, int, 0644); + MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO"); + +-static int modparam_allhwsupport = !IS_ENABLED(CPTCFG_BRCMSMAC); ++static int modparam_allhwsupport = 1; + module_param_named(allhwsupport, modparam_allhwsupport, int, 0444); + MODULE_PARM_DESC(allhwsupport, "Enable support for all hardware (even it if overlaps with the brcmsmac driver)"); + diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/850-brcmsmac-remove-extra-regulation-restriction.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/850-brcmsmac-remove-extra-regulation-restriction.patch new file mode 100644 index 0000000000..3c93386b30 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/850-brcmsmac-remove-extra-regulation-restriction.patch @@ -0,0 +1,27 @@ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +@@ -58,19 +58,12 @@ + (((c) < 149) ? 3 : 4)))) + + #define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0) +-#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \ +- NL80211_RRF_NO_IR) ++#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, 0) + +-#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \ +- NL80211_RRF_NO_IR) +-#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \ +- NL80211_RRF_DFS | \ +- NL80211_RRF_NO_IR) +-#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \ +- NL80211_RRF_DFS | \ +- NL80211_RRF_NO_IR) +-#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \ +- NL80211_RRF_NO_IR) ++#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, 0) ++#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, 0) ++#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, 0) ++#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, 0) + + static const struct ieee80211_regdomain brcms_regdom_x2 = { + .n_reg_rules = 6, diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/860-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/860-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch new file mode 100644 index 0000000000..9992ccfe37 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/860-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch @@ -0,0 +1,49 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 9 Jul 2015 00:07:59 +0200 +Subject: [PATCH] brcmfmac: workaround bug with some inconsistent BSSes state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Rafał Miłecki +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -983,8 +983,36 @@ static struct wireless_dev *brcmf_cfg802 + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_pub *drvr = cfg->pub; + struct wireless_dev *wdev; ++ struct net_device *dev; + int err; + ++ /* ++ * There is a bug with in-firmware BSS management. When adding virtual ++ * interface brcmfmac first tells firmware to create new BSS and then ++ * it creates new struct net_device. ++ * ++ * If creating/registering netdev(ice) fails, BSS remains in some bugged ++ * state. It conflicts with existing BSSes by overtaking their auth ++ * requests. ++ * ++ * It results in one BSS (addresss X) sending beacons and another BSS ++ * (address Y) replying to authentication requests. This makes interface ++ * unusable as AP. ++ * ++ * To workaround this bug we may try to guess if register_netdev(ice) ++ * will fail. The most obvious case is using interface name that already ++ * exists. This is actually quite likely with brcmfmac & some user space ++ * scripts as brcmfmac doesn't allow deleting virtual interfaces. ++ * So this bug can be triggered even by something trivial like: ++ * iw dev wlan0 delete ++ * iw phy phy0 interface add wlan0 type __ap ++ */ ++ dev = dev_get_by_name(&init_net, name); ++ if (dev) { ++ dev_put(dev); ++ return ERR_PTR(-ENFILE); ++ } ++ + brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); + err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type); + if (err) { diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/870-01-rpi-6.12-brcmfmac-adds-support-for-BCM43341-wifi.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/870-01-rpi-6.12-brcmfmac-adds-support-for-BCM43341-wifi.patch new file mode 100644 index 0000000000..23526c9365 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/870-01-rpi-6.12-brcmfmac-adds-support-for-BCM43341-wifi.patch @@ -0,0 +1,29 @@ +From 88759af56f126e6e151f07fa9efc7447079fca9d Mon Sep 17 00:00:00 2001 +From: Cheong2K +Date: Fri, 26 Feb 2016 18:20:10 +0800 +Subject: [PATCH] brcmfmac: adds support for BCM43341 wifi + +Signed-off-by: Phil Elwell +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 3 ++- + 3 files changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -609,6 +609,7 @@ BRCMF_FW_DEF(4329, "brcmfmac4329-sdio"); + BRCMF_FW_DEF(4330, "brcmfmac4330-sdio"); + BRCMF_FW_DEF(4334, "brcmfmac4334-sdio"); + BRCMF_FW_DEF(43340, "brcmfmac43340-sdio"); ++BRCMF_FW_DEF(43341, "brcmfmac43341-sdio"); + BRCMF_FW_DEF(4335, "brcmfmac4335-sdio"); + BRCMF_FW_DEF(43362, "brcmfmac43362-sdio"); + BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); +@@ -641,7 +642,7 @@ static const struct brcmf_firmware_mappi + BRCMF_FW_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330), + BRCMF_FW_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334), + BRCMF_FW_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340), +- BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340), ++ BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43341), + BRCMF_FW_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), + BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), + BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/870-02-rpi-6.12-brcmfmac-Prefer-a-ccode-from-OTP-over-nvram-file.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/870-02-rpi-6.12-brcmfmac-Prefer-a-ccode-from-OTP-over-nvram-file.patch new file mode 100644 index 0000000000..bff8e2dac3 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/870-02-rpi-6.12-brcmfmac-Prefer-a-ccode-from-OTP-over-nvram-file.patch @@ -0,0 +1,130 @@ +From 3ac592da09acb47b728ef320e9fecde55c8e0824 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 26 Jun 2020 11:51:05 +0100 +Subject: [PATCH] brcmfmac: Prefer a ccode from OTP over nvram file + +Allow the nvram file to set a default ccode (regulatory domain) without +overriding one set in OTP. + +Signed-off-by: Phil Elwell +--- + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 39 +++++++++++++------ + .../broadcom/brcm80211/brcmfmac/firmware.c | 21 +++++++++- + 2 files changed, 47 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -8270,31 +8271,45 @@ static void brcmf_cfg80211_reg_notifier( + struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); + struct brcmf_pub *drvr = cfg->pub; + struct brcmf_fil_country_le ccreq; ++ char *alpha2; + s32 err; + int i; + +- /* The country code gets set to "00" by default at boot, ignore */ +- if (req->alpha2[0] == '0' && req->alpha2[1] == '0') ++ err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq)); ++ if (err) { ++ bphy_err(drvr, "Country code iovar returned err = %d\n", err); + return; ++ } ++ ++ /* The country code gets set to "00" by default at boot - substitute ++ * any saved ccode from the nvram file unless there is a valid code ++ * already set. ++ */ ++ alpha2 = req->alpha2; ++ if (alpha2[0] == '0' && alpha2[1] == '0') { ++ extern char saved_ccode[2]; ++ ++ if ((isupper(ccreq.country_abbrev[0]) && ++ isupper(ccreq.country_abbrev[1])) || ++ !saved_ccode[0]) ++ return; ++ alpha2 = saved_ccode; ++ pr_debug("brcmfmac: substituting saved ccode %c%c\n", ++ alpha2[0], alpha2[1]); ++ } + + /* ignore non-ISO3166 country codes */ + for (i = 0; i < 2; i++) +- if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { ++ if (alpha2[i] < 'A' || alpha2[i] > 'Z') { + bphy_err(drvr, "not an ISO3166 code (0x%02x 0x%02x)\n", +- req->alpha2[0], req->alpha2[1]); ++ alpha2[0], alpha2[1]); + return; + } + + brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator, +- req->alpha2[0], req->alpha2[1]); +- +- err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq)); +- if (err) { +- bphy_err(drvr, "Country code iovar returned err = %d\n", err); +- return; +- } ++ alpha2[0], alpha2[1]); + +- err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq); ++ err = brcmf_translate_country_code(ifp->drvr, alpha2, &ccreq); + if (err) + return; + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "debug.h" + #include "firmware.h" +@@ -32,6 +33,8 @@ enum nvram_parser_state { + END + }; + ++char saved_ccode[2] = {}; ++ + /** + * struct nvram_parser - internal info for parser. + * +@@ -566,11 +569,27 @@ static int brcmf_fw_request_nvram_done(c + } + } + +- if (data) ++ if (data) { ++ char *ccode = strnstr((char *)data, "ccode=", data_len); ++ /* Ensure this is a whole token */ ++ if (ccode && ((void *)ccode == (void *)data || isspace(ccode[-1]))) { ++ /* Comment out the line */ ++ ccode[0] = '#'; ++ ccode += 6; ++ if (isupper(ccode[0]) && isupper(ccode[1]) && ++ isspace(ccode[2])) { ++ pr_debug("brcmfmac: intercepting ccode=%c%c\n", ++ ccode[0], ccode[1]); ++ saved_ccode[0] = ccode[0]; ++ saved_ccode[1] = ccode[1]; ++ } ++ }; ++ + nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length, + fwctx->req->domain_nr, + fwctx->req->bus_nr, + fwctx->dev); ++ } + + if (free_bcm47xx_nvram) + bcm47xx_nvram_release_contents(data); diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/870-03-rpi-6.12-brcmfmac-Increase-power-saving-delay-to-2s.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/870-03-rpi-6.12-brcmfmac-Increase-power-saving-delay-to-2s.patch new file mode 100644 index 0000000000..843d134e6b --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/870-03-rpi-6.12-brcmfmac-Increase-power-saving-delay-to-2s.patch @@ -0,0 +1,24 @@ +From 12722e472a963598a88011dd4b6805ed0a0e318f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 3 Feb 2020 09:32:22 +0000 +Subject: [PATCH] brcmfmac: Increase power saving delay to 2s + +Increase the delay before entering the lower power state to 2 seconds +(the maximum allowed) in order to reduce the packet latencies, +particularly for inbound packets. + +Signed-off-by: Phil Elwell +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -3360,6 +3360,7 @@ brcmf_cfg80211_set_power_mgmt(struct wip + bphy_err(drvr, "error (%d)\n", err); + } + ++ timeout = 2000; /* 2000ms - the maximum */ + err = brcmf_fil_iovar_int_set(ifp, "pm2_sleep_ret", + min_t(u32, timeout, BRCMF_PS_MAX_TIMEOUT_MS)); + if (err) diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/870-04-rpi-6.12-brcmfmac-non-upstream-support-DS1-exit-firmware-re-download.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/870-04-rpi-6.12-brcmfmac-non-upstream-support-DS1-exit-firmware-re-download.patch new file mode 100644 index 0000000000..ef3e7ee20a --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/870-04-rpi-6.12-brcmfmac-non-upstream-support-DS1-exit-firmware-re-download.patch @@ -0,0 +1,721 @@ +From e7400640cafcf6bd84049308feb5aeabecf55b46 Mon Sep 17 00:00:00 2001 +From: Praveen Babu C +Date: Tue, 9 Jan 2018 11:33:10 +0530 +Subject: [PATCH] non-upstream: support DS1 exit firmware re-download + +In deep sleep mode (DS1) ARM is off and once exit trigger comes than +mailbox Interrupt comes to host and whole reinitiation should be done +in the ARM to start TX/RX. + +Also fix below issus for DS1 exit: +1. Sent Tx Control frame only after firmware redownload complete (check +F2 Ready before sending Tx Control frame to Firmware) +2. intermittent High DS1 TX Exit latency time (almost 3sec) ==> This is +fixed by skipping host Mailbox interrupt Multiple times (ulp state +mechanism) +3. RX GlOM save/restore in Firmware +4. Add ULP event enable & event_msgs_ext iovar configuration in FMAC +5. Add ULP_EVENT_RECV state machine for sbwad support +6. Support 2 Byte Shared memory read for DS1 Exit HUDI implementation + +Signed-off-by: Praveen Babu C +Signed-off-by: Naveen Gupta +[Merge from 4.14.77 to 5.4.18; set BRCMF_SDIO_MAX_ACCESS_ERRORS to 20] +Signed-off-by: Chi-hsien Lin +JIRA: SWWLAN-135583 +JIRA: SWWLAN-136577 +--- + .../broadcom/brcm80211/brcmfmac/bus.h | 2 +- + .../broadcom/brcm80211/brcmfmac/common.c | 39 +++ + .../broadcom/brcm80211/brcmfmac/core.c | 13 +- + .../broadcom/brcm80211/brcmfmac/debug.h | 1 + + .../broadcom/brcm80211/brcmfmac/fweh.h | 31 ++- + .../broadcom/brcm80211/brcmfmac/pcie.c | 2 +- + .../broadcom/brcm80211/brcmfmac/sdio.c | 260 +++++++++++++++++- + .../broadcom/brcm80211/brcmfmac/sdio.h | 110 ++++++++ + .../broadcom/brcm80211/brcmfmac/usb.c | 4 +- + .../broadcom/brcm80211/include/chipcommon.h | 2 + + 10 files changed, 448 insertions(+), 16 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +@@ -298,7 +298,7 @@ void brcmf_rx_event(struct device *dev, + + int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings); + /* Indication from bus module regarding presence/insertion of dongle. */ +-int brcmf_attach(struct device *dev); ++int brcmf_attach(struct device *dev, bool start_bus); + /* Indication from bus module regarding removal/absence of dongle */ + void brcmf_detach(struct device *dev); + void brcmf_free(struct device *dev); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +@@ -20,6 +20,8 @@ + #include "of.h" + #include "firmware.h" + #include "chip.h" ++#include "fweh.h" ++#include + + MODULE_AUTHOR("Broadcom Corporation"); + MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); +@@ -274,6 +276,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_i + char *clmver; + char *ptr; + s32 err; ++ struct eventmsgs_ext *eventmask_msg = NULL; ++ u8 msglen; + + if (is_valid_ether_addr(ifp->mac_addr)) { + /* set mac address */ +@@ -433,6 +437,41 @@ int brcmf_c_preinit_dcmds(struct brcmf_i + goto done; + } + ++ /* Enable event_msg_ext specific to 43012 chip */ ++ if (bus->chip == CY_CC_43012_CHIP_ID) { ++ /* Program event_msg_ext to support event larger than 128 */ ++ msglen = (roundup(BRCMF_E_LAST, NBBY) / NBBY) + ++ EVENTMSGS_EXT_STRUCT_SIZE; ++ /* Allocate buffer for eventmask_msg */ ++ eventmask_msg = kzalloc(msglen, GFP_KERNEL); ++ if (!eventmask_msg) { ++ err = -ENOMEM; ++ goto done; ++ } ++ ++ /* Read the current programmed event_msgs_ext */ ++ eventmask_msg->ver = EVENTMSGS_VER; ++ eventmask_msg->len = roundup(BRCMF_E_LAST, NBBY) / NBBY; ++ err = brcmf_fil_iovar_data_get(ifp, "event_msgs_ext", ++ eventmask_msg, ++ msglen); ++ ++ /* Enable ULP event */ ++ brcmf_dbg(EVENT, "enable event ULP\n"); ++ setbit(eventmask_msg->mask, BRCMF_E_ULP); ++ ++ /* Write updated Event mask */ ++ eventmask_msg->ver = EVENTMSGS_VER; ++ eventmask_msg->command = EVENTMSGS_SET_MASK; ++ eventmask_msg->len = (roundup(BRCMF_E_LAST, NBBY) / NBBY); ++ ++ err = brcmf_fil_iovar_data_set(ifp, "event_msgs_ext", ++ eventmask_msg, msglen); ++ if (err) { ++ brcmf_err("Set event_msgs_ext error (%d)\n", err); ++ goto done; ++ } ++ } + /* Setup default scan channel time */ + err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME, + BRCMF_DEFAULT_SCAN_CHANNEL_TIME); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +@@ -1327,7 +1327,7 @@ int brcmf_alloc(struct device *dev, stru + return 0; + } + +-int brcmf_attach(struct device *dev) ++int brcmf_attach(struct device *dev, bool start_bus) + { + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; +@@ -1370,10 +1370,13 @@ int brcmf_attach(struct device *dev) + + brcmf_fwvid_get_cfg80211_ops(drvr); + +- ret = brcmf_bus_started(drvr, drvr->ops); +- if (ret != 0) { +- bphy_err(drvr, "dongle is not responding: err=%d\n", ret); +- goto fail; ++ if (start_bus) { ++ ret = brcmf_bus_started(drvr, drvr->ops); ++ if (ret != 0) { ++ bphy_err(drvr, "dongle is not responding: err=%d\n", ++ ret); ++ goto fail; ++ } + } + + return 0; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h +@@ -29,6 +29,7 @@ + #define BRCMF_MSGBUF_VAL 0x00040000 + #define BRCMF_PCIE_VAL 0x00080000 + #define BRCMF_FWCON_VAL 0x00100000 ++#define BRCMF_ULP_VAL 0x00200000 + + /* set default print format */ + #undef pr_fmt +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +@@ -98,7 +98,8 @@ struct brcmf_cfg80211_info; + BRCMF_ABSTRACT_ENUM_DEF(EXT_AUTH_REQ, 0) \ + BRCMF_ABSTRACT_ENUM_DEF(EXT_AUTH_FRAME_RX, 1) \ + BRCMF_ABSTRACT_ENUM_DEF(MGMT_FRAME_TXSTATUS, 2) \ +- BRCMF_ABSTRACT_ENUM_DEF(MGMT_FRAME_OFFCHAN_DONE, 3) ++ BRCMF_ABSTRACT_ENUM_DEF(MGMT_FRAME_OFFCHAN_DONE, 3) \ ++ BRCMF_ENUM_DEF(ULP, 146) + + #define BRCMF_ENUM_DEF(id, val) \ + BRCMF_E_##id = (val), +@@ -106,6 +107,12 @@ struct brcmf_cfg80211_info; + /* firmware event codes sent by the dongle */ + enum brcmf_fweh_event_code { + BRCMF_FWEH_EVENT_ENUM_DEFLIST ++ ++ /* this determines event mask length which must match ++ * minimum length check in device firmware so it is ++ * hard-coded here. ++ */ ++ BRCMF_E_LAST + }; + #undef BRCMF_ENUM_DEF + +@@ -284,6 +291,28 @@ struct brcmf_if_event { + u8 role; + }; + ++enum event_msgs_ext_command { ++ EVENTMSGS_NONE = 0, ++ EVENTMSGS_SET_BIT = 1, ++ EVENTMSGS_RESET_BIT = 2, ++ EVENTMSGS_SET_MASK = 3 ++}; ++ ++#define EVENTMSGS_VER 1 ++#define EVENTMSGS_EXT_STRUCT_SIZE offsetof(struct eventmsgs_ext, mask[0]) ++ ++/* len- for SET it would be mask size from the application to the firmware */ ++/* for GET it would be actual firmware mask size */ ++/* maxgetsize - is only used for GET. indicate max mask size that the */ ++/* application can read from the firmware */ ++struct eventmsgs_ext { ++ u8 ver; ++ u8 command; ++ u8 len; ++ u8 maxgetsize; ++ u8 mask[1]; ++}; ++ + typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, + const struct brcmf_event_msg *evtmsg, + void *data); +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -2214,7 +2214,7 @@ static void brcmf_pcie_setup(struct devi + + init_waitqueue_head(&devinfo->mbdata_resp_wait); + +- ret = brcmf_attach(&devinfo->pdev->dev); ++ ret = brcmf_attach(&devinfo->pdev->dev, true); + if (ret) + goto fail; + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -35,9 +35,12 @@ + #include "core.h" + #include "common.h" + #include "bcdc.h" ++#include "debug.h" ++#include "fwil.h" + + #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) + #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) ++#define ULP_HUDI_PROC_DONE_TIME msecs_to_jiffies(2500) + + /* watermark expressed in number of words */ + #define DEFAULT_F2_WATERMARK 0x8 +@@ -325,7 +328,16 @@ struct rte_console { + + #define KSO_WAIT_US 50 + #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) +-#define BRCMF_SDIO_MAX_ACCESS_ERRORS 5 ++#define BRCMF_SDIO_MAX_ACCESS_ERRORS 20 ++ ++static void brcmf_sdio_firmware_callback(struct device *dev, int err, ++ struct brcmf_fw_request *fwreq); ++static struct brcmf_fw_request * ++ brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus); ++static int brcmf_sdio_f2_ready(struct brcmf_sdio *bus); ++static int brcmf_ulp_event_notify(struct brcmf_if *ifp, ++ const struct brcmf_event_msg *evtmsg, ++ void *data); + + #ifdef DEBUG + /* Device console log buffer state */ +@@ -1106,7 +1118,7 @@ static void brcmf_sdio_get_console_addr( + } + #endif /* DEBUG */ + +-static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus) ++static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus, u32 *hmbd) + { + struct brcmf_sdio_dev *sdiod = bus->sdiodev; + struct brcmf_core *core = bus->sdio_core; +@@ -1195,6 +1207,9 @@ static u32 brcmf_sdio_hostmail(struct br + HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) + brcmf_err("Unknown mailbox data content: 0x%02x\n", + hmb_data); ++ /* Populate hmb_data if argument is passed for DS1 check later */ ++ if (hmbd) ++ *hmbd = hmb_data; + + return intstatus; + } +@@ -2581,6 +2596,182 @@ static int brcmf_sdio_intr_rstatus(struc + return ret; + } + ++/* This Function is used to retrieve important ++ * details from dongle related to ULP mode Mostly ++ * values/SHM details that will be vary depending ++ * on the firmware branches ++ */ ++static void ++brcmf_sdio_ulp_preinit(struct device *dev) ++{ ++ struct brcmf_bus *bus_if = dev_get_drvdata(dev); ++ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ struct brcmf_if *ifp = bus_if->drvr->iflist[0]; ++ ++ brcmf_dbg(ULP, "Enter\n"); ++ ++ /* Query ulp_sdioctrl iovar to get the ULP related SHM offsets */ ++ brcmf_fil_iovar_data_get(ifp, "ulp_sdioctrl", ++ &sdiodev->fmac_ulp.ulp_shm_offset, ++ sizeof(sdiodev->fmac_ulp.ulp_shm_offset)); ++ ++ sdiodev->ulp = false; ++ ++ brcmf_dbg(ULP, "m_ulp_ctrl_sdio[%x] m_ulp_wakeevt_ind [%x]\n", ++ M_DS1_CTRL_SDIO(sdiodev->fmac_ulp), ++ M_WAKEEVENT_IND(sdiodev->fmac_ulp)); ++ brcmf_dbg(ULP, "m_ulp_wakeind [%x]\n", ++ M_ULP_WAKE_IND(sdiodev->fmac_ulp)); ++} ++ ++/* Reinitialize ARM because In DS1 mode ARM got off */ ++static int ++brcmf_sdio_ulp_reinit_fw(struct brcmf_sdio *bus) ++{ ++ struct brcmf_sdio_dev *sdiodev = bus->sdiodev; ++ struct brcmf_fw_request *fwreq; ++ int err = 0; ++ ++ /* After firmware redownload tx/rx seq are reset accordingly ++ * these values are reset on FMAC side tx_max is initially set to 4, ++ * which later is updated by FW. ++ */ ++ bus->tx_seq = 0; ++ bus->rx_seq = 0; ++ bus->tx_max = 4; ++ ++ fwreq = brcmf_sdio_prepare_fw_request(bus); ++ if (!fwreq) ++ return -ENOMEM; ++ ++ err = brcmf_fw_get_firmwares(sdiodev->dev, fwreq, ++ brcmf_sdio_firmware_callback); ++ if (err != 0) { ++ brcmf_err("async firmware request failed: %d\n", err); ++ kfree(fwreq); ++ } ++ ++ return err; ++} ++ ++/* Check if device is in DS1 mode and handshake with ULP UCODE */ ++static bool ++brcmf_sdio_ulp_pre_redownload_check(struct brcmf_sdio *bus, u32 hmb_data) ++{ ++ struct brcmf_sdio_dev *sdiod = bus->sdiodev; ++ int err = 0; ++ u32 value = 0; ++ u32 val32, ulp_wake_ind, wowl_wake_ind; ++ int reg_addr; ++ unsigned long timeout; ++ struct brcmf_ulp *fmac_ulp = &bus->sdiodev->fmac_ulp; ++ int i = 0; ++ ++ /* If any host mail box data is present, ignore DS1 exit sequence */ ++ if (hmb_data) ++ return false; ++ /* Skip if DS1 Exit is already in progress ++ * This can happen if firmware download is taking more time ++ */ ++ if (fmac_ulp->ulp_state == FMAC_ULP_TRIGGERED) ++ return false; ++ ++ value = brcmf_sdiod_func0_rb(sdiod, SDIO_CCCR_IOEx, &err); ++ ++ if (value == SDIO_FUNC_ENABLE_1) { ++ brcmf_dbg(ULP, "GOT THE INTERRUPT FROM UCODE\n"); ++ sdiod->ulp = true; ++ fmac_ulp->ulp_state = FMAC_ULP_TRIGGERED; ++ ulp_wake_ind = D11SHM_RDW(sdiod, ++ M_ULP_WAKE_IND(sdiod->fmac_ulp), ++ &err); ++ wowl_wake_ind = D11SHM_RDW(sdiod, ++ M_WAKEEVENT_IND(sdiod->fmac_ulp), ++ &err); ++ ++ brcmf_dbg(ULP, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x state %s\n", ++ wowl_wake_ind, ulp_wake_ind, (fmac_ulp->ulp_state) ? ++ "DS1 Exit Triggered" : "IDLE State"); ++ ++ if (wowl_wake_ind || ulp_wake_ind) { ++ /* RX wake Don't do anything. ++ * Just bail out and re-download firmware. ++ */ ++ /* Print out PHY TX error block when bit 9 set */ ++ if ((ulp_wake_ind & C_DS1_PHY_TXERR) && ++ M_DS1_PHYTX_ERR_BLK(sdiod->fmac_ulp)) { ++ brcmf_err("Dump PHY TX Error SHM Locations\n"); ++ for (i = 0; i < PHYTX_ERR_BLK_SIZE; i++) { ++ pr_err("0x%x", ++ D11SHM_RDW(sdiod, ++ (M_DS1_PHYTX_ERR_BLK(sdiod->fmac_ulp) + ++ (i * 2)), &err)); ++ } ++ brcmf_err("\n"); ++ } ++ } else { ++ /* TX wake negotiate with MAC */ ++ brcmf_dbg(ULP, "M_DS1_CTRL_SDIO: 0x%08x\n", ++ (u32)D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err)); ++ val32 = D11SHM_RD(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err); ++ D11SHM_WR(sdiod, M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ val32, (C_DS1_CTRL_SDIO_DS1_EXIT | ++ C_DS1_CTRL_REQ_VALID), &err); ++ val32 = D11REG_RD(sdiod, D11_MACCONTROL_REG, &err); ++ val32 = val32 | D11_MACCONTROL_REG_WAKE; ++ D11REG_WR(sdiod, D11_MACCONTROL_REG, val32, &err); ++ ++ /* Poll for PROC_DONE to be set by ucode */ ++ value = D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err); ++ /* Wait here (polling) for C_DS1_CTRL_PROC_DONE */ ++ timeout = jiffies + ULP_HUDI_PROC_DONE_TIME; ++ while (!(value & C_DS1_CTRL_PROC_DONE)) { ++ value = D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err); ++ if (time_after(jiffies, timeout)) ++ break; ++ usleep_range(1000, 2000); ++ } ++ brcmf_dbg(ULP, "M_DS1_CTRL_SDIO: 0x%08x\n", ++ (u32)D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), &err)); ++ value = D11SHM_RDW(sdiod, ++ M_DS1_CTRL_SDIO(sdiod->fmac_ulp), ++ &err); ++ if (!(value & C_DS1_CTRL_PROC_DONE)) { ++ brcmf_err("Timeout Failed to enter DS1 Exit state!\n"); ++ return false; ++ } ++ } ++ ++ ulp_wake_ind = D11SHM_RDW(sdiod, ++ M_ULP_WAKE_IND(sdiod->fmac_ulp), ++ &err); ++ wowl_wake_ind = D11SHM_RDW(sdiod, ++ M_WAKEEVENT_IND(sdiod->fmac_ulp), ++ &err); ++ brcmf_dbg(ULP, "wowl_wake_ind: 0x%08x, ulp_wake_ind: 0x%08x\n", ++ wowl_wake_ind, ulp_wake_ind); ++ reg_addr = CORE_CC_REG( ++ brcmf_chip_get_pmu(bus->ci)->base, min_res_mask); ++ brcmf_sdiod_writel(sdiod, reg_addr, ++ DEFAULT_43012_MIN_RES_MASK, &err); ++ if (err) ++ brcmf_err("min_res_mask failed\n"); ++ ++ return true; ++ } ++ ++ return false; ++} ++ + static void brcmf_sdio_dpc(struct brcmf_sdio *bus) + { + struct brcmf_sdio_dev *sdiod = bus->sdiodev; +@@ -2652,8 +2843,11 @@ static void brcmf_sdio_dpc(struct brcmf_ + + /* Handle host mailbox indication */ + if (intstatus & I_HMB_HOST_INT) { ++ u32 hmb_data = 0; + intstatus &= ~I_HMB_HOST_INT; +- intstatus |= brcmf_sdio_hostmail(bus); ++ intstatus |= brcmf_sdio_hostmail(bus, &hmb_data); ++ if (brcmf_sdio_ulp_pre_redownload_check(bus, hmb_data)) ++ brcmf_sdio_ulp_reinit_fw(bus); + } + + sdio_release_host(bus->sdiodev->func1); +@@ -2698,7 +2892,7 @@ static void brcmf_sdio_dpc(struct brcmf_ + brcmf_sdio_clrintr(bus); + + if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && +- txctl_ok(bus)) { ++ txctl_ok(bus) && brcmf_sdio_f2_ready(bus)) { + sdio_claim_host(bus->sdiodev->func1); + if (bus->ctrl_frame_stat) { + err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, +@@ -3569,6 +3763,10 @@ static int brcmf_sdio_bus_preinit(struct + if (err < 0) + goto done; + ++ /* initialize SHM address from firmware for DS1 */ ++ if (!bus->sdiodev->ulp) ++ brcmf_sdio_ulp_preinit(dev); ++ + bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; + if (sdiodev->sg_support) { + bus->txglom = false; +@@ -4219,7 +4417,7 @@ static void brcmf_sdio_firmware_callback + u8 saveclk, bpreq; + u8 devctl; + +- brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); ++ brcmf_dbg(ULP, "Enter: dev=%s, err=%d\n", dev_name(dev), err); + + if (err) + goto fail; +@@ -4397,12 +4595,25 @@ static void brcmf_sdio_firmware_callback + } + + /* Attach to the common layer, reserve hdr space */ +- err = brcmf_attach(sdiod->dev); ++ err = brcmf_attach(sdiod->dev, !bus->sdiodev->ulp); + if (err != 0) { + brcmf_err("brcmf_attach failed\n"); + goto free; + } + ++ /* Register for ULP events */ ++ if (sdiod->func1->device == SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012) ++ brcmf_fweh_register(bus_if->drvr, BRCMF_E_ULP, ++ brcmf_ulp_event_notify); ++ ++ if (bus->sdiodev->ulp) { ++ /* For ULP, after firmware redownload complete ++ * set ULP state to IDLE ++ */ ++ if (bus->sdiodev->fmac_ulp.ulp_state == FMAC_ULP_TRIGGERED) ++ bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_IDLE; ++ } ++ + /* ready */ + return; + +@@ -4649,3 +4860,40 @@ int brcmf_sdio_sleep(struct brcmf_sdio * + + return ret; + } ++ ++/* Check F2 Ready bit before sending data to Firmware */ ++static int ++brcmf_sdio_f2_ready(struct brcmf_sdio *bus) ++{ ++ int ret = -1; ++ int iordy_status = 0; ++ ++ sdio_claim_host(bus->sdiodev->func1); ++ /* Read the status of IOR2 */ ++ iordy_status = brcmf_sdiod_func0_rb(bus->sdiodev, SDIO_CCCR_IORx, NULL); ++ ++ sdio_release_host(bus->sdiodev->func1); ++ ret = iordy_status & SDIO_FUNC_ENABLE_2; ++ return ret; ++} ++ ++static int brcmf_ulp_event_notify(struct brcmf_if *ifp, ++ const struct brcmf_event_msg *evtmsg, ++ void *data) ++{ ++ int err = 0; ++ struct brcmf_bus *bus_if = ifp->drvr->bus_if; ++ struct brcmf_sdio_dev *sdiodev; ++ struct brcmf_sdio *bus; ++ struct brcmf_ulp_event *ulp_event = (struct brcmf_ulp_event *)data; ++ ++ sdiodev = bus_if->bus_priv.sdio; ++ bus = sdiodev->bus; ++ ++ brcmf_dbg(ULP, "Chip went to DS1 state : action %d\n", ++ ulp_event->ulp_dongle_action); ++ if (ulp_event->ulp_dongle_action == FMAC_ULP_ENTRY) ++ bus->sdiodev->fmac_ulp.ulp_state = FMAC_ULP_ENTRY_RECV; ++ ++ return err; ++} +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +@@ -165,6 +165,35 @@ struct brcmf_sdreg { + struct brcmf_sdio; + struct brcmf_sdiod_freezer; + ++/* ULP SHM Offsets info */ ++struct ulp_shm_info { ++ u32 m_ulp_ctrl_sdio; ++ u32 m_ulp_wakeevt_ind; ++ u32 m_ulp_wakeind; ++ u32 m_ulp_phytxblk; ++}; ++ ++/* FMAC ULP state machine */ ++#define FMAC_ULP_IDLE (0) ++#define FMAC_ULP_ENTRY_RECV (1) ++#define FMAC_ULP_TRIGGERED (2) ++ ++/* BRCMF_E_ULP event data */ ++#define FMAC_ULP_EVENT_VERSION 1 ++#define FMAC_ULP_DISABLE_CONSOLE 1 /* Disable console */ ++#define FMAC_ULP_UCODE_DOWNLOAD 2 /* Download ULP ucode file */ ++#define FMAC_ULP_ENTRY 3 /* Inform ulp entry to Host */ ++ ++struct brcmf_ulp { ++ uint ulp_state; ++ struct ulp_shm_info ulp_shm_offset; ++}; ++ ++struct brcmf_ulp_event { ++ u16 version; ++ u16 ulp_dongle_action; ++}; ++ + struct brcmf_sdio_dev { + struct sdio_func *func1; + struct sdio_func *func2; +@@ -193,6 +222,8 @@ struct brcmf_sdio_dev { + enum brcmf_sdiod_state state; + struct brcmf_sdiod_freezer *freezer; + const struct firmware *clm_fw; ++ struct brcmf_ulp fmac_ulp; ++ bool ulp; + }; + + /* sdio core registers */ +@@ -367,4 +398,83 @@ void brcmf_sdio_wowl_config(struct devic + int brcmf_sdio_sleep(struct brcmf_sdio *bus, bool sleep); + void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus); + ++/* SHM offsets */ ++#define M_DS1_CTRL_SDIO(ptr) ((ptr).ulp_shm_offset.m_ulp_ctrl_sdio) ++#define M_WAKEEVENT_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeevt_ind) ++#define M_ULP_WAKE_IND(ptr) ((ptr).ulp_shm_offset.m_ulp_wakeind) ++#define M_DS1_PHYTX_ERR_BLK(ptr) ((ptr).ulp_shm_offset.m_ulp_phytxblk) ++ ++#define D11_BASE_ADDR 0x18001000 ++#define D11_AXI_BASE_ADDR 0xE8000000 ++#define D11_SHM_BASE_ADDR (D11_AXI_BASE_ADDR + 0x4000) ++ ++#define D11REG_ADDR(offset) (D11_BASE_ADDR + (offset)) ++#define D11IHR_ADDR(offset) (D11_AXI_BASE_ADDR + 0x400 + (2 * (offset))) ++#define D11SHM_ADDR(offset) (D11_SHM_BASE_ADDR + (offset)) ++ ++/* MacControl register */ ++#define D11_MACCONTROL_REG D11REG_ADDR(0x120) ++#define D11_MACCONTROL_REG_WAKE 0x4000000 ++ ++/* HUDI Sequence SHM bits */ ++#define C_DS1_CTRL_SDIO_DS1_SLEEP 0x1 ++#define C_DS1_CTRL_SDIO_MAC_ON 0x2 ++#define C_DS1_CTRL_SDIO_RADIO_PHY_ON 0x4 ++#define C_DS1_CTRL_SDIO_DS1_EXIT 0x8 ++#define C_DS1_CTRL_PROC_DONE 0x100 ++#define C_DS1_CTRL_REQ_VALID 0x200 ++ ++/* M_ULP_WAKEIND bits */ ++#define C_WATCHDOG_EXPIRY BIT(0) ++#define C_FCBS_ERROR BIT(1) ++#define C_RETX_FAILURE BIT(2) ++#define C_HOST_WAKEUP BIT(3) ++#define C_INVALID_FCBS_BLOCK BIT(4) ++#define C_HUDI_DS1_EXIT BIT(5) ++#define C_LOB_SLEEP BIT(6) ++#define C_DS1_PHY_TXERR BIT(9) ++#define C_DS1_WAKE_TIMER BIT(10) ++ ++#define PHYTX_ERR_BLK_SIZE 18 ++#define D11SHM_FIRST2BYTE_MASK 0xFFFF0000 ++#define D11SHM_SECOND2BYTE_MASK 0x0000FFFF ++#define D11SHM_2BYTE_SHIFT 16 ++ ++#define D11SHM_RD(sdh, offset, ret) \ ++ brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret) ++ ++/* SHM Read is motified based on SHM 4 byte alignment as SHM size is 2 bytes and ++ * 2 byte is currently not working on FMAC ++ * If SHM address is not 4 byte aligned, then right shift by 16 ++ * otherwise, mask the first two MSB bytes ++ * Suppose data in address 7260 is 0x440002 and it is 4 byte aligned ++ * Correct SHM value is 0x2 for this SHM offset and next SHM value is 0x44 ++ */ ++#define D11SHM_RDW(sdh, offset, ret) \ ++ ((offset % 4) ? \ ++ (brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret) \ ++ >> D11SHM_2BYTE_SHIFT) : \ ++ (brcmf_sdiod_readl(sdh, D11SHM_ADDR(offset), ret) \ ++ & D11SHM_SECOND2BYTE_MASK)) ++ ++/* SHM is of size 2 bytes, 4 bytes write will overwrite other SHM's ++ * First read 4 bytes and then clear the required two bytes based on ++ * 4 byte alignment, then update the required value and write the ++ * 4 byte value now ++ */ ++#define D11SHM_WR(sdh, offset, val, mask, ret) \ ++ do { \ ++ if ((offset) % 4) \ ++ val = (val & D11SHM_SECOND2BYTE_MASK) | \ ++ ((mask) << D11SHM_2BYTE_SHIFT); \ ++ else \ ++ val = (mask) | (val & D11SHM_FIRST2BYTE_MASK); \ ++ brcmf_sdiod_writel(sdh, D11SHM_ADDR(offset), val, ret); \ ++ } while (0) ++#define D11REG_WR(sdh, addr, val, ret) \ ++ brcmf_sdiod_writel(sdh, addr, val, ret) ++ ++#define D11REG_RD(sdh, addr, ret) \ ++ brcmf_sdiod_readl(sdh, addr, ret) ++ + #endif /* BRCMFMAC_SDIO_H */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -1208,7 +1208,7 @@ static void brcmf_usb_probe_phase2(struc + goto error; + + /* Attach to the common driver interface */ +- ret = brcmf_attach(devinfo->dev); ++ ret = brcmf_attach(devinfo->dev, true); + if (ret) + goto error; + +@@ -1288,7 +1288,7 @@ static int brcmf_usb_probe_cb(struct brc + ret = brcmf_alloc(devinfo->dev, devinfo->settings); + if (ret) + goto fail; +- ret = brcmf_attach(devinfo->dev); ++ ret = brcmf_attach(devinfo->dev, true); + if (ret) + goto fail; + /* we are done */ +--- a/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h ++++ b/drivers/net/wireless/broadcom/brcm80211/include/chipcommon.h +@@ -308,4 +308,6 @@ struct chipcregs { + */ + #define PMU_MAX_TRANSITION_DLY 15000 + ++#define DEFAULT_43012_MIN_RES_MASK 0x0f8bfe77 ++ + #endif /* _SBCHIPC_H */ diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/870-05-rpi-6.12-brcmfmac-Fix-interoperating-DPP-and-other-encryption.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/870-05-rpi-6.12-brcmfmac-Fix-interoperating-DPP-and-other-encryption.patch new file mode 100644 index 0000000000..cc8a842f4e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/870-05-rpi-6.12-brcmfmac-Fix-interoperating-DPP-and-other-encryption.patch @@ -0,0 +1,129 @@ +From 4c1d4af0ac83705828dd11fded409163a87ea515 Mon Sep 17 00:00:00 2001 +From: Kurt Lee +Date: Thu, 20 Aug 2020 03:07:02 -0500 +Subject: [PATCH] brcmfmac: Fix interoperating DPP and other encryption network + access + +1. If firmware supports 4-way handshake offload but not supports DPP +4-way offload, when user first connects encryption network, driver will +set "sup_wpa 1" to firmware, but it will further result in DPP +connection failure since firmware won't send EAPOL frame to host. + +2. Fix DPP AP mode handling action frames. + +3. For some firmware without fwsup support, the join procedure will be +skipped due to "sup_wpa" iovar returning not-support. Check the fwsup +feature before do such iovar. + +Signed-off-by: Kurt Lee +Signed-off-by: Double Lo +Signed-off-by: Chi-hsien Lin +--- + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 67 ++++++++++--------- + .../broadcom/brcm80211/brcmfmac/p2p.c | 5 ++ + 2 files changed, 42 insertions(+), 30 deletions(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -2512,43 +2512,50 @@ brcmf_cfg80211_connect(struct wiphy *wip + goto done; + } + +- if (sme->crypto.psk && +- profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) { +- if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) { +- err = -EINVAL; +- goto done; ++ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) { ++ if (sme->crypto.psk) { ++ if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) { ++ if (WARN_ON(profile->use_fwsup != ++ BRCMF_PROFILE_FWSUP_NONE)) { ++ err = -EINVAL; ++ goto done; ++ } ++ brcmf_dbg(INFO, "using PSK offload\n"); ++ profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK; ++ } ++ } else { ++ profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + } +- brcmf_dbg(INFO, "using PSK offload\n"); +- profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK; +- } + +- if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { +- /* enable firmware supplicant for this interface */ +- err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1); +- if (err < 0) { +- bphy_err(drvr, "failed to enable fw supplicant\n"); +- goto done; ++ if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) { ++ /* enable firmware supplicant for this interface */ ++ err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1); ++ if (err < 0) { ++ bphy_err(drvr, "failed to enable fw supplicant\n"); ++ goto done; ++ } ++ } else { ++ err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 0); + } +- } + +- if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) +- err = brcmf_set_pmk(ifp, sme->crypto.psk, +- BRCMF_WSEC_MAX_PSK_LEN); +- else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) { +- /* clean up user-space RSNE */ +- err = brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0); +- if (err) { +- bphy_err(drvr, "failed to clean up user-space RSNE\n"); +- goto done; +- } +- err = brcmf_fwvid_set_sae_password(ifp, &sme->crypto); +- if (!err && sme->crypto.psk) ++ if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) { + err = brcmf_set_pmk(ifp, sme->crypto.psk, + BRCMF_WSEC_MAX_PSK_LEN); ++ } else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) { ++ /* clean up user-space RSNE */ ++ err = brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0); ++ if (err) { ++ bphy_err(drvr, "failed to clean up user-space RSNE\n"); ++ goto done; ++ } ++ err = brcmf_fwvid_set_sae_password(ifp, &sme->crypto); ++ if (!err && sme->crypto.psk) ++ err = brcmf_set_pmk(ifp, sme->crypto.psk, ++ BRCMF_WSEC_MAX_PSK_LEN); ++ } ++ if (err) ++ goto done; + } +- if (err) +- goto done; +- + /* Join with specific BSSID and cached SSID + * If SSID is zero join based on BSSID only + */ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +@@ -1281,6 +1281,10 @@ static s32 brcmf_p2p_abort_action_frame( + brcmf_dbg(TRACE, "Enter\n"); + + vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; ++ ++ if (!vif) ++ vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; ++ + err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe_abort", &int_val, + sizeof(s32)); + if (err) +@@ -1817,6 +1821,7 @@ bool brcmf_p2p_send_action_frame(struct + /* validate channel and p2p ies */ + if (config_af_params.search_channel && + IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) && ++ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif && + p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) { + afx_hdl = &p2p->afx_hdl; + afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel); diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/870-06-rpi-6.12-brcmfmac-Include-modinfo-for-43456-CLM-blob.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/870-06-rpi-6.12-brcmfmac-Include-modinfo-for-43456-CLM-blob.patch new file mode 100644 index 0000000000..f90406fa9a --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/870-06-rpi-6.12-brcmfmac-Include-modinfo-for-43456-CLM-blob.patch @@ -0,0 +1,26 @@ +From 0ff7f575b657b3fdfbd6902b68a28548208f4d36 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 8 May 2025 16:55:27 +0100 +Subject: [PATCH] wifi: brcmfmac: Include modinfo for 43456 CLM blob + +Listing firmware files in the brcmfmac modinfo helps with e.g. initramfs +creation. + +See: https://github.com/raspberrypi/linux/issues/6828 + +Signed-off-by: Phil Elwell +--- + drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -631,7 +631,7 @@ BRCMF_FW_CLM_DEF(43430A1, "brcmfmac43430 + BRCMF_FW_DEF(43430B0, "brcmfmac43430b0-sdio"); + BRCMF_FW_CLM_DEF(43439, "brcmfmac43439-sdio"); + BRCMF_FW_CLM_DEF(43455, "brcmfmac43455-sdio"); +-BRCMF_FW_DEF(43456, "brcmfmac43456-sdio"); ++BRCMF_FW_CLM_DEF(43456, "brcmfmac43456-sdio"); + BRCMF_FW_CLM_DEF(4354, "brcmfmac4354-sdio"); + BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-sdio"); + BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); diff --git a/lede/package/kernel/mac80211/patches-6.18/brcm/871-brcmfmac-disable-dump_survey-on-bcm2835.patch b/lede/package/kernel/mac80211/patches-6.18/brcm/871-brcmfmac-disable-dump_survey-on-bcm2835.patch new file mode 100644 index 0000000000..e2c1eb8e23 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/brcm/871-brcmfmac-disable-dump_survey-on-bcm2835.patch @@ -0,0 +1,38 @@ +brcmfmac: disable dump_survey on Raspberry Pi + +Enabling this causes slow iwinfo calls on Raspberry Pi and LuCI slows down +when wireless is enabled. +https://github.com/openwrt/openwrt/issues/14013 + +Signed-off-by: Álvaro Fernández Rojas +--- + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -8049,6 +8049,7 @@ static s32 brcmf_translate_country_code( + return 0; + } + ++#if !defined(CONFIG_ARCH_BCM2835) + static int + brcmf_parse_dump_obss(char *buf, struct brcmf_dump_survey *survey) + { +@@ -8271,6 +8272,7 @@ exit: + brcmf_set_mpc(ifp, 1); + return err; + } ++#endif /* CONFIG_ARCH_BCM2835 */ + + static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *req) +@@ -8437,8 +8439,10 @@ struct brcmf_cfg80211_info *brcmf_cfg802 + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) + ops->set_rekey_data = brcmf_cfg80211_set_rekey_data; + #endif ++#if !defined(CONFIG_ARCH_BCM2835) + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_DUMP_OBSS)) + ops->dump_survey = brcmf_cfg80211_dump_survey; ++#endif /* CONFIG_ARCH_BCM2835 */ + + err = wiphy_register(wiphy); + if (err < 0) { diff --git a/lede/package/kernel/mac80211/patches-6.18/build/000-fix_kconfig.patch b/lede/package/kernel/mac80211/patches-6.18/build/000-fix_kconfig.patch new file mode 100644 index 0000000000..3987aae4f5 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/000-fix_kconfig.patch @@ -0,0 +1,14 @@ +--- a/kconf/Makefile ++++ b/kconf/Makefile +@@ -1,9 +1,9 @@ +-CFLAGS=-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer ++CFLAGS=-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -DKBUILD_NO_NLS + + LXDIALOG := lxdialog/checklist.o lxdialog/inputbox.o lxdialog/menubox.o lxdialog/textbox.o lxdialog/util.o lxdialog/yesno.o + + conf: conf.o zconf.tab.o +-mconf_CFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ccflags) -DLOCALE ++mconf_CFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ccflags) + mconf_LDFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ldflags $(CC)) + mconf: CFLAGS += $(mconf_CFLAGS) + diff --git a/lede/package/kernel/mac80211/patches-6.18/build/001-fix_build.patch b/lede/package/kernel/mac80211/patches-6.18/build/001-fix_build.patch new file mode 100644 index 0000000000..085eae3cd3 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/001-fix_build.patch @@ -0,0 +1,168 @@ +--- a/Makefile ++++ b/Makefile +@@ -5,7 +5,7 @@ + ifeq ($(KERNELRELEASE),) + + MAKEFLAGS += --no-print-directory +-SHELL := /bin/bash ++SHELL := /usr/bin/env bash + BACKPORT_DIR := $(shell pwd) + + KMODDIR ?= updates +@@ -19,6 +19,7 @@ KLIB_BUILD ?= $(KLIB)/build/ + KERNEL_CONFIG := $(KLIB_BUILD)/.config + KERNEL_MAKEFILE := $(KLIB_BUILD)/Makefile + CONFIG_MD5 := $(shell md5sum $(KERNEL_CONFIG) 2>/dev/null | sed 's/\s.*//') ++STAMP_KERNEL_CONFIG := .kernel_config_md5_$(CONFIG_MD5) + + export KLIB KLIB_BUILD BACKPORT_DIR KMODDIR KMODPATH_ARG + +@@ -36,7 +37,8 @@ mrproper: + @rm -f .kernel_config_md5 Kconfig.versions Kconfig.kernel + @rm -f backport-include/backport/autoconf.h + +-.DEFAULT: ++.SILENT: $(STAMP_KERNEL_CONFIG) ++$(STAMP_KERNEL_CONFIG): + @set -e ; test -f local-symbols || ( \ + echo "/--------------" ;\ + echo "| You shouldn't run make in the backports tree, but only in" ;\ +@@ -60,57 +62,62 @@ mrproper: + echo "| (that isn't currently running.)" ;\ + echo "\\--" ;\ + false) +- @set -e ; if [ "$$(cat .kernel_config_md5 2>/dev/null)" != "$(CONFIG_MD5)" ] ;\ +- then \ +- echo -n "Generating local configuration database from kernel ..." ;\ +- grep -v -f local-symbols $(KERNEL_CONFIG) | grep = | ( \ +- while read l ; do \ +- if [ "$${l:0:7}" != "CONFIG_" ] ; then \ +- continue ;\ +- fi ;\ +- l=$${l:7} ;\ +- n=$${l%%=*} ;\ +- v=$${l#*=} ;\ +- if [ "$$v" = "m" ] ; then \ +- echo config $$n ;\ +- echo ' tristate' ;\ +- elif [ "$$v" = "y" ] ; then \ +- echo config $$n ;\ +- echo ' bool' ;\ +- else \ +- continue ;\ +- fi ;\ +- echo " default $$v" ;\ +- echo "" ;\ +- done \ +- ) > Kconfig.kernel ;\ +- kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) M=$(BACKPORT_DIR) \ +- kernelversion | sed 's/^\(\([3-6]\|2\.6\)\.[0-9]\+\).*/\1/;t;d');\ +- test "$$kver" != "" || echo "Kernel version parse failed!" ;\ +- test "$$kver" != "" ;\ +- kvers="$$kvers $$(seq 0 20 | sed 's/^/4./')" ;\ +- kvers="$$kvers $$(seq 0 19 | sed 's/^/5./')" ;\ +- kvers="$$kvers $$(seq 0 20 | sed 's/^/6./')" ;\ +- print=0 ;\ +- for v in $$kvers ; do \ +- if [ "$$print" = "1" ] ; then \ +- echo config KERNEL_$$(echo $$v | tr . _) ;\ +- echo " def_bool y" ;\ +- fi ;\ +- if [ "$$v" = "$$kver" ] ; then print=1 ; fi ;\ +- done > Kconfig.versions ;\ +- # RHEL as well, sadly we need to grep for it ;\ +- RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | \ +- sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\ +- RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | \ +- sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\ +- for v in $$(seq 0 $$RHEL_MINOR) ; do \ +- echo config BACKPORT_RHEL_KERNEL_$${RHEL_MAJOR}_$$v ;\ +- echo " def_bool y" ;\ +- done >> Kconfig.versions ;\ +- echo " done." ;\ +- fi ;\ +- echo "$(CONFIG_MD5)" > .kernel_config_md5 ++ @rm -f .kernel_config_md5_* ++ @touch $@ ++ ++Kconfig.kernel: $(STAMP_KERNEL_CONFIG) local-symbols ++ @printf "Generating local configuration database from kernel ..." ++ @grep -v -f local-symbols $(KERNEL_CONFIG) | grep = | ( \ ++ while read l ; do \ ++ if [ "$${l:0:7}" != "CONFIG_" ] ; then \ ++ continue ;\ ++ fi ;\ ++ l=$${l:7} ;\ ++ n=$${l%%=*} ;\ ++ v=$${l#*=} ;\ ++ if [ "$$v" = "m" ] ; then \ ++ echo config $$n ;\ ++ echo ' tristate' ;\ ++ elif [ "$$v" = "y" ] ; then \ ++ echo config $$n ;\ ++ echo ' bool' ;\ ++ else \ ++ continue ;\ ++ fi ;\ ++ echo " default $$v" ;\ ++ echo "" ;\ ++ done \ ++ ) > $@ ++ @echo " done." ++ ++Kconfig.versions: Kconfig.kernel ++ @kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) M=$(BACKPORT_DIR) \ ++ kernelversion | sed 's/^\(\([3-6]\|2\.6\)\.[0-9]\+\).*/\1/;t;d');\ ++ test "$$kver" != "" || echo "Kernel version parse failed!" ;\ ++ test "$$kver" != "" ;\ ++ kvers="$$kvers $$(seq 0 20 | sed 's/^/4./')" ;\ ++ kvers="$$kvers $$(seq 0 19 | sed 's/^/5./')" ;\ ++ kvers="$$kvers $$(seq 0 20 | sed 's/^/6./')" ;\ ++ print=0 ;\ ++ for v in $$kvers ; do \ ++ if [ "$$print" = "1" ] ; then \ ++ echo config KERNEL_$$(echo $$v | tr . _) ;\ ++ echo " def_bool y" ;\ ++ fi ;\ ++ if [ "$$v" = "$$kver" ] ; then print=1 ; fi ;\ ++ done > Kconfig.versions ;\ ++ # RHEL as well, sadly we need to grep for it ;\ ++ RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | \ ++ sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\ ++ RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | \ ++ sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\ ++ for v in $$(seq 0 $$RHEL_MINOR) ; do \ ++ echo config BACKPORT_RHEL_KERNEL_$${RHEL_MAJOR}_$$v ;\ ++ echo " def_bool y" ;\ ++ done >> $@ ++ ++.DEFAULT: ++ @$(MAKE) Kconfig.versions + @$(MAKE) -f Makefile.real "$@" + + .PHONY: defconfig-help +--- a/Makefile.real ++++ b/Makefile.real +@@ -59,7 +59,7 @@ defconfig-%:: + + backport-include/backport/autoconf.h: .config Kconfig.versions Kconfig.kernel + @$(MAKE) oldconfig +- @echo -n "Building backport-include/backport/autoconf.h ..." ++ @printf "Building backport-include/backport/autoconf.h ..." + @grep -f local-symbols .config | ( \ + echo "#ifndef COMPAT_AUTOCONF_INCLUDED" ;\ + echo "#define COMPAT_AUTOCONF_INCLUDED" ;\ +@@ -80,7 +80,12 @@ backport-include/backport/autoconf.h: .c + esac ;\ + done ;\ + echo "#endif /* COMPAT_AUTOCONF_INCLUDED */" ;\ +- ) > backport-include/backport/autoconf.h ++ ) > $@.new ++ @if cmp -s $@ $@.new; then \ ++ rm -f $@.new; \ ++ else \ ++ mv $@.new $@; \ ++ fi + @echo " done." + + .PHONY: modules diff --git a/lede/package/kernel/mac80211/patches-6.18/build/002-change_allconfig.patch b/lede/package/kernel/mac80211/patches-6.18/build/002-change_allconfig.patch new file mode 100644 index 0000000000..368725d0c3 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/002-change_allconfig.patch @@ -0,0 +1,64 @@ +--- a/kconf/conf.c ++++ b/kconf/conf.c +@@ -598,40 +598,12 @@ int main(int ac, char **av) + case oldconfig: + case listnewconfig: + case olddefconfig: +- conf_read(NULL); +- break; + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case randconfig: +- name = getenv("KCONFIG_ALLCONFIG"); +- if (!name) +- break; +- if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { +- if (conf_read_simple(name, S_DEF_USER)) { +- fprintf(stderr, +- _("*** Can't read seed configuration \"%s\"!\n"), +- name); +- exit(1); +- } +- break; +- } +- switch (input_mode) { +- case allnoconfig: name = "allno.config"; break; +- case allyesconfig: name = "allyes.config"; break; +- case allmodconfig: name = "allmod.config"; break; +- case alldefconfig: name = "alldef.config"; break; +- case randconfig: name = "allrandom.config"; break; +- default: break; +- } +- if (conf_read_simple(name, S_DEF_USER) && +- conf_read_simple("all.config", S_DEF_USER)) { +- fprintf(stderr, +- _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), +- name); +- exit(1); +- } ++ conf_read(NULL); + break; + default: + break; +--- a/kconf/confdata.c ++++ b/kconf/confdata.c +@@ -1170,6 +1170,8 @@ bool conf_set_all_new_symbols(enum conf_ + } + bool has_changed = false; + ++ sym_clear_all_valid(); ++ + for_all_symbols(i, sym) { + if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) + continue; +@@ -1213,8 +1215,6 @@ bool conf_set_all_new_symbols(enum conf_ + + } + +- sym_clear_all_valid(); +- + /* + * We have different type of choice blocks. + * If curr.tri equals to mod then we can select several diff --git a/lede/package/kernel/mac80211/patches-6.18/build/003-remove_bogus_modparams.patch b/lede/package/kernel/mac80211/patches-6.18/build/003-remove_bogus_modparams.patch new file mode 100644 index 0000000000..aa26c8cb2a --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/003-remove_bogus_modparams.patch @@ -0,0 +1,34 @@ +--- a/compat/main.c ++++ b/compat/main.c +@@ -19,31 +19,6 @@ MODULE_LICENSE("GPL"); + #error "You need a CPTCFG_VERSION" + #endif + +-static char *backported_kernel_name = CPTCFG_KERNEL_NAME; +- +-module_param(backported_kernel_name, charp, 0400); +-MODULE_PARM_DESC(backported_kernel_name, +- "The kernel tree name that was used for this backport (" CPTCFG_KERNEL_NAME ")"); +- +-#ifdef BACKPORTS_GIT_TRACKED +-static char *backports_tracker_id = BACKPORTS_GIT_TRACKED; +-module_param(backports_tracker_id, charp, 0400); +-MODULE_PARM_DESC(backports_tracker_id, +- "The version of the tree containing this backport (" BACKPORTS_GIT_TRACKED ")"); +-#else +-static char *backported_kernel_version = CPTCFG_KERNEL_VERSION; +-static char *backports_version = CPTCFG_VERSION; +- +-module_param(backported_kernel_version, charp, 0400); +-MODULE_PARM_DESC(backported_kernel_version, +- "The kernel version that was used for this backport (" CPTCFG_KERNEL_VERSION ")"); +- +-module_param(backports_version, charp, 0400); +-MODULE_PARM_DESC(backports_version, +- "The git version of the backports tree used to generate this backport (" CPTCFG_VERSION ")"); +- +-#endif +- + void backport_dependency_symbol(void) + { + } diff --git a/lede/package/kernel/mac80211/patches-6.18/build/004-fix-kconf-compiling.patch b/lede/package/kernel/mac80211/patches-6.18/build/004-fix-kconf-compiling.patch new file mode 100644 index 0000000000..8bae8367f7 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/004-fix-kconf-compiling.patch @@ -0,0 +1,47 @@ +--- a/Makefile.real ++++ b/Makefile.real +@@ -6,6 +6,18 @@ else + export BACKPORTS_GIT_TRACKER_DEF= + endif + ++ifneq ($(LLVM),) ++ifneq ($(filter %/,$(LLVM)),) ++LLVM_PREFIX := $(LLVM) ++else ifneq ($(filter -%,$(LLVM)),) ++LLVM_SUFFIX := $(LLVM) ++endif ++ ++HOSTCC = $(LLVM_PREFIX)clang$(LLVM_SUFFIX) ++else ++HOSTCC = gcc ++endif ++ + # disable built-in rules for this file + .SUFFIXES: + +@@ -24,21 +36,21 @@ listnewconfig oldaskconfig oldconfig \ + silentoldconfig olddefconfig oldnoconfig \ + allnoconfig allyesconfig allmodconfig \ + alldefconfig randconfig: +- @$(MAKE) -C kconf conf ++ @$(MAKE) -C kconf CC=$(HOSTCC) conf + @./kconf/conf --$@ Kconfig + + .PHONY: usedefconfig + usedefconfig: +- @$(MAKE) -C kconf conf ++ @$(MAKE) -C kconf CC=$(HOSTCC) conf + @./kconf/conf --defconfig=defconfig Kconfig + + .PHONY: savedefconfig + savedefconfig: +- @$(MAKE) -C kconf conf ++ @$(MAKE) -C kconf CC=$(HOSTCC) conf + @./kconf/conf --savedefconfig=defconfig Kconfig + + defconfig-%:: +- @$(MAKE) -C kconf conf ++ @$(MAKE) -C kconf CC=$(HOSTCC) conf + @./kconf/conf --defconfig=defconfigs/$(@:defconfig-%=%) Kconfig + + .config: diff --git a/lede/package/kernel/mac80211/patches-6.18/build/005-fix-kconf-warnings.patch b/lede/package/kernel/mac80211/patches-6.18/build/005-fix-kconf-warnings.patch new file mode 100644 index 0000000000..00e94003f2 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/005-fix-kconf-warnings.patch @@ -0,0 +1,76 @@ +--- a/kconf/conf.c ++++ b/kconf/conf.c +@@ -86,7 +86,7 @@ static int conf_askvalue(struct symbol * + enum symbol_type type = sym_get_type(sym); + + if (!sym_has_value(sym)) +- printf(_("(NEW) ")); ++ printf("%s", _("(NEW) ")); + + line[0] = '\n'; + line[1] = 0; +@@ -282,7 +282,7 @@ static int conf_choice(struct menu *menu + if (child->sym->name) + printf(" (%s)", child->sym->name); + if (!sym_has_value(child->sym)) +- printf(_(" (NEW)")); ++ printf("%s", _(" (NEW)")); + printf("\n"); + } + printf(_("%*schoice"), indent - 1, ""); +@@ -437,7 +437,7 @@ static void check_conf(struct menu *menu + } + } else { + if (!conf_cnt++) +- printf(_("*\n* Restart config...\n*\n")); ++ printf("%s", _("*\n* Restart config...\n*\n")); + rootEntry = menu_get_parent_menu(menu); + conf(rootEntry); + } +@@ -614,7 +614,7 @@ int main(int ac, char **av) + name = getenv("KCONFIG_NOSILENTUPDATE"); + if (name && *name) { + fprintf(stderr, +- _("\n*** The configuration requires explicit update.\n\n")); ++ "%s", _("\n*** The configuration requires explicit update.\n\n")); + return 1; + } + } +@@ -666,22 +666,22 @@ int main(int ac, char **av) + * All other commands are only used to generate a config. + */ + if (conf_get_changed() && conf_write(NULL)) { +- fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); ++ fprintf(stderr, "%s", _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + if (conf_write_autoconf()) { +- fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); ++ fprintf(stderr, "%s", _("\n*** Error during update of the configuration.\n\n")); + return 1; + } + } else if (input_mode == savedefconfig) { + if (conf_write_defconfig(defconfig_file)) { +- fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), ++ fprintf(stderr, _("\n*** Error while saving defconfig to: %s\n\n"), + defconfig_file); + return 1; + } + } else if (input_mode != listnewconfig) { + if (conf_write(NULL)) { +- fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); ++ fprintf(stderr, "%s", _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + } +--- a/kconf/Makefile ++++ b/kconf/Makefile +@@ -17,7 +17,7 @@ clean: + zconf.tab.c: zconf.lex.c + + %.tab.c: %.y +- $(YACC) -o$@ -t -l $< ++ $(YACC) -Wno-yacc -o$@ -t -l $< + + %.lex.c: %.l + $(LEX) -o$@ -L $< diff --git a/lede/package/kernel/mac80211/patches-6.18/build/012-kernel_build_check.patch b/lede/package/kernel/mac80211/patches-6.18/build/012-kernel_build_check.patch new file mode 100644 index 0000000000..d225ba1820 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/012-kernel_build_check.patch @@ -0,0 +1,11 @@ +--- a/Makefile ++++ b/Makefile +@@ -2,7 +2,7 @@ + # Makefile for the output source package + # + +-ifeq ($(KERNELRELEASE),) ++ifeq ($(KERNELVERSION),) + + MAKEFLAGS += --no-print-directory + SHELL := /usr/bin/env bash diff --git a/lede/package/kernel/mac80211/patches-6.18/build/020-intel-mld-compile.patch b/lede/package/kernel/mac80211/patches-6.18/build/020-intel-mld-compile.patch new file mode 100644 index 0000000000..b501ec770f --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/020-intel-mld-compile.patch @@ -0,0 +1,54 @@ +Fix Intel mld thermal compilation + +Do the same changes done also in iwlwifi/mvm/tt.c in the iwlwifi/mld/thermal.c file. + +This fixes the compilation. + +--- a/drivers/net/wireless/intel/iwlwifi/mld/thermal.c ++++ b/drivers/net/wireless/intel/iwlwifi/mld/thermal.c +@@ -209,9 +209,15 @@ unlock: + return ret; + } + ++#if LINUX_VERSION_IS_GEQ(6,11,0) + static int iwl_mld_tzone_set_trip_temp(struct thermal_zone_device *device, + const struct thermal_trip *trip, + int temp) ++#else ++static int iwl_mld_tzone_set_trip_temp(struct thermal_zone_device *device, ++ int trip, ++ int temp) ++#endif + { + struct iwl_mld *mld = thermal_zone_device_priv(device); + int ret; +@@ -248,18 +254,29 @@ static void iwl_mld_thermal_zone_registe + [0 ... IWL_MAX_DTS_TRIPS - 1] = { + .temperature = THERMAL_TEMP_INVALID, + .type = THERMAL_TRIP_PASSIVE, ++#if LINUX_VERSION_IS_GEQ(6,9,0) + .flags = THERMAL_TRIP_FLAG_RW_TEMP, ++#endif + }, + }; + + BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH); + + sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF); ++#if LINUX_VERSION_IS_GEQ(6,9,0) + mld->tzone = + thermal_zone_device_register_with_trips(name, trips, + IWL_MAX_DTS_TRIPS, + mld, &tzone_ops, + NULL, 0, 0); ++#else ++ mld->tzone = ++ thermal_zone_device_register_with_trips(name, trips, ++ IWL_MAX_DTS_TRIPS, 0, ++ mld, &tzone_ops, ++ NULL, 0, 0); ++#endif ++ + if (IS_ERR(mld->tzone)) { + IWL_DEBUG_TEMP(mld, + "Failed to register to thermal zone (err = %ld)\n", diff --git a/lede/package/kernel/mac80211/patches-6.18/build/100-backports-drop-QRTR-and-MHI.patch b/lede/package/kernel/mac80211/patches-6.18/build/100-backports-drop-QRTR-and-MHI.patch new file mode 100644 index 0000000000..c9cac8284f --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/100-backports-drop-QRTR-and-MHI.patch @@ -0,0 +1,76 @@ +From 54e0f9aaf340377fb76acdffee9ec7372c4b70ae Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Mon, 17 Oct 2022 11:35:36 +0200 +Subject: [PATCH] backports: drop QRTR and MHI + +Backports currently include QRTR and MHI due to ath11k-pci requiring them, +however this at the same time prevents us from adding ath11k-ahb as it +also requires QRTR however its AHB variant from the kernel will conflict +with the core provided by backports. + +Since MHI also conflicts with existing OpenWrt kmods providing MHI drop +both from backports and use the ones provided by OpenWrt kernel. + +Signed-off-by: Robert Marko +--- + Kconfig.sources | 2 -- + Makefile.kernel | 2 -- + drivers/net/wireless/ath/ath11k/Kconfig | 6 +++--- + local-symbols | 8 -------- + 4 files changed, 3 insertions(+), 15 deletions(-) + +--- a/Kconfig.sources ++++ b/Kconfig.sources +@@ -4,8 +4,6 @@ source "$BACKPORT_DIR/compat/Kconfig" + # these are copied from the kernel + source "$BACKPORT_DIR/net/wireless/Kconfig" + source "$BACKPORT_DIR/net/mac80211/Kconfig" +-source "$BACKPORT_DIR/net/qrtr/Kconfig" +-source "$BACKPORT_DIR/drivers/bus/mhi/Kconfig" + source "$BACKPORT_DIR/drivers/soc/qcom/Kconfig" + source "$BACKPORT_DIR/drivers/net/wireless/Kconfig" + source "$BACKPORT_DIR/drivers/net/usb/Kconfig" +--- a/Makefile.kernel ++++ b/Makefile.kernel +@@ -38,9 +38,7 @@ obj-y += compat/ + + obj-$(CPTCFG_CFG80211) += net/wireless/ + obj-$(CPTCFG_MAC80211) += net/mac80211/ +-obj-$(CPTCFG_QRTR) += net/qrtr/ + obj-$(CPTCFG_QCOM_QMI_HELPERS) += drivers/soc/qcom/ +-obj-$(CPTCFG_MHI_BUS) += drivers/bus/mhi/ + obj-$(CPTCFG_WLAN) += drivers/net/wireless/ + obj-$(CPTCFG_USB_NET_RNDIS_WLAN) += drivers/net/usb/ + +--- a/drivers/net/wireless/ath/ath11k/Kconfig ++++ b/drivers/net/wireless/ath/ath11k/Kconfig +@@ -25,9 +25,9 @@ config ATH11K_PCI + tristate "Atheros ath11k PCI support" + depends on m + depends on ATH11K && PCI +- select MHI_BUS +- select QRTR +- select QRTR_MHI ++ depends on MHI_BUS ++ depends on QRTR ++ depends on QRTR_MHI + select PCI_PWRCTRL_PWRSEQ if HAVE_PWRCTRL + help + This module adds support for PCIE bus +--- a/local-symbols ++++ b/local-symbols +@@ -53,14 +53,6 @@ MAC80211_MESH_PS_DEBUG= + MAC80211_TDLS_DEBUG= + MAC80211_DEBUG_COUNTERS= + MAC80211_STA_HASH_MAX_SIZE= +-QRTR= +-QRTR_SMD= +-QRTR_TUN= +-QRTR_MHI= +-MHI_BUS= +-MHI_BUS_DEBUG= +-MHI_BUS_PCI_GENERIC= +-MHI_BUS_EP= + QCOM_AOSS_QMP= + QCOM_COMMAND_DB= + QCOM_GENI_SE= diff --git a/lede/package/kernel/mac80211/patches-6.18/build/120-backport-fix-unaligned.h-header-location.patch b/lede/package/kernel/mac80211/patches-6.18/build/120-backport-fix-unaligned.h-header-location.patch new file mode 100644 index 0000000000..1fe6ab25fc --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/120-backport-fix-unaligned.h-header-location.patch @@ -0,0 +1,26 @@ +From: Shiji Yang +Date: Mon, 28 Apr 2025 22:03:18 +0800 +Subject: [PATCH] backport: fix unaligned.h header location + +unaligned.h was moved from include/asm-generic/ to include/linux/ +in 6.12-rc2 kernel. + +Link: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-6.12.y&id=5f60d5f6bbc12e782fac78110b0ee62698f3b576 +Signed-off-by: Shiji Yang +--- + backport-include/asm/unaligned.h | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/backport-include/asm/unaligned.h ++++ b/backport-include/asm/unaligned.h +@@ -1,6 +1,10 @@ + #ifndef __BACKPORT_ASM_GENERIC_UNALIGNED_H + #define __BACKPORT_ASM_GENERIC_UNALIGNED_H ++#if LINUX_VERSION_IS_GEQ(6,12,0) ++#include_next ++#else + #include_next ++#endif + + #if LINUX_VERSION_IS_LESS(5,7,0) + static inline u32 __get_unaligned_be24(const u8 *p) diff --git a/lede/package/kernel/mac80211/patches-6.18/build/140-trace_backport.patch b/lede/package/kernel/mac80211/patches-6.18/build/140-trace_backport.patch new file mode 100644 index 0000000000..6de40cd617 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/140-trace_backport.patch @@ -0,0 +1,694 @@ +--- a/drivers/bus/mhi/host/trace.h ++++ b/drivers/bus/mhi/host/trace.h +@@ -104,7 +104,11 @@ TRACE_EVENT(mhi_gen_tre, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(name); ++#else ++ __assign_str(name, mhi_cntrl->mhi_dev->name); ++#endif + __entry->ch_num = mhi_chan->chan; + __entry->wp = mhi_tre; + __entry->tre_ptr = le64_to_cpu(mhi_tre->ptr); +@@ -132,7 +136,11 @@ TRACE_EVENT(mhi_intvec_states, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(name); ++#else ++ __assign_str(name, mhi_cntrl->mhi_dev->name); ++#endif + __entry->local_ee = mhi_cntrl->ee; + __entry->state = mhi_cntrl->dev_state; + __entry->dev_ee = dev_ee; +@@ -159,7 +167,11 @@ TRACE_EVENT(mhi_tryset_pm_state, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(name); ++#else ++ __assign_str(name, mhi_cntrl->mhi_dev->name); ++#endif + if (pm_state) + pm_state = __fls(pm_state); + __entry->pm_state = pm_state; +@@ -185,7 +197,11 @@ DECLARE_EVENT_CLASS(mhi_process_event_ri + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(name); ++#else ++ __assign_str(name, mhi_cntrl->mhi_dev->name); ++#endif + __entry->rp = rp; + __entry->ptr = le64_to_cpu(rp->ptr); + __entry->dword0 = le32_to_cpu(rp->dword[0]); +@@ -227,7 +243,11 @@ DECLARE_EVENT_CLASS(mhi_update_channel_s + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(name); ++#else ++ __assign_str(name, mhi_cntrl->mhi_dev->name); ++#endif + __entry->ch_num = mhi_chan->chan; + __entry->state = state; + __entry->reason = reason; +@@ -266,7 +286,11 @@ TRACE_EVENT(mhi_pm_st_transition, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(name); ++#else ++ __assign_str(name, mhi_cntrl->mhi_dev->name); ++#endif + __entry->state = state; + ), + +--- a/drivers/net/wireless/ath/ath10k/trace.h ++++ b/drivers/net/wireless/ath/ath10k/trace.h +@@ -55,8 +55,13 @@ DECLARE_EVENT_CLASS(ath10k_log_event, + __vstring(msg, vaf->fmt, vaf->va) + ), + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __assign_vstr(msg, vaf->fmt, vaf->va); + ), + TP_printk( +@@ -92,8 +97,13 @@ TRACE_EVENT(ath10k_log_dbg, + __vstring(msg, vaf->fmt, vaf->va) + ), + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->level = level; + __assign_vstr(msg, vaf->fmt, vaf->va); + ), +@@ -121,10 +131,17 @@ TRACE_EVENT(ath10k_log_dbg_dump, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); + __assign_str(msg); + __assign_str(prefix); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++ __assign_str(msg, msg); ++ __assign_str(prefix, prefix); ++#endif + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); + ), +@@ -152,8 +169,13 @@ TRACE_EVENT(ath10k_wmi_cmd, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->id = id; + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); +@@ -182,8 +204,13 @@ TRACE_EVENT(ath10k_wmi_event, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->id = id; + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); +@@ -211,8 +238,13 @@ TRACE_EVENT(ath10k_htt_stats, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); + ), +@@ -239,8 +271,13 @@ TRACE_EVENT(ath10k_wmi_dbglog, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->hw_type = ar->hw_rev; + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); +@@ -269,8 +306,13 @@ TRACE_EVENT(ath10k_htt_pktlog, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->hw_type = ar->hw_rev; + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(pktlog), buf, buf_len); +@@ -301,8 +343,13 @@ TRACE_EVENT(ath10k_htt_tx, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->msdu_id = msdu_id; + __entry->msdu_len = msdu_len; + __entry->vdev_id = vdev_id; +@@ -332,8 +379,13 @@ TRACE_EVENT(ath10k_txrx_tx_unref, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->msdu_id = msdu_id; + ), + +@@ -358,8 +410,13 @@ DECLARE_EVENT_CLASS(ath10k_hdr_event, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->len = ath10k_frm_hdr_len(data, len); + memcpy(__get_dynamic_array(data), data, __entry->len); + ), +@@ -386,8 +443,13 @@ DECLARE_EVENT_CLASS(ath10k_payload_event + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->len = len - ath10k_frm_hdr_len(data, len); + memcpy(__get_dynamic_array(payload), + data + ath10k_frm_hdr_len(data, len), __entry->len); +@@ -435,8 +497,13 @@ TRACE_EVENT(ath10k_htt_rx_desc, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->hw_type = ar->hw_rev; + __entry->len = len; + memcpy(__get_dynamic_array(rxdesc), data, len); +@@ -472,8 +539,13 @@ TRACE_EVENT(ath10k_wmi_diag_container, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->type = type; + __entry->timestamp = timestamp; + __entry->code = code; +@@ -505,8 +577,13 @@ TRACE_EVENT(ath10k_wmi_diag, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->dev)); ++ __assign_str(driver, dev_driver_string(ar->dev)); ++#endif + __entry->len = len; + memcpy(__get_dynamic_array(data), data, len); + ), +--- a/drivers/net/wireless/ath/ath11k/trace.h ++++ b/drivers/net/wireless/ath/ath11k/trace.h +@@ -48,8 +48,13 @@ TRACE_EVENT(ath11k_htt_pktlog, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->ab->dev)); ++ __assign_str(driver, dev_driver_string(ar->ab->dev)); ++#endif + __entry->buf_len = buf_len; + __entry->pktlog_checksum = pktlog_checksum; + memcpy(__get_dynamic_array(pktlog), buf, buf_len); +@@ -77,8 +82,13 @@ TRACE_EVENT(ath11k_htt_ppdu_stats, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->ab->dev)); ++ __assign_str(driver, dev_driver_string(ar->ab->dev)); ++#endif + __entry->len = len; + memcpy(__get_dynamic_array(ppdu), data, len); + ), +@@ -105,8 +115,13 @@ TRACE_EVENT(ath11k_htt_rxdesc, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->ab->dev)); ++ __assign_str(driver, dev_driver_string(ar->ab->dev)); ++#endif + __entry->len = len; + __entry->log_type = log_type; + memcpy(__get_dynamic_array(rxdesc), data, len); +@@ -130,8 +145,13 @@ DECLARE_EVENT_CLASS(ath11k_log_event, + __vstring(msg, vaf->fmt, vaf->va) + ), + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++#endif + __assign_vstr(msg, vaf->fmt, vaf->va); + ), + TP_printk( +@@ -171,8 +191,13 @@ TRACE_EVENT(ath11k_wmi_cmd, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++#endif + __entry->id = id; + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); +@@ -201,8 +226,13 @@ TRACE_EVENT(ath11k_wmi_event, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++#endif + __entry->id = id; + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); +@@ -230,8 +260,13 @@ TRACE_EVENT(ath11k_log_dbg, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++#endif + __entry->level = level; + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + ATH11K_MSG_MAX, vaf->fmt, +@@ -262,10 +297,17 @@ TRACE_EVENT(ath11k_log_dbg_dump, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); + __assign_str(msg); + __assign_str(prefix); ++#else ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++ __assign_str(msg, msg); ++ __assign_str(prefix, prefix); ++#endif + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); + ), +@@ -292,8 +334,13 @@ TRACE_EVENT(ath11k_wmi_diag, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++#endif + __entry->len = len; + memcpy(__get_dynamic_array(data), data, len); + ), +@@ -318,8 +365,14 @@ TRACE_EVENT(ath11k_ps_timekeeper, + __field(u32, peer_ps_timestamp) + ), + +- TP_fast_assign(__assign_str(device); ++ TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) ++ __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->ab->dev)); ++ __assign_str(driver, dev_driver_string(ar->ab->dev)); ++#endif + memcpy(__get_dynamic_array(peer_addr), peer_addr, + ETH_ALEN); + __entry->peer_ps_state = peer_ps_state; +--- a/drivers/net/wireless/ath/ath12k/trace.h ++++ b/drivers/net/wireless/ath/ath12k/trace.h +@@ -36,8 +36,13 @@ TRACE_EVENT(ath12k_htt_pktlog, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->ab->dev)); ++ __assign_str(driver, dev_driver_string(ar->ab->dev)); ++#endif + __entry->buf_len = buf_len; + __entry->pktlog_checksum = pktlog_checksum; + memcpy(__get_dynamic_array(pktlog), buf, buf_len); +@@ -73,8 +78,13 @@ TRACE_EVENT(ath12k_htt_ppdu_stats, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->ab->dev)); ++ __assign_str(driver, dev_driver_string(ar->ab->dev)); ++#endif + __entry->len = len; + __entry->info = ar->pdev->timestamp.info; + __entry->sync_tstmp_lo_us = ar->pdev->timestamp.sync_timestamp_hi_us; +@@ -117,8 +127,13 @@ TRACE_EVENT(ath12k_htt_rxdesc, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ar->ab->dev)); ++ __assign_str(driver, dev_driver_string(ar->ab->dev)); ++#endif + __entry->len = len; + __entry->type = type; + __entry->info = ar->pdev->timestamp.info; +@@ -153,8 +168,13 @@ TRACE_EVENT(ath12k_wmi_diag, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, dev_name(ab->dev)); ++ __assign_str(driver, dev_driver_string(ab->dev)); ++#endif + __entry->len = len; + memcpy(__get_dynamic_array(data), data, len); + ), +--- a/drivers/net/wireless/ath/ath6kl/trace.h ++++ b/drivers/net/wireless/ath/ath6kl/trace.h +@@ -304,8 +304,13 @@ TRACE_EVENT(ath6kl_log_dbg_dump, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(msg); + __assign_str(prefix); ++#else ++ __assign_str(msg, msg); ++ __assign_str(prefix, prefix); ++#endif + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(buf), buf, buf_len); + ), +--- a/drivers/net/wireless/ath/trace.h ++++ b/drivers/net/wireless/ath/trace.h +@@ -44,8 +44,13 @@ TRACE_EVENT(ath_log, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(device); + __assign_str(driver); ++#else ++ __assign_str(device, wiphy_name(wiphy)); ++ __assign_str(driver, KBUILD_MODNAME); ++#endif + __assign_vstr(msg, vaf->fmt, vaf->va); + ), + +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h +@@ -41,7 +41,11 @@ TRACE_EVENT(brcmf_err, + __vstring(msg, vaf->fmt, vaf->va) + ), + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(func); ++#else ++ __assign_str(func, func); ++#endif + __assign_vstr(msg, vaf->fmt, vaf->va); + ), + TP_printk("%s: %s", __get_str(func), __get_str(msg)) +@@ -57,7 +61,11 @@ TRACE_EVENT(brcmf_dbg, + ), + TP_fast_assign( + __entry->level = level; ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(func); ++#else ++ __assign_str(func, func); ++#endif + __assign_vstr(msg, vaf->fmt, vaf->va); + ), + TP_printk("%s: %s", __get_str(func), __get_str(msg)) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac.h +@@ -81,7 +81,11 @@ TRACE_EVENT(brcms_macintstatus, + __field(u32, mask) + ), + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(dev); ++#else ++ __assign_str(dev, dev_name(dev)); ++#endif + __entry->in_isr = in_isr; + __entry->macintstatus = macintstatus; + __entry->mask = mask; +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h +@@ -71,7 +71,11 @@ TRACE_EVENT(brcms_dbg, + ), + TP_fast_assign( + __entry->level = level; ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(func); ++#else ++ __assign_str(func, func); ++#endif + __assign_vstr(msg, vaf->fmt, vaf->va); + ), + TP_printk("%s: %s", __get_str(func), __get_str(msg)) +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_tx.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_tx.h +@@ -31,7 +31,11 @@ TRACE_EVENT(brcms_txdesc, + __dynamic_array(u8, txh, txh_len) + ), + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(dev); ++#else ++ __assign_str(dev, dev_name(dev)); ++#endif + memcpy(__get_dynamic_array(txh), txh, txh_len); + ), + TP_printk("[%s] txdesc", __get_str(dev)) +@@ -54,7 +58,11 @@ TRACE_EVENT(brcms_txstatus, + __field(u16, ackphyrxsh) + ), + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(dev); ++#else ++ __assign_str(dev, dev_name(dev)); ++#endif + __entry->framelen = framelen; + __entry->frameid = frameid; + __entry->status = status; +@@ -85,7 +93,11 @@ TRACE_EVENT(brcms_ampdu_session, + __field(u16, dma_len) + ), + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(dev); ++#else ++ __assign_str(dev, dev_name(dev)); ++#endif + __entry->max_ampdu_len = max_ampdu_len; + __entry->max_ampdu_frames = max_ampdu_frames; + __entry->ampdu_len = ampdu_len; +--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-msg.h +@@ -57,7 +57,11 @@ TRACE_EVENT(iwlwifi_dbg, + ), + TP_fast_assign( + __entry->level = level; ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(function); ++#else ++ __assign_str(function, function); ++#endif + __assign_vstr(msg, vaf->fmt, vaf->va); + ), + TP_printk("%s", __get_str(msg)) +--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h +@@ -88,7 +88,11 @@ static inline void trace_ ## name(proto) + #endif + + #define DEV_ENTRY __string(dev, dev_name(dev)) ++#if LINUX_VERSION_IS_GEQ(6,10,0) + #define DEV_ASSIGN __assign_str(dev) ++#else ++#define DEV_ASSIGN __assign_str(dev, dev_name(dev)) ++#endif + + #include "iwl-devtrace-io.h" + #include "iwl-devtrace-ucode.h" +--- a/include/trace/events/qrtr.h ++++ b/include/trace/events/qrtr.h +@@ -102,7 +102,11 @@ TRACE_EVENT(qrtr_ns_message, + ), + + TP_fast_assign( ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(ctrl_pkt_str); ++#else ++ __assign_str(ctrl_pkt_str, ctrl_pkt_str); ++#endif + __entry->sq_node = sq_node; + __entry->sq_port = sq_port; + ), +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -31,9 +31,15 @@ + #define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \ + __field(bool, p2p) \ + __string(vif_name, sdata->name) ++#if LINUX_VERSION_IS_GEQ(6,10,0) + #define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ + __entry->p2p = sdata->vif.p2p; \ + __assign_str(vif_name) ++#else ++#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ ++ __entry->p2p = sdata->vif.p2p; \ ++ __assign_str(vif_name, sdata->name) ++#endif + #define VIF_PR_FMT " vif:%s(%d%s)" + #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" + +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -478,7 +478,11 @@ TRACE_EVENT(rdev_add_virtual_intf, + ), + TP_fast_assign( + WIPHY_ASSIGN; ++#if LINUX_VERSION_IS_GEQ(6,10,0) + __assign_str(vir_intf_name); ++#else ++ __assign_str(vir_intf_name, name ? name : ""); ++#endif + __entry->type = type; + ), + TP_printk(WIPHY_PR_FMT ", virtual intf name: %s, type: %d", diff --git a/lede/package/kernel/mac80211/patches-6.18/build/150-ath_iommu_paging_domain_revert.patch b/lede/package/kernel/mac80211/patches-6.18/build/150-ath_iommu_paging_domain_revert.patch new file mode 100644 index 0000000000..f020af7c23 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/150-ath_iommu_paging_domain_revert.patch @@ -0,0 +1,32 @@ +--- a/drivers/net/wireless/ath/ath10k/snoc.c ++++ b/drivers/net/wireless/ath/ath10k/snoc.c +@@ -1630,10 +1630,10 @@ static int ath10k_fw_init(struct ath10k + + ar_snoc->fw.dev = &pdev->dev; + +- iommu_dom = iommu_paging_domain_alloc(ar_snoc->fw.dev); +- if (IS_ERR(iommu_dom)) { ++ iommu_dom = iommu_domain_alloc(&platform_bus_type); ++ if (!iommu_dom) { + ath10k_err(ar, "failed to allocate iommu domain\n"); +- ret = PTR_ERR(iommu_dom); ++ ret = -ENOMEM; + goto err_unregister; + } + +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -1020,10 +1020,10 @@ static int ath11k_ahb_fw_resources_init( + + ab_ahb->fw.dev = &pdev->dev; + +- iommu_dom = iommu_paging_domain_alloc(ab_ahb->fw.dev); +- if (IS_ERR(iommu_dom)) { ++ iommu_dom = iommu_domain_alloc(&platform_bus_type); ++ if (!iommu_dom) { + ath11k_err(ab, "failed to allocate iommu domain\n"); +- ret = PTR_ERR(iommu_dom); ++ ret = -ENOMEM; + goto err_unregister; + } + diff --git a/lede/package/kernel/mac80211/patches-6.18/build/200-iwlwifi_thermal_backport.patch b/lede/package/kernel/mac80211/patches-6.18/build/200-iwlwifi_thermal_backport.patch new file mode 100644 index 0000000000..4180682e81 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/200-iwlwifi_thermal_backport.patch @@ -0,0 +1,40 @@ +--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +@@ -626,8 +626,13 @@ static int iwl_mvm_tzone_get_temp(struct + return 0; + } + ++#if LINUX_VERSION_IS_GEQ(6,11,0) + static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device, + const struct thermal_trip *trip, int temp) ++#else ++static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device, ++ int trip, int temp) ++#endif + { + struct iwl_mvm *mvm = thermal_zone_device_priv(device); + +@@ -670,13 +675,23 @@ static void iwl_mvm_thermal_zone_registe + for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) { + mvm->tz_device.trips[i].temperature = THERMAL_TEMP_INVALID; + mvm->tz_device.trips[i].type = THERMAL_TRIP_PASSIVE; ++#if LINUX_VERSION_IS_GEQ(6,9,0) + mvm->tz_device.trips[i].flags = THERMAL_TRIP_FLAG_RW_TEMP; ++#endif + } ++#if LINUX_VERSION_IS_GEQ(6,9,0) + mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name, + mvm->tz_device.trips, + IWL_MAX_DTS_TRIPS, + mvm, &tzone_ops, + NULL, 0, 0); ++#else ++ mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name, ++ mvm->tz_device.trips, ++ IWL_MAX_DTS_TRIPS, 0, ++ mvm, &tzone_ops, ++ NULL, 0, 0); ++#endif + if (IS_ERR(mvm->tz_device.tzone)) { + IWL_DEBUG_TEMP(mvm, + "Failed to register to thermal zone (err = %ld)\n", diff --git a/lede/package/kernel/mac80211/patches-6.18/build/210-wireless_netns_local_backport.patch b/lede/package/kernel/mac80211/patches-6.18/build/210-wireless_netns_local_backport.patch new file mode 100644 index 0000000000..428d8df0f1 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/210-wireless_netns_local_backport.patch @@ -0,0 +1,54 @@ +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -162,11 +162,19 @@ int cfg80211_switch_netns(struct cfg8021 + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + if (!wdev->netdev) + continue; ++#if LINUX_VERSION_IS_GEQ(6,15,0) + wdev->netdev->netns_immutable = false; ++#elif LINUX_VERSION_IS_GEQ(6,12,0) ++ wdev->netdev->netns_local = false; ++#endif + err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); + if (err) + break; ++#if LINUX_VERSION_IS_GEQ(6,15,0) + wdev->netdev->netns_immutable = true; ++#elif LINUX_VERSION_IS_GEQ(6,12,0) ++ wdev->netdev->netns_local = true; ++#endif + } + + if (err) { +@@ -178,11 +186,19 @@ int cfg80211_switch_netns(struct cfg8021 + list) { + if (!wdev->netdev) + continue; ++#if LINUX_VERSION_IS_GEQ(6,15,0) + wdev->netdev->netns_immutable = false; ++#elif LINUX_VERSION_IS_GEQ(6,12,0) ++ wdev->netdev->netns_local = false; ++#endif + err = dev_change_net_namespace(wdev->netdev, net, + "wlan%d"); + WARN_ON(err); ++#if LINUX_VERSION_IS_GEQ(6,15,0) + wdev->netdev->netns_immutable = true; ++#elif LINUX_VERSION_IS_GEQ(6,12,0) ++ wdev->netdev->netns_local = true; ++#endif + } + + return err; +@@ -1550,7 +1566,11 @@ static int cfg80211_netdev_notifier_call + SET_NETDEV_DEVTYPE(dev, &wiphy_type); + wdev->netdev = dev; + /* can only change netns with wiphy */ ++#if LINUX_VERSION_IS_GEQ(6,15,0) + dev->netns_immutable = true; ++#elif LINUX_VERSION_IS_GEQ(6,12,0) ++ dev->netns_local = true; ++#endif + + cfg80211_init_wdev(wdev); + break; diff --git a/lede/package/kernel/mac80211/patches-6.18/build/220-brcmfmac_usb_driver_backport.patch b/lede/package/kernel/mac80211/patches-6.18/build/220-brcmfmac_usb_driver_backport.patch new file mode 100644 index 0000000000..f2f4e7bfec --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/220-brcmfmac_usb_driver_backport.patch @@ -0,0 +1,14 @@ +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +@@ -1585,7 +1585,11 @@ static int brcmf_usb_reset_device(struct + + void brcmf_usb_exit(void) + { ++#if LINUX_VERSION_IS_GEQ(6,8,0) + struct device_driver *drv = &brcmf_usbdrvr.driver; ++#else ++ struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver; ++#endif + int ret; + + brcmf_dbg(USB, "Enter\n"); diff --git a/lede/package/kernel/mac80211/patches-6.18/build/230-fix-init_vqs-build-error-on-kernel-6.6.patch b/lede/package/kernel/mac80211/patches-6.18/build/230-fix-init_vqs-build-error-on-kernel-6.6.patch new file mode 100644 index 0000000000..500ebe172e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/230-fix-init_vqs-build-error-on-kernel-6.6.patch @@ -0,0 +1,30 @@ +--- a/drivers/net/wireless/virtual/mac80211_hwsim.c ++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c +@@ -6927,6 +6927,7 @@ static void hwsim_virtio_rx_done(struct + + static int init_vqs(struct virtio_device *vdev) + { ++#if LINUX_VERSION_IS_GEQ(6,11,0) + struct virtqueue_info vqs_info[HWSIM_NUM_VQS] = { + [HWSIM_VQ_TX] = { "tx", hwsim_virtio_tx_done }, + [HWSIM_VQ_RX] = { "rx", hwsim_virtio_rx_done }, +@@ -6934,6 +6935,19 @@ static int init_vqs(struct virtio_device + + return virtio_find_vqs(vdev, HWSIM_NUM_VQS, + hwsim_vqs, vqs_info, NULL); ++#else /* Using the old ABI, copied from kernel 6.6 */ ++ vq_callback_t *callbacks[HWSIM_NUM_VQS] = { ++ [HWSIM_VQ_TX] = hwsim_virtio_tx_done, ++ [HWSIM_VQ_RX] = hwsim_virtio_rx_done, ++ }; ++ const char *names[HWSIM_NUM_VQS] = { ++ [HWSIM_VQ_TX] = "tx", ++ [HWSIM_VQ_RX] = "rx", ++ }; ++ ++ return virtio_find_vqs(vdev, HWSIM_NUM_VQS, ++ hwsim_vqs, callbacks, names, NULL); ++#endif + } + + static int fill_vq(struct virtqueue *vq) diff --git a/lede/package/kernel/mac80211/patches-6.18/build/240-realtek-rtw88-BH-workqueue.patch b/lede/package/kernel/mac80211/patches-6.18/build/240-realtek-rtw88-BH-workqueue.patch new file mode 100644 index 0000000000..53631859f0 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/240-realtek-rtw88-BH-workqueue.patch @@ -0,0 +1,14 @@ +--- a/drivers/net/wireless/realtek/rtw88/usb.c ++++ b/drivers/net/wireless/realtek/rtw88/usb.c +@@ -965,7 +965,11 @@ static int rtw_usb_init_rx(struct rtw_de + struct sk_buff *rx_skb; + int i; + ++#if LINUX_VERSION_IS_GEQ(6,9,0) + rtwusb->rxwq = alloc_workqueue("rtw88_usb: rx wq", WQ_BH, 0); ++#else ++ rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq"); ++#endif + if (!rtwusb->rxwq) { + rtw_err(rtwdev, "failed to create RX work queue\n"); + return -ENOMEM; diff --git a/lede/package/kernel/mac80211/patches-6.18/build/300-backports-handle-genlmsg_multicast_allns-upstream-ba.patch b/lede/package/kernel/mac80211/patches-6.18/build/300-backports-handle-genlmsg_multicast_allns-upstream-ba.patch new file mode 100644 index 0000000000..1e1b03514b --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/300-backports-handle-genlmsg_multicast_allns-upstream-ba.patch @@ -0,0 +1,121 @@ +From 8dc94a59cfad70ec3a808add56718255eee39ab2 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 29 Mar 2025 12:50:55 +0100 +Subject: [PATCH] backports: handle genlmsg_multicast_allns upstream backport + changes + +Better handle genlmsg_multicast_allns upstream backport changes that +dropped a flag to the function middle version. Use a backport function +if backports project is tried to be built on older kernel version. + +Signed-off-by: Christian Marangi +--- + backport-include/net/genetlink.h | 11 +++++ + compat/Makefile | 3 +- + compat/backport-genetlink.c | 60 +++++++++++++++++++++++ + 3 files changed, 73 insertions(+), 1 deletion(-) + +--- a/backport-include/net/genetlink.h ++++ b/backport-include/net/genetlink.h +@@ -192,4 +192,15 @@ int backport_genlmsg_multicast_allns(con + #define genlmsg_multicast_allns LINUX_BACKPORT(genlmsg_multicast_allns) + #endif /* LINUX_VERSION_IS_LESS(5,2,0) */ + ++#if LINUX_VERSION_IN_RANGE(5,15,0,5,15,169) || \ ++ LINUX_VERSION_IN_RANGE(6,1,0,6,1,115) || \ ++ LINUX_VERSION_IN_RANGE(6,6,0,6,6,58) ++#define genlmsg_multicast_allns LINUX_BACKPORT(genlmsg_multicast_allns) ++int backport_genlmsg_multicast_allns(const struct genl_family *family, ++ struct sk_buff *skb, u32 portid, ++ unsigned int group); ++#endif /* LINUX_VERSION_IN_RANGE(5,15,0,5,15,169) || ++ LINUX_VERSION_IN_RANGE(6,1,0,6,1,115) || ++ LINUX_VERSION_IN_RANGE(6,6,0,6,6,58) */ ++ + #endif /* __BACKPORT_NET_GENETLINK_H */ +--- a/compat/Makefile ++++ b/compat/Makefile +@@ -16,7 +16,8 @@ compat-$(CPTCFG_KERNEL_5_9) += backport- + compat-$(CPTCFG_KERNEL_5_10) += backport-5.10.o + compat-$(CPTCFG_KERNEL_5_11) += backport-5.11.o + compat-$(CPTCFG_KERNEL_5_13) += backport-5.13.o +-compat-$(CPTCFG_KERNEL_5_15) += backport-5.15.o ++compat-$(CPTCFG_KERNEL_5_15) += backport-5.15.o backport-genetlink.o ++compat-$(CPTCFG_KERNEL_6_1) += backport-genetlink.o + compat-$(CPTCFG_KERNEL_6_4) += backport-6.4.o + compat-$(CPTCFG_KERNEL_6_11) += backport-6.11.o + +--- a/compat/backport-genetlink.c ++++ b/compat/backport-genetlink.c +@@ -17,6 +17,7 @@ + #include + #include + ++#if LINUX_VERSION_IS_LESS(5,2,0) + static const struct genl_family *find_family_real_ops(const struct genl_ops **ops) + { + const struct genl_family *family; +@@ -249,3 +250,63 @@ int backport_genlmsg_multicast_allns(con + return genlmsg_mcast(skb, portid, group); + } + EXPORT_SYMBOL_GPL(backport_genlmsg_multicast_allns); ++#endif /* LINUX_VERSION_IS_LESS(5,2,0) */ ++ ++#if LINUX_VERSION_IN_RANGE(5,15,0,5,15,169) || \ ++ LINUX_VERSION_IN_RANGE(6,1,0,6,1,115) || \ ++ LINUX_VERSION_IN_RANGE(6,6,0,6,6,58) ++static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group) ++{ ++ struct sk_buff *tmp; ++ struct net *net, *prev = NULL; ++ bool delivered = false; ++ int err; ++ ++ rcu_read_lock(); ++ for_each_net_rcu(net) { ++ if (prev) { ++ tmp = skb_clone(skb, GFP_ATOMIC); ++ if (!tmp) { ++ err = -ENOMEM; ++ goto error; ++ } ++ err = nlmsg_multicast(prev->genl_sock, tmp, ++ portid, group, GFP_ATOMIC); ++ if (!err) ++ delivered = true; ++ else if (err != -ESRCH) ++ goto error; ++ } ++ ++ prev = net; ++ } ++ err = nlmsg_multicast(prev->genl_sock, skb, portid, group, GFP_ATOMIC); ++ ++ rcu_read_unlock(); ++ ++ if (!err) ++ delivered = true; ++ else if (err != -ESRCH) ++ return err; ++ return delivered ? 0 : -ESRCH; ++ error: ++ rcu_read_unlock(); ++ ++ kfree_skb(skb); ++ return err; ++} ++ ++int backport_genlmsg_multicast_allns(const struct genl_family *family, ++ struct sk_buff *skb, u32 portid, ++ unsigned int group) ++{ ++ if (WARN_ON_ONCE(group >= family->n_mcgrps)) ++ return -EINVAL; ++ ++ group = family->mcgrp_offset + group; ++ return genlmsg_mcast(skb, portid, group); ++} ++EXPORT_SYMBOL_GPL(backport_genlmsg_multicast_allns); ++#endif /* LINUX_VERSION_IN_RANGE(5,15,0,5,15,169) || ++ LINUX_VERSION_IN_RANGE(6,1,0,6,1,115) || ++ LINUX_VERSION_IN_RANGE(6,6,0,6,6,58) */ diff --git a/lede/package/kernel/mac80211/patches-6.18/build/400-restore-old-debugfs_fops.patch b/lede/package/kernel/mac80211/patches-6.18/build/400-restore-old-debugfs_fops.patch new file mode 100644 index 0000000000..14a707b7ef --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/400-restore-old-debugfs_fops.patch @@ -0,0 +1,252 @@ +--- a/drivers/net/wireless/ath/carl9170/debug.c ++++ b/drivers/net/wireless/ath/carl9170/debug.c +@@ -54,6 +54,7 @@ struct carl9170_debugfs_fops { + char *(*read)(struct ar9170 *ar, char *buf, size_t bufsize, + ssize_t *len); + ssize_t (*write)(struct ar9170 *aru, const char *buf, size_t size); ++ const struct file_operations fops; + + enum carl9170_device_state req_dev_state; + }; +@@ -61,7 +62,7 @@ struct carl9170_debugfs_fops { + static ssize_t carl9170_debugfs_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) + { +- const struct carl9170_debugfs_fops *dfops; ++ struct carl9170_debugfs_fops *dfops; + struct ar9170 *ar; + char *buf = NULL, *res_buf = NULL; + ssize_t ret = 0; +@@ -74,7 +75,8 @@ static ssize_t carl9170_debugfs_read(str + + if (!ar) + return -ENODEV; +- dfops = debugfs_get_aux(file); ++ dfops = container_of(debugfs_real_fops(file), ++ struct carl9170_debugfs_fops, fops); + + if (!dfops->read) + return -ENOSYS; +@@ -111,7 +113,7 @@ out_free: + static ssize_t carl9170_debugfs_write(struct file *file, + const char __user *userbuf, size_t count, loff_t *ppos) + { +- const struct carl9170_debugfs_fops *dfops; ++ struct carl9170_debugfs_fops *dfops; + struct ar9170 *ar; + char *buf = NULL; + int err = 0; +@@ -126,7 +128,8 @@ static ssize_t carl9170_debugfs_write(st + + if (!ar) + return -ENODEV; +- dfops = debugfs_get_aux(file); ++ dfops = container_of(debugfs_real_fops(file), ++ struct carl9170_debugfs_fops, fops); + + if (!dfops->write) + return -ENOSYS; +@@ -162,11 +165,6 @@ out_free: + return err; + } + +-static struct debugfs_short_fops debugfs_fops = { +- .read = carl9170_debugfs_read, +- .write = carl9170_debugfs_write, +-}; +- + #define __DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, \ + _attr, _dstate) \ + static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\ +@@ -175,6 +173,12 @@ static const struct carl9170_debugfs_fop + .write = _write, \ + .attr = _attr, \ + .req_dev_state = _dstate, \ ++ .fops = { \ ++ .open = simple_open, \ ++ .read = carl9170_debugfs_read, \ ++ .write = carl9170_debugfs_write, \ ++ .owner = THIS_MODULE \ ++ }, \ + } + + #define DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, _attr) \ +@@ -812,9 +816,9 @@ void carl9170_debugfs_register(struct ar + ar->hw->wiphy->debugfsdir); + + #define DEBUGFS_ADD(name) \ +- debugfs_create_file_aux(#name, carl_debugfs_##name ##_ops.attr, \ +- ar->debug_dir, ar, &carl_debugfs_##name ## _ops, \ +- &debugfs_fops) ++ debugfs_create_file(#name, carl_debugfs_##name ##_ops.attr, \ ++ ar->debug_dir, ar, \ ++ &carl_debugfs_##name ## _ops.fops) + + DEBUGFS_ADD(usb_tx_anch_urbs); + DEBUGFS_ADD(usb_rx_pool_urbs); +--- a/drivers/net/wireless/broadcom/b43/debugfs.c ++++ b/drivers/net/wireless/broadcom/b43/debugfs.c +@@ -30,6 +30,7 @@ static struct dentry *rootdir; + struct b43_debugfs_fops { + ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize); + int (*write)(struct b43_wldev *dev, const char *buf, size_t count); ++ struct file_operations fops; + /* Offset of struct b43_dfs_file in struct b43_dfsentry */ + size_t file_struct_offset; + }; +@@ -490,7 +491,7 @@ static ssize_t b43_debugfs_read(struct f + size_t count, loff_t *ppos) + { + struct b43_wldev *dev; +- const struct b43_debugfs_fops *dfops; ++ struct b43_debugfs_fops *dfops; + struct b43_dfs_file *dfile; + ssize_t ret; + char *buf; +@@ -510,7 +511,8 @@ static ssize_t b43_debugfs_read(struct f + goto out_unlock; + } + +- dfops = debugfs_get_aux(file); ++ dfops = container_of(debugfs_real_fops(file), ++ struct b43_debugfs_fops, fops); + if (!dfops->read) { + err = -ENOSYS; + goto out_unlock; +@@ -553,7 +555,7 @@ static ssize_t b43_debugfs_write(struct + size_t count, loff_t *ppos) + { + struct b43_wldev *dev; +- const struct b43_debugfs_fops *dfops; ++ struct b43_debugfs_fops *dfops; + char *buf; + int err = 0; + +@@ -571,7 +573,8 @@ static ssize_t b43_debugfs_write(struct + goto out_unlock; + } + +- dfops = debugfs_get_aux(file); ++ dfops = container_of(debugfs_real_fops(file), ++ struct b43_debugfs_fops, fops); + if (!dfops->write) { + err = -ENOSYS; + goto out_unlock; +@@ -599,16 +602,16 @@ out_unlock: + } + + +-static struct debugfs_short_fops debugfs_ops = { +- .read = b43_debugfs_read, +- .write = b43_debugfs_write, +- .llseek = generic_file_llseek, +-}; +- + #define B43_DEBUGFS_FOPS(name, _read, _write) \ + static struct b43_debugfs_fops fops_##name = { \ + .read = _read, \ + .write = _write, \ ++ .fops = { \ ++ .open = simple_open, \ ++ .read = b43_debugfs_read, \ ++ .write = b43_debugfs_write, \ ++ .llseek = generic_file_llseek, \ ++ }, \ + .file_struct_offset = offsetof(struct b43_dfsentry, \ + file_##name), \ + } +@@ -700,9 +703,9 @@ void b43_debugfs_add_device(struct b43_w + + #define ADD_FILE(name, mode) \ + do { \ +- debugfs_create_file_aux(__stringify(name), \ ++ debugfs_create_file(__stringify(name), \ + mode, e->subdir, dev, \ +- &fops_##name, &debugfs_ops); \ ++ &fops_##name.fops); \ + } while (0) + + +--- a/drivers/net/wireless/broadcom/b43legacy/debugfs.c ++++ b/drivers/net/wireless/broadcom/b43legacy/debugfs.c +@@ -31,6 +31,7 @@ static struct dentry *rootdir; + struct b43legacy_debugfs_fops { + ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize); + int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count); ++ struct file_operations fops; + /* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */ + size_t file_struct_offset; + /* Take wl->irq_lock before calling read/write? */ +@@ -187,7 +188,7 @@ static ssize_t b43legacy_debugfs_read(st + size_t count, loff_t *ppos) + { + struct b43legacy_wldev *dev; +- const struct b43legacy_debugfs_fops *dfops; ++ struct b43legacy_debugfs_fops *dfops; + struct b43legacy_dfs_file *dfile; + ssize_t ret; + char *buf; +@@ -207,7 +208,8 @@ static ssize_t b43legacy_debugfs_read(st + goto out_unlock; + } + +- dfops = debugfs_get_aux(file); ++ dfops = container_of(debugfs_real_fops(file), ++ struct b43legacy_debugfs_fops, fops); + if (!dfops->read) { + err = -ENOSYS; + goto out_unlock; +@@ -255,7 +257,7 @@ static ssize_t b43legacy_debugfs_write(s + size_t count, loff_t *ppos) + { + struct b43legacy_wldev *dev; +- const struct b43legacy_debugfs_fops *dfops; ++ struct b43legacy_debugfs_fops *dfops; + char *buf; + int err = 0; + +@@ -273,7 +275,8 @@ static ssize_t b43legacy_debugfs_write(s + goto out_unlock; + } + +- dfops = debugfs_get_aux(file); ++ dfops = container_of(debugfs_real_fops(file), ++ struct b43legacy_debugfs_fops, fops); + if (!dfops->write) { + err = -ENOSYS; + goto out_unlock; +@@ -305,16 +308,17 @@ out_unlock: + return err ? err : count; + } + +-static struct debugfs_short_fops debugfs_ops = { +- .read = b43legacy_debugfs_read, +- .write = b43legacy_debugfs_write, +- .llseek = generic_file_llseek +-}; + + #define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ + static struct b43legacy_debugfs_fops fops_##name = { \ + .read = _read, \ + .write = _write, \ ++ .fops = { \ ++ .open = simple_open, \ ++ .read = b43legacy_debugfs_read, \ ++ .write = b43legacy_debugfs_write, \ ++ .llseek = generic_file_llseek, \ ++ }, \ + .file_struct_offset = offsetof(struct b43legacy_dfsentry, \ + file_##name), \ + .take_irqlock = _take_irqlock, \ +@@ -382,9 +386,9 @@ void b43legacy_debugfs_add_device(struct + + #define ADD_FILE(name, mode) \ + do { \ +- debugfs_create_file_aux(__stringify(name), mode, \ ++ debugfs_create_file(__stringify(name), mode, \ + e->subdir, dev, \ +- &fops_##name, &debugfs_ops); \ ++ &fops_##name.fops); \ + } while (0) + + diff --git a/lede/package/kernel/mac80211/patches-6.18/build/410-mac80211-convert-short-fops-to-debugfs-files.patch b/lede/package/kernel/mac80211/patches-6.18/build/410-mac80211-convert-short-fops-to-debugfs-files.patch new file mode 100644 index 0000000000..e5b0372a30 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/build/410-mac80211-convert-short-fops-to-debugfs-files.patch @@ -0,0 +1,210 @@ +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -42,8 +42,9 @@ static ssize_t name## _read(struct file + } + + #define DEBUGFS_READONLY_FILE_OPS(name) \ +-static const struct debugfs_short_fops name## _ops = { \ ++static const struct file_operations name## _ops = { \ + .read = name## _read, \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + }; + +@@ -139,9 +140,10 @@ static ssize_t aqm_write(struct file *fi + return -EINVAL; + } + +-static const struct debugfs_short_fops aqm_ops = { ++static const struct file_operations aqm_ops = { + .write = aqm_write, + .read = aqm_read, ++ .open = simple_open, + .llseek = default_llseek, + }; + +@@ -190,9 +192,10 @@ static ssize_t airtime_flags_write(struc + return count; + } + +-static const struct debugfs_short_fops airtime_flags_ops = { ++static const struct file_operations airtime_flags_ops = { + .write = airtime_flags_write, + .read = airtime_flags_read, ++ .open = simple_open, + .llseek = default_llseek, + }; + +@@ -220,8 +223,9 @@ static ssize_t aql_pending_read(struct f + buf, len); + } + +-static const struct debugfs_short_fops aql_pending_ops = { ++static const struct file_operations aql_pending_ops = { + .read = aql_pending_read, ++ .open = simple_open, + .llseek = default_llseek, + }; + +@@ -299,9 +303,10 @@ static ssize_t aql_txq_limit_write(struc + return count; + } + +-static const struct debugfs_short_fops aql_txq_limit_ops = { ++static const struct file_operations aql_txq_limit_ops = { + .write = aql_txq_limit_write, + .read = aql_txq_limit_read, ++ .open = simple_open, + .llseek = default_llseek, + }; + +@@ -348,9 +353,10 @@ static ssize_t aql_enable_write(struct f + return count; + } + +-static const struct debugfs_short_fops aql_enable_ops = { ++static const struct file_operations aql_enable_ops = { + .write = aql_enable_write, + .read = aql_enable_read, ++ .open = simple_open, + .llseek = default_llseek, + }; + +@@ -398,9 +404,10 @@ static ssize_t force_tx_status_write(str + return count; + } + +-static const struct debugfs_short_fops force_tx_status_ops = { ++static const struct file_operations force_tx_status_ops = { + .write = force_tx_status_write, + .read = force_tx_status_read, ++ .open = simple_open, + .llseek = default_llseek, + }; + +@@ -425,8 +432,9 @@ static ssize_t reset_write(struct file * + return count; + } + +-static const struct debugfs_short_fops reset_ops = { ++static const struct file_operations reset_ops = { + .write = reset_write, ++ .open = simple_open, + .llseek = noop_llseek, + }; + #endif +@@ -653,8 +661,9 @@ static ssize_t stats_ ##name## _read(str + print_devstats_##name); \ + } \ + \ +-static const struct debugfs_short_fops stats_ ##name## _ops = { \ ++static const struct file_operations stats_ ##name## _ops = { \ + .read = stats_ ##name## _read, \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + }; + +--- a/net/mac80211/debugfs_key.c ++++ b/net/mac80211/debugfs_key.c +@@ -26,15 +26,17 @@ static ssize_t key_##name##_read(struct + #define KEY_READ_X(name) KEY_READ(name, name, "0x%x\n") + + #define KEY_OPS(name) \ +-static const struct debugfs_short_fops key_ ##name## _ops = { \ ++static const struct file_operations key_ ##name## _ops = { \ + .read = key_##name##_read, \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + } + + #define KEY_OPS_W(name) \ +-static const struct debugfs_short_fops key_ ##name## _ops = { \ ++static const struct file_operations key_ ##name## _ops = { \ + .read = key_##name##_read, \ + .write = key_##name##_write, \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + } + +@@ -47,8 +49,9 @@ static const struct debugfs_short_fops k + #define KEY_CONF_READ_D(name) KEY_CONF_READ(name, "%d\n") + + #define KEY_CONF_OPS(name) \ +-static const struct debugfs_short_fops key_ ##name## _ops = { \ ++static const struct file_operations key_ ##name## _ops = { \ + .read = key_conf_##name##_read, \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + } + +--- a/net/mac80211/debugfs_netdev.c ++++ b/net/mac80211/debugfs_netdev.c +@@ -221,9 +221,10 @@ static ssize_t ieee80211_if_fmt_##name( + } + + #define _IEEE80211_IF_FILE_OPS(name, _read, _write) \ +-static const struct debugfs_short_fops name##_ops = { \ ++static const struct file_operations name##_ops = { \ + .read = (_read), \ + .write = (_write), \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + } + +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -30,15 +30,17 @@ static ssize_t sta_ ##name## _read(struc + #define STA_READ_D(name, field) STA_READ(name, field, "%d\n") + + #define STA_OPS(name) \ +-static const struct debugfs_short_fops sta_ ##name## _ops = { \ ++static const struct file_operations sta_ ##name## _ops = { \ + .read = sta_##name##_read, \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + } + + #define STA_OPS_RW(name) \ +-static const struct debugfs_short_fops sta_ ##name## _ops = { \ ++static const struct file_operations sta_ ##name## _ops = { \ + .read = sta_##name##_read, \ + .write = sta_##name##_write, \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + } + +@@ -440,8 +442,9 @@ STA_OPS_RW(agg_status); + + /* link sta attributes */ + #define LINK_STA_OPS(name) \ +-static const struct debugfs_short_fops link_sta_ ##name## _ops = { \ ++static const struct file_operations link_sta_ ##name## _ops = { \ + .read = link_sta_##name##_read, \ ++ .open = simple_open, \ + .llseek = generic_file_llseek, \ + } + +--- a/net/mac80211/rate.c ++++ b/net/mac80211/rate.c +@@ -252,8 +252,9 @@ static ssize_t rcname_read(struct file * + ref->ops->name, len); + } + +-const struct debugfs_short_fops rcname_ops = { ++const struct file_operations rcname_ops = { + .read = rcname_read, ++ .open = simple_open, + .llseek = default_llseek, + }; + #endif +--- a/net/mac80211/rate.h ++++ b/net/mac80211/rate.h +@@ -62,7 +62,7 @@ static inline void rate_control_add_sta_ + #endif + } + +-extern const struct debugfs_short_fops rcname_ops; ++extern const struct file_operations rcname_ops; + + static inline void rate_control_add_debugfs(struct ieee80211_local *local) + { diff --git a/lede/package/kernel/mac80211/patches-6.18/mt7601u/001-wifi-mt7601u-update-firmware-path.patch b/lede/package/kernel/mac80211/patches-6.18/mt7601u/001-wifi-mt7601u-update-firmware-path.patch new file mode 100644 index 0000000000..5d982906c5 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/mt7601u/001-wifi-mt7601u-update-firmware-path.patch @@ -0,0 +1,55 @@ +From patchwork Mon May 15 22:56:53 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 13242309 +X-Patchwork-Delegate: kvalo@adurom.com +Return-Path: +Date: Tue, 16 May 2023 00:56:53 +0200 +From: Daniel Golle +To: Jakub Kicinski , Kalle Valo , + "David S. Miller" , + Eric Dumazet , + Paolo Abeni , + Matthias Brugger , + AngeloGioacchino Del Regno + , + linux-wireless@vger.kernel.org, netdev@vger.kernel.org, + linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org +Subject: [PATCH] wifi: mt7601u: update firmware path +Message-ID: + +MIME-Version: 1.0 +Content-Disposition: inline +Precedence: bulk +List-ID: +X-Mailing-List: linux-wireless@vger.kernel.org + +mt7601u.bin was moved to mediatek/ folder in linux-wireless via commit +8451c2b1 ("mt76xx: Move the old Mediatek WiFi firmware to mediatek") +and linux-firmware release 20230515. + +Update the firmware path requested by the mt7601u driver to follow up +with the move of the file. + +Signed-off-by: Daniel Golle +--- + drivers/net/wireless/mediatek/mt7601u/usb.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + + +base-commit: 0d9b41daa5907756a31772d8af8ac5ff25cf17c1 + +--- a/drivers/net/wireless/mediatek/mt7601u/usb.h ++++ b/drivers/net/wireless/mediatek/mt7601u/usb.h +@@ -8,7 +8,7 @@ + + #include "mt7601u.h" + +-#define MT7601U_FIRMWARE "mt7601u.bin" ++#define MT7601U_FIRMWARE "mediatek/mt7601u.bin" + + #define MT_VEND_REQ_MAX_RETRY 10 + #define MT_VEND_REQ_TOUT_MS 300 diff --git a/lede/package/kernel/mac80211/patches-6.18/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch b/lede/package/kernel/mac80211/patches-6.18/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch new file mode 100644 index 0000000000..76f1fb094e --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch @@ -0,0 +1,10 @@ +--- a/drivers/net/wireless/marvell/mwl8k.c ++++ b/drivers/net/wireless/marvell/mwl8k.c +@@ -5779,6 +5779,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw") + MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API)); + + static const struct pci_device_id mwl8k_pci_id_table[] = { ++ { PCI_VDEVICE(MARVELL, 0x2a02), .driver_data = MWL8363, }, + { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, }, + { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, + { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, diff --git a/lede/package/kernel/mac80211/patches-6.18/mwl/801-libertas-configure-sysfs-links.patch b/lede/package/kernel/mac80211/patches-6.18/mwl/801-libertas-configure-sysfs-links.patch new file mode 100644 index 0000000000..bc24fdc744 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/mwl/801-libertas-configure-sysfs-links.patch @@ -0,0 +1,21 @@ +--- a/drivers/net/wireless/marvell/libertas/cfg.c ++++ b/drivers/net/wireless/marvell/libertas/cfg.c +@@ -2105,6 +2105,8 @@ struct wireless_dev *lbs_cfg_alloc(struc + goto err_wiphy_new; + } + ++ set_wiphy_dev(wdev->wiphy, dev); ++ + return wdev; + + err_wiphy_new: +--- a/drivers/net/wireless/marvell/libertas/main.c ++++ b/drivers/net/wireless/marvell/libertas/main.c +@@ -852,6 +852,7 @@ struct lbs_private *lbs_add_card(void *c + goto err_adapter; + } + ++ dev_net_set(dev, wiphy_net(wdev->wiphy)); + dev->ieee80211_ptr = wdev; + dev->ml_priv = priv; + SET_NETDEV_DEV(dev, dmdev); diff --git a/lede/package/kernel/mac80211/patches-6.18/mwl/802-libertas-set-wireless-macaddr.patch b/lede/package/kernel/mac80211/patches-6.18/mwl/802-libertas-set-wireless-macaddr.patch new file mode 100644 index 0000000000..9aa4d05473 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/mwl/802-libertas-set-wireless-macaddr.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/marvell/libertas/cfg.c ++++ b/drivers/net/wireless/marvell/libertas/cfg.c +@@ -2182,6 +2182,8 @@ int lbs_cfg_register(struct lbs_private + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + wdev->wiphy->reg_notifier = lbs_reg_notifier; + ++ memcpy(wdev->wiphy->perm_addr, priv->current_addr, ETH_ALEN); ++ + ret = wiphy_register(wdev->wiphy); + if (ret < 0) + pr_err("cannot register wiphy device\n"); diff --git a/lede/package/kernel/mac80211/patches-6.18/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch b/lede/package/kernel/mac80211/patches-6.18/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch new file mode 100644 index 0000000000..484b37bfcc --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch @@ -0,0 +1,41 @@ +From ef8098cd6cb8b5989afef2e8461fe6ba9570a854 Mon Sep 17 00:00:00 2001 +From: Josef Schlehofer +Date: Wed, 24 Nov 2021 12:47:40 +0100 +Subject: [PATCH] mwifiex: increase the global limit up to 4 SSID + +Firmware for SDIO (88W8997), which is used in Turris MOX SDIO addon [1], +allows up to 4 SSID. Unfortunately, driver (even in mainline kernel) +has a global limit for all Marvell cards up to 3 SSID. + +Pali Rohár tested this patch and verified that the SDIO Wi-Fi addon works +with the 4 SSID. So, let's increase the global limit from 3 to 4. + +Ideally, this patch should be done differently before sending +it to Linux kernel. It means that limit definition should be moved to +the card-specific structure. + +[1] https://docs.turris.cz/hw/mox/addons/#wi-fi-sdio +--- + drivers/net/wireless/marvell/mwifiex/decl.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/marvell/mwifiex/decl.h ++++ b/drivers/net/wireless/marvell/mwifiex/decl.h +@@ -18,7 +18,7 @@ + #include + + #define MWIFIEX_BSS_COEX_COUNT 2 +-#define MWIFIEX_MAX_BSS_NUM (3) ++#define MWIFIEX_MAX_BSS_NUM (4) + + #define MWIFIEX_DMA_ALIGN_SZ 64 + #define MWIFIEX_RX_HEADROOM 64 +@@ -123,7 +123,7 @@ + #define MWIFIEX_RATE_INDEX_OFDM0 4 + + #define MWIFIEX_MAX_STA_NUM 3 +-#define MWIFIEX_MAX_UAP_NUM 3 ++#define MWIFIEX_MAX_UAP_NUM 4 + #define MWIFIEX_MAX_P2P_NUM 3 + + #define MWIFIEX_A_BAND_START_FREQ 5000 diff --git a/lede/package/kernel/mac80211/patches-6.18/mwl/940-mwl8k_init_devices_synchronously.patch b/lede/package/kernel/mac80211/patches-6.18/mwl/940-mwl8k_init_devices_synchronously.patch new file mode 100644 index 0000000000..5e9008126c --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/mwl/940-mwl8k_init_devices_synchronously.patch @@ -0,0 +1,20 @@ +--- a/drivers/net/wireless/marvell/mwl8k.c ++++ b/drivers/net/wireless/marvell/mwl8k.c +@@ -6365,6 +6365,8 @@ static int mwl8k_probe(struct pci_dev *p + + priv->running_bsses = 0; + ++ wait_for_completion(&priv->firmware_loading_complete); ++ + return rc; + + err_stop_firmware: +@@ -6398,8 +6400,6 @@ static void mwl8k_remove(struct pci_dev + return; + priv = hw->priv; + +- wait_for_completion(&priv->firmware_loading_complete); +- + if (priv->fw_state == FW_STATE_ERROR) { + mwl8k_hw_reset(priv); + goto unmap; diff --git a/lede/package/kernel/mac80211/patches-6.18/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch b/lede/package/kernel/mac80211/patches-6.18/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch new file mode 100644 index 0000000000..a8a5047260 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch @@ -0,0 +1,177 @@ +From f7252b1b5755150535af226e806594bbefd45e0f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Sun, 26 Sep 2021 14:39:44 +0200 +Subject: [PATCH] mwifiex: Print stringified name of command in error log +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Failed hex command number in error log is hard to understand. +So add also more human readable stringified command name into error log. + +Signed-off-by: Pali Rohár +--- + drivers/net/wireless/marvell/mwifiex/cmdevt.c | 96 +++++++++++++++++-- + drivers/net/wireless/marvell/mwifiex/main.h | 2 + + .../wireless/marvell/mwifiex/sta_cmdresp.c | 5 +- + .../net/wireless/marvell/mwifiex/uap_cmd.c | 3 +- + 4 files changed, 95 insertions(+), 11 deletions(-) + +--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c ++++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c +@@ -16,6 +16,85 @@ + + static void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); + ++const char * ++mwifiex_cmd_to_str(u16 command) ++{ ++ switch (command) { ++ case HostCmd_CMD_GET_HW_SPEC: return "GET_HW_SPEC"; ++ case HostCmd_CMD_802_11_SCAN: return "SCAN"; ++ case HostCmd_CMD_802_11_GET_LOG: return "GET_LOG"; ++ case HostCmd_CMD_MAC_MULTICAST_ADR: return "MAC_MULTICAST_ADR"; ++ case HostCmd_CMD_802_11_EEPROM_ACCESS: return "EEPROM_ACCESS"; ++ case HostCmd_CMD_802_11_ASSOCIATE: return "ASSOCIATE"; ++ case HostCmd_CMD_802_11_SNMP_MIB: return "SNMP_MIB"; ++ case HostCmd_CMD_MAC_REG_ACCESS: return "MAC_REG_ACCESS"; ++ case HostCmd_CMD_BBP_REG_ACCESS: return "BBP_REG_ACCESS"; ++ case HostCmd_CMD_RF_REG_ACCESS: return "RF_REG_ACCESS"; ++ case HostCmd_CMD_PMIC_REG_ACCESS: return "PMIC_REG_ACCESS"; ++ case HostCmd_CMD_RF_TX_PWR: return "RF_TX_PWR"; ++ case HostCmd_CMD_RF_ANTENNA: return "RF_ANTENNA"; ++ case HostCmd_CMD_802_11_DEAUTHENTICATE: return "DEAUTHENTICATE"; ++ case HostCmd_CMD_MAC_CONTROL: return "MAC_CONTROL"; ++ case HostCmd_CMD_802_11_AD_HOC_START: return "AD_HOC_START"; ++ case HostCmd_CMD_802_11_AD_HOC_JOIN: return "AD_HOC_JOIN"; ++ case HostCmd_CMD_802_11_AD_HOC_STOP: return "AD_HOC_STOP"; ++ case HostCmd_CMD_802_11_MAC_ADDRESS: return "MAC_ADDRESS"; ++ case HostCmd_CMD_802_11D_DOMAIN_INFO: return "DOMAIN_INFO"; ++ case HostCmd_CMD_802_11_KEY_MATERIAL: return "KEY_MATERIAL"; ++ case HostCmd_CMD_802_11_BG_SCAN_CONFIG: return "BG_SCAN_CONFIG"; ++ case HostCmd_CMD_802_11_BG_SCAN_QUERY: return "BG_SCAN_QUERY"; ++ case HostCmd_CMD_WMM_GET_STATUS: return "WMM_GET_STATUS"; ++ case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: return "SUBSCRIBE_EVENT"; ++ case HostCmd_CMD_802_11_TX_RATE_QUERY: return "TX_RATE_QUERY"; ++ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: return "IBSS_COALESCING_STATUS"; ++ case HostCmd_CMD_MEM_ACCESS: return "MEM_ACCESS"; ++ case HostCmd_CMD_CFG_DATA: return "CFG_DATA"; ++ case HostCmd_CMD_VERSION_EXT: return "VERSION_EXT"; ++ case HostCmd_CMD_MEF_CFG: return "MEF_CFG"; ++ case HostCmd_CMD_RSSI_INFO: return "RSSI_INFO"; ++ case HostCmd_CMD_FUNC_INIT: return "FUNC_INIT"; ++ case HostCmd_CMD_FUNC_SHUTDOWN: return "FUNC_SHUTDOWN"; ++ case HOST_CMD_APCMD_SYS_RESET: return "SYS_RESET"; ++ case HostCmd_CMD_UAP_SYS_CONFIG: return "UAP_SYS_CONFIG"; ++ case HostCmd_CMD_UAP_BSS_START: return "UAP_BSS_START"; ++ case HostCmd_CMD_UAP_BSS_STOP: return "UAP_BSS_STOP"; ++ case HOST_CMD_APCMD_STA_LIST: return "STA_LIST"; ++ case HostCmd_CMD_UAP_STA_DEAUTH: return "UAP_STA_DEAUTH"; ++ case HostCmd_CMD_11N_CFG: return "11N_CFG"; ++ case HostCmd_CMD_11N_ADDBA_REQ: return "ADDBA_REQ"; ++ case HostCmd_CMD_11N_ADDBA_RSP: return "ADDBA_RSP"; ++ case HostCmd_CMD_11N_DELBA: return "DELBA"; ++ case HostCmd_CMD_RECONFIGURE_TX_BUFF: return "RECONFIGURE_TX_BUFF"; ++ case HostCmd_CMD_CHAN_REPORT_REQUEST: return "CHAN_REPORT_REQUEST"; ++ case HostCmd_CMD_AMSDU_AGGR_CTRL: return "AMSDU_AGGR_CTRL"; ++ case HostCmd_CMD_TXPWR_CFG: return "TXPWR_CFG"; ++ case HostCmd_CMD_TX_RATE_CFG: return "TX_RATE_CFG"; ++ case HostCmd_CMD_ROBUST_COEX: return "ROBUST_COEX"; ++ case HostCmd_CMD_802_11_PS_MODE_ENH: return "PS_MODE_ENH"; ++ case HostCmd_CMD_802_11_HS_CFG_ENH: return "HS_CFG_ENH"; ++ case HostCmd_CMD_P2P_MODE_CFG: return "P2P_MODE_CFG"; ++ case HostCmd_CMD_CAU_REG_ACCESS: return "CAU_REG_ACCESS"; ++ case HostCmd_CMD_SET_BSS_MODE: return "SET_BSS_MODE"; ++ case HostCmd_CMD_PCIE_DESC_DETAILS: return "PCIE_DESC_DETAILS"; ++ case HostCmd_CMD_802_11_SCAN_EXT: return "SCAN_EXT"; ++ case HostCmd_CMD_COALESCE_CFG: return "COALESCE_CFG"; ++ case HostCmd_CMD_MGMT_FRAME_REG: return "MGMT_FRAME_REG"; ++ case HostCmd_CMD_REMAIN_ON_CHAN: return "REMAIN_ON_CHAN"; ++ case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG: return "GTK_REKEY_OFFLOAD_CFG"; ++ case HostCmd_CMD_11AC_CFG: return "11AC_CFG"; ++ case HostCmd_CMD_HS_WAKEUP_REASON: return "HS_WAKEUP_REASON"; ++ case HostCmd_CMD_TDLS_CONFIG: return "TDLS_CONFIG"; ++ case HostCmd_CMD_MC_POLICY: return "MC_POLICY"; ++ case HostCmd_CMD_TDLS_OPER: return "TDLS_OPER"; ++ case HostCmd_CMD_FW_DUMP_EVENT: return "FW_DUMP_EVENT"; ++ case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: return "SDIO_SP_RX_AGGR_CFG"; ++ case HostCmd_CMD_STA_CONFIGURE: return "STA_CONFIGURE"; ++ case HostCmd_CMD_CHAN_REGION_CFG: return "CHAN_REGION_CFG"; ++ case HostCmd_CMD_PACKET_AGGR_CTRL: return "PACKET_AGGR_CTRL"; ++ default: return "UNKNOWN"; ++ } ++} ++ + /* + * This function initializes a command node. + * +@@ -191,8 +270,8 @@ static int mwifiex_dnld_cmd_to_fw(struct + cmd_code != HostCmd_CMD_FUNC_SHUTDOWN && + cmd_code != HostCmd_CMD_FUNC_INIT) { + mwifiex_dbg(adapter, ERROR, +- "DNLD_CMD: FW in reset state, ignore cmd %#x\n", +- cmd_code); ++ "DNLD_CMD: FW in reset state, ignore cmd %s (%#x)\n", ++ mwifiex_cmd_to_str(cmd_code), cmd_code); + mwifiex_recycle_cmd_node(adapter, cmd_node); + queue_work(adapter->workqueue, &adapter->main_work); + return -1; +@@ -651,8 +730,8 @@ int mwifiex_send_cmd(struct mwifiex_priv + /* Return error, since the command preparation failed */ + if (ret) { + mwifiex_dbg(adapter, ERROR, +- "PREP_CMD: cmd %#x preparation failed\n", +- cmd_no); ++ "PREP_CMD: cmd %s (%#x) preparation failed\n", ++ mwifiex_cmd_to_str(cmd_no), cmd_no); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + return -1; + } +@@ -1262,8 +1341,8 @@ mwifiex_process_sleep_confirm_resp(struc + + if (command != HostCmd_CMD_802_11_PS_MODE_ENH) { + mwifiex_dbg(adapter, ERROR, +- "%s: rcvd unexpected resp for cmd %#x, result = %x\n", +- __func__, command, result); ++ "%s: rcvd unexpected resp for cmd %s (%#x), result = %x\n", ++ __func__, mwifiex_cmd_to_str(command), command, result); + return; + } + +--- a/drivers/net/wireless/marvell/mwifiex/main.h ++++ b/drivers/net/wireless/marvell/mwifiex/main.h +@@ -1091,6 +1091,8 @@ void mwifiex_cancel_all_pending_cmd(stru + void mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter); + void mwifiex_cancel_scan(struct mwifiex_adapter *adapter); + ++const char *mwifiex_cmd_to_str(u16 command); ++ + void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node); + +--- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c ++++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +@@ -36,8 +36,9 @@ mwifiex_process_cmdresp_error(struct mwi + struct host_cmd_ds_802_11_ps_mode_enh *pm; + + mwifiex_dbg(adapter, ERROR, +- "CMD_RESP: cmd %#x error, result=%#x\n", +- resp->command, resp->result); ++ "CMD_RESP: cmd %s (%#x) error, result=%#x\n", ++ mwifiex_cmd_to_str(le16_to_cpu(resp->command)), ++ le16_to_cpu(resp->command), le16_to_cpu(resp->result)); + + if (adapter->curr_cmd->wait_q_enabled) + adapter->cmd_wait_q.status = -1; +--- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c ++++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +@@ -964,7 +964,8 @@ int mwifiex_uap_prepare_cmd(struct mwifi + break; + default: + mwifiex_dbg(priv->adapter, ERROR, +- "PREP_CMD: unknown cmd %#x\n", cmd_no); ++ "PREP_CMD: unknown cmd (%s) %#x\n", ++ mwifiex_cmd_to_str(cmd_no), cmd_no); + return -1; + } + diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/100-rt2x00_options.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/100-rt2x00_options.patch new file mode 100644 index 0000000000..9f5002da9d --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/100-rt2x00_options.patch @@ -0,0 +1,42 @@ +--- a/drivers/net/wireless/ralink/rt2x00/Kconfig ++++ b/drivers/net/wireless/ralink/rt2x00/Kconfig +@@ -223,33 +223,33 @@ config RT2800SOC + + + config RT2800_LIB +- tristate ++ tristate "RT2800 USB/PCI support" + depends on m + depends on CRC_CCITT + + config RT2800_LIB_MMIO +- tristate ++ tristate "RT2800 MMIO support" + depends on m + select RT2X00_LIB_MMIO + select RT2800_LIB + + config RT2X00_LIB_MMIO +- tristate ++ tristate "RT2x00 MMIO support" + depends on m + select RT2X00_LIB + + config RT2X00_LIB_PCI +- tristate ++ tristate "RT2x00 PCI support" + depends on m + select RT2X00_LIB + + config RT2X00_LIB_USB +- tristate ++ tristate "RT2x00 USB support" + depends on m + select RT2X00_LIB + + config RT2X00_LIB +- tristate ++ tristate "RT2x00 support" + depends on m + + config RT2X00_LIB_FIRMWARE diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/501-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/501-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch new file mode 100644 index 0000000000..8a957822c0 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/501-rt2x00-allow-to-build-rt2800soc-module-for-RT3883.patch @@ -0,0 +1,21 @@ +From 91094ed065f7794886b4a5490fd6de942f036bb4 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +Date: Sun, 24 Mar 2013 19:26:26 +0100 +Subject: [PATCH] rt2x00: allow to build rt2800soc module for RT3883 + +Signed-off-by: Gabor Juhos +--- + drivers/net/wireless/ralink/rt2x00/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ralink/rt2x00/Kconfig ++++ b/drivers/net/wireless/ralink/rt2x00/Kconfig +@@ -209,7 +209,7 @@ endif + config RT2800SOC + tristate "Ralink WiSoC support" + depends on m +- depends on OF && (SOC_RT288X || SOC_RT305X || SOC_MT7620 || COMPILE_TEST) ++ depends on OF && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620 || COMPILE_TEST) + select RT2X00_LIB_MMIO + select RT2X00_LIB_CRYPTO + select RT2X00_LIB_FIRMWARE diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-01-wifi-rt2x00-Add-support-for-loading-EEPROM-from-user.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-01-wifi-rt2x00-Add-support-for-loading-EEPROM-from-user.patch new file mode 100644 index 0000000000..ac9e2060bb --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-01-wifi-rt2x00-Add-support-for-loading-EEPROM-from-user.patch @@ -0,0 +1,225 @@ +From 1046fc9e98936991aeb0b0656c84833d96a63c0f Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sun, 15 Oct 2023 14:22:49 +0200 +Subject: [PATCH 1/5] wifi: rt2x00: Add support for loading EEPROM from + userspace + +Add support for loading EEPROM from userspace. + +Signed-off-by: Christian Marangi +--- + drivers/net/wireless/ralink/rt2x00/Kconfig | 5 ++ + drivers/net/wireless/ralink/rt2x00/Makefile | 1 + + .../net/wireless/ralink/rt2x00/rt2800soc.c | 15 +--- + drivers/net/wireless/ralink/rt2x00/rt2x00.h | 1 + + .../net/wireless/ralink/rt2x00/rt2x00dev.c | 9 +++ + .../net/wireless/ralink/rt2x00/rt2x00eeprom.c | 75 +++++++++++++++++++ + .../net/wireless/ralink/rt2x00/rt2800soc.c | 1 + + .../net/wireless/ralink/rt2x00/rt2800soc.h | 9 +++ + 8 files changed, 102 insertions(+), 14 deletions(-) + create mode 100644 drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c + +--- a/local-symbols ++++ b/local-symbols +@@ -337,6 +337,7 @@ RT2X00_LIB_FIRMWARE= + RT2X00_LIB_CRYPTO= + RT2X00_LIB_LEDS= + RT2X00_LIB_DEBUGFS= ++RT2X00_LIB_EEPROM= + RT2X00_DEBUG= + WLAN_VENDOR_REALTEK= + RTL8180= +--- a/drivers/net/wireless/ralink/rt2x00/Kconfig ++++ b/drivers/net/wireless/ralink/rt2x00/Kconfig +@@ -70,6 +70,7 @@ config RT2800PCI + select RT2X00_LIB_MMIO + select RT2X00_LIB_PCI + select RT2X00_LIB_FIRMWARE ++ select RT2X00_LIB_EEPROM + select RT2X00_LIB_CRYPTO + depends on EEPROM_93CX6 + help +@@ -213,6 +214,7 @@ config RT2800SOC + select RT2X00_LIB_MMIO + select RT2X00_LIB_CRYPTO + select RT2X00_LIB_FIRMWARE ++ select RT2X00_LIB_EEPROM + select RT2800_LIB + select RT2800_LIB_MMIO + help +@@ -259,6 +261,9 @@ config RT2X00_LIB_FIRMWARE + config RT2X00_LIB_CRYPTO + bool + ++config RT2X00_LIB_EEPROM ++ bool ++ + config RT2X00_LIB_LEDS + bool + default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) +--- a/drivers/net/wireless/ralink/rt2x00/Makefile ++++ b/drivers/net/wireless/ralink/rt2x00/Makefile +@@ -8,6 +8,7 @@ rt2x00lib-$(CPTCFG_RT2X00_LIB_DEBUGFS) + + rt2x00lib-$(CPTCFG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o + rt2x00lib-$(CPTCFG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o + rt2x00lib-$(CPTCFG_RT2X00_LIB_LEDS) += rt2x00leds.o ++rt2x00lib-$(CPTCFG_RT2X00_LIB_EEPROM) += rt2x00eeprom.o + + obj-$(CPTCFG_RT2X00_LIB) += rt2x00lib.o + obj-$(CPTCFG_RT2X00_LIB_MMIO) += rt2x00mmio.o +--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +@@ -90,19 +90,6 @@ static int rt2800soc_set_device_state(st + return retval; + } + +-static int rt2800soc_read_eeprom(struct rt2x00_dev *rt2x00dev) +-{ +- void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE); +- +- if (!base_addr) +- return -ENOMEM; +- +- memcpy_fromio(rt2x00dev->eeprom, base_addr, EEPROM_SIZE); +- +- iounmap(base_addr); +- return 0; +-} +- + /* Firmware functions */ + static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev) + { +@@ -190,7 +177,7 @@ static const struct rt2800_ops rt2800soc + .register_multiread = rt2x00mmio_register_multiread, + .register_multiwrite = rt2x00mmio_register_multiwrite, + .regbusy_read = rt2x00mmio_regbusy_read, +- .read_eeprom = rt2800soc_read_eeprom, ++ .read_eeprom = rt2x00lib_read_eeprom, + .hwcrypt_disabled = rt2800soc_hwcrypt_disabled, + .drv_write_firmware = rt2800soc_write_firmware, + .drv_init_registers = rt2800mmio_init_registers, +@@ -304,6 +291,7 @@ static int rt2x00soc_probe(struct platfo + rt2x00dev->name = pdev->dev.driver->name; + rt2x00dev->csr.base = mem; + ++ set_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags); + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); + + retval = rt2x00lib_probe_dev(rt2x00dev); +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h +@@ -692,6 +692,7 @@ enum rt2x00_capability_flags { + REQUIRE_HT_TX_DESC, + REQUIRE_PS_AUTOWAKE, + REQUIRE_DELAYED_RFKILL, ++ REQUIRE_EEPROM_FILE, + + /* + * Capabilities +@@ -1506,4 +1507,13 @@ void rt2x00lib_remove_dev(struct rt2x00_ + int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev); + int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev); + ++/* ++ * EEPROM file handlers. ++ */ ++#ifdef CPTCFG_RT2X00_LIB_EEPROM ++int rt2x00lib_read_eeprom(struct rt2x00_dev *rt2x00dev); ++#else ++#define rt2x00lib_read_eeprom NULL ++#endif /* CPTCFG_RT2X00_LIB_EEPROM */ ++ + #endif /* RT2X00_H */ +--- /dev/null ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c +@@ -0,0 +1,78 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* Copyright (C) 2004 - 2009 Ivo van Doorn ++ * Copyright (C) 2004 - 2009 Gertjan van Wingerde ++ * ++ */ ++ ++/* Module: rt2x00lib ++ * Abstract: rt2x00 eeprom file loading routines. ++ */ ++ ++#include ++#include ++#include ++ ++#include "rt2x00.h" ++ ++static const char * ++rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev) ++{ ++ struct device_node *np = rt2x00dev->dev->of_node; ++ const char *eep; ++ ++ if (np && !of_property_read_string(np, "ralink,eeprom", &eep)) ++ return eep; ++ ++ return NULL; ++} ++ ++static int rt2x00lib_read_eeprom_file(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct firmware *ee; ++ const char *ee_name; ++ int retval; ++ ++ ee_name = rt2x00lib_get_eeprom_file_name(rt2x00dev); ++ if (!ee_name && test_bit(REQUIRE_EEPROM_FILE, &rt2x00dev->cap_flags)) { ++ rt2x00_err(rt2x00dev, "Required EEPROM name is missing."); ++ return -EINVAL; ++ } ++ ++ if (!ee_name) ++ return -ENOENT; ++ ++ rt2x00_info(rt2x00dev, "Loading EEPROM data from '%s'.\n", ee_name); ++ ++ retval = request_firmware(&ee, ee_name, rt2x00dev->dev); ++ if (retval) { ++ rt2x00_err(rt2x00dev, "Failed to request EEPROM.\n"); ++ return retval; ++ } ++ ++ if (!ee || !ee->size || !ee->data) { ++ rt2x00_err(rt2x00dev, "Failed to read EEPROM file.\n"); ++ retval = -ENOENT; ++ goto err_exit; ++ } ++ ++ if (ee->size != rt2x00dev->ops->eeprom_size) { ++ rt2x00_err(rt2x00dev, ++ "EEPROM file size is invalid, it should be %d bytes\n", ++ rt2x00dev->ops->eeprom_size); ++ retval = -EINVAL; ++ goto err_release_ee; ++ } ++ ++ memcpy(rt2x00dev->eeprom, ee->data, rt2x00dev->ops->eeprom_size); ++ ++err_release_ee: ++ release_firmware(ee); ++err_exit: ++ return retval; ++} ++ ++int rt2x00lib_read_eeprom(struct rt2x00_dev *rt2x00dev) ++{ ++ return rt2x00lib_read_eeprom_file(rt2x00dev); ++} ++EXPORT_SYMBOL_GPL(rt2x00lib_read_eeprom); +--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +@@ -278,6 +278,9 @@ static int rt2800pci_read_eeprom(struct + { + int retval; + ++ if (!rt2x00lib_read_eeprom(rt2x00dev)) ++ return 0; ++ + if (rt2800pci_efuse_detect(rt2x00dev)) + retval = rt2800pci_read_eeprom_efuse(rt2x00dev); + else diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-03-wifi-rt2x00-Add-support-for-loading-EEPROM-from-MTD.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-03-wifi-rt2x00-Add-support-for-loading-EEPROM-from-MTD.patch new file mode 100644 index 0000000000..9b64e9c880 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-03-wifi-rt2x00-Add-support-for-loading-EEPROM-from-MTD.patch @@ -0,0 +1,107 @@ +From 71261ca81b491a4c3b08690347c12e96a75ad0d0 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Sun, 17 Mar 2013 00:55:04 +0100 +Subject: [PATCH 3/5] wifi: rt2x00: Add support for loading EEPROM from MTD + +Add support for loading EEPROM from MTD. + +Signed-off-by: John Crispin +Signed-off-by: Christian Marangi +--- + drivers/net/wireless/ralink/rt2x00/Kconfig | 1 + + .../net/wireless/ralink/rt2x00/rt2x00eeprom.c | 66 +++++++++++++++++++ + 2 files changed, 67 insertions(+) + +--- a/drivers/net/wireless/ralink/rt2x00/Kconfig ++++ b/drivers/net/wireless/ralink/rt2x00/Kconfig +@@ -217,6 +217,7 @@ config RT2800SOC + select RT2X00_LIB_EEPROM + select RT2800_LIB + select RT2800_LIB_MMIO ++ select MTD if SOC_RT288X || SOC_RT305X + help + This adds support for Ralink WiSoC devices. + Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352. +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c +@@ -11,9 +11,65 @@ + #include + #include + #include ++#if IS_ENABLED(CONFIG_MTD) ++#include ++#include ++#endif + + #include "rt2x00.h" + ++#if IS_ENABLED(CONFIG_MTD) ++static int rt2800lib_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev) ++{ ++ struct device_node *np = rt2x00dev->dev->of_node, *mtd_np = NULL; ++ int size, offset = 0; ++ struct mtd_info *mtd; ++ const char *part; ++ const __be32 *list; ++ phandle phandle; ++ size_t retlen; ++ int ret; ++ ++ list = of_get_property(np, "ralink,mtd-eeprom", &size); ++ if (!list) ++ return -ENOENT; ++ ++ phandle = be32_to_cpup(list++); ++ if (phandle) ++ mtd_np = of_find_node_by_phandle(phandle); ++ if (!mtd_np) { ++ dev_err(rt2x00dev->dev, "failed to load mtd phandle\n"); ++ return -EINVAL; ++ } ++ ++ part = of_get_property(mtd_np, "label", NULL); ++ if (!part) ++ part = mtd_np->name; ++ ++ mtd = get_mtd_device_nm(part); ++ if (IS_ERR(mtd)) { ++ dev_err(rt2x00dev->dev, "failed to get mtd device \"%s\"\n", part); ++ return PTR_ERR(mtd); ++ } ++ ++ if (size > sizeof(*list)) ++ offset = be32_to_cpup(list); ++ ++ ret = mtd_read(mtd, offset, rt2x00dev->ops->eeprom_size, ++ &retlen, (u_char *)rt2x00dev->eeprom); ++ put_mtd_device(mtd); ++ ++ if (ret || retlen != rt2x00dev->ops->eeprom_size) { ++ dev_err(rt2x00dev->dev, "failed to load eeprom from device \"%s\"\n", part); ++ return ret; ++ } ++ ++ dev_info(rt2x00dev->dev, "loaded eeprom from mtd device \"%s\"\n", part); ++ ++ return ret; ++} ++#endif ++ + static const char * + rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev) + { +@@ -73,6 +129,14 @@ err_exit: + + int rt2x00lib_read_eeprom(struct rt2x00_dev *rt2x00dev) + { ++ int ret; ++ ++#if IS_ENABLED(CONFIG_MTD) ++ ret = rt2800lib_read_eeprom_mtd(rt2x00dev); ++ if (!ret) ++ return 0; ++#endif ++ + return rt2x00lib_read_eeprom_file(rt2x00dev); + } + EXPORT_SYMBOL_GPL(rt2x00lib_read_eeprom); diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-04-wifi-rt2x00-Support-EEPROM-swap-binding.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-04-wifi-rt2x00-Support-EEPROM-swap-binding.patch new file mode 100644 index 0000000000..9791f7efd0 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-04-wifi-rt2x00-Support-EEPROM-swap-binding.patch @@ -0,0 +1,44 @@ +From 9c9a3c27b96e057f3c3f47151d7a170d84e3bb5f Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sun, 15 Oct 2023 15:31:47 +0200 +Subject: [PATCH 4/5] wifi: rt2x00: Support EEPROM swap binding + +Add binding "ralink,eeprom-swap" to swap bytes of EEPROM before using +it. + +Signed-off-by: Christian Marangi +--- + drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c +@@ -19,6 +19,19 @@ + #include "rt2x00.h" + + #if IS_ENABLED(CONFIG_MTD) ++static void rt2800lib_eeprom_swap(struct rt2x00_dev *rt2x00dev) ++{ ++ struct device_node *np = rt2x00dev->dev->of_node; ++ size_t len = rt2x00dev->ops->eeprom_size; ++ int i; ++ ++ if (!of_property_present(np, "ralink,eeprom-swap")) ++ return; ++ ++ for (i = 0; i < len / sizeof(u16); i++) ++ rt2x00dev->eeprom[i] = swab16(rt2x00dev->eeprom[i]); ++} ++ + static int rt2800lib_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev) + { + struct device_node *np = rt2x00dev->dev->of_node, *mtd_np = NULL; +@@ -64,6 +77,8 @@ static int rt2800lib_read_eeprom_mtd(str + return ret; + } + ++ rt2800lib_eeprom_swap(rt2x00dev); ++ + dev_info(rt2x00dev->dev, "loaded eeprom from mtd device \"%s\"\n", part); + + return ret; diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-05-wifi-rt2x00-support-loading-eeprom-from-NVMEM-cells.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-05-wifi-rt2x00-support-loading-eeprom-from-NVMEM-cells.patch new file mode 100644 index 0000000000..44bf9b6082 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/602-05-wifi-rt2x00-support-loading-eeprom-from-NVMEM-cells.patch @@ -0,0 +1,95 @@ +From 9008cdacdc41f8233f4444b86cf3a17201686e2d Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Tue, 18 Jul 2023 20:18:16 +0800 +Subject: [PATCH 5/5] wifi: rt2x00: support loading eeprom from NVMEM cells + +This patch allows rt2x00 to load eeprom from "eeprom" NVMEM cell. + +Example: + +/* load eeprom from NVMEM provider 'eep' */ +&wmac { + nvmem-cells = <&eep>; + nvmem-cell-names = "eeprom"; +}; + +Signed-off-by: Shiji Yang +Signed-off-by: Christian Marangi +--- + .../net/wireless/ralink/rt2x00/rt2x00eeprom.c | 41 ++++++++++++++++++- + 1 file changed, 40 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c +@@ -15,10 +15,10 @@ + #include + #include + #endif ++#include + + #include "rt2x00.h" + +-#if IS_ENABLED(CONFIG_MTD) + static void rt2800lib_eeprom_swap(struct rt2x00_dev *rt2x00dev) + { + struct device_node *np = rt2x00dev->dev->of_node; +@@ -32,6 +32,7 @@ static void rt2800lib_eeprom_swap(struct + rt2x00dev->eeprom[i] = swab16(rt2x00dev->eeprom[i]); + } + ++#if IS_ENABLED(CONFIG_MTD) + static int rt2800lib_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev) + { + struct device_node *np = rt2x00dev->dev->of_node, *mtd_np = NULL; +@@ -85,6 +86,40 @@ static int rt2800lib_read_eeprom_mtd(str + } + #endif + ++static int rt2800lib_read_eeprom_nvmem(struct rt2x00_dev *rt2x00dev) ++{ ++ struct device_node *np = rt2x00dev->dev->of_node; ++ unsigned int len = rt2x00dev->ops->eeprom_size; ++ struct nvmem_cell *cell; ++ const void *data; ++ size_t retlen; ++ int ret = 0; ++ ++ cell = of_nvmem_cell_get(np, "eeprom"); ++ if (IS_ERR(cell)) ++ return PTR_ERR(cell); ++ ++ data = nvmem_cell_read(cell, &retlen); ++ nvmem_cell_put(cell); ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ if (retlen != len) { ++ dev_err(rt2x00dev->dev, "invalid eeprom size, required: 0x%04x\n", len); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ memcpy(rt2x00dev->eeprom, data, len); ++ ++ rt2800lib_eeprom_swap(rt2x00dev); ++ ++exit: ++ kfree(data); ++ return ret; ++} ++ + static const char * + rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev) + { +@@ -152,6 +187,10 @@ int rt2x00lib_read_eeprom(struct rt2x00_ + return 0; + #endif + ++ ret = rt2800lib_read_eeprom_nvmem(rt2x00dev); ++ if (!ret) ++ return 0; ++ + return rt2x00lib_read_eeprom_file(rt2x00dev); + } + EXPORT_SYMBOL_GPL(rt2x00lib_read_eeprom); diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/603-wifi-rt2x00-Add-support-for-loading-EEPROM-from-devicetree-embedded-data.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/603-wifi-rt2x00-Add-support-for-loading-EEPROM-from-devicetree-embedded-data.patch new file mode 100644 index 0000000000..9001439262 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/603-wifi-rt2x00-Add-support-for-loading-EEPROM-from-devicetree-embedded-data.patch @@ -0,0 +1,76 @@ +From adf957124a115bdf3e4728e1ea8c70a632648cf0 Mon Sep 17 00:00:00 2001 +From: Coia Prant +Date: Fri, 14 Feb 2025 15:49:55 +0800 +Subject: [PATCH] wifi: rt2x00: Add support for loading EEPROM from devicetree + embedded data + +This patch allows rt2x00 to load eeprom from devicetree embedded data. + +Example: + +/* load eeprom from embedded data 'eeprom-data' */ +&wmac { + ralink,eeprom-data = <0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff + 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff 0xffffffff>; +}; + +Signed-off-by: Coia Prant +--- + .../net/wireless/ralink/rt2x00/rt2x00eeprom.c | 25 +++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c +@@ -32,6 +32,27 @@ static void rt2800lib_eeprom_swap(struct + rt2x00dev->eeprom[i] = swab16(rt2x00dev->eeprom[i]); + } + ++static int rt2800lib_read_eeprom_data(struct rt2x00_dev *rt2x00dev) ++{ ++ struct device_node *np = rt2x00dev->dev->of_node; ++ unsigned int len = rt2x00dev->ops->eeprom_size; ++ const void *data; ++ int size; ++ ++ data = of_get_property(np, "ralink,eeprom-data", &size); ++ if (!data) ++ return -ENOENT; ++ ++ if (size != len) { ++ dev_err(rt2x00dev->dev, "invalid eeprom size, required: 0x%04x\n", len); ++ return -EINVAL; ++ } ++ ++ memcpy(rt2x00dev->eeprom, data, size); ++ ++ return 0; ++} ++ + #if IS_ENABLED(CONFIG_MTD) + static int rt2800lib_read_eeprom_mtd(struct rt2x00_dev *rt2x00dev) + { +@@ -181,6 +202,10 @@ int rt2x00lib_read_eeprom(struct rt2x00_ + { + int ret; + ++ ret = rt2800lib_read_eeprom_data(rt2x00dev); ++ if (!ret) ++ return 0; ++ + #if IS_ENABLED(CONFIG_MTD) + ret = rt2800lib_read_eeprom_mtd(rt2x00dev); + if (!ret) diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch new file mode 100644 index 0000000000..7a44d1725f --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch @@ -0,0 +1,17 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +@@ -1007,6 +1007,14 @@ static int rt2x00lib_probe_hw_modes(stru + struct ieee80211_rate *rates; + unsigned int num_rates; + unsigned int i; ++ struct device_node *np = rt2x00dev->dev->of_node; ++ unsigned int enabled; ++ if (!of_property_read_u32(np, "ralink,2ghz", ++ &enabled) && !enabled) ++ spec->supported_bands &= ~SUPPORT_BAND_2GHZ; ++ if (!of_property_read_u32(np, "ralink,5ghz", ++ &enabled) && !enabled) ++ spec->supported_bands &= ~SUPPORT_BAND_5GHZ; + + num_rates = 0; + if (spec->supported_rates & SUPPORT_RATE_CCK) diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch new file mode 100644 index 0000000000..3adf74faa2 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch @@ -0,0 +1,40 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include "rt2x00.h" + #include "rt2800lib.h" +@@ -11276,6 +11277,17 @@ static int rt2800_init_eeprom(struct rt2 + rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); + rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); + ++ { ++ struct device_node *np = rt2x00dev->dev->of_node; ++ unsigned int led_polarity; ++ ++ /* Allow overriding polarity from OF */ ++ if (!of_property_read_u32(np, "ralink,led-polarity", ++ &led_polarity)) ++ rt2x00_set_field16(&eeprom, EEPROM_FREQ_LED_POLARITY, ++ led_polarity); ++ } ++ + rt2x00dev->led_mcu_reg = eeprom; + #endif /* CPTCFG_RT2X00_LIB_LEDS */ + +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00leds.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00leds.c +@@ -98,6 +98,9 @@ static int rt2x00leds_register_led(struc + led->led_dev.name = name; + led->led_dev.brightness = LED_OFF; + ++ if (rt2x00_is_soc(rt2x00dev)) ++ led->led_dev.brightness_set(&led->led_dev, LED_OFF); ++ + retval = led_classdev_register(device, &led->led_dev); + if (retval) { + rt2x00_err(rt2x00dev, "Failed to register led handler\n"); diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/611-rt2x00-add-AP+STA-support.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/611-rt2x00-add-AP+STA-support.patch new file mode 100644 index 0000000000..64291e8f89 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/611-rt2x00-add-AP+STA-support.patch @@ -0,0 +1,11 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +@@ -1338,7 +1338,7 @@ static inline void rt2x00lib_set_if_comb + */ + if_limit = &rt2x00dev->if_limits_ap; + if_limit->max = rt2x00dev->ops->max_ap_intf; +- if_limit->types = BIT(NL80211_IFTYPE_AP); ++ if_limit->types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION); + #ifdef CPTCFG_MAC80211_MESH + if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT); + #endif diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/620-01-rt2x00-respect-rt2800-hardware-TX-queue-index.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/620-01-rt2x00-respect-rt2800-hardware-TX-queue-index.patch new file mode 100644 index 0000000000..1d88ac7c60 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/620-01-rt2x00-respect-rt2800-hardware-TX-queue-index.patch @@ -0,0 +1,257 @@ +From 654653e718f6c55c6f29fd94cc8152a92c8166ac Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Tue, 24 Dec 2024 08:36:32 +0800 +Subject: [PATCH 1/2] rt2x00: respect the rt2800 hardware TX queue index + +The Ralink TX queue register index is different from the Linux +IEEE80211 queue id definition. Their conversion table is as follows: + +Queue IEEE80211 Ralink +AC_VO 0 3 +AC_VI 1 2 +AC_BE 2 0 +AC_BK 3 1 + +The TX queues are still functioning properly under the current +configuration. I don't have evidence, but I believe there should +be some differences in the internal hardware implementation of +different TX queues, e.g. interrupt priority. so it's better to +respect the queue index defined by the Ralink when we construct +the TX rings and descriptors. + +And the more important thing is that we are using the wrong queue +index to calculate the register offset and mask in .conf_tx(), +which resulted in writing incorrect AIFSN, CWMAX, CWMIN and TXOP +values for all TX queues. This patch introduces a index conversion +table to fix these parameters. + +Signed-off-by: Shiji Yang +--- + drivers/net/wireless/ralink/rt2x00/rt2800.h | 24 ++++++------ + .../net/wireless/ralink/rt2x00/rt2800lib.c | 20 +++++++--- + .../net/wireless/ralink/rt2x00/rt2800mmio.c | 38 ++++++++++--------- + .../net/wireless/ralink/rt2x00/rt2x00queue.h | 20 ++++++++++ + 4 files changed, 67 insertions(+), 35 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h +@@ -379,10 +379,10 @@ + + /* + * WMM_AIFSN_CFG: Aifsn for each EDCA AC +- * AIFSN0: AC_VO +- * AIFSN1: AC_VI +- * AIFSN2: AC_BE +- * AIFSN3: AC_BK ++ * AIFSN0: AC_BE ++ * AIFSN1: AC_BK ++ * AIFSN2: AC_VI ++ * AIFSN3: AC_VO + */ + #define WMM_AIFSN_CFG 0x0214 + #define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f) +@@ -392,10 +392,10 @@ + + /* + * WMM_CWMIN_CSR: CWmin for each EDCA AC +- * CWMIN0: AC_VO +- * CWMIN1: AC_VI +- * CWMIN2: AC_BE +- * CWMIN3: AC_BK ++ * CWMIN0: AC_BE ++ * CWMIN1: AC_BK ++ * CWMIN2: AC_VI ++ * CWMIN3: AC_VO + */ + #define WMM_CWMIN_CFG 0x0218 + #define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f) +@@ -405,10 +405,10 @@ + + /* + * WMM_CWMAX_CSR: CWmax for each EDCA AC +- * CWMAX0: AC_VO +- * CWMAX1: AC_VI +- * CWMAX2: AC_BE +- * CWMAX3: AC_BK ++ * CWMAX0: AC_BE ++ * CWMAX1: AC_BK ++ * CWMAX2: AC_VI ++ * CWMAX3: AC_VO + */ + #define WMM_CWMAX_CFG 0x021c + #define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f) +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -835,7 +835,8 @@ void rt2800_write_tx_data(struct queue_e + txdesc->key_idx : txdesc->u.ht.wcid); + rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, + txdesc->length); +- rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid); ++ rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, ++ rt2x00_ac_to_hwq(entry->queue->qid)); + rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1); + rt2x00_desc_write(txwi, 1, word); + +@@ -1125,6 +1126,12 @@ void rt2800_txdone(struct rt2x00_dev *rt + u32 reg; + u8 qid; + bool match; ++ static const u8 rt2ac[] = { ++ IEEE80211_AC_BE, ++ IEEE80211_AC_BK, ++ IEEE80211_AC_VI, ++ IEEE80211_AC_VO, ++ }; + + while (quota-- > 0 && kfifo_get(&rt2x00dev->txstatus_fifo, ®)) { + /* +@@ -1132,6 +1139,8 @@ void rt2800_txdone(struct rt2x00_dev *rt + * guaranteed to be one of the TX QIDs . + */ + qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE); ++ /* Convert Ralink hardware queue index to IEEE80211 queue id. */ ++ qid = rt2ac[qid]; + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); + + if (unlikely(rt2x00queue_empty(queue))) { +@@ -12182,8 +12191,9 @@ int rt2800_conf_tx(struct ieee80211_hw * + queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ +- offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2))); +- field.bit_offset = (queue_idx & 1) * 16; ++ offset = WMM_TXOP0_CFG + ++ (sizeof(u32) * (!!(rt2x00_ac_to_hwq(queue_idx) & 2))); ++ field.bit_offset = (rt2x00_ac_to_hwq(queue_idx) & 1) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + reg = rt2800_register_read(rt2x00dev, offset); +@@ -12191,7 +12201,7 @@ int rt2800_conf_tx(struct ieee80211_hw * + rt2800_register_write(rt2x00dev, offset, reg); + + /* Update WMM registers */ +- field.bit_offset = queue_idx * 4; ++ field.bit_offset = rt2x00_ac_to_hwq(queue_idx) * 4; + field.bit_mask = 0xf << field.bit_offset; + + reg = rt2800_register_read(rt2x00dev, WMM_AIFSN_CFG); +@@ -12207,7 +12217,7 @@ int rt2800_conf_tx(struct ieee80211_hw * + rt2800_register_write(rt2x00dev, WMM_CWMAX_CFG, reg); + + /* Update EDCA registers */ +- offset = EDCA_AC0_CFG + (sizeof(u32) * queue_idx); ++ offset = EDCA_AC0_CFG + (sizeof(u32) * rt2x00_ac_to_hwq(queue_idx)); + + reg = rt2800_register_read(rt2x00dev, offset); + rt2x00_set_field32(®, EDCA_AC0_CFG_TX_OP, queue->txop); +--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +@@ -35,7 +35,7 @@ unsigned int rt2800mmio_get_dma_done(str + case QID_AC_VI: + case QID_AC_BE: + case QID_AC_BK: +- qid = queue->qid; ++ qid = rt2x00_ac_to_hwq(queue->qid); + idx = rt2x00mmio_register_read(rt2x00dev, TX_DTX_IDX(qid)); + break; + case QID_MGMT: +@@ -456,6 +456,7 @@ void rt2800mmio_kick_queue(struct data_q + { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; + struct queue_entry *entry; ++ u8 qid; + + switch (queue->qid) { + case QID_AC_VO: +@@ -464,7 +465,8 @@ void rt2800mmio_kick_queue(struct data_q + case QID_AC_BK: + WARN_ON_ONCE(rt2x00queue_empty(queue)); + entry = rt2x00queue_get_entry(queue, Q_INDEX); +- rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), ++ qid = rt2x00_ac_to_hwq(queue->qid); ++ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX(qid), + entry->entry_idx); + hrtimer_start(&rt2x00dev->txstatus_timer, + TXSTATUS_TIMEOUT, HRTIMER_MODE_REL); +@@ -666,36 +668,36 @@ int rt2800mmio_init_queues(struct rt2x00 + * Initialize registers. + */ + entry_priv = rt2x00dev->tx[0].entries[0].priv_data; +- rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR0, ++ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR3, + entry_priv->desc_dma); +- rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT0, ++ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT3, + rt2x00dev->tx[0].limit); +- rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX0, 0); +- rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX0, 0); ++ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX3, 0); ++ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX3, 0); + + entry_priv = rt2x00dev->tx[1].entries[0].priv_data; +- rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR1, ++ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR2, + entry_priv->desc_dma); +- rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT1, ++ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT2, + rt2x00dev->tx[1].limit); +- rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX1, 0); +- rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX1, 0); ++ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX2, 0); ++ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX2, 0); + + entry_priv = rt2x00dev->tx[2].entries[0].priv_data; +- rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR2, ++ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR0, + entry_priv->desc_dma); +- rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT2, ++ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT0, + rt2x00dev->tx[2].limit); +- rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX2, 0); +- rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX2, 0); ++ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX0, 0); ++ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX0, 0); + + entry_priv = rt2x00dev->tx[3].entries[0].priv_data; +- rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR3, ++ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR1, + entry_priv->desc_dma); +- rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT3, ++ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT1, + rt2x00dev->tx[3].limit); +- rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX3, 0); +- rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX3, 0); ++ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX1, 0); ++ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX1, 0); + + rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR4, 0); + rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT4, 0); +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.h +@@ -57,6 +57,26 @@ enum data_queue_qid { + }; + + /** ++ * rt2x00_ac_to_hwq - Convert IEEE80211 queue id to Ralink hardware ++ * queue register index. ++ * @ac: TX queue id. ++ */ ++static inline u8 rt2x00_ac_to_hwq(enum data_queue_qid ac) ++{ ++ static const u8 ralink_queue_map[] = { ++ [IEEE80211_AC_BE] = 0, ++ [IEEE80211_AC_BK] = 1, ++ [IEEE80211_AC_VI] = 2, ++ [IEEE80211_AC_VO] = 3, ++ }; ++ ++ if (unlikely(ac >= IEEE80211_NUM_ACS)) ++ return ac; ++ ++ return ralink_queue_map[ac]; ++} ++ ++/** + * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc + * + * @SKBDESC_DMA_MAPPED_RX: &skb_dma field has been mapped for RX diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/620-02-rt2x00-increase-the-watchdog-sampling-frequency.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/620-02-rt2x00-increase-the-watchdog-sampling-frequency.patch new file mode 100644 index 0000000000..c60d2ad54a --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/620-02-rt2x00-increase-the-watchdog-sampling-frequency.patch @@ -0,0 +1,74 @@ +From aec50d1a30349759de0ac535f54c3441bf7ebef7 Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Sun, 22 Dec 2024 17:06:59 +0800 +Subject: [PATCH 2/2] rt2x00: increase the watchdog sampling frequency + +Increase the sampling frequency of the watchdog when the hung +counter reaches the threshold to avoid some unnecessary resets. + +Signed-off-by: Shiji Yang +--- + .../net/wireless/ralink/rt2x00/rt2800lib.c | 45 +++++++++++++------ + 1 file changed, 32 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -1320,26 +1320,45 @@ static bool rt2800_watchdog_hung(struct + return true; + } + ++static inline bool check_dma_busy_rx(u32 reg_cfg, u32 reg_int) ++{ ++ return (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) && ++ rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT)); ++} ++ ++static inline bool check_dma_busy_tx(u32 reg_cfg, u32 reg_int) ++{ ++ return (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) && ++ rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT)); ++} ++ + static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev) + { + bool busy_rx, busy_tx; + u32 reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); + u32 reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR); + +- if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) && +- rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT)) +- rt2x00dev->rxdma_busy++; +- else +- rt2x00dev->rxdma_busy = 0; +- +- if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) && +- rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT)) +- rt2x00dev->txdma_busy++; +- else +- rt2x00dev->txdma_busy = 0; ++ rt2x00dev->rxdma_busy = check_dma_busy_rx(reg_cfg, reg_int) ? ++ rt2x00dev->rxdma_busy + 1 : 0; ++ rt2x00dev->txdma_busy = check_dma_busy_tx(reg_cfg, reg_int) ? ++ rt2x00dev->txdma_busy + 1 : 0; ++ ++ if (rt2x00dev->rxdma_busy > 25 || rt2x00dev->txdma_busy > 25) { ++ int cnt; ++ for (cnt = 0; cnt < 10; cnt++) { ++ msleep(5); ++ reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG); ++ reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR); ++ ++ if (!check_dma_busy_rx(reg_cfg, reg_int)) ++ rt2x00dev->rxdma_busy = 0; ++ if (!check_dma_busy_tx(reg_cfg, reg_int)) ++ rt2x00dev->txdma_busy = 0; ++ } ++ } + +- busy_rx = rt2x00dev->rxdma_busy > 30; +- busy_tx = rt2x00dev->txdma_busy > 30; ++ busy_rx = rt2x00dev->rxdma_busy > 40; ++ busy_tx = rt2x00dev->txdma_busy > 40; + + if (!busy_rx && !busy_tx) + return false; diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-01-rt2x00-always-calibrate-MT7620-when-switching-channe.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-01-rt2x00-always-calibrate-MT7620-when-switching-channe.patch new file mode 100644 index 0000000000..01ae04e6e2 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-01-rt2x00-always-calibrate-MT7620-when-switching-channe.patch @@ -0,0 +1,77 @@ +From 2c5aad0f9990724cce48e0a53b66bc0438e4603d Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Sun, 22 Dec 2024 17:06:59 +0800 +Subject: [PATCH 1/4] rt2x00: always calibrate MT7620 when switching channel + +Perform calibration work after each channel switching operation. +This should help improve the rx/tx signal strength for MT7620. + +Signed-off-by: Shiji Yang +--- + .../net/wireless/ralink/rt2x00/rt2800lib.c | 24 ++++++++++++++----- + 1 file changed, 18 insertions(+), 6 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -5704,6 +5704,9 @@ static void rt2800_config_ps(struct rt2x + } + } + ++static void rt2800_calibration_rt6352_stage1(struct rt2x00_dev *rt2x00dev); ++static void rt2800_calibration_rt6352_stage2(struct rt2x00_dev *rt2x00dev); ++ + void rt2800_config(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf, + const unsigned int flags) +@@ -5718,10 +5721,18 @@ void rt2800_config(struct rt2x00_dev *rt + */ + rt2800_update_survey(rt2x00dev); + ++ if (rt2x00_rt(rt2x00dev, RT6352) && ++ !test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) ++ rt2800_calibration_rt6352_stage1(rt2x00dev); ++ + rt2800_config_channel(rt2x00dev, libconf->conf, + &libconf->rf, &libconf->channel); + rt2800_config_txpower(rt2x00dev, libconf->conf->chandef.chan, + libconf->conf->power_level); ++ ++ if (rt2x00_rt(rt2x00dev, RT6352) && ++ !test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) ++ rt2800_calibration_rt6352_stage2(rt2x00dev); + } + if (flags & IEEE80211_CONF_CHANGE_POWER) + rt2800_config_txpower(rt2x00dev, libconf->conf->chandef.chan, +@@ -10421,15 +10432,19 @@ static void rt2800_restore_rf_bbp_rt6352 + } + } + +-static void rt2800_calibration_rt6352(struct rt2x00_dev *rt2x00dev) ++static void rt2800_calibration_rt6352_stage1(struct rt2x00_dev *rt2x00dev) + { +- u32 reg; +- + if (rt2x00_has_cap_external_pa(rt2x00dev) || + rt2x00_has_cap_external_lna_bg(rt2x00dev)) + rt2800_restore_rf_bbp_rt6352(rt2x00dev); + + rt2800_r_calibration(rt2x00dev); ++} ++ ++static void rt2800_calibration_rt6352_stage2(struct rt2x00_dev *rt2x00dev) ++{ ++ u32 reg; ++ + rt2800_rf_self_txdc_cal(rt2x00dev); + rt2800_rxdcoc_calibration(rt2x00dev); + rt2800_bw_filter_calibration(rt2x00dev, true); +@@ -10760,9 +10775,6 @@ static void rt2800_init_rfcsr_6352(struc + + rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); + rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); +- +- /* Do calibration and init PA/LNA */ +- rt2800_calibration_rt6352(rt2x00dev); + } + + static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-02-rt2x00-rework-link-tuner-for-MT7620.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-02-rt2x00-rework-link-tuner-for-MT7620.patch new file mode 100644 index 0000000000..f7e7a8e5ff --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-02-rt2x00-rework-link-tuner-for-MT7620.patch @@ -0,0 +1,48 @@ +From aaa57924324c1ee77afa5e3effc95cc86158ddcc Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Sun, 22 Dec 2024 17:06:59 +0800 +Subject: [PATCH 2/4] rt2x00: rework link tuner for MT7620 + +Correct the VGC gain value for MT7620 and only do gain calibration +for supported devices. + +Signed-off-by: Shiji Yang +--- + drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -5561,6 +5561,9 @@ static void rt2800_config_txpower(struct + + void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev) + { ++ if (rt2x00_rt(rt2x00dev, RT6352)) ++ return; ++ + rt2800_config_txpower(rt2x00dev, rt2x00dev->hw->conf.chandef.chan, + rt2x00dev->tx_power); + } +@@ -5773,9 +5776,10 @@ static u8 rt2800_get_default_vgc(struct + rt2x00_rt(rt2x00dev, RT3593) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392) || +- rt2x00_rt(rt2x00dev, RT5592) || +- rt2x00_rt(rt2x00dev, RT6352)) ++ rt2x00_rt(rt2x00dev, RT5592)) + vgc = 0x1c + (2 * rt2x00dev->lna_gain); ++ else if(rt2x00_rt(rt2x00dev, RT6352)) ++ vgc = 0x04 + (2 * rt2x00dev->lna_gain); + else + vgc = 0x2e + rt2x00dev->lna_gain; + } else { /* 5GHZ band */ +@@ -5828,7 +5832,8 @@ void rt2800_link_tuner(struct rt2x00_dev + { + u8 vgc; + +- if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) ++ if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C) || ++ rt2x00_rt(rt2x00dev, RT6352)) + return; + + /* When RSSI is better than a certain threshold, increase VGC diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-03-rt2x00-correct-MT7620-SDM-mode-register-value.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-03-rt2x00-correct-MT7620-SDM-mode-register-value.patch new file mode 100644 index 0000000000..7c376df197 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-03-rt2x00-correct-MT7620-SDM-mode-register-value.patch @@ -0,0 +1,25 @@ +From b672507ca9f06bb17213036b16bc4f5c5bc65357 Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Sun, 22 Dec 2024 17:06:59 +0800 +Subject: [PATCH 3/4] rt2x00: correct MT7620 SDM mode register value + +rt2x00_set_field8() is a mask writing function. If we want to set +the BIT(7) for the SDM mode register here, we only need to fill "4" +in the mask. + +Signed-off-by: Shiji Yang +--- + drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -3848,7 +3848,7 @@ static void rt2800_config_channel_rf7620 + + /* Default: XO=20MHz , SDM mode */ + rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); +- rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80); ++ rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 4); + rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); + + rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-04-rt2x00-fix-register-operation-on-RXIQ-calibration.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-04-rt2x00-fix-register-operation-on-RXIQ-calibration.patch new file mode 100644 index 0000000000..0e0245e492 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/621-04-rt2x00-fix-register-operation-on-RXIQ-calibration.patch @@ -0,0 +1,26 @@ +From 2585ada646e4dcf152ab813a24d667e6903105f4 Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Sun, 22 Dec 2024 17:06:59 +0800 +Subject: [PATCH 4/4] rt2x00: fix register operation on RXIQ calibration + +In rt2800_rxiq_calibration(), some variables are overwritten +before being used. Based on the values of the relevant registers +in other functions, I believe the correct operation should be +bit mask writing. + +Signed-off-by: Shiji Yang +--- + drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -8846,7 +8846,7 @@ static void rt2800_rxiq_calibration(stru + rt2x00_warn(rt2x00dev, "Timeout waiting for MAC status in RXIQ calibration\n"); + + bbpval = bbp4 & (~0x18); +- bbpval = bbp4 | 0x00; ++ bbpval = bbpval | 0x00; + rt2800_bbp_write(rt2x00dev, 4, bbpval); + + bbpval = rt2800_bbp_read(rt2x00dev, 21); diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/622-01-rt2x00-fix-RFCSR-register-init-values-for-RT5592.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/622-01-rt2x00-fix-RFCSR-register-init-values-for-RT5592.patch new file mode 100644 index 0000000000..72a8f0073d --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/622-01-rt2x00-fix-RFCSR-register-init-values-for-RT5592.patch @@ -0,0 +1,230 @@ +From b48887d5de9921d0ff9e88068e3cd555a383d702 Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Sun, 22 Dec 2024 17:06:59 +0800 +Subject: [PATCH 1/2] rt2x00: fix RFCSR register init values for RT5592 + +Based on Raink proprietary driver 2.7.1.5, correct the initial +values of some RFCSR registers for RT5592. + +Signed-off-by: Shiji Yang +--- + .../net/wireless/ralink/rt2x00/rt2800lib.c | 122 ++++++++---------- + 1 file changed, 53 insertions(+), 69 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -3576,9 +3576,8 @@ static void rt2800_config_channel_rf55xx + + /* TODO RF27 <- tssi */ + +- rfcsr = rf->channel <= 10 ? 0x07 : 0x06; +- rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); +- rt2800_rfcsr_write(rt2x00dev, 59, rfcsr); ++ rt2800_rfcsr_write(rt2x00dev, 23, rf->channel <= 10 ? 0x08 : 0x07); ++ rt2800_rfcsr_write(rt2x00dev, 59, rf->channel <= 4 ? 0x06 : 0x04); + + if (is_11b) { + /* CCK */ +@@ -3599,7 +3598,7 @@ static void rt2800_config_channel_rf55xx + power_bound = POWER_BOUND; + ep_reg = 0x2; + } else { +- rt2800_rfcsr_write(rt2x00dev, 10, 0x97); ++ rt2800_rfcsr_write(rt2x00dev, 10, 0x95); + /* FIMXE: RF11 overwrite */ + rt2800_rfcsr_write(rt2x00dev, 11, 0x40); + rt2800_rfcsr_write(rt2x00dev, 25, 0xBF); +@@ -3608,13 +3607,15 @@ static void rt2800_config_channel_rf55xx + rt2800_rfcsr_write(rt2x00dev, 37, 0x04); + rt2800_rfcsr_write(rt2x00dev, 38, 0x85); + rt2800_rfcsr_write(rt2x00dev, 40, 0x42); +- rt2800_rfcsr_write(rt2x00dev, 41, 0xBB); ++ rt2800_rfcsr_write(rt2x00dev, 41, 0xAB); + rt2800_rfcsr_write(rt2x00dev, 42, 0xD7); +- rt2800_rfcsr_write(rt2x00dev, 45, 0x41); ++ rt2800_rfcsr_write(rt2x00dev, 45, 0x01); + rt2800_rfcsr_write(rt2x00dev, 48, 0x00); + rt2800_rfcsr_write(rt2x00dev, 57, 0x77); ++ rt2800_rfcsr_write(rt2x00dev, 58, 0x19); + rt2800_rfcsr_write(rt2x00dev, 60, 0x05); + rt2800_rfcsr_write(rt2x00dev, 61, 0x01); ++ rt2800_rfcsr_write(rt2x00dev, 62, 0x19); + + /* TODO RF27 <- tssi */ + +@@ -3623,82 +3624,59 @@ static void rt2800_config_channel_rf55xx + rt2800_rfcsr_write(rt2x00dev, 12, 0x2E); + rt2800_rfcsr_write(rt2x00dev, 13, 0x22); + rt2800_rfcsr_write(rt2x00dev, 22, 0x60); +- rt2800_rfcsr_write(rt2x00dev, 23, 0x7F); +- if (rf->channel <= 50) +- rt2800_rfcsr_write(rt2x00dev, 24, 0x09); +- else if (rf->channel >= 52) +- rt2800_rfcsr_write(rt2x00dev, 24, 0x07); ++ rt2800_rfcsr_write(rt2x00dev, 23, 0x7E); ++ rt2800_rfcsr_write(rt2x00dev, 24, 0x07); + rt2800_rfcsr_write(rt2x00dev, 39, 0x1C); + rt2800_rfcsr_write(rt2x00dev, 43, 0x5B); +- rt2800_rfcsr_write(rt2x00dev, 44, 0X40); + rt2800_rfcsr_write(rt2x00dev, 46, 0X00); +- rt2800_rfcsr_write(rt2x00dev, 51, 0xFE); +- rt2800_rfcsr_write(rt2x00dev, 52, 0x0C); +- rt2800_rfcsr_write(rt2x00dev, 54, 0xF8); ++ rt2800_rfcsr_write(rt2x00dev, 51, 0xFD); ++ rt2800_rfcsr_write(rt2x00dev, 52, 0x0E); ++ rt2800_rfcsr_write(rt2x00dev, 55, 0x04); ++ rt2800_rfcsr_write(rt2x00dev, 56, 0xBB); ++ rt2800_rfcsr_write(rt2x00dev, 59, 0x7C); ++ + if (rf->channel <= 50) { +- rt2800_rfcsr_write(rt2x00dev, 55, 0x06); +- rt2800_rfcsr_write(rt2x00dev, 56, 0xD3); ++ rt2800_rfcsr_write(rt2x00dev, 44, 0X32); ++ rt2800_rfcsr_write(rt2x00dev, 54, 0xF9); + } else if (rf->channel >= 52) { +- rt2800_rfcsr_write(rt2x00dev, 55, 0x04); +- rt2800_rfcsr_write(rt2x00dev, 56, 0xBB); ++ rt2800_rfcsr_write(rt2x00dev, 44, 0X2A); ++ rt2800_rfcsr_write(rt2x00dev, 54, 0xF8); + } +- +- rt2800_rfcsr_write(rt2x00dev, 58, 0x15); +- rt2800_rfcsr_write(rt2x00dev, 59, 0x7F); +- rt2800_rfcsr_write(rt2x00dev, 62, 0x15); +- + } else if (rf->channel >= 100 && rf->channel <= 165) { +- + rt2800_rfcsr_write(rt2x00dev, 12, 0x0E); + rt2800_rfcsr_write(rt2x00dev, 13, 0x42); + rt2800_rfcsr_write(rt2x00dev, 22, 0x40); +- if (rf->channel <= 153) { +- rt2800_rfcsr_write(rt2x00dev, 23, 0x3C); +- rt2800_rfcsr_write(rt2x00dev, 24, 0x06); +- } else if (rf->channel >= 155) { +- rt2800_rfcsr_write(rt2x00dev, 23, 0x38); +- rt2800_rfcsr_write(rt2x00dev, 24, 0x05); +- } ++ rt2800_rfcsr_write(rt2x00dev, 52, 0x06); ++ rt2800_rfcsr_write(rt2x00dev, 55, 0x01); ++ + if (rf->channel <= 138) { ++ rt2800_rfcsr_write(rt2x00dev, 23, 0x7C); + rt2800_rfcsr_write(rt2x00dev, 39, 0x1A); + rt2800_rfcsr_write(rt2x00dev, 43, 0x3B); +- rt2800_rfcsr_write(rt2x00dev, 44, 0x20); + rt2800_rfcsr_write(rt2x00dev, 46, 0x18); +- } else if (rf->channel >= 140) { ++ } else { ++ rt2800_rfcsr_write(rt2x00dev, 23, 0x78); + rt2800_rfcsr_write(rt2x00dev, 39, 0x18); + rt2800_rfcsr_write(rt2x00dev, 43, 0x1B); +- rt2800_rfcsr_write(rt2x00dev, 44, 0x10); + rt2800_rfcsr_write(rt2x00dev, 46, 0X08); + } +- if (rf->channel <= 124) +- rt2800_rfcsr_write(rt2x00dev, 51, 0xFC); +- else if (rf->channel >= 126) +- rt2800_rfcsr_write(rt2x00dev, 51, 0xEC); +- if (rf->channel <= 138) +- rt2800_rfcsr_write(rt2x00dev, 52, 0x06); +- else if (rf->channel >= 140) +- rt2800_rfcsr_write(rt2x00dev, 52, 0x06); +- rt2800_rfcsr_write(rt2x00dev, 54, 0xEB); +- if (rf->channel <= 138) +- rt2800_rfcsr_write(rt2x00dev, 55, 0x01); +- else if (rf->channel >= 140) +- rt2800_rfcsr_write(rt2x00dev, 55, 0x00); +- if (rf->channel <= 128) +- rt2800_rfcsr_write(rt2x00dev, 56, 0xBB); +- else if (rf->channel >= 130) +- rt2800_rfcsr_write(rt2x00dev, 56, 0xAB); +- if (rf->channel <= 116) +- rt2800_rfcsr_write(rt2x00dev, 58, 0x1D); +- else if (rf->channel >= 118) +- rt2800_rfcsr_write(rt2x00dev, 58, 0x15); +- if (rf->channel <= 138) +- rt2800_rfcsr_write(rt2x00dev, 59, 0x3F); +- else if (rf->channel >= 140) +- rt2800_rfcsr_write(rt2x00dev, 59, 0x7C); +- if (rf->channel <= 116) +- rt2800_rfcsr_write(rt2x00dev, 62, 0x1D); +- else if (rf->channel >= 118) +- rt2800_rfcsr_write(rt2x00dev, 62, 0x15); ++ ++ if (rf->channel <= 114) { ++ rt2800_rfcsr_write(rt2x00dev, 24, 0x02); ++ rt2800_rfcsr_write(rt2x00dev, 44, 0x1A); ++ rt2800_rfcsr_write(rt2x00dev, 54, 0xEA); ++ rt2800_rfcsr_write(rt2x00dev, 56, 0xB3); ++ } else { ++ rt2800_rfcsr_write(rt2x00dev, 24, 0x03); ++ rt2800_rfcsr_write(rt2x00dev, 44, 0x0A); ++ rt2800_rfcsr_write(rt2x00dev, 54, 0xF9); ++ rt2800_rfcsr_write(rt2x00dev, 56, 0x9B); ++ } ++ ++ rt2800_rfcsr_write(rt2x00dev, 51, rf->channel <= 124 ? 0xFC : 0xEC); ++ rt2800_rfcsr_write(rt2x00dev, 58, rf->channel <= 116 ? 0x1D : 0x15); ++ rfcsr = (rf->channel >= 116 && rf->channel <= 138) ? 0x7E : 0x7C; ++ rt2800_rfcsr_write(rt2x00dev, 59, rfcsr); + } + + power_bound = POWER_BOUND_5G; +@@ -3710,7 +3688,7 @@ static void rt2800_config_channel_rf55xx + rt2x00_set_field8(&rfcsr, RFCSR49_TX, power_bound); + else + rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); +- if (is_type_ep) ++ if (!is_type_ep) + rt2x00_set_field8(&rfcsr, RFCSR49_EP, ep_reg); + rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); + +@@ -3719,7 +3697,7 @@ static void rt2800_config_channel_rf55xx + rt2x00_set_field8(&rfcsr, RFCSR50_TX, power_bound); + else + rt2x00_set_field8(&rfcsr, RFCSR50_TX, info->default_power2); +- if (is_type_ep) ++ if (!is_type_ep) + rt2x00_set_field8(&rfcsr, RFCSR50_EP, ep_reg); + rt2800_rfcsr_write(rt2x00dev, 50, rfcsr); + +@@ -3740,7 +3718,6 @@ static void rt2800_config_channel_rf55xx + rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0); + + rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); +- rt2800_rfcsr_write(rt2x00dev, 6, 0xe4); + + if (conf_is_ht40(conf)) + rt2800_rfcsr_write(rt2x00dev, 30, 0x16); +@@ -8505,12 +8482,15 @@ static void rt2800_init_rfcsr_5392(struc + + static void rt2800_init_rfcsr_5592(struct rt2x00_dev *rt2x00dev) + { ++ u16 eeprom; ++ + rt2800_rf_init_calibration(rt2x00dev, 30); + + rt2800_rfcsr_write(rt2x00dev, 1, 0x3F); ++ rt2800_rfcsr_write(rt2x00dev, 2, 0x80); + rt2800_rfcsr_write(rt2x00dev, 3, 0x08); + rt2800_rfcsr_write(rt2x00dev, 5, 0x10); +- rt2800_rfcsr_write(rt2x00dev, 6, 0xE4); ++ rt2800_rfcsr_write(rt2x00dev, 6, 0xE0); + rt2800_rfcsr_write(rt2x00dev, 7, 0x00); + rt2800_rfcsr_write(rt2x00dev, 14, 0x00); + rt2800_rfcsr_write(rt2x00dev, 15, 0x00); +@@ -8526,9 +8506,13 @@ static void rt2800_init_rfcsr_5592(struc + rt2800_rfcsr_write(rt2x00dev, 34, 0x07); + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); + rt2800_rfcsr_write(rt2x00dev, 47, 0x0C); +- rt2800_rfcsr_write(rt2x00dev, 53, 0x22); ++ rt2800_rfcsr_write(rt2x00dev, 53, 0x44); + rt2800_rfcsr_write(rt2x00dev, 63, 0x07); + ++ eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF2); ++ if (!rt2x00_get_field16(eeprom, EEPROM_NIC_CONF2_CRYSTAL)) ++ rt2800_rfcsr_write(rt2x00dev, 6, 0xE4); ++ + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); + msleep(1); + diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/622-02-rt2x00-fix-BBP-register-init-values-for-RT5592.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/622-02-rt2x00-fix-BBP-register-init-values-for-RT5592.patch new file mode 100644 index 0000000000..19d1951b7b --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/622-02-rt2x00-fix-BBP-register-init-values-for-RT5592.patch @@ -0,0 +1,119 @@ +From 1847d817df5585f9d957d16ed2a56ceb41cf6df7 Mon Sep 17 00:00:00 2001 +From: Shiji Yang +Date: Sun, 22 Dec 2024 17:06:59 +0800 +Subject: [PATCH 2/2] rt2x00: fix BBP register init values for RT5592 + +Based on Raink proprietary driver 2.7.1.5, correct the initial +values of some BBP registers for RT5592. + +Signed-off-by: Shiji Yang +--- + .../net/wireless/ralink/rt2x00/rt2800lib.c | 32 +++++++++---------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -3746,6 +3746,7 @@ static void rt2800_config_channel_rf55xx + rt2800_bbp_write(rt2x00dev, 80, (rf->channel <= 14) ? 0x0E : 0x08); + rt2800_bbp_write(rt2x00dev, 81, (rf->channel <= 14) ? 0x3A : 0x38); + rt2800_bbp_write(rt2x00dev, 82, (rf->channel <= 14) ? 0x62 : 0x92); ++ rt2800_bbp_write(rt2x00dev, 95, (rf->channel <= 14) ? 0x9A : 0x1A); + + /* GLRT band configuration */ + rt2800_bbp_write(rt2x00dev, 195, 128); +@@ -3758,7 +3759,7 @@ static void rt2800_config_channel_rf55xx + rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x32 : 0x20); + rt2800_bbp_write(rt2x00dev, 195, 133); + rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x28 : 0x7F); +- rt2800_bbp_write(rt2x00dev, 195, 124); ++ rt2800_bbp_write(rt2x00dev, 195, 134); + rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x19 : 0x7F); + } + +@@ -4304,7 +4305,8 @@ static void rt2800_config_channel(struct + rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); + rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); +- if (rt2x00_rt(rt2x00dev, RT6352)) ++ if (rt2x00_rt(rt2x00dev, RT5592) || ++ rt2x00_rt(rt2x00dev, RT6352)) + rt2800_bbp_write(rt2x00dev, 86, 0x38); + else + rt2800_bbp_write(rt2x00dev, 86, 0); +@@ -4313,6 +4315,7 @@ static void rt2800_config_channel(struct + if (rf->channel <= 14) { + if (!rt2x00_rt(rt2x00dev, RT5390) && + !rt2x00_rt(rt2x00dev, RT5392) && ++ !rt2x00_rt(rt2x00dev, RT5592) && + !rt2x00_rt(rt2x00dev, RT6352)) { + if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { + rt2800_bbp_write(rt2x00dev, 82, 0x62); +@@ -4336,17 +4339,20 @@ static void rt2800_config_channel(struct + else if (rt2x00_rt(rt2x00dev, RT3593) || + rt2x00_rt(rt2x00dev, RT3883)) + rt2800_bbp_write(rt2x00dev, 82, 0x82); +- else if (!rt2x00_rt(rt2x00dev, RT6352)) ++ else if (!rt2x00_rt(rt2x00dev, RT5592) && ++ !rt2x00_rt(rt2x00dev, RT6352)) + rt2800_bbp_write(rt2x00dev, 82, 0xf2); + + if (rt2x00_rt(rt2x00dev, RT3593) || + rt2x00_rt(rt2x00dev, RT3883)) + rt2800_bbp_write(rt2x00dev, 83, 0x9a); + +- if (rt2x00_has_cap_external_lna_a(rt2x00dev)) +- rt2800_bbp_write(rt2x00dev, 75, 0x46); +- else +- rt2800_bbp_write(rt2x00dev, 75, 0x50); ++ if (!rt2x00_rt(rt2x00dev, RT5592)) { ++ if (rt2x00_has_cap_external_lna_a(rt2x00dev)) ++ rt2800_bbp_write(rt2x00dev, 75, 0x46); ++ else ++ rt2800_bbp_write(rt2x00dev, 75, 0x50); ++ } + } + + reg = rt2800_register_read(rt2x00dev, TX_BAND_CFG); +@@ -5783,12 +5789,10 @@ static inline void rt2800_set_vgc(struct + if (rt2x00_rt(rt2x00dev, RT3572) || + rt2x00_rt(rt2x00dev, RT3593) || + rt2x00_rt(rt2x00dev, RT3883) || ++ rt2x00_rt(rt2x00dev, RT5592) || + rt2x00_rt(rt2x00dev, RT6352)) { + rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, + vgc_level); +- } else if (rt2x00_rt(rt2x00dev, RT5592)) { +- rt2800_bbp_write(rt2x00dev, 83, qual->rssi > -65 ? 0x4a : 0x7a); +- rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, vgc_level); + } else { + rt2800_bbp_write(rt2x00dev, 66, vgc_level); + } +@@ -7016,7 +7020,6 @@ static void rt2800_init_bbp_5592(struct + rt2800_bbp_write(rt2x00dev, 88, 0x90); + rt2800_bbp_write(rt2x00dev, 91, 0x04); + rt2800_bbp_write(rt2x00dev, 92, 0x02); +- rt2800_bbp_write(rt2x00dev, 95, 0x9a); + rt2800_bbp_write(rt2x00dev, 98, 0x12); + rt2800_bbp_write(rt2x00dev, 103, 0xC0); + rt2800_bbp_write(rt2x00dev, 104, 0x92); +@@ -7027,6 +7030,7 @@ static void rt2800_init_bbp_5592(struct + rt2800_bbp_write(rt2x00dev, 134, 0xD0); + rt2800_bbp_write(rt2x00dev, 135, 0xF6); + rt2800_bbp_write(rt2x00dev, 137, 0x0F); ++ rt2800_bbp_write(rt2x00dev, 148, 0x84); + + /* Initialize GLRT (Generalized Likehood Radio Test) */ + rt2800_init_bbp_5592_glrt(rt2x00dev); +@@ -7051,12 +7055,6 @@ static void rt2800_init_bbp_5592(struct + rt2x00_set_field8(&value, BBP254_BIT7, 1); + rt2800_bbp_write(rt2x00dev, 254, value); + } +- +- rt2800_init_freq_calibration(rt2x00dev); +- +- rt2800_bbp_write(rt2x00dev, 84, 0x19); +- if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) +- rt2800_bbp_write(rt2x00dev, 103, 0xc0); + } + + static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev) diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch new file mode 100644 index 0000000000..0e05491f12 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch @@ -0,0 +1,121 @@ +From 0fce1109f894ec7fcd72cb098843a1eff786716a Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 16 Sep 2022 20:49:42 +0100 +Subject: [PATCH 16/16] rt2x00: import support for external LNA on MT7620 +To: linux-wireless@vger.kernel.org, + Stanislaw Gruszka , + Helmut Schaa +Cc: Kalle Valo , + David S. Miller , + Eric Dumazet , + Jakub Kicinski , + Paolo Abeni , + Johannes Berg + +In order to carry out calibration on boards with ePA or eLNA the PA pin +needs to be switch to GPIO mode on MT7620. Implement that by selecting +pinctrl state "pa_gpio" which should be defined for MT7620 boards with +eLNA or ePA beside the "default" state. + +Reported-by: Serge Vasilugin +Signed-off-by: Daniel Golle +--- + .../net/wireless/ralink/rt2x00/rt2800lib.c | 58 +++++++++++++++++++ + drivers/net/wireless/ralink/rt2x00/rt2x00.h | 5 ++ + .../net/wireless/ralink/rt2x00/rt2800soc.c | 15 +++++ + 3 files changed, 78 insertions(+) + +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -305,6 +305,24 @@ static void rt2800_rf_write(struct rt2x0 + mutex_unlock(&rt2x00dev->csr_mutex); + } + ++static void rt6352_enable_pa_pin(struct rt2x00_dev *rt2x00dev, int enable) ++{ ++ if (!rt2x00dev->pinctrl) ++ return; ++ ++ if (enable) { ++ if (!rt2x00dev->pins_default) ++ return; ++ ++ pinctrl_select_state(rt2x00dev->pinctrl, rt2x00dev->pins_default); ++ } else { ++ if (!rt2x00dev->pins_pa_gpio) ++ return; ++ ++ pinctrl_select_state(rt2x00dev->pinctrl, rt2x00dev->pins_pa_gpio); ++ } ++} ++ + static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = { + [EEPROM_CHIP_ID] = 0x0000, + [EEPROM_VERSION] = 0x0001, +@@ -10422,8 +10440,10 @@ static void rt2800_restore_rf_bbp_rt6352 + static void rt2800_calibration_rt6352_stage1(struct rt2x00_dev *rt2x00dev) + { + if (rt2x00_has_cap_external_pa(rt2x00dev) || +- rt2x00_has_cap_external_lna_bg(rt2x00dev)) ++ rt2x00_has_cap_external_lna_bg(rt2x00dev)) { ++ rt6352_enable_pa_pin(rt2x00dev, 0); + rt2800_restore_rf_bbp_rt6352(rt2x00dev); ++ } + + rt2800_r_calibration(rt2x00dev); + } +@@ -10447,6 +10467,8 @@ static void rt2800_calibration_rt6352_st + !rt2x00_has_cap_external_lna_bg(rt2x00dev)) + return; + ++ rt6352_enable_pa_pin(rt2x00dev, 1); ++ + if (rt2x00_has_cap_external_pa(rt2x00dev)) { + reg = rt2800_register_read(rt2x00dev, RF_CONTROL3); + reg |= 0x00000101; +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1015,6 +1016,11 @@ struct rt2x00_dev { + + /* Clock for System On Chip devices. */ + struct clk *clk; ++ ++ /* pinctrl and states for System On Chip devices with PA/LNA. */ ++ struct pinctrl *pinctrl; ++ struct pinctrl_state *pins_default; ++ struct pinctrl_state *pins_pa_gpio; + }; + + struct rt2x00_bar_list_entry { +--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +@@ -298,6 +298,21 @@ static int rt2x00soc_probe(struct platfo + if (retval) + goto exit_free_device; + ++ rt2x00dev->pinctrl = devm_pinctrl_get(&pdev->dev); ++ if (IS_ERR(rt2x00dev->pinctrl)) { ++ rt2x00dev->pinctrl = NULL; ++ rt2x00dev->pins_default = NULL; ++ rt2x00dev->pins_pa_gpio = NULL; ++ } else { ++ rt2x00dev->pins_default = pinctrl_lookup_state(rt2x00dev->pinctrl, "default"); ++ if (IS_ERR(rt2x00dev->pins_default)) ++ rt2x00dev->pins_default = NULL; ++ ++ rt2x00dev->pins_pa_gpio = pinctrl_lookup_state(rt2x00dev->pinctrl, "pa_gpio"); ++ if (IS_ERR(rt2x00dev->pins_pa_gpio)) ++ rt2x00dev->pins_pa_gpio = NULL; ++ } ++ + return 0; + + exit_free_device: diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch new file mode 100644 index 0000000000..46966c6022 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch @@ -0,0 +1,139 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +@@ -76,6 +76,9 @@ struct rt2800_ops { + int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev); + __le32 *(*drv_get_txwi)(struct queue_entry *entry); + unsigned int (*drv_get_dma_done)(struct data_queue *queue); ++ int (*hw_get_chippkg)(void); ++ int (*hw_get_chipver)(void); ++ int (*hw_get_chipeco)(void); + }; + + static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev, +@@ -184,6 +187,27 @@ static inline unsigned int rt2800_drv_ge + return rt2800ops->drv_get_dma_done(queue); + } + ++static inline int rt2800_hw_get_chippkg(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ return rt2800ops->hw_get_chippkg(); ++} ++ ++static inline int rt2800_hw_get_chipver(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ return rt2800ops->hw_get_chipver(); ++} ++ ++static inline int rt2800_hw_get_chipeco(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ return rt2800ops->hw_get_chipeco(); ++} ++ + void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1); +--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +@@ -289,6 +289,10 @@ static int rt2800pci_read_eeprom(struct + return retval; + } + ++static int rt2800pci_get_chippkg(void) { return 0; } ++static int rt2800pci_get_chipver(void) { return 0; } ++static int rt2800pci_get_chipeco(void) { return 0; } ++ + static const struct ieee80211_ops rt2800pci_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, +@@ -336,6 +340,9 @@ static const struct rt2800_ops rt2800pci + .drv_init_registers = rt2800mmio_init_registers, + .drv_get_txwi = rt2800mmio_get_txwi, + .drv_get_dma_done = rt2800mmio_get_dma_done, ++ .hw_get_chippkg = rt2800pci_get_chippkg, ++ .hw_get_chipver = rt2800pci_get_chipver, ++ .hw_get_chipeco = rt2800pci_get_chipeco, + }; + + static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { +--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +@@ -27,6 +27,12 @@ + #include "rt2800lib.h" + #include "rt2800mmio.h" + ++/* Needed to probe CHIP_VER register on MT7620 */ ++#ifdef CONFIG_SOC_MT7620 ++#include ++#include ++#endif ++ + /* Allow hardware encryption to be disabled. */ + static bool modparam_nohwcrypt; + module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); +@@ -136,6 +142,27 @@ static int rt2800soc_resume(struct platf + } + #endif /* CONFIG_PM */ + ++#ifdef CONFIG_SOC_MT7620 ++static int rt2800soc_get_chippkg(void) ++{ ++ return mt7620_get_pkg(); ++} ++ ++static int rt2800soc_get_chipver(void) ++{ ++ return mt7620_get_chipver(); ++} ++ ++static int rt2800soc_get_chipeco(void) ++{ ++ return mt7620_get_eco(); ++} ++#else ++static int rt2800soc_get_chippkg(void) { return 0; } ++static int rt2800soc_get_chipver(void) { return 0; } ++static int rt2800soc_get_chipeco(void) { return 0; } ++#endif ++ + static const struct ieee80211_ops rt2800soc_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, +@@ -183,6 +210,9 @@ static const struct rt2800_ops rt2800soc + .drv_init_registers = rt2800mmio_init_registers, + .drv_get_txwi = rt2800mmio_get_txwi, + .drv_get_dma_done = rt2800mmio_get_dma_done, ++ .hw_get_chippkg = rt2800soc_get_chippkg, ++ .hw_get_chipver = rt2800soc_get_chipver, ++ .hw_get_chipeco = rt2800soc_get_chipeco, + }; + + static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = { +--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +@@ -628,6 +628,10 @@ static int rt2800usb_probe_hw(struct rt2 + return 0; + } + ++static int rt2800usb_get_chippkg(void) { return 0; } ++static int rt2800usb_get_chipver(void) { return 0; } ++static int rt2800usb_get_chipeco(void) { return 0; } ++ + static const struct ieee80211_ops rt2800usb_mac80211_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, +@@ -676,6 +680,9 @@ static const struct rt2800_ops rt2800usb + .drv_init_registers = rt2800usb_init_registers, + .drv_get_txwi = rt2800usb_get_txwi, + .drv_get_dma_done = rt2800usb_get_dma_done, ++ .hw_get_chippkg = rt2800usb_get_chippkg, ++ .hw_get_chipver = rt2800usb_get_chipver, ++ .hw_get_chipeco = rt2800usb_get_chipeco, + }; + + static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { diff --git a/lede/package/kernel/mac80211/patches-6.18/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch b/lede/package/kernel/mac80211/patches-6.18/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch new file mode 100644 index 0000000000..0b2e7313dd --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch @@ -0,0 +1,437 @@ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h +@@ -1056,6 +1056,11 @@ + #define MIMO_PS_CFG_RX_STBY_POL FIELD32(0x00000010) + #define MIMO_PS_CFG_RX_RX_STBY0 FIELD32(0x00000020) + ++#define BB_PA_MODE_CFG0 0x1214 ++#define BB_PA_MODE_CFG1 0x1218 ++#define RF_PA_MODE_CFG0 0x121C ++#define RF_PA_MODE_CFG1 0x1220 ++ + /* + * EDCA_AC0_CFG: + */ +--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +@@ -3842,14 +3842,16 @@ static void rt2800_config_channel_rf7620 + rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4); + rt2800_rfcsr_write(rt2x00dev, 19, rfcsr); + +- /* Default: XO=20MHz , SDM mode */ +- rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); +- rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 4); +- rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); +- +- rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); +- rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1); +- rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ /* Default: XO=20MHz , SDM mode */ ++ rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); ++ rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 4); ++ rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); ++ ++ rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); ++ rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1); ++ rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); ++ } + + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); + rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620, +@@ -3883,18 +3885,23 @@ static void rt2800_config_channel_rf7620 + rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x20); + } + +- if (conf_is_ht40(conf)) { +- rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08); +- rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08); +- } else { +- rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28); +- rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ if (conf_is_ht40(conf)) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08); ++ } else { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28); ++ } + } + +- rfcsr = rt2800_rfcsr_read(rt2x00dev, 28); +- rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40, +- conf_is_ht40(conf) && (rf->channel == 11)); +- rt2800_rfcsr_write(rt2x00dev, 28, rfcsr); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) == 2) { ++ rfcsr = rt2800_rfcsr_read(rt2x00dev, 28); ++ rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40, ++ conf_is_ht40(conf) && (rf->channel == 11)); ++ rt2800_rfcsr_write(rt2x00dev, 28, rfcsr); ++ } + + if (!test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) { + if (conf_is_ht40(conf)) { +@@ -4008,25 +4015,29 @@ static void rt2800_config_alc_rt6352(str + if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY))) + rt2x00_warn(rt2x00dev, "RF busy while configuring ALC\n"); + +- if (chan->center_freq > 2457) { +- bbp = rt2800_bbp_read(rt2x00dev, 30); +- bbp = 0x40; +- rt2800_bbp_write(rt2x00dev, 30, bbp); +- rt2800_rfcsr_write(rt2x00dev, 39, 0); +- if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) +- rt2800_rfcsr_write(rt2x00dev, 42, 0xfb); +- else +- rt2800_rfcsr_write(rt2x00dev, 42, 0x7b); +- } else { +- bbp = rt2800_bbp_read(rt2x00dev, 30); +- bbp = 0x1f; +- rt2800_bbp_write(rt2x00dev, 30, bbp); +- rt2800_rfcsr_write(rt2x00dev, 39, 0x80); +- if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) +- rt2800_rfcsr_write(rt2x00dev, 42, 0xdb); +- else +- rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) >= 2) { ++ if (chan->center_freq > 2457) { ++ bbp = rt2800_bbp_read(rt2x00dev, 30); ++ bbp = 0x40; ++ rt2800_bbp_write(rt2x00dev, 30, bbp); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0); ++ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) ++ rt2800_rfcsr_write(rt2x00dev, 42, 0xfb); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 42, 0x7b); ++ } else { ++ bbp = rt2800_bbp_read(rt2x00dev, 30); ++ bbp = 0x1f; ++ rt2800_bbp_write(rt2x00dev, 30, bbp); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x80); ++ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) ++ rt2800_rfcsr_write(rt2x00dev, 42, 0xdb); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); ++ } + } ++ + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl); + + rt2800_vco_calibration(rt2x00dev); +@@ -4524,7 +4535,8 @@ static void rt2800_config_channel(struct + if (rt2x00_rt(rt2x00dev, RT6352)) { + /* BBP for GLRT BW */ + bbp = conf_is_ht40(conf) ? +- 0x10 : rt2x00_has_cap_external_lna_bg(rt2x00dev) ? ++ 0x10 : !rt2x00_has_cap_external_lna_bg(rt2x00dev) ? ++ 0x1a : rt2800_hw_get_chippkg(rt2x00dev) == 1 ? + 0x15 : 0x1a; + rt2800_bbp_glrt_write(rt2x00dev, 141, bbp); + +@@ -6042,18 +6054,34 @@ static int rt2800_init_registers(struct + } else if (rt2x00_rt(rt2x00dev, RT5350)) { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); + } else if (rt2x00_rt(rt2x00dev, RT6352)) { +- rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401); +- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0001); +- rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); +- rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000); +- rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0); +- rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0); +- rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, 0x6C6C666C); +- rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, 0x6C6C666C); +- rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT, +- 0x3630363A); +- rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT, +- 0x3630363A); ++ if (rt2800_hw_get_chipver(rt2x00dev) <= 1) { ++ rt2800_register_write(rt2x00dev, TX_ALC_VGA3, ++ 0x00000000); ++ rt2800_register_write(rt2x00dev, BB_PA_MODE_CFG0, ++ 0x000055FF); ++ rt2800_register_write(rt2x00dev, BB_PA_MODE_CFG1, ++ 0x00550055); ++ rt2800_register_write(rt2x00dev, RF_PA_MODE_CFG0, ++ 0x000055FF); ++ rt2800_register_write(rt2x00dev, RF_PA_MODE_CFG1, ++ 0x00550055); ++ } else { ++ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0001); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); ++ rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0x00150f0f); ++ rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x06060606); ++ rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0); ++ rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0); ++ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, ++ 0x6C6C666C); ++ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, ++ 0x6C6C666C); ++ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT, ++ 0x3630363A); ++ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT, ++ 0x3630363A); ++ } + reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1); + rt2x00_set_field32(®, TX_ALC_CFG_1_ROS_BUSY_EN, 0); + rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg); +@@ -7160,14 +7188,16 @@ static void rt2800_init_bbp_6352(struct + rt2800_bbp_write(rt2x00dev, 188, 0x00); + rt2800_bbp_write(rt2x00dev, 189, 0x00); + +- rt2800_bbp_write(rt2x00dev, 91, 0x06); +- rt2800_bbp_write(rt2x00dev, 92, 0x04); +- rt2800_bbp_write(rt2x00dev, 93, 0x54); +- rt2800_bbp_write(rt2x00dev, 99, 0x50); +- rt2800_bbp_write(rt2x00dev, 148, 0x84); +- rt2800_bbp_write(rt2x00dev, 167, 0x80); +- rt2800_bbp_write(rt2x00dev, 178, 0xFF); +- rt2800_bbp_write(rt2x00dev, 106, 0x13); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ rt2800_bbp_write(rt2x00dev, 91, 0x06); ++ rt2800_bbp_write(rt2x00dev, 92, 0x04); ++ rt2800_bbp_write(rt2x00dev, 93, 0x54); ++ rt2800_bbp_write(rt2x00dev, 99, 0x50); ++ rt2800_bbp_write(rt2x00dev, 148, 0x84); ++ rt2800_bbp_write(rt2x00dev, 167, 0x80); ++ rt2800_bbp_write(rt2x00dev, 178, 0xFF); ++ rt2800_bbp_write(rt2x00dev, 106, 0x13); ++ } + + /* BBP for G band GLRT function (BBP_128 ~ BBP_221) */ + rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00); +@@ -10398,6 +10428,9 @@ static void rt2800_restore_rf_bbp_rt6352 + rt2800_register_write(rt2x00dev, RF_BYPASS3, 0x0); + } + ++ if (rt2800_hw_get_chippkg(rt2x00dev) != 1) ++ return; ++ + if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { + rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16); + rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23); +@@ -10479,6 +10512,9 @@ static void rt2800_calibration_rt6352_st + rt2800_register_write(rt2x00dev, RF_BYPASS3, reg); + } + ++ if (rt2800_hw_get_chippkg(rt2x00dev) != 1) ++ return; ++ + if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) { + rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66); + rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20); +@@ -10569,31 +10605,36 @@ static void rt2800_init_rfcsr_6352(struc + rt2800_rfcsr_write(rt2x00dev, 42, 0x5B); + rt2800_rfcsr_write(rt2x00dev, 43, 0x00); + +- rt2800_rfcsr_write(rt2x00dev, 11, 0x21); +- if (rt2800_clk_is_20mhz(rt2x00dev)) +- rt2800_rfcsr_write(rt2x00dev, 13, 0x03); +- else +- rt2800_rfcsr_write(rt2x00dev, 13, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 14, 0x7C); +- rt2800_rfcsr_write(rt2x00dev, 16, 0x80); +- rt2800_rfcsr_write(rt2x00dev, 17, 0x99); +- rt2800_rfcsr_write(rt2x00dev, 18, 0x99); +- rt2800_rfcsr_write(rt2x00dev, 19, 0x09); +- rt2800_rfcsr_write(rt2x00dev, 20, 0x50); +- rt2800_rfcsr_write(rt2x00dev, 21, 0xB0); +- rt2800_rfcsr_write(rt2x00dev, 22, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 23, 0x06); +- rt2800_rfcsr_write(rt2x00dev, 24, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 25, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 26, 0x5D); +- rt2800_rfcsr_write(rt2x00dev, 27, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 28, 0x61); +- rt2800_rfcsr_write(rt2x00dev, 29, 0xB5); +- rt2800_rfcsr_write(rt2x00dev, 43, 0x02); +- +- rt2800_rfcsr_write(rt2x00dev, 28, 0x62); +- rt2800_rfcsr_write(rt2x00dev, 29, 0xAD); +- rt2800_rfcsr_write(rt2x00dev, 39, 0x80); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ rt2800_rfcsr_write(rt2x00dev, 11, 0x21); ++ if (rt2800_clk_is_20mhz(rt2x00dev)) ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x03); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 14, 0x7C); ++ rt2800_rfcsr_write(rt2x00dev, 16, 0x80); ++ rt2800_rfcsr_write(rt2x00dev, 17, 0x99); ++ rt2800_rfcsr_write(rt2x00dev, 18, 0x99); ++ rt2800_rfcsr_write(rt2x00dev, 19, 0x09); ++ rt2800_rfcsr_write(rt2x00dev, 20, 0x50); ++ rt2800_rfcsr_write(rt2x00dev, 21, 0xB0); ++ rt2800_rfcsr_write(rt2x00dev, 22, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 23, 0x06); ++ rt2800_rfcsr_write(rt2x00dev, 24, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 25, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 26, 0x5D); ++ rt2800_rfcsr_write(rt2x00dev, 27, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 28, 0x61); ++ rt2800_rfcsr_write(rt2x00dev, 29, 0xB5); ++ rt2800_rfcsr_write(rt2x00dev, 43, 0x02); ++ } ++ ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) >= 2) { ++ rt2800_rfcsr_write(rt2x00dev, 28, 0x62); ++ rt2800_rfcsr_write(rt2x00dev, 29, 0xAD); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x80); ++ } + + /* Initialize RF channel register to default value */ + rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03); +@@ -10659,63 +10700,71 @@ static void rt2800_init_rfcsr_6352(struc + + rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5); + +- rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27); +- rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67); +- rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF); +- rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27); +- rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27); ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF); ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09); ++ } + +- rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) >= 2) { ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16); ++ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); ++ } + +- rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); +- +- /* Initialize RF channel register for DRQFN */ +- rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7); ++ if (rt2800_hw_get_chippkg(rt2x00dev) == 0 && ++ rt2800_hw_get_chipver(rt2x00dev) == 1) { ++ /* Initialize RF channel register for DRQFN */ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7); ++ } + + /* Initialize RF DC calibration register to default value */ + rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47); +@@ -10778,12 +10827,17 @@ static void rt2800_init_rfcsr_6352(struc + rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00); + rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00); + +- rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08); +- rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04); +- rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20); ++ } + +- rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); +- rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) >= 2) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); ++ } + } + + static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/110-mac80211_keep_keys_on_stop_ap.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/110-mac80211_keep_keys_on_stop_ap.patch new file mode 100644 index 0000000000..f9956ea05c --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/110-mac80211_keep_keys_on_stop_ap.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +Date: Mon, 27 Oct 2014 00:00:00 +0100 +Subject: [PATCH] mac80211: preseve AP mode keys across STA reconnect + +Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnect +--- + net/mac80211/cfg.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1872,12 +1872,6 @@ static int ieee80211_stop_ap(struct wiph + + __sta_info_flush(sdata, true, link_id, NULL); + +- ieee80211_remove_link_keys(link, &keys); +- if (!list_empty(&keys)) { +- synchronize_net(); +- ieee80211_free_key_list(local, &keys); +- } +- + ieee80211_stop_mbssid(sdata); + RCU_INIT_POINTER(link_conf->tx_bss_conf, NULL); + diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/120-cfg80211_allow_perm_addr_change.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/120-cfg80211_allow_perm_addr_change.patch new file mode 100644 index 0000000000..f315ae5ca2 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/120-cfg80211_allow_perm_addr_change.patch @@ -0,0 +1,52 @@ +From: Felix Fietkau +Date: Thu, 11 Dec 2014 00:00:00 +0100 +Subject: [PATCH] cfg80211: add support for changing the device mac address via + sysfs + +--- + net/wireless/sysfs.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +--- a/net/wireless/sysfs.c ++++ b/net/wireless/sysfs.c +@@ -24,18 +24,35 @@ static inline struct cfg80211_registered + return container_of(dev, struct cfg80211_registered_device, wiphy.dev); + } + +-#define SHOW_FMT(name, fmt, member) \ ++#define SHOW_FMT(name, fmt, member, mode) \ + static ssize_t name ## _show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ + } \ +-static DEVICE_ATTR_RO(name) ++static DEVICE_ATTR_##mode(name) + +-SHOW_FMT(index, "%d", wiphy_idx); +-SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); +-SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); ++static ssize_t macaddress_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ if (!mac_pton(buf, mac)) ++ return -EINVAL; ++ ++ if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') ++ return -EINVAL; ++ ++ memcpy(dev_to_rdev(dev)->wiphy.perm_addr, mac, ETH_ALEN); ++ ++ return strnlen(buf, len); ++} ++ ++SHOW_FMT(index, "%d", wiphy_idx, RO); ++SHOW_FMT(macaddress, "%pM", wiphy.perm_addr, RW); ++SHOW_FMT(address_mask, "%pM", wiphy.addr_mask, RO); + + static ssize_t name_show(struct device *dev, + struct device_attribute *attr, diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/130-disable_auto_vif.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/130-disable_auto_vif.patch new file mode 100644 index 0000000000..b08655b174 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/130-disable_auto_vif.patch @@ -0,0 +1,27 @@ +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -1597,24 +1597,6 @@ int ieee80211_register_hw(struct ieee802 + + ieee80211_check_wbrf_support(local); + +- rtnl_lock(); +- wiphy_lock(hw->wiphy); +- +- /* add one default STA interface if supported */ +- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && +- !ieee80211_hw_check(hw, NO_AUTO_VIF)) { +- struct vif_params params = {0}; +- +- result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL, +- NL80211_IFTYPE_STATION, ¶ms); +- if (result) +- wiphy_warn(local->hw.wiphy, +- "Failed to add default virtual iface\n"); +- } +- +- wiphy_unlock(hw->wiphy); +- rtnl_unlock(); +- + #ifdef CONFIG_INET + local->ifa_notifier.notifier_call = ieee80211_ifa_changed; + result = register_inetaddr_notifier(&local->ifa_notifier); diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/210-ap_scan.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/210-ap_scan.patch new file mode 100644 index 0000000000..6289334b56 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/210-ap_scan.patch @@ -0,0 +1,19 @@ +From: Felix Fietkau +Date: Wed, 3 Oct 2012 00:00:00 +0200 +Subject: [PATCH] mac80211: allow scans in access point mode (for site survey) + +--- + net/mac80211/cfg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -3121,6 +3121,8 @@ static int ieee80211_scan(struct wiphy * + */ + fallthrough; + case NL80211_IFTYPE_AP: ++ /* skip check */ ++ break; + /* + * If the scan has been forced (and the driver supports + * forcing), don't care about being beaconing already. diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/220-allow-ibss-mixed.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/220-allow-ibss-mixed.patch new file mode 100644 index 0000000000..6ef7fb2777 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/220-allow-ibss-mixed.patch @@ -0,0 +1,40 @@ +From: Hauke Mehrtens +Date: Mon, 24 Feb 2020 00:00:00 +0100 +Subject: [PATCH] mac80211: Allow IBSS mode and different beacon intervals + +ath10k-ct supports the combination to select IBSS (ADHOC) mode and +different beacon intervals together. mac80211 does not like this +combination, but Ben says this is ok, so remove this check. + +ath10k-ct starting with version 5.2 allows the combination of +NL80211_IFTYPE_ADHOC and beacon_int_min_gcd in ath10k_10x_ct_if_comb +which triggers this warning. Ben told me that this is not a big problem +and we should ignore this. +--- + net/wireless/core.c | 15 --------------- + 1 file changed, 15 deletions(-) + +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -679,21 +679,6 @@ int wiphy_verify_iface_combinations(stru + c->limits[j].max > 1)) + return -EINVAL; + +- /* +- * This isn't well-defined right now. If you have an +- * IBSS interface, then its beacon interval may change +- * by joining other networks, and nothing prevents it +- * from doing that. +- * So technically we probably shouldn't even allow AP +- * and IBSS in the same interface, but it seems that +- * some drivers support that, possibly only with fixed +- * beacon intervals for IBSS. +- */ +- if (WARN_ON(types & BIT(NL80211_IFTYPE_ADHOC) && +- c->beacon_int_min_gcd)) { +- return -EINVAL; +- } +- + cnt += c->limits[j].max; + /* + * Don't advertise an unsupported type diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/230-avoid-crashing-missing-band.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/230-avoid-crashing-missing-band.patch new file mode 100644 index 0000000000..70992c5695 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/230-avoid-crashing-missing-band.patch @@ -0,0 +1,34 @@ +From: David Bauer +Date: Thu, 30 Nov 2023 07:32:52 +0100 +Subject: [PATCH] mac80211: avoid crashing on invalid band info + +Frequent crashes have been observed on MT7916 based platforms. While the +root of these crashes are currently unknown, they happen when decoding +rate information of connected STAs in AP mode. The rate-information is +associated with a band which is not available on the PHY. + +Check for this condition in order to avoid crashing the whole system. +This patch should be removed once the roout cause has been found and +fixed. + +Link: https://github.com/freifunk-gluon/gluon/issues/2980 + +Signed-off-by: David Bauer +--- + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -2526,6 +2526,13 @@ static void sta_stats_decode_rate(struct + + sband = local->hw.wiphy->bands[band]; + ++ if (!sband) { ++ wiphy_warn(local->hw.wiphy, ++ "Invalid band %d\n", ++ band); ++ break; ++ } ++ + if (WARN_ON_ONCE(!sband->bitrates)) + break; + diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch new file mode 100644 index 0000000000..7c840dd809 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/301-mac80211-sta-randomize-BA-session-dialog-token-alloc.patch @@ -0,0 +1,38 @@ +From b478e06a16a8baa00c5ecc87c1d636981f2206d5 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Tue, 29 Oct 2019 10:25:25 +0100 +Subject: [PATCH] mac80211: sta: randomize BA session dialog token allocator + +We currently always start the dialog token generator at zero, +so the first dialog token we use is always 1. This would be +OK if we had a perfect guarantee that we always do a proper +deauth/re-auth handshake, but in IBSS mode this doesn't always +happen properly. + +To make problems with block ack (aggregation) sessions getting +stuck less likely, randomize the dialog token so if we start a +new session but the peer still has old state for us, it can +better detect this. + +This is really just a workaround to make things a bit more +robust than they are now - a better fix would be to do a full +authentication handshake in IBSS mode upon having discovered a +new station, and on the receiver resetting the state (removing +and re-adding the station) on receiving the authentication +packet. + +Signed-off-by: Johannes Berg +--- + net/mac80211/sta_info.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -630,6 +630,7 @@ __sta_info_alloc(struct ieee80211_sub_if + spin_lock_init(&sta->ps_lock); + INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); + wiphy_work_init(&sta->ampdu_mlme.work, ieee80211_ba_session_work); ++ sta->ampdu_mlme.dialog_token_allocator = get_random_u32_below(U8_MAX); + #ifdef CPTCFG_MAC80211_MESH + if (ieee80211_vif_is_mesh(&sdata->vif)) { + sta->mesh = kzalloc(sizeof(*sta->mesh), gfp); diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/302-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/302-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch new file mode 100644 index 0000000000..0d475b7329 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/302-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch @@ -0,0 +1,21 @@ +From: Felix Fietkau +Date: Wed, 28 Apr 2021 21:03:13 +0200 +Subject: [PATCH] mac80211: minstrel_ht: fix MINSTREL_FRAC macro + +Add missing braces to avoid issues with e.g. using additions in the +div expression + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.h ++++ b/net/mac80211/rc80211_minstrel_ht.h +@@ -14,7 +14,7 @@ + + /* scaled fraction values */ + #define MINSTREL_SCALE 12 +-#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) ++#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / (div)) + #define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) + + #define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */ diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch new file mode 100644 index 0000000000..f26477e811 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/303-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch @@ -0,0 +1,30 @@ +From: Felix Fietkau +Date: Sat, 6 Feb 2021 16:08:01 +0100 +Subject: [PATCH] mac80211: minstrel_ht: reduce fluctuations in rate + probability stats + +In some scenarios when there is a lot of fluctuation in packet error rates, +rate switching can be amplified when the statistics get skewed by time slots +with very few tries. +Make the input data to the moving average more smooth by adding the +success/attempts count from the last stats window as well. This has the +advantage of smoothing the data without introducing any extra lag to sampling +rates. +This significantly improves rate stability on a strong test link subjected to +periodic noise bursts generated with a SDR + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -769,7 +769,8 @@ minstrel_ht_calc_rate_stats(struct minst + unsigned int cur_prob; + + if (unlikely(mrs->attempts > 0)) { +- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); ++ cur_prob = MINSTREL_FRAC(mrs->success + mrs->last_success, ++ mrs->attempts + mrs->last_attempts); + minstrel_filter_avg_add(&mrs->prob_avg, + &mrs->prob_avg_1, cur_prob); + mrs->att_hist += mrs->attempts; diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch new file mode 100644 index 0000000000..9b3cc3a664 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/304-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch @@ -0,0 +1,151 @@ +From: Felix Fietkau +Date: Sat, 6 Feb 2021 16:33:14 +0100 +Subject: [PATCH] mac80211: minstrel_ht: rework rate downgrade code and + max_prob rate selection + +The current fallback code for fast rate switching on potentially failing rates +is triggering too often if there is some strong noise on the channel. This can +lead to wild fluctuations in the rate selection. +Additionally, switching down to max_prob_rate can create a significant gap down +in throughput, especially when using only 2 spatial streams, because max_prob_rate +is limited to using fewer streams than the max_tp rates. +In order to improve throughput without reducing reliability too much, use the +rate downgrade code for the max_prob_rate only, and allow the non-downgraded +max_prob_rate to use as many spatial streams as the max_tp rates + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -580,6 +580,14 @@ minstrel_ht_set_best_prob_rate(struct mi + int cur_tp_avg, cur_group, cur_idx; + int max_gpr_group, max_gpr_idx; + int max_gpr_tp_avg, max_gpr_prob; ++ int min_dur; ++ ++ min_dur = max(minstrel_get_duration(mi->max_tp_rate[0]), ++ minstrel_get_duration(mi->max_tp_rate[1])); ++ ++ /* make the rate at least 18% slower than max tp rates */ ++ if (minstrel_get_duration(index) <= min_dur * 19 / 16) ++ return; + + cur_group = MI_RATE_GROUP(index); + cur_idx = MI_RATE_IDX(index); +@@ -601,11 +609,6 @@ minstrel_ht_set_best_prob_rate(struct mi + !minstrel_ht_is_legacy_group(max_tp_group)) + return; + +- /* skip rates faster than max tp rate with lower prob */ +- if (minstrel_get_duration(mi->max_tp_rate[0]) > minstrel_get_duration(index) && +- mrs->prob_avg < max_tp_prob) +- return; +- + max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate); + max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate); + max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; +@@ -663,40 +666,6 @@ minstrel_ht_assign_best_tp_rates(struct + + } + +-/* +- * Try to increase robustness of max_prob rate by decrease number of +- * streams if possible. +- */ +-static inline void +-minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) +-{ +- struct minstrel_mcs_group_data *mg; +- int tmp_max_streams, group, tmp_idx, tmp_prob; +- int tmp_tp = 0; +- +- if (!mi->sta->deflink.ht_cap.ht_supported) +- return; +- +- group = MI_RATE_GROUP(mi->max_tp_rate[0]); +- tmp_max_streams = minstrel_mcs_groups[group].streams; +- for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { +- mg = &mi->groups[group]; +- if (!mi->supported[group] || group == MINSTREL_CCK_GROUP) +- continue; +- +- tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate); +- tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg; +- +- if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) && +- (minstrel_mcs_groups[group].streams < tmp_max_streams)) { +- mi->max_prob_rate = mg->max_group_prob_rate; +- tmp_tp = minstrel_ht_get_tp_avg(mi, group, +- tmp_idx, +- tmp_prob); +- } +- } +-} +- + static u16 + __minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi, + enum minstrel_sample_type type) +@@ -1176,8 +1145,6 @@ minstrel_ht_update_stats(struct minstrel + + mi->max_prob_rate = tmp_max_prob_rate; + +- /* Try to increase robustness of max_prob_rate*/ +- minstrel_ht_prob_rate_reduce_streams(mi); + minstrel_ht_refill_sample_rates(mi); + + #ifdef CPTCFG_MAC80211_DEBUGFS +@@ -1256,7 +1223,7 @@ minstrel_ht_ri_txstat_valid(struct minst + } + + static void +-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) ++minstrel_downgrade_prob_rate(struct minstrel_ht_sta *mi, u16 *idx) + { + int group, orig_group; + +@@ -1271,11 +1238,7 @@ minstrel_downgrade_rate(struct minstrel_ + minstrel_mcs_groups[orig_group].streams) + continue; + +- if (primary) +- *idx = mi->groups[group].max_group_tp_rate[0]; +- else +- *idx = mi->groups[group].max_group_tp_rate[1]; +- break; ++ *idx = mi->groups[group].max_group_prob_rate; + } + } + +@@ -1286,7 +1249,7 @@ minstrel_ht_tx_status(void *priv, struct + struct ieee80211_tx_info *info = st->info; + struct minstrel_ht_sta *mi = priv_sta; + struct ieee80211_tx_rate *ar = info->status.rates; +- struct minstrel_rate_stats *rate, *rate2; ++ struct minstrel_rate_stats *rate; + struct minstrel_priv *mp = priv; + u32 update_interval = mp->update_interval; + bool last, update = false; +@@ -1354,18 +1317,13 @@ minstrel_ht_tx_status(void *priv, struct + /* + * check for sudden death of spatial multiplexing, + * downgrade to a lower number of streams if necessary. ++ * only do this for the max_prob_rate to prevent spurious ++ * rate fluctuations when the link changes suddenly + */ +- rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); ++ rate = minstrel_get_ratestats(mi, mi->max_prob_rate); + if (rate->attempts > 30 && + rate->success < rate->attempts / 4) { +- minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true); +- update = true; +- } +- +- rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]); +- if (rate2->attempts > 30 && +- rate2->success < rate2->attempts / 4) { +- minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false); ++ minstrel_downgrade_prob_rate(mi, &mi->max_prob_rate); + update = true; + } + } diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch new file mode 100644 index 0000000000..e553f11080 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/305-mac80211-increase-quantum-for-airtime-scheduler.patch @@ -0,0 +1,53 @@ +From: Felix Fietkau +Date: Sun, 26 Jun 2022 11:43:25 +0200 +Subject: [PATCH] mac80211: increase quantum for airtime scheduler + +Given the typical AQL budget and queue length, a quantum of 256 with the +default station weight often requires iterating over all queues frequently, +until one of them becomes eligible. +Improve performance by using 8 times station weight as scheduler quantum + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -111,6 +111,8 @@ ieee80211_sta_keep_active(struct sta_inf + return time_before_eq(jiffies, sta->airtime[ac].last_active + HZ / 10); + } + ++#define AIRTIME_QUANTUM_SHIFT 3 ++ + struct ieee80211_bss { + u32 device_ts_beacon, device_ts_presp; + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4086,7 +4086,7 @@ struct ieee80211_txq *ieee80211_next_txq + + if (deficit < 0) + sta->airtime[txqi->txq.ac].deficit += +- sta->airtime_weight; ++ sta->airtime_weight << AIRTIME_QUANTUM_SHIFT; + + if (deficit < 0 || !aql_check) { + list_move_tail(&txqi->schedule_order, +@@ -4231,7 +4231,8 @@ bool ieee80211_txq_may_transmit(struct i + } + sta = container_of(iter->txq.sta, struct sta_info, sta); + if (ieee80211_sta_deficit(sta, ac) < 0) +- sta->airtime[ac].deficit += sta->airtime_weight; ++ sta->airtime[ac].deficit += sta->airtime_weight << ++ AIRTIME_QUANTUM_SHIFT; + list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); + } + +@@ -4239,7 +4240,7 @@ bool ieee80211_txq_may_transmit(struct i + if (sta->airtime[ac].deficit >= 0) + goto out; + +- sta->airtime[ac].deficit += sta->airtime_weight; ++ sta->airtime[ac].deficit += sta->airtime_weight << AIRTIME_QUANTUM_SHIFT; + list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]); + spin_unlock_bh(&local->active_txq_lock[ac]); + diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/310-cfg80211-allow-grace-period-for-DFS-available-after-.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/310-cfg80211-allow-grace-period-for-DFS-available-after-.patch new file mode 100644 index 0000000000..01fe5dd7df --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/310-cfg80211-allow-grace-period-for-DFS-available-after-.patch @@ -0,0 +1,153 @@ +From: Felix Fietkau +Date: Thu, 14 Sep 2023 13:17:16 +0200 +Subject: [PATCH] cfg80211: allow grace period for DFS available after beacon + shutdown + +Fixes reconfiguring an AP on a DFS channel in non-ETSI regdomain + +Fixes: b35a51c7dd25 ("cfg80211: Make pre-CAC results valid only for ETSI domain") +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -187,6 +187,8 @@ enum ieee80211_channel_flags { + * @dfs_state: current state of this channel. Only relevant if radar is required + * on this channel. + * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered. ++ * @dfs_state_last_available: timestamp (jiffies) of the last time when the ++ * channel was available. + * @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels. + * @psd: power spectral density (in dBm) + */ +@@ -204,6 +206,7 @@ struct ieee80211_channel { + int orig_mag, orig_mpwr; + enum nl80211_dfs_state dfs_state; + unsigned long dfs_state_entered; ++ unsigned long dfs_state_last_available; + unsigned int dfs_cac_ms; + s8 psd; + }; +--- a/net/wireless/ap.c ++++ b/net/wireless/ap.c +@@ -30,6 +30,9 @@ static int ___cfg80211_stop_ap(struct cf + if (!wdev->links[link_id].ap.beacon_interval) + return -ENOENT; + ++ cfg80211_update_last_available(wdev->wiphy, ++ &wdev->links[link_id].ap.chandef); ++ + err = rdev_stop_ap(rdev, dev, link_id); + if (!err) { + wdev->conn_owner_nlportid = 0; +@@ -41,9 +44,6 @@ static int ___cfg80211_stop_ap(struct cf + if (notify) + nl80211_send_ap_stopped(wdev, link_id); + +- /* Should we apply the grace period during beaconing interface +- * shutdown also? +- */ + cfg80211_sched_dfs_chan_update(rdev); + } + +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -639,6 +639,8 @@ void cfg80211_set_dfs_state(struct wiphy + + c->dfs_state = dfs_state; + c->dfs_state_entered = jiffies; ++ if (dfs_state == NL80211_DFS_AVAILABLE) ++ c->dfs_state_last_available = jiffies; + } + } + +@@ -990,6 +992,53 @@ bool cfg80211_any_wiphy_oper_chan(struct + return false; + } + ++static void ++__cfg80211_update_last_available(struct wiphy *wiphy, ++ u32 center_freq, ++ u32 bandwidth) ++{ ++ struct ieee80211_channel *c; ++ u32 freq, start_freq, end_freq; ++ ++ if (bandwidth <= MHZ_TO_KHZ(20)) ++ start_freq = end_freq = center_freq; ++ else { ++ start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10); ++ end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10); ++ } ++ ++ /* ++ * Check entire range of channels for the bandwidth. ++ * If any channel in between is disabled or has not ++ * had gone through CAC return false ++ */ ++ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) { ++ c = ieee80211_get_channel_khz(wiphy, freq); ++ if (!c) ++ return; ++ ++ c->dfs_state_last_available = jiffies; ++ } ++} ++ ++void cfg80211_update_last_available(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef) ++{ ++ int width; ++ ++ width = cfg80211_chandef_get_width(chandef); ++ if (width < 0) ++ return; ++ ++ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq1), ++ width); ++ if (chandef->width != NL80211_CHAN_WIDTH_80P80) ++ return; ++ ++ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq2), ++ width); ++} ++ + static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy, + const struct cfg80211_chan_def *chandef) + { +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -481,6 +481,8 @@ void cfg80211_set_dfs_state(struct wiphy + enum nl80211_dfs_state dfs_state); + + void cfg80211_dfs_channels_update_work(struct work_struct *work); ++void cfg80211_update_last_available(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef); + + void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); + +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -1056,6 +1056,8 @@ void cfg80211_dfs_channels_update_work(s + if (c->dfs_state == NL80211_DFS_UNAVAILABLE) { + time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS; + radar_event = NL80211_RADAR_NOP_FINISHED; ++ timeout = c->dfs_state_entered + ++ msecs_to_jiffies(time_dfs_update); + } else { + if (regulatory_pre_cac_allowed(wiphy) || + cfg80211_any_wiphy_oper_chan(wiphy, c)) +@@ -1063,11 +1065,10 @@ void cfg80211_dfs_channels_update_work(s + + time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS; + radar_event = NL80211_RADAR_PRE_CAC_EXPIRED; ++ timeout = c->dfs_state_last_available + ++ msecs_to_jiffies(time_dfs_update); + } + +- timeout = c->dfs_state_entered + +- msecs_to_jiffies(time_dfs_update); +- + if (time_after_eq(jiffies, timeout)) { + c->dfs_state = NL80211_DFS_USABLE; + c->dfs_state_entered = jiffies; diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/320-mac80211-add-AQL-support-for-broadcast-packets.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/320-mac80211-add-AQL-support-for-broadcast-packets.patch new file mode 100644 index 0000000000..f9e917467d --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/320-mac80211-add-AQL-support-for-broadcast-packets.patch @@ -0,0 +1,293 @@ +From: Felix Fietkau +Date: Fri, 9 Feb 2024 19:43:40 +0100 +Subject: [PATCH] mac80211: add AQL support for broadcast packets + +Excessive broadcast traffic with little competing unicast traffic can easily +flood hardware queues, leading to throughput issues. Additionally, filling +the hardware queues with too many packets breaks FQ for broadcast data. +Fix this by enabling AQL for broadcast packets. + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -3604,6 +3604,7 @@ enum wiphy_params_flags { + /* The per TXQ device queue limit in airtime */ + #define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000 + #define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000 ++#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_BC 50000 + + /* The per interface airtime threshold to switch to lower queue limit */ + #define IEEE80211_AQL_THRESHOLD 24000 +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -213,11 +213,13 @@ static ssize_t aql_pending_read(struct f + "VI %u us\n" + "BE %u us\n" + "BK %u us\n" ++ "BC/MC %u us\n" + "total %u us\n", + atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]), + atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]), + atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]), + atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]), ++ atomic_read(&local->aql_bc_pending_airtime), + atomic_read(&local->aql_total_pending_airtime)); + return simple_read_from_buffer(user_buf, count, ppos, + buf, len); +@@ -243,7 +245,8 @@ static ssize_t aql_txq_limit_read(struct + "VO %u %u\n" + "VI %u %u\n" + "BE %u %u\n" +- "BK %u %u\n", ++ "BK %u %u\n" ++ "BC/MC %u\n", + local->aql_txq_limit_low[IEEE80211_AC_VO], + local->aql_txq_limit_high[IEEE80211_AC_VO], + local->aql_txq_limit_low[IEEE80211_AC_VI], +@@ -251,7 +254,8 @@ static ssize_t aql_txq_limit_read(struct + local->aql_txq_limit_low[IEEE80211_AC_BE], + local->aql_txq_limit_high[IEEE80211_AC_BE], + local->aql_txq_limit_low[IEEE80211_AC_BK], +- local->aql_txq_limit_high[IEEE80211_AC_BK]); ++ local->aql_txq_limit_high[IEEE80211_AC_BK], ++ local->aql_txq_limit_bc); + return simple_read_from_buffer(user_buf, count, ppos, + buf, len); + } +@@ -277,6 +281,11 @@ static ssize_t aql_txq_limit_write(struc + else + buf[count] = '\0'; + ++ if (sscanf(buf, "mcast %u", &q_limit_low) == 1) { ++ local->aql_txq_limit_bc = q_limit_low; ++ return count; ++ } ++ + if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3) + return -EINVAL; + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1428,10 +1428,12 @@ struct ieee80211_local { + spinlock_t handle_wake_tx_queue_lock; + + u16 airtime_flags; ++ u32 aql_txq_limit_bc; + u32 aql_txq_limit_low[IEEE80211_NUM_ACS]; + u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; + u32 aql_threshold; + atomic_t aql_total_pending_airtime; ++ atomic_t aql_bc_pending_airtime; + atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS]; + + const struct ieee80211_ops *ops; +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -984,6 +984,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ + spin_lock_init(&local->rx_path_lock); + spin_lock_init(&local->queue_stop_reason_lock); + ++ local->aql_txq_limit_bc = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_BC; + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + INIT_LIST_HEAD(&local->active_txqs[i]); + spin_lock_init(&local->active_txq_lock[i]); +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -2431,13 +2431,28 @@ EXPORT_SYMBOL(ieee80211_sta_recalc_aggre + + void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, + struct sta_info *sta, u8 ac, +- u16 tx_airtime, bool tx_completed) ++ u16 tx_airtime, bool tx_completed, ++ bool mcast) + { + int tx_pending; + + if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) + return; + ++ if (mcast) { ++ if (!tx_completed) { ++ atomic_add(tx_airtime, &local->aql_bc_pending_airtime); ++ return; ++ } ++ ++ tx_pending = atomic_sub_return(tx_airtime, ++ &local->aql_bc_pending_airtime); ++ if (tx_pending < 0) ++ atomic_cmpxchg(&local->aql_bc_pending_airtime, ++ tx_pending, 0); ++ return; ++ } ++ + if (!tx_completed) { + if (sta) + atomic_add(tx_airtime, +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -2556,7 +2556,7 @@ static u16 ieee80211_store_ack_skb(struc + + spin_lock_irqsave(&local->ack_status_lock, flags); + id = idr_alloc(&local->ack_status_frames, ack_skb, +- 1, 0x2000, GFP_ATOMIC); ++ 1, 0x1000, GFP_ATOMIC); + spin_unlock_irqrestore(&local->ack_status_lock, flags); + + if (id >= 0) { +@@ -3987,20 +3987,20 @@ begin: + encap_out: + info->control.vif = vif; + +- if (tx.sta && +- wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { +- bool ampdu = txq->ac != IEEE80211_AC_VO; ++ if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { ++ bool ampdu = txq->sta && txq->ac != IEEE80211_AC_VO; + u32 airtime; + + airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta, + skb->len, ampdu); +- if (airtime) { +- airtime = ieee80211_info_set_tx_time_est(info, airtime); +- ieee80211_sta_update_pending_airtime(local, tx.sta, +- txq->ac, +- airtime, +- false); +- } ++ if (!airtime) ++ return skb; ++ ++ airtime = ieee80211_info_set_tx_time_est(info, airtime); ++ info->tx_time_mc = !tx.sta; ++ ieee80211_sta_update_pending_airtime(local, tx.sta, txq->ac, ++ airtime, false, ++ info->tx_time_mc); + } + + return skb; +@@ -4052,6 +4052,7 @@ struct ieee80211_txq *ieee80211_next_txq + struct ieee80211_txq *ret = NULL; + struct txq_info *txqi = NULL, *head = NULL; + bool found_eligible_txq = false; ++ bool aql_check; + + spin_lock_bh(&local->active_txq_lock[ac]); + +@@ -4075,26 +4076,26 @@ struct ieee80211_txq *ieee80211_next_txq + if (!head) + head = txqi; + ++ aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); ++ if (aql_check) ++ found_eligible_txq = true; ++ + if (txqi->txq.sta) { + struct sta_info *sta = container_of(txqi->txq.sta, + struct sta_info, sta); +- bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); +- s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac); +- +- if (aql_check) +- found_eligible_txq = true; +- +- if (deficit < 0) ++ if (ieee80211_sta_deficit(sta, txqi->txq.ac) < 0) { + sta->airtime[txqi->txq.ac].deficit += + sta->airtime_weight << AIRTIME_QUANTUM_SHIFT; +- +- if (deficit < 0 || !aql_check) { +- list_move_tail(&txqi->schedule_order, +- &local->active_txqs[txqi->txq.ac]); +- goto begin; ++ aql_check = false; + } + } + ++ if (!aql_check) { ++ list_move_tail(&txqi->schedule_order, ++ &local->active_txqs[txqi->txq.ac]); ++ goto begin; ++ } ++ + if (txqi->schedule_round == local->schedule_round[ac]) + goto out; + +@@ -4161,7 +4162,8 @@ bool ieee80211_txq_airtime_check(struct + return true; + + if (!txq->sta) +- return true; ++ return atomic_read(&local->aql_bc_pending_airtime) < ++ local->aql_txq_limit_bc; + + if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) + return true; +@@ -4210,15 +4212,15 @@ bool ieee80211_txq_may_transmit(struct i + + spin_lock_bh(&local->active_txq_lock[ac]); + +- if (!txqi->txq.sta) +- goto out; +- + if (list_empty(&txqi->schedule_order)) + goto out; + + if (!ieee80211_txq_schedule_airtime_check(local, ac)) + goto out; + ++ if (!txqi->txq.sta) ++ goto out; ++ + list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], + schedule_order) { + if (iter == txqi) +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1249,8 +1249,8 @@ struct ieee80211_tx_info { + status_data_idr:1, + status_data:13, + hw_queue:4, ++ tx_time_mc:1, + tx_time_est:10; +- /* 1 free bit */ + + union { + struct { +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -147,7 +147,8 @@ struct airtime_info { + + void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, + struct sta_info *sta, u8 ac, +- u16 tx_airtime, bool tx_completed); ++ u16 tx_airtime, bool tx_completed, ++ bool mcast); + + struct sta_info; + +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -751,7 +751,7 @@ static void ieee80211_report_used_skb(st + ieee80211_sta_update_pending_airtime(local, sta, + skb_get_queue_mapping(skb), + tx_time_est, +- true); ++ true, info->tx_time_mc); + rcu_read_unlock(); + } + +@@ -1160,10 +1160,11 @@ void ieee80211_tx_status_ext(struct ieee + /* Do this here to avoid the expensive lookup of the sta + * in ieee80211_report_used_skb(). + */ ++ bool mcast = IEEE80211_SKB_CB(skb)->tx_time_mc; + ieee80211_sta_update_pending_airtime(local, sta, + skb_get_queue_mapping(skb), + tx_time_est, +- true); ++ true, mcast); + ieee80211_info_set_tx_time_est(IEEE80211_SKB_CB(skb), 0); + } + diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/330-mac80211-fix-crash-in-ieee80211_chan_bw_change-for-A.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/330-mac80211-fix-crash-in-ieee80211_chan_bw_change-for-A.patch new file mode 100644 index 0000000000..6693829ba2 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/330-mac80211-fix-crash-in-ieee80211_chan_bw_change-for-A.patch @@ -0,0 +1,39 @@ +From: Felix Fietkau +Date: Thu, 5 Mar 2026 17:04:11 +0000 +Subject: [PATCH] mac80211: fix crash in ieee80211_chan_bw_change for AP_VLAN + stations + +ieee80211_chan_bw_change() iterates all stations and accesses +link->reserved.oper via sta->sdata->link[link_id]. For stations on +AP_VLAN interfaces (e.g. 4addr WDS clients), sta->sdata points to +the VLAN sdata, whose link never participates in chanctx reservations. +This leaves link->reserved.oper zero-initialized with chan == NULL, +causing a NULL pointer dereference in __ieee80211_sta_cap_rx_bw() +when accessing chandef->chan->band during CSA. + +Resolve the VLAN sdata to its parent AP sdata using get_bss_sdata() +before accessing link data. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/chan.c ++++ b/net/mac80211/chan.c +@@ -441,13 +441,15 @@ static void ieee80211_chan_bw_change(str + rcu_read_lock(); + list_for_each_entry_rcu(sta, &local->sta_list, + list) { +- struct ieee80211_sub_if_data *sdata = sta->sdata; ++ struct ieee80211_sub_if_data *sdata; + enum ieee80211_sta_rx_bandwidth new_sta_bw; + unsigned int link_id; + + if (!ieee80211_sdata_running(sta->sdata)) + continue; + ++ sdata = get_bss_sdata(sta->sdata); ++ + for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) { + struct ieee80211_link_data *link = + rcu_dereference(sdata->link[link_id]); diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/350-mac80211-allow-scanning-while-on-radar-channel.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/350-mac80211-allow-scanning-while-on-radar-channel.patch new file mode 100644 index 0000000000..9e934f24ff --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/350-mac80211-allow-scanning-while-on-radar-channel.patch @@ -0,0 +1,399 @@ +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -3815,6 +3815,27 @@ static bool ieee80211_is_scan_ongoing(st + return false; + } + ++bool ieee80211_scanning_busy(struct ieee80211_local *local, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct cfg80211_scan_request *scan_req; ++ struct wiphy *wiphy = local->hw.wiphy; ++ u32 mask; ++ ++ if (!ieee80211_is_scan_ongoing(wiphy, local, chandef)) ++ return false; ++ ++ if (!wiphy->n_radio) ++ return true; ++ ++ mask = ieee80211_offchannel_radio_mask(local); ++ scan_req = wiphy_dereference(wiphy, local->scan_req); ++ if (scan_req) ++ mask |= ieee80211_scan_req_radio_mask(local, scan_req); ++ ++ return mask & ieee80211_chandef_radio_mask(local, chandef); ++} ++ + static int ieee80211_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, +@@ -3828,7 +3849,7 @@ static int ieee80211_start_radar_detecti + + lockdep_assert_wiphy(local->hw.wiphy); + +- if (ieee80211_is_scan_ongoing(wiphy, local, chandef)) ++ if (ieee80211_scanning_busy(local, chandef)) + return -EBUSY; + + link_data = sdata_dereference(sdata->link[link_id], sdata); +@@ -4320,7 +4341,7 @@ __ieee80211_channel_switch(struct wiphy + + lockdep_assert_wiphy(local->hw.wiphy); + +- if (ieee80211_is_scan_ongoing(wiphy, local, ¶ms->chandef)) ++ if (ieee80211_scanning_busy(local, ¶ms->chandef)) + return -EBUSY; + + if (sdata->wdev.links[link_id].cac_started) +--- a/net/mac80211/chan.c ++++ b/net/mac80211/chan.c +@@ -646,10 +646,11 @@ ieee80211_find_chanctx(struct ieee80211_ + return NULL; + } + +-bool ieee80211_is_radar_required(struct ieee80211_local *local, ++bool ieee80211_is_radar_required(struct ieee80211_local *local, u32 radio_mask, + struct cfg80211_scan_request *req) + { + struct wiphy *wiphy = local->hw.wiphy; ++ struct ieee80211_chanctx_conf *conf; + struct ieee80211_link_data *link; + struct ieee80211_channel *chan; + int radio_idx; +@@ -660,14 +661,25 @@ bool ieee80211_is_radar_required(struct + return false; + + for_each_sdata_link(local, link) { +- if (link->radar_required) { +- chan = link->conf->chanreq.oper.chan; +- radio_idx = cfg80211_get_radio_idx_by_chan(wiphy, chan); +- +- if (ieee80211_is_radio_idx_in_scan_req(wiphy, req, +- radio_idx)) +- return true; +- } ++ if (!link->radar_required) ++ continue; ++ ++ chan = link->conf->chanreq.oper.chan; ++ radio_idx = cfg80211_get_radio_idx_by_chan(wiphy, chan); ++ ++ if (ieee80211_is_radio_idx_in_scan_req(wiphy, req, ++ radio_idx)) ++ return true; ++ ++ if (!local->hw.wiphy->n_radio) ++ return true; ++ ++ conf = wiphy_dereference(local->hw.wiphy, link->conf->chanctx_conf); ++ if (!conf) ++ continue; ++ ++ if (conf->radio_idx >= 0 && (radio_mask & BIT(conf->radio_idx))) ++ return true; + } + + return false; +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2022,6 +2022,13 @@ int ieee80211_mesh_finish_csa(struct iee + u64 *changed); + + /* scan/BSS handling */ ++u32 ieee80211_scan_req_radio_mask(struct ieee80211_local *local, ++ struct cfg80211_scan_request *req); ++bool ieee80211_scanning_busy(struct ieee80211_local *local, ++ struct cfg80211_chan_def *chandef); ++u32 ieee80211_can_leave_ch(struct ieee80211_sub_if_data *sdata, ++ struct cfg80211_scan_request *req, ++ u32 radio_mask); + void ieee80211_scan_work(struct wiphy *wiphy, struct wiphy_work *work); + int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, + const u8 *ssid, u8 ssid_len, +@@ -2060,6 +2067,7 @@ void ieee80211_sched_scan_stopped_work(s + /* off-channel/mgmt-tx */ + void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local); + void ieee80211_offchannel_return(struct ieee80211_local *local); ++u32 ieee80211_offchannel_radio_mask(struct ieee80211_local *local); + void ieee80211_roc_setup(struct ieee80211_local *local); + void ieee80211_start_next_roc(struct ieee80211_local *local); + void ieee80211_reconfig_roc(struct ieee80211_local *local); +@@ -2719,6 +2727,8 @@ bool ieee80211_chandef_s1g_oper(struct i + struct cfg80211_chan_def *chandef); + void ieee80211_chandef_downgrade(struct cfg80211_chan_def *chandef, + struct ieee80211_conn_settings *conn); ++u32 ieee80211_chandef_radio_mask(struct ieee80211_local *local, ++ struct cfg80211_chan_def *chandef); + static inline void + ieee80211_chanreq_downgrade(struct ieee80211_chan_req *chanreq, + struct ieee80211_conn_settings *conn) +@@ -2775,7 +2785,7 @@ void ieee80211_recalc_chanctx_min_def(st + struct ieee80211_chanctx *ctx, + struct ieee80211_link_data *rsvd_for, + bool check_reserved); +-bool ieee80211_is_radar_required(struct ieee80211_local *local, ++bool ieee80211_is_radar_required(struct ieee80211_local *local, u32 radio_mask, + struct cfg80211_scan_request *req); + bool ieee80211_is_radio_idx_in_scan_req(struct wiphy *wiphy, + struct cfg80211_scan_request *scan_req, +--- a/net/mac80211/offchannel.c ++++ b/net/mac80211/offchannel.c +@@ -168,6 +168,35 @@ void ieee80211_offchannel_return(struct + false); + } + ++u32 ieee80211_offchannel_radio_mask(struct ieee80211_local *local) ++{ ++ const struct wiphy_radio *radio; ++ struct ieee80211_roc_work *roc; ++ u32 mask = 0; ++ int r; ++ ++ for (r = 0; r < local->hw.wiphy->n_radio; r++) { ++ radio = &local->hw.wiphy->radio[r]; ++ ++ list_for_each_entry(roc, &local->roc_list, list) { ++ struct cfg80211_chan_def chandef = {}; ++ ++ if (!roc->started) ++ continue; ++ ++ cfg80211_chandef_create(&chandef, roc->chan, ++ NL80211_CHAN_NO_HT); ++ if (!cfg80211_radio_chandef_valid(radio, &chandef)) ++ continue; ++ ++ mask |= BIT(r); ++ break; ++ } ++ } ++ ++ return mask; ++} ++ + static void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) + { + /* was never transmitted */ +@@ -566,8 +595,10 @@ static int ieee80211_start_roc_work(stru + enum ieee80211_roc_type type) + { + struct ieee80211_roc_work *roc, *tmp; ++ struct cfg80211_chan_def chandef = {}; + bool queued = false, combine_started = true; + struct cfg80211_scan_request *req; ++ u32 radio_mask; + int ret; + + lockdep_assert_wiphy(local->hw.wiphy); +@@ -579,6 +610,12 @@ static int ieee80211_start_roc_work(stru + if (!local->emulate_chanctx && !local->ops->remain_on_channel) + return -EOPNOTSUPP; + ++ cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); ++ radio_mask = ieee80211_chandef_radio_mask(local, &chandef); ++ if (!ieee80211_can_leave_ch(sdata, req, radio_mask) && ++ !ieee80211_scanning_busy(local, &chandef)) ++ return -EBUSY; ++ + roc = kzalloc(sizeof(*roc), GFP_KERNEL); + if (!roc) + return -ENOMEM; +@@ -616,8 +653,7 @@ static int ieee80211_start_roc_work(stru + req = wiphy_dereference(local->hw.wiphy, local->scan_req); + + /* if there's no need to queue, handle it immediately */ +- if (list_empty(&local->roc_list) && +- !local->scanning && !ieee80211_is_radar_required(local, req)) { ++ if (list_empty(&local->roc_list) && !local->scanning) { + /* if not HW assist, just queue & schedule work */ + if (!local->ops->remain_on_channel) { + list_add_tail(&roc->list, &local->roc_list); +--- a/net/mac80211/scan.c ++++ b/net/mac80211/scan.c +@@ -586,25 +586,72 @@ static int ieee80211_start_sw_scan(struc + return 0; + } + +-static bool __ieee80211_can_leave_ch(struct ieee80211_sub_if_data *sdata, +- struct cfg80211_scan_request *req) ++u32 ieee80211_scan_req_radio_mask(struct ieee80211_local *local, ++ struct cfg80211_scan_request *req) ++{ ++ const struct wiphy_radio *radio; ++ u32 mask = 0; ++ int i, r; ++ ++ for (r = 0; r < local->hw.wiphy->n_radio; r++) { ++ radio = &local->hw.wiphy->radio[r]; ++ ++ for (i = 0; i < req->n_channels; i++) { ++ struct cfg80211_chan_def chandef = {}; ++ ++ chandef.chan = req->channels[i]; ++ cfg80211_chandef_create(&chandef, req->channels[i], ++ NL80211_CHAN_NO_HT); ++ if (!cfg80211_radio_chandef_valid(radio, &chandef)) ++ continue; ++ ++ mask |= BIT(r); ++ break; ++ } ++ } ++ ++ return mask; ++} ++ ++u32 ieee80211_can_leave_ch(struct ieee80211_sub_if_data *sdata, ++ struct cfg80211_scan_request *req, ++ u32 radio_mask) + { + struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *sdata_iter; ++ struct wiphy *wiphy = local->hw.wiphy; ++ struct ieee80211_chanctx_conf *conf; ++ struct ieee80211_link_data *link; + unsigned int link_id; + + lockdep_assert_wiphy(local->hw.wiphy); + +- if (!ieee80211_is_radar_required(local, req)) ++ if (!ieee80211_is_radar_required(local, radio_mask, req)) + return true; + + if (!regulatory_pre_cac_allowed(local->hw.wiphy)) + return false; + + list_for_each_entry(sdata_iter, &local->interfaces, list) { +- for_each_valid_link(&sdata_iter->wdev, link_id) +- if (sdata_iter->wdev.links[link_id].cac_started) ++ for_each_valid_link(&sdata_iter->wdev, link_id) { ++ if (!sdata_iter->wdev.links[link_id].cac_started) ++ continue; ++ ++ if (!wiphy->n_radio) ++ return false; ++ ++ link = sdata_dereference(sdata->link[link_id], sdata); ++ if (!link) ++ continue; ++ ++ conf = wiphy_dereference(wiphy, link->conf->chanctx_conf); ++ if (!conf) ++ continue; ++ ++ if (conf->radio_idx >= 0 && ++ (radio_mask & BIT(conf->radio_idx))) + return false; ++ } + } + + return true; +@@ -612,12 +659,12 @@ static bool __ieee80211_can_leave_ch(str + + static bool ieee80211_can_scan(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, +- struct cfg80211_scan_request *req) ++ struct cfg80211_scan_request *req, ++ u32 radio_mask) + { +- if (!__ieee80211_can_leave_ch(sdata, req)) +- return false; +- +- if (!list_empty(&local->roc_list)) ++ if (!list_empty(&local->roc_list) && ++ (!local->hw.wiphy->n_radio || ++ (radio_mask & ieee80211_offchannel_radio_mask(local)))) + return false; + + if (sdata->vif.type == NL80211_IFTYPE_STATION && +@@ -629,19 +676,22 @@ static bool ieee80211_can_scan(struct ie + + void ieee80211_run_deferred_scan(struct ieee80211_local *local) + { ++ struct ieee80211_sub_if_data *sdata; + struct cfg80211_scan_request *req; ++ u32 radio_mask; + + lockdep_assert_wiphy(local->hw.wiphy); + +- if (!local->scan_req || local->scanning) ++ req = wiphy_dereference(local->hw.wiphy, local->scan_req); ++ if (!req || local->scanning) + return; + +- req = wiphy_dereference(local->hw.wiphy, local->scan_req); +- if (!ieee80211_can_scan(local, +- rcu_dereference_protected( +- local->scan_sdata, +- lockdep_is_held(&local->hw.wiphy->mtx)), +- req)) ++ radio_mask = ieee80211_scan_req_radio_mask(local, req); ++ sdata = wiphy_dereference(local->hw.wiphy, local->scan_sdata); ++ if (!ieee80211_can_leave_ch(sdata, req, radio_mask)) ++ return; ++ ++ if (!ieee80211_can_scan(local, sdata, req, radio_mask)) + return; + + wiphy_delayed_work_queue(local->hw.wiphy, &local->scan_work, +@@ -724,6 +774,7 @@ static int __ieee80211_start_scan(struct + { + struct ieee80211_local *local = sdata->local; + bool hw_scan = local->ops->hw_scan; ++ u32 radio_mask; + int rc; + + lockdep_assert_wiphy(local->hw.wiphy); +@@ -738,10 +789,11 @@ static int __ieee80211_start_scan(struct + !(sdata->vif.active_links & BIT(req->tsf_report_link_id))) + return -EINVAL; + +- if (!__ieee80211_can_leave_ch(sdata, req)) ++ radio_mask = ieee80211_scan_req_radio_mask(local, req); ++ if (!ieee80211_can_leave_ch(sdata, req, radio_mask)) + return -EBUSY; + +- if (!ieee80211_can_scan(local, sdata, req)) { ++ if (!ieee80211_can_scan(local, sdata, req, radio_mask)) { + /* wait for the work to finish/time out */ + rcu_assign_pointer(local->scan_req, req); + rcu_assign_pointer(local->scan_sdata, sdata); +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -877,6 +877,23 @@ struct wireless_dev *ieee80211_vif_to_wd + } + EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev); + ++u32 ieee80211_chandef_radio_mask(struct ieee80211_local *local, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct wiphy *wiphy = local->hw.wiphy; ++ const struct wiphy_radio *radio; ++ u32 mask = 0; ++ int i; ++ ++ for (i = 0; i < wiphy->n_radio; i++) { ++ radio = &wiphy->radio[i]; ++ if (cfg80211_radio_chandef_valid(radio, chandef)) ++ mask |= BIT(i); ++ } ++ ++ return mask; ++} ++ + /* + * Nothing should have been stuffed into the workqueue during + * the suspend->resume cycle. Since we can't check each caller +--- a/net/wireless/util.c ++++ b/net/wireless/util.c +@@ -2943,6 +2943,9 @@ bool cfg80211_radio_chandef_valid(const + { + u32 freq, width; + ++ if (!cfg80211_chandef_valid(chandef)) ++ return false; ++ + freq = ieee80211_chandef_to_khz(chandef); + width = MHZ_TO_KHZ(cfg80211_chandef_get_width(chandef)); + if (!ieee80211_radio_freq_range_valid(radio, freq, width)) diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/360-mac80211-factor-out-part-of-ieee80211_calc_expected_.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/360-mac80211-factor-out-part-of-ieee80211_calc_expected_.patch new file mode 100644 index 0000000000..15ec47a078 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/360-mac80211-factor-out-part-of-ieee80211_calc_expected_.patch @@ -0,0 +1,140 @@ +From: Felix Fietkau +Date: Wed, 6 Aug 2025 10:49:54 +0200 +Subject: [PATCH] mac80211: factor out part of + ieee80211_calc_expected_tx_airtime + +Create ieee80211_rate_expected_tx_airtime helper function, which returns +the expected tx airtime for a given rate and packet length in units of +1024 usec, for more accuracy. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/airtime.c ++++ b/net/mac80211/airtime.c +@@ -685,7 +685,7 @@ static int ieee80211_fill_rx_status(stru + if (ieee80211_fill_rate_info(hw, stat, band, ri)) + return 0; + +- if (!ieee80211_rate_valid(rate)) ++ if (!rate || !ieee80211_rate_valid(rate)) + return -1; + + if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) +@@ -753,6 +753,53 @@ u32 ieee80211_calc_tx_airtime(struct iee + } + EXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime); + ++u32 ieee80211_rate_expected_tx_airtime(struct ieee80211_hw *hw, ++ struct ieee80211_tx_rate *tx_rate, ++ struct rate_info *ri, ++ enum nl80211_band band, ++ bool ampdu, int len) ++{ ++ struct ieee80211_rx_status stat; ++ u32 duration, overhead; ++ u8 agg_shift; ++ ++ if (ieee80211_fill_rx_status(&stat, hw, tx_rate, ri, band, len)) ++ return 0; ++ ++ if (stat.encoding == RX_ENC_LEGACY || !ampdu) ++ return ieee80211_calc_rx_airtime(hw, &stat, len) * 1024; ++ ++ duration = ieee80211_get_rate_duration(hw, &stat, &overhead); ++ ++ /* ++ * Assume that HT/VHT transmission on any AC except VO will ++ * use aggregation. Since we don't have reliable reporting ++ * of aggregation length, assume an average size based on the ++ * tx rate. ++ * This will not be very accurate, but much better than simply ++ * assuming un-aggregated tx in all cases. ++ */ ++ if (duration > 400 * 1024) /* <= VHT20 MCS2 1S */ ++ agg_shift = 1; ++ else if (duration > 250 * 1024) /* <= VHT20 MCS3 1S or MCS1 2S */ ++ agg_shift = 2; ++ else if (duration > 150 * 1024) /* <= VHT20 MCS5 1S or MCS2 2S */ ++ agg_shift = 3; ++ else if (duration > 70 * 1024) /* <= VHT20 MCS5 2S */ ++ agg_shift = 4; ++ else if (stat.encoding != RX_ENC_HE || ++ duration > 20 * 1024) /* <= HE40 MCS6 2S */ ++ agg_shift = 5; ++ else ++ agg_shift = 6; ++ ++ duration *= len; ++ duration /= AVG_PKT_SIZE; ++ duration += (overhead * 1024 >> agg_shift); ++ ++ return duration; ++} ++ + u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *pubsta, +@@ -775,45 +822,13 @@ u32 ieee80211_calc_expected_tx_airtime(s + if (pubsta) { + struct sta_info *sta = container_of(pubsta, struct sta_info, + sta); +- struct ieee80211_rx_status stat; + struct ieee80211_tx_rate *tx_rate = &sta->deflink.tx_stats.last_rate; + struct rate_info *ri = &sta->deflink.tx_stats.last_rate_info; +- u32 duration, overhead; +- u8 agg_shift; +- +- if (ieee80211_fill_rx_status(&stat, hw, tx_rate, ri, band, len)) +- return 0; +- +- if (stat.encoding == RX_ENC_LEGACY || !ampdu) +- return ieee80211_calc_rx_airtime(hw, &stat, len); +- +- duration = ieee80211_get_rate_duration(hw, &stat, &overhead); +- /* +- * Assume that HT/VHT transmission on any AC except VO will +- * use aggregation. Since we don't have reliable reporting +- * of aggregation length, assume an average size based on the +- * tx rate. +- * This will not be very accurate, but much better than simply +- * assuming un-aggregated tx in all cases. +- */ +- if (duration > 400 * 1024) /* <= VHT20 MCS2 1S */ +- agg_shift = 1; +- else if (duration > 250 * 1024) /* <= VHT20 MCS3 1S or MCS1 2S */ +- agg_shift = 2; +- else if (duration > 150 * 1024) /* <= VHT20 MCS5 1S or MCS2 2S */ +- agg_shift = 3; +- else if (duration > 70 * 1024) /* <= VHT20 MCS5 2S */ +- agg_shift = 4; +- else if (stat.encoding != RX_ENC_HE || +- duration > 20 * 1024) /* <= HE40 MCS6 2S */ +- agg_shift = 5; +- else +- agg_shift = 6; ++ u32 duration; + +- duration *= len; +- duration /= AVG_PKT_SIZE; ++ duration = ieee80211_rate_expected_tx_airtime(hw, tx_rate, ri, ++ band, true, len); + duration /= 1024; +- duration += (overhead >> agg_shift); + + return max_t(u32, duration, 4); + } +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2839,6 +2839,11 @@ u8 *ieee80211_get_bssid(struct ieee80211 + + extern const struct ethtool_ops ieee80211_ethtool_ops; + ++u32 ieee80211_rate_expected_tx_airtime(struct ieee80211_hw *hw, ++ struct ieee80211_tx_rate *tx_rate, ++ struct rate_info *ri, ++ enum nl80211_band band, ++ bool ampdu, int len); + u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *pubsta, diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/361-mac80211-estimate-expected-throughput-if-not-provide.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/361-mac80211-estimate-expected-throughput-if-not-provide.patch new file mode 100644 index 0000000000..bbda2ecdff --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/361-mac80211-estimate-expected-throughput-if-not-provide.patch @@ -0,0 +1,53 @@ +From: Felix Fietkau +Date: Wed, 6 Aug 2025 10:52:03 +0200 +Subject: [PATCH] mac80211: estimate expected throughput if not provided by + driver/rc + +Estimate the tx throughput based on the expected per-packet tx time. +This is useful for mesh implementations that rely on expected throughput, +e.g. 802.11s or batman-adv. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -2977,6 +2977,29 @@ static void sta_set_link_sinfo(struct st + } + } + ++static u32 sta_estimate_expected_throughput(struct sta_info *sta, ++ struct station_info *sinfo) ++{ ++ struct ieee80211_sub_if_data *sdata = sta->sdata; ++ struct ieee80211_local *local = sdata->local; ++ struct rate_info *ri = &sinfo->txrate; ++ struct ieee80211_hw *hw = &local->hw; ++ struct ieee80211_chanctx_conf *conf; ++ u32 duration; ++ u8 band = 0; ++ ++ conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); ++ if (conf) ++ band = conf->def.chan->band; ++ ++ duration = ieee80211_rate_expected_tx_airtime(hw, NULL, ri, band, true, 1024); ++ duration += duration >> 4; /* add assumed packet error rate of ~6% */ ++ if (!duration) ++ return 0; ++ ++ return ((1024 * USEC_PER_SEC) / duration) * 8; ++} ++ + void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, + bool tidstats) + { +@@ -3201,6 +3224,8 @@ void sta_set_sinfo(struct sta_info *sta, + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); + + thr = sta_get_expected_throughput(sta); ++ if (!thr && (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE))) ++ thr = sta_estimate_expected_throughput(sta, sinfo); + + if (thr != 0) { + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT); diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/370-wifi-mac80211-add-MLO-support-to-ieee80211_probe_cli.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/370-wifi-mac80211-add-MLO-support-to-ieee80211_probe_cli.patch new file mode 100644 index 0000000000..f6538694c4 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/370-wifi-mac80211-add-MLO-support-to-ieee80211_probe_cli.patch @@ -0,0 +1,64 @@ +From: Felix Fietkau +Date: Thu, 28 Aug 2025 14:41:57 +0200 +Subject: [PATCH] wifi: mac80211: add MLO support to ieee80211_probe_client + +Use the first available link to probe the client. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4584,7 +4584,9 @@ static int ieee80211_probe_client(struct + struct ieee80211_tx_info *info; + struct sta_info *sta; + struct ieee80211_chanctx_conf *chanctx_conf; ++ struct ieee80211_bss_conf *link_conf; + enum nl80211_band band; ++ u8 link_id; + int ret; + + /* the lock is needed to assign the cookie later */ +@@ -4599,7 +4601,23 @@ static int ieee80211_probe_client(struct + + qos = sta->sta.wme; + +- chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); ++ if (ieee80211_vif_is_mld(&sdata->vif)) { ++ if (sta->sta.valid_links) ++ link_id = ffs(sta->sta.valid_links) - 1; ++ else ++ link_id = sta->deflink.link_id; ++ ++ link_conf = rcu_dereference(sdata->vif.link_conf[link_id]); ++ if (unlikely(!link_conf)) { ++ ret = -ENOLINK; ++ goto unlock; ++ } ++ } else { ++ link_id = IEEE80211_LINK_UNSPECIFIED; ++ link_conf = &sdata->vif.bss_conf; ++ } ++ ++ chanctx_conf = rcu_dereference(link_conf->chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + ret = -EINVAL; + goto unlock; +@@ -4631,14 +4649,15 @@ static int ieee80211_probe_client(struct + nullfunc->frame_control = fc; + nullfunc->duration_id = 0; + memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); +- memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); +- memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN); ++ memcpy(nullfunc->addr2, link_conf->addr, ETH_ALEN); ++ memcpy(nullfunc->addr3, link_conf->addr, ETH_ALEN); + nullfunc->seq_ctrl = 0; + + info = IEEE80211_SKB_CB(skb); + + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_INTFL_NL80211_FRAME_TX; ++ info->control.flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); + info->band = band; + + skb_set_queue_mapping(skb, IEEE80211_AC_VO); diff --git a/lede/package/kernel/mac80211/patches-6.18/subsys/371-wifi-mac80211-Add-eMLSR-eMLMR-action-frame-parsing-s.patch b/lede/package/kernel/mac80211/patches-6.18/subsys/371-wifi-mac80211-Add-eMLSR-eMLMR-action-frame-parsing-s.patch new file mode 100644 index 0000000000..c20ed61a62 --- /dev/null +++ b/lede/package/kernel/mac80211/patches-6.18/subsys/371-wifi-mac80211-Add-eMLSR-eMLMR-action-frame-parsing-s.patch @@ -0,0 +1,412 @@ +From: Lorenzo Bianconi +Date: Thu, 29 Jan 2026 14:15:46 +0100 +Subject: [PATCH] wifi: mac80211: Add eMLSR/eMLMR action frame parsing support + +Introduce support in AP mode for parsing of the Operating Mode Notification +frame sent by the client to enable/disable MLO eMLSR or eMLMR if supported +by both the AP and the client. +Add drv_set_eml_op_mode mac80211 callback in order to configure underlay +driver with eMLSR/eMLMR info. + +Tested-by: Christian Marangi +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20260129-mac80211-emlsr-v4-1-14bdadf57380@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -1612,6 +1612,12 @@ struct ieee80211_mgmt { + u8 action_code; + u8 variable[]; + } __packed epcs; ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u8 control; ++ u8 variable[]; ++ } __packed eml_omn; + } u; + } __packed action; + DECLARE_FLEX_ARRAY(u8, body); /* Generic frame body */ +@@ -5462,6 +5468,17 @@ struct ieee80211_mle_tdls_common_info { + + /* no fixed fields in PRIO_ACCESS */ + ++#define IEEE80211_EML_CTRL_EMLSR_MODE BIT(0) ++#define IEEE80211_EML_CTRL_EMLMR_MODE BIT(1) ++#define IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE BIT(2) ++#define IEEE80211_EML_CTRL_INDEV_COEX_ACT BIT(3) ++ ++#define IEEE80211_EML_EMLSR_PAD_DELAY 0x07 ++#define IEEE80211_EML_EMLSR_TRANS_DELAY 0x38 ++ ++#define IEEE80211_EML_EMLMR_RX_MCS_MAP 0xf0 ++#define IEEE80211_EML_EMLMR_TX_MCS_MAP 0x0f ++ + /** + * ieee80211_mle_common_size - check multi-link element common size + * @data: multi-link element, must already be checked for size using +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1901,6 +1901,31 @@ enum ieee80211_offload_flags { + }; + + /** ++ * struct ieee80211_eml_params - EHT Operating mode notification parameters ++ * ++ * EML Operating mode notification parameters received in the Operating mode ++ * notification frame. This struct is used as a container to pass the info to ++ * the underlay driver. ++ * ++ * @link_id: the link ID where the Operating mode notification frame has been ++ * received. ++ * @control: EML control field defined in P802.11be section 9.4.1.76. ++ * @link_bitmap: eMLSR/eMLMR enabled links defined in P802.11be ++ * section 9.4.1.76. ++ * @emlmr_mcs_map_count: eMLMR number of valid mcs_map_bw fields according to ++ * P802.11be section 9.4.1.76 (valid if eMLMR mode control bit is set). ++ * @emlmr_mcs_map_bw: eMLMR supported MCS and NSS set subfileds defined in ++ * P802.11be section 9.4.1.76 (valid if eMLMR mode control bit is set). ++ */ ++struct ieee80211_eml_params { ++ u8 link_id; ++ u8 control; ++ u16 link_bitmap; ++ u8 emlmr_mcs_map_count; ++ u8 emlmr_mcs_map_bw[9]; ++}; ++ ++/** + * struct ieee80211_vif_cfg - interface configuration + * @assoc: association status + * @ibss_joined: indicates whether this station is part of an IBSS or not +@@ -4509,6 +4534,9 @@ struct ieee80211_prep_tx_info { + * interface with the specified type would be added, and thus drivers that + * implement this callback need to handle such cases. The type is the full + * &enum nl80211_iftype. ++ * @set_eml_op_mode: Configure eMLSR/eMLMR operation mode in the underlay ++ * driver according to the parameter received in the EML Operating mode ++ * notification frame. + */ + struct ieee80211_ops { + void (*tx)(struct ieee80211_hw *hw, +@@ -4904,6 +4932,10 @@ struct ieee80211_ops { + struct ieee80211_neg_ttlm *ttlm); + void (*prep_add_interface)(struct ieee80211_hw *hw, + enum nl80211_iftype type); ++ int (*set_eml_op_mode)(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++ struct ieee80211_eml_params *eml_params); + }; + + /** +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -1772,4 +1772,25 @@ drv_prep_add_interface(struct ieee80211_ + trace_drv_return_void(local); + } + ++static inline int drv_set_eml_op_mode(struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, ++ struct ieee80211_eml_params *eml_params) ++{ ++ struct ieee80211_local *local = sdata->local; ++ int ret = -EOPNOTSUPP; ++ ++ might_sleep(); ++ lockdep_assert_wiphy(local->hw.wiphy); ++ ++ trace_drv_set_eml_op_mode(local, sdata, sta, eml_params->link_id, ++ eml_params->control, ++ eml_params->link_bitmap); ++ if (local->ops->set_eml_op_mode) ++ ret = local->ops->set_eml_op_mode(&local->hw, &sdata->vif, ++ sta, eml_params); ++ trace_drv_return_int(local, ret); ++ ++ return ret; ++} ++ + #endif /* __MAC80211_DRIVER_OPS */ +--- a/net/mac80211/eht.c ++++ b/net/mac80211/eht.c +@@ -5,6 +5,7 @@ + * Copyright(c) 2021-2025 Intel Corporation + */ + ++#include "driver-ops.h" + #include "ieee80211_i.h" + + void +@@ -102,3 +103,177 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(stru + + ieee80211_sta_recalc_aggregates(&link_sta->sta->sta); + } ++ ++static void ++ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_mgmt *req, int opt_len) ++{ ++ int len = offsetofend(struct ieee80211_mgmt, u.action.u.eml_omn); ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_mgmt *mgmt; ++ struct sk_buff *skb; ++ ++ len += opt_len; /* optional len */ ++ skb = dev_alloc_skb(local->tx_headroom + len); ++ if (!skb) ++ return; ++ ++ skb_reserve(skb, local->tx_headroom); ++ mgmt = skb_put_zero(skb, len); ++ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | ++ IEEE80211_STYPE_ACTION); ++ memcpy(mgmt->da, req->sa, ETH_ALEN); ++ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); ++ memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); ++ ++ mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT; ++ mgmt->u.action.u.eml_omn.action_code = ++ WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF; ++ mgmt->u.action.u.eml_omn.dialog_token = ++ req->u.action.u.eml_omn.dialog_token; ++ mgmt->u.action.u.eml_omn.control = req->u.action.u.eml_omn.control & ++ ~(IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE | ++ IEEE80211_EML_CTRL_INDEV_COEX_ACT); ++ /* Copy optional fields from the received notification frame */ ++ memcpy(mgmt->u.action.u.eml_omn.variable, ++ req->u.action.u.eml_omn.variable, opt_len); ++ ++ ieee80211_tx_skb(sdata, skb); ++} ++ ++void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb) ++{ ++ int len = offsetofend(struct ieee80211_mgmt, u.action.u.eml_omn); ++ enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif); ++ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); ++ const struct wiphy_iftype_ext_capab *ift_ext_capa; ++ struct ieee80211_mgmt *mgmt = (void *)skb->data; ++ struct ieee80211_local *local = sdata->local; ++ u8 control = mgmt->u.action.u.eml_omn.control; ++ u8 *ptr = mgmt->u.action.u.eml_omn.variable; ++ struct ieee80211_eml_params eml_params = { ++ .link_id = status->link_id, ++ }; ++ struct sta_info *sta; ++ int opt_len = 0; ++ ++ if (!ieee80211_vif_is_mld(&sdata->vif)) ++ return; ++ ++ /* eMLSR and eMLMR can't be enabled at the same time */ ++ if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) && ++ (control & IEEE80211_EML_CTRL_EMLMR_MODE)) ++ return; ++ ++ if ((control & IEEE80211_EML_CTRL_EMLMR_MODE) && ++ (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE)) ++ return; ++ ++ ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type); ++ if (!ift_ext_capa) ++ return; ++ ++ if (!status->link_valid) ++ return; ++ ++ sta = sta_info_get_bss(sdata, mgmt->sa); ++ if (!sta) ++ return; ++ ++ if (control & IEEE80211_EML_CTRL_EMLSR_MODE) { ++ u8 emlsr_param_update_len; ++ ++ if (!(ift_ext_capa->eml_capabilities & ++ IEEE80211_EML_CAP_EMLSR_SUPP)) ++ return; ++ ++ opt_len += sizeof(__le16); /* eMLSR link_bitmap */ ++ /* eMLSR param update field is not part of Notfication frame ++ * sent by the AP to client so account it separately. ++ */ ++ emlsr_param_update_len = ++ !!(control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE); ++ ++ if (skb->len < len + opt_len + emlsr_param_update_len) ++ return; ++ ++ if (control & IEEE80211_EML_CTRL_EMLSR_PARAM_UPDATE) { ++ u8 pad_delay, trans_delay; ++ ++ pad_delay = u8_get_bits(ptr[2], ++ IEEE80211_EML_EMLSR_PAD_DELAY); ++ if (pad_delay > ++ IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US) ++ return; ++ ++ trans_delay = u8_get_bits(ptr[2], ++ IEEE80211_EML_EMLSR_TRANS_DELAY); ++ if (trans_delay > ++ IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US) ++ return; ++ ++ /* Update sta padding and transition delay */ ++ sta->sta.eml_cap = ++ u8_replace_bits(sta->sta.eml_cap, ++ pad_delay, ++ IEEE80211_EML_CAP_EMLSR_PADDING_DELAY); ++ sta->sta.eml_cap = ++ u8_replace_bits(sta->sta.eml_cap, ++ trans_delay, ++ IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY); ++ } ++ } ++ ++ if (control & IEEE80211_EML_CTRL_EMLMR_MODE) { ++ u8 mcs_map_size; ++ int i; ++ ++ if (!(ift_ext_capa->eml_capabilities & ++ IEEE80211_EML_CAP_EMLMR_SUPPORT)) ++ return; ++ ++ opt_len += sizeof(__le16); /* eMLMR link_bitmap */ ++ opt_len++; /* eMLMR mcs_map_count */ ++ if (skb->len < len + opt_len) ++ return; ++ ++ eml_params.emlmr_mcs_map_count = ptr[2]; ++ if (eml_params.emlmr_mcs_map_count > 2) ++ return; ++ ++ mcs_map_size = 3 * (1 + eml_params.emlmr_mcs_map_count); ++ opt_len += mcs_map_size; ++ if (skb->len < len + opt_len) ++ return; ++ ++ for (i = 0; i < mcs_map_size; i++) { ++ u8 rx_mcs, tx_mcs; ++ ++ rx_mcs = u8_get_bits(ptr[3 + i], ++ IEEE80211_EML_EMLMR_RX_MCS_MAP); ++ if (rx_mcs > 8) ++ return; ++ ++ tx_mcs = u8_get_bits(ptr[3 + i], ++ IEEE80211_EML_EMLMR_TX_MCS_MAP); ++ if (tx_mcs > 8) ++ return; ++ } ++ ++ memcpy(eml_params.emlmr_mcs_map_bw, &ptr[3], mcs_map_size); ++ } ++ ++ if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) || ++ (control & IEEE80211_EML_CTRL_EMLMR_MODE)) { ++ eml_params.link_bitmap = get_unaligned_le16(ptr); ++ if ((eml_params.link_bitmap & sdata->vif.active_links) != ++ eml_params.link_bitmap) ++ return; ++ } ++ ++ if (drv_set_eml_op_mode(sdata, &sta->sta, &eml_params)) ++ return; ++ ++ ieee80211_send_eml_op_mode_notif(sdata, mgmt, opt_len); ++} +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2859,6 +2859,8 @@ void ieee80211_destroy_frag_cache(struct + + u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata); + ++void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb); + void + ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -1630,7 +1630,15 @@ static void ieee80211_iface_process_skb( + } + } else if (ieee80211_is_action(mgmt->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_EHT) { +- if (sdata->vif.type == NL80211_IFTYPE_STATION) { ++ if (sdata->vif.type == NL80211_IFTYPE_AP) { ++ switch (mgmt->u.action.u.eml_omn.action_code) { ++ case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF: ++ ieee80211_rx_eml_op_mode_notif(sdata, skb); ++ break; ++ default: ++ break; ++ } ++ } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { + switch (mgmt->u.action.u.ttlm_req.action_code) { + case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ: + ieee80211_process_neg_ttlm_req(sdata, mgmt, +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -3834,6 +3834,14 @@ ieee80211_rx_h_action(struct ieee80211_r + u.action.u.epcs)) + goto invalid; + goto queue; ++ case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF: ++ if (sdata->vif.type != NL80211_IFTYPE_AP) ++ break; ++ ++ if (len < offsetofend(typeof(*mgmt), ++ u.action.u.eml_omn)) ++ goto invalid; ++ goto queue; + default: + break; + } +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -3359,6 +3359,38 @@ TRACE_EVENT(drv_prep_add_interface, + ) + ); + ++TRACE_EVENT(drv_set_eml_op_mode, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, ++ unsigned int link_id, ++ u8 control, u16 link_bitmap), ++ ++ TP_ARGS(local, sdata, sta, link_id, control, link_bitmap), ++ ++ TP_STRUCT__entry(LOCAL_ENTRY ++ VIF_ENTRY ++ STA_ENTRY ++ __field(u32, link_id) ++ __field(u8, control) ++ __field(u16, link_bitmap)), ++ ++ TP_fast_assign(LOCAL_ASSIGN; ++ VIF_ASSIGN; ++ STA_NAMED_ASSIGN(sta); ++ __entry->link_id = link_id; ++ __entry->control = control; ++ __entry->link_bitmap = link_bitmap; ++ ), ++ ++ TP_printk( ++ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT ++ " (link:%d control:%02x link_bitmap:%04x)", ++ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->link_id, ++ __entry->control, __entry->link_bitmap ++ ) ++); ++ + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH +--- /dev/null ++++ b/include/linux/ieee80211-eht.h +@@ -0,0 +1 @@ ++#include diff --git a/lede/package/kernel/mt76/Makefile b/lede/package/kernel/mt76/Makefile index 6e65cf500a..b693436910 100644 --- a/lede/package/kernel/mt76/Makefile +++ b/lede/package/kernel/mt76/Makefile @@ -22,6 +22,11 @@ else ifdef CONFIG_LINUX_5_15 PKG_SOURCE_DATE:=2023-09-18 PKG_SOURCE_VERSION:=2afc7285f75dca5a0583fd917285bf33f1429cc6 PKG_MIRROR_HASH:=2c9556b298246277ac2d65415e4449f98e6d5fdb99e0d0a92262f162df772bbc +else ifdef CONFIG_LINUX_6_12 +PKG_SOURCE_DATE:=2026-03-19 +PKG_SOURCE_VERSION:=39c960c3ada558b4c2e7915772483d3731573d09 +PKG_MIRROR_HASH:=73762d5c977cd7fb6dab8304c393e79cf7497930928a4871f85803ed6a86a03e +PATCH_DIR:=./patches-6.18 else PKG_SOURCE_DATE:=2024-10-14 PKG_SOURCE_VERSION:=8dfead68c20251fccb39113ee864fbbafc5b7f76 @@ -341,6 +346,12 @@ define KernelPackage/mt7996e AUTOLOAD:=$(call AutoProbe,mt7996e) endef +define KernelPackage/mt7990-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7990 firmware + DEPENDS+=+kmod-mt7996e +endef + define KernelPackage/mt7992-firmware $(KernelPackage/mt76-default) TITLE:=MediaTek MT7992 firmware @@ -512,6 +523,12 @@ ifdef CONFIG_PACKAGE_kmod-mt7921e endif ifdef CONFIG_PACKAGE_kmod-mt7996e PKG_MAKE_FLAGS += CONFIG_MT7996E=m + ifdef CONFIG_TARGET_airoha_an7581 + PKG_MAKE_FLAGS += CONFIG_MT76_NPU=y + PKG_MAKE_FLAGS += CONFIG_MT7996_NPU=y + NOSTDINC_FLAGS += -DCONFIG_MT76_NPU + NOSTDINC_FLAGS += -DCONFIG_MT7996_NPU + endif endif ifdef CONFIG_PACKAGE_kmod-mt7925-common PKG_MAKE_FLAGS += CONFIG_MT7925_COMMON=m @@ -673,6 +690,16 @@ define KernelPackage/mt7925-firmware/install $(1)/lib/firmware/mediatek/mt7925 endef +define KernelPackage/mt7990-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 + cp \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7990_eeprom.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7990_eeprom_2i5i.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7990_rom_patch.bin \ + $(PKG_BUILD_DIR)/firmware/mt7996/mt7990_wm.bin \ + $(1)/lib/firmware/mediatek/mt7996 +endef + define KernelPackage/mt7992-firmware/install $(INSTALL_DIR) $(1)/lib/firmware/mediatek/mt7996 cp \ @@ -772,6 +799,7 @@ $(eval $(call KernelPackage,mt7921e)) $(eval $(call KernelPackage,mt7925u)) $(eval $(call KernelPackage,mt7925e)) $(eval $(call KernelPackage,mt7996e)) +$(eval $(call KernelPackage,mt7990-firmware)) $(eval $(call KernelPackage,mt7992-firmware)) $(eval $(call KernelPackage,mt7992-23-firmware)) $(eval $(call KernelPackage,mt7996-firmware-common)) diff --git a/lede/target/linux/generic/backport-6.12/731-v6.18-net-mediatek-wed-Introduce-MT7992-WED-support-to-MT7.patch b/lede/target/linux/generic/backport-6.12/731-v6.18-net-mediatek-wed-Introduce-MT7992-WED-support-to-MT7.patch new file mode 100644 index 0000000000..8b1844df67 --- /dev/null +++ b/lede/target/linux/generic/backport-6.12/731-v6.18-net-mediatek-wed-Introduce-MT7992-WED-support-to-MT7.patch @@ -0,0 +1,116 @@ +From: Lorenzo Bianconi +Date: Tue, 12 Aug 2025 06:57:23 +0200 +Subject: [PATCH] net: mediatek: wed: Introduce MT7992 WED support to MT7988 + SoC + +Introduce the second WDMA RX ring in WED driver for MT7988 SoC since the +Mediatek MT7992 WiFi chipset supports two separated WDMA rings. +Add missing MT7988 configurations to properly support WED for MT7992 in +MT76 driver. + +Co-developed-by: Rex Lu +Signed-off-by: Rex Lu +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20250812-mt7992-wed-support-v3-1-9ada78a819a4@kernel.org +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -59,7 +59,9 @@ struct mtk_wed_flow_block_priv { + static const struct mtk_wed_soc_data mt7622_data = { + .regmap = { + .tx_bm_tkid = 0x088, +- .wpdma_rx_ring0 = 0x770, ++ .wpdma_rx_ring = { ++ 0x770, ++ }, + .reset_idx_tx_mask = GENMASK(3, 0), + .reset_idx_rx_mask = GENMASK(17, 16), + }, +@@ -70,7 +72,9 @@ static const struct mtk_wed_soc_data mt7 + static const struct mtk_wed_soc_data mt7986_data = { + .regmap = { + .tx_bm_tkid = 0x0c8, +- .wpdma_rx_ring0 = 0x770, ++ .wpdma_rx_ring = { ++ 0x770, ++ }, + .reset_idx_tx_mask = GENMASK(1, 0), + .reset_idx_rx_mask = GENMASK(7, 6), + }, +@@ -81,7 +85,10 @@ static const struct mtk_wed_soc_data mt7 + static const struct mtk_wed_soc_data mt7988_data = { + .regmap = { + .tx_bm_tkid = 0x0c8, +- .wpdma_rx_ring0 = 0x7d0, ++ .wpdma_rx_ring = { ++ 0x7d0, ++ 0x7d8, ++ }, + .reset_idx_tx_mask = GENMASK(1, 0), + .reset_idx_rx_mask = GENMASK(7, 6), + }, +@@ -621,8 +628,8 @@ mtk_wed_amsdu_init(struct mtk_wed_device + return ret; + } + +- /* eagle E1 PCIE1 tx ring 22 flow control issue */ +- if (dev->wlan.id == 0x7991) ++ /* Kite and Eagle E1 PCIE1 tx ring 22 flow control issue */ ++ if (dev->wlan.id == 0x7991 || dev->wlan.id == 0x7992) + wed_clr(dev, MTK_WED_AMSDU_FIFO, MTK_WED_AMSDU_IS_PRIOR0_RING); + + wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN); +@@ -1239,7 +1246,11 @@ mtk_wed_set_wpdma(struct mtk_wed_device + return; + + wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo); +- wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0, dev->wlan.wpdma_rx); ++ wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[0], ++ dev->wlan.wpdma_rx[0]); ++ if (mtk_wed_is_v3_or_greater(dev->hw)) ++ wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[1], ++ dev->wlan.wpdma_rx[1]); + + if (!dev->wlan.hw_rro) + return; +@@ -2335,6 +2346,16 @@ mtk_wed_start(struct mtk_wed_device *dev + if (!dev->rx_wdma[i].desc) + mtk_wed_wdma_rx_ring_setup(dev, i, 16, false); + ++ if (dev->wlan.hw_rro) { ++ for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) { ++ u32 addr = MTK_WED_RRO_MSDU_PG_CTRL0(i) + ++ MTK_WED_RING_OFS_COUNT; ++ ++ if (!wed_r32(dev, addr)) ++ wed_w32(dev, addr, 1); ++ } ++ } ++ + mtk_wed_hw_init(dev); + mtk_wed_configure_irq(dev, irq_mask); + +--- a/drivers/net/ethernet/mediatek/mtk_wed.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -17,7 +17,7 @@ struct mtk_wed_wo; + struct mtk_wed_soc_data { + struct { + u32 tx_bm_tkid; +- u32 wpdma_rx_ring0; ++ u32 wpdma_rx_ring[MTK_WED_RX_QUEUES]; + u32 reset_idx_tx_mask; + u32 reset_idx_rx_mask; + } regmap; +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -147,7 +147,7 @@ struct mtk_wed_device { + u32 wpdma_tx; + u32 wpdma_txfree; + u32 wpdma_rx_glo; +- u32 wpdma_rx; ++ u32 wpdma_rx[MTK_WED_RX_QUEUES]; + u32 wpdma_rx_rro[MTK_WED_RX_QUEUES]; + u32 wpdma_rx_pg; + diff --git a/lede/target/linux/generic/backport-6.12/732-v6.18-wifi-mt76-wed-use-proper-wed-reference-in-mt76-wed-d.patch b/lede/target/linux/generic/backport-6.12/732-v6.18-wifi-mt76-wed-use-proper-wed-reference-in-mt76-wed-d.patch new file mode 100644 index 0000000000..883de549cd --- /dev/null +++ b/lede/target/linux/generic/backport-6.12/732-v6.18-wifi-mt76-wed-use-proper-wed-reference-in-mt76-wed-d.patch @@ -0,0 +1,79 @@ +From: Lorenzo Bianconi +Date: Wed, 8 Oct 2025 12:41:48 +0200 +Subject: [PATCH] wifi: mt76: wed: use proper wed reference in mt76 wed driver + callabacks + +MT7996 driver can use both wed and wed_hif2 devices to offload traffic +from/to the wireless NIC. In the current codebase we assume to always +use the primary wed device in wed callbacks resulting in the following +crash if the hw runs wed_hif2 (e.g. 6GHz link). + +[ 297.455876] Unable to handle kernel read from unreadable memory at virtual address 000000000000080a +[ 297.464928] Mem abort info: +[ 297.467722] ESR = 0x0000000096000005 +[ 297.471461] EC = 0x25: DABT (current EL), IL = 32 bits +[ 297.476766] SET = 0, FnV = 0 +[ 297.479809] EA = 0, S1PTW = 0 +[ 297.482940] FSC = 0x05: level 1 translation fault +[ 297.487809] Data abort info: +[ 297.490679] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000 +[ 297.496156] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 +[ 297.501196] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 297.506500] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000107480000 +[ 297.512927] [000000000000080a] pgd=08000001097fb003, p4d=08000001097fb003, pud=08000001097fb003, pmd=0000000000000000 +[ 297.523532] Internal error: Oops: 0000000096000005 [#1] SMP +[ 297.715393] CPU: 2 UID: 0 PID: 45 Comm: kworker/u16:2 Tainted: G O 6.12.50 #0 +[ 297.723908] Tainted: [O]=OOT_MODULE +[ 297.727384] Hardware name: Banana Pi BPI-R4 (2x SFP+) (DT) +[ 297.732857] Workqueue: nf_ft_offload_del nf_flow_rule_route_ipv6 [nf_flow_table] +[ 297.740254] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 297.747205] pc : mt76_wed_offload_disable+0x64/0xa0 [mt76] +[ 297.752688] lr : mtk_wed_flow_remove+0x58/0x80 +[ 297.757126] sp : ffffffc080fe3ae0 +[ 297.760430] x29: ffffffc080fe3ae0 x28: ffffffc080fe3be0 x27: 00000000deadbef7 +[ 297.767557] x26: ffffff80c5ebca00 x25: 0000000000000001 x24: ffffff80c85f4c00 +[ 297.774683] x23: ffffff80c1875b78 x22: ffffffc080d42cd0 x21: ffffffc080660018 +[ 297.781809] x20: ffffff80c6a076d0 x19: ffffff80c6a043c8 x18: 0000000000000000 +[ 297.788935] x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000 +[ 297.796060] x14: 0000000000000019 x13: ffffff80c0ad8ec0 x12: 00000000fa83b2da +[ 297.803185] x11: ffffff80c02700c0 x10: ffffff80c0ad8ec0 x9 : ffffff81fef96200 +[ 297.810311] x8 : ffffff80c02700c0 x7 : ffffff80c02700d0 x6 : 0000000000000002 +[ 297.817435] x5 : 0000000000000400 x4 : 0000000000000000 x3 : 0000000000000000 +[ 297.824561] x2 : 0000000000000001 x1 : 0000000000000800 x0 : ffffff80c6a063c8 +[ 297.831686] Call trace: +[ 297.834123] mt76_wed_offload_disable+0x64/0xa0 [mt76] +[ 297.839254] mtk_wed_flow_remove+0x58/0x80 +[ 297.843342] mtk_flow_offload_cmd+0x434/0x574 +[ 297.847689] mtk_wed_setup_tc_block_cb+0x30/0x40 +[ 297.852295] nf_flow_offload_ipv6_hook+0x7f4/0x964 [nf_flow_table] +[ 297.858466] nf_flow_rule_route_ipv6+0x438/0x4a4 [nf_flow_table] +[ 297.864463] process_one_work+0x174/0x300 +[ 297.868465] worker_thread+0x278/0x430 +[ 297.872204] kthread+0xd8/0xdc +[ 297.875251] ret_from_fork+0x10/0x20 +[ 297.878820] Code: 928b5ae0 8b000273 91400a60 f943fa61 (79401421) +[ 297.884901] ---[ end trace 0000000000000000 ]--- + +Fix the issue detecting the proper wed reference to use running wed +callabacks. + +-- Partial backport for data structure change only (rest is in the mt76 package) + +Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support") +Tested-by: Daniel Pawlik +Tested-by: Matteo Croce +Signed-off-by: Lorenzo Bianconi +Link: https://patch.msgid.link/20251008-wed-fixes-v1-1-8f7678583385@kernel.org +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -154,6 +154,7 @@ struct mtk_wed_device { + bool wcid_512; + bool hw_rro; + bool msi; ++ bool hif2; + + u16 token_start; + unsigned int nbuf; diff --git a/lede/target/linux/generic/backport-6.12/733-v6.18-net-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-fo.patch b/lede/target/linux/generic/backport-6.12/733-v6.18-net-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-fo.patch new file mode 100644 index 0000000000..c1bb1b972b --- /dev/null +++ b/lede/target/linux/generic/backport-6.12/733-v6.18-net-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-fo.patch @@ -0,0 +1,50 @@ +From: Rex Lu +Date: Thu, 9 Oct 2025 08:29:34 +0200 +Subject: [PATCH] net: mtk: wed: add dma mask limitation and GFP_DMA32 for + device with more than 4GB DRAM + +Limit tx/rx buffer address to 32-bit address space for board with more +than 4GB DRAM. + +Fixes: 804775dfc2885 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Fixes: 6757d345dd7db ("net: ethernet: mtk_wed: introduce hw_rro support for MT7988") +Tested-by: Daniel Pawlik +Tested-by: Matteo Croce +Signed-off-by: Rex Lu +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -677,7 +677,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_d + void *buf; + int s; + +- page = __dev_alloc_page(GFP_KERNEL); ++ page = __dev_alloc_page(GFP_KERNEL | GFP_DMA32); + if (!page) + return -ENOMEM; + +@@ -800,7 +800,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_we + struct page *page; + int s; + +- page = __dev_alloc_page(GFP_KERNEL); ++ page = __dev_alloc_page(GFP_KERNEL | GFP_DMA32); + if (!page) + return -ENOMEM; + +@@ -2438,6 +2438,10 @@ mtk_wed_attach(struct mtk_wed_device *de + dev->version = hw->version; + dev->hw->pcie_base = mtk_wed_get_pcie_base(dev); + ++ ret = dma_set_mask_and_coherent(hw->dev, DMA_BIT_MASK(32)); ++ if (ret) ++ goto out; ++ + if (hw->eth->dma_dev == hw->eth->dev && + of_dma_is_coherent(hw->eth->dev->of_node)) + mtk_eth_set_dma_device(hw->eth, hw->dev); diff --git a/lede/target/linux/generic/backport-6.12/900-v6.14-driver-core-add-a-faux-bus-for-use-when-a-simple-dev.patch b/lede/target/linux/generic/backport-6.12/900-v6.14-driver-core-add-a-faux-bus-for-use-when-a-simple-dev.patch new file mode 100644 index 0000000000..324d22d6a4 --- /dev/null +++ b/lede/target/linux/generic/backport-6.12/900-v6.14-driver-core-add-a-faux-bus-for-use-when-a-simple-dev.patch @@ -0,0 +1,386 @@ +From 35fa2d88ca9481e5caf533d58b99ca259c63b2fe Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Mon, 10 Feb 2025 13:30:25 +0100 +Subject: [PATCH] driver core: add a faux bus for use when a simple device/bus + is needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Many drivers abuse the platform driver/bus system as it provides a +simple way to create and bind a device to a driver-specific set of +probe/release functions. Instead of doing that, and wasting all of the +memory associated with a platform device, here is a "faux" bus that +can be used instead. + +Reviewed-by: Jonathan Cameron +Reviewed-by: Danilo Krummrich +Reviewed-by: Lyude Paul +Reviewed-by: Thomas Wei?schuh +Reviewed-by: Zijun Hu +Link: https://lore.kernel.org/r/2025021026-atlantic-gibberish-3f0c@gregkh +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/driver-api/infrastructure.rst | 6 + + drivers/base/Makefile | 2 +- + drivers/base/base.h | 1 + + drivers/base/faux.c | 232 ++++++++++++++++++++ + drivers/base/init.c | 1 + + include/linux/device/faux.h | 69 ++++++ + 6 files changed, 310 insertions(+), 1 deletion(-) + create mode 100644 drivers/base/faux.c + create mode 100644 include/linux/device/faux.h + +--- a/Documentation/driver-api/infrastructure.rst ++++ b/Documentation/driver-api/infrastructure.rst +@@ -41,6 +41,12 @@ Device Drivers Base + .. kernel-doc:: drivers/base/class.c + :export: + ++.. kernel-doc:: include/linux/device/faux.h ++ :internal: ++ ++.. kernel-doc:: drivers/base/faux.c ++ :export: ++ + .. kernel-doc:: drivers/base/node.c + :internal: + +--- a/drivers/base/Makefile ++++ b/drivers/base/Makefile +@@ -6,7 +6,7 @@ obj-y := component.o core.o bus.o dd.o + cpu.o firmware.o init.o map.o devres.o \ + attribute_container.o transport_class.o \ + topology.o container.o property.o cacheinfo.o \ +- swnode.o ++ swnode.o faux.o + obj-$(CONFIG_AUXILIARY_BUS) += auxiliary.o + obj-$(CONFIG_DEVTMPFS) += devtmpfs.o + obj-y += power/ +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -138,6 +138,7 @@ int hypervisor_init(void); + static inline int hypervisor_init(void) { return 0; } + #endif + int platform_bus_init(void); ++int faux_bus_init(void); + void cpu_dev_init(void); + void container_dev_init(void); + #ifdef CONFIG_AUXILIARY_BUS +--- /dev/null ++++ b/drivers/base/faux.c +@@ -0,0 +1,232 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2025 Greg Kroah-Hartman ++ * Copyright (c) 2025 The Linux Foundation ++ * ++ * A "simple" faux bus that allows devices to be created and added ++ * automatically to it. This is to be used whenever you need to create a ++ * device that is not associated with any "real" system resources, and do ++ * not want to have to deal with a bus/driver binding logic. It is ++ * intended to be very simple, with only a create and a destroy function ++ * available. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "base.h" ++ ++/* ++ * Internal wrapper structure so we can hold a pointer to the ++ * faux_device_ops for this device. ++ */ ++struct faux_object { ++ struct faux_device faux_dev; ++ const struct faux_device_ops *faux_ops; ++}; ++#define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev) ++ ++static struct device faux_bus_root = { ++ .init_name = "faux", ++}; ++ ++static int faux_match(struct device *dev, const struct device_driver *drv) ++{ ++ /* Match always succeeds, we only have one driver */ ++ return 1; ++} ++ ++static int faux_probe(struct device *dev) ++{ ++ struct faux_object *faux_obj = to_faux_object(dev); ++ struct faux_device *faux_dev = &faux_obj->faux_dev; ++ const struct faux_device_ops *faux_ops = faux_obj->faux_ops; ++ int ret = 0; ++ ++ if (faux_ops && faux_ops->probe) ++ ret = faux_ops->probe(faux_dev); ++ ++ return ret; ++} ++ ++static void faux_remove(struct device *dev) ++{ ++ struct faux_object *faux_obj = to_faux_object(dev); ++ struct faux_device *faux_dev = &faux_obj->faux_dev; ++ const struct faux_device_ops *faux_ops = faux_obj->faux_ops; ++ ++ if (faux_ops && faux_ops->remove) ++ faux_ops->remove(faux_dev); ++} ++ ++static const struct bus_type faux_bus_type = { ++ .name = "faux", ++ .match = faux_match, ++ .probe = faux_probe, ++ .remove = faux_remove, ++}; ++ ++static struct device_driver faux_driver = { ++ .name = "faux_driver", ++ .bus = &faux_bus_type, ++ .probe_type = PROBE_FORCE_SYNCHRONOUS, ++}; ++ ++static void faux_device_release(struct device *dev) ++{ ++ struct faux_object *faux_obj = to_faux_object(dev); ++ ++ kfree(faux_obj); ++} ++ ++/** ++ * faux_device_create_with_groups - Create and register with the driver ++ * core a faux device and populate the device with an initial ++ * set of sysfs attributes. ++ * @name: The name of the device we are adding, must be unique for ++ * all faux devices. ++ * @parent: Pointer to a potential parent struct device. If set to ++ * NULL, the device will be created in the "root" of the faux ++ * device tree in sysfs. ++ * @faux_ops: struct faux_device_ops that the new device will call back ++ * into, can be NULL. ++ * @groups: The set of sysfs attributes that will be created for this ++ * device when it is registered with the driver core. ++ * ++ * Create a new faux device and register it in the driver core properly. ++ * If present, callbacks in @faux_ops will be called with the device that ++ * for the caller to do something with at the proper time given the ++ * device's lifecycle. ++ * ++ * Note, when this function is called, the functions specified in struct ++ * faux_ops can be called before the function returns, so be prepared for ++ * everything to be properly initialized before that point in time. ++ * ++ * Return: ++ * * NULL if an error happened with creating the device ++ * * pointer to a valid struct faux_device that is registered with sysfs ++ */ ++struct faux_device *faux_device_create_with_groups(const char *name, ++ struct device *parent, ++ const struct faux_device_ops *faux_ops, ++ const struct attribute_group **groups) ++{ ++ struct faux_object *faux_obj; ++ struct faux_device *faux_dev; ++ struct device *dev; ++ int ret; ++ ++ faux_obj = kzalloc(sizeof(*faux_obj), GFP_KERNEL); ++ if (!faux_obj) ++ return NULL; ++ ++ /* Save off the callbacks so we can use them in the future */ ++ faux_obj->faux_ops = faux_ops; ++ ++ /* Initialize the device portion and register it with the driver core */ ++ faux_dev = &faux_obj->faux_dev; ++ dev = &faux_dev->dev; ++ ++ device_initialize(dev); ++ dev->release = faux_device_release; ++ if (parent) ++ dev->parent = parent; ++ else ++ dev->parent = &faux_bus_root; ++ dev->bus = &faux_bus_type; ++ dev->groups = groups; ++ dev_set_name(dev, "%s", name); ++ ++ ret = device_add(dev); ++ if (ret) { ++ pr_err("%s: device_add for faux device '%s' failed with %d\n", ++ __func__, name, ret); ++ put_device(dev); ++ return NULL; ++ } ++ ++ return faux_dev; ++} ++EXPORT_SYMBOL_GPL(faux_device_create_with_groups); ++ ++/** ++ * faux_device_create - create and register with the driver core a faux device ++ * @name: The name of the device we are adding, must be unique for all ++ * faux devices. ++ * @parent: Pointer to a potential parent struct device. If set to ++ * NULL, the device will be created in the "root" of the faux ++ * device tree in sysfs. ++ * @faux_ops: struct faux_device_ops that the new device will call back ++ * into, can be NULL. ++ * ++ * Create a new faux device and register it in the driver core properly. ++ * If present, callbacks in @faux_ops will be called with the device that ++ * for the caller to do something with at the proper time given the ++ * device's lifecycle. ++ * ++ * Note, when this function is called, the functions specified in struct ++ * faux_ops can be called before the function returns, so be prepared for ++ * everything to be properly initialized before that point in time. ++ * ++ * Return: ++ * * NULL if an error happened with creating the device ++ * * pointer to a valid struct faux_device that is registered with sysfs ++ */ ++struct faux_device *faux_device_create(const char *name, ++ struct device *parent, ++ const struct faux_device_ops *faux_ops) ++{ ++ return faux_device_create_with_groups(name, parent, faux_ops, NULL); ++} ++EXPORT_SYMBOL_GPL(faux_device_create); ++ ++/** ++ * faux_device_destroy - destroy a faux device ++ * @faux_dev: faux device to destroy ++ * ++ * Unregisters and cleans up a device that was created with a call to ++ * faux_device_create() ++ */ ++void faux_device_destroy(struct faux_device *faux_dev) ++{ ++ struct device *dev = &faux_dev->dev; ++ ++ if (!faux_dev) ++ return; ++ ++ device_del(dev); ++ ++ /* The final put_device() will clean up the memory we allocated for this device. */ ++ put_device(dev); ++} ++EXPORT_SYMBOL_GPL(faux_device_destroy); ++ ++int __init faux_bus_init(void) ++{ ++ int ret; ++ ++ ret = device_register(&faux_bus_root); ++ if (ret) { ++ put_device(&faux_bus_root); ++ return ret; ++ } ++ ++ ret = bus_register(&faux_bus_type); ++ if (ret) ++ goto error_bus; ++ ++ ret = driver_register(&faux_driver); ++ if (ret) ++ goto error_driver; ++ ++ return ret; ++ ++error_driver: ++ bus_unregister(&faux_bus_type); ++ ++error_bus: ++ device_unregister(&faux_bus_root); ++ return ret; ++} +--- a/drivers/base/init.c ++++ b/drivers/base/init.c +@@ -32,6 +32,7 @@ void __init driver_init(void) + /* These are also core pieces, but must come after the + * core core pieces. + */ ++ faux_bus_init(); + of_core_init(); + platform_bus_init(); + auxiliary_bus_init(); +--- /dev/null ++++ b/include/linux/device/faux.h +@@ -0,0 +1,69 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (c) 2025 Greg Kroah-Hartman ++ * Copyright (c) 2025 The Linux Foundation ++ * ++ * A "simple" faux bus that allows devices to be created and added ++ * automatically to it. This is to be used whenever you need to create a ++ * device that is not associated with any "real" system resources, and do ++ * not want to have to deal with a bus/driver binding logic. It is ++ * intended to be very simple, with only a create and a destroy function ++ * available. ++ */ ++#ifndef _FAUX_DEVICE_H_ ++#define _FAUX_DEVICE_H_ ++ ++#include ++#include ++ ++/** ++ * struct faux_device - a "faux" device ++ * @dev: internal struct device of the object ++ * ++ * A simple faux device that can be created/destroyed. To be used when a ++ * driver only needs to have a device to "hang" something off. This can be ++ * used for downloading firmware or other basic tasks. Use this instead of ++ * a struct platform_device if the device has no resources assigned to ++ * it at all. ++ */ ++struct faux_device { ++ struct device dev; ++}; ++#define to_faux_device(x) container_of_const((x), struct faux_device, dev) ++ ++/** ++ * struct faux_device_ops - a set of callbacks for a struct faux_device ++ * @probe: called when a faux device is probed by the driver core ++ * before the device is fully bound to the internal faux bus ++ * code. If probe succeeds, return 0, otherwise return a ++ * negative error number to stop the probe sequence from ++ * succeeding. ++ * @remove: called when a faux device is removed from the system ++ * ++ * Both @probe and @remove are optional, if not needed, set to NULL. ++ */ ++struct faux_device_ops { ++ int (*probe)(struct faux_device *faux_dev); ++ void (*remove)(struct faux_device *faux_dev); ++}; ++ ++struct faux_device *faux_device_create(const char *name, ++ struct device *parent, ++ const struct faux_device_ops *faux_ops); ++struct faux_device *faux_device_create_with_groups(const char *name, ++ struct device *parent, ++ const struct faux_device_ops *faux_ops, ++ const struct attribute_group **groups); ++void faux_device_destroy(struct faux_device *faux_dev); ++ ++static inline void *faux_device_get_drvdata(const struct faux_device *faux_dev) ++{ ++ return dev_get_drvdata(&faux_dev->dev); ++} ++ ++static inline void faux_device_set_drvdata(struct faux_device *faux_dev, void *data) ++{ ++ dev_set_drvdata(&faux_dev->dev, data); ++} ++ ++#endif /* _FAUX_DEVICE_H_ */ diff --git a/lede/target/linux/mediatek/dts/mt7987a-glinet-gl-mt3600be.dts b/lede/target/linux/mediatek/dts/mt7987a-glinet-gl-mt3600be.dts new file mode 100644 index 0000000000..784e134fff --- /dev/null +++ b/lede/target/linux/mediatek/dts/mt7987a-glinet-gl-mt3600be.dts @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (C) 2026 Tianling Shen + */ + +/dts-v1/; +#include +#include + +#include "mt7987a.dtsi" + +/ { + model = "GL.iNet GL-MT3600BE"; + compatible = "glinet,gl-mt3600be", "mediatek,mt7987a", "mediatek,mt7987"; + + aliases { + serial0 = &uart0; + label-mac-device = &gmac0; + led-boot = &led_status_white; + led-failsafe = &led_status_blue; + led-running = &led_status_blue; + led-upgrade = &led_status_blue; + }; + + chosen { + bootargs = "console=ttyS0,115200n1 earlycon=uart8250,mmio32,0x11000000 pci=pcie_bus_perf"; + stdout-path = "serial0:115200n8"; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led_status_blue: led-0 { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&pio 48 GPIO_ACTIVE_LOW>; + }; + + led_status_white: led-1 { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&pio 49 GPIO_ACTIVE_LOW>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + button-mode { + label = "mode"; + linux,code = ; + linux,input-type = ; + gpios = <&pio 3 GPIO_ACTIVE_HIGH>; + debounce-interval = <10>; + }; + + button-reset { + label = "reset"; + linux,code = ; + gpios = <&pio 4 GPIO_ACTIVE_LOW>; + debounce-interval = <10>; + }; + }; + + fan_3p3v: regulator-fan-3p3v { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&pio 6 GPIO_ACTIVE_HIGH>; + regulator-name = "fan"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + usb_vbus: regulator-usb-vbus { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&pio 14 GPIO_ACTIVE_HIGH>; + regulator-name = "usb_vbus"; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; +}; + +&fan { + fan-supply = <&fan_3p3v>; + interrupt-parent = <&pio>; + interrupts = <5 IRQ_TYPE_EDGE_RISING>; + pwms = <&pwm 1 50000 0>; + status = "okay"; +}; + +&gmac0 { + nvmem-cells = <&macaddr_factory_4000 0>; + nvmem-cell-names = "mac-address"; + phy-handle = <&phy7>; + phy-mode = "2500base-x"; + status = "okay"; +}; + +&gmac1 { + nvmem-cells = <&macaddr_factory_4000 1>; + nvmem-cell-names = "mac-address"; + phy-handle = <&phy15>; + phy-mode = "internal"; + status = "okay"; +}; + +&mdio { + reset-delay-us = <10000>; + reset-gpios = <&pio 0 GPIO_ACTIVE_LOW>; + + phy7: phy@7 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <7>; + interrupt-parent = <&pio>; + interrupts = <41 IRQ_TYPE_LEVEL_LOW>; + reset-assert-us = <100000>; + reset-deassert-us = <100000>; + reset-gpios = <&pio 42 GPIO_ACTIVE_LOW>; + }; + + phy15: phy@f { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <15>; + pinctrl-names = "i2p5gbe-led"; + pinctrl-0 = <&i2p5gbe_led0_pins>; + }; +}; + +&pcie0 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_pins>; + reset-gpios = <&pio 38 GPIO_ACTIVE_HIGH>; + status = "okay"; + + pcie@0,0 { + reg = <0x0000 0 0 0 0>; + + mt7990@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + #address-cells = <1>; + #size-cells = <0>; + + device_type = "pci"; + + ieee80211-freq-limit = <2400000 2500000>, + <5170000 5835000>; + + nvmem-cells = <&eeprom_factory_0>; + nvmem-cell-names = "eeprom"; + + band@0 { + reg = <0>; + nvmem-cells = <&macaddr_factory_4006 0>; + nvmem-cell-names = "mac-address"; + }; + + band@1 { + reg = <1>; + nvmem-cells = <&macaddr_factory_4006 1>; + nvmem-cell-names = "mac-address"; + }; + }; + }; +}; + +&pio { + pwm1_pins: pwm1-pins { + mux { + function = "pwm"; + groups = "pwm1_0"; + }; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm1_pins>; + status = "okay"; +}; + +&spi2 { + pinctrl-names = "default"; + pinctrl-0 = <&spi2_flash_pins>; + status = "okay"; + + flash@0 { + compatible = "spi-nand"; + reg = <0>; + + spi-cal-enable; + spi-cal-mode = "read-data"; + spi-cal-datalen = <7>; + spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4e 0x41 0x4e 0x44>; + spi-cal-addrlen = <5>; + spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>; + + spi-max-frequency = <52000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + mediatek,nmbm; + mediatek,bmt-max-ratio = <1>; + mediatek,bmt-max-reserved-blocks = <256>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "BL2"; + reg = <0x0 0x100000>; + read-only; + }; + + partition@100000 { + label = "u-boot-env"; + reg = <0x100000 0x80000>; + }; + + partition@180000 { + label = "Factory"; + reg = <0x180000 0x400000>; + read-only; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + eeprom_factory_0: eeprom@0 { + reg = <0x0 0x1e00>; + }; + + macaddr_factory_4000: macaddr@4000 { + compatible = "mac-base"; + reg = <0x4000 0x6>; + #nvmem-cell-cells = <1>; + }; + + macaddr_factory_4006: macaddr@4006 { + compatible = "mac-base"; + reg = <0x4006 0x6>; + #nvmem-cell-cells = <1>; + }; + }; + }; + + partition@580000 { + label = "FIP"; + reg = <0x580000 0x200000>; + read-only; + }; + + partition@780000 { + label = "log"; + reg = <0x780000 0x40000>; + read-only; + }; + + partition@7c0000 { + label = "CFG"; + reg = <0x7c0000 0x40000>; + read-only; + }; + + partition@800000 { + label = "ubi"; + reg = <0x800000 0x1d800000>; + compatible = "linux,ubi"; + }; + }; + }; +}; + +&ssusb { + vbus-supply = <&usb_vbus>; + status = "okay"; +}; + +&tphyu3port0 { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; diff --git a/lede/target/linux/mediatek/filogic/base-files/etc/board.d/02_network b/lede/target/linux/mediatek/filogic/base-files/etc/board.d/02_network index b67b1d7e98..e50f9949a5 100644 --- a/lede/target/linux/mediatek/filogic/base-files/etc/board.d/02_network +++ b/lede/target/linux/mediatek/filogic/base-files/etc/board.d/02_network @@ -60,6 +60,7 @@ mediatek_setup_interfaces() cudy,tr3000*|\ glinet,gl-mt2500|\ glinet,gl-mt3000|\ + glinet,gl-mt3600be|\ glinet,gl-x3000|\ glinet,gl-xe3000|\ openembed,som7981) diff --git a/lede/target/linux/mediatek/image/filogic.mk b/lede/target/linux/mediatek/image/filogic.mk index 8001c99c3a..55edcd2cb8 100644 --- a/lede/target/linux/mediatek/image/filogic.mk +++ b/lede/target/linux/mediatek/image/filogic.mk @@ -536,6 +536,27 @@ define Device/glinet_gl-mt3000 endef TARGET_DEVICES += glinet_gl-mt3000 +define Device/glinet_gl-mt3600be + DEVICE_VENDOR := GL.iNet + DEVICE_MODEL := GL-MT3600BE + DEVICE_DTS := mt7987a-glinet-gl-mt3600be + DEVICE_DTS_DIR := ../dts + DEVICE_PACKAGES := mt7987-2p5g-phy-firmware kmod-mt7990-firmware \ + kmod-hwmon-pwmfan kmod-usb3 + 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 + KERNEL_IN_UBI := 1 + KERNEL_LOADADDR := 0x40000000 + UBINIZE_OPTS := -E 5 + BLOCKSIZE := 128k + PAGESIZE := 2048 + IMAGE_SIZE := 483328k + IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata +endef +TARGET_DEVICES += glinet_gl-mt3600be + define Device/glinet_gl-mt6000 DEVICE_VENDOR := GL.iNet DEVICE_MODEL := GL-MT6000 diff --git a/mihomo/adapter/outboundgroup/fallback.go b/mihomo/adapter/outboundgroup/fallback.go index 0174a7b944..ef4a74c37f 100644 --- a/mihomo/adapter/outboundgroup/fallback.go +++ b/mihomo/adapter/outboundgroup/fallback.go @@ -19,8 +19,6 @@ type Fallback struct { testUrl string selected string expectedStatus string - Hidden bool - Icon string } func (f *Fallback) Now() string { @@ -90,8 +88,8 @@ func (f *Fallback) MarshalJSON() ([]byte, error) { "testUrl": f.testUrl, "expectedStatus": f.expectedStatus, "fixed": f.selected, - "hidden": f.Hidden, - "icon": f.Icon, + "hidden": f.Hidden(), + "icon": f.Icon(), }) } @@ -163,6 +161,8 @@ func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallba GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.Fallback, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -173,7 +173,5 @@ func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallba disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, } } diff --git a/mihomo/adapter/outboundgroup/groupbase.go b/mihomo/adapter/outboundgroup/groupbase.go index 1a1b3cfd0b..7dd085c033 100644 --- a/mihomo/adapter/outboundgroup/groupbase.go +++ b/mihomo/adapter/outboundgroup/groupbase.go @@ -22,6 +22,8 @@ import ( type GroupBase struct { *outbound.Base + hidden bool + icon string filterRegs []*regexp2.Regexp excludeFilterRegs []*regexp2.Regexp excludeTypeArray []string @@ -30,7 +32,7 @@ type GroupBase struct { failedTimes int failedTime time.Time failedTesting atomic.Bool - TestTimeout int + testTimeout int maxFailedTimes int // for GetProxies @@ -42,6 +44,8 @@ type GroupBase struct { type GroupBaseOption struct { Name string Type C.AdapterType + Hidden bool + Icon string Filter string ExcludeFilter string ExcludeType string @@ -74,17 +78,19 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { gb := &GroupBase{ Base: outbound.NewBase(outbound.BaseOption{Name: opt.Name, Type: opt.Type}), + hidden: opt.Hidden, + icon: opt.Icon, filterRegs: filterRegs, excludeFilterRegs: excludeFilterRegs, excludeTypeArray: excludeTypeArray, providers: opt.Providers, failedTesting: atomic.NewBool(false), - TestTimeout: opt.TestTimeout, + testTimeout: opt.TestTimeout, maxFailedTimes: opt.MaxFailedTimes, } - if gb.TestTimeout == 0 { - gb.TestTimeout = 5000 + if gb.testTimeout == 0 { + gb.testTimeout = 5000 } if gb.maxFailedTimes == 0 { gb.maxFailedTimes = 5 @@ -93,6 +99,14 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { return gb } +func (gb *GroupBase) Hidden() bool { + return gb.hidden +} + +func (gb *GroupBase) Icon() string { + return gb.icon +} + func (gb *GroupBase) Touch() { for _, pd := range gb.providers { pd.Touch() @@ -265,7 +279,7 @@ func (gb *GroupBase) onDialFailed(adapterType C.AdapterType, err error, fn func( log.Debugln("ProxyGroup: %s first failed", gb.Name()) gb.failedTime = time.Now() } else { - if time.Since(gb.failedTime) > time.Duration(gb.TestTimeout)*time.Millisecond { + if time.Since(gb.failedTime) > time.Duration(gb.testTimeout)*time.Millisecond { gb.failedTimes = 0 return } diff --git a/mihomo/adapter/outboundgroup/loadbalance.go b/mihomo/adapter/outboundgroup/loadbalance.go index 19ee38c7de..8d68af3d5b 100644 --- a/mihomo/adapter/outboundgroup/loadbalance.go +++ b/mihomo/adapter/outboundgroup/loadbalance.go @@ -27,8 +27,6 @@ type LoadBalance struct { strategyFn strategyFn testUrl string expectedStatus string - Hidden bool - Icon string } var errStrategy = errors.New("unsupported strategy") @@ -234,8 +232,8 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) { "all": all, "testUrl": lb.testUrl, "expectedStatus": lb.expectedStatus, - "hidden": lb.Hidden, - "icon": lb.Icon, + "hidden": lb.Hidden(), + "icon": lb.Icon(), }) } @@ -267,6 +265,8 @@ func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, stra GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.LoadBalance, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -278,7 +278,5 @@ func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, stra disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, }, nil } diff --git a/mihomo/adapter/outboundgroup/selector.go b/mihomo/adapter/outboundgroup/selector.go index 7bc138fdc7..b0272f6c1a 100644 --- a/mihomo/adapter/outboundgroup/selector.go +++ b/mihomo/adapter/outboundgroup/selector.go @@ -14,8 +14,6 @@ type Selector struct { disableUDP bool selected string testUrl string - Hidden bool - Icon string } // DialContext implements C.ProxyAdapter @@ -68,8 +66,8 @@ func (s *Selector) MarshalJSON() ([]byte, error) { "now": s.Now(), "all": all, "testUrl": url, - "hidden": s.Hidden, - "icon": s.Icon, + "hidden": s.Hidden(), + "icon": s.Icon(), }) } @@ -121,6 +119,8 @@ func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Select GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.Selector, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -131,7 +131,5 @@ func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Select selected: "COMPATIBLE", disableUDP: option.DisableUDP, testUrl: option.URL, - Hidden: option.Hidden, - Icon: option.Icon, } } diff --git a/mihomo/adapter/outboundgroup/urltest.go b/mihomo/adapter/outboundgroup/urltest.go index 49ea12aa0b..640c840c8e 100644 --- a/mihomo/adapter/outboundgroup/urltest.go +++ b/mihomo/adapter/outboundgroup/urltest.go @@ -29,8 +29,6 @@ type URLTest struct { expectedStatus string tolerance uint16 disableUDP bool - Hidden bool - Icon string fastNode C.Proxy fastSingle *singledo.Single[C.Proxy] } @@ -180,8 +178,8 @@ func (u *URLTest) MarshalJSON() ([]byte, error) { "testUrl": u.testUrl, "expectedStatus": u.expectedStatus, "fixed": u.selected, - "hidden": u.Hidden, - "icon": u.Icon, + "hidden": u.Hidden(), + "icon": u.Icon(), }) } @@ -215,6 +213,8 @@ func NewURLTest(option *GroupCommonOption, providers []P.ProxyProvider, options GroupBase: NewGroupBase(GroupBaseOption{ Name: option.Name, Type: C.URLTest, + Hidden: option.Hidden, + Icon: option.Icon, Filter: option.Filter, ExcludeFilter: option.ExcludeFilter, ExcludeType: option.ExcludeType, @@ -226,8 +226,6 @@ func NewURLTest(option *GroupCommonOption, providers []P.ProxyProvider, options disableUDP: option.DisableUDP, testUrl: option.URL, expectedStatus: option.ExpectedStatus, - Hidden: option.Hidden, - Icon: option.Icon, } for _, option := range options { diff --git a/mihomo/adapter/outboundgroup/util.go b/mihomo/adapter/outboundgroup/util.go index d35ea66f15..22d6b1890b 100644 --- a/mihomo/adapter/outboundgroup/util.go +++ b/mihomo/adapter/outboundgroup/util.go @@ -16,6 +16,9 @@ type ProxyGroup interface { Now() string Touch() + Hidden() bool + Icon() string + URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (mp map[string]uint16, err error) } diff --git a/mihomo/go.mod b/mihomo/go.mod index 7e82371848..f1b15792ab 100644 --- a/mihomo/go.mod +++ b/mihomo/go.mod @@ -23,6 +23,7 @@ require ( github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/http v0.1.0 github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 + github.com/metacubex/mhurl v0.1.0 github.com/metacubex/mlkem v0.1.0 github.com/metacubex/quic-go v0.59.1-0.20260213014310-4df8f0de5b56 github.com/metacubex/randv2 v0.2.0 @@ -43,7 +44,6 @@ require ( github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 - github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a github.com/samber/lo v1.53.0 github.com/sirupsen/logrus v1.9.4 github.com/stretchr/testify v1.11.1 @@ -104,6 +104,7 @@ require ( github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect diff --git a/mihomo/go.sum b/mihomo/go.sum index 91b61d786e..e295e21651 100644 --- a/mihomo/go.sum +++ b/mihomo/go.sum @@ -107,6 +107,8 @@ github.com/metacubex/http v0.1.0 h1:Jcy0I9zKjYijSUaksZU34XEe2xNdoFkgUTB7z7K5q0o= github.com/metacubex/http v0.1.0/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604 h1:hJwCVlE3ojViC35MGHB+FBr8TuIf3BUFn2EQ1VIamsI= github.com/metacubex/kcp-go v0.0.0-20260105040817-550693377604/go.mod h1:lpmN3m269b3V5jFCWtffqBLS4U3QQoIid9ugtO+OhVc= +github.com/metacubex/mhurl v0.1.0 h1:ZdW4Zxe3j3uJ89gNytOazHu6kbHn5owutN/VfXOI8GE= +github.com/metacubex/mhurl v0.1.0/go.mod h1:2qpQImCbXoUs6GwJrjuEXKelPyoimsIXr07eNKZdS00= github.com/metacubex/mlkem v0.1.0 h1:wFClitonSFcmipzzQvax75beLQU+D7JuC+VK1RzSL8I= github.com/metacubex/mlkem v0.1.0/go.mod h1:amhaXZVeYNShuy9BILcR7P0gbeo/QLZsnqCdL8U2PDQ= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= diff --git a/mihomo/listener/shadowsocks/utils.go b/mihomo/listener/shadowsocks/utils.go index 5d6a2977ee..6bdddb232b 100644 --- a/mihomo/listener/shadowsocks/utils.go +++ b/mihomo/listener/shadowsocks/utils.go @@ -4,9 +4,10 @@ import ( "bytes" "errors" "net" - "net/url" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/mhurl" ) type packet struct { @@ -48,7 +49,7 @@ func (c *packet) InAddr() net.Addr { } func ParseSSURL(s string) (addr, cipher, password string, err error) { - u, err := url.Parse(s) + u, err := mhurl.Parse(s) // we need multiple hosts url supports if err != nil { return } diff --git a/mihomo/listener/shadowsocks/utils_test.go b/mihomo/listener/shadowsocks/utils_test.go new file mode 100644 index 0000000000..b2b7739f00 --- /dev/null +++ b/mihomo/listener/shadowsocks/utils_test.go @@ -0,0 +1,22 @@ +package shadowsocks + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseSSURL(t *testing.T) { + for _, test := range []struct{ method, passwd, hosts string }{ + {method: "aes-256-gcm", passwd: "password", hosts: ":1000,:2000,:3000"}, + {method: "aes-256-gcm", passwd: "password", hosts: "127.0.0.1:1000,127.0.0.1:2000,127.0.0.1:3000"}, + {method: "aes-256-gcm", passwd: "password", hosts: "[::1]:1000,[::1]:2000,[::1]:3000"}, + } { + addr, cipher, password, err := ParseSSURL(fmt.Sprintf("ss://%s:%s@%s", test.method, test.passwd, test.hosts)) + require.NoError(t, err) + require.Equal(t, test.hosts, addr) + require.Equal(t, test.method, cipher) + require.Equal(t, test.passwd, password) + } +} diff --git a/mihomo/listener/sing_tun/server.go b/mihomo/listener/sing_tun/server.go index e873bff861..0c7778c82d 100644 --- a/mihomo/listener/sing_tun/server.go +++ b/mihomo/listener/sing_tun/server.go @@ -506,8 +506,6 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis } } - //l.openAndroidHotspot(tunOptions) - if !l.options.AutoDetectInterface { resolver.ResetConnection() } diff --git a/mihomo/listener/sing_tun/server_android.go b/mihomo/listener/sing_tun/server_android.go index d8240534ed..f180bd3051 100644 --- a/mihomo/listener/sing_tun/server_android.go +++ b/mihomo/listener/sing_tun/server_android.go @@ -4,7 +4,6 @@ package sing_tun import ( "errors" - "runtime" "sync" "github.com/metacubex/mihomo/component/process" @@ -13,8 +12,6 @@ import ( "github.com/metacubex/mihomo/log" "github.com/metacubex/sing-tun" - "github.com/sagernet/netlink" - "golang.org/x/sys/unix" ) type packageManagerCallback struct{} @@ -78,25 +75,3 @@ func init() { process.DefaultPackageNameResolver = findPackageName } } - -func (l *Listener) openAndroidHotspot(tunOptions tun.Options) { - if runtime.GOOS == "android" && tunOptions.AutoRoute { - priority := 9000 - if len(tunOptions.ExcludedRanges()) > 0 { - priority++ - } - if tunOptions.InterfaceMonitor.AndroidVPNEnabled() { - priority++ - } - it := netlink.NewRule() - it.Priority = priority - it.IifName = tunOptions.Name - it.Table = 254 //main - it.Family = unix.AF_INET - it.SuppressPrefixlen = 0 - err := netlink.RuleAdd(it) - if err != nil { - log.Warnln("[TUN] add AndroidHotspot rule error") - } - } -} diff --git a/mihomo/listener/sing_tun/server_notandroid.go b/mihomo/listener/sing_tun/server_notandroid.go index 10fd3997b4..e393d4ca0d 100644 --- a/mihomo/listener/sing_tun/server_notandroid.go +++ b/mihomo/listener/sing_tun/server_notandroid.go @@ -9,4 +9,3 @@ import ( func (l *Listener) buildAndroidRules(tunOptions *tun.Options) error { return nil } -func (l *Listener) openAndroidHotspot(tunOptions tun.Options) {} diff --git a/mihomo/listener/sing_vmess/server.go b/mihomo/listener/sing_vmess/server.go index 7dd0a163ba..5604700f63 100644 --- a/mihomo/listener/sing_vmess/server.go +++ b/mihomo/listener/sing_vmess/server.go @@ -4,7 +4,6 @@ import ( "context" "errors" "net" - "net/url" "strings" "github.com/metacubex/mihomo/adapter/inbound" @@ -19,6 +18,7 @@ import ( mihomoVMess "github.com/metacubex/mihomo/transport/vmess" "github.com/metacubex/http" + "github.com/metacubex/mhurl" vmess "github.com/metacubex/sing-vmess" "github.com/metacubex/sing/common" "github.com/metacubex/sing/common/metadata" @@ -230,7 +230,7 @@ func HandleVmess(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) } func ParseVmessURL(s string) (addr, username, password string, err error) { - u, err := url.Parse(s) + u, err := mhurl.Parse(s) // we need multiple hosts url supports if err != nil { return } diff --git a/mihomo/listener/sing_vmess/server_test.go b/mihomo/listener/sing_vmess/server_test.go new file mode 100644 index 0000000000..36b2ab14ba --- /dev/null +++ b/mihomo/listener/sing_vmess/server_test.go @@ -0,0 +1,22 @@ +package sing_vmess + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseVmessURL(t *testing.T) { + for _, test := range []struct{ username, passwd, hosts string }{ + {username: "username", passwd: "password", hosts: ":1000,:2000,:3000"}, + {username: "username", passwd: "password", hosts: "127.0.0.1:1000,127.0.0.1:2000,127.0.0.1:3000"}, + {username: "username", passwd: "password", hosts: "[::1]:1000,[::1]:2000,[::1]:3000"}, + } { + addr, username, password, err := ParseVmessURL(fmt.Sprintf("vmess://%s:%s@%s", test.username, test.passwd, test.hosts)) + require.NoError(t, err) + require.Equal(t, test.hosts, addr) + require.Equal(t, test.username, username) + require.Equal(t, test.passwd, password) + } +} diff --git a/openclash/luci-app-openclash/Makefile b/openclash/luci-app-openclash/Makefile index be18e68abd..fba51093bd 100644 --- a/openclash/luci-app-openclash/Makefile +++ b/openclash/luci-app-openclash/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-openclash -PKG_VERSION:=0.47.071 +PKG_VERSION:=0.47.075 PKG_MAINTAINER:=vernesong PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/openclash/luci-app-openclash/luasrc/controller/openclash.lua b/openclash/luci-app-openclash/luasrc/controller/openclash.lua index 6906d09fa8..b6673ac2f7 100644 --- a/openclash/luci-app-openclash/luasrc/controller/openclash.lua +++ b/openclash/luci-app-openclash/luasrc/controller/openclash.lua @@ -537,10 +537,10 @@ function fetch_sub_info(sub_url, sub_ua) local info, upload, download, total, day_expire, http_code local used, expire, day_left, percent, surplus - info = luci.sys.exec(string.format("curl -sLI -X GET -m 10 --retry 2 -w 'http_code=%%{http_code}' -H 'User-Agent: %s' '%s'", sub_ua, sub_url)) + info = luci.sys.exec(string.format("curl -sLI -X GET -m 5 --retry 2 -w 'http_code=%%{http_code}' -H 'User-Agent: %s' '%s'", sub_ua, sub_url)) local http_match = string.match(info, "http_code=(%d+)") if not info or not http_match or tonumber(http_match) ~= 200 then - info = luci.sys.exec(string.format("curl -sLI -X GET -m 10 --retry 2 -w 'http_code=%%{http_code}' -H 'User-Agent: Quantumultx' '%s'", sub_url)) + info = luci.sys.exec(string.format("curl -sLI -X GET -m 5 --retry 2 -w 'http_code=%%{http_code}' -H 'User-Agent: Quantumultx' '%s'", sub_url)) http_match = string.match(info, "http_code=(%d+)") end @@ -735,7 +735,15 @@ function get_sub_url(filename) function(s) if s.name == filename and s.address and string.find(s.address, "http") then string.gsub(s.address, '[^\n]+', function(w) table.insert(info_tb, w) end) - sub_url = info_tb[1] + if #info_tb == 1 then + local url, _ = parse_url_with_name(info_tb[1], filename) + sub_url = url + elseif #info_tb > 1 then + for _, raw in ipairs(info_tb) do + local url, name = parse_url_with_name(raw, filename) + table.insert(providers, {name = name, url = url}) + end + end end end ) @@ -744,6 +752,10 @@ function get_sub_url(filename) return {type = "single", url = sub_url} end + if #providers > 0 then + return {type = "multiple", providers = providers} + end + return nil end @@ -766,36 +778,33 @@ function sub_info_get() if filename and not is_start() then url_result = get_sub_url(filename) - if not url_result then - sub_info = "No Sub Info Found" - elseif url_result.type == "single" then - local info = fetch_sub_info(url_result.url, sub_ua) - if info then - table.insert(providers_data, info) - sub_info = "Successful" - else - sub_info = "No Sub Info Found" - end - elseif url_result.type == "multiple" then - for i, provider in ipairs(url_result.providers) do - local info = fetch_sub_info(provider.url, sub_ua) + if url_result then + if url_result.type == "single" then + local info = fetch_sub_info(url_result.url, sub_ua) if info then - info.provider_name = provider.name table.insert(providers_data, info) end - end - - if #providers_data > 0 then - sub_info = "Successful" else - sub_info = "No Sub Info Found" + for i, provider in ipairs(url_result.providers) do + local info = fetch_sub_info(provider.url, sub_ua) + if info then + info.provider_name = provider.name + table.insert(providers_data, info) + end + end end end end + if #providers_data == 0 then + if not url_result then + luci.http.status(400, "Subscription information not found") + return + end + end + luci.http.prepare_content("application/json") luci.http.write_json({ - sub_info = sub_info, providers = providers_data, get_time = os.time(), url_result = url_result @@ -903,6 +912,27 @@ function action_log_level() }) end +function action_switch_log() + local level, info + if is_running() then + local daip = daip() + local dase = dase() or "" + local cn_port = cn_port() + level = luci.http.formvalue("log_level") + if not daip or not cn_port or not level then luci.http.status(500, "Switch Faild") return end + info = luci.sys.exec(string.format('curl -sL -m 3 --retry 2 -H "Content-Type: application/json" -H "Authorization: Bearer %s" -XPATCH http://"%s":"%s"/configs -d \'{\"log-level\": \"%s\"}\'', dase, daip, cn_port, level)) + if info ~= "" then + luci.http.status(500, "Switch Faild") + end + else + luci.http.status(500, "Switch Faild") + end + luci.http.prepare_content("application/json") + luci.http.write_json({ + info = info; + }) +end + local function s(e) local t=0 local a={' B/S',' KB/S',' MB/S',' GB/S',' TB/S',' PB/S'} diff --git a/openclash/luci-app-openclash/luasrc/model/cbi/openclash/config-subscribe.lua b/openclash/luci-app-openclash/luasrc/model/cbi/openclash/config-subscribe.lua index 7fd27a7427..d0cb5deb18 100644 --- a/openclash/luci-app-openclash/luasrc/model/cbi/openclash/config-subscribe.lua +++ b/openclash/luci-app-openclash/luasrc/model/cbi/openclash/config-subscribe.lua @@ -123,6 +123,14 @@ end o = s:option(TextValue, "address", translate("Subscribe Address")) function o.cfgvalue(...) return Value.cfgvalue(...) or translate("None") + +end +function o.validate(self, value) + if value then + value = value:gsub("\r\n?", "\n") + value = value:gsub("%c*$", "") + end + return value end ---- template diff --git a/openclash/luci-app-openclash/luasrc/model/cbi/openclash/settings.lua b/openclash/luci-app-openclash/luasrc/model/cbi/openclash/settings.lua index 073e68133b..c0a2349b94 100644 --- a/openclash/luci-app-openclash/luasrc/model/cbi/openclash/settings.lua +++ b/openclash/luci-app-openclash/luasrc/model/cbi/openclash/settings.lua @@ -510,8 +510,8 @@ function o.write(self, section, value) value = value:gsub("\r\n?", "\n") local old_value = NXFS.readfile("/etc/openclash/custom/openclash_custom_chnroute_pass.list") if value ~= old_value then - NXFS.writefile("/etc/openclash/custom/openclash_custom_chnroute_pass.list", value) - end + NXFS.writefile("/etc/openclash/custom/openclash_custom_chnroute_pass.list", value) + end end end diff --git a/openclash/luci-app-openclash/luasrc/view/openclash/config_edit.htm b/openclash/luci-app-openclash/luasrc/view/openclash/config_edit.htm index b825965d18..09c2f08764 100644 --- a/openclash/luci-app-openclash/luasrc/view/openclash/config_edit.htm +++ b/openclash/luci-app-openclash/luasrc/view/openclash/config_edit.htm @@ -612,8 +612,6 @@ - - diff --git a/openclash/luci-app-openclash/luasrc/view/openclash/status.htm b/openclash/luci-app-openclash/luasrc/view/openclash/status.htm index bd87dd196a..0586746992 100644 --- a/openclash/luci-app-openclash/luasrc/view/openclash/status.htm +++ b/openclash/luci-app-openclash/luasrc/view/openclash/status.htm @@ -2972,13 +2972,15 @@ try { var parsedData = JSON.parse(cachedData); - if (parsedData.sub_info && parsedData.sub_info !== "No Sub Info Found") { - if (this.currentConfigFile === requestConfigFile) { - this.displaySubscriptionInfo(parsedData); - } - } else if (parsedData.sub_info === "No Sub Info Found") { - if (this.currentConfigFile === requestConfigFile) { - this.showNoInfo(); + if (parsedData.providers) { + if (parsedData.providers.length > 0) { + if (this.currentConfigFile === requestConfigFile) { + this.displaySubscriptionInfo(parsedData); + } + } else { + if (this.currentConfigFile === requestConfigFile) { + this.showNoInfo(); + } } } @@ -3006,16 +3008,32 @@ if (SubscriptionManager.currentConfigFile !== requestConfigFile) { return; } - if (x && x.status == 200 && status.sub_info && status.sub_info !== "No Sub Info Found") { - SubscriptionManager.retryCount = 0; - localStorage.setItem('sub_info_' + filename, JSON.stringify(status)); - SubscriptionManager.displaySubscriptionInfo(status); - } else if (x && x.status == 200 && status.sub_info === "No Sub Info Found") { - SubscriptionManager.retryCount = 0; - localStorage.setItem('sub_info_' + filename, JSON.stringify(status)); - SubscriptionManager.showNoInfo(); + + var needsErrorHandling = false; + if (x && x.status == 200 && status.providers) { + var newProvidersLength = (status.providers) ? status.providers.length : 0; + var cachedProvidersLength = (parsedData && parsedData.providers) ? parsedData.providers.length : 0; + + if (newProvidersLength !== cachedProvidersLength && cachedProvidersLength > newProvidersLength) { + needsErrorHandling = true; + } + + if (!needsErrorHandling) { + SubscriptionManager.retryCount = 0; + localStorage.setItem('sub_info_' + filename, JSON.stringify(status)); + if (status.providers && status.providers.length === 0) { + SubscriptionManager.showNoInfo(); + return; + } + SubscriptionManager.displaySubscriptionInfo(status); + return; + } } else { - SubscriptionManager.handleError(); + needsErrorHandling = true; + } + + if (needsErrorHandling) { + SubscriptionManager.handleError(cachedData); } }, true); } @@ -3039,15 +3057,11 @@ container.style.display = 'flex'; - if (data && data.sub_info && data.sub_info !== "No Sub Info Found") { - if (data.providers && Array.isArray(data.providers) && data.providers.length > 0) { - if (data.providers.length > 1 || data.providers[0].provider_name) { - this.displayMultipleProviders(data.providers, progressSection); - } else { - this.displaySingleProvider(data.providers[0], progressSection); - } + if (data && data.providers && data.providers.length > 0) { + if (data.providers.length > 1 || data.providers[0].provider_name) { + this.displayMultipleProviders(data.providers, progressSection); } else { - progressSection.style.display = 'none'; + this.displaySingleProvider(data.providers[0], progressSection); } } else { progressSection.style.display = 'none'; @@ -3284,18 +3298,21 @@ } }, - handleError: function() { - if (this.retryCount >= this.maxRetries) { + handleError: function(cachedData) { + if (!cachedData) { this.showNoInfo(); + } + + if (this.retryCount >= this.maxRetries) { this.retryCount = 0; - if (this.currentConfigFile) { + if (this.currentConfigFile && cachedData) { localStorage.removeItem('sub_info_' + this.extractFilename(this.currentConfigFile)); } } else { this.retryCount++; setTimeout(function() { SubscriptionManager.getSubscriptionInfo(); - }, 5000); + }, 15000); } }, diff --git a/openclash/luci-app-openclash/luasrc/view/openclash/sub_info_show.htm b/openclash/luci-app-openclash/luasrc/view/openclash/sub_info_show.htm index d8627d825c..f84e049691 100644 --- a/openclash/luci-app-openclash/luasrc/view/openclash/sub_info_show.htm +++ b/openclash/luci-app-openclash/luasrc/view/openclash/sub_info_show.htm @@ -432,9 +432,11 @@ border: 1px solid #999999; border-radius: 6px; display: flex; + flex-direction: column; align-items: center; justify-content: center; box-sizing: border-box; + gap: 2px; } .sub_provider_fill { @@ -458,6 +460,22 @@ text-overflow: ellipsis; max-width: 100%; padding: 0 4px; + line-height: 1; +} + +.sub_provider_percent { + position: relative; + z-index: 1; + font-size: 12px; + color: #333; + font-weight: 400; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + padding: 0 4px; + line-height: 1; } /* Dark mode support */ @@ -470,6 +488,10 @@ color: #e0e0e0; } +:root[data-darkmode="true"] .sub_provider_percent { + color: #e0e0e0; +} + /* Responsive adjustments for multiple providers */ @media (max-width: 1024px) { .sub_providers_container { @@ -483,6 +505,10 @@ .sub_provider_name { font-size: 11px; } + + .sub_provider_percent { + font-size: 11px; + } } @media (max-width: 768px) { @@ -498,6 +524,10 @@ .sub_provider_name { font-size: 10px; } + + .sub_provider_percent { + font-size: 10px; + } } @media (max-width: 480px) { @@ -510,6 +540,10 @@ .sub_provider_name { font-size: 9px; } + + .sub_provider_percent { + font-size: 9px; + } } @media (max-width: 320px) { @@ -521,6 +555,10 @@ .sub_provider_name { font-size: 8px; } + + .sub_provider_percent { + font-size: 8px; + } } @@ -533,7 +571,7 @@
-