Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
commit
807965a921
@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-5.10 = .107
|
||||
LINUX_KERNEL_HASH-5.10.107 = c467c3077946370fb26c9277313b601d6c48bb557abc889f4892caf627fcdfea
|
||||
LINUX_VERSION-5.10 = .108
|
||||
LINUX_KERNEL_HASH-5.10.108 = bf6cc2d6e0918b8f34d1cde2fa39a6ad69c45025425048be1a1dac4a5b3641d8
|
||||
|
||||
2
include/kernel-5.15
Normal file
2
include/kernel-5.15
Normal file
@ -0,0 +1,2 @@
|
||||
LINUX_VERSION-5.15 = .31
|
||||
LINUX_KERNEL_HASH-5.15.31 = f621384b47d5bed927910bf5211e7b4ccac925f28218e483bb1a9c484b246b88
|
||||
@ -48,8 +48,9 @@ $(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MATCH_COMMENT, $(P_XT)xt_comme
|
||||
$(eval $(call nf_add,IPT_CLUSTER,CONFIG_NETFILTER_XT_MATCH_CLUSTER, $(P_XT)xt_cluster))
|
||||
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_XT)xt_LOG))
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_XT)nf_log_common))
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_V4)nf_log_ipv4))
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_XT)nf_log_common, lt 5.13))
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_V4)nf_log_ipv4, lt 5.13))
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_LOG, $(P_XT)nf_log_syslog, ge 5.13))
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_TARGET_TCPMSS, $(P_XT)xt_TCPMSS))
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_IP_NF_TARGET_REJECT, $(P_V4)ipt_REJECT))
|
||||
$(eval $(call nf_add,IPT_CORE,CONFIG_NETFILTER_XT_MATCH_TIME, $(P_XT)xt_time))
|
||||
@ -160,7 +161,7 @@ $(eval $(if $(NF_KMOD),$(call nf_add,NF_CONNTRACK,CONFIG_NF_DEFRAG_IPV6, $(P_V6)
|
||||
|
||||
$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_IP6_NF_FILTER, $(P_V6)ip6table_filter),))
|
||||
$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_IP6_NF_MANGLE, $(P_V6)ip6table_mangle),))
|
||||
$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_NF_LOG_IPV6, $(P_V6)nf_log_ipv6),))
|
||||
$(eval $(if $(NF_KMOD),$(call nf_add,IPT_IPV6,CONFIG_NF_LOG_IPV6, $(P_V6)nf_log_ipv6,lt 5.13),))
|
||||
|
||||
$(eval $(if $(NF_KMOD),,$(call nf_add,IPT_IPV6,CONFIG_IP6_NF_IPTABLES, ip6t_icmp6)))
|
||||
|
||||
|
||||
@ -513,11 +513,13 @@ define KernelPackage/scsi-core
|
||||
TITLE:=SCSI device support
|
||||
KCONFIG:= \
|
||||
CONFIG_SCSI \
|
||||
CONFIG_SCSI_COMMON@ge5.15 \
|
||||
CONFIG_BLK_DEV_SD
|
||||
FILES:= \
|
||||
$(LINUX_DIR)/drivers/scsi/scsi_mod.ko \
|
||||
$(LINUX_DIR)/drivers/scsi/scsi_common.ko@ge5.15 \
|
||||
$(LINUX_DIR)/drivers/scsi/sd_mod.ko
|
||||
AUTOLOAD:=$(call AutoLoad,40,scsi_mod sd_mod,1)
|
||||
AUTOLOAD:=$(call AutoLoad,40,scsi_mod scsi_common@ge5.15 sd_mod,1)
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,scsi-core))
|
||||
|
||||
@ -451,9 +451,7 @@ define KernelPackage/crypto-lib-blake2s
|
||||
TITLE:=BLAKE2s hash function library
|
||||
KCONFIG:=CONFIG_CRYPTO_LIB_BLAKE2S
|
||||
HIDDEN:=1
|
||||
FILES:= \
|
||||
$(LINUX_DIR)/lib/crypto/libblake2s.ko \
|
||||
$(LINUX_DIR)/lib/crypto/libblake2s-generic.ko
|
||||
FILES:=$(LINUX_DIR)/lib/crypto/libblake2s.ko
|
||||
$(call AddDepends/crypto,+PACKAGE_kmod-crypto-hash:kmod-crypto-hash)
|
||||
endef
|
||||
|
||||
@ -463,9 +461,30 @@ endef
|
||||
|
||||
define KernelPackage/crypto-lib-blake2s/x86/64
|
||||
KCONFIG+=CONFIG_CRYPTO_BLAKE2S_X86
|
||||
FILES+=$(LINUX_DIR)/arch/x86/crypto/blake2s-x86_64.ko
|
||||
FILES+=\
|
||||
$(LINUX_DIR)/lib/crypto/libblake2s-generic.ko \
|
||||
$(LINUX_DIR)/arch/x86/crypto/blake2s-x86_64.ko
|
||||
endef
|
||||
|
||||
define KernelPackage/crypto-lib-blake2s/arm
|
||||
KCONFIG+=CONFIG_CRYPTO_BLAKE2S_ARM
|
||||
FILES+=\
|
||||
$(LINUX_DIR)/lib/crypto/libblake2s-generic.ko@lt5.12 \
|
||||
$(LINUX_DIR)/arch/arm/crypto/blake2s-arm.ko@ge5.12
|
||||
endef
|
||||
|
||||
ifndef KernelPackage/crypto-lib-blake2s/$(CRYPTO_TARGET)
|
||||
define KernelPackage/crypto-lib-blake2s/$(CRYPTO_TARGET)
|
||||
KCONFIG+=CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC
|
||||
FILES+=$(LINUX_DIR)/lib/crypto/libblake2s-generic.ko
|
||||
endef
|
||||
endif
|
||||
|
||||
ifdef KernelPackage/crypto-lib-blake2s/$(ARCH)
|
||||
KernelPackage/crypto-lib-blake2s/$(CRYPTO_TARGET)=\
|
||||
$(KernelPackage/crypto-lib-blake2s/$(ARCH))
|
||||
endif
|
||||
|
||||
$(eval $(call KernelPackage,crypto-lib-blake2s))
|
||||
|
||||
|
||||
@ -683,7 +702,7 @@ define KernelPackage/crypto-misc
|
||||
CONFIG_CRYPTO_KHAZAD \
|
||||
CONFIG_CRYPTO_SERPENT \
|
||||
CONFIG_CRYPTO_TEA \
|
||||
CONFIG_CRYPTO_TGR192 \
|
||||
CONFIG_CRYPTO_TGR192@lt5.12 \
|
||||
CONFIG_CRYPTO_TWOFISH \
|
||||
CONFIG_CRYPTO_TWOFISH_COMMON \
|
||||
CONFIG_CRYPTO_TWOFISH_586 \
|
||||
@ -696,7 +715,7 @@ define KernelPackage/crypto-misc
|
||||
$(LINUX_DIR)/crypto/cast6_generic.ko \
|
||||
$(LINUX_DIR)/crypto/khazad.ko \
|
||||
$(LINUX_DIR)/crypto/tea.ko \
|
||||
$(LINUX_DIR)/crypto/tgr192.ko \
|
||||
$(LINUX_DIR)/crypto/tgr192.ko@lt5.12 \
|
||||
$(LINUX_DIR)/crypto/twofish_common.ko \
|
||||
$(LINUX_DIR)/crypto/wp512.ko \
|
||||
$(LINUX_DIR)/crypto/twofish_generic.ko \
|
||||
@ -704,7 +723,7 @@ define KernelPackage/crypto-misc
|
||||
$(LINUX_DIR)/crypto/blowfish_generic.ko \
|
||||
$(LINUX_DIR)/crypto/serpent_generic.ko
|
||||
AUTOLOAD:=$(call AutoLoad,10,anubis camellia_generic cast_common \
|
||||
cast5_generic cast6_generic khazad tea tgr192 twofish_common \
|
||||
cast5_generic cast6_generic khazad tea tgr192@lt5.12 twofish_common \
|
||||
wp512 blowfish_common serpent_generic)
|
||||
ifndef CONFIG_TARGET_x86
|
||||
AUTOLOAD+= $(call AutoLoad,10,twofish_generic blowfish_generic)
|
||||
|
||||
@ -87,24 +87,31 @@ define KernelPackage/fs-cifs
|
||||
SUBMENU:=$(FS_MENU)
|
||||
TITLE:=CIFS support
|
||||
KCONFIG:= \
|
||||
CONFIG_SMBFS_COMMON@ge5.15 \
|
||||
CONFIG_CIFS \
|
||||
CONFIG_CIFS_DFS_UPCALL=n \
|
||||
CONFIG_CIFS_UPCALL=n
|
||||
FILES:=$(LINUX_DIR)/fs/cifs/cifs.ko
|
||||
FILES:= \
|
||||
$(LINUX_DIR)/fs/smbfs_common/cifs_arc4.ko@ge5.15 \
|
||||
$(LINUX_DIR)/fs/smbfs_common/cifs_md4.ko@ge5.15 \
|
||||
$(LINUX_DIR)/fs/cifs/cifs.ko
|
||||
AUTOLOAD:=$(call AutoLoad,30,cifs)
|
||||
$(call AddDepends/nls)
|
||||
DEPENDS+= \
|
||||
+kmod-crypto-md4 \
|
||||
+(LINUX_5_4||LINUX_5_10):kmod-crypto-md4\
|
||||
+kmod-crypto-md5 \
|
||||
+kmod-crypto-sha256 \
|
||||
+kmod-crypto-sha512 \
|
||||
+kmod-crypto-cmac \
|
||||
+kmod-crypto-hmac \
|
||||
+kmod-crypto-arc4 \
|
||||
+(LINUX_5_4||LINUX_5_10):kmod-crypto-arc4 \
|
||||
+kmod-crypto-aead \
|
||||
+kmod-crypto-ccm \
|
||||
+kmod-crypto-ecb \
|
||||
+kmod-crypto-des
|
||||
+kmod-crypto-des \
|
||||
+(LINUX_5_15):kmod-asn1-decoder \
|
||||
+(LINUX_5_15):kmod-oid-registry \
|
||||
+(LINUX_5_15):kmod-dnsresolver
|
||||
endef
|
||||
|
||||
define KernelPackage/fs-cifs/description
|
||||
@ -239,10 +246,21 @@ endef
|
||||
$(eval $(call KernelPackage,fs-f2fs))
|
||||
|
||||
|
||||
define KernelPackage/fs-netfs
|
||||
SUBMENU:=$(FS_MENU)
|
||||
TITLE:=Network Filesystems support
|
||||
DEPENDS:=@LINUX_5_15
|
||||
KCONFIG:= CONFIG_NETFS_SUPPORT
|
||||
FILES:=$(LINUX_DIR)/fs/netfs/netfs.ko
|
||||
AUTOLOAD:=$(call AutoLoad,28,netfs)
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,fs-netfs))
|
||||
|
||||
define KernelPackage/fs-fscache
|
||||
SUBMENU:=$(FS_MENU)
|
||||
TITLE:=General filesystem local cache manager
|
||||
DEPENDS:=
|
||||
DEPENDS:=+kmod-fs-netfs
|
||||
KCONFIG:=\
|
||||
CONFIG_FSCACHE=m \
|
||||
CONFIG_FSCACHE_STATS=y \
|
||||
@ -616,3 +634,18 @@ define KernelPackage/fuse/description
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,fuse))
|
||||
|
||||
|
||||
define KernelPackage/fs-ntfs3
|
||||
SUBMENU:=$(FS_MENU)
|
||||
TITLE:=Ntfs3 support
|
||||
KCONFIG:= CONFIG_NTFS3_FS CONFIG_NTFS3_FS_POSIX_ACL=y
|
||||
FILES:=$(LINUX_DIR)/fs/ntfs3/ntfs3.ko
|
||||
AUTOLOAD:=$(call AutoLoad,80,ntfs3)
|
||||
endef
|
||||
|
||||
define KernelPackage/fuse/description
|
||||
Kernel module for new NTFS3 filesystem support
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,fs-ntfs3))
|
||||
|
||||
@ -179,10 +179,10 @@ define KernelPackage/input-touchscreen-ads7846
|
||||
DEPENDS:=+kmod-hwmon-core +kmod-input-core +kmod-spi-bitbang
|
||||
KCONFIG:= \
|
||||
CONFIG_INPUT_TOUCHSCREEN=y \
|
||||
CONFIG_TOUCHSCREEN_PROPERTIES=y \
|
||||
CONFIG_TOUCHSCREEN_PROPERTIES=y@lt5.13 \
|
||||
CONFIG_TOUCHSCREEN_ADS7846
|
||||
FILES:=$(LINUX_DIR)/drivers/input/touchscreen/ads7846.ko \
|
||||
$(LINUX_DIR)/drivers/input/touchscreen/of_touchscreen.ko
|
||||
$(LINUX_DIR)/drivers/input/touchscreen/of_touchscreen.ko@lt5.13
|
||||
AUTOLOAD:=$(call AutoProbe,ads7846)
|
||||
endef
|
||||
|
||||
|
||||
@ -274,6 +274,16 @@ endef
|
||||
|
||||
$(eval $(call KernelPackage,asn1-decoder))
|
||||
|
||||
define KernelPackage/asn1-encoder
|
||||
SUBMENU:=$(LIB_MENU)
|
||||
TITLE:=Simple ASN1 encoder
|
||||
KCONFIG:= CONFIG_ASN1_ENCODER
|
||||
HIDDEN:=1
|
||||
FILES:=$(LINUX_DIR)/lib/asn1_encoder.ko
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,asn1-encoder))
|
||||
|
||||
define KernelPackage/oid-registry
|
||||
SUBMENU:=$(LIB_MENU)
|
||||
TITLE:=Object identifier registry
|
||||
|
||||
@ -1123,7 +1123,7 @@ define KernelPackage/nft-bridge
|
||||
FILES:=$(foreach mod,$(NFT_BRIDGE-m),$(LINUX_DIR)/net/$(mod).ko)
|
||||
AUTOLOAD:=$(call AutoProbe,$(notdir $(NFT_BRIDGE-m)))
|
||||
KCONFIG:= \
|
||||
CONFIG_NF_LOG_BRIDGE=n \
|
||||
CONFIG_NF_LOG_BRIDGE=n@lt5.13 \
|
||||
$(KCONFIG_NFT_BRIDGE)
|
||||
endef
|
||||
|
||||
|
||||
@ -1111,7 +1111,8 @@ define KernelPackage/sctp
|
||||
CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y
|
||||
FILES:= $(LINUX_DIR)/net/sctp/sctp.ko
|
||||
AUTOLOAD:= $(call AutoLoad,32,sctp)
|
||||
DEPENDS:=+kmod-lib-crc32c +kmod-crypto-md5 +kmod-crypto-hmac
|
||||
DEPENDS:=+kmod-lib-crc32c +kmod-crypto-md5 +kmod-crypto-hmac \
|
||||
+LINUX_5_15:kmod-udptunnel4 +LINUX_5_15:kmod-udptunnel6
|
||||
endef
|
||||
|
||||
define KernelPackage/sctp/description
|
||||
|
||||
@ -959,7 +959,6 @@ $(eval $(call KernelPackage,ikconfig))
|
||||
define KernelPackage/zram
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=ZRAM
|
||||
DEPENDS:=+kmod-lib-lzo
|
||||
KCONFIG:= \
|
||||
CONFIG_ZSMALLOC \
|
||||
CONFIG_ZRAM \
|
||||
@ -976,8 +975,31 @@ define KernelPackage/zram/description
|
||||
Compressed RAM block device support
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,zram))
|
||||
define KernelPackage/zram/config
|
||||
choice
|
||||
prompt "ZRAM Default compressor"
|
||||
default ZRAM_DEF_COMP_LZORLE
|
||||
|
||||
config ZRAM_DEF_COMP_LZORLE
|
||||
bool "lzo-rle"
|
||||
select PACKAGE_kmod-lib-lzo
|
||||
|
||||
config ZRAM_DEF_COMP_LZO
|
||||
bool "lzo"
|
||||
select PACKAGE_kmod-lib-lzo
|
||||
|
||||
config ZRAM_DEF_COMP_LZ4
|
||||
bool "lz4"
|
||||
select PACKAGE_kmod-lib-lz4
|
||||
|
||||
config ZRAM_DEF_COMP_ZSTD
|
||||
bool "zstd"
|
||||
select PACKAGE_kmod-lib-zstd
|
||||
|
||||
endchoice
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,zram))
|
||||
|
||||
define KernelPackage/pps
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
@ -1190,7 +1212,8 @@ $(eval $(call KernelPackage,keys-trusted))
|
||||
define KernelPackage/tpm
|
||||
SUBMENU:=$(OTHER_MENU)
|
||||
TITLE:=TPM Hardware Support
|
||||
DEPENDS:= +kmod-random-core
|
||||
DEPENDS:= +kmod-random-core +(LINUX_5_15):kmod-asn1-decoder \
|
||||
+(LINUX_5_15):kmod-asn1-encoder +(LINUX_5_15):kmod-oid-registry
|
||||
KCONFIG:= CONFIG_TCG_TPM
|
||||
FILES:= $(LINUX_DIR)/drivers/char/tpm/tpm.ko
|
||||
AUTOLOAD:=$(call AutoLoad,10,tpm,1)
|
||||
|
||||
@ -312,7 +312,11 @@ mvswitch_config_init(struct phy_device *pdev)
|
||||
priv->orig_features = dev->features;
|
||||
|
||||
#ifdef HEADER_MODE
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0)
|
||||
dev->extra_priv_flags |= IFF_NO_IP_ALIGN;
|
||||
#else
|
||||
dev->priv_flags |= IFF_NO_IP_ALIGN;
|
||||
#endif
|
||||
dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX;
|
||||
#else
|
||||
dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
|
||||
@ -372,7 +376,11 @@ mvswitch_detach(struct phy_device *pdev)
|
||||
dev->eth_mangle_rx = NULL;
|
||||
dev->eth_mangle_tx = NULL;
|
||||
dev->features = priv->orig_features;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0)
|
||||
dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN;
|
||||
#else
|
||||
dev->priv_flags &= ~IFF_NO_IP_ALIGN;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@ -25,7 +25,7 @@ Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>
|
||||
static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
|
||||
u32 *data, int in_pm)
|
||||
{
|
||||
@@ -1830,7 +1834,8 @@ static int smsc95xx_rx_fixup(struct usbn
|
||||
@@ -1839,7 +1843,8 @@ static int smsc95xx_rx_fixup(struct usbn
|
||||
if (dev->net->features & NETIF_F_RXCSUM)
|
||||
smsc95xx_rx_csum_offload(skb);
|
||||
skb_trim(skb, skb->len - 4); /* remove fcs */
|
||||
@ -35,7 +35,7 @@ Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1848,7 +1853,8 @@ static int smsc95xx_rx_fixup(struct usbn
|
||||
@@ -1857,7 +1862,8 @@ static int smsc95xx_rx_fixup(struct usbn
|
||||
if (dev->net->features & NETIF_F_RXCSUM)
|
||||
smsc95xx_rx_csum_offload(ax_skb);
|
||||
skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
|
||||
|
||||
@ -22,7 +22,7 @@ See: http://forum.kodi.tv/showthread.php?tid=285288
|
||||
static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
|
||||
u32 *data, int in_pm)
|
||||
{
|
||||
@@ -905,13 +909,13 @@ static int smsc95xx_reset(struct usbnet
|
||||
@@ -917,13 +921,13 @@ static int smsc95xx_reset(struct usbnet
|
||||
|
||||
if (!turbo_mode) {
|
||||
burst_cap = 0;
|
||||
|
||||
@ -29,7 +29,7 @@ Signed-off-by: popcornmix <popcornmix@gmail.com>
|
||||
static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
|
||||
u32 *data, int in_pm)
|
||||
{
|
||||
@@ -761,6 +766,53 @@ static int smsc95xx_ioctl(struct net_dev
|
||||
@@ -773,6 +778,53 @@ static int smsc95xx_ioctl(struct net_dev
|
||||
return phy_mii_ioctl(netdev->phydev, rq, cmd);
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ Signed-off-by: popcornmix <popcornmix@gmail.com>
|
||||
static void smsc95xx_init_mac_address(struct usbnet *dev)
|
||||
{
|
||||
/* maybe the boot loader passed the MAC address in devicetree */
|
||||
@@ -783,6 +835,10 @@ static void smsc95xx_init_mac_address(st
|
||||
@@ -795,6 +847,10 @@ static void smsc95xx_init_mac_address(st
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
@@ -2595,7 +2595,7 @@ static void bcmgenet_init_tx_ring(struct
|
||||
@@ -2597,7 +2597,7 @@ static void bcmgenet_init_tx_ring(struct
|
||||
|
||||
bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
|
||||
bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
|
||||
@ -27,7 +27,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
/* Disable rate control for now */
|
||||
bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
|
||||
TDMA_FLOW_PERIOD);
|
||||
@@ -4060,9 +4060,12 @@ static int bcmgenet_probe(struct platfor
|
||||
@@ -4062,9 +4062,12 @@ static int bcmgenet_probe(struct platfor
|
||||
netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
|
||||
|
||||
/* Set default coalescing parameters */
|
||||
|
||||
@ -37,7 +37,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||||
|
||||
static inline void bcmgenet_writel(u32 value, void __iomem *offset)
|
||||
{
|
||||
@@ -2426,6 +2429,11 @@ static void reset_umac(struct bcmgenet_p
|
||||
@@ -2428,6 +2431,11 @@ static void reset_umac(struct bcmgenet_p
|
||||
bcmgenet_rbuf_ctrl_set(priv, 0);
|
||||
udelay(10);
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
|
||||
@@ -3244,7 +3244,7 @@ static void bcmgenet_get_hw_addr(struct
|
||||
@@ -3246,7 +3246,7 @@ static void bcmgenet_get_hw_addr(struct
|
||||
}
|
||||
|
||||
/* Returns a reusable dma control register value */
|
||||
@ -33,7 +33,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
{
|
||||
unsigned int i;
|
||||
u32 reg;
|
||||
@@ -3269,6 +3269,14 @@ static u32 bcmgenet_dma_disable(struct b
|
||||
@@ -3271,6 +3271,14 @@ static u32 bcmgenet_dma_disable(struct b
|
||||
udelay(10);
|
||||
bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH);
|
||||
|
||||
@ -48,7 +48,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
return dma_ctrl;
|
||||
}
|
||||
|
||||
@@ -3332,8 +3340,8 @@ static int bcmgenet_open(struct net_devi
|
||||
@@ -3334,8 +3342,8 @@ static int bcmgenet_open(struct net_devi
|
||||
|
||||
bcmgenet_set_hw_addr(priv, dev->dev_addr);
|
||||
|
||||
@ -59,7 +59,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
/* Reinitialize TDMA and RDMA and SW housekeeping */
|
||||
ret = bcmgenet_init_dma(priv);
|
||||
@@ -4189,7 +4197,7 @@ static int bcmgenet_resume(struct device
|
||||
@@ -4191,7 +4199,7 @@ static int bcmgenet_resume(struct device
|
||||
bcmgenet_hfb_create_rxnfc_filter(priv, rule);
|
||||
|
||||
/* Disable RX/TX DMA and flush TX queues */
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
From 173019b66dcc9d68ad9333aa744dad1e369b5aa8 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 9 Jul 2017 00:26:53 +0200
|
||||
Subject: [PATCH 34/34] kernel: add compile fix for linux 4.9 on x86
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
Makefile | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -523,7 +523,7 @@ KBUILD_LDFLAGS_MODULE :=
|
||||
KBUILD_LDFLAGS :=
|
||||
CLANG_FLAGS :=
|
||||
|
||||
-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
|
||||
+export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
|
||||
export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
|
||||
export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
|
||||
export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD
|
||||
@ -0,0 +1,65 @@
|
||||
From: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
Date: Tue, 5 Oct 2021 18:54:02 +0200
|
||||
Subject: [PATCH] MIPS: uasm: Enable muhu opcode for MIPS R6
|
||||
|
||||
Enable the 'muhu' instruction, complementing the existing 'mulu', needed
|
||||
to implement a MIPS32 BPF JIT.
|
||||
|
||||
Also fix a typo in the existing definition of 'dmulu'.
|
||||
|
||||
Signed-off-by: Tony Ambardar <Tony.Ambardar@gmail.com>
|
||||
|
||||
This patch is a dependency for my 32-bit MIPS eBPF JIT.
|
||||
|
||||
Signed-off-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
---
|
||||
|
||||
--- a/arch/mips/include/asm/uasm.h
|
||||
+++ b/arch/mips/include/asm/uasm.h
|
||||
@@ -145,6 +145,7 @@ Ip_u1(_mtlo);
|
||||
Ip_u3u1u2(_mul);
|
||||
Ip_u1u2(_multu);
|
||||
Ip_u3u1u2(_mulu);
|
||||
+Ip_u3u1u2(_muhu);
|
||||
Ip_u3u1u2(_nor);
|
||||
Ip_u3u1u2(_or);
|
||||
Ip_u2u1u3(_ori);
|
||||
--- a/arch/mips/mm/uasm-mips.c
|
||||
+++ b/arch/mips/mm/uasm-mips.c
|
||||
@@ -90,7 +90,7 @@ static const struct insn insn_table[insn
|
||||
RS | RT | RD},
|
||||
[insn_dmtc0] = {M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
|
||||
[insn_dmultu] = {M(spec_op, 0, 0, 0, 0, dmultu_op), RS | RT},
|
||||
- [insn_dmulu] = {M(spec_op, 0, 0, 0, dmult_dmul_op, dmultu_op),
|
||||
+ [insn_dmulu] = {M(spec_op, 0, 0, 0, dmultu_dmulu_op, dmultu_op),
|
||||
RS | RT | RD},
|
||||
[insn_drotr] = {M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE},
|
||||
[insn_drotr32] = {M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE},
|
||||
@@ -150,6 +150,8 @@ static const struct insn insn_table[insn
|
||||
[insn_mtlo] = {M(spec_op, 0, 0, 0, 0, mtlo_op), RS},
|
||||
[insn_mulu] = {M(spec_op, 0, 0, 0, multu_mulu_op, multu_op),
|
||||
RS | RT | RD},
|
||||
+ [insn_muhu] = {M(spec_op, 0, 0, 0, multu_muhu_op, multu_op),
|
||||
+ RS | RT | RD},
|
||||
#ifndef CONFIG_CPU_MIPSR6
|
||||
[insn_mul] = {M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD},
|
||||
#else
|
||||
--- a/arch/mips/mm/uasm.c
|
||||
+++ b/arch/mips/mm/uasm.c
|
||||
@@ -59,7 +59,7 @@ enum opcode {
|
||||
insn_lddir, insn_ldpte, insn_ldx, insn_lh, insn_lhu, insn_ll, insn_lld,
|
||||
insn_lui, insn_lw, insn_lwu, insn_lwx, insn_mfc0, insn_mfhc0, insn_mfhi,
|
||||
insn_mflo, insn_modu, insn_movn, insn_movz, insn_mtc0, insn_mthc0,
|
||||
- insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_mulu, insn_nor,
|
||||
+ insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_mulu, insn_muhu, insn_nor,
|
||||
insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sb, insn_sc,
|
||||
insn_scd, insn_seleqz, insn_selnez, insn_sd, insn_sh, insn_sll,
|
||||
insn_sllv, insn_slt, insn_slti, insn_sltiu, insn_sltu, insn_sra,
|
||||
@@ -344,6 +344,7 @@ I_u1(_mtlo)
|
||||
I_u3u1u2(_mul)
|
||||
I_u1u2(_multu)
|
||||
I_u3u1u2(_mulu)
|
||||
+I_u3u1u2(_muhu)
|
||||
I_u3u1u2(_nor)
|
||||
I_u3u1u2(_or)
|
||||
I_u2u1u3(_ori)
|
||||
@ -0,0 +1,31 @@
|
||||
From: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
Date: Tue, 5 Oct 2021 18:54:03 +0200
|
||||
Subject: [PATCH] mips: uasm: Add workaround for Loongson-2F nop CPU errata
|
||||
|
||||
This patch implements a workaround for the Loongson-2F nop in generated,
|
||||
code, if the existing option CONFIG_CPU_NOP_WORKAROUND is set. Before,
|
||||
the binutils option -mfix-loongson2f-nop was enabled, but no workaround
|
||||
was done when emitting MIPS code. Now, the nop pseudo instruction is
|
||||
emitted as "or ax,ax,zero" instead of the default "sll zero,zero,0". This
|
||||
is consistent with the workaround implemented by binutils.
|
||||
|
||||
Link: https://sourceware.org/legacy-ml/binutils/2009-11/msg00387.html
|
||||
|
||||
Signed-off-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
|
||||
---
|
||||
|
||||
--- a/arch/mips/include/asm/uasm.h
|
||||
+++ b/arch/mips/include/asm/uasm.h
|
||||
@@ -249,7 +249,11 @@ static inline void uasm_l##lb(struct uas
|
||||
#define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off)
|
||||
#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3)
|
||||
#define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b)
|
||||
+#ifdef CONFIG_CPU_NOP_WORKAROUNDS
|
||||
+#define uasm_i_nop(buf) uasm_i_or(buf, 1, 1, 0)
|
||||
+#else
|
||||
#define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0)
|
||||
+#endif
|
||||
#define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1)
|
||||
|
||||
static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1,
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,120 @@
|
||||
From: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
Date: Tue, 5 Oct 2021 18:54:06 +0200
|
||||
Subject: [PATCH] mips: bpf: Add JIT workarounds for CPU errata
|
||||
|
||||
This patch adds workarounds for the following CPU errata to the MIPS
|
||||
eBPF JIT, if enabled in the kernel configuration.
|
||||
|
||||
- R10000 ll/sc weak ordering
|
||||
- Loongson-3 ll/sc weak ordering
|
||||
- Loongson-2F jump hang
|
||||
|
||||
The Loongson-2F nop errata is implemented in uasm, which the JIT uses,
|
||||
so no additional mitigations are needed for that.
|
||||
|
||||
Signed-off-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
|
||||
---
|
||||
|
||||
--- a/arch/mips/net/bpf_jit_comp.c
|
||||
+++ b/arch/mips/net/bpf_jit_comp.c
|
||||
@@ -404,6 +404,7 @@ void emit_alu_r(struct jit_context *ctx,
|
||||
/* Atomic read-modify-write (32-bit) */
|
||||
void emit_atomic_r(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 code)
|
||||
{
|
||||
+ LLSC_sync(ctx);
|
||||
emit(ctx, ll, MIPS_R_T9, off, dst);
|
||||
switch (code) {
|
||||
case BPF_ADD:
|
||||
@@ -420,18 +421,19 @@ void emit_atomic_r(struct jit_context *c
|
||||
break;
|
||||
}
|
||||
emit(ctx, sc, MIPS_R_T8, off, dst);
|
||||
- emit(ctx, beqz, MIPS_R_T8, -16);
|
||||
+ emit(ctx, LLSC_beqz, MIPS_R_T8, -16 - LLSC_offset);
|
||||
emit(ctx, nop); /* Delay slot */
|
||||
}
|
||||
|
||||
/* Atomic compare-and-exchange (32-bit) */
|
||||
void emit_cmpxchg_r(struct jit_context *ctx, u8 dst, u8 src, u8 res, s16 off)
|
||||
{
|
||||
+ LLSC_sync(ctx);
|
||||
emit(ctx, ll, MIPS_R_T9, off, dst);
|
||||
emit(ctx, bne, MIPS_R_T9, res, 12);
|
||||
emit(ctx, move, MIPS_R_T8, src); /* Delay slot */
|
||||
emit(ctx, sc, MIPS_R_T8, off, dst);
|
||||
- emit(ctx, beqz, MIPS_R_T8, -20);
|
||||
+ emit(ctx, LLSC_beqz, MIPS_R_T8, -20 - LLSC_offset);
|
||||
emit(ctx, move, res, MIPS_R_T9); /* Delay slot */
|
||||
clobber_reg(ctx, res);
|
||||
}
|
||||
--- a/arch/mips/net/bpf_jit_comp.h
|
||||
+++ b/arch/mips/net/bpf_jit_comp.h
|
||||
@@ -87,7 +87,7 @@ struct jit_context {
|
||||
};
|
||||
|
||||
/* Emit the instruction if the JIT memory space has been allocated */
|
||||
-#define emit(ctx, func, ...) \
|
||||
+#define __emit(ctx, func, ...) \
|
||||
do { \
|
||||
if ((ctx)->target != NULL) { \
|
||||
u32 *p = &(ctx)->target[ctx->jit_index]; \
|
||||
@@ -95,6 +95,30 @@ do { \
|
||||
} \
|
||||
(ctx)->jit_index++; \
|
||||
} while (0)
|
||||
+#define emit(...) __emit(__VA_ARGS__)
|
||||
+
|
||||
+/* Workaround for R10000 ll/sc errata */
|
||||
+#ifdef CONFIG_WAR_R10000
|
||||
+#define LLSC_beqz beqzl
|
||||
+#else
|
||||
+#define LLSC_beqz beqz
|
||||
+#endif
|
||||
+
|
||||
+/* Workaround for Loongson-3 ll/sc errata */
|
||||
+#ifdef CONFIG_CPU_LOONGSON3_WORKAROUNDS
|
||||
+#define LLSC_sync(ctx) emit(ctx, sync, 0)
|
||||
+#define LLSC_offset 4
|
||||
+#else
|
||||
+#define LLSC_sync(ctx)
|
||||
+#define LLSC_offset 0
|
||||
+#endif
|
||||
+
|
||||
+/* Workaround for Loongson-2F jump errata */
|
||||
+#ifdef CONFIG_CPU_JUMP_WORKAROUNDS
|
||||
+#define JALR_MASK 0xffffffffcfffffffULL
|
||||
+#else
|
||||
+#define JALR_MASK (~0ULL)
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* Mark a BPF register as accessed, it needs to be
|
||||
--- a/arch/mips/net/bpf_jit_comp64.c
|
||||
+++ b/arch/mips/net/bpf_jit_comp64.c
|
||||
@@ -375,6 +375,7 @@ static void emit_atomic_r64(struct jit_c
|
||||
u8 t1 = MIPS_R_T6;
|
||||
u8 t2 = MIPS_R_T7;
|
||||
|
||||
+ LLSC_sync(ctx);
|
||||
emit(ctx, lld, t1, off, dst);
|
||||
switch (code) {
|
||||
case BPF_ADD:
|
||||
@@ -391,7 +392,7 @@ static void emit_atomic_r64(struct jit_c
|
||||
break;
|
||||
}
|
||||
emit(ctx, scd, t2, off, dst);
|
||||
- emit(ctx, beqz, t2, -16);
|
||||
+ emit(ctx, LLSC_beqz, t2, -16 - LLSC_offset);
|
||||
emit(ctx, nop); /* Delay slot */
|
||||
}
|
||||
|
||||
@@ -414,7 +415,7 @@ static int emit_call(struct jit_context
|
||||
push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, 0, 0);
|
||||
|
||||
/* Emit function call */
|
||||
- emit_mov_i64(ctx, tmp, addr);
|
||||
+ emit_mov_i64(ctx, tmp, addr & JALR_MASK);
|
||||
emit(ctx, jalr, MIPS_R_RA, tmp);
|
||||
emit(ctx, nop); /* Delay slot */
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
From: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
Date: Tue, 5 Oct 2021 18:54:07 +0200
|
||||
Subject: [PATCH] mips: bpf: Enable eBPF JITs
|
||||
|
||||
This patch enables the new eBPF JITs for 32-bit and 64-bit MIPS. It also
|
||||
disables the old cBPF JIT to so cBPF programs are converted to use the
|
||||
new JIT.
|
||||
|
||||
Workarounds for R4000 CPU errata are not implemented by the JIT, so the
|
||||
JIT is disabled if any of those workarounds are configured.
|
||||
|
||||
Signed-off-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
---
|
||||
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -3428,6 +3428,7 @@ S: Supported
|
||||
F: arch/arm64/net/
|
||||
|
||||
BPF JIT for MIPS (32-BIT AND 64-BIT)
|
||||
+M: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
M: Paul Burton <paulburton@kernel.org>
|
||||
L: netdev@vger.kernel.org
|
||||
L: bpf@vger.kernel.org
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -57,7 +57,6 @@ config MIPS
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES
|
||||
select HAVE_ASM_MODVERSIONS
|
||||
- select HAVE_CBPF_JIT if !64BIT && !CPU_MICROMIPS
|
||||
select HAVE_CONTEXT_TRACKING
|
||||
select HAVE_TIF_NOHZ
|
||||
select HAVE_C_RECORDMCOUNT
|
||||
@@ -65,7 +64,10 @@ config MIPS
|
||||
select HAVE_DEBUG_STACKOVERFLOW
|
||||
select HAVE_DMA_CONTIGUOUS
|
||||
select HAVE_DYNAMIC_FTRACE
|
||||
- select HAVE_EBPF_JIT if 64BIT && !CPU_MICROMIPS && TARGET_ISA_REV >= 2
|
||||
+ select HAVE_EBPF_JIT if !CPU_MICROMIPS && \
|
||||
+ !CPU_DADDI_WORKAROUNDS && \
|
||||
+ !CPU_R4000_WORKAROUNDS && \
|
||||
+ !CPU_R4400_WORKAROUNDS
|
||||
select HAVE_EXIT_THREAD
|
||||
select HAVE_FAST_GUP
|
||||
select HAVE_FTRACE_MCOUNT_RECORD
|
||||
--- a/arch/mips/net/Makefile
|
||||
+++ b/arch/mips/net/Makefile
|
||||
@@ -2,9 +2,10 @@
|
||||
# MIPS networking code
|
||||
|
||||
obj-$(CONFIG_MIPS_CBPF_JIT) += bpf_jit.o bpf_jit_asm.o
|
||||
+obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp.o
|
||||
|
||||
ifeq ($(CONFIG_32BIT),y)
|
||||
- obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp.o bpf_jit_comp32.o
|
||||
+ obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp32.o
|
||||
else
|
||||
- obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o
|
||||
+ obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp64.o
|
||||
endif
|
||||
@ -0,0 +1,387 @@
|
||||
From: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
Date: Tue, 5 Oct 2021 18:54:08 +0200
|
||||
Subject: [PATCH] mips: bpf: Remove old BPF JIT implementations
|
||||
|
||||
This patch removes the old 32-bit cBPF and 64-bit eBPF JIT implementations.
|
||||
They are replaced by a new eBPF implementation that supports both 32-bit
|
||||
and 64-bit MIPS CPUs.
|
||||
|
||||
Signed-off-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
|
||||
---
|
||||
delete mode 100644 arch/mips/net/bpf_jit.c
|
||||
delete mode 100644 arch/mips/net/bpf_jit.h
|
||||
delete mode 100644 arch/mips/net/bpf_jit_asm.S
|
||||
delete mode 100644 arch/mips/net/ebpf_jit.c
|
||||
|
||||
--- a/arch/mips/net/bpf_jit.h
|
||||
+++ /dev/null
|
||||
@@ -1,81 +0,0 @@
|
||||
-/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
-/*
|
||||
- * Just-In-Time compiler for BPF filters on MIPS
|
||||
- *
|
||||
- * Copyright (c) 2014 Imagination Technologies Ltd.
|
||||
- * Author: Markos Chandras <markos.chandras@imgtec.com>
|
||||
- */
|
||||
-
|
||||
-#ifndef BPF_JIT_MIPS_OP_H
|
||||
-#define BPF_JIT_MIPS_OP_H
|
||||
-
|
||||
-/* Registers used by JIT */
|
||||
-#define MIPS_R_ZERO 0
|
||||
-#define MIPS_R_V0 2
|
||||
-#define MIPS_R_A0 4
|
||||
-#define MIPS_R_A1 5
|
||||
-#define MIPS_R_T4 12
|
||||
-#define MIPS_R_T5 13
|
||||
-#define MIPS_R_T6 14
|
||||
-#define MIPS_R_T7 15
|
||||
-#define MIPS_R_S0 16
|
||||
-#define MIPS_R_S1 17
|
||||
-#define MIPS_R_S2 18
|
||||
-#define MIPS_R_S3 19
|
||||
-#define MIPS_R_S4 20
|
||||
-#define MIPS_R_S5 21
|
||||
-#define MIPS_R_S6 22
|
||||
-#define MIPS_R_S7 23
|
||||
-#define MIPS_R_SP 29
|
||||
-#define MIPS_R_RA 31
|
||||
-
|
||||
-/* Conditional codes */
|
||||
-#define MIPS_COND_EQ 0x1
|
||||
-#define MIPS_COND_GE (0x1 << 1)
|
||||
-#define MIPS_COND_GT (0x1 << 2)
|
||||
-#define MIPS_COND_NE (0x1 << 3)
|
||||
-#define MIPS_COND_ALL (0x1 << 4)
|
||||
-/* Conditionals on X register or K immediate */
|
||||
-#define MIPS_COND_X (0x1 << 5)
|
||||
-#define MIPS_COND_K (0x1 << 6)
|
||||
-
|
||||
-#define r_ret MIPS_R_V0
|
||||
-
|
||||
-/*
|
||||
- * Use 2 scratch registers to avoid pipeline interlocks.
|
||||
- * There is no overhead during epilogue and prologue since
|
||||
- * any of the $s0-$s6 registers will only be preserved if
|
||||
- * they are going to actually be used.
|
||||
- */
|
||||
-#define r_skb_hl MIPS_R_S0 /* skb header length */
|
||||
-#define r_skb_data MIPS_R_S1 /* skb actual data */
|
||||
-#define r_off MIPS_R_S2
|
||||
-#define r_A MIPS_R_S3
|
||||
-#define r_X MIPS_R_S4
|
||||
-#define r_skb MIPS_R_S5
|
||||
-#define r_M MIPS_R_S6
|
||||
-#define r_skb_len MIPS_R_S7
|
||||
-#define r_s0 MIPS_R_T4 /* scratch reg 1 */
|
||||
-#define r_s1 MIPS_R_T5 /* scratch reg 2 */
|
||||
-#define r_tmp_imm MIPS_R_T6 /* No need to preserve this */
|
||||
-#define r_tmp MIPS_R_T7 /* No need to preserve this */
|
||||
-#define r_zero MIPS_R_ZERO
|
||||
-#define r_sp MIPS_R_SP
|
||||
-#define r_ra MIPS_R_RA
|
||||
-
|
||||
-#ifndef __ASSEMBLY__
|
||||
-
|
||||
-/* Declare ASM helpers */
|
||||
-
|
||||
-#define DECLARE_LOAD_FUNC(func) \
|
||||
- extern u8 func(unsigned long *skb, int offset); \
|
||||
- extern u8 func##_negative(unsigned long *skb, int offset); \
|
||||
- extern u8 func##_positive(unsigned long *skb, int offset)
|
||||
-
|
||||
-DECLARE_LOAD_FUNC(sk_load_word);
|
||||
-DECLARE_LOAD_FUNC(sk_load_half);
|
||||
-DECLARE_LOAD_FUNC(sk_load_byte);
|
||||
-
|
||||
-#endif
|
||||
-
|
||||
-#endif /* BPF_JIT_MIPS_OP_H */
|
||||
--- a/arch/mips/net/bpf_jit_asm.S
|
||||
+++ /dev/null
|
||||
@@ -1,285 +0,0 @@
|
||||
-/*
|
||||
- * bpf_jib_asm.S: Packet/header access helper functions for MIPS/MIPS64 BPF
|
||||
- * compiler.
|
||||
- *
|
||||
- * Copyright (C) 2015 Imagination Technologies Ltd.
|
||||
- * Author: Markos Chandras <markos.chandras@imgtec.com>
|
||||
- *
|
||||
- * This program is free software; you can redistribute it and/or modify it
|
||||
- * under the terms of the GNU General Public License as published by the
|
||||
- * Free Software Foundation; version 2 of the License.
|
||||
- */
|
||||
-
|
||||
-#include <asm/asm.h>
|
||||
-#include <asm/isa-rev.h>
|
||||
-#include <asm/regdef.h>
|
||||
-#include "bpf_jit.h"
|
||||
-
|
||||
-/* ABI
|
||||
- *
|
||||
- * r_skb_hl skb header length
|
||||
- * r_skb_data skb data
|
||||
- * r_off(a1) offset register
|
||||
- * r_A BPF register A
|
||||
- * r_X PF register X
|
||||
- * r_skb(a0) *skb
|
||||
- * r_M *scratch memory
|
||||
- * r_skb_le skb length
|
||||
- * r_s0 Scratch register 0
|
||||
- * r_s1 Scratch register 1
|
||||
- *
|
||||
- * On entry:
|
||||
- * a0: *skb
|
||||
- * a1: offset (imm or imm + X)
|
||||
- *
|
||||
- * All non-BPF-ABI registers are free for use. On return, we only
|
||||
- * care about r_ret. The BPF-ABI registers are assumed to remain
|
||||
- * unmodified during the entire filter operation.
|
||||
- */
|
||||
-
|
||||
-#define skb a0
|
||||
-#define offset a1
|
||||
-#define SKF_LL_OFF (-0x200000) /* Can't include linux/filter.h in assembly */
|
||||
-
|
||||
- /* We know better :) so prevent assembler reordering etc */
|
||||
- .set noreorder
|
||||
-
|
||||
-#define is_offset_negative(TYPE) \
|
||||
- /* If offset is negative we have more work to do */ \
|
||||
- slti t0, offset, 0; \
|
||||
- bgtz t0, bpf_slow_path_##TYPE##_neg; \
|
||||
- /* Be careful what follows in DS. */
|
||||
-
|
||||
-#define is_offset_in_header(SIZE, TYPE) \
|
||||
- /* Reading from header? */ \
|
||||
- addiu $r_s0, $r_skb_hl, -SIZE; \
|
||||
- slt t0, $r_s0, offset; \
|
||||
- bgtz t0, bpf_slow_path_##TYPE; \
|
||||
-
|
||||
-LEAF(sk_load_word)
|
||||
- is_offset_negative(word)
|
||||
-FEXPORT(sk_load_word_positive)
|
||||
- is_offset_in_header(4, word)
|
||||
- /* Offset within header boundaries */
|
||||
- PTR_ADDU t1, $r_skb_data, offset
|
||||
- .set reorder
|
||||
- lw $r_A, 0(t1)
|
||||
- .set noreorder
|
||||
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
|
||||
-# if MIPS_ISA_REV >= 2
|
||||
- wsbh t0, $r_A
|
||||
- rotr $r_A, t0, 16
|
||||
-# else
|
||||
- sll t0, $r_A, 24
|
||||
- srl t1, $r_A, 24
|
||||
- srl t2, $r_A, 8
|
||||
- or t0, t0, t1
|
||||
- andi t2, t2, 0xff00
|
||||
- andi t1, $r_A, 0xff00
|
||||
- or t0, t0, t2
|
||||
- sll t1, t1, 8
|
||||
- or $r_A, t0, t1
|
||||
-# endif
|
||||
-#endif
|
||||
- jr $r_ra
|
||||
- move $r_ret, zero
|
||||
- END(sk_load_word)
|
||||
-
|
||||
-LEAF(sk_load_half)
|
||||
- is_offset_negative(half)
|
||||
-FEXPORT(sk_load_half_positive)
|
||||
- is_offset_in_header(2, half)
|
||||
- /* Offset within header boundaries */
|
||||
- PTR_ADDU t1, $r_skb_data, offset
|
||||
- lhu $r_A, 0(t1)
|
||||
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
|
||||
-# if MIPS_ISA_REV >= 2
|
||||
- wsbh $r_A, $r_A
|
||||
-# else
|
||||
- sll t0, $r_A, 8
|
||||
- srl t1, $r_A, 8
|
||||
- andi t0, t0, 0xff00
|
||||
- or $r_A, t0, t1
|
||||
-# endif
|
||||
-#endif
|
||||
- jr $r_ra
|
||||
- move $r_ret, zero
|
||||
- END(sk_load_half)
|
||||
-
|
||||
-LEAF(sk_load_byte)
|
||||
- is_offset_negative(byte)
|
||||
-FEXPORT(sk_load_byte_positive)
|
||||
- is_offset_in_header(1, byte)
|
||||
- /* Offset within header boundaries */
|
||||
- PTR_ADDU t1, $r_skb_data, offset
|
||||
- lbu $r_A, 0(t1)
|
||||
- jr $r_ra
|
||||
- move $r_ret, zero
|
||||
- END(sk_load_byte)
|
||||
-
|
||||
-/*
|
||||
- * call skb_copy_bits:
|
||||
- * (prototype in linux/skbuff.h)
|
||||
- *
|
||||
- * int skb_copy_bits(sk_buff *skb, int offset, void *to, int len)
|
||||
- *
|
||||
- * o32 mandates we leave 4 spaces for argument registers in case
|
||||
- * the callee needs to use them. Even though we don't care about
|
||||
- * the argument registers ourselves, we need to allocate that space
|
||||
- * to remain ABI compliant since the callee may want to use that space.
|
||||
- * We also allocate 2 more spaces for $r_ra and our return register (*to).
|
||||
- *
|
||||
- * n64 is a bit different. The *caller* will allocate the space to preserve
|
||||
- * the arguments. So in 64-bit kernels, we allocate the 4-arg space for no
|
||||
- * good reason but it does not matter that much really.
|
||||
- *
|
||||
- * (void *to) is returned in r_s0
|
||||
- *
|
||||
- */
|
||||
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
|
||||
-#define DS_OFFSET(SIZE) (4 * SZREG)
|
||||
-#else
|
||||
-#define DS_OFFSET(SIZE) ((4 * SZREG) + (4 - SIZE))
|
||||
-#endif
|
||||
-#define bpf_slow_path_common(SIZE) \
|
||||
- /* Quick check. Are we within reasonable boundaries? */ \
|
||||
- LONG_ADDIU $r_s1, $r_skb_len, -SIZE; \
|
||||
- sltu $r_s0, offset, $r_s1; \
|
||||
- beqz $r_s0, fault; \
|
||||
- /* Load 4th argument in DS */ \
|
||||
- LONG_ADDIU a3, zero, SIZE; \
|
||||
- PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \
|
||||
- PTR_LA t0, skb_copy_bits; \
|
||||
- PTR_S $r_ra, (5 * SZREG)($r_sp); \
|
||||
- /* Assign low slot to a2 */ \
|
||||
- PTR_ADDIU a2, $r_sp, DS_OFFSET(SIZE); \
|
||||
- jalr t0; \
|
||||
- /* Reset our destination slot (DS but it's ok) */ \
|
||||
- INT_S zero, (4 * SZREG)($r_sp); \
|
||||
- /* \
|
||||
- * skb_copy_bits returns 0 on success and -EFAULT \
|
||||
- * on error. Our data live in a2. Do not bother with \
|
||||
- * our data if an error has been returned. \
|
||||
- */ \
|
||||
- /* Restore our frame */ \
|
||||
- PTR_L $r_ra, (5 * SZREG)($r_sp); \
|
||||
- INT_L $r_s0, (4 * SZREG)($r_sp); \
|
||||
- bltz v0, fault; \
|
||||
- PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \
|
||||
- move $r_ret, zero; \
|
||||
-
|
||||
-NESTED(bpf_slow_path_word, (6 * SZREG), $r_sp)
|
||||
- bpf_slow_path_common(4)
|
||||
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
|
||||
-# if MIPS_ISA_REV >= 2
|
||||
- wsbh t0, $r_s0
|
||||
- jr $r_ra
|
||||
- rotr $r_A, t0, 16
|
||||
-# else
|
||||
- sll t0, $r_s0, 24
|
||||
- srl t1, $r_s0, 24
|
||||
- srl t2, $r_s0, 8
|
||||
- or t0, t0, t1
|
||||
- andi t2, t2, 0xff00
|
||||
- andi t1, $r_s0, 0xff00
|
||||
- or t0, t0, t2
|
||||
- sll t1, t1, 8
|
||||
- jr $r_ra
|
||||
- or $r_A, t0, t1
|
||||
-# endif
|
||||
-#else
|
||||
- jr $r_ra
|
||||
- move $r_A, $r_s0
|
||||
-#endif
|
||||
-
|
||||
- END(bpf_slow_path_word)
|
||||
-
|
||||
-NESTED(bpf_slow_path_half, (6 * SZREG), $r_sp)
|
||||
- bpf_slow_path_common(2)
|
||||
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
|
||||
-# if MIPS_ISA_REV >= 2
|
||||
- jr $r_ra
|
||||
- wsbh $r_A, $r_s0
|
||||
-# else
|
||||
- sll t0, $r_s0, 8
|
||||
- andi t1, $r_s0, 0xff00
|
||||
- andi t0, t0, 0xff00
|
||||
- srl t1, t1, 8
|
||||
- jr $r_ra
|
||||
- or $r_A, t0, t1
|
||||
-# endif
|
||||
-#else
|
||||
- jr $r_ra
|
||||
- move $r_A, $r_s0
|
||||
-#endif
|
||||
-
|
||||
- END(bpf_slow_path_half)
|
||||
-
|
||||
-NESTED(bpf_slow_path_byte, (6 * SZREG), $r_sp)
|
||||
- bpf_slow_path_common(1)
|
||||
- jr $r_ra
|
||||
- move $r_A, $r_s0
|
||||
-
|
||||
- END(bpf_slow_path_byte)
|
||||
-
|
||||
-/*
|
||||
- * Negative entry points
|
||||
- */
|
||||
- .macro bpf_is_end_of_data
|
||||
- li t0, SKF_LL_OFF
|
||||
- /* Reading link layer data? */
|
||||
- slt t1, offset, t0
|
||||
- bgtz t1, fault
|
||||
- /* Be careful what follows in DS. */
|
||||
- .endm
|
||||
-/*
|
||||
- * call skb_copy_bits:
|
||||
- * (prototype in linux/filter.h)
|
||||
- *
|
||||
- * void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb,
|
||||
- * int k, unsigned int size)
|
||||
- *
|
||||
- * see above (bpf_slow_path_common) for ABI restrictions
|
||||
- */
|
||||
-#define bpf_negative_common(SIZE) \
|
||||
- PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \
|
||||
- PTR_LA t0, bpf_internal_load_pointer_neg_helper; \
|
||||
- PTR_S $r_ra, (5 * SZREG)($r_sp); \
|
||||
- jalr t0; \
|
||||
- li a2, SIZE; \
|
||||
- PTR_L $r_ra, (5 * SZREG)($r_sp); \
|
||||
- /* Check return pointer */ \
|
||||
- beqz v0, fault; \
|
||||
- PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \
|
||||
- /* Preserve our pointer */ \
|
||||
- move $r_s0, v0; \
|
||||
- /* Set return value */ \
|
||||
- move $r_ret, zero; \
|
||||
-
|
||||
-bpf_slow_path_word_neg:
|
||||
- bpf_is_end_of_data
|
||||
-NESTED(sk_load_word_negative, (6 * SZREG), $r_sp)
|
||||
- bpf_negative_common(4)
|
||||
- jr $r_ra
|
||||
- lw $r_A, 0($r_s0)
|
||||
- END(sk_load_word_negative)
|
||||
-
|
||||
-bpf_slow_path_half_neg:
|
||||
- bpf_is_end_of_data
|
||||
-NESTED(sk_load_half_negative, (6 * SZREG), $r_sp)
|
||||
- bpf_negative_common(2)
|
||||
- jr $r_ra
|
||||
- lhu $r_A, 0($r_s0)
|
||||
- END(sk_load_half_negative)
|
||||
-
|
||||
-bpf_slow_path_byte_neg:
|
||||
- bpf_is_end_of_data
|
||||
-NESTED(sk_load_byte_negative, (6 * SZREG), $r_sp)
|
||||
- bpf_negative_common(1)
|
||||
- jr $r_ra
|
||||
- lbu $r_A, 0($r_s0)
|
||||
- END(sk_load_byte_negative)
|
||||
-
|
||||
-fault:
|
||||
- jr $r_ra
|
||||
- addiu $r_ret, zero, 1
|
||||
@ -0,0 +1,52 @@
|
||||
From 02d6fdecb9c38de19065f6bed8d5214556fd061d Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 4 Nov 2021 16:00:40 +0100
|
||||
Subject: regmap: allow to define reg_update_bits for no bus configuration
|
||||
|
||||
Some device requires a special handling for reg_update_bits and can't use
|
||||
the normal regmap read write logic. An example is when locking is
|
||||
handled by the device and rmw operations requires to do atomic operations.
|
||||
Allow to declare a dedicated function in regmap_config for
|
||||
reg_update_bits in no bus configuration.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Link: https://lore.kernel.org/r/20211104150040.1260-1-ansuelsmth@gmail.com
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
---
|
||||
drivers/base/regmap/regmap.c | 1 +
|
||||
include/linux/regmap.h | 7 +++++++
|
||||
2 files changed, 8 insertions(+)
|
||||
|
||||
--- a/drivers/base/regmap/regmap.c
|
||||
+++ b/drivers/base/regmap/regmap.c
|
||||
@@ -877,6 +877,7 @@ struct regmap *__regmap_init(struct devi
|
||||
if (!bus) {
|
||||
map->reg_read = config->reg_read;
|
||||
map->reg_write = config->reg_write;
|
||||
+ map->reg_update_bits = config->reg_update_bits;
|
||||
|
||||
map->defer_caching = false;
|
||||
goto skip_format_initialization;
|
||||
--- a/include/linux/regmap.h
|
||||
+++ b/include/linux/regmap.h
|
||||
@@ -290,6 +290,11 @@ typedef void (*regmap_unlock)(void *);
|
||||
* read operation on a bus such as SPI, I2C, etc. Most of the
|
||||
* devices do not need this.
|
||||
* @reg_write: Same as above for writing.
|
||||
+ * @reg_update_bits: Optional callback that if filled will be used to perform
|
||||
+ * all the update_bits(rmw) operation. Should only be provided
|
||||
+ * if the function require special handling with lock and reg
|
||||
+ * handling and the operation cannot be represented as a simple
|
||||
+ * update_bits operation on a bus such as SPI, I2C, etc.
|
||||
* @fast_io: Register IO is fast. Use a spinlock instead of a mutex
|
||||
* to perform locking. This field is ignored if custom lock/unlock
|
||||
* functions are used (see fields lock/unlock of struct regmap_config).
|
||||
@@ -372,6 +377,8 @@ struct regmap_config {
|
||||
|
||||
int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
|
||||
int (*reg_write)(void *context, unsigned int reg, unsigned int val);
|
||||
+ int (*reg_update_bits)(void *context, unsigned int reg,
|
||||
+ unsigned int mask, unsigned int val);
|
||||
|
||||
bool fast_io;
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
To: linus.walleij@linaro.org
|
||||
Cc: bjorn.andersson@linaro.org, dianders@chromium.org,
|
||||
linux-arm-msm@vger.kernel.org, linux-gpio@vger.kernel.org,
|
||||
linux-kernel@vger.kernel.org,
|
||||
Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
Subject: [PATCH] pinctrl: qcom: Return -EINVAL for setting affinity if no IRQ
|
||||
parent
|
||||
Date: Thu, 13 Jan 2022 21:56:17 +0530
|
||||
Message-Id: <20220113162617.131697-1-manivannan.sadhasivam@linaro.org>
|
||||
|
||||
The MSM GPIO IRQ controller relies on the parent IRQ controller to set the
|
||||
CPU affinity for the IRQ. And this is only valid if there is any wakeup
|
||||
parent available and defined in DT.
|
||||
|
||||
For the case of no parent IRQ controller defined in DT,
|
||||
msm_gpio_irq_set_affinity() and msm_gpio_irq_set_vcpu_affinity() should
|
||||
return -EINVAL instead of 0 as the affinity can't be set.
|
||||
|
||||
Otherwise, below warning will be printed by genirq:
|
||||
|
||||
genirq: irq_chip msmgpio did not update eff. affinity mask of irq 70
|
||||
|
||||
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
---
|
||||
drivers/pinctrl/qcom/pinctrl-msm.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
|
||||
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
|
||||
@@ -1157,7 +1157,7 @@ static int msm_gpio_irq_set_affinity(str
|
||||
if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs))
|
||||
return irq_chip_set_affinity_parent(d, dest, force);
|
||||
|
||||
- return 0;
|
||||
+ return -EINVAL;
|
||||
}
|
||||
|
||||
static int msm_gpio_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
|
||||
@@ -1168,7 +1168,7 @@ static int msm_gpio_irq_set_vcpu_affinit
|
||||
if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs))
|
||||
return irq_chip_set_vcpu_affinity_parent(d, vcpu_info);
|
||||
|
||||
- return 0;
|
||||
+ return -EINVAL;
|
||||
}
|
||||
|
||||
static void msm_gpio_irq_handler(struct irq_desc *desc)
|
||||
@ -0,0 +1,106 @@
|
||||
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Thu, 25 Jan 2018 12:58:55 +0100
|
||||
Subject: [PATCH] netfilter: nft_flow_offload: handle netdevice events from
|
||||
nf_flow_table
|
||||
|
||||
Move the code that deals with device events to the core.
|
||||
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -646,13 +646,41 @@ void nf_flow_table_free(struct nf_flowta
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_table_free);
|
||||
|
||||
+static int nf_flow_table_netdev_event(struct notifier_block *this,
|
||||
+ unsigned long event, void *ptr)
|
||||
+{
|
||||
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
+
|
||||
+ if (event != NETDEV_DOWN)
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ nf_flow_table_cleanup(dev);
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block flow_offload_netdev_notifier = {
|
||||
+ .notifier_call = nf_flow_table_netdev_event,
|
||||
+};
|
||||
+
|
||||
static int __init nf_flow_table_module_init(void)
|
||||
{
|
||||
- return nf_flow_table_offload_init();
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = nf_flow_table_offload_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = register_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
+ if (ret)
|
||||
+ nf_flow_table_offload_exit();
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static void __exit nf_flow_table_module_exit(void)
|
||||
{
|
||||
+ unregister_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
nf_flow_table_offload_exit();
|
||||
}
|
||||
|
||||
--- a/net/netfilter/nft_flow_offload.c
|
||||
+++ b/net/netfilter/nft_flow_offload.c
|
||||
@@ -438,47 +438,14 @@ static struct nft_expr_type nft_flow_off
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
-static int flow_offload_netdev_event(struct notifier_block *this,
|
||||
- unsigned long event, void *ptr)
|
||||
-{
|
||||
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
-
|
||||
- if (event != NETDEV_DOWN)
|
||||
- return NOTIFY_DONE;
|
||||
-
|
||||
- nf_flow_table_cleanup(dev);
|
||||
-
|
||||
- return NOTIFY_DONE;
|
||||
-}
|
||||
-
|
||||
-static struct notifier_block flow_offload_netdev_notifier = {
|
||||
- .notifier_call = flow_offload_netdev_event,
|
||||
-};
|
||||
-
|
||||
static int __init nft_flow_offload_module_init(void)
|
||||
{
|
||||
- int err;
|
||||
-
|
||||
- err = register_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
- if (err)
|
||||
- goto err;
|
||||
-
|
||||
- err = nft_register_expr(&nft_flow_offload_type);
|
||||
- if (err < 0)
|
||||
- goto register_expr;
|
||||
-
|
||||
- return 0;
|
||||
-
|
||||
-register_expr:
|
||||
- unregister_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
-err:
|
||||
- return err;
|
||||
+ return nft_register_expr(&nft_flow_offload_type);
|
||||
}
|
||||
|
||||
static void __exit nft_flow_offload_module_exit(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_flow_offload_type);
|
||||
- unregister_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
}
|
||||
|
||||
module_init(nft_flow_offload_module_init);
|
||||
@ -0,0 +1,33 @@
|
||||
From 2365f91c861cbfeef7141c69842848c7b2d3c2db Mon Sep 17 00:00:00 2001
|
||||
From: INAGAKI Hiroshi <musashino.open@gmail.com>
|
||||
Date: Sun, 13 Feb 2022 15:40:44 +0900
|
||||
Subject: [PATCH] mtd: parsers: trx: allow to use on MediaTek MIPS SoCs
|
||||
|
||||
Buffalo sells some router devices which have trx-formatted firmware,
|
||||
based on MediaTek MIPS SoCs. To use parser_trx on those devices, add
|
||||
"RALINK" to dependency and allow to compile for MediaTek MIPS SoCs.
|
||||
|
||||
examples:
|
||||
|
||||
- WCR-1166DS (MT7628)
|
||||
- WSR-1166DHP (MT7621)
|
||||
- WSR-2533DHP (MT7621)
|
||||
|
||||
Signed-off-by: INAGAKI Hiroshi <musashino.open@gmail.com>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
Link: https://lore.kernel.org/linux-mtd/20220213064045.1781-1-musashino.open@gmail.com
|
||||
---
|
||||
drivers/mtd/parsers/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/parsers/Kconfig
|
||||
+++ b/drivers/mtd/parsers/Kconfig
|
||||
@@ -115,7 +115,7 @@ config MTD_AFS_PARTS
|
||||
|
||||
config MTD_PARSER_TRX
|
||||
tristate "Parser for TRX format partitions"
|
||||
- depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || COMPILE_TEST)
|
||||
+ depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST)
|
||||
help
|
||||
TRX is a firmware format used by Broadcom on their devices. It
|
||||
may contain up to 3/4 partitions (depending on the version).
|
||||
@ -0,0 +1,279 @@
|
||||
From dc452a471dbae8aca8257c565174212620880093 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Fri, 10 Dec 2021 01:34:37 +0200
|
||||
Subject: net: dsa: introduce tagger-owned storage for private and shared data
|
||||
|
||||
Ansuel is working on register access over Ethernet for the qca8k switch
|
||||
family. This requires the qca8k tagging protocol driver to receive
|
||||
frames which aren't intended for the network stack, but instead for the
|
||||
qca8k switch driver itself.
|
||||
|
||||
The dp->priv is currently the prevailing method for passing data back
|
||||
and forth between the tagging protocol driver and the switch driver.
|
||||
However, this method is riddled with caveats.
|
||||
|
||||
The DSA design allows in principle for any switch driver to return any
|
||||
protocol it desires in ->get_tag_protocol(). The dsa_loop driver can be
|
||||
modified to do just that. But in the current design, the memory behind
|
||||
dp->priv has to be allocated by the switch driver, so if the tagging
|
||||
protocol is paired to an unexpected switch driver, we may end up in NULL
|
||||
pointer dereferences inside the kernel, or worse (a switch driver may
|
||||
allocate dp->priv according to the expectations of a different tagger).
|
||||
|
||||
The latter possibility is even more plausible considering that DSA
|
||||
switches can dynamically change tagging protocols in certain cases
|
||||
(dsa <-> edsa, ocelot <-> ocelot-8021q), and the current design lends
|
||||
itself to mistakes that are all too easy to make.
|
||||
|
||||
This patch proposes that the tagging protocol driver should manage its
|
||||
own memory, instead of relying on the switch driver to do so.
|
||||
After analyzing the different in-tree needs, it can be observed that the
|
||||
required tagger storage is per switch, therefore a ds->tagger_data
|
||||
pointer is introduced. In principle, per-port storage could also be
|
||||
introduced, although there is no need for it at the moment. Future
|
||||
changes will replace the current usage of dp->priv with ds->tagger_data.
|
||||
|
||||
We define a "binding" event between the DSA switch tree and the tagging
|
||||
protocol. During this binding event, the tagging protocol's ->connect()
|
||||
method is called first, and this may allocate some memory for each
|
||||
switch of the tree. Then a cross-chip notifier is emitted for the
|
||||
switches within that tree, and they are given the opportunity to fix up
|
||||
the tagger's memory (for example, they might set up some function
|
||||
pointers that represent virtual methods for consuming packets).
|
||||
Because the memory is owned by the tagger, there exists a ->disconnect()
|
||||
method for the tagger (which is the place to free the resources), but
|
||||
there doesn't exist a ->disconnect() method for the switch driver.
|
||||
This is part of the design. The switch driver should make minimal use of
|
||||
the public part of the tagger data, and only after type-checking it
|
||||
using the supplied "proto" argument.
|
||||
|
||||
In the code there are in fact two binding events, one is the initial
|
||||
event in dsa_switch_setup_tag_protocol(). At this stage, the cross chip
|
||||
notifier chains aren't initialized, so we call each switch's connect()
|
||||
method by hand. Then there is dsa_tree_bind_tag_proto() during
|
||||
dsa_tree_change_tag_proto(), and here we have an old protocol and a new
|
||||
one. We first connect to the new one before disconnecting from the old
|
||||
one, to simplify error handling a bit and to ensure we remain in a valid
|
||||
state at all times.
|
||||
|
||||
Co-developed-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/net/dsa.h | 12 +++++++++
|
||||
net/dsa/dsa2.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
net/dsa/dsa_priv.h | 1 +
|
||||
net/dsa/switch.c | 14 +++++++++++
|
||||
4 files changed, 96 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@@ -80,12 +80,15 @@ enum dsa_tag_protocol {
|
||||
};
|
||||
|
||||
struct dsa_switch;
|
||||
+struct dsa_switch_tree;
|
||||
|
||||
struct dsa_device_ops {
|
||||
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
|
||||
struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev);
|
||||
void (*flow_dissect)(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset);
|
||||
+ int (*connect)(struct dsa_switch_tree *dst);
|
||||
+ void (*disconnect)(struct dsa_switch_tree *dst);
|
||||
unsigned int needed_headroom;
|
||||
unsigned int needed_tailroom;
|
||||
const char *name;
|
||||
@@ -329,6 +332,8 @@ struct dsa_switch {
|
||||
*/
|
||||
void *priv;
|
||||
|
||||
+ void *tagger_data;
|
||||
+
|
||||
/*
|
||||
* Configuration data for this switch.
|
||||
*/
|
||||
@@ -584,6 +589,13 @@ struct dsa_switch_ops {
|
||||
enum dsa_tag_protocol mprot);
|
||||
int (*change_tag_protocol)(struct dsa_switch *ds, int port,
|
||||
enum dsa_tag_protocol proto);
|
||||
+ /*
|
||||
+ * Method for switch drivers to connect to the tagging protocol driver
|
||||
+ * in current use. The switch driver can provide handlers for certain
|
||||
+ * types of packets for switch management.
|
||||
+ */
|
||||
+ int (*connect_tag_protocol)(struct dsa_switch *ds,
|
||||
+ enum dsa_tag_protocol proto);
|
||||
|
||||
/* Optional switch-wide initialization and destruction methods */
|
||||
int (*setup)(struct dsa_switch *ds);
|
||||
--- a/net/dsa/dsa2.c
|
||||
+++ b/net/dsa/dsa2.c
|
||||
@@ -230,8 +230,12 @@ static struct dsa_switch_tree *dsa_tree_
|
||||
|
||||
static void dsa_tree_free(struct dsa_switch_tree *dst)
|
||||
{
|
||||
- if (dst->tag_ops)
|
||||
+ if (dst->tag_ops) {
|
||||
+ if (dst->tag_ops->disconnect)
|
||||
+ dst->tag_ops->disconnect(dst);
|
||||
+
|
||||
dsa_tag_driver_put(dst->tag_ops);
|
||||
+ }
|
||||
list_del(&dst->list);
|
||||
kfree(dst);
|
||||
}
|
||||
@@ -805,7 +809,7 @@ static int dsa_switch_setup_tag_protocol
|
||||
int port, err;
|
||||
|
||||
if (tag_ops->proto == dst->default_proto)
|
||||
- return 0;
|
||||
+ goto connect;
|
||||
|
||||
for (port = 0; port < ds->num_ports; port++) {
|
||||
if (!dsa_is_cpu_port(ds, port))
|
||||
@@ -821,6 +825,17 @@ static int dsa_switch_setup_tag_protocol
|
||||
}
|
||||
}
|
||||
|
||||
+connect:
|
||||
+ if (ds->ops->connect_tag_protocol) {
|
||||
+ err = ds->ops->connect_tag_protocol(ds, tag_ops->proto);
|
||||
+ if (err) {
|
||||
+ dev_err(ds->dev,
|
||||
+ "Unable to connect to tag protocol \"%s\": %pe\n",
|
||||
+ tag_ops->name, ERR_PTR(err));
|
||||
+ return err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1132,6 +1147,46 @@ static void dsa_tree_teardown(struct dsa
|
||||
dst->setup = false;
|
||||
}
|
||||
|
||||
+static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst,
|
||||
+ const struct dsa_device_ops *tag_ops)
|
||||
+{
|
||||
+ const struct dsa_device_ops *old_tag_ops = dst->tag_ops;
|
||||
+ struct dsa_notifier_tag_proto_info info;
|
||||
+ int err;
|
||||
+
|
||||
+ dst->tag_ops = tag_ops;
|
||||
+
|
||||
+ /* Notify the new tagger about the connection to this tree */
|
||||
+ if (tag_ops->connect) {
|
||||
+ err = tag_ops->connect(dst);
|
||||
+ if (err)
|
||||
+ goto out_revert;
|
||||
+ }
|
||||
+
|
||||
+ /* Notify the switches from this tree about the connection
|
||||
+ * to the new tagger
|
||||
+ */
|
||||
+ info.tag_ops = tag_ops;
|
||||
+ err = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_CONNECT, &info);
|
||||
+ if (err && err != -EOPNOTSUPP)
|
||||
+ goto out_disconnect;
|
||||
+
|
||||
+ /* Notify the old tagger about the disconnection from this tree */
|
||||
+ if (old_tag_ops->disconnect)
|
||||
+ old_tag_ops->disconnect(dst);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_disconnect:
|
||||
+ /* Revert the new tagger's connection to this tree */
|
||||
+ if (tag_ops->disconnect)
|
||||
+ tag_ops->disconnect(dst);
|
||||
+out_revert:
|
||||
+ dst->tag_ops = old_tag_ops;
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
/* Since the dsa/tagging sysfs device attribute is per master, the assumption
|
||||
* is that all DSA switches within a tree share the same tagger, otherwise
|
||||
* they would have formed disjoint trees (different "dsa,member" values).
|
||||
@@ -1164,12 +1219,15 @@ int dsa_tree_change_tag_proto(struct dsa
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
+ /* Notify the tag protocol change */
|
||||
info.tag_ops = tag_ops;
|
||||
err = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, &info);
|
||||
if (err)
|
||||
- goto out_unwind_tagger;
|
||||
+ return err;
|
||||
|
||||
- dst->tag_ops = tag_ops;
|
||||
+ err = dsa_tree_bind_tag_proto(dst, tag_ops);
|
||||
+ if (err)
|
||||
+ goto out_unwind_tagger;
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
@@ -1257,6 +1315,7 @@ static int dsa_port_parse_cpu(struct dsa
|
||||
struct dsa_switch_tree *dst = ds->dst;
|
||||
const struct dsa_device_ops *tag_ops;
|
||||
enum dsa_tag_protocol default_proto;
|
||||
+ int err;
|
||||
|
||||
/* Find out which protocol the switch would prefer. */
|
||||
default_proto = dsa_get_tag_protocol(dp, master);
|
||||
@@ -1304,6 +1363,12 @@ static int dsa_port_parse_cpu(struct dsa
|
||||
*/
|
||||
dsa_tag_driver_put(tag_ops);
|
||||
} else {
|
||||
+ if (tag_ops->connect) {
|
||||
+ err = tag_ops->connect(dst);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
dst->tag_ops = tag_ops;
|
||||
}
|
||||
|
||||
--- a/net/dsa/dsa_priv.h
|
||||
+++ b/net/dsa/dsa_priv.h
|
||||
@@ -37,6 +37,7 @@ enum {
|
||||
DSA_NOTIFIER_VLAN_DEL,
|
||||
DSA_NOTIFIER_MTU,
|
||||
DSA_NOTIFIER_TAG_PROTO,
|
||||
+ DSA_NOTIFIER_TAG_PROTO_CONNECT,
|
||||
DSA_NOTIFIER_MRP_ADD,
|
||||
DSA_NOTIFIER_MRP_DEL,
|
||||
DSA_NOTIFIER_MRP_ADD_RING_ROLE,
|
||||
--- a/net/dsa/switch.c
|
||||
+++ b/net/dsa/switch.c
|
||||
@@ -616,6 +616,17 @@ static int dsa_switch_change_tag_proto(s
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int dsa_switch_connect_tag_proto(struct dsa_switch *ds,
|
||||
+ struct dsa_notifier_tag_proto_info *info)
|
||||
+{
|
||||
+ const struct dsa_device_ops *tag_ops = info->tag_ops;
|
||||
+
|
||||
+ if (!ds->ops->connect_tag_protocol)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ return ds->ops->connect_tag_protocol(ds, tag_ops->proto);
|
||||
+}
|
||||
+
|
||||
static int dsa_switch_mrp_add(struct dsa_switch *ds,
|
||||
struct dsa_notifier_mrp_info *info)
|
||||
{
|
||||
@@ -735,6 +746,9 @@ static int dsa_switch_event(struct notif
|
||||
case DSA_NOTIFIER_TAG_PROTO:
|
||||
err = dsa_switch_change_tag_proto(ds, info);
|
||||
break;
|
||||
+ case DSA_NOTIFIER_TAG_PROTO_CONNECT:
|
||||
+ err = dsa_switch_connect_tag_proto(ds, info);
|
||||
+ break;
|
||||
case DSA_NOTIFIER_MRP_ADD:
|
||||
err = dsa_switch_mrp_add(ds, info);
|
||||
break;
|
||||
@ -0,0 +1,274 @@
|
||||
From 7f2973149c22e7a6fee4c0c9fa6b8e4108e9c208 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Tue, 14 Dec 2021 03:45:36 +0200
|
||||
Subject: net: dsa: make tagging protocols connect to individual switches from
|
||||
a tree
|
||||
|
||||
On the NXP Bluebox 3 board which uses a multi-switch setup with sja1105,
|
||||
the mechanism through which the tagger connects to the switch tree is
|
||||
broken, due to improper DSA code design. At the time when tag_ops->connect()
|
||||
is called in dsa_port_parse_cpu(), DSA hasn't finished "touching" all
|
||||
the ports, so it doesn't know how large the tree is and how many ports
|
||||
it has. It has just seen the first CPU port by this time. As a result,
|
||||
this function will call the tagger's ->connect method too early, and the
|
||||
tagger will connect only to the first switch from the tree.
|
||||
|
||||
This could be perhaps addressed a bit more simply by just moving the
|
||||
tag_ops->connect(dst) call a bit later (for example in dsa_tree_setup),
|
||||
but there is already a design inconsistency at present: on the switch
|
||||
side, the notification is on a per-switch basis, but on the tagger side,
|
||||
it is on a per-tree basis. Furthermore, the persistent storage itself is
|
||||
per switch (ds->tagger_data). And the tagger connect and disconnect
|
||||
procedures (at least the ones that exist currently) could see a fair bit
|
||||
of simplification if they didn't have to iterate through the switches of
|
||||
a tree.
|
||||
|
||||
To fix the issue, this change transforms tag_ops->connect(dst) into
|
||||
tag_ops->connect(ds) and moves it somewhere where we already iterate
|
||||
over all switches of a tree. That is in dsa_switch_setup_tag_protocol(),
|
||||
which is a good placement because we already have there the connection
|
||||
call to the switch side of things.
|
||||
|
||||
As for the dsa_tree_bind_tag_proto() method (called from the code path
|
||||
that changes the tag protocol), things are a bit more complicated
|
||||
because we receive the tree as argument, yet when we unwind on errors,
|
||||
it would be nice to not call tag_ops->disconnect(ds) where we didn't
|
||||
previously call tag_ops->connect(ds). We didn't have this problem before
|
||||
because the tag_ops connection operations passed the entire dst before,
|
||||
and this is more fine grained now. To solve the error rewind case using
|
||||
the new API, we have to create yet one more cross-chip notifier for
|
||||
disconnection, and stay connected with the old tag protocol to all the
|
||||
switches in the tree until we've succeeded to connect with the new one
|
||||
as well. So if something fails half way, the whole tree is still
|
||||
connected to the old tagger. But there may still be leaks if the tagger
|
||||
fails to connect to the 2nd out of 3 switches in a tree: somebody needs
|
||||
to tell the tagger to disconnect from the first switch. Nothing comes
|
||||
for free, and this was previously handled privately by the tagging
|
||||
protocol driver before, but now we need to emit a disconnect cross-chip
|
||||
notifier for that, because DSA has to take care of the unwind path. We
|
||||
assume that the tagging protocol has connected to a switch if it has set
|
||||
ds->tagger_data to something, otherwise we avoid calling its
|
||||
disconnection method in the error rewind path.
|
||||
|
||||
The rest of the changes are in the tagging protocol drivers, and have to
|
||||
do with the replacement of dst with ds. The iteration is removed and the
|
||||
error unwind path is simplified, as mentioned above.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/net/dsa.h | 5 ++--
|
||||
net/dsa/dsa2.c | 44 +++++++++++++-----------------
|
||||
net/dsa/dsa_priv.h | 1 +
|
||||
net/dsa/switch.c | 52 ++++++++++++++++++++++++++++++++---
|
||||
net/dsa/tag_ocelot_8021q.c | 53 +++++++++++-------------------------
|
||||
net/dsa/tag_sja1105.c | 67 ++++++++++++++++------------------------------
|
||||
6 files changed, 109 insertions(+), 113 deletions(-)
|
||||
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@@ -80,15 +80,14 @@ enum dsa_tag_protocol {
|
||||
};
|
||||
|
||||
struct dsa_switch;
|
||||
-struct dsa_switch_tree;
|
||||
|
||||
struct dsa_device_ops {
|
||||
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
|
||||
struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev);
|
||||
void (*flow_dissect)(const struct sk_buff *skb, __be16 *proto,
|
||||
int *offset);
|
||||
- int (*connect)(struct dsa_switch_tree *dst);
|
||||
- void (*disconnect)(struct dsa_switch_tree *dst);
|
||||
+ int (*connect)(struct dsa_switch *ds);
|
||||
+ void (*disconnect)(struct dsa_switch *ds);
|
||||
unsigned int needed_headroom;
|
||||
unsigned int needed_tailroom;
|
||||
const char *name;
|
||||
--- a/net/dsa/dsa2.c
|
||||
+++ b/net/dsa/dsa2.c
|
||||
@@ -230,12 +230,8 @@ static struct dsa_switch_tree *dsa_tree_
|
||||
|
||||
static void dsa_tree_free(struct dsa_switch_tree *dst)
|
||||
{
|
||||
- if (dst->tag_ops) {
|
||||
- if (dst->tag_ops->disconnect)
|
||||
- dst->tag_ops->disconnect(dst);
|
||||
-
|
||||
+ if (dst->tag_ops)
|
||||
dsa_tag_driver_put(dst->tag_ops);
|
||||
- }
|
||||
list_del(&dst->list);
|
||||
kfree(dst);
|
||||
}
|
||||
@@ -826,17 +822,29 @@ static int dsa_switch_setup_tag_protocol
|
||||
}
|
||||
|
||||
connect:
|
||||
+ if (tag_ops->connect) {
|
||||
+ err = tag_ops->connect(ds);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
if (ds->ops->connect_tag_protocol) {
|
||||
err = ds->ops->connect_tag_protocol(ds, tag_ops->proto);
|
||||
if (err) {
|
||||
dev_err(ds->dev,
|
||||
"Unable to connect to tag protocol \"%s\": %pe\n",
|
||||
tag_ops->name, ERR_PTR(err));
|
||||
- return err;
|
||||
+ goto disconnect;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
+
|
||||
+disconnect:
|
||||
+ if (tag_ops->disconnect)
|
||||
+ tag_ops->disconnect(ds);
|
||||
+
|
||||
+ return err;
|
||||
}
|
||||
|
||||
static int dsa_switch_setup(struct dsa_switch *ds)
|
||||
@@ -1156,13 +1164,6 @@ static int dsa_tree_bind_tag_proto(struc
|
||||
|
||||
dst->tag_ops = tag_ops;
|
||||
|
||||
- /* Notify the new tagger about the connection to this tree */
|
||||
- if (tag_ops->connect) {
|
||||
- err = tag_ops->connect(dst);
|
||||
- if (err)
|
||||
- goto out_revert;
|
||||
- }
|
||||
-
|
||||
/* Notify the switches from this tree about the connection
|
||||
* to the new tagger
|
||||
*/
|
||||
@@ -1172,16 +1173,14 @@ static int dsa_tree_bind_tag_proto(struc
|
||||
goto out_disconnect;
|
||||
|
||||
/* Notify the old tagger about the disconnection from this tree */
|
||||
- if (old_tag_ops->disconnect)
|
||||
- old_tag_ops->disconnect(dst);
|
||||
+ info.tag_ops = old_tag_ops;
|
||||
+ dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_DISCONNECT, &info);
|
||||
|
||||
return 0;
|
||||
|
||||
out_disconnect:
|
||||
- /* Revert the new tagger's connection to this tree */
|
||||
- if (tag_ops->disconnect)
|
||||
- tag_ops->disconnect(dst);
|
||||
-out_revert:
|
||||
+ info.tag_ops = tag_ops;
|
||||
+ dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_DISCONNECT, &info);
|
||||
dst->tag_ops = old_tag_ops;
|
||||
|
||||
return err;
|
||||
@@ -1315,7 +1314,6 @@ static int dsa_port_parse_cpu(struct dsa
|
||||
struct dsa_switch_tree *dst = ds->dst;
|
||||
const struct dsa_device_ops *tag_ops;
|
||||
enum dsa_tag_protocol default_proto;
|
||||
- int err;
|
||||
|
||||
/* Find out which protocol the switch would prefer. */
|
||||
default_proto = dsa_get_tag_protocol(dp, master);
|
||||
@@ -1363,12 +1361,6 @@ static int dsa_port_parse_cpu(struct dsa
|
||||
*/
|
||||
dsa_tag_driver_put(tag_ops);
|
||||
} else {
|
||||
- if (tag_ops->connect) {
|
||||
- err = tag_ops->connect(dst);
|
||||
- if (err)
|
||||
- return err;
|
||||
- }
|
||||
-
|
||||
dst->tag_ops = tag_ops;
|
||||
}
|
||||
|
||||
--- a/net/dsa/dsa_priv.h
|
||||
+++ b/net/dsa/dsa_priv.h
|
||||
@@ -38,6 +38,7 @@ enum {
|
||||
DSA_NOTIFIER_MTU,
|
||||
DSA_NOTIFIER_TAG_PROTO,
|
||||
DSA_NOTIFIER_TAG_PROTO_CONNECT,
|
||||
+ DSA_NOTIFIER_TAG_PROTO_DISCONNECT,
|
||||
DSA_NOTIFIER_MRP_ADD,
|
||||
DSA_NOTIFIER_MRP_DEL,
|
||||
DSA_NOTIFIER_MRP_ADD_RING_ROLE,
|
||||
--- a/net/dsa/switch.c
|
||||
+++ b/net/dsa/switch.c
|
||||
@@ -616,15 +616,58 @@ static int dsa_switch_change_tag_proto(s
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int dsa_switch_connect_tag_proto(struct dsa_switch *ds,
|
||||
- struct dsa_notifier_tag_proto_info *info)
|
||||
+/* We use the same cross-chip notifiers to inform both the tagger side, as well
|
||||
+ * as the switch side, of connection and disconnection events.
|
||||
+ * Since ds->tagger_data is owned by the tagger, it isn't a hard error if the
|
||||
+ * switch side doesn't support connecting to this tagger, and therefore, the
|
||||
+ * fact that we don't disconnect the tagger side doesn't constitute a memory
|
||||
+ * leak: the tagger will still operate with persistent per-switch memory, just
|
||||
+ * with the switch side unconnected to it. What does constitute a hard error is
|
||||
+ * when the switch side supports connecting but fails.
|
||||
+ */
|
||||
+static int
|
||||
+dsa_switch_connect_tag_proto(struct dsa_switch *ds,
|
||||
+ struct dsa_notifier_tag_proto_info *info)
|
||||
{
|
||||
const struct dsa_device_ops *tag_ops = info->tag_ops;
|
||||
+ int err;
|
||||
+
|
||||
+ /* Notify the new tagger about the connection to this switch */
|
||||
+ if (tag_ops->connect) {
|
||||
+ err = tag_ops->connect(ds);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ }
|
||||
|
||||
if (!ds->ops->connect_tag_protocol)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
- return ds->ops->connect_tag_protocol(ds, tag_ops->proto);
|
||||
+ /* Notify the switch about the connection to the new tagger */
|
||||
+ err = ds->ops->connect_tag_protocol(ds, tag_ops->proto);
|
||||
+ if (err) {
|
||||
+ /* Revert the new tagger's connection to this tree */
|
||||
+ if (tag_ops->disconnect)
|
||||
+ tag_ops->disconnect(ds);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+dsa_switch_disconnect_tag_proto(struct dsa_switch *ds,
|
||||
+ struct dsa_notifier_tag_proto_info *info)
|
||||
+{
|
||||
+ const struct dsa_device_ops *tag_ops = info->tag_ops;
|
||||
+
|
||||
+ /* Notify the tagger about the disconnection from this switch */
|
||||
+ if (tag_ops->disconnect && ds->tagger_data)
|
||||
+ tag_ops->disconnect(ds);
|
||||
+
|
||||
+ /* No need to notify the switch, since it shouldn't have any
|
||||
+ * resources to tear down
|
||||
+ */
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int dsa_switch_mrp_add(struct dsa_switch *ds,
|
||||
@@ -749,6 +792,9 @@ static int dsa_switch_event(struct notif
|
||||
case DSA_NOTIFIER_TAG_PROTO_CONNECT:
|
||||
err = dsa_switch_connect_tag_proto(ds, info);
|
||||
break;
|
||||
+ case DSA_NOTIFIER_TAG_PROTO_DISCONNECT:
|
||||
+ err = dsa_switch_disconnect_tag_proto(ds, info);
|
||||
+ break;
|
||||
case DSA_NOTIFIER_MRP_ADD:
|
||||
err = dsa_switch_mrp_add(ds, info);
|
||||
break;
|
||||
@ -0,0 +1,84 @@
|
||||
From b5375509184dc23d2b7fa0c5ed8763899ccc9674 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Sat, 2 Oct 2021 19:58:11 +0200
|
||||
Subject: [PATCH] net: bgmac: improve handling PHY
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
1. Use info from DT if available
|
||||
|
||||
It allows describing for example a fixed link. It's more accurate than
|
||||
just guessing there may be one (depending on a chipset).
|
||||
|
||||
2. Verify PHY ID before trying to connect PHY
|
||||
|
||||
PHY addr 0x1e (30) is special in Broadcom routers and means a switch
|
||||
connected as MDIO devices instead of a real PHY. Don't try connecting to
|
||||
it.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma.c | 33 ++++++++++++++--------
|
||||
1 file changed, 21 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/brcmphy.h>
|
||||
#include <linux/etherdevice.h>
|
||||
+#include <linux/of_mdio.h>
|
||||
#include <linux/of_net.h>
|
||||
#include "bgmac.h"
|
||||
|
||||
@@ -86,17 +87,28 @@ static int bcma_phy_connect(struct bgmac
|
||||
struct phy_device *phy_dev;
|
||||
char bus_id[MII_BUS_ID_SIZE + 3];
|
||||
|
||||
+ /* DT info should be the most accurate */
|
||||
+ phy_dev = of_phy_get_and_connect(bgmac->net_dev, bgmac->dev->of_node,
|
||||
+ bgmac_adjust_link);
|
||||
+ if (phy_dev)
|
||||
+ return 0;
|
||||
+
|
||||
/* Connect to the PHY */
|
||||
- snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id,
|
||||
- bgmac->phyaddr);
|
||||
- phy_dev = phy_connect(bgmac->net_dev, bus_id, bgmac_adjust_link,
|
||||
- PHY_INTERFACE_MODE_MII);
|
||||
- if (IS_ERR(phy_dev)) {
|
||||
- dev_err(bgmac->dev, "PHY connection failed\n");
|
||||
- return PTR_ERR(phy_dev);
|
||||
+ if (bgmac->mii_bus && bgmac->phyaddr != BGMAC_PHY_NOREGS) {
|
||||
+ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id,
|
||||
+ bgmac->phyaddr);
|
||||
+ phy_dev = phy_connect(bgmac->net_dev, bus_id, bgmac_adjust_link,
|
||||
+ PHY_INTERFACE_MODE_MII);
|
||||
+ if (IS_ERR(phy_dev)) {
|
||||
+ dev_err(bgmac->dev, "PHY connection failed\n");
|
||||
+ return PTR_ERR(phy_dev);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ /* Assume a fixed link to the switch port */
|
||||
+ return bgmac_phy_connect_direct(bgmac);
|
||||
}
|
||||
|
||||
static const struct bcma_device_id bgmac_bcma_tbl[] = {
|
||||
@@ -297,10 +309,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
bgmac->cco_ctl_maskset = bcma_bgmac_cco_ctl_maskset;
|
||||
bgmac->get_bus_clock = bcma_bgmac_get_bus_clock;
|
||||
bgmac->cmn_maskset32 = bcma_bgmac_cmn_maskset32;
|
||||
- if (bgmac->mii_bus)
|
||||
- bgmac->phy_connect = bcma_phy_connect;
|
||||
- else
|
||||
- bgmac->phy_connect = bgmac_phy_connect_direct;
|
||||
+ bgmac->phy_connect = bcma_phy_connect;
|
||||
|
||||
err = bgmac_enet_probe(bgmac);
|
||||
if (err)
|
||||
@ -0,0 +1,54 @@
|
||||
From 45c9d966688e7fad7f24bfc450547d91e4304d0b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Sat, 2 Oct 2021 19:58:12 +0200
|
||||
Subject: [PATCH] net: bgmac: support MDIO described in DT
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Check ethernet controller DT node for "mdio" subnode and use it with
|
||||
of_mdiobus_register() when present. That allows specifying MDIO and its
|
||||
PHY devices in a standard DT based way.
|
||||
|
||||
This is required for BCM53573 SoC support. That family is sometimes
|
||||
called Northstar (by marketing?) but is quite different from it. It uses
|
||||
different CPU(s) and many different hw blocks.
|
||||
|
||||
One of shared blocks in BCM53573 is Ethernet controller. Switch however
|
||||
is not SRAB accessible (as it Northstar) but is MDIO attached.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/brcmphy.h>
|
||||
+#include <linux/of_mdio.h>
|
||||
#include "bgmac.h"
|
||||
|
||||
static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask,
|
||||
@@ -211,6 +212,7 @@ struct mii_bus *bcma_mdio_mii_register(s
|
||||
{
|
||||
struct bcma_device *core = bgmac->bcma.core;
|
||||
struct mii_bus *mii_bus;
|
||||
+ struct device_node *np;
|
||||
int err;
|
||||
|
||||
mii_bus = mdiobus_alloc();
|
||||
@@ -229,7 +231,9 @@ struct mii_bus *bcma_mdio_mii_register(s
|
||||
mii_bus->parent = &core->dev;
|
||||
mii_bus->phy_mask = ~(1 << bgmac->phyaddr);
|
||||
|
||||
- err = mdiobus_register(mii_bus);
|
||||
+ np = of_get_child_by_name(core->dev.of_node, "mdio");
|
||||
+
|
||||
+ err = of_mdiobus_register(mii_bus, np);
|
||||
if (err) {
|
||||
dev_err(&core->dev, "Registration of mii bus failed\n");
|
||||
goto err_free_bus;
|
||||
@ -0,0 +1,48 @@
|
||||
From 0ccf8511182436183c031e8a2f740ae91a02c625 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Tue, 14 Sep 2021 14:33:45 +0200
|
||||
Subject: net: phy: at803x: add support for qca 8327 internal phy
|
||||
|
||||
Add support for qca8327 internal phy needed for correct init of the
|
||||
switch port. It does use the same qca8337 function and reg just with a
|
||||
different id.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Tested-by: Rosen Penev <rosenp@gmail.com>
|
||||
Tested-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 15 +++++++++++++++
|
||||
1 file changed, 15 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -1420,6 +1420,19 @@ static struct phy_driver at803x_driver[]
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
+}, {
|
||||
+ /* QCA8327 */
|
||||
+ .phy_id = QCA8327_PHY_ID,
|
||||
+ .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
+ .name = "QCA PHY 8327",
|
||||
+ /* PHY_GBIT_FEATURES */
|
||||
+ .probe = at803x_probe,
|
||||
+ .flags = PHY_IS_INTERNAL,
|
||||
+ .config_init = qca83xx_config_init,
|
||||
+ .soft_reset = genphy_soft_reset,
|
||||
+ .get_sset_count = at803x_get_sset_count,
|
||||
+ .get_strings = at803x_get_strings,
|
||||
+ .get_stats = at803x_get_stats,
|
||||
}, };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
@@ -1430,6 +1443,8 @@ static struct mdio_device_id __maybe_unu
|
||||
{ PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
|
||||
{ PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
|
||||
{ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
|
||||
+ { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
|
||||
+ { PHY_ID_MATCH_EXACT(QCA8327_PHY_ID) },
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -0,0 +1,131 @@
|
||||
From 983d96a9116a328668601555d96736261d33170c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 16 Sep 2021 14:03:51 +0200
|
||||
Subject: [PATCH] net: dsa: b53: Include all ports in "enabled_ports"
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Make "enabled_ports" bitfield contain all available switch ports
|
||||
including a CPU port. This way there is no need for fixup during
|
||||
initialization.
|
||||
|
||||
For BCM53010, BCM53018 and BCM53019 include also other available ports.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/b53/b53_common.c | 23 +++++++++++------------
|
||||
1 file changed, 11 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/b53/b53_common.c
|
||||
+++ b/drivers/net/dsa/b53/b53_common.c
|
||||
@@ -2302,7 +2302,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM5325_DEVICE_ID,
|
||||
.dev_name = "BCM5325",
|
||||
.vlans = 16,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x3f,
|
||||
.arl_bins = 2,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 5,
|
||||
@@ -2313,7 +2313,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM5365_DEVICE_ID,
|
||||
.dev_name = "BCM5365",
|
||||
.vlans = 256,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x3f,
|
||||
.arl_bins = 2,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 5,
|
||||
@@ -2324,7 +2324,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM5389_DEVICE_ID,
|
||||
.dev_name = "BCM5389",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x11f,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
@@ -2338,7 +2338,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM5395_DEVICE_ID,
|
||||
.dev_name = "BCM5395",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x11f,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
@@ -2352,7 +2352,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM5397_DEVICE_ID,
|
||||
.dev_name = "BCM5397",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x11f,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
@@ -2366,7 +2366,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM5398_DEVICE_ID,
|
||||
.dev_name = "BCM5398",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0x7f,
|
||||
+ .enabled_ports = 0x17f,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
@@ -2380,7 +2380,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM53115_DEVICE_ID,
|
||||
.dev_name = "BCM53115",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x11f,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
@@ -2394,7 +2394,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM53125_DEVICE_ID,
|
||||
.dev_name = "BCM53125",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0xff,
|
||||
+ .enabled_ports = 0x1ff,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
@@ -2436,7 +2436,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM53010_DEVICE_ID,
|
||||
.dev_name = "BCM53010",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x1bf,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
@@ -2478,7 +2478,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM53018_DEVICE_ID,
|
||||
.dev_name = "BCM53018",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x1bf,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
@@ -2492,7 +2492,7 @@ static const struct b53_chip_data b53_sw
|
||||
.chip_id = BCM53019_DEVICE_ID,
|
||||
.dev_name = "BCM53019",
|
||||
.vlans = 4096,
|
||||
- .enabled_ports = 0x1f,
|
||||
+ .enabled_ports = 0x1bf,
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
@@ -2634,7 +2634,6 @@ static int b53_switch_init(struct b53_de
|
||||
dev->cpu_port = 5;
|
||||
}
|
||||
|
||||
- dev->enabled_ports |= BIT(dev->cpu_port);
|
||||
dev->num_ports = fls(dev->enabled_ports);
|
||||
|
||||
dev->ds->num_ports = min_t(unsigned int, dev->num_ports, DSA_MAX_PORTS);
|
||||
@ -0,0 +1,42 @@
|
||||
From b290c6384afabbca5ae6e2af72fb1b2bc37922be Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 16 Sep 2021 14:03:52 +0200
|
||||
Subject: [PATCH] net: dsa: b53: Drop BCM5301x workaround for a wrong CPU/IMP
|
||||
port
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
On BCM5301x port 8 requires a fixed link when used.
|
||||
|
||||
Years ago when b53 was an OpenWrt downstream driver (with configuration
|
||||
based on sometimes bugged NVRAM) there was a need for a fixup. In case
|
||||
of forcing fixed link for (incorrectly specified) port 5 the code had to
|
||||
actually setup port 8 link.
|
||||
|
||||
For upstream b53 driver with setup based on DT there is no need for that
|
||||
workaround. In DT we have and require correct ports setup.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/b53/b53_common.c | 6 ------
|
||||
1 file changed, 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/b53/b53_common.c
|
||||
+++ b/drivers/net/dsa/b53/b53_common.c
|
||||
@@ -1291,12 +1291,6 @@ static void b53_adjust_link(struct dsa_s
|
||||
return;
|
||||
}
|
||||
}
|
||||
- } else if (is5301x(dev)) {
|
||||
- if (port != dev->cpu_port) {
|
||||
- b53_force_port_config(dev, dev->cpu_port, 2000,
|
||||
- DUPLEX_FULL, true, true);
|
||||
- b53_force_link(dev, dev->cpu_port, 1);
|
||||
- }
|
||||
}
|
||||
|
||||
/* Re-negotiate EEE if it was enabled already */
|
||||
@ -0,0 +1,32 @@
|
||||
From 3ff26b29230c54fea2353b63124c589b61953e14 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 16 Sep 2021 14:03:53 +0200
|
||||
Subject: [PATCH] net: dsa: b53: Improve flow control setup on BCM5301x
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
According to the Broadcom's reference driver flow control needs to be
|
||||
enabled for any CPU switch port (5, 7 or 8 - depending on which one is
|
||||
used). Current code makes it work only for the port 5. Use
|
||||
dsa_is_cpu_port() which solved that problem.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/b53/b53_common.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/b53/b53_common.c
|
||||
+++ b/drivers/net/dsa/b53/b53_common.c
|
||||
@@ -1222,7 +1222,7 @@ static void b53_adjust_link(struct dsa_s
|
||||
return;
|
||||
|
||||
/* Enable flow control on BCM5301x's CPU port */
|
||||
- if (is5301x(dev) && port == dev->cpu_port)
|
||||
+ if (is5301x(dev) && dsa_is_cpu_port(ds, port))
|
||||
tx_pause = rx_pause = true;
|
||||
|
||||
if (phydev->pause) {
|
||||
@ -0,0 +1,205 @@
|
||||
From 7d5af56418d7d01e43247a33b6fe6492ea871923 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 16 Sep 2021 14:03:54 +0200
|
||||
Subject: [PATCH] net: dsa: b53: Drop unused "cpu_port" field
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It's set but never used anymore.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/b53/b53_common.c | 28 ----------------------------
|
||||
drivers/net/dsa/b53/b53_priv.h | 1 -
|
||||
2 files changed, 29 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/b53/b53_common.c
|
||||
+++ b/drivers/net/dsa/b53/b53_common.c
|
||||
@@ -2300,7 +2300,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 2,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 5,
|
||||
- .cpu_port = B53_CPU_PORT_25,
|
||||
.duplex_reg = B53_DUPLEX_STAT_FE,
|
||||
},
|
||||
{
|
||||
@@ -2311,7 +2310,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 2,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 5,
|
||||
- .cpu_port = B53_CPU_PORT_25,
|
||||
.duplex_reg = B53_DUPLEX_STAT_FE,
|
||||
},
|
||||
{
|
||||
@@ -2322,7 +2320,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2336,7 +2333,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2350,7 +2346,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS_9798,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2364,7 +2359,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS_9798,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2379,7 +2373,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_buckets = 1024,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
|
||||
@@ -2392,7 +2385,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2406,7 +2398,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2420,7 +2411,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS_63XX,
|
||||
.duplex_reg = B53_DUPLEX_STAT_63XX,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX,
|
||||
@@ -2434,7 +2424,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2448,7 +2437,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2462,7 +2450,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2476,7 +2463,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2490,7 +2476,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2504,7 +2489,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2518,7 +2502,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2547,7 +2530,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 1024,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2561,7 +2543,6 @@ static const struct b53_chip_data b53_sw
|
||||
.arl_bins = 4,
|
||||
.arl_buckets = 256,
|
||||
.imp_port = 8,
|
||||
- .cpu_port = B53_CPU_PORT,
|
||||
.vta_regs = B53_VTA_REGS,
|
||||
.duplex_reg = B53_DUPLEX_STAT_GE,
|
||||
.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
|
||||
@@ -2587,7 +2568,6 @@ static int b53_switch_init(struct b53_de
|
||||
dev->vta_regs[2] = chip->vta_regs[2];
|
||||
dev->jumbo_pm_reg = chip->jumbo_pm_reg;
|
||||
dev->imp_port = chip->imp_port;
|
||||
- dev->cpu_port = chip->cpu_port;
|
||||
dev->num_vlans = chip->vlans;
|
||||
dev->num_arl_bins = chip->arl_bins;
|
||||
dev->num_arl_buckets = chip->arl_buckets;
|
||||
@@ -2619,13 +2599,6 @@ static int b53_switch_init(struct b53_de
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
- } else if (dev->chip_id == BCM53115_DEVICE_ID) {
|
||||
- u64 strap_value;
|
||||
-
|
||||
- b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value);
|
||||
- /* use second IMP port if GMII is enabled */
|
||||
- if (strap_value & SV_GMII_CTRL_115)
|
||||
- dev->cpu_port = 5;
|
||||
}
|
||||
|
||||
dev->num_ports = fls(dev->enabled_ports);
|
||||
--- a/drivers/net/dsa/b53/b53_priv.h
|
||||
+++ b/drivers/net/dsa/b53/b53_priv.h
|
||||
@@ -124,7 +124,6 @@ struct b53_device {
|
||||
/* used ports mask */
|
||||
u16 enabled_ports;
|
||||
unsigned int imp_port;
|
||||
- unsigned int cpu_port;
|
||||
|
||||
/* connect specific data */
|
||||
u8 current_page;
|
||||
@ -0,0 +1,65 @@
|
||||
From b4df02b562f4aa14ff6811f30e1b4d2159585c59 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sun, 19 Sep 2021 18:28:15 +0200
|
||||
Subject: net: phy: at803x: add support for qca 8327 A variant internal phy
|
||||
|
||||
For qca8327 internal phy there are 2 different switch variant with 2
|
||||
different phy id. Add this missing variant so the internal phy can be
|
||||
correctly identified and fixed.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 25 ++++++++++++++++++++-----
|
||||
1 file changed, 20 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -150,7 +150,8 @@
|
||||
#define ATH8035_PHY_ID 0x004dd072
|
||||
#define AT8030_PHY_ID_MASK 0xffffffef
|
||||
|
||||
-#define QCA8327_PHY_ID 0x004dd034
|
||||
+#define QCA8327_A_PHY_ID 0x004dd033
|
||||
+#define QCA8327_B_PHY_ID 0x004dd034
|
||||
#define QCA8337_PHY_ID 0x004dd036
|
||||
#define QCA8K_PHY_ID_MASK 0xffffffff
|
||||
|
||||
@@ -1421,10 +1422,23 @@ static struct phy_driver at803x_driver[]
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
}, {
|
||||
- /* QCA8327 */
|
||||
- .phy_id = QCA8327_PHY_ID,
|
||||
+ /* QCA8327-A from switch QCA8327-AL1A */
|
||||
+ .phy_id = QCA8327_A_PHY_ID,
|
||||
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
- .name = "QCA PHY 8327",
|
||||
+ .name = "QCA PHY 8327-A",
|
||||
+ /* PHY_GBIT_FEATURES */
|
||||
+ .probe = at803x_probe,
|
||||
+ .flags = PHY_IS_INTERNAL,
|
||||
+ .config_init = qca83xx_config_init,
|
||||
+ .soft_reset = genphy_soft_reset,
|
||||
+ .get_sset_count = at803x_get_sset_count,
|
||||
+ .get_strings = at803x_get_strings,
|
||||
+ .get_stats = at803x_get_stats,
|
||||
+}, {
|
||||
+ /* QCA8327-B from switch QCA8327-BL1A */
|
||||
+ .phy_id = QCA8327_B_PHY_ID,
|
||||
+ .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
+ .name = "QCA PHY 8327-B",
|
||||
/* PHY_GBIT_FEATURES */
|
||||
.probe = at803x_probe,
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
@@ -1444,7 +1458,8 @@ static struct mdio_device_id __maybe_unu
|
||||
{ PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
|
||||
{ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
|
||||
{ PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
|
||||
- { PHY_ID_MATCH_EXACT(QCA8327_PHY_ID) },
|
||||
+ { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
|
||||
+ { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
From 15b9df4ece17d084f14eb0ca1cf05f2ad497e425 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sun, 19 Sep 2021 18:28:16 +0200
|
||||
Subject: net: phy: at803x: add resume/suspend function to qca83xx phy
|
||||
|
||||
Add resume/suspend function to qca83xx internal phy.
|
||||
We can't use the at803x generic function as the documentation lacks of
|
||||
any support for WoL regs.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -1421,6 +1421,8 @@ static struct phy_driver at803x_driver[]
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
+ .suspend = genphy_suspend,
|
||||
+ .resume = genphy_resume,
|
||||
}, {
|
||||
/* QCA8327-A from switch QCA8327-AL1A */
|
||||
.phy_id = QCA8327_A_PHY_ID,
|
||||
@@ -1434,6 +1436,8 @@ static struct phy_driver at803x_driver[]
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
+ .suspend = genphy_suspend,
|
||||
+ .resume = genphy_resume,
|
||||
}, {
|
||||
/* QCA8327-B from switch QCA8327-BL1A */
|
||||
.phy_id = QCA8327_B_PHY_ID,
|
||||
@@ -1447,6 +1451,8 @@ static struct phy_driver at803x_driver[]
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
+ .suspend = genphy_suspend,
|
||||
+ .resume = genphy_resume,
|
||||
}, };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
@ -0,0 +1,95 @@
|
||||
From d44fd8604a4ab92119adb35f05fd87612af722b5 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sun, 19 Sep 2021 18:28:17 +0200
|
||||
Subject: net: phy: at803x: fix spacing and improve name for 83xx phy
|
||||
|
||||
Fix spacing and improve name for 83xx phy following other phy in the
|
||||
same driver.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 60 ++++++++++++++++++++++++------------------------
|
||||
1 file changed, 30 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -1410,47 +1410,47 @@ static struct phy_driver at803x_driver[]
|
||||
.config_aneg = at803x_config_aneg,
|
||||
}, {
|
||||
/* QCA8337 */
|
||||
- .phy_id = QCA8337_PHY_ID,
|
||||
- .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
- .name = "QCA PHY 8337",
|
||||
+ .phy_id = QCA8337_PHY_ID,
|
||||
+ .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
+ .name = "Qualcomm Atheros 8337 internal PHY",
|
||||
/* PHY_GBIT_FEATURES */
|
||||
- .probe = at803x_probe,
|
||||
- .flags = PHY_IS_INTERNAL,
|
||||
- .config_init = qca83xx_config_init,
|
||||
- .soft_reset = genphy_soft_reset,
|
||||
- .get_sset_count = at803x_get_sset_count,
|
||||
- .get_strings = at803x_get_strings,
|
||||
- .get_stats = at803x_get_stats,
|
||||
+ .probe = at803x_probe,
|
||||
+ .flags = PHY_IS_INTERNAL,
|
||||
+ .config_init = qca83xx_config_init,
|
||||
+ .soft_reset = genphy_soft_reset,
|
||||
+ .get_sset_count = at803x_get_sset_count,
|
||||
+ .get_strings = at803x_get_strings,
|
||||
+ .get_stats = at803x_get_stats,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
}, {
|
||||
/* QCA8327-A from switch QCA8327-AL1A */
|
||||
- .phy_id = QCA8327_A_PHY_ID,
|
||||
- .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
- .name = "QCA PHY 8327-A",
|
||||
+ .phy_id = QCA8327_A_PHY_ID,
|
||||
+ .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
+ .name = "Qualcomm Atheros 8327-A internal PHY",
|
||||
/* PHY_GBIT_FEATURES */
|
||||
- .probe = at803x_probe,
|
||||
- .flags = PHY_IS_INTERNAL,
|
||||
- .config_init = qca83xx_config_init,
|
||||
- .soft_reset = genphy_soft_reset,
|
||||
- .get_sset_count = at803x_get_sset_count,
|
||||
- .get_strings = at803x_get_strings,
|
||||
- .get_stats = at803x_get_stats,
|
||||
+ .probe = at803x_probe,
|
||||
+ .flags = PHY_IS_INTERNAL,
|
||||
+ .config_init = qca83xx_config_init,
|
||||
+ .soft_reset = genphy_soft_reset,
|
||||
+ .get_sset_count = at803x_get_sset_count,
|
||||
+ .get_strings = at803x_get_strings,
|
||||
+ .get_stats = at803x_get_stats,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
}, {
|
||||
/* QCA8327-B from switch QCA8327-BL1A */
|
||||
- .phy_id = QCA8327_B_PHY_ID,
|
||||
- .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
- .name = "QCA PHY 8327-B",
|
||||
+ .phy_id = QCA8327_B_PHY_ID,
|
||||
+ .phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
+ .name = "Qualcomm Atheros 8327-B internal PHY",
|
||||
/* PHY_GBIT_FEATURES */
|
||||
- .probe = at803x_probe,
|
||||
- .flags = PHY_IS_INTERNAL,
|
||||
- .config_init = qca83xx_config_init,
|
||||
- .soft_reset = genphy_soft_reset,
|
||||
- .get_sset_count = at803x_get_sset_count,
|
||||
- .get_strings = at803x_get_strings,
|
||||
- .get_stats = at803x_get_stats,
|
||||
+ .probe = at803x_probe,
|
||||
+ .flags = PHY_IS_INTERNAL,
|
||||
+ .config_init = qca83xx_config_init,
|
||||
+ .soft_reset = genphy_soft_reset,
|
||||
+ .get_sset_count = at803x_get_sset_count,
|
||||
+ .get_strings = at803x_get_strings,
|
||||
+ .get_stats = at803x_get_stats,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
}, };
|
||||
@ -0,0 +1,131 @@
|
||||
From ba3c01ee02ed0d821c9f241f179bbc9457542b8f Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sun, 10 Oct 2021 00:46:15 +0200
|
||||
Subject: net: phy: at803x: fix resume for QCA8327 phy
|
||||
|
||||
From Documentation phy resume triggers phy reset and restart
|
||||
auto-negotiation. Add a dedicated function to wait reset to finish as
|
||||
it was notice a regression where port sometime are not reliable after a
|
||||
suspend/resume session. The reset wait logic is copied from phy_poll_reset.
|
||||
Add dedicated suspend function to use genphy_suspend only with QCA8337
|
||||
phy and set only additional debug settings for QCA8327. With more test
|
||||
it was reported that QCA8327 doesn't proprely support this mode and
|
||||
using this cause the unreliability of the switch ports, especially the
|
||||
malfunction of the port0.
|
||||
|
||||
Fixes: 15b9df4ece17 ("net: phy: at803x: add resume/suspend function to qca83xx phy")
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 69 +++++++++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 63 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -92,9 +92,14 @@
|
||||
#define AT803X_DEBUG_REG_5 0x05
|
||||
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
|
||||
|
||||
+#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
|
||||
+#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10)
|
||||
+#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
|
||||
+
|
||||
#define AT803X_DEBUG_REG_3C 0x3C
|
||||
|
||||
#define AT803X_DEBUG_REG_3D 0x3D
|
||||
+#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
|
||||
|
||||
#define AT803X_DEBUG_REG_1F 0x1F
|
||||
#define AT803X_DEBUG_PLL_ON BIT(2)
|
||||
@@ -1312,6 +1317,58 @@ static int qca83xx_config_init(struct ph
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int qca83xx_resume(struct phy_device *phydev)
|
||||
+{
|
||||
+ int ret, val;
|
||||
+
|
||||
+ /* Skip reset if not suspended */
|
||||
+ if (!phydev->suspended)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Reinit the port, reset values set by suspend */
|
||||
+ qca83xx_config_init(phydev);
|
||||
+
|
||||
+ /* Reset the port on port resume */
|
||||
+ phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
|
||||
+
|
||||
+ /* On resume from suspend the switch execute a reset and
|
||||
+ * restart auto-negotiation. Wait for reset to complete.
|
||||
+ */
|
||||
+ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
|
||||
+ 50000, 600000, true);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ msleep(1);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int qca83xx_suspend(struct phy_device *phydev)
|
||||
+{
|
||||
+ u16 mask = 0;
|
||||
+
|
||||
+ /* Only QCA8337 support actual suspend.
|
||||
+ * QCA8327 cause port unreliability when phy suspend
|
||||
+ * is set.
|
||||
+ */
|
||||
+ if (phydev->drv->phy_id == QCA8337_PHY_ID) {
|
||||
+ genphy_suspend(phydev);
|
||||
+ } else {
|
||||
+ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
|
||||
+ phy_modify(phydev, MII_BMCR, mask, 0);
|
||||
+ }
|
||||
+
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D,
|
||||
+ AT803X_DEBUG_GATE_CLK_IN1000, 0);
|
||||
+
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
|
||||
+ AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
|
||||
+ AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static struct phy_driver at803x_driver[] = {
|
||||
{
|
||||
/* Qualcomm Atheros AR8035 */
|
||||
@@ -1421,8 +1478,8 @@ static struct phy_driver at803x_driver[]
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
- .suspend = genphy_suspend,
|
||||
- .resume = genphy_resume,
|
||||
+ .suspend = qca83xx_suspend,
|
||||
+ .resume = qca83xx_resume,
|
||||
}, {
|
||||
/* QCA8327-A from switch QCA8327-AL1A */
|
||||
.phy_id = QCA8327_A_PHY_ID,
|
||||
@@ -1436,8 +1493,8 @@ static struct phy_driver at803x_driver[]
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
- .suspend = genphy_suspend,
|
||||
- .resume = genphy_resume,
|
||||
+ .suspend = qca83xx_suspend,
|
||||
+ .resume = qca83xx_resume,
|
||||
}, {
|
||||
/* QCA8327-B from switch QCA8327-BL1A */
|
||||
.phy_id = QCA8327_B_PHY_ID,
|
||||
@@ -1451,8 +1508,8 @@ static struct phy_driver at803x_driver[]
|
||||
.get_sset_count = at803x_get_sset_count,
|
||||
.get_strings = at803x_get_strings,
|
||||
.get_stats = at803x_get_stats,
|
||||
- .suspend = genphy_suspend,
|
||||
- .resume = genphy_resume,
|
||||
+ .suspend = qca83xx_suspend,
|
||||
+ .resume = qca83xx_resume,
|
||||
}, };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
@ -0,0 +1,91 @@
|
||||
From 1ca8311949aec5c9447645731ef1c6bc5bd71350 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sun, 10 Oct 2021 00:46:16 +0200
|
||||
Subject: net: phy: at803x: add DAC amplitude fix for 8327 phy
|
||||
|
||||
QCA8327 internal phy require DAC amplitude adjustement set to +6% with
|
||||
100m speed. Also add additional define to report a change of the same
|
||||
reg in QCA8337. (different scope it does set 1000m voltage)
|
||||
Add link_change_notify function to set the proper amplitude adjustement
|
||||
on PHY_RUNNING state and disable on any other state.
|
||||
|
||||
Fixes: b4df02b562f4 ("net: phy: at803x: add support for qca 8327 A variant internal phy")
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 33 +++++++++++++++++++++++++++++++++
|
||||
1 file changed, 33 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -87,6 +87,8 @@
|
||||
#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
|
||||
|
||||
#define AT803X_DEBUG_REG_0 0x00
|
||||
+#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
|
||||
+#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
|
||||
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
|
||||
|
||||
#define AT803X_DEBUG_REG_5 0x05
|
||||
@@ -1314,9 +1316,37 @@ static int qca83xx_config_init(struct ph
|
||||
break;
|
||||
}
|
||||
|
||||
+ /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
|
||||
+ * Disable on init and enable only with 100m speed following
|
||||
+ * qca original source code.
|
||||
+ */
|
||||
+ if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
|
||||
+ phydev->drv->phy_id == QCA8327_B_PHY_ID)
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void qca83xx_link_change_notify(struct phy_device *phydev)
|
||||
+{
|
||||
+ /* QCA8337 doesn't require DAC Amplitude adjustement */
|
||||
+ if (phydev->drv->phy_id == QCA8337_PHY_ID)
|
||||
+ return;
|
||||
+
|
||||
+ /* Set DAC Amplitude adjustment to +6% for 100m on link running */
|
||||
+ if (phydev->state == PHY_RUNNING) {
|
||||
+ if (phydev->speed == SPEED_100)
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
+ QCA8327_DEBUG_MANU_CTRL_EN,
|
||||
+ QCA8327_DEBUG_MANU_CTRL_EN);
|
||||
+ } else {
|
||||
+ /* Reset DAC Amplitude adjustment */
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int qca83xx_resume(struct phy_device *phydev)
|
||||
{
|
||||
int ret, val;
|
||||
@@ -1471,6 +1501,7 @@ static struct phy_driver at803x_driver[]
|
||||
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
.name = "Qualcomm Atheros 8337 internal PHY",
|
||||
/* PHY_GBIT_FEATURES */
|
||||
+ .link_change_notify = qca83xx_link_change_notify,
|
||||
.probe = at803x_probe,
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
.config_init = qca83xx_config_init,
|
||||
@@ -1486,6 +1517,7 @@ static struct phy_driver at803x_driver[]
|
||||
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
.name = "Qualcomm Atheros 8327-A internal PHY",
|
||||
/* PHY_GBIT_FEATURES */
|
||||
+ .link_change_notify = qca83xx_link_change_notify,
|
||||
.probe = at803x_probe,
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
.config_init = qca83xx_config_init,
|
||||
@@ -1501,6 +1533,7 @@ static struct phy_driver at803x_driver[]
|
||||
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||
.name = "Qualcomm Atheros 8327-B internal PHY",
|
||||
/* PHY_GBIT_FEATURES */
|
||||
+ .link_change_notify = qca83xx_link_change_notify,
|
||||
.probe = at803x_probe,
|
||||
.flags = PHY_IS_INTERNAL,
|
||||
.config_init = qca83xx_config_init,
|
||||
@ -0,0 +1,27 @@
|
||||
From 9d1c29b4028557a496be9c5eb2b4b86063700636 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sun, 10 Oct 2021 00:46:17 +0200
|
||||
Subject: net: phy: at803x: enable prefer master for 83xx internal phy
|
||||
|
||||
From original QCA source code the port was set to prefer master as port
|
||||
type in 1000BASE-T mode. Apply the same settings also here.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -1325,6 +1325,9 @@ static int qca83xx_config_init(struct ph
|
||||
at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
||||
|
||||
+ /* Following original QCA sourcecode set port to prefer master */
|
||||
+ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -0,0 +1,127 @@
|
||||
From 67999555ff42e91de7654488d9a7735bd9e84555 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sun, 10 Oct 2021 00:46:18 +0200
|
||||
Subject: net: phy: at803x: better describe debug regs
|
||||
|
||||
Give a name to known debug regs from Documentation instead of using
|
||||
unknown hex values.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 30 +++++++++++++++---------------
|
||||
1 file changed, 15 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -86,12 +86,12 @@
|
||||
#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
|
||||
#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
|
||||
|
||||
-#define AT803X_DEBUG_REG_0 0x00
|
||||
+#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00
|
||||
#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
|
||||
#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
|
||||
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
|
||||
|
||||
-#define AT803X_DEBUG_REG_5 0x05
|
||||
+#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05
|
||||
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
|
||||
|
||||
#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
#define AT803X_DEBUG_REG_3C 0x3C
|
||||
|
||||
-#define AT803X_DEBUG_REG_3D 0x3D
|
||||
+#define AT803X_DEBUG_REG_GREEN 0x3D
|
||||
#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
|
||||
|
||||
#define AT803X_DEBUG_REG_1F 0x1F
|
||||
@@ -284,25 +284,25 @@ static int at803x_read_page(struct phy_d
|
||||
|
||||
static int at803x_enable_rx_delay(struct phy_device *phydev)
|
||||
{
|
||||
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
|
||||
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0,
|
||||
AT803X_DEBUG_RX_CLK_DLY_EN);
|
||||
}
|
||||
|
||||
static int at803x_enable_tx_delay(struct phy_device *phydev)
|
||||
{
|
||||
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
|
||||
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0,
|
||||
AT803X_DEBUG_TX_CLK_DLY_EN);
|
||||
}
|
||||
|
||||
static int at803x_disable_rx_delay(struct phy_device *phydev)
|
||||
{
|
||||
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
|
||||
AT803X_DEBUG_RX_CLK_DLY_EN, 0);
|
||||
}
|
||||
|
||||
static int at803x_disable_tx_delay(struct phy_device *phydev)
|
||||
{
|
||||
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
|
||||
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE,
|
||||
AT803X_DEBUG_TX_CLK_DLY_EN, 0);
|
||||
}
|
||||
|
||||
@@ -1300,9 +1300,9 @@ static int qca83xx_config_init(struct ph
|
||||
switch (switch_revision) {
|
||||
case 1:
|
||||
/* For 100M waveform */
|
||||
- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea);
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
|
||||
/* Turn on Gigabit clock */
|
||||
- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0);
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -1310,8 +1310,8 @@ static int qca83xx_config_init(struct ph
|
||||
fallthrough;
|
||||
case 4:
|
||||
phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
|
||||
- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860);
|
||||
- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46);
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
|
||||
+ at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
|
||||
at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
|
||||
break;
|
||||
}
|
||||
@@ -1322,7 +1322,7 @@ static int qca83xx_config_init(struct ph
|
||||
*/
|
||||
if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
|
||||
phydev->drv->phy_id == QCA8327_B_PHY_ID)
|
||||
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
|
||||
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
||||
|
||||
/* Following original QCA sourcecode set port to prefer master */
|
||||
@@ -1340,12 +1340,12 @@ static void qca83xx_link_change_notify(s
|
||||
/* Set DAC Amplitude adjustment to +6% for 100m on link running */
|
||||
if (phydev->state == PHY_RUNNING) {
|
||||
if (phydev->speed == SPEED_100)
|
||||
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
|
||||
QCA8327_DEBUG_MANU_CTRL_EN,
|
||||
QCA8327_DEBUG_MANU_CTRL_EN);
|
||||
} else {
|
||||
/* Reset DAC Amplitude adjustment */
|
||||
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
|
||||
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
||||
}
|
||||
}
|
||||
@@ -1392,7 +1392,7 @@ static int qca83xx_suspend(struct phy_de
|
||||
phy_modify(phydev, MII_BMCR, mask, 0);
|
||||
}
|
||||
|
||||
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D,
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
|
||||
AT803X_DEBUG_GATE_CLK_IN1000, 0);
|
||||
|
||||
at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
|
||||
@ -0,0 +1,80 @@
|
||||
From d8b6f5bae6d3b648a67b6958cb98e4e97256d652 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:06 +0200
|
||||
Subject: dsa: qca8k: add mac_power_sel support
|
||||
|
||||
Add missing mac power sel support needed for ipq8064/5 SoC that require
|
||||
1.8v for the internal regulator port instead of the default 1.5v.
|
||||
If other device needs this, consider adding a dedicated binding to
|
||||
support this.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 31 +++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 5 +++++
|
||||
2 files changed, 36 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -951,6 +951,33 @@ qca8k_setup_of_rgmii_delay(struct qca8k_
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ u32 mask = 0;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ /* SoC specific settings for ipq8064.
|
||||
+ * If more device require this consider adding
|
||||
+ * a dedicated binding.
|
||||
+ */
|
||||
+ if (of_machine_is_compatible("qcom,ipq8064"))
|
||||
+ mask |= QCA8K_MAC_PWR_RGMII0_1_8V;
|
||||
+
|
||||
+ /* SoC specific settings for ipq8065 */
|
||||
+ if (of_machine_is_compatible("qcom,ipq8065"))
|
||||
+ mask |= QCA8K_MAC_PWR_RGMII1_1_8V;
|
||||
+
|
||||
+ if (mask) {
|
||||
+ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL,
|
||||
+ QCA8K_MAC_PWR_RGMII0_1_8V |
|
||||
+ QCA8K_MAC_PWR_RGMII1_1_8V,
|
||||
+ mask);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
@@ -979,6 +1006,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = qca8k_setup_mac_pwr_sel(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
/* Enable CPU Port */
|
||||
ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -100,6 +100,11 @@
|
||||
#define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22)
|
||||
#define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22)
|
||||
|
||||
+/* MAC_PWR_SEL registers */
|
||||
+#define QCA8K_REG_MAC_PWR_SEL 0x0e4
|
||||
+#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18)
|
||||
+#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19)
|
||||
+
|
||||
/* EEE control registers */
|
||||
#define QCA8K_REG_EEE_CTRL 0x100
|
||||
#define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2)
|
||||
@ -0,0 +1,30 @@
|
||||
From fdbf35df9c091db9c46e57e9938e3f7a4f603a7c Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:07 +0200
|
||||
Subject: dt-bindings: net: dsa: qca8k: Add SGMII clock phase properties
|
||||
|
||||
Add names and descriptions of additional PORT0_PAD_CTRL properties.
|
||||
qca,sgmii-(rx|tx)clk-falling-edge are for setting the respective clock
|
||||
phase to failling edge.
|
||||
|
||||
Co-developed-by: Matthew Hagan <mnhagan88@gmail.com>
|
||||
Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
Documentation/devicetree/bindings/net/dsa/qca8k.txt | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
@@ -37,6 +37,10 @@ A CPU port node has the following option
|
||||
managed entity. See
|
||||
Documentation/devicetree/bindings/net/fixed-link.txt
|
||||
for details.
|
||||
+- qca,sgmii-rxclk-falling-edge: Set the receive clock phase to falling edge.
|
||||
+ Mostly used in qca8327 with CPU port 0 set to
|
||||
+ sgmii.
|
||||
+- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge.
|
||||
|
||||
For QCA8K the 'fixed-link' sub-node supports only the following properties:
|
||||
|
||||
@ -0,0 +1,127 @@
|
||||
From 6c43809bf1bee76c434e365a26546a92a5fbec14 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:08 +0200
|
||||
Subject: net: dsa: qca8k: add support for sgmii falling edge
|
||||
|
||||
Add support for this in the qca8k driver. Also add support for SGMII
|
||||
rx/tx clock falling edge. This is only present for pad0, pad5 and
|
||||
pad6 have these bit reserved from Documentation. Add a comment that this
|
||||
is hardcoded to PAD0 as qca8327/28/34/37 have an unique sgmii line and
|
||||
setting falling in port0 applies to both configuration with sgmii used
|
||||
for port0 or port6.
|
||||
|
||||
Co-developed-by: Matthew Hagan <mnhagan88@gmail.com>
|
||||
Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 4 ++++
|
||||
2 files changed, 67 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -978,6 +978,42 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_parse_port_config(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ struct device_node *port_dn;
|
||||
+ phy_interface_t mode;
|
||||
+ struct dsa_port *dp;
|
||||
+ int port, ret;
|
||||
+
|
||||
+ /* We have 2 CPU port. Check them */
|
||||
+ for (port = 0; port < QCA8K_NUM_PORTS; port++) {
|
||||
+ /* Skip every other port */
|
||||
+ if (port != 0 && port != 6)
|
||||
+ continue;
|
||||
+
|
||||
+ dp = dsa_to_port(priv->ds, port);
|
||||
+ port_dn = dp->dn;
|
||||
+
|
||||
+ if (!of_device_is_available(port_dn))
|
||||
+ continue;
|
||||
+
|
||||
+ ret = of_get_phy_mode(port_dn, &mode);
|
||||
+ if (ret)
|
||||
+ continue;
|
||||
+
|
||||
+ if (mode == PHY_INTERFACE_MODE_SGMII) {
|
||||
+ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
|
||||
+ priv->sgmii_tx_clk_falling_edge = true;
|
||||
+
|
||||
+ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge"))
|
||||
+ priv->sgmii_rx_clk_falling_edge = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
@@ -990,6 +1026,11 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ /* Parse CPU port config to be later used in phy_link mac_config */
|
||||
+ ret = qca8k_parse_port_config(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
mutex_init(&priv->reg_mutex);
|
||||
|
||||
/* Start by setting up the register mapping */
|
||||
@@ -1274,6 +1315,28 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
}
|
||||
|
||||
qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val);
|
||||
+
|
||||
+ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and
|
||||
+ * falling edge is set writing in the PORT0 PAD reg
|
||||
+ */
|
||||
+ if (priv->switch_id == QCA8K_ID_QCA8327 ||
|
||||
+ priv->switch_id == QCA8K_ID_QCA8337)
|
||||
+ reg = QCA8K_REG_PORT0_PAD_CTRL;
|
||||
+
|
||||
+ val = 0;
|
||||
+
|
||||
+ /* SGMII Clock phase configuration */
|
||||
+ if (priv->sgmii_rx_clk_falling_edge)
|
||||
+ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE;
|
||||
+
|
||||
+ if (priv->sgmii_tx_clk_falling_edge)
|
||||
+ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE;
|
||||
+
|
||||
+ if (val)
|
||||
+ ret = qca8k_rmw(priv, reg,
|
||||
+ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
|
||||
+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
|
||||
+ val);
|
||||
break;
|
||||
default:
|
||||
dev_err(ds->dev, "xMII mode %s not supported for port %d\n",
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -35,6 +35,8 @@
|
||||
#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8)
|
||||
#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8)
|
||||
#define QCA8K_REG_PORT0_PAD_CTRL 0x004
|
||||
+#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19)
|
||||
+#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18)
|
||||
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
|
||||
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
|
||||
#define QCA8K_PORT_PAD_RGMII_EN BIT(26)
|
||||
@@ -260,6 +262,8 @@ struct qca8k_priv {
|
||||
u8 switch_revision;
|
||||
u8 rgmii_tx_delay;
|
||||
u8 rgmii_rx_delay;
|
||||
+ bool sgmii_rx_clk_falling_edge;
|
||||
+ bool sgmii_tx_clk_falling_edge;
|
||||
bool legacy_phy_port_mapping;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
@ -0,0 +1,29 @@
|
||||
From 731d613338ec6de482053ffa3f71be2325b0f8eb Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:09 +0200
|
||||
Subject: dt-bindings: net: dsa: qca8k: Document support for CPU port 6
|
||||
|
||||
The switch now support CPU port to be set 6 instead of be hardcoded to
|
||||
0. Document support for it and describe logic selection.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
Documentation/devicetree/bindings/net/dsa/qca8k.txt | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
@@ -29,7 +29,11 @@ the mdio MASTER is used as communication
|
||||
Don't use mixed external and internal mdio-bus configurations, as this is
|
||||
not supported by the hardware.
|
||||
|
||||
-The CPU port of this switch is always port 0.
|
||||
+This switch support 2 CPU port. Normally and advised configuration is with
|
||||
+CPU port set to port 0. It is also possible to set the CPU port to port 6
|
||||
+if the device requires it. The driver will configure the switch to the defined
|
||||
+port. With both CPU port declared the first CPU port is selected as primary
|
||||
+and the secondary CPU ignored.
|
||||
|
||||
A CPU port node has the following optional node:
|
||||
|
||||
@ -0,0 +1,153 @@
|
||||
From 3fcf734aa482487df83cf8f18608438fcf59127f Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:10 +0200
|
||||
Subject: net: dsa: qca8k: add support for cpu port 6
|
||||
|
||||
Currently CPU port is always hardcoded to port 0. This switch have 2 CPU
|
||||
ports. The original intention of this driver seems to be use the
|
||||
mac06_exchange bit to swap MAC0 with MAC6 in the strange configuration
|
||||
where device have connected only the CPU port 6. To skip the
|
||||
introduction of a new binding, rework the driver to address the
|
||||
secondary CPU port as primary and drop any reference of hardcoded port.
|
||||
With configuration of mac06 exchange, just skip the definition of port0
|
||||
and define the CPU port as a secondary. The driver will autoconfigure
|
||||
the switch to use that as the primary CPU port.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 51 ++++++++++++++++++++++++++++++++++---------------
|
||||
drivers/net/dsa/qca8k.h | 2 --
|
||||
2 files changed, 36 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -977,6 +977,22 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int qca8k_find_cpu_port(struct dsa_switch *ds)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
+ /* Find the connected cpu port. Valid port are 0 or 6 */
|
||||
+ if (dsa_is_cpu_port(ds, 0))
|
||||
+ return 0;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6");
|
||||
+
|
||||
+ if (dsa_is_cpu_port(ds, 6))
|
||||
+ return 6;
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
qca8k_parse_port_config(struct qca8k_priv *priv)
|
||||
{
|
||||
@@ -1017,13 +1033,13 @@ static int
|
||||
qca8k_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- int ret, i;
|
||||
+ int cpu_port, ret, i;
|
||||
u32 mask;
|
||||
|
||||
- /* Make sure that port 0 is the cpu port */
|
||||
- if (!dsa_is_cpu_port(ds, 0)) {
|
||||
- dev_err(priv->dev, "port 0 is not the CPU port");
|
||||
- return -EINVAL;
|
||||
+ cpu_port = qca8k_find_cpu_port(ds);
|
||||
+ if (cpu_port < 0) {
|
||||
+ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6");
|
||||
+ return cpu_port;
|
||||
}
|
||||
|
||||
/* Parse CPU port config to be later used in phy_link mac_config */
|
||||
@@ -1065,7 +1081,7 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
dev_warn(priv->dev, "mib init failed");
|
||||
|
||||
/* Enable QCA header mode on the cpu port */
|
||||
- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(cpu_port),
|
||||
QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
|
||||
QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
|
||||
if (ret) {
|
||||
@@ -1087,10 +1103,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
|
||||
/* Forward all unknown frames to CPU port for Linux processing */
|
||||
ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
|
||||
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
|
||||
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
|
||||
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
|
||||
- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
|
||||
+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
|
||||
+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
|
||||
+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
|
||||
+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1098,7 +1114,7 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
/* CPU port gets connected to all user ports of the switch */
|
||||
if (dsa_is_cpu_port(ds, i)) {
|
||||
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
|
||||
QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1110,7 +1126,7 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
|
||||
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
QCA8K_PORT_LOOKUP_MEMBER,
|
||||
- BIT(QCA8K_CPU_PORT));
|
||||
+ BIT(cpu_port));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1616,9 +1632,12 @@ static int
|
||||
qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- int port_mask = BIT(QCA8K_CPU_PORT);
|
||||
+ int port_mask, cpu_port;
|
||||
int i, ret;
|
||||
|
||||
+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
+ port_mask = BIT(cpu_port);
|
||||
+
|
||||
for (i = 1; i < QCA8K_NUM_PORTS; i++) {
|
||||
if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
continue;
|
||||
@@ -1645,7 +1664,9 @@ static void
|
||||
qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
- int i;
|
||||
+ int cpu_port, i;
|
||||
+
|
||||
+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
|
||||
for (i = 1; i < QCA8K_NUM_PORTS; i++) {
|
||||
if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
@@ -1662,7 +1683,7 @@ qca8k_port_bridge_leave(struct dsa_switc
|
||||
* this port
|
||||
*/
|
||||
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_MEMBER, BIT(QCA8K_CPU_PORT));
|
||||
+ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
|
||||
}
|
||||
|
||||
static int
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
#define QCA8K_NUM_FDB_RECORDS 2048
|
||||
|
||||
-#define QCA8K_CPU_PORT 0
|
||||
-
|
||||
#define QCA8K_PORT_VID_DEF 1
|
||||
|
||||
/* Global control registers */
|
||||
@ -0,0 +1,295 @@
|
||||
From 5654ec78dd7e64b1e04777b24007344329e6a63b Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:11 +0200
|
||||
Subject: net: dsa: qca8k: rework rgmii delay logic and scan for cpu port 6
|
||||
|
||||
Future proof commit. This switch have 2 CPU ports and one valid
|
||||
configuration is first CPU port set to sgmii and second CPU port set to
|
||||
rgmii-id. The current implementation detects delay only for CPU port
|
||||
zero set to rgmii and doesn't count any delay set in a secondary CPU
|
||||
port. Drop the current delay scan function and move it to the sgmii
|
||||
parser function to generalize and implicitly add support for secondary
|
||||
CPU port set to rgmii-id. Introduce new logic where delay is enabled
|
||||
also with internal delay binding declared and rgmii set as PHY mode.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 165 ++++++++++++++++++++++++------------------------
|
||||
drivers/net/dsa/qca8k.h | 10 ++-
|
||||
2 files changed, 89 insertions(+), 86 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -889,68 +889,6 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
|
||||
-{
|
||||
- struct device_node *port_dn;
|
||||
- phy_interface_t mode;
|
||||
- struct dsa_port *dp;
|
||||
- u32 val;
|
||||
-
|
||||
- /* CPU port is already checked */
|
||||
- dp = dsa_to_port(priv->ds, 0);
|
||||
-
|
||||
- port_dn = dp->dn;
|
||||
-
|
||||
- /* Check if port 0 is set to the correct type */
|
||||
- of_get_phy_mode(port_dn, &mode);
|
||||
- if (mode != PHY_INTERFACE_MODE_RGMII_ID &&
|
||||
- mode != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||||
- mode != PHY_INTERFACE_MODE_RGMII_TXID) {
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- switch (mode) {
|
||||
- case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
- case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
- if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val))
|
||||
- val = 2;
|
||||
- else
|
||||
- /* Switch regs accept value in ns, convert ps to ns */
|
||||
- val = val / 1000;
|
||||
-
|
||||
- if (val > QCA8K_MAX_DELAY) {
|
||||
- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
|
||||
- val = 3;
|
||||
- }
|
||||
-
|
||||
- priv->rgmii_rx_delay = val;
|
||||
- /* Stop here if we need to check only for rx delay */
|
||||
- if (mode != PHY_INTERFACE_MODE_RGMII_ID)
|
||||
- break;
|
||||
-
|
||||
- fallthrough;
|
||||
- case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
- if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val))
|
||||
- val = 1;
|
||||
- else
|
||||
- /* Switch regs accept value in ns, convert ps to ns */
|
||||
- val = val / 1000;
|
||||
-
|
||||
- if (val > QCA8K_MAX_DELAY) {
|
||||
- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
|
||||
- val = 3;
|
||||
- }
|
||||
-
|
||||
- priv->rgmii_tx_delay = val;
|
||||
- break;
|
||||
- default:
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv)
|
||||
{
|
||||
u32 mask = 0;
|
||||
@@ -996,19 +934,21 @@ static int qca8k_find_cpu_port(struct ds
|
||||
static int
|
||||
qca8k_parse_port_config(struct qca8k_priv *priv)
|
||||
{
|
||||
+ int port, cpu_port_index = 0, ret;
|
||||
struct device_node *port_dn;
|
||||
phy_interface_t mode;
|
||||
struct dsa_port *dp;
|
||||
- int port, ret;
|
||||
+ u32 delay;
|
||||
|
||||
/* We have 2 CPU port. Check them */
|
||||
- for (port = 0; port < QCA8K_NUM_PORTS; port++) {
|
||||
+ for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) {
|
||||
/* Skip every other port */
|
||||
if (port != 0 && port != 6)
|
||||
continue;
|
||||
|
||||
dp = dsa_to_port(priv->ds, port);
|
||||
port_dn = dp->dn;
|
||||
+ cpu_port_index++;
|
||||
|
||||
if (!of_device_is_available(port_dn))
|
||||
continue;
|
||||
@@ -1017,12 +957,54 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
- if (mode == PHY_INTERFACE_MODE_SGMII) {
|
||||
+ switch (mode) {
|
||||
+ case PHY_INTERFACE_MODE_RGMII:
|
||||
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
+ delay = 0;
|
||||
+
|
||||
+ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay))
|
||||
+ /* Switch regs accept value in ns, convert ps to ns */
|
||||
+ delay = delay / 1000;
|
||||
+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
+ mode == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
+ delay = 1;
|
||||
+
|
||||
+ if (delay > QCA8K_MAX_DELAY) {
|
||||
+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
|
||||
+ delay = 3;
|
||||
+ }
|
||||
+
|
||||
+ priv->rgmii_tx_delay[cpu_port_index] = delay;
|
||||
+
|
||||
+ delay = 0;
|
||||
+
|
||||
+ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay))
|
||||
+ /* Switch regs accept value in ns, convert ps to ns */
|
||||
+ delay = delay / 1000;
|
||||
+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
+ mode == PHY_INTERFACE_MODE_RGMII_RXID)
|
||||
+ delay = 2;
|
||||
+
|
||||
+ if (delay > QCA8K_MAX_DELAY) {
|
||||
+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
|
||||
+ delay = 3;
|
||||
+ }
|
||||
+
|
||||
+ priv->rgmii_rx_delay[cpu_port_index] = delay;
|
||||
+
|
||||
+ break;
|
||||
+ case PHY_INTERFACE_MODE_SGMII:
|
||||
if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
|
||||
priv->sgmii_tx_clk_falling_edge = true;
|
||||
|
||||
if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge"))
|
||||
priv->sgmii_rx_clk_falling_edge = true;
|
||||
+
|
||||
+ break;
|
||||
+ default:
|
||||
+ continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1059,10 +1041,6 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- ret = qca8k_setup_of_rgmii_delay(priv);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
ret = qca8k_setup_mac_pwr_sel(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1229,8 +1207,8 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
- u32 reg, val;
|
||||
- int ret;
|
||||
+ int cpu_port_index, ret;
|
||||
+ u32 reg, val, delay;
|
||||
|
||||
switch (port) {
|
||||
case 0: /* 1st CPU port */
|
||||
@@ -1242,6 +1220,7 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
return;
|
||||
|
||||
reg = QCA8K_REG_PORT0_PAD_CTRL;
|
||||
+ cpu_port_index = QCA8K_CPU_PORT0;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
@@ -1260,6 +1239,7 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
return;
|
||||
|
||||
reg = QCA8K_REG_PORT6_PAD_CTRL;
|
||||
+ cpu_port_index = QCA8K_CPU_PORT6;
|
||||
break;
|
||||
default:
|
||||
dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
|
||||
@@ -1274,23 +1254,40 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
|
||||
switch (state->interface) {
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
- /* RGMII mode means no delay so don't enable the delay */
|
||||
- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
|
||||
- break;
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
- /* RGMII_ID needs internal delay. This is enabled through
|
||||
- * PORT5_PAD_CTRL for all ports, rather than individual port
|
||||
- * registers
|
||||
+ val = QCA8K_PORT_PAD_RGMII_EN;
|
||||
+
|
||||
+ /* Delay can be declared in 3 different way.
|
||||
+ * Mode to rgmii and internal-delay standard binding defined
|
||||
+ * rgmii-id or rgmii-tx/rx phy mode set.
|
||||
+ * The parse logic set a delay different than 0 only when one
|
||||
+ * of the 3 different way is used. In all other case delay is
|
||||
+ * not enabled. With ID or TX/RXID delay is enabled and set
|
||||
+ * to the default and recommended value.
|
||||
+ */
|
||||
+ if (priv->rgmii_tx_delay[cpu_port_index]) {
|
||||
+ delay = priv->rgmii_tx_delay[cpu_port_index];
|
||||
+
|
||||
+ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
|
||||
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
|
||||
+ }
|
||||
+
|
||||
+ if (priv->rgmii_rx_delay[cpu_port_index]) {
|
||||
+ delay = priv->rgmii_rx_delay[cpu_port_index];
|
||||
+
|
||||
+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
|
||||
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
|
||||
+ }
|
||||
+
|
||||
+ /* Set RGMII delay based on the selected values */
|
||||
+ qca8k_write(priv, reg, val);
|
||||
+
|
||||
+ /* QCA8337 requires to set rgmii rx delay for all ports.
|
||||
+ * This is enabled through PORT5_PAD_CTRL for all ports,
|
||||
+ * rather than individual port registers.
|
||||
*/
|
||||
- qca8k_write(priv, reg,
|
||||
- QCA8K_PORT_PAD_RGMII_EN |
|
||||
- QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
|
||||
- QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
|
||||
- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
|
||||
- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
|
||||
- /* QCA8337 requires to set rgmii rx delay */
|
||||
if (priv->switch_id == QCA8K_ID_QCA8337)
|
||||
qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
|
||||
QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#define QCA8K_NUM_PORTS 7
|
||||
+#define QCA8K_NUM_CPU_PORTS 2
|
||||
#define QCA8K_MAX_MTU 9000
|
||||
|
||||
#define PHY_ID_QCA8327 0x004dd034
|
||||
@@ -255,13 +256,18 @@ struct qca8k_match_data {
|
||||
u8 id;
|
||||
};
|
||||
|
||||
+enum {
|
||||
+ QCA8K_CPU_PORT0,
|
||||
+ QCA8K_CPU_PORT6,
|
||||
+};
|
||||
+
|
||||
struct qca8k_priv {
|
||||
u8 switch_id;
|
||||
u8 switch_revision;
|
||||
- u8 rgmii_tx_delay;
|
||||
- u8 rgmii_rx_delay;
|
||||
bool sgmii_rx_clk_falling_edge;
|
||||
bool sgmii_tx_clk_falling_edge;
|
||||
+ u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||||
+ u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||||
bool legacy_phy_port_mapping;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
@ -0,0 +1,33 @@
|
||||
From 13ad5ccc093ff448b99ac7e138e91e78796adb48 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:12 +0200
|
||||
Subject: dt-bindings: net: dsa: qca8k: Document qca,sgmii-enable-pll
|
||||
|
||||
Document qca,sgmii-enable-pll binding used in the CPU nodes to
|
||||
enable SGMII PLL on MAC config.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
Documentation/devicetree/bindings/net/dsa/qca8k.txt | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
@@ -45,6 +45,16 @@ A CPU port node has the following option
|
||||
Mostly used in qca8327 with CPU port 0 set to
|
||||
sgmii.
|
||||
- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge.
|
||||
+- qca,sgmii-enable-pll : For SGMII CPU port, explicitly enable PLL, TX and RX
|
||||
+ chain along with Signal Detection.
|
||||
+ This should NOT be enabled for qca8327. If enabled with
|
||||
+ qca8327 the sgmii port won't correctly init and an err
|
||||
+ is printed.
|
||||
+ This can be required for qca8337 switch with revision 2.
|
||||
+ A warning is displayed when used with revision greater
|
||||
+ 2.
|
||||
+ With CPU port set to sgmii and qca8337 it is advised
|
||||
+ to set this unless a communication problem is observed.
|
||||
|
||||
For QCA8K the 'fixed-link' sub-node supports only the following properties:
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
From bbc4799e8bb6c397e3b3fec13de68e179f5db9ff Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:13 +0200
|
||||
Subject: net: dsa: qca8k: add explicit SGMII PLL enable
|
||||
|
||||
Support enabling PLL on the SGMII CPU port. Some device require this
|
||||
special configuration or no traffic is transmitted and the switch
|
||||
doesn't work at all. A dedicated binding is added to the CPU node
|
||||
port to apply the correct reg on mac config.
|
||||
Fail to correctly configure sgmii with qca8327 switch and warn if pll is
|
||||
used on qca8337 with a revision greater than 1.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 19 +++++++++++++++++--
|
||||
drivers/net/dsa/qca8k.h | 1 +
|
||||
2 files changed, 18 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1002,6 +1002,18 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge"))
|
||||
priv->sgmii_rx_clk_falling_edge = true;
|
||||
|
||||
+ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) {
|
||||
+ priv->sgmii_enable_pll = true;
|
||||
+
|
||||
+ if (priv->switch_id == QCA8K_ID_QCA8327) {
|
||||
+ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling");
|
||||
+ priv->sgmii_enable_pll = false;
|
||||
+ }
|
||||
+
|
||||
+ if (priv->switch_revision < 2)
|
||||
+ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more.");
|
||||
+ }
|
||||
+
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
@@ -1312,8 +1324,11 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
|
||||
- QCA8K_SGMII_EN_TX | QCA8K_SGMII_EN_SD;
|
||||
+ val |= QCA8K_SGMII_EN_SD;
|
||||
+
|
||||
+ if (priv->sgmii_enable_pll)
|
||||
+ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
|
||||
+ QCA8K_SGMII_EN_TX;
|
||||
|
||||
if (dsa_is_cpu_port(ds, port)) {
|
||||
/* CPU port, we're talking to the CPU MAC, be a PHY */
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -266,6 +266,7 @@ struct qca8k_priv {
|
||||
u8 switch_revision;
|
||||
bool sgmii_rx_clk_falling_edge;
|
||||
bool sgmii_tx_clk_falling_edge;
|
||||
+ bool sgmii_enable_pll;
|
||||
u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||||
u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||||
bool legacy_phy_port_mapping;
|
||||
@ -0,0 +1,37 @@
|
||||
From 924087c5c3d41553700b0eb83ca2a53b91643dca Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:14 +0200
|
||||
Subject: dt-bindings: net: dsa: qca8k: Document qca,led-open-drain binding
|
||||
|
||||
Document new binding qca,ignore-power-on-sel used to ignore
|
||||
power on strapping and use sw regs instead.
|
||||
Document qca,led-open.drain to set led to open drain mode, the
|
||||
qca,ignore-power-on-sel is mandatory with this enabled or an error will
|
||||
be reported.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
Documentation/devicetree/bindings/net/dsa/qca8k.txt | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
@@ -13,6 +13,17 @@ Required properties:
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios: GPIO to be used to reset the whole device
|
||||
+- qca,ignore-power-on-sel: Ignore power on pin strapping to configure led open
|
||||
+ drain or eeprom presence. This is needed for broken
|
||||
+ devices that have wrong configuration or when the oem
|
||||
+ decided to not use pin strapping and fallback to sw
|
||||
+ regs.
|
||||
+- qca,led-open-drain: Set leds to open-drain mode. This requires the
|
||||
+ qca,ignore-power-on-sel to be set or the driver will fail
|
||||
+ to probe. This is needed if the oem doesn't use pin
|
||||
+ strapping to set this mode and prefers to set it using sw
|
||||
+ regs. The pin strapping related to led open drain mode is
|
||||
+ the pin B68 for QCA832x and B49 for QCA833x
|
||||
|
||||
Subnodes:
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
From 362bb238d8bf1470424214a8a5968d9c6cce68fa Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:15 +0200
|
||||
Subject: net: dsa: qca8k: add support for pws config reg
|
||||
|
||||
Some qca8327 switch require to force the ignore of power on sel
|
||||
strapping. Some switch require to set the led open drain mode in regs
|
||||
instead of using strapping. While most of the device implements this
|
||||
using the correct way using pin strapping, there are still some broken
|
||||
device that require to be set using sw regs.
|
||||
Introduce a new binding and support these special configuration.
|
||||
As led open drain require to ignore pin strapping to work, the probe
|
||||
fails with EINVAL error with incorrect configuration.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 39 +++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 6 ++++++
|
||||
2 files changed, 45 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -932,6 +932,41 @@ static int qca8k_find_cpu_port(struct ds
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_setup_of_pws_reg(struct qca8k_priv *priv)
|
||||
+{
|
||||
+ struct device_node *node = priv->dev->of_node;
|
||||
+ u32 val = 0;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* QCA8327 require to set to the correct mode.
|
||||
+ * His bigger brother QCA8328 have the 172 pin layout.
|
||||
+ * Should be applied by default but we set this just to make sure.
|
||||
+ */
|
||||
+ if (priv->switch_id == QCA8K_ID_QCA8327) {
|
||||
+ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN,
|
||||
+ QCA8327_PWS_PACKAGE148_EN);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (of_property_read_bool(node, "qca,ignore-power-on-sel"))
|
||||
+ val |= QCA8K_PWS_POWER_ON_SEL;
|
||||
+
|
||||
+ if (of_property_read_bool(node, "qca,led-open-drain")) {
|
||||
+ if (!(val & QCA8K_PWS_POWER_ON_SEL)) {
|
||||
+ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set.");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ val |= QCA8K_PWS_LED_OPEN_EN_CSR;
|
||||
+ }
|
||||
+
|
||||
+ return qca8k_rmw(priv, QCA8K_REG_PWS,
|
||||
+ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL,
|
||||
+ val);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_parse_port_config(struct qca8k_priv *priv)
|
||||
{
|
||||
int port, cpu_port_index = 0, ret;
|
||||
@@ -1053,6 +1088,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = qca8k_setup_of_pws_reg(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
ret = qca8k_setup_mac_pwr_sel(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -46,6 +46,12 @@
|
||||
#define QCA8K_MAX_DELAY 3
|
||||
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
|
||||
#define QCA8K_REG_PWS 0x010
|
||||
+#define QCA8K_PWS_POWER_ON_SEL BIT(31)
|
||||
+/* This reg is only valid for QCA832x and toggle the package
|
||||
+ * type from 176 pin (by default) to 148 pin used on QCA8327
|
||||
+ */
|
||||
+#define QCA8327_PWS_PACKAGE148_EN BIT(30)
|
||||
+#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24)
|
||||
#define QCA8K_PWS_SERDES_AEN_DIS BIT(7)
|
||||
#define QCA8K_REG_MODULE_EN 0x030
|
||||
#define QCA8K_MODULE_EN_MIB BIT(0)
|
||||
@ -0,0 +1,32 @@
|
||||
From ed7988d77fbfb79366b68f9e7fa60a6080da23d4 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:16 +0200
|
||||
Subject: dt-bindings: net: dsa: qca8k: document support for qca8328
|
||||
|
||||
QCA8328 is the bigger brother of qca8327. Document the new compatible
|
||||
binding and add some information to understand the various switch
|
||||
compatible.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
Documentation/devicetree/bindings/net/dsa/qca8k.txt | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
@@ -3,9 +3,10 @@
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of:
|
||||
- "qca,qca8327"
|
||||
- "qca,qca8334"
|
||||
- "qca,qca8337"
|
||||
+ "qca,qca8328": referenced as AR8328(N)-AK1(A/B) QFN 176 pin package
|
||||
+ "qca,qca8327": referenced as AR8327(N)-AL1A DR-QFN 148 pin package
|
||||
+ "qca,qca8334": referenced as QCA8334-AL3C QFN 88 pin package
|
||||
+ "qca,qca8337": referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package
|
||||
|
||||
- #size-cells: must be 0
|
||||
- #address-cells: must be 1
|
||||
@ -0,0 +1,78 @@
|
||||
From f477d1c8bdbef4f400718238e350f16f521d2a3e Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:17 +0200
|
||||
Subject: net: dsa: qca8k: add support for QCA8328
|
||||
|
||||
QCA8328 switch is the bigger brother of the qca8327. Same regs different
|
||||
chip. Change the function to set the correct pin layout and introduce a
|
||||
new match_data to differentiate the 2 switch as they have the same ID
|
||||
and their internal PHY have the same ID.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 19 ++++++++++++++++---
|
||||
drivers/net/dsa/qca8k.h | 1 +
|
||||
2 files changed, 17 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -935,6 +935,7 @@ static int
|
||||
qca8k_setup_of_pws_reg(struct qca8k_priv *priv)
|
||||
{
|
||||
struct device_node *node = priv->dev->of_node;
|
||||
+ const struct qca8k_match_data *data;
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
||||
@@ -943,8 +944,14 @@ qca8k_setup_of_pws_reg(struct qca8k_priv
|
||||
* Should be applied by default but we set this just to make sure.
|
||||
*/
|
||||
if (priv->switch_id == QCA8K_ID_QCA8327) {
|
||||
+ data = of_device_get_match_data(priv->dev);
|
||||
+
|
||||
+ /* Set the correct package of 148 pin for QCA8327 */
|
||||
+ if (data->reduced_package)
|
||||
+ val |= QCA8327_PWS_PACKAGE148_EN;
|
||||
+
|
||||
ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN,
|
||||
- QCA8327_PWS_PACKAGE148_EN);
|
||||
+ val);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -2105,7 +2112,12 @@ static int qca8k_resume(struct device *d
|
||||
static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
|
||||
qca8k_suspend, qca8k_resume);
|
||||
|
||||
-static const struct qca8k_match_data qca832x = {
|
||||
+static const struct qca8k_match_data qca8327 = {
|
||||
+ .id = QCA8K_ID_QCA8327,
|
||||
+ .reduced_package = true,
|
||||
+};
|
||||
+
|
||||
+static const struct qca8k_match_data qca8328 = {
|
||||
.id = QCA8K_ID_QCA8327,
|
||||
};
|
||||
|
||||
@@ -2114,7 +2126,8 @@ static const struct qca8k_match_data qca
|
||||
};
|
||||
|
||||
static const struct of_device_id qca8k_of_match[] = {
|
||||
- { .compatible = "qca,qca8327", .data = &qca832x },
|
||||
+ { .compatible = "qca,qca8327", .data = &qca8327 },
|
||||
+ { .compatible = "qca,qca8328", .data = &qca8328 },
|
||||
{ .compatible = "qca,qca8334", .data = &qca833x },
|
||||
{ .compatible = "qca,qca8337", .data = &qca833x },
|
||||
{ /* sentinel */ },
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -260,6 +260,7 @@ struct ar8xxx_port_status {
|
||||
|
||||
struct qca8k_match_data {
|
||||
u8 id;
|
||||
+ bool reduced_package;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -0,0 +1,159 @@
|
||||
From cef08115846e581f80ff99abf7bf218da1840616 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:18 +0200
|
||||
Subject: net: dsa: qca8k: set internal delay also for sgmii
|
||||
|
||||
QCA original code report port instability and sa that SGMII also require
|
||||
to set internal delay. Generalize the rgmii delay function and apply the
|
||||
advised value if they are not defined in DT.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 88 +++++++++++++++++++++++++++++++++----------------
|
||||
drivers/net/dsa/qca8k.h | 2 ++
|
||||
2 files changed, 62 insertions(+), 28 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1004,6 +1004,7 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
+ case PHY_INTERFACE_MODE_SGMII:
|
||||
delay = 0;
|
||||
|
||||
if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay))
|
||||
@@ -1036,8 +1037,13 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
|
||||
priv->rgmii_rx_delay[cpu_port_index] = delay;
|
||||
|
||||
- break;
|
||||
- case PHY_INTERFACE_MODE_SGMII:
|
||||
+ /* Skip sgmii parsing for rgmii* mode */
|
||||
+ if (mode == PHY_INTERFACE_MODE_RGMII ||
|
||||
+ mode == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
+ mode == PHY_INTERFACE_MODE_RGMII_TXID ||
|
||||
+ mode == PHY_INTERFACE_MODE_RGMII_RXID)
|
||||
+ break;
|
||||
+
|
||||
if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
|
||||
priv->sgmii_tx_clk_falling_edge = true;
|
||||
|
||||
@@ -1261,12 +1267,53 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
}
|
||||
|
||||
static void
|
||||
+qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index,
|
||||
+ u32 reg)
|
||||
+{
|
||||
+ u32 delay, val = 0;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Delay can be declared in 3 different way.
|
||||
+ * Mode to rgmii and internal-delay standard binding defined
|
||||
+ * rgmii-id or rgmii-tx/rx phy mode set.
|
||||
+ * The parse logic set a delay different than 0 only when one
|
||||
+ * of the 3 different way is used. In all other case delay is
|
||||
+ * not enabled. With ID or TX/RXID delay is enabled and set
|
||||
+ * to the default and recommended value.
|
||||
+ */
|
||||
+ if (priv->rgmii_tx_delay[cpu_port_index]) {
|
||||
+ delay = priv->rgmii_tx_delay[cpu_port_index];
|
||||
+
|
||||
+ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
|
||||
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
|
||||
+ }
|
||||
+
|
||||
+ if (priv->rgmii_rx_delay[cpu_port_index]) {
|
||||
+ delay = priv->rgmii_rx_delay[cpu_port_index];
|
||||
+
|
||||
+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
|
||||
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
|
||||
+ }
|
||||
+
|
||||
+ /* Set RGMII delay based on the selected values */
|
||||
+ ret = qca8k_rmw(priv, reg,
|
||||
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK |
|
||||
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK |
|
||||
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
|
||||
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN,
|
||||
+ val);
|
||||
+ if (ret)
|
||||
+ dev_err(priv->dev, "Failed to set internal delay for CPU port%d",
|
||||
+ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
int cpu_port_index, ret;
|
||||
- u32 reg, val, delay;
|
||||
+ u32 reg, val;
|
||||
|
||||
switch (port) {
|
||||
case 0: /* 1st CPU port */
|
||||
@@ -1315,32 +1362,10 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
- val = QCA8K_PORT_PAD_RGMII_EN;
|
||||
-
|
||||
- /* Delay can be declared in 3 different way.
|
||||
- * Mode to rgmii and internal-delay standard binding defined
|
||||
- * rgmii-id or rgmii-tx/rx phy mode set.
|
||||
- * The parse logic set a delay different than 0 only when one
|
||||
- * of the 3 different way is used. In all other case delay is
|
||||
- * not enabled. With ID or TX/RXID delay is enabled and set
|
||||
- * to the default and recommended value.
|
||||
- */
|
||||
- if (priv->rgmii_tx_delay[cpu_port_index]) {
|
||||
- delay = priv->rgmii_tx_delay[cpu_port_index];
|
||||
-
|
||||
- val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
|
||||
- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
|
||||
- }
|
||||
-
|
||||
- if (priv->rgmii_rx_delay[cpu_port_index]) {
|
||||
- delay = priv->rgmii_rx_delay[cpu_port_index];
|
||||
-
|
||||
- val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
|
||||
- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
|
||||
- }
|
||||
+ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
|
||||
|
||||
- /* Set RGMII delay based on the selected values */
|
||||
- qca8k_write(priv, reg, val);
|
||||
+ /* Configure rgmii delay */
|
||||
+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg);
|
||||
|
||||
/* QCA8337 requires to set rgmii rx delay for all ports.
|
||||
* This is enabled through PORT5_PAD_CTRL for all ports,
|
||||
@@ -1411,6 +1436,13 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
|
||||
QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
|
||||
val);
|
||||
+
|
||||
+ /* From original code is reported port instability as SGMII also
|
||||
+ * require delay set. Apply advised values here or take them from DT.
|
||||
+ */
|
||||
+ if (state->interface == PHY_INTERFACE_MODE_SGMII)
|
||||
+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg);
|
||||
+
|
||||
break;
|
||||
default:
|
||||
dev_err(ds->dev, "xMII mode %s not supported for port %d\n",
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -39,7 +39,9 @@
|
||||
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
|
||||
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
|
||||
#define QCA8K_PORT_PAD_RGMII_EN BIT(26)
|
||||
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22)
|
||||
#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22)
|
||||
+#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20)
|
||||
#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20)
|
||||
#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
|
||||
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
|
||||
@ -0,0 +1,124 @@
|
||||
From fd0bb28c547f7c8affb1691128cece38f5b626a1 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:19 +0200
|
||||
Subject: net: dsa: qca8k: move port config to dedicated struct
|
||||
|
||||
Move ports related config to dedicated struct to keep things organized.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 26 +++++++++++++-------------
|
||||
drivers/net/dsa/qca8k.h | 10 +++++++---
|
||||
2 files changed, 20 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1019,7 +1019,7 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
delay = 3;
|
||||
}
|
||||
|
||||
- priv->rgmii_tx_delay[cpu_port_index] = delay;
|
||||
+ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay;
|
||||
|
||||
delay = 0;
|
||||
|
||||
@@ -1035,7 +1035,7 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
delay = 3;
|
||||
}
|
||||
|
||||
- priv->rgmii_rx_delay[cpu_port_index] = delay;
|
||||
+ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay;
|
||||
|
||||
/* Skip sgmii parsing for rgmii* mode */
|
||||
if (mode == PHY_INTERFACE_MODE_RGMII ||
|
||||
@@ -1045,17 +1045,17 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
break;
|
||||
|
||||
if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
|
||||
- priv->sgmii_tx_clk_falling_edge = true;
|
||||
+ priv->ports_config.sgmii_tx_clk_falling_edge = true;
|
||||
|
||||
if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge"))
|
||||
- priv->sgmii_rx_clk_falling_edge = true;
|
||||
+ priv->ports_config.sgmii_rx_clk_falling_edge = true;
|
||||
|
||||
if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) {
|
||||
- priv->sgmii_enable_pll = true;
|
||||
+ priv->ports_config.sgmii_enable_pll = true;
|
||||
|
||||
if (priv->switch_id == QCA8K_ID_QCA8327) {
|
||||
dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling");
|
||||
- priv->sgmii_enable_pll = false;
|
||||
+ priv->ports_config.sgmii_enable_pll = false;
|
||||
}
|
||||
|
||||
if (priv->switch_revision < 2)
|
||||
@@ -1281,15 +1281,15 @@ qca8k_mac_config_setup_internal_delay(st
|
||||
* not enabled. With ID or TX/RXID delay is enabled and set
|
||||
* to the default and recommended value.
|
||||
*/
|
||||
- if (priv->rgmii_tx_delay[cpu_port_index]) {
|
||||
- delay = priv->rgmii_tx_delay[cpu_port_index];
|
||||
+ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) {
|
||||
+ delay = priv->ports_config.rgmii_tx_delay[cpu_port_index];
|
||||
|
||||
val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
|
||||
QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
|
||||
}
|
||||
|
||||
- if (priv->rgmii_rx_delay[cpu_port_index]) {
|
||||
- delay = priv->rgmii_rx_delay[cpu_port_index];
|
||||
+ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) {
|
||||
+ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index];
|
||||
|
||||
val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
|
||||
QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
|
||||
@@ -1397,7 +1397,7 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
|
||||
val |= QCA8K_SGMII_EN_SD;
|
||||
|
||||
- if (priv->sgmii_enable_pll)
|
||||
+ if (priv->ports_config.sgmii_enable_pll)
|
||||
val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
|
||||
QCA8K_SGMII_EN_TX;
|
||||
|
||||
@@ -1425,10 +1425,10 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
val = 0;
|
||||
|
||||
/* SGMII Clock phase configuration */
|
||||
- if (priv->sgmii_rx_clk_falling_edge)
|
||||
+ if (priv->ports_config.sgmii_rx_clk_falling_edge)
|
||||
val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE;
|
||||
|
||||
- if (priv->sgmii_tx_clk_falling_edge)
|
||||
+ if (priv->ports_config.sgmii_tx_clk_falling_edge)
|
||||
val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE;
|
||||
|
||||
if (val)
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -270,15 +270,19 @@ enum {
|
||||
QCA8K_CPU_PORT6,
|
||||
};
|
||||
|
||||
-struct qca8k_priv {
|
||||
- u8 switch_id;
|
||||
- u8 switch_revision;
|
||||
+struct qca8k_ports_config {
|
||||
bool sgmii_rx_clk_falling_edge;
|
||||
bool sgmii_tx_clk_falling_edge;
|
||||
bool sgmii_enable_pll;
|
||||
u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||||
u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||||
+};
|
||||
+
|
||||
+struct qca8k_priv {
|
||||
+ u8 switch_id;
|
||||
+ u8 switch_revision;
|
||||
bool legacy_phy_port_mapping;
|
||||
+ struct qca8k_ports_config ports_config;
|
||||
struct regmap *regmap;
|
||||
struct mii_bus *bus;
|
||||
struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
|
||||
@ -0,0 +1,26 @@
|
||||
From e52073a8e3086046a098b8a7cbeb282ff0cdb424 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:20 +0200
|
||||
Subject: dt-bindings: net: ipq8064-mdio: fix warning with new qca8k switch
|
||||
|
||||
Fix warning now that we have qca8k switch Documentation using yaml.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml
|
||||
+++ b/Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml
|
||||
@@ -51,6 +51,9 @@ examples:
|
||||
switch@10 {
|
||||
compatible = "qca,qca8337";
|
||||
reg = <0x10>;
|
||||
- /* ... */
|
||||
+
|
||||
+ ports {
|
||||
+ /* ... */
|
||||
+ };
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,631 @@
|
||||
From d291fbb8245d5ba04979fed85575860a5cea7196 Mon Sep 17 00:00:00 2001
|
||||
From: Matthew Hagan <mnhagan88@gmail.com>
|
||||
Date: Thu, 14 Oct 2021 00:39:21 +0200
|
||||
Subject: dt-bindings: net: dsa: qca8k: convert to YAML schema
|
||||
|
||||
Convert the qca8k bindings to YAML format.
|
||||
|
||||
Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
|
||||
Co-developed-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
.../devicetree/bindings/net/dsa/qca8k.txt | 245 --------------
|
||||
.../devicetree/bindings/net/dsa/qca8k.yaml | 362 +++++++++++++++++++++
|
||||
2 files changed, 362 insertions(+), 245 deletions(-)
|
||||
delete mode 100644 Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
create mode 100644 Documentation/devicetree/bindings/net/dsa/qca8k.yaml
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
|
||||
+++ /dev/null
|
||||
@@ -1,245 +0,0 @@
|
||||
-* Qualcomm Atheros QCA8xxx switch family
|
||||
-
|
||||
-Required properties:
|
||||
-
|
||||
-- compatible: should be one of:
|
||||
- "qca,qca8328": referenced as AR8328(N)-AK1(A/B) QFN 176 pin package
|
||||
- "qca,qca8327": referenced as AR8327(N)-AL1A DR-QFN 148 pin package
|
||||
- "qca,qca8334": referenced as QCA8334-AL3C QFN 88 pin package
|
||||
- "qca,qca8337": referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package
|
||||
-
|
||||
-- #size-cells: must be 0
|
||||
-- #address-cells: must be 1
|
||||
-
|
||||
-Optional properties:
|
||||
-
|
||||
-- reset-gpios: GPIO to be used to reset the whole device
|
||||
-- qca,ignore-power-on-sel: Ignore power on pin strapping to configure led open
|
||||
- drain or eeprom presence. This is needed for broken
|
||||
- devices that have wrong configuration or when the oem
|
||||
- decided to not use pin strapping and fallback to sw
|
||||
- regs.
|
||||
-- qca,led-open-drain: Set leds to open-drain mode. This requires the
|
||||
- qca,ignore-power-on-sel to be set or the driver will fail
|
||||
- to probe. This is needed if the oem doesn't use pin
|
||||
- strapping to set this mode and prefers to set it using sw
|
||||
- regs. The pin strapping related to led open drain mode is
|
||||
- the pin B68 for QCA832x and B49 for QCA833x
|
||||
-
|
||||
-Subnodes:
|
||||
-
|
||||
-The integrated switch subnode should be specified according to the binding
|
||||
-described in dsa/dsa.txt. If the QCA8K switch is connect to a SoC's external
|
||||
-mdio-bus each subnode describing a port needs to have a valid phandle
|
||||
-referencing the internal PHY it is connected to. This is because there's no
|
||||
-N:N mapping of port and PHY id.
|
||||
-To declare the internal mdio-bus configuration, declare a mdio node in the
|
||||
-switch node and declare the phandle for the port referencing the internal
|
||||
-PHY is connected to. In this config a internal mdio-bus is registered and
|
||||
-the mdio MASTER is used as communication.
|
||||
-
|
||||
-Don't use mixed external and internal mdio-bus configurations, as this is
|
||||
-not supported by the hardware.
|
||||
-
|
||||
-This switch support 2 CPU port. Normally and advised configuration is with
|
||||
-CPU port set to port 0. It is also possible to set the CPU port to port 6
|
||||
-if the device requires it. The driver will configure the switch to the defined
|
||||
-port. With both CPU port declared the first CPU port is selected as primary
|
||||
-and the secondary CPU ignored.
|
||||
-
|
||||
-A CPU port node has the following optional node:
|
||||
-
|
||||
-- fixed-link : Fixed-link subnode describing a link to a non-MDIO
|
||||
- managed entity. See
|
||||
- Documentation/devicetree/bindings/net/fixed-link.txt
|
||||
- for details.
|
||||
-- qca,sgmii-rxclk-falling-edge: Set the receive clock phase to falling edge.
|
||||
- Mostly used in qca8327 with CPU port 0 set to
|
||||
- sgmii.
|
||||
-- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge.
|
||||
-- qca,sgmii-enable-pll : For SGMII CPU port, explicitly enable PLL, TX and RX
|
||||
- chain along with Signal Detection.
|
||||
- This should NOT be enabled for qca8327. If enabled with
|
||||
- qca8327 the sgmii port won't correctly init and an err
|
||||
- is printed.
|
||||
- This can be required for qca8337 switch with revision 2.
|
||||
- A warning is displayed when used with revision greater
|
||||
- 2.
|
||||
- With CPU port set to sgmii and qca8337 it is advised
|
||||
- to set this unless a communication problem is observed.
|
||||
-
|
||||
-For QCA8K the 'fixed-link' sub-node supports only the following properties:
|
||||
-
|
||||
-- 'speed' (integer, mandatory), to indicate the link speed. Accepted
|
||||
- values are 10, 100 and 1000
|
||||
-- 'full-duplex' (boolean, optional), to indicate that full duplex is
|
||||
- used. When absent, half duplex is assumed.
|
||||
-
|
||||
-Examples:
|
||||
-
|
||||
-for the external mdio-bus configuration:
|
||||
-
|
||||
- &mdio0 {
|
||||
- phy_port1: phy@0 {
|
||||
- reg = <0>;
|
||||
- };
|
||||
-
|
||||
- phy_port2: phy@1 {
|
||||
- reg = <1>;
|
||||
- };
|
||||
-
|
||||
- phy_port3: phy@2 {
|
||||
- reg = <2>;
|
||||
- };
|
||||
-
|
||||
- phy_port4: phy@3 {
|
||||
- reg = <3>;
|
||||
- };
|
||||
-
|
||||
- phy_port5: phy@4 {
|
||||
- reg = <4>;
|
||||
- };
|
||||
-
|
||||
- switch@10 {
|
||||
- compatible = "qca,qca8337";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
-
|
||||
- reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
|
||||
- reg = <0x10>;
|
||||
-
|
||||
- ports {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- port@0 {
|
||||
- reg = <0>;
|
||||
- label = "cpu";
|
||||
- ethernet = <&gmac1>;
|
||||
- phy-mode = "rgmii";
|
||||
- fixed-link {
|
||||
- speed = 1000;
|
||||
- full-duplex;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- port@1 {
|
||||
- reg = <1>;
|
||||
- label = "lan1";
|
||||
- phy-handle = <&phy_port1>;
|
||||
- };
|
||||
-
|
||||
- port@2 {
|
||||
- reg = <2>;
|
||||
- label = "lan2";
|
||||
- phy-handle = <&phy_port2>;
|
||||
- };
|
||||
-
|
||||
- port@3 {
|
||||
- reg = <3>;
|
||||
- label = "lan3";
|
||||
- phy-handle = <&phy_port3>;
|
||||
- };
|
||||
-
|
||||
- port@4 {
|
||||
- reg = <4>;
|
||||
- label = "lan4";
|
||||
- phy-handle = <&phy_port4>;
|
||||
- };
|
||||
-
|
||||
- port@5 {
|
||||
- reg = <5>;
|
||||
- label = "wan";
|
||||
- phy-handle = <&phy_port5>;
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
-
|
||||
-for the internal master mdio-bus configuration:
|
||||
-
|
||||
- &mdio0 {
|
||||
- switch@10 {
|
||||
- compatible = "qca,qca8337";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
-
|
||||
- reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
|
||||
- reg = <0x10>;
|
||||
-
|
||||
- ports {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
-
|
||||
- port@0 {
|
||||
- reg = <0>;
|
||||
- label = "cpu";
|
||||
- ethernet = <&gmac1>;
|
||||
- phy-mode = "rgmii";
|
||||
- fixed-link {
|
||||
- speed = 1000;
|
||||
- full-duplex;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- port@1 {
|
||||
- reg = <1>;
|
||||
- label = "lan1";
|
||||
- phy-mode = "internal";
|
||||
- phy-handle = <&phy_port1>;
|
||||
- };
|
||||
-
|
||||
- port@2 {
|
||||
- reg = <2>;
|
||||
- label = "lan2";
|
||||
- phy-mode = "internal";
|
||||
- phy-handle = <&phy_port2>;
|
||||
- };
|
||||
-
|
||||
- port@3 {
|
||||
- reg = <3>;
|
||||
- label = "lan3";
|
||||
- phy-mode = "internal";
|
||||
- phy-handle = <&phy_port3>;
|
||||
- };
|
||||
-
|
||||
- port@4 {
|
||||
- reg = <4>;
|
||||
- label = "lan4";
|
||||
- phy-mode = "internal";
|
||||
- phy-handle = <&phy_port4>;
|
||||
- };
|
||||
-
|
||||
- port@5 {
|
||||
- reg = <5>;
|
||||
- label = "wan";
|
||||
- phy-mode = "internal";
|
||||
- phy-handle = <&phy_port5>;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- mdio {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
-
|
||||
- phy_port1: phy@0 {
|
||||
- reg = <0>;
|
||||
- };
|
||||
-
|
||||
- phy_port2: phy@1 {
|
||||
- reg = <1>;
|
||||
- };
|
||||
-
|
||||
- phy_port3: phy@2 {
|
||||
- reg = <2>;
|
||||
- };
|
||||
-
|
||||
- phy_port4: phy@3 {
|
||||
- reg = <3>;
|
||||
- };
|
||||
-
|
||||
- phy_port5: phy@4 {
|
||||
- reg = <4>;
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.yaml
|
||||
@@ -0,0 +1,362 @@
|
||||
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/net/dsa/qca8k.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Qualcomm Atheros QCA83xx switch family
|
||||
+
|
||||
+maintainers:
|
||||
+ - John Crispin <john@phrozen.org>
|
||||
+
|
||||
+description:
|
||||
+ If the QCA8K switch is connect to an SoC's external mdio-bus, each subnode
|
||||
+ describing a port needs to have a valid phandle referencing the internal PHY
|
||||
+ it is connected to. This is because there is no N:N mapping of port and PHY
|
||||
+ ID. To declare the internal mdio-bus configuration, declare an MDIO node in
|
||||
+ the switch node and declare the phandle for the port, referencing the internal
|
||||
+ PHY it is connected to. In this config, an internal mdio-bus is registered and
|
||||
+ the MDIO master is used for communication. Mixed external and internal
|
||||
+ mdio-bus configurations are not supported by the hardware.
|
||||
+
|
||||
+properties:
|
||||
+ compatible:
|
||||
+ oneOf:
|
||||
+ - enum:
|
||||
+ - qca,qca8327
|
||||
+ - qca,qca8328
|
||||
+ - qca,qca8334
|
||||
+ - qca,qca8337
|
||||
+ description: |
|
||||
+ qca,qca8328: referenced as AR8328(N)-AK1(A/B) QFN 176 pin package
|
||||
+ qca,qca8327: referenced as AR8327(N)-AL1A DR-QFN 148 pin package
|
||||
+ qca,qca8334: referenced as QCA8334-AL3C QFN 88 pin package
|
||||
+ qca,qca8337: referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package
|
||||
+
|
||||
+ reg:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+ reset-gpios:
|
||||
+ description:
|
||||
+ GPIO to be used to reset the whole device
|
||||
+ maxItems: 1
|
||||
+
|
||||
+ qca,ignore-power-on-sel:
|
||||
+ $ref: /schemas/types.yaml#/definitions/flag
|
||||
+ description:
|
||||
+ Ignore power-on pin strapping to configure LED open-drain or EEPROM
|
||||
+ presence. This is needed for devices with incorrect configuration or when
|
||||
+ the OEM has decided not to use pin strapping and falls back to SW regs.
|
||||
+
|
||||
+ qca,led-open-drain:
|
||||
+ $ref: /schemas/types.yaml#/definitions/flag
|
||||
+ description:
|
||||
+ Set LEDs to open-drain mode. This requires the qca,ignore-power-on-sel to
|
||||
+ be set, otherwise the driver will fail at probe. This is required if the
|
||||
+ OEM does not use pin strapping to set this mode and prefers to set it
|
||||
+ using SW regs. The pin strappings related to LED open-drain mode are
|
||||
+ B68 on the QCA832x and B49 on the QCA833x.
|
||||
+
|
||||
+ mdio:
|
||||
+ type: object
|
||||
+ description: Qca8k switch have an internal mdio to access switch port.
|
||||
+ If this is not present, the legacy mapping is used and the
|
||||
+ internal mdio access is used.
|
||||
+ With the legacy mapping the reg corresponding to the internal
|
||||
+ mdio is the switch reg with an offset of -1.
|
||||
+
|
||||
+ properties:
|
||||
+ '#address-cells':
|
||||
+ const: 1
|
||||
+ '#size-cells':
|
||||
+ const: 0
|
||||
+
|
||||
+ patternProperties:
|
||||
+ "^(ethernet-)?phy@[0-4]$":
|
||||
+ type: object
|
||||
+
|
||||
+ allOf:
|
||||
+ - $ref: "http://devicetree.org/schemas/net/mdio.yaml#"
|
||||
+
|
||||
+ properties:
|
||||
+ reg:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+ required:
|
||||
+ - reg
|
||||
+
|
||||
+patternProperties:
|
||||
+ "^(ethernet-)?ports$":
|
||||
+ type: object
|
||||
+ properties:
|
||||
+ '#address-cells':
|
||||
+ const: 1
|
||||
+ '#size-cells':
|
||||
+ const: 0
|
||||
+
|
||||
+ patternProperties:
|
||||
+ "^(ethernet-)?port@[0-6]$":
|
||||
+ type: object
|
||||
+ description: Ethernet switch ports
|
||||
+
|
||||
+ properties:
|
||||
+ reg:
|
||||
+ description: Port number
|
||||
+
|
||||
+ label:
|
||||
+ description:
|
||||
+ Describes the label associated with this port, which will become
|
||||
+ the netdev name
|
||||
+ $ref: /schemas/types.yaml#/definitions/string
|
||||
+
|
||||
+ link:
|
||||
+ description:
|
||||
+ Should be a list of phandles to other switch's DSA port. This
|
||||
+ port is used as the outgoing port towards the phandle ports. The
|
||||
+ full routing information must be given, not just the one hop
|
||||
+ routes to neighbouring switches
|
||||
+ $ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
+
|
||||
+ ethernet:
|
||||
+ description:
|
||||
+ Should be a phandle to a valid Ethernet device node. This host
|
||||
+ device is what the switch port is connected to
|
||||
+ $ref: /schemas/types.yaml#/definitions/phandle
|
||||
+
|
||||
+ phy-handle: true
|
||||
+
|
||||
+ phy-mode: true
|
||||
+
|
||||
+ fixed-link: true
|
||||
+
|
||||
+ mac-address: true
|
||||
+
|
||||
+ sfp: true
|
||||
+
|
||||
+ qca,sgmii-rxclk-falling-edge:
|
||||
+ $ref: /schemas/types.yaml#/definitions/flag
|
||||
+ description:
|
||||
+ Set the receive clock phase to falling edge. Mostly commonly used on
|
||||
+ the QCA8327 with CPU port 0 set to SGMII.
|
||||
+
|
||||
+ qca,sgmii-txclk-falling-edge:
|
||||
+ $ref: /schemas/types.yaml#/definitions/flag
|
||||
+ description:
|
||||
+ Set the transmit clock phase to falling edge.
|
||||
+
|
||||
+ qca,sgmii-enable-pll:
|
||||
+ $ref: /schemas/types.yaml#/definitions/flag
|
||||
+ description:
|
||||
+ For SGMII CPU port, explicitly enable PLL, TX and RX chain along with
|
||||
+ Signal Detection. On the QCA8327 this should not be enabled, otherwise
|
||||
+ the SGMII port will not initialize. When used on the QCA8337, revision 3
|
||||
+ or greater, a warning will be displayed. When the CPU port is set to
|
||||
+ SGMII on the QCA8337, it is advised to set this unless a communication
|
||||
+ issue is observed.
|
||||
+
|
||||
+ required:
|
||||
+ - reg
|
||||
+
|
||||
+ additionalProperties: false
|
||||
+
|
||||
+oneOf:
|
||||
+ - required:
|
||||
+ - ports
|
||||
+ - required:
|
||||
+ - ethernet-ports
|
||||
+
|
||||
+required:
|
||||
+ - compatible
|
||||
+ - reg
|
||||
+
|
||||
+additionalProperties: true
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ #include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
+ mdio {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ external_phy_port1: ethernet-phy@0 {
|
||||
+ reg = <0>;
|
||||
+ };
|
||||
+
|
||||
+ external_phy_port2: ethernet-phy@1 {
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+
|
||||
+ external_phy_port3: ethernet-phy@2 {
|
||||
+ reg = <2>;
|
||||
+ };
|
||||
+
|
||||
+ external_phy_port4: ethernet-phy@3 {
|
||||
+ reg = <3>;
|
||||
+ };
|
||||
+
|
||||
+ external_phy_port5: ethernet-phy@4 {
|
||||
+ reg = <4>;
|
||||
+ };
|
||||
+
|
||||
+ switch@10 {
|
||||
+ compatible = "qca,qca8337";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
|
||||
+ reg = <0x10>;
|
||||
+
|
||||
+ ports {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ port@0 {
|
||||
+ reg = <0>;
|
||||
+ label = "cpu";
|
||||
+ ethernet = <&gmac1>;
|
||||
+ phy-mode = "rgmii";
|
||||
+
|
||||
+ fixed-link {
|
||||
+ speed = <1000>;
|
||||
+ full-duplex;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ port@1 {
|
||||
+ reg = <1>;
|
||||
+ label = "lan1";
|
||||
+ phy-handle = <&external_phy_port1>;
|
||||
+ };
|
||||
+
|
||||
+ port@2 {
|
||||
+ reg = <2>;
|
||||
+ label = "lan2";
|
||||
+ phy-handle = <&external_phy_port2>;
|
||||
+ };
|
||||
+
|
||||
+ port@3 {
|
||||
+ reg = <3>;
|
||||
+ label = "lan3";
|
||||
+ phy-handle = <&external_phy_port3>;
|
||||
+ };
|
||||
+
|
||||
+ port@4 {
|
||||
+ reg = <4>;
|
||||
+ label = "lan4";
|
||||
+ phy-handle = <&external_phy_port4>;
|
||||
+ };
|
||||
+
|
||||
+ port@5 {
|
||||
+ reg = <5>;
|
||||
+ label = "wan";
|
||||
+ phy-handle = <&external_phy_port5>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ - |
|
||||
+ #include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
+ mdio {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ switch@10 {
|
||||
+ compatible = "qca,qca8337";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
|
||||
+ reg = <0x10>;
|
||||
+
|
||||
+ ports {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ port@0 {
|
||||
+ reg = <0>;
|
||||
+ label = "cpu";
|
||||
+ ethernet = <&gmac1>;
|
||||
+ phy-mode = "rgmii";
|
||||
+
|
||||
+ fixed-link {
|
||||
+ speed = <1000>;
|
||||
+ full-duplex;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ port@1 {
|
||||
+ reg = <1>;
|
||||
+ label = "lan1";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&internal_phy_port1>;
|
||||
+ };
|
||||
+
|
||||
+ port@2 {
|
||||
+ reg = <2>;
|
||||
+ label = "lan2";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&internal_phy_port2>;
|
||||
+ };
|
||||
+
|
||||
+ port@3 {
|
||||
+ reg = <3>;
|
||||
+ label = "lan3";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&internal_phy_port3>;
|
||||
+ };
|
||||
+
|
||||
+ port@4 {
|
||||
+ reg = <4>;
|
||||
+ label = "lan4";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&internal_phy_port4>;
|
||||
+ };
|
||||
+
|
||||
+ port@5 {
|
||||
+ reg = <5>;
|
||||
+ label = "wan";
|
||||
+ phy-mode = "internal";
|
||||
+ phy-handle = <&internal_phy_port5>;
|
||||
+ };
|
||||
+
|
||||
+ port@6 {
|
||||
+ reg = <0>;
|
||||
+ label = "cpu";
|
||||
+ ethernet = <&gmac1>;
|
||||
+ phy-mode = "sgmii";
|
||||
+
|
||||
+ qca,sgmii-rxclk-falling-edge;
|
||||
+
|
||||
+ fixed-link {
|
||||
+ speed = <1000>;
|
||||
+ full-duplex;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ mdio {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ internal_phy_port1: ethernet-phy@0 {
|
||||
+ reg = <0>;
|
||||
+ };
|
||||
+
|
||||
+ internal_phy_port2: ethernet-phy@1 {
|
||||
+ reg = <1>;
|
||||
+ };
|
||||
+
|
||||
+ internal_phy_port3: ethernet-phy@2 {
|
||||
+ reg = <2>;
|
||||
+ };
|
||||
+
|
||||
+ internal_phy_port4: ethernet-phy@3 {
|
||||
+ reg = <3>;
|
||||
+ };
|
||||
+
|
||||
+ internal_phy_port5: ethernet-phy@4 {
|
||||
+ reg = <4>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
@ -0,0 +1,28 @@
|
||||
From 06dd34a628ae5b6a839b757e746de165d6789ca8 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Sun, 17 Oct 2021 16:56:46 +0200
|
||||
Subject: net: dsa: qca8k: fix delay applied to wrong cpu in parse_port_config
|
||||
|
||||
Fix delay settings applied to wrong cpu in parse_port_config. The delay
|
||||
values is set to the wrong index as the cpu_port_index is incremented
|
||||
too early. Start the cpu_port_index to -1 so the correct value is
|
||||
applied to address also the case with invalid phy mode and not available
|
||||
port.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -976,7 +976,7 @@ qca8k_setup_of_pws_reg(struct qca8k_priv
|
||||
static int
|
||||
qca8k_parse_port_config(struct qca8k_priv *priv)
|
||||
{
|
||||
- int port, cpu_port_index = 0, ret;
|
||||
+ int port, cpu_port_index = -1, ret;
|
||||
struct device_node *port_dn;
|
||||
phy_interface_t mode;
|
||||
struct dsa_port *dp;
|
||||
@ -0,0 +1,151 @@
|
||||
From 040e926f5813a5f4cc18dbff7c942d1e52f368f2 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Tue, 19 Oct 2021 02:08:50 +0200
|
||||
Subject: net: dsa: qca8k: tidy for loop in setup and add cpu port check
|
||||
|
||||
Tidy and organize qca8k setup function from multiple for loop.
|
||||
Change for loop in bridge leave/join to scan all port and skip cpu port.
|
||||
No functional change intended.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 74 +++++++++++++++++++++++++++++--------------------
|
||||
1 file changed, 44 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1122,28 +1122,34 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
dev_warn(priv->dev, "mib init failed");
|
||||
|
||||
- /* Enable QCA header mode on the cpu port */
|
||||
- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(cpu_port),
|
||||
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
|
||||
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
|
||||
- if (ret) {
|
||||
- dev_err(priv->dev, "failed enabling QCA header mode");
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- /* Disable forwarding by default on all ports */
|
||||
+ /* Initial setup of all ports */
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ /* Disable forwarding by default on all ports */
|
||||
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
QCA8K_PORT_LOOKUP_MEMBER, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
- }
|
||||
|
||||
- /* Disable MAC by default on all ports */
|
||||
- for (i = 1; i < QCA8K_NUM_PORTS; i++)
|
||||
- qca8k_port_set_status(priv, i, 0);
|
||||
+ /* Enable QCA header mode on all cpu ports */
|
||||
+ if (dsa_is_cpu_port(ds, i)) {
|
||||
+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i),
|
||||
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
|
||||
+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
|
||||
+ if (ret) {
|
||||
+ dev_err(priv->dev, "failed enabling QCA header mode");
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Disable MAC by default on all user ports */
|
||||
+ if (dsa_is_user_port(ds, i))
|
||||
+ qca8k_port_set_status(priv, i, 0);
|
||||
+ }
|
||||
|
||||
- /* Forward all unknown frames to CPU port for Linux processing */
|
||||
+ /* Forward all unknown frames to CPU port for Linux processing
|
||||
+ * Notice that in multi-cpu config only one port should be set
|
||||
+ * for igmp, unknown, multicast and broadcast packet
|
||||
+ */
|
||||
ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
|
||||
BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
|
||||
BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
|
||||
@@ -1152,11 +1158,13 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- /* Setup connection between CPU port & user ports */
|
||||
+ /* Setup connection between CPU port & user ports
|
||||
+ * Configure specific switch configuration for ports
|
||||
+ */
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
/* CPU port gets connected to all user ports of the switch */
|
||||
if (dsa_is_cpu_port(ds, i)) {
|
||||
- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
|
||||
+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1193,16 +1201,14 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
- }
|
||||
|
||||
- /* The port 5 of the qca8337 have some problem in flood condition. The
|
||||
- * original legacy driver had some specific buffer and priority settings
|
||||
- * for the different port suggested by the QCA switch team. Add this
|
||||
- * missing settings to improve switch stability under load condition.
|
||||
- * This problem is limited to qca8337 and other qca8k switch are not affected.
|
||||
- */
|
||||
- if (priv->switch_id == QCA8K_ID_QCA8337) {
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ /* The port 5 of the qca8337 have some problem in flood condition. The
|
||||
+ * original legacy driver had some specific buffer and priority settings
|
||||
+ * for the different port suggested by the QCA switch team. Add this
|
||||
+ * missing settings to improve switch stability under load condition.
|
||||
+ * This problem is limited to qca8337 and other qca8k switch are not affected.
|
||||
+ */
|
||||
+ if (priv->switch_id == QCA8K_ID_QCA8337) {
|
||||
switch (i) {
|
||||
/* The 2 CPU port and port 5 requires some different
|
||||
* priority than any other ports.
|
||||
@@ -1238,6 +1244,12 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
QCA8K_PORT_HOL_CTRL1_WRED_EN,
|
||||
mask);
|
||||
}
|
||||
+
|
||||
+ /* Set initial MTU for every port.
|
||||
+ * We have only have a general MTU setting. So track
|
||||
+ * every port and set the max across all port.
|
||||
+ */
|
||||
+ priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
|
||||
}
|
||||
|
||||
/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */
|
||||
@@ -1251,8 +1263,6 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
}
|
||||
|
||||
/* Setup our port MTUs to match power on defaults */
|
||||
- for (i = 0; i < QCA8K_NUM_PORTS; i++)
|
||||
- priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
|
||||
ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
|
||||
if (ret)
|
||||
dev_warn(priv->dev, "failed setting MTU settings");
|
||||
@@ -1728,7 +1738,9 @@ qca8k_port_bridge_join(struct dsa_switch
|
||||
cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
port_mask = BIT(cpu_port);
|
||||
|
||||
- for (i = 1; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ if (dsa_is_cpu_port(ds, i))
|
||||
+ continue;
|
||||
if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
continue;
|
||||
/* Add this port to the portvlan mask of the other ports
|
||||
@@ -1758,7 +1770,9 @@ qca8k_port_bridge_leave(struct dsa_switc
|
||||
|
||||
cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
|
||||
|
||||
- for (i = 1; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
+ if (dsa_is_cpu_port(ds, i))
|
||||
+ continue;
|
||||
if (dsa_to_port(ds, i)->bridge_dev != br)
|
||||
continue;
|
||||
/* Remove this port to the portvlan mask of the other ports
|
||||
@ -0,0 +1,47 @@
|
||||
From 5f15d392dcb4aa250a63d6f2c5adfc26c0aedc78 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Tue, 2 Nov 2021 19:30:41 +0100
|
||||
Subject: net: dsa: qca8k: make sure PAD0 MAC06 exchange is disabled
|
||||
|
||||
Some device set MAC06 exchange in the bootloader. This cause some
|
||||
problem as we don't support this strange mode and we just set the port6
|
||||
as the primary CPU port. With MAC06 exchange, PAD0 reg configure port6
|
||||
instead of port0. Add an extra check and explicitly disable MAC06 exchange
|
||||
to correctly configure the port PAD config.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Fixes: 3fcf734aa482 ("net: dsa: qca8k: add support for cpu port 6")
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 8 ++++++++
|
||||
drivers/net/dsa/qca8k.h | 1 +
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1109,6 +1109,14 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ /* Make sure MAC06 is disabled */
|
||||
+ ret = qca8k_reg_clear(priv, QCA8K_REG_PORT0_PAD_CTRL,
|
||||
+ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN);
|
||||
+ if (ret) {
|
||||
+ dev_err(priv->dev, "failed disabling MAC06 exchange");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
/* Enable CPU Port */
|
||||
ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -34,6 +34,7 @@
|
||||
#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8)
|
||||
#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8)
|
||||
#define QCA8K_REG_PORT0_PAD_CTRL 0x004
|
||||
+#define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31)
|
||||
#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19)
|
||||
#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18)
|
||||
#define QCA8K_REG_PORT5_PAD_CTRL 0x008
|
||||
@ -0,0 +1,48 @@
|
||||
From 3b00a07c2443745d62babfe08dbb2ad8e649526e Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Fri, 19 Nov 2021 03:03:49 +0100
|
||||
Subject: [PATCH] net: dsa: qca8k: fix internal delay applied to the wrong PAD
|
||||
config
|
||||
|
||||
With SGMII phy the internal delay is always applied to the PAD0 config.
|
||||
This is caused by the falling edge configuration that hardcode the reg
|
||||
to PAD0 (as the falling edge bits are present only in PAD0 reg)
|
||||
Move the delay configuration before the reg overwrite to correctly apply
|
||||
the delay.
|
||||
|
||||
Fixes: cef08115846e ("net: dsa: qca8k: set internal delay also for sgmii")
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1433,6 +1433,12 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
|
||||
qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val);
|
||||
|
||||
+ /* From original code is reported port instability as SGMII also
|
||||
+ * require delay set. Apply advised values here or take them from DT.
|
||||
+ */
|
||||
+ if (state->interface == PHY_INTERFACE_MODE_SGMII)
|
||||
+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg);
|
||||
+
|
||||
/* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and
|
||||
* falling edge is set writing in the PORT0 PAD reg
|
||||
*/
|
||||
@@ -1455,12 +1461,6 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||||
QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
|
||||
val);
|
||||
|
||||
- /* From original code is reported port instability as SGMII also
|
||||
- * require delay set. Apply advised values here or take them from DT.
|
||||
- */
|
||||
- if (state->interface == PHY_INTERFACE_MODE_SGMII)
|
||||
- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg);
|
||||
-
|
||||
break;
|
||||
default:
|
||||
dev_err(ds->dev, "xMII mode %s not supported for port %d\n",
|
||||
@ -0,0 +1,46 @@
|
||||
From 65258b9d8cde45689bdc86ca39b50f01f983733b Mon Sep 17 00:00:00 2001
|
||||
From: Robert Marko <robert.marko@sartura.hr>
|
||||
Date: Fri, 19 Nov 2021 03:03:50 +0100
|
||||
Subject: [PATCH] net: dsa: qca8k: fix MTU calculation
|
||||
|
||||
qca8k has a global MTU, so its tracking the MTU per port to make sure
|
||||
that the largest MTU gets applied.
|
||||
Since it uses the frame size instead of MTU the driver MTU change function
|
||||
will then add the size of Ethernet header and checksum on top of MTU.
|
||||
|
||||
The driver currently populates the per port MTU size as Ethernet frame
|
||||
length + checksum which equals 1518.
|
||||
|
||||
The issue is that then MTU change function will go through all of the
|
||||
ports, find the largest MTU and apply the Ethernet header + checksum on
|
||||
top of it again, so for a desired MTU of 1500 you will end up with 1536.
|
||||
|
||||
This is obviously incorrect, so to correct it populate the per port struct
|
||||
MTU with just the MTU and not include the Ethernet header + checksum size
|
||||
as those will be added by the MTU change function.
|
||||
|
||||
Fixes: f58d2598cf70 ("net: dsa: qca8k: implement the port MTU callbacks")
|
||||
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1256,8 +1256,12 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
/* Set initial MTU for every port.
|
||||
* We have only have a general MTU setting. So track
|
||||
* every port and set the max across all port.
|
||||
+ * Set per port MTU to 1500 as the MTU change function
|
||||
+ * will add the overhead and if its set to 1518 then it
|
||||
+ * will apply the overhead again and we will end up with
|
||||
+ * MTU of 1536 instead of 1518
|
||||
*/
|
||||
- priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN;
|
||||
+ priv->port_mtu[i] = ETH_DATA_LEN;
|
||||
}
|
||||
|
||||
/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */
|
||||
@ -0,0 +1,29 @@
|
||||
From b9133f3ef5a2659730cf47a74bd0a9259f1cf8ff Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:40 +0100
|
||||
Subject: net: dsa: qca8k: remove redundant check in parse_port_config
|
||||
|
||||
The very next check for port 0 and 6 already makes sure we don't go out
|
||||
of bounds with the ports_config delay table.
|
||||
Remove the redundant check.
|
||||
|
||||
Reported-by: kernel test robot <lkp@intel.com>
|
||||
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -983,7 +983,7 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
u32 delay;
|
||||
|
||||
/* We have 2 CPU port. Check them */
|
||||
- for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) {
|
||||
+ for (port = 0; port < QCA8K_NUM_PORTS; port++) {
|
||||
/* Skip every other port */
|
||||
if (port != 0 && port != 6)
|
||||
continue;
|
||||
@ -0,0 +1,507 @@
|
||||
From 90ae68bfc2ffcb54a4ba4f64edbeb84a80cbb57c Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:41 +0100
|
||||
Subject: net: dsa: qca8k: convert to GENMASK/FIELD_PREP/FIELD_GET
|
||||
|
||||
Convert and try to standardize bit fields using
|
||||
GENMASK/FIELD_PREP/FIELD_GET macros. Rework some logic to support the
|
||||
standard macro and tidy things up. No functional change intended.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 98 +++++++++++++++----------------
|
||||
drivers/net/dsa/qca8k.h | 153 ++++++++++++++++++++++++++----------------------
|
||||
2 files changed, 130 insertions(+), 121 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/netdevice.h>
|
||||
+#include <linux/bitfield.h>
|
||||
#include <net/dsa.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/of_mdio.h>
|
||||
@@ -319,18 +320,18 @@ qca8k_fdb_read(struct qca8k_priv *priv,
|
||||
}
|
||||
|
||||
/* vid - 83:72 */
|
||||
- fdb->vid = (reg[2] >> QCA8K_ATU_VID_S) & QCA8K_ATU_VID_M;
|
||||
+ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]);
|
||||
/* aging - 67:64 */
|
||||
- fdb->aging = reg[2] & QCA8K_ATU_STATUS_M;
|
||||
+ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]);
|
||||
/* portmask - 54:48 */
|
||||
- fdb->port_mask = (reg[1] >> QCA8K_ATU_PORT_S) & QCA8K_ATU_PORT_M;
|
||||
+ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]);
|
||||
/* mac - 47:0 */
|
||||
- fdb->mac[0] = (reg[1] >> QCA8K_ATU_ADDR0_S) & 0xff;
|
||||
- fdb->mac[1] = reg[1] & 0xff;
|
||||
- fdb->mac[2] = (reg[0] >> QCA8K_ATU_ADDR2_S) & 0xff;
|
||||
- fdb->mac[3] = (reg[0] >> QCA8K_ATU_ADDR3_S) & 0xff;
|
||||
- fdb->mac[4] = (reg[0] >> QCA8K_ATU_ADDR4_S) & 0xff;
|
||||
- fdb->mac[5] = reg[0] & 0xff;
|
||||
+ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]);
|
||||
+ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]);
|
||||
+ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]);
|
||||
+ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]);
|
||||
+ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]);
|
||||
+ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -343,18 +344,18 @@ qca8k_fdb_write(struct qca8k_priv *priv,
|
||||
int i;
|
||||
|
||||
/* vid - 83:72 */
|
||||
- reg[2] = (vid & QCA8K_ATU_VID_M) << QCA8K_ATU_VID_S;
|
||||
+ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid);
|
||||
/* aging - 67:64 */
|
||||
- reg[2] |= aging & QCA8K_ATU_STATUS_M;
|
||||
+ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging);
|
||||
/* portmask - 54:48 */
|
||||
- reg[1] = (port_mask & QCA8K_ATU_PORT_M) << QCA8K_ATU_PORT_S;
|
||||
+ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask);
|
||||
/* mac - 47:0 */
|
||||
- reg[1] |= mac[0] << QCA8K_ATU_ADDR0_S;
|
||||
- reg[1] |= mac[1];
|
||||
- reg[0] |= mac[2] << QCA8K_ATU_ADDR2_S;
|
||||
- reg[0] |= mac[3] << QCA8K_ATU_ADDR3_S;
|
||||
- reg[0] |= mac[4] << QCA8K_ATU_ADDR4_S;
|
||||
- reg[0] |= mac[5];
|
||||
+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]);
|
||||
+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]);
|
||||
+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]);
|
||||
+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]);
|
||||
+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]);
|
||||
+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]);
|
||||
|
||||
/* load the array into the ARL table */
|
||||
for (i = 0; i < 3; i++)
|
||||
@@ -372,7 +373,7 @@ qca8k_fdb_access(struct qca8k_priv *priv
|
||||
reg |= cmd;
|
||||
if (port >= 0) {
|
||||
reg |= QCA8K_ATU_FUNC_PORT_EN;
|
||||
- reg |= (port & QCA8K_ATU_FUNC_PORT_M) << QCA8K_ATU_FUNC_PORT_S;
|
||||
+ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port);
|
||||
}
|
||||
|
||||
/* Write the function register triggering the table access */
|
||||
@@ -454,7 +455,7 @@ qca8k_vlan_access(struct qca8k_priv *pri
|
||||
/* Set the command and VLAN index */
|
||||
reg = QCA8K_VTU_FUNC1_BUSY;
|
||||
reg |= cmd;
|
||||
- reg |= vid << QCA8K_VTU_FUNC1_VID_S;
|
||||
+ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid);
|
||||
|
||||
/* Write the function register triggering the table access */
|
||||
ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg);
|
||||
@@ -500,13 +501,11 @@ qca8k_vlan_add(struct qca8k_priv *priv,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN;
|
||||
- reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port));
|
||||
+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
|
||||
if (untagged)
|
||||
- reg |= QCA8K_VTU_FUNC0_EG_MODE_UNTAG <<
|
||||
- QCA8K_VTU_FUNC0_EG_MODE_S(port);
|
||||
+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port);
|
||||
else
|
||||
- reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG <<
|
||||
- QCA8K_VTU_FUNC0_EG_MODE_S(port);
|
||||
+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port);
|
||||
|
||||
ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg);
|
||||
if (ret)
|
||||
@@ -534,15 +533,13 @@ qca8k_vlan_del(struct qca8k_priv *priv,
|
||||
ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
- reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port));
|
||||
- reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT <<
|
||||
- QCA8K_VTU_FUNC0_EG_MODE_S(port);
|
||||
+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port);
|
||||
+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port);
|
||||
|
||||
/* Check if we're the last member to be removed */
|
||||
del = true;
|
||||
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
|
||||
- mask = QCA8K_VTU_FUNC0_EG_MODE_NOT;
|
||||
- mask <<= QCA8K_VTU_FUNC0_EG_MODE_S(i);
|
||||
+ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i);
|
||||
|
||||
if ((reg & mask) != mask) {
|
||||
del = false;
|
||||
@@ -1014,7 +1011,7 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
mode == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
delay = 1;
|
||||
|
||||
- if (delay > QCA8K_MAX_DELAY) {
|
||||
+ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) {
|
||||
dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
|
||||
delay = 3;
|
||||
}
|
||||
@@ -1030,7 +1027,7 @@ qca8k_parse_port_config(struct qca8k_pri
|
||||
mode == PHY_INTERFACE_MODE_RGMII_RXID)
|
||||
delay = 2;
|
||||
|
||||
- if (delay > QCA8K_MAX_DELAY) {
|
||||
+ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) {
|
||||
dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
|
||||
delay = 3;
|
||||
}
|
||||
@@ -1141,8 +1138,8 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
/* Enable QCA header mode on all cpu ports */
|
||||
if (dsa_is_cpu_port(ds, i)) {
|
||||
ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i),
|
||||
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
|
||||
- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
|
||||
+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) |
|
||||
+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL));
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed enabling QCA header mode");
|
||||
return ret;
|
||||
@@ -1159,10 +1156,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
* for igmp, unknown, multicast and broadcast packet
|
||||
*/
|
||||
ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
|
||||
- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S |
|
||||
- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S |
|
||||
- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S |
|
||||
- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S);
|
||||
+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) |
|
||||
+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) |
|
||||
+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) |
|
||||
+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port)));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1180,8 +1177,6 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
|
||||
/* Individual user ports get connected to CPU port only */
|
||||
if (dsa_is_user_port(ds, i)) {
|
||||
- int shift = 16 * (i % 2);
|
||||
-
|
||||
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
QCA8K_PORT_LOOKUP_MEMBER,
|
||||
BIT(cpu_port));
|
||||
@@ -1198,8 +1193,8 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
* default egress vid
|
||||
*/
|
||||
ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i),
|
||||
- 0xfff << shift,
|
||||
- QCA8K_PORT_VID_DEF << shift);
|
||||
+ QCA8K_EGREES_VLAN_PORT_MASK(i),
|
||||
+ QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1246,7 +1241,7 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
|
||||
QCA8K_PORT_HOL_CTRL1_WRED_EN;
|
||||
qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i),
|
||||
- QCA8K_PORT_HOL_CTRL1_ING_BUF |
|
||||
+ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK |
|
||||
QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
|
||||
QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
|
||||
QCA8K_PORT_HOL_CTRL1_WRED_EN,
|
||||
@@ -1269,8 +1264,8 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) |
|
||||
QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496);
|
||||
qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH,
|
||||
- QCA8K_GLOBAL_FC_GOL_XON_THRES_S |
|
||||
- QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S,
|
||||
+ QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK |
|
||||
+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK,
|
||||
mask);
|
||||
}
|
||||
|
||||
@@ -1916,11 +1911,11 @@ qca8k_port_vlan_filtering(struct dsa_swi
|
||||
|
||||
if (vlan_filtering) {
|
||||
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_VLAN_MODE,
|
||||
+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
|
||||
QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE);
|
||||
} else {
|
||||
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
- QCA8K_PORT_LOOKUP_VLAN_MODE,
|
||||
+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK,
|
||||
QCA8K_PORT_LOOKUP_VLAN_MODE_NONE);
|
||||
}
|
||||
|
||||
@@ -1944,10 +1939,9 @@ qca8k_port_vlan_add(struct dsa_switch *d
|
||||
}
|
||||
|
||||
if (pvid) {
|
||||
- int shift = 16 * (port % 2);
|
||||
-
|
||||
ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
|
||||
- 0xfff << shift, vlan->vid << shift);
|
||||
+ QCA8K_EGREES_VLAN_PORT_MASK(port),
|
||||
+ QCA8K_EGREES_VLAN_PORT(port, vlan->vid));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -2041,7 +2035,7 @@ static int qca8k_read_switch_id(struct q
|
||||
if (ret < 0)
|
||||
return -ENODEV;
|
||||
|
||||
- id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK);
|
||||
+ id = QCA8K_MASK_CTRL_DEVICE_ID(val);
|
||||
if (id != data->id) {
|
||||
dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id);
|
||||
return -ENODEV;
|
||||
@@ -2050,7 +2044,7 @@ static int qca8k_read_switch_id(struct q
|
||||
priv->switch_id = id;
|
||||
|
||||
/* Save revision to communicate to the internal PHY driver */
|
||||
- priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK);
|
||||
+ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -30,9 +30,9 @@
|
||||
/* Global control registers */
|
||||
#define QCA8K_REG_MASK_CTRL 0x000
|
||||
#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0)
|
||||
-#define QCA8K_MASK_CTRL_REV_ID(x) ((x) >> 0)
|
||||
+#define QCA8K_MASK_CTRL_REV_ID(x) FIELD_GET(QCA8K_MASK_CTRL_REV_ID_MASK, x)
|
||||
#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8)
|
||||
-#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8)
|
||||
+#define QCA8K_MASK_CTRL_DEVICE_ID(x) FIELD_GET(QCA8K_MASK_CTRL_DEVICE_ID_MASK, x)
|
||||
#define QCA8K_REG_PORT0_PAD_CTRL 0x004
|
||||
#define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31)
|
||||
#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19)
|
||||
@@ -41,12 +41,11 @@
|
||||
#define QCA8K_REG_PORT6_PAD_CTRL 0x00c
|
||||
#define QCA8K_PORT_PAD_RGMII_EN BIT(26)
|
||||
#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22)
|
||||
-#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22)
|
||||
+#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, x)
|
||||
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20)
|
||||
-#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20)
|
||||
+#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, x)
|
||||
#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25)
|
||||
#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24)
|
||||
-#define QCA8K_MAX_DELAY 3
|
||||
#define QCA8K_PORT_PAD_SGMII_EN BIT(7)
|
||||
#define QCA8K_REG_PWS 0x010
|
||||
#define QCA8K_PWS_POWER_ON_SEL BIT(31)
|
||||
@@ -68,10 +67,12 @@
|
||||
#define QCA8K_MDIO_MASTER_READ BIT(27)
|
||||
#define QCA8K_MDIO_MASTER_WRITE 0
|
||||
#define QCA8K_MDIO_MASTER_SUP_PRE BIT(26)
|
||||
-#define QCA8K_MDIO_MASTER_PHY_ADDR(x) ((x) << 21)
|
||||
-#define QCA8K_MDIO_MASTER_REG_ADDR(x) ((x) << 16)
|
||||
-#define QCA8K_MDIO_MASTER_DATA(x) (x)
|
||||
+#define QCA8K_MDIO_MASTER_PHY_ADDR_MASK GENMASK(25, 21)
|
||||
+#define QCA8K_MDIO_MASTER_PHY_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_PHY_ADDR_MASK, x)
|
||||
+#define QCA8K_MDIO_MASTER_REG_ADDR_MASK GENMASK(20, 16)
|
||||
+#define QCA8K_MDIO_MASTER_REG_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_REG_ADDR_MASK, x)
|
||||
#define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0)
|
||||
+#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x)
|
||||
#define QCA8K_MDIO_MASTER_MAX_PORTS 5
|
||||
#define QCA8K_MDIO_MASTER_MAX_REG 32
|
||||
#define QCA8K_GOL_MAC_ADDR0 0x60
|
||||
@@ -93,9 +94,7 @@
|
||||
#define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12)
|
||||
#define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4))
|
||||
#define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2)
|
||||
-#define QCA8K_PORT_HDR_CTRL_RX_S 2
|
||||
#define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0)
|
||||
-#define QCA8K_PORT_HDR_CTRL_TX_S 0
|
||||
#define QCA8K_PORT_HDR_CTRL_ALL 2
|
||||
#define QCA8K_PORT_HDR_CTRL_MGMT 1
|
||||
#define QCA8K_PORT_HDR_CTRL_NONE 0
|
||||
@@ -105,10 +104,11 @@
|
||||
#define QCA8K_SGMII_EN_TX BIT(3)
|
||||
#define QCA8K_SGMII_EN_SD BIT(4)
|
||||
#define QCA8K_SGMII_CLK125M_DELAY BIT(7)
|
||||
-#define QCA8K_SGMII_MODE_CTRL_MASK (BIT(22) | BIT(23))
|
||||
-#define QCA8K_SGMII_MODE_CTRL_BASEX (0 << 22)
|
||||
-#define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22)
|
||||
-#define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22)
|
||||
+#define QCA8K_SGMII_MODE_CTRL_MASK GENMASK(23, 22)
|
||||
+#define QCA8K_SGMII_MODE_CTRL(x) FIELD_PREP(QCA8K_SGMII_MODE_CTRL_MASK, x)
|
||||
+#define QCA8K_SGMII_MODE_CTRL_BASEX QCA8K_SGMII_MODE_CTRL(0x0)
|
||||
+#define QCA8K_SGMII_MODE_CTRL_PHY QCA8K_SGMII_MODE_CTRL(0x1)
|
||||
+#define QCA8K_SGMII_MODE_CTRL_MAC QCA8K_SGMII_MODE_CTRL(0x2)
|
||||
|
||||
/* MAC_PWR_SEL registers */
|
||||
#define QCA8K_REG_MAC_PWR_SEL 0x0e4
|
||||
@@ -121,100 +121,115 @@
|
||||
|
||||
/* ACL registers */
|
||||
#define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8))
|
||||
-#define QCA8K_PORT_VLAN_CVID(x) (x << 16)
|
||||
-#define QCA8K_PORT_VLAN_SVID(x) x
|
||||
+#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16)
|
||||
+#define QCA8K_PORT_VLAN_CVID(x) FIELD_PREP(QCA8K_PORT_VLAN_CVID_MASK, x)
|
||||
+#define QCA8K_PORT_VLAN_SVID_MASK GENMASK(11, 0)
|
||||
+#define QCA8K_PORT_VLAN_SVID(x) FIELD_PREP(QCA8K_PORT_VLAN_SVID_MASK, x)
|
||||
#define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8))
|
||||
#define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470
|
||||
#define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474
|
||||
|
||||
/* Lookup registers */
|
||||
#define QCA8K_REG_ATU_DATA0 0x600
|
||||
-#define QCA8K_ATU_ADDR2_S 24
|
||||
-#define QCA8K_ATU_ADDR3_S 16
|
||||
-#define QCA8K_ATU_ADDR4_S 8
|
||||
+#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24)
|
||||
+#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16)
|
||||
+#define QCA8K_ATU_ADDR4_MASK GENMASK(15, 8)
|
||||
+#define QCA8K_ATU_ADDR5_MASK GENMASK(7, 0)
|
||||
#define QCA8K_REG_ATU_DATA1 0x604
|
||||
-#define QCA8K_ATU_PORT_M 0x7f
|
||||
-#define QCA8K_ATU_PORT_S 16
|
||||
-#define QCA8K_ATU_ADDR0_S 8
|
||||
+#define QCA8K_ATU_PORT_MASK GENMASK(22, 16)
|
||||
+#define QCA8K_ATU_ADDR0_MASK GENMASK(15, 8)
|
||||
+#define QCA8K_ATU_ADDR1_MASK GENMASK(7, 0)
|
||||
#define QCA8K_REG_ATU_DATA2 0x608
|
||||
-#define QCA8K_ATU_VID_M 0xfff
|
||||
-#define QCA8K_ATU_VID_S 8
|
||||
-#define QCA8K_ATU_STATUS_M 0xf
|
||||
+#define QCA8K_ATU_VID_MASK GENMASK(19, 8)
|
||||
+#define QCA8K_ATU_STATUS_MASK GENMASK(3, 0)
|
||||
#define QCA8K_ATU_STATUS_STATIC 0xf
|
||||
#define QCA8K_REG_ATU_FUNC 0x60c
|
||||
#define QCA8K_ATU_FUNC_BUSY BIT(31)
|
||||
#define QCA8K_ATU_FUNC_PORT_EN BIT(14)
|
||||
#define QCA8K_ATU_FUNC_MULTI_EN BIT(13)
|
||||
#define QCA8K_ATU_FUNC_FULL BIT(12)
|
||||
-#define QCA8K_ATU_FUNC_PORT_M 0xf
|
||||
-#define QCA8K_ATU_FUNC_PORT_S 8
|
||||
+#define QCA8K_ATU_FUNC_PORT_MASK GENMASK(11, 8)
|
||||
#define QCA8K_REG_VTU_FUNC0 0x610
|
||||
#define QCA8K_VTU_FUNC0_VALID BIT(20)
|
||||
#define QCA8K_VTU_FUNC0_IVL_EN BIT(19)
|
||||
-#define QCA8K_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2)
|
||||
-#define QCA8K_VTU_FUNC0_EG_MODE_MASK 3
|
||||
-#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD 0
|
||||
-#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG 1
|
||||
-#define QCA8K_VTU_FUNC0_EG_MODE_TAG 2
|
||||
-#define QCA8K_VTU_FUNC0_EG_MODE_NOT 3
|
||||
+/* QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(17, 4)
|
||||
+ * It does contain VLAN_MODE for each port [5:4] for port0,
|
||||
+ * [7:6] for port1 ... [17:16] for port6. Use virtual port
|
||||
+ * define to handle this.
|
||||
+ */
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i) (4 + (_i) * 2)
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(1, 0)
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(_i) (GENMASK(1, 0) << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i))
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x0)
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNMOD(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNMOD << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i))
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x1)
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNTAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i))
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_TAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x2)
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_TAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i))
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_NOT FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x3)
|
||||
+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(_i) (QCA8K_VTU_FUNC0_EG_MODE_NOT << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i))
|
||||
#define QCA8K_REG_VTU_FUNC1 0x614
|
||||
#define QCA8K_VTU_FUNC1_BUSY BIT(31)
|
||||
-#define QCA8K_VTU_FUNC1_VID_S 16
|
||||
+#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16)
|
||||
#define QCA8K_VTU_FUNC1_FULL BIT(4)
|
||||
#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620
|
||||
#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10)
|
||||
#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624
|
||||
-#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S 24
|
||||
-#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_S 16
|
||||
-#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_S 8
|
||||
-#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_S 0
|
||||
+#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24)
|
||||
+#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16)
|
||||
+#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8)
|
||||
+#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0)
|
||||
#define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc)
|
||||
#define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0)
|
||||
-#define QCA8K_PORT_LOOKUP_VLAN_MODE GENMASK(9, 8)
|
||||
-#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE (0 << 8)
|
||||
-#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK (1 << 8)
|
||||
-#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK (2 << 8)
|
||||
-#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE (3 << 8)
|
||||
+#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8)
|
||||
+#define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x)
|
||||
+#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE QCA8K_PORT_LOOKUP_VLAN_MODE(0x0)
|
||||
+#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK QCA8K_PORT_LOOKUP_VLAN_MODE(0x1)
|
||||
+#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK QCA8K_PORT_LOOKUP_VLAN_MODE(0x2)
|
||||
+#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE QCA8K_PORT_LOOKUP_VLAN_MODE(0x3)
|
||||
#define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16)
|
||||
-#define QCA8K_PORT_LOOKUP_STATE_DISABLED (0 << 16)
|
||||
-#define QCA8K_PORT_LOOKUP_STATE_BLOCKING (1 << 16)
|
||||
-#define QCA8K_PORT_LOOKUP_STATE_LISTENING (2 << 16)
|
||||
-#define QCA8K_PORT_LOOKUP_STATE_LEARNING (3 << 16)
|
||||
-#define QCA8K_PORT_LOOKUP_STATE_FORWARD (4 << 16)
|
||||
-#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16)
|
||||
+#define QCA8K_PORT_LOOKUP_STATE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_STATE_MASK, x)
|
||||
+#define QCA8K_PORT_LOOKUP_STATE_DISABLED QCA8K_PORT_LOOKUP_STATE(0x0)
|
||||
+#define QCA8K_PORT_LOOKUP_STATE_BLOCKING QCA8K_PORT_LOOKUP_STATE(0x1)
|
||||
+#define QCA8K_PORT_LOOKUP_STATE_LISTENING QCA8K_PORT_LOOKUP_STATE(0x2)
|
||||
+#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3)
|
||||
+#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4)
|
||||
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
|
||||
|
||||
#define QCA8K_REG_GLOBAL_FC_THRESH 0x800
|
||||
-#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) ((x) << 16)
|
||||
-#define QCA8K_GLOBAL_FC_GOL_XON_THRES_S GENMASK(24, 16)
|
||||
-#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) ((x) << 0)
|
||||
-#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S GENMASK(8, 0)
|
||||
+#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16)
|
||||
+#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x)
|
||||
+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK GENMASK(8, 0)
|
||||
+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, x)
|
||||
|
||||
#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF GENMASK(7, 4)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) ((x) << 4)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF GENMASK(11, 8)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) ((x) << 8)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF GENMASK(15, 12)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) ((x) << 12)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF GENMASK(19, 16)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) ((x) << 16)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF GENMASK(23, 20)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) ((x) << 20)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF GENMASK(29, 24)
|
||||
-#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) ((x) << 24)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK GENMASK(3, 0)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK, x)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK GENMASK(7, 4)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK, x)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK GENMASK(11, 8)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK, x)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK GENMASK(15, 12)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK, x)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK GENMASK(19, 16)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK, x)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK GENMASK(23, 20)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK, x)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK GENMASK(29, 24)
|
||||
+#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK, x)
|
||||
|
||||
#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8)
|
||||
-#define QCA8K_PORT_HOL_CTRL1_ING_BUF GENMASK(3, 0)
|
||||
-#define QCA8K_PORT_HOL_CTRL1_ING(x) ((x) << 0)
|
||||
+#define QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK GENMASK(3, 0)
|
||||
+#define QCA8K_PORT_HOL_CTRL1_ING(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK, x)
|
||||
#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6)
|
||||
#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7)
|
||||
#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8)
|
||||
#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16)
|
||||
|
||||
/* Pkt edit registers */
|
||||
+#define QCA8K_EGREES_VLAN_PORT_SHIFT(_i) (16 * ((_i) % 2))
|
||||
+#define QCA8K_EGREES_VLAN_PORT_MASK(_i) (GENMASK(11, 0) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i))
|
||||
+#define QCA8K_EGREES_VLAN_PORT(_i, x) ((x) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i))
|
||||
#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2)))
|
||||
|
||||
/* L3 registers */
|
||||
@ -0,0 +1,25 @@
|
||||
From 994c28b6f971fa5db8ae977daea37eee87d93d51 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:42 +0100
|
||||
Subject: net: dsa: qca8k: remove extra mutex_init in qca8k_setup
|
||||
|
||||
Mutex is already init in sw_probe. Remove the extra init in qca8k_setup.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1086,8 +1086,6 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- mutex_init(&priv->reg_mutex);
|
||||
-
|
||||
/* Start by setting up the register mapping */
|
||||
priv->regmap = devm_regmap_init(ds->dev, NULL, priv,
|
||||
&qca8k_regmap_config);
|
||||
@ -0,0 +1,46 @@
|
||||
From 36b8af12f424e7a7f60a935c60a0fd4aa0822378 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:43 +0100
|
||||
Subject: net: dsa: qca8k: move regmap init in probe and set it mandatory
|
||||
|
||||
In preparation for regmap conversion, move regmap init in the probe
|
||||
function and make it mandatory as any read/write/rmw operation will be
|
||||
converted to regmap API.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 14 ++++++++------
|
||||
1 file changed, 8 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1086,12 +1086,6 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- /* Start by setting up the register mapping */
|
||||
- priv->regmap = devm_regmap_init(ds->dev, NULL, priv,
|
||||
- &qca8k_regmap_config);
|
||||
- if (IS_ERR(priv->regmap))
|
||||
- dev_warn(priv->dev, "regmap initialization failed");
|
||||
-
|
||||
ret = qca8k_setup_mdio_bus(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -2077,6 +2071,14 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
gpiod_set_value_cansleep(priv->reset_gpio, 0);
|
||||
}
|
||||
|
||||
+ /* Start by setting up the register mapping */
|
||||
+ priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv,
|
||||
+ &qca8k_regmap_config);
|
||||
+ if (IS_ERR(priv->regmap)) {
|
||||
+ dev_err(priv->dev, "regmap initialization failed");
|
||||
+ return PTR_ERR(priv->regmap);
|
||||
+ }
|
||||
+
|
||||
/* Check the detected switch id */
|
||||
ret = qca8k_read_switch_id(priv);
|
||||
if (ret)
|
||||
@ -0,0 +1,249 @@
|
||||
From 8b5f3f29a81a71934d004e21a1292c1148b05926 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:44 +0100
|
||||
Subject: net: dsa: qca8k: initial conversion to regmap helper
|
||||
|
||||
Convert any qca8k set/clear/pool to regmap helper and add
|
||||
missing config to regmap_config struct.
|
||||
Read/write/rmw operation are reworked to use the regmap helper
|
||||
internally to keep the delta of this patch low. These additional
|
||||
function will then be dropped when the code split will be proposed.
|
||||
|
||||
Ipq40xx SoC have the internal switch based on the qca8k regmap but use
|
||||
mmio for read/write/rmw operation instead of mdio.
|
||||
In preparation for the support of this internal switch, convert the
|
||||
driver to regmap API to later split the driver to common and specific
|
||||
code. The overhead introduced by the use of regamp API is marginal as the
|
||||
internal mdio will bypass it by using its direct access and regmap will be
|
||||
used only by configuration functions or fdb access.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 107 +++++++++++++++++++++---------------------------
|
||||
1 file changed, 47 insertions(+), 60 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/phy.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/bitfield.h>
|
||||
+#include <linux/regmap.h>
|
||||
#include <net/dsa.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/of_mdio.h>
|
||||
@@ -152,6 +153,25 @@ qca8k_set_page(struct mii_bus *bus, u16
|
||||
static int
|
||||
qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val)
|
||||
{
|
||||
+ return regmap_read(priv->regmap, reg, val);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
+{
|
||||
+ return regmap_write(priv->regmap, reg, val);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
|
||||
+{
|
||||
+ return regmap_update_bits(priv->regmap, reg, mask, write_val);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||
struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
int ret;
|
||||
@@ -172,8 +192,9 @@ exit:
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
+qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)
|
||||
{
|
||||
+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||
struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
int ret;
|
||||
@@ -194,8 +215,9 @@ exit:
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
|
||||
+qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val)
|
||||
{
|
||||
+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||
struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
u32 val;
|
||||
@@ -223,34 +245,6 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int
|
||||
-qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
-{
|
||||
- return qca8k_rmw(priv, reg, 0, val);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
-{
|
||||
- return qca8k_rmw(priv, reg, val, 0);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||
-
|
||||
- return qca8k_read(priv, reg, val);
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
-qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val)
|
||||
-{
|
||||
- struct qca8k_priv *priv = (struct qca8k_priv *)ctx;
|
||||
-
|
||||
- return qca8k_write(priv, reg, val);
|
||||
-}
|
||||
-
|
||||
static const struct regmap_range qca8k_readable_ranges[] = {
|
||||
regmap_reg_range(0x0000, 0x00e4), /* Global control */
|
||||
regmap_reg_range(0x0100, 0x0168), /* EEE control */
|
||||
@@ -282,26 +276,19 @@ static struct regmap_config qca8k_regmap
|
||||
.max_register = 0x16ac, /* end MIB - Port6 range */
|
||||
.reg_read = qca8k_regmap_read,
|
||||
.reg_write = qca8k_regmap_write,
|
||||
+ .reg_update_bits = qca8k_regmap_update_bits,
|
||||
.rd_table = &qca8k_readable_table,
|
||||
+ .disable_locking = true, /* Locking is handled by qca8k read/write */
|
||||
+ .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */
|
||||
};
|
||||
|
||||
static int
|
||||
qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask)
|
||||
{
|
||||
- int ret, ret1;
|
||||
u32 val;
|
||||
|
||||
- ret = read_poll_timeout(qca8k_read, ret1, !(val & mask),
|
||||
- 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
|
||||
- priv, reg, &val);
|
||||
-
|
||||
- /* Check if qca8k_read has failed for a different reason
|
||||
- * before returning -ETIMEDOUT
|
||||
- */
|
||||
- if (ret < 0 && ret1 < 0)
|
||||
- return ret1;
|
||||
-
|
||||
- return ret;
|
||||
+ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0,
|
||||
+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -568,7 +555,7 @@ qca8k_mib_init(struct qca8k_priv *priv)
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
- ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
|
||||
+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -576,7 +563,7 @@ qca8k_mib_init(struct qca8k_priv *priv)
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
- ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
|
||||
+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -597,9 +584,9 @@ qca8k_port_set_status(struct qca8k_priv
|
||||
mask |= QCA8K_PORT_STATUS_LINK_AUTO;
|
||||
|
||||
if (enable)
|
||||
- qca8k_reg_set(priv, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
+ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
else
|
||||
- qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
+ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
}
|
||||
|
||||
static u32
|
||||
@@ -861,8 +848,8 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||||
* a dt-overlay and driver reload changed the configuration
|
||||
*/
|
||||
|
||||
- return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL,
|
||||
- QCA8K_MDIO_MASTER_EN);
|
||||
+ return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ QCA8K_MDIO_MASTER_EN);
|
||||
}
|
||||
|
||||
/* Check if the devicetree declare the port:phy mapping */
|
||||
@@ -1099,16 +1086,16 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
return ret;
|
||||
|
||||
/* Make sure MAC06 is disabled */
|
||||
- ret = qca8k_reg_clear(priv, QCA8K_REG_PORT0_PAD_CTRL,
|
||||
- QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN);
|
||||
+ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL,
|
||||
+ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed disabling MAC06 exchange");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable CPU Port */
|
||||
- ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||||
+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed enabling CPU port");
|
||||
return ret;
|
||||
@@ -1176,8 +1163,8 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
return ret;
|
||||
|
||||
/* Enable ARP Auto-learning by default */
|
||||
- ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- QCA8K_PORT_LOOKUP_LEARN);
|
||||
+ ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
+ QCA8K_PORT_LOOKUP_LEARN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1745,9 +1732,9 @@ qca8k_port_bridge_join(struct dsa_switch
|
||||
/* Add this port to the portvlan mask of the other ports
|
||||
* in the bridge
|
||||
*/
|
||||
- ret = qca8k_reg_set(priv,
|
||||
- QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- BIT(port));
|
||||
+ ret = regmap_set_bits(priv->regmap,
|
||||
+ QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
+ BIT(port));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (i != port)
|
||||
@@ -1777,9 +1764,9 @@ qca8k_port_bridge_leave(struct dsa_switc
|
||||
/* Remove this port to the portvlan mask of the other ports
|
||||
* in the bridge
|
||||
*/
|
||||
- qca8k_reg_clear(priv,
|
||||
- QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
- BIT(port));
|
||||
+ regmap_clear_bits(priv->regmap,
|
||||
+ QCA8K_PORT_LOOKUP_CTRL(i),
|
||||
+ BIT(port));
|
||||
}
|
||||
|
||||
/* Set the cpu port to be the only one in the portvlan mask of
|
||||
@ -0,0 +1,120 @@
|
||||
From c126f118b330ccf0db0dda4a4bd6c729865a205f Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:45 +0100
|
||||
Subject: net: dsa: qca8k: add additional MIB counter and make it dynamic
|
||||
|
||||
We are currently missing 2 additionals MIB counter present in QCA833x
|
||||
switch.
|
||||
QC832x switch have 39 MIB counter and QCA833X have 41 MIB counter.
|
||||
Add the additional MIB counter and rework the MIB function to print the
|
||||
correct supported counter from the match_data struct.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 23 ++++++++++++++++++++---
|
||||
drivers/net/dsa/qca8k.h | 4 ++++
|
||||
2 files changed, 24 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -70,6 +70,8 @@ static const struct qca8k_mib_desc ar832
|
||||
MIB_DESC(1, 0x9c, "TxExcDefer"),
|
||||
MIB_DESC(1, 0xa0, "TxDefer"),
|
||||
MIB_DESC(1, 0xa4, "TxLateCol"),
|
||||
+ MIB_DESC(1, 0xa8, "RXUnicast"),
|
||||
+ MIB_DESC(1, 0xac, "TXUnicast"),
|
||||
};
|
||||
|
||||
/* The 32bit switch registers are accessed indirectly. To achieve this we need
|
||||
@@ -1605,12 +1607,16 @@ qca8k_phylink_mac_link_up(struct dsa_swi
|
||||
static void
|
||||
qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data)
|
||||
{
|
||||
+ const struct qca8k_match_data *match_data;
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
int i;
|
||||
|
||||
if (stringset != ETH_SS_STATS)
|
||||
return;
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++)
|
||||
+ match_data = of_device_get_match_data(priv->dev);
|
||||
+
|
||||
+ for (i = 0; i < match_data->mib_count; i++)
|
||||
strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name,
|
||||
ETH_GSTRING_LEN);
|
||||
}
|
||||
@@ -1620,12 +1626,15 @@ qca8k_get_ethtool_stats(struct dsa_switc
|
||||
uint64_t *data)
|
||||
{
|
||||
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
|
||||
+ const struct qca8k_match_data *match_data;
|
||||
const struct qca8k_mib_desc *mib;
|
||||
u32 reg, i, val;
|
||||
u32 hi = 0;
|
||||
int ret;
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) {
|
||||
+ match_data = of_device_get_match_data(priv->dev);
|
||||
+
|
||||
+ for (i = 0; i < match_data->mib_count; i++) {
|
||||
mib = &ar8327_mib[i];
|
||||
reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset;
|
||||
|
||||
@@ -1648,10 +1657,15 @@ qca8k_get_ethtool_stats(struct dsa_switc
|
||||
static int
|
||||
qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset)
|
||||
{
|
||||
+ const struct qca8k_match_data *match_data;
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
if (sset != ETH_SS_STATS)
|
||||
return 0;
|
||||
|
||||
- return ARRAY_SIZE(ar8327_mib);
|
||||
+ match_data = of_device_get_match_data(priv->dev);
|
||||
+
|
||||
+ return match_data->mib_count;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -2154,14 +2168,17 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,
|
||||
static const struct qca8k_match_data qca8327 = {
|
||||
.id = QCA8K_ID_QCA8327,
|
||||
.reduced_package = true,
|
||||
+ .mib_count = QCA8K_QCA832X_MIB_COUNT,
|
||||
};
|
||||
|
||||
static const struct qca8k_match_data qca8328 = {
|
||||
.id = QCA8K_ID_QCA8327,
|
||||
+ .mib_count = QCA8K_QCA832X_MIB_COUNT,
|
||||
};
|
||||
|
||||
static const struct qca8k_match_data qca833x = {
|
||||
.id = QCA8K_ID_QCA8337,
|
||||
+ .mib_count = QCA8K_QCA833X_MIB_COUNT,
|
||||
};
|
||||
|
||||
static const struct of_device_id qca8k_of_match[] = {
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -21,6 +21,9 @@
|
||||
#define PHY_ID_QCA8337 0x004dd036
|
||||
#define QCA8K_ID_QCA8337 0x13
|
||||
|
||||
+#define QCA8K_QCA832X_MIB_COUNT 39
|
||||
+#define QCA8K_QCA833X_MIB_COUNT 41
|
||||
+
|
||||
#define QCA8K_BUSY_WAIT_TIMEOUT 2000
|
||||
|
||||
#define QCA8K_NUM_FDB_RECORDS 2048
|
||||
@@ -279,6 +282,7 @@ struct ar8xxx_port_status {
|
||||
struct qca8k_match_data {
|
||||
u8 id;
|
||||
bool reduced_package;
|
||||
+ u8 mib_count;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -0,0 +1,53 @@
|
||||
From 4592538bfb0d5d3c3c8a1d7071724d081412ac91 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:46 +0100
|
||||
Subject: net: dsa: qca8k: add support for port fast aging
|
||||
|
||||
The switch supports fast aging by flushing any rule in the ARL
|
||||
table for a specific port.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 11 +++++++++++
|
||||
drivers/net/dsa/qca8k.h | 1 +
|
||||
2 files changed, 12 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1790,6 +1790,16 @@ qca8k_port_bridge_leave(struct dsa_switc
|
||||
QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port));
|
||||
}
|
||||
|
||||
+static void
|
||||
+qca8k_port_fast_age(struct dsa_switch *ds, int port)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port);
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+}
|
||||
+
|
||||
static int
|
||||
qca8k_port_enable(struct dsa_switch *ds, int port,
|
||||
struct phy_device *phy)
|
||||
@@ -1998,6 +2008,7 @@ static const struct dsa_switch_ops qca8k
|
||||
.port_stp_state_set = qca8k_port_stp_state_set,
|
||||
.port_bridge_join = qca8k_port_bridge_join,
|
||||
.port_bridge_leave = qca8k_port_bridge_leave,
|
||||
+ .port_fast_age = qca8k_port_fast_age,
|
||||
.port_fdb_add = qca8k_port_fdb_add,
|
||||
.port_fdb_del = qca8k_port_fdb_del,
|
||||
.port_fdb_dump = qca8k_port_fdb_dump,
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -262,6 +262,7 @@ enum qca8k_fdb_cmd {
|
||||
QCA8K_FDB_FLUSH = 1,
|
||||
QCA8K_FDB_LOAD = 2,
|
||||
QCA8K_FDB_PURGE = 3,
|
||||
+ QCA8K_FDB_FLUSH_PORT = 5,
|
||||
QCA8K_FDB_NEXT = 6,
|
||||
QCA8K_FDB_SEARCH = 7,
|
||||
};
|
||||
@ -0,0 +1,78 @@
|
||||
From 6a3bdc5209f45d2af83aa92433ab6e5cf2297aa4 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:47 +0100
|
||||
Subject: net: dsa: qca8k: add set_ageing_time support
|
||||
|
||||
qca8k support setting ageing time in step of 7s. Add support for it and
|
||||
set the max value accepted of 7645m.
|
||||
Documentation talks about support for 10000m but that values doesn't
|
||||
make sense as the value doesn't match the max value in the reg.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 25 +++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 3 +++
|
||||
2 files changed, 28 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1261,6 +1261,10 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
/* We don't have interrupts for link changes, so we need to poll */
|
||||
ds->pcs_poll = true;
|
||||
|
||||
+ /* Set min a max ageing value supported */
|
||||
+ ds->ageing_time_min = 7000;
|
||||
+ ds->ageing_time_max = 458745000;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1801,6 +1805,26 @@ qca8k_port_fast_age(struct dsa_switch *d
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ unsigned int secs = msecs / 1000;
|
||||
+ u32 val;
|
||||
+
|
||||
+ /* AGE_TIME reg is set in 7s step */
|
||||
+ val = secs / 7;
|
||||
+
|
||||
+ /* Handle case with 0 as val to NOT disable
|
||||
+ * learning
|
||||
+ */
|
||||
+ if (!val)
|
||||
+ val = 1;
|
||||
+
|
||||
+ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK,
|
||||
+ QCA8K_ATU_AGE_TIME(val));
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_port_enable(struct dsa_switch *ds, int port,
|
||||
struct phy_device *phy)
|
||||
{
|
||||
@@ -1999,6 +2023,7 @@ static const struct dsa_switch_ops qca8k
|
||||
.get_strings = qca8k_get_strings,
|
||||
.get_ethtool_stats = qca8k_get_ethtool_stats,
|
||||
.get_sset_count = qca8k_get_sset_count,
|
||||
+ .set_ageing_time = qca8k_set_ageing_time,
|
||||
.get_mac_eee = qca8k_get_mac_eee,
|
||||
.set_mac_eee = qca8k_set_mac_eee,
|
||||
.port_enable = qca8k_port_enable,
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -175,6 +175,9 @@
|
||||
#define QCA8K_VTU_FUNC1_BUSY BIT(31)
|
||||
#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16)
|
||||
#define QCA8K_VTU_FUNC1_FULL BIT(4)
|
||||
+#define QCA8K_REG_ATU_CTRL 0x618
|
||||
+#define QCA8K_ATU_AGE_TIME_MASK GENMASK(15, 0)
|
||||
+#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x))
|
||||
#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620
|
||||
#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10)
|
||||
#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624
|
||||
@ -0,0 +1,142 @@
|
||||
From ba8f870dfa635113ce6e8095a5eb1835ecde2e9e Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 22 Nov 2021 16:23:48 +0100
|
||||
Subject: net: dsa: qca8k: add support for mdb_add/del
|
||||
|
||||
Add support for mdb add/del function. The ARL table is used to insert
|
||||
the rule. The rule will be searched, deleted and reinserted with the
|
||||
port mask updated. The function will check if the rule has to be updated
|
||||
or insert directly with no deletion of the old rule.
|
||||
If every port is removed from the port mask, the rule is removed.
|
||||
The rule is set STATIC in the ARL table (aka it doesn't age) to not be
|
||||
flushed by fast age function.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 99 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -436,6 +436,81 @@ qca8k_fdb_flush(struct qca8k_priv *priv)
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask,
|
||||
+ const u8 *mac, u16 vid)
|
||||
+{
|
||||
+ struct qca8k_fdb fdb = { 0 };
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+
|
||||
+ qca8k_fdb_write(priv, vid, 0, mac, 0);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
+ ret = qca8k_fdb_read(priv, &fdb);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
+ /* Rule exist. Delete first */
|
||||
+ if (!fdb.aging) {
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ /* Add port to fdb portmask */
|
||||
+ fdb.port_mask |= port_mask;
|
||||
+
|
||||
+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
|
||||
+
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask,
|
||||
+ const u8 *mac, u16 vid)
|
||||
+{
|
||||
+ struct qca8k_fdb fdb = { 0 };
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+
|
||||
+ qca8k_fdb_write(priv, vid, 0, mac, 0);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1);
|
||||
+ if (ret < 0)
|
||||
+ goto exit;
|
||||
+
|
||||
+ /* Rule doesn't exist. Why delete? */
|
||||
+ if (!fdb.aging) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1);
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+
|
||||
+ /* Only port in the rule is this port. Don't re insert */
|
||||
+ if (fdb.port_mask == port_mask)
|
||||
+ goto exit;
|
||||
+
|
||||
+ /* Remove port from port mask */
|
||||
+ fdb.port_mask &= ~port_mask;
|
||||
+
|
||||
+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging);
|
||||
+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1);
|
||||
+
|
||||
+exit:
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid)
|
||||
{
|
||||
u32 reg;
|
||||
@@ -1930,6 +2005,28 @@ qca8k_port_fdb_dump(struct dsa_switch *d
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_port_mdb_add(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_mdb *mdb)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ const u8 *addr = mdb->addr;
|
||||
+ u16 vid = mdb->vid;
|
||||
+
|
||||
+ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_port_mdb_del(struct dsa_switch *ds, int port,
|
||||
+ const struct switchdev_obj_port_mdb *mdb)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ const u8 *addr = mdb->addr;
|
||||
+ u16 vid = mdb->vid;
|
||||
+
|
||||
+ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
@@ -2037,6 +2134,8 @@ static const struct dsa_switch_ops qca8k
|
||||
.port_fdb_add = qca8k_port_fdb_add,
|
||||
.port_fdb_del = qca8k_port_fdb_del,
|
||||
.port_fdb_dump = qca8k_port_fdb_dump,
|
||||
+ .port_mdb_add = qca8k_port_mdb_add,
|
||||
+ .port_mdb_del = qca8k_port_mdb_del,
|
||||
.port_vlan_filtering = qca8k_port_vlan_filtering,
|
||||
.port_vlan_add = qca8k_port_vlan_add,
|
||||
.port_vlan_del = qca8k_port_vlan_del,
|
||||
@ -0,0 +1,155 @@
|
||||
From 2c1bdbc7e7560d7de754cad277d968d56bb1899e Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Tue, 23 Nov 2021 03:59:10 +0100
|
||||
Subject: net: dsa: qca8k: add support for mirror mode
|
||||
|
||||
The switch supports mirror mode. Only one port can set as mirror port and
|
||||
every other port can set to both ingress and egress mode. The mirror
|
||||
port is disabled and reverted to normal operation once every port is
|
||||
removed from sending packet to it.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 4 +++
|
||||
2 files changed, 99 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -2027,6 +2027,99 @@ qca8k_port_mdb_del(struct dsa_switch *ds
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_mall_mirror_tc_entry *mirror,
|
||||
+ bool ingress)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int monitor_port, ret;
|
||||
+ u32 reg, val;
|
||||
+
|
||||
+ /* Check for existent entry */
|
||||
+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
|
||||
+ return -EEXIST;
|
||||
+
|
||||
+ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* QCA83xx can have only one port set to mirror mode.
|
||||
+ * Check that the correct port is requested and return error otherwise.
|
||||
+ * When no mirror port is set, the values is set to 0xF
|
||||
+ */
|
||||
+ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
+ if (monitor_port != 0xF && monitor_port != mirror->to_local_port)
|
||||
+ return -EEXIST;
|
||||
+
|
||||
+ /* Set the monitor port */
|
||||
+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM,
|
||||
+ mirror->to_local_port);
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (ingress) {
|
||||
+ reg = QCA8K_PORT_LOOKUP_CTRL(port);
|
||||
+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
|
||||
+ } else {
|
||||
+ reg = QCA8K_REG_PORT_HOL_CTRL1(port);
|
||||
+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
|
||||
+ }
|
||||
+
|
||||
+ ret = regmap_update_bits(priv->regmap, reg, val, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Track mirror port for tx and rx to decide when the
|
||||
+ * mirror port has to be disabled.
|
||||
+ */
|
||||
+ if (ingress)
|
||||
+ priv->mirror_rx |= BIT(port);
|
||||
+ else
|
||||
+ priv->mirror_tx |= BIT(port);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+qca8k_port_mirror_del(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_mall_mirror_tc_entry *mirror)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ u32 reg, val;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (mirror->ingress) {
|
||||
+ reg = QCA8K_PORT_LOOKUP_CTRL(port);
|
||||
+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN;
|
||||
+ } else {
|
||||
+ reg = QCA8K_REG_PORT_HOL_CTRL1(port);
|
||||
+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN;
|
||||
+ }
|
||||
+
|
||||
+ ret = regmap_clear_bits(priv->regmap, reg, val);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+
|
||||
+ if (mirror->ingress)
|
||||
+ priv->mirror_rx &= ~BIT(port);
|
||||
+ else
|
||||
+ priv->mirror_tx &= ~BIT(port);
|
||||
+
|
||||
+ /* No port set to send packet to mirror port. Disable mirror port */
|
||||
+ if (!priv->mirror_rx && !priv->mirror_tx) {
|
||||
+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF);
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
|
||||
+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+ }
|
||||
+err:
|
||||
+ dev_err(priv->dev, "Failed to del mirror port from %d", port);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
@@ -2136,6 +2229,8 @@ static const struct dsa_switch_ops qca8k
|
||||
.port_fdb_dump = qca8k_port_fdb_dump,
|
||||
.port_mdb_add = qca8k_port_mdb_add,
|
||||
.port_mdb_del = qca8k_port_mdb_del,
|
||||
+ .port_mirror_add = qca8k_port_mirror_add,
|
||||
+ .port_mirror_del = qca8k_port_mirror_del,
|
||||
.port_vlan_filtering = qca8k_port_vlan_filtering,
|
||||
.port_vlan_add = qca8k_port_vlan_add,
|
||||
.port_vlan_del = qca8k_port_vlan_del,
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -180,6 +180,7 @@
|
||||
#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x))
|
||||
#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620
|
||||
#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10)
|
||||
+#define QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM GENMASK(7, 4)
|
||||
#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624
|
||||
#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24)
|
||||
#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16)
|
||||
@@ -201,6 +202,7 @@
|
||||
#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3)
|
||||
#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4)
|
||||
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
|
||||
+#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
|
||||
|
||||
#define QCA8K_REG_GLOBAL_FC_THRESH 0x800
|
||||
#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16)
|
||||
@@ -305,6 +307,8 @@ struct qca8k_ports_config {
|
||||
struct qca8k_priv {
|
||||
u8 switch_id;
|
||||
u8 switch_revision;
|
||||
+ u8 mirror_rx;
|
||||
+ u8 mirror_tx;
|
||||
bool legacy_phy_port_mapping;
|
||||
struct qca8k_ports_config ports_config;
|
||||
struct regmap *regmap;
|
||||
@ -0,0 +1,288 @@
|
||||
From def975307c01191b6f0170048c3724b0ed3348af Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Tue, 23 Nov 2021 03:59:11 +0100
|
||||
Subject: net: dsa: qca8k: add LAG support
|
||||
|
||||
Add LAG support to this switch. In Documentation this is described as
|
||||
trunk mode. A max of 4 LAGs are supported and each can support up to 4
|
||||
port. The current tx mode supported is Hash mode with both L2 and L2+3
|
||||
mode.
|
||||
When no port are present in the trunk, the trunk is disabled in the
|
||||
switch.
|
||||
When a port is disconnected, the traffic is redirected to the other
|
||||
available port.
|
||||
The hash mode is global and each LAG require to have the same hash mode
|
||||
set. To change the hash mode when multiple LAG are configured, it's
|
||||
required to remove each LAG and set the desired hash mode to the last.
|
||||
An error is printed when it's asked to set a not supported hadh mode.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 33 +++++++++
|
||||
2 files changed, 210 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -1340,6 +1340,9 @@ qca8k_setup(struct dsa_switch *ds)
|
||||
ds->ageing_time_min = 7000;
|
||||
ds->ageing_time_max = 458745000;
|
||||
|
||||
+ /* Set max number of LAGs supported */
|
||||
+ ds->num_lag_ids = QCA8K_NUM_LAGS;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2207,6 +2210,178 @@ qca8k_get_tag_protocol(struct dsa_switch
|
||||
return DSA_TAG_PROTO_QCA;
|
||||
}
|
||||
|
||||
+static bool
|
||||
+qca8k_lag_can_offload(struct dsa_switch *ds,
|
||||
+ struct net_device *lag,
|
||||
+ struct netdev_lag_upper_info *info)
|
||||
+{
|
||||
+ struct dsa_port *dp;
|
||||
+ int id, members = 0;
|
||||
+
|
||||
+ id = dsa_lag_id(ds->dst, lag);
|
||||
+ if (id < 0 || id >= ds->num_lag_ids)
|
||||
+ return false;
|
||||
+
|
||||
+ dsa_lag_foreach_port(dp, ds->dst, lag)
|
||||
+ /* Includes the port joining the LAG */
|
||||
+ members++;
|
||||
+
|
||||
+ if (members > QCA8K_NUM_PORTS_FOR_LAG)
|
||||
+ return false;
|
||||
+
|
||||
+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
|
||||
+ return false;
|
||||
+
|
||||
+ if (info->hash_type != NETDEV_LAG_HASH_L2 ||
|
||||
+ info->hash_type != NETDEV_LAG_HASH_L23)
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_lag_setup_hash(struct dsa_switch *ds,
|
||||
+ struct net_device *lag,
|
||||
+ struct netdev_lag_upper_info *info)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ bool unique_lag = true;
|
||||
+ int i, id;
|
||||
+ u32 hash;
|
||||
+
|
||||
+ id = dsa_lag_id(ds->dst, lag);
|
||||
+
|
||||
+ switch (info->hash_type) {
|
||||
+ case NETDEV_LAG_HASH_L23:
|
||||
+ hash |= QCA8K_TRUNK_HASH_SIP_EN;
|
||||
+ hash |= QCA8K_TRUNK_HASH_DIP_EN;
|
||||
+ fallthrough;
|
||||
+ case NETDEV_LAG_HASH_L2:
|
||||
+ hash |= QCA8K_TRUNK_HASH_SA_EN;
|
||||
+ hash |= QCA8K_TRUNK_HASH_DA_EN;
|
||||
+ break;
|
||||
+ default: /* We should NEVER reach this */
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ /* Check if we are the unique configured LAG */
|
||||
+ dsa_lags_foreach_id(i, ds->dst)
|
||||
+ if (i != id && dsa_lag_dev(ds->dst, i)) {
|
||||
+ unique_lag = false;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Hash Mode is global. Make sure the same Hash Mode
|
||||
+ * is set to all the 4 possible lag.
|
||||
+ * If we are the unique LAG we can set whatever hash
|
||||
+ * mode we want.
|
||||
+ * To change hash mode it's needed to remove all LAG
|
||||
+ * and change the mode with the latest.
|
||||
+ */
|
||||
+ if (unique_lag) {
|
||||
+ priv->lag_hash_mode = hash;
|
||||
+ } else if (priv->lag_hash_mode != hash) {
|
||||
+ netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n");
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL,
|
||||
+ QCA8K_TRUNK_HASH_MASK, hash);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *lag, bool delete)
|
||||
+{
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int ret, id, i;
|
||||
+ u32 val;
|
||||
+
|
||||
+ id = dsa_lag_id(ds->dst, lag);
|
||||
+
|
||||
+ /* Read current port member */
|
||||
+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Shift val to the correct trunk */
|
||||
+ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id);
|
||||
+ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK;
|
||||
+ if (delete)
|
||||
+ val &= ~BIT(port);
|
||||
+ else
|
||||
+ val |= BIT(port);
|
||||
+
|
||||
+ /* Update port member. With empty portmap disable trunk */
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0,
|
||||
+ QCA8K_REG_GOL_TRUNK_MEMBER(id) |
|
||||
+ QCA8K_REG_GOL_TRUNK_EN(id),
|
||||
+ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) |
|
||||
+ val << QCA8K_REG_GOL_TRUNK_SHIFT(id));
|
||||
+
|
||||
+ /* Search empty member if adding or port on deleting */
|
||||
+ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) {
|
||||
+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i);
|
||||
+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK;
|
||||
+
|
||||
+ if (delete) {
|
||||
+ /* If port flagged to be disabled assume this member is
|
||||
+ * empty
|
||||
+ */
|
||||
+ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK)
|
||||
+ continue;
|
||||
+
|
||||
+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK;
|
||||
+ if (val != port)
|
||||
+ continue;
|
||||
+ } else {
|
||||
+ /* If port flagged to be enabled assume this member is
|
||||
+ * already set
|
||||
+ */
|
||||
+ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK)
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* We have found the member to add/remove */
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Set port in the correct port mask or disable port if in delete mode */
|
||||
+ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id),
|
||||
+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) |
|
||||
+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i),
|
||||
+ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) |
|
||||
+ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i));
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_port_lag_join(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *lag,
|
||||
+ struct netdev_lag_upper_info *info)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!qca8k_lag_can_offload(ds, lag, info))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ ret = qca8k_lag_setup_hash(ds, lag, info);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return qca8k_lag_refresh_portmap(ds, port, lag, false);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_port_lag_leave(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *lag)
|
||||
+{
|
||||
+ return qca8k_lag_refresh_portmap(ds, port, lag, true);
|
||||
+}
|
||||
+
|
||||
static const struct dsa_switch_ops qca8k_switch_ops = {
|
||||
.get_tag_protocol = qca8k_get_tag_protocol,
|
||||
.setup = qca8k_setup,
|
||||
@@ -2240,6 +2415,8 @@ static const struct dsa_switch_ops qca8k
|
||||
.phylink_mac_link_down = qca8k_phylink_mac_link_down,
|
||||
.phylink_mac_link_up = qca8k_phylink_mac_link_up,
|
||||
.get_phy_flags = qca8k_get_phy_flags,
|
||||
+ .port_lag_join = qca8k_port_lag_join,
|
||||
+ .port_lag_leave = qca8k_port_lag_leave,
|
||||
};
|
||||
|
||||
static int qca8k_read_switch_id(struct qca8k_priv *priv)
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -15,6 +15,8 @@
|
||||
#define QCA8K_NUM_PORTS 7
|
||||
#define QCA8K_NUM_CPU_PORTS 2
|
||||
#define QCA8K_MAX_MTU 9000
|
||||
+#define QCA8K_NUM_LAGS 4
|
||||
+#define QCA8K_NUM_PORTS_FOR_LAG 4
|
||||
|
||||
#define PHY_ID_QCA8327 0x004dd034
|
||||
#define QCA8K_ID_QCA8327 0x12
|
||||
@@ -122,6 +124,14 @@
|
||||
#define QCA8K_REG_EEE_CTRL 0x100
|
||||
#define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2)
|
||||
|
||||
+/* TRUNK_HASH_EN registers */
|
||||
+#define QCA8K_TRUNK_HASH_EN_CTRL 0x270
|
||||
+#define QCA8K_TRUNK_HASH_SIP_EN BIT(3)
|
||||
+#define QCA8K_TRUNK_HASH_DIP_EN BIT(2)
|
||||
+#define QCA8K_TRUNK_HASH_SA_EN BIT(1)
|
||||
+#define QCA8K_TRUNK_HASH_DA_EN BIT(0)
|
||||
+#define QCA8K_TRUNK_HASH_MASK GENMASK(3, 0)
|
||||
+
|
||||
/* ACL registers */
|
||||
#define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8))
|
||||
#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16)
|
||||
@@ -204,6 +214,28 @@
|
||||
#define QCA8K_PORT_LOOKUP_LEARN BIT(20)
|
||||
#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
|
||||
|
||||
+#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700
|
||||
+/* 4 max trunk first
|
||||
+ * first 6 bit for member bitmap
|
||||
+ * 7th bit is to enable trunk port
|
||||
+ */
|
||||
+#define QCA8K_REG_GOL_TRUNK_SHIFT(_i) ((_i) * 8)
|
||||
+#define QCA8K_REG_GOL_TRUNK_EN_MASK BIT(7)
|
||||
+#define QCA8K_REG_GOL_TRUNK_EN(_i) (QCA8K_REG_GOL_TRUNK_EN_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i))
|
||||
+#define QCA8K_REG_GOL_TRUNK_MEMBER_MASK GENMASK(6, 0)
|
||||
+#define QCA8K_REG_GOL_TRUNK_MEMBER(_i) (QCA8K_REG_GOL_TRUNK_MEMBER_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i))
|
||||
+/* 0x704 for TRUNK 0-1 --- 0x708 for TRUNK 2-3 */
|
||||
+#define QCA8K_REG_GOL_TRUNK_CTRL(_i) (0x704 + (((_i) / 2) * 4))
|
||||
+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK GENMASK(3, 0)
|
||||
+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK BIT(3)
|
||||
+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK GENMASK(2, 0)
|
||||
+#define QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i) (((_i) / 2) * 16)
|
||||
+#define QCA8K_REG_GOL_MEM_ID_SHIFT(_i) ((_i) * 4)
|
||||
+/* Complex shift: FIRST shift for port THEN shift for trunk */
|
||||
+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j) (QCA8K_REG_GOL_MEM_ID_SHIFT(_j) + QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i))
|
||||
+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j))
|
||||
+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j))
|
||||
+
|
||||
#define QCA8K_REG_GLOBAL_FC_THRESH 0x800
|
||||
#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16)
|
||||
#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x)
|
||||
@@ -309,6 +341,7 @@ struct qca8k_priv {
|
||||
u8 switch_revision;
|
||||
u8 mirror_rx;
|
||||
u8 mirror_tx;
|
||||
+ u8 lag_hash_mode;
|
||||
bool legacy_phy_port_mapping;
|
||||
struct qca8k_ports_config ports_config;
|
||||
struct regmap *regmap;
|
||||
@ -0,0 +1,40 @@
|
||||
From 0898ca67b86e14207d4feb3f3fea8b87cec5aab1 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Tue, 23 Nov 2021 16:44:46 +0100
|
||||
Subject: net: dsa: qca8k: fix warning in LAG feature
|
||||
|
||||
Fix warning reported by bot.
|
||||
Make sure hash is init to 0 and fix wrong logic for hash_type in
|
||||
qca8k_lag_can_offload.
|
||||
|
||||
Reported-by: kernel test robot <lkp@intel.com>
|
||||
Fixes: def975307c01 ("net: dsa: qca8k: add LAG support")
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Link: https://lore.kernel.org/r/20211123154446.31019-1-ansuelsmth@gmail.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -2232,7 +2232,7 @@ qca8k_lag_can_offload(struct dsa_switch
|
||||
if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH)
|
||||
return false;
|
||||
|
||||
- if (info->hash_type != NETDEV_LAG_HASH_L2 ||
|
||||
+ if (info->hash_type != NETDEV_LAG_HASH_L2 &&
|
||||
info->hash_type != NETDEV_LAG_HASH_L23)
|
||||
return false;
|
||||
|
||||
@@ -2246,8 +2246,8 @@ qca8k_lag_setup_hash(struct dsa_switch *
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
bool unique_lag = true;
|
||||
+ u32 hash = 0;
|
||||
int i, id;
|
||||
- u32 hash;
|
||||
|
||||
id = dsa_lag_id(ds->dst, lag);
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
From 904e112ad431492b34f235f59738e8312802bbf9 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Thu, 6 Jan 2022 01:11:12 +0200
|
||||
Subject: [PATCH 1/6] net: dsa: reorder PHY initialization with MTU setup in
|
||||
slave.c
|
||||
|
||||
In dsa_slave_create() there are 2 sections that take rtnl_lock():
|
||||
MTU change and netdev registration. They are separated by PHY
|
||||
initialization.
|
||||
|
||||
There isn't any strict ordering requirement except for the fact that
|
||||
netdev registration should be last. Therefore, we can perform the MTU
|
||||
change a bit later, after the PHY setup. A future change will then be
|
||||
able to merge the two rtnl_lock sections into one.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/slave.c | 14 +++++++-------
|
||||
1 file changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1986,13 +1986,6 @@ int dsa_slave_create(struct dsa_port *po
|
||||
port->slave = slave_dev;
|
||||
dsa_slave_setup_tagger(slave_dev);
|
||||
|
||||
- rtnl_lock();
|
||||
- ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN);
|
||||
- rtnl_unlock();
|
||||
- if (ret && ret != -EOPNOTSUPP)
|
||||
- dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n",
|
||||
- ret, ETH_DATA_LEN, port->index);
|
||||
-
|
||||
netif_carrier_off(slave_dev);
|
||||
|
||||
ret = dsa_slave_phy_setup(slave_dev);
|
||||
@@ -2004,6 +1997,13 @@ int dsa_slave_create(struct dsa_port *po
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
+ ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN);
|
||||
+ rtnl_unlock();
|
||||
+ if (ret && ret != -EOPNOTSUPP)
|
||||
+ dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n",
|
||||
+ ret, ETH_DATA_LEN, port->index);
|
||||
+
|
||||
+ rtnl_lock();
|
||||
|
||||
ret = register_netdevice(slave_dev);
|
||||
if (ret) {
|
||||
@ -0,0 +1,34 @@
|
||||
From e31dbd3b6aba585231cd84a87adeb22e7c6a8c19 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Thu, 6 Jan 2022 01:11:13 +0200
|
||||
Subject: [PATCH 2/6] net: dsa: merge rtnl_lock sections in dsa_slave_create
|
||||
|
||||
Currently dsa_slave_create() has two sequences of rtnl_lock/rtnl_unlock
|
||||
in a row. Remove the rtnl_unlock() and rtnl_lock() in between, such that
|
||||
the operation can execute slighly faster.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/slave.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -1997,14 +1997,12 @@ int dsa_slave_create(struct dsa_port *po
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
+
|
||||
ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN);
|
||||
- rtnl_unlock();
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n",
|
||||
ret, ETH_DATA_LEN, port->index);
|
||||
|
||||
- rtnl_lock();
|
||||
-
|
||||
ret = register_netdevice(slave_dev);
|
||||
if (ret) {
|
||||
netdev_err(master, "error %d registering interface %s\n",
|
||||
@ -0,0 +1,91 @@
|
||||
From a1ff94c2973c43bc1e2677ac63ebb15b1d1ff846 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Thu, 6 Jan 2022 01:11:14 +0200
|
||||
Subject: [PATCH 3/6] net: dsa: stop updating master MTU from master.c
|
||||
|
||||
At present there are two paths for changing the MTU of the DSA master.
|
||||
|
||||
The first is:
|
||||
|
||||
dsa_tree_setup
|
||||
-> dsa_tree_setup_ports
|
||||
-> dsa_port_setup
|
||||
-> dsa_slave_create
|
||||
-> dsa_slave_change_mtu
|
||||
-> dev_set_mtu(master)
|
||||
|
||||
The second is:
|
||||
|
||||
dsa_tree_setup
|
||||
-> dsa_tree_setup_master
|
||||
-> dsa_master_setup
|
||||
-> dev_set_mtu(dev)
|
||||
|
||||
So the dev_set_mtu() call from dsa_master_setup() has been effectively
|
||||
superseded by the dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN) that is
|
||||
done from dsa_slave_create() for each user port. The later function also
|
||||
updates the master MTU according to the largest user port MTU from the
|
||||
tree. Therefore, updating the master MTU through a separate code path
|
||||
isn't needed.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/master.c | 25 +------------------------
|
||||
1 file changed, 1 insertion(+), 24 deletions(-)
|
||||
|
||||
--- a/net/dsa/master.c
|
||||
+++ b/net/dsa/master.c
|
||||
@@ -330,28 +330,13 @@ static const struct attribute_group dsa_
|
||||
.attrs = dsa_slave_attrs,
|
||||
};
|
||||
|
||||
-static void dsa_master_reset_mtu(struct net_device *dev)
|
||||
-{
|
||||
- int err;
|
||||
-
|
||||
- rtnl_lock();
|
||||
- err = dev_set_mtu(dev, ETH_DATA_LEN);
|
||||
- if (err)
|
||||
- netdev_dbg(dev,
|
||||
- "Unable to reset MTU to exclude DSA overheads\n");
|
||||
- rtnl_unlock();
|
||||
-}
|
||||
-
|
||||
static struct lock_class_key dsa_master_addr_list_lock_key;
|
||||
|
||||
int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
|
||||
{
|
||||
- const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops;
|
||||
struct dsa_switch *ds = cpu_dp->ds;
|
||||
struct device_link *consumer_link;
|
||||
- int mtu, ret;
|
||||
-
|
||||
- mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops);
|
||||
+ int ret;
|
||||
|
||||
/* The DSA master must use SET_NETDEV_DEV for this to work. */
|
||||
consumer_link = device_link_add(ds->dev, dev->dev.parent,
|
||||
@@ -361,13 +346,6 @@ int dsa_master_setup(struct net_device *
|
||||
"Failed to create a device link to DSA switch %s\n",
|
||||
dev_name(ds->dev));
|
||||
|
||||
- rtnl_lock();
|
||||
- ret = dev_set_mtu(dev, mtu);
|
||||
- rtnl_unlock();
|
||||
- if (ret)
|
||||
- netdev_warn(dev, "error %d setting MTU to %d to include DSA overhead\n",
|
||||
- ret, mtu);
|
||||
-
|
||||
/* If we use a tagging format that doesn't have an ethertype
|
||||
* field, make sure that all packets from this point on get
|
||||
* sent to the tag format's receive function.
|
||||
@@ -405,7 +383,6 @@ void dsa_master_teardown(struct net_devi
|
||||
sysfs_remove_group(&dev->dev.kobj, &dsa_group);
|
||||
dsa_netdev_ops_set(dev, NULL);
|
||||
dsa_master_ethtool_teardown(dev);
|
||||
- dsa_master_reset_mtu(dev);
|
||||
dsa_master_set_promiscuity(dev, -1);
|
||||
|
||||
dev->dsa_ptr = NULL;
|
||||
@ -0,0 +1,78 @@
|
||||
From c146f9bc195a9dc3ad7fd000a14540e7c9df952d Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Thu, 6 Jan 2022 01:11:15 +0200
|
||||
Subject: [PATCH 4/6] net: dsa: hold rtnl_mutex when calling
|
||||
dsa_master_{setup,teardown}
|
||||
|
||||
DSA needs to simulate master tracking events when a binding is first
|
||||
with a DSA master established and torn down, in order to give drivers
|
||||
the simplifying guarantee that ->master_state_change calls are made
|
||||
only when the master's readiness state to pass traffic changes.
|
||||
master_state_change() provide a operational bool that DSA driver can use
|
||||
to understand if DSA master is operational or not.
|
||||
To avoid races, we need to block the reception of
|
||||
NETDEV_UP/NETDEV_CHANGE/NETDEV_GOING_DOWN events in the netdev notifier
|
||||
chain while we are changing the master's dev->dsa_ptr (this changes what
|
||||
netdev_uses_dsa(dev) reports).
|
||||
|
||||
The dsa_master_setup() and dsa_master_teardown() functions optionally
|
||||
require the rtnl_mutex to be held, if the tagger needs the master to be
|
||||
promiscuous, these functions call dev_set_promiscuity(). Move the
|
||||
rtnl_lock() from that function and make it top-level.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/dsa2.c | 8 ++++++++
|
||||
net/dsa/master.c | 4 ++--
|
||||
2 files changed, 10 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/net/dsa/dsa2.c
|
||||
+++ b/net/dsa/dsa2.c
|
||||
@@ -1034,6 +1034,8 @@ static int dsa_tree_setup_master(struct
|
||||
struct dsa_port *dp;
|
||||
int err;
|
||||
|
||||
+ rtnl_lock();
|
||||
+
|
||||
list_for_each_entry(dp, &dst->ports, list) {
|
||||
if (dsa_port_is_cpu(dp)) {
|
||||
err = dsa_master_setup(dp->master, dp);
|
||||
@@ -1042,6 +1044,8 @@ static int dsa_tree_setup_master(struct
|
||||
}
|
||||
}
|
||||
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1049,9 +1053,13 @@ static void dsa_tree_teardown_master(str
|
||||
{
|
||||
struct dsa_port *dp;
|
||||
|
||||
+ rtnl_lock();
|
||||
+
|
||||
list_for_each_entry(dp, &dst->ports, list)
|
||||
if (dsa_port_is_cpu(dp))
|
||||
dsa_master_teardown(dp->master);
|
||||
+
|
||||
+ rtnl_unlock();
|
||||
}
|
||||
|
||||
static int dsa_tree_setup_lags(struct dsa_switch_tree *dst)
|
||||
--- a/net/dsa/master.c
|
||||
+++ b/net/dsa/master.c
|
||||
@@ -267,9 +267,9 @@ static void dsa_master_set_promiscuity(s
|
||||
if (!ops->promisc_on_master)
|
||||
return;
|
||||
|
||||
- rtnl_lock();
|
||||
+ ASSERT_RTNL();
|
||||
+
|
||||
dev_set_promiscuity(dev, inc);
|
||||
- rtnl_unlock();
|
||||
}
|
||||
|
||||
static ssize_t tagging_show(struct device *d, struct device_attribute *attr,
|
||||
@ -0,0 +1,118 @@
|
||||
From 1e3f407f3cacc5dcfe27166c412ed9bc263d82bf Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Thu, 6 Jan 2022 01:11:16 +0200
|
||||
Subject: [PATCH 5/6] net: dsa: first set up shared ports, then non-shared
|
||||
ports
|
||||
|
||||
After commit a57d8c217aad ("net: dsa: flush switchdev workqueue before
|
||||
tearing down CPU/DSA ports"), the port setup and teardown procedure
|
||||
became asymmetric.
|
||||
|
||||
The fact of the matter is that user ports need the shared ports to be up
|
||||
before they can be used for CPU-initiated termination. And since we
|
||||
register net devices for the user ports, those won't be functional until
|
||||
we also call the setup for the shared (CPU, DSA) ports. But we may do
|
||||
that later, depending on the port numbering scheme of the hardware we
|
||||
are dealing with.
|
||||
|
||||
It just makes sense that all shared ports are brought up before any user
|
||||
port is. I can't pinpoint any issue due to the current behavior, but
|
||||
let's change it nonetheless, for consistency's sake.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/dsa2.c | 50 +++++++++++++++++++++++++++++++++++++-------------
|
||||
1 file changed, 37 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/net/dsa/dsa2.c
|
||||
+++ b/net/dsa/dsa2.c
|
||||
@@ -999,23 +999,28 @@ static void dsa_tree_teardown_switches(s
|
||||
dsa_switch_teardown(dp->ds);
|
||||
}
|
||||
|
||||
-static int dsa_tree_setup_switches(struct dsa_switch_tree *dst)
|
||||
+/* Bring shared ports up first, then non-shared ports */
|
||||
+static int dsa_tree_setup_ports(struct dsa_switch_tree *dst)
|
||||
{
|
||||
struct dsa_port *dp;
|
||||
- int err;
|
||||
+ int err = 0;
|
||||
|
||||
list_for_each_entry(dp, &dst->ports, list) {
|
||||
- err = dsa_switch_setup(dp->ds);
|
||||
- if (err)
|
||||
- goto teardown;
|
||||
+ if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp)) {
|
||||
+ err = dsa_port_setup(dp);
|
||||
+ if (err)
|
||||
+ goto teardown;
|
||||
+ }
|
||||
}
|
||||
|
||||
list_for_each_entry(dp, &dst->ports, list) {
|
||||
- err = dsa_port_setup(dp);
|
||||
- if (err) {
|
||||
- err = dsa_port_reinit_as_unused(dp);
|
||||
- if (err)
|
||||
- goto teardown;
|
||||
+ if (dsa_port_is_user(dp) || dsa_port_is_unused(dp)) {
|
||||
+ err = dsa_port_setup(dp);
|
||||
+ if (err) {
|
||||
+ err = dsa_port_reinit_as_unused(dp);
|
||||
+ if (err)
|
||||
+ goto teardown;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1024,7 +1029,21 @@ static int dsa_tree_setup_switches(struc
|
||||
teardown:
|
||||
dsa_tree_teardown_ports(dst);
|
||||
|
||||
- dsa_tree_teardown_switches(dst);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int dsa_tree_setup_switches(struct dsa_switch_tree *dst)
|
||||
+{
|
||||
+ struct dsa_port *dp;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ list_for_each_entry(dp, &dst->ports, list) {
|
||||
+ err = dsa_switch_setup(dp->ds);
|
||||
+ if (err) {
|
||||
+ dsa_tree_teardown_switches(dst);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1111,10 +1130,14 @@ static int dsa_tree_setup(struct dsa_swi
|
||||
if (err)
|
||||
goto teardown_cpu_ports;
|
||||
|
||||
- err = dsa_tree_setup_master(dst);
|
||||
+ err = dsa_tree_setup_ports(dst);
|
||||
if (err)
|
||||
goto teardown_switches;
|
||||
|
||||
+ err = dsa_tree_setup_master(dst);
|
||||
+ if (err)
|
||||
+ goto teardown_ports;
|
||||
+
|
||||
err = dsa_tree_setup_lags(dst);
|
||||
if (err)
|
||||
goto teardown_master;
|
||||
@@ -1127,8 +1150,9 @@ static int dsa_tree_setup(struct dsa_swi
|
||||
|
||||
teardown_master:
|
||||
dsa_tree_teardown_master(dst);
|
||||
-teardown_switches:
|
||||
+teardown_ports:
|
||||
dsa_tree_teardown_ports(dst);
|
||||
+teardown_switches:
|
||||
dsa_tree_teardown_switches(dst);
|
||||
teardown_cpu_ports:
|
||||
dsa_tree_teardown_cpu_ports(dst);
|
||||
@ -0,0 +1,115 @@
|
||||
From 11fd667dac315ea3f2469961f6d2869271a46cae Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Thu, 6 Jan 2022 01:11:17 +0200
|
||||
Subject: [PATCH 6/6] net: dsa: setup master before ports
|
||||
|
||||
It is said that as soon as a network interface is registered, all its
|
||||
resources should have already been prepared, so that it is available for
|
||||
sending and receiving traffic. One of the resources needed by a DSA
|
||||
slave interface is the master.
|
||||
|
||||
dsa_tree_setup
|
||||
-> dsa_tree_setup_ports
|
||||
-> dsa_port_setup
|
||||
-> dsa_slave_create
|
||||
-> register_netdevice
|
||||
-> dsa_tree_setup_master
|
||||
-> dsa_master_setup
|
||||
-> sets up master->dsa_ptr, which enables reception
|
||||
|
||||
Therefore, there is a short period of time after register_netdevice()
|
||||
during which the master isn't prepared to pass traffic to the DSA layer
|
||||
(master->dsa_ptr is checked by eth_type_trans). Same thing during
|
||||
unregistration, there is a time frame in which packets might be missed.
|
||||
|
||||
Note that this change opens us to another race: dsa_master_find_slave()
|
||||
will get invoked potentially earlier than the slave creation, and later
|
||||
than the slave deletion. Since dp->slave starts off as a NULL pointer,
|
||||
the earlier calls aren't a problem, but the later calls are. To avoid
|
||||
use-after-free, we should zeroize dp->slave before calling
|
||||
dsa_slave_destroy().
|
||||
|
||||
In practice I cannot really test real life improvements brought by this
|
||||
change, since in my systems, netdevice creation races with PHY autoneg
|
||||
which takes a few seconds to complete, and that masks quite a few races.
|
||||
Effects might be noticeable in a setup with fixed links all the way to
|
||||
an external system.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/dsa2.c | 23 +++++++++++++----------
|
||||
1 file changed, 13 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/net/dsa/dsa2.c
|
||||
+++ b/net/dsa/dsa2.c
|
||||
@@ -545,6 +545,7 @@ static void dsa_port_teardown(struct dsa
|
||||
struct devlink_port *dlp = &dp->devlink_port;
|
||||
struct dsa_switch *ds = dp->ds;
|
||||
struct dsa_mac_addr *a, *tmp;
|
||||
+ struct net_device *slave;
|
||||
|
||||
if (!dp->setup)
|
||||
return;
|
||||
@@ -566,9 +567,11 @@ static void dsa_port_teardown(struct dsa
|
||||
dsa_port_link_unregister_of(dp);
|
||||
break;
|
||||
case DSA_PORT_TYPE_USER:
|
||||
- if (dp->slave) {
|
||||
- dsa_slave_destroy(dp->slave);
|
||||
+ slave = dp->slave;
|
||||
+
|
||||
+ if (slave) {
|
||||
dp->slave = NULL;
|
||||
+ dsa_slave_destroy(slave);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1130,17 +1133,17 @@ static int dsa_tree_setup(struct dsa_swi
|
||||
if (err)
|
||||
goto teardown_cpu_ports;
|
||||
|
||||
- err = dsa_tree_setup_ports(dst);
|
||||
+ err = dsa_tree_setup_master(dst);
|
||||
if (err)
|
||||
goto teardown_switches;
|
||||
|
||||
- err = dsa_tree_setup_master(dst);
|
||||
+ err = dsa_tree_setup_ports(dst);
|
||||
if (err)
|
||||
- goto teardown_ports;
|
||||
+ goto teardown_master;
|
||||
|
||||
err = dsa_tree_setup_lags(dst);
|
||||
if (err)
|
||||
- goto teardown_master;
|
||||
+ goto teardown_ports;
|
||||
|
||||
dst->setup = true;
|
||||
|
||||
@@ -1148,10 +1151,10 @@ static int dsa_tree_setup(struct dsa_swi
|
||||
|
||||
return 0;
|
||||
|
||||
-teardown_master:
|
||||
- dsa_tree_teardown_master(dst);
|
||||
teardown_ports:
|
||||
dsa_tree_teardown_ports(dst);
|
||||
+teardown_master:
|
||||
+ dsa_tree_teardown_master(dst);
|
||||
teardown_switches:
|
||||
dsa_tree_teardown_switches(dst);
|
||||
teardown_cpu_ports:
|
||||
@@ -1169,10 +1172,10 @@ static void dsa_tree_teardown(struct dsa
|
||||
|
||||
dsa_tree_teardown_lags(dst);
|
||||
|
||||
- dsa_tree_teardown_master(dst);
|
||||
-
|
||||
dsa_tree_teardown_ports(dst);
|
||||
|
||||
+ dsa_tree_teardown_master(dst);
|
||||
+
|
||||
dsa_tree_teardown_switches(dst);
|
||||
|
||||
dsa_tree_teardown_cpu_ports(dst);
|
||||
@ -0,0 +1,254 @@
|
||||
From 295ab96f478d0fa56393e85406f19a867e26ce22 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:20 +0100
|
||||
Subject: [PATCH 01/16] net: dsa: provide switch operations for tracking the
|
||||
master state
|
||||
|
||||
Certain drivers may need to send management traffic to the switch for
|
||||
things like register access, FDB dump, etc, to accelerate what their
|
||||
slow bus (SPI, I2C, MDIO) can already do.
|
||||
|
||||
Ethernet is faster (especially in bulk transactions) but is also more
|
||||
unreliable, since the user may decide to bring the DSA master down (or
|
||||
not bring it up), therefore severing the link between the host and the
|
||||
attached switch.
|
||||
|
||||
Drivers needing Ethernet-based register access already should have
|
||||
fallback logic to the slow bus if the Ethernet method fails, but that
|
||||
fallback may be based on a timeout, and the I/O to the switch may slow
|
||||
down to a halt if the master is down, because every Ethernet packet will
|
||||
have to time out. The driver also doesn't have the option to turn off
|
||||
Ethernet-based I/O momentarily, because it wouldn't know when to turn it
|
||||
back on.
|
||||
|
||||
Which is where this change comes in. By tracking NETDEV_CHANGE,
|
||||
NETDEV_UP and NETDEV_GOING_DOWN events on the DSA master, we should know
|
||||
the exact interval of time during which this interface is reliably
|
||||
available for traffic. Provide this information to switches so they can
|
||||
use it as they wish.
|
||||
|
||||
An helper is added dsa_port_master_is_operational() to check if a master
|
||||
port is operational.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/net/dsa.h | 17 +++++++++++++++++
|
||||
net/dsa/dsa2.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
net/dsa/dsa_priv.h | 13 +++++++++++++
|
||||
net/dsa/slave.c | 32 ++++++++++++++++++++++++++++++++
|
||||
net/dsa/switch.c | 15 +++++++++++++++
|
||||
5 files changed, 123 insertions(+)
|
||||
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@@ -291,6 +291,10 @@ struct dsa_port {
|
||||
struct list_head mdbs;
|
||||
|
||||
bool setup;
|
||||
+ /* Master state bits, valid only on CPU ports */
|
||||
+ u8 master_admin_up:1;
|
||||
+ u8 master_oper_up:1;
|
||||
+
|
||||
};
|
||||
|
||||
/* TODO: ideally DSA ports would have a single dp->link_dp member,
|
||||
@@ -456,6 +460,12 @@ static inline bool dsa_port_is_unused(st
|
||||
return dp->type == DSA_PORT_TYPE_UNUSED;
|
||||
}
|
||||
|
||||
+static inline bool dsa_port_master_is_operational(struct dsa_port *dp)
|
||||
+{
|
||||
+ return dsa_port_is_cpu(dp) && dp->master_admin_up &&
|
||||
+ dp->master_oper_up;
|
||||
+}
|
||||
+
|
||||
static inline bool dsa_is_unused_port(struct dsa_switch *ds, int p)
|
||||
{
|
||||
return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_UNUSED;
|
||||
@@ -916,6 +926,13 @@ struct dsa_switch_ops {
|
||||
int (*tag_8021q_vlan_add)(struct dsa_switch *ds, int port, u16 vid,
|
||||
u16 flags);
|
||||
int (*tag_8021q_vlan_del)(struct dsa_switch *ds, int port, u16 vid);
|
||||
+
|
||||
+ /*
|
||||
+ * DSA master tracking operations
|
||||
+ */
|
||||
+ void (*master_state_change)(struct dsa_switch *ds,
|
||||
+ const struct net_device *master,
|
||||
+ bool operational);
|
||||
};
|
||||
|
||||
#define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes) \
|
||||
--- a/net/dsa/dsa2.c
|
||||
+++ b/net/dsa/dsa2.c
|
||||
@@ -1275,6 +1275,52 @@ out_unlock:
|
||||
return err;
|
||||
}
|
||||
|
||||
+static void dsa_tree_master_state_change(struct dsa_switch_tree *dst,
|
||||
+ struct net_device *master)
|
||||
+{
|
||||
+ struct dsa_notifier_master_state_info info;
|
||||
+ struct dsa_port *cpu_dp = master->dsa_ptr;
|
||||
+
|
||||
+ info.master = master;
|
||||
+ info.operational = dsa_port_master_is_operational(cpu_dp);
|
||||
+
|
||||
+ dsa_tree_notify(dst, DSA_NOTIFIER_MASTER_STATE_CHANGE, &info);
|
||||
+}
|
||||
+
|
||||
+void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
|
||||
+ struct net_device *master,
|
||||
+ bool up)
|
||||
+{
|
||||
+ struct dsa_port *cpu_dp = master->dsa_ptr;
|
||||
+ bool notify = false;
|
||||
+
|
||||
+ if ((dsa_port_master_is_operational(cpu_dp)) !=
|
||||
+ (up && cpu_dp->master_oper_up))
|
||||
+ notify = true;
|
||||
+
|
||||
+ cpu_dp->master_admin_up = up;
|
||||
+
|
||||
+ if (notify)
|
||||
+ dsa_tree_master_state_change(dst, master);
|
||||
+}
|
||||
+
|
||||
+void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
|
||||
+ struct net_device *master,
|
||||
+ bool up)
|
||||
+{
|
||||
+ struct dsa_port *cpu_dp = master->dsa_ptr;
|
||||
+ bool notify = false;
|
||||
+
|
||||
+ if ((dsa_port_master_is_operational(cpu_dp)) !=
|
||||
+ (cpu_dp->master_admin_up && up))
|
||||
+ notify = true;
|
||||
+
|
||||
+ cpu_dp->master_oper_up = up;
|
||||
+
|
||||
+ if (notify)
|
||||
+ dsa_tree_master_state_change(dst, master);
|
||||
+}
|
||||
+
|
||||
static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
|
||||
{
|
||||
struct dsa_switch_tree *dst = ds->dst;
|
||||
--- a/net/dsa/dsa_priv.h
|
||||
+++ b/net/dsa/dsa_priv.h
|
||||
@@ -45,6 +45,7 @@ enum {
|
||||
DSA_NOTIFIER_MRP_DEL_RING_ROLE,
|
||||
DSA_NOTIFIER_TAG_8021Q_VLAN_ADD,
|
||||
DSA_NOTIFIER_TAG_8021Q_VLAN_DEL,
|
||||
+ DSA_NOTIFIER_MASTER_STATE_CHANGE,
|
||||
};
|
||||
|
||||
/* DSA_NOTIFIER_AGEING_TIME */
|
||||
@@ -127,6 +128,12 @@ struct dsa_notifier_tag_8021q_vlan_info
|
||||
u16 vid;
|
||||
};
|
||||
|
||||
+/* DSA_NOTIFIER_MASTER_STATE_CHANGE */
|
||||
+struct dsa_notifier_master_state_info {
|
||||
+ const struct net_device *master;
|
||||
+ bool operational;
|
||||
+};
|
||||
+
|
||||
struct dsa_switchdev_event_work {
|
||||
struct dsa_switch *ds;
|
||||
int port;
|
||||
@@ -548,6 +555,12 @@ int dsa_tree_change_tag_proto(struct dsa
|
||||
struct net_device *master,
|
||||
const struct dsa_device_ops *tag_ops,
|
||||
const struct dsa_device_ops *old_tag_ops);
|
||||
+void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst,
|
||||
+ struct net_device *master,
|
||||
+ bool up);
|
||||
+void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst,
|
||||
+ struct net_device *master,
|
||||
+ bool up);
|
||||
int dsa_bridge_num_get(const struct net_device *bridge_dev, int max);
|
||||
void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num);
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2320,6 +2320,36 @@ static int dsa_slave_netdevice_event(str
|
||||
err = dsa_port_lag_change(dp, info->lower_state_info);
|
||||
return notifier_from_errno(err);
|
||||
}
|
||||
+ case NETDEV_CHANGE:
|
||||
+ case NETDEV_UP: {
|
||||
+ /* Track state of master port.
|
||||
+ * DSA driver may require the master port (and indirectly
|
||||
+ * the tagger) to be available for some special operation.
|
||||
+ */
|
||||
+ if (netdev_uses_dsa(dev)) {
|
||||
+ struct dsa_port *cpu_dp = dev->dsa_ptr;
|
||||
+ struct dsa_switch_tree *dst = cpu_dp->ds->dst;
|
||||
+
|
||||
+ /* Track when the master port is UP */
|
||||
+ dsa_tree_master_oper_state_change(dst, dev,
|
||||
+ netif_oper_up(dev));
|
||||
+
|
||||
+ /* Track when the master port is ready and can accept
|
||||
+ * packet.
|
||||
+ * NETDEV_UP event is not enough to flag a port as ready.
|
||||
+ * We also have to wait for linkwatch_do_dev to dev_activate
|
||||
+ * and emit a NETDEV_CHANGE event.
|
||||
+ * We check if a master port is ready by checking if the dev
|
||||
+ * have a qdisc assigned and is not noop.
|
||||
+ */
|
||||
+ dsa_tree_master_admin_state_change(dst, dev,
|
||||
+ !qdisc_tx_is_noop(dev));
|
||||
+
|
||||
+ return NOTIFY_OK;
|
||||
+ }
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+ }
|
||||
case NETDEV_GOING_DOWN: {
|
||||
struct dsa_port *dp, *cpu_dp;
|
||||
struct dsa_switch_tree *dst;
|
||||
@@ -2331,6 +2361,8 @@ static int dsa_slave_netdevice_event(str
|
||||
cpu_dp = dev->dsa_ptr;
|
||||
dst = cpu_dp->ds->dst;
|
||||
|
||||
+ dsa_tree_master_admin_state_change(dst, dev, false);
|
||||
+
|
||||
list_for_each_entry(dp, &dst->ports, list) {
|
||||
if (!dsa_is_user_port(dp->ds, dp->index))
|
||||
continue;
|
||||
--- a/net/dsa/switch.c
|
||||
+++ b/net/dsa/switch.c
|
||||
@@ -722,6 +722,18 @@ dsa_switch_mrp_del_ring_role(struct dsa_
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int
|
||||
+dsa_switch_master_state_change(struct dsa_switch *ds,
|
||||
+ struct dsa_notifier_master_state_info *info)
|
||||
+{
|
||||
+ if (!ds->ops->master_state_change)
|
||||
+ return 0;
|
||||
+
|
||||
+ ds->ops->master_state_change(ds, info->master, info->operational);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int dsa_switch_event(struct notifier_block *nb,
|
||||
unsigned long event, void *info)
|
||||
{
|
||||
@@ -813,6 +825,9 @@ static int dsa_switch_event(struct notif
|
||||
case DSA_NOTIFIER_TAG_8021Q_VLAN_DEL:
|
||||
err = dsa_switch_tag_8021q_vlan_del(ds, info);
|
||||
break;
|
||||
+ case DSA_NOTIFIER_MASTER_STATE_CHANGE:
|
||||
+ err = dsa_switch_master_state_change(ds, info);
|
||||
+ break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
@ -0,0 +1,89 @@
|
||||
From e83d56537859849f2223b90749e554831b1f3c27 Mon Sep 17 00:00:00 2001
|
||||
From: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:21 +0100
|
||||
Subject: [PATCH 02/16] net: dsa: replay master state events in
|
||||
dsa_tree_{setup,teardown}_master
|
||||
|
||||
In order for switch driver to be able to make simple and reliable use of
|
||||
the master tracking operations, they must also be notified of the
|
||||
initial state of the DSA master, not just of the changes. This is
|
||||
because they might enable certain features only during the time when
|
||||
they know that the DSA master is up and running.
|
||||
|
||||
Therefore, this change explicitly checks the state of the DSA master
|
||||
under the same rtnl_mutex as we were holding during the
|
||||
dsa_master_setup() and dsa_master_teardown() call. The idea being that
|
||||
if the DSA master became operational in between the moment in which it
|
||||
became a DSA master (dsa_master_setup set dev->dsa_ptr) and the moment
|
||||
when we checked for the master being up, there is a chance that we
|
||||
would emit a ->master_state_change() call with no actual state change.
|
||||
We need to avoid that by serializing the concurrent netdevice event with
|
||||
us. If the netdevice event started before, we force it to finish before
|
||||
we begin, because we take rtnl_lock before making netdev_uses_dsa()
|
||||
return true. So we also handle that early event and do nothing on it.
|
||||
Similarly, if the dev_open() attempt is concurrent with us, it will
|
||||
attempt to take the rtnl_mutex, but we're holding it. We'll see that
|
||||
the master flag IFF_UP isn't set, then when we release the rtnl_mutex
|
||||
we'll process the NETDEV_UP notifier.
|
||||
|
||||
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/dsa2.c | 28 ++++++++++++++++++++++++----
|
||||
1 file changed, 24 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/net/dsa/dsa2.c
|
||||
+++ b/net/dsa/dsa2.c
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <net/devlink.h>
|
||||
+#include <net/sch_generic.h>
|
||||
|
||||
#include "dsa_priv.h"
|
||||
|
||||
@@ -1060,9 +1061,18 @@ static int dsa_tree_setup_master(struct
|
||||
|
||||
list_for_each_entry(dp, &dst->ports, list) {
|
||||
if (dsa_port_is_cpu(dp)) {
|
||||
- err = dsa_master_setup(dp->master, dp);
|
||||
+ struct net_device *master = dp->master;
|
||||
+ bool admin_up = (master->flags & IFF_UP) &&
|
||||
+ !qdisc_tx_is_noop(master);
|
||||
+
|
||||
+ err = dsa_master_setup(master, dp);
|
||||
if (err)
|
||||
return err;
|
||||
+
|
||||
+ /* Replay master state event */
|
||||
+ dsa_tree_master_admin_state_change(dst, master, admin_up);
|
||||
+ dsa_tree_master_oper_state_change(dst, master,
|
||||
+ netif_oper_up(master));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1077,9 +1087,19 @@ static void dsa_tree_teardown_master(str
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
- list_for_each_entry(dp, &dst->ports, list)
|
||||
- if (dsa_port_is_cpu(dp))
|
||||
- dsa_master_teardown(dp->master);
|
||||
+ list_for_each_entry(dp, &dst->ports, list) {
|
||||
+ if (dsa_port_is_cpu(dp)) {
|
||||
+ struct net_device *master = dp->master;
|
||||
+
|
||||
+ /* Synthesizing an "admin down" state is sufficient for
|
||||
+ * the switches to get a notification if the master is
|
||||
+ * currently up and running.
|
||||
+ */
|
||||
+ dsa_tree_master_admin_state_change(dst, master, false);
|
||||
+
|
||||
+ dsa_master_teardown(master);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
rtnl_unlock();
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
From 6b0458299297ca4ab6fb295800e29a4e501d50c1 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:22 +0100
|
||||
Subject: [PATCH 03/16] net: dsa: tag_qca: convert to FIELD macro
|
||||
|
||||
Convert driver to FIELD macro to drop redundant define.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/tag_qca.c | 34 +++++++++++++++-------------------
|
||||
1 file changed, 15 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/net/dsa/tag_qca.c
|
||||
+++ b/net/dsa/tag_qca.c
|
||||
@@ -4,29 +4,24 @@
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
+#include <linux/bitfield.h>
|
||||
|
||||
#include "dsa_priv.h"
|
||||
|
||||
#define QCA_HDR_LEN 2
|
||||
#define QCA_HDR_VERSION 0x2
|
||||
|
||||
-#define QCA_HDR_RECV_VERSION_MASK GENMASK(15, 14)
|
||||
-#define QCA_HDR_RECV_VERSION_S 14
|
||||
-#define QCA_HDR_RECV_PRIORITY_MASK GENMASK(13, 11)
|
||||
-#define QCA_HDR_RECV_PRIORITY_S 11
|
||||
-#define QCA_HDR_RECV_TYPE_MASK GENMASK(10, 6)
|
||||
-#define QCA_HDR_RECV_TYPE_S 6
|
||||
+#define QCA_HDR_RECV_VERSION GENMASK(15, 14)
|
||||
+#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11)
|
||||
+#define QCA_HDR_RECV_TYPE GENMASK(10, 6)
|
||||
#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3)
|
||||
-#define QCA_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0)
|
||||
+#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0)
|
||||
|
||||
-#define QCA_HDR_XMIT_VERSION_MASK GENMASK(15, 14)
|
||||
-#define QCA_HDR_XMIT_VERSION_S 14
|
||||
-#define QCA_HDR_XMIT_PRIORITY_MASK GENMASK(13, 11)
|
||||
-#define QCA_HDR_XMIT_PRIORITY_S 11
|
||||
-#define QCA_HDR_XMIT_CONTROL_MASK GENMASK(10, 8)
|
||||
-#define QCA_HDR_XMIT_CONTROL_S 8
|
||||
+#define QCA_HDR_XMIT_VERSION GENMASK(15, 14)
|
||||
+#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11)
|
||||
+#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8)
|
||||
#define QCA_HDR_XMIT_FROM_CPU BIT(7)
|
||||
-#define QCA_HDR_XMIT_DP_BIT_MASK GENMASK(6, 0)
|
||||
+#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0)
|
||||
|
||||
static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
@@ -40,8 +35,9 @@ static struct sk_buff *qca_tag_xmit(stru
|
||||
phdr = dsa_etype_header_pos_tx(skb);
|
||||
|
||||
/* Set the version field, and set destination port information */
|
||||
- hdr = QCA_HDR_VERSION << QCA_HDR_XMIT_VERSION_S |
|
||||
- QCA_HDR_XMIT_FROM_CPU | BIT(dp->index);
|
||||
+ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION);
|
||||
+ hdr |= QCA_HDR_XMIT_FROM_CPU;
|
||||
+ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(dp->index));
|
||||
|
||||
*phdr = htons(hdr);
|
||||
|
||||
@@ -62,7 +58,7 @@ static struct sk_buff *qca_tag_rcv(struc
|
||||
hdr = ntohs(*phdr);
|
||||
|
||||
/* Make sure the version is correct */
|
||||
- ver = (hdr & QCA_HDR_RECV_VERSION_MASK) >> QCA_HDR_RECV_VERSION_S;
|
||||
+ ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr);
|
||||
if (unlikely(ver != QCA_HDR_VERSION))
|
||||
return NULL;
|
||||
|
||||
@@ -71,7 +67,7 @@ static struct sk_buff *qca_tag_rcv(struc
|
||||
dsa_strip_etype_header(skb, QCA_HDR_LEN);
|
||||
|
||||
/* Get source port information */
|
||||
- port = (hdr & QCA_HDR_RECV_SOURCE_PORT_MASK);
|
||||
+ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr);
|
||||
|
||||
skb->dev = dsa_master_find_slave(dev, 0, port);
|
||||
if (!skb->dev)
|
||||
@ -0,0 +1,71 @@
|
||||
From 3ec762fb13c7e7273800b94c80db1c2cc37590d1 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:23 +0100
|
||||
Subject: [PATCH 04/16] net: dsa: tag_qca: move define to include linux/dsa
|
||||
|
||||
Move tag_qca define to include dir linux/dsa as the qca8k require access
|
||||
to the tagger define to support in-band mdio read/write using ethernet
|
||||
packet.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/dsa/tag_qca.h | 21 +++++++++++++++++++++
|
||||
net/dsa/tag_qca.c | 16 +---------------
|
||||
2 files changed, 22 insertions(+), 15 deletions(-)
|
||||
create mode 100644 include/linux/dsa/tag_qca.h
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/linux/dsa/tag_qca.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+
|
||||
+#ifndef __TAG_QCA_H
|
||||
+#define __TAG_QCA_H
|
||||
+
|
||||
+#define QCA_HDR_LEN 2
|
||||
+#define QCA_HDR_VERSION 0x2
|
||||
+
|
||||
+#define QCA_HDR_RECV_VERSION GENMASK(15, 14)
|
||||
+#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11)
|
||||
+#define QCA_HDR_RECV_TYPE GENMASK(10, 6)
|
||||
+#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3)
|
||||
+#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0)
|
||||
+
|
||||
+#define QCA_HDR_XMIT_VERSION GENMASK(15, 14)
|
||||
+#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11)
|
||||
+#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8)
|
||||
+#define QCA_HDR_XMIT_FROM_CPU BIT(7)
|
||||
+#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0)
|
||||
+
|
||||
+#endif /* __TAG_QCA_H */
|
||||
--- a/net/dsa/tag_qca.c
|
||||
+++ b/net/dsa/tag_qca.c
|
||||
@@ -5,24 +5,10 @@
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/bitfield.h>
|
||||
+#include <linux/dsa/tag_qca.h>
|
||||
|
||||
#include "dsa_priv.h"
|
||||
|
||||
-#define QCA_HDR_LEN 2
|
||||
-#define QCA_HDR_VERSION 0x2
|
||||
-
|
||||
-#define QCA_HDR_RECV_VERSION GENMASK(15, 14)
|
||||
-#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11)
|
||||
-#define QCA_HDR_RECV_TYPE GENMASK(10, 6)
|
||||
-#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3)
|
||||
-#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0)
|
||||
-
|
||||
-#define QCA_HDR_XMIT_VERSION GENMASK(15, 14)
|
||||
-#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11)
|
||||
-#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8)
|
||||
-#define QCA_HDR_XMIT_FROM_CPU BIT(7)
|
||||
-#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0)
|
||||
-
|
||||
static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct dsa_port *dp = dsa_slave_to_port(dev);
|
||||
@ -0,0 +1,27 @@
|
||||
From 101c04c3463b87061e6a3d4f72c1bc57670685a6 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:24 +0100
|
||||
Subject: [PATCH 05/16] net: dsa: tag_qca: enable promisc_on_master flag
|
||||
|
||||
Ethernet MDIO packets are non-standard and DSA master expects the first
|
||||
6 octets to be the MAC DA. To address these kind of packet, enable
|
||||
promisc_on_master flag for the tagger.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/dsa/tag_qca.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/net/dsa/tag_qca.c
|
||||
+++ b/net/dsa/tag_qca.c
|
||||
@@ -68,6 +68,7 @@ static const struct dsa_device_ops qca_n
|
||||
.xmit = qca_tag_xmit,
|
||||
.rcv = qca_tag_rcv,
|
||||
.needed_headroom = QCA_HDR_LEN,
|
||||
+ .promisc_on_master = true,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@ -0,0 +1,110 @@
|
||||
From c2ee8181fddb293d296477f60b3eb4fa3ce4e1a6 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:25 +0100
|
||||
Subject: [PATCH 06/16] net: dsa: tag_qca: add define for handling mgmt
|
||||
Ethernet packet
|
||||
|
||||
Add all the required define to prepare support for mgmt read/write in
|
||||
Ethernet packet. Any packet of this type has to be dropped as the only
|
||||
use of these special packet is receive ack for an mgmt write request or
|
||||
receive data for an mgmt read request.
|
||||
A struct is used that emulates the Ethernet header but is used for a
|
||||
different purpose.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/dsa/tag_qca.h | 44 +++++++++++++++++++++++++++++++++++++
|
||||
net/dsa/tag_qca.c | 15 ++++++++++---
|
||||
2 files changed, 56 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/include/linux/dsa/tag_qca.h
|
||||
+++ b/include/linux/dsa/tag_qca.h
|
||||
@@ -12,10 +12,54 @@
|
||||
#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3)
|
||||
#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0)
|
||||
|
||||
+/* Packet type for recv */
|
||||
+#define QCA_HDR_RECV_TYPE_NORMAL 0x0
|
||||
+#define QCA_HDR_RECV_TYPE_MIB 0x1
|
||||
+#define QCA_HDR_RECV_TYPE_RW_REG_ACK 0x2
|
||||
+
|
||||
#define QCA_HDR_XMIT_VERSION GENMASK(15, 14)
|
||||
#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11)
|
||||
#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8)
|
||||
#define QCA_HDR_XMIT_FROM_CPU BIT(7)
|
||||
#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0)
|
||||
|
||||
+/* Packet type for xmit */
|
||||
+#define QCA_HDR_XMIT_TYPE_NORMAL 0x0
|
||||
+#define QCA_HDR_XMIT_TYPE_RW_REG 0x1
|
||||
+
|
||||
+/* Check code for a valid mgmt packet. Switch will ignore the packet
|
||||
+ * with this wrong.
|
||||
+ */
|
||||
+#define QCA_HDR_MGMT_CHECK_CODE_VAL 0x5
|
||||
+
|
||||
+/* Specific define for in-band MDIO read/write with Ethernet packet */
|
||||
+#define QCA_HDR_MGMT_SEQ_LEN 4 /* 4 byte for the seq */
|
||||
+#define QCA_HDR_MGMT_COMMAND_LEN 4 /* 4 byte for the command */
|
||||
+#define QCA_HDR_MGMT_DATA1_LEN 4 /* First 4 byte for the mdio data */
|
||||
+#define QCA_HDR_MGMT_HEADER_LEN (QCA_HDR_MGMT_SEQ_LEN + \
|
||||
+ QCA_HDR_MGMT_COMMAND_LEN + \
|
||||
+ QCA_HDR_MGMT_DATA1_LEN)
|
||||
+
|
||||
+#define QCA_HDR_MGMT_DATA2_LEN 12 /* Other 12 byte for the mdio data */
|
||||
+#define QCA_HDR_MGMT_PADDING_LEN 34 /* Padding to reach the min Ethernet packet */
|
||||
+
|
||||
+#define QCA_HDR_MGMT_PKT_LEN (QCA_HDR_MGMT_HEADER_LEN + \
|
||||
+ QCA_HDR_LEN + \
|
||||
+ QCA_HDR_MGMT_DATA2_LEN + \
|
||||
+ QCA_HDR_MGMT_PADDING_LEN)
|
||||
+
|
||||
+#define QCA_HDR_MGMT_SEQ_NUM GENMASK(31, 0) /* 63, 32 */
|
||||
+#define QCA_HDR_MGMT_CHECK_CODE GENMASK(31, 29) /* 31, 29 */
|
||||
+#define QCA_HDR_MGMT_CMD BIT(28) /* 28 */
|
||||
+#define QCA_HDR_MGMT_LENGTH GENMASK(23, 20) /* 23, 20 */
|
||||
+#define QCA_HDR_MGMT_ADDR GENMASK(18, 0) /* 18, 0 */
|
||||
+
|
||||
+/* Special struct emulating a Ethernet header */
|
||||
+struct qca_mgmt_ethhdr {
|
||||
+ u32 command; /* command bit 31:0 */
|
||||
+ u32 seq; /* seq 63:32 */
|
||||
+ u32 mdio_data; /* first 4byte mdio */
|
||||
+ __be16 hdr; /* qca hdr */
|
||||
+} __packed;
|
||||
+
|
||||
#endif /* __TAG_QCA_H */
|
||||
--- a/net/dsa/tag_qca.c
|
||||
+++ b/net/dsa/tag_qca.c
|
||||
@@ -32,10 +32,12 @@ static struct sk_buff *qca_tag_xmit(stru
|
||||
|
||||
static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
- u8 ver;
|
||||
- u16 hdr;
|
||||
- int port;
|
||||
+ u8 ver, pk_type;
|
||||
__be16 *phdr;
|
||||
+ int port;
|
||||
+ u16 hdr;
|
||||
+
|
||||
+ BUILD_BUG_ON(sizeof(struct qca_mgmt_ethhdr) != QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN);
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
|
||||
return NULL;
|
||||
@@ -48,6 +50,13 @@ static struct sk_buff *qca_tag_rcv(struc
|
||||
if (unlikely(ver != QCA_HDR_VERSION))
|
||||
return NULL;
|
||||
|
||||
+ /* Get pk type */
|
||||
+ pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
|
||||
+
|
||||
+ /* Ethernet MDIO read/write packet */
|
||||
+ if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK)
|
||||
+ return NULL;
|
||||
+
|
||||
/* Remove QCA tag and recalculate checksum */
|
||||
skb_pull_rcsum(skb, QCA_HDR_LEN);
|
||||
dsa_strip_etype_header(skb, QCA_HDR_LEN);
|
||||
@ -0,0 +1,45 @@
|
||||
From 18be654a4345f7d937b4bfbad74bea8093e3a93c Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:26 +0100
|
||||
Subject: [PATCH 07/16] net: dsa: tag_qca: add define for handling MIB packet
|
||||
|
||||
Add struct to correctly parse a mib Ethernet packet.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/dsa/tag_qca.h | 10 ++++++++++
|
||||
net/dsa/tag_qca.c | 4 ++++
|
||||
2 files changed, 14 insertions(+)
|
||||
|
||||
--- a/include/linux/dsa/tag_qca.h
|
||||
+++ b/include/linux/dsa/tag_qca.h
|
||||
@@ -62,4 +62,14 @@ struct qca_mgmt_ethhdr {
|
||||
__be16 hdr; /* qca hdr */
|
||||
} __packed;
|
||||
|
||||
+enum mdio_cmd {
|
||||
+ MDIO_WRITE = 0x0,
|
||||
+ MDIO_READ
|
||||
+};
|
||||
+
|
||||
+struct mib_ethhdr {
|
||||
+ u32 data[3]; /* first 3 mib counter */
|
||||
+ __be16 hdr; /* qca hdr */
|
||||
+} __packed;
|
||||
+
|
||||
#endif /* __TAG_QCA_H */
|
||||
--- a/net/dsa/tag_qca.c
|
||||
+++ b/net/dsa/tag_qca.c
|
||||
@@ -57,6 +57,10 @@ static struct sk_buff *qca_tag_rcv(struc
|
||||
if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK)
|
||||
return NULL;
|
||||
|
||||
+ /* Ethernet MIB counter packet */
|
||||
+ if (pk_type == QCA_HDR_RECV_TYPE_MIB)
|
||||
+ return NULL;
|
||||
+
|
||||
/* Remove QCA tag and recalculate checksum */
|
||||
skb_pull_rcsum(skb, QCA_HDR_LEN);
|
||||
dsa_strip_etype_header(skb, QCA_HDR_LEN);
|
||||
@ -0,0 +1,116 @@
|
||||
From 31eb6b4386ad91930417e3f5c8157a4b5e31cbd5 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:27 +0100
|
||||
Subject: [PATCH 08/16] net: dsa: tag_qca: add support for handling mgmt and
|
||||
MIB Ethernet packet
|
||||
|
||||
Add connect/disconnect helper to assign private struct to the DSA switch.
|
||||
Add support for Ethernet mgmt and MIB if the DSA driver provide an handler
|
||||
to correctly parse and elaborate the data.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/linux/dsa/tag_qca.h | 7 +++++++
|
||||
net/dsa/tag_qca.c | 39 ++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 43 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/include/linux/dsa/tag_qca.h
|
||||
+++ b/include/linux/dsa/tag_qca.h
|
||||
@@ -72,4 +72,11 @@ struct mib_ethhdr {
|
||||
__be16 hdr; /* qca hdr */
|
||||
} __packed;
|
||||
|
||||
+struct qca_tagger_data {
|
||||
+ void (*rw_reg_ack_handler)(struct dsa_switch *ds,
|
||||
+ struct sk_buff *skb);
|
||||
+ void (*mib_autocast_handler)(struct dsa_switch *ds,
|
||||
+ struct sk_buff *skb);
|
||||
+};
|
||||
+
|
||||
#endif /* __TAG_QCA_H */
|
||||
--- a/net/dsa/tag_qca.c
|
||||
+++ b/net/dsa/tag_qca.c
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/bitfield.h>
|
||||
+#include <net/dsa.h>
|
||||
#include <linux/dsa/tag_qca.h>
|
||||
|
||||
#include "dsa_priv.h"
|
||||
@@ -32,6 +33,9 @@ static struct sk_buff *qca_tag_xmit(stru
|
||||
|
||||
static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
+ struct qca_tagger_data *tagger_data;
|
||||
+ struct dsa_port *dp = dev->dsa_ptr;
|
||||
+ struct dsa_switch *ds = dp->ds;
|
||||
u8 ver, pk_type;
|
||||
__be16 *phdr;
|
||||
int port;
|
||||
@@ -39,6 +43,8 @@ static struct sk_buff *qca_tag_rcv(struc
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct qca_mgmt_ethhdr) != QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN);
|
||||
|
||||
+ tagger_data = ds->tagger_data;
|
||||
+
|
||||
if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
|
||||
return NULL;
|
||||
|
||||
@@ -53,13 +59,19 @@ static struct sk_buff *qca_tag_rcv(struc
|
||||
/* Get pk type */
|
||||
pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
|
||||
|
||||
- /* Ethernet MDIO read/write packet */
|
||||
- if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK)
|
||||
+ /* Ethernet mgmt read/write packet */
|
||||
+ if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) {
|
||||
+ if (likely(tagger_data->rw_reg_ack_handler))
|
||||
+ tagger_data->rw_reg_ack_handler(ds, skb);
|
||||
return NULL;
|
||||
+ }
|
||||
|
||||
/* Ethernet MIB counter packet */
|
||||
- if (pk_type == QCA_HDR_RECV_TYPE_MIB)
|
||||
+ if (pk_type == QCA_HDR_RECV_TYPE_MIB) {
|
||||
+ if (likely(tagger_data->mib_autocast_handler))
|
||||
+ tagger_data->mib_autocast_handler(ds, skb);
|
||||
return NULL;
|
||||
+ }
|
||||
|
||||
/* Remove QCA tag and recalculate checksum */
|
||||
skb_pull_rcsum(skb, QCA_HDR_LEN);
|
||||
@@ -75,9 +87,30 @@ static struct sk_buff *qca_tag_rcv(struc
|
||||
return skb;
|
||||
}
|
||||
|
||||
+static int qca_tag_connect(struct dsa_switch *ds)
|
||||
+{
|
||||
+ struct qca_tagger_data *tagger_data;
|
||||
+
|
||||
+ tagger_data = kzalloc(sizeof(*tagger_data), GFP_KERNEL);
|
||||
+ if (!tagger_data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ds->tagger_data = tagger_data;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void qca_tag_disconnect(struct dsa_switch *ds)
|
||||
+{
|
||||
+ kfree(ds->tagger_data);
|
||||
+ ds->tagger_data = NULL;
|
||||
+}
|
||||
+
|
||||
static const struct dsa_device_ops qca_netdev_ops = {
|
||||
.name = "qca",
|
||||
.proto = DSA_TAG_PROTO_QCA,
|
||||
+ .connect = qca_tag_connect,
|
||||
+ .disconnect = qca_tag_disconnect,
|
||||
.xmit = qca_tag_xmit,
|
||||
.rcv = qca_tag_rcv,
|
||||
.needed_headroom = QCA_HDR_LEN,
|
||||
@ -0,0 +1,67 @@
|
||||
From cddbec19466a1dfb4d45ddd507d9f09f991d54ae Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:28 +0100
|
||||
Subject: [PATCH 09/16] net: dsa: qca8k: add tracking state of master port
|
||||
|
||||
MDIO/MIB Ethernet require the master port and the tagger availabale to
|
||||
correctly work. Use the new api master_state_change to track when master
|
||||
is operational or not and set a bool in qca8k_priv.
|
||||
We cache the first cached master available and we check if other cpu
|
||||
port are operational when the cached one goes down.
|
||||
This cached master will later be used by mdio read/write and mib request to
|
||||
correctly use the working function.
|
||||
|
||||
qca8k implementation for MDIO/MIB Ethernet is bad. CPU port0 is the only
|
||||
one that answers with the ack packet or sends MIB Ethernet packets. For
|
||||
this reason the master_state_change ignore CPU port6 and only checks
|
||||
CPU port0 if it's operational and enables this mode.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 15 +++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 1 +
|
||||
2 files changed, 16 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -2382,6 +2382,20 @@ qca8k_port_lag_leave(struct dsa_switch *
|
||||
return qca8k_lag_refresh_portmap(ds, port, lag, true);
|
||||
}
|
||||
|
||||
+static void
|
||||
+qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
|
||||
+ bool operational)
|
||||
+{
|
||||
+ struct dsa_port *dp = master->dsa_ptr;
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+
|
||||
+ /* Ethernet MIB/MDIO is only supported for CPU port 0 */
|
||||
+ if (dp->index != 0)
|
||||
+ return;
|
||||
+
|
||||
+ priv->mgmt_master = operational ? (struct net_device *)master : NULL;
|
||||
+}
|
||||
+
|
||||
static const struct dsa_switch_ops qca8k_switch_ops = {
|
||||
.get_tag_protocol = qca8k_get_tag_protocol,
|
||||
.setup = qca8k_setup,
|
||||
@@ -2417,6 +2431,7 @@ static const struct dsa_switch_ops qca8k
|
||||
.get_phy_flags = qca8k_get_phy_flags,
|
||||
.port_lag_join = qca8k_port_lag_join,
|
||||
.port_lag_leave = qca8k_port_lag_leave,
|
||||
+ .master_state_change = qca8k_master_change,
|
||||
};
|
||||
|
||||
static int qca8k_read_switch_id(struct qca8k_priv *priv)
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -353,6 +353,7 @@ struct qca8k_priv {
|
||||
struct dsa_switch_ops ops;
|
||||
struct gpio_desc *reset_gpio;
|
||||
unsigned int port_mtu[QCA8K_NUM_PORTS];
|
||||
+ struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
|
||||
};
|
||||
|
||||
struct qca8k_mib_desc {
|
||||
@ -0,0 +1,363 @@
|
||||
From 5950c7c0a68c915b336c70f79388626e2d576ab7 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:29 +0100
|
||||
Subject: [PATCH 10/16] net: dsa: qca8k: add support for mgmt read/write in
|
||||
Ethernet packet
|
||||
|
||||
Add qca8k side support for mgmt read/write in Ethernet packet.
|
||||
qca8k supports some specially crafted Ethernet packet that can be used
|
||||
for mgmt read/write instead of the legacy method uart/internal mdio.
|
||||
This add support for the qca8k side to craft the packet and enqueue it.
|
||||
Each port and the qca8k_priv have a special struct to put data in it.
|
||||
The completion API is used to wait for the packet to be received back
|
||||
with the requested data.
|
||||
|
||||
The various steps are:
|
||||
1. Craft the special packet with the qca hdr set to mgmt read/write
|
||||
mode.
|
||||
2. Set the lock in the dedicated mgmt struct.
|
||||
3. Increment the seq number and set it in the mgmt pkt
|
||||
4. Reinit the completion.
|
||||
5. Enqueue the packet.
|
||||
6. Wait the packet to be received.
|
||||
7. Use the data set by the tagger to complete the mdio operation.
|
||||
|
||||
If the completion timeouts or the ack value is not true, the legacy
|
||||
mdio way is used.
|
||||
|
||||
It has to be considered that in the initial setup mdio is still used and
|
||||
mdio is still used until DSA is ready to accept and tag packet.
|
||||
|
||||
tag_proto_connect() is used to fill the required handler for the tagger
|
||||
to correctly parse and elaborate the special Ethernet mdio packet.
|
||||
|
||||
Locking is added to qca8k_master_change() to make sure no mgmt Ethernet
|
||||
are in progress.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 225 ++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 13 +++
|
||||
2 files changed, 238 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/etherdevice.h>
|
||||
+#include <linux/dsa/tag_qca.h>
|
||||
|
||||
#include "qca8k.h"
|
||||
|
||||
@@ -170,6 +171,194 @@ qca8k_rmw(struct qca8k_priv *priv, u32 r
|
||||
return regmap_update_bits(priv->regmap, reg, mask, write_val);
|
||||
}
|
||||
|
||||
+static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct qca8k_mgmt_eth_data *mgmt_eth_data;
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ struct qca_mgmt_ethhdr *mgmt_ethhdr;
|
||||
+ u8 len, cmd;
|
||||
+
|
||||
+ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb);
|
||||
+ mgmt_eth_data = &priv->mgmt_eth_data;
|
||||
+
|
||||
+ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command);
|
||||
+ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command);
|
||||
+
|
||||
+ /* Make sure the seq match the requested packet */
|
||||
+ if (mgmt_ethhdr->seq == mgmt_eth_data->seq)
|
||||
+ mgmt_eth_data->ack = true;
|
||||
+
|
||||
+ if (cmd == MDIO_READ) {
|
||||
+ mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data;
|
||||
+
|
||||
+ /* Get the rest of the 12 byte of data */
|
||||
+ if (len > QCA_HDR_MGMT_DATA1_LEN)
|
||||
+ memcpy(mgmt_eth_data->data + 1, skb->data,
|
||||
+ QCA_HDR_MGMT_DATA2_LEN);
|
||||
+ }
|
||||
+
|
||||
+ complete(&mgmt_eth_data->rw_done);
|
||||
+}
|
||||
+
|
||||
+static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
|
||||
+ int priority)
|
||||
+{
|
||||
+ struct qca_mgmt_ethhdr *mgmt_ethhdr;
|
||||
+ struct sk_buff *skb;
|
||||
+ u16 hdr;
|
||||
+
|
||||
+ skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN);
|
||||
+ if (!skb)
|
||||
+ return NULL;
|
||||
+
|
||||
+ skb_reset_mac_header(skb);
|
||||
+ skb_set_network_header(skb, skb->len);
|
||||
+
|
||||
+ mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN);
|
||||
+
|
||||
+ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION);
|
||||
+ hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority);
|
||||
+ hdr |= QCA_HDR_XMIT_FROM_CPU;
|
||||
+ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0));
|
||||
+ hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);
|
||||
+
|
||||
+ mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg);
|
||||
+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, 4);
|
||||
+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd);
|
||||
+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE,
|
||||
+ QCA_HDR_MGMT_CHECK_CODE_VAL);
|
||||
+
|
||||
+ if (cmd == MDIO_WRITE)
|
||||
+ mgmt_ethhdr->mdio_data = *val;
|
||||
+
|
||||
+ mgmt_ethhdr->hdr = htons(hdr);
|
||||
+
|
||||
+ skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
|
||||
+
|
||||
+ return skb;
|
||||
+}
|
||||
+
|
||||
+static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num)
|
||||
+{
|
||||
+ struct qca_mgmt_ethhdr *mgmt_ethhdr;
|
||||
+
|
||||
+ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data;
|
||||
+ mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num);
|
||||
+}
|
||||
+
|
||||
+static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
|
||||
+{
|
||||
+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
|
||||
+ struct sk_buff *skb;
|
||||
+ bool ack;
|
||||
+ int ret;
|
||||
+
|
||||
+ skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL,
|
||||
+ QCA8K_ETHERNET_MDIO_PRIORITY);
|
||||
+ if (!skb)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mutex_lock(&mgmt_eth_data->mutex);
|
||||
+
|
||||
+ /* Check mgmt_master if is operational */
|
||||
+ if (!priv->mgmt_master) {
|
||||
+ kfree_skb(skb);
|
||||
+ mutex_unlock(&mgmt_eth_data->mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ skb->dev = priv->mgmt_master;
|
||||
+
|
||||
+ reinit_completion(&mgmt_eth_data->rw_done);
|
||||
+
|
||||
+ /* Increment seq_num and set it in the mdio pkt */
|
||||
+ mgmt_eth_data->seq++;
|
||||
+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
|
||||
+ mgmt_eth_data->ack = false;
|
||||
+
|
||||
+ dev_queue_xmit(skb);
|
||||
+
|
||||
+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
|
||||
+ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT));
|
||||
+
|
||||
+ *val = mgmt_eth_data->data[0];
|
||||
+ ack = mgmt_eth_data->ack;
|
||||
+
|
||||
+ mutex_unlock(&mgmt_eth_data->mutex);
|
||||
+
|
||||
+ if (ret <= 0)
|
||||
+ return -ETIMEDOUT;
|
||||
+
|
||||
+ if (!ack)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
+{
|
||||
+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
|
||||
+ struct sk_buff *skb;
|
||||
+ bool ack;
|
||||
+ int ret;
|
||||
+
|
||||
+ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val,
|
||||
+ QCA8K_ETHERNET_MDIO_PRIORITY);
|
||||
+ if (!skb)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mutex_lock(&mgmt_eth_data->mutex);
|
||||
+
|
||||
+ /* Check mgmt_master if is operational */
|
||||
+ if (!priv->mgmt_master) {
|
||||
+ kfree_skb(skb);
|
||||
+ mutex_unlock(&mgmt_eth_data->mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ skb->dev = priv->mgmt_master;
|
||||
+
|
||||
+ reinit_completion(&mgmt_eth_data->rw_done);
|
||||
+
|
||||
+ /* Increment seq_num and set it in the mdio pkt */
|
||||
+ mgmt_eth_data->seq++;
|
||||
+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
|
||||
+ mgmt_eth_data->ack = false;
|
||||
+
|
||||
+ dev_queue_xmit(skb);
|
||||
+
|
||||
+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
|
||||
+ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT));
|
||||
+
|
||||
+ ack = mgmt_eth_data->ack;
|
||||
+
|
||||
+ mutex_unlock(&mgmt_eth_data->mutex);
|
||||
+
|
||||
+ if (ret <= 0)
|
||||
+ return -ETIMEDOUT;
|
||||
+
|
||||
+ if (!ack)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
|
||||
+{
|
||||
+ u32 val = 0;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = qca8k_read_eth(priv, reg, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ val &= ~mask;
|
||||
+ val |= write_val;
|
||||
+
|
||||
+ return qca8k_write_eth(priv, reg, val);
|
||||
+}
|
||||
+
|
||||
static int
|
||||
qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val)
|
||||
{
|
||||
@@ -178,6 +367,9 @@ qca8k_regmap_read(void *ctx, uint32_t re
|
||||
u16 r1, r2, page;
|
||||
int ret;
|
||||
|
||||
+ if (!qca8k_read_eth(priv, reg, val))
|
||||
+ return 0;
|
||||
+
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
@@ -201,6 +393,9 @@ qca8k_regmap_write(void *ctx, uint32_t r
|
||||
u16 r1, r2, page;
|
||||
int ret;
|
||||
|
||||
+ if (!qca8k_write_eth(priv, reg, val))
|
||||
+ return 0;
|
||||
+
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
@@ -225,6 +420,9 @@ qca8k_regmap_update_bits(void *ctx, uint
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
+ if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val))
|
||||
+ return 0;
|
||||
+
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
@@ -2393,7 +2591,30 @@ qca8k_master_change(struct dsa_switch *d
|
||||
if (dp->index != 0)
|
||||
return;
|
||||
|
||||
+ mutex_lock(&priv->mgmt_eth_data.mutex);
|
||||
+
|
||||
priv->mgmt_master = operational ? (struct net_device *)master : NULL;
|
||||
+
|
||||
+ mutex_unlock(&priv->mgmt_eth_data.mutex);
|
||||
+}
|
||||
+
|
||||
+static int qca8k_connect_tag_protocol(struct dsa_switch *ds,
|
||||
+ enum dsa_tag_protocol proto)
|
||||
+{
|
||||
+ struct qca_tagger_data *tagger_data;
|
||||
+
|
||||
+ switch (proto) {
|
||||
+ case DSA_TAG_PROTO_QCA:
|
||||
+ tagger_data = ds->tagger_data;
|
||||
+
|
||||
+ tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler;
|
||||
+
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static const struct dsa_switch_ops qca8k_switch_ops = {
|
||||
@@ -2432,6 +2653,7 @@ static const struct dsa_switch_ops qca8k
|
||||
.port_lag_join = qca8k_port_lag_join,
|
||||
.port_lag_leave = qca8k_port_lag_leave,
|
||||
.master_state_change = qca8k_master_change,
|
||||
+ .connect_tag_protocol = qca8k_connect_tag_protocol,
|
||||
};
|
||||
|
||||
static int qca8k_read_switch_id(struct qca8k_priv *priv)
|
||||
@@ -2511,6 +2733,9 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
if (!priv->ds)
|
||||
return -ENOMEM;
|
||||
|
||||
+ mutex_init(&priv->mgmt_eth_data.mutex);
|
||||
+ init_completion(&priv->mgmt_eth_data.rw_done);
|
||||
+
|
||||
priv->ds->dev = &mdiodev->dev;
|
||||
priv->ds->num_ports = QCA8K_NUM_PORTS;
|
||||
priv->ds->priv = priv;
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -11,6 +11,10 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/gpio.h>
|
||||
+#include <linux/dsa/tag_qca.h>
|
||||
+
|
||||
+#define QCA8K_ETHERNET_MDIO_PRIORITY 7
|
||||
+#define QCA8K_ETHERNET_TIMEOUT 100
|
||||
|
||||
#define QCA8K_NUM_PORTS 7
|
||||
#define QCA8K_NUM_CPU_PORTS 2
|
||||
@@ -328,6 +332,14 @@ enum {
|
||||
QCA8K_CPU_PORT6,
|
||||
};
|
||||
|
||||
+struct qca8k_mgmt_eth_data {
|
||||
+ struct completion rw_done;
|
||||
+ struct mutex mutex; /* Enforce one mdio read/write at time */
|
||||
+ bool ack;
|
||||
+ u32 seq;
|
||||
+ u32 data[4];
|
||||
+};
|
||||
+
|
||||
struct qca8k_ports_config {
|
||||
bool sgmii_rx_clk_falling_edge;
|
||||
bool sgmii_tx_clk_falling_edge;
|
||||
@@ -354,6 +366,7 @@ struct qca8k_priv {
|
||||
struct gpio_desc *reset_gpio;
|
||||
unsigned int port_mtu[QCA8K_NUM_PORTS];
|
||||
struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
|
||||
+ struct qca8k_mgmt_eth_data mgmt_eth_data;
|
||||
};
|
||||
|
||||
struct qca8k_mib_desc {
|
||||
@ -0,0 +1,226 @@
|
||||
From 5c957c7ca78cce5e4b96866722b0115bd758d945 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:30 +0100
|
||||
Subject: [PATCH 11/16] net: dsa: qca8k: add support for mib autocast in
|
||||
Ethernet packet
|
||||
|
||||
The switch can autocast MIB counter using Ethernet packet.
|
||||
Add support for this and provide a handler for the tagger.
|
||||
The switch will send packet with MIB counter for each port, the switch
|
||||
will use completion API to wait for the correct packet to be received
|
||||
and will complete the task only when each packet is received.
|
||||
Although the handler will drop all the other packet, we still have to
|
||||
consume each MIB packet to complete the request. This is done to prevent
|
||||
mixed data with concurrent ethtool request.
|
||||
|
||||
connect_tag_protocol() is used to add the handler to the tag_qca tagger,
|
||||
master_state_change() use the MIB lock to make sure no MIB Ethernet is
|
||||
in progress.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 106 +++++++++++++++++++++++++++++++++++++++-
|
||||
drivers/net/dsa/qca8k.h | 17 ++++++-
|
||||
2 files changed, 121 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -830,7 +830,10 @@ qca8k_mib_init(struct qca8k_priv *priv)
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY);
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
|
||||
+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
|
||||
+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) |
|
||||
+ QCA8K_MIB_BUSY);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -1901,6 +1904,97 @@ qca8k_get_strings(struct dsa_switch *ds,
|
||||
ETH_GSTRING_LEN);
|
||||
}
|
||||
|
||||
+static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb)
|
||||
+{
|
||||
+ const struct qca8k_match_data *match_data;
|
||||
+ struct qca8k_mib_eth_data *mib_eth_data;
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ const struct qca8k_mib_desc *mib;
|
||||
+ struct mib_ethhdr *mib_ethhdr;
|
||||
+ int i, mib_len, offset = 0;
|
||||
+ u64 *data;
|
||||
+ u8 port;
|
||||
+
|
||||
+ mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb);
|
||||
+ mib_eth_data = &priv->mib_eth_data;
|
||||
+
|
||||
+ /* The switch autocast every port. Ignore other packet and
|
||||
+ * parse only the requested one.
|
||||
+ */
|
||||
+ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr));
|
||||
+ if (port != mib_eth_data->req_port)
|
||||
+ goto exit;
|
||||
+
|
||||
+ match_data = device_get_match_data(priv->dev);
|
||||
+ data = mib_eth_data->data;
|
||||
+
|
||||
+ for (i = 0; i < match_data->mib_count; i++) {
|
||||
+ mib = &ar8327_mib[i];
|
||||
+
|
||||
+ /* First 3 mib are present in the skb head */
|
||||
+ if (i < 3) {
|
||||
+ data[i] = mib_ethhdr->data[i];
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ mib_len = sizeof(uint32_t);
|
||||
+
|
||||
+ /* Some mib are 64 bit wide */
|
||||
+ if (mib->size == 2)
|
||||
+ mib_len = sizeof(uint64_t);
|
||||
+
|
||||
+ /* Copy the mib value from packet to the */
|
||||
+ memcpy(data + i, skb->data + offset, mib_len);
|
||||
+
|
||||
+ /* Set the offset for the next mib */
|
||||
+ offset += mib_len;
|
||||
+ }
|
||||
+
|
||||
+exit:
|
||||
+ /* Complete on receiving all the mib packet */
|
||||
+ if (refcount_dec_and_test(&mib_eth_data->port_parsed))
|
||||
+ complete(&mib_eth_data->rw_done);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
|
||||
+{
|
||||
+ struct dsa_port *dp = dsa_to_port(ds, port);
|
||||
+ struct qca8k_mib_eth_data *mib_eth_data;
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ mib_eth_data = &priv->mib_eth_data;
|
||||
+
|
||||
+ mutex_lock(&mib_eth_data->mutex);
|
||||
+
|
||||
+ reinit_completion(&mib_eth_data->rw_done);
|
||||
+
|
||||
+ mib_eth_data->req_port = dp->index;
|
||||
+ mib_eth_data->data = data;
|
||||
+ refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS);
|
||||
+
|
||||
+ mutex_lock(&priv->reg_mutex);
|
||||
+
|
||||
+ /* Send mib autocast request */
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB,
|
||||
+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY,
|
||||
+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) |
|
||||
+ QCA8K_MIB_BUSY);
|
||||
+
|
||||
+ mutex_unlock(&priv->reg_mutex);
|
||||
+
|
||||
+ if (ret)
|
||||
+ goto exit;
|
||||
+
|
||||
+ ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT);
|
||||
+
|
||||
+exit:
|
||||
+ mutex_unlock(&mib_eth_data->mutex);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
|
||||
uint64_t *data)
|
||||
@@ -1912,6 +2006,10 @@ qca8k_get_ethtool_stats(struct dsa_switc
|
||||
u32 hi = 0;
|
||||
int ret;
|
||||
|
||||
+ if (priv->mgmt_master &&
|
||||
+ qca8k_get_ethtool_stats_eth(ds, port, data) > 0)
|
||||
+ return;
|
||||
+
|
||||
match_data = of_device_get_match_data(priv->dev);
|
||||
|
||||
for (i = 0; i < match_data->mib_count; i++) {
|
||||
@@ -2592,9 +2690,11 @@ qca8k_master_change(struct dsa_switch *d
|
||||
return;
|
||||
|
||||
mutex_lock(&priv->mgmt_eth_data.mutex);
|
||||
+ mutex_lock(&priv->mib_eth_data.mutex);
|
||||
|
||||
priv->mgmt_master = operational ? (struct net_device *)master : NULL;
|
||||
|
||||
+ mutex_unlock(&priv->mib_eth_data.mutex);
|
||||
mutex_unlock(&priv->mgmt_eth_data.mutex);
|
||||
}
|
||||
|
||||
@@ -2608,6 +2708,7 @@ static int qca8k_connect_tag_protocol(st
|
||||
tagger_data = ds->tagger_data;
|
||||
|
||||
tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler;
|
||||
+ tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler;
|
||||
|
||||
break;
|
||||
default:
|
||||
@@ -2736,6 +2837,9 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
mutex_init(&priv->mgmt_eth_data.mutex);
|
||||
init_completion(&priv->mgmt_eth_data.rw_done);
|
||||
|
||||
+ mutex_init(&priv->mib_eth_data.mutex);
|
||||
+ init_completion(&priv->mib_eth_data.rw_done);
|
||||
+
|
||||
priv->ds->dev = &mdiodev->dev;
|
||||
priv->ds->num_ports = QCA8K_NUM_PORTS;
|
||||
priv->ds->priv = priv;
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -67,7 +67,7 @@
|
||||
#define QCA8K_REG_MODULE_EN 0x030
|
||||
#define QCA8K_MODULE_EN_MIB BIT(0)
|
||||
#define QCA8K_REG_MIB 0x034
|
||||
-#define QCA8K_MIB_FLUSH BIT(24)
|
||||
+#define QCA8K_MIB_FUNC GENMASK(26, 24)
|
||||
#define QCA8K_MIB_CPU_KEEP BIT(20)
|
||||
#define QCA8K_MIB_BUSY BIT(17)
|
||||
#define QCA8K_MDIO_MASTER_CTRL 0x3c
|
||||
@@ -317,6 +317,12 @@ enum qca8k_vlan_cmd {
|
||||
QCA8K_VLAN_READ = 6,
|
||||
};
|
||||
|
||||
+enum qca8k_mid_cmd {
|
||||
+ QCA8K_MIB_FLUSH = 1,
|
||||
+ QCA8K_MIB_FLUSH_PORT = 2,
|
||||
+ QCA8K_MIB_CAST = 3,
|
||||
+};
|
||||
+
|
||||
struct ar8xxx_port_status {
|
||||
int enabled;
|
||||
};
|
||||
@@ -340,6 +346,14 @@ struct qca8k_mgmt_eth_data {
|
||||
u32 data[4];
|
||||
};
|
||||
|
||||
+struct qca8k_mib_eth_data {
|
||||
+ struct completion rw_done;
|
||||
+ struct mutex mutex; /* Process one command at time */
|
||||
+ refcount_t port_parsed; /* Counter to track parsed port */
|
||||
+ u8 req_port;
|
||||
+ u64 *data; /* pointer to ethtool data */
|
||||
+};
|
||||
+
|
||||
struct qca8k_ports_config {
|
||||
bool sgmii_rx_clk_falling_edge;
|
||||
bool sgmii_tx_clk_falling_edge;
|
||||
@@ -367,6 +381,7 @@ struct qca8k_priv {
|
||||
unsigned int port_mtu[QCA8K_NUM_PORTS];
|
||||
struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
|
||||
struct qca8k_mgmt_eth_data mgmt_eth_data;
|
||||
+ struct qca8k_mib_eth_data mib_eth_data;
|
||||
};
|
||||
|
||||
struct qca8k_mib_desc {
|
||||
@ -0,0 +1,287 @@
|
||||
From 2cd5485663847d468dc207b3ff85fb1fab44d97f Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:31 +0100
|
||||
Subject: [PATCH 12/16] net: dsa: qca8k: add support for phy read/write with
|
||||
mgmt Ethernet
|
||||
|
||||
Use mgmt Ethernet also for phy read/write if availabale. Use a different
|
||||
seq number to make sure we receive the correct packet.
|
||||
On any error, we fallback to the legacy mdio read/write.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 216 ++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/qca8k.h | 1 +
|
||||
2 files changed, 217 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -867,6 +867,199 @@ qca8k_port_set_status(struct qca8k_priv
|
||||
regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
|
||||
}
|
||||
|
||||
+static int
|
||||
+qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data,
|
||||
+ struct sk_buff *read_skb, u32 *val)
|
||||
+{
|
||||
+ struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL);
|
||||
+ bool ack;
|
||||
+ int ret;
|
||||
+
|
||||
+ reinit_completion(&mgmt_eth_data->rw_done);
|
||||
+
|
||||
+ /* Increment seq_num and set it in the copy pkt */
|
||||
+ mgmt_eth_data->seq++;
|
||||
+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
|
||||
+ mgmt_eth_data->ack = false;
|
||||
+
|
||||
+ dev_queue_xmit(skb);
|
||||
+
|
||||
+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
|
||||
+ QCA8K_ETHERNET_TIMEOUT);
|
||||
+
|
||||
+ ack = mgmt_eth_data->ack;
|
||||
+
|
||||
+ if (ret <= 0)
|
||||
+ return -ETIMEDOUT;
|
||||
+
|
||||
+ if (!ack)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ *val = mgmt_eth_data->data[0];
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy,
|
||||
+ int regnum, u16 data)
|
||||
+{
|
||||
+ struct sk_buff *write_skb, *clear_skb, *read_skb;
|
||||
+ struct qca8k_mgmt_eth_data *mgmt_eth_data;
|
||||
+ u32 write_val, clear_val = 0, val;
|
||||
+ struct net_device *mgmt_master;
|
||||
+ int ret, ret1;
|
||||
+ bool ack;
|
||||
+
|
||||
+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mgmt_eth_data = &priv->mgmt_eth_data;
|
||||
+
|
||||
+ write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN |
|
||||
+ QCA8K_MDIO_MASTER_PHY_ADDR(phy) |
|
||||
+ QCA8K_MDIO_MASTER_REG_ADDR(regnum);
|
||||
+
|
||||
+ if (read) {
|
||||
+ write_val |= QCA8K_MDIO_MASTER_READ;
|
||||
+ } else {
|
||||
+ write_val |= QCA8K_MDIO_MASTER_WRITE;
|
||||
+ write_val |= QCA8K_MDIO_MASTER_DATA(data);
|
||||
+ }
|
||||
+
|
||||
+ /* Prealloc all the needed skb before the lock */
|
||||
+ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ &write_val, QCA8K_ETHERNET_PHY_PRIORITY);
|
||||
+ if (!write_skb)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
|
||||
+ if (!write_skb) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_clear_skb;
|
||||
+ }
|
||||
+
|
||||
+ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL,
|
||||
+ &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
|
||||
+ if (!write_skb) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_read_skb;
|
||||
+ }
|
||||
+
|
||||
+ /* Actually start the request:
|
||||
+ * 1. Send mdio master packet
|
||||
+ * 2. Busy Wait for mdio master command
|
||||
+ * 3. Get the data if we are reading
|
||||
+ * 4. Reset the mdio master (even with error)
|
||||
+ */
|
||||
+ mutex_lock(&mgmt_eth_data->mutex);
|
||||
+
|
||||
+ /* Check if mgmt_master is operational */
|
||||
+ mgmt_master = priv->mgmt_master;
|
||||
+ if (!mgmt_master) {
|
||||
+ mutex_unlock(&mgmt_eth_data->mutex);
|
||||
+ ret = -EINVAL;
|
||||
+ goto err_mgmt_master;
|
||||
+ }
|
||||
+
|
||||
+ read_skb->dev = mgmt_master;
|
||||
+ clear_skb->dev = mgmt_master;
|
||||
+ write_skb->dev = mgmt_master;
|
||||
+
|
||||
+ reinit_completion(&mgmt_eth_data->rw_done);
|
||||
+
|
||||
+ /* Increment seq_num and set it in the write pkt */
|
||||
+ mgmt_eth_data->seq++;
|
||||
+ qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq);
|
||||
+ mgmt_eth_data->ack = false;
|
||||
+
|
||||
+ dev_queue_xmit(write_skb);
|
||||
+
|
||||
+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
|
||||
+ QCA8K_ETHERNET_TIMEOUT);
|
||||
+
|
||||
+ ack = mgmt_eth_data->ack;
|
||||
+
|
||||
+ if (ret <= 0) {
|
||||
+ ret = -ETIMEDOUT;
|
||||
+ kfree_skb(read_skb);
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ if (!ack) {
|
||||
+ ret = -EINVAL;
|
||||
+ kfree_skb(read_skb);
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1,
|
||||
+ !(val & QCA8K_MDIO_MASTER_BUSY), 0,
|
||||
+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false,
|
||||
+ mgmt_eth_data, read_skb, &val);
|
||||
+
|
||||
+ if (ret < 0 && ret1 < 0) {
|
||||
+ ret = ret1;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ if (read) {
|
||||
+ reinit_completion(&mgmt_eth_data->rw_done);
|
||||
+
|
||||
+ /* Increment seq_num and set it in the read pkt */
|
||||
+ mgmt_eth_data->seq++;
|
||||
+ qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq);
|
||||
+ mgmt_eth_data->ack = false;
|
||||
+
|
||||
+ dev_queue_xmit(read_skb);
|
||||
+
|
||||
+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
|
||||
+ QCA8K_ETHERNET_TIMEOUT);
|
||||
+
|
||||
+ ack = mgmt_eth_data->ack;
|
||||
+
|
||||
+ if (ret <= 0) {
|
||||
+ ret = -ETIMEDOUT;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ if (!ack) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK;
|
||||
+ } else {
|
||||
+ kfree_skb(read_skb);
|
||||
+ }
|
||||
+exit:
|
||||
+ reinit_completion(&mgmt_eth_data->rw_done);
|
||||
+
|
||||
+ /* Increment seq_num and set it in the clear pkt */
|
||||
+ mgmt_eth_data->seq++;
|
||||
+ qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq);
|
||||
+ mgmt_eth_data->ack = false;
|
||||
+
|
||||
+ dev_queue_xmit(clear_skb);
|
||||
+
|
||||
+ wait_for_completion_timeout(&mgmt_eth_data->rw_done,
|
||||
+ QCA8K_ETHERNET_TIMEOUT);
|
||||
+
|
||||
+ mutex_unlock(&mgmt_eth_data->mutex);
|
||||
+
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Error handling before lock */
|
||||
+err_mgmt_master:
|
||||
+ kfree_skb(read_skb);
|
||||
+err_read_skb:
|
||||
+ kfree_skb(clear_skb);
|
||||
+err_clear_skb:
|
||||
+ kfree_skb(write_skb);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static u32
|
||||
qca8k_port_to_phy(int port)
|
||||
{
|
||||
@@ -989,6 +1182,12 @@ qca8k_internal_mdio_write(struct mii_bus
|
||||
{
|
||||
struct qca8k_priv *priv = slave_bus->priv;
|
||||
struct mii_bus *bus = priv->bus;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Use mdio Ethernet when available, fallback to legacy one on error */
|
||||
+ ret = qca8k_phy_eth_command(priv, false, phy, regnum, data);
|
||||
+ if (!ret)
|
||||
+ return 0;
|
||||
|
||||
return qca8k_mdio_write(bus, phy, regnum, data);
|
||||
}
|
||||
@@ -998,6 +1197,12 @@ qca8k_internal_mdio_read(struct mii_bus
|
||||
{
|
||||
struct qca8k_priv *priv = slave_bus->priv;
|
||||
struct mii_bus *bus = priv->bus;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Use mdio Ethernet when available, fallback to legacy one on error */
|
||||
+ ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0);
|
||||
+ if (ret >= 0)
|
||||
+ return ret;
|
||||
|
||||
return qca8k_mdio_read(bus, phy, regnum);
|
||||
}
|
||||
@@ -1006,6 +1211,7 @@ static int
|
||||
qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data)
|
||||
{
|
||||
struct qca8k_priv *priv = ds->priv;
|
||||
+ int ret;
|
||||
|
||||
/* Check if the legacy mapping should be used and the
|
||||
* port is not correctly mapped to the right PHY in the
|
||||
@@ -1014,6 +1220,11 @@ qca8k_phy_write(struct dsa_switch *ds, i
|
||||
if (priv->legacy_phy_port_mapping)
|
||||
port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
|
||||
+ /* Use mdio Ethernet when available, fallback to legacy one on error */
|
||||
+ ret = qca8k_phy_eth_command(priv, false, port, regnum, 0);
|
||||
+ if (!ret)
|
||||
+ return ret;
|
||||
+
|
||||
return qca8k_mdio_write(priv->bus, port, regnum, data);
|
||||
}
|
||||
|
||||
@@ -1030,6 +1241,11 @@ qca8k_phy_read(struct dsa_switch *ds, in
|
||||
if (priv->legacy_phy_port_mapping)
|
||||
port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
|
||||
|
||||
+ /* Use mdio Ethernet when available, fallback to legacy one on error */
|
||||
+ ret = qca8k_phy_eth_command(priv, true, port, regnum, 0);
|
||||
+ if (ret >= 0)
|
||||
+ return ret;
|
||||
+
|
||||
ret = qca8k_mdio_read(priv->bus, port, regnum);
|
||||
|
||||
if (ret < 0)
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/dsa/tag_qca.h>
|
||||
|
||||
#define QCA8K_ETHERNET_MDIO_PRIORITY 7
|
||||
+#define QCA8K_ETHERNET_PHY_PRIORITY 6
|
||||
#define QCA8K_ETHERNET_TIMEOUT 100
|
||||
|
||||
#define QCA8K_NUM_PORTS 7
|
||||
@ -0,0 +1,208 @@
|
||||
From 4264350acb75430d5021a1d7de56a33faf69a097 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:32 +0100
|
||||
Subject: [PATCH 13/16] net: dsa: qca8k: move page cache to driver priv
|
||||
|
||||
There can be multiple qca8k switch on the same system. Move the static
|
||||
qca8k_current_page to qca8k_priv and make it specific for each switch.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 42 ++++++++++++++++++++---------------------
|
||||
drivers/net/dsa/qca8k.h | 9 +++++++++
|
||||
2 files changed, 29 insertions(+), 22 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -75,12 +75,6 @@ static const struct qca8k_mib_desc ar832
|
||||
MIB_DESC(1, 0xac, "TXUnicast"),
|
||||
};
|
||||
|
||||
-/* The 32bit switch registers are accessed indirectly. To achieve this we need
|
||||
- * to set the page of the register. Track the last page that was set to reduce
|
||||
- * mdio writes
|
||||
- */
|
||||
-static u16 qca8k_current_page = 0xffff;
|
||||
-
|
||||
static void
|
||||
qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
|
||||
{
|
||||
@@ -134,11 +128,13 @@ qca8k_mii_write32(struct mii_bus *bus, i
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_set_page(struct mii_bus *bus, u16 page)
|
||||
+qca8k_set_page(struct qca8k_priv *priv, u16 page)
|
||||
{
|
||||
+ u16 *cached_page = &priv->mdio_cache.page;
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
int ret;
|
||||
|
||||
- if (page == qca8k_current_page)
|
||||
+ if (page == *cached_page)
|
||||
return 0;
|
||||
|
||||
ret = bus->write(bus, 0x18, 0, page);
|
||||
@@ -148,7 +144,7 @@ qca8k_set_page(struct mii_bus *bus, u16
|
||||
return ret;
|
||||
}
|
||||
|
||||
- qca8k_current_page = page;
|
||||
+ *cached_page = page;
|
||||
usleep_range(1000, 2000);
|
||||
return 0;
|
||||
}
|
||||
@@ -374,7 +370,7 @@ qca8k_regmap_read(void *ctx, uint32_t re
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- ret = qca8k_set_page(bus, page);
|
||||
+ ret = qca8k_set_page(priv, page);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
@@ -400,7 +396,7 @@ qca8k_regmap_write(void *ctx, uint32_t r
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- ret = qca8k_set_page(bus, page);
|
||||
+ ret = qca8k_set_page(priv, page);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
@@ -427,7 +423,7 @@ qca8k_regmap_update_bits(void *ctx, uint
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- ret = qca8k_set_page(bus, page);
|
||||
+ ret = qca8k_set_page(priv, page);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
@@ -1098,8 +1094,9 @@ qca8k_mdio_busy_wait(struct mii_bus *bus
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_mdio_write(struct mii_bus *bus, int phy, int regnum, u16 data)
|
||||
+qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data)
|
||||
{
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
u32 val;
|
||||
int ret;
|
||||
@@ -1116,7 +1113,7 @@ qca8k_mdio_write(struct mii_bus *bus, in
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- ret = qca8k_set_page(bus, page);
|
||||
+ ret = qca8k_set_page(priv, page);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -1135,8 +1132,9 @@ exit:
|
||||
}
|
||||
|
||||
static int
|
||||
-qca8k_mdio_read(struct mii_bus *bus, int phy, int regnum)
|
||||
+qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum)
|
||||
{
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
u16 r1, r2, page;
|
||||
u32 val;
|
||||
int ret;
|
||||
@@ -1152,7 +1150,7 @@ qca8k_mdio_read(struct mii_bus *bus, int
|
||||
|
||||
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
|
||||
|
||||
- ret = qca8k_set_page(bus, page);
|
||||
+ ret = qca8k_set_page(priv, page);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -1181,7 +1179,6 @@ static int
|
||||
qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data)
|
||||
{
|
||||
struct qca8k_priv *priv = slave_bus->priv;
|
||||
- struct mii_bus *bus = priv->bus;
|
||||
int ret;
|
||||
|
||||
/* Use mdio Ethernet when available, fallback to legacy one on error */
|
||||
@@ -1189,14 +1186,13 @@ qca8k_internal_mdio_write(struct mii_bus
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
- return qca8k_mdio_write(bus, phy, regnum, data);
|
||||
+ return qca8k_mdio_write(priv, phy, regnum, data);
|
||||
}
|
||||
|
||||
static int
|
||||
qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum)
|
||||
{
|
||||
struct qca8k_priv *priv = slave_bus->priv;
|
||||
- struct mii_bus *bus = priv->bus;
|
||||
int ret;
|
||||
|
||||
/* Use mdio Ethernet when available, fallback to legacy one on error */
|
||||
@@ -1204,7 +1200,7 @@ qca8k_internal_mdio_read(struct mii_bus
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
- return qca8k_mdio_read(bus, phy, regnum);
|
||||
+ return qca8k_mdio_read(priv, phy, regnum);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1225,7 +1221,7 @@ qca8k_phy_write(struct dsa_switch *ds, i
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
- return qca8k_mdio_write(priv->bus, port, regnum, data);
|
||||
+ return qca8k_mdio_write(priv, port, regnum, data);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1246,7 +1242,7 @@ qca8k_phy_read(struct dsa_switch *ds, in
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
- ret = qca8k_mdio_read(priv->bus, port, regnum);
|
||||
+ ret = qca8k_mdio_read(priv, port, regnum);
|
||||
|
||||
if (ret < 0)
|
||||
return 0xffff;
|
||||
@@ -3041,6 +3037,8 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
return PTR_ERR(priv->regmap);
|
||||
}
|
||||
|
||||
+ priv->mdio_cache.page = 0xffff;
|
||||
+
|
||||
/* Check the detected switch id */
|
||||
ret = qca8k_read_switch_id(priv);
|
||||
if (ret)
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -363,6 +363,14 @@ struct qca8k_ports_config {
|
||||
u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||||
};
|
||||
|
||||
+struct qca8k_mdio_cache {
|
||||
+/* The 32bit switch registers are accessed indirectly. To achieve this we need
|
||||
+ * to set the page of the register. Track the last page that was set to reduce
|
||||
+ * mdio writes
|
||||
+ */
|
||||
+ u16 page;
|
||||
+};
|
||||
+
|
||||
struct qca8k_priv {
|
||||
u8 switch_id;
|
||||
u8 switch_revision;
|
||||
@@ -383,6 +391,7 @@ struct qca8k_priv {
|
||||
struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */
|
||||
struct qca8k_mgmt_eth_data mgmt_eth_data;
|
||||
struct qca8k_mib_eth_data mib_eth_data;
|
||||
+ struct qca8k_mdio_cache mdio_cache;
|
||||
};
|
||||
|
||||
struct qca8k_mib_desc {
|
||||
@ -0,0 +1,164 @@
|
||||
From 2481d206fae7884cd07014fd1318e63af35e99eb Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:33 +0100
|
||||
Subject: [PATCH 14/16] net: dsa: qca8k: cache lo and hi for mdio write
|
||||
|
||||
From Documentation, we can cache lo and hi the same way we do with the
|
||||
page. This massively reduce the mdio write as 3/4 of the time as we only
|
||||
require to write the lo or hi part for a mdio write.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 61 +++++++++++++++++++++++++++++++++--------
|
||||
drivers/net/dsa/qca8k.h | 5 ++++
|
||||
2 files changed, 54 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -89,6 +89,44 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u
|
||||
}
|
||||
|
||||
static int
|
||||
+qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo)
|
||||
+{
|
||||
+ u16 *cached_lo = &priv->mdio_cache.lo;
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (lo == *cached_lo)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = bus->write(bus, phy_id, regnum, lo);
|
||||
+ if (ret < 0)
|
||||
+ dev_err_ratelimited(&bus->dev,
|
||||
+ "failed to write qca8k 32bit lo register\n");
|
||||
+
|
||||
+ *cached_lo = lo;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi)
|
||||
+{
|
||||
+ u16 *cached_hi = &priv->mdio_cache.hi;
|
||||
+ struct mii_bus *bus = priv->bus;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (hi == *cached_hi)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = bus->write(bus, phy_id, regnum, hi);
|
||||
+ if (ret < 0)
|
||||
+ dev_err_ratelimited(&bus->dev,
|
||||
+ "failed to write qca8k 32bit hi register\n");
|
||||
+
|
||||
+ *cached_hi = hi;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val)
|
||||
{
|
||||
int ret;
|
||||
@@ -111,7 +149,7 @@ qca8k_mii_read32(struct mii_bus *bus, in
|
||||
}
|
||||
|
||||
static void
|
||||
-qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)
|
||||
+qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val)
|
||||
{
|
||||
u16 lo, hi;
|
||||
int ret;
|
||||
@@ -119,12 +157,9 @@ qca8k_mii_write32(struct mii_bus *bus, i
|
||||
lo = val & 0xffff;
|
||||
hi = (u16)(val >> 16);
|
||||
|
||||
- ret = bus->write(bus, phy_id, regnum, lo);
|
||||
+ ret = qca8k_set_lo(priv, phy_id, regnum, lo);
|
||||
if (ret >= 0)
|
||||
- ret = bus->write(bus, phy_id, regnum + 1, hi);
|
||||
- if (ret < 0)
|
||||
- dev_err_ratelimited(&bus->dev,
|
||||
- "failed to write qca8k 32bit register\n");
|
||||
+ ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -400,7 +435,7 @@ qca8k_regmap_write(void *ctx, uint32_t r
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
- qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
+ qca8k_mii_write32(priv, 0x10 | r2, r1, val);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
@@ -433,7 +468,7 @@ qca8k_regmap_update_bits(void *ctx, uint
|
||||
|
||||
val &= ~mask;
|
||||
val |= write_val;
|
||||
- qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
+ qca8k_mii_write32(priv, 0x10 | r2, r1, val);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
@@ -1117,14 +1152,14 @@ qca8k_mdio_write(struct qca8k_priv *priv
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
- qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
+ qca8k_mii_write32(priv, 0x10 | r2, r1, val);
|
||||
|
||||
ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_BUSY);
|
||||
|
||||
exit:
|
||||
/* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
- qca8k_mii_write32(bus, 0x10 | r2, r1, 0);
|
||||
+ qca8k_mii_write32(priv, 0x10 | r2, r1, 0);
|
||||
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
@@ -1154,7 +1189,7 @@ qca8k_mdio_read(struct qca8k_priv *priv,
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
- qca8k_mii_write32(bus, 0x10 | r2, r1, val);
|
||||
+ qca8k_mii_write32(priv, 0x10 | r2, r1, val);
|
||||
|
||||
ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
|
||||
QCA8K_MDIO_MASTER_BUSY);
|
||||
@@ -1165,7 +1200,7 @@ qca8k_mdio_read(struct qca8k_priv *priv,
|
||||
|
||||
exit:
|
||||
/* even if the busy_wait timeouts try to clear the MASTER_EN */
|
||||
- qca8k_mii_write32(bus, 0x10 | r2, r1, 0);
|
||||
+ qca8k_mii_write32(priv, 0x10 | r2, r1, 0);
|
||||
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
@@ -3038,6 +3073,8 @@ qca8k_sw_probe(struct mdio_device *mdiod
|
||||
}
|
||||
|
||||
priv->mdio_cache.page = 0xffff;
|
||||
+ priv->mdio_cache.lo = 0xffff;
|
||||
+ priv->mdio_cache.hi = 0xffff;
|
||||
|
||||
/* Check the detected switch id */
|
||||
ret = qca8k_read_switch_id(priv);
|
||||
--- a/drivers/net/dsa/qca8k.h
|
||||
+++ b/drivers/net/dsa/qca8k.h
|
||||
@@ -369,6 +369,11 @@ struct qca8k_mdio_cache {
|
||||
* mdio writes
|
||||
*/
|
||||
u16 page;
|
||||
+/* lo and hi can also be cached and from Documentation we can skip one
|
||||
+ * extra mdio write if lo or hi is didn't change.
|
||||
+ */
|
||||
+ u16 lo;
|
||||
+ u16 hi;
|
||||
};
|
||||
|
||||
struct qca8k_priv {
|
||||
@ -0,0 +1,206 @@
|
||||
From 90386223f44e2a751d7e9e9ac8f78ea33358a891 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Wed, 2 Feb 2022 01:03:34 +0100
|
||||
Subject: [PATCH 15/16] net: dsa: qca8k: add support for larger read/write size
|
||||
with mgmt Ethernet
|
||||
|
||||
mgmt Ethernet packet can read/write up to 16byte at times. The len reg
|
||||
is limited to 15 (0xf). The switch actually sends and accepts data in 4
|
||||
different steps of len values.
|
||||
Len steps:
|
||||
- 0: nothing
|
||||
- 1-4: first 4 byte
|
||||
- 5-6: first 12 byte
|
||||
- 7-15: all 16 byte
|
||||
|
||||
In the alloc skb function we check if the len is 16 and we fix it to a
|
||||
len of 15. It the read/write function interest to extract the real asked
|
||||
data. The tagger handler will always copy the fully 16byte with a READ
|
||||
command. This is useful for some big regs like the fdb reg that are
|
||||
more than 4byte of data. This permits to introduce a bulk function that
|
||||
will send and request the entire entry in one go.
|
||||
Write function is changed and it does now require to pass the pointer to
|
||||
val to also handle array val.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/qca8k.c | 61 +++++++++++++++++++++++++++--------------
|
||||
1 file changed, 41 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca8k.c
|
||||
+++ b/drivers/net/dsa/qca8k.c
|
||||
@@ -222,7 +222,9 @@ static void qca8k_rw_reg_ack_handler(str
|
||||
if (cmd == MDIO_READ) {
|
||||
mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data;
|
||||
|
||||
- /* Get the rest of the 12 byte of data */
|
||||
+ /* Get the rest of the 12 byte of data.
|
||||
+ * The read/write function will extract the requested data.
|
||||
+ */
|
||||
if (len > QCA_HDR_MGMT_DATA1_LEN)
|
||||
memcpy(mgmt_eth_data->data + 1, skb->data,
|
||||
QCA_HDR_MGMT_DATA2_LEN);
|
||||
@@ -232,16 +234,30 @@ static void qca8k_rw_reg_ack_handler(str
|
||||
}
|
||||
|
||||
static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val,
|
||||
- int priority)
|
||||
+ int priority, unsigned int len)
|
||||
{
|
||||
struct qca_mgmt_ethhdr *mgmt_ethhdr;
|
||||
+ unsigned int real_len;
|
||||
struct sk_buff *skb;
|
||||
+ u32 *data2;
|
||||
u16 hdr;
|
||||
|
||||
skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
+ /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte
|
||||
+ * Actually for some reason the steps are:
|
||||
+ * 0: nothing
|
||||
+ * 1-4: first 4 byte
|
||||
+ * 5-6: first 12 byte
|
||||
+ * 7-15: all 16 byte
|
||||
+ */
|
||||
+ if (len == 16)
|
||||
+ real_len = 15;
|
||||
+ else
|
||||
+ real_len = len;
|
||||
+
|
||||
skb_reset_mac_header(skb);
|
||||
skb_set_network_header(skb, skb->len);
|
||||
|
||||
@@ -254,7 +270,7 @@ static struct sk_buff *qca8k_alloc_mdio_
|
||||
hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG);
|
||||
|
||||
mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg);
|
||||
- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, 4);
|
||||
+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len);
|
||||
mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd);
|
||||
mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE,
|
||||
QCA_HDR_MGMT_CHECK_CODE_VAL);
|
||||
@@ -264,7 +280,9 @@ static struct sk_buff *qca8k_alloc_mdio_
|
||||
|
||||
mgmt_ethhdr->hdr = htons(hdr);
|
||||
|
||||
- skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
|
||||
+ data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN);
|
||||
+ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN)
|
||||
+ memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN);
|
||||
|
||||
return skb;
|
||||
}
|
||||
@@ -277,7 +295,7 @@ static void qca8k_mdio_header_fill_seq_n
|
||||
mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num);
|
||||
}
|
||||
|
||||
-static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val)
|
||||
+static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
{
|
||||
struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
|
||||
struct sk_buff *skb;
|
||||
@@ -285,7 +303,7 @@ static int qca8k_read_eth(struct qca8k_p
|
||||
int ret;
|
||||
|
||||
skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL,
|
||||
- QCA8K_ETHERNET_MDIO_PRIORITY);
|
||||
+ QCA8K_ETHERNET_MDIO_PRIORITY, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -313,6 +331,9 @@ static int qca8k_read_eth(struct qca8k_p
|
||||
msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT));
|
||||
|
||||
*val = mgmt_eth_data->data[0];
|
||||
+ if (len > QCA_HDR_MGMT_DATA1_LEN)
|
||||
+ memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN);
|
||||
+
|
||||
ack = mgmt_eth_data->ack;
|
||||
|
||||
mutex_unlock(&mgmt_eth_data->mutex);
|
||||
@@ -326,15 +347,15 @@ static int qca8k_read_eth(struct qca8k_p
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val)
|
||||
+static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len)
|
||||
{
|
||||
struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data;
|
||||
struct sk_buff *skb;
|
||||
bool ack;
|
||||
int ret;
|
||||
|
||||
- skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val,
|
||||
- QCA8K_ETHERNET_MDIO_PRIORITY);
|
||||
+ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val,
|
||||
+ QCA8K_ETHERNET_MDIO_PRIORITY, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -380,14 +401,14 @@ qca8k_regmap_update_bits_eth(struct qca8
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
||||
- ret = qca8k_read_eth(priv, reg, &val);
|
||||
+ ret = qca8k_read_eth(priv, reg, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val &= ~mask;
|
||||
val |= write_val;
|
||||
|
||||
- return qca8k_write_eth(priv, reg, val);
|
||||
+ return qca8k_write_eth(priv, reg, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -398,7 +419,7 @@ qca8k_regmap_read(void *ctx, uint32_t re
|
||||
u16 r1, r2, page;
|
||||
int ret;
|
||||
|
||||
- if (!qca8k_read_eth(priv, reg, val))
|
||||
+ if (!qca8k_read_eth(priv, reg, val, sizeof(val)))
|
||||
return 0;
|
||||
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
@@ -424,7 +445,7 @@ qca8k_regmap_write(void *ctx, uint32_t r
|
||||
u16 r1, r2, page;
|
||||
int ret;
|
||||
|
||||
- if (!qca8k_write_eth(priv, reg, val))
|
||||
+ if (!qca8k_write_eth(priv, reg, &val, sizeof(val)))
|
||||
return 0;
|
||||
|
||||
qca8k_split_addr(reg, &r1, &r2, &page);
|
||||
@@ -959,21 +980,21 @@ qca8k_phy_eth_command(struct qca8k_priv
|
||||
}
|
||||
|
||||
/* Prealloc all the needed skb before the lock */
|
||||
- write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
|
||||
- &write_val, QCA8K_ETHERNET_PHY_PRIORITY);
|
||||
+ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val,
|
||||
+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val));
|
||||
if (!write_skb)
|
||||
return -ENOMEM;
|
||||
|
||||
- clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL,
|
||||
- &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
|
||||
+ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val,
|
||||
+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val));
|
||||
if (!write_skb) {
|
||||
ret = -ENOMEM;
|
||||
goto err_clear_skb;
|
||||
}
|
||||
|
||||
- read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL,
|
||||
- &clear_val, QCA8K_ETHERNET_PHY_PRIORITY);
|
||||
- if (!write_skb) {
|
||||
+ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val,
|
||||
+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val));
|
||||
+ if (!read_skb) {
|
||||
ret = -ENOMEM;
|
||||
goto err_read_skb;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user