Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
commit
609ff7d330
@ -7,10 +7,10 @@ ifdef CONFIG_TESTING_KERNEL
|
||||
endif
|
||||
|
||||
LINUX_VERSION-5.4 = .124
|
||||
LINUX_VERSION-5.10 = .43
|
||||
LINUX_VERSION-5.10 = .44
|
||||
|
||||
LINUX_KERNEL_HASH-5.4.124 = f7f29dda2b042d7b5986d18274413131cf70e17288c05e9a683df1f46c507d82
|
||||
LINUX_KERNEL_HASH-5.10.43 = 83b81e433ba2f8ee143064fb163699ee857e26dd789006bc1e9edf1ccd0bd403
|
||||
LINUX_KERNEL_HASH-5.10.44 = 77beefa59c854ce1e8353db947a71a8a91f2a907aed45c1335ac1f209983c767
|
||||
|
||||
remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1))))
|
||||
sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1)))))))
|
||||
|
||||
@ -4,8 +4,7 @@
|
||||
START=10
|
||||
USE_PROCD=1
|
||||
|
||||
validate_system_section()
|
||||
{
|
||||
validate_system_section() {
|
||||
uci_load_validate system system "$1" "$2" \
|
||||
'hostname:string:OpenWrt' \
|
||||
'conloglevel:uinteger' \
|
||||
@ -23,8 +22,9 @@ system_config() {
|
||||
echo "$hostname" > /proc/sys/kernel/hostname
|
||||
[ -z "$conloglevel" -a -z "$buffersize" ] || dmesg ${conloglevel:+-n $conloglevel} ${buffersize:+-s $buffersize}
|
||||
echo "$timezone" > /tmp/TZ
|
||||
[ -n "$zonename" ] && [ -f "/usr/share/zoneinfo/$zonename" ] && \
|
||||
ln -sf "/usr/share/zoneinfo/$zonename" /tmp/localtime && rm -f /tmp/TZ
|
||||
[ -n "$zonename" ] && [ -f "/usr/share/zoneinfo/${zonename// /_}" ] \
|
||||
&& ln -sf "/usr/share/zoneinfo/${zonename// /_}" /tmp/localtime \
|
||||
&& rm -f /tmp/TZ
|
||||
|
||||
# apply timezone to kernel
|
||||
hwclock -u --systz
|
||||
@ -35,8 +35,7 @@ reload_service() {
|
||||
config_foreach validate_system_section system system_config
|
||||
}
|
||||
|
||||
service_triggers()
|
||||
{
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "system"
|
||||
procd_add_validation validate_system_section
|
||||
}
|
||||
|
||||
@ -55,7 +55,12 @@ enable() {
|
||||
|
||||
enabled() {
|
||||
name="$(basename "${initscript}")"
|
||||
[ -x "$IPKG_INSTROOT/etc/rc.d/S${START}${name##S[0-9][0-9]}" ]
|
||||
name="${name##[SK][0-9][0-9]}"
|
||||
{
|
||||
[ -z "${START:-}" ] || [ -L "$IPKG_INSTROOT/etc/rc.d/S${START}$name" ]
|
||||
} && {
|
||||
[ -z "${STOP:-}" ] || [ -L "$IPKG_INSTROOT/etc/rc.d/K${STOP}$name" ]
|
||||
}
|
||||
}
|
||||
|
||||
depends() {
|
||||
|
||||
@ -18,6 +18,9 @@ preinit_ip_config() {
|
||||
fi
|
||||
|
||||
ip link set dev $netdev up
|
||||
if [ -n "$vid" ]; then
|
||||
ip link set dev $1 up
|
||||
fi
|
||||
ip -4 address add $pi_ip/$pi_netmask broadcast $pi_broadcast dev $1
|
||||
}
|
||||
|
||||
@ -72,14 +75,20 @@ preinit_config_board() {
|
||||
|
||||
json_select network
|
||||
json_select "lan"
|
||||
json_get_vars ifname
|
||||
json_get_vars device
|
||||
json_get_values ports ports
|
||||
json_select ..
|
||||
json_select ..
|
||||
|
||||
[ -n "$ifname" ] || return
|
||||
[ -n "$device" -o -n "$ports" ] || return
|
||||
|
||||
# swconfig uses $device and DSA uses ports
|
||||
[ -z "$ports" ] && {
|
||||
ports="$device"
|
||||
}
|
||||
|
||||
# only use the first one
|
||||
ifname=${ifname%% *}
|
||||
ifname=${ports%% *}
|
||||
|
||||
if [ -x /sbin/swconfig ]; then
|
||||
# configure the switch, if present
|
||||
@ -91,6 +100,8 @@ preinit_config_board() {
|
||||
else
|
||||
# trim any vlan ids
|
||||
ifname=${ifname%\.*}
|
||||
# trim any vlan modifiers like :t
|
||||
ifname=${ifname%\:*}
|
||||
fi
|
||||
|
||||
pi_ifname=$ifname
|
||||
|
||||
@ -2,13 +2,13 @@ include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=bcm63xx-cfe
|
||||
PKG_RELEASE:=2
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/openwrt/bcm63xx-cfe.git
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2021-03-05
|
||||
PKG_SOURCE_VERSION:=d03501629fc8b1ba8f9b0961d543c256a3d0098f
|
||||
PKG_MIRROR_HASH:=b32a6f68d59c8f4534def7ec2568ad7da7a612a605b9406328309c78115ee88d
|
||||
PKG_SOURCE_DATE:=2021-06-22
|
||||
PKG_SOURCE_VERSION:=e5050f37150b34deb547b50feccd0e7439cb5bd7
|
||||
PKG_MIRROR_HASH:=85fed9f4bdf23cf7d33a02f549ffe9073666890f786d5ffa484c0368552b75ae
|
||||
|
||||
PKG_FLAGS:=nonshared
|
||||
|
||||
|
||||
@ -360,7 +360,7 @@ $(eval $(call KernelPackage,crypto-hw-geode))
|
||||
|
||||
define KernelPackage/crypto-hw-hifn-795x
|
||||
TITLE:=HIFN 795x crypto accelerator
|
||||
DEPENDS:=+kmod-random-core +kmod-crypto-manager
|
||||
DEPENDS:=@PCI_SUPPORT +kmod-random-core +kmod-crypto-manager
|
||||
KCONFIG:= \
|
||||
CONFIG_CRYPTO_HW=y \
|
||||
CONFIG_CRYPTO_DEV_HIFN_795X \
|
||||
|
||||
@ -298,9 +298,10 @@ hostapd_common_add_bss_config() {
|
||||
config_add_string wps_device_type wps_device_name wps_manufacturer wps_pin
|
||||
config_add_string multi_ap_backhaul_ssid multi_ap_backhaul_key
|
||||
|
||||
config_add_boolean wnm_sleep_mode bss_transition
|
||||
config_add_boolean wnm_sleep_mode wnm_sleep_mode_no_keys bss_transition
|
||||
config_add_int time_advertisement
|
||||
config_add_string time_zone
|
||||
config_add_string vendor_elements
|
||||
|
||||
config_add_boolean ieee80211k rrm_neighbor_report rrm_beacon_report
|
||||
|
||||
@ -353,6 +354,7 @@ hostapd_common_add_bss_config() {
|
||||
config_add_boolean multicast_to_unicast proxy_arp per_sta_vif
|
||||
|
||||
config_add_array hostapd_bss_options
|
||||
config_add_boolean default_disabled
|
||||
|
||||
config_add_boolean request_cui
|
||||
config_add_array radius_auth_req_attr
|
||||
@ -531,7 +533,8 @@ hostapd_set_bss_options() {
|
||||
multi_ap multi_ap_backhaul_ssid multi_ap_backhaul_key skip_inactivity_poll \
|
||||
airtime_bss_weight airtime_bss_limit airtime_sta_weight \
|
||||
multicast_to_unicast proxy_arp per_sta_vif \
|
||||
eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id
|
||||
eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id \
|
||||
vendor_elements
|
||||
|
||||
set_default isolate 0
|
||||
set_default maxassoc 0
|
||||
@ -579,6 +582,7 @@ hostapd_set_bss_options() {
|
||||
append bss_conf "uapsd_advertisement_enabled=$uapsd" "$N"
|
||||
append bss_conf "utf8_ssid=$utf8_ssid" "$N"
|
||||
append bss_conf "multi_ap=$multi_ap" "$N"
|
||||
[ -n "$vendor_elements" ] && append bss_conf "vendor_elements=$vendor_elements" "$N"
|
||||
|
||||
[ "$tdls_prohibit" -gt 0 ] && append bss_conf "tdls_prohibit=$tdls_prohibit" "$N"
|
||||
|
||||
@ -759,13 +763,17 @@ hostapd_set_bss_options() {
|
||||
append bss_conf "iapp_interface=$ifname" "$N"
|
||||
}
|
||||
|
||||
json_get_vars time_advertisement time_zone wnm_sleep_mode bss_transition
|
||||
json_get_vars time_advertisement time_zone wnm_sleep_mode wnm_sleep_mode_no_keys bss_transition
|
||||
set_default bss_transition 0
|
||||
set_default wnm_sleep_mode 0
|
||||
set_default wnm_sleep_mode_no_keys 0
|
||||
|
||||
[ -n "$time_advertisement" ] && append bss_conf "time_advertisement=$time_advertisement" "$N"
|
||||
[ -n "$time_zone" ] && append bss_conf "time_zone=$time_zone" "$N"
|
||||
[ "$wnm_sleep_mode" -eq "1" ] && append bss_conf "wnm_sleep_mode=1" "$N"
|
||||
if [ "$wnm_sleep_mode" -eq "1" ]; then
|
||||
append bss_conf "wnm_sleep_mode=1" "$N"
|
||||
[ "$wnm_sleep_mode_no_keys" -eq "1" ] && append bss_conf "wnm_sleep_mode_no_keys=1" "$N"
|
||||
fi
|
||||
[ "$bss_transition" -eq "1" ] && append bss_conf "bss_transition=1" "$N"
|
||||
|
||||
json_get_vars ieee80211k rrm_neighbor_report rrm_beacon_report
|
||||
@ -1187,7 +1195,8 @@ wpa_supplicant_add_network() {
|
||||
ssid bssid key \
|
||||
basic_rate mcast_rate \
|
||||
ieee80211w ieee80211r \
|
||||
multi_ap
|
||||
multi_ap \
|
||||
default_disabled
|
||||
|
||||
case "$auth_type" in
|
||||
sae|owe|eap192|eap-eap192)
|
||||
@ -1200,6 +1209,7 @@ wpa_supplicant_add_network() {
|
||||
|
||||
set_default ieee80211r 0
|
||||
set_default multi_ap 0
|
||||
set_default default_disabled 0
|
||||
|
||||
local key_mgmt='NONE'
|
||||
local network_data=
|
||||
@ -1231,7 +1241,10 @@ wpa_supplicant_add_network() {
|
||||
scan_ssid=""
|
||||
}
|
||||
|
||||
[ "$multi_ap" = 1 -a "$_w_mode" = "sta" ] && append network_data "multi_ap_backhaul_sta=1" "$N$T"
|
||||
[ "$_w_mode" = "sta" ] && {
|
||||
[ "$multi_ap" = 1 ] && append network_data "multi_ap_backhaul_sta=1" "$N$T"
|
||||
[ "$default_disabled" = 1 ] && append network_data "disabled=1" "$N$T"
|
||||
}
|
||||
|
||||
case "$auth_type" in
|
||||
none) ;;
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright (C) 2013 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
# Copyright (C) 2013-2021 OpenWrt.org
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=zram-swap
|
||||
PKG_RELEASE:=8
|
||||
PKG_RELEASE:=$(AUTORELEASE)
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
||||
@ -25,31 +25,6 @@ zram_getsize() # in megabytes
|
||||
fi
|
||||
}
|
||||
|
||||
zram_applicable()
|
||||
{
|
||||
local zram_dev="$1"
|
||||
|
||||
[ -e "$zram_dev" ] || {
|
||||
logger -s -t zram_applicable -p daemon.crit "[ERROR] device '$zram_dev' not found"
|
||||
return 1
|
||||
}
|
||||
|
||||
[ -x /sbin/mkswap ] || {
|
||||
logger -s -t zram_applicable -p daemon.err "[ERROR] 'BusyBox mkswap' not installed"
|
||||
return 1
|
||||
}
|
||||
|
||||
[ -x /sbin/swapon ] || {
|
||||
logger -s -t zram_applicable -p daemon.err "[ERROR] 'BusyBox swapon' not installed"
|
||||
return 1
|
||||
}
|
||||
|
||||
[ -x /sbin/swapoff ] || {
|
||||
logger -s -t zram_applicable -p daemon.err "[ERROR] 'BusyBox swapoff' not installed"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
zram_dev()
|
||||
{
|
||||
local idx="$1"
|
||||
@ -160,9 +135,14 @@ start()
|
||||
return 1
|
||||
fi
|
||||
|
||||
local zram_size="$( zram_getsize )"
|
||||
local zram_dev="$( zram_getdev )"
|
||||
zram_applicable "$zram_dev" || return 1
|
||||
|
||||
[ -e "$zram_dev" ] || {
|
||||
logger -s -t zram_start -p daemon.crit "[ERROR] device '$zram_dev' not found"
|
||||
return 1
|
||||
}
|
||||
|
||||
local zram_size="$( zram_getsize )"
|
||||
local zram_priority="$( uci -q get system.@system[0].zram_priority )"
|
||||
zram_priority=${zram_priority:+-p $zram_priority}
|
||||
|
||||
@ -171,8 +151,8 @@ start()
|
||||
zram_reset "$zram_dev" "enforcing defaults"
|
||||
zram_comp_algo "$zram_dev"
|
||||
echo $(( $zram_size * 1024 * 1024 )) >"/sys/block/$( basename "$zram_dev" )/disksize"
|
||||
/sbin/mkswap "$zram_dev"
|
||||
/sbin/swapon -d $zram_priority "$zram_dev"
|
||||
busybox mkswap "$zram_dev"
|
||||
busybox swapon -d $zram_priority "$zram_dev"
|
||||
}
|
||||
|
||||
stop()
|
||||
@ -181,7 +161,7 @@ stop()
|
||||
|
||||
for zram_dev in $( grep zram /proc/swaps |awk '{print $1}' ); do {
|
||||
logger -s -t zram_stop -p daemon.debug "deactivate swap $zram_dev"
|
||||
/sbin/swapoff "$zram_dev" && zram_reset "$zram_dev" "claiming memory back"
|
||||
busybox swapoff "$zram_dev" && zram_reset "$zram_dev" "claiming memory back"
|
||||
local dev_index="$( echo $zram_dev | grep -o "[0-9]*$" )"
|
||||
if [ $dev_index -ne 0 ]; then
|
||||
logger -s -t zram_stop -p daemon.debug "removing zram $zram_dev"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -383,6 +383,13 @@ static int at803x_aneg_done(struct phy_d
|
||||
@@ -404,6 +404,13 @@ static int at803x_aneg_done(struct phy_d
|
||||
if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) {
|
||||
phydev_warn(phydev, "803x_aneg_done: SGMII link is not ok\n");
|
||||
aneg_done = 0;
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
From 9d5ef190e5615a7b63af89f88c4106a5bc127974 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Fri, 5 Feb 2021 15:37:10 +0200
|
||||
Subject: [PATCH] net: dsa: automatically bring up DSA master when opening user
|
||||
port
|
||||
|
||||
DSA wants the master interface to be open before the user port is due to
|
||||
historical reasons. The promiscuity of interfaces that are down used to
|
||||
have issues, as referenced Lennert Buytenhek in commit df02c6ff2e39
|
||||
("dsa: fix master interface allmulti/promisc handling").
|
||||
|
||||
The bugfix mentioned there, commit b6c40d68ff64 ("net: only invoke
|
||||
dev->change_rx_flags when device is UP"), was basically a "don't do
|
||||
that" approach to working around the promiscuity while down issue.
|
||||
|
||||
Further work done by Vlad Yasevich in commit d2615bf45069 ("net: core:
|
||||
Always propagate flag changes to interfaces") has resolved the
|
||||
underlying issue, and it is strictly up to the DSA and 8021q drivers
|
||||
now, it is no longer mandated by the networking core that the master
|
||||
interface must be up when changing its promiscuity.
|
||||
|
||||
From DSA's point of view, deciding to error out in dsa_slave_open
|
||||
because the master isn't up is
|
||||
(a) a bad user experience and
|
||||
(b) knocking at an open door.
|
||||
Even if there still was an issue with promiscuity while down, DSA could
|
||||
still just open the master and avoid it.
|
||||
|
||||
Doing it this way has the additional benefit that user space can now
|
||||
remove DSA-specific workarounds, like systemd-networkd with BindCarrier:
|
||||
https://github.com/systemd/systemd/issues/7478
|
||||
|
||||
And we can finally remove one of the 2 bullets in the "Common pitfalls
|
||||
using DSA setups" chapter.
|
||||
|
||||
Tested with two cascaded DSA switches:
|
||||
|
||||
$ ip link set sw0p2 up
|
||||
fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode
|
||||
fsl_enetc 0000:00:00.2 eno2: Link is Up - 1Gbps/Full - flow control rx/tx
|
||||
mscc_felix 0000:00:00.5 swp0: configuring for fixed/sgmii link mode
|
||||
mscc_felix 0000:00:00.5 swp0: Link is Up - 1Gbps/Full - flow control off
|
||||
8021q: adding VLAN 0 to HW filter on device swp0
|
||||
sja1105 spi2.0 sw0p2: configuring for phy/rgmii-id link mode
|
||||
IPv6: ADDRCONF(NETDEV_CHANGE): eno2: link becomes ready
|
||||
IPv6: ADDRCONF(NETDEV_CHANGE): swp0: link becomes ready
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
Documentation/networking/dsa/dsa.rst | 4 ----
|
||||
net/dsa/slave.c | 7 +++++--
|
||||
2 files changed, 5 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/Documentation/networking/dsa/dsa.rst
|
||||
+++ b/Documentation/networking/dsa/dsa.rst
|
||||
@@ -273,10 +273,6 @@ will not make us go through the switch t
|
||||
the Ethernet switch on the other end, expecting a tag will typically drop this
|
||||
frame.
|
||||
|
||||
-Slave network devices check that the master network device is UP before allowing
|
||||
-you to administratively bring UP these slave network devices. A common
|
||||
-configuration mistake is forgetting to bring UP the master network device first.
|
||||
-
|
||||
Interactions with other subsystems
|
||||
==================================
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -68,8 +68,11 @@ static int dsa_slave_open(struct net_dev
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
int err;
|
||||
|
||||
- if (!(master->flags & IFF_UP))
|
||||
- return -ENETDOWN;
|
||||
+ err = dev_open(master, NULL);
|
||||
+ if (err < 0) {
|
||||
+ netdev_err(dev, "failed to open master %s\n", master->name);
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
|
||||
err = dev_uc_add(master, dev->dev_addr);
|
||||
@ -25,7 +25,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2111,7 +2111,9 @@ static void dsa_slave_switchdev_event_wo
|
||||
@@ -2114,7 +2114,9 @@ static void dsa_slave_switchdev_event_wo
|
||||
|
||||
err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
|
||||
if (err) {
|
||||
@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
break;
|
||||
}
|
||||
fdb_info->offloaded = true;
|
||||
@@ -2126,9 +2128,11 @@ static void dsa_slave_switchdev_event_wo
|
||||
@@ -2129,9 +2131,11 @@ static void dsa_slave_switchdev_event_wo
|
||||
|
||||
err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
|
||||
if (err) {
|
||||
|
||||
@ -54,7 +54,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
struct sk_buff * (*xmit)(struct sk_buff *skb,
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2086,76 +2086,66 @@ static int dsa_slave_netdevice_event(str
|
||||
@@ -2089,76 +2089,66 @@ static int dsa_slave_netdevice_event(str
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
@ -167,7 +167,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
|
||||
/* Called under rcu_read_lock() */
|
||||
@@ -2163,7 +2153,9 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2166,7 +2156,9 @@ static int dsa_slave_switchdev_event(str
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
|
||||
@ -177,7 +177,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
int err;
|
||||
|
||||
if (event == SWITCHDEV_PORT_ATTR_SET) {
|
||||
@@ -2176,20 +2168,32 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2179,20 +2171,32 @@ static int dsa_slave_switchdev_event(str
|
||||
if (!dsa_slave_dev_check(dev))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
@ -213,7 +213,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
dev_hold(dev);
|
||||
break;
|
||||
default:
|
||||
@@ -2199,10 +2203,6 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2202,10 +2206,6 @@ static int dsa_slave_switchdev_event(str
|
||||
|
||||
dsa_schedule_work(&switchdev_work->work);
|
||||
return NOTIFY_OK;
|
||||
|
||||
@ -20,7 +20,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2158,31 +2158,29 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2161,31 +2161,29 @@ static int dsa_slave_switchdev_event(str
|
||||
struct dsa_port *dp;
|
||||
int err;
|
||||
|
||||
@ -68,7 +68,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
fdb_info = ptr;
|
||||
|
||||
if (!fdb_info->added_by_user) {
|
||||
@@ -2195,13 +2193,12 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2198,13 +2196,12 @@ static int dsa_slave_switchdev_event(str
|
||||
switchdev_work->vid = fdb_info->vid;
|
||||
|
||||
dev_hold(dev);
|
||||
|
||||
@ -30,7 +30,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2171,6 +2171,9 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2174,6 +2174,9 @@ static int dsa_slave_switchdev_event(str
|
||||
|
||||
dp = dsa_slave_to_port(dev);
|
||||
|
||||
|
||||
@ -170,7 +170,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
*/
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2148,6 +2148,28 @@ static void dsa_slave_switchdev_event_wo
|
||||
@@ -2151,6 +2151,28 @@ static void dsa_slave_switchdev_event_wo
|
||||
dev_put(dp->slave);
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
/* Called under rcu_read_lock() */
|
||||
static int dsa_slave_switchdev_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
@@ -2166,10 +2188,37 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2169,10 +2191,37 @@ static int dsa_slave_switchdev_event(str
|
||||
return notifier_from_errno(err);
|
||||
case SWITCHDEV_FDB_ADD_TO_DEVICE:
|
||||
case SWITCHDEV_FDB_DEL_TO_DEVICE:
|
||||
@ -240,7 +240,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del)
|
||||
return NOTIFY_DONE;
|
||||
@@ -2184,18 +2233,13 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2187,18 +2236,13 @@ static int dsa_slave_switchdev_event(str
|
||||
switchdev_work->port = dp->index;
|
||||
switchdev_work->event = event;
|
||||
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Maciej W. Rozycki" <macro@orcam.me.uk>
|
||||
Date: Thu, 11 Mar 2021 21:50:47 -0700
|
||||
Subject: [PATCH] crypto: mips/poly1305 - enable for all MIPS processors
|
||||
|
||||
commit 6c810cf20feef0d4338e9b424ab7f2644a8b353e upstream.
|
||||
|
||||
The MIPS Poly1305 implementation is generic MIPS code written such as to
|
||||
support down to the original MIPS I and MIPS III ISA for the 32-bit and
|
||||
64-bit variant respectively. Lift the current limitation then to enable
|
||||
code for MIPSr1 ISA or newer processors only and have it available for
|
||||
all MIPS processors.
|
||||
|
||||
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
|
||||
Fixes: a11d055e7a64 ("crypto: mips/poly1305 - incorporate OpenSSL/CRYPTOGAMS optimized implementation")
|
||||
Cc: stable@vger.kernel.org # v5.5+
|
||||
Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
arch/mips/crypto/Makefile | 4 ++--
|
||||
crypto/Kconfig | 2 +-
|
||||
drivers/net/Kconfig | 2 +-
|
||||
3 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/arch/mips/crypto/Makefile
|
||||
+++ b/arch/mips/crypto/Makefile
|
||||
@@ -12,8 +12,8 @@ AFLAGS_chacha-core.o += -O2 # needed to
|
||||
obj-$(CONFIG_CRYPTO_POLY1305_MIPS) += poly1305-mips.o
|
||||
poly1305-mips-y := poly1305-core.o poly1305-glue.o
|
||||
|
||||
-perlasm-flavour-$(CONFIG_CPU_MIPS32) := o32
|
||||
-perlasm-flavour-$(CONFIG_CPU_MIPS64) := 64
|
||||
+perlasm-flavour-$(CONFIG_32BIT) := o32
|
||||
+perlasm-flavour-$(CONFIG_64BIT) := 64
|
||||
|
||||
quiet_cmd_perlasm = PERLASM $@
|
||||
cmd_perlasm = $(PERL) $(<) $(perlasm-flavour-y) $(@)
|
||||
--- a/crypto/Kconfig
|
||||
+++ b/crypto/Kconfig
|
||||
@@ -740,7 +740,7 @@ config CRYPTO_POLY1305_X86_64
|
||||
|
||||
config CRYPTO_POLY1305_MIPS
|
||||
tristate "Poly1305 authenticator algorithm (MIPS optimized)"
|
||||
- depends on CPU_MIPS32 || (CPU_MIPS64 && 64BIT)
|
||||
+ depends on MIPS
|
||||
select CRYPTO_ARCH_HAVE_LIB_POLY1305
|
||||
|
||||
config CRYPTO_MD4
|
||||
--- a/drivers/net/Kconfig
|
||||
+++ b/drivers/net/Kconfig
|
||||
@@ -92,7 +92,7 @@ config WIREGUARD
|
||||
select CRYPTO_POLY1305_ARM if ARM
|
||||
select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON
|
||||
select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2
|
||||
- select CRYPTO_POLY1305_MIPS if CPU_MIPS32 || (CPU_MIPS64 && 64BIT)
|
||||
+ select CRYPTO_POLY1305_MIPS if MIPS
|
||||
help
|
||||
WireGuard is a secure, fast, and easy to use replacement for IPSec
|
||||
that uses modern cryptography and clever networking tricks. It's
|
||||
@ -0,0 +1,24 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
|
||||
Date: Sat, 27 Mar 2021 19:39:43 -0700
|
||||
Subject: [PATCH] crypto: mips: add poly1305-core.S to .gitignore
|
||||
|
||||
commit dc92d0df51dc61de88bf6f4884a17bf73d5c6326 upstream.
|
||||
|
||||
poly1305-core.S is an auto-generated file, so it should be ignored.
|
||||
|
||||
Fixes: a11d055e7a64 ("crypto: mips/poly1305 - incorporate OpenSSL/CRYPTOGAMS optimized implementation")
|
||||
Signed-off-by: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
|
||||
Cc: Ard Biesheuvel <ardb@kernel.org>
|
||||
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
arch/mips/crypto/.gitignore | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
create mode 100644 arch/mips/crypto/.gitignore
|
||||
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/crypto/.gitignore
|
||||
@@ -0,0 +1,2 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0-only
|
||||
+poly1305-core.S
|
||||
@ -0,0 +1,172 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Arnd Bergmann <arnd@arndb.de>
|
||||
Date: Mon, 22 Mar 2021 18:05:15 +0100
|
||||
Subject: [PATCH] crypto: poly1305 - fix poly1305_core_setkey() declaration
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
commit 8d195e7a8ada68928f2aedb2c18302a4518fe68e upstream.
|
||||
|
||||
gcc-11 points out a mismatch between the declaration and the definition
|
||||
of poly1305_core_setkey():
|
||||
|
||||
lib/crypto/poly1305-donna32.c:13:67: error: argument 2 of type ‘const u8[16]’ {aka ‘const unsigned char[16]’} with mismatched bound [-Werror=array-parameter=]
|
||||
13 | void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16])
|
||||
| ~~~~~~~~~^~~~~~~~~~~
|
||||
In file included from lib/crypto/poly1305-donna32.c:11:
|
||||
include/crypto/internal/poly1305.h:21:68: note: previously declared as ‘const u8 *’ {aka ‘const unsigned char *’}
|
||||
21 | void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key);
|
||||
|
||||
This is harmless in principle, as the calling conventions are the same,
|
||||
but the more specific prototype allows better type checking in the
|
||||
caller.
|
||||
|
||||
Change the declaration to match the actual function definition.
|
||||
The poly1305_simd_init() is a bit suspicious here, as it previously
|
||||
had a 32-byte argument type, but looks like it needs to take the
|
||||
16-byte POLY1305_BLOCK_SIZE array instead.
|
||||
|
||||
Fixes: 1c08a104360f ("crypto: poly1305 - add new 32 and 64-bit generic versions")
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
|
||||
Reviewed-by: Eric Biggers <ebiggers@google.com>
|
||||
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
arch/arm/crypto/poly1305-glue.c | 2 +-
|
||||
arch/arm64/crypto/poly1305-glue.c | 2 +-
|
||||
arch/mips/crypto/poly1305-glue.c | 2 +-
|
||||
arch/x86/crypto/poly1305_glue.c | 6 +++---
|
||||
include/crypto/internal/poly1305.h | 3 ++-
|
||||
include/crypto/poly1305.h | 6 ++++--
|
||||
lib/crypto/poly1305-donna32.c | 3 ++-
|
||||
lib/crypto/poly1305-donna64.c | 3 ++-
|
||||
lib/crypto/poly1305.c | 3 ++-
|
||||
9 files changed, 18 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/arch/arm/crypto/poly1305-glue.c
|
||||
+++ b/arch/arm/crypto/poly1305-glue.c
|
||||
@@ -29,7 +29,7 @@ void __weak poly1305_blocks_neon(void *s
|
||||
|
||||
static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
|
||||
|
||||
-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
|
||||
+void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
|
||||
{
|
||||
poly1305_init_arm(&dctx->h, key);
|
||||
dctx->s[0] = get_unaligned_le32(key + 16);
|
||||
--- a/arch/arm64/crypto/poly1305-glue.c
|
||||
+++ b/arch/arm64/crypto/poly1305-glue.c
|
||||
@@ -25,7 +25,7 @@ asmlinkage void poly1305_emit(void *stat
|
||||
|
||||
static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
|
||||
|
||||
-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
|
||||
+void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
|
||||
{
|
||||
poly1305_init_arm64(&dctx->h, key);
|
||||
dctx->s[0] = get_unaligned_le32(key + 16);
|
||||
--- a/arch/mips/crypto/poly1305-glue.c
|
||||
+++ b/arch/mips/crypto/poly1305-glue.c
|
||||
@@ -17,7 +17,7 @@ asmlinkage void poly1305_init_mips(void
|
||||
asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit);
|
||||
asmlinkage void poly1305_emit_mips(void *state, u8 *digest, const u32 *nonce);
|
||||
|
||||
-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
|
||||
+void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
|
||||
{
|
||||
poly1305_init_mips(&dctx->h, key);
|
||||
dctx->s[0] = get_unaligned_le32(key + 16);
|
||||
--- a/arch/x86/crypto/poly1305_glue.c
|
||||
+++ b/arch/x86/crypto/poly1305_glue.c
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <asm/simd.h>
|
||||
|
||||
asmlinkage void poly1305_init_x86_64(void *ctx,
|
||||
- const u8 key[POLY1305_KEY_SIZE]);
|
||||
+ const u8 key[POLY1305_BLOCK_SIZE]);
|
||||
asmlinkage void poly1305_blocks_x86_64(void *ctx, const u8 *inp,
|
||||
const size_t len, const u32 padbit);
|
||||
asmlinkage void poly1305_emit_x86_64(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],
|
||||
@@ -80,7 +80,7 @@ static void convert_to_base2_64(void *ct
|
||||
state->is_base2_26 = 0;
|
||||
}
|
||||
|
||||
-static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_KEY_SIZE])
|
||||
+static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_BLOCK_SIZE])
|
||||
{
|
||||
poly1305_init_x86_64(ctx, key);
|
||||
}
|
||||
@@ -128,7 +128,7 @@ static void poly1305_simd_emit(void *ctx
|
||||
poly1305_emit_avx(ctx, mac, nonce);
|
||||
}
|
||||
|
||||
-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
|
||||
+void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
|
||||
{
|
||||
poly1305_simd_init(&dctx->h, key);
|
||||
dctx->s[0] = get_unaligned_le32(&key[16]);
|
||||
--- a/include/crypto/internal/poly1305.h
|
||||
+++ b/include/crypto/internal/poly1305.h
|
||||
@@ -18,7 +18,8 @@
|
||||
* only the ε-almost-∆-universal hash function (not the full MAC) is computed.
|
||||
*/
|
||||
|
||||
-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key);
|
||||
+void poly1305_core_setkey(struct poly1305_core_key *key,
|
||||
+ const u8 raw_key[POLY1305_BLOCK_SIZE]);
|
||||
static inline void poly1305_core_init(struct poly1305_state *state)
|
||||
{
|
||||
*state = (struct poly1305_state){};
|
||||
--- a/include/crypto/poly1305.h
|
||||
+++ b/include/crypto/poly1305.h
|
||||
@@ -58,8 +58,10 @@ struct poly1305_desc_ctx {
|
||||
};
|
||||
};
|
||||
|
||||
-void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key);
|
||||
-void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key);
|
||||
+void poly1305_init_arch(struct poly1305_desc_ctx *desc,
|
||||
+ const u8 key[POLY1305_KEY_SIZE]);
|
||||
+void poly1305_init_generic(struct poly1305_desc_ctx *desc,
|
||||
+ const u8 key[POLY1305_KEY_SIZE]);
|
||||
|
||||
static inline void poly1305_init(struct poly1305_desc_ctx *desc, const u8 *key)
|
||||
{
|
||||
--- a/lib/crypto/poly1305-donna32.c
|
||||
+++ b/lib/crypto/poly1305-donna32.c
|
||||
@@ -10,7 +10,8 @@
|
||||
#include <asm/unaligned.h>
|
||||
#include <crypto/internal/poly1305.h>
|
||||
|
||||
-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16])
|
||||
+void poly1305_core_setkey(struct poly1305_core_key *key,
|
||||
+ const u8 raw_key[POLY1305_BLOCK_SIZE])
|
||||
{
|
||||
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
|
||||
key->key.r[0] = (get_unaligned_le32(&raw_key[0])) & 0x3ffffff;
|
||||
--- a/lib/crypto/poly1305-donna64.c
|
||||
+++ b/lib/crypto/poly1305-donna64.c
|
||||
@@ -12,7 +12,8 @@
|
||||
|
||||
typedef __uint128_t u128;
|
||||
|
||||
-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16])
|
||||
+void poly1305_core_setkey(struct poly1305_core_key *key,
|
||||
+ const u8 raw_key[POLY1305_BLOCK_SIZE])
|
||||
{
|
||||
u64 t0, t1;
|
||||
|
||||
--- a/lib/crypto/poly1305.c
|
||||
+++ b/lib/crypto/poly1305.c
|
||||
@@ -12,7 +12,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
-void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key)
|
||||
+void poly1305_init_generic(struct poly1305_desc_ctx *desc,
|
||||
+ const u8 key[POLY1305_KEY_SIZE])
|
||||
{
|
||||
poly1305_core_setkey(&desc->core_r, key);
|
||||
desc->s[0] = get_unaligned_le32(key + 16);
|
||||
@ -0,0 +1,29 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:30 +0200
|
||||
Subject: [PATCH] wireguard: selftests: remove old conntrack kconfig value
|
||||
|
||||
commit acf2492b51c9a3c4dfb947f4d3477a86d315150f upstream.
|
||||
|
||||
On recent kernels, this config symbol is no longer used.
|
||||
|
||||
Reported-by: Rui Salvaterra <rsalvaterra@gmail.com>
|
||||
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
tools/testing/selftests/wireguard/qemu/kernel.config | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
--- a/tools/testing/selftests/wireguard/qemu/kernel.config
|
||||
+++ b/tools/testing/selftests/wireguard/qemu/kernel.config
|
||||
@@ -19,7 +19,6 @@ CONFIG_NETFILTER_XTABLES=y
|
||||
CONFIG_NETFILTER_XT_NAT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LENGTH=y
|
||||
CONFIG_NETFILTER_XT_MARK=y
|
||||
-CONFIG_NF_CONNTRACK_IPV4=y
|
||||
CONFIG_NF_NAT_IPV4=y
|
||||
CONFIG_IP_NF_IPTABLES=y
|
||||
CONFIG_IP_NF_FILTER=y
|
||||
@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:31 +0200
|
||||
Subject: [PATCH] wireguard: selftests: make sure rp_filter is disabled on
|
||||
vethc
|
||||
|
||||
commit f8873d11d4121aad35024f9379e431e0c83abead upstream.
|
||||
|
||||
Some distros may enable strict rp_filter by default, which will prevent
|
||||
vethc from receiving the packets with an unrouteable reverse path address.
|
||||
|
||||
Reported-by: Hangbin Liu <liuhangbin@gmail.com>
|
||||
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
tools/testing/selftests/wireguard/netns.sh | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/tools/testing/selftests/wireguard/netns.sh
|
||||
+++ b/tools/testing/selftests/wireguard/netns.sh
|
||||
@@ -363,6 +363,7 @@ ip1 -6 rule add table main suppress_pref
|
||||
ip1 -4 route add default dev wg0 table 51820
|
||||
ip1 -4 rule add not fwmark 51820 table 51820
|
||||
ip1 -4 rule add table main suppress_prefixlength 0
|
||||
+n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/vethc/rp_filter'
|
||||
# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
|
||||
n1 ping -W 1 -c 100 -f 192.168.99.7
|
||||
n1 ping -W 1 -c 100 -f abab::1111
|
||||
@ -0,0 +1,33 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:32 +0200
|
||||
Subject: [PATCH] wireguard: do not use -O3
|
||||
|
||||
commit cc5060ca0285efe2728bced399a1955a7ce808b2 upstream.
|
||||
|
||||
Apparently, various versions of gcc have O3-related miscompiles. Looking
|
||||
at the difference between -O2 and -O3 for gcc 11 doesn't indicate
|
||||
miscompiles, but the difference also doesn't seem so significant for
|
||||
performance that it's worth risking.
|
||||
|
||||
Link: https://lore.kernel.org/lkml/CAHk-=wjuoGyxDhAF8SsrTkN0-YfCx7E6jUN3ikC_tn2AKWTTsA@mail.gmail.com/
|
||||
Link: https://lore.kernel.org/lkml/CAHmME9otB5Wwxp7H8bR_i2uH2esEMvoBMC8uEXBMH9p0q1s6Bw@mail.gmail.com/
|
||||
Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
drivers/net/wireguard/Makefile | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireguard/Makefile
|
||||
+++ b/drivers/net/wireguard/Makefile
|
||||
@@ -1,5 +1,4 @@
|
||||
-ccflags-y := -O3
|
||||
-ccflags-y += -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt'
|
||||
+ccflags-y := -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt'
|
||||
ccflags-$(CONFIG_WIREGUARD_DEBUG) += -DDEBUG
|
||||
wireguard-y := main.o
|
||||
wireguard-y += noise.o
|
||||
@ -0,0 +1,66 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:33 +0200
|
||||
Subject: [PATCH] wireguard: use synchronize_net rather than synchronize_rcu
|
||||
|
||||
commit 24b70eeeb4f46c09487f8155239ebfb1f875774a upstream.
|
||||
|
||||
Many of the synchronization points are sometimes called under the rtnl
|
||||
lock, which means we should use synchronize_net rather than
|
||||
synchronize_rcu. Under the hood, this expands to using the expedited
|
||||
flavor of function in the event that rtnl is held, in order to not stall
|
||||
other concurrent changes.
|
||||
|
||||
This fixes some very, very long delays when removing multiple peers at
|
||||
once, which would cause some operations to take several minutes.
|
||||
|
||||
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
drivers/net/wireguard/peer.c | 6 +++---
|
||||
drivers/net/wireguard/socket.c | 2 +-
|
||||
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireguard/peer.c
|
||||
+++ b/drivers/net/wireguard/peer.c
|
||||
@@ -88,7 +88,7 @@ static void peer_make_dead(struct wg_pee
|
||||
/* Mark as dead, so that we don't allow jumping contexts after. */
|
||||
WRITE_ONCE(peer->is_dead, true);
|
||||
|
||||
- /* The caller must now synchronize_rcu() for this to take effect. */
|
||||
+ /* The caller must now synchronize_net() for this to take effect. */
|
||||
}
|
||||
|
||||
static void peer_remove_after_dead(struct wg_peer *peer)
|
||||
@@ -160,7 +160,7 @@ void wg_peer_remove(struct wg_peer *peer
|
||||
lockdep_assert_held(&peer->device->device_update_lock);
|
||||
|
||||
peer_make_dead(peer);
|
||||
- synchronize_rcu();
|
||||
+ synchronize_net();
|
||||
peer_remove_after_dead(peer);
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ void wg_peer_remove_all(struct wg_device
|
||||
peer_make_dead(peer);
|
||||
list_add_tail(&peer->peer_list, &dead_peers);
|
||||
}
|
||||
- synchronize_rcu();
|
||||
+ synchronize_net();
|
||||
list_for_each_entry_safe(peer, temp, &dead_peers, peer_list)
|
||||
peer_remove_after_dead(peer);
|
||||
}
|
||||
--- a/drivers/net/wireguard/socket.c
|
||||
+++ b/drivers/net/wireguard/socket.c
|
||||
@@ -430,7 +430,7 @@ void wg_socket_reinit(struct wg_device *
|
||||
if (new4)
|
||||
wg->incoming_port = ntohs(inet_sk(new4)->inet_sport);
|
||||
mutex_unlock(&wg->socket_update_lock);
|
||||
- synchronize_rcu();
|
||||
+ synchronize_net();
|
||||
sock_free(old4);
|
||||
sock_free(old6);
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:34 +0200
|
||||
Subject: [PATCH] wireguard: peer: allocate in kmem_cache
|
||||
|
||||
commit a4e9f8e3287c9eb6bf70df982870980dd3341863 upstream.
|
||||
|
||||
With deployments having upwards of 600k peers now, this somewhat heavy
|
||||
structure could benefit from more fine-grained allocations.
|
||||
Specifically, instead of using a 2048-byte slab for a 1544-byte object,
|
||||
we can now use 1544-byte objects directly, thus saving almost 25%
|
||||
per-peer, or with 600k peers, that's a savings of 303 MiB. This also
|
||||
makes wireguard's memory usage more transparent in tools like slabtop
|
||||
and /proc/slabinfo.
|
||||
|
||||
Fixes: 8b5553ace83c ("wireguard: queueing: get rid of per-peer ring buffers")
|
||||
Suggested-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Suggested-by: Matthew Wilcox <willy@infradead.org>
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
drivers/net/wireguard/main.c | 7 +++++++
|
||||
drivers/net/wireguard/peer.c | 21 +++++++++++++++++----
|
||||
drivers/net/wireguard/peer.h | 3 +++
|
||||
3 files changed, 27 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireguard/main.c
|
||||
+++ b/drivers/net/wireguard/main.c
|
||||
@@ -28,6 +28,10 @@ static int __init mod_init(void)
|
||||
#endif
|
||||
wg_noise_init();
|
||||
|
||||
+ ret = wg_peer_init();
|
||||
+ if (ret < 0)
|
||||
+ goto err_peer;
|
||||
+
|
||||
ret = wg_device_init();
|
||||
if (ret < 0)
|
||||
goto err_device;
|
||||
@@ -44,6 +48,8 @@ static int __init mod_init(void)
|
||||
err_netlink:
|
||||
wg_device_uninit();
|
||||
err_device:
|
||||
+ wg_peer_uninit();
|
||||
+err_peer:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -51,6 +57,7 @@ static void __exit mod_exit(void)
|
||||
{
|
||||
wg_genetlink_uninit();
|
||||
wg_device_uninit();
|
||||
+ wg_peer_uninit();
|
||||
}
|
||||
|
||||
module_init(mod_init);
|
||||
--- a/drivers/net/wireguard/peer.c
|
||||
+++ b/drivers/net/wireguard/peer.c
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
+static struct kmem_cache *peer_cache;
|
||||
static atomic64_t peer_counter = ATOMIC64_INIT(0);
|
||||
|
||||
struct wg_peer *wg_peer_create(struct wg_device *wg,
|
||||
@@ -29,10 +30,10 @@ struct wg_peer *wg_peer_create(struct wg
|
||||
if (wg->num_peers >= MAX_PEERS_PER_DEVICE)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
- peer = kzalloc(sizeof(*peer), GFP_KERNEL);
|
||||
+ peer = kmem_cache_zalloc(peer_cache, GFP_KERNEL);
|
||||
if (unlikely(!peer))
|
||||
return ERR_PTR(ret);
|
||||
- if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
|
||||
+ if (unlikely(dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)))
|
||||
goto err;
|
||||
|
||||
peer->device = wg;
|
||||
@@ -64,7 +65,7 @@ struct wg_peer *wg_peer_create(struct wg
|
||||
return peer;
|
||||
|
||||
err:
|
||||
- kfree(peer);
|
||||
+ kmem_cache_free(peer_cache, peer);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@@ -193,7 +194,8 @@ static void rcu_release(struct rcu_head
|
||||
/* The final zeroing takes care of clearing any remaining handshake key
|
||||
* material and other potentially sensitive information.
|
||||
*/
|
||||
- kzfree(peer);
|
||||
+ memzero_explicit(peer, sizeof(*peer));
|
||||
+ kmem_cache_free(peer_cache, peer);
|
||||
}
|
||||
|
||||
static void kref_release(struct kref *refcount)
|
||||
@@ -225,3 +227,14 @@ void wg_peer_put(struct wg_peer *peer)
|
||||
return;
|
||||
kref_put(&peer->refcount, kref_release);
|
||||
}
|
||||
+
|
||||
+int __init wg_peer_init(void)
|
||||
+{
|
||||
+ peer_cache = KMEM_CACHE(wg_peer, 0);
|
||||
+ return peer_cache ? 0 : -ENOMEM;
|
||||
+}
|
||||
+
|
||||
+void wg_peer_uninit(void)
|
||||
+{
|
||||
+ kmem_cache_destroy(peer_cache);
|
||||
+}
|
||||
--- a/drivers/net/wireguard/peer.h
|
||||
+++ b/drivers/net/wireguard/peer.h
|
||||
@@ -80,4 +80,7 @@ void wg_peer_put(struct wg_peer *peer);
|
||||
void wg_peer_remove(struct wg_peer *peer);
|
||||
void wg_peer_remove_all(struct wg_device *wg);
|
||||
|
||||
+int wg_peer_init(void);
|
||||
+void wg_peer_uninit(void);
|
||||
+
|
||||
#endif /* _WG_PEER_H */
|
||||
@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:35 +0200
|
||||
Subject: [PATCH] wireguard: allowedips: initialize list head in selftest
|
||||
|
||||
commit 46cfe8eee285cde465b420637507884551f5d7ca upstream.
|
||||
|
||||
The randomized trie tests weren't initializing the dummy peer list head,
|
||||
resulting in a NULL pointer dereference when used. Fix this by
|
||||
initializing it in the randomized trie test, just like we do for the
|
||||
static unit test.
|
||||
|
||||
While we're at it, all of the other strings like this have the word
|
||||
"self-test", so add it to the missing place here.
|
||||
|
||||
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
drivers/net/wireguard/selftest/allowedips.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/wireguard/selftest/allowedips.c
|
||||
+++ b/drivers/net/wireguard/selftest/allowedips.c
|
||||
@@ -296,6 +296,7 @@ static __init bool randomized_test(void)
|
||||
goto free;
|
||||
}
|
||||
kref_init(&peers[i]->refcount);
|
||||
+ INIT_LIST_HEAD(&peers[i]->allowedips_list);
|
||||
}
|
||||
|
||||
mutex_lock(&mutex);
|
||||
@@ -333,7 +334,7 @@ static __init bool randomized_test(void)
|
||||
if (wg_allowedips_insert_v4(&t,
|
||||
(struct in_addr *)mutated,
|
||||
cidr, peer, &mutex) < 0) {
|
||||
- pr_err("allowedips random malloc: FAIL\n");
|
||||
+ pr_err("allowedips random self-test malloc: FAIL\n");
|
||||
goto free_locked;
|
||||
}
|
||||
if (horrible_allowedips_insert_v4(&h,
|
||||
@ -0,0 +1,237 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:36 +0200
|
||||
Subject: [PATCH] wireguard: allowedips: remove nodes in O(1)
|
||||
|
||||
commit f634f418c227c912e7ea95a3299efdc9b10e4022 upstream.
|
||||
|
||||
Previously, deleting peers would require traversing the entire trie in
|
||||
order to rebalance nodes and safely free them. This meant that removing
|
||||
1000 peers from a trie with a half million nodes would take an extremely
|
||||
long time, during which we're holding the rtnl lock. Large-scale users
|
||||
were reporting 200ms latencies added to the networking stack as a whole
|
||||
every time their userspace software would queue up significant removals.
|
||||
That's a serious situation.
|
||||
|
||||
This commit fixes that by maintaining a double pointer to the parent's
|
||||
bit pointer for each node, and then using the already existing node list
|
||||
belonging to each peer to go directly to the node, fix up its pointers,
|
||||
and free it with RCU. This means removal is O(1) instead of O(n), and we
|
||||
don't use gobs of stack.
|
||||
|
||||
The removal algorithm has the same downside as the code that it fixes:
|
||||
it won't collapse needlessly long runs of fillers. We can enhance that
|
||||
in the future if it ever becomes a problem. This commit documents that
|
||||
limitation with a TODO comment in code, a small but meaningful
|
||||
improvement over the prior situation.
|
||||
|
||||
Currently the biggest flaw, which the next commit addresses, is that
|
||||
because this increases the node size on 64-bit machines from 60 bytes to
|
||||
68 bytes. 60 rounds up to 64, but 68 rounds up to 128. So we wind up
|
||||
using twice as much memory per node, because of power-of-two
|
||||
allocations, which is a big bummer. We'll need to figure something out
|
||||
there.
|
||||
|
||||
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
drivers/net/wireguard/allowedips.c | 132 ++++++++++++-----------------
|
||||
drivers/net/wireguard/allowedips.h | 9 +-
|
||||
2 files changed, 57 insertions(+), 84 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireguard/allowedips.c
|
||||
+++ b/drivers/net/wireguard/allowedips.c
|
||||
@@ -66,60 +66,6 @@ static void root_remove_peer_lists(struc
|
||||
}
|
||||
}
|
||||
|
||||
-static void walk_remove_by_peer(struct allowedips_node __rcu **top,
|
||||
- struct wg_peer *peer, struct mutex *lock)
|
||||
-{
|
||||
-#define REF(p) rcu_access_pointer(p)
|
||||
-#define DEREF(p) rcu_dereference_protected(*(p), lockdep_is_held(lock))
|
||||
-#define PUSH(p) ({ \
|
||||
- WARN_ON(IS_ENABLED(DEBUG) && len >= 128); \
|
||||
- stack[len++] = p; \
|
||||
- })
|
||||
-
|
||||
- struct allowedips_node __rcu **stack[128], **nptr;
|
||||
- struct allowedips_node *node, *prev;
|
||||
- unsigned int len;
|
||||
-
|
||||
- if (unlikely(!peer || !REF(*top)))
|
||||
- return;
|
||||
-
|
||||
- for (prev = NULL, len = 0, PUSH(top); len > 0; prev = node) {
|
||||
- nptr = stack[len - 1];
|
||||
- node = DEREF(nptr);
|
||||
- if (!node) {
|
||||
- --len;
|
||||
- continue;
|
||||
- }
|
||||
- if (!prev || REF(prev->bit[0]) == node ||
|
||||
- REF(prev->bit[1]) == node) {
|
||||
- if (REF(node->bit[0]))
|
||||
- PUSH(&node->bit[0]);
|
||||
- else if (REF(node->bit[1]))
|
||||
- PUSH(&node->bit[1]);
|
||||
- } else if (REF(node->bit[0]) == prev) {
|
||||
- if (REF(node->bit[1]))
|
||||
- PUSH(&node->bit[1]);
|
||||
- } else {
|
||||
- if (rcu_dereference_protected(node->peer,
|
||||
- lockdep_is_held(lock)) == peer) {
|
||||
- RCU_INIT_POINTER(node->peer, NULL);
|
||||
- list_del_init(&node->peer_list);
|
||||
- if (!node->bit[0] || !node->bit[1]) {
|
||||
- rcu_assign_pointer(*nptr, DEREF(
|
||||
- &node->bit[!REF(node->bit[0])]));
|
||||
- kfree_rcu(node, rcu);
|
||||
- node = DEREF(nptr);
|
||||
- }
|
||||
- }
|
||||
- --len;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
-#undef REF
|
||||
-#undef DEREF
|
||||
-#undef PUSH
|
||||
-}
|
||||
-
|
||||
static unsigned int fls128(u64 a, u64 b)
|
||||
{
|
||||
return a ? fls64(a) + 64U : fls64(b);
|
||||
@@ -224,6 +170,7 @@ static int add(struct allowedips_node __
|
||||
RCU_INIT_POINTER(node->peer, peer);
|
||||
list_add_tail(&node->peer_list, &peer->allowedips_list);
|
||||
copy_and_assign_cidr(node, key, cidr, bits);
|
||||
+ rcu_assign_pointer(node->parent_bit, trie);
|
||||
rcu_assign_pointer(*trie, node);
|
||||
return 0;
|
||||
}
|
||||
@@ -243,9 +190,9 @@ static int add(struct allowedips_node __
|
||||
if (!node) {
|
||||
down = rcu_dereference_protected(*trie, lockdep_is_held(lock));
|
||||
} else {
|
||||
- down = rcu_dereference_protected(CHOOSE_NODE(node, key),
|
||||
- lockdep_is_held(lock));
|
||||
+ down = rcu_dereference_protected(CHOOSE_NODE(node, key), lockdep_is_held(lock));
|
||||
if (!down) {
|
||||
+ rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, key));
|
||||
rcu_assign_pointer(CHOOSE_NODE(node, key), newnode);
|
||||
return 0;
|
||||
}
|
||||
@@ -254,29 +201,37 @@ static int add(struct allowedips_node __
|
||||
parent = node;
|
||||
|
||||
if (newnode->cidr == cidr) {
|
||||
+ rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(newnode, down->bits));
|
||||
rcu_assign_pointer(CHOOSE_NODE(newnode, down->bits), down);
|
||||
- if (!parent)
|
||||
+ if (!parent) {
|
||||
+ rcu_assign_pointer(newnode->parent_bit, trie);
|
||||
rcu_assign_pointer(*trie, newnode);
|
||||
- else
|
||||
- rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits),
|
||||
- newnode);
|
||||
- } else {
|
||||
- node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||||
- if (unlikely(!node)) {
|
||||
- list_del(&newnode->peer_list);
|
||||
- kfree(newnode);
|
||||
- return -ENOMEM;
|
||||
+ } else {
|
||||
+ rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(parent, newnode->bits));
|
||||
+ rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits), newnode);
|
||||
}
|
||||
- INIT_LIST_HEAD(&node->peer_list);
|
||||
- copy_and_assign_cidr(node, newnode->bits, cidr, bits);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||||
+ if (unlikely(!node)) {
|
||||
+ list_del(&newnode->peer_list);
|
||||
+ kfree(newnode);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+ INIT_LIST_HEAD(&node->peer_list);
|
||||
+ copy_and_assign_cidr(node, newnode->bits, cidr, bits);
|
||||
|
||||
- rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down);
|
||||
- rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode);
|
||||
- if (!parent)
|
||||
- rcu_assign_pointer(*trie, node);
|
||||
- else
|
||||
- rcu_assign_pointer(CHOOSE_NODE(parent, node->bits),
|
||||
- node);
|
||||
+ rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(node, down->bits));
|
||||
+ rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down);
|
||||
+ rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, newnode->bits));
|
||||
+ rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode);
|
||||
+ if (!parent) {
|
||||
+ rcu_assign_pointer(node->parent_bit, trie);
|
||||
+ rcu_assign_pointer(*trie, node);
|
||||
+ } else {
|
||||
+ rcu_assign_pointer(node->parent_bit, &CHOOSE_NODE(parent, node->bits));
|
||||
+ rcu_assign_pointer(CHOOSE_NODE(parent, node->bits), node);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -335,9 +290,30 @@ int wg_allowedips_insert_v6(struct allow
|
||||
void wg_allowedips_remove_by_peer(struct allowedips *table,
|
||||
struct wg_peer *peer, struct mutex *lock)
|
||||
{
|
||||
+ struct allowedips_node *node, *child, *tmp;
|
||||
+
|
||||
+ if (list_empty(&peer->allowedips_list))
|
||||
+ return;
|
||||
++table->seq;
|
||||
- walk_remove_by_peer(&table->root4, peer, lock);
|
||||
- walk_remove_by_peer(&table->root6, peer, lock);
|
||||
+ list_for_each_entry_safe(node, tmp, &peer->allowedips_list, peer_list) {
|
||||
+ list_del_init(&node->peer_list);
|
||||
+ RCU_INIT_POINTER(node->peer, NULL);
|
||||
+ if (node->bit[0] && node->bit[1])
|
||||
+ continue;
|
||||
+ child = rcu_dereference_protected(
|
||||
+ node->bit[!rcu_access_pointer(node->bit[0])],
|
||||
+ lockdep_is_held(lock));
|
||||
+ if (child)
|
||||
+ child->parent_bit = node->parent_bit;
|
||||
+ *rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child;
|
||||
+ kfree_rcu(node, rcu);
|
||||
+
|
||||
+ /* TODO: Note that we currently don't walk up and down in order to
|
||||
+ * free any potential filler nodes. This means that this function
|
||||
+ * doesn't free up as much as it could, which could be revisited
|
||||
+ * at some point.
|
||||
+ */
|
||||
+ }
|
||||
}
|
||||
|
||||
int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr)
|
||||
--- a/drivers/net/wireguard/allowedips.h
|
||||
+++ b/drivers/net/wireguard/allowedips.h
|
||||
@@ -15,14 +15,11 @@ struct wg_peer;
|
||||
struct allowedips_node {
|
||||
struct wg_peer __rcu *peer;
|
||||
struct allowedips_node __rcu *bit[2];
|
||||
- /* While it may seem scandalous that we waste space for v4,
|
||||
- * we're alloc'ing to the nearest power of 2 anyway, so this
|
||||
- * doesn't actually make a difference.
|
||||
- */
|
||||
- u8 bits[16] __aligned(__alignof(u64));
|
||||
u8 cidr, bit_at_a, bit_at_b, bitlen;
|
||||
+ u8 bits[16] __aligned(__alignof(u64));
|
||||
|
||||
- /* Keep rarely used list at bottom to be beyond cache line. */
|
||||
+ /* Keep rarely used members at bottom to be beyond cache line. */
|
||||
+ struct allowedips_node *__rcu *parent_bit; /* XXX: this puts us at 68->128 bytes instead of 60->64 bytes!! */
|
||||
union {
|
||||
struct list_head peer_list;
|
||||
struct rcu_head rcu;
|
||||
@ -0,0 +1,173 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:37 +0200
|
||||
Subject: [PATCH] wireguard: allowedips: allocate nodes in kmem_cache
|
||||
|
||||
commit dc680de28ca849dfe589dc15ac56d22505f0ef11 upstream.
|
||||
|
||||
The previous commit moved from O(n) to O(1) for removal, but in the
|
||||
process introduced an additional pointer member to a struct that
|
||||
increased the size from 60 to 68 bytes, putting nodes in the 128-byte
|
||||
slab. With deployed systems having as many as 2 million nodes, this
|
||||
represents a significant doubling in memory usage (128 MiB -> 256 MiB).
|
||||
Fix this by using our own kmem_cache, that's sized exactly right. This
|
||||
also makes wireguard's memory usage more transparent in tools like
|
||||
slabtop and /proc/slabinfo.
|
||||
|
||||
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
|
||||
Suggested-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Suggested-by: Matthew Wilcox <willy@infradead.org>
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
drivers/net/wireguard/allowedips.c | 31 ++++++++++++++++++++++++------
|
||||
drivers/net/wireguard/allowedips.h | 5 ++++-
|
||||
drivers/net/wireguard/main.c | 10 +++++++++-
|
||||
3 files changed, 38 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireguard/allowedips.c
|
||||
+++ b/drivers/net/wireguard/allowedips.c
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "allowedips.h"
|
||||
#include "peer.h"
|
||||
|
||||
+static struct kmem_cache *node_cache;
|
||||
+
|
||||
static void swap_endian(u8 *dst, const u8 *src, u8 bits)
|
||||
{
|
||||
if (bits == 32) {
|
||||
@@ -40,6 +42,11 @@ static void push_rcu(struct allowedips_n
|
||||
}
|
||||
}
|
||||
|
||||
+static void node_free_rcu(struct rcu_head *rcu)
|
||||
+{
|
||||
+ kmem_cache_free(node_cache, container_of(rcu, struct allowedips_node, rcu));
|
||||
+}
|
||||
+
|
||||
static void root_free_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct allowedips_node *node, *stack[128] = {
|
||||
@@ -49,7 +56,7 @@ static void root_free_rcu(struct rcu_hea
|
||||
while (len > 0 && (node = stack[--len])) {
|
||||
push_rcu(stack, node->bit[0], &len);
|
||||
push_rcu(stack, node->bit[1], &len);
|
||||
- kfree(node);
|
||||
+ kmem_cache_free(node_cache, node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +171,7 @@ static int add(struct allowedips_node __
|
||||
return -EINVAL;
|
||||
|
||||
if (!rcu_access_pointer(*trie)) {
|
||||
- node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||||
+ node = kmem_cache_zalloc(node_cache, GFP_KERNEL);
|
||||
if (unlikely(!node))
|
||||
return -ENOMEM;
|
||||
RCU_INIT_POINTER(node->peer, peer);
|
||||
@@ -180,7 +187,7 @@ static int add(struct allowedips_node __
|
||||
return 0;
|
||||
}
|
||||
|
||||
- newnode = kzalloc(sizeof(*newnode), GFP_KERNEL);
|
||||
+ newnode = kmem_cache_zalloc(node_cache, GFP_KERNEL);
|
||||
if (unlikely(!newnode))
|
||||
return -ENOMEM;
|
||||
RCU_INIT_POINTER(newnode->peer, peer);
|
||||
@@ -213,10 +220,10 @@ static int add(struct allowedips_node __
|
||||
return 0;
|
||||
}
|
||||
|
||||
- node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||||
+ node = kmem_cache_zalloc(node_cache, GFP_KERNEL);
|
||||
if (unlikely(!node)) {
|
||||
list_del(&newnode->peer_list);
|
||||
- kfree(newnode);
|
||||
+ kmem_cache_free(node_cache, newnode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_LIST_HEAD(&node->peer_list);
|
||||
@@ -306,7 +313,7 @@ void wg_allowedips_remove_by_peer(struct
|
||||
if (child)
|
||||
child->parent_bit = node->parent_bit;
|
||||
*rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child;
|
||||
- kfree_rcu(node, rcu);
|
||||
+ call_rcu(&node->rcu, node_free_rcu);
|
||||
|
||||
/* TODO: Note that we currently don't walk up and down in order to
|
||||
* free any potential filler nodes. This means that this function
|
||||
@@ -350,4 +357,16 @@ struct wg_peer *wg_allowedips_lookup_src
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+int __init wg_allowedips_slab_init(void)
|
||||
+{
|
||||
+ node_cache = KMEM_CACHE(allowedips_node, 0);
|
||||
+ return node_cache ? 0 : -ENOMEM;
|
||||
+}
|
||||
+
|
||||
+void wg_allowedips_slab_uninit(void)
|
||||
+{
|
||||
+ rcu_barrier();
|
||||
+ kmem_cache_destroy(node_cache);
|
||||
+}
|
||||
+
|
||||
#include "selftest/allowedips.c"
|
||||
--- a/drivers/net/wireguard/allowedips.h
|
||||
+++ b/drivers/net/wireguard/allowedips.h
|
||||
@@ -19,7 +19,7 @@ struct allowedips_node {
|
||||
u8 bits[16] __aligned(__alignof(u64));
|
||||
|
||||
/* Keep rarely used members at bottom to be beyond cache line. */
|
||||
- struct allowedips_node *__rcu *parent_bit; /* XXX: this puts us at 68->128 bytes instead of 60->64 bytes!! */
|
||||
+ struct allowedips_node *__rcu *parent_bit;
|
||||
union {
|
||||
struct list_head peer_list;
|
||||
struct rcu_head rcu;
|
||||
@@ -53,4 +53,7 @@ struct wg_peer *wg_allowedips_lookup_src
|
||||
bool wg_allowedips_selftest(void);
|
||||
#endif
|
||||
|
||||
+int wg_allowedips_slab_init(void);
|
||||
+void wg_allowedips_slab_uninit(void);
|
||||
+
|
||||
#endif /* _WG_ALLOWEDIPS_H */
|
||||
--- a/drivers/net/wireguard/main.c
|
||||
+++ b/drivers/net/wireguard/main.c
|
||||
@@ -21,10 +21,15 @@ static int __init mod_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
+ ret = wg_allowedips_slab_init();
|
||||
+ if (ret < 0)
|
||||
+ goto err_allowedips;
|
||||
+
|
||||
#ifdef DEBUG
|
||||
+ ret = -ENOTRECOVERABLE;
|
||||
if (!wg_allowedips_selftest() || !wg_packet_counter_selftest() ||
|
||||
!wg_ratelimiter_selftest())
|
||||
- return -ENOTRECOVERABLE;
|
||||
+ goto err_peer;
|
||||
#endif
|
||||
wg_noise_init();
|
||||
|
||||
@@ -50,6 +55,8 @@ err_netlink:
|
||||
err_device:
|
||||
wg_peer_uninit();
|
||||
err_peer:
|
||||
+ wg_allowedips_slab_uninit();
|
||||
+err_allowedips:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -58,6 +65,7 @@ static void __exit mod_exit(void)
|
||||
wg_genetlink_uninit();
|
||||
wg_device_uninit();
|
||||
wg_peer_uninit();
|
||||
+ wg_allowedips_slab_uninit();
|
||||
}
|
||||
|
||||
module_init(mod_init);
|
||||
@ -0,0 +1,521 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
|
||||
Date: Fri, 4 Jun 2021 17:17:38 +0200
|
||||
Subject: [PATCH] wireguard: allowedips: free empty intermediate nodes when
|
||||
removing single node
|
||||
|
||||
commit bf7b042dc62a31f66d3a41dd4dfc7806f267b307 upstream.
|
||||
|
||||
When removing single nodes, it's possible that that node's parent is an
|
||||
empty intermediate node, in which case, it too should be removed.
|
||||
Otherwise the trie fills up and never is fully emptied, leading to
|
||||
gradual memory leaks over time for tries that are modified often. There
|
||||
was originally code to do this, but was removed during refactoring in
|
||||
2016 and never reworked. Now that we have proper parent pointers from
|
||||
the previous commits, we can implement this properly.
|
||||
|
||||
In order to reduce branching and expensive comparisons, we want to keep
|
||||
the double pointer for parent assignment (which lets us easily chain up
|
||||
to the root), but we still need to actually get the parent's base
|
||||
address. So encode the bit number into the last two bits of the pointer,
|
||||
and pack and unpack it as needed. This is a little bit clumsy but is the
|
||||
fastest and less memory wasteful of the compromises. Note that we align
|
||||
the root struct here to a minimum of 4, because it's embedded into a
|
||||
larger struct, and we're relying on having the bottom two bits for our
|
||||
flag, which would only be 16-bit aligned on m68k.
|
||||
|
||||
The existing macro-based helpers were a bit unwieldy for adding the bit
|
||||
packing to, so this commit replaces them with safer and clearer ordinary
|
||||
functions.
|
||||
|
||||
We add a test to the randomized/fuzzer part of the selftests, to free
|
||||
the randomized tries by-peer, refuzz it, and repeat, until it's supposed
|
||||
to be empty, and then then see if that actually resulted in the whole
|
||||
thing being emptied. That combined with kmemcheck should hopefully make
|
||||
sure this commit is doing what it should. Along the way this resulted in
|
||||
various other cleanups of the tests and fixes for recent graphviz.
|
||||
|
||||
Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
|
||||
---
|
||||
drivers/net/wireguard/allowedips.c | 102 ++++++------
|
||||
drivers/net/wireguard/allowedips.h | 4 +-
|
||||
drivers/net/wireguard/selftest/allowedips.c | 162 ++++++++++----------
|
||||
3 files changed, 137 insertions(+), 131 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireguard/allowedips.c
|
||||
+++ b/drivers/net/wireguard/allowedips.c
|
||||
@@ -30,8 +30,11 @@ static void copy_and_assign_cidr(struct
|
||||
node->bitlen = bits;
|
||||
memcpy(node->bits, src, bits / 8U);
|
||||
}
|
||||
-#define CHOOSE_NODE(parent, key) \
|
||||
- parent->bit[(key[parent->bit_at_a] >> parent->bit_at_b) & 1]
|
||||
+
|
||||
+static inline u8 choose(struct allowedips_node *node, const u8 *key)
|
||||
+{
|
||||
+ return (key[node->bit_at_a] >> node->bit_at_b) & 1;
|
||||
+}
|
||||
|
||||
static void push_rcu(struct allowedips_node **stack,
|
||||
struct allowedips_node __rcu *p, unsigned int *len)
|
||||
@@ -112,7 +115,7 @@ static struct allowedips_node *find_node
|
||||
found = node;
|
||||
if (node->cidr == bits)
|
||||
break;
|
||||
- node = rcu_dereference_bh(CHOOSE_NODE(node, key));
|
||||
+ node = rcu_dereference_bh(node->bit[choose(node, key)]);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
@@ -144,8 +147,7 @@ static bool node_placement(struct allowe
|
||||
u8 cidr, u8 bits, struct allowedips_node **rnode,
|
||||
struct mutex *lock)
|
||||
{
|
||||
- struct allowedips_node *node = rcu_dereference_protected(trie,
|
||||
- lockdep_is_held(lock));
|
||||
+ struct allowedips_node *node = rcu_dereference_protected(trie, lockdep_is_held(lock));
|
||||
struct allowedips_node *parent = NULL;
|
||||
bool exact = false;
|
||||
|
||||
@@ -155,13 +157,24 @@ static bool node_placement(struct allowe
|
||||
exact = true;
|
||||
break;
|
||||
}
|
||||
- node = rcu_dereference_protected(CHOOSE_NODE(parent, key),
|
||||
- lockdep_is_held(lock));
|
||||
+ node = rcu_dereference_protected(parent->bit[choose(parent, key)], lockdep_is_held(lock));
|
||||
}
|
||||
*rnode = parent;
|
||||
return exact;
|
||||
}
|
||||
|
||||
+static inline void connect_node(struct allowedips_node **parent, u8 bit, struct allowedips_node *node)
|
||||
+{
|
||||
+ node->parent_bit_packed = (unsigned long)parent | bit;
|
||||
+ rcu_assign_pointer(*parent, node);
|
||||
+}
|
||||
+
|
||||
+static inline void choose_and_connect_node(struct allowedips_node *parent, struct allowedips_node *node)
|
||||
+{
|
||||
+ u8 bit = choose(parent, node->bits);
|
||||
+ connect_node(&parent->bit[bit], bit, node);
|
||||
+}
|
||||
+
|
||||
static int add(struct allowedips_node __rcu **trie, u8 bits, const u8 *key,
|
||||
u8 cidr, struct wg_peer *peer, struct mutex *lock)
|
||||
{
|
||||
@@ -177,8 +190,7 @@ static int add(struct allowedips_node __
|
||||
RCU_INIT_POINTER(node->peer, peer);
|
||||
list_add_tail(&node->peer_list, &peer->allowedips_list);
|
||||
copy_and_assign_cidr(node, key, cidr, bits);
|
||||
- rcu_assign_pointer(node->parent_bit, trie);
|
||||
- rcu_assign_pointer(*trie, node);
|
||||
+ connect_node(trie, 2, node);
|
||||
return 0;
|
||||
}
|
||||
if (node_placement(*trie, key, cidr, bits, &node, lock)) {
|
||||
@@ -197,10 +209,10 @@ static int add(struct allowedips_node __
|
||||
if (!node) {
|
||||
down = rcu_dereference_protected(*trie, lockdep_is_held(lock));
|
||||
} else {
|
||||
- down = rcu_dereference_protected(CHOOSE_NODE(node, key), lockdep_is_held(lock));
|
||||
+ const u8 bit = choose(node, key);
|
||||
+ down = rcu_dereference_protected(node->bit[bit], lockdep_is_held(lock));
|
||||
if (!down) {
|
||||
- rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, key));
|
||||
- rcu_assign_pointer(CHOOSE_NODE(node, key), newnode);
|
||||
+ connect_node(&node->bit[bit], bit, newnode);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -208,15 +220,11 @@ static int add(struct allowedips_node __
|
||||
parent = node;
|
||||
|
||||
if (newnode->cidr == cidr) {
|
||||
- rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(newnode, down->bits));
|
||||
- rcu_assign_pointer(CHOOSE_NODE(newnode, down->bits), down);
|
||||
- if (!parent) {
|
||||
- rcu_assign_pointer(newnode->parent_bit, trie);
|
||||
- rcu_assign_pointer(*trie, newnode);
|
||||
- } else {
|
||||
- rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(parent, newnode->bits));
|
||||
- rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits), newnode);
|
||||
- }
|
||||
+ choose_and_connect_node(newnode, down);
|
||||
+ if (!parent)
|
||||
+ connect_node(trie, 2, newnode);
|
||||
+ else
|
||||
+ choose_and_connect_node(parent, newnode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -229,17 +237,12 @@ static int add(struct allowedips_node __
|
||||
INIT_LIST_HEAD(&node->peer_list);
|
||||
copy_and_assign_cidr(node, newnode->bits, cidr, bits);
|
||||
|
||||
- rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(node, down->bits));
|
||||
- rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down);
|
||||
- rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, newnode->bits));
|
||||
- rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode);
|
||||
- if (!parent) {
|
||||
- rcu_assign_pointer(node->parent_bit, trie);
|
||||
- rcu_assign_pointer(*trie, node);
|
||||
- } else {
|
||||
- rcu_assign_pointer(node->parent_bit, &CHOOSE_NODE(parent, node->bits));
|
||||
- rcu_assign_pointer(CHOOSE_NODE(parent, node->bits), node);
|
||||
- }
|
||||
+ choose_and_connect_node(node, down);
|
||||
+ choose_and_connect_node(node, newnode);
|
||||
+ if (!parent)
|
||||
+ connect_node(trie, 2, node);
|
||||
+ else
|
||||
+ choose_and_connect_node(parent, node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -297,7 +300,8 @@ int wg_allowedips_insert_v6(struct allow
|
||||
void wg_allowedips_remove_by_peer(struct allowedips *table,
|
||||
struct wg_peer *peer, struct mutex *lock)
|
||||
{
|
||||
- struct allowedips_node *node, *child, *tmp;
|
||||
+ struct allowedips_node *node, *child, **parent_bit, *parent, *tmp;
|
||||
+ bool free_parent;
|
||||
|
||||
if (list_empty(&peer->allowedips_list))
|
||||
return;
|
||||
@@ -307,19 +311,29 @@ void wg_allowedips_remove_by_peer(struct
|
||||
RCU_INIT_POINTER(node->peer, NULL);
|
||||
if (node->bit[0] && node->bit[1])
|
||||
continue;
|
||||
- child = rcu_dereference_protected(
|
||||
- node->bit[!rcu_access_pointer(node->bit[0])],
|
||||
- lockdep_is_held(lock));
|
||||
+ child = rcu_dereference_protected(node->bit[!rcu_access_pointer(node->bit[0])],
|
||||
+ lockdep_is_held(lock));
|
||||
if (child)
|
||||
- child->parent_bit = node->parent_bit;
|
||||
- *rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child;
|
||||
+ child->parent_bit_packed = node->parent_bit_packed;
|
||||
+ parent_bit = (struct allowedips_node **)(node->parent_bit_packed & ~3UL);
|
||||
+ *parent_bit = child;
|
||||
+ parent = (void *)parent_bit -
|
||||
+ offsetof(struct allowedips_node, bit[node->parent_bit_packed & 1]);
|
||||
+ free_parent = !rcu_access_pointer(node->bit[0]) &&
|
||||
+ !rcu_access_pointer(node->bit[1]) &&
|
||||
+ (node->parent_bit_packed & 3) <= 1 &&
|
||||
+ !rcu_access_pointer(parent->peer);
|
||||
+ if (free_parent)
|
||||
+ child = rcu_dereference_protected(
|
||||
+ parent->bit[!(node->parent_bit_packed & 1)],
|
||||
+ lockdep_is_held(lock));
|
||||
call_rcu(&node->rcu, node_free_rcu);
|
||||
-
|
||||
- /* TODO: Note that we currently don't walk up and down in order to
|
||||
- * free any potential filler nodes. This means that this function
|
||||
- * doesn't free up as much as it could, which could be revisited
|
||||
- * at some point.
|
||||
- */
|
||||
+ if (!free_parent)
|
||||
+ continue;
|
||||
+ if (child)
|
||||
+ child->parent_bit_packed = parent->parent_bit_packed;
|
||||
+ *(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child;
|
||||
+ call_rcu(&parent->rcu, node_free_rcu);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireguard/allowedips.h
|
||||
+++ b/drivers/net/wireguard/allowedips.h
|
||||
@@ -19,7 +19,7 @@ struct allowedips_node {
|
||||
u8 bits[16] __aligned(__alignof(u64));
|
||||
|
||||
/* Keep rarely used members at bottom to be beyond cache line. */
|
||||
- struct allowedips_node *__rcu *parent_bit;
|
||||
+ unsigned long parent_bit_packed;
|
||||
union {
|
||||
struct list_head peer_list;
|
||||
struct rcu_head rcu;
|
||||
@@ -30,7 +30,7 @@ struct allowedips {
|
||||
struct allowedips_node __rcu *root4;
|
||||
struct allowedips_node __rcu *root6;
|
||||
u64 seq;
|
||||
-};
|
||||
+} __aligned(4); /* We pack the lower 2 bits of &root, but m68k only gives 16-bit alignment. */
|
||||
|
||||
void wg_allowedips_init(struct allowedips *table);
|
||||
void wg_allowedips_free(struct allowedips *table, struct mutex *mutex);
|
||||
--- a/drivers/net/wireguard/selftest/allowedips.c
|
||||
+++ b/drivers/net/wireguard/selftest/allowedips.c
|
||||
@@ -19,32 +19,22 @@
|
||||
|
||||
#include <linux/siphash.h>
|
||||
|
||||
-static __init void swap_endian_and_apply_cidr(u8 *dst, const u8 *src, u8 bits,
|
||||
- u8 cidr)
|
||||
-{
|
||||
- swap_endian(dst, src, bits);
|
||||
- memset(dst + (cidr + 7) / 8, 0, bits / 8 - (cidr + 7) / 8);
|
||||
- if (cidr)
|
||||
- dst[(cidr + 7) / 8 - 1] &= ~0U << ((8 - (cidr % 8)) % 8);
|
||||
-}
|
||||
-
|
||||
static __init void print_node(struct allowedips_node *node, u8 bits)
|
||||
{
|
||||
char *fmt_connection = KERN_DEBUG "\t\"%p/%d\" -> \"%p/%d\";\n";
|
||||
- char *fmt_declaration = KERN_DEBUG
|
||||
- "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n";
|
||||
+ char *fmt_declaration = KERN_DEBUG "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n";
|
||||
+ u8 ip1[16], ip2[16], cidr1, cidr2;
|
||||
char *style = "dotted";
|
||||
- u8 ip1[16], ip2[16];
|
||||
u32 color = 0;
|
||||
|
||||
+ if (node == NULL)
|
||||
+ return;
|
||||
if (bits == 32) {
|
||||
fmt_connection = KERN_DEBUG "\t\"%pI4/%d\" -> \"%pI4/%d\";\n";
|
||||
- fmt_declaration = KERN_DEBUG
|
||||
- "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n";
|
||||
+ fmt_declaration = KERN_DEBUG "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n";
|
||||
} else if (bits == 128) {
|
||||
fmt_connection = KERN_DEBUG "\t\"%pI6/%d\" -> \"%pI6/%d\";\n";
|
||||
- fmt_declaration = KERN_DEBUG
|
||||
- "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n";
|
||||
+ fmt_declaration = KERN_DEBUG "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n";
|
||||
}
|
||||
if (node->peer) {
|
||||
hsiphash_key_t key = { { 0 } };
|
||||
@@ -55,24 +45,20 @@ static __init void print_node(struct all
|
||||
hsiphash_1u32(0xabad1dea, &key) % 200;
|
||||
style = "bold";
|
||||
}
|
||||
- swap_endian_and_apply_cidr(ip1, node->bits, bits, node->cidr);
|
||||
- printk(fmt_declaration, ip1, node->cidr, style, color);
|
||||
+ wg_allowedips_read_node(node, ip1, &cidr1);
|
||||
+ printk(fmt_declaration, ip1, cidr1, style, color);
|
||||
if (node->bit[0]) {
|
||||
- swap_endian_and_apply_cidr(ip2,
|
||||
- rcu_dereference_raw(node->bit[0])->bits, bits,
|
||||
- node->cidr);
|
||||
- printk(fmt_connection, ip1, node->cidr, ip2,
|
||||
- rcu_dereference_raw(node->bit[0])->cidr);
|
||||
- print_node(rcu_dereference_raw(node->bit[0]), bits);
|
||||
+ wg_allowedips_read_node(rcu_dereference_raw(node->bit[0]), ip2, &cidr2);
|
||||
+ printk(fmt_connection, ip1, cidr1, ip2, cidr2);
|
||||
}
|
||||
if (node->bit[1]) {
|
||||
- swap_endian_and_apply_cidr(ip2,
|
||||
- rcu_dereference_raw(node->bit[1])->bits,
|
||||
- bits, node->cidr);
|
||||
- printk(fmt_connection, ip1, node->cidr, ip2,
|
||||
- rcu_dereference_raw(node->bit[1])->cidr);
|
||||
- print_node(rcu_dereference_raw(node->bit[1]), bits);
|
||||
+ wg_allowedips_read_node(rcu_dereference_raw(node->bit[1]), ip2, &cidr2);
|
||||
+ printk(fmt_connection, ip1, cidr1, ip2, cidr2);
|
||||
}
|
||||
+ if (node->bit[0])
|
||||
+ print_node(rcu_dereference_raw(node->bit[0]), bits);
|
||||
+ if (node->bit[1])
|
||||
+ print_node(rcu_dereference_raw(node->bit[1]), bits);
|
||||
}
|
||||
|
||||
static __init void print_tree(struct allowedips_node __rcu *top, u8 bits)
|
||||
@@ -121,8 +107,8 @@ static __init inline union nf_inet_addr
|
||||
{
|
||||
union nf_inet_addr mask;
|
||||
|
||||
- memset(&mask, 0x00, 128 / 8);
|
||||
- memset(&mask, 0xff, cidr / 8);
|
||||
+ memset(&mask, 0, sizeof(mask));
|
||||
+ memset(&mask.all, 0xff, cidr / 8);
|
||||
if (cidr % 32)
|
||||
mask.all[cidr / 32] = (__force u32)htonl(
|
||||
(0xFFFFFFFFUL << (32 - (cidr % 32))) & 0xFFFFFFFFUL);
|
||||
@@ -149,42 +135,36 @@ horrible_mask_self(struct horrible_allow
|
||||
}
|
||||
|
||||
static __init inline bool
|
||||
-horrible_match_v4(const struct horrible_allowedips_node *node,
|
||||
- struct in_addr *ip)
|
||||
+horrible_match_v4(const struct horrible_allowedips_node *node, struct in_addr *ip)
|
||||
{
|
||||
return (ip->s_addr & node->mask.ip) == node->ip.ip;
|
||||
}
|
||||
|
||||
static __init inline bool
|
||||
-horrible_match_v6(const struct horrible_allowedips_node *node,
|
||||
- struct in6_addr *ip)
|
||||
+horrible_match_v6(const struct horrible_allowedips_node *node, struct in6_addr *ip)
|
||||
{
|
||||
- return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) ==
|
||||
- node->ip.ip6[0] &&
|
||||
- (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) ==
|
||||
- node->ip.ip6[1] &&
|
||||
- (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) ==
|
||||
- node->ip.ip6[2] &&
|
||||
+ return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) == node->ip.ip6[0] &&
|
||||
+ (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) == node->ip.ip6[1] &&
|
||||
+ (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) == node->ip.ip6[2] &&
|
||||
(ip->in6_u.u6_addr32[3] & node->mask.ip6[3]) == node->ip.ip6[3];
|
||||
}
|
||||
|
||||
static __init void
|
||||
-horrible_insert_ordered(struct horrible_allowedips *table,
|
||||
- struct horrible_allowedips_node *node)
|
||||
+horrible_insert_ordered(struct horrible_allowedips *table, struct horrible_allowedips_node *node)
|
||||
{
|
||||
struct horrible_allowedips_node *other = NULL, *where = NULL;
|
||||
u8 my_cidr = horrible_mask_to_cidr(node->mask);
|
||||
|
||||
hlist_for_each_entry(other, &table->head, table) {
|
||||
- if (!memcmp(&other->mask, &node->mask,
|
||||
- sizeof(union nf_inet_addr)) &&
|
||||
- !memcmp(&other->ip, &node->ip,
|
||||
- sizeof(union nf_inet_addr)) &&
|
||||
- other->ip_version == node->ip_version) {
|
||||
+ if (other->ip_version == node->ip_version &&
|
||||
+ !memcmp(&other->mask, &node->mask, sizeof(union nf_inet_addr)) &&
|
||||
+ !memcmp(&other->ip, &node->ip, sizeof(union nf_inet_addr))) {
|
||||
other->value = node->value;
|
||||
kfree(node);
|
||||
return;
|
||||
}
|
||||
+ }
|
||||
+ hlist_for_each_entry(other, &table->head, table) {
|
||||
where = other;
|
||||
if (horrible_mask_to_cidr(other->mask) <= my_cidr)
|
||||
break;
|
||||
@@ -201,8 +181,7 @@ static __init int
|
||||
horrible_allowedips_insert_v4(struct horrible_allowedips *table,
|
||||
struct in_addr *ip, u8 cidr, void *value)
|
||||
{
|
||||
- struct horrible_allowedips_node *node = kzalloc(sizeof(*node),
|
||||
- GFP_KERNEL);
|
||||
+ struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||||
|
||||
if (unlikely(!node))
|
||||
return -ENOMEM;
|
||||
@@ -219,8 +198,7 @@ static __init int
|
||||
horrible_allowedips_insert_v6(struct horrible_allowedips *table,
|
||||
struct in6_addr *ip, u8 cidr, void *value)
|
||||
{
|
||||
- struct horrible_allowedips_node *node = kzalloc(sizeof(*node),
|
||||
- GFP_KERNEL);
|
||||
+ struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||||
|
||||
if (unlikely(!node))
|
||||
return -ENOMEM;
|
||||
@@ -234,39 +212,43 @@ horrible_allowedips_insert_v6(struct hor
|
||||
}
|
||||
|
||||
static __init void *
|
||||
-horrible_allowedips_lookup_v4(struct horrible_allowedips *table,
|
||||
- struct in_addr *ip)
|
||||
+horrible_allowedips_lookup_v4(struct horrible_allowedips *table, struct in_addr *ip)
|
||||
{
|
||||
struct horrible_allowedips_node *node;
|
||||
- void *ret = NULL;
|
||||
|
||||
hlist_for_each_entry(node, &table->head, table) {
|
||||
- if (node->ip_version != 4)
|
||||
- continue;
|
||||
- if (horrible_match_v4(node, ip)) {
|
||||
- ret = node->value;
|
||||
- break;
|
||||
- }
|
||||
+ if (node->ip_version == 4 && horrible_match_v4(node, ip))
|
||||
+ return node->value;
|
||||
}
|
||||
- return ret;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
static __init void *
|
||||
-horrible_allowedips_lookup_v6(struct horrible_allowedips *table,
|
||||
- struct in6_addr *ip)
|
||||
+horrible_allowedips_lookup_v6(struct horrible_allowedips *table, struct in6_addr *ip)
|
||||
{
|
||||
struct horrible_allowedips_node *node;
|
||||
- void *ret = NULL;
|
||||
|
||||
hlist_for_each_entry(node, &table->head, table) {
|
||||
- if (node->ip_version != 6)
|
||||
+ if (node->ip_version == 6 && horrible_match_v6(node, ip))
|
||||
+ return node->value;
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static __init void
|
||||
+horrible_allowedips_remove_by_value(struct horrible_allowedips *table, void *value)
|
||||
+{
|
||||
+ struct horrible_allowedips_node *node;
|
||||
+ struct hlist_node *h;
|
||||
+
|
||||
+ hlist_for_each_entry_safe(node, h, &table->head, table) {
|
||||
+ if (node->value != value)
|
||||
continue;
|
||||
- if (horrible_match_v6(node, ip)) {
|
||||
- ret = node->value;
|
||||
- break;
|
||||
- }
|
||||
+ hlist_del(&node->table);
|
||||
+ kfree(node);
|
||||
}
|
||||
- return ret;
|
||||
+
|
||||
}
|
||||
|
||||
static __init bool randomized_test(void)
|
||||
@@ -397,23 +379,33 @@ static __init bool randomized_test(void)
|
||||
print_tree(t.root6, 128);
|
||||
}
|
||||
|
||||
- for (i = 0; i < NUM_QUERIES; ++i) {
|
||||
- prandom_bytes(ip, 4);
|
||||
- if (lookup(t.root4, 32, ip) !=
|
||||
- horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) {
|
||||
- pr_err("allowedips random self-test: FAIL\n");
|
||||
- goto free;
|
||||
+ for (j = 0;; ++j) {
|
||||
+ for (i = 0; i < NUM_QUERIES; ++i) {
|
||||
+ prandom_bytes(ip, 4);
|
||||
+ if (lookup(t.root4, 32, ip) != horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) {
|
||||
+ horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip);
|
||||
+ pr_err("allowedips random v4 self-test: FAIL\n");
|
||||
+ goto free;
|
||||
+ }
|
||||
+ prandom_bytes(ip, 16);
|
||||
+ if (lookup(t.root6, 128, ip) != horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) {
|
||||
+ pr_err("allowedips random v6 self-test: FAIL\n");
|
||||
+ goto free;
|
||||
+ }
|
||||
}
|
||||
+ if (j >= NUM_PEERS)
|
||||
+ break;
|
||||
+ mutex_lock(&mutex);
|
||||
+ wg_allowedips_remove_by_peer(&t, peers[j], &mutex);
|
||||
+ mutex_unlock(&mutex);
|
||||
+ horrible_allowedips_remove_by_value(&h, peers[j]);
|
||||
}
|
||||
|
||||
- for (i = 0; i < NUM_QUERIES; ++i) {
|
||||
- prandom_bytes(ip, 16);
|
||||
- if (lookup(t.root6, 128, ip) !=
|
||||
- horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) {
|
||||
- pr_err("allowedips random self-test: FAIL\n");
|
||||
- goto free;
|
||||
- }
|
||||
+ if (t.root4 || t.root6) {
|
||||
+ pr_err("allowedips random self-test removal: FAIL\n");
|
||||
+ goto free;
|
||||
}
|
||||
+
|
||||
ret = true;
|
||||
|
||||
free:
|
||||
@ -0,0 +1,85 @@
|
||||
From 9d5ef190e5615a7b63af89f88c4106a5bc127974 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Fri, 5 Feb 2021 15:37:10 +0200
|
||||
Subject: [PATCH] net: dsa: automatically bring up DSA master when opening user
|
||||
port
|
||||
|
||||
DSA wants the master interface to be open before the user port is due to
|
||||
historical reasons. The promiscuity of interfaces that are down used to
|
||||
have issues, as referenced Lennert Buytenhek in commit df02c6ff2e39
|
||||
("dsa: fix master interface allmulti/promisc handling").
|
||||
|
||||
The bugfix mentioned there, commit b6c40d68ff64 ("net: only invoke
|
||||
dev->change_rx_flags when device is UP"), was basically a "don't do
|
||||
that" approach to working around the promiscuity while down issue.
|
||||
|
||||
Further work done by Vlad Yasevich in commit d2615bf45069 ("net: core:
|
||||
Always propagate flag changes to interfaces") has resolved the
|
||||
underlying issue, and it is strictly up to the DSA and 8021q drivers
|
||||
now, it is no longer mandated by the networking core that the master
|
||||
interface must be up when changing its promiscuity.
|
||||
|
||||
From DSA's point of view, deciding to error out in dsa_slave_open
|
||||
because the master isn't up is
|
||||
(a) a bad user experience and
|
||||
(b) knocking at an open door.
|
||||
Even if there still was an issue with promiscuity while down, DSA could
|
||||
still just open the master and avoid it.
|
||||
|
||||
Doing it this way has the additional benefit that user space can now
|
||||
remove DSA-specific workarounds, like systemd-networkd with BindCarrier:
|
||||
https://github.com/systemd/systemd/issues/7478
|
||||
|
||||
And we can finally remove one of the 2 bullets in the "Common pitfalls
|
||||
using DSA setups" chapter.
|
||||
|
||||
Tested with two cascaded DSA switches:
|
||||
|
||||
$ ip link set sw0p2 up
|
||||
fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode
|
||||
fsl_enetc 0000:00:00.2 eno2: Link is Up - 1Gbps/Full - flow control rx/tx
|
||||
mscc_felix 0000:00:00.5 swp0: configuring for fixed/sgmii link mode
|
||||
mscc_felix 0000:00:00.5 swp0: Link is Up - 1Gbps/Full - flow control off
|
||||
8021q: adding VLAN 0 to HW filter on device swp0
|
||||
sja1105 spi2.0 sw0p2: configuring for phy/rgmii-id link mode
|
||||
IPv6: ADDRCONF(NETDEV_CHANGE): eno2: link becomes ready
|
||||
IPv6: ADDRCONF(NETDEV_CHANGE): swp0: link becomes ready
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
Documentation/networking/dsa/dsa.rst | 4 ----
|
||||
net/dsa/slave.c | 7 +++++--
|
||||
2 files changed, 5 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/Documentation/networking/dsa/dsa.rst
|
||||
+++ b/Documentation/networking/dsa/dsa.rst
|
||||
@@ -273,10 +273,6 @@ will not make us go through the switch t
|
||||
the Ethernet switch on the other end, expecting a tag will typically drop this
|
||||
frame.
|
||||
|
||||
-Slave network devices check that the master network device is UP before allowing
|
||||
-you to administratively bring UP these slave network devices. A common
|
||||
-configuration mistake is forgetting to bring UP the master network device first.
|
||||
-
|
||||
Interactions with other subsystems
|
||||
==================================
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -70,8 +70,11 @@ static int dsa_slave_open(struct net_dev
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
int err;
|
||||
|
||||
- if (!(master->flags & IFF_UP))
|
||||
- return -ENETDOWN;
|
||||
+ err = dev_open(master, NULL);
|
||||
+ if (err < 0) {
|
||||
+ netdev_err(dev, "failed to open master %s\n", master->name);
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
|
||||
err = dev_uc_add(master, dev->dev_addr);
|
||||
@ -25,7 +25,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1592,7 +1592,9 @@ static void dsa_slave_switchdev_event_wo
|
||||
@@ -1595,7 +1595,9 @@ static void dsa_slave_switchdev_event_wo
|
||||
|
||||
err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
|
||||
if (err) {
|
||||
@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
break;
|
||||
}
|
||||
fdb_info->offloaded = true;
|
||||
@@ -1607,9 +1609,11 @@ static void dsa_slave_switchdev_event_wo
|
||||
@@ -1610,9 +1612,11 @@ static void dsa_slave_switchdev_event_wo
|
||||
|
||||
err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
|
||||
if (err) {
|
||||
|
||||
@ -54,7 +54,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
struct sk_buff * (*xmit)(struct sk_buff *skb,
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1567,76 +1567,66 @@ static int dsa_slave_netdevice_event(str
|
||||
@@ -1570,76 +1570,66 @@ static int dsa_slave_netdevice_event(str
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
@ -167,7 +167,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
}
|
||||
|
||||
/* Called under rcu_read_lock() */
|
||||
@@ -1644,7 +1634,9 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1647,7 +1637,9 @@ static int dsa_slave_switchdev_event(str
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
|
||||
@ -177,7 +177,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
int err;
|
||||
|
||||
if (event == SWITCHDEV_PORT_ATTR_SET) {
|
||||
@@ -1657,20 +1649,32 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1660,20 +1652,32 @@ static int dsa_slave_switchdev_event(str
|
||||
if (!dsa_slave_dev_check(dev))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
@ -213,7 +213,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
dev_hold(dev);
|
||||
break;
|
||||
default:
|
||||
@@ -1680,10 +1684,6 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1683,10 +1687,6 @@ static int dsa_slave_switchdev_event(str
|
||||
|
||||
dsa_schedule_work(&switchdev_work->work);
|
||||
return NOTIFY_OK;
|
||||
|
||||
@ -20,7 +20,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1639,31 +1639,29 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1642,31 +1642,29 @@ static int dsa_slave_switchdev_event(str
|
||||
struct dsa_port *dp;
|
||||
int err;
|
||||
|
||||
@ -68,7 +68,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
fdb_info = ptr;
|
||||
|
||||
if (!fdb_info->added_by_user) {
|
||||
@@ -1676,13 +1674,12 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1679,13 +1677,12 @@ static int dsa_slave_switchdev_event(str
|
||||
switchdev_work->vid = fdb_info->vid;
|
||||
|
||||
dev_hold(dev);
|
||||
|
||||
@ -30,7 +30,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1652,6 +1652,9 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1655,6 +1655,9 @@ static int dsa_slave_switchdev_event(str
|
||||
|
||||
dp = dsa_slave_to_port(dev);
|
||||
|
||||
|
||||
@ -172,7 +172,7 @@ Signed-off-by: DENG Qingfang <dqfext@gmail.com>
|
||||
*/
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1629,6 +1629,25 @@ static void dsa_slave_switchdev_event_wo
|
||||
@@ -1632,6 +1632,25 @@ static void dsa_slave_switchdev_event_wo
|
||||
dev_put(dp->slave);
|
||||
}
|
||||
|
||||
@ -198,7 +198,7 @@ Signed-off-by: DENG Qingfang <dqfext@gmail.com>
|
||||
/* Called under rcu_read_lock() */
|
||||
static int dsa_slave_switchdev_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
@@ -1647,10 +1666,37 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1650,10 +1669,37 @@ static int dsa_slave_switchdev_event(str
|
||||
return notifier_from_errno(err);
|
||||
case SWITCHDEV_FDB_ADD_TO_DEVICE:
|
||||
case SWITCHDEV_FDB_DEL_TO_DEVICE:
|
||||
@ -239,7 +239,7 @@ Signed-off-by: DENG Qingfang <dqfext@gmail.com>
|
||||
|
||||
if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del)
|
||||
return NOTIFY_DONE;
|
||||
@@ -1665,18 +1711,13 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1668,18 +1714,13 @@ static int dsa_slave_switchdev_event(str
|
||||
switchdev_work->port = dp->index;
|
||||
switchdev_work->event = event;
|
||||
|
||||
|
||||
@ -4167,6 +4167,7 @@ CONFIG_NMI_LOG_BUF_SHIFT=13
|
||||
# CONFIG_NVMEM_SYSFS is not set
|
||||
# CONFIG_NVME_FC is not set
|
||||
# CONFIG_NVME_TARGET is not set
|
||||
# CONFIG_NVME_TCP is not set
|
||||
# CONFIG_NVRAM is not set
|
||||
# CONFIG_NV_TCO is not set
|
||||
# CONFIG_NXP_STB220 is not set
|
||||
|
||||
@ -56,7 +56,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
} \
|
||||
\
|
||||
/* __*init sections */ \
|
||||
@@ -1017,6 +1027,8 @@
|
||||
@@ -1018,6 +1028,8 @@
|
||||
|
||||
#define COMMON_DISCARDS \
|
||||
SANITIZER_DISCARDS \
|
||||
|
||||
@ -18,7 +18,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2191,10 +2191,12 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2194,10 +2194,12 @@ static int dsa_slave_switchdev_event(str
|
||||
fdb_info = ptr;
|
||||
|
||||
if (dsa_slave_dev_check(dev)) {
|
||||
|
||||
@ -15,7 +15,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2205,7 +2205,11 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2208,7 +2208,11 @@ static int dsa_slave_switchdev_event(str
|
||||
struct net_device *br_dev;
|
||||
struct dsa_slave_priv *p;
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2198,9 +2198,12 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2201,9 +2201,12 @@ static int dsa_slave_switchdev_event(str
|
||||
else if (!fdb_info->added_by_user)
|
||||
return NOTIFY_OK;
|
||||
} else {
|
||||
@ -44,7 +44,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
*/
|
||||
struct net_device *br_dev;
|
||||
struct dsa_slave_priv *p;
|
||||
@@ -2222,7 +2225,8 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -2225,7 +2228,8 @@ static int dsa_slave_switchdev_event(str
|
||||
|
||||
dp = p->dp->cpu_dp;
|
||||
|
||||
|
||||
@ -17,9 +17,9 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
#define AT803X_PHY_ID_MASK 0xffffffef
|
||||
+#define AT8032_PHY_ID_MASK 0xffffffff
|
||||
|
||||
MODULE_DESCRIPTION("Atheros 803x PHY driver");
|
||||
MODULE_AUTHOR("Matus Ujhelyi");
|
||||
@@ -314,7 +316,7 @@ static int at803x_config_intr(struct phy
|
||||
#define AT803X_PAGE_FIBER 0
|
||||
#define AT803X_PAGE_COPPER 1
|
||||
@@ -357,7 +359,7 @@ static int at803x_config_intr(struct phy
|
||||
static void at803x_link_change_notify(struct phy_device *phydev)
|
||||
{
|
||||
/*
|
||||
@ -28,7 +28,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
* signalled. This is necessary to circumvent a hardware bug that
|
||||
* occurs when the cable is unplugged while TX packets are pending
|
||||
* in the FIFO. In such cases, the FIFO enters an error mode it
|
||||
@@ -471,6 +473,24 @@ static struct phy_driver at803x_driver[]
|
||||
@@ -516,6 +518,24 @@ static struct phy_driver at803x_driver[]
|
||||
.aneg_done = at803x_aneg_done,
|
||||
.ack_interrupt = &at803x_ack_interrupt,
|
||||
.config_intr = &at803x_config_intr,
|
||||
@ -53,7 +53,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
} };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
@@ -478,6 +498,7 @@ module_phy_driver(at803x_driver);
|
||||
@@ -523,6 +543,7 @@ module_phy_driver(at803x_driver);
|
||||
static struct mdio_device_id __maybe_unused atheros_tbl[] = {
|
||||
{ ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
|
||||
{ ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
|
||||
|
||||
@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
#include "dsa_priv.h"
|
||||
|
||||
@@ -1223,6 +1227,27 @@ static struct devlink_port *dsa_slave_ge
|
||||
@@ -1226,6 +1230,27 @@ static struct devlink_port *dsa_slave_ge
|
||||
return dp->ds->devlink ? &dp->devlink_port : NULL;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
static const struct net_device_ops dsa_slave_netdev_ops = {
|
||||
.ndo_open = dsa_slave_open,
|
||||
.ndo_stop = dsa_slave_close,
|
||||
@@ -1247,6 +1272,9 @@ static const struct net_device_ops dsa_s
|
||||
@@ -1250,6 +1275,9 @@ static const struct net_device_ops dsa_s
|
||||
.ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,
|
||||
.ndo_get_devlink_port = dsa_slave_get_devlink_port,
|
||||
|
||||
@ -18,7 +18,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1697,10 +1697,12 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1700,10 +1700,12 @@ static int dsa_slave_switchdev_event(str
|
||||
fdb_info = ptr;
|
||||
|
||||
if (dsa_slave_dev_check(dev)) {
|
||||
|
||||
@ -15,7 +15,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1711,7 +1711,11 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1714,7 +1714,11 @@ static int dsa_slave_switchdev_event(str
|
||||
struct net_device *br_dev;
|
||||
struct dsa_slave_priv *p;
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1704,9 +1704,12 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1707,9 +1707,12 @@ static int dsa_slave_switchdev_event(str
|
||||
else if (!fdb_info->added_by_user)
|
||||
return NOTIFY_OK;
|
||||
} else {
|
||||
@ -44,7 +44,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
*/
|
||||
struct net_device *br_dev;
|
||||
struct dsa_slave_priv *p;
|
||||
@@ -1728,7 +1731,8 @@ static int dsa_slave_switchdev_event(str
|
||||
@@ -1731,7 +1734,8 @@ static int dsa_slave_switchdev_event(str
|
||||
|
||||
dp = p->dp->cpu_dp;
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@ ipq40xx_setup_interfaces()
|
||||
;;
|
||||
avm,fritzbox-7530)
|
||||
ucidef_add_switch "switch0" \
|
||||
"0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan"
|
||||
"0u@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1"
|
||||
;;
|
||||
avm,fritzrepeater-3000)
|
||||
ucidef_add_switch "switch0" \
|
||||
|
||||
@ -72,10 +72,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&ohci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -141,10 +141,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&i2c {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -114,10 +114,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&ohci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -153,8 +153,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
ðernet {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&ephy_pins>;
|
||||
};
|
||||
|
||||
@ -157,10 +157,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
@ -144,10 +144,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
@ -144,10 +144,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
@ -132,10 +132,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&gpio2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -171,10 +171,6 @@
|
||||
mtd-mac-address = <&factory 0x4>;
|
||||
};
|
||||
|
||||
&gsw {
|
||||
ralink,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
@ -120,10 +120,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&state_default {
|
||||
default {
|
||||
groups = "i2c", "uartf";
|
||||
|
||||
@ -185,5 +185,6 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
@ -173,6 +173,6 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,ephy-base-address = /bits/ 16 < 2 >;
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <2>;
|
||||
};
|
||||
|
||||
@ -135,7 +135,8 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&pcie {
|
||||
|
||||
@ -178,7 +178,7 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,ephy-base = /bits/ 8 <12>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
|
||||
@ -170,7 +170,7 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,ephy-base = /bits/ 8 <12>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
|
||||
@ -155,8 +155,6 @@
|
||||
|
||||
mtd-mac-address = <&factory 0x4>;
|
||||
|
||||
mediatek,mdio-mode = <1>;
|
||||
|
||||
phy-reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
|
||||
phy-reset-duration = <30>;
|
||||
|
||||
@ -202,7 +200,7 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port5 = "gmac";
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
|
||||
@ -144,7 +144,6 @@
|
||||
|
||||
mdio-bus {
|
||||
status = "okay";
|
||||
mediatek,mdio-mode;
|
||||
|
||||
ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
@ -155,11 +154,15 @@
|
||||
0x7c 0x0000007e /* PORT0 STATUS */
|
||||
0x0c 0x05600000 /* PORT6 PAD MODE CTRL */
|
||||
0x94 0x0000007e /* PORT6 STATUS */
|
||||
>;
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&state_default {
|
||||
gpio {
|
||||
groups = "i2c", "uartf", "nd_sd", "wled";
|
||||
|
||||
@ -136,7 +136,8 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
|
||||
@ -149,6 +149,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
@ -184,6 +184,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,ephy-base = /bits/ 8 <12>;
|
||||
};
|
||||
|
||||
&state_default {
|
||||
gpio {
|
||||
groups = "i2c", "uartf";
|
||||
|
||||
@ -101,3 +101,7 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,ephy-base = /bits/ 8 <12>;
|
||||
};
|
||||
|
||||
@ -115,9 +115,8 @@
|
||||
|
||||
mdio-bus {
|
||||
status = "okay";
|
||||
mediatek,mdio-mode = <1>;
|
||||
|
||||
phy0: ethernet-phy@0 {
|
||||
ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
phy-mode = "rgmii";
|
||||
qca,ar8327-initvals = <
|
||||
@ -127,29 +126,13 @@
|
||||
0x94 0x00000000 /* PORT6_STATUS */
|
||||
>;
|
||||
};
|
||||
|
||||
phy1: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
phy-mode = "rgmii";
|
||||
};
|
||||
|
||||
phy2: ethernet-phy@2 {
|
||||
reg = <2>;
|
||||
phy-mode = "rgmii";
|
||||
};
|
||||
|
||||
phy3: ethernet-phy@3 {
|
||||
reg = <3>;
|
||||
phy-mode = "rgmii";
|
||||
};
|
||||
|
||||
phy4: ethernet-phy@4 {
|
||||
reg = <4>;
|
||||
phy-mode = "rgmii";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&pcie {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -135,6 +135,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,ephy-base = /bits/ 8 <12>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
@ -111,5 +111,6 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
@ -145,7 +145,7 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,ephy-base = /bits/ 8 <12>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
|
||||
@ -142,6 +142,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,ephy-base = /bits/ 8 <12>;
|
||||
};
|
||||
|
||||
&pcie {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -103,10 +103,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
@ -122,10 +122,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
ralink,port4 = "ephy";
|
||||
};
|
||||
|
||||
&sdhci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -94,10 +94,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
@ -114,10 +114,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
@ -105,7 +105,8 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&sdhci {
|
||||
|
||||
@ -100,7 +100,7 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,ephy-base = /bits/ 8 <12>;
|
||||
};
|
||||
|
||||
&pcie {
|
||||
|
||||
@ -71,10 +71,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&sdhci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -99,7 +99,8 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&pcie {
|
||||
|
||||
@ -166,7 +166,8 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&ehci {
|
||||
|
||||
@ -178,10 +178,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&radio 0x0>;
|
||||
};
|
||||
|
||||
@ -105,10 +105,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&radio 0x0>;
|
||||
};
|
||||
|
||||
@ -61,7 +61,8 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
ðernet {
|
||||
|
||||
@ -195,7 +195,8 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
|
||||
@ -103,6 +103,7 @@
|
||||
|
||||
ðernet {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&ephy_pins>;
|
||||
|
||||
mtd-mac-address = <&factory 0x28>;
|
||||
|
||||
|
||||
@ -141,10 +141,6 @@
|
||||
mediatek,portmap = "llllw";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
ralink,port4 = "ephy";
|
||||
};
|
||||
|
||||
&wmac {
|
||||
ralink,mtd-eeprom = <&factory 0x0>;
|
||||
};
|
||||
|
||||
@ -111,7 +111,3 @@
|
||||
&ohci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
@ -157,7 +157,8 @@
|
||||
};
|
||||
|
||||
&gsw {
|
||||
mediatek,port4 = "gmac";
|
||||
mediatek,port4-gmac;
|
||||
mediatek,ephy-base = /bits/ 8 <8>;
|
||||
};
|
||||
|
||||
&wmac {
|
||||
|
||||
@ -322,20 +322,6 @@
|
||||
reset-names = "fe", "esw";
|
||||
|
||||
mediatek,switch = <&gsw>;
|
||||
|
||||
mdio-bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
port@4 {
|
||||
compatible = "mediatek,mt7620a-gsw-port", "mediatek,eth-port";
|
||||
reg = <4>;
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
gsw: gsw@10110000 {
|
||||
@ -347,7 +333,6 @@
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <17>;
|
||||
mediatek,port4 = "ephy";
|
||||
};
|
||||
|
||||
ehci: ehci@101c0000 {
|
||||
|
||||
@ -133,12 +133,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ðernet {
|
||||
port@4 {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
&state_default {
|
||||
default {
|
||||
groups = "spi refclk", "i2c", "ephy", "wled";
|
||||
|
||||
@ -136,12 +136,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ðernet {
|
||||
port@4 {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
&state_default {
|
||||
default {
|
||||
groups = "spi refclk", "i2c", "ephy", "wled";
|
||||
|
||||
@ -429,8 +429,8 @@
|
||||
interrupt-parent = <&cpuintc>;
|
||||
interrupts = <5>;
|
||||
|
||||
resets = <&rstctrl 21 &rstctrl 23>;
|
||||
reset-names = "fe", "esw";
|
||||
resets = <&rstctrl 21>;
|
||||
reset-names = "fe";
|
||||
|
||||
mediatek,switch = <&esw>;
|
||||
};
|
||||
@ -439,8 +439,8 @@
|
||||
compatible = "mediatek,mt7628-esw", "ralink,rt3050-esw";
|
||||
reg = <0x10110000 0x8000>;
|
||||
|
||||
resets = <&rstctrl 23>;
|
||||
reset-names = "esw";
|
||||
resets = <&rstctrl 23 &rstctrl 24>;
|
||||
reset-names = "esw", "ephy";
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <17>;
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <10000000>;
|
||||
broken-flash-reset;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
|
||||
@ -319,8 +319,8 @@
|
||||
compatible = "ralink,rt3050-esw";
|
||||
reg = <0x10110000 0x8000>;
|
||||
|
||||
resets = <&rstctrl 23>;
|
||||
reset-names = "esw";
|
||||
resets = <&rstctrl 23 &rstctrl 24>;
|
||||
reset-names = "esw", "ephy";
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <17>;
|
||||
|
||||
@ -331,8 +331,8 @@
|
||||
compatible = "ralink,rt3352-esw", "ralink,rt3050-esw";
|
||||
reg = <0x10110000 0x8000>;
|
||||
|
||||
resets = <&rstctrl 23>;
|
||||
reset-names = "esw";
|
||||
resets = <&rstctrl 23 &rstctrl 24>;
|
||||
reset-names = "esw", "ephy";
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <17>;
|
||||
|
||||
@ -343,8 +343,8 @@
|
||||
compatible = "ralink,rt5350-eth";
|
||||
reg = <0x10100000 0x10000>;
|
||||
|
||||
resets = <&rstctrl 21 &rstctrl 23>;
|
||||
reset-names = "fe", "esw";
|
||||
resets = <&rstctrl 21>;
|
||||
reset-names = "fe";
|
||||
|
||||
interrupt-parent = <&cpuintc>;
|
||||
interrupts = <5>;
|
||||
@ -356,8 +356,8 @@
|
||||
compatible = "ralink,rt5350-esw", "ralink,rt3050-esw";
|
||||
reg = <0x10110000 0x8000>;
|
||||
|
||||
resets = <&rstctrl 23>;
|
||||
reset-names = "esw";
|
||||
resets = <&rstctrl 23 &rstctrl 24>;
|
||||
reset-names = "esw", "ephy";
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <17>;
|
||||
|
||||
@ -17,11 +17,14 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/mach-ralink/ralink_regs.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <linux/switch.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "mtk_eth_soc.h"
|
||||
#include "esw_rt3050.h"
|
||||
|
||||
/* HW limitations for this switch:
|
||||
* - No large frame support (PKT_MAX_LEN at most 1536)
|
||||
@ -172,7 +175,6 @@
|
||||
|
||||
#define RT5350_ESW_REG_PXTPC(_x) (0x150 + (4 * _x))
|
||||
#define RT5350_EWS_REG_LED_POLARITY 0x168
|
||||
#define RT5350_RESET_EPHY BIT(24)
|
||||
|
||||
enum {
|
||||
/* Global attributes. */
|
||||
@ -215,6 +217,7 @@ struct rt305x_esw {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
struct fe_priv *priv;
|
||||
|
||||
/* Protects against concurrent register r/w operations. */
|
||||
spinlock_t reg_rw_lock;
|
||||
@ -232,6 +235,8 @@ struct rt305x_esw {
|
||||
int led_frequency;
|
||||
struct esw_vlan vlans[RT305X_ESW_NUM_VLANS];
|
||||
struct esw_port ports[RT305X_ESW_NUM_PORTS];
|
||||
struct reset_control *rst_esw;
|
||||
struct reset_control *rst_ephy;
|
||||
|
||||
};
|
||||
|
||||
@ -254,6 +259,29 @@ static inline void esw_rmw_raw(struct rt305x_esw *esw, unsigned reg,
|
||||
__raw_writel(t | val, esw->base + reg);
|
||||
}
|
||||
|
||||
static void esw_reset(struct rt305x_esw *esw)
|
||||
{
|
||||
if (!esw->rst_esw)
|
||||
return;
|
||||
|
||||
reset_control_assert(esw->rst_esw);
|
||||
usleep_range(60, 120);
|
||||
reset_control_deassert(esw->rst_esw);
|
||||
/* the esw takes long to reset otherwise the board hang */
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static void esw_reset_ephy(struct rt305x_esw *esw)
|
||||
{
|
||||
if (!esw->rst_ephy)
|
||||
return;
|
||||
|
||||
reset_control_assert(esw->rst_ephy);
|
||||
usleep_range(60, 120);
|
||||
reset_control_deassert(esw->rst_ephy);
|
||||
usleep_range(60, 120);
|
||||
}
|
||||
|
||||
static void esw_rmw(struct rt305x_esw *esw, unsigned reg,
|
||||
unsigned long mask, unsigned long val)
|
||||
{
|
||||
@ -436,6 +464,8 @@ static void esw_hw_init(struct rt305x_esw *esw)
|
||||
u8 port_disable = 0;
|
||||
u8 port_map = RT305X_ESW_PMAP_LLLLLL;
|
||||
|
||||
esw_reset(esw);
|
||||
|
||||
/* vodoo from original driver */
|
||||
esw_w32(esw, 0xC8A07850, RT305X_ESW_REG_FCT0);
|
||||
esw_w32(esw, 0x00000000, RT305X_ESW_REG_SGC2);
|
||||
@ -505,8 +535,7 @@ static void esw_hw_init(struct rt305x_esw *esw)
|
||||
esw->ports[i].disable = (port_disable & (1 << i)) != 0;
|
||||
|
||||
if (ralink_soc == RT305X_SOC_RT3352) {
|
||||
/* reset EPHY */
|
||||
fe_reset(RT5350_RESET_EPHY);
|
||||
esw_reset_ephy(esw);
|
||||
|
||||
rt305x_mii_write(esw, 0, 31, 0x8000);
|
||||
for (i = 0; i < 5; i++) {
|
||||
@ -556,8 +585,7 @@ static void esw_hw_init(struct rt305x_esw *esw)
|
||||
/* select local register */
|
||||
rt305x_mii_write(esw, 0, 31, 0x8000);
|
||||
} else if (ralink_soc == RT305X_SOC_RT5350) {
|
||||
/* reset EPHY */
|
||||
fe_reset(RT5350_RESET_EPHY);
|
||||
esw_reset_ephy(esw);
|
||||
|
||||
/* set the led polarity */
|
||||
esw_w32(esw, esw->reg_led_polarity & 0x1F,
|
||||
@ -614,8 +642,7 @@ static void esw_hw_init(struct rt305x_esw *esw)
|
||||
} else if (ralink_soc == MT762X_SOC_MT7628AN || ralink_soc == MT762X_SOC_MT7688) {
|
||||
int i;
|
||||
|
||||
/* reset EPHY */
|
||||
fe_reset(RT5350_RESET_EPHY);
|
||||
esw_reset_ephy(esw);
|
||||
|
||||
/* set the led polarity */
|
||||
esw_w32(esw, esw->reg_led_polarity & 0x1F,
|
||||
@ -711,19 +738,44 @@ static void esw_hw_init(struct rt305x_esw *esw)
|
||||
esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR);
|
||||
}
|
||||
|
||||
|
||||
int rt3050_esw_has_carrier(struct fe_priv *priv)
|
||||
{
|
||||
struct rt305x_esw *esw = priv->soc->swpriv;
|
||||
u32 link;
|
||||
int i;
|
||||
bool cpuport;
|
||||
|
||||
link = esw_r32(esw, RT305X_ESW_REG_POA);
|
||||
link >>= RT305X_ESW_POA_LINK_SHIFT;
|
||||
cpuport = link & BIT(RT305X_ESW_PORT6);
|
||||
link &= RT305X_ESW_POA_LINK_MASK;
|
||||
for (i = 0; i <= RT305X_ESW_PORT5; i++) {
|
||||
if (priv->link[i] != (link & BIT(i)))
|
||||
dev_info(esw->dev, "port %d link %s\n", i, link & BIT(i) ? "up" : "down");
|
||||
priv->link[i] = link & BIT(i);
|
||||
}
|
||||
|
||||
return !!link && cpuport;
|
||||
}
|
||||
|
||||
static irqreturn_t esw_interrupt(int irq, void *_esw)
|
||||
{
|
||||
struct rt305x_esw *esw = (struct rt305x_esw *)_esw;
|
||||
struct rt305x_esw *esw = (struct rt305x_esw *) _esw;
|
||||
u32 status;
|
||||
int i;
|
||||
|
||||
status = esw_r32(esw, RT305X_ESW_REG_ISR);
|
||||
if (status & RT305X_ESW_PORT_ST_CHG) {
|
||||
u32 link = esw_r32(esw, RT305X_ESW_REG_POA);
|
||||
|
||||
link >>= RT305X_ESW_POA_LINK_SHIFT;
|
||||
link &= RT305X_ESW_POA_LINK_MASK;
|
||||
dev_info(esw->dev, "link changed 0x%02X\n", link);
|
||||
if (!esw->priv)
|
||||
goto out;
|
||||
if (rt3050_esw_has_carrier(esw->priv))
|
||||
netif_carrier_on(esw->priv->netdev);
|
||||
else
|
||||
netif_carrier_off(esw->priv->netdev);
|
||||
}
|
||||
|
||||
out:
|
||||
esw_w32(esw, status, RT305X_ESW_REG_ISR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@ -1351,9 +1403,7 @@ static int esw_probe(struct platform_device *pdev)
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const __be32 *port_map, *port_disable, *reg_init;
|
||||
struct switch_dev *swdev;
|
||||
struct rt305x_esw *esw;
|
||||
int ret;
|
||||
|
||||
esw = devm_kzalloc(&pdev->dev, sizeof(*esw), GFP_KERNEL);
|
||||
if (!esw)
|
||||
@ -1385,48 +1435,17 @@ static int esw_probe(struct platform_device *pdev)
|
||||
if (reg_init)
|
||||
esw->reg_led_polarity = be32_to_cpu(*reg_init);
|
||||
|
||||
swdev = &esw->swdev;
|
||||
swdev->of_node = pdev->dev.of_node;
|
||||
swdev->name = "rt305x-esw";
|
||||
swdev->alias = "rt305x";
|
||||
swdev->cpu_port = RT305X_ESW_PORT6;
|
||||
swdev->ports = RT305X_ESW_NUM_PORTS;
|
||||
swdev->vlans = RT305X_ESW_NUM_VIDS;
|
||||
swdev->ops = &esw_ops;
|
||||
|
||||
ret = register_switch(swdev, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "register_switch failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, esw);
|
||||
esw->rst_esw = devm_reset_control_get(&pdev->dev, "esw");
|
||||
if (IS_ERR(esw->rst_esw))
|
||||
esw->rst_esw = NULL;
|
||||
esw->rst_ephy = devm_reset_control_get(&pdev->dev, "ephy");
|
||||
if (IS_ERR(esw->rst_ephy))
|
||||
esw->rst_ephy = NULL;
|
||||
|
||||
spin_lock_init(&esw->reg_rw_lock);
|
||||
platform_set_drvdata(pdev, esw);
|
||||
|
||||
esw_hw_init(esw);
|
||||
|
||||
reg_init = of_get_property(np, "ralink,rgmii", NULL);
|
||||
if (reg_init && be32_to_cpu(*reg_init) == 1) {
|
||||
/*
|
||||
* External switch connected to RGMII interface.
|
||||
* Unregister the switch device after initialization.
|
||||
*/
|
||||
dev_err(&pdev->dev, "RGMII mode, not exporting switch device.\n");
|
||||
unregister_switch(&esw->swdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, esw->irq, esw_interrupt, 0, "esw",
|
||||
esw);
|
||||
|
||||
if (!ret) {
|
||||
esw_w32(esw, RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_ISR);
|
||||
esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int esw_remove(struct platform_device *pdev)
|
||||
@ -1447,6 +1466,71 @@ static const struct of_device_id ralink_esw_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ralink_esw_match);
|
||||
|
||||
/* called by the ethernet driver to bound with the switch driver */
|
||||
int rt3050_esw_init(struct fe_priv *priv)
|
||||
{
|
||||
struct device_node *np = priv->switch_np;
|
||||
struct platform_device *pdev = of_find_device_by_node(np);
|
||||
struct switch_dev *swdev;
|
||||
struct rt305x_esw *esw;
|
||||
const __be32 *rgmii;
|
||||
int ret;
|
||||
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!of_device_is_compatible(np, ralink_esw_match->compatible))
|
||||
return -EINVAL;
|
||||
|
||||
esw = platform_get_drvdata(pdev);
|
||||
if (!esw)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
priv->soc->swpriv = esw;
|
||||
esw->priv = priv;
|
||||
|
||||
esw_hw_init(esw);
|
||||
|
||||
rgmii = of_get_property(np, "ralink,rgmii", NULL);
|
||||
if (rgmii && be32_to_cpu(*rgmii) == 1) {
|
||||
/*
|
||||
* External switch connected to RGMII interface.
|
||||
* Unregister the switch device after initialization.
|
||||
*/
|
||||
dev_err(&pdev->dev, "RGMII mode, not exporting switch device.\n");
|
||||
unregister_switch(&esw->swdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
swdev = &esw->swdev;
|
||||
swdev->of_node = pdev->dev.of_node;
|
||||
swdev->name = "rt305x-esw";
|
||||
swdev->alias = "rt305x";
|
||||
swdev->cpu_port = RT305X_ESW_PORT6;
|
||||
swdev->ports = RT305X_ESW_NUM_PORTS;
|
||||
swdev->vlans = RT305X_ESW_NUM_VIDS;
|
||||
swdev->ops = &esw_ops;
|
||||
|
||||
ret = register_switch(swdev, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "register_switch failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, esw->irq, esw_interrupt, 0, "esw",
|
||||
esw);
|
||||
if (!ret) {
|
||||
esw_w32(esw, RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_ISR);
|
||||
esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR);
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "mediatek esw at 0x%08lx, irq %d initialized\n",
|
||||
esw->base, esw->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver esw_driver = {
|
||||
.probe = esw_probe,
|
||||
.remove = esw_remove,
|
||||
|
||||
@ -26,4 +26,7 @@ static inline int __init mtk_switch_init(void) { return 0; }
|
||||
static inline void mtk_switch_exit(void) { }
|
||||
|
||||
#endif
|
||||
|
||||
int rt3050_esw_init(struct fe_priv *priv);
|
||||
int rt3050_esw_has_carrier(struct fe_priv *priv);
|
||||
#endif
|
||||
|
||||
@ -40,7 +40,7 @@ static irqreturn_t gsw_interrupt_mt7620(int irq, void *_priv)
|
||||
struct fe_priv *priv = (struct fe_priv *)_priv;
|
||||
struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
|
||||
u32 status;
|
||||
int i, max = (gsw->port4 == PORT4_EPHY) ? (4) : (3);
|
||||
int i, max = (gsw->port4_ephy) ? (4) : (3);
|
||||
|
||||
status = mtk_switch_r32(gsw, GSW_REG_ISR);
|
||||
if (status & PORT_IRQ_ST_CHG)
|
||||
@ -61,119 +61,82 @@ static irqreturn_t gsw_interrupt_mt7620(int irq, void *_priv)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mt7620_mdio_mode(struct device_node *eth_node)
|
||||
{
|
||||
struct device_node *phy_node, *mdiobus_node;
|
||||
const __be32 *id;
|
||||
int ret = 0;
|
||||
|
||||
mdiobus_node = of_get_child_by_name(eth_node, "mdio-bus");
|
||||
|
||||
if (mdiobus_node) {
|
||||
if (of_property_read_bool(mdiobus_node, "mediatek,mdio-mode"))
|
||||
ret = 1;
|
||||
|
||||
for_each_child_of_node(mdiobus_node, phy_node) {
|
||||
id = of_get_property(phy_node, "reg", NULL);
|
||||
if (id && (be32_to_cpu(*id) == 0x1f))
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
of_node_put(mdiobus_node);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mt7620_hw_init(struct mt7620_gsw *gsw, int mdio_mode)
|
||||
static void mt7620_hw_init(struct mt7620_gsw *gsw)
|
||||
{
|
||||
u32 i;
|
||||
u32 val;
|
||||
u32 is_BGA = (rt_sysc_r32(0x0c) >> 16) & 1;
|
||||
u32 is_BGA = (rt_sysc_r32(SYSC_REG_CHIP_REV_ID) >> 16) & 1;
|
||||
|
||||
/* Internal ethernet requires PCIe RC mode */
|
||||
rt_sysc_w32(rt_sysc_r32(SYSC_REG_CFG1) | PCIE_RC_MODE, SYSC_REG_CFG1);
|
||||
|
||||
rt_sysc_w32(rt_sysc_r32(SYSC_REG_CFG1) | BIT(8), SYSC_REG_CFG1);
|
||||
mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_CKGCR) & ~(0x3 << 4), GSW_REG_CKGCR);
|
||||
|
||||
/* Enable MIB stats */
|
||||
mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_MIB_CNT_EN) | (1 << 1), GSW_REG_MIB_CNT_EN);
|
||||
|
||||
if (mdio_mode) {
|
||||
u32 val;
|
||||
|
||||
/* turn off ephy and set phy base addr to 12 */
|
||||
if (gsw->ephy_disable) {
|
||||
mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_GPC1) |
|
||||
(0x1f << 24) | (0xc << 16),
|
||||
(gsw->ephy_base << 16) | (0x1f << 24),
|
||||
GSW_REG_GPC1);
|
||||
|
||||
/* set MT7530 central align */
|
||||
val = mt7530_mdio_r32(gsw, 0x7830);
|
||||
val &= ~BIT(0);
|
||||
val |= BIT(1);
|
||||
mt7530_mdio_w32(gsw, 0x7830, val);
|
||||
pr_info("gsw: internal ephy disabled\n");
|
||||
} else if (gsw->ephy_base) {
|
||||
mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_GPC1) |
|
||||
(gsw->ephy_base << 16),
|
||||
GSW_REG_GPC1);
|
||||
fe_reset(MT7620A_RESET_EPHY);
|
||||
|
||||
val = mt7530_mdio_r32(gsw, 0x7a40);
|
||||
val &= ~BIT(30);
|
||||
mt7530_mdio_w32(gsw, 0x7a40, val);
|
||||
pr_info("gsw: ephy base address: %d\n", gsw->ephy_base);
|
||||
}
|
||||
|
||||
mt7530_mdio_w32(gsw, 0x7a78, 0x855);
|
||||
/* global page 4 */
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x4000);
|
||||
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0x7444);
|
||||
if (is_BGA)
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 19, 0x0114);
|
||||
else
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 19, 0x0117);
|
||||
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x10cf);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x6212);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0777);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 29, 0x4000);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 28, 0xc077);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0000);
|
||||
|
||||
/* global page 3 */
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x3000);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0x4838);
|
||||
|
||||
/* global page 2 */
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x2000);
|
||||
if (is_BGA) {
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 21, 0x0515);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x0053);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 23, 0x00bf);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0aaf);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x0fad);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0fc1);
|
||||
} else {
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 21, 0x0517);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x0fd2);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 23, 0x00bf);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0aab);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x00ae);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0fff);
|
||||
}
|
||||
/* global page 1 */
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x1000);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0xe7f8);
|
||||
|
||||
if (gsw->ephy_base) {
|
||||
/* set phy base addr to ephy_base */
|
||||
mtk_switch_w32(gsw, mtk_switch_r32(gsw, GSW_REG_GPC1) |
|
||||
(gsw->ephy_base << 16),
|
||||
GSW_REG_GPC1);
|
||||
fe_reset(BIT(24)); /* Resets the Ethernet PHY block. */
|
||||
}
|
||||
|
||||
/* global page 4 */
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x4000);
|
||||
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0x7444);
|
||||
if (is_BGA)
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 19, 0x0114);
|
||||
else
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 19, 0x0117);
|
||||
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x10cf);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x6212);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0777);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 29, 0x4000);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 28, 0xc077);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0000);
|
||||
|
||||
/* global page 3 */
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x3000);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0x4838);
|
||||
|
||||
/* global page 2 */
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x2000);
|
||||
if (is_BGA) {
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 21, 0x0515);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x0053);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 23, 0x00bf);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0aaf);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x0fad);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0fc1);
|
||||
} else {
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 21, 0x0517);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 22, 0x0fd2);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 23, 0x00bf);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 24, 0x0aab);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 25, 0x00ae);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 26, 0x0fff);
|
||||
}
|
||||
/* global page 1 */
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 31, 0x1000);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 1, 17, 0xe7f8);
|
||||
|
||||
/* turn on all PHYs */
|
||||
for (i = 0; i <= 4; i++) {
|
||||
val = _mt7620_mii_read(gsw, gsw->ephy_base + i, MII_BMCR);
|
||||
val &= ~BMCR_PDOWN;
|
||||
val |= BMCR_ANRESTART | BMCR_ANENABLE | BMCR_SPEED100;
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + i, MII_BMCR, val);
|
||||
}
|
||||
/* turn on all PHYs */
|
||||
for (i = 0; i <= 4; i++) {
|
||||
val = _mt7620_mii_read(gsw, gsw->ephy_base + i, MII_BMCR);
|
||||
val &= ~BMCR_PDOWN;
|
||||
val |= BMCR_ANRESTART | BMCR_ANENABLE | BMCR_SPEED100;
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + i, MII_BMCR, val);
|
||||
}
|
||||
|
||||
/* global page 0 */
|
||||
@ -202,8 +165,8 @@ static void mt7620_hw_init(struct mt7620_gsw *gsw, int mdio_mode)
|
||||
mtk_switch_w32(gsw, 0x7f7f7fe0, 0x0010);
|
||||
|
||||
/* setup port 4 */
|
||||
if (gsw->port4 == PORT4_EPHY) {
|
||||
u32 val = rt_sysc_r32(SYSC_REG_CFG1);
|
||||
if (gsw->port4_ephy) {
|
||||
val = rt_sysc_r32(SYSC_REG_CFG1);
|
||||
|
||||
val |= 3 << 14;
|
||||
rt_sysc_w32(val, SYSC_REG_CFG1);
|
||||
@ -211,12 +174,6 @@ static void mt7620_hw_init(struct mt7620_gsw *gsw, int mdio_mode)
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 4, 4, 0x05e1);
|
||||
_mt7620_mii_write(gsw, gsw->ephy_base + 4, 16, 0x1313);
|
||||
pr_info("gsw: setting port4 to ephy mode\n");
|
||||
} else if (!mdio_mode) {
|
||||
u32 val = rt_sysc_r32(SYSC_REG_CFG1);
|
||||
|
||||
val &= ~(3 << 14);
|
||||
rt_sysc_w32(val, SYSC_REG_CFG1);
|
||||
pr_info("gsw: setting port4 to gmac mode\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,9 +185,13 @@ MODULE_DEVICE_TABLE(of, mediatek_gsw_match);
|
||||
|
||||
int mtk_gsw_init(struct fe_priv *priv)
|
||||
{
|
||||
struct device_node *eth_node = priv->dev->of_node;
|
||||
struct device_node *phy_node, *mdiobus_node;
|
||||
struct device_node *np = priv->switch_np;
|
||||
struct platform_device *pdev = of_find_device_by_node(np);
|
||||
struct mt7620_gsw *gsw;
|
||||
const __be32 *id;
|
||||
u8 val;
|
||||
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
@ -241,7 +202,27 @@ int mtk_gsw_init(struct fe_priv *priv)
|
||||
gsw = platform_get_drvdata(pdev);
|
||||
priv->soc->swpriv = gsw;
|
||||
|
||||
mt7620_hw_init(gsw, mt7620_mdio_mode(priv->dev->of_node));
|
||||
gsw->ephy_disable = of_property_read_bool(np, "mediatek,ephy-disable");
|
||||
|
||||
mdiobus_node = of_get_child_by_name(eth_node, "mdio-bus");
|
||||
if (mdiobus_node) {
|
||||
for_each_child_of_node(mdiobus_node, phy_node) {
|
||||
id = of_get_property(phy_node, "reg", NULL);
|
||||
if (id && (be32_to_cpu(*id) == 0x1f))
|
||||
gsw->ephy_disable = true;
|
||||
}
|
||||
|
||||
of_node_put(mdiobus_node);
|
||||
}
|
||||
|
||||
gsw->port4_ephy = !of_property_read_bool(np, "mediatek,port4-gmac");
|
||||
|
||||
if (of_property_read_u8(np, "mediatek,ephy-base", &val) == 0)
|
||||
gsw->ephy_base = val;
|
||||
else
|
||||
gsw->ephy_base = 0;
|
||||
|
||||
mt7620_hw_init(gsw);
|
||||
|
||||
if (gsw->irq) {
|
||||
request_irq(gsw->irq, gsw_interrupt_mt7620, 0,
|
||||
@ -255,10 +236,7 @@ int mtk_gsw_init(struct fe_priv *priv)
|
||||
static int mt7620_gsw_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
const char *port4 = NULL;
|
||||
struct mt7620_gsw *gsw;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u16 val;
|
||||
|
||||
gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL);
|
||||
if (!gsw)
|
||||
@ -270,19 +248,6 @@ static int mt7620_gsw_probe(struct platform_device *pdev)
|
||||
|
||||
gsw->dev = &pdev->dev;
|
||||
|
||||
of_property_read_string(np, "mediatek,port4", &port4);
|
||||
if (port4 && !strcmp(port4, "ephy"))
|
||||
gsw->port4 = PORT4_EPHY;
|
||||
else if (port4 && !strcmp(port4, "gmac"))
|
||||
gsw->port4 = PORT4_EXT;
|
||||
else
|
||||
gsw->port4 = PORT4_EPHY;
|
||||
|
||||
if (of_property_read_u16(np, "mediatek,ephy-base-address", &val) == 0)
|
||||
gsw->ephy_base = val;
|
||||
else
|
||||
gsw->ephy_base = 0;
|
||||
|
||||
gsw->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
platform_set_drvdata(pdev, gsw);
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
|
||||
#define SYSC_REG_CHIP_REV_ID 0x0c
|
||||
#define SYSC_REG_CFG1 0x14
|
||||
#define RST_CTRL_MCM BIT(2)
|
||||
#define PCIE_RC_MODE BIT(8)
|
||||
#define SYSC_PAD_RGMII2_MDIO 0x58
|
||||
#define SYSC_GPIO_MODE 0x60
|
||||
|
||||
@ -88,16 +88,12 @@ enum {
|
||||
GSW_ATTR_PORT_UNTAG,
|
||||
};
|
||||
|
||||
enum {
|
||||
PORT4_EPHY = 0,
|
||||
PORT4_EXT,
|
||||
};
|
||||
|
||||
struct mt7620_gsw {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
int port4;
|
||||
bool ephy_disable;
|
||||
bool port4_ephy;
|
||||
unsigned long int autopoll;
|
||||
u16 ephy_base;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user