kernel: Remove support for kernel 3.18
No target is using kernel 3.18 anymore, remove all the generic support for kernel 3.18. The removed packages are depending on kernel 3.18 only and are not used on any recent kernel. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
parent
675832de79
commit
1325e74e0c
@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
LINUX_RELEASE?=1
|
LINUX_RELEASE?=1
|
||||||
|
|
||||||
LINUX_VERSION-3.18 = .136
|
|
||||||
LINUX_VERSION-4.9 = .171
|
LINUX_VERSION-4.9 = .171
|
||||||
LINUX_VERSION-4.14 = .114
|
LINUX_VERSION-4.14 = .114
|
||||||
LINUX_VERSION-4.19 = .37
|
LINUX_VERSION-4.19 = .37
|
||||||
|
|
||||||
LINUX_KERNEL_HASH-3.18.136 = 48c8775013d23229462134f911bbb14c7935096fcccfb19ce28ecd5f7154f35c
|
|
||||||
LINUX_KERNEL_HASH-4.9.171 = 431cd992bf74da9851dd5938dbe45ff7577219b84b237ae5e30067d483b57f01
|
LINUX_KERNEL_HASH-4.9.171 = 431cd992bf74da9851dd5938dbe45ff7577219b84b237ae5e30067d483b57f01
|
||||||
LINUX_KERNEL_HASH-4.14.114 = b75e1dcfabc8d18051a07cbf9b60eaee8ac470a2311fed20447fd0d022c19e15
|
LINUX_KERNEL_HASH-4.14.114 = b75e1dcfabc8d18051a07cbf9b60eaee8ac470a2311fed20447fd0d022c19e15
|
||||||
LINUX_KERNEL_HASH-4.19.37 = ecb0b30ec32c0c7d614c394158c7d37099a815507ed62235cca32052d7ff9c65
|
LINUX_KERNEL_HASH-4.19.37 = ecb0b30ec32c0c7d614c394158c7d37099a815507ed62235cca32052d7ff9c65
|
||||||
|
@ -51,7 +51,7 @@ else
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(filter 3.18 4.9,$(KERNEL_PATCHVER)),)
|
ifneq ($(filter 4.9,$(KERNEL_PATCHVER)),)
|
||||||
DEFAULT_PACKAGES.router:=$(filter-out kmod-ipt-offload,$(DEFAULT_PACKAGES.router))
|
DEFAULT_PACKAGES.router:=$(filter-out kmod-ipt-offload,$(DEFAULT_PACKAGES.router))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ include $(INCLUDE_DIR)/package.mk
|
|||||||
define Package/perf
|
define Package/perf
|
||||||
SECTION:=devel
|
SECTION:=devel
|
||||||
CATEGORY:=Development
|
CATEGORY:=Development
|
||||||
DEPENDS:= +libelf +libdw +(mips||mipsel||powerpc||i386||x86_64||arm||aarch64):libunwind +libpthread +librt +objdump @!LINUX_3_18 @!IN_SDK @!TARGET_arc770 @KERNEL_PERF_EVENTS
|
DEPENDS:= +libelf +libdw +(mips||mipsel||powerpc||i386||x86_64||arm||aarch64):libunwind +libpthread +librt +objdump @!IN_SDK @!TARGET_arc770 @KERNEL_PERF_EVENTS
|
||||||
TITLE:=Linux performance monitoring tool
|
TITLE:=Linux performance monitoring tool
|
||||||
VERSION:=$(LINUX_VERSION)-$(PKG_RELEASE)
|
VERSION:=$(LINUX_VERSION)-$(PKG_RELEASE)
|
||||||
URL:=http://www.kernel.org
|
URL:=http://www.kernel.org
|
||||||
|
@ -26,7 +26,7 @@ define KernelPackage/sched-cake
|
|||||||
URL:=https://github.com/dtaht/sch_cake
|
URL:=https://github.com/dtaht/sch_cake
|
||||||
FILES:=$(PKG_BUILD_DIR)/sch_cake.ko
|
FILES:=$(PKG_BUILD_DIR)/sch_cake.ko
|
||||||
AUTOLOAD:=$(call AutoLoad,75,sch_cake)
|
AUTOLOAD:=$(call AutoLoad,75,sch_cake)
|
||||||
DEPENDS:=+kmod-ipt-conntrack @!LINUX_3_18
|
DEPENDS:=+kmod-ipt-conntrack
|
||||||
endef
|
endef
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/kernel-defaults.mk
|
include $(INCLUDE_DIR)/kernel-defaults.mk
|
||||||
|
@ -209,7 +209,7 @@ $(eval $(call KernelPackage,block2mtd))
|
|||||||
define KernelPackage/dax
|
define KernelPackage/dax
|
||||||
SUBMENU:=$(BLOCK_MENU)
|
SUBMENU:=$(BLOCK_MENU)
|
||||||
TITLE:=DAX: direct access to differentiated memory
|
TITLE:=DAX: direct access to differentiated memory
|
||||||
DEPENDS:=@!LINUX_3_18 @!LINUX_4_9
|
DEPENDS:=@!LINUX_4_9
|
||||||
KCONFIG:=CONFIG_DAX
|
KCONFIG:=CONFIG_DAX
|
||||||
FILES:=$(LINUX_DIR)/drivers/dax/dax.ko
|
FILES:=$(LINUX_DIR)/drivers/dax/dax.ko
|
||||||
endef
|
endef
|
||||||
@ -220,7 +220,7 @@ $(eval $(call KernelPackage,dax))
|
|||||||
define KernelPackage/dm
|
define KernelPackage/dm
|
||||||
SUBMENU:=$(BLOCK_MENU)
|
SUBMENU:=$(BLOCK_MENU)
|
||||||
TITLE:=Device Mapper
|
TITLE:=Device Mapper
|
||||||
DEPENDS:=+kmod-crypto-manager +!(LINUX_3_18||LINUX_4_9):kmod-dax
|
DEPENDS:=+kmod-crypto-manager +!LINUX_4_9:kmod-dax
|
||||||
# All the "=n" are unnecessary, they're only there
|
# All the "=n" are unnecessary, they're only there
|
||||||
# to stop the config from asking the question.
|
# to stop the config from asking the question.
|
||||||
# MIRROR is M because I've needed it for pvmove.
|
# MIRROR is M because I've needed it for pvmove.
|
||||||
@ -337,7 +337,7 @@ $(eval $(call KernelPackage,md-raid10))
|
|||||||
|
|
||||||
|
|
||||||
define KernelPackage/md-raid456
|
define KernelPackage/md-raid456
|
||||||
$(call KernelPackage/md/Depends,+kmod-lib-raid6 +kmod-lib-xor +!LINUX_3_18:kmod-lib-crc32c)
|
$(call KernelPackage/md/Depends,+kmod-lib-raid6 +kmod-lib-xor +kmod-lib-crc32c)
|
||||||
TITLE:=RAID Level 456 Driver
|
TITLE:=RAID Level 456 Driver
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_ASYNC_CORE \
|
CONFIG_ASYNC_CORE \
|
||||||
|
@ -98,7 +98,7 @@ $(eval $(call KernelPackage,can-c-can-pci))
|
|||||||
define KernelPackage/can-c-can-platform
|
define KernelPackage/can-c-can-platform
|
||||||
TITLE:=Platform Bus based BOSCH C_CAN/D_CAN driver
|
TITLE:=Platform Bus based BOSCH C_CAN/D_CAN driver
|
||||||
KCONFIG:=CONFIG_CAN_C_CAN_PLATFORM
|
KCONFIG:=CONFIG_CAN_C_CAN_PLATFORM
|
||||||
DEPENDS:=kmod-can-c-can +!LINUX_3_18:kmod-regmap-core
|
DEPENDS:=kmod-can-c-can +kmod-regmap-core
|
||||||
FILES:=$(LINUX_DIR)/drivers/net/can/c_can/c_can_platform.ko
|
FILES:=$(LINUX_DIR)/drivers/net/can/c_can/c_can_platform.ko
|
||||||
AUTOLOAD:=$(call AutoProbe,c_can_platform)
|
AUTOLOAD:=$(call AutoProbe,c_can_platform)
|
||||||
$(call AddDepends/can)
|
$(call AddDepends/can)
|
||||||
|
@ -40,7 +40,7 @@ define KernelPackage/crypto-aead
|
|||||||
CONFIG_CRYPTO_AEAD2
|
CONFIG_CRYPTO_AEAD2
|
||||||
FILES:=$(LINUX_DIR)/crypto/aead.ko
|
FILES:=$(LINUX_DIR)/crypto/aead.ko
|
||||||
AUTOLOAD:=$(call AutoLoad,09,aead,1)
|
AUTOLOAD:=$(call AutoLoad,09,aead,1)
|
||||||
$(call AddDepends/crypto, +!LINUX_3_18:kmod-crypto-null)
|
$(call AddDepends/crypto, +kmod-crypto-null)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call KernelPackage,crypto-aead))
|
$(eval $(call KernelPackage,crypto-aead))
|
||||||
@ -48,7 +48,7 @@ $(eval $(call KernelPackage,crypto-aead))
|
|||||||
|
|
||||||
define KernelPackage/crypto-authenc
|
define KernelPackage/crypto-authenc
|
||||||
TITLE:=Combined mode wrapper for IPsec
|
TITLE:=Combined mode wrapper for IPsec
|
||||||
DEPENDS:=+kmod-crypto-manager +!LINUX_3_18:kmod-crypto-null
|
DEPENDS:=+kmod-crypto-manager +kmod-crypto-null
|
||||||
KCONFIG:=CONFIG_CRYPTO_AUTHENC
|
KCONFIG:=CONFIG_CRYPTO_AUTHENC
|
||||||
FILES:=$(LINUX_DIR)/crypto/authenc.ko
|
FILES:=$(LINUX_DIR)/crypto/authenc.ko
|
||||||
AUTOLOAD:=$(call AutoLoad,09,authenc)
|
AUTOLOAD:=$(call AutoLoad,09,authenc)
|
||||||
@ -145,7 +145,7 @@ $(eval $(call KernelPackage,crypto-cts))
|
|||||||
|
|
||||||
define KernelPackage/crypto-deflate
|
define KernelPackage/crypto-deflate
|
||||||
TITLE:=Deflate compression CryptoAPI module
|
TITLE:=Deflate compression CryptoAPI module
|
||||||
DEPENDS:=+kmod-lib-zlib-inflate +kmod-lib-zlib-deflate +!(LINUX_3_18||LINUX_4_9):kmod-crypto-acompress
|
DEPENDS:=+kmod-lib-zlib-inflate +kmod-lib-zlib-deflate +!LINUX_4_9:kmod-crypto-acompress
|
||||||
KCONFIG:=CONFIG_CRYPTO_DEFLATE
|
KCONFIG:=CONFIG_CRYPTO_DEFLATE
|
||||||
FILES:=$(LINUX_DIR)/crypto/deflate.ko
|
FILES:=$(LINUX_DIR)/crypto/deflate.ko
|
||||||
AUTOLOAD:=$(call AutoLoad,09,deflate)
|
AUTOLOAD:=$(call AutoLoad,09,deflate)
|
||||||
@ -180,7 +180,7 @@ $(eval $(call KernelPackage,crypto-ecb))
|
|||||||
|
|
||||||
define KernelPackage/crypto-ecdh
|
define KernelPackage/crypto-ecdh
|
||||||
TITLE:=ECDH algorithm
|
TITLE:=ECDH algorithm
|
||||||
DEPENDS:=@!LINUX_3_18 +kmod-crypto-kpp
|
DEPENDS:=+kmod-crypto-kpp
|
||||||
KCONFIG:= CONFIG_CRYPTO_ECDH
|
KCONFIG:= CONFIG_CRYPTO_ECDH
|
||||||
FILES:= \
|
FILES:= \
|
||||||
$(LINUX_DIR)/crypto/ecdh_generic.ko
|
$(LINUX_DIR)/crypto/ecdh_generic.ko
|
||||||
@ -286,7 +286,7 @@ $(eval $(call KernelPackage,crypto-hmac))
|
|||||||
|
|
||||||
define KernelPackage/crypto-hw-ccp
|
define KernelPackage/crypto-hw-ccp
|
||||||
TITLE:=AMD Cryptographic Coprocessor
|
TITLE:=AMD Cryptographic Coprocessor
|
||||||
DEPENDS:=+kmod-crypto-authenc +kmod-crypto-hash +kmod-crypto-manager +kmod-random-core +kmod-crypto-sha1 +kmod-crypto-sha256 +!(LINUX_3_18||LINUX_4_9):kmod-crypto-rsa
|
DEPENDS:=+kmod-crypto-authenc +kmod-crypto-hash +kmod-crypto-manager +kmod-random-core +kmod-crypto-sha1 +kmod-crypto-sha256 +!LINUX_4_9:kmod-crypto-rsa
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_CRYPTO_HW=y \
|
CONFIG_CRYPTO_HW=y \
|
||||||
CONFIG_CRYPTO_DEV_CCP=y \
|
CONFIG_CRYPTO_DEV_CCP=y \
|
||||||
@ -583,7 +583,7 @@ $(eval $(call KernelPackage,crypto-pcompress))
|
|||||||
|
|
||||||
define KernelPackage/crypto-rsa
|
define KernelPackage/crypto-rsa
|
||||||
TITLE:=RSA algorithm
|
TITLE:=RSA algorithm
|
||||||
DEPENDS:=@!LINUX_3_18 +kmod-crypto-manager +kmod-asn1-decoder
|
DEPENDS:=+kmod-crypto-manager +kmod-asn1-decoder
|
||||||
KCONFIG:= CONFIG_CRYPTO_RSA
|
KCONFIG:= CONFIG_CRYPTO_RSA
|
||||||
HIDDEN:=1
|
HIDDEN:=1
|
||||||
FILES:= \
|
FILES:= \
|
||||||
|
@ -68,7 +68,7 @@ $(eval $(call KernelPackage,fs-autofs4))
|
|||||||
define KernelPackage/fs-btrfs
|
define KernelPackage/fs-btrfs
|
||||||
SUBMENU:=$(FS_MENU)
|
SUBMENU:=$(FS_MENU)
|
||||||
TITLE:=BTRFS filesystem support
|
TITLE:=BTRFS filesystem support
|
||||||
DEPENDS:=+kmod-lib-crc32c +kmod-lib-lzo +kmod-lib-zlib-inflate +kmod-lib-zlib-deflate +kmod-lib-raid6 +kmod-lib-xor +!(LINUX_3_18||LINUX_4_9):kmod-lib-zstd
|
DEPENDS:=+kmod-lib-crc32c +kmod-lib-lzo +kmod-lib-zlib-inflate +kmod-lib-zlib-deflate +kmod-lib-raid6 +kmod-lib-xor +!LINUX_4_9:kmod-lib-zstd
|
||||||
KCONFIG:=\
|
KCONFIG:=\
|
||||||
CONFIG_BTRFS_FS \
|
CONFIG_BTRFS_FS \
|
||||||
CONFIG_BTRFS_FS_POSIX_ACL=n \
|
CONFIG_BTRFS_FS_POSIX_ACL=n \
|
||||||
|
@ -112,7 +112,7 @@ define KernelPackage/hwmon-ina2xx
|
|||||||
KCONFIG:=CONFIG_SENSORS_INA2XX
|
KCONFIG:=CONFIG_SENSORS_INA2XX
|
||||||
FILES:=$(LINUX_DIR)/drivers/hwmon/ina2xx.ko
|
FILES:=$(LINUX_DIR)/drivers/hwmon/ina2xx.ko
|
||||||
AUTOLOAD:=$(call AutoProbe,ina2xx)
|
AUTOLOAD:=$(call AutoProbe,ina2xx)
|
||||||
$(call AddDepends/hwmon,+kmod-i2c-core +!LINUX_3_18:kmod-regmap-i2c)
|
$(call AddDepends/hwmon,+kmod-i2c-core +kmod-regmap-i2c)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define KernelPackage/hwmon-ina2xx/description
|
define KernelPackage/hwmon-ina2xx/description
|
||||||
|
@ -132,7 +132,7 @@ $(eval $(call KernelPackage,iio-dht11))
|
|||||||
define KernelPackage/iio-bmp280
|
define KernelPackage/iio-bmp280
|
||||||
SUBMENU:=$(IIO_MENU)
|
SUBMENU:=$(IIO_MENU)
|
||||||
TITLE:=BMP180/BMP280/BME280 pressure/temperatur sensor
|
TITLE:=BMP180/BMP280/BME280 pressure/temperatur sensor
|
||||||
DEPENDS:=@!LINUX_3_18 +kmod-iio-core +kmod-regmap-core
|
DEPENDS:=+kmod-iio-core +kmod-regmap-core
|
||||||
KCONFIG:=CONFIG_BMP280
|
KCONFIG:=CONFIG_BMP280
|
||||||
FILES:=$(LINUX_DIR)/drivers/iio/pressure/bmp280.ko
|
FILES:=$(LINUX_DIR)/drivers/iio/pressure/bmp280.ko
|
||||||
endef
|
endef
|
||||||
|
@ -101,7 +101,7 @@ $(eval $(call KernelPackage,lib-crc32c))
|
|||||||
define KernelPackage/lib-lzo
|
define KernelPackage/lib-lzo
|
||||||
SUBMENU:=$(LIB_MENU)
|
SUBMENU:=$(LIB_MENU)
|
||||||
TITLE:=LZO support
|
TITLE:=LZO support
|
||||||
DEPENDS:=+!(LINUX_3_18||LINUX_4_9):kmod-crypto-acompress
|
DEPENDS:=+!LINUX_4_9:kmod-crypto-acompress
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_CRYPTO_LZO@ge4.9 \
|
CONFIG_CRYPTO_LZO@ge4.9 \
|
||||||
CONFIG_LZO_COMPRESS \
|
CONFIG_LZO_COMPRESS \
|
||||||
@ -146,7 +146,7 @@ $(eval $(call KernelPackage,lib-zstd))
|
|||||||
define KernelPackage/lib-lz4
|
define KernelPackage/lib-lz4
|
||||||
SUBMENU:=$(LIB_MENU)
|
SUBMENU:=$(LIB_MENU)
|
||||||
TITLE:=LZ4 support
|
TITLE:=LZ4 support
|
||||||
DEPENDS:=+!(LINUX_3_18||LINUX_4_9):kmod-crypto-acompress
|
DEPENDS:=+!LINUX_4_9:kmod-crypto-acompress
|
||||||
HIDDEN:=1
|
HIDDEN:=1
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_CRYPTO_LZ4@ge4.9 \
|
CONFIG_CRYPTO_LZ4@ge4.9 \
|
||||||
|
@ -700,7 +700,7 @@ define KernelPackage/tg3
|
|||||||
TITLE:=Broadcom Tigon3 Gigabit Ethernet
|
TITLE:=Broadcom Tigon3 Gigabit Ethernet
|
||||||
KCONFIG:=CONFIG_TIGON3 \
|
KCONFIG:=CONFIG_TIGON3 \
|
||||||
CONFIG_TIGON3_HWMON=n
|
CONFIG_TIGON3_HWMON=n
|
||||||
DEPENDS:=+!TARGET_brcm47xx:kmod-libphy +(LINUX_3_18||LINUX_4_9):kmod-hwmon-core +kmod-ptp
|
DEPENDS:=+!TARGET_brcm47xx:kmod-libphy +LINUX_4_9:kmod-hwmon-core +kmod-ptp
|
||||||
SUBMENU:=$(NETWORK_DEVICES_MENU)
|
SUBMENU:=$(NETWORK_DEVICES_MENU)
|
||||||
FILES:=$(LINUX_DIR)/drivers/net/ethernet/broadcom/tg3.ko
|
FILES:=$(LINUX_DIR)/drivers/net/ethernet/broadcom/tg3.ko
|
||||||
AUTOLOAD:=$(call AutoLoad,19,tg3,1)
|
AUTOLOAD:=$(call AutoLoad,19,tg3,1)
|
||||||
|
@ -152,7 +152,7 @@ define KernelPackage/nf-flow
|
|||||||
CONFIG_NETFILTER_INGRESS=y \
|
CONFIG_NETFILTER_INGRESS=y \
|
||||||
CONFIG_NF_FLOW_TABLE \
|
CONFIG_NF_FLOW_TABLE \
|
||||||
CONFIG_NF_FLOW_TABLE_HW
|
CONFIG_NF_FLOW_TABLE_HW
|
||||||
DEPENDS:=+kmod-nf-conntrack @!LINUX_3_18 @!LINUX_4_9
|
DEPENDS:=+kmod-nf-conntrack @!LINUX_4_9
|
||||||
FILES:= \
|
FILES:= \
|
||||||
$(LINUX_DIR)/net/netfilter/nf_flow_table.ko \
|
$(LINUX_DIR)/net/netfilter/nf_flow_table.ko \
|
||||||
$(LINUX_DIR)/net/netfilter/nf_flow_table_hw.ko
|
$(LINUX_DIR)/net/netfilter/nf_flow_table_hw.ko
|
||||||
|
@ -725,7 +725,6 @@ SCHED_FILES_EXTRA = $(patsubst %,$(LINUX_DIR)/net/sched/%.ko,$(SCHED_MODULES_EXT
|
|||||||
define KernelPackage/sched-core
|
define KernelPackage/sched-core
|
||||||
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
||||||
TITLE:=Traffic schedulers
|
TITLE:=Traffic schedulers
|
||||||
DEPENDS:=@!LINUX_3_18
|
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_NET_SCHED=y \
|
CONFIG_NET_SCHED=y \
|
||||||
CONFIG_NET_SCH_HFSC \
|
CONFIG_NET_SCH_HFSC \
|
||||||
@ -833,7 +832,6 @@ $(eval $(call KernelPackage,sched-ipset))
|
|||||||
define KernelPackage/sched-bpf
|
define KernelPackage/sched-bpf
|
||||||
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
||||||
TITLE:=Traffic shaper support for Berkeley Packet Filter
|
TITLE:=Traffic shaper support for Berkeley Packet Filter
|
||||||
DEPENDS:=@!LINUX_3_18
|
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_NET_CLS_BPF \
|
CONFIG_NET_CLS_BPF \
|
||||||
CONFIG_NET_ACT_BPF
|
CONFIG_NET_ACT_BPF
|
||||||
@ -849,7 +847,6 @@ $(eval $(call KernelPackage,sched-bpf))
|
|||||||
define KernelPackage/bpf-test
|
define KernelPackage/bpf-test
|
||||||
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
||||||
TITLE:=Test Berkeley Packet Filter functionality
|
TITLE:=Test Berkeley Packet Filter functionality
|
||||||
DEPENDS:=@!LINUX_3_18
|
|
||||||
KCONFIG:=CONFIG_TEST_BPF
|
KCONFIG:=CONFIG_TEST_BPF
|
||||||
FILES:=$(LINUX_DIR)/lib/test_bpf.ko
|
FILES:=$(LINUX_DIR)/lib/test_bpf.ko
|
||||||
endef
|
endef
|
||||||
@ -897,7 +894,7 @@ $(eval $(call KernelPackage,sched))
|
|||||||
define KernelPackage/tcp-bbr
|
define KernelPackage/tcp-bbr
|
||||||
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
||||||
TITLE:=BBR TCP congestion control
|
TITLE:=BBR TCP congestion control
|
||||||
DEPENDS:=@!LINUX_3_18 +LINUX_4_9:kmod-sched
|
DEPENDS:=+LINUX_4_9:kmod-sched
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_TCP_CONG_ADVANCED=y \
|
CONFIG_TCP_CONG_ADVANCED=y \
|
||||||
CONFIG_TCP_CONG_BBR
|
CONFIG_TCP_CONG_BBR
|
||||||
@ -1113,7 +1110,7 @@ $(eval $(call KernelPackage,rxrpc))
|
|||||||
define KernelPackage/mpls
|
define KernelPackage/mpls
|
||||||
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
||||||
TITLE:=MPLS support
|
TITLE:=MPLS support
|
||||||
DEPENDS:=@!LINUX_3_18 +LINUX_4_19:kmod-iptunnel
|
DEPENDS:=+LINUX_4_19:kmod-iptunnel
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_MPLS=y \
|
CONFIG_MPLS=y \
|
||||||
CONFIG_LWTUNNEL=y \
|
CONFIG_LWTUNNEL=y \
|
||||||
@ -1190,7 +1187,7 @@ $(eval $(call KernelPackage,mdio))
|
|||||||
define KernelPackage/macsec
|
define KernelPackage/macsec
|
||||||
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
SUBMENU:=$(NETWORK_SUPPORT_MENU)
|
||||||
TITLE:=IEEE 802.1AE MAC-level encryption (MAC)
|
TITLE:=IEEE 802.1AE MAC-level encryption (MAC)
|
||||||
DEPENDS:=+kmod-crypto-gcm @!LINUX_3_18
|
DEPENDS:=+kmod-crypto-gcm
|
||||||
KCONFIG:=CONFIG_MACSEC
|
KCONFIG:=CONFIG_MACSEC
|
||||||
FILES:=$(LINUX_DIR)/drivers/net/macsec.ko
|
FILES:=$(LINUX_DIR)/drivers/net/macsec.ko
|
||||||
AUTOLOAD:=$(call AutoLoad,13,macsec)
|
AUTOLOAD:=$(call AutoLoad,13,macsec)
|
||||||
|
@ -30,7 +30,7 @@ $(eval $(call KernelPackage,6lowpan))
|
|||||||
define KernelPackage/bluetooth
|
define KernelPackage/bluetooth
|
||||||
SUBMENU:=$(OTHER_MENU)
|
SUBMENU:=$(OTHER_MENU)
|
||||||
TITLE:=Bluetooth support
|
TITLE:=Bluetooth support
|
||||||
DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-crypto-hash +kmod-crypto-ecb +kmod-lib-crc16 +kmod-hid +!LINUX_3_18:kmod-crypto-cmac +!LINUX_3_18:kmod-regmap-core +!(LINUX_3_18||LINUX_4_9):kmod-crypto-ecdh
|
DEPENDS:=@USB_SUPPORT +kmod-usb-core +kmod-crypto-hash +kmod-crypto-ecb +kmod-lib-crc16 +kmod-hid +kmod-crypto-cmac +kmod-regmap-core +!LINUX_4_9:kmod-crypto-ecdh
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_BT \
|
CONFIG_BT \
|
||||||
CONFIG_BT_BREDR=y \
|
CONFIG_BT_BREDR=y \
|
||||||
@ -219,7 +219,7 @@ $(eval $(call KernelPackage,gpio-dev))
|
|||||||
define KernelPackage/gpio-mcp23s08
|
define KernelPackage/gpio-mcp23s08
|
||||||
SUBMENU:=$(OTHER_MENU)
|
SUBMENU:=$(OTHER_MENU)
|
||||||
TITLE:=Microchip MCP23xxx I/O expander
|
TITLE:=Microchip MCP23xxx I/O expander
|
||||||
DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core +!(LINUX_3_18||LINUX_4_9):kmod-regmap-i2c
|
DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core +!LINUX_4_9:kmod-regmap-i2c
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_GPIO_MCP23S08 \
|
CONFIG_GPIO_MCP23S08 \
|
||||||
CONFIG_PINCTRL_MCP23S08
|
CONFIG_PINCTRL_MCP23S08
|
||||||
@ -476,7 +476,7 @@ define KernelPackage/rtc-ds1307
|
|||||||
SUBMENU:=$(OTHER_MENU)
|
SUBMENU:=$(OTHER_MENU)
|
||||||
TITLE:=Dallas/Maxim DS1307 (and compatible) RTC support
|
TITLE:=Dallas/Maxim DS1307 (and compatible) RTC support
|
||||||
DEFAULT:=m if ALL_KMODS && RTC_SUPPORT
|
DEFAULT:=m if ALL_KMODS && RTC_SUPPORT
|
||||||
DEPENDS:=+kmod-i2c-core +!(LINUX_3_18||LINUX_4_9):kmod-regmap-i2c +!(LINUX_3_18||LINUX_4_9):kmod-hwmon-core
|
DEPENDS:=+kmod-i2c-core +!LINUX_4_9:kmod-regmap-i2c +!LINUX_4_9:kmod-hwmon-core
|
||||||
KCONFIG:=CONFIG_RTC_DRV_DS1307 \
|
KCONFIG:=CONFIG_RTC_DRV_DS1307 \
|
||||||
CONFIG_RTC_CLASS=y
|
CONFIG_RTC_CLASS=y
|
||||||
FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1307.ko
|
FILES:=$(LINUX_DIR)/drivers/rtc/rtc-ds1307.ko
|
||||||
@ -1038,7 +1038,7 @@ $(eval $(call KernelPackage,echo))
|
|||||||
define KernelPackage/bmp085
|
define KernelPackage/bmp085
|
||||||
SUBMENU:=$(OTHER_MENU)
|
SUBMENU:=$(OTHER_MENU)
|
||||||
TITLE:=BMP085/BMP18x pressure sensor
|
TITLE:=BMP085/BMP18x pressure sensor
|
||||||
DEPENDS:= +kmod-regmap-core @!LINUX_3_18
|
DEPENDS:= +kmod-regmap-core
|
||||||
KCONFIG:= CONFIG_BMP085
|
KCONFIG:= CONFIG_BMP085
|
||||||
FILES:= $(LINUX_DIR)/drivers/misc/bmp085.ko
|
FILES:= $(LINUX_DIR)/drivers/misc/bmp085.ko
|
||||||
endef
|
endef
|
||||||
|
@ -39,7 +39,6 @@ endef
|
|||||||
define KernelPackage/usb-ledtrig-usbport
|
define KernelPackage/usb-ledtrig-usbport
|
||||||
TITLE:=LED trigger for USB ports
|
TITLE:=LED trigger for USB ports
|
||||||
KCONFIG:=CONFIG_USB_LEDS_TRIGGER_USBPORT
|
KCONFIG:=CONFIG_USB_LEDS_TRIGGER_USBPORT
|
||||||
DEPENDS:=@!LINUX_3_18
|
|
||||||
FILES:=$(LINUX_DIR)/drivers/usb/core/ledtrig-usbport.ko
|
FILES:=$(LINUX_DIR)/drivers/usb/core/ledtrig-usbport.ko
|
||||||
AUTOLOAD:=$(call AutoLoad,50,ledtrig-usbport)
|
AUTOLOAD:=$(call AutoLoad,50,ledtrig-usbport)
|
||||||
$(call AddDepends/usb)
|
$(call AddDepends/usb)
|
||||||
|
@ -187,7 +187,7 @@ define KernelPackage/fb-tft
|
|||||||
SUBMENU:=$(VIDEO_MENU)
|
SUBMENU:=$(VIDEO_MENU)
|
||||||
TITLE:=Support for small TFT LCD display modules
|
TITLE:=Support for small TFT LCD display modules
|
||||||
DEPENDS:= \
|
DEPENDS:= \
|
||||||
@GPIO_SUPPORT @!LINUX_3_18 @!LINUX_4_9 +kmod-backlight \
|
@GPIO_SUPPORT @!LINUX_4_9 +kmod-backlight \
|
||||||
+kmod-fb +kmod-fb-sys-fops +kmod-fb-sys-ram +kmod-spi-bitbang
|
+kmod-fb +kmod-fb-sys-fops +kmod-fb-sys-ram +kmod-spi-bitbang
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_FB_BACKLIGHT=y \
|
CONFIG_FB_BACKLIGHT=y \
|
||||||
@ -433,7 +433,7 @@ endef
|
|||||||
|
|
||||||
define KernelPackage/video-videobuf2
|
define KernelPackage/video-videobuf2
|
||||||
TITLE:=videobuf2 lib
|
TITLE:=videobuf2 lib
|
||||||
DEPENDS:=+kmod-dma-buf @!LINUX_3_18
|
DEPENDS:=+kmod-dma-buf
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_VIDEOBUF2_CORE \
|
CONFIG_VIDEOBUF2_CORE \
|
||||||
CONFIG_VIDEOBUF2_MEMOPS \
|
CONFIG_VIDEOBUF2_MEMOPS \
|
||||||
|
@ -14,7 +14,7 @@ define KernelPackage/w1
|
|||||||
TITLE:=Dallas's 1-wire support
|
TITLE:=Dallas's 1-wire support
|
||||||
KCONFIG:=CONFIG_W1
|
KCONFIG:=CONFIG_W1
|
||||||
FILES:=$(LINUX_DIR)/drivers/w1/wire.ko
|
FILES:=$(LINUX_DIR)/drivers/w1/wire.ko
|
||||||
DEPENDS:=+!(LINUX_3_18||LINUX_4_9):kmod-hwmon-core
|
DEPENDS:=+!LINUX_4_9:kmod-hwmon-core
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define KernelPackage/w1/description
|
define KernelPackage/w1/description
|
||||||
|
@ -9,7 +9,6 @@ WPAN_MENU:=WPAN 802.15.4 Support
|
|||||||
define KernelPackage/ieee802154
|
define KernelPackage/ieee802154
|
||||||
SUBMENU:=$(WPAN_MENU)
|
SUBMENU:=$(WPAN_MENU)
|
||||||
TITLE:=IEEE-802.15.4 support
|
TITLE:=IEEE-802.15.4 support
|
||||||
DEPENDS:=@!LINUX_3_18
|
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_IEEE802154 \
|
CONFIG_IEEE802154 \
|
||||||
CONFIG_IEEE802154_SOCKET=y \
|
CONFIG_IEEE802154_SOCKET=y \
|
||||||
@ -33,7 +32,7 @@ $(eval $(call KernelPackage,ieee802154))
|
|||||||
define KernelPackage/mac802154
|
define KernelPackage/mac802154
|
||||||
SUBMENU:=$(WPAN_MENU)
|
SUBMENU:=$(WPAN_MENU)
|
||||||
TITLE:=MAC-802.15.4 support
|
TITLE:=MAC-802.15.4 support
|
||||||
DEPENDS:=+kmod-ieee802154 +kmod-crypto-aead +kmod-lib-crc-ccitt @!LINUX_3_18
|
DEPENDS:=+kmod-ieee802154 +kmod-crypto-aead +kmod-lib-crc-ccitt
|
||||||
KCONFIG:= \
|
KCONFIG:= \
|
||||||
CONFIG_MAC802154 \
|
CONFIG_MAC802154 \
|
||||||
CONFIG_IEEE802154_DRIVERS=y
|
CONFIG_IEEE802154_DRIVERS=y
|
||||||
@ -56,7 +55,7 @@ $(eval $(call KernelPackage,mac802154))
|
|||||||
define KernelPackage/fakelb
|
define KernelPackage/fakelb
|
||||||
SUBMENU:=$(WPAN_MENU)
|
SUBMENU:=$(WPAN_MENU)
|
||||||
TITLE:=Fake LR-WPAN driver
|
TITLE:=Fake LR-WPAN driver
|
||||||
DEPENDS:=+kmod-mac802154 @!LINUX_3_18
|
DEPENDS:=+kmod-mac802154
|
||||||
KCONFIG:=CONFIG_IEEE802154_FAKELB
|
KCONFIG:=CONFIG_IEEE802154_FAKELB
|
||||||
FILES:=$(LINUX_DIR)/drivers/net/ieee802154/fakelb.ko
|
FILES:=$(LINUX_DIR)/drivers/net/ieee802154/fakelb.ko
|
||||||
AUTOLOAD:=$(call AutoLoad,92,fakelb)
|
AUTOLOAD:=$(call AutoLoad,92,fakelb)
|
||||||
@ -109,7 +108,7 @@ $(eval $(call KernelPackage,cc2520))
|
|||||||
define KernelPackage/ieee802154_6lowpan
|
define KernelPackage/ieee802154_6lowpan
|
||||||
SUBMENU:=$(WPAN_MENU)
|
SUBMENU:=$(WPAN_MENU)
|
||||||
TITLE:= 6LoWPAN support over IEEE-802.15.4
|
TITLE:= 6LoWPAN support over IEEE-802.15.4
|
||||||
DEPENDS:=@!LINUX_3_18 +kmod-6lowpan +kmod-ieee802154
|
DEPENDS:=+kmod-6lowpan +kmod-ieee802154
|
||||||
KCONFIG:=CONFIG_IEEE802154_6LOWPAN
|
KCONFIG:=CONFIG_IEEE802154_6LOWPAN
|
||||||
FILES:= \
|
FILES:= \
|
||||||
$(LINUX_DIR)/net/ieee802154/6lowpan/ieee802154_6lowpan.ko@ge4.0 \
|
$(LINUX_DIR)/net/ieee802154/6lowpan/ieee802154_6lowpan.ko@ge4.0 \
|
||||||
|
@ -15,7 +15,7 @@ config-$(call config_package,ipw2200) += IPW2200
|
|||||||
|
|
||||||
define KernelPackage/iwlwifi
|
define KernelPackage/iwlwifi
|
||||||
$(call KernelPackage/mac80211/Default)
|
$(call KernelPackage/mac80211/Default)
|
||||||
DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11W_SUPPORT @!LINUX_3_18
|
DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11W_SUPPORT
|
||||||
TITLE:=Intel AGN Wireless support
|
TITLE:=Intel AGN Wireless support
|
||||||
FILES:= \
|
FILES:= \
|
||||||
$(PKG_BUILD_DIR)/drivers/net/wireless/intel/iwlwifi/iwlwifi.ko \
|
$(PKG_BUILD_DIR)/drivers/net/wireless/intel/iwlwifi/iwlwifi.ko \
|
||||||
@ -124,7 +124,7 @@ endef
|
|||||||
define KernelPackage/libipw
|
define KernelPackage/libipw
|
||||||
$(call KernelPackage/mac80211/Default)
|
$(call KernelPackage/mac80211/Default)
|
||||||
TITLE:=libipw for ipw2100 and ipw2200
|
TITLE:=libipw for ipw2100 and ipw2200
|
||||||
DEPENDS:=@PCI_SUPPORT +kmod-crypto-michael-mic +kmod-crypto-ecb +kmod-lib80211 +kmod-cfg80211 +@DRIVER_WEXT_SUPPORT @!BIG_ENDIAN @!LINUX_3_18
|
DEPENDS:=@PCI_SUPPORT +kmod-crypto-michael-mic +kmod-crypto-ecb +kmod-lib80211 +kmod-cfg80211 +@DRIVER_WEXT_SUPPORT @!BIG_ENDIAN
|
||||||
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/intel/ipw2x00/libipw.ko
|
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/intel/ipw2x00/libipw.ko
|
||||||
AUTOLOAD:=$(call AutoProbe,libipw)
|
AUTOLOAD:=$(call AutoProbe,libipw)
|
||||||
endef
|
endef
|
||||||
|
@ -11,7 +11,7 @@ config-$(call config_package,mwifiex-sdio) += MWIFIEX MWIFIEX_SDIO
|
|||||||
|
|
||||||
define KernelPackage/libertas-usb
|
define KernelPackage/libertas-usb
|
||||||
$(call KernelPackage/mac80211/Default)
|
$(call KernelPackage/mac80211/Default)
|
||||||
DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +kmod-usb-core +kmod-lib80211 +@DRIVER_WEXT_SUPPORT +libertas-usb-firmware @!LINUX_3_18
|
DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +kmod-usb-core +kmod-lib80211 +@DRIVER_WEXT_SUPPORT +libertas-usb-firmware
|
||||||
TITLE:=Marvell 88W8015 Wireless Driver
|
TITLE:=Marvell 88W8015 Wireless Driver
|
||||||
FILES:= \
|
FILES:= \
|
||||||
$(PKG_BUILD_DIR)/drivers/net/wireless/marvell/libertas/libertas.ko \
|
$(PKG_BUILD_DIR)/drivers/net/wireless/marvell/libertas/libertas.ko \
|
||||||
@ -21,7 +21,7 @@ endef
|
|||||||
|
|
||||||
define KernelPackage/libertas-sdio
|
define KernelPackage/libertas-sdio
|
||||||
$(call KernelPackage/mac80211/Default)
|
$(call KernelPackage/mac80211/Default)
|
||||||
DEPENDS+= +kmod-cfg80211 +kmod-lib80211 +kmod-mmc +@DRIVER_WEXT_SUPPORT @!TARGET_uml +libertas-sdio-firmware @!LINUX_3_18
|
DEPENDS+= +kmod-cfg80211 +kmod-lib80211 +kmod-mmc +@DRIVER_WEXT_SUPPORT @!TARGET_uml +libertas-sdio-firmware
|
||||||
TITLE:=Marvell 88W8686 Wireless Driver
|
TITLE:=Marvell 88W8686 Wireless Driver
|
||||||
FILES:= \
|
FILES:= \
|
||||||
$(PKG_BUILD_DIR)/drivers/net/wireless/marvell/libertas/libertas.ko \
|
$(PKG_BUILD_DIR)/drivers/net/wireless/marvell/libertas/libertas.ko \
|
||||||
@ -32,7 +32,7 @@ endef
|
|||||||
define KernelPackage/libertas-spi
|
define KernelPackage/libertas-spi
|
||||||
$(call KernelPackage/mac80211/Default)
|
$(call KernelPackage/mac80211/Default)
|
||||||
SUBMENU:=Wireless Drivers
|
SUBMENU:=Wireless Drivers
|
||||||
DEPENDS+= +kmod-cfg80211 +kmod-lib80211 +@DRIVER_WEXT_SUPPORT @!TARGET_uml +libertas-spi-firmware @!LINUX_3_18
|
DEPENDS+= +kmod-cfg80211 +kmod-lib80211 +@DRIVER_WEXT_SUPPORT @!TARGET_uml +libertas-spi-firmware
|
||||||
KCONFIG := \
|
KCONFIG := \
|
||||||
CONFIG_SPI=y \
|
CONFIG_SPI=y \
|
||||||
CONFIG_SPI_MASTER=y
|
CONFIG_SPI_MASTER=y
|
||||||
|
@ -33,7 +33,7 @@ include $(INCLUDE_DIR)/package.mk
|
|||||||
define KernelPackage/mt76-default
|
define KernelPackage/mt76-default
|
||||||
SUBMENU:=Wireless Drivers
|
SUBMENU:=Wireless Drivers
|
||||||
DEPENDS:= \
|
DEPENDS:= \
|
||||||
+kmod-mac80211 @!LINUX_3_18 \
|
+kmod-mac80211 \
|
||||||
+@DRIVER_11AC_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT
|
+@DRIVER_11AC_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (C) 2008-2010 OpenWrt.org
|
|
||||||
#
|
|
||||||
# This is free software, licensed under the GNU General Public License v2.
|
|
||||||
# See /LICENSE for more information.
|
|
||||||
#
|
|
||||||
|
|
||||||
include $(TOPDIR)/rules.mk
|
|
||||||
include $(INCLUDE_DIR)/kernel.mk
|
|
||||||
|
|
||||||
PKG_NAME:=rotary-gpio-custom
|
|
||||||
PKG_RELEASE:=1
|
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
|
||||||
|
|
||||||
define KernelPackage/rotary-gpio-custom
|
|
||||||
SUBMENU:=Other modules
|
|
||||||
TITLE:=Custom GPIO-based rotary encoder device
|
|
||||||
DEPENDS:=@GPIO_SUPPORT +kmod-input-gpio-encoder @LINUX_3_18
|
|
||||||
FILES:=$(PKG_BUILD_DIR)/rotary-gpio-custom.ko
|
|
||||||
KCONFIG:=
|
|
||||||
endef
|
|
||||||
|
|
||||||
define KernelPackage/rotary-gpio-custom/description
|
|
||||||
Kernel module for register a custom rotary-gpio-encoder platform device.
|
|
||||||
endef
|
|
||||||
|
|
||||||
EXTRA_KCONFIG:= \
|
|
||||||
CONFIG_ROTARY_GPIO_CUSTOM=m
|
|
||||||
|
|
||||||
EXTRA_CFLAGS:= \
|
|
||||||
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
|
|
||||||
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
|
|
||||||
|
|
||||||
MAKE_OPTS:= \
|
|
||||||
$(KERNEL_MAKE_FLAGS) \
|
|
||||||
SUBDIRS="$(PKG_BUILD_DIR)" \
|
|
||||||
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
|
|
||||||
$(EXTRA_KCONFIG)
|
|
||||||
|
|
||||||
define Build/Compile
|
|
||||||
$(MAKE) -C "$(LINUX_DIR)" \
|
|
||||||
$(MAKE_OPTS) \
|
|
||||||
modules
|
|
||||||
endef
|
|
||||||
|
|
||||||
$(eval $(call KernelPackage,rotary-gpio-custom))
|
|
@ -1,9 +0,0 @@
|
|||||||
config ROTARY_GPIO_CUSTOM
|
|
||||||
tristate "Custom GPIO-based rotary driver"
|
|
||||||
depends on GENERIC_GPIO
|
|
||||||
help
|
|
||||||
This is a driver to register 1 to 4 custom rotary encoder using
|
|
||||||
GPIO lines.
|
|
||||||
|
|
||||||
This support is also available as a module. If so, the module
|
|
||||||
will be called rotary-gpio-custom.
|
|
@ -1 +0,0 @@
|
|||||||
obj-${CONFIG_ROTARY_GPIO_CUSTOM} += rotary-gpio-custom.o
|
|
@ -1,193 +0,0 @@
|
|||||||
/*
|
|
||||||
* Custom GPIO-based rotary driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 Claudio Mignanti <c.mignanti@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* Strongly based on Custom GPIO-based I2C driver by:
|
|
||||||
* Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
|
|
||||||
*
|
|
||||||
* ---------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* The behaviour of this driver can be altered by setting some parameters
|
|
||||||
* from the insmod command line.
|
|
||||||
*
|
|
||||||
* The following parameters are adjustable:
|
|
||||||
*
|
|
||||||
* bus0 These four arguments can be arrays of
|
|
||||||
* bus1 1-8 unsigned integers as follows:
|
|
||||||
* bus2
|
|
||||||
* bus3 <id>,<steps>,<axis>,<gpioa>,<gpiob>,<inverted>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* If this driver is built into the kernel, you can use the following kernel
|
|
||||||
* command line parameters, with the same values as the corresponding module
|
|
||||||
* parameters listed above:
|
|
||||||
*
|
|
||||||
* rotary-gpio-custom.bus0
|
|
||||||
* rotary-gpio-custom.bus1
|
|
||||||
* rotary-gpio-custom.bus2
|
|
||||||
* rotary-gpio-custom.bus3
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/rotary_encoder.h>
|
|
||||||
|
|
||||||
#define DRV_NAME "rotary-gpio-custom"
|
|
||||||
#define DRV_DESC "Custom GPIO-based rotary driver"
|
|
||||||
#define DRV_VERSION "0.1.0"
|
|
||||||
|
|
||||||
#define PFX DRV_NAME ": "
|
|
||||||
|
|
||||||
#define BUS_PARAM_REQUIRED 5
|
|
||||||
#define BUS_PARAM_COUNT 6
|
|
||||||
#define BUS_COUNT_MAX 4
|
|
||||||
|
|
||||||
static unsigned int bus0[BUS_PARAM_COUNT] __initdata;
|
|
||||||
static unsigned int bus1[BUS_PARAM_COUNT] __initdata;
|
|
||||||
static unsigned int bus2[BUS_PARAM_COUNT] __initdata;
|
|
||||||
static unsigned int bus3[BUS_PARAM_COUNT] __initdata;
|
|
||||||
|
|
||||||
static unsigned int bus_nump[BUS_COUNT_MAX] __initdata;
|
|
||||||
|
|
||||||
#define BUS_PARM_DESC \
|
|
||||||
" config -> id,steps,axis,gpioa,gpiob[,inverted]"
|
|
||||||
|
|
||||||
module_param_array(bus0, uint, &bus_nump[0], 0);
|
|
||||||
MODULE_PARM_DESC(bus0, "bus0" BUS_PARM_DESC);
|
|
||||||
module_param_array(bus1, uint, &bus_nump[1], 0);
|
|
||||||
MODULE_PARM_DESC(bus1, "bus1" BUS_PARM_DESC);
|
|
||||||
module_param_array(bus2, uint, &bus_nump[2], 0);
|
|
||||||
MODULE_PARM_DESC(bus2, "bus2" BUS_PARM_DESC);
|
|
||||||
module_param_array(bus3, uint, &bus_nump[3], 0);
|
|
||||||
MODULE_PARM_DESC(bus3, "bus3" BUS_PARM_DESC);
|
|
||||||
|
|
||||||
static struct platform_device *devices[BUS_COUNT_MAX];
|
|
||||||
static unsigned int nr_devices;
|
|
||||||
|
|
||||||
static void rotary_gpio_custom_cleanup(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < nr_devices; i++)
|
|
||||||
if (devices[i])
|
|
||||||
platform_device_put(devices[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init rotary_gpio_custom_add_one(unsigned int id,
|
|
||||||
unsigned int *params)
|
|
||||||
{
|
|
||||||
struct platform_device *pdev;
|
|
||||||
struct rotary_encoder_platform_data pdata;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!bus_nump[id])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (bus_nump[id] < BUS_PARAM_REQUIRED) {
|
|
||||||
printk(KERN_ERR PFX "not enough parameters for bus%d\n", id);
|
|
||||||
err = -EINVAL;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdev = platform_device_alloc("rotary-gpio", params[0]);
|
|
||||||
if (!pdev) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdata.steps = params[1];
|
|
||||||
pdata.axis = params[2];
|
|
||||||
pdata.relative_axis = false;
|
|
||||||
pdata.rollover = false;
|
|
||||||
pdata.gpio_a = params[3];
|
|
||||||
pdata.gpio_b = params[4];
|
|
||||||
|
|
||||||
if (params[5] == 1) {
|
|
||||||
pdata.inverted_a = 1;
|
|
||||||
pdata.inverted_b = 1;
|
|
||||||
} else {
|
|
||||||
pdata.inverted_a = 0;
|
|
||||||
pdata.inverted_b = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
|
|
||||||
if (err)
|
|
||||||
goto err_put;
|
|
||||||
|
|
||||||
err = platform_device_add(pdev);
|
|
||||||
if (err)
|
|
||||||
goto err_put;
|
|
||||||
|
|
||||||
devices[nr_devices++] = pdev;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_put:
|
|
||||||
platform_device_put(pdev);
|
|
||||||
err:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init rotary_gpio_custom_probe(void)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
|
|
||||||
|
|
||||||
err = rotary_gpio_custom_add_one(0, bus0);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
err = rotary_gpio_custom_add_one(1, bus1);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
err = rotary_gpio_custom_add_one(2, bus2);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
err = rotary_gpio_custom_add_one(3, bus3);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (!nr_devices) {
|
|
||||||
printk(KERN_ERR PFX "no bus parameter(s) specified\n");
|
|
||||||
err = -ENODEV;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
rotary_gpio_custom_cleanup();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MODULE
|
|
||||||
static int __init rotary_gpio_custom_init(void)
|
|
||||||
{
|
|
||||||
return rotary_gpio_custom_probe();
|
|
||||||
}
|
|
||||||
module_init(rotary_gpio_custom_init);
|
|
||||||
|
|
||||||
static void __exit rotary_gpio_custom_exit(void)
|
|
||||||
{
|
|
||||||
rotary_gpio_custom_cleanup();
|
|
||||||
}
|
|
||||||
module_exit(rotary_gpio_custom_exit);
|
|
||||||
#else
|
|
||||||
subsys_initcall(rotary_gpio_custom_probe);
|
|
||||||
#endif /* MODULE*/
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
|
||||||
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org >");
|
|
||||||
MODULE_AUTHOR("Claudio Mignanti <c.mignanti@gmail.com>");
|
|
||||||
MODULE_DESCRIPTION(DRV_DESC);
|
|
||||||
MODULE_VERSION(DRV_VERSION);
|
|
@ -24,7 +24,7 @@ include $(INCLUDE_DIR)/package.mk
|
|||||||
define KernelPackage/rtl8812au-ct
|
define KernelPackage/rtl8812au-ct
|
||||||
SUBMENU:=Wireless Drivers
|
SUBMENU:=Wireless Drivers
|
||||||
TITLE:=Driver for Realtek 8812 AU devices comfast 912-ac, etc
|
TITLE:=Driver for Realtek 8812 AU devices comfast 912-ac, etc
|
||||||
DEPENDS:=+kmod-cfg80211 +kmod-usb-core +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT @!LINUX_3_18 @!LINUX_4_9
|
DEPENDS:=+kmod-cfg80211 +kmod-usb-core +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT @!LINUX_4_9
|
||||||
FILES:=\
|
FILES:=\
|
||||||
$(PKG_BUILD_DIR)/rtl8812au.ko
|
$(PKG_BUILD_DIR)/rtl8812au.ko
|
||||||
AUTOLOAD:=$(call AutoProbe,rtl8812au)
|
AUTOLOAD:=$(call AutoProbe,rtl8812au)
|
||||||
|
@ -269,7 +269,7 @@ config OPENSSL_ENGINE_BUILTIN
|
|||||||
config OPENSSL_ENGINE_BUILTIN_AFALG
|
config OPENSSL_ENGINE_BUILTIN_AFALG
|
||||||
bool
|
bool
|
||||||
prompt "Acceleration support through AF_ALG sockets engine"
|
prompt "Acceleration support through AF_ALG sockets engine"
|
||||||
depends on OPENSSL_ENGINE_BUILTIN && KERNEL_AIO && !LINUX_3_18
|
depends on OPENSSL_ENGINE_BUILTIN && KERNEL_AIO
|
||||||
select PACKAGE_libopenssl-conf
|
select PACKAGE_libopenssl-conf
|
||||||
help
|
help
|
||||||
This enables use of hardware acceleration through the
|
This enables use of hardware acceleration through the
|
||||||
|
@ -139,7 +139,7 @@ define Package/libopenssl-afalg
|
|||||||
$(call Package/openssl/Default)
|
$(call Package/openssl/Default)
|
||||||
SUBMENU:=SSL
|
SUBMENU:=SSL
|
||||||
TITLE:=AFALG hardware acceleration engine
|
TITLE:=AFALG hardware acceleration engine
|
||||||
DEPENDS:=libopenssl @OPENSSL_ENGINE @KERNEL_AIO @!LINUX_3_18 \
|
DEPENDS:=libopenssl @OPENSSL_ENGINE @KERNEL_AIO \
|
||||||
+PACKAGE_libopenssl-afalg:kmod-crypto-user +libopenssl-conf @!OPENSSL_ENGINE_BUILTIN
|
+PACKAGE_libopenssl-afalg:kmod-crypto-user +libopenssl-conf @!OPENSSL_ENGINE_BUILTIN
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,142 +0,0 @@
|
|||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
|
|
||||||
@@ -27,7 +27,7 @@
|
|
||||||
#define BRNIMAGE_MAX_OVERHEAD (BRNIMAGE_ALIGN_BYTES + BRNIMAGE_FOOTER_SIZE)
|
|
||||||
|
|
||||||
static int mtdsplit_parse_brnimage(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct mtd_partition *parts;
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_eva.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_eva.c
|
|
||||||
@@ -29,7 +29,7 @@ struct eva_image_header {
|
|
||||||
};
|
|
||||||
|
|
||||||
static int mtdsplit_parse_eva(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct mtd_partition *parts;
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_fit.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_fit.c
|
|
||||||
@@ -45,8 +45,7 @@ struct fdt_header {
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
-mtdsplit_fit_parse(struct mtd_info *mtd,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+mtdsplit_fit_parse(struct mtd_info *mtd, struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct fdt_header hdr;
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_lzma.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_lzma.c
|
|
||||||
@@ -28,7 +28,7 @@ struct lzma_header {
|
|
||||||
};
|
|
||||||
|
|
||||||
static int mtdsplit_parse_lzma(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct lzma_header hdr;
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_seama.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_seama.c
|
|
||||||
@@ -30,7 +30,7 @@ struct seama_header {
|
|
||||||
};
|
|
||||||
|
|
||||||
static int mtdsplit_parse_seama(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct seama_header hdr;
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
|
|
||||||
@@ -23,7 +23,7 @@
|
|
||||||
|
|
||||||
static int
|
|
||||||
mtdsplit_parse_squashfs(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct mtd_partition *part;
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_tplink.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_tplink.c
|
|
||||||
@@ -83,8 +83,8 @@ struct tplink_fw_header {
|
|
||||||
};
|
|
||||||
|
|
||||||
static int mtdsplit_parse_tplink(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
- struct mtd_part_parser_data *data)
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct tplink_fw_header hdr;
|
|
||||||
size_t hdr_len, retlen, kernel_size;
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_trx.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_trx.c
|
|
||||||
@@ -56,7 +56,7 @@ read_trx_header(struct mtd_info *mtd, si
|
|
||||||
|
|
||||||
static int
|
|
||||||
mtdsplit_parse_trx(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct mtd_partition *parts;
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_uimage.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_uimage.c
|
|
||||||
@@ -82,7 +82,7 @@ read_uimage_header(struct mtd_info *mtd,
|
|
||||||
* of a valid uImage header if found
|
|
||||||
*/
|
|
||||||
static int __mtdsplit_parse_uimage(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data,
|
|
||||||
ssize_t (*find_header)(u_char *buf, size_t len))
|
|
||||||
{
|
|
||||||
@@ -233,7 +233,7 @@ static ssize_t uimage_verify_default(u_c
|
|
||||||
|
|
||||||
static int
|
|
||||||
mtdsplit_uimage_parse_generic(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
return __mtdsplit_parse_uimage(master, pparts, data,
|
|
||||||
@@ -300,7 +300,7 @@ static ssize_t uimage_verify_wndr3700(u_
|
|
||||||
|
|
||||||
static int
|
|
||||||
mtdsplit_uimage_parse_netgear(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
return __mtdsplit_parse_uimage(master, pparts, data,
|
|
||||||
@@ -352,7 +352,7 @@ static ssize_t uimage_find_edimax(u_char
|
|
||||||
|
|
||||||
static int
|
|
||||||
mtdsplit_uimage_parse_edimax(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
return __mtdsplit_parse_uimage(master, pparts, data,
|
|
||||||
--- a/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
|
|
||||||
+++ b/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
|
|
||||||
@@ -51,8 +51,8 @@ struct wrg_header {
|
|
||||||
|
|
||||||
|
|
||||||
static int mtdsplit_parse_wrgg(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
- struct mtd_part_parser_data *data)
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct wrgg03_header hdr;
|
|
||||||
size_t hdr_len, retlen, kernel_ent_size;
|
|
@ -1,552 +0,0 @@
|
|||||||
--- a/drivers/net/phy/adm6996.c
|
|
||||||
+++ b/drivers/net/phy/adm6996.c
|
|
||||||
@@ -289,7 +289,7 @@ static u16
|
|
||||||
adm6996_read_mii_reg(struct adm6996_priv *priv, enum admreg reg)
|
|
||||||
{
|
|
||||||
struct phy_device *phydev = priv->priv;
|
|
||||||
- struct mii_bus *bus = phydev->mdio.bus;
|
|
||||||
+ struct mii_bus *bus = phydev->bus;
|
|
||||||
|
|
||||||
return bus->read(bus, PHYADDR(reg));
|
|
||||||
}
|
|
||||||
@@ -298,7 +298,7 @@ static void
|
|
||||||
adm6996_write_mii_reg(struct adm6996_priv *priv, enum admreg reg, u16 val)
|
|
||||||
{
|
|
||||||
struct phy_device *phydev = priv->priv;
|
|
||||||
- struct mii_bus *bus = phydev->mdio.bus;
|
|
||||||
+ struct mii_bus *bus = phydev->bus;
|
|
||||||
|
|
||||||
bus->write(bus, PHYADDR(reg), val);
|
|
||||||
}
|
|
||||||
@@ -1050,13 +1050,13 @@ static int adm6996_config_init(struct ph
|
|
||||||
pdev->supported = ADVERTISED_100baseT_Full;
|
|
||||||
pdev->advertising = ADVERTISED_100baseT_Full;
|
|
||||||
|
|
||||||
- if (pdev->mdio.addr != 0) {
|
|
||||||
+ if (pdev->addr != 0) {
|
|
||||||
pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n"
|
|
||||||
- , pdev->attached_dev->name, pdev->mdio.addr);
|
|
||||||
+ , pdev->attached_dev->name, pdev->addr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
- priv = devm_kzalloc(&pdev->mdio.dev, sizeof(struct adm6996_priv), GFP_KERNEL);
|
|
||||||
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL);
|
|
||||||
if (!priv)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
@@ -1076,7 +1076,7 @@ static int adm6996_config_init(struct ph
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
- * Warning: phydev->priv is NULL if phydev->mdio.addr != 0
|
|
||||||
+ * Warning: phydev->priv is NULL if phydev->addr != 0
|
|
||||||
*/
|
|
||||||
static int adm6996_read_status(struct phy_device *phydev)
|
|
||||||
{
|
|
||||||
@@ -1092,7 +1092,7 @@ static int adm6996_read_status(struct ph
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
- * Warning: phydev->priv is NULL if phydev->mdio.addr != 0
|
|
||||||
+ * Warning: phydev->priv is NULL if phydev->addr != 0
|
|
||||||
*/
|
|
||||||
static int adm6996_config_aneg(struct phy_device *phydev)
|
|
||||||
{
|
|
||||||
@@ -1101,11 +1101,11 @@ static int adm6996_config_aneg(struct ph
|
|
||||||
|
|
||||||
static int adm6996_fixup(struct phy_device *dev)
|
|
||||||
{
|
|
||||||
- struct mii_bus *bus = dev->mdio.bus;
|
|
||||||
+ struct mii_bus *bus = dev->bus;
|
|
||||||
u16 reg;
|
|
||||||
|
|
||||||
/* Our custom registers are at PHY addresses 0-10. Claim those. */
|
|
||||||
- if (dev->mdio.addr > 10)
|
|
||||||
+ if (dev->addr > 10)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* look for the switch on the bus */
|
|
||||||
@@ -1152,6 +1152,7 @@ static struct phy_driver adm6996_phy_dri
|
|
||||||
.config_aneg = &adm6996_config_aneg,
|
|
||||||
.read_status = &adm6996_read_status,
|
|
||||||
.soft_reset = adm6996_soft_reset,
|
|
||||||
+ .driver = { .owner = THIS_MODULE,},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int adm6996_gpio_probe(struct platform_device *pdev)
|
|
||||||
@@ -1220,7 +1221,7 @@ static int __init adm6996_init(void)
|
|
||||||
int err;
|
|
||||||
|
|
||||||
phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup);
|
|
||||||
- err = phy_driver_register(&adm6996_phy_driver, THIS_MODULE);
|
|
||||||
+ err = phy_driver_register(&adm6996_phy_driver);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
--- a/drivers/net/phy/ar8216.c
|
|
||||||
+++ b/drivers/net/phy/ar8216.c
|
|
||||||
@@ -177,7 +177,7 @@ ar8xxx_phy_check_aneg(struct phy_device
|
|
||||||
if (ret & BMCR_ANENABLE)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
- dev_info(&phydev->mdio.dev, "ANEG disabled, re-enabling ...\n");
|
|
||||||
+ dev_info(&phydev->dev, "ANEG disabled, re-enabling ...\n");
|
|
||||||
ret |= BMCR_ANENABLE | BMCR_ANRESTART;
|
|
||||||
return phy_write(phydev, MII_BMCR, ret);
|
|
||||||
}
|
|
||||||
@@ -2021,7 +2021,7 @@ ar8xxx_phy_config_init(struct phy_device
|
|
||||||
|
|
||||||
priv->phy = phydev;
|
|
||||||
|
|
||||||
- if (phydev->mdio.addr != 0) {
|
|
||||||
+ if (phydev->addr != 0) {
|
|
||||||
if (chip_is_ar8316(priv)) {
|
|
||||||
/* switch device has been initialized, reinit */
|
|
||||||
priv->dev.ports = (AR8216_NUM_PORTS - 1);
|
|
||||||
@@ -2069,7 +2069,7 @@ ar8xxx_check_link_states(struct ar8xxx_p
|
|
||||||
/* flush ARL entries for this port if it went down*/
|
|
||||||
if (!link_new)
|
|
||||||
priv->chip->atu_flush_port(priv, i);
|
|
||||||
- dev_info(&priv->phy->mdio.dev, "Port %d is %s\n",
|
|
||||||
+ dev_info(&priv->phy->dev, "Port %d is %s\n",
|
|
||||||
i, link_new ? "up" : "down");
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2088,10 +2088,10 @@ ar8xxx_phy_read_status(struct phy_device
|
|
||||||
if (phydev->state == PHY_CHANGELINK)
|
|
||||||
ar8xxx_check_link_states(priv);
|
|
||||||
|
|
||||||
- if (phydev->mdio.addr != 0)
|
|
||||||
+ if (phydev->addr != 0)
|
|
||||||
return genphy_read_status(phydev);
|
|
||||||
|
|
||||||
- ar8216_read_port_link(priv, phydev->mdio.addr, &link);
|
|
||||||
+ ar8216_read_port_link(priv, phydev->addr, &link);
|
|
||||||
phydev->link = !!link.link;
|
|
||||||
if (!phydev->link)
|
|
||||||
return 0;
|
|
||||||
@@ -2122,7 +2122,7 @@ ar8xxx_phy_read_status(struct phy_device
|
|
||||||
static int
|
|
||||||
ar8xxx_phy_config_aneg(struct phy_device *phydev)
|
|
||||||
{
|
|
||||||
- if (phydev->mdio.addr == 0)
|
|
||||||
+ if (phydev->addr == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return genphy_config_aneg(phydev);
|
|
||||||
@@ -2177,15 +2177,15 @@ ar8xxx_phy_probe(struct phy_device *phyd
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* skip PHYs at unused adresses */
|
|
||||||
- if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && phydev->mdio.addr != 4)
|
|
||||||
+ if (phydev->addr != 0 && phydev->addr != 3 && phydev->addr != 4)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
- if (!ar8xxx_is_possible(phydev->mdio.bus))
|
|
||||||
+ if (!ar8xxx_is_possible(phydev->bus))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
mutex_lock(&ar8xxx_dev_list_lock);
|
|
||||||
list_for_each_entry(priv, &ar8xxx_dev_list, list)
|
|
||||||
- if (priv->mii_bus == phydev->mdio.bus)
|
|
||||||
+ if (priv->mii_bus == phydev->bus)
|
|
||||||
goto found;
|
|
||||||
|
|
||||||
priv = ar8xxx_create();
|
|
||||||
@@ -2194,7 +2194,7 @@ ar8xxx_phy_probe(struct phy_device *phyd
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
- priv->mii_bus = phydev->mdio.bus;
|
|
||||||
+ priv->mii_bus = phydev->bus;
|
|
||||||
|
|
||||||
ret = ar8xxx_probe_switch(priv);
|
|
||||||
if (ret)
|
|
||||||
@@ -2215,7 +2215,7 @@ ar8xxx_phy_probe(struct phy_device *phyd
|
|
||||||
found:
|
|
||||||
priv->use_count++;
|
|
||||||
|
|
||||||
- if (phydev->mdio.addr == 0) {
|
|
||||||
+ if (phydev->addr == 0) {
|
|
||||||
if (ar8xxx_has_gige(priv)) {
|
|
||||||
phydev->supported = SUPPORTED_1000baseT_Full;
|
|
||||||
phydev->advertising = ADVERTISED_1000baseT_Full;
|
|
||||||
@@ -2305,21 +2305,33 @@ ar8xxx_phy_soft_reset(struct phy_device
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct phy_driver ar8xxx_phy_driver[] = {
|
|
||||||
- {
|
|
||||||
- .phy_id = 0x004d0000,
|
|
||||||
- .name = "Atheros AR8216/AR8236/AR8316",
|
|
||||||
- .phy_id_mask = 0xffff0000,
|
|
||||||
- .features = PHY_BASIC_FEATURES,
|
|
||||||
- .probe = ar8xxx_phy_probe,
|
|
||||||
- .remove = ar8xxx_phy_remove,
|
|
||||||
- .detach = ar8xxx_phy_detach,
|
|
||||||
- .config_init = ar8xxx_phy_config_init,
|
|
||||||
- .config_aneg = ar8xxx_phy_config_aneg,
|
|
||||||
- .read_status = ar8xxx_phy_read_status,
|
|
||||||
- .soft_reset = ar8xxx_phy_soft_reset,
|
|
||||||
- }
|
|
||||||
+static struct phy_driver ar8xxx_phy_driver = {
|
|
||||||
+ .phy_id = 0x004d0000,
|
|
||||||
+ .name = "Atheros AR8216/AR8236/AR8316",
|
|
||||||
+ .phy_id_mask = 0xffff0000,
|
|
||||||
+ .features = PHY_BASIC_FEATURES,
|
|
||||||
+ .probe = ar8xxx_phy_probe,
|
|
||||||
+ .remove = ar8xxx_phy_remove,
|
|
||||||
+ .detach = ar8xxx_phy_detach,
|
|
||||||
+ .config_init = ar8xxx_phy_config_init,
|
|
||||||
+ .config_aneg = ar8xxx_phy_config_aneg,
|
|
||||||
+ .read_status = ar8xxx_phy_read_status,
|
|
||||||
+ .soft_reset = ar8xxx_phy_soft_reset,
|
|
||||||
+ .driver = { .owner = THIS_MODULE },
|
|
||||||
};
|
|
||||||
|
|
||||||
-module_phy_driver(ar8xxx_phy_driver);
|
|
||||||
+int __init
|
|
||||||
+ar8xxx_init(void)
|
|
||||||
+{
|
|
||||||
+ return phy_driver_register(&ar8xxx_phy_driver);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void __exit
|
|
||||||
+ar8xxx_exit(void)
|
|
||||||
+{
|
|
||||||
+ phy_driver_unregister(&ar8xxx_phy_driver);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+module_init(ar8xxx_init);
|
|
||||||
+module_exit(ar8xxx_exit);
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
--- a/drivers/net/phy/ar8327.c
|
|
||||||
+++ b/drivers/net/phy/ar8327.c
|
|
||||||
@@ -662,11 +662,11 @@ ar8327_hw_init(struct ar8xxx_priv *priv)
|
|
||||||
if (!priv->chip_data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
- if (priv->phy->mdio.dev.of_node)
|
|
||||||
- ret = ar8327_hw_config_of(priv, priv->phy->mdio.dev.of_node);
|
|
||||||
+ if (priv->phy->dev.of_node)
|
|
||||||
+ ret = ar8327_hw_config_of(priv, priv->phy->dev.of_node);
|
|
||||||
else
|
|
||||||
ret = ar8327_hw_config_pdata(priv,
|
|
||||||
- priv->phy->mdio.dev.platform_data);
|
|
||||||
+ priv->phy->dev.platform_data);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
--- a/drivers/net/phy/ip17xx.c
|
|
||||||
+++ b/drivers/net/phy/ip17xx.c
|
|
||||||
@@ -1273,7 +1273,7 @@ static int ip17xx_probe(struct phy_devic
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* We only attach to PHY 0, but use all available PHYs */
|
|
||||||
- if (pdev->mdio.addr != 0)
|
|
||||||
+ if (pdev->addr != 0)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
||||||
@@ -1283,7 +1283,7 @@ static int ip17xx_probe(struct phy_devic
|
|
||||||
dev = &state->dev;
|
|
||||||
|
|
||||||
pdev->priv = state;
|
|
||||||
- state->mii_bus = pdev->mdio.bus;
|
|
||||||
+ state->mii_bus = pdev->bus;
|
|
||||||
|
|
||||||
err = get_model(state);
|
|
||||||
if (err < 0)
|
|
||||||
@@ -1295,7 +1295,7 @@ static int ip17xx_probe(struct phy_devic
|
|
||||||
dev->name = state->regs->NAME;
|
|
||||||
dev->ops = &ip17xx_ops;
|
|
||||||
|
|
||||||
- pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->mdio.dev));
|
|
||||||
+ pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->dev));
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
@@ -1353,25 +1353,58 @@ static int ip17xx_read_status(struct phy
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct phy_driver ip17xx_driver[] = {
|
|
||||||
- {
|
|
||||||
- .name = "IC+ IP17xx",
|
|
||||||
- .phy_id = 0x02430c00,
|
|
||||||
- .phy_id_mask = 0x0ffffc00,
|
|
||||||
- .features = PHY_BASIC_FEATURES,
|
|
||||||
- .probe = ip17xx_probe,
|
|
||||||
- .remove = ip17xx_remove,
|
|
||||||
- .config_init = ip17xx_config_init,
|
|
||||||
- .config_aneg = ip17xx_config_aneg,
|
|
||||||
- .aneg_done = ip17xx_aneg_done,
|
|
||||||
- .update_link = ip17xx_update_link,
|
|
||||||
- .read_status = ip17xx_read_status,
|
|
||||||
- }
|
|
||||||
+static struct phy_driver ip17xx_driver = {
|
|
||||||
+ .name = "IC+ IP17xx",
|
|
||||||
+ .phy_id = 0x02430c00,
|
|
||||||
+ .phy_id_mask = 0x0ffffc00,
|
|
||||||
+ .features = PHY_BASIC_FEATURES,
|
|
||||||
+ .probe = ip17xx_probe,
|
|
||||||
+ .remove = ip17xx_remove,
|
|
||||||
+ .config_init = ip17xx_config_init,
|
|
||||||
+ .config_aneg = ip17xx_config_aneg,
|
|
||||||
+ .aneg_done = ip17xx_aneg_done,
|
|
||||||
+ .update_link = ip17xx_update_link,
|
|
||||||
+ .read_status = ip17xx_read_status,
|
|
||||||
+ .driver = { .owner = THIS_MODULE },
|
|
||||||
};
|
|
||||||
|
|
||||||
-module_phy_driver(ip17xx_driver);
|
|
||||||
+static struct phy_driver ip175a_driver = {
|
|
||||||
+ .name = "IC+ IP175A",
|
|
||||||
+ .phy_id = 0x02430c50,
|
|
||||||
+ .phy_id_mask = 0x0ffffff0,
|
|
||||||
+ .features = PHY_BASIC_FEATURES,
|
|
||||||
+ .probe = ip17xx_probe,
|
|
||||||
+ .remove = ip17xx_remove,
|
|
||||||
+ .config_init = ip17xx_config_init,
|
|
||||||
+ .config_aneg = ip17xx_config_aneg,
|
|
||||||
+ .aneg_done = ip17xx_aneg_done,
|
|
||||||
+ .update_link = ip17xx_update_link,
|
|
||||||
+ .read_status = ip17xx_read_status,
|
|
||||||
+ .driver = { .owner = THIS_MODULE },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+int __init ip17xx_init(void)
|
|
||||||
+{
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ ret = phy_driver_register(&ip175a_driver);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
+
|
|
||||||
+ return phy_driver_register(&ip17xx_driver);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void __exit ip17xx_exit(void)
|
|
||||||
+{
|
|
||||||
+ phy_driver_unregister(&ip17xx_driver);
|
|
||||||
+ phy_driver_unregister(&ip175a_driver);
|
|
||||||
+}
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Patrick Horn <patrick.horn@gmail.com>");
|
|
||||||
MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
|
|
||||||
MODULE_AUTHOR("Martin Mares <mj@ucw.cz>");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
+
|
|
||||||
+module_init(ip17xx_init);
|
|
||||||
+module_exit(ip17xx_exit);
|
|
||||||
--- a/drivers/net/phy/mvswitch.c
|
|
||||||
+++ b/drivers/net/phy/mvswitch.c
|
|
||||||
@@ -50,17 +50,13 @@ struct mvswitch_priv {
|
|
||||||
static inline u16
|
|
||||||
r16(struct phy_device *phydev, int addr, int reg)
|
|
||||||
{
|
|
||||||
- struct mii_bus *bus = phydev->mdio.bus;
|
|
||||||
-
|
|
||||||
- return bus->read(bus, addr, reg);
|
|
||||||
+ return phydev->bus->read(phydev->bus, addr, reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
w16(struct phy_device *phydev, int addr, int reg, u16 val)
|
|
||||||
{
|
|
||||||
- struct mii_bus *bus = phydev->mdio.bus;
|
|
||||||
-
|
|
||||||
- bus->write(bus, addr, reg, val);
|
|
||||||
+ phydev->bus->write(phydev->bus, addr, reg, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -398,13 +394,12 @@ mvswitch_probe(struct phy_device *pdev)
|
|
||||||
static int
|
|
||||||
mvswitch_fixup(struct phy_device *dev)
|
|
||||||
{
|
|
||||||
- struct mii_bus *bus = dev->mdio.bus;
|
|
||||||
u16 reg;
|
|
||||||
|
|
||||||
- if (dev->mdio.addr != 0x10)
|
|
||||||
+ if (dev->addr != 0x10)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
- reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
|
|
||||||
+ reg = dev->bus->read(dev->bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
|
|
||||||
if (reg != MV_IDENT_VALUE)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
@@ -425,13 +420,14 @@ static struct phy_driver mvswitch_driver
|
|
||||||
.config_aneg = &mvswitch_config_aneg,
|
|
||||||
.aneg_done = &mvswitch_aneg_done,
|
|
||||||
.read_status = &mvswitch_read_status,
|
|
||||||
+ .driver = { .owner = THIS_MODULE,},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init
|
|
||||||
mvswitch_init(void)
|
|
||||||
{
|
|
||||||
phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup);
|
|
||||||
- return phy_driver_register(&mvswitch_driver, THIS_MODULE);
|
|
||||||
+ return phy_driver_register(&mvswitch_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit
|
|
||||||
--- a/drivers/net/phy/psb6970.c
|
|
||||||
+++ b/drivers/net/phy/psb6970.c
|
|
||||||
@@ -70,16 +70,12 @@ struct psb6970_priv {
|
|
||||||
|
|
||||||
static u16 psb6970_mii_read(struct phy_device *phydev, int reg)
|
|
||||||
{
|
|
||||||
- struct mii_bus *bus = phydev->mdio.bus;
|
|
||||||
-
|
|
||||||
- return bus->read(bus, PHYADDR(reg));
|
|
||||||
+ return phydev->bus->read(phydev->bus, PHYADDR(reg));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val)
|
|
||||||
{
|
|
||||||
- struct mii_bus *bus = phydev->mdio.bus;
|
|
||||||
-
|
|
||||||
- bus->write(bus, PHYADDR(reg), val);
|
|
||||||
+ phydev->bus->write(phydev->bus, PHYADDR(reg), val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
@@ -316,11 +312,11 @@ static int psb6970_config_init(struct ph
|
|
||||||
|
|
||||||
priv->phy = pdev;
|
|
||||||
|
|
||||||
- if (pdev->mdio.addr == 0)
|
|
||||||
+ if (pdev->addr == 0)
|
|
||||||
printk(KERN_INFO "%s: psb6970 switch driver attached.\n",
|
|
||||||
pdev->attached_dev->name);
|
|
||||||
|
|
||||||
- if (pdev->mdio.addr != 0) {
|
|
||||||
+ if (pdev->addr != 0) {
|
|
||||||
kfree(priv);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -388,14 +384,14 @@ static void psb6970_remove(struct phy_de
|
|
||||||
if (!priv)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- if (pdev->mdio.addr == 0)
|
|
||||||
+ if (pdev->addr == 0)
|
|
||||||
unregister_switch(&priv->dev);
|
|
||||||
kfree(priv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int psb6970_fixup(struct phy_device *dev)
|
|
||||||
{
|
|
||||||
- struct mii_bus *bus = dev->mdio.bus;
|
|
||||||
+ struct mii_bus *bus = dev->bus;
|
|
||||||
u16 reg;
|
|
||||||
|
|
||||||
/* look for the switch on the bus */
|
|
||||||
@@ -419,12 +415,13 @@ static struct phy_driver psb6970_driver
|
|
||||||
.config_init = &psb6970_config_init,
|
|
||||||
.config_aneg = &psb6970_config_aneg,
|
|
||||||
.read_status = &psb6970_read_status,
|
|
||||||
+ .driver = {.owner = THIS_MODULE},
|
|
||||||
};
|
|
||||||
|
|
||||||
int __init psb6970_init(void)
|
|
||||||
{
|
|
||||||
phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup);
|
|
||||||
- return phy_driver_register(&psb6970_driver, THIS_MODULE);
|
|
||||||
+ return phy_driver_register(&psb6970_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(psb6970_init);
|
|
||||||
--- a/drivers/net/phy/rtl8306.c
|
|
||||||
+++ b/drivers/net/phy/rtl8306.c
|
|
||||||
@@ -877,7 +877,7 @@ rtl8306_config_init(struct phy_device *p
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* Only init the switch for the primary PHY */
|
|
||||||
- if (pdev->mdio.addr != 0)
|
|
||||||
+ if (pdev->addr != 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
val.value.i = 1;
|
|
||||||
@@ -887,7 +887,7 @@ rtl8306_config_init(struct phy_device *p
|
|
||||||
priv->dev.ops = &rtl8306_ops;
|
|
||||||
priv->do_cpu = 0;
|
|
||||||
priv->page = -1;
|
|
||||||
- priv->bus = pdev->mdio.bus;
|
|
||||||
+ priv->bus = pdev->bus;
|
|
||||||
|
|
||||||
chipid = rtl_get(dev, RTL_REG_CHIPID);
|
|
||||||
chipver = rtl_get(dev, RTL_REG_CHIPVER);
|
|
||||||
@@ -933,13 +933,13 @@ rtl8306_fixup(struct phy_device *pdev)
|
|
||||||
u16 chipid;
|
|
||||||
|
|
||||||
/* Attach to primary LAN port and WAN port */
|
|
||||||
- if (pdev->mdio.addr != 0 && pdev->mdio.addr != 4)
|
|
||||||
+ if (pdev->addr != 0 && pdev->addr != 4)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
memset(&priv, 0, sizeof(priv));
|
|
||||||
priv.fixup = true;
|
|
||||||
priv.page = -1;
|
|
||||||
- priv.bus = pdev->mdio.bus;
|
|
||||||
+ priv.bus = pdev->bus;
|
|
||||||
chipid = rtl_get(&priv.dev, RTL_REG_CHIPID);
|
|
||||||
if (chipid == 0x5988)
|
|
||||||
pdev->phy_id = RTL8306_MAGIC;
|
|
||||||
@@ -957,14 +957,14 @@ rtl8306_probe(struct phy_device *pdev)
|
|
||||||
* share one rtl_priv instance between virtual phy
|
|
||||||
* devices on the same bus
|
|
||||||
*/
|
|
||||||
- if (priv->bus == pdev->mdio.bus)
|
|
||||||
+ if (priv->bus == pdev->bus)
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL);
|
|
||||||
if (!priv)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
- priv->bus = pdev->mdio.bus;
|
|
||||||
+ priv->bus = pdev->bus;
|
|
||||||
|
|
||||||
found:
|
|
||||||
pdev->priv = priv;
|
|
||||||
@@ -985,7 +985,7 @@ rtl8306_config_aneg(struct phy_device *p
|
|
||||||
struct rtl_priv *priv = pdev->priv;
|
|
||||||
|
|
||||||
/* Only for WAN */
|
|
||||||
- if (pdev->mdio.addr == 0)
|
|
||||||
+ if (pdev->addr == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Restart autonegotiation */
|
|
||||||
@@ -1001,7 +1001,7 @@ rtl8306_read_status(struct phy_device *p
|
|
||||||
struct rtl_priv *priv = pdev->priv;
|
|
||||||
struct switch_dev *dev = &priv->dev;
|
|
||||||
|
|
||||||
- if (pdev->mdio.addr == 4) {
|
|
||||||
+ if (pdev->addr == 4) {
|
|
||||||
/* WAN */
|
|
||||||
pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10;
|
|
||||||
pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF;
|
|
||||||
@@ -1044,6 +1044,7 @@ static struct phy_driver rtl8306_driver
|
|
||||||
.config_init = &rtl8306_config_init,
|
|
||||||
.config_aneg = &rtl8306_config_aneg,
|
|
||||||
.read_status = &rtl8306_read_status,
|
|
||||||
+ .driver = { .owner = THIS_MODULE,},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1051,7 +1052,7 @@ static int __init
|
|
||||||
rtl_init(void)
|
|
||||||
{
|
|
||||||
phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup);
|
|
||||||
- return phy_driver_register(&rtl8306_driver, THIS_MODULE);
|
|
||||||
+ return phy_driver_register(&rtl8306_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit
|
|
@ -1,11 +0,0 @@
|
|||||||
--- a/drivers/mtd/myloader.c
|
|
||||||
+++ b/drivers/mtd/myloader.c
|
|
||||||
@@ -33,7 +33,7 @@ struct part_data {
|
|
||||||
};
|
|
||||||
|
|
||||||
static int myloader_parse_partitions(struct mtd_info *master,
|
|
||||||
- const struct mtd_partition **pparts,
|
|
||||||
+ struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
{
|
|
||||||
struct part_data *buf;
|
|
@ -1,134 +0,0 @@
|
|||||||
--- a/drivers/ssb/pcihost_wrapper.c
|
|
||||||
+++ b/drivers/ssb/pcihost_wrapper.c
|
|
||||||
@@ -11,15 +11,17 @@
|
|
||||||
* Licensed under the GNU/GPL. See COPYING for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
+#include <linux/pm.h>
|
|
||||||
#include <linux/pci.h>
|
|
||||||
#include <linux/export.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/ssb/ssb.h>
|
|
||||||
|
|
||||||
|
|
||||||
-#ifdef CONFIG_PM
|
|
||||||
-static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
|
|
||||||
+#ifdef CONFIG_PM_SLEEP
|
|
||||||
+static int ssb_pcihost_suspend(struct device *d)
|
|
||||||
{
|
|
||||||
+ struct pci_dev *dev = to_pci_dev(d);
|
|
||||||
struct ssb_bus *ssb = pci_get_drvdata(dev);
|
|
||||||
int err;
|
|
||||||
|
|
||||||
@@ -28,17 +30,23 @@ static int ssb_pcihost_suspend(struct pc
|
|
||||||
return err;
|
|
||||||
pci_save_state(dev);
|
|
||||||
pci_disable_device(dev);
|
|
||||||
- pci_set_power_state(dev, pci_choose_state(dev, state));
|
|
||||||
+
|
|
||||||
+ /* if there is a wakeup enabled child device on ssb bus,
|
|
||||||
+ enable pci wakeup posibility. */
|
|
||||||
+ device_set_wakeup_enable(d, d->power.wakeup_path);
|
|
||||||
+
|
|
||||||
+ pci_prepare_to_sleep(dev);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int ssb_pcihost_resume(struct pci_dev *dev)
|
|
||||||
+static int ssb_pcihost_resume(struct device *d)
|
|
||||||
{
|
|
||||||
+ struct pci_dev *dev = to_pci_dev(d);
|
|
||||||
struct ssb_bus *ssb = pci_get_drvdata(dev);
|
|
||||||
int err;
|
|
||||||
|
|
||||||
- pci_set_power_state(dev, PCI_D0);
|
|
||||||
+ pci_back_from_sleep(dev);
|
|
||||||
err = pci_enable_device(dev);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
@@ -49,10 +57,12 @@ static int ssb_pcihost_resume(struct pci
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
-#else /* CONFIG_PM */
|
|
||||||
-# define ssb_pcihost_suspend NULL
|
|
||||||
-# define ssb_pcihost_resume NULL
|
|
||||||
-#endif /* CONFIG_PM */
|
|
||||||
+
|
|
||||||
+static const struct dev_pm_ops ssb_pcihost_pm_ops = {
|
|
||||||
+ SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume)
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#endif /* CONFIG_PM_SLEEP */
|
|
||||||
|
|
||||||
static int ssb_pcihost_probe(struct pci_dev *dev,
|
|
||||||
const struct pci_device_id *id)
|
|
||||||
@@ -115,8 +125,9 @@ int ssb_pcihost_register(struct pci_driv
|
|
||||||
{
|
|
||||||
driver->probe = ssb_pcihost_probe;
|
|
||||||
driver->remove = ssb_pcihost_remove;
|
|
||||||
- driver->suspend = ssb_pcihost_suspend;
|
|
||||||
- driver->resume = ssb_pcihost_resume;
|
|
||||||
+#ifdef CONFIG_PM_SLEEP
|
|
||||||
+ driver->driver.pm = &ssb_pcihost_pm_ops;
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
return pci_register_driver(driver);
|
|
||||||
}
|
|
||||||
--- a/drivers/ssb/driver_pcicore.c
|
|
||||||
+++ b/drivers/ssb/driver_pcicore.c
|
|
||||||
@@ -357,6 +357,16 @@ static void ssb_pcicore_init_hostmode(st
|
|
||||||
pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
|
|
||||||
SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
|
|
||||||
|
|
||||||
+ /*
|
|
||||||
+ * Accessing PCI config without a proper delay after devices reset (not
|
|
||||||
+ * GPIO reset) was causing reboots on WRT300N v1.0 (BCM4704).
|
|
||||||
+ * Tested delay 850 us lowered reboot chance to 50-80%, 1000 us fixed it
|
|
||||||
+ * completely. Flushing all writes was also tested but with no luck.
|
|
||||||
+ * The same problem was reported for WRT350N v1 (BCM4705), so we just
|
|
||||||
+ * sleep here unconditionally.
|
|
||||||
+ */
|
|
||||||
+ usleep_range(1000, 2000);
|
|
||||||
+
|
|
||||||
/* Enable PCI bridge BAR0 prefetch and burst */
|
|
||||||
val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
|
|
||||||
ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
|
|
||||||
--- a/drivers/ssb/main.c
|
|
||||||
+++ b/drivers/ssb/main.c
|
|
||||||
@@ -90,25 +90,6 @@ found:
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_SSB_PCMCIAHOST */
|
|
||||||
|
|
||||||
-#ifdef CONFIG_SSB_SDIOHOST
|
|
||||||
-struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func)
|
|
||||||
-{
|
|
||||||
- struct ssb_bus *bus;
|
|
||||||
-
|
|
||||||
- ssb_buses_lock();
|
|
||||||
- list_for_each_entry(bus, &buses, list) {
|
|
||||||
- if (bus->bustype == SSB_BUSTYPE_SDIO &&
|
|
||||||
- bus->host_sdio == func)
|
|
||||||
- goto found;
|
|
||||||
- }
|
|
||||||
- bus = NULL;
|
|
||||||
-found:
|
|
||||||
- ssb_buses_unlock();
|
|
||||||
-
|
|
||||||
- return bus;
|
|
||||||
-}
|
|
||||||
-#endif /* CONFIG_SSB_SDIOHOST */
|
|
||||||
-
|
|
||||||
int ssb_for_each_bus_call(unsigned long data,
|
|
||||||
int (*func)(struct ssb_bus *bus, unsigned long data))
|
|
||||||
{
|
|
||||||
@@ -1154,6 +1135,8 @@ static u32 ssb_tmslow_reject_bitmask(str
|
|
||||||
case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */
|
|
||||||
case SSB_IDLOW_SSBREV_27: /* same here */
|
|
||||||
return SSB_TMSLOW_REJECT; /* this is a guess */
|
|
||||||
+ case SSB_IDLOW_SSBREV:
|
|
||||||
+ break;
|
|
||||||
default:
|
|
||||||
WARN(1, KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
--- a/include/linux/ssb/ssb.h
|
|
||||||
+++ b/include/linux/ssb/ssb.h
|
|
||||||
@@ -29,10 +29,13 @@ struct ssb_sprom {
|
|
||||||
u8 il0mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11b/g */
|
|
||||||
u8 et0mac[6] __aligned(sizeof(u16)); /* MAC address for Ethernet */
|
|
||||||
u8 et1mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11a */
|
|
||||||
+ u8 et2mac[6] __aligned(sizeof(u16)); /* MAC address for extra Ethernet */
|
|
||||||
u8 et0phyaddr; /* MII address for enet0 */
|
|
||||||
u8 et1phyaddr; /* MII address for enet1 */
|
|
||||||
+ u8 et2phyaddr; /* MII address for enet2 */
|
|
||||||
u8 et0mdcport; /* MDIO for enet0 */
|
|
||||||
u8 et1mdcport; /* MDIO for enet1 */
|
|
||||||
+ u8 et2mdcport; /* MDIO for enet2 */
|
|
||||||
u16 dev_id; /* Device ID overriding e.g. PCI ID */
|
|
||||||
u16 board_rev; /* Board revision number from SPROM. */
|
|
||||||
u16 board_num; /* Board number from SPROM. */
|
|
||||||
@@ -88,11 +91,14 @@ struct ssb_sprom {
|
|
||||||
u32 ofdm5glpo; /* 5.2GHz OFDM power offset */
|
|
||||||
u32 ofdm5gpo; /* 5.3GHz OFDM power offset */
|
|
||||||
u32 ofdm5ghpo; /* 5.8GHz OFDM power offset */
|
|
||||||
+ u32 boardflags;
|
|
||||||
+ u32 boardflags2;
|
|
||||||
+ u32 boardflags3;
|
|
||||||
+ /* TODO: Switch all drivers to new u32 fields and drop below ones */
|
|
||||||
u16 boardflags_lo; /* Board flags (bits 0-15) */
|
|
||||||
u16 boardflags_hi; /* Board flags (bits 16-31) */
|
|
||||||
u16 boardflags2_lo; /* Board flags (bits 32-47) */
|
|
||||||
u16 boardflags2_hi; /* Board flags (bits 48-63) */
|
|
||||||
- /* TODO store board flags in a single u64 */
|
|
||||||
|
|
||||||
struct ssb_sprom_core_pwr_info core_pwr_info[4];
|
|
||||||
|
|
@ -1,286 +0,0 @@
|
|||||||
--- a/drivers/bcma/bcma_private.h
|
|
||||||
+++ b/drivers/bcma/bcma_private.h
|
|
||||||
@@ -22,6 +22,7 @@ struct bcma_bus;
|
|
||||||
/* main.c */
|
|
||||||
bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
|
|
||||||
int timeout);
|
|
||||||
+void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
|
|
||||||
int bcma_bus_register(struct bcma_bus *bus);
|
|
||||||
void bcma_bus_unregister(struct bcma_bus *bus);
|
|
||||||
int __init bcma_bus_early_register(struct bcma_bus *bus,
|
|
||||||
--- a/drivers/bcma/driver_chipcommon.c
|
|
||||||
+++ b/drivers/bcma/driver_chipcommon.c
|
|
||||||
@@ -339,7 +339,7 @@ void bcma_chipco_serial_init(struct bcma
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
- irq = bcma_core_irq(cc->core);
|
|
||||||
+ irq = bcma_core_irq(cc->core, 0);
|
|
||||||
|
|
||||||
/* Determine the registers of the UARTs */
|
|
||||||
cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
|
|
||||||
--- a/drivers/bcma/driver_gpio.c
|
|
||||||
+++ b/drivers/bcma/driver_gpio.c
|
|
||||||
@@ -152,7 +152,7 @@ static int bcma_gpio_irq_domain_init(str
|
|
||||||
handle_simple_irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
- hwirq = bcma_core_irq(cc->core);
|
|
||||||
+ hwirq = bcma_core_irq(cc->core, 0);
|
|
||||||
err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio",
|
|
||||||
cc);
|
|
||||||
if (err)
|
|
||||||
@@ -183,7 +183,7 @@ static void bcma_gpio_irq_domain_exit(st
|
|
||||||
return;
|
|
||||||
|
|
||||||
bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO);
|
|
||||||
- free_irq(bcma_core_irq(cc->core), cc);
|
|
||||||
+ free_irq(bcma_core_irq(cc->core, 0), cc);
|
|
||||||
for (gpio = 0; gpio < chip->ngpio; gpio++) {
|
|
||||||
int irq = irq_find_mapping(cc->irq_domain, gpio);
|
|
||||||
|
|
||||||
--- a/drivers/bcma/driver_mips.c
|
|
||||||
+++ b/drivers/bcma/driver_mips.c
|
|
||||||
@@ -115,7 +115,7 @@ static u32 bcma_core_mips_irqflag(struct
|
|
||||||
* If disabled, 5 is returned.
|
|
||||||
* If not supported, 6 is returned.
|
|
||||||
*/
|
|
||||||
-static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
|
|
||||||
+unsigned int bcma_core_mips_irq(struct bcma_device *dev)
|
|
||||||
{
|
|
||||||
struct bcma_device *mdev = dev->bus->drv_mips.core;
|
|
||||||
u32 irqflag;
|
|
||||||
@@ -133,13 +133,6 @@ static unsigned int bcma_core_mips_irq(s
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
-unsigned int bcma_core_irq(struct bcma_device *dev)
|
|
||||||
-{
|
|
||||||
- unsigned int mips_irq = bcma_core_mips_irq(dev);
|
|
||||||
- return mips_irq <= 4 ? mips_irq + 2 : 0;
|
|
||||||
-}
|
|
||||||
-EXPORT_SYMBOL(bcma_core_irq);
|
|
||||||
-
|
|
||||||
static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
|
|
||||||
{
|
|
||||||
unsigned int oldirq = bcma_core_mips_irq(dev);
|
|
||||||
@@ -423,7 +416,7 @@ void bcma_core_mips_init(struct bcma_drv
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
list_for_each_entry(core, &bus->cores, list) {
|
|
||||||
- core->irq = bcma_core_irq(core);
|
|
||||||
+ core->irq = bcma_core_irq(core, 0);
|
|
||||||
}
|
|
||||||
bcma_err(bus,
|
|
||||||
"Unknown device (0x%x) found, can not configure IRQs\n",
|
|
||||||
--- a/drivers/bcma/driver_pci_host.c
|
|
||||||
+++ b/drivers/bcma/driver_pci_host.c
|
|
||||||
@@ -593,7 +593,7 @@ int bcma_core_pci_plat_dev_init(struct p
|
|
||||||
pr_info("PCI: Fixing up device %s\n", pci_name(dev));
|
|
||||||
|
|
||||||
/* Fix up interrupt lines */
|
|
||||||
- dev->irq = bcma_core_irq(pc_host->pdev->core);
|
|
||||||
+ dev->irq = bcma_core_irq(pc_host->pdev->core, 0);
|
|
||||||
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
|
|
||||||
|
|
||||||
readrq = pcie_get_readrq(dev);
|
|
||||||
@@ -617,6 +617,6 @@ int bcma_core_pci_pcibios_map_irq(const
|
|
||||||
|
|
||||||
pc_host = container_of(dev->bus->ops, struct bcma_drv_pci_host,
|
|
||||||
pci_ops);
|
|
||||||
- return bcma_core_irq(pc_host->pdev->core);
|
|
||||||
+ return bcma_core_irq(pc_host->pdev->core, 0);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(bcma_core_pci_pcibios_map_irq);
|
|
||||||
--- a/drivers/bcma/main.c
|
|
||||||
+++ b/drivers/bcma/main.c
|
|
||||||
@@ -11,6 +11,7 @@
|
|
||||||
#include <linux/bcma/bcma.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/of_address.h>
|
|
||||||
+#include <linux/of_irq.h>
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
@@ -153,6 +154,46 @@ static struct device_node *bcma_of_find_
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int bcma_of_irq_parse(struct platform_device *parent,
|
|
||||||
+ struct bcma_device *core,
|
|
||||||
+ struct of_phandle_args *out_irq, int num)
|
|
||||||
+{
|
|
||||||
+ __be32 laddr[1];
|
|
||||||
+ int rc;
|
|
||||||
+
|
|
||||||
+ if (core->dev.of_node) {
|
|
||||||
+ rc = of_irq_parse_one(core->dev.of_node, num, out_irq);
|
|
||||||
+ if (!rc)
|
|
||||||
+ return rc;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ out_irq->np = parent->dev.of_node;
|
|
||||||
+ out_irq->args_count = 1;
|
|
||||||
+ out_irq->args[0] = num;
|
|
||||||
+
|
|
||||||
+ laddr[0] = cpu_to_be32(core->addr);
|
|
||||||
+ return of_irq_parse_raw(laddr, out_irq);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static unsigned int bcma_of_get_irq(struct platform_device *parent,
|
|
||||||
+ struct bcma_device *core, int num)
|
|
||||||
+{
|
|
||||||
+ struct of_phandle_args out_irq;
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ if (!parent || !parent->dev.of_node)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+ ret = bcma_of_irq_parse(parent, core, &out_irq, num);
|
|
||||||
+ if (ret) {
|
|
||||||
+ bcma_debug(core->bus, "bcma_of_get_irq() failed with rc=%d\n",
|
|
||||||
+ ret);
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return irq_create_of_mapping(&out_irq);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void bcma_of_fill_device(struct platform_device *parent,
|
|
||||||
struct bcma_device *core)
|
|
||||||
{
|
|
||||||
@@ -161,18 +202,47 @@ static void bcma_of_fill_device(struct p
|
|
||||||
node = bcma_of_find_child_device(parent, core);
|
|
||||||
if (node)
|
|
||||||
core->dev.of_node = node;
|
|
||||||
+
|
|
||||||
+ core->irq = bcma_of_get_irq(parent, core, 0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void bcma_of_fill_device(struct platform_device *parent,
|
|
||||||
struct bcma_device *core)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
+static inline unsigned int bcma_of_get_irq(struct platform_device *parent,
|
|
||||||
+ struct bcma_device *core, int num)
|
|
||||||
+{
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
#endif /* CONFIG_OF */
|
|
||||||
|
|
||||||
-static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
|
|
||||||
+unsigned int bcma_core_irq(struct bcma_device *core, int num)
|
|
||||||
{
|
|
||||||
- int err;
|
|
||||||
+ struct bcma_bus *bus = core->bus;
|
|
||||||
+ unsigned int mips_irq;
|
|
||||||
+
|
|
||||||
+ switch (bus->hosttype) {
|
|
||||||
+ case BCMA_HOSTTYPE_PCI:
|
|
||||||
+ return bus->host_pci->irq;
|
|
||||||
+ case BCMA_HOSTTYPE_SOC:
|
|
||||||
+ if (bus->drv_mips.core && num == 0) {
|
|
||||||
+ mips_irq = bcma_core_mips_irq(core);
|
|
||||||
+ return mips_irq <= 4 ? mips_irq + 2 : 0;
|
|
||||||
+ }
|
|
||||||
+ if (bus->host_pdev)
|
|
||||||
+ return bcma_of_get_irq(bus->host_pdev, core, num);
|
|
||||||
+ return 0;
|
|
||||||
+ case BCMA_HOSTTYPE_SDIO:
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(bcma_core_irq);
|
|
||||||
+
|
|
||||||
+void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
|
|
||||||
+{
|
|
||||||
core->dev.release = bcma_release_core_dev;
|
|
||||||
core->dev.bus = &bcma_bus_type;
|
|
||||||
dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
|
|
||||||
@@ -196,6 +266,11 @@ static void bcma_register_core(struct bc
|
|
||||||
case BCMA_HOSTTYPE_SDIO:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
|
|
||||||
+{
|
|
||||||
+ int err;
|
|
||||||
|
|
||||||
err = device_register(&core->dev);
|
|
||||||
if (err) {
|
|
||||||
--- a/drivers/bcma/scan.c
|
|
||||||
+++ b/drivers/bcma/scan.c
|
|
||||||
@@ -505,6 +505,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
|
|
||||||
bus->nr_cores++;
|
|
||||||
other_core = bcma_find_core_reverse(bus, core->id.id);
|
|
||||||
core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
|
|
||||||
+ bcma_prepare_core(bus, core);
|
|
||||||
|
|
||||||
bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
|
|
||||||
core->core_index, bcma_device_name(&core->id),
|
|
||||||
--- a/include/linux/bcma/bcma.h
|
|
||||||
+++ b/include/linux/bcma/bcma.h
|
|
||||||
@@ -448,4 +448,6 @@ extern u32 bcma_chipco_pll_read(struct b
|
|
||||||
#define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */
|
|
||||||
extern u32 bcma_core_dma_translation(struct bcma_device *core);
|
|
||||||
|
|
||||||
+extern unsigned int bcma_core_irq(struct bcma_device *core, int num);
|
|
||||||
+
|
|
||||||
#endif /* LINUX_BCMA_H_ */
|
|
||||||
--- a/include/linux/bcma/bcma_driver_mips.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_mips.h
|
|
||||||
@@ -43,12 +43,12 @@ struct bcma_drv_mips {
|
|
||||||
extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
|
|
||||||
extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
|
|
||||||
|
|
||||||
-extern unsigned int bcma_core_irq(struct bcma_device *core);
|
|
||||||
+extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
|
|
||||||
#else
|
|
||||||
static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
|
|
||||||
static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
|
|
||||||
|
|
||||||
-static inline unsigned int bcma_core_irq(struct bcma_device *core)
|
|
||||||
+static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
--- a/Documentation/devicetree/bindings/bus/bcma.txt
|
|
||||||
+++ b/Documentation/devicetree/bindings/bus/bcma.txt
|
|
||||||
@@ -8,6 +8,11 @@ Required properties:
|
|
||||||
|
|
||||||
The cores on the AXI bus are automatically detected by bcma with the
|
|
||||||
memory ranges they are using and they get registered afterwards.
|
|
||||||
+Automatic detection of the IRQ number is not working on
|
|
||||||
+BCM47xx/BCM53xx ARM SoCs. To assign IRQ numbers to the cores, provide
|
|
||||||
+them manually through device tree. Use an interrupt-map to specify the
|
|
||||||
+IRQ used by the devices on the bus. The first address is just an index,
|
|
||||||
+because we do not have any special register.
|
|
||||||
|
|
||||||
The top-level axi bus may contain children representing attached cores
|
|
||||||
(devices). This is needed since some hardware details can't be auto
|
|
||||||
@@ -22,6 +27,22 @@ Example:
|
|
||||||
ranges = <0x00000000 0x18000000 0x00100000>;
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <1>;
|
|
||||||
+ #interrupt-cells = <1>;
|
|
||||||
+ interrupt-map-mask = <0x000fffff 0xffff>;
|
|
||||||
+ interrupt-map =
|
|
||||||
+ /* Ethernet Controller 0 */
|
|
||||||
+ <0x00024000 0 &gic GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
+
|
|
||||||
+ /* Ethernet Controller 1 */
|
|
||||||
+ <0x00025000 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
|
|
||||||
+
|
|
||||||
+ /* PCIe Controller 0 */
|
|
||||||
+ <0x00012000 0 &gic GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
+ <0x00012000 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
+ <0x00012000 2 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
+ <0x00012000 3 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
+ <0x00012000 4 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
|
|
||||||
+ <0x00012000 5 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
|
|
||||||
|
|
||||||
chipcommon {
|
|
||||||
reg = <0x00000000 0x1000>;
|
|
@ -1,527 +0,0 @@
|
|||||||
--- a/drivers/bcma/bcma_private.h
|
|
||||||
+++ b/drivers/bcma/bcma_private.h
|
|
||||||
@@ -23,22 +23,18 @@ struct bcma_bus;
|
|
||||||
bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
|
|
||||||
int timeout);
|
|
||||||
void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
|
|
||||||
+void bcma_init_bus(struct bcma_bus *bus);
|
|
||||||
int bcma_bus_register(struct bcma_bus *bus);
|
|
||||||
void bcma_bus_unregister(struct bcma_bus *bus);
|
|
||||||
-int __init bcma_bus_early_register(struct bcma_bus *bus,
|
|
||||||
- struct bcma_device *core_cc,
|
|
||||||
- struct bcma_device *core_mips);
|
|
||||||
+int __init bcma_bus_early_register(struct bcma_bus *bus);
|
|
||||||
#ifdef CONFIG_PM
|
|
||||||
int bcma_bus_suspend(struct bcma_bus *bus);
|
|
||||||
int bcma_bus_resume(struct bcma_bus *bus);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* scan.c */
|
|
||||||
+void bcma_detect_chip(struct bcma_bus *bus);
|
|
||||||
int bcma_bus_scan(struct bcma_bus *bus);
|
|
||||||
-int __init bcma_bus_scan_early(struct bcma_bus *bus,
|
|
||||||
- struct bcma_device_id *match,
|
|
||||||
- struct bcma_device *core);
|
|
||||||
-void bcma_init_bus(struct bcma_bus *bus);
|
|
||||||
|
|
||||||
/* sprom.c */
|
|
||||||
int bcma_sprom_get(struct bcma_bus *bus);
|
|
||||||
@@ -109,6 +105,14 @@ extern int bcma_chipco_watchdog_register
|
|
||||||
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
|
|
||||||
bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
|
|
||||||
void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
|
|
||||||
+#else
|
|
||||||
+static inline bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
|
|
||||||
+{
|
|
||||||
+ return false;
|
|
||||||
+}
|
|
||||||
+static inline void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
|
|
||||||
|
|
||||||
#ifdef CONFIG_BCMA_DRIVER_GPIO
|
|
||||||
--- a/drivers/bcma/driver_chipcommon.c
|
|
||||||
+++ b/drivers/bcma/driver_chipcommon.c
|
|
||||||
@@ -79,7 +79,9 @@ static int bcma_chipco_watchdog_ticks_pe
|
|
||||||
|
|
||||||
if (cc->capabilities & BCMA_CC_CAP_PMU) {
|
|
||||||
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
|
|
||||||
- /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */
|
|
||||||
+ /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP
|
|
||||||
+ * clock
|
|
||||||
+ */
|
|
||||||
return bcma_chipco_get_alp_clock(cc) / 4000;
|
|
||||||
else
|
|
||||||
/* based on 32KHz ILP clock */
|
|
||||||
@@ -97,7 +99,8 @@ int bcma_chipco_watchdog_register(struct
|
|
||||||
wdt.driver_data = cc;
|
|
||||||
wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
|
|
||||||
wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
|
|
||||||
- wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
|
|
||||||
+ wdt.max_timer_ms =
|
|
||||||
+ bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
|
|
||||||
|
|
||||||
pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
|
|
||||||
cc->core->bus->num, &wdt,
|
|
||||||
@@ -175,7 +178,6 @@ void bcma_core_chipcommon_init(struct bc
|
|
||||||
u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
|
|
||||||
{
|
|
||||||
u32 maxt;
|
|
||||||
- enum bcma_clkmode clkmode;
|
|
||||||
|
|
||||||
maxt = bcma_chipco_watchdog_get_max_timer(cc);
|
|
||||||
if (cc->capabilities & BCMA_CC_CAP_PMU) {
|
|
||||||
@@ -185,8 +187,13 @@ u32 bcma_chipco_watchdog_timer_set(struc
|
|
||||||
ticks = maxt;
|
|
||||||
bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
|
|
||||||
} else {
|
|
||||||
- clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
|
|
||||||
- bcma_core_set_clockmode(cc->core, clkmode);
|
|
||||||
+ struct bcma_bus *bus = cc->core->bus;
|
|
||||||
+
|
|
||||||
+ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
|
|
||||||
+ bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
|
|
||||||
+ bcma_core_set_clockmode(cc->core,
|
|
||||||
+ ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
|
|
||||||
+
|
|
||||||
if (ticks > maxt)
|
|
||||||
ticks = maxt;
|
|
||||||
/* instant NMI */
|
|
||||||
@@ -335,7 +342,8 @@ void bcma_chipco_serial_init(struct bcma
|
|
||||||
| BCMA_CC_CORECTL_UARTCLKEN);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
- bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev);
|
|
||||||
+ bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n",
|
|
||||||
+ ccrev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/drivers/bcma/driver_pci.c
|
|
||||||
+++ b/drivers/bcma/driver_pci.c
|
|
||||||
@@ -145,6 +145,47 @@ static u16 bcma_pcie_mdio_writeread(stru
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************
|
|
||||||
+ * Early init.
|
|
||||||
+ **************************************************/
|
|
||||||
+
|
|
||||||
+static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
|
|
||||||
+{
|
|
||||||
+ struct bcma_device *core = pc->core;
|
|
||||||
+ u16 val16, core_index;
|
|
||||||
+ uint regoff;
|
|
||||||
+
|
|
||||||
+ regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
|
|
||||||
+ core_index = (u16)core->core_index;
|
|
||||||
+
|
|
||||||
+ val16 = pcicore_read16(pc, regoff);
|
|
||||||
+ if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
|
|
||||||
+ != core_index) {
|
|
||||||
+ val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
|
|
||||||
+ (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
|
|
||||||
+ pcicore_write16(pc, regoff, val16);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Apply some early fixes required before accessing SPROM.
|
|
||||||
+ * See also si_pci_fixcfg.
|
|
||||||
+ */
|
|
||||||
+void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
|
|
||||||
+{
|
|
||||||
+ if (pc->early_setup_done)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
|
|
||||||
+ if (pc->hostmode)
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+ bcma_core_pci_fixcfg(pc);
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ pc->early_setup_done = true;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/**************************************************
|
|
||||||
* Workarounds.
|
|
||||||
**************************************************/
|
|
||||||
|
|
||||||
@@ -175,24 +216,6 @@ static void bcma_pcicore_serdes_workarou
|
|
||||||
tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
|
|
||||||
-{
|
|
||||||
- struct bcma_device *core = pc->core;
|
|
||||||
- u16 val16, core_index;
|
|
||||||
- uint regoff;
|
|
||||||
-
|
|
||||||
- regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
|
|
||||||
- core_index = (u16)core->core_index;
|
|
||||||
-
|
|
||||||
- val16 = pcicore_read16(pc, regoff);
|
|
||||||
- if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
|
|
||||||
- != core_index) {
|
|
||||||
- val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
|
|
||||||
- (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
|
|
||||||
- pcicore_write16(pc, regoff, val16);
|
|
||||||
- }
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
|
|
||||||
/* Needs to happen when coming out of 'standby'/'hibernate' */
|
|
||||||
static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
|
|
||||||
@@ -216,7 +239,6 @@ static void bcma_core_pci_config_fixup(s
|
|
||||||
|
|
||||||
static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
|
|
||||||
{
|
|
||||||
- bcma_core_pci_fixcfg(pc);
|
|
||||||
bcma_pcicore_serdes_workaround(pc);
|
|
||||||
bcma_core_pci_config_fixup(pc);
|
|
||||||
}
|
|
||||||
@@ -226,13 +248,11 @@ void bcma_core_pci_init(struct bcma_drv_
|
|
||||||
if (pc->setup_done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
-#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
|
|
||||||
- pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
|
|
||||||
+ bcma_core_pci_early_init(pc);
|
|
||||||
+
|
|
||||||
if (pc->hostmode)
|
|
||||||
bcma_core_pci_hostmode_init(pc);
|
|
||||||
-#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
|
|
||||||
-
|
|
||||||
- if (!pc->hostmode)
|
|
||||||
+ else
|
|
||||||
bcma_core_pci_clientmode_init(pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/drivers/bcma/host_pci.c
|
|
||||||
+++ b/drivers/bcma/host_pci.c
|
|
||||||
@@ -13,10 +13,12 @@
|
|
||||||
|
|
||||||
static void bcma_host_pci_switch_core(struct bcma_device *core)
|
|
||||||
{
|
|
||||||
+ int win2 = core->bus->host_is_pcie2 ?
|
|
||||||
+ BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2;
|
|
||||||
+
|
|
||||||
pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
|
|
||||||
core->addr);
|
|
||||||
- pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
|
|
||||||
- core->wrap);
|
|
||||||
+ pci_write_config_dword(core->bus->host_pci, win2, core->wrap);
|
|
||||||
core->bus->mapped_core = core;
|
|
||||||
bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id);
|
|
||||||
}
|
|
||||||
--- a/drivers/bcma/host_soc.c
|
|
||||||
+++ b/drivers/bcma/host_soc.c
|
|
||||||
@@ -193,7 +193,7 @@ int __init bcma_host_soc_init(struct bcm
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* Scan bus and initialize it */
|
|
||||||
- err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
|
|
||||||
+ err = bcma_bus_early_register(bus);
|
|
||||||
if (err)
|
|
||||||
iounmap(bus->mmio);
|
|
||||||
|
|
||||||
--- a/drivers/bcma/main.c
|
|
||||||
+++ b/drivers/bcma/main.c
|
|
||||||
@@ -268,6 +268,18 @@ void bcma_prepare_core(struct bcma_bus *
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+void bcma_init_bus(struct bcma_bus *bus)
|
|
||||||
+{
|
|
||||||
+ mutex_lock(&bcma_buses_mutex);
|
|
||||||
+ bus->num = bcma_bus_next_num++;
|
|
||||||
+ mutex_unlock(&bcma_buses_mutex);
|
|
||||||
+
|
|
||||||
+ INIT_LIST_HEAD(&bus->cores);
|
|
||||||
+ bus->nr_cores = 0;
|
|
||||||
+
|
|
||||||
+ bcma_detect_chip(bus);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
@@ -356,12 +368,19 @@ static void bcma_unregister_cores(struct
|
|
||||||
struct bcma_device *core, *tmp;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(core, tmp, &bus->cores, list) {
|
|
||||||
+ if (!core->dev_registered)
|
|
||||||
+ continue;
|
|
||||||
list_del(&core->list);
|
|
||||||
- if (core->dev_registered)
|
|
||||||
- device_unregister(&core->dev);
|
|
||||||
+ device_unregister(&core->dev);
|
|
||||||
}
|
|
||||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
|
||||||
platform_device_unregister(bus->drv_cc.watchdog);
|
|
||||||
+
|
|
||||||
+ /* Now noone uses internally-handled cores, we can free them */
|
|
||||||
+ list_for_each_entry_safe(core, tmp, &bus->cores, list) {
|
|
||||||
+ list_del(&core->list);
|
|
||||||
+ kfree(core);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
int bcma_bus_register(struct bcma_bus *bus)
|
|
||||||
@@ -369,10 +388,6 @@ int bcma_bus_register(struct bcma_bus *b
|
|
||||||
int err;
|
|
||||||
struct bcma_device *core;
|
|
||||||
|
|
||||||
- mutex_lock(&bcma_buses_mutex);
|
|
||||||
- bus->num = bcma_bus_next_num++;
|
|
||||||
- mutex_unlock(&bcma_buses_mutex);
|
|
||||||
-
|
|
||||||
/* Scan for devices (cores) */
|
|
||||||
err = bcma_bus_scan(bus);
|
|
||||||
if (err) {
|
|
||||||
@@ -387,6 +402,13 @@ int bcma_bus_register(struct bcma_bus *b
|
|
||||||
bcma_core_chipcommon_early_init(&bus->drv_cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* Early init PCIE core */
|
|
||||||
+ core = bcma_find_core(bus, BCMA_CORE_PCIE);
|
|
||||||
+ if (core) {
|
|
||||||
+ bus->drv_pci[0].core = core;
|
|
||||||
+ bcma_core_pci_early_init(&bus->drv_pci[0]);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* Cores providing flash access go before SPROM init */
|
|
||||||
list_for_each_entry(core, &bus->cores, list) {
|
|
||||||
if (bcma_is_core_needed_early(core->id.id))
|
|
||||||
@@ -459,7 +481,6 @@ int bcma_bus_register(struct bcma_bus *b
|
|
||||||
|
|
||||||
void bcma_bus_unregister(struct bcma_bus *bus)
|
|
||||||
{
|
|
||||||
- struct bcma_device *cores[3];
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = bcma_gpio_unregister(&bus->drv_cc);
|
|
||||||
@@ -470,46 +491,23 @@ void bcma_bus_unregister(struct bcma_bus
|
|
||||||
|
|
||||||
bcma_core_chipcommon_b_free(&bus->drv_cc_b);
|
|
||||||
|
|
||||||
- cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
|
|
||||||
- cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
|
|
||||||
- cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
|
|
||||||
-
|
|
||||||
bcma_unregister_cores(bus);
|
|
||||||
-
|
|
||||||
- kfree(cores[2]);
|
|
||||||
- kfree(cores[1]);
|
|
||||||
- kfree(cores[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
-int __init bcma_bus_early_register(struct bcma_bus *bus,
|
|
||||||
- struct bcma_device *core_cc,
|
|
||||||
- struct bcma_device *core_mips)
|
|
||||||
+/*
|
|
||||||
+ * This is a special version of bus registration function designed for SoCs.
|
|
||||||
+ * It scans bus and performs basic initialization of main cores only.
|
|
||||||
+ * Please note it requires memory allocation, however it won't try to sleep.
|
|
||||||
+ */
|
|
||||||
+int __init bcma_bus_early_register(struct bcma_bus *bus)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct bcma_device *core;
|
|
||||||
- struct bcma_device_id match;
|
|
||||||
-
|
|
||||||
- match.manuf = BCMA_MANUF_BCM;
|
|
||||||
- match.id = bcma_cc_core_id(bus);
|
|
||||||
- match.class = BCMA_CL_SIM;
|
|
||||||
- match.rev = BCMA_ANY_REV;
|
|
||||||
|
|
||||||
- /* Scan for chip common core */
|
|
||||||
- err = bcma_bus_scan_early(bus, &match, core_cc);
|
|
||||||
- if (err) {
|
|
||||||
- bcma_err(bus, "Failed to scan for common core: %d\n", err);
|
|
||||||
- return -1;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- match.manuf = BCMA_MANUF_MIPS;
|
|
||||||
- match.id = BCMA_CORE_MIPS_74K;
|
|
||||||
- match.class = BCMA_CL_SIM;
|
|
||||||
- match.rev = BCMA_ANY_REV;
|
|
||||||
-
|
|
||||||
- /* Scan for mips core */
|
|
||||||
- err = bcma_bus_scan_early(bus, &match, core_mips);
|
|
||||||
+ /* Scan for devices (cores) */
|
|
||||||
+ err = bcma_bus_scan(bus);
|
|
||||||
if (err) {
|
|
||||||
- bcma_err(bus, "Failed to scan for mips core: %d\n", err);
|
|
||||||
+ bcma_err(bus, "Failed to scan bus: %d\n", err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/drivers/bcma/scan.c
|
|
||||||
+++ b/drivers/bcma/scan.c
|
|
||||||
@@ -435,15 +435,12 @@ static int bcma_get_next_core(struct bcm
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
-void bcma_init_bus(struct bcma_bus *bus)
|
|
||||||
+void bcma_detect_chip(struct bcma_bus *bus)
|
|
||||||
{
|
|
||||||
s32 tmp;
|
|
||||||
struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
|
|
||||||
char chip_id[8];
|
|
||||||
|
|
||||||
- INIT_LIST_HEAD(&bus->cores);
|
|
||||||
- bus->nr_cores = 0;
|
|
||||||
-
|
|
||||||
bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
|
|
||||||
|
|
||||||
tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
|
|
||||||
@@ -464,6 +461,10 @@ int bcma_bus_scan(struct bcma_bus *bus)
|
|
||||||
|
|
||||||
int err, core_num = 0;
|
|
||||||
|
|
||||||
+ /* Skip if bus was already scanned (e.g. during early register) */
|
|
||||||
+ if (bus->nr_cores)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
|
|
||||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
|
|
||||||
eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
|
|
||||||
@@ -519,64 +520,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
|
|
||||||
out:
|
|
||||||
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
|
||||||
iounmap(eromptr);
|
|
||||||
-
|
|
||||||
- return err;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-int __init bcma_bus_scan_early(struct bcma_bus *bus,
|
|
||||||
- struct bcma_device_id *match,
|
|
||||||
- struct bcma_device *core)
|
|
||||||
-{
|
|
||||||
- u32 erombase;
|
|
||||||
- u32 __iomem *eromptr, *eromend;
|
|
||||||
-
|
|
||||||
- int err = -ENODEV;
|
|
||||||
- int core_num = 0;
|
|
||||||
-
|
|
||||||
- erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
|
|
||||||
- if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
|
|
||||||
- eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
|
|
||||||
- if (!eromptr)
|
|
||||||
- return -ENOMEM;
|
|
||||||
- } else {
|
|
||||||
- eromptr = bus->mmio;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
|
|
||||||
-
|
|
||||||
- bcma_scan_switch_core(bus, erombase);
|
|
||||||
-
|
|
||||||
- while (eromptr < eromend) {
|
|
||||||
- memset(core, 0, sizeof(*core));
|
|
||||||
- INIT_LIST_HEAD(&core->list);
|
|
||||||
- core->bus = bus;
|
|
||||||
-
|
|
||||||
- err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
|
|
||||||
- if (err == -ENODEV) {
|
|
||||||
- core_num++;
|
|
||||||
- continue;
|
|
||||||
- } else if (err == -ENXIO)
|
|
||||||
- continue;
|
|
||||||
- else if (err == -ESPIPE)
|
|
||||||
- break;
|
|
||||||
- else if (err < 0)
|
|
||||||
- goto out;
|
|
||||||
-
|
|
||||||
- core->core_index = core_num++;
|
|
||||||
- bus->nr_cores++;
|
|
||||||
- bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
|
|
||||||
- core->core_index, bcma_device_name(&core->id),
|
|
||||||
- core->id.manuf, core->id.id, core->id.rev,
|
|
||||||
- core->id.class);
|
|
||||||
-
|
|
||||||
- list_add_tail(&core->list, &bus->cores);
|
|
||||||
- err = 0;
|
|
||||||
- break;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
-out:
|
|
||||||
- if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
|
||||||
- iounmap(eromptr);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
--- a/drivers/bcma/sprom.c
|
|
||||||
+++ b/drivers/bcma/sprom.c
|
|
||||||
@@ -579,7 +579,8 @@ int bcma_sprom_get(struct bcma_bus *bus)
|
|
||||||
u16 offset = BCMA_CC_SPROM;
|
|
||||||
u16 *sprom;
|
|
||||||
size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
|
|
||||||
- SSB_SPROMSIZE_WORDS_R10, };
|
|
||||||
+ SSB_SPROMSIZE_WORDS_R10,
|
|
||||||
+ SSB_SPROMSIZE_WORDS_R11, };
|
|
||||||
int i, err = 0;
|
|
||||||
|
|
||||||
if (!bus->drv_cc.core)
|
|
||||||
--- a/include/linux/bcma/bcma.h
|
|
||||||
+++ b/include/linux/bcma/bcma.h
|
|
||||||
@@ -319,6 +319,7 @@ struct bcma_bus {
|
|
||||||
const struct bcma_host_ops *ops;
|
|
||||||
|
|
||||||
enum bcma_hosttype hosttype;
|
|
||||||
+ bool host_is_pcie2; /* Used for BCMA_HOSTTYPE_PCI only */
|
|
||||||
union {
|
|
||||||
/* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */
|
|
||||||
struct pci_dev *host_pci;
|
|
||||||
--- a/include/linux/bcma/bcma_driver_pci.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_pci.h
|
|
||||||
@@ -223,6 +223,7 @@ struct bcma_drv_pci_host {
|
|
||||||
|
|
||||||
struct bcma_drv_pci {
|
|
||||||
struct bcma_device *core;
|
|
||||||
+ u8 early_setup_done:1;
|
|
||||||
u8 setup_done:1;
|
|
||||||
u8 hostmode:1;
|
|
||||||
|
|
||||||
@@ -237,6 +238,7 @@ struct bcma_drv_pci {
|
|
||||||
#define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val)
|
|
||||||
#define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val)
|
|
||||||
|
|
||||||
+extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
|
|
||||||
extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
|
|
||||||
extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
|
|
||||||
struct bcma_device *core, bool enable);
|
|
||||||
--- a/include/linux/bcma/bcma_regs.h
|
|
||||||
+++ b/include/linux/bcma/bcma_regs.h
|
|
||||||
@@ -64,6 +64,8 @@
|
|
||||||
#define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
|
|
||||||
#define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
|
|
||||||
|
|
||||||
+#define BCMA_PCIE2_BAR0_WIN2 0x70
|
|
||||||
+
|
|
||||||
/* SiliconBackplane Address Map.
|
|
||||||
* All regions may not exist on all chips.
|
|
||||||
*/
|
|
||||||
--- a/include/linux/bcma/bcma_soc.h
|
|
||||||
+++ b/include/linux/bcma/bcma_soc.h
|
|
||||||
@@ -5,8 +5,6 @@
|
|
||||||
|
|
||||||
struct bcma_soc {
|
|
||||||
struct bcma_bus bus;
|
|
||||||
- struct bcma_device core_cc;
|
|
||||||
- struct bcma_device core_mips;
|
|
||||||
};
|
|
||||||
|
|
||||||
int __init bcma_host_soc_register(struct bcma_soc *soc);
|
|
||||||
--- a/include/linux/ssb/ssb_regs.h
|
|
||||||
+++ b/include/linux/ssb/ssb_regs.h
|
|
||||||
@@ -173,6 +173,7 @@
|
|
||||||
#define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
|
|
||||||
#define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
|
|
||||||
#define SSB_SPROMSIZE_WORDS_R10 230
|
|
||||||
+#define SSB_SPROMSIZE_WORDS_R11 234
|
|
||||||
#define SSB_SPROM_BASE1 0x1000
|
|
||||||
#define SSB_SPROM_BASE31 0x0800
|
|
||||||
#define SSB_SPROM_REVISION 0x007E
|
|
@ -1,680 +0,0 @@
|
|||||||
--- a/drivers/bcma/bcma_private.h
|
|
||||||
+++ b/drivers/bcma/bcma_private.h
|
|
||||||
@@ -24,6 +24,7 @@ bool bcma_wait_value(struct bcma_device
|
|
||||||
int timeout);
|
|
||||||
void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
|
|
||||||
void bcma_init_bus(struct bcma_bus *bus);
|
|
||||||
+void bcma_unregister_cores(struct bcma_bus *bus);
|
|
||||||
int bcma_bus_register(struct bcma_bus *bus);
|
|
||||||
void bcma_bus_unregister(struct bcma_bus *bus);
|
|
||||||
int __init bcma_bus_early_register(struct bcma_bus *bus);
|
|
||||||
@@ -40,6 +41,9 @@ int bcma_bus_scan(struct bcma_bus *bus);
|
|
||||||
int bcma_sprom_get(struct bcma_bus *bus);
|
|
||||||
|
|
||||||
/* driver_chipcommon.c */
|
|
||||||
+void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
|
|
||||||
+void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
|
|
||||||
+void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
|
|
||||||
#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
|
||||||
extern struct platform_device bcma_pflash_dev;
|
|
||||||
@@ -50,6 +54,8 @@ int bcma_core_chipcommon_b_init(struct b
|
|
||||||
void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb);
|
|
||||||
|
|
||||||
/* driver_chipcommon_pmu.c */
|
|
||||||
+void bcma_pmu_early_init(struct bcma_drv_cc *cc);
|
|
||||||
+void bcma_pmu_init(struct bcma_drv_cc *cc);
|
|
||||||
u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
|
|
||||||
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
|
|
||||||
|
|
||||||
@@ -98,7 +104,35 @@ static inline void __exit bcma_host_soc_
|
|
||||||
#endif /* CONFIG_BCMA_HOST_SOC && CONFIG_OF */
|
|
||||||
|
|
||||||
/* driver_pci.c */
|
|
||||||
+#ifdef CONFIG_BCMA_DRIVER_PCI
|
|
||||||
u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
|
|
||||||
+void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
|
|
||||||
+void bcma_core_pci_init(struct bcma_drv_pci *pc);
|
|
||||||
+void bcma_core_pci_up(struct bcma_drv_pci *pc);
|
|
||||||
+void bcma_core_pci_down(struct bcma_drv_pci *pc);
|
|
||||||
+#else
|
|
||||||
+static inline void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
|
|
||||||
+{
|
|
||||||
+ WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
|
|
||||||
+}
|
|
||||||
+static inline void bcma_core_pci_init(struct bcma_drv_pci *pc)
|
|
||||||
+{
|
|
||||||
+ /* Initialization is required for PCI hosted bus */
|
|
||||||
+ WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+/* driver_pcie2.c */
|
|
||||||
+#ifdef CONFIG_BCMA_DRIVER_PCI
|
|
||||||
+void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2);
|
|
||||||
+void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2);
|
|
||||||
+#else
|
|
||||||
+static inline void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2)
|
|
||||||
+{
|
|
||||||
+ /* Initialization is required for PCI hosted bus */
|
|
||||||
+ WARN_ON(pcie2->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
|
|
||||||
|
|
||||||
@@ -115,6 +149,39 @@ static inline void bcma_core_pci_hostmod
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
|
|
||||||
|
|
||||||
+/**************************************************
|
|
||||||
+ * driver_mips.c
|
|
||||||
+ **************************************************/
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
+unsigned int bcma_core_mips_irq(struct bcma_device *dev);
|
|
||||||
+void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
|
|
||||||
+void bcma_core_mips_init(struct bcma_drv_mips *mcore);
|
|
||||||
+#else
|
|
||||||
+static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev)
|
|
||||||
+{
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+/**************************************************
|
|
||||||
+ * driver_gmac_cmn.c
|
|
||||||
+ **************************************************/
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN
|
|
||||||
+void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc);
|
|
||||||
+#else
|
|
||||||
+static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
#ifdef CONFIG_BCMA_DRIVER_GPIO
|
|
||||||
/* driver_gpio.c */
|
|
||||||
int bcma_gpio_init(struct bcma_drv_cc *cc);
|
|
||||||
--- a/drivers/bcma/driver_gpio.c
|
|
||||||
+++ b/drivers/bcma/driver_gpio.c
|
|
||||||
@@ -17,6 +17,8 @@
|
|
||||||
|
|
||||||
#include "bcma_private.h"
|
|
||||||
|
|
||||||
+#define BCMA_GPIO_MAX_PINS 32
|
|
||||||
+
|
|
||||||
static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip)
|
|
||||||
{
|
|
||||||
return container_of(chip, struct bcma_drv_cc, gpio);
|
|
||||||
@@ -76,7 +78,7 @@ static void bcma_gpio_free(struct gpio_c
|
|
||||||
bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
-#if IS_BUILTIN(CONFIG_BCM47XX)
|
|
||||||
+#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
|
|
||||||
static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
|
|
||||||
{
|
|
||||||
struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
|
|
||||||
@@ -204,6 +206,7 @@ static void bcma_gpio_irq_domain_exit(st
|
|
||||||
|
|
||||||
int bcma_gpio_init(struct bcma_drv_cc *cc)
|
|
||||||
{
|
|
||||||
+ struct bcma_bus *bus = cc->core->bus;
|
|
||||||
struct gpio_chip *chip = &cc->gpio;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
@@ -215,14 +218,14 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
|
||||||
chip->set = bcma_gpio_set_value;
|
|
||||||
chip->direction_input = bcma_gpio_direction_input;
|
|
||||||
chip->direction_output = bcma_gpio_direction_output;
|
|
||||||
-#if IS_BUILTIN(CONFIG_BCM47XX)
|
|
||||||
+#if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
|
|
||||||
chip->to_irq = bcma_gpio_to_irq;
|
|
||||||
#endif
|
|
||||||
#if IS_BUILTIN(CONFIG_OF)
|
|
||||||
if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
|
||||||
chip->of_node = cc->core->dev.of_node;
|
|
||||||
#endif
|
|
||||||
- switch (cc->core->bus->chipinfo.id) {
|
|
||||||
+ switch (bus->chipinfo.id) {
|
|
||||||
case BCMA_CHIP_ID_BCM5357:
|
|
||||||
case BCMA_CHIP_ID_BCM53572:
|
|
||||||
chip->ngpio = 32;
|
|
||||||
@@ -231,13 +234,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
|
||||||
chip->ngpio = 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* There is just one SoC in one device and its GPIO addresses should be
|
|
||||||
- * deterministic to address them more easily. The other buses could get
|
|
||||||
- * a random base number. */
|
|
||||||
- if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
|
||||||
- chip->base = 0;
|
|
||||||
- else
|
|
||||||
- chip->base = -1;
|
|
||||||
+ /*
|
|
||||||
+ * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
|
|
||||||
+ * pin numbers. We don't have Device Tree there and we can't really use
|
|
||||||
+ * relative (per chip) numbers.
|
|
||||||
+ * So let's use predictable base for BCM47XX and "random" for all other.
|
|
||||||
+ */
|
|
||||||
+#if IS_BUILTIN(CONFIG_BCM47XX)
|
|
||||||
+ chip->base = bus->num * BCMA_GPIO_MAX_PINS;
|
|
||||||
+#else
|
|
||||||
+ chip->base = -1;
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
err = bcma_gpio_irq_domain_init(cc);
|
|
||||||
if (err)
|
|
||||||
--- a/drivers/bcma/driver_pci.c
|
|
||||||
+++ b/drivers/bcma/driver_pci.c
|
|
||||||
@@ -282,39 +282,6 @@ void bcma_core_pci_power_save(struct bcm
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bcma_core_pci_power_save);
|
|
||||||
|
|
||||||
-int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
|
|
||||||
- bool enable)
|
|
||||||
-{
|
|
||||||
- struct pci_dev *pdev;
|
|
||||||
- u32 coremask, tmp;
|
|
||||||
- int err = 0;
|
|
||||||
-
|
|
||||||
- if (!pc || core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
|
|
||||||
- /* This bcma device is not on a PCI host-bus. So the IRQs are
|
|
||||||
- * not routed through the PCI core.
|
|
||||||
- * So we must not enable routing through the PCI core. */
|
|
||||||
- goto out;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- pdev = pc->core->bus->host_pci;
|
|
||||||
-
|
|
||||||
- err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
|
||||||
- if (err)
|
|
||||||
- goto out;
|
|
||||||
-
|
|
||||||
- coremask = BIT(core->core_index) << 8;
|
|
||||||
- if (enable)
|
|
||||||
- tmp |= coremask;
|
|
||||||
- else
|
|
||||||
- tmp &= ~coremask;
|
|
||||||
-
|
|
||||||
- err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
|
|
||||||
-
|
|
||||||
-out:
|
|
||||||
- return err;
|
|
||||||
-}
|
|
||||||
-EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
|
|
||||||
-
|
|
||||||
static void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend)
|
|
||||||
{
|
|
||||||
u32 w;
|
|
||||||
@@ -328,28 +295,12 @@ static void bcma_core_pci_extend_L1timer
|
|
||||||
bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
|
|
||||||
}
|
|
||||||
|
|
||||||
-void bcma_core_pci_up(struct bcma_bus *bus)
|
|
||||||
+void bcma_core_pci_up(struct bcma_drv_pci *pc)
|
|
||||||
{
|
|
||||||
- struct bcma_drv_pci *pc;
|
|
||||||
-
|
|
||||||
- if (bus->hosttype != BCMA_HOSTTYPE_PCI)
|
|
||||||
- return;
|
|
||||||
-
|
|
||||||
- pc = &bus->drv_pci[0];
|
|
||||||
-
|
|
||||||
bcma_core_pci_extend_L1timer(pc, true);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL_GPL(bcma_core_pci_up);
|
|
||||||
|
|
||||||
-void bcma_core_pci_down(struct bcma_bus *bus)
|
|
||||||
+void bcma_core_pci_down(struct bcma_drv_pci *pc)
|
|
||||||
{
|
|
||||||
- struct bcma_drv_pci *pc;
|
|
||||||
-
|
|
||||||
- if (bus->hosttype != BCMA_HOSTTYPE_PCI)
|
|
||||||
- return;
|
|
||||||
-
|
|
||||||
- pc = &bus->drv_pci[0];
|
|
||||||
-
|
|
||||||
bcma_core_pci_extend_L1timer(pc, false);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL_GPL(bcma_core_pci_down);
|
|
||||||
--- a/drivers/bcma/driver_pci_host.c
|
|
||||||
+++ b/drivers/bcma/driver_pci_host.c
|
|
||||||
@@ -11,6 +11,7 @@
|
|
||||||
|
|
||||||
#include "bcma_private.h"
|
|
||||||
#include <linux/pci.h>
|
|
||||||
+#include <linux/slab.h>
|
|
||||||
#include <linux/export.h>
|
|
||||||
#include <linux/bcma/bcma.h>
|
|
||||||
#include <asm/paccess.h>
|
|
||||||
--- a/drivers/bcma/driver_pcie2.c
|
|
||||||
+++ b/drivers/bcma/driver_pcie2.c
|
|
||||||
@@ -10,6 +10,7 @@
|
|
||||||
|
|
||||||
#include "bcma_private.h"
|
|
||||||
#include <linux/bcma/bcma.h>
|
|
||||||
+#include <linux/pci.h>
|
|
||||||
|
|
||||||
/**************************************************
|
|
||||||
* R/W ops.
|
|
||||||
@@ -156,14 +157,23 @@ static void pciedev_reg_pm_clk_period(st
|
|
||||||
|
|
||||||
void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2)
|
|
||||||
{
|
|
||||||
- struct bcma_chipinfo *ci = &pcie2->core->bus->chipinfo;
|
|
||||||
+ struct bcma_bus *bus = pcie2->core->bus;
|
|
||||||
+ struct bcma_chipinfo *ci = &bus->chipinfo;
|
|
||||||
u32 tmp;
|
|
||||||
|
|
||||||
tmp = pcie2_read32(pcie2, BCMA_CORE_PCIE2_SPROM(54));
|
|
||||||
if ((tmp & 0xe) >> 1 == 2)
|
|
||||||
bcma_core_pcie2_cfg_write(pcie2, 0x4e0, 0x17);
|
|
||||||
|
|
||||||
- /* TODO: Do we need pcie_reqsize? */
|
|
||||||
+ switch (bus->chipinfo.id) {
|
|
||||||
+ case BCMA_CHIP_ID_BCM4360:
|
|
||||||
+ case BCMA_CHIP_ID_BCM4352:
|
|
||||||
+ pcie2->reqsize = 1024;
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ pcie2->reqsize = 128;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
if (ci->id == BCMA_CHIP_ID_BCM4360 && ci->rev > 3)
|
|
||||||
bcma_core_pcie2_war_delay_perst_enab(pcie2, true);
|
|
||||||
@@ -173,3 +183,18 @@ void bcma_core_pcie2_init(struct bcma_dr
|
|
||||||
pciedev_crwlpciegen2_180(pcie2);
|
|
||||||
pciedev_crwlpciegen2_182(pcie2);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+/**************************************************
|
|
||||||
+ * Runtime ops.
|
|
||||||
+ **************************************************/
|
|
||||||
+
|
|
||||||
+void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2)
|
|
||||||
+{
|
|
||||||
+ struct bcma_bus *bus = pcie2->core->bus;
|
|
||||||
+ struct pci_dev *dev = bus->host_pci;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ err = pcie_set_readrq(dev, pcie2->reqsize);
|
|
||||||
+ if (err)
|
|
||||||
+ bcma_err(bus, "Error setting PCI_EXP_DEVCTL_READRQ: %d\n", err);
|
|
||||||
+}
|
|
||||||
--- a/drivers/bcma/host_pci.c
|
|
||||||
+++ b/drivers/bcma/host_pci.c
|
|
||||||
@@ -213,16 +213,26 @@ static int bcma_host_pci_probe(struct pc
|
|
||||||
/* Initialize struct, detect chip */
|
|
||||||
bcma_init_bus(bus);
|
|
||||||
|
|
||||||
+ /* Scan bus to find out generation of PCIe core */
|
|
||||||
+ err = bcma_bus_scan(bus);
|
|
||||||
+ if (err)
|
|
||||||
+ goto err_pci_unmap_mmio;
|
|
||||||
+
|
|
||||||
+ if (bcma_find_core(bus, BCMA_CORE_PCIE2))
|
|
||||||
+ bus->host_is_pcie2 = true;
|
|
||||||
+
|
|
||||||
/* Register */
|
|
||||||
err = bcma_bus_register(bus);
|
|
||||||
if (err)
|
|
||||||
- goto err_pci_unmap_mmio;
|
|
||||||
+ goto err_unregister_cores;
|
|
||||||
|
|
||||||
pci_set_drvdata(dev, bus);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
|
|
||||||
+err_unregister_cores:
|
|
||||||
+ bcma_unregister_cores(bus);
|
|
||||||
err_pci_unmap_mmio:
|
|
||||||
pci_iounmap(dev, bus->mmio);
|
|
||||||
err_pci_release_regions:
|
|
||||||
@@ -283,9 +293,12 @@ static const struct pci_device_id bcma_p
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
|
|
||||||
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
|
|
||||||
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
|
|
||||||
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43b1) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) }, /* 0xa8db, BCM43217 (sic!) */
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43228) }, /* 0xa8dc */
|
|
||||||
@@ -310,3 +323,65 @@ void __exit bcma_host_pci_exit(void)
|
|
||||||
{
|
|
||||||
pci_unregister_driver(&bcma_pci_bridge_driver);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+/**************************************************
|
|
||||||
+ * Runtime ops for drivers.
|
|
||||||
+ **************************************************/
|
|
||||||
+
|
|
||||||
+/* See also pcicore_up */
|
|
||||||
+void bcma_host_pci_up(struct bcma_bus *bus)
|
|
||||||
+{
|
|
||||||
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ if (bus->host_is_pcie2)
|
|
||||||
+ bcma_core_pcie2_up(&bus->drv_pcie2);
|
|
||||||
+ else
|
|
||||||
+ bcma_core_pci_up(&bus->drv_pci[0]);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(bcma_host_pci_up);
|
|
||||||
+
|
|
||||||
+/* See also pcicore_down */
|
|
||||||
+void bcma_host_pci_down(struct bcma_bus *bus)
|
|
||||||
+{
|
|
||||||
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ if (!bus->host_is_pcie2)
|
|
||||||
+ bcma_core_pci_down(&bus->drv_pci[0]);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(bcma_host_pci_down);
|
|
||||||
+
|
|
||||||
+/* See also si_pci_setup */
|
|
||||||
+int bcma_host_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core,
|
|
||||||
+ bool enable)
|
|
||||||
+{
|
|
||||||
+ struct pci_dev *pdev;
|
|
||||||
+ u32 coremask, tmp;
|
|
||||||
+ int err = 0;
|
|
||||||
+
|
|
||||||
+ if (bus->hosttype != BCMA_HOSTTYPE_PCI) {
|
|
||||||
+ /* This bcma device is not on a PCI host-bus. So the IRQs are
|
|
||||||
+ * not routed through the PCI core.
|
|
||||||
+ * So we must not enable routing through the PCI core. */
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ pdev = bus->host_pci;
|
|
||||||
+
|
|
||||||
+ err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
|
||||||
+ if (err)
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+ coremask = BIT(core->core_index) << 8;
|
|
||||||
+ if (enable)
|
|
||||||
+ tmp |= coremask;
|
|
||||||
+ else
|
|
||||||
+ tmp &= ~coremask;
|
|
||||||
+
|
|
||||||
+ err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL_GPL(bcma_host_pci_irq_ctl);
|
|
||||||
--- a/drivers/bcma/main.c
|
|
||||||
+++ b/drivers/bcma/main.c
|
|
||||||
@@ -363,7 +363,7 @@ static int bcma_register_devices(struct
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void bcma_unregister_cores(struct bcma_bus *bus)
|
|
||||||
+void bcma_unregister_cores(struct bcma_bus *bus)
|
|
||||||
{
|
|
||||||
struct bcma_device *core, *tmp;
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/b43/main.c
|
|
||||||
+++ b/drivers/net/wireless/b43/main.c
|
|
||||||
@@ -4770,7 +4770,7 @@ static void b43_wireless_core_exit(struc
|
|
||||||
switch (dev->dev->bus_type) {
|
|
||||||
#ifdef CONFIG_B43_BCMA
|
|
||||||
case B43_BUS_BCMA:
|
|
||||||
- bcma_core_pci_down(dev->dev->bdev->bus);
|
|
||||||
+ bcma_host_pci_down(dev->dev->bdev->bus);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_B43_SSB
|
|
||||||
@@ -4817,9 +4817,9 @@ static int b43_wireless_core_init(struct
|
|
||||||
switch (dev->dev->bus_type) {
|
|
||||||
#ifdef CONFIG_B43_BCMA
|
|
||||||
case B43_BUS_BCMA:
|
|
||||||
- bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0],
|
|
||||||
+ bcma_host_pci_irq_ctl(dev->dev->bdev->bus,
|
|
||||||
dev->dev->bdev, true);
|
|
||||||
- bcma_core_pci_up(dev->dev->bdev->bus);
|
|
||||||
+ bcma_host_pci_up(dev->dev->bdev->bus);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_B43_SSB
|
|
||||||
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
|
|
||||||
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
|
|
||||||
@@ -4669,7 +4669,7 @@ static int brcms_b_attach(struct brcms_c
|
|
||||||
brcms_c_coredisable(wlc_hw);
|
|
||||||
|
|
||||||
/* Match driver "down" state */
|
|
||||||
- bcma_core_pci_down(wlc_hw->d11core->bus);
|
|
||||||
+ bcma_host_pci_down(wlc_hw->d11core->bus);
|
|
||||||
|
|
||||||
/* turn off pll and xtal to match driver "down" state */
|
|
||||||
brcms_b_xtal(wlc_hw, OFF);
|
|
||||||
@@ -4960,7 +4960,7 @@ static int brcms_b_up_prep(struct brcms_
|
|
||||||
* Configure pci/pcmcia here instead of in brcms_c_attach()
|
|
||||||
* to allow mfg hotswap: down, hotswap (chip power cycle), up.
|
|
||||||
*/
|
|
||||||
- bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core,
|
|
||||||
+ bcma_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,
|
|
||||||
true);
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -4970,12 +4970,12 @@ static int brcms_b_up_prep(struct brcms_
|
|
||||||
*/
|
|
||||||
if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
|
|
||||||
/* put SB PCI in down state again */
|
|
||||||
- bcma_core_pci_down(wlc_hw->d11core->bus);
|
|
||||||
+ bcma_host_pci_down(wlc_hw->d11core->bus);
|
|
||||||
brcms_b_xtal(wlc_hw, OFF);
|
|
||||||
return -ENOMEDIUM;
|
|
||||||
}
|
|
||||||
|
|
||||||
- bcma_core_pci_up(wlc_hw->d11core->bus);
|
|
||||||
+ bcma_host_pci_up(wlc_hw->d11core->bus);
|
|
||||||
|
|
||||||
/* reset the d11 core */
|
|
||||||
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
|
|
||||||
@@ -5172,7 +5172,7 @@ static int brcms_b_down_finish(struct br
|
|
||||||
|
|
||||||
/* turn off primary xtal and pll */
|
|
||||||
if (!wlc_hw->noreset) {
|
|
||||||
- bcma_core_pci_down(wlc_hw->d11core->bus);
|
|
||||||
+ bcma_host_pci_down(wlc_hw->d11core->bus);
|
|
||||||
brcms_b_xtal(wlc_hw, OFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
--- a/include/linux/bcma/bcma.h
|
|
||||||
+++ b/include/linux/bcma/bcma.h
|
|
||||||
@@ -435,6 +435,27 @@ static inline struct bcma_device *bcma_f
|
|
||||||
return bcma_find_core_unit(bus, coreid, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
+#ifdef CONFIG_BCMA_HOST_PCI
|
|
||||||
+extern void bcma_host_pci_up(struct bcma_bus *bus);
|
|
||||||
+extern void bcma_host_pci_down(struct bcma_bus *bus);
|
|
||||||
+extern int bcma_host_pci_irq_ctl(struct bcma_bus *bus,
|
|
||||||
+ struct bcma_device *core, bool enable);
|
|
||||||
+#else
|
|
||||||
+static inline void bcma_host_pci_up(struct bcma_bus *bus)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+static inline void bcma_host_pci_down(struct bcma_bus *bus)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+static inline int bcma_host_pci_irq_ctl(struct bcma_bus *bus,
|
|
||||||
+ struct bcma_device *core, bool enable)
|
|
||||||
+{
|
|
||||||
+ if (bus->hosttype == BCMA_HOSTTYPE_PCI)
|
|
||||||
+ return -ENOTSUPP;
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
extern bool bcma_core_is_enabled(struct bcma_device *core);
|
|
||||||
extern void bcma_core_disable(struct bcma_device *core, u32 flags);
|
|
||||||
extern int bcma_core_enable(struct bcma_device *core, u32 flags);
|
|
||||||
--- a/include/linux/bcma/bcma_driver_pci.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_pci.h
|
|
||||||
@@ -238,13 +238,13 @@ struct bcma_drv_pci {
|
|
||||||
#define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val)
|
|
||||||
#define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val)
|
|
||||||
|
|
||||||
-extern void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
|
|
||||||
-extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
|
|
||||||
-extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
|
|
||||||
- struct bcma_device *core, bool enable);
|
|
||||||
-extern void bcma_core_pci_up(struct bcma_bus *bus);
|
|
||||||
-extern void bcma_core_pci_down(struct bcma_bus *bus);
|
|
||||||
+#ifdef CONFIG_BCMA_DRIVER_PCI
|
|
||||||
extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up);
|
|
||||||
+#else
|
|
||||||
+static inline void bcma_core_pci_power_save(struct bcma_bus *bus, bool up)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
|
|
||||||
extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
|
|
||||||
--- a/include/linux/bcma/bcma_driver_pcie2.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_pcie2.h
|
|
||||||
@@ -143,6 +143,8 @@
|
|
||||||
|
|
||||||
struct bcma_drv_pcie2 {
|
|
||||||
struct bcma_device *core;
|
|
||||||
+
|
|
||||||
+ u16 reqsize;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define pcie2_read16(pcie2, offset) bcma_read16((pcie2)->core, offset)
|
|
||||||
@@ -153,6 +155,4 @@ struct bcma_drv_pcie2 {
|
|
||||||
#define pcie2_set32(pcie2, offset, set) bcma_set32((pcie2)->core, offset, set)
|
|
||||||
#define pcie2_mask32(pcie2, offset, mask) bcma_mask32((pcie2)->core, offset, mask)
|
|
||||||
|
|
||||||
-void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2);
|
|
||||||
-
|
|
||||||
#endif /* LINUX_BCMA_DRIVER_PCIE2_H_ */
|
|
||||||
--- a/drivers/bcma/Kconfig
|
|
||||||
+++ b/drivers/bcma/Kconfig
|
|
||||||
@@ -26,6 +26,7 @@ config BCMA_HOST_PCI_POSSIBLE
|
|
||||||
config BCMA_HOST_PCI
|
|
||||||
bool "Support for BCMA on PCI-host bus"
|
|
||||||
depends on BCMA_HOST_PCI_POSSIBLE
|
|
||||||
+ select BCMA_DRIVER_PCI
|
|
||||||
default y
|
|
||||||
|
|
||||||
config BCMA_DRIVER_PCI_HOSTMODE
|
|
||||||
@@ -44,6 +45,22 @@ config BCMA_HOST_SOC
|
|
||||||
|
|
||||||
If unsure, say N
|
|
||||||
|
|
||||||
+config BCMA_DRIVER_PCI
|
|
||||||
+ bool "BCMA Broadcom PCI core driver"
|
|
||||||
+ depends on BCMA && PCI
|
|
||||||
+ default y
|
|
||||||
+ help
|
|
||||||
+ BCMA bus may have many versions of PCIe core. This driver
|
|
||||||
+ supports:
|
|
||||||
+ 1) PCIe core working in clientmode
|
|
||||||
+ 2) PCIe Gen 2 clientmode core
|
|
||||||
+
|
|
||||||
+ In general PCIe (Gen 2) clientmode core is required on PCIe
|
|
||||||
+ hosted buses. It's responsible for initialization and basic
|
|
||||||
+ hardware management.
|
|
||||||
+ This driver is also prerequisite for a hostmode PCIe core
|
|
||||||
+ support.
|
|
||||||
+
|
|
||||||
config BCMA_DRIVER_MIPS
|
|
||||||
bool "BCMA Broadcom MIPS core driver"
|
|
||||||
depends on BCMA && MIPS
|
|
||||||
--- a/drivers/bcma/Makefile
|
|
||||||
+++ b/drivers/bcma/Makefile
|
|
||||||
@@ -3,8 +3,8 @@ bcma-y += driver_chipcommon.o driver
|
|
||||||
bcma-y += driver_chipcommon_b.o
|
|
||||||
bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
|
|
||||||
bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
|
|
||||||
-bcma-y += driver_pci.o
|
|
||||||
-bcma-y += driver_pcie2.o
|
|
||||||
+bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pci.o
|
|
||||||
+bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pcie2.o
|
|
||||||
bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
|
|
||||||
bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
|
|
||||||
bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o
|
|
||||||
--- a/include/linux/bcma/bcma_driver_chipcommon.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
|
|
||||||
@@ -663,14 +663,6 @@ struct bcma_drv_cc_b {
|
|
||||||
#define bcma_cc_maskset32(cc, offset, mask, set) \
|
|
||||||
bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
|
|
||||||
|
|
||||||
-extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
|
|
||||||
-extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
|
|
||||||
-
|
|
||||||
-extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
|
|
||||||
-extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
|
|
||||||
-
|
|
||||||
-void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
|
|
||||||
-
|
|
||||||
extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
|
|
||||||
|
|
||||||
extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
|
|
||||||
@@ -690,9 +682,6 @@ u32 bcma_chipco_gpio_pullup(struct bcma_
|
|
||||||
u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value);
|
|
||||||
|
|
||||||
/* PMU support */
|
|
||||||
-extern void bcma_pmu_init(struct bcma_drv_cc *cc);
|
|
||||||
-extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
|
|
||||||
-
|
|
||||||
extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
|
|
||||||
u32 value);
|
|
||||||
extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
|
|
||||||
--- a/include/linux/bcma/bcma_driver_gmac_cmn.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_gmac_cmn.h
|
|
||||||
@@ -91,10 +91,4 @@ struct bcma_drv_gmac_cmn {
|
|
||||||
#define gmac_cmn_write16(gc, offset, val) bcma_write16((gc)->core, offset, val)
|
|
||||||
#define gmac_cmn_write32(gc, offset, val) bcma_write32((gc)->core, offset, val)
|
|
||||||
|
|
||||||
-#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN
|
|
||||||
-extern void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc);
|
|
||||||
-#else
|
|
||||||
-static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) { }
|
|
||||||
-#endif
|
|
||||||
-
|
|
||||||
#endif /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */
|
|
||||||
--- a/include/linux/bcma/bcma_driver_mips.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_mips.h
|
|
||||||
@@ -39,21 +39,6 @@ struct bcma_drv_mips {
|
|
||||||
u8 early_setup_done:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
-extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
|
|
||||||
-extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
|
|
||||||
-
|
|
||||||
-extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
|
|
||||||
-#else
|
|
||||||
-static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
|
|
||||||
-static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
|
|
||||||
-
|
|
||||||
-static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev)
|
|
||||||
-{
|
|
||||||
- return 0;
|
|
||||||
-}
|
|
||||||
-#endif
|
|
||||||
-
|
|
||||||
extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
|
|
||||||
|
|
||||||
#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
|
|
@ -1,86 +0,0 @@
|
|||||||
--- a/drivers/bcma/driver_gpio.c
|
|
||||||
+++ b/drivers/bcma/driver_gpio.c
|
|
||||||
@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
|
||||||
chip->of_node = cc->core->dev.of_node;
|
|
||||||
#endif
|
|
||||||
switch (bus->chipinfo.id) {
|
|
||||||
+ case BCMA_CHIP_ID_BCM4707:
|
|
||||||
case BCMA_CHIP_ID_BCM5357:
|
|
||||||
case BCMA_CHIP_ID_BCM53572:
|
|
||||||
chip->ngpio = 32;
|
|
||||||
@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
- * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
|
|
||||||
- * pin numbers. We don't have Device Tree there and we can't really use
|
|
||||||
- * relative (per chip) numbers.
|
|
||||||
- * So let's use predictable base for BCM47XX and "random" for all other.
|
|
||||||
+ * Register SoC GPIO devices with absolute GPIO pin base.
|
|
||||||
+ * On MIPS, we don't have Device Tree and we can't use relative (per chip)
|
|
||||||
+ * GPIO numbers.
|
|
||||||
+ * On some ARM devices, user space may want to access some system GPIO
|
|
||||||
+ * pins directly, which is easier to do with a predictable GPIO base.
|
|
||||||
*/
|
|
||||||
-#if IS_BUILTIN(CONFIG_BCM47XX)
|
|
||||||
- chip->base = bus->num * BCMA_GPIO_MAX_PINS;
|
|
||||||
-#else
|
|
||||||
- chip->base = -1;
|
|
||||||
-#endif
|
|
||||||
+ if (IS_BUILTIN(CONFIG_BCM47XX) ||
|
|
||||||
+ cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
|
||||||
+ chip->base = bus->num * BCMA_GPIO_MAX_PINS;
|
|
||||||
+ else
|
|
||||||
+ chip->base = -1;
|
|
||||||
|
|
||||||
err = bcma_gpio_irq_domain_init(cc);
|
|
||||||
if (err)
|
|
||||||
--- a/drivers/bcma/Kconfig
|
|
||||||
+++ b/drivers/bcma/Kconfig
|
|
||||||
@@ -29,12 +29,6 @@ config BCMA_HOST_PCI
|
|
||||||
select BCMA_DRIVER_PCI
|
|
||||||
default y
|
|
||||||
|
|
||||||
-config BCMA_DRIVER_PCI_HOSTMODE
|
|
||||||
- bool "Driver for PCI core working in hostmode"
|
|
||||||
- depends on BCMA && MIPS && BCMA_HOST_PCI
|
|
||||||
- help
|
|
||||||
- PCI core hostmode operation (external PCI bus).
|
|
||||||
-
|
|
||||||
config BCMA_HOST_SOC
|
|
||||||
bool "Support for BCMA in a SoC"
|
|
||||||
depends on BCMA
|
|
||||||
@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI
|
|
||||||
This driver is also prerequisite for a hostmode PCIe core
|
|
||||||
support.
|
|
||||||
|
|
||||||
+config BCMA_DRIVER_PCI_HOSTMODE
|
|
||||||
+ bool "Driver for PCI core working in hostmode"
|
|
||||||
+ depends on BCMA && MIPS && BCMA_DRIVER_PCI
|
|
||||||
+ help
|
|
||||||
+ PCI core hostmode operation (external PCI bus).
|
|
||||||
+
|
|
||||||
config BCMA_DRIVER_MIPS
|
|
||||||
bool "BCMA Broadcom MIPS core driver"
|
|
||||||
depends on BCMA && MIPS
|
|
||||||
--- a/include/linux/bcma/bcma_driver_pci.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_pci.h
|
|
||||||
@@ -246,7 +246,18 @@ static inline void bcma_core_pci_power_s
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
|
|
||||||
extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
|
|
||||||
extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
|
|
||||||
+#else
|
|
||||||
+static inline int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
|
|
||||||
+{
|
|
||||||
+ return -ENOTSUPP;
|
|
||||||
+}
|
|
||||||
+static inline int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
|
|
||||||
+{
|
|
||||||
+ return -ENOTSUPP;
|
|
||||||
+}
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
#endif /* LINUX_BCMA_DRIVER_PCI_H_ */
|
|
@ -1,26 +0,0 @@
|
|||||||
commit 55acca90da52b85299c033354e51ddaa7b73e019
|
|
||||||
Author: Hante Meuleman <meuleman@broadcom.com>
|
|
||||||
Date: Fri Sep 18 22:08:17 2015 +0200
|
|
||||||
|
|
||||||
brcmfmac: Add support for the BCM4365 and BCM4366 PCIE devices.
|
|
||||||
|
|
||||||
This patch adds support for the BCM4365 and BCM4366 11ac Wave2
|
|
||||||
PCIE devices.
|
|
||||||
|
|
||||||
Reviewed-by: Arend Van Spriel <arend@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
|
|
||||||
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
|
|
||||||
--- a/include/linux/bcma/bcma.h
|
|
||||||
+++ b/include/linux/bcma/bcma.h
|
|
||||||
@@ -151,6 +151,8 @@ struct bcma_host_ops {
|
|
||||||
#define BCMA_CORE_PCIE2 0x83C /* PCI Express Gen2 */
|
|
||||||
#define BCMA_CORE_USB30_DEV 0x83D
|
|
||||||
#define BCMA_CORE_ARM_CR4 0x83E
|
|
||||||
+#define BCMA_CORE_ARM_CA7 0x847
|
|
||||||
+#define BCMA_CORE_SYS_MEM 0x849
|
|
||||||
#define BCMA_CORE_DEFAULT 0xFFF
|
|
||||||
|
|
||||||
#define BCMA_MAX_NR_CORES 16
|
|
@ -1,52 +0,0 @@
|
|||||||
--- /dev/null
|
|
||||||
+++ b/include/linux/bcm47xx_nvram.h
|
|
||||||
@@ -0,0 +1,49 @@
|
|
||||||
+/*
|
|
||||||
+ * This program is free software; you can redistribute it and/or modify it
|
|
||||||
+ * under the terms of the GNU General Public License as published by the
|
|
||||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
|
||||||
+ * option) any later version.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef __BCM47XX_NVRAM_H
|
|
||||||
+#define __BCM47XX_NVRAM_H
|
|
||||||
+
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/vmalloc.h>
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_BCM47XX_NVRAM
|
|
||||||
+int bcm47xx_nvram_init_from_mem(u32 base, u32 lim);
|
|
||||||
+int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
|
|
||||||
+int bcm47xx_nvram_gpio_pin(const char *name);
|
|
||||||
+char *bcm47xx_nvram_get_contents(size_t *val_len);
|
|
||||||
+static inline void bcm47xx_nvram_release_contents(char *nvram)
|
|
||||||
+{
|
|
||||||
+ vfree(nvram);
|
|
||||||
+};
|
|
||||||
+#else
|
|
||||||
+static inline int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
|
|
||||||
+{
|
|
||||||
+ return -ENOTSUPP;
|
|
||||||
+};
|
|
||||||
+static inline int bcm47xx_nvram_getenv(const char *name, char *val,
|
|
||||||
+ size_t val_len)
|
|
||||||
+{
|
|
||||||
+ return -ENOTSUPP;
|
|
||||||
+};
|
|
||||||
+static inline int bcm47xx_nvram_gpio_pin(const char *name)
|
|
||||||
+{
|
|
||||||
+ return -ENOTSUPP;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static inline char *bcm47xx_nvram_get_contents(size_t *val_len)
|
|
||||||
+{
|
|
||||||
+ return NULL;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static inline void bcm47xx_nvram_release_contents(char *nvram)
|
|
||||||
+{
|
|
||||||
+};
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+#endif /* __BCM47XX_NVRAM_H */
|
|
@ -1,21 +0,0 @@
|
|||||||
From: Vadim Kochan <vadim4j@gmail.com>
|
|
||||||
Date: Mon, 12 Jan 2015 16:34:05 +0200
|
|
||||||
Subject: [PATCH] nl80211: Allow set network namespace by fd
|
|
||||||
|
|
||||||
Added new NL80211_ATTR_NETNS_FD which allows to
|
|
||||||
set namespace via nl80211 by fd.
|
|
||||||
|
|
||||||
Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
|
|
||||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/core/net_namespace.c
|
|
||||||
+++ b/net/core/net_namespace.c
|
|
||||||
@@ -380,6 +380,7 @@ struct net *get_net_ns_by_fd(int fd)
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
+EXPORT_SYMBOL_GPL(get_net_ns_by_fd);
|
|
||||||
|
|
||||||
struct net *get_net_ns_by_pid(pid_t pid)
|
|
||||||
{
|
|
@ -1,49 +0,0 @@
|
|||||||
--- a/drivers/bcma/main.c
|
|
||||||
+++ b/drivers/bcma/main.c
|
|
||||||
@@ -637,11 +637,36 @@ static int bcma_device_uevent(struct dev
|
|
||||||
core->id.rev, core->id.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int __init bcma_modinit(void)
|
|
||||||
+static unsigned int bcma_bus_registered;
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * If built-in, bus has to be registered early, before any driver calls
|
|
||||||
+ * bcma_driver_register.
|
|
||||||
+ * Otherwise registering driver would trigger BUG in driver_register.
|
|
||||||
+ */
|
|
||||||
+static int __init bcma_init_bus_register(void)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
+ if (bcma_bus_registered)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
err = bus_register(&bcma_bus_type);
|
|
||||||
+ if (!err)
|
|
||||||
+ bcma_bus_registered = 1;
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+#ifndef MODULE
|
|
||||||
+fs_initcall(bcma_init_bus_register);
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+/* Main initialization has to be done with SPI/mtd/NAND/SPROM available */
|
|
||||||
+static int __init bcma_modinit(void)
|
|
||||||
+{
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ err = bcma_init_bus_register();
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
@@ -660,7 +685,7 @@ static int __init bcma_modinit(void)
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
-fs_initcall(bcma_modinit);
|
|
||||||
+module_init(bcma_modinit);
|
|
||||||
|
|
||||||
static void __exit bcma_modexit(void)
|
|
||||||
{
|
|
@ -1,716 +0,0 @@
|
|||||||
--- a/drivers/bcma/driver_chipcommon.c
|
|
||||||
+++ b/drivers/bcma/driver_chipcommon.c
|
|
||||||
@@ -15,6 +15,8 @@
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/bcma/bcma.h>
|
|
||||||
|
|
||||||
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
|
||||||
+
|
|
||||||
static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
|
|
||||||
u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
@@ -113,8 +115,37 @@ int bcma_chipco_watchdog_register(struct
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc)
|
|
||||||
+{
|
|
||||||
+ struct bcma_bus *bus = cc->core->bus;
|
|
||||||
+
|
|
||||||
+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
|
|
||||||
+ case BCMA_CC_FLASHT_STSER:
|
|
||||||
+ case BCMA_CC_FLASHT_ATSER:
|
|
||||||
+ bcma_debug(bus, "Found serial flash\n");
|
|
||||||
+ bcma_sflash_init(cc);
|
|
||||||
+ break;
|
|
||||||
+ case BCMA_CC_FLASHT_PARA:
|
|
||||||
+ bcma_debug(bus, "Found parallel flash\n");
|
|
||||||
+ bcma_pflash_init(cc);
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ bcma_err(bus, "Flash type not supported\n");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (cc->core->id.rev == 38 ||
|
|
||||||
+ bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
|
|
||||||
+ if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
|
|
||||||
+ bcma_debug(bus, "Found NAND flash\n");
|
|
||||||
+ bcma_nflash_init(cc);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
|
|
||||||
{
|
|
||||||
+ struct bcma_bus *bus = cc->core->bus;
|
|
||||||
+
|
|
||||||
if (cc->early_setup_done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
@@ -129,6 +160,12 @@ void bcma_core_chipcommon_early_init(str
|
|
||||||
if (cc->capabilities & BCMA_CC_CAP_PMU)
|
|
||||||
bcma_pmu_early_init(cc);
|
|
||||||
|
|
||||||
+ if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
|
|
||||||
+ bcma_chipco_serial_init(cc);
|
|
||||||
+
|
|
||||||
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
|
||||||
+ bcma_core_chipcommon_flash_detect(cc);
|
|
||||||
+
|
|
||||||
cc->early_setup_done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -185,11 +222,12 @@ u32 bcma_chipco_watchdog_timer_set(struc
|
|
||||||
ticks = 2;
|
|
||||||
else if (ticks > maxt)
|
|
||||||
ticks = maxt;
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
|
|
||||||
} else {
|
|
||||||
struct bcma_bus *bus = cc->core->bus;
|
|
||||||
|
|
||||||
if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
|
|
||||||
+ bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 &&
|
|
||||||
bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
|
|
||||||
bcma_core_set_clockmode(cc->core,
|
|
||||||
ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
|
|
||||||
@@ -314,9 +352,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcm
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
|
|
||||||
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
|
|
||||||
{
|
|
||||||
+#if IS_BUILTIN(CONFIG_BCM47XX)
|
|
||||||
unsigned int irq;
|
|
||||||
u32 baud_base;
|
|
||||||
u32 i;
|
|
||||||
@@ -358,5 +396,5 @@ void bcma_chipco_serial_init(struct bcma
|
|
||||||
ports[i].baud_base = baud_base;
|
|
||||||
ports[i].reg_shift = 0;
|
|
||||||
}
|
|
||||||
+#endif /* CONFIG_BCM47XX */
|
|
||||||
}
|
|
||||||
-#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
|
||||||
--- a/drivers/bcma/driver_chipcommon_pmu.c
|
|
||||||
+++ b/drivers/bcma/driver_chipcommon_pmu.c
|
|
||||||
@@ -15,44 +15,44 @@
|
|
||||||
|
|
||||||
u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
|
|
||||||
{
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
|
||||||
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
|
|
||||||
- return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
|
|
||||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
|
|
||||||
+ return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
|
|
||||||
|
|
||||||
void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
|
|
||||||
{
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
|
||||||
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
|
|
||||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
|
|
||||||
|
|
||||||
void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
|
|
||||||
u32 set)
|
|
||||||
{
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
|
||||||
- bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
|
|
||||||
- bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
|
|
||||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
|
|
||||||
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
|
|
||||||
|
|
||||||
void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
|
|
||||||
u32 offset, u32 mask, u32 set)
|
|
||||||
{
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
|
|
||||||
- bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
|
|
||||||
- bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
|
|
||||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
|
|
||||||
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
|
|
||||||
|
|
||||||
void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
|
|
||||||
u32 set)
|
|
||||||
{
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
|
|
||||||
- bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
|
|
||||||
- bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
|
|
||||||
+ bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
|
|
||||||
+ bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
|
|
||||||
|
|
||||||
@@ -60,18 +60,18 @@ static u32 bcma_pmu_xtalfreq(struct bcma
|
|
||||||
{
|
|
||||||
u32 ilp_ctl, alp_hz;
|
|
||||||
|
|
||||||
- if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
|
|
||||||
+ if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
|
|
||||||
BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
|
|
||||||
- BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
|
|
||||||
+ BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
|
|
||||||
usleep_range(1000, 2000);
|
|
||||||
|
|
||||||
- ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
|
|
||||||
+ ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
|
|
||||||
ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
|
|
||||||
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
|
|
||||||
|
|
||||||
alp_hz = ilp_ctl * 32768 / 4;
|
|
||||||
return (alp_hz + 50000) / 100000 * 100;
|
|
||||||
@@ -127,8 +127,8 @@ static void bcma_pmu2_pll_init0(struct b
|
|
||||||
mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
|
|
||||||
BCMA_RES_4314_MACPHY_CLK_AVAIL);
|
|
||||||
|
|
||||||
- bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
|
|
||||||
- bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
|
|
||||||
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
|
|
||||||
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
|
|
||||||
bcma_wait_value(cc->core, BCMA_CLKCTLST,
|
|
||||||
BCMA_CLKCTLST_HAVEHT, 0, 20000);
|
|
||||||
break;
|
|
||||||
@@ -140,7 +140,7 @@ static void bcma_pmu2_pll_init0(struct b
|
|
||||||
|
|
||||||
/* Flush */
|
|
||||||
if (cc->pmu.rev >= 2)
|
|
||||||
- bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
|
|
||||||
+ bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
|
|
||||||
|
|
||||||
/* TODO: Do we need to update OTP? */
|
|
||||||
}
|
|
||||||
@@ -195,9 +195,9 @@ static void bcma_pmu_resources_init(stru
|
|
||||||
|
|
||||||
/* Set the resource masks. */
|
|
||||||
if (min_msk)
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
|
|
||||||
if (max_msk)
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add some delay; allow resources to come up and settle.
|
|
||||||
@@ -269,23 +269,33 @@ static void bcma_pmu_workarounds(struct
|
|
||||||
|
|
||||||
void bcma_pmu_early_init(struct bcma_drv_cc *cc)
|
|
||||||
{
|
|
||||||
+ struct bcma_bus *bus = cc->core->bus;
|
|
||||||
u32 pmucap;
|
|
||||||
|
|
||||||
- pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
|
|
||||||
+ if (cc->core->id.rev >= 35 &&
|
|
||||||
+ cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
|
|
||||||
+ cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
|
|
||||||
+ if (!cc->pmu.core)
|
|
||||||
+ bcma_warn(bus, "Couldn't find expected PMU core");
|
|
||||||
+ }
|
|
||||||
+ if (!cc->pmu.core)
|
|
||||||
+ cc->pmu.core = cc->core;
|
|
||||||
+
|
|
||||||
+ pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
|
|
||||||
cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
|
|
||||||
|
|
||||||
- bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
|
|
||||||
- cc->pmu.rev, pmucap);
|
|
||||||
+ bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
|
|
||||||
+ pmucap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bcma_pmu_init(struct bcma_drv_cc *cc)
|
|
||||||
{
|
|
||||||
if (cc->pmu.rev == 1)
|
|
||||||
- bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
|
|
||||||
- ~BCMA_CC_PMU_CTL_NOILPONW);
|
|
||||||
+ bcma_pmu_mask32(cc, BCMA_CC_PMU_CTL,
|
|
||||||
+ ~BCMA_CC_PMU_CTL_NOILPONW);
|
|
||||||
else
|
|
||||||
- bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
|
|
||||||
- BCMA_CC_PMU_CTL_NOILPONW);
|
|
||||||
+ bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
|
|
||||||
+ BCMA_CC_PMU_CTL_NOILPONW);
|
|
||||||
|
|
||||||
bcma_pmu_pll_init(cc);
|
|
||||||
bcma_pmu_resources_init(cc);
|
|
||||||
@@ -472,8 +482,8 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_d
|
|
||||||
static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
|
|
||||||
u32 value)
|
|
||||||
{
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
|
|
||||||
@@ -497,20 +507,20 @@ void bcma_pmu_spuravoid_pllupdate(struct
|
|
||||||
bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
|
|
||||||
|
|
||||||
/* RMW only the P1 divider */
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
|
|
||||||
BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
|
|
||||||
- tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
|
|
||||||
+ tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
|
|
||||||
tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
|
|
||||||
tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
|
|
||||||
|
|
||||||
/* RMW only the int feedback divider */
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
|
|
||||||
BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
|
|
||||||
- tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
|
|
||||||
+ tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
|
|
||||||
tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
|
|
||||||
tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
|
|
||||||
|
|
||||||
tmp = BCMA_CC_PMU_CTL_PLL_UPD;
|
|
||||||
break;
|
|
||||||
@@ -646,7 +656,7 @@ void bcma_pmu_spuravoid_pllupdate(struct
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
- tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
|
|
||||||
- bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
|
|
||||||
+ tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
|
|
||||||
+ bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
|
|
||||||
--- a/drivers/bcma/driver_chipcommon_sflash.c
|
|
||||||
+++ b/drivers/bcma/driver_chipcommon_sflash.c
|
|
||||||
@@ -38,6 +38,7 @@ static const struct bcma_sflash_tbl_e bc
|
|
||||||
{ "M25P32", 0x15, 0x10000, 64, },
|
|
||||||
{ "M25P64", 0x16, 0x10000, 128, },
|
|
||||||
{ "M25FL128", 0x17, 0x10000, 256, },
|
|
||||||
+ { "MX25L25635F", 0x18, 0x10000, 512, },
|
|
||||||
{ NULL },
|
|
||||||
};
|
|
||||||
|
|
||||||
--- a/drivers/bcma/scan.c
|
|
||||||
+++ b/drivers/bcma/scan.c
|
|
||||||
@@ -98,6 +98,9 @@ static const struct bcma_device_id_name
|
|
||||||
{ BCMA_CORE_SHIM, "SHIM" },
|
|
||||||
{ BCMA_CORE_PCIE2, "PCIe Gen2" },
|
|
||||||
{ BCMA_CORE_ARM_CR4, "ARM CR4" },
|
|
||||||
+ { BCMA_CORE_GCI, "GCI" },
|
|
||||||
+ { BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
|
|
||||||
+ { BCMA_CORE_ARM_CA7, "ARM CA7" },
|
|
||||||
{ BCMA_CORE_DEFAULT, "Default" },
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -315,6 +318,8 @@ static int bcma_get_next_core(struct bcm
|
|
||||||
switch (core->id.id) {
|
|
||||||
case BCMA_CORE_4706_MAC_GBIT_COMMON:
|
|
||||||
case BCMA_CORE_NS_CHIPCOMMON_B:
|
|
||||||
+ case BCMA_CORE_PMU:
|
|
||||||
+ case BCMA_CORE_GCI:
|
|
||||||
/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
--- a/drivers/net/wireless/b43/main.c
|
|
||||||
+++ b/drivers/net/wireless/b43/main.c
|
|
||||||
@@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(str
|
|
||||||
case B43_BUS_BCMA:
|
|
||||||
bcma_cc = &dev->dev->bdev->bus->drv_cc;
|
|
||||||
|
|
||||||
- bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
|
|
||||||
- bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
|
|
||||||
- bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
|
|
||||||
- bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
|
|
||||||
+ bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
|
|
||||||
+ bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
|
|
||||||
+ bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
|
|
||||||
+ bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_B43_SSB
|
|
||||||
--- a/include/linux/bcma/bcma.h
|
|
||||||
+++ b/include/linux/bcma/bcma.h
|
|
||||||
@@ -151,6 +151,8 @@ struct bcma_host_ops {
|
|
||||||
#define BCMA_CORE_PCIE2 0x83C /* PCI Express Gen2 */
|
|
||||||
#define BCMA_CORE_USB30_DEV 0x83D
|
|
||||||
#define BCMA_CORE_ARM_CR4 0x83E
|
|
||||||
+#define BCMA_CORE_GCI 0x840
|
|
||||||
+#define BCMA_CORE_CMEM 0x846 /* CNDS DDR2/3 memory controller */
|
|
||||||
#define BCMA_CORE_ARM_CA7 0x847
|
|
||||||
#define BCMA_CORE_SYS_MEM 0x849
|
|
||||||
#define BCMA_CORE_DEFAULT 0xFFF
|
|
||||||
@@ -200,6 +202,7 @@ struct bcma_host_ops {
|
|
||||||
#define BCMA_PKG_ID_BCM4707 1
|
|
||||||
#define BCMA_PKG_ID_BCM4708 2
|
|
||||||
#define BCMA_PKG_ID_BCM4709 0
|
|
||||||
+#define BCMA_CHIP_ID_BCM47094 53030
|
|
||||||
#define BCMA_CHIP_ID_BCM53018 53018
|
|
||||||
|
|
||||||
/* Board types (on PCI usually equals to the subsystem dev id) */
|
|
||||||
--- a/include/linux/bcma/bcma_driver_chipcommon.h
|
|
||||||
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
|
|
||||||
@@ -217,6 +217,11 @@
|
|
||||||
#define BCMA_CC_CLKDIV_JTAG_SHIFT 8
|
|
||||||
#define BCMA_CC_CLKDIV_UART 0x000000FF
|
|
||||||
#define BCMA_CC_CAP_EXT 0x00AC /* Capabilities */
|
|
||||||
+#define BCMA_CC_CAP_EXT_SECI_PRESENT 0x00000001
|
|
||||||
+#define BCMA_CC_CAP_EXT_GSIO_PRESENT 0x00000002
|
|
||||||
+#define BCMA_CC_CAP_EXT_GCI_PRESENT 0x00000004
|
|
||||||
+#define BCMA_CC_CAP_EXT_SECI_PUART_PRESENT 0x00000008 /* UART present */
|
|
||||||
+#define BCMA_CC_CAP_EXT_AOB_PRESENT 0x00000040
|
|
||||||
#define BCMA_CC_PLLONDELAY 0x00B0 /* Rev >= 4 only */
|
|
||||||
#define BCMA_CC_FREFSELDELAY 0x00B4 /* Rev >= 4 only */
|
|
||||||
#define BCMA_CC_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */
|
|
||||||
@@ -351,12 +356,12 @@
|
|
||||||
#define BCMA_CC_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */
|
|
||||||
#define BCMA_CC_PMU_RES_REQT 0x0644 /* PMU res req timer */
|
|
||||||
#define BCMA_CC_PMU_RES_REQM 0x0648 /* PMU res req mask */
|
|
||||||
-#define BCMA_CC_CHIPCTL_ADDR 0x0650
|
|
||||||
-#define BCMA_CC_CHIPCTL_DATA 0x0654
|
|
||||||
-#define BCMA_CC_REGCTL_ADDR 0x0658
|
|
||||||
-#define BCMA_CC_REGCTL_DATA 0x065C
|
|
||||||
-#define BCMA_CC_PLLCTL_ADDR 0x0660
|
|
||||||
-#define BCMA_CC_PLLCTL_DATA 0x0664
|
|
||||||
+#define BCMA_CC_PMU_CHIPCTL_ADDR 0x0650
|
|
||||||
+#define BCMA_CC_PMU_CHIPCTL_DATA 0x0654
|
|
||||||
+#define BCMA_CC_PMU_REGCTL_ADDR 0x0658
|
|
||||||
+#define BCMA_CC_PMU_REGCTL_DATA 0x065C
|
|
||||||
+#define BCMA_CC_PMU_PLLCTL_ADDR 0x0660
|
|
||||||
+#define BCMA_CC_PMU_PLLCTL_DATA 0x0664
|
|
||||||
#define BCMA_CC_PMU_STRAPOPT 0x0668 /* (corerev >= 28) */
|
|
||||||
#define BCMA_CC_PMU_XTAL_FREQ 0x066C /* (pmurev >= 10) */
|
|
||||||
#define BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK 0x00001FFF
|
|
||||||
@@ -566,17 +571,16 @@
|
|
||||||
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
|
|
||||||
*/
|
|
||||||
struct bcma_chipcommon_pmu {
|
|
||||||
+ struct bcma_device *core; /* Can be separated core or just ChipCommon one */
|
|
||||||
u8 rev; /* PMU revision */
|
|
||||||
u32 crystalfreq; /* The active crystal frequency (in kHz) */
|
|
||||||
};
|
|
||||||
|
|
||||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
+#ifdef CONFIG_BCMA_PFLASH
|
|
||||||
struct bcma_pflash {
|
|
||||||
bool present;
|
|
||||||
- u8 buswidth;
|
|
||||||
- u32 window;
|
|
||||||
- u32 window_size;
|
|
||||||
};
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_BCMA_SFLASH
|
|
||||||
struct bcma_sflash {
|
|
||||||
@@ -602,6 +606,7 @@ struct bcma_nflash {
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
struct bcma_serial_port {
|
|
||||||
void *regs;
|
|
||||||
unsigned long clockspeed;
|
|
||||||
@@ -621,8 +626,9 @@ struct bcma_drv_cc {
|
|
||||||
/* Fast Powerup Delay constant */
|
|
||||||
u16 fast_pwrup_delay;
|
|
||||||
struct bcma_chipcommon_pmu pmu;
|
|
||||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
+#ifdef CONFIG_BCMA_PFLASH
|
|
||||||
struct bcma_pflash pflash;
|
|
||||||
+#endif
|
|
||||||
#ifdef CONFIG_BCMA_SFLASH
|
|
||||||
struct bcma_sflash sflash;
|
|
||||||
#endif
|
|
||||||
@@ -630,6 +636,7 @@ struct bcma_drv_cc {
|
|
||||||
struct bcma_nflash nflash;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
int nr_serial_ports;
|
|
||||||
struct bcma_serial_port serial_ports[4];
|
|
||||||
#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
|
||||||
@@ -663,6 +670,19 @@ struct bcma_drv_cc_b {
|
|
||||||
#define bcma_cc_maskset32(cc, offset, mask, set) \
|
|
||||||
bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
|
|
||||||
|
|
||||||
+/* PMU registers access */
|
|
||||||
+#define bcma_pmu_read32(cc, offset) \
|
|
||||||
+ bcma_read32((cc)->pmu.core, offset)
|
|
||||||
+#define bcma_pmu_write32(cc, offset, val) \
|
|
||||||
+ bcma_write32((cc)->pmu.core, offset, val)
|
|
||||||
+
|
|
||||||
+#define bcma_pmu_mask32(cc, offset, mask) \
|
|
||||||
+ bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) & (mask))
|
|
||||||
+#define bcma_pmu_set32(cc, offset, set) \
|
|
||||||
+ bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) | (set))
|
|
||||||
+#define bcma_pmu_maskset32(cc, offset, mask, set) \
|
|
||||||
+ bcma_pmu_write32(cc, offset, (bcma_pmu_read32(cc, offset) & (mask)) | (set))
|
|
||||||
+
|
|
||||||
extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
|
|
||||||
|
|
||||||
extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
|
|
||||||
--- a/drivers/bcma/bcma_private.h
|
|
||||||
+++ b/drivers/bcma/bcma_private.h
|
|
||||||
@@ -44,10 +44,6 @@ int bcma_sprom_get(struct bcma_bus *bus)
|
|
||||||
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
|
|
||||||
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
|
|
||||||
void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
|
|
||||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
|
||||||
-extern struct platform_device bcma_pflash_dev;
|
|
||||||
-#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
|
||||||
|
|
||||||
/* driver_chipcommon_b.c */
|
|
||||||
int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
|
|
||||||
@@ -59,6 +55,21 @@ void bcma_pmu_init(struct bcma_drv_cc *c
|
|
||||||
u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
|
|
||||||
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
|
|
||||||
|
|
||||||
+/**************************************************
|
|
||||||
+ * driver_chipcommon_sflash.c
|
|
||||||
+ **************************************************/
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_BCMA_PFLASH
|
|
||||||
+extern struct platform_device bcma_pflash_dev;
|
|
||||||
+int bcma_pflash_init(struct bcma_drv_cc *cc);
|
|
||||||
+#else
|
|
||||||
+static inline int bcma_pflash_init(struct bcma_drv_cc *cc)
|
|
||||||
+{
|
|
||||||
+ bcma_err(cc->core->bus, "Parallel flash not supported\n");
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+#endif /* CONFIG_BCMA_PFLASH */
|
|
||||||
+
|
|
||||||
#ifdef CONFIG_BCMA_SFLASH
|
|
||||||
/* driver_chipcommon_sflash.c */
|
|
||||||
int bcma_sflash_init(struct bcma_drv_cc *cc);
|
|
||||||
--- a/drivers/bcma/driver_gpio.c
|
|
||||||
+++ b/drivers/bcma/driver_gpio.c
|
|
||||||
@@ -229,6 +229,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
|
||||||
case BCMA_CHIP_ID_BCM4707:
|
|
||||||
case BCMA_CHIP_ID_BCM5357:
|
|
||||||
case BCMA_CHIP_ID_BCM53572:
|
|
||||||
+ case BCMA_CHIP_ID_BCM47094:
|
|
||||||
chip->ngpio = 32;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
--- a/drivers/bcma/driver_mips.c
|
|
||||||
+++ b/drivers/bcma/driver_mips.c
|
|
||||||
@@ -14,8 +14,6 @@
|
|
||||||
|
|
||||||
#include <linux/bcma/bcma.h>
|
|
||||||
|
|
||||||
-#include <linux/mtd/physmap.h>
|
|
||||||
-#include <linux/platform_device.h>
|
|
||||||
#include <linux/serial.h>
|
|
||||||
#include <linux/serial_core.h>
|
|
||||||
#include <linux/serial_reg.h>
|
|
||||||
@@ -29,26 +27,6 @@ enum bcma_boot_dev {
|
|
||||||
BCMA_BOOT_DEV_NAND,
|
|
||||||
};
|
|
||||||
|
|
||||||
-static const char * const part_probes[] = { "bcm47xxpart", NULL };
|
|
||||||
-
|
|
||||||
-static struct physmap_flash_data bcma_pflash_data = {
|
|
||||||
- .part_probe_types = part_probes,
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
-static struct resource bcma_pflash_resource = {
|
|
||||||
- .name = "bcma_pflash",
|
|
||||||
- .flags = IORESOURCE_MEM,
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
-struct platform_device bcma_pflash_dev = {
|
|
||||||
- .name = "physmap-flash",
|
|
||||||
- .dev = {
|
|
||||||
- .platform_data = &bcma_pflash_data,
|
|
||||||
- },
|
|
||||||
- .resource = &bcma_pflash_resource,
|
|
||||||
- .num_resources = 1,
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
/* The 47162a0 hangs when reading MIPS DMP registers registers */
|
|
||||||
static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
|
|
||||||
{
|
|
||||||
@@ -269,48 +247,11 @@ static enum bcma_boot_dev bcma_boot_dev(
|
|
||||||
return BCMA_BOOT_DEV_SERIAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
|
|
||||||
+static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
|
|
||||||
{
|
|
||||||
struct bcma_bus *bus = mcore->core->bus;
|
|
||||||
- struct bcma_drv_cc *cc = &bus->drv_cc;
|
|
||||||
- struct bcma_pflash *pflash = &cc->pflash;
|
|
||||||
enum bcma_boot_dev boot_dev;
|
|
||||||
|
|
||||||
- switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
|
|
||||||
- case BCMA_CC_FLASHT_STSER:
|
|
||||||
- case BCMA_CC_FLASHT_ATSER:
|
|
||||||
- bcma_debug(bus, "Found serial flash\n");
|
|
||||||
- bcma_sflash_init(cc);
|
|
||||||
- break;
|
|
||||||
- case BCMA_CC_FLASHT_PARA:
|
|
||||||
- bcma_debug(bus, "Found parallel flash\n");
|
|
||||||
- pflash->present = true;
|
|
||||||
- pflash->window = BCMA_SOC_FLASH2;
|
|
||||||
- pflash->window_size = BCMA_SOC_FLASH2_SZ;
|
|
||||||
-
|
|
||||||
- if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
|
|
||||||
- BCMA_CC_FLASH_CFG_DS) == 0)
|
|
||||||
- pflash->buswidth = 1;
|
|
||||||
- else
|
|
||||||
- pflash->buswidth = 2;
|
|
||||||
-
|
|
||||||
- bcma_pflash_data.width = pflash->buswidth;
|
|
||||||
- bcma_pflash_resource.start = pflash->window;
|
|
||||||
- bcma_pflash_resource.end = pflash->window + pflash->window_size;
|
|
||||||
-
|
|
||||||
- break;
|
|
||||||
- default:
|
|
||||||
- bcma_err(bus, "Flash type not supported\n");
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (cc->core->id.rev == 38 ||
|
|
||||||
- bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
|
|
||||||
- if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
|
|
||||||
- bcma_debug(bus, "Found NAND flash\n");
|
|
||||||
- bcma_nflash_init(cc);
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
/* Determine flash type this SoC boots from */
|
|
||||||
boot_dev = bcma_boot_dev(bus);
|
|
||||||
switch (boot_dev) {
|
|
||||||
@@ -328,13 +269,10 @@ static void bcma_core_mips_flash_detect(
|
|
||||||
|
|
||||||
void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
|
|
||||||
{
|
|
||||||
- struct bcma_bus *bus = mcore->core->bus;
|
|
||||||
-
|
|
||||||
if (mcore->early_setup_done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- bcma_chipco_serial_init(&bus->drv_cc);
|
|
||||||
- bcma_core_mips_flash_detect(mcore);
|
|
||||||
+ bcma_core_mips_nvram_init(mcore);
|
|
||||||
|
|
||||||
mcore->early_setup_done = true;
|
|
||||||
}
|
|
||||||
--- a/drivers/bcma/host_pci.c
|
|
||||||
+++ b/drivers/bcma/host_pci.c
|
|
||||||
@@ -294,7 +294,7 @@ static const struct pci_device_id bcma_p
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
|
|
||||||
- { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
|
|
||||||
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
|
|
||||||
--- a/drivers/bcma/Kconfig
|
|
||||||
+++ b/drivers/bcma/Kconfig
|
|
||||||
@@ -70,6 +70,11 @@ config BCMA_DRIVER_MIPS
|
|
||||||
|
|
||||||
If unsure, say N
|
|
||||||
|
|
||||||
+config BCMA_PFLASH
|
|
||||||
+ bool
|
|
||||||
+ depends on BCMA_DRIVER_MIPS
|
|
||||||
+ default y
|
|
||||||
+
|
|
||||||
config BCMA_SFLASH
|
|
||||||
bool
|
|
||||||
depends on BCMA_DRIVER_MIPS
|
|
||||||
--- a/drivers/bcma/Makefile
|
|
||||||
+++ b/drivers/bcma/Makefile
|
|
||||||
@@ -1,6 +1,7 @@
|
|
||||||
bcma-y += main.o scan.o core.o sprom.o
|
|
||||||
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
|
|
||||||
bcma-y += driver_chipcommon_b.o
|
|
||||||
+bcma-$(CONFIG_BCMA_PFLASH) += driver_chipcommon_pflash.o
|
|
||||||
bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
|
|
||||||
bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
|
|
||||||
bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pci.o
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/drivers/bcma/driver_chipcommon_pflash.c
|
|
||||||
@@ -0,0 +1,49 @@
|
|
||||||
+/*
|
|
||||||
+ * Broadcom specific AMBA
|
|
||||||
+ * ChipCommon parallel flash
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the GNU/GPL. See COPYING for details.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include "bcma_private.h"
|
|
||||||
+
|
|
||||||
+#include <linux/bcma/bcma.h>
|
|
||||||
+#include <linux/mtd/physmap.h>
|
|
||||||
+#include <linux/platform_device.h>
|
|
||||||
+
|
|
||||||
+static const char * const part_probes[] = { "bcm47xxpart", NULL };
|
|
||||||
+
|
|
||||||
+static struct physmap_flash_data bcma_pflash_data = {
|
|
||||||
+ .part_probe_types = part_probes,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct resource bcma_pflash_resource = {
|
|
||||||
+ .name = "bcma_pflash",
|
|
||||||
+ .flags = IORESOURCE_MEM,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct platform_device bcma_pflash_dev = {
|
|
||||||
+ .name = "physmap-flash",
|
|
||||||
+ .dev = {
|
|
||||||
+ .platform_data = &bcma_pflash_data,
|
|
||||||
+ },
|
|
||||||
+ .resource = &bcma_pflash_resource,
|
|
||||||
+ .num_resources = 1,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+int bcma_pflash_init(struct bcma_drv_cc *cc)
|
|
||||||
+{
|
|
||||||
+ struct bcma_pflash *pflash = &cc->pflash;
|
|
||||||
+
|
|
||||||
+ pflash->present = true;
|
|
||||||
+
|
|
||||||
+ if (!(bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & BCMA_CC_FLASH_CFG_DS))
|
|
||||||
+ bcma_pflash_data.width = 1;
|
|
||||||
+ else
|
|
||||||
+ bcma_pflash_data.width = 2;
|
|
||||||
+
|
|
||||||
+ bcma_pflash_resource.start = BCMA_SOC_FLASH2;
|
|
||||||
+ bcma_pflash_resource.end = BCMA_SOC_FLASH2 + BCMA_SOC_FLASH2_SZ;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
--- a/drivers/bcma/main.c
|
|
||||||
+++ b/drivers/bcma/main.c
|
|
||||||
@@ -325,7 +325,7 @@ static int bcma_register_devices(struct
|
|
||||||
bcma_register_core(bus, core);
|
|
||||||
}
|
|
||||||
|
|
||||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
|
||||||
+#ifdef CONFIG_BCMA_PFLASH
|
|
||||||
if (bus->drv_cc.pflash.present) {
|
|
||||||
err = platform_device_register(&bcma_pflash_dev);
|
|
||||||
if (err)
|
|
@ -1,50 +0,0 @@
|
|||||||
--- a/drivers/mtd/bcm47xxpart.c
|
|
||||||
+++ b/drivers/mtd/bcm47xxpart.c
|
|
||||||
@@ -15,8 +15,12 @@
|
|
||||||
#include <linux/mtd/mtd.h>
|
|
||||||
#include <linux/mtd/partitions.h>
|
|
||||||
|
|
||||||
-/* 10 parts were found on sflash on Netgear WNDR4500 */
|
|
||||||
-#define BCM47XXPART_MAX_PARTS 12
|
|
||||||
+/*
|
|
||||||
+ * NAND flash on Netgear R6250 was verified to contain 15 partitions.
|
|
||||||
+ * This will result in allocating too big array for some old devices, but the
|
|
||||||
+ * memory will be freed soon anyway (see mtd_device_parse_register).
|
|
||||||
+ */
|
|
||||||
+#define BCM47XXPART_MAX_PARTS 20
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Amount of bytes we read when analyzing each block of flash memory.
|
|
||||||
@@ -168,18 +172,26 @@ static int bcm47xxpart_parse(struct mtd_
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
- bcm47xxpart_add_part(&parts[curr_part++], "linux",
|
|
||||||
- offset + trx->offset[i], 0);
|
|
||||||
- i++;
|
|
||||||
+ if (trx->offset[i]) {
|
|
||||||
+ bcm47xxpart_add_part(&parts[curr_part++],
|
|
||||||
+ "linux",
|
|
||||||
+ offset + trx->offset[i],
|
|
||||||
+ 0);
|
|
||||||
+ i++;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pure rootfs size is known and can be calculated as:
|
|
||||||
* trx->length - trx->offset[i]. We don't fill it as
|
|
||||||
* we want to have jffs2 (overlay) in the same mtd.
|
|
||||||
*/
|
|
||||||
- bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
|
|
||||||
- offset + trx->offset[i], 0);
|
|
||||||
- i++;
|
|
||||||
+ if (trx->offset[i]) {
|
|
||||||
+ bcm47xxpart_add_part(&parts[curr_part++],
|
|
||||||
+ "rootfs",
|
|
||||||
+ offset + trx->offset[i],
|
|
||||||
+ 0);
|
|
||||||
+ i++;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
last_trx_part = curr_part - 1;
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
|||||||
--- a/drivers/mtd/bcm47xxpart.c
|
|
||||||
+++ b/drivers/mtd/bcm47xxpart.c
|
|
||||||
@@ -15,6 +15,8 @@
|
|
||||||
#include <linux/mtd/mtd.h>
|
|
||||||
#include <linux/mtd/partitions.h>
|
|
||||||
|
|
||||||
+#include <uapi/linux/magic.h>
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* NAND flash on Netgear R6250 was verified to contain 15 partitions.
|
|
||||||
* This will result in allocating too big array for some old devices, but the
|
|
||||||
@@ -39,7 +41,8 @@
|
|
||||||
#define ML_MAGIC1 0x39685a42
|
|
||||||
#define ML_MAGIC2 0x26594131
|
|
||||||
#define TRX_MAGIC 0x30524448
|
|
||||||
-#define SQSH_MAGIC 0x71736873 /* shsq */
|
|
||||||
+#define SHSQ_MAGIC 0x71736873 /* shsq (weird ZTE H218N endianness) */
|
|
||||||
+#define UBI_EC_MAGIC 0x23494255 /* UBI# */
|
|
||||||
|
|
||||||
struct trx_header {
|
|
||||||
uint32_t magic;
|
|
||||||
@@ -50,7 +53,7 @@ struct trx_header {
|
|
||||||
uint32_t offset[3];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
-static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
|
|
||||||
+static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name,
|
|
||||||
u64 offset, uint32_t mask_flags)
|
|
||||||
{
|
|
||||||
part->name = name;
|
|
||||||
@@ -58,6 +61,26 @@ static void bcm47xxpart_add_part(struct
|
|
||||||
part->mask_flags = mask_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
|
|
||||||
+ size_t offset)
|
|
||||||
+{
|
|
||||||
+ uint32_t buf;
|
|
||||||
+ size_t bytes_read;
|
|
||||||
+
|
|
||||||
+ if (mtd_read(master, offset, sizeof(buf), &bytes_read,
|
|
||||||
+ (uint8_t *)&buf) < 0) {
|
|
||||||
+ pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
|
|
||||||
+ offset);
|
|
||||||
+ goto out_default;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (buf == UBI_EC_MAGIC)
|
|
||||||
+ return "ubi";
|
|
||||||
+
|
|
||||||
+out_default:
|
|
||||||
+ return "rootfs";
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int bcm47xxpart_parse(struct mtd_info *master,
|
|
||||||
struct mtd_partition **pparts,
|
|
||||||
struct mtd_part_parser_data *data)
|
|
||||||
@@ -73,8 +96,12 @@ static int bcm47xxpart_parse(struct mtd_
|
|
||||||
int last_trx_part = -1;
|
|
||||||
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
|
|
||||||
|
|
||||||
- if (blocksize <= 0x10000)
|
|
||||||
- blocksize = 0x10000;
|
|
||||||
+ /*
|
|
||||||
+ * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
|
|
||||||
+ * partitions were aligned to at least 0x1000 anyway.
|
|
||||||
+ */
|
|
||||||
+ if (blocksize < 0x1000)
|
|
||||||
+ blocksize = 0x1000;
|
|
||||||
|
|
||||||
/* Alloc */
|
|
||||||
parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
|
|
||||||
@@ -186,8 +213,11 @@ static int bcm47xxpart_parse(struct mtd_
|
|
||||||
* we want to have jffs2 (overlay) in the same mtd.
|
|
||||||
*/
|
|
||||||
if (trx->offset[i]) {
|
|
||||||
+ const char *name;
|
|
||||||
+
|
|
||||||
+ name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
|
|
||||||
bcm47xxpart_add_part(&parts[curr_part++],
|
|
||||||
- "rootfs",
|
|
||||||
+ name,
|
|
||||||
offset + trx->offset[i],
|
|
||||||
0);
|
|
||||||
i++;
|
|
||||||
@@ -203,7 +233,8 @@ static int bcm47xxpart_parse(struct mtd_
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Squashfs on devices not using TRX */
|
|
||||||
- if (buf[0x000 / 4] == SQSH_MAGIC) {
|
|
||||||
+ if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
|
|
||||||
+ buf[0x000 / 4] == SHSQ_MAGIC) {
|
|
||||||
bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
|
|
||||||
offset, 0);
|
|
||||||
continue;
|
|
@ -1,15 +0,0 @@
|
|||||||
mtd: spi-nor: support for (GigaDevice) GD25Q128B
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
|
||||||
|
|
||||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
|
||||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
|
||||||
@@ -510,6 +510,7 @@ static const struct spi_device_id spi_no
|
|
||||||
/* GigaDevice */
|
|
||||||
{ "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) },
|
|
||||||
{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
|
|
||||||
+ { "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K) },
|
|
||||||
|
|
||||||
/* Intel/Numonyx -- xxxs33b */
|
|
||||||
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
|
|
@ -1,39 +0,0 @@
|
|||||||
--- a/drivers/mtd/devices/m25p80.c
|
|
||||||
+++ b/drivers/mtd/devices/m25p80.c
|
|
||||||
@@ -310,11 +310,21 @@ static const struct spi_device_id m25p_i
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(spi, m25p_ids);
|
|
||||||
|
|
||||||
+static const struct of_device_id m25p_of_table[] = {
|
|
||||||
+ /*
|
|
||||||
+ * Generic compatibility for SPI NOR that can be identified by the
|
|
||||||
+ * JEDEC READ ID opcode (0x9F). Use this, if possible.
|
|
||||||
+ */
|
|
||||||
+ { .compatible = "jedec,spi-nor" },
|
|
||||||
+ {}
|
|
||||||
+};
|
|
||||||
+MODULE_DEVICE_TABLE(of, m25p_of_table);
|
|
||||||
|
|
||||||
static struct spi_driver m25p80_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "m25p80",
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
+ .of_match_table = m25p_of_table,
|
|
||||||
},
|
|
||||||
.id_table = m25p_ids,
|
|
||||||
.probe = m25p_probe,
|
|
||||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
|
||||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
|
||||||
@@ -934,8 +934,11 @@ int spi_nor_scan(struct spi_nor *nor, co
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
- id = spi_nor_match_id(name);
|
|
||||||
+ if (name)
|
|
||||||
+ id = spi_nor_match_id(name);
|
|
||||||
if (!id)
|
|
||||||
+ id = nor->read_id(nor);
|
|
||||||
+ if (IS_ERR_OR_NULL(id))
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
info = (void *)id->driver_data;
|
|
@ -1,509 +0,0 @@
|
|||||||
Subject: netfilter: conntrack: cache route for forwarded connections
|
|
||||||
|
|
||||||
... to avoid per-packet FIB lookup if possible.
|
|
||||||
|
|
||||||
The cached dst is re-used provided the input interface
|
|
||||||
is the same as that of the previous packet in the same direction.
|
|
||||||
|
|
||||||
If not, the cached dst is invalidated.
|
|
||||||
|
|
||||||
For ipv6 we also need to store sernum, else dst_check doesn't work,
|
|
||||||
pointed out by Eric Dumazet.
|
|
||||||
|
|
||||||
This should speed up forwarding when conntrack is already in use
|
|
||||||
anyway, especially when using reverse path filtering -- active RPF
|
|
||||||
enforces two FIB lookups for each packet.
|
|
||||||
|
|
||||||
Before the routing cache removal this didn't matter since RPF was performed
|
|
||||||
only when route cache didn't yield a result; but without route cache it
|
|
||||||
comes at higher price.
|
|
||||||
|
|
||||||
Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
|
|
||||||
avoid holding on to dsts of 'frozen' conntracks.
|
|
||||||
|
|
||||||
Signed-off-by: Florian Westphal <fw@strlen.de>
|
|
||||||
|
|
||||||
--- a/include/net/netfilter/nf_conntrack_extend.h
|
|
||||||
+++ b/include/net/netfilter/nf_conntrack_extend.h
|
|
||||||
@@ -30,6 +30,9 @@ enum nf_ct_ext_id {
|
|
||||||
#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
|
|
||||||
NF_CT_EXT_SYNPROXY,
|
|
||||||
#endif
|
|
||||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
|
|
||||||
+ NF_CT_EXT_RTCACHE,
|
|
||||||
+#endif
|
|
||||||
NF_CT_EXT_NUM,
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -43,6 +46,7 @@ enum nf_ct_ext_id {
|
|
||||||
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
|
|
||||||
#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
|
|
||||||
#define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
|
|
||||||
+#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
|
|
||||||
|
|
||||||
/* Extensions: optional stuff which isn't permanently in struct. */
|
|
||||||
struct nf_ct_ext {
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/include/net/netfilter/nf_conntrack_rtcache.h
|
|
||||||
@@ -0,0 +1,34 @@
|
|
||||||
+#include <linux/gfp.h>
|
|
||||||
+#include <net/netfilter/nf_conntrack.h>
|
|
||||||
+#include <net/netfilter/nf_conntrack_extend.h>
|
|
||||||
+
|
|
||||||
+struct dst_entry;
|
|
||||||
+
|
|
||||||
+struct nf_conn_dst_cache {
|
|
||||||
+ struct dst_entry *dst;
|
|
||||||
+ int iif;
|
|
||||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
|
||||||
+ u32 cookie;
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+struct nf_conn_rtcache {
|
|
||||||
+ struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static inline
|
|
||||||
+struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
|
|
||||||
+{
|
|
||||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
|
|
||||||
+ return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
|
|
||||||
+#else
|
|
||||||
+ return NULL;
|
|
||||||
+#endif
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
|
|
||||||
+ enum ip_conntrack_dir dir)
|
|
||||||
+{
|
|
||||||
+ return rtc->cached_dst[dir].iif;
|
|
||||||
+}
|
|
||||||
--- a/net/netfilter/Kconfig
|
|
||||||
+++ b/net/netfilter/Kconfig
|
|
||||||
@@ -106,6 +106,18 @@ config NF_CONNTRACK_EVENTS
|
|
||||||
|
|
||||||
If unsure, say `N'.
|
|
||||||
|
|
||||||
+config NF_CONNTRACK_RTCACHE
|
|
||||||
+ tristate "Cache route entries in conntrack objects"
|
|
||||||
+ depends on NETFILTER_ADVANCED
|
|
||||||
+ depends on NF_CONNTRACK
|
|
||||||
+ help
|
|
||||||
+ If this option is enabled, the connection tracking code will
|
|
||||||
+ cache routing information for each connection that is being
|
|
||||||
+ forwarded, at a cost of 32 bytes per conntrack object.
|
|
||||||
+
|
|
||||||
+ To compile it as a module, choose M here. If unsure, say N.
|
|
||||||
+ The module will be called nf_conntrack_rtcache.
|
|
||||||
+
|
|
||||||
config NF_CONNTRACK_TIMEOUT
|
|
||||||
bool 'Connection tracking timeout'
|
|
||||||
depends on NETFILTER_ADVANCED
|
|
||||||
--- a/net/netfilter/Makefile
|
|
||||||
+++ b/net/netfilter/Makefile
|
|
||||||
@@ -18,6 +18,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n
|
|
||||||
# connection tracking
|
|
||||||
obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
|
|
||||||
|
|
||||||
+# optional conntrack route cache extension
|
|
||||||
+obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
|
|
||||||
+
|
|
||||||
# SCTP protocol connection tracking
|
|
||||||
obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
|
|
||||||
obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/net/netfilter/nf_conntrack_rtcache.c
|
|
||||||
@@ -0,0 +1,391 @@
|
|
||||||
+/* route cache for netfilter.
|
|
||||||
+ *
|
|
||||||
+ * (C) 2014 Red Hat GmbH
|
|
||||||
+ *
|
|
||||||
+ * This program is free software; you can redistribute it and/or modify
|
|
||||||
+ * it under the terms of the GNU General Public License version 2 as
|
|
||||||
+ * published by the Free Software Foundation.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
||||||
+
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/netfilter.h>
|
|
||||||
+#include <linux/skbuff.h>
|
|
||||||
+#include <linux/stddef.h>
|
|
||||||
+#include <linux/kernel.h>
|
|
||||||
+#include <linux/netdevice.h>
|
|
||||||
+#include <linux/export.h>
|
|
||||||
+#include <linux/module.h>
|
|
||||||
+
|
|
||||||
+#include <net/dst.h>
|
|
||||||
+
|
|
||||||
+#include <net/netfilter/nf_conntrack.h>
|
|
||||||
+#include <net/netfilter/nf_conntrack_core.h>
|
|
||||||
+#include <net/netfilter/nf_conntrack_extend.h>
|
|
||||||
+#include <net/netfilter/nf_conntrack_rtcache.h>
|
|
||||||
+
|
|
||||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
|
||||||
+#include <net/ip6_fib.h>
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
|
|
||||||
+ enum ip_conntrack_dir dir)
|
|
||||||
+{
|
|
||||||
+ struct dst_entry *dst = rtc->cached_dst[dir].dst;
|
|
||||||
+
|
|
||||||
+ dst_release(dst);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void nf_conn_rtcache_destroy(struct nf_conn *ct)
|
|
||||||
+{
|
|
||||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
|
||||||
+
|
|
||||||
+ if (!rtc)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
|
|
||||||
+ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
|
|
||||||
+{
|
|
||||||
+ struct nf_conn_rtcache *rtc;
|
|
||||||
+
|
|
||||||
+ rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
|
|
||||||
+ if (rtc) {
|
|
||||||
+ rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
|
|
||||||
+ rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
|
|
||||||
+ rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
|
|
||||||
+ rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
|
|
||||||
+{
|
|
||||||
+ if (nf_ct_is_untracked(ct))
|
|
||||||
+ return NULL;
|
|
||||||
+ return nf_ct_rtcache_find(ct);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct dst_entry *
|
|
||||||
+nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
|
|
||||||
+ enum ip_conntrack_dir dir)
|
|
||||||
+{
|
|
||||||
+ return rtc->cached_dst[dir].dst;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
|
|
||||||
+{
|
|
||||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
|
||||||
+ if (pf == NFPROTO_IPV6) {
|
|
||||||
+ const struct rt6_info *rt = (const struct rt6_info *)dst;
|
|
||||||
+
|
|
||||||
+ if (rt->rt6i_node)
|
|
||||||
+ return (u32)rt->rt6i_node->fn_sernum;
|
|
||||||
+ }
|
|
||||||
+#endif
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void nf_conn_rtcache_dst_set(int pf,
|
|
||||||
+ struct nf_conn_rtcache *rtc,
|
|
||||||
+ struct dst_entry *dst,
|
|
||||||
+ enum ip_conntrack_dir dir, int iif)
|
|
||||||
+{
|
|
||||||
+ if (rtc->cached_dst[dir].iif != iif)
|
|
||||||
+ rtc->cached_dst[dir].iif = iif;
|
|
||||||
+
|
|
||||||
+ if (rtc->cached_dst[dir].dst != dst) {
|
|
||||||
+ struct dst_entry *old;
|
|
||||||
+
|
|
||||||
+ dst_hold(dst);
|
|
||||||
+
|
|
||||||
+ old = xchg(&rtc->cached_dst[dir].dst, dst);
|
|
||||||
+ dst_release(old);
|
|
||||||
+
|
|
||||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
|
||||||
+ if (pf == NFPROTO_IPV6)
|
|
||||||
+ rtc->cached_dst[dir].cookie =
|
|
||||||
+ nf_rtcache_get_cookie(pf, dst);
|
|
||||||
+#endif
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
|
|
||||||
+ enum ip_conntrack_dir dir)
|
|
||||||
+{
|
|
||||||
+ struct dst_entry *old;
|
|
||||||
+
|
|
||||||
+ pr_debug("Invalidate iif %d for dir %d on cache %p\n",
|
|
||||||
+ rtc->cached_dst[dir].iif, dir, rtc);
|
|
||||||
+
|
|
||||||
+ old = xchg(&rtc->cached_dst[dir].dst, NULL);
|
|
||||||
+ dst_release(old);
|
|
||||||
+ rtc->cached_dst[dir].iif = -1;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static unsigned int nf_rtcache_in(const struct nf_hook_ops *ops,
|
|
||||||
+ struct sk_buff *skb,
|
|
||||||
+ const struct net_device *in,
|
|
||||||
+ const struct net_device *out,
|
|
||||||
+ int (*okfn)(struct sk_buff *))
|
|
||||||
+{
|
|
||||||
+ struct nf_conn_rtcache *rtc;
|
|
||||||
+ enum ip_conntrack_info ctinfo;
|
|
||||||
+ enum ip_conntrack_dir dir;
|
|
||||||
+ struct dst_entry *dst;
|
|
||||||
+ struct nf_conn *ct;
|
|
||||||
+ int iif;
|
|
||||||
+ u32 cookie;
|
|
||||||
+
|
|
||||||
+ if (skb_dst(skb) || skb->sk)
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+
|
|
||||||
+ ct = nf_ct_get(skb, &ctinfo);
|
|
||||||
+ if (!ct)
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+
|
|
||||||
+ rtc = nf_ct_rtcache_find_usable(ct);
|
|
||||||
+ if (!rtc)
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+
|
|
||||||
+ /* if iif changes, don't use cache and let ip stack
|
|
||||||
+ * do route lookup.
|
|
||||||
+ *
|
|
||||||
+ * If rp_filter is enabled it might toss skb, so
|
|
||||||
+ * we don't want to avoid these checks.
|
|
||||||
+ */
|
|
||||||
+ dir = CTINFO2DIR(ctinfo);
|
|
||||||
+ iif = nf_conn_rtcache_iif_get(rtc, dir);
|
|
||||||
+ if (in->ifindex != iif) {
|
|
||||||
+ pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
|
|
||||||
+ ct, iif, in->ifindex);
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+ }
|
|
||||||
+ dst = nf_conn_rtcache_dst_get(rtc, dir);
|
|
||||||
+ if (dst == NULL)
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+
|
|
||||||
+ cookie = nf_rtcache_get_cookie(ops->pf, dst);
|
|
||||||
+
|
|
||||||
+ dst = dst_check(dst, cookie);
|
|
||||||
+ pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
|
|
||||||
+ if (likely(dst))
|
|
||||||
+ skb_dst_set_noref_force(skb, dst);
|
|
||||||
+ else
|
|
||||||
+ nf_conn_rtcache_dst_obsolete(rtc, dir);
|
|
||||||
+
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static unsigned int nf_rtcache_forward(const struct nf_hook_ops *ops,
|
|
||||||
+ struct sk_buff *skb,
|
|
||||||
+ const struct net_device *in,
|
|
||||||
+ const struct net_device *out,
|
|
||||||
+ int (*okfn)(struct sk_buff *))
|
|
||||||
+{
|
|
||||||
+ struct nf_conn_rtcache *rtc;
|
|
||||||
+ enum ip_conntrack_info ctinfo;
|
|
||||||
+ enum ip_conntrack_dir dir;
|
|
||||||
+ struct nf_conn *ct;
|
|
||||||
+ struct dst_entry *dst = skb_dst(skb);
|
|
||||||
+ int iif;
|
|
||||||
+
|
|
||||||
+ ct = nf_ct_get(skb, &ctinfo);
|
|
||||||
+ if (!ct)
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+
|
|
||||||
+ if (dst && dst_xfrm(dst))
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+
|
|
||||||
+ if (!nf_ct_is_confirmed(ct)) {
|
|
||||||
+ if (WARN_ON(nf_ct_rtcache_find(ct)))
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+ nf_ct_rtcache_ext_add(ct);
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ rtc = nf_ct_rtcache_find_usable(ct);
|
|
||||||
+ if (!rtc)
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+
|
|
||||||
+ dir = CTINFO2DIR(ctinfo);
|
|
||||||
+ iif = nf_conn_rtcache_iif_get(rtc, dir);
|
|
||||||
+ pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
|
|
||||||
+ ct, skb, dir, iif, in->ifindex);
|
|
||||||
+ if (likely(in->ifindex == iif))
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+
|
|
||||||
+ nf_conn_rtcache_dst_set(ops->pf, rtc, skb_dst(skb), dir, in->ifindex);
|
|
||||||
+ return NF_ACCEPT;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
|
|
||||||
+{
|
|
||||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
|
||||||
+ struct net_device *dev = data;
|
|
||||||
+
|
|
||||||
+ if (!rtc)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+ if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
|
|
||||||
+ dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
|
|
||||||
+ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
|
|
||||||
+ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int nf_rtcache_netdev_event(struct notifier_block *this,
|
|
||||||
+ unsigned long event, void *ptr)
|
|
||||||
+{
|
|
||||||
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
|
||||||
+ struct net *net = dev_net(dev);
|
|
||||||
+
|
|
||||||
+ if (event == NETDEV_DOWN)
|
|
||||||
+ nf_ct_iterate_cleanup(net, nf_rtcache_dst_remove, dev, 0, 0);
|
|
||||||
+
|
|
||||||
+ return NOTIFY_DONE;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct notifier_block nf_rtcache_notifier = {
|
|
||||||
+ .notifier_call = nf_rtcache_netdev_event,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct nf_hook_ops rtcache_ops[] = {
|
|
||||||
+ {
|
|
||||||
+ .hook = nf_rtcache_in,
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ .pf = NFPROTO_IPV4,
|
|
||||||
+ .hooknum = NF_INET_PRE_ROUTING,
|
|
||||||
+ .priority = NF_IP_PRI_LAST,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .hook = nf_rtcache_forward,
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ .pf = NFPROTO_IPV4,
|
|
||||||
+ .hooknum = NF_INET_FORWARD,
|
|
||||||
+ .priority = NF_IP_PRI_LAST,
|
|
||||||
+ },
|
|
||||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
|
||||||
+ {
|
|
||||||
+ .hook = nf_rtcache_in,
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ .pf = NFPROTO_IPV6,
|
|
||||||
+ .hooknum = NF_INET_PRE_ROUTING,
|
|
||||||
+ .priority = NF_IP_PRI_LAST,
|
|
||||||
+ },
|
|
||||||
+ {
|
|
||||||
+ .hook = nf_rtcache_forward,
|
|
||||||
+ .owner = THIS_MODULE,
|
|
||||||
+ .pf = NFPROTO_IPV6,
|
|
||||||
+ .hooknum = NF_INET_FORWARD,
|
|
||||||
+ .priority = NF_IP_PRI_LAST,
|
|
||||||
+ },
|
|
||||||
+#endif
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static struct nf_ct_ext_type rtcache_extend __read_mostly = {
|
|
||||||
+ .len = sizeof(struct nf_conn_rtcache),
|
|
||||||
+ .align = __alignof__(struct nf_conn_rtcache),
|
|
||||||
+ .id = NF_CT_EXT_RTCACHE,
|
|
||||||
+ .destroy = nf_conn_rtcache_destroy,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static int __init nf_conntrack_rtcache_init(void)
|
|
||||||
+{
|
|
||||||
+ int ret = nf_ct_extend_register(&rtcache_extend);
|
|
||||||
+
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ pr_err("nf_conntrack_rtcache: Unable to register extension\n");
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
|
||||||
+ if (ret < 0) {
|
|
||||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ret = register_netdevice_notifier(&nf_rtcache_notifier);
|
|
||||||
+ if (ret) {
|
|
||||||
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
|
||||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
|
|
||||||
+{
|
|
||||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
|
||||||
+
|
|
||||||
+ return rtc != NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
|
|
||||||
+{
|
|
||||||
+ bool wait = false;
|
|
||||||
+ int cpu;
|
|
||||||
+
|
|
||||||
+ for_each_possible_cpu(cpu) {
|
|
||||||
+ struct nf_conntrack_tuple_hash *h;
|
|
||||||
+ struct hlist_nulls_node *n;
|
|
||||||
+ struct nf_conn *ct;
|
|
||||||
+ struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
|
|
||||||
+
|
|
||||||
+ rcu_read_lock();
|
|
||||||
+ spin_lock_bh(&pcpu->lock);
|
|
||||||
+
|
|
||||||
+ hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
|
|
||||||
+ ct = nf_ct_tuplehash_to_ctrack(h);
|
|
||||||
+ if (nf_ct_rtcache_find(ct) != NULL) {
|
|
||||||
+ wait = true;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ spin_unlock_bh(&pcpu->lock);
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return wait;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void __exit nf_conntrack_rtcache_fini(void)
|
|
||||||
+{
|
|
||||||
+ struct net *net;
|
|
||||||
+ int count = 0;
|
|
||||||
+
|
|
||||||
+ /* remove hooks so no new connections get rtcache extension */
|
|
||||||
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
|
||||||
+
|
|
||||||
+ synchronize_net();
|
|
||||||
+
|
|
||||||
+ unregister_netdevice_notifier(&nf_rtcache_notifier);
|
|
||||||
+
|
|
||||||
+ rtnl_lock();
|
|
||||||
+
|
|
||||||
+ /* zap all conntracks with rtcache extension */
|
|
||||||
+ for_each_net(net)
|
|
||||||
+ nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0);
|
|
||||||
+
|
|
||||||
+ for_each_net(net) {
|
|
||||||
+ /* .. and make sure they're gone from dying list, too */
|
|
||||||
+ while (nf_conntrack_rtcache_wait_for_dying(net)) {
|
|
||||||
+ msleep(200);
|
|
||||||
+ WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ rtnl_unlock();
|
|
||||||
+ synchronize_net();
|
|
||||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
|
||||||
+}
|
|
||||||
+module_init(nf_conntrack_rtcache_init);
|
|
||||||
+module_exit(nf_conntrack_rtcache_fini);
|
|
||||||
+
|
|
||||||
+MODULE_LICENSE("GPL");
|
|
||||||
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
|
|
||||||
+MODULE_DESCRIPTION("Conntrack route cache extension");
|
|
@ -1,99 +0,0 @@
|
|||||||
From 6ae4ae8e512bd229f806c22f8a2cd751e4f987c2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
|
|
||||||
Date: Sat, 23 May 2015 03:12:34 +0200
|
|
||||||
Subject: [PATCH] bridge: allow setting hash_max + multicast_router if
|
|
||||||
interface is down
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
Network managers like netifd (used in OpenWRT for instance) try to
|
|
||||||
configure interface options after creation but before setting the
|
|
||||||
interface up.
|
|
||||||
|
|
||||||
Unfortunately the sysfs / bridge currently only allows to configure the
|
|
||||||
hash_max and multicast_router options when the bridge interface is up.
|
|
||||||
But since br_multicast_init() doesn't start any timers and only sets
|
|
||||||
default values and initializes timers it should be save to reconfigure
|
|
||||||
the default values after that, before things actually get active after
|
|
||||||
the bridge is set up.
|
|
||||||
|
|
||||||
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
net/bridge/br_multicast.c | 24 +++---------------------
|
|
||||||
1 file changed, 3 insertions(+), 21 deletions(-)
|
|
||||||
|
|
||||||
--- a/net/bridge/br_multicast.c
|
|
||||||
+++ b/net/bridge/br_multicast.c
|
|
||||||
@@ -1948,11 +1948,9 @@ out:
|
|
||||||
|
|
||||||
int br_multicast_set_router(struct net_bridge *br, unsigned long val)
|
|
||||||
{
|
|
||||||
- int err = -ENOENT;
|
|
||||||
+ int err = -EINVAL;
|
|
||||||
|
|
||||||
spin_lock_bh(&br->multicast_lock);
|
|
||||||
- if (!netif_running(br->dev))
|
|
||||||
- goto unlock;
|
|
||||||
|
|
||||||
switch (val) {
|
|
||||||
case 0:
|
|
||||||
@@ -1963,13 +1961,8 @@ int br_multicast_set_router(struct net_b
|
|
||||||
br->multicast_router = val;
|
|
||||||
err = 0;
|
|
||||||
break;
|
|
||||||
-
|
|
||||||
- default:
|
|
||||||
- err = -EINVAL;
|
|
||||||
- break;
|
|
||||||
}
|
|
||||||
|
|
||||||
-unlock:
|
|
||||||
spin_unlock_bh(&br->multicast_lock);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
@@ -1978,11 +1971,9 @@ unlock:
|
|
||||||
int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
|
|
||||||
{
|
|
||||||
struct net_bridge *br = p->br;
|
|
||||||
- int err = -ENOENT;
|
|
||||||
+ int err = -EINVAL;
|
|
||||||
|
|
||||||
spin_lock(&br->multicast_lock);
|
|
||||||
- if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED)
|
|
||||||
- goto unlock;
|
|
||||||
|
|
||||||
switch (val) {
|
|
||||||
case 0:
|
|
||||||
@@ -2004,13 +1995,8 @@ int br_multicast_set_port_router(struct
|
|
||||||
|
|
||||||
br_multicast_add_router(br, p);
|
|
||||||
break;
|
|
||||||
-
|
|
||||||
- default:
|
|
||||||
- err = -EINVAL;
|
|
||||||
- break;
|
|
||||||
}
|
|
||||||
|
|
||||||
-unlock:
|
|
||||||
spin_unlock(&br->multicast_lock);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
@@ -2115,15 +2101,11 @@ unlock:
|
|
||||||
|
|
||||||
int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
|
|
||||||
{
|
|
||||||
- int err = -ENOENT;
|
|
||||||
+ int err = -EINVAL;
|
|
||||||
u32 old;
|
|
||||||
struct net_bridge_mdb_htable *mdb;
|
|
||||||
|
|
||||||
spin_lock_bh(&br->multicast_lock);
|
|
||||||
- if (!netif_running(br->dev))
|
|
||||||
- goto unlock;
|
|
||||||
-
|
|
||||||
- err = -EINVAL;
|
|
||||||
if (!is_power_of_2(val))
|
|
||||||
goto unlock;
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
--- a/arch/mips/boot/compressed/string.c
|
|
||||||
+++ b/arch/mips/boot/compressed/string.c
|
|
||||||
@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n)
|
|
||||||
ss[i] = c;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+void *memmove(void *__dest, __const void *__src, size_t count)
|
|
||||||
+{
|
|
||||||
+ unsigned char *d = __dest;
|
|
||||||
+ const unsigned char *s = __src;
|
|
||||||
+
|
|
||||||
+ if (__dest == __src)
|
|
||||||
+ return __dest;
|
|
||||||
+
|
|
||||||
+ if (__dest < __src)
|
|
||||||
+ return memcpy(__dest, __src, count);
|
|
||||||
+
|
|
||||||
+ while (count--)
|
|
||||||
+ d[count] = s[count];
|
|
||||||
+ return __dest;
|
|
||||||
+}
|
|
@ -1,44 +0,0 @@
|
|||||||
From 6216642f200258708e47170ff14ba8ecb486f4f0 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
|
||||||
Date: Sun, 18 Jan 2015 19:49:58 +0100
|
|
||||||
Subject: [PATCH] bgmac: register napi before the device
|
|
||||||
|
|
||||||
napi should get registered before the netdev and not after.
|
|
||||||
|
|
||||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
drivers/net/ethernet/broadcom/bgmac.c | 6 +++---
|
|
||||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -1521,6 +1521,8 @@ static int bgmac_probe(struct bcma_devic
|
|
||||||
if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
|
|
||||||
bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
|
|
||||||
|
|
||||||
+ netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
|
|
||||||
+
|
|
||||||
err = bgmac_mii_register(bgmac);
|
|
||||||
if (err) {
|
|
||||||
bgmac_err(bgmac, "Cannot register MDIO\n");
|
|
||||||
@@ -1535,8 +1537,6 @@ static int bgmac_probe(struct bcma_devic
|
|
||||||
|
|
||||||
netif_carrier_off(net_dev);
|
|
||||||
|
|
||||||
- netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
|
|
||||||
-
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_mii_unregister:
|
|
||||||
@@ -1555,9 +1555,9 @@ static void bgmac_remove(struct bcma_dev
|
|
||||||
{
|
|
||||||
struct bgmac *bgmac = bcma_get_drvdata(core);
|
|
||||||
|
|
||||||
- netif_napi_del(&bgmac->napi);
|
|
||||||
unregister_netdev(bgmac->net_dev);
|
|
||||||
bgmac_mii_unregister(bgmac);
|
|
||||||
+ netif_napi_del(&bgmac->napi);
|
|
||||||
bgmac_dma_free(bgmac);
|
|
||||||
bcma_set_drvdata(core, NULL);
|
|
||||||
free_netdev(bgmac->net_dev);
|
|
@ -1,30 +0,0 @@
|
|||||||
From 43f159c60a99318b1ef7d1d7c16c4dfdd06bfd90 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
|
||||||
Date: Sun, 18 Jan 2015 19:49:59 +0100
|
|
||||||
Subject: [PATCH] bgmac: activate irqs only if there is nothing to poll
|
|
||||||
|
|
||||||
IRQs should only get activated when there is nothing to poll in the
|
|
||||||
queue any more and to after every poll.
|
|
||||||
|
|
||||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
drivers/net/ethernet/broadcom/bgmac.c | 6 +++---
|
|
||||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -1167,10 +1167,10 @@ static int bgmac_poll(struct napi_struct
|
|
||||||
bgmac->int_status = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (handled < weight)
|
|
||||||
+ if (handled < weight) {
|
|
||||||
napi_complete(napi);
|
|
||||||
-
|
|
||||||
- bgmac_chip_intrs_on(bgmac);
|
|
||||||
+ bgmac_chip_intrs_on(bgmac);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
return handled;
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
From 8edfe3b6fad28da191c8fa15e4e0d8f7335a0091 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Peter Senna Tschudin <peter.senna@gmail.com>
|
|
||||||
Date: Sat, 7 Mar 2015 12:10:26 +0100
|
|
||||||
Subject: [PATCH] bgmac: Clean warning messages
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
On my test environment the throughput of a file transfer drops
|
|
||||||
from 4.4MBps to 116KBps due the number of repeated warning
|
|
||||||
messages. This patch removes the warning messages as DMA works
|
|
||||||
correctly with addresses using 0xC0000000 bits.
|
|
||||||
|
|
||||||
Signed-off-by: Peter Senna Tschudin <peter.senna@gmail.com>
|
|
||||||
Acked-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
drivers/net/ethernet/broadcom/bgmac.c | 7 -------
|
|
||||||
1 file changed, 7 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -302,9 +302,6 @@ static int bgmac_dma_rx_skb_for_slot(str
|
|
||||||
slot->skb = skb;
|
|
||||||
slot->dma_addr = dma_addr;
|
|
||||||
|
|
||||||
- if (slot->dma_addr & 0xC0000000)
|
|
||||||
- bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
|
|
||||||
-
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -505,8 +502,6 @@ static int bgmac_dma_alloc(struct bgmac
|
|
||||||
ring->mmio_base);
|
|
||||||
goto err_dma_free;
|
|
||||||
}
|
|
||||||
- if (ring->dma_base & 0xC0000000)
|
|
||||||
- bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
|
|
||||||
|
|
||||||
ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
|
|
||||||
BGMAC_DMA_RING_TX);
|
|
||||||
@@ -536,8 +531,6 @@ static int bgmac_dma_alloc(struct bgmac
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto err_dma_free;
|
|
||||||
}
|
|
||||||
- if (ring->dma_base & 0xC0000000)
|
|
||||||
- bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
|
|
||||||
|
|
||||||
ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
|
|
||||||
BGMAC_DMA_RING_RX);
|
|
@ -1,76 +0,0 @@
|
|||||||
From c25b23b8a387e7d31f7a74af8e37b61e9e6ebb21 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Fri, 20 Mar 2015 23:14:31 +0100
|
|
||||||
Subject: [PATCH] bgmac: register fixed PHY for ARM BCM470X / BCM5301X chipsets
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
On ARM SoCs with bgmac Ethernet hardware we don't have any normal PHY.
|
|
||||||
There is always a switch attached but it's not even controlled over MDIO
|
|
||||||
like in case of MIPS devices.
|
|
||||||
We need a fixed PHY to be able to send/receive packets from the switch.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
drivers/net/ethernet/broadcom/bgmac.c | 34 ++++++++++++++++++++++++++++++++++
|
|
||||||
1 file changed, 34 insertions(+)
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -14,6 +14,7 @@
|
|
||||||
#include <linux/etherdevice.h>
|
|
||||||
#include <linux/mii.h>
|
|
||||||
#include <linux/phy.h>
|
|
||||||
+#include <linux/phy_fixed.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/dma-mapping.h>
|
|
||||||
#include <bcm47xx_nvram.h>
|
|
||||||
@@ -1330,13 +1331,46 @@ static void bgmac_adjust_link(struct net
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int bgmac_fixed_phy_register(struct bgmac *bgmac)
|
|
||||||
+{
|
|
||||||
+ struct fixed_phy_status fphy_status = {
|
|
||||||
+ .link = 1,
|
|
||||||
+ .speed = SPEED_1000,
|
|
||||||
+ .duplex = DUPLEX_FULL,
|
|
||||||
+ };
|
|
||||||
+ struct phy_device *phy_dev;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
|
|
||||||
+ if (!phy_dev || IS_ERR(phy_dev)) {
|
|
||||||
+ bgmac_err(bgmac, "Failed to register fixed PHY device\n");
|
|
||||||
+ return -ENODEV;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
|
|
||||||
+ PHY_INTERFACE_MODE_MII);
|
|
||||||
+ if (err) {
|
|
||||||
+ bgmac_err(bgmac, "Connecting PHY failed\n");
|
|
||||||
+ return err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ bgmac->phy_dev = phy_dev;
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int bgmac_mii_register(struct bgmac *bgmac)
|
|
||||||
{
|
|
||||||
+ struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
|
|
||||||
struct mii_bus *mii_bus;
|
|
||||||
struct phy_device *phy_dev;
|
|
||||||
char bus_id[MII_BUS_ID_SIZE + 3];
|
|
||||||
int i, err = 0;
|
|
||||||
|
|
||||||
+ if (ci->id == BCMA_CHIP_ID_BCM4707 ||
|
|
||||||
+ ci->id == BCMA_CHIP_ID_BCM53018)
|
|
||||||
+ return bgmac_fixed_phy_register(bgmac);
|
|
||||||
+
|
|
||||||
mii_bus = mdiobus_alloc();
|
|
||||||
if (!mii_bus)
|
|
||||||
return -ENOMEM;
|
|
@ -1,28 +0,0 @@
|
|||||||
From fc300dc3733fdc328e6e10c7b8379b60c26cd648 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Fri, 20 Mar 2015 23:14:32 +0100
|
|
||||||
Subject: [PATCH] bgmac: allow enabling on ARCH_BCM_5301X
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
Home routers based on ARM SoCs like BCM4708 also have bcma bus with core
|
|
||||||
supported by bgmac.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
drivers/net/ethernet/broadcom/Kconfig | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/Kconfig
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/Kconfig
|
|
||||||
@@ -143,7 +143,7 @@ config BNX2X_SRIOV
|
|
||||||
|
|
||||||
config BGMAC
|
|
||||||
tristate "BCMA bus GBit core support"
|
|
||||||
- depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
|
|
||||||
+ depends on BCMA_HOST_SOC && HAS_DMA && (BCM47XX || ARCH_BCM_5301X)
|
|
||||||
select PHYLIB
|
|
||||||
---help---
|
|
||||||
This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
|
|
@ -1,30 +0,0 @@
|
|||||||
From 37e9a6904520b525b542ecd67201164d06fdb95a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Mark Salter <msalter@redhat.com>
|
|
||||||
Date: Thu, 11 Dec 2014 23:03:26 -0500
|
|
||||||
Subject: [PATCH] net: phy: export fixed_phy_register()
|
|
||||||
|
|
||||||
When building the bcmgenet driver as module, I get:
|
|
||||||
|
|
||||||
ERROR: "fixed_phy_register" [drivers/net/ethernet/broadcom/genet/genet.ko] undefined!
|
|
||||||
|
|
||||||
commit b0ba512e225d72 ("net: bcmgenet: enable driver to work without device
|
|
||||||
tree") which added a call to fixed_phy_register. But fixed_phy_register
|
|
||||||
needs to be exported if used from a module.
|
|
||||||
|
|
||||||
Signed-off-by: Mark Salter <msalter@redhat.com>
|
|
||||||
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
drivers/net/phy/fixed.c | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
--- a/drivers/net/phy/fixed.c
|
|
||||||
+++ b/drivers/net/phy/fixed.c
|
|
||||||
@@ -274,6 +274,7 @@ struct phy_device *fixed_phy_register(un
|
|
||||||
|
|
||||||
return phy;
|
|
||||||
}
|
|
||||||
+EXPORT_SYMBOL_GPL(fixed_phy_register);
|
|
||||||
|
|
||||||
static int __init fixed_mdio_bus_init(void)
|
|
||||||
{
|
|
@ -1,24 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Mon, 23 Mar 2015 02:40:06 +0100
|
|
||||||
Subject: [PATCH] bgmac: fix descriptor frame start/end definitions
|
|
||||||
|
|
||||||
The start-of-frame and end-of-frame bits were accidentally swapped.
|
|
||||||
In the current code it does not make any difference, since they are
|
|
||||||
always used together.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
@@ -345,8 +345,8 @@
|
|
||||||
|
|
||||||
#define BGMAC_DESC_CTL0_EOT 0x10000000 /* End of ring */
|
|
||||||
#define BGMAC_DESC_CTL0_IOC 0x20000000 /* IRQ on complete */
|
|
||||||
-#define BGMAC_DESC_CTL0_SOF 0x40000000 /* Start of frame */
|
|
||||||
-#define BGMAC_DESC_CTL0_EOF 0x80000000 /* End of frame */
|
|
||||||
+#define BGMAC_DESC_CTL0_EOF 0x40000000 /* End of frame */
|
|
||||||
+#define BGMAC_DESC_CTL0_SOF 0x80000000 /* Start of frame */
|
|
||||||
#define BGMAC_DESC_CTL1_LEN 0x00001FFF
|
|
||||||
|
|
||||||
#define BGMAC_PHY_NOREGS 0x1E
|
|
@ -1,189 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Mon, 23 Mar 2015 02:41:25 +0100
|
|
||||||
Subject: [PATCH] bgmac: implement GRO and use build_skb
|
|
||||||
|
|
||||||
This improves performance for routing and local rx
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -276,31 +276,31 @@ static int bgmac_dma_rx_skb_for_slot(str
|
|
||||||
struct bgmac_slot_info *slot)
|
|
||||||
{
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
- struct sk_buff *skb;
|
|
||||||
dma_addr_t dma_addr;
|
|
||||||
struct bgmac_rx_header *rx;
|
|
||||||
+ void *buf;
|
|
||||||
|
|
||||||
/* Alloc skb */
|
|
||||||
- skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE);
|
|
||||||
- if (!skb)
|
|
||||||
+ buf = netdev_alloc_frag(BGMAC_RX_ALLOC_SIZE);
|
|
||||||
+ if (!buf)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* Poison - if everything goes fine, hardware will overwrite it */
|
|
||||||
- rx = (struct bgmac_rx_header *)skb->data;
|
|
||||||
+ rx = buf;
|
|
||||||
rx->len = cpu_to_le16(0xdead);
|
|
||||||
rx->flags = cpu_to_le16(0xbeef);
|
|
||||||
|
|
||||||
/* Map skb for the DMA */
|
|
||||||
- dma_addr = dma_map_single(dma_dev, skb->data,
|
|
||||||
- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
|
||||||
+ dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE,
|
|
||||||
+ DMA_FROM_DEVICE);
|
|
||||||
if (dma_mapping_error(dma_dev, dma_addr)) {
|
|
||||||
bgmac_err(bgmac, "DMA mapping error\n");
|
|
||||||
- dev_kfree_skb(skb);
|
|
||||||
+ put_page(virt_to_head_page(buf));
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the slot */
|
|
||||||
- slot->skb = skb;
|
|
||||||
+ slot->buf = buf;
|
|
||||||
slot->dma_addr = dma_addr;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
@@ -343,8 +343,9 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
while (ring->start != ring->end) {
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
|
||||||
- struct sk_buff *skb = slot->skb;
|
|
||||||
- struct bgmac_rx_header *rx;
|
|
||||||
+ struct bgmac_rx_header *rx = slot->buf;
|
|
||||||
+ struct sk_buff *skb;
|
|
||||||
+ void *buf = slot->buf;
|
|
||||||
u16 len, flags;
|
|
||||||
|
|
||||||
/* Unmap buffer to make it accessible to the CPU */
|
|
||||||
@@ -352,7 +353,6 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
|
||||||
|
|
||||||
/* Get info from the header */
|
|
||||||
- rx = (struct bgmac_rx_header *)skb->data;
|
|
||||||
len = le16_to_cpu(rx->len);
|
|
||||||
flags = le16_to_cpu(rx->flags);
|
|
||||||
|
|
||||||
@@ -393,12 +393,13 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
dma_unmap_single(dma_dev, old_dma_addr,
|
|
||||||
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
|
||||||
|
|
||||||
+ skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
|
|
||||||
skb_put(skb, BGMAC_RX_FRAME_OFFSET + len);
|
|
||||||
skb_pull(skb, BGMAC_RX_FRAME_OFFSET);
|
|
||||||
|
|
||||||
skb_checksum_none_assert(skb);
|
|
||||||
skb->protocol = eth_type_trans(skb, bgmac->net_dev);
|
|
||||||
- netif_receive_skb(skb);
|
|
||||||
+ napi_gro_receive(&bgmac->napi, skb);
|
|
||||||
handled++;
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
@@ -434,12 +435,11 @@ static bool bgmac_dma_unaligned(struct b
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void bgmac_dma_ring_free(struct bgmac *bgmac,
|
|
||||||
- struct bgmac_dma_ring *ring)
|
|
||||||
+static void bgmac_dma_tx_ring_free(struct bgmac *bgmac,
|
|
||||||
+ struct bgmac_dma_ring *ring)
|
|
||||||
{
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
struct bgmac_slot_info *slot;
|
|
||||||
- int size;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ring->num_slots; i++) {
|
|
||||||
@@ -451,23 +451,55 @@ static void bgmac_dma_ring_free(struct b
|
|
||||||
dev_kfree_skb(slot->skb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void bgmac_dma_rx_ring_free(struct bgmac *bgmac,
|
|
||||||
+ struct bgmac_dma_ring *ring)
|
|
||||||
+{
|
|
||||||
+ struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
+ struct bgmac_slot_info *slot;
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < ring->num_slots; i++) {
|
|
||||||
+ slot = &ring->slots[i];
|
|
||||||
+ if (!slot->buf)
|
|
||||||
+ continue;
|
|
||||||
|
|
||||||
- if (ring->cpu_base) {
|
|
||||||
- /* Free ring of descriptors */
|
|
||||||
- size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
|
||||||
- dma_free_coherent(dma_dev, size, ring->cpu_base,
|
|
||||||
- ring->dma_base);
|
|
||||||
+ if (slot->dma_addr)
|
|
||||||
+ dma_unmap_single(dma_dev, slot->dma_addr,
|
|
||||||
+ BGMAC_RX_BUF_SIZE,
|
|
||||||
+ DMA_FROM_DEVICE);
|
|
||||||
+ put_page(virt_to_head_page(slot->buf));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void bgmac_dma_ring_desc_free(struct bgmac *bgmac,
|
|
||||||
+ struct bgmac_dma_ring *ring)
|
|
||||||
+{
|
|
||||||
+ struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
+ int size;
|
|
||||||
+
|
|
||||||
+ if (!ring->cpu_base)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ /* Free ring of descriptors */
|
|
||||||
+ size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
|
||||||
+ dma_free_coherent(dma_dev, size, ring->cpu_base,
|
|
||||||
+ ring->dma_base);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void bgmac_dma_free(struct bgmac *bgmac)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
- for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
|
|
||||||
- bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]);
|
|
||||||
- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
|
|
||||||
- bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]);
|
|
||||||
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
|
|
||||||
+ bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]);
|
|
||||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
|
|
||||||
+ }
|
|
||||||
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
|
||||||
+ bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]);
|
|
||||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bgmac_dma_alloc(struct bgmac *bgmac)
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
@@ -362,6 +362,8 @@
|
|
||||||
#define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
|
|
||||||
#define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */
|
|
||||||
#define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
|
|
||||||
+#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \
|
|
||||||
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
|
||||||
|
|
||||||
#define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */
|
|
||||||
#define BGMAC_BFL_ENETADM 0x0080 /* has ADMtek switch */
|
|
||||||
@@ -383,7 +385,10 @@
|
|
||||||
#define ETHER_MAX_LEN 1518
|
|
||||||
|
|
||||||
struct bgmac_slot_info {
|
|
||||||
- struct sk_buff *skb;
|
|
||||||
+ union {
|
|
||||||
+ struct sk_buff *skb;
|
|
||||||
+ void *buf;
|
|
||||||
+ };
|
|
||||||
dma_addr_t dma_addr;
|
|
||||||
};
|
|
||||||
|
|
@ -1,267 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Mon, 23 Mar 2015 02:42:26 +0100
|
|
||||||
Subject: [PATCH] bgmac: implement scatter/gather support
|
|
||||||
|
|
||||||
Always use software checksumming, since the hardware does not have any
|
|
||||||
checksum offload support.
|
|
||||||
This significantly improves local TCP tx performance.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -115,53 +115,91 @@ static void bgmac_dma_tx_enable(struct b
|
|
||||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void
|
|
||||||
+bgmac_dma_tx_add_buf(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
|
|
||||||
+ int i, int len, u32 ctl0)
|
|
||||||
+{
|
|
||||||
+ struct bgmac_slot_info *slot;
|
|
||||||
+ struct bgmac_dma_desc *dma_desc;
|
|
||||||
+ u32 ctl1;
|
|
||||||
+
|
|
||||||
+ if (i == ring->num_slots - 1)
|
|
||||||
+ ctl0 |= BGMAC_DESC_CTL0_EOT;
|
|
||||||
+
|
|
||||||
+ ctl1 = len & BGMAC_DESC_CTL1_LEN;
|
|
||||||
+
|
|
||||||
+ slot = &ring->slots[i];
|
|
||||||
+ dma_desc = &ring->cpu_base[i];
|
|
||||||
+ dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
|
|
||||||
+ dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
|
|
||||||
+ dma_desc->ctl0 = cpu_to_le32(ctl0);
|
|
||||||
+ dma_desc->ctl1 = cpu_to_le32(ctl1);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
|
|
||||||
struct bgmac_dma_ring *ring,
|
|
||||||
struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
struct net_device *net_dev = bgmac->net_dev;
|
|
||||||
- struct bgmac_dma_desc *dma_desc;
|
|
||||||
- struct bgmac_slot_info *slot;
|
|
||||||
- u32 ctl0, ctl1;
|
|
||||||
+ struct bgmac_slot_info *slot = &ring->slots[ring->end];
|
|
||||||
int free_slots;
|
|
||||||
+ int nr_frags;
|
|
||||||
+ u32 flags;
|
|
||||||
+ int index = ring->end;
|
|
||||||
+ int i;
|
|
||||||
|
|
||||||
if (skb->len > BGMAC_DESC_CTL1_LEN) {
|
|
||||||
bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
|
|
||||||
- goto err_stop_drop;
|
|
||||||
+ goto err_drop;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
|
|
||||||
+ skb_checksum_help(skb);
|
|
||||||
+
|
|
||||||
+ nr_frags = skb_shinfo(skb)->nr_frags;
|
|
||||||
+
|
|
||||||
if (ring->start <= ring->end)
|
|
||||||
free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
|
|
||||||
else
|
|
||||||
free_slots = ring->start - ring->end;
|
|
||||||
- if (free_slots == 1) {
|
|
||||||
+
|
|
||||||
+ if (free_slots <= nr_frags + 1) {
|
|
||||||
bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
|
|
||||||
netif_stop_queue(net_dev);
|
|
||||||
return NETDEV_TX_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
- slot = &ring->slots[ring->end];
|
|
||||||
- slot->skb = skb;
|
|
||||||
- slot->dma_addr = dma_map_single(dma_dev, skb->data, skb->len,
|
|
||||||
+ slot->dma_addr = dma_map_single(dma_dev, skb->data, skb_headlen(skb),
|
|
||||||
DMA_TO_DEVICE);
|
|
||||||
- if (dma_mapping_error(dma_dev, slot->dma_addr)) {
|
|
||||||
- bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
|
|
||||||
- ring->mmio_base);
|
|
||||||
- goto err_stop_drop;
|
|
||||||
- }
|
|
||||||
+ if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr)))
|
|
||||||
+ goto err_dma_head;
|
|
||||||
|
|
||||||
- ctl0 = BGMAC_DESC_CTL0_IOC | BGMAC_DESC_CTL0_SOF | BGMAC_DESC_CTL0_EOF;
|
|
||||||
- if (ring->end == ring->num_slots - 1)
|
|
||||||
- ctl0 |= BGMAC_DESC_CTL0_EOT;
|
|
||||||
- ctl1 = skb->len & BGMAC_DESC_CTL1_LEN;
|
|
||||||
+ flags = BGMAC_DESC_CTL0_SOF;
|
|
||||||
+ if (!nr_frags)
|
|
||||||
+ flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC;
|
|
||||||
+
|
|
||||||
+ bgmac_dma_tx_add_buf(bgmac, ring, index, skb_headlen(skb), flags);
|
|
||||||
+ flags = 0;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < nr_frags; i++) {
|
|
||||||
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
|
|
||||||
+ int len = skb_frag_size(frag);
|
|
||||||
+
|
|
||||||
+ index = (index + 1) % BGMAC_TX_RING_SLOTS;
|
|
||||||
+ slot = &ring->slots[index];
|
|
||||||
+ slot->dma_addr = skb_frag_dma_map(dma_dev, frag, 0,
|
|
||||||
+ len, DMA_TO_DEVICE);
|
|
||||||
+ if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr)))
|
|
||||||
+ goto err_dma;
|
|
||||||
|
|
||||||
- dma_desc = ring->cpu_base;
|
|
||||||
- dma_desc += ring->end;
|
|
||||||
- dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
|
|
||||||
- dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
|
|
||||||
- dma_desc->ctl0 = cpu_to_le32(ctl0);
|
|
||||||
- dma_desc->ctl1 = cpu_to_le32(ctl1);
|
|
||||||
+ if (i == nr_frags - 1)
|
|
||||||
+ flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC;
|
|
||||||
+
|
|
||||||
+ bgmac_dma_tx_add_buf(bgmac, ring, index, len, flags);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ slot->skb = skb;
|
|
||||||
|
|
||||||
netdev_sent_queue(net_dev, skb->len);
|
|
||||||
|
|
||||||
@@ -170,20 +208,35 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
|
||||||
/* Increase ring->end to point empty slot. We tell hardware the first
|
|
||||||
* slot it should *not* read.
|
|
||||||
*/
|
|
||||||
- if (++ring->end >= BGMAC_TX_RING_SLOTS)
|
|
||||||
- ring->end = 0;
|
|
||||||
+ ring->end = (index + 1) % BGMAC_TX_RING_SLOTS;
|
|
||||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
|
|
||||||
ring->index_base +
|
|
||||||
ring->end * sizeof(struct bgmac_dma_desc));
|
|
||||||
|
|
||||||
- /* Always keep one slot free to allow detecting bugged calls. */
|
|
||||||
- if (--free_slots == 1)
|
|
||||||
+ free_slots -= nr_frags + 1;
|
|
||||||
+ if (free_slots < 8)
|
|
||||||
netif_stop_queue(net_dev);
|
|
||||||
|
|
||||||
return NETDEV_TX_OK;
|
|
||||||
|
|
||||||
-err_stop_drop:
|
|
||||||
- netif_stop_queue(net_dev);
|
|
||||||
+err_dma:
|
|
||||||
+ dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb),
|
|
||||||
+ DMA_TO_DEVICE);
|
|
||||||
+
|
|
||||||
+ while (i > 0) {
|
|
||||||
+ int index = (ring->end + i) % BGMAC_TX_RING_SLOTS;
|
|
||||||
+ struct bgmac_slot_info *slot = &ring->slots[index];
|
|
||||||
+ u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1);
|
|
||||||
+ int len = ctl1 & BGMAC_DESC_CTL1_LEN;
|
|
||||||
+
|
|
||||||
+ dma_unmap_page(dma_dev, slot->dma_addr, len, DMA_TO_DEVICE);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+err_dma_head:
|
|
||||||
+ bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
|
|
||||||
+ ring->mmio_base);
|
|
||||||
+
|
|
||||||
+err_drop:
|
|
||||||
dev_kfree_skb(skb);
|
|
||||||
return NETDEV_TX_OK;
|
|
||||||
}
|
|
||||||
@@ -205,32 +258,45 @@ static void bgmac_dma_tx_free(struct bgm
|
|
||||||
|
|
||||||
while (ring->start != empty_slot) {
|
|
||||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
|
||||||
+ u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1);
|
|
||||||
+ int len = ctl1 & BGMAC_DESC_CTL1_LEN;
|
|
||||||
|
|
||||||
- if (slot->skb) {
|
|
||||||
+ if (!slot->dma_addr) {
|
|
||||||
+ bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
|
|
||||||
+ ring->start, ring->end);
|
|
||||||
+ goto next;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (ctl1 & BGMAC_DESC_CTL0_SOF)
|
|
||||||
/* Unmap no longer used buffer */
|
|
||||||
- dma_unmap_single(dma_dev, slot->dma_addr,
|
|
||||||
- slot->skb->len, DMA_TO_DEVICE);
|
|
||||||
- slot->dma_addr = 0;
|
|
||||||
+ dma_unmap_single(dma_dev, slot->dma_addr, len,
|
|
||||||
+ DMA_TO_DEVICE);
|
|
||||||
+ else
|
|
||||||
+ dma_unmap_page(dma_dev, slot->dma_addr, len,
|
|
||||||
+ DMA_TO_DEVICE);
|
|
||||||
|
|
||||||
+ if (slot->skb) {
|
|
||||||
bytes_compl += slot->skb->len;
|
|
||||||
pkts_compl++;
|
|
||||||
|
|
||||||
/* Free memory! :) */
|
|
||||||
dev_kfree_skb(slot->skb);
|
|
||||||
slot->skb = NULL;
|
|
||||||
- } else {
|
|
||||||
- bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
|
|
||||||
- ring->start, ring->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
+next:
|
|
||||||
+ slot->dma_addr = 0;
|
|
||||||
if (++ring->start >= BGMAC_TX_RING_SLOTS)
|
|
||||||
ring->start = 0;
|
|
||||||
freed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (!pkts_compl)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
netdev_completed_queue(bgmac->net_dev, pkts_compl, bytes_compl);
|
|
||||||
|
|
||||||
- if (freed && netif_queue_stopped(bgmac->net_dev))
|
|
||||||
+ if (netif_queue_stopped(bgmac->net_dev))
|
|
||||||
netif_wake_queue(bgmac->net_dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -439,17 +505,25 @@ static void bgmac_dma_tx_ring_free(struc
|
|
||||||
struct bgmac_dma_ring *ring)
|
|
||||||
{
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
+ struct bgmac_dma_desc *dma_desc = ring->cpu_base;
|
|
||||||
struct bgmac_slot_info *slot;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ring->num_slots; i++) {
|
|
||||||
+ int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN;
|
|
||||||
+
|
|
||||||
slot = &ring->slots[i];
|
|
||||||
- if (slot->skb) {
|
|
||||||
- if (slot->dma_addr)
|
|
||||||
- dma_unmap_single(dma_dev, slot->dma_addr,
|
|
||||||
- slot->skb->len, DMA_TO_DEVICE);
|
|
||||||
- dev_kfree_skb(slot->skb);
|
|
||||||
- }
|
|
||||||
+ dev_kfree_skb(slot->skb);
|
|
||||||
+
|
|
||||||
+ if (!slot->dma_addr)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ if (slot->skb)
|
|
||||||
+ dma_unmap_single(dma_dev, slot->dma_addr,
|
|
||||||
+ len, DMA_TO_DEVICE);
|
|
||||||
+ else
|
|
||||||
+ dma_unmap_page(dma_dev, slot->dma_addr,
|
|
||||||
+ len, DMA_TO_DEVICE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1588,6 +1662,10 @@ static int bgmac_probe(struct bcma_devic
|
|
||||||
goto err_dma_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
|
|
||||||
+ net_dev->hw_features = net_dev->features;
|
|
||||||
+ net_dev->vlan_features = net_dev->features;
|
|
||||||
+
|
|
||||||
err = register_netdev(bgmac->net_dev);
|
|
||||||
if (err) {
|
|
||||||
bgmac_err(bgmac, "Cannot register net device\n");
|
|
@ -1,125 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 09:58:56 +0200
|
|
||||||
Subject: [PATCH] bgmac: simplify tx ring index handling
|
|
||||||
|
|
||||||
Keep incrementing ring->start and ring->end instead of pointing it to
|
|
||||||
the actual ring slot entry. This simplifies the calculation of the
|
|
||||||
number of free slots.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -142,11 +142,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
|
||||||
{
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
struct net_device *net_dev = bgmac->net_dev;
|
|
||||||
- struct bgmac_slot_info *slot = &ring->slots[ring->end];
|
|
||||||
- int free_slots;
|
|
||||||
+ int index = ring->end % BGMAC_TX_RING_SLOTS;
|
|
||||||
+ struct bgmac_slot_info *slot = &ring->slots[index];
|
|
||||||
int nr_frags;
|
|
||||||
u32 flags;
|
|
||||||
- int index = ring->end;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (skb->len > BGMAC_DESC_CTL1_LEN) {
|
|
||||||
@@ -159,12 +158,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
|
||||||
|
|
||||||
nr_frags = skb_shinfo(skb)->nr_frags;
|
|
||||||
|
|
||||||
- if (ring->start <= ring->end)
|
|
||||||
- free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
|
|
||||||
- else
|
|
||||||
- free_slots = ring->start - ring->end;
|
|
||||||
-
|
|
||||||
- if (free_slots <= nr_frags + 1) {
|
|
||||||
+ /* ring->end - ring->start will return the number of valid slots,
|
|
||||||
+ * even when ring->end overflows
|
|
||||||
+ */
|
|
||||||
+ if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) {
|
|
||||||
bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
|
|
||||||
netif_stop_queue(net_dev);
|
|
||||||
return NETDEV_TX_BUSY;
|
|
||||||
@@ -200,7 +197,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
|
||||||
}
|
|
||||||
|
|
||||||
slot->skb = skb;
|
|
||||||
-
|
|
||||||
+ ring->end += nr_frags + 1;
|
|
||||||
netdev_sent_queue(net_dev, skb->len);
|
|
||||||
|
|
||||||
wmb();
|
|
||||||
@@ -208,13 +205,12 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
|
||||||
/* Increase ring->end to point empty slot. We tell hardware the first
|
|
||||||
* slot it should *not* read.
|
|
||||||
*/
|
|
||||||
- ring->end = (index + 1) % BGMAC_TX_RING_SLOTS;
|
|
||||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
|
|
||||||
ring->index_base +
|
|
||||||
- ring->end * sizeof(struct bgmac_dma_desc));
|
|
||||||
+ (ring->end % BGMAC_TX_RING_SLOTS) *
|
|
||||||
+ sizeof(struct bgmac_dma_desc));
|
|
||||||
|
|
||||||
- free_slots -= nr_frags + 1;
|
|
||||||
- if (free_slots < 8)
|
|
||||||
+ if (ring->end - ring->start >= BGMAC_TX_RING_SLOTS - 8)
|
|
||||||
netif_stop_queue(net_dev);
|
|
||||||
|
|
||||||
return NETDEV_TX_OK;
|
|
||||||
@@ -256,17 +252,17 @@ static void bgmac_dma_tx_free(struct bgm
|
|
||||||
empty_slot &= BGMAC_DMA_TX_STATDPTR;
|
|
||||||
empty_slot /= sizeof(struct bgmac_dma_desc);
|
|
||||||
|
|
||||||
- while (ring->start != empty_slot) {
|
|
||||||
- struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
|
||||||
- u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1);
|
|
||||||
- int len = ctl1 & BGMAC_DESC_CTL1_LEN;
|
|
||||||
+ while (ring->start != ring->end) {
|
|
||||||
+ int slot_idx = ring->start % BGMAC_TX_RING_SLOTS;
|
|
||||||
+ struct bgmac_slot_info *slot = &ring->slots[slot_idx];
|
|
||||||
+ u32 ctl1;
|
|
||||||
+ int len;
|
|
||||||
|
|
||||||
- if (!slot->dma_addr) {
|
|
||||||
- bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
|
|
||||||
- ring->start, ring->end);
|
|
||||||
- goto next;
|
|
||||||
- }
|
|
||||||
+ if (slot_idx == empty_slot)
|
|
||||||
+ break;
|
|
||||||
|
|
||||||
+ ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1);
|
|
||||||
+ len = ctl1 & BGMAC_DESC_CTL1_LEN;
|
|
||||||
if (ctl1 & BGMAC_DESC_CTL0_SOF)
|
|
||||||
/* Unmap no longer used buffer */
|
|
||||||
dma_unmap_single(dma_dev, slot->dma_addr, len,
|
|
||||||
@@ -284,10 +280,8 @@ static void bgmac_dma_tx_free(struct bgm
|
|
||||||
slot->skb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
-next:
|
|
||||||
slot->dma_addr = 0;
|
|
||||||
- if (++ring->start >= BGMAC_TX_RING_SLOTS)
|
|
||||||
- ring->start = 0;
|
|
||||||
+ ring->start++;
|
|
||||||
freed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
@@ -414,10 +414,10 @@ enum bgmac_dma_ring_type {
|
|
||||||
* empty.
|
|
||||||
*/
|
|
||||||
struct bgmac_dma_ring {
|
|
||||||
- u16 num_slots;
|
|
||||||
- u16 start;
|
|
||||||
- u16 end;
|
|
||||||
+ u32 start;
|
|
||||||
+ u32 end;
|
|
||||||
|
|
||||||
+ u16 num_slots;
|
|
||||||
u16 mmio_base;
|
|
||||||
struct bgmac_dma_desc *cpu_base;
|
|
||||||
dma_addr_t dma_base;
|
|
@ -1,87 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 10:08:04 +0200
|
|
||||||
Subject: [PATCH] bgmac: leave interrupts disabled as long as there is work
|
|
||||||
to do
|
|
||||||
|
|
||||||
Always poll rx and tx during NAPI poll instead of relying on the status
|
|
||||||
of the first interrupt. This prevents bgmac_poll from leaving unfinished
|
|
||||||
work around until the next IRQ.
|
|
||||||
In my tests this makes bridging/routing throughput under heavy load more
|
|
||||||
stable and ensures that no new IRQs arrive as long as bgmac_poll uses up
|
|
||||||
the entire budget.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -1109,8 +1109,6 @@ static void bgmac_chip_reset(struct bgma
|
|
||||||
bgmac_phy_init(bgmac);
|
|
||||||
|
|
||||||
netdev_reset_queue(bgmac->net_dev);
|
|
||||||
-
|
|
||||||
- bgmac->int_status = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bgmac_chip_intrs_on(struct bgmac *bgmac)
|
|
||||||
@@ -1225,14 +1223,13 @@ static irqreturn_t bgmac_interrupt(int i
|
|
||||||
if (!int_status)
|
|
||||||
return IRQ_NONE;
|
|
||||||
|
|
||||||
- /* Ack */
|
|
||||||
- bgmac_write(bgmac, BGMAC_INT_STATUS, int_status);
|
|
||||||
+ int_status &= ~(BGMAC_IS_TX0 | BGMAC_IS_RX);
|
|
||||||
+ if (int_status)
|
|
||||||
+ bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", int_status);
|
|
||||||
|
|
||||||
/* Disable new interrupts until handling existing ones */
|
|
||||||
bgmac_chip_intrs_off(bgmac);
|
|
||||||
|
|
||||||
- bgmac->int_status = int_status;
|
|
||||||
-
|
|
||||||
napi_schedule(&bgmac->napi);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
@@ -1241,25 +1238,17 @@ static irqreturn_t bgmac_interrupt(int i
|
|
||||||
static int bgmac_poll(struct napi_struct *napi, int weight)
|
|
||||||
{
|
|
||||||
struct bgmac *bgmac = container_of(napi, struct bgmac, napi);
|
|
||||||
- struct bgmac_dma_ring *ring;
|
|
||||||
int handled = 0;
|
|
||||||
|
|
||||||
- if (bgmac->int_status & BGMAC_IS_TX0) {
|
|
||||||
- ring = &bgmac->tx_ring[0];
|
|
||||||
- bgmac_dma_tx_free(bgmac, ring);
|
|
||||||
- bgmac->int_status &= ~BGMAC_IS_TX0;
|
|
||||||
- }
|
|
||||||
+ /* Ack */
|
|
||||||
+ bgmac_write(bgmac, BGMAC_INT_STATUS, ~0);
|
|
||||||
|
|
||||||
- if (bgmac->int_status & BGMAC_IS_RX) {
|
|
||||||
- ring = &bgmac->rx_ring[0];
|
|
||||||
- handled += bgmac_dma_rx_read(bgmac, ring, weight);
|
|
||||||
- bgmac->int_status &= ~BGMAC_IS_RX;
|
|
||||||
- }
|
|
||||||
+ bgmac_dma_tx_free(bgmac, &bgmac->tx_ring[0]);
|
|
||||||
+ handled += bgmac_dma_rx_read(bgmac, &bgmac->rx_ring[0], weight);
|
|
||||||
|
|
||||||
- if (bgmac->int_status) {
|
|
||||||
- bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", bgmac->int_status);
|
|
||||||
- bgmac->int_status = 0;
|
|
||||||
- }
|
|
||||||
+ /* Poll again if more events arrived in the meantime */
|
|
||||||
+ if (bgmac_read(bgmac, BGMAC_INT_STATUS) & (BGMAC_IS_TX0 | BGMAC_IS_RX))
|
|
||||||
+ return handled;
|
|
||||||
|
|
||||||
if (handled < weight) {
|
|
||||||
napi_complete(napi);
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
@@ -452,7 +452,6 @@ struct bgmac {
|
|
||||||
|
|
||||||
/* Int */
|
|
||||||
u32 int_mask;
|
|
||||||
- u32 int_status;
|
|
||||||
|
|
||||||
/* Current MAC state */
|
|
||||||
int mac_speed;
|
|
@ -1,66 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 10:13:28 +0200
|
|
||||||
Subject: [PATCH] bgmac: set received skb headroom to NET_SKB_PAD
|
|
||||||
|
|
||||||
A packet buffer offset of 30 bytes is inefficient, because the first 2
|
|
||||||
bytes end up in a different cacheline.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -346,13 +346,13 @@ static int bgmac_dma_rx_skb_for_slot(str
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* Poison - if everything goes fine, hardware will overwrite it */
|
|
||||||
- rx = buf;
|
|
||||||
+ rx = buf + BGMAC_RX_BUF_OFFSET;
|
|
||||||
rx->len = cpu_to_le16(0xdead);
|
|
||||||
rx->flags = cpu_to_le16(0xbeef);
|
|
||||||
|
|
||||||
/* Map skb for the DMA */
|
|
||||||
- dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE,
|
|
||||||
- DMA_FROM_DEVICE);
|
|
||||||
+ dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET,
|
|
||||||
+ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
|
||||||
if (dma_mapping_error(dma_dev, dma_addr)) {
|
|
||||||
bgmac_err(bgmac, "DMA mapping error\n");
|
|
||||||
put_page(virt_to_head_page(buf));
|
|
||||||
@@ -403,7 +403,7 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
while (ring->start != ring->end) {
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
|
||||||
- struct bgmac_rx_header *rx = slot->buf;
|
|
||||||
+ struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
void *buf = slot->buf;
|
|
||||||
u16 len, flags;
|
|
||||||
@@ -454,8 +454,10 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
|
||||||
|
|
||||||
skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
|
|
||||||
- skb_put(skb, BGMAC_RX_FRAME_OFFSET + len);
|
|
||||||
- skb_pull(skb, BGMAC_RX_FRAME_OFFSET);
|
|
||||||
+ skb_put(skb, BGMAC_RX_FRAME_OFFSET +
|
|
||||||
+ BGMAC_RX_BUF_OFFSET + len);
|
|
||||||
+ skb_pull(skb, BGMAC_RX_FRAME_OFFSET +
|
|
||||||
+ BGMAC_RX_BUF_OFFSET);
|
|
||||||
|
|
||||||
skb_checksum_none_assert(skb);
|
|
||||||
skb->protocol = eth_type_trans(skb, bgmac->net_dev);
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
@@ -360,9 +360,11 @@
|
|
||||||
|
|
||||||
#define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */
|
|
||||||
#define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
|
|
||||||
+#define BGMAC_RX_BUF_OFFSET (NET_SKB_PAD + NET_IP_ALIGN - \
|
|
||||||
+ BGMAC_RX_FRAME_OFFSET)
|
|
||||||
#define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */
|
|
||||||
#define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
|
|
||||||
-#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \
|
|
||||||
+#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE + BGMAC_RX_BUF_OFFSET) + \
|
|
||||||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
|
||||||
|
|
||||||
#define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */
|
|
@ -1,130 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 22:23:07 +0200
|
|
||||||
Subject: [PATCH] bgmac: simplify/optimize rx DMA error handling
|
|
||||||
|
|
||||||
Allocate a new buffer before processing the completed one. If allocation
|
|
||||||
fails, reuse the old buffer.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -386,6 +386,19 @@ static void bgmac_dma_rx_setup_desc(stru
|
|
||||||
dma_desc->ctl1 = cpu_to_le32(ctl1);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
|
|
||||||
+ struct bgmac_slot_info *slot)
|
|
||||||
+{
|
|
||||||
+ struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
|
||||||
+
|
|
||||||
+ dma_sync_single_for_cpu(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
|
|
||||||
+ DMA_FROM_DEVICE);
|
|
||||||
+ rx->len = cpu_to_le16(0xdead);
|
|
||||||
+ rx->flags = cpu_to_le16(0xbeef);
|
|
||||||
+ dma_sync_single_for_device(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
|
|
||||||
+ DMA_FROM_DEVICE);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
|
|
||||||
int weight)
|
|
||||||
{
|
|
||||||
@@ -406,53 +419,35 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
void *buf = slot->buf;
|
|
||||||
+ dma_addr_t dma_addr = slot->dma_addr;
|
|
||||||
u16 len, flags;
|
|
||||||
|
|
||||||
- /* Unmap buffer to make it accessible to the CPU */
|
|
||||||
- dma_sync_single_for_cpu(dma_dev, slot->dma_addr,
|
|
||||||
- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
|
||||||
-
|
|
||||||
- /* Get info from the header */
|
|
||||||
- len = le16_to_cpu(rx->len);
|
|
||||||
- flags = le16_to_cpu(rx->flags);
|
|
||||||
-
|
|
||||||
do {
|
|
||||||
- dma_addr_t old_dma_addr = slot->dma_addr;
|
|
||||||
- int err;
|
|
||||||
+ /* Prepare new skb as replacement */
|
|
||||||
+ if (bgmac_dma_rx_skb_for_slot(bgmac, slot)) {
|
|
||||||
+ bgmac_dma_rx_poison_buf(dma_dev, slot);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Unmap buffer to make it accessible to the CPU */
|
|
||||||
+ dma_unmap_single(dma_dev, dma_addr,
|
|
||||||
+ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
|
||||||
+
|
|
||||||
+ /* Get info from the header */
|
|
||||||
+ len = le16_to_cpu(rx->len);
|
|
||||||
+ flags = le16_to_cpu(rx->flags);
|
|
||||||
|
|
||||||
/* Check for poison and drop or pass the packet */
|
|
||||||
if (len == 0xdead && flags == 0xbeef) {
|
|
||||||
bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
|
|
||||||
ring->start);
|
|
||||||
- dma_sync_single_for_device(dma_dev,
|
|
||||||
- slot->dma_addr,
|
|
||||||
- BGMAC_RX_BUF_SIZE,
|
|
||||||
- DMA_FROM_DEVICE);
|
|
||||||
+ put_page(virt_to_head_page(buf));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Omit CRC. */
|
|
||||||
len -= ETH_FCS_LEN;
|
|
||||||
|
|
||||||
- /* Prepare new skb as replacement */
|
|
||||||
- err = bgmac_dma_rx_skb_for_slot(bgmac, slot);
|
|
||||||
- if (err) {
|
|
||||||
- /* Poison the old skb */
|
|
||||||
- rx->len = cpu_to_le16(0xdead);
|
|
||||||
- rx->flags = cpu_to_le16(0xbeef);
|
|
||||||
-
|
|
||||||
- dma_sync_single_for_device(dma_dev,
|
|
||||||
- slot->dma_addr,
|
|
||||||
- BGMAC_RX_BUF_SIZE,
|
|
||||||
- DMA_FROM_DEVICE);
|
|
||||||
- break;
|
|
||||||
- }
|
|
||||||
- bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
|
|
||||||
-
|
|
||||||
- /* Unmap old skb, we'll pass it to the netfif */
|
|
||||||
- dma_unmap_single(dma_dev, old_dma_addr,
|
|
||||||
- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
|
||||||
-
|
|
||||||
skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
|
|
||||||
skb_put(skb, BGMAC_RX_FRAME_OFFSET +
|
|
||||||
BGMAC_RX_BUF_OFFSET + len);
|
|
||||||
@@ -465,6 +460,8 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
handled++;
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
+ bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
|
|
||||||
+
|
|
||||||
if (++ring->start >= BGMAC_RX_RING_SLOTS)
|
|
||||||
ring->start = 0;
|
|
||||||
|
|
||||||
@@ -532,14 +529,14 @@ static void bgmac_dma_rx_ring_free(struc
|
|
||||||
|
|
||||||
for (i = 0; i < ring->num_slots; i++) {
|
|
||||||
slot = &ring->slots[i];
|
|
||||||
- if (!slot->buf)
|
|
||||||
+ if (!slot->dma_addr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
- if (slot->dma_addr)
|
|
||||||
- dma_unmap_single(dma_dev, slot->dma_addr,
|
|
||||||
- BGMAC_RX_BUF_SIZE,
|
|
||||||
- DMA_FROM_DEVICE);
|
|
||||||
+ dma_unmap_single(dma_dev, slot->dma_addr,
|
|
||||||
+ BGMAC_RX_BUF_SIZE,
|
|
||||||
+ DMA_FROM_DEVICE);
|
|
||||||
put_page(virt_to_head_page(slot->buf));
|
|
||||||
+ slot->dma_addr = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 22:28:20 +0200
|
|
||||||
Subject: [PATCH] bgmac: add check for oversized packets
|
|
||||||
|
|
||||||
In very rare cases, the MAC can catch an internal buffer that is bigger
|
|
||||||
than it's supposed to be. Instead of crashing the kernel, simply pass
|
|
||||||
the buffer back to the hardware
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -445,6 +445,13 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (len > BGMAC_RX_ALLOC_SIZE) {
|
|
||||||
+ bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n",
|
|
||||||
+ ring->start);
|
|
||||||
+ put_page(virt_to_head_page(buf));
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* Omit CRC. */
|
|
||||||
len -= ETH_FCS_LEN;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 22:36:16 +0200
|
|
||||||
Subject: [PATCH] bgmac: increase rx ring size from 511 to 512
|
|
||||||
|
|
||||||
Limiting it to 511 looks like a failed attempt at leaving one descriptor
|
|
||||||
empty to allow the hardware to stop processing a buffer that has not
|
|
||||||
been prepared yet. However, this doesn't work because this affects the
|
|
||||||
total ring size as well
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
@@ -356,7 +356,7 @@
|
|
||||||
#define BGMAC_MAX_RX_RINGS 1
|
|
||||||
|
|
||||||
#define BGMAC_TX_RING_SLOTS 128
|
|
||||||
-#define BGMAC_RX_RING_SLOTS 512 - 1 /* Why -1? Well, Broadcom does that... */
|
|
||||||
+#define BGMAC_RX_RING_SLOTS 512
|
|
||||||
|
|
||||||
#define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */
|
|
||||||
#define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
|
|
@ -1,184 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 23:19:32 +0200
|
|
||||||
Subject: [PATCH] bgmac: simplify dma init/cleanup
|
|
||||||
|
|
||||||
Instead of allocating buffers at device init time and initializing
|
|
||||||
descriptors at device open, do both at the same time (during open).
|
|
||||||
Free all buffers when closing the device.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -562,18 +562,26 @@ static void bgmac_dma_ring_desc_free(str
|
|
||||||
ring->dma_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void bgmac_dma_free(struct bgmac *bgmac)
|
|
||||||
+static void bgmac_dma_cleanup(struct bgmac *bgmac)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
- for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
|
|
||||||
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
|
|
||||||
bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]);
|
|
||||||
- bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
|
|
||||||
- }
|
|
||||||
- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
|
|
||||||
bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void bgmac_dma_free(struct bgmac *bgmac)
|
|
||||||
+{
|
|
||||||
+ int i;
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
|
|
||||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
|
|
||||||
bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
|
|
||||||
- }
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bgmac_dma_alloc(struct bgmac *bgmac)
|
|
||||||
@@ -621,8 +629,6 @@ static int bgmac_dma_alloc(struct bgmac
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
|
||||||
- int j;
|
|
||||||
-
|
|
||||||
ring = &bgmac->rx_ring[i];
|
|
||||||
ring->num_slots = BGMAC_RX_RING_SLOTS;
|
|
||||||
ring->mmio_base = ring_base[i];
|
|
||||||
@@ -645,15 +651,6 @@ static int bgmac_dma_alloc(struct bgmac
|
|
||||||
ring->index_base = lower_32_bits(ring->dma_base);
|
|
||||||
else
|
|
||||||
ring->index_base = 0;
|
|
||||||
-
|
|
||||||
- /* Alloc RX slots */
|
|
||||||
- for (j = 0; j < ring->num_slots; j++) {
|
|
||||||
- err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
|
|
||||||
- if (err) {
|
|
||||||
- bgmac_err(bgmac, "Can't allocate skb for slot in RX ring\n");
|
|
||||||
- goto err_dma_free;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
@@ -663,10 +660,10 @@ err_dma_free:
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void bgmac_dma_init(struct bgmac *bgmac)
|
|
||||||
+static int bgmac_dma_init(struct bgmac *bgmac)
|
|
||||||
{
|
|
||||||
struct bgmac_dma_ring *ring;
|
|
||||||
- int i;
|
|
||||||
+ int i, err;
|
|
||||||
|
|
||||||
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
|
|
||||||
ring = &bgmac->tx_ring[i];
|
|
||||||
@@ -698,8 +695,13 @@ static void bgmac_dma_init(struct bgmac
|
|
||||||
if (ring->unaligned)
|
|
||||||
bgmac_dma_rx_enable(bgmac, ring);
|
|
||||||
|
|
||||||
- for (j = 0; j < ring->num_slots; j++)
|
|
||||||
+ for (j = 0; j < ring->num_slots; j++) {
|
|
||||||
+ err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
|
|
||||||
+ if (err)
|
|
||||||
+ goto error;
|
|
||||||
+
|
|
||||||
bgmac_dma_rx_setup_desc(bgmac, ring, j);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
|
|
||||||
ring->index_base +
|
|
||||||
@@ -708,6 +710,12 @@ static void bgmac_dma_init(struct bgmac
|
|
||||||
ring->start = 0;
|
|
||||||
ring->end = 0;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+error:
|
|
||||||
+ bgmac_dma_cleanup(bgmac);
|
|
||||||
+ return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************
|
|
||||||
@@ -1183,11 +1191,8 @@ static void bgmac_enable(struct bgmac *b
|
|
||||||
}
|
|
||||||
|
|
||||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
|
|
||||||
-static void bgmac_chip_init(struct bgmac *bgmac, bool full_init)
|
|
||||||
+static void bgmac_chip_init(struct bgmac *bgmac)
|
|
||||||
{
|
|
||||||
- struct bgmac_dma_ring *ring;
|
|
||||||
- int i;
|
|
||||||
-
|
|
||||||
/* 1 interrupt per received frame */
|
|
||||||
bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
|
|
||||||
|
|
||||||
@@ -1205,16 +1210,7 @@ static void bgmac_chip_init(struct bgmac
|
|
||||||
|
|
||||||
bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN);
|
|
||||||
|
|
||||||
- if (full_init) {
|
|
||||||
- bgmac_dma_init(bgmac);
|
|
||||||
- if (1) /* FIXME: is there any case we don't want IRQs? */
|
|
||||||
- bgmac_chip_intrs_on(bgmac);
|
|
||||||
- } else {
|
|
||||||
- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
|
||||||
- ring = &bgmac->rx_ring[i];
|
|
||||||
- bgmac_dma_rx_enable(bgmac, ring);
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
+ bgmac_chip_intrs_on(bgmac);
|
|
||||||
|
|
||||||
bgmac_enable(bgmac);
|
|
||||||
}
|
|
||||||
@@ -1274,23 +1270,27 @@ static int bgmac_open(struct net_device
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
bgmac_chip_reset(bgmac);
|
|
||||||
+
|
|
||||||
+ err = bgmac_dma_init(bgmac);
|
|
||||||
+ if (err)
|
|
||||||
+ return err;
|
|
||||||
+
|
|
||||||
/* Specs say about reclaiming rings here, but we do that in DMA init */
|
|
||||||
- bgmac_chip_init(bgmac, true);
|
|
||||||
+ bgmac_chip_init(bgmac);
|
|
||||||
|
|
||||||
err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
|
|
||||||
KBUILD_MODNAME, net_dev);
|
|
||||||
if (err < 0) {
|
|
||||||
bgmac_err(bgmac, "IRQ request error: %d!\n", err);
|
|
||||||
- goto err_out;
|
|
||||||
+ bgmac_dma_cleanup(bgmac);
|
|
||||||
+ return err;
|
|
||||||
}
|
|
||||||
napi_enable(&bgmac->napi);
|
|
||||||
|
|
||||||
phy_start(bgmac->phy_dev);
|
|
||||||
|
|
||||||
netif_carrier_on(net_dev);
|
|
||||||
-
|
|
||||||
-err_out:
|
|
||||||
- return err;
|
|
||||||
+ return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bgmac_stop(struct net_device *net_dev)
|
|
||||||
@@ -1306,6 +1306,7 @@ static int bgmac_stop(struct net_device
|
|
||||||
free_irq(bgmac->core->irq, net_dev);
|
|
||||||
|
|
||||||
bgmac_chip_reset(bgmac);
|
|
||||||
+ bgmac_dma_cleanup(bgmac);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 11:59:47 +0200
|
|
||||||
Subject: [PATCH] bgmac: fix DMA rx corruption
|
|
||||||
|
|
||||||
The driver needs to inform the hardware about the first invalid (not yet
|
|
||||||
filled) rx slot, by writing its DMA descriptor pointer offset to the
|
|
||||||
BGMAC_DMA_RX_INDEX register.
|
|
||||||
|
|
||||||
This register was set to a value exceeding the rx ring size, effectively
|
|
||||||
allowing the hardware constant access to the full ring, regardless of
|
|
||||||
which slots are initialized.
|
|
||||||
|
|
||||||
To fix this issue, always mark the last filled rx slot as invalid.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -366,6 +366,16 @@ static int bgmac_dma_rx_skb_for_slot(str
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void bgmac_dma_rx_update_index(struct bgmac *bgmac,
|
|
||||||
+ struct bgmac_dma_ring *ring)
|
|
||||||
+{
|
|
||||||
+ wmb();
|
|
||||||
+
|
|
||||||
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
|
|
||||||
+ ring->index_base +
|
|
||||||
+ ring->end * sizeof(struct bgmac_dma_desc));
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac,
|
|
||||||
struct bgmac_dma_ring *ring, int desc_idx)
|
|
||||||
{
|
|
||||||
@@ -384,6 +394,8 @@ static void bgmac_dma_rx_setup_desc(stru
|
|
||||||
dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[desc_idx].dma_addr));
|
|
||||||
dma_desc->ctl0 = cpu_to_le32(ctl0);
|
|
||||||
dma_desc->ctl1 = cpu_to_le32(ctl1);
|
|
||||||
+
|
|
||||||
+ ring->end = desc_idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
|
|
||||||
@@ -411,9 +423,7 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
end_slot &= BGMAC_DMA_RX_STATDPTR;
|
|
||||||
end_slot /= sizeof(struct bgmac_dma_desc);
|
|
||||||
|
|
||||||
- ring->end = end_slot;
|
|
||||||
-
|
|
||||||
- while (ring->start != ring->end) {
|
|
||||||
+ while (ring->start != end_slot) {
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
|
||||||
struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
|
||||||
@@ -476,6 +486,8 @@ static int bgmac_dma_rx_read(struct bgma
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ bgmac_dma_rx_update_index(bgmac, ring);
|
|
||||||
+
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -695,6 +707,8 @@ static int bgmac_dma_init(struct bgmac *
|
|
||||||
if (ring->unaligned)
|
|
||||||
bgmac_dma_rx_enable(bgmac, ring);
|
|
||||||
|
|
||||||
+ ring->start = 0;
|
|
||||||
+ ring->end = 0;
|
|
||||||
for (j = 0; j < ring->num_slots; j++) {
|
|
||||||
err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
|
|
||||||
if (err)
|
|
||||||
@@ -703,12 +717,7 @@ static int bgmac_dma_init(struct bgmac *
|
|
||||||
bgmac_dma_rx_setup_desc(bgmac, ring, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
- bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
|
|
||||||
- ring->index_base +
|
|
||||||
- ring->num_slots * sizeof(struct bgmac_dma_desc));
|
|
||||||
-
|
|
||||||
- ring->start = 0;
|
|
||||||
- ring->end = 0;
|
|
||||||
+ bgmac_dma_rx_update_index(bgmac, ring);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
@ -1,132 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 12 Apr 2015 23:28:38 +0200
|
|
||||||
Subject: [PATCH] bgmac: drop ring->num_slots
|
|
||||||
|
|
||||||
The ring size is always known at compile time, so make the code a bit
|
|
||||||
more efficient
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -123,7 +123,7 @@ bgmac_dma_tx_add_buf(struct bgmac *bgmac
|
|
||||||
struct bgmac_dma_desc *dma_desc;
|
|
||||||
u32 ctl1;
|
|
||||||
|
|
||||||
- if (i == ring->num_slots - 1)
|
|
||||||
+ if (i == BGMAC_TX_RING_SLOTS - 1)
|
|
||||||
ctl0 |= BGMAC_DESC_CTL0_EOT;
|
|
||||||
|
|
||||||
ctl1 = len & BGMAC_DESC_CTL1_LEN;
|
|
||||||
@@ -382,7 +382,7 @@ static void bgmac_dma_rx_setup_desc(stru
|
|
||||||
struct bgmac_dma_desc *dma_desc = ring->cpu_base + desc_idx;
|
|
||||||
u32 ctl0 = 0, ctl1 = 0;
|
|
||||||
|
|
||||||
- if (desc_idx == ring->num_slots - 1)
|
|
||||||
+ if (desc_idx == BGMAC_RX_RING_SLOTS - 1)
|
|
||||||
ctl0 |= BGMAC_DESC_CTL0_EOT;
|
|
||||||
ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN;
|
|
||||||
/* Is there any BGMAC device that requires extension? */
|
|
||||||
@@ -521,7 +521,7 @@ static void bgmac_dma_tx_ring_free(struc
|
|
||||||
struct bgmac_slot_info *slot;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
- for (i = 0; i < ring->num_slots; i++) {
|
|
||||||
+ for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) {
|
|
||||||
int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN;
|
|
||||||
|
|
||||||
slot = &ring->slots[i];
|
|
||||||
@@ -546,7 +546,7 @@ static void bgmac_dma_rx_ring_free(struc
|
|
||||||
struct bgmac_slot_info *slot;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
- for (i = 0; i < ring->num_slots; i++) {
|
|
||||||
+ for (i = 0; i < BGMAC_RX_RING_SLOTS; i++) {
|
|
||||||
slot = &ring->slots[i];
|
|
||||||
if (!slot->dma_addr)
|
|
||||||
continue;
|
|
||||||
@@ -560,7 +560,8 @@ static void bgmac_dma_rx_ring_free(struc
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bgmac_dma_ring_desc_free(struct bgmac *bgmac,
|
|
||||||
- struct bgmac_dma_ring *ring)
|
|
||||||
+ struct bgmac_dma_ring *ring,
|
|
||||||
+ int num_slots)
|
|
||||||
{
|
|
||||||
struct device *dma_dev = bgmac->core->dma_dev;
|
|
||||||
int size;
|
|
||||||
@@ -569,7 +570,7 @@ static void bgmac_dma_ring_desc_free(str
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Free ring of descriptors */
|
|
||||||
- size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
|
||||||
+ size = num_slots * sizeof(struct bgmac_dma_desc);
|
|
||||||
dma_free_coherent(dma_dev, size, ring->cpu_base,
|
|
||||||
ring->dma_base);
|
|
||||||
}
|
|
||||||
@@ -590,10 +591,12 @@ static void bgmac_dma_free(struct bgmac
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
|
|
||||||
- bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
|
|
||||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i],
|
|
||||||
+ BGMAC_TX_RING_SLOTS);
|
|
||||||
|
|
||||||
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
|
|
||||||
- bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
|
|
||||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i],
|
|
||||||
+ BGMAC_RX_RING_SLOTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bgmac_dma_alloc(struct bgmac *bgmac)
|
|
||||||
@@ -616,11 +619,10 @@ static int bgmac_dma_alloc(struct bgmac
|
|
||||||
|
|
||||||
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
|
|
||||||
ring = &bgmac->tx_ring[i];
|
|
||||||
- ring->num_slots = BGMAC_TX_RING_SLOTS;
|
|
||||||
ring->mmio_base = ring_base[i];
|
|
||||||
|
|
||||||
/* Alloc ring of descriptors */
|
|
||||||
- size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
|
||||||
+ size = BGMAC_TX_RING_SLOTS * sizeof(struct bgmac_dma_desc);
|
|
||||||
ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
|
|
||||||
&ring->dma_base,
|
|
||||||
GFP_KERNEL);
|
|
||||||
@@ -642,11 +644,10 @@ static int bgmac_dma_alloc(struct bgmac
|
|
||||||
|
|
||||||
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
|
||||||
ring = &bgmac->rx_ring[i];
|
|
||||||
- ring->num_slots = BGMAC_RX_RING_SLOTS;
|
|
||||||
ring->mmio_base = ring_base[i];
|
|
||||||
|
|
||||||
/* Alloc ring of descriptors */
|
|
||||||
- size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
|
||||||
+ size = BGMAC_RX_RING_SLOTS * sizeof(struct bgmac_dma_desc);
|
|
||||||
ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
|
|
||||||
&ring->dma_base,
|
|
||||||
GFP_KERNEL);
|
|
||||||
@@ -709,7 +710,7 @@ static int bgmac_dma_init(struct bgmac *
|
|
||||||
|
|
||||||
ring->start = 0;
|
|
||||||
ring->end = 0;
|
|
||||||
- for (j = 0; j < ring->num_slots; j++) {
|
|
||||||
+ for (j = 0; j < BGMAC_RX_RING_SLOTS; j++) {
|
|
||||||
err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
|
|
||||||
if (err)
|
|
||||||
goto error;
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
@@ -419,11 +419,10 @@ struct bgmac_dma_ring {
|
|
||||||
u32 start;
|
|
||||||
u32 end;
|
|
||||||
|
|
||||||
- u16 num_slots;
|
|
||||||
- u16 mmio_base;
|
|
||||||
struct bgmac_dma_desc *cpu_base;
|
|
||||||
dma_addr_t dma_base;
|
|
||||||
u32 index_base; /* Used for unaligned rings only, otherwise 0 */
|
|
||||||
+ u16 mmio_base;
|
|
||||||
bool unaligned;
|
|
||||||
|
|
||||||
struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS];
|
|
@ -1,31 +0,0 @@
|
|||||||
From b4dfd8e92956b396d3438212bc9a0be6267b8b34 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Tue, 12 Apr 2016 13:30:45 +0200
|
|
||||||
Subject: [PATCH] bgmac: reset & enable Ethernet core before using it
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
This fixes Ethernet on D-Link DIR-885L with BCM47094 SoC. Felix reported
|
|
||||||
similar fix was needed for his BCM4709 device (Buffalo WXR-1900DHP?).
|
|
||||||
I tested this for regressions on BCM4706, BCM4708A0 and BCM47081A0.
|
|
||||||
|
|
||||||
Cc: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
|
||||||
@@ -1569,6 +1569,11 @@ static int bgmac_probe(struct bcma_devic
|
|
||||||
*/
|
|
||||||
bcma_core_enable(core, 0);
|
|
||||||
|
|
||||||
+ /* This (reset &) enable is not preset in specs or reference driver but
|
|
||||||
+ * Broadcom does it in arch PCI code when enabling fake PCI device.
|
|
||||||
+ */
|
|
||||||
+ bcma_core_enable(core, 0);
|
|
||||||
+
|
|
||||||
/* Allocation and references */
|
|
||||||
net_dev = alloc_etherdev(sizeof(*bgmac));
|
|
||||||
if (!net_dev)
|
|
@ -1,34 +0,0 @@
|
|||||||
From c02bc350f9dbce7d637c394a6e1c4d29dc5b28b2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Tue, 12 Apr 2016 18:27:29 +0200
|
|
||||||
Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0. This mainly
|
|
||||||
fixes support for BCM4708A0KF SoCs with Ethernet core rev 5 (it means
|
|
||||||
only some devices as most of BCM4708A0KF-s got core rev 4).
|
|
||||||
This was tested for regressions on BCM47094 which doesn't seem to care
|
|
||||||
which bit gets used.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
|
||||||
@@ -198,9 +198,9 @@
|
|
||||||
#define BGMAC_CMDCFG_TAI 0x00000200
|
|
||||||
#define BGMAC_CMDCFG_HD 0x00000400 /* Set if in half duplex mode */
|
|
||||||
#define BGMAC_CMDCFG_HD_SHIFT 10
|
|
||||||
-#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for other revs */
|
|
||||||
-#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, only for core rev 4 */
|
|
||||||
-#define BGMAC_CMDCFG_SR(rev) ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
|
|
||||||
+#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */
|
|
||||||
+#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */
|
|
||||||
+#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
|
|
||||||
#define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */
|
|
||||||
#define BGMAC_CMDCFG_AE 0x00400000
|
|
||||||
#define BGMAC_CMDCFG_CFE 0x00800000
|
|
@ -1,46 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Tue, 2 Dec 2014 10:58:21 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Fix /proc/net/fib_trie when
|
|
||||||
CONFIG_IP_MULTIPLE_TABLES is not defined
|
|
||||||
|
|
||||||
In recent testing I had disabled CONFIG_IP_MULTIPLE_TABLES and as a result
|
|
||||||
when I ran "cat /proc/net/fib_trie" the main trie was displayed multiple
|
|
||||||
times. I found that the problem line of code was in the function
|
|
||||||
fib_trie_seq_next. Specifically the line below caused the indexes to go in
|
|
||||||
the opposite direction of our traversal:
|
|
||||||
|
|
||||||
h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
|
|
||||||
|
|
||||||
This issue was that the RT tables are defined such that RT_TABLE_LOCAL is ID
|
|
||||||
255, while it is located at TABLE_LOCAL_INDEX of 0, and RT_TABLE_MAIN is 254
|
|
||||||
with a TABLE_MAIN_INDEX of 1. This means that the above line will return 1
|
|
||||||
for the local table and 0 for main. The result is that fib_trie_seq_next
|
|
||||||
will return NULL at the end of the local table, fib_trie_seq_start will
|
|
||||||
return the start of the main table, and then fib_trie_seq_next will loop on
|
|
||||||
main forever as h will always return 0.
|
|
||||||
|
|
||||||
The fix for this is to reverse the ordering of the two tables. It has the
|
|
||||||
advantage of making it so that the tables now print in the same order
|
|
||||||
regardless of if multiple tables are enabled or not. In order to make the
|
|
||||||
definition consistent with the multiple tables case I simply masked the to
|
|
||||||
RT_TABLE_XXX values by (FIB_TABLE_HASHSZ - 1). This way the two table
|
|
||||||
layouts should always stay consistent.
|
|
||||||
|
|
||||||
Fixes: 93456b6 ("[IPV4]: Unify access to the routing tables")
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/include/net/ip_fib.h
|
|
||||||
+++ b/include/net/ip_fib.h
|
|
||||||
@@ -201,8 +201,8 @@ void fib_free_table(struct fib_table *tb
|
|
||||||
|
|
||||||
#ifndef CONFIG_IP_MULTIPLE_TABLES
|
|
||||||
|
|
||||||
-#define TABLE_LOCAL_INDEX 0
|
|
||||||
-#define TABLE_MAIN_INDEX 1
|
|
||||||
+#define TABLE_LOCAL_INDEX (RT_TABLE_LOCAL & (FIB_TABLE_HASHSZ - 1))
|
|
||||||
+#define TABLE_MAIN_INDEX (RT_TABLE_MAIN & (FIB_TABLE_HASHSZ - 1))
|
|
||||||
|
|
||||||
static inline struct fib_table *fib_get_table(struct net *net, u32 id)
|
|
||||||
{
|
|
@ -1,72 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 10 Dec 2014 21:49:22 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Fix trie balancing issue if new node pushes down
|
|
||||||
existing node
|
|
||||||
|
|
||||||
This patch addresses an issue with the level compression of the fib_trie.
|
|
||||||
Specifically in the case of adding a new leaf that triggers a new node to
|
|
||||||
be added that takes the place of the old node. The result is a trie where
|
|
||||||
the 1 child tnode is on one side and one leaf is on the other which gives
|
|
||||||
you a very deep trie. Below is the script I used to generate a trie on
|
|
||||||
dummy0 with a 10.X.X.X family of addresses.
|
|
||||||
|
|
||||||
ip link add type dummy
|
|
||||||
ipval=184549374
|
|
||||||
bit=2
|
|
||||||
for i in `seq 1 23`
|
|
||||||
do
|
|
||||||
ifconfig dummy0:$bit $ipval/8
|
|
||||||
ipval=`expr $ipval - $bit`
|
|
||||||
bit=`expr $bit \* 2`
|
|
||||||
done
|
|
||||||
cat /proc/net/fib_triestat
|
|
||||||
|
|
||||||
Running the script before the patch:
|
|
||||||
|
|
||||||
Local:
|
|
||||||
Aver depth: 10.82
|
|
||||||
Max depth: 23
|
|
||||||
Leaves: 29
|
|
||||||
Prefixes: 30
|
|
||||||
Internal nodes: 27
|
|
||||||
1: 26 2: 1
|
|
||||||
Pointers: 56
|
|
||||||
Null ptrs: 1
|
|
||||||
Total size: 5 kB
|
|
||||||
|
|
||||||
After applying the patch and repeating:
|
|
||||||
|
|
||||||
Local:
|
|
||||||
Aver depth: 4.72
|
|
||||||
Max depth: 9
|
|
||||||
Leaves: 29
|
|
||||||
Prefixes: 30
|
|
||||||
Internal nodes: 12
|
|
||||||
1: 3 2: 2 3: 7
|
|
||||||
Pointers: 70
|
|
||||||
Null ptrs: 30
|
|
||||||
Total size: 4 kB
|
|
||||||
|
|
||||||
What this fix does is start the rebalance at the newly created tnode
|
|
||||||
instead of at the parent tnode. This way if there is a gap between the
|
|
||||||
parent and the new node it doesn't prevent the new tnode from being
|
|
||||||
coalesced with any pre-existing nodes that may have been pushed into one
|
|
||||||
of the new nodes child branches.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -1143,8 +1143,9 @@ static struct list_head *fib_insert_node
|
|
||||||
put_child(tp, cindex, (struct rt_trie_node *)tn);
|
|
||||||
} else {
|
|
||||||
rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
|
|
||||||
- tp = tn;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ tp = tn;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tp && tp->pos + tp->bits > 32)
|
|
@ -1,200 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:55:29 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Update usage stats to be percpu instead of
|
|
||||||
global variables
|
|
||||||
|
|
||||||
The trie usage stats were currently being shared by all threads that were
|
|
||||||
calling fib_table_lookup. As a result when multiple threads were
|
|
||||||
performing lookups simultaneously the trie would begin to cache bounce
|
|
||||||
between those threads.
|
|
||||||
|
|
||||||
In order to prevent this I have updated the usage stats to use a set of
|
|
||||||
percpu variables. By doing this we should be able to avoid the cache
|
|
||||||
bouncing and still make use of these stats.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_frontend.c
|
|
||||||
+++ b/net/ipv4/fib_frontend.c
|
|
||||||
@@ -67,7 +67,7 @@ static int __net_init fib4_rules_init(st
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
- kfree(local_table);
|
|
||||||
+ fib_free_table(local_table);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -153,7 +153,7 @@ struct trie_stat {
|
|
||||||
struct trie {
|
|
||||||
struct rt_trie_node __rcu *trie;
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- struct trie_use_stats stats;
|
|
||||||
+ struct trie_use_stats __percpu *stats;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -631,7 +631,7 @@ static struct rt_trie_node *resize(struc
|
|
||||||
if (IS_ERR(tn)) {
|
|
||||||
tn = old_tn;
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- t->stats.resize_node_skipped++;
|
|
||||||
+ this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
@@ -658,7 +658,7 @@ static struct rt_trie_node *resize(struc
|
|
||||||
if (IS_ERR(tn)) {
|
|
||||||
tn = old_tn;
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- t->stats.resize_node_skipped++;
|
|
||||||
+ this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
@@ -1357,7 +1357,7 @@ static int check_leaf(struct fib_table *
|
|
||||||
err = fib_props[fa->fa_type].error;
|
|
||||||
if (err) {
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- t->stats.semantic_match_passed++;
|
|
||||||
+ this_cpu_inc(t->stats->semantic_match_passed);
|
|
||||||
#endif
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
@@ -1372,7 +1372,7 @@ static int check_leaf(struct fib_table *
|
|
||||||
continue;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- t->stats.semantic_match_passed++;
|
|
||||||
+ this_cpu_inc(t->stats->semantic_match_passed);
|
|
||||||
#endif
|
|
||||||
res->prefixlen = li->plen;
|
|
||||||
res->nh_sel = nhsel;
|
|
||||||
@@ -1388,7 +1388,7 @@ static int check_leaf(struct fib_table *
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- t->stats.semantic_match_miss++;
|
|
||||||
+ this_cpu_inc(t->stats->semantic_match_miss);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1399,6 +1399,9 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
struct fib_result *res, int fib_flags)
|
|
||||||
{
|
|
||||||
struct trie *t = (struct trie *) tb->tb_data;
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ struct trie_use_stats __percpu *stats = t->stats;
|
|
||||||
+#endif
|
|
||||||
int ret;
|
|
||||||
struct rt_trie_node *n;
|
|
||||||
struct tnode *pn;
|
|
||||||
@@ -1417,7 +1420,7 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
goto failed;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- t->stats.gets++;
|
|
||||||
+ this_cpu_inc(stats->gets);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Just a leaf? */
|
|
||||||
@@ -1441,7 +1444,7 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
|
|
||||||
if (n == NULL) {
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- t->stats.null_node_hit++;
|
|
||||||
+ this_cpu_inc(stats->null_node_hit);
|
|
||||||
#endif
|
|
||||||
goto backtrace;
|
|
||||||
}
|
|
||||||
@@ -1576,7 +1579,7 @@ backtrace:
|
|
||||||
chopped_off = 0;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- t->stats.backtrack++;
|
|
||||||
+ this_cpu_inc(stats->backtrack);
|
|
||||||
#endif
|
|
||||||
goto backtrace;
|
|
||||||
}
|
|
||||||
@@ -1830,6 +1833,11 @@ int fib_table_flush(struct fib_table *tb
|
|
||||||
|
|
||||||
void fib_free_table(struct fib_table *tb)
|
|
||||||
{
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ struct trie *t = (struct trie *)tb->tb_data;
|
|
||||||
+
|
|
||||||
+ free_percpu(t->stats);
|
|
||||||
+#endif /* CONFIG_IP_FIB_TRIE_STATS */
|
|
||||||
kfree(tb);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1973,7 +1981,14 @@ struct fib_table *fib_trie_table(u32 id)
|
|
||||||
tb->tb_num_default = 0;
|
|
||||||
|
|
||||||
t = (struct trie *) tb->tb_data;
|
|
||||||
- memset(t, 0, sizeof(*t));
|
|
||||||
+ RCU_INIT_POINTER(t->trie, NULL);
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ t->stats = alloc_percpu(struct trie_use_stats);
|
|
||||||
+ if (!t->stats) {
|
|
||||||
+ kfree(tb);
|
|
||||||
+ tb = NULL;
|
|
||||||
+ }
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
return tb;
|
|
||||||
}
|
|
||||||
@@ -2139,18 +2154,31 @@ static void trie_show_stats(struct seq_f
|
|
||||||
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
static void trie_show_usage(struct seq_file *seq,
|
|
||||||
- const struct trie_use_stats *stats)
|
|
||||||
+ const struct trie_use_stats __percpu *stats)
|
|
||||||
{
|
|
||||||
+ struct trie_use_stats s = { 0 };
|
|
||||||
+ int cpu;
|
|
||||||
+
|
|
||||||
+ /* loop through all of the CPUs and gather up the stats */
|
|
||||||
+ for_each_possible_cpu(cpu) {
|
|
||||||
+ const struct trie_use_stats *pcpu = per_cpu_ptr(stats, cpu);
|
|
||||||
+
|
|
||||||
+ s.gets += pcpu->gets;
|
|
||||||
+ s.backtrack += pcpu->backtrack;
|
|
||||||
+ s.semantic_match_passed += pcpu->semantic_match_passed;
|
|
||||||
+ s.semantic_match_miss += pcpu->semantic_match_miss;
|
|
||||||
+ s.null_node_hit += pcpu->null_node_hit;
|
|
||||||
+ s.resize_node_skipped += pcpu->resize_node_skipped;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
seq_printf(seq, "\nCounters:\n---------\n");
|
|
||||||
- seq_printf(seq, "gets = %u\n", stats->gets);
|
|
||||||
- seq_printf(seq, "backtracks = %u\n", stats->backtrack);
|
|
||||||
+ seq_printf(seq, "gets = %u\n", s.gets);
|
|
||||||
+ seq_printf(seq, "backtracks = %u\n", s.backtrack);
|
|
||||||
seq_printf(seq, "semantic match passed = %u\n",
|
|
||||||
- stats->semantic_match_passed);
|
|
||||||
- seq_printf(seq, "semantic match miss = %u\n",
|
|
||||||
- stats->semantic_match_miss);
|
|
||||||
- seq_printf(seq, "null node hit= %u\n", stats->null_node_hit);
|
|
||||||
- seq_printf(seq, "skipped node resize = %u\n\n",
|
|
||||||
- stats->resize_node_skipped);
|
|
||||||
+ s.semantic_match_passed);
|
|
||||||
+ seq_printf(seq, "semantic match miss = %u\n", s.semantic_match_miss);
|
|
||||||
+ seq_printf(seq, "null node hit= %u\n", s.null_node_hit);
|
|
||||||
+ seq_printf(seq, "skipped node resize = %u\n\n", s.resize_node_skipped);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_IP_FIB_TRIE_STATS */
|
|
||||||
|
|
||||||
@@ -2191,7 +2219,7 @@ static int fib_triestat_seq_show(struct
|
|
||||||
trie_collect_stats(t, &stat);
|
|
||||||
trie_show_stats(seq, &stat);
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- trie_show_usage(seq, &t->stats);
|
|
||||||
+ trie_show_usage(seq, t->stats);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,421 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:55:35 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Make leaf and tnode more uniform
|
|
||||||
|
|
||||||
This change makes some fundamental changes to the way leaves and tnodes are
|
|
||||||
constructed. The big differences are:
|
|
||||||
1. Leaves now populate pos and bits indicating their full key size.
|
|
||||||
2. Trie nodes now mask out their lower bits to be consistent with the leaf
|
|
||||||
3. Both structures have been reordered so that rt_trie_node now consisists
|
|
||||||
of a much larger region including the pos, bits, and rcu portions of
|
|
||||||
the tnode structure.
|
|
||||||
|
|
||||||
On 32b systems this will result in the leaf being 4B larger as the pos and
|
|
||||||
bits values were added to a hole created by the key as it was only 4B in
|
|
||||||
length.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -87,24 +87,38 @@
|
|
||||||
|
|
||||||
typedef unsigned int t_key;
|
|
||||||
|
|
||||||
-#define T_TNODE 0
|
|
||||||
-#define T_LEAF 1
|
|
||||||
-#define NODE_TYPE_MASK 0x1UL
|
|
||||||
-#define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK)
|
|
||||||
+#define IS_TNODE(n) ((n)->bits)
|
|
||||||
+#define IS_LEAF(n) (!(n)->bits)
|
|
||||||
|
|
||||||
-#define IS_TNODE(n) (!(n->parent & T_LEAF))
|
|
||||||
-#define IS_LEAF(n) (n->parent & T_LEAF)
|
|
||||||
+struct tnode {
|
|
||||||
+ t_key key;
|
|
||||||
+ unsigned char bits; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
+ unsigned char pos; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
+ struct tnode __rcu *parent;
|
|
||||||
+ union {
|
|
||||||
+ struct rcu_head rcu;
|
|
||||||
+ struct tnode *tnode_free;
|
|
||||||
+ };
|
|
||||||
+ unsigned int full_children; /* KEYLENGTH bits needed */
|
|
||||||
+ unsigned int empty_children; /* KEYLENGTH bits needed */
|
|
||||||
+ struct rt_trie_node __rcu *child[0];
|
|
||||||
+};
|
|
||||||
|
|
||||||
struct rt_trie_node {
|
|
||||||
- unsigned long parent;
|
|
||||||
t_key key;
|
|
||||||
+ unsigned char bits;
|
|
||||||
+ unsigned char pos;
|
|
||||||
+ struct tnode __rcu *parent;
|
|
||||||
+ struct rcu_head rcu;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct leaf {
|
|
||||||
- unsigned long parent;
|
|
||||||
t_key key;
|
|
||||||
- struct hlist_head list;
|
|
||||||
+ unsigned char bits;
|
|
||||||
+ unsigned char pos;
|
|
||||||
+ struct tnode __rcu *parent;
|
|
||||||
struct rcu_head rcu;
|
|
||||||
+ struct hlist_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct leaf_info {
|
|
||||||
@@ -115,20 +129,6 @@ struct leaf_info {
|
|
||||||
struct rcu_head rcu;
|
|
||||||
};
|
|
||||||
|
|
||||||
-struct tnode {
|
|
||||||
- unsigned long parent;
|
|
||||||
- t_key key;
|
|
||||||
- unsigned char pos; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
- unsigned char bits; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
- unsigned int full_children; /* KEYLENGTH bits needed */
|
|
||||||
- unsigned int empty_children; /* KEYLENGTH bits needed */
|
|
||||||
- union {
|
|
||||||
- struct rcu_head rcu;
|
|
||||||
- struct tnode *tnode_free;
|
|
||||||
- };
|
|
||||||
- struct rt_trie_node __rcu *child[0];
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
struct trie_use_stats {
|
|
||||||
unsigned int gets;
|
|
||||||
@@ -176,38 +176,27 @@ static const int sync_pages = 128;
|
|
||||||
static struct kmem_cache *fn_alias_kmem __read_mostly;
|
|
||||||
static struct kmem_cache *trie_leaf_kmem __read_mostly;
|
|
||||||
|
|
||||||
-/*
|
|
||||||
- * caller must hold RTNL
|
|
||||||
- */
|
|
||||||
-static inline struct tnode *node_parent(const struct rt_trie_node *node)
|
|
||||||
-{
|
|
||||||
- unsigned long parent;
|
|
||||||
+/* caller must hold RTNL */
|
|
||||||
+#define node_parent(n) rtnl_dereference((n)->parent)
|
|
||||||
|
|
||||||
- parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held());
|
|
||||||
+/* caller must hold RCU read lock or RTNL */
|
|
||||||
+#define node_parent_rcu(n) rcu_dereference_rtnl((n)->parent)
|
|
||||||
|
|
||||||
- return (struct tnode *)(parent & ~NODE_TYPE_MASK);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-/*
|
|
||||||
- * caller must hold RCU read lock or RTNL
|
|
||||||
- */
|
|
||||||
-static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
|
|
||||||
+/* wrapper for rcu_assign_pointer */
|
|
||||||
+static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
|
|
||||||
{
|
|
||||||
- unsigned long parent;
|
|
||||||
-
|
|
||||||
- parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() ||
|
|
||||||
- lockdep_rtnl_is_held());
|
|
||||||
-
|
|
||||||
- return (struct tnode *)(parent & ~NODE_TYPE_MASK);
|
|
||||||
+ if (node)
|
|
||||||
+ rcu_assign_pointer(node->parent, ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
-/* Same as rcu_assign_pointer
|
|
||||||
- * but that macro() assumes that value is a pointer.
|
|
||||||
+#define NODE_INIT_PARENT(n, p) RCU_INIT_POINTER((n)->parent, p)
|
|
||||||
+
|
|
||||||
+/* This provides us with the number of children in this node, in the case of a
|
|
||||||
+ * leaf this will return 0 meaning none of the children are accessible.
|
|
||||||
*/
|
|
||||||
-static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
|
|
||||||
+static inline int tnode_child_length(const struct tnode *tn)
|
|
||||||
{
|
|
||||||
- smp_wmb();
|
|
||||||
- node->parent = (unsigned long)ptr | NODE_TYPE(node);
|
|
||||||
+ return (1ul << tn->bits) & ~(1ul);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -215,7 +204,7 @@ static inline void node_set_parent(struc
|
|
||||||
*/
|
|
||||||
static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
|
|
||||||
{
|
|
||||||
- BUG_ON(i >= 1U << tn->bits);
|
|
||||||
+ BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
return rtnl_dereference(tn->child[i]);
|
|
||||||
}
|
|
||||||
@@ -225,16 +214,11 @@ static inline struct rt_trie_node *tnode
|
|
||||||
*/
|
|
||||||
static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
|
|
||||||
{
|
|
||||||
- BUG_ON(i >= 1U << tn->bits);
|
|
||||||
+ BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
return rcu_dereference_rtnl(tn->child[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static inline int tnode_child_length(const struct tnode *tn)
|
|
||||||
-{
|
|
||||||
- return 1 << tn->bits;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static inline t_key mask_pfx(t_key k, unsigned int l)
|
|
||||||
{
|
|
||||||
return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l);
|
|
||||||
@@ -336,11 +320,6 @@ static inline int tkey_mismatch(t_key a,
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
-static inline void check_tnode(const struct tnode *tn)
|
|
||||||
-{
|
|
||||||
- WARN_ON(tn && tn->pos+tn->bits > 32);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static const int halve_threshold = 25;
|
|
||||||
static const int inflate_threshold = 50;
|
|
||||||
static const int halve_threshold_root = 15;
|
|
||||||
@@ -426,11 +405,20 @@ static void tnode_free_flush(void)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct leaf *leaf_new(void)
|
|
||||||
+static struct leaf *leaf_new(t_key key)
|
|
||||||
{
|
|
||||||
struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
|
|
||||||
if (l) {
|
|
||||||
- l->parent = T_LEAF;
|
|
||||||
+ l->parent = NULL;
|
|
||||||
+ /* set key and pos to reflect full key value
|
|
||||||
+ * any trailing zeros in the key should be ignored
|
|
||||||
+ * as the nodes are searched
|
|
||||||
+ */
|
|
||||||
+ l->key = key;
|
|
||||||
+ l->pos = KEYLENGTH;
|
|
||||||
+ /* set bits to 0 indicating we are not a tnode */
|
|
||||||
+ l->bits = 0;
|
|
||||||
+
|
|
||||||
INIT_HLIST_HEAD(&l->list);
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
@@ -451,12 +439,16 @@ static struct tnode *tnode_new(t_key key
|
|
||||||
{
|
|
||||||
size_t sz = sizeof(struct tnode) + (sizeof(struct rt_trie_node *) << bits);
|
|
||||||
struct tnode *tn = tnode_alloc(sz);
|
|
||||||
+ unsigned int shift = pos + bits;
|
|
||||||
+
|
|
||||||
+ /* verify bits and pos their msb bits clear and values are valid */
|
|
||||||
+ BUG_ON(!bits || (shift > KEYLENGTH));
|
|
||||||
|
|
||||||
if (tn) {
|
|
||||||
- tn->parent = T_TNODE;
|
|
||||||
+ tn->parent = NULL;
|
|
||||||
tn->pos = pos;
|
|
||||||
tn->bits = bits;
|
|
||||||
- tn->key = key;
|
|
||||||
+ tn->key = mask_pfx(key, pos);
|
|
||||||
tn->full_children = 0;
|
|
||||||
tn->empty_children = 1<<bits;
|
|
||||||
}
|
|
||||||
@@ -473,10 +465,7 @@ static struct tnode *tnode_new(t_key key
|
|
||||||
|
|
||||||
static inline int tnode_full(const struct tnode *tn, const struct rt_trie_node *n)
|
|
||||||
{
|
|
||||||
- if (n == NULL || IS_LEAF(n))
|
|
||||||
- return 0;
|
|
||||||
-
|
|
||||||
- return ((struct tnode *) n)->pos == tn->pos + tn->bits;
|
|
||||||
+ return n && IS_TNODE(n) && (n->pos == (tn->pos + tn->bits));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void put_child(struct tnode *tn, int i,
|
|
||||||
@@ -514,8 +503,7 @@ static void tnode_put_child_reorg(struct
|
|
||||||
else if (!wasfull && isfull)
|
|
||||||
tn->full_children++;
|
|
||||||
|
|
||||||
- if (n)
|
|
||||||
- node_set_parent(n, tn);
|
|
||||||
+ node_set_parent(n, tn);
|
|
||||||
|
|
||||||
rcu_assign_pointer(tn->child[i], n);
|
|
||||||
}
|
|
||||||
@@ -523,7 +511,7 @@ static void tnode_put_child_reorg(struct
|
|
||||||
#define MAX_WORK 10
|
|
||||||
static struct rt_trie_node *resize(struct trie *t, struct tnode *tn)
|
|
||||||
{
|
|
||||||
- int i;
|
|
||||||
+ struct rt_trie_node *n = NULL;
|
|
||||||
struct tnode *old_tn;
|
|
||||||
int inflate_threshold_use;
|
|
||||||
int halve_threshold_use;
|
|
||||||
@@ -536,12 +524,11 @@ static struct rt_trie_node *resize(struc
|
|
||||||
tn, inflate_threshold, halve_threshold);
|
|
||||||
|
|
||||||
/* No children */
|
|
||||||
- if (tn->empty_children == tnode_child_length(tn)) {
|
|
||||||
- tnode_free_safe(tn);
|
|
||||||
- return NULL;
|
|
||||||
- }
|
|
||||||
+ if (tn->empty_children > (tnode_child_length(tn) - 1))
|
|
||||||
+ goto no_children;
|
|
||||||
+
|
|
||||||
/* One child */
|
|
||||||
- if (tn->empty_children == tnode_child_length(tn) - 1)
|
|
||||||
+ if (tn->empty_children == (tnode_child_length(tn) - 1))
|
|
||||||
goto one_child;
|
|
||||||
/*
|
|
||||||
* Double as long as the resulting node has a number of
|
|
||||||
@@ -607,11 +594,9 @@ static struct rt_trie_node *resize(struc
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
- check_tnode(tn);
|
|
||||||
-
|
|
||||||
/* Keep root node larger */
|
|
||||||
|
|
||||||
- if (!node_parent((struct rt_trie_node *)tn)) {
|
|
||||||
+ if (!node_parent(tn)) {
|
|
||||||
inflate_threshold_use = inflate_threshold_root;
|
|
||||||
halve_threshold_use = halve_threshold_root;
|
|
||||||
} else {
|
|
||||||
@@ -637,8 +622,6 @@ static struct rt_trie_node *resize(struc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- check_tnode(tn);
|
|
||||||
-
|
|
||||||
/* Return if at least one inflate is run */
|
|
||||||
if (max_work != MAX_WORK)
|
|
||||||
return (struct rt_trie_node *) tn;
|
|
||||||
@@ -666,21 +649,16 @@ static struct rt_trie_node *resize(struc
|
|
||||||
|
|
||||||
|
|
||||||
/* Only one child remains */
|
|
||||||
- if (tn->empty_children == tnode_child_length(tn) - 1) {
|
|
||||||
+ if (tn->empty_children == (tnode_child_length(tn) - 1)) {
|
|
||||||
+ unsigned long i;
|
|
||||||
one_child:
|
|
||||||
- for (i = 0; i < tnode_child_length(tn); i++) {
|
|
||||||
- struct rt_trie_node *n;
|
|
||||||
-
|
|
||||||
- n = rtnl_dereference(tn->child[i]);
|
|
||||||
- if (!n)
|
|
||||||
- continue;
|
|
||||||
-
|
|
||||||
- /* compress one level */
|
|
||||||
-
|
|
||||||
- node_set_parent(n, NULL);
|
|
||||||
- tnode_free_safe(tn);
|
|
||||||
- return n;
|
|
||||||
- }
|
|
||||||
+ for (i = tnode_child_length(tn); !n && i;)
|
|
||||||
+ n = tnode_get_child(tn, --i);
|
|
||||||
+no_children:
|
|
||||||
+ /* compress one level */
|
|
||||||
+ node_set_parent(n, NULL);
|
|
||||||
+ tnode_free_safe(tn);
|
|
||||||
+ return n;
|
|
||||||
}
|
|
||||||
return (struct rt_trie_node *) tn;
|
|
||||||
}
|
|
||||||
@@ -760,8 +738,7 @@ static struct tnode *inflate(struct trie
|
|
||||||
|
|
||||||
/* A leaf or an internal node with skipped bits */
|
|
||||||
|
|
||||||
- if (IS_LEAF(node) || ((struct tnode *) node)->pos >
|
|
||||||
- tn->pos + tn->bits - 1) {
|
|
||||||
+ if (IS_LEAF(node) || (node->pos > (tn->pos + tn->bits - 1))) {
|
|
||||||
put_child(tn,
|
|
||||||
tkey_extract_bits(node->key, oldtnode->pos, oldtnode->bits + 1),
|
|
||||||
node);
|
|
||||||
@@ -958,11 +935,9 @@ fib_find_node(struct trie *t, u32 key)
|
|
||||||
pos = 0;
|
|
||||||
n = rcu_dereference_rtnl(t->trie);
|
|
||||||
|
|
||||||
- while (n != NULL && NODE_TYPE(n) == T_TNODE) {
|
|
||||||
+ while (n && IS_TNODE(n)) {
|
|
||||||
tn = (struct tnode *) n;
|
|
||||||
|
|
||||||
- check_tnode(tn);
|
|
||||||
-
|
|
||||||
if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
|
|
||||||
pos = tn->pos + tn->bits;
|
|
||||||
n = tnode_get_child_rcu(tn,
|
|
||||||
@@ -988,7 +963,7 @@ static void trie_rebalance(struct trie *
|
|
||||||
|
|
||||||
key = tn->key;
|
|
||||||
|
|
||||||
- while (tn != NULL && (tp = node_parent((struct rt_trie_node *)tn)) != NULL) {
|
|
||||||
+ while (tn != NULL && (tp = node_parent(tn)) != NULL) {
|
|
||||||
cindex = tkey_extract_bits(key, tp->pos, tp->bits);
|
|
||||||
wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
|
|
||||||
tn = (struct tnode *)resize(t, tn);
|
|
||||||
@@ -996,7 +971,7 @@ static void trie_rebalance(struct trie *
|
|
||||||
tnode_put_child_reorg(tp, cindex,
|
|
||||||
(struct rt_trie_node *)tn, wasfull);
|
|
||||||
|
|
||||||
- tp = node_parent((struct rt_trie_node *) tn);
|
|
||||||
+ tp = node_parent(tn);
|
|
||||||
if (!tp)
|
|
||||||
rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
|
|
||||||
|
|
||||||
@@ -1048,11 +1023,9 @@ static struct list_head *fib_insert_node
|
|
||||||
* If it doesn't, we need to replace it with a T_TNODE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
- while (n != NULL && NODE_TYPE(n) == T_TNODE) {
|
|
||||||
+ while (n && IS_TNODE(n)) {
|
|
||||||
tn = (struct tnode *) n;
|
|
||||||
|
|
||||||
- check_tnode(tn);
|
|
||||||
-
|
|
||||||
if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
|
|
||||||
tp = tn;
|
|
||||||
pos = tn->pos + tn->bits;
|
|
||||||
@@ -1087,12 +1060,11 @@ static struct list_head *fib_insert_node
|
|
||||||
insert_leaf_info(&l->list, li);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
- l = leaf_new();
|
|
||||||
+ l = leaf_new(key);
|
|
||||||
|
|
||||||
if (!l)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
- l->key = key;
|
|
||||||
li = leaf_info_new(plen);
|
|
||||||
|
|
||||||
if (!li) {
|
|
||||||
@@ -1569,7 +1541,7 @@ backtrace:
|
|
||||||
if (chopped_off <= pn->bits) {
|
|
||||||
cindex &= ~(1 << (chopped_off-1));
|
|
||||||
} else {
|
|
||||||
- struct tnode *parent = node_parent_rcu((struct rt_trie_node *) pn);
|
|
||||||
+ struct tnode *parent = node_parent_rcu(pn);
|
|
||||||
if (!parent)
|
|
||||||
goto failed;
|
|
||||||
|
|
||||||
@@ -1597,7 +1569,7 @@ EXPORT_SYMBOL_GPL(fib_table_lookup);
|
|
||||||
*/
|
|
||||||
static void trie_leaf_remove(struct trie *t, struct leaf *l)
|
|
||||||
{
|
|
||||||
- struct tnode *tp = node_parent((struct rt_trie_node *) l);
|
|
||||||
+ struct tnode *tp = node_parent(l);
|
|
||||||
|
|
||||||
pr_debug("entering trie_leaf_remove(%p)\n", l);
|
|
||||||
|
|
||||||
@@ -2374,7 +2346,7 @@ static int fib_trie_seq_show(struct seq_
|
|
||||||
|
|
||||||
if (IS_TNODE(n)) {
|
|
||||||
struct tnode *tn = (struct tnode *) n;
|
|
||||||
- __be32 prf = htonl(mask_pfx(tn->key, tn->pos));
|
|
||||||
+ __be32 prf = htonl(tn->key);
|
|
||||||
|
|
||||||
seq_indent(seq, iter->depth-1);
|
|
||||||
seq_printf(seq, " +-- %pI4/%d %d %d %d\n",
|
|
@ -1,209 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:55:41 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Merge tnode_free and leaf_free into node_free
|
|
||||||
|
|
||||||
Both the leaf and the tnode had an rcu_head in them, but they had them in
|
|
||||||
slightly different places. Since we now have them in the same spot and
|
|
||||||
know that any node with bits == 0 is a leaf and the rest are either vmalloc
|
|
||||||
or kmalloc tnodes depending on the value of bits it makes it easy to combine
|
|
||||||
the functions and reduce overhead.
|
|
||||||
|
|
||||||
In addition I have taken advantage of the rcu_head pointer to go ahead and
|
|
||||||
put together a simple linked list instead of using the tnode pointer as
|
|
||||||
this way we can merge either type of structure for freeing.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -95,15 +95,17 @@ struct tnode {
|
|
||||||
unsigned char bits; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
unsigned char pos; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
struct tnode __rcu *parent;
|
|
||||||
- union {
|
|
||||||
- struct rcu_head rcu;
|
|
||||||
- struct tnode *tnode_free;
|
|
||||||
- };
|
|
||||||
+ struct rcu_head rcu;
|
|
||||||
+ /* everything above this comment must be the same as rt_trie_node */
|
|
||||||
unsigned int full_children; /* KEYLENGTH bits needed */
|
|
||||||
unsigned int empty_children; /* KEYLENGTH bits needed */
|
|
||||||
struct rt_trie_node __rcu *child[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
+/* This struct represents the shared bits between tnode and leaf. If any
|
|
||||||
+ * ordering is changed here is must also be updated in tnode and leaf as
|
|
||||||
+ * well.
|
|
||||||
+ */
|
|
||||||
struct rt_trie_node {
|
|
||||||
t_key key;
|
|
||||||
unsigned char bits;
|
|
||||||
@@ -118,6 +120,7 @@ struct leaf {
|
|
||||||
unsigned char pos;
|
|
||||||
struct tnode __rcu *parent;
|
|
||||||
struct rcu_head rcu;
|
|
||||||
+ /* everything above this comment must be the same as rt_trie_node */
|
|
||||||
struct hlist_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -163,7 +166,7 @@ static struct rt_trie_node *resize(struc
|
|
||||||
static struct tnode *inflate(struct trie *t, struct tnode *tn);
|
|
||||||
static struct tnode *halve(struct trie *t, struct tnode *tn);
|
|
||||||
/* tnodes to free after resize(); protected by RTNL */
|
|
||||||
-static struct tnode *tnode_free_head;
|
|
||||||
+static struct callback_head *tnode_free_head;
|
|
||||||
static size_t tnode_free_size;
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -336,17 +339,23 @@ static inline void alias_free_mem_rcu(st
|
|
||||||
call_rcu(&fa->rcu, __alias_free_mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void __leaf_free_rcu(struct rcu_head *head)
|
|
||||||
-{
|
|
||||||
- struct leaf *l = container_of(head, struct leaf, rcu);
|
|
||||||
- kmem_cache_free(trie_leaf_kmem, l);
|
|
||||||
-}
|
|
||||||
+#define TNODE_KMALLOC_MAX \
|
|
||||||
+ ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct rt_trie_node *))
|
|
||||||
|
|
||||||
-static inline void free_leaf(struct leaf *l)
|
|
||||||
+static void __node_free_rcu(struct rcu_head *head)
|
|
||||||
{
|
|
||||||
- call_rcu(&l->rcu, __leaf_free_rcu);
|
|
||||||
+ struct rt_trie_node *n = container_of(head, struct rt_trie_node, rcu);
|
|
||||||
+
|
|
||||||
+ if (IS_LEAF(n))
|
|
||||||
+ kmem_cache_free(trie_leaf_kmem, n);
|
|
||||||
+ else if (n->bits <= TNODE_KMALLOC_MAX)
|
|
||||||
+ kfree(n);
|
|
||||||
+ else
|
|
||||||
+ vfree(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
+#define node_free(n) call_rcu(&n->rcu, __node_free_rcu)
|
|
||||||
+
|
|
||||||
static inline void free_leaf_info(struct leaf_info *leaf)
|
|
||||||
{
|
|
||||||
kfree_rcu(leaf, rcu);
|
|
||||||
@@ -360,43 +369,24 @@ static struct tnode *tnode_alloc(size_t
|
|
||||||
return vzalloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void __tnode_free_rcu(struct rcu_head *head)
|
|
||||||
-{
|
|
||||||
- struct tnode *tn = container_of(head, struct tnode, rcu);
|
|
||||||
- size_t size = sizeof(struct tnode) +
|
|
||||||
- (sizeof(struct rt_trie_node *) << tn->bits);
|
|
||||||
-
|
|
||||||
- if (size <= PAGE_SIZE)
|
|
||||||
- kfree(tn);
|
|
||||||
- else
|
|
||||||
- vfree(tn);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-static inline void tnode_free(struct tnode *tn)
|
|
||||||
-{
|
|
||||||
- if (IS_LEAF(tn))
|
|
||||||
- free_leaf((struct leaf *) tn);
|
|
||||||
- else
|
|
||||||
- call_rcu(&tn->rcu, __tnode_free_rcu);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static void tnode_free_safe(struct tnode *tn)
|
|
||||||
{
|
|
||||||
BUG_ON(IS_LEAF(tn));
|
|
||||||
- tn->tnode_free = tnode_free_head;
|
|
||||||
- tnode_free_head = tn;
|
|
||||||
- tnode_free_size += sizeof(struct tnode) +
|
|
||||||
- (sizeof(struct rt_trie_node *) << tn->bits);
|
|
||||||
+ tn->rcu.next = tnode_free_head;
|
|
||||||
+ tnode_free_head = &tn->rcu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tnode_free_flush(void)
|
|
||||||
{
|
|
||||||
- struct tnode *tn;
|
|
||||||
+ struct callback_head *head;
|
|
||||||
+
|
|
||||||
+ while ((head = tnode_free_head)) {
|
|
||||||
+ struct tnode *tn = container_of(head, struct tnode, rcu);
|
|
||||||
+
|
|
||||||
+ tnode_free_head = head->next;
|
|
||||||
+ tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]);
|
|
||||||
|
|
||||||
- while ((tn = tnode_free_head)) {
|
|
||||||
- tnode_free_head = tn->tnode_free;
|
|
||||||
- tn->tnode_free = NULL;
|
|
||||||
- tnode_free(tn);
|
|
||||||
+ node_free(tn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tnode_free_size >= PAGE_SIZE * sync_pages) {
|
|
||||||
@@ -437,7 +427,7 @@ static struct leaf_info *leaf_info_new(i
|
|
||||||
|
|
||||||
static struct tnode *tnode_new(t_key key, int pos, int bits)
|
|
||||||
{
|
|
||||||
- size_t sz = sizeof(struct tnode) + (sizeof(struct rt_trie_node *) << bits);
|
|
||||||
+ size_t sz = offsetof(struct tnode, child[1 << bits]);
|
|
||||||
struct tnode *tn = tnode_alloc(sz);
|
|
||||||
unsigned int shift = pos + bits;
|
|
||||||
|
|
||||||
@@ -666,15 +656,15 @@ no_children:
|
|
||||||
|
|
||||||
static void tnode_clean_free(struct tnode *tn)
|
|
||||||
{
|
|
||||||
+ struct rt_trie_node *tofree;
|
|
||||||
int i;
|
|
||||||
- struct tnode *tofree;
|
|
||||||
|
|
||||||
for (i = 0; i < tnode_child_length(tn); i++) {
|
|
||||||
- tofree = (struct tnode *)rtnl_dereference(tn->child[i]);
|
|
||||||
+ tofree = rtnl_dereference(tn->child[i]);
|
|
||||||
if (tofree)
|
|
||||||
- tnode_free(tofree);
|
|
||||||
+ node_free(tofree);
|
|
||||||
}
|
|
||||||
- tnode_free(tn);
|
|
||||||
+ node_free(tn);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct tnode *inflate(struct trie *t, struct tnode *tn)
|
|
||||||
@@ -717,7 +707,7 @@ static struct tnode *inflate(struct trie
|
|
||||||
inode->bits - 1);
|
|
||||||
|
|
||||||
if (!right) {
|
|
||||||
- tnode_free(left);
|
|
||||||
+ node_free(left);
|
|
||||||
goto nomem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1068,7 +1058,7 @@ static struct list_head *fib_insert_node
|
|
||||||
li = leaf_info_new(plen);
|
|
||||||
|
|
||||||
if (!li) {
|
|
||||||
- free_leaf(l);
|
|
||||||
+ node_free(l);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1100,7 +1090,7 @@ static struct list_head *fib_insert_node
|
|
||||||
|
|
||||||
if (!tn) {
|
|
||||||
free_leaf_info(li);
|
|
||||||
- free_leaf(l);
|
|
||||||
+ node_free(l);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1580,7 +1570,7 @@ static void trie_leaf_remove(struct trie
|
|
||||||
} else
|
|
||||||
RCU_INIT_POINTER(t->trie, NULL);
|
|
||||||
|
|
||||||
- free_leaf(l);
|
|
||||||
+ node_free(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
@ -1,928 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:55:47 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Merge leaf into tnode
|
|
||||||
|
|
||||||
This change makes it so that leaf and tnode are the same struct. As a
|
|
||||||
result there is no need for rt_trie_node anymore since everyting can be
|
|
||||||
merged into tnode.
|
|
||||||
|
|
||||||
On 32b systems this results in the leaf being 4 bytes larger, however I
|
|
||||||
don't know if that is really an issue as this and an eariler patch that
|
|
||||||
added bits & pos have increased the size from 20 to 28. If I am not
|
|
||||||
mistaken slub/slab allocate on power of 2 sizes so 20 was likely being
|
|
||||||
rounded up to 32 anyway.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -96,32 +96,16 @@ struct tnode {
|
|
||||||
unsigned char pos; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
struct tnode __rcu *parent;
|
|
||||||
struct rcu_head rcu;
|
|
||||||
- /* everything above this comment must be the same as rt_trie_node */
|
|
||||||
- unsigned int full_children; /* KEYLENGTH bits needed */
|
|
||||||
- unsigned int empty_children; /* KEYLENGTH bits needed */
|
|
||||||
- struct rt_trie_node __rcu *child[0];
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
-/* This struct represents the shared bits between tnode and leaf. If any
|
|
||||||
- * ordering is changed here is must also be updated in tnode and leaf as
|
|
||||||
- * well.
|
|
||||||
- */
|
|
||||||
-struct rt_trie_node {
|
|
||||||
- t_key key;
|
|
||||||
- unsigned char bits;
|
|
||||||
- unsigned char pos;
|
|
||||||
- struct tnode __rcu *parent;
|
|
||||||
- struct rcu_head rcu;
|
|
||||||
-};
|
|
||||||
-
|
|
||||||
-struct leaf {
|
|
||||||
- t_key key;
|
|
||||||
- unsigned char bits;
|
|
||||||
- unsigned char pos;
|
|
||||||
- struct tnode __rcu *parent;
|
|
||||||
- struct rcu_head rcu;
|
|
||||||
- /* everything above this comment must be the same as rt_trie_node */
|
|
||||||
- struct hlist_head list;
|
|
||||||
+ union {
|
|
||||||
+ /* The fields in this struct are valid if bits > 0 (TNODE) */
|
|
||||||
+ struct {
|
|
||||||
+ unsigned int full_children; /* KEYLENGTH bits needed */
|
|
||||||
+ unsigned int empty_children; /* KEYLENGTH bits needed */
|
|
||||||
+ struct tnode __rcu *child[0];
|
|
||||||
+ };
|
|
||||||
+ /* This list pointer if valid if bits == 0 (LEAF) */
|
|
||||||
+ struct hlist_head list;
|
|
||||||
+ };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct leaf_info {
|
|
||||||
@@ -154,15 +138,15 @@ struct trie_stat {
|
|
||||||
};
|
|
||||||
|
|
||||||
struct trie {
|
|
||||||
- struct rt_trie_node __rcu *trie;
|
|
||||||
+ struct tnode __rcu *trie;
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
struct trie_use_stats __percpu *stats;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
-static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
|
|
||||||
+static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n,
|
|
||||||
int wasfull);
|
|
||||||
-static struct rt_trie_node *resize(struct trie *t, struct tnode *tn);
|
|
||||||
+static struct tnode *resize(struct trie *t, struct tnode *tn);
|
|
||||||
static struct tnode *inflate(struct trie *t, struct tnode *tn);
|
|
||||||
static struct tnode *halve(struct trie *t, struct tnode *tn);
|
|
||||||
/* tnodes to free after resize(); protected by RTNL */
|
|
||||||
@@ -186,10 +170,10 @@ static struct kmem_cache *trie_leaf_kmem
|
|
||||||
#define node_parent_rcu(n) rcu_dereference_rtnl((n)->parent)
|
|
||||||
|
|
||||||
/* wrapper for rcu_assign_pointer */
|
|
||||||
-static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
|
|
||||||
+static inline void node_set_parent(struct tnode *n, struct tnode *tp)
|
|
||||||
{
|
|
||||||
- if (node)
|
|
||||||
- rcu_assign_pointer(node->parent, ptr);
|
|
||||||
+ if (n)
|
|
||||||
+ rcu_assign_pointer(n->parent, tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NODE_INIT_PARENT(n, p) RCU_INIT_POINTER((n)->parent, p)
|
|
||||||
@@ -205,7 +189,7 @@ static inline int tnode_child_length(con
|
|
||||||
/*
|
|
||||||
* caller must hold RTNL
|
|
||||||
*/
|
|
||||||
-static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i)
|
|
||||||
+static inline struct tnode *tnode_get_child(const struct tnode *tn, unsigned int i)
|
|
||||||
{
|
|
||||||
BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
@@ -215,7 +199,7 @@ static inline struct rt_trie_node *tnode
|
|
||||||
/*
|
|
||||||
* caller must hold RCU read lock or RTNL
|
|
||||||
*/
|
|
||||||
-static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
|
|
||||||
+static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
|
|
||||||
{
|
|
||||||
BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
@@ -340,11 +324,11 @@ static inline void alias_free_mem_rcu(st
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TNODE_KMALLOC_MAX \
|
|
||||||
- ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct rt_trie_node *))
|
|
||||||
+ ilog2((PAGE_SIZE - sizeof(struct tnode)) / sizeof(struct tnode *))
|
|
||||||
|
|
||||||
static void __node_free_rcu(struct rcu_head *head)
|
|
||||||
{
|
|
||||||
- struct rt_trie_node *n = container_of(head, struct rt_trie_node, rcu);
|
|
||||||
+ struct tnode *n = container_of(head, struct tnode, rcu);
|
|
||||||
|
|
||||||
if (IS_LEAF(n))
|
|
||||||
kmem_cache_free(trie_leaf_kmem, n);
|
|
||||||
@@ -395,9 +379,9 @@ static void tnode_free_flush(void)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct leaf *leaf_new(t_key key)
|
|
||||||
+static struct tnode *leaf_new(t_key key)
|
|
||||||
{
|
|
||||||
- struct leaf *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
|
|
||||||
+ struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
|
|
||||||
if (l) {
|
|
||||||
l->parent = NULL;
|
|
||||||
/* set key and pos to reflect full key value
|
|
||||||
@@ -444,7 +428,7 @@ static struct tnode *tnode_new(t_key key
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode),
|
|
||||||
- sizeof(struct rt_trie_node *) << bits);
|
|
||||||
+ sizeof(struct tnode *) << bits);
|
|
||||||
return tn;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -453,13 +437,13 @@ static struct tnode *tnode_new(t_key key
|
|
||||||
* and no bits are skipped. See discussion in dyntree paper p. 6
|
|
||||||
*/
|
|
||||||
|
|
||||||
-static inline int tnode_full(const struct tnode *tn, const struct rt_trie_node *n)
|
|
||||||
+static inline int tnode_full(const struct tnode *tn, const struct tnode *n)
|
|
||||||
{
|
|
||||||
return n && IS_TNODE(n) && (n->pos == (tn->pos + tn->bits));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void put_child(struct tnode *tn, int i,
|
|
||||||
- struct rt_trie_node *n)
|
|
||||||
+ struct tnode *n)
|
|
||||||
{
|
|
||||||
tnode_put_child_reorg(tn, i, n, -1);
|
|
||||||
}
|
|
||||||
@@ -469,10 +453,10 @@ static inline void put_child(struct tnod
|
|
||||||
* Update the value of full_children and empty_children.
|
|
||||||
*/
|
|
||||||
|
|
||||||
-static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n,
|
|
||||||
+static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n,
|
|
||||||
int wasfull)
|
|
||||||
{
|
|
||||||
- struct rt_trie_node *chi = rtnl_dereference(tn->child[i]);
|
|
||||||
+ struct tnode *chi = rtnl_dereference(tn->child[i]);
|
|
||||||
int isfull;
|
|
||||||
|
|
||||||
BUG_ON(i >= 1<<tn->bits);
|
|
||||||
@@ -499,10 +483,9 @@ static void tnode_put_child_reorg(struct
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_WORK 10
|
|
||||||
-static struct rt_trie_node *resize(struct trie *t, struct tnode *tn)
|
|
||||||
+static struct tnode *resize(struct trie *t, struct tnode *tn)
|
|
||||||
{
|
|
||||||
- struct rt_trie_node *n = NULL;
|
|
||||||
- struct tnode *old_tn;
|
|
||||||
+ struct tnode *old_tn, *n = NULL;
|
|
||||||
int inflate_threshold_use;
|
|
||||||
int halve_threshold_use;
|
|
||||||
int max_work;
|
|
||||||
@@ -614,7 +597,7 @@ static struct rt_trie_node *resize(struc
|
|
||||||
|
|
||||||
/* Return if at least one inflate is run */
|
|
||||||
if (max_work != MAX_WORK)
|
|
||||||
- return (struct rt_trie_node *) tn;
|
|
||||||
+ return tn;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Halve as long as the number of empty children in this
|
|
||||||
@@ -650,13 +633,13 @@ no_children:
|
|
||||||
tnode_free_safe(tn);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
- return (struct rt_trie_node *) tn;
|
|
||||||
+ return tn;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void tnode_clean_free(struct tnode *tn)
|
|
||||||
{
|
|
||||||
- struct rt_trie_node *tofree;
|
|
||||||
+ struct tnode *tofree;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < tnode_child_length(tn); i++) {
|
|
||||||
@@ -667,10 +650,10 @@ static void tnode_clean_free(struct tnod
|
|
||||||
node_free(tn);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct tnode *inflate(struct trie *t, struct tnode *tn)
|
|
||||||
+static struct tnode *inflate(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
- struct tnode *oldtnode = tn;
|
|
||||||
- int olen = tnode_child_length(tn);
|
|
||||||
+ int olen = tnode_child_length(oldtnode);
|
|
||||||
+ struct tnode *tn;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
pr_debug("In inflate\n");
|
|
||||||
@@ -690,11 +673,8 @@ static struct tnode *inflate(struct trie
|
|
||||||
for (i = 0; i < olen; i++) {
|
|
||||||
struct tnode *inode;
|
|
||||||
|
|
||||||
- inode = (struct tnode *) tnode_get_child(oldtnode, i);
|
|
||||||
- if (inode &&
|
|
||||||
- IS_TNODE(inode) &&
|
|
||||||
- inode->pos == oldtnode->pos + oldtnode->bits &&
|
|
||||||
- inode->bits > 1) {
|
|
||||||
+ inode = tnode_get_child(oldtnode, i);
|
|
||||||
+ if (tnode_full(oldtnode, inode) && inode->bits > 1) {
|
|
||||||
struct tnode *left, *right;
|
|
||||||
t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos;
|
|
||||||
|
|
||||||
@@ -711,33 +691,29 @@ static struct tnode *inflate(struct trie
|
|
||||||
goto nomem;
|
|
||||||
}
|
|
||||||
|
|
||||||
- put_child(tn, 2*i, (struct rt_trie_node *) left);
|
|
||||||
- put_child(tn, 2*i+1, (struct rt_trie_node *) right);
|
|
||||||
+ put_child(tn, 2*i, left);
|
|
||||||
+ put_child(tn, 2*i+1, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < olen; i++) {
|
|
||||||
- struct tnode *inode;
|
|
||||||
- struct rt_trie_node *node = tnode_get_child(oldtnode, i);
|
|
||||||
+ struct tnode *inode = tnode_get_child(oldtnode, i);
|
|
||||||
struct tnode *left, *right;
|
|
||||||
int size, j;
|
|
||||||
|
|
||||||
/* An empty child */
|
|
||||||
- if (node == NULL)
|
|
||||||
+ if (inode == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* A leaf or an internal node with skipped bits */
|
|
||||||
-
|
|
||||||
- if (IS_LEAF(node) || (node->pos > (tn->pos + tn->bits - 1))) {
|
|
||||||
+ if (!tnode_full(oldtnode, inode)) {
|
|
||||||
put_child(tn,
|
|
||||||
- tkey_extract_bits(node->key, oldtnode->pos, oldtnode->bits + 1),
|
|
||||||
- node);
|
|
||||||
+ tkey_extract_bits(inode->key, tn->pos, tn->bits),
|
|
||||||
+ inode);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* An internal node with two children */
|
|
||||||
- inode = (struct tnode *) node;
|
|
||||||
-
|
|
||||||
if (inode->bits == 1) {
|
|
||||||
put_child(tn, 2*i, rtnl_dereference(inode->child[0]));
|
|
||||||
put_child(tn, 2*i+1, rtnl_dereference(inode->child[1]));
|
|
||||||
@@ -769,12 +745,12 @@ static struct tnode *inflate(struct trie
|
|
||||||
* bit to zero.
|
|
||||||
*/
|
|
||||||
|
|
||||||
- left = (struct tnode *) tnode_get_child(tn, 2*i);
|
|
||||||
+ left = tnode_get_child(tn, 2*i);
|
|
||||||
put_child(tn, 2*i, NULL);
|
|
||||||
|
|
||||||
BUG_ON(!left);
|
|
||||||
|
|
||||||
- right = (struct tnode *) tnode_get_child(tn, 2*i+1);
|
|
||||||
+ right = tnode_get_child(tn, 2*i+1);
|
|
||||||
put_child(tn, 2*i+1, NULL);
|
|
||||||
|
|
||||||
BUG_ON(!right);
|
|
||||||
@@ -796,12 +772,11 @@ nomem:
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct tnode *halve(struct trie *t, struct tnode *tn)
|
|
||||||
+static struct tnode *halve(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
- struct tnode *oldtnode = tn;
|
|
||||||
- struct rt_trie_node *left, *right;
|
|
||||||
+ int olen = tnode_child_length(oldtnode);
|
|
||||||
+ struct tnode *tn, *left, *right;
|
|
||||||
int i;
|
|
||||||
- int olen = tnode_child_length(tn);
|
|
||||||
|
|
||||||
pr_debug("In halve\n");
|
|
||||||
|
|
||||||
@@ -830,7 +805,7 @@ static struct tnode *halve(struct trie *
|
|
||||||
if (!newn)
|
|
||||||
goto nomem;
|
|
||||||
|
|
||||||
- put_child(tn, i/2, (struct rt_trie_node *)newn);
|
|
||||||
+ put_child(tn, i/2, newn);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -855,7 +830,7 @@ static struct tnode *halve(struct trie *
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Two nonempty children */
|
|
||||||
- newBinNode = (struct tnode *) tnode_get_child(tn, i/2);
|
|
||||||
+ newBinNode = tnode_get_child(tn, i/2);
|
|
||||||
put_child(tn, i/2, NULL);
|
|
||||||
put_child(newBinNode, 0, left);
|
|
||||||
put_child(newBinNode, 1, right);
|
|
||||||
@@ -871,7 +846,7 @@ nomem:
|
|
||||||
/* readside must use rcu_read_lock currently dump routines
|
|
||||||
via get_fa_head and dump */
|
|
||||||
|
|
||||||
-static struct leaf_info *find_leaf_info(struct leaf *l, int plen)
|
|
||||||
+static struct leaf_info *find_leaf_info(struct tnode *l, int plen)
|
|
||||||
{
|
|
||||||
struct hlist_head *head = &l->list;
|
|
||||||
struct leaf_info *li;
|
|
||||||
@@ -883,7 +858,7 @@ static struct leaf_info *find_leaf_info(
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static inline struct list_head *get_fa_head(struct leaf *l, int plen)
|
|
||||||
+static inline struct list_head *get_fa_head(struct tnode *l, int plen)
|
|
||||||
{
|
|
||||||
struct leaf_info *li = find_leaf_info(l, plen);
|
|
||||||
|
|
||||||
@@ -915,32 +890,25 @@ static void insert_leaf_info(struct hlis
|
|
||||||
|
|
||||||
/* rcu_read_lock needs to be hold by caller from readside */
|
|
||||||
|
|
||||||
-static struct leaf *
|
|
||||||
-fib_find_node(struct trie *t, u32 key)
|
|
||||||
+static struct tnode *fib_find_node(struct trie *t, u32 key)
|
|
||||||
{
|
|
||||||
- int pos;
|
|
||||||
- struct tnode *tn;
|
|
||||||
- struct rt_trie_node *n;
|
|
||||||
-
|
|
||||||
- pos = 0;
|
|
||||||
- n = rcu_dereference_rtnl(t->trie);
|
|
||||||
+ struct tnode *n = rcu_dereference_rtnl(t->trie);
|
|
||||||
+ int pos = 0;
|
|
||||||
|
|
||||||
while (n && IS_TNODE(n)) {
|
|
||||||
- tn = (struct tnode *) n;
|
|
||||||
-
|
|
||||||
- if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
|
|
||||||
- pos = tn->pos + tn->bits;
|
|
||||||
- n = tnode_get_child_rcu(tn,
|
|
||||||
+ if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
|
|
||||||
+ pos = n->pos + n->bits;
|
|
||||||
+ n = tnode_get_child_rcu(n,
|
|
||||||
tkey_extract_bits(key,
|
|
||||||
- tn->pos,
|
|
||||||
- tn->bits));
|
|
||||||
+ n->pos,
|
|
||||||
+ n->bits));
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Case we have found a leaf. Compare prefixes */
|
|
||||||
|
|
||||||
if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))
|
|
||||||
- return (struct leaf *)n;
|
|
||||||
+ return n;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
@@ -956,14 +924,13 @@ static void trie_rebalance(struct trie *
|
|
||||||
while (tn != NULL && (tp = node_parent(tn)) != NULL) {
|
|
||||||
cindex = tkey_extract_bits(key, tp->pos, tp->bits);
|
|
||||||
wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
|
|
||||||
- tn = (struct tnode *)resize(t, tn);
|
|
||||||
+ tn = resize(t, tn);
|
|
||||||
|
|
||||||
- tnode_put_child_reorg(tp, cindex,
|
|
||||||
- (struct rt_trie_node *)tn, wasfull);
|
|
||||||
+ tnode_put_child_reorg(tp, cindex, tn, wasfull);
|
|
||||||
|
|
||||||
tp = node_parent(tn);
|
|
||||||
if (!tp)
|
|
||||||
- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
|
|
||||||
+ rcu_assign_pointer(t->trie, tn);
|
|
||||||
|
|
||||||
tnode_free_flush();
|
|
||||||
if (!tp)
|
|
||||||
@@ -973,9 +940,9 @@ static void trie_rebalance(struct trie *
|
|
||||||
|
|
||||||
/* Handle last (top) tnode */
|
|
||||||
if (IS_TNODE(tn))
|
|
||||||
- tn = (struct tnode *)resize(t, tn);
|
|
||||||
+ tn = resize(t, tn);
|
|
||||||
|
|
||||||
- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
|
|
||||||
+ rcu_assign_pointer(t->trie, tn);
|
|
||||||
tnode_free_flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -985,8 +952,8 @@ static struct list_head *fib_insert_node
|
|
||||||
{
|
|
||||||
int pos, newpos;
|
|
||||||
struct tnode *tp = NULL, *tn = NULL;
|
|
||||||
- struct rt_trie_node *n;
|
|
||||||
- struct leaf *l;
|
|
||||||
+ struct tnode *n;
|
|
||||||
+ struct tnode *l;
|
|
||||||
int missbit;
|
|
||||||
struct list_head *fa_head = NULL;
|
|
||||||
struct leaf_info *li;
|
|
||||||
@@ -1014,17 +981,15 @@ static struct list_head *fib_insert_node
|
|
||||||
*/
|
|
||||||
|
|
||||||
while (n && IS_TNODE(n)) {
|
|
||||||
- tn = (struct tnode *) n;
|
|
||||||
-
|
|
||||||
- if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
|
|
||||||
- tp = tn;
|
|
||||||
- pos = tn->pos + tn->bits;
|
|
||||||
- n = tnode_get_child(tn,
|
|
||||||
+ if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
|
|
||||||
+ tp = n;
|
|
||||||
+ pos = n->pos + n->bits;
|
|
||||||
+ n = tnode_get_child(n,
|
|
||||||
tkey_extract_bits(key,
|
|
||||||
- tn->pos,
|
|
||||||
- tn->bits));
|
|
||||||
+ n->pos,
|
|
||||||
+ n->bits));
|
|
||||||
|
|
||||||
- BUG_ON(n && node_parent(n) != tn);
|
|
||||||
+ BUG_ON(n && node_parent(n) != tp);
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
@@ -1040,14 +1005,13 @@ static struct list_head *fib_insert_node
|
|
||||||
/* Case 1: n is a leaf. Compare prefixes */
|
|
||||||
|
|
||||||
if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
|
|
||||||
- l = (struct leaf *) n;
|
|
||||||
li = leaf_info_new(plen);
|
|
||||||
|
|
||||||
if (!li)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
fa_head = &li->falh;
|
|
||||||
- insert_leaf_info(&l->list, li);
|
|
||||||
+ insert_leaf_info(&n->list, li);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
l = leaf_new(key);
|
|
||||||
@@ -1068,10 +1032,10 @@ static struct list_head *fib_insert_node
|
|
||||||
if (t->trie && n == NULL) {
|
|
||||||
/* Case 2: n is NULL, and will just insert a new leaf */
|
|
||||||
|
|
||||||
- node_set_parent((struct rt_trie_node *)l, tp);
|
|
||||||
+ node_set_parent(l, tp);
|
|
||||||
|
|
||||||
cindex = tkey_extract_bits(key, tp->pos, tp->bits);
|
|
||||||
- put_child(tp, cindex, (struct rt_trie_node *)l);
|
|
||||||
+ put_child(tp, cindex, l);
|
|
||||||
} else {
|
|
||||||
/* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
|
|
||||||
/*
|
|
||||||
@@ -1094,17 +1058,17 @@ static struct list_head *fib_insert_node
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
- node_set_parent((struct rt_trie_node *)tn, tp);
|
|
||||||
+ node_set_parent(tn, tp);
|
|
||||||
|
|
||||||
missbit = tkey_extract_bits(key, newpos, 1);
|
|
||||||
- put_child(tn, missbit, (struct rt_trie_node *)l);
|
|
||||||
+ put_child(tn, missbit, l);
|
|
||||||
put_child(tn, 1-missbit, n);
|
|
||||||
|
|
||||||
if (tp) {
|
|
||||||
cindex = tkey_extract_bits(key, tp->pos, tp->bits);
|
|
||||||
- put_child(tp, cindex, (struct rt_trie_node *)tn);
|
|
||||||
+ put_child(tp, cindex, tn);
|
|
||||||
} else {
|
|
||||||
- rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
|
|
||||||
+ rcu_assign_pointer(t->trie, tn);
|
|
||||||
}
|
|
||||||
|
|
||||||
tp = tn;
|
|
||||||
@@ -1134,7 +1098,7 @@ int fib_table_insert(struct fib_table *t
|
|
||||||
u8 tos = cfg->fc_tos;
|
|
||||||
u32 key, mask;
|
|
||||||
int err;
|
|
||||||
- struct leaf *l;
|
|
||||||
+ struct tnode *l;
|
|
||||||
|
|
||||||
if (plen > 32)
|
|
||||||
return -EINVAL;
|
|
||||||
@@ -1292,7 +1256,7 @@ err:
|
|
||||||
}
|
|
||||||
|
|
||||||
/* should be called with rcu_read_lock */
|
|
||||||
-static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l,
|
|
||||||
+static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l,
|
|
||||||
t_key key, const struct flowi4 *flp,
|
|
||||||
struct fib_result *res, int fib_flags)
|
|
||||||
{
|
|
||||||
@@ -1365,7 +1329,7 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
struct trie_use_stats __percpu *stats = t->stats;
|
|
||||||
#endif
|
|
||||||
int ret;
|
|
||||||
- struct rt_trie_node *n;
|
|
||||||
+ struct tnode *n;
|
|
||||||
struct tnode *pn;
|
|
||||||
unsigned int pos, bits;
|
|
||||||
t_key key = ntohl(flp->daddr);
|
|
||||||
@@ -1387,11 +1351,11 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
|
|
||||||
/* Just a leaf? */
|
|
||||||
if (IS_LEAF(n)) {
|
|
||||||
- ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags);
|
|
||||||
+ ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
|
|
||||||
- pn = (struct tnode *) n;
|
|
||||||
+ pn = n;
|
|
||||||
chopped_off = 0;
|
|
||||||
|
|
||||||
while (pn) {
|
|
||||||
@@ -1412,13 +1376,13 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_LEAF(n)) {
|
|
||||||
- ret = check_leaf(tb, t, (struct leaf *)n, key, flp, res, fib_flags);
|
|
||||||
+ ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
|
|
||||||
if (ret > 0)
|
|
||||||
goto backtrace;
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
|
|
||||||
- cn = (struct tnode *)n;
|
|
||||||
+ cn = n;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It's a tnode, and we can do some extra checks here if we
|
|
||||||
@@ -1506,7 +1470,7 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
current_prefix_length = mp;
|
|
||||||
}
|
|
||||||
|
|
||||||
- pn = (struct tnode *)n; /* Descend */
|
|
||||||
+ pn = n; /* Descend */
|
|
||||||
chopped_off = 0;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
@@ -1557,7 +1521,7 @@ EXPORT_SYMBOL_GPL(fib_table_lookup);
|
|
||||||
/*
|
|
||||||
* Remove the leaf and return parent.
|
|
||||||
*/
|
|
||||||
-static void trie_leaf_remove(struct trie *t, struct leaf *l)
|
|
||||||
+static void trie_leaf_remove(struct trie *t, struct tnode *l)
|
|
||||||
{
|
|
||||||
struct tnode *tp = node_parent(l);
|
|
||||||
|
|
||||||
@@ -1584,7 +1548,7 @@ int fib_table_delete(struct fib_table *t
|
|
||||||
u8 tos = cfg->fc_tos;
|
|
||||||
struct fib_alias *fa, *fa_to_delete;
|
|
||||||
struct list_head *fa_head;
|
|
||||||
- struct leaf *l;
|
|
||||||
+ struct tnode *l;
|
|
||||||
struct leaf_info *li;
|
|
||||||
|
|
||||||
if (plen > 32)
|
|
||||||
@@ -1682,7 +1646,7 @@ static int trie_flush_list(struct list_h
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int trie_flush_leaf(struct leaf *l)
|
|
||||||
+static int trie_flush_leaf(struct tnode *l)
|
|
||||||
{
|
|
||||||
int found = 0;
|
|
||||||
struct hlist_head *lih = &l->list;
|
|
||||||
@@ -1704,7 +1668,7 @@ static int trie_flush_leaf(struct leaf *
|
|
||||||
* Scan for the next right leaf starting at node p->child[idx]
|
|
||||||
* Since we have back pointer, no recursion necessary.
|
|
||||||
*/
|
|
||||||
-static struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c)
|
|
||||||
+static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
t_key idx;
|
|
||||||
@@ -1720,47 +1684,46 @@ static struct leaf *leaf_walk_rcu(struct
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (IS_LEAF(c))
|
|
||||||
- return (struct leaf *) c;
|
|
||||||
+ return c;
|
|
||||||
|
|
||||||
/* Rescan start scanning in new node */
|
|
||||||
- p = (struct tnode *) c;
|
|
||||||
+ p = c;
|
|
||||||
idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Node empty, walk back up to parent */
|
|
||||||
- c = (struct rt_trie_node *) p;
|
|
||||||
+ c = p;
|
|
||||||
} while ((p = node_parent_rcu(c)) != NULL);
|
|
||||||
|
|
||||||
return NULL; /* Root of trie */
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct leaf *trie_firstleaf(struct trie *t)
|
|
||||||
+static struct tnode *trie_firstleaf(struct trie *t)
|
|
||||||
{
|
|
||||||
- struct tnode *n = (struct tnode *)rcu_dereference_rtnl(t->trie);
|
|
||||||
+ struct tnode *n = rcu_dereference_rtnl(t->trie);
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (IS_LEAF(n)) /* trie is just a leaf */
|
|
||||||
- return (struct leaf *) n;
|
|
||||||
+ return n;
|
|
||||||
|
|
||||||
return leaf_walk_rcu(n, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct leaf *trie_nextleaf(struct leaf *l)
|
|
||||||
+static struct tnode *trie_nextleaf(struct tnode *l)
|
|
||||||
{
|
|
||||||
- struct rt_trie_node *c = (struct rt_trie_node *) l;
|
|
||||||
- struct tnode *p = node_parent_rcu(c);
|
|
||||||
+ struct tnode *p = node_parent_rcu(l);
|
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return NULL; /* trie with just one leaf */
|
|
||||||
|
|
||||||
- return leaf_walk_rcu(p, c);
|
|
||||||
+ return leaf_walk_rcu(p, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct leaf *trie_leafindex(struct trie *t, int index)
|
|
||||||
+static struct tnode *trie_leafindex(struct trie *t, int index)
|
|
||||||
{
|
|
||||||
- struct leaf *l = trie_firstleaf(t);
|
|
||||||
+ struct tnode *l = trie_firstleaf(t);
|
|
||||||
|
|
||||||
while (l && index-- > 0)
|
|
||||||
l = trie_nextleaf(l);
|
|
||||||
@@ -1775,7 +1738,7 @@ static struct leaf *trie_leafindex(struc
|
|
||||||
int fib_table_flush(struct fib_table *tb)
|
|
||||||
{
|
|
||||||
struct trie *t = (struct trie *) tb->tb_data;
|
|
||||||
- struct leaf *l, *ll = NULL;
|
|
||||||
+ struct tnode *l, *ll = NULL;
|
|
||||||
int found = 0;
|
|
||||||
|
|
||||||
for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
|
|
||||||
@@ -1840,7 +1803,7 @@ static int fn_trie_dump_fa(t_key key, in
|
|
||||||
return skb->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
|
|
||||||
+static int fn_trie_dump_leaf(struct tnode *l, struct fib_table *tb,
|
|
||||||
struct sk_buff *skb, struct netlink_callback *cb)
|
|
||||||
{
|
|
||||||
struct leaf_info *li;
|
|
||||||
@@ -1876,7 +1839,7 @@ static int fn_trie_dump_leaf(struct leaf
|
|
||||||
int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
|
|
||||||
struct netlink_callback *cb)
|
|
||||||
{
|
|
||||||
- struct leaf *l;
|
|
||||||
+ struct tnode *l;
|
|
||||||
struct trie *t = (struct trie *) tb->tb_data;
|
|
||||||
t_key key = cb->args[2];
|
|
||||||
int count = cb->args[3];
|
|
||||||
@@ -1922,7 +1885,7 @@ void __init fib_trie_init(void)
|
|
||||||
0, SLAB_PANIC, NULL);
|
|
||||||
|
|
||||||
trie_leaf_kmem = kmem_cache_create("ip_fib_trie",
|
|
||||||
- max(sizeof(struct leaf),
|
|
||||||
+ max(sizeof(struct tnode),
|
|
||||||
sizeof(struct leaf_info)),
|
|
||||||
0, SLAB_PANIC, NULL);
|
|
||||||
}
|
|
||||||
@@ -1965,7 +1928,7 @@ struct fib_trie_iter {
|
|
||||||
unsigned int depth;
|
|
||||||
};
|
|
||||||
|
|
||||||
-static struct rt_trie_node *fib_trie_get_next(struct fib_trie_iter *iter)
|
|
||||||
+static struct tnode *fib_trie_get_next(struct fib_trie_iter *iter)
|
|
||||||
{
|
|
||||||
struct tnode *tn = iter->tnode;
|
|
||||||
unsigned int cindex = iter->index;
|
|
||||||
@@ -1979,7 +1942,7 @@ static struct rt_trie_node *fib_trie_get
|
|
||||||
iter->tnode, iter->index, iter->depth);
|
|
||||||
rescan:
|
|
||||||
while (cindex < (1<<tn->bits)) {
|
|
||||||
- struct rt_trie_node *n = tnode_get_child_rcu(tn, cindex);
|
|
||||||
+ struct tnode *n = tnode_get_child_rcu(tn, cindex);
|
|
||||||
|
|
||||||
if (n) {
|
|
||||||
if (IS_LEAF(n)) {
|
|
||||||
@@ -1987,7 +1950,7 @@ rescan:
|
|
||||||
iter->index = cindex + 1;
|
|
||||||
} else {
|
|
||||||
/* push down one level */
|
|
||||||
- iter->tnode = (struct tnode *) n;
|
|
||||||
+ iter->tnode = n;
|
|
||||||
iter->index = 0;
|
|
||||||
++iter->depth;
|
|
||||||
}
|
|
||||||
@@ -1998,7 +1961,7 @@ rescan:
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Current node exhausted, pop back up */
|
|
||||||
- p = node_parent_rcu((struct rt_trie_node *)tn);
|
|
||||||
+ p = node_parent_rcu(tn);
|
|
||||||
if (p) {
|
|
||||||
cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
|
|
||||||
tn = p;
|
|
||||||
@@ -2010,10 +1973,10 @@ rescan:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct rt_trie_node *fib_trie_get_first(struct fib_trie_iter *iter,
|
|
||||||
+static struct tnode *fib_trie_get_first(struct fib_trie_iter *iter,
|
|
||||||
struct trie *t)
|
|
||||||
{
|
|
||||||
- struct rt_trie_node *n;
|
|
||||||
+ struct tnode *n;
|
|
||||||
|
|
||||||
if (!t)
|
|
||||||
return NULL;
|
|
||||||
@@ -2023,7 +1986,7 @@ static struct rt_trie_node *fib_trie_get
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (IS_TNODE(n)) {
|
|
||||||
- iter->tnode = (struct tnode *) n;
|
|
||||||
+ iter->tnode = n;
|
|
||||||
iter->index = 0;
|
|
||||||
iter->depth = 1;
|
|
||||||
} else {
|
|
||||||
@@ -2037,7 +2000,7 @@ static struct rt_trie_node *fib_trie_get
|
|
||||||
|
|
||||||
static void trie_collect_stats(struct trie *t, struct trie_stat *s)
|
|
||||||
{
|
|
||||||
- struct rt_trie_node *n;
|
|
||||||
+ struct tnode *n;
|
|
||||||
struct fib_trie_iter iter;
|
|
||||||
|
|
||||||
memset(s, 0, sizeof(*s));
|
|
||||||
@@ -2045,7 +2008,6 @@ static void trie_collect_stats(struct tr
|
|
||||||
rcu_read_lock();
|
|
||||||
for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) {
|
|
||||||
if (IS_LEAF(n)) {
|
|
||||||
- struct leaf *l = (struct leaf *)n;
|
|
||||||
struct leaf_info *li;
|
|
||||||
|
|
||||||
s->leaves++;
|
|
||||||
@@ -2053,18 +2015,17 @@ static void trie_collect_stats(struct tr
|
|
||||||
if (iter.depth > s->maxdepth)
|
|
||||||
s->maxdepth = iter.depth;
|
|
||||||
|
|
||||||
- hlist_for_each_entry_rcu(li, &l->list, hlist)
|
|
||||||
+ hlist_for_each_entry_rcu(li, &n->list, hlist)
|
|
||||||
++s->prefixes;
|
|
||||||
} else {
|
|
||||||
- const struct tnode *tn = (const struct tnode *) n;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
s->tnodes++;
|
|
||||||
- if (tn->bits < MAX_STAT_DEPTH)
|
|
||||||
- s->nodesizes[tn->bits]++;
|
|
||||||
+ if (n->bits < MAX_STAT_DEPTH)
|
|
||||||
+ s->nodesizes[n->bits]++;
|
|
||||||
|
|
||||||
- for (i = 0; i < (1<<tn->bits); i++)
|
|
||||||
- if (!tn->child[i])
|
|
||||||
+ for (i = 0; i < tnode_child_length(n); i++)
|
|
||||||
+ if (!rcu_access_pointer(n->child[i]))
|
|
||||||
s->nullpointers++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2088,7 +2049,7 @@ static void trie_show_stats(struct seq_f
|
|
||||||
seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth);
|
|
||||||
|
|
||||||
seq_printf(seq, "\tLeaves: %u\n", stat->leaves);
|
|
||||||
- bytes = sizeof(struct leaf) * stat->leaves;
|
|
||||||
+ bytes = sizeof(struct tnode) * stat->leaves;
|
|
||||||
|
|
||||||
seq_printf(seq, "\tPrefixes: %u\n", stat->prefixes);
|
|
||||||
bytes += sizeof(struct leaf_info) * stat->prefixes;
|
|
||||||
@@ -2109,7 +2070,7 @@ static void trie_show_stats(struct seq_f
|
|
||||||
seq_putc(seq, '\n');
|
|
||||||
seq_printf(seq, "\tPointers: %u\n", pointers);
|
|
||||||
|
|
||||||
- bytes += sizeof(struct rt_trie_node *) * pointers;
|
|
||||||
+ bytes += sizeof(struct tnode *) * pointers;
|
|
||||||
seq_printf(seq, "Null ptrs: %u\n", stat->nullpointers);
|
|
||||||
seq_printf(seq, "Total size: %u kB\n", (bytes + 1023) / 1024);
|
|
||||||
}
|
|
||||||
@@ -2163,7 +2124,7 @@ static int fib_triestat_seq_show(struct
|
|
||||||
seq_printf(seq,
|
|
||||||
"Basic info: size of leaf:"
|
|
||||||
" %Zd bytes, size of tnode: %Zd bytes.\n",
|
|
||||||
- sizeof(struct leaf), sizeof(struct tnode));
|
|
||||||
+ sizeof(struct tnode), sizeof(struct tnode));
|
|
||||||
|
|
||||||
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
|
|
||||||
struct hlist_head *head = &net->ipv4.fib_table_hash[h];
|
|
||||||
@@ -2202,7 +2163,7 @@ static const struct file_operations fib_
|
|
||||||
.release = single_release_net,
|
|
||||||
};
|
|
||||||
|
|
||||||
-static struct rt_trie_node *fib_trie_get_idx(struct seq_file *seq, loff_t pos)
|
|
||||||
+static struct tnode *fib_trie_get_idx(struct seq_file *seq, loff_t pos)
|
|
||||||
{
|
|
||||||
struct fib_trie_iter *iter = seq->private;
|
|
||||||
struct net *net = seq_file_net(seq);
|
|
||||||
@@ -2214,7 +2175,7 @@ static struct rt_trie_node *fib_trie_get
|
|
||||||
struct fib_table *tb;
|
|
||||||
|
|
||||||
hlist_for_each_entry_rcu(tb, head, tb_hlist) {
|
|
||||||
- struct rt_trie_node *n;
|
|
||||||
+ struct tnode *n;
|
|
||||||
|
|
||||||
for (n = fib_trie_get_first(iter,
|
|
||||||
(struct trie *) tb->tb_data);
|
|
||||||
@@ -2243,7 +2204,7 @@ static void *fib_trie_seq_next(struct se
|
|
||||||
struct fib_table *tb = iter->tb;
|
|
||||||
struct hlist_node *tb_node;
|
|
||||||
unsigned int h;
|
|
||||||
- struct rt_trie_node *n;
|
|
||||||
+ struct tnode *n;
|
|
||||||
|
|
||||||
++*pos;
|
|
||||||
/* next node in same table */
|
|
||||||
@@ -2329,29 +2290,26 @@ static inline const char *rtn_type(char
|
|
||||||
static int fib_trie_seq_show(struct seq_file *seq, void *v)
|
|
||||||
{
|
|
||||||
const struct fib_trie_iter *iter = seq->private;
|
|
||||||
- struct rt_trie_node *n = v;
|
|
||||||
+ struct tnode *n = v;
|
|
||||||
|
|
||||||
if (!node_parent_rcu(n))
|
|
||||||
fib_table_print(seq, iter->tb);
|
|
||||||
|
|
||||||
if (IS_TNODE(n)) {
|
|
||||||
- struct tnode *tn = (struct tnode *) n;
|
|
||||||
- __be32 prf = htonl(tn->key);
|
|
||||||
+ __be32 prf = htonl(n->key);
|
|
||||||
|
|
||||||
- seq_indent(seq, iter->depth-1);
|
|
||||||
+ seq_indent(seq, iter->depth - 1);
|
|
||||||
seq_printf(seq, " +-- %pI4/%d %d %d %d\n",
|
|
||||||
- &prf, tn->pos, tn->bits, tn->full_children,
|
|
||||||
- tn->empty_children);
|
|
||||||
-
|
|
||||||
+ &prf, n->pos, n->bits, n->full_children,
|
|
||||||
+ n->empty_children);
|
|
||||||
} else {
|
|
||||||
- struct leaf *l = (struct leaf *) n;
|
|
||||||
struct leaf_info *li;
|
|
||||||
- __be32 val = htonl(l->key);
|
|
||||||
+ __be32 val = htonl(n->key);
|
|
||||||
|
|
||||||
seq_indent(seq, iter->depth);
|
|
||||||
seq_printf(seq, " |-- %pI4\n", &val);
|
|
||||||
|
|
||||||
- hlist_for_each_entry_rcu(li, &l->list, hlist) {
|
|
||||||
+ hlist_for_each_entry_rcu(li, &n->list, hlist) {
|
|
||||||
struct fib_alias *fa;
|
|
||||||
|
|
||||||
list_for_each_entry_rcu(fa, &li->falh, fa_list) {
|
|
||||||
@@ -2401,9 +2359,9 @@ struct fib_route_iter {
|
|
||||||
t_key key;
|
|
||||||
};
|
|
||||||
|
|
||||||
-static struct leaf *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos)
|
|
||||||
+static struct tnode *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos)
|
|
||||||
{
|
|
||||||
- struct leaf *l = NULL;
|
|
||||||
+ struct tnode *l = NULL;
|
|
||||||
struct trie *t = iter->main_trie;
|
|
||||||
|
|
||||||
/* use cache location of last found key */
|
|
||||||
@@ -2448,7 +2406,7 @@ static void *fib_route_seq_start(struct
|
|
||||||
static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
||||||
{
|
|
||||||
struct fib_route_iter *iter = seq->private;
|
|
||||||
- struct leaf *l = v;
|
|
||||||
+ struct tnode *l = v;
|
|
||||||
|
|
||||||
++*pos;
|
|
||||||
if (v == SEQ_START_TOKEN) {
|
|
||||||
@@ -2494,7 +2452,7 @@ static unsigned int fib_flag_trans(int t
|
|
||||||
*/
|
|
||||||
static int fib_route_seq_show(struct seq_file *seq, void *v)
|
|
||||||
{
|
|
||||||
- struct leaf *l = v;
|
|
||||||
+ struct tnode *l = v;
|
|
||||||
struct leaf_info *li;
|
|
||||||
|
|
||||||
if (v == SEQ_START_TOKEN) {
|
|
@ -1,343 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:55:54 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Optimize fib_table_lookup to avoid wasting
|
|
||||||
time on loops/variables
|
|
||||||
|
|
||||||
This patch is meant to reduce the complexity of fib_table_lookup by reducing
|
|
||||||
the number of variables to the bare minimum while still keeping the same if
|
|
||||||
not improved functionality versus the original.
|
|
||||||
|
|
||||||
Most of this change was started off by the desire to rid the function of
|
|
||||||
chopped_off and current_prefix_length as they actually added very little to
|
|
||||||
the function since they only applied when computing the cindex. I was able
|
|
||||||
to replace them mostly with just a check for the prefix match. As long as
|
|
||||||
the prefix between the key and the node being tested was the same we know
|
|
||||||
we can search the tnode fully versus just testing cindex 0.
|
|
||||||
|
|
||||||
The second portion of the change ended up being a massive reordering.
|
|
||||||
Originally the calls to check_leaf were up near the start of the loop, and
|
|
||||||
the backtracing and descending into lower levels of tnodes was later. This
|
|
||||||
didn't make much sense as the structure of the tree means the leaves are
|
|
||||||
always the last thing to be tested. As such I reordered things so that we
|
|
||||||
instead have a loop that will delve into the tree and only exit when we
|
|
||||||
have either found a leaf or we have exhausted the tree. The advantage of
|
|
||||||
rearranging things like this is that we can fully inline check_leaf since
|
|
||||||
there is now only one reference to it in the function.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -90,6 +90,9 @@ typedef unsigned int t_key;
|
|
||||||
#define IS_TNODE(n) ((n)->bits)
|
|
||||||
#define IS_LEAF(n) (!(n)->bits)
|
|
||||||
|
|
||||||
+#define get_shift(_kv) (KEYLENGTH - (_kv)->pos - (_kv)->bits)
|
|
||||||
+#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> get_shift(_kv))
|
|
||||||
+
|
|
||||||
struct tnode {
|
|
||||||
t_key key;
|
|
||||||
unsigned char bits; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
@@ -1281,7 +1284,7 @@ static int check_leaf(struct fib_table *
|
|
||||||
continue;
|
|
||||||
fib_alias_accessed(fa);
|
|
||||||
err = fib_props[fa->fa_type].error;
|
|
||||||
- if (err) {
|
|
||||||
+ if (unlikely(err < 0)) {
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
this_cpu_inc(t->stats->semantic_match_passed);
|
|
||||||
#endif
|
|
||||||
@@ -1303,7 +1306,7 @@ static int check_leaf(struct fib_table *
|
|
||||||
res->prefixlen = li->plen;
|
|
||||||
res->nh_sel = nhsel;
|
|
||||||
res->type = fa->fa_type;
|
|
||||||
- res->scope = fa->fa_info->fib_scope;
|
|
||||||
+ res->scope = fi->fib_scope;
|
|
||||||
res->fi = fi;
|
|
||||||
res->table = tb;
|
|
||||||
res->fa_head = &li->falh;
|
|
||||||
@@ -1321,23 +1324,24 @@ static int check_leaf(struct fib_table *
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static inline t_key prefix_mismatch(t_key key, struct tnode *n)
|
|
||||||
+{
|
|
||||||
+ t_key prefix = n->key;
|
|
||||||
+
|
|
||||||
+ return (key ^ prefix) & (prefix | -prefix);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
|
|
||||||
struct fib_result *res, int fib_flags)
|
|
||||||
{
|
|
||||||
- struct trie *t = (struct trie *) tb->tb_data;
|
|
||||||
+ struct trie *t = (struct trie *)tb->tb_data;
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
struct trie_use_stats __percpu *stats = t->stats;
|
|
||||||
#endif
|
|
||||||
- int ret;
|
|
||||||
- struct tnode *n;
|
|
||||||
- struct tnode *pn;
|
|
||||||
- unsigned int pos, bits;
|
|
||||||
- t_key key = ntohl(flp->daddr);
|
|
||||||
- unsigned int chopped_off;
|
|
||||||
- t_key cindex = 0;
|
|
||||||
- unsigned int current_prefix_length = KEYLENGTH;
|
|
||||||
- struct tnode *cn;
|
|
||||||
- t_key pref_mismatch;
|
|
||||||
+ const t_key key = ntohl(flp->daddr);
|
|
||||||
+ struct tnode *n, *pn;
|
|
||||||
+ t_key cindex;
|
|
||||||
+ int ret = 1;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
@@ -1349,170 +1353,102 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
this_cpu_inc(stats->gets);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
- /* Just a leaf? */
|
|
||||||
- if (IS_LEAF(n)) {
|
|
||||||
- ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
|
|
||||||
- goto found;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
pn = n;
|
|
||||||
- chopped_off = 0;
|
|
||||||
-
|
|
||||||
- while (pn) {
|
|
||||||
- pos = pn->pos;
|
|
||||||
- bits = pn->bits;
|
|
||||||
+ cindex = 0;
|
|
||||||
|
|
||||||
- if (!chopped_off)
|
|
||||||
- cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length),
|
|
||||||
- pos, bits);
|
|
||||||
-
|
|
||||||
- n = tnode_get_child_rcu(pn, cindex);
|
|
||||||
-
|
|
||||||
- if (n == NULL) {
|
|
||||||
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- this_cpu_inc(stats->null_node_hit);
|
|
||||||
-#endif
|
|
||||||
- goto backtrace;
|
|
||||||
- }
|
|
||||||
+ /* Step 1: Travel to the longest prefix match in the trie */
|
|
||||||
+ for (;;) {
|
|
||||||
+ unsigned long index = get_index(key, n);
|
|
||||||
+
|
|
||||||
+ /* This bit of code is a bit tricky but it combines multiple
|
|
||||||
+ * checks into a single check. The prefix consists of the
|
|
||||||
+ * prefix plus zeros for the "bits" in the prefix. The index
|
|
||||||
+ * is the difference between the key and this value. From
|
|
||||||
+ * this we can actually derive several pieces of data.
|
|
||||||
+ * if !(index >> bits)
|
|
||||||
+ * we know the value is child index
|
|
||||||
+ * else
|
|
||||||
+ * we have a mismatch in skip bits and failed
|
|
||||||
+ */
|
|
||||||
+ if (index >> n->bits)
|
|
||||||
+ break;
|
|
||||||
|
|
||||||
- if (IS_LEAF(n)) {
|
|
||||||
- ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
|
|
||||||
- if (ret > 0)
|
|
||||||
- goto backtrace;
|
|
||||||
+ /* we have found a leaf. Prefixes have already been compared */
|
|
||||||
+ if (IS_LEAF(n))
|
|
||||||
goto found;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- cn = n;
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * It's a tnode, and we can do some extra checks here if we
|
|
||||||
- * like, to avoid descending into a dead-end branch.
|
|
||||||
- * This tnode is in the parent's child array at index
|
|
||||||
- * key[p_pos..p_pos+p_bits] but potentially with some bits
|
|
||||||
- * chopped off, so in reality the index may be just a
|
|
||||||
- * subprefix, padded with zero at the end.
|
|
||||||
- * We can also take a look at any skipped bits in this
|
|
||||||
- * tnode - everything up to p_pos is supposed to be ok,
|
|
||||||
- * and the non-chopped bits of the index (se previous
|
|
||||||
- * paragraph) are also guaranteed ok, but the rest is
|
|
||||||
- * considered unknown.
|
|
||||||
- *
|
|
||||||
- * The skipped bits are key[pos+bits..cn->pos].
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
- /* If current_prefix_length < pos+bits, we are already doing
|
|
||||||
- * actual prefix matching, which means everything from
|
|
||||||
- * pos+(bits-chopped_off) onward must be zero along some
|
|
||||||
- * branch of this subtree - otherwise there is *no* valid
|
|
||||||
- * prefix present. Here we can only check the skipped
|
|
||||||
- * bits. Remember, since we have already indexed into the
|
|
||||||
- * parent's child array, we know that the bits we chopped of
|
|
||||||
- * *are* zero.
|
|
||||||
+ /* only record pn and cindex if we are going to be chopping
|
|
||||||
+ * bits later. Otherwise we are just wasting cycles.
|
|
||||||
*/
|
|
||||||
-
|
|
||||||
- /* NOTA BENE: Checking only skipped bits
|
|
||||||
- for the new node here */
|
|
||||||
-
|
|
||||||
- if (current_prefix_length < pos+bits) {
|
|
||||||
- if (tkey_extract_bits(cn->key, current_prefix_length,
|
|
||||||
- cn->pos - current_prefix_length)
|
|
||||||
- || !(cn->child[0]))
|
|
||||||
- goto backtrace;
|
|
||||||
+ if (index) {
|
|
||||||
+ pn = n;
|
|
||||||
+ cindex = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * If chopped_off=0, the index is fully validated and we
|
|
||||||
- * only need to look at the skipped bits for this, the new,
|
|
||||||
- * tnode. What we actually want to do is to find out if
|
|
||||||
- * these skipped bits match our key perfectly, or if we will
|
|
||||||
- * have to count on finding a matching prefix further down,
|
|
||||||
- * because if we do, we would like to have some way of
|
|
||||||
- * verifying the existence of such a prefix at this point.
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
- /* The only thing we can do at this point is to verify that
|
|
||||||
- * any such matching prefix can indeed be a prefix to our
|
|
||||||
- * key, and if the bits in the node we are inspecting that
|
|
||||||
- * do not match our key are not ZERO, this cannot be true.
|
|
||||||
- * Thus, find out where there is a mismatch (before cn->pos)
|
|
||||||
- * and verify that all the mismatching bits are zero in the
|
|
||||||
- * new tnode's key.
|
|
||||||
- */
|
|
||||||
+ n = rcu_dereference(n->child[index]);
|
|
||||||
+ if (unlikely(!n))
|
|
||||||
+ goto backtrace;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * Note: We aren't very concerned about the piece of
|
|
||||||
- * the key that precede pn->pos+pn->bits, since these
|
|
||||||
- * have already been checked. The bits after cn->pos
|
|
||||||
- * aren't checked since these are by definition
|
|
||||||
- * "unknown" at this point. Thus, what we want to see
|
|
||||||
- * is if we are about to enter the "prefix matching"
|
|
||||||
- * state, and in that case verify that the skipped
|
|
||||||
- * bits that will prevail throughout this subtree are
|
|
||||||
- * zero, as they have to be if we are to find a
|
|
||||||
- * matching prefix.
|
|
||||||
+ /* Step 2: Sort out leaves and begin backtracing for longest prefix */
|
|
||||||
+ for (;;) {
|
|
||||||
+ /* record the pointer where our next node pointer is stored */
|
|
||||||
+ struct tnode __rcu **cptr = n->child;
|
|
||||||
+
|
|
||||||
+ /* This test verifies that none of the bits that differ
|
|
||||||
+ * between the key and the prefix exist in the region of
|
|
||||||
+ * the lsb and higher in the prefix.
|
|
||||||
*/
|
|
||||||
+ if (unlikely(prefix_mismatch(key, n)))
|
|
||||||
+ goto backtrace;
|
|
||||||
|
|
||||||
- pref_mismatch = mask_pfx(cn->key ^ key, cn->pos);
|
|
||||||
+ /* exit out and process leaf */
|
|
||||||
+ if (unlikely(IS_LEAF(n)))
|
|
||||||
+ break;
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * In short: If skipped bits in this node do not match
|
|
||||||
- * the search key, enter the "prefix matching"
|
|
||||||
- * state.directly.
|
|
||||||
+ /* Don't bother recording parent info. Since we are in
|
|
||||||
+ * prefix match mode we will have to come back to wherever
|
|
||||||
+ * we started this traversal anyway
|
|
||||||
*/
|
|
||||||
- if (pref_mismatch) {
|
|
||||||
- /* fls(x) = __fls(x) + 1 */
|
|
||||||
- int mp = KEYLENGTH - __fls(pref_mismatch) - 1;
|
|
||||||
-
|
|
||||||
- if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0)
|
|
||||||
- goto backtrace;
|
|
||||||
-
|
|
||||||
- if (current_prefix_length >= cn->pos)
|
|
||||||
- current_prefix_length = mp;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- pn = n; /* Descend */
|
|
||||||
- chopped_off = 0;
|
|
||||||
- continue;
|
|
||||||
|
|
||||||
+ while ((n = rcu_dereference(*cptr)) == NULL) {
|
|
||||||
backtrace:
|
|
||||||
- chopped_off++;
|
|
||||||
-
|
|
||||||
- /* As zero don't change the child key (cindex) */
|
|
||||||
- while ((chopped_off <= pn->bits)
|
|
||||||
- && !(cindex & (1<<(chopped_off-1))))
|
|
||||||
- chopped_off++;
|
|
||||||
-
|
|
||||||
- /* Decrease current_... with bits chopped off */
|
|
||||||
- if (current_prefix_length > pn->pos + pn->bits - chopped_off)
|
|
||||||
- current_prefix_length = pn->pos + pn->bits
|
|
||||||
- - chopped_off;
|
|
||||||
-
|
|
||||||
- /*
|
|
||||||
- * Either we do the actual chop off according or if we have
|
|
||||||
- * chopped off all bits in this tnode walk up to our parent.
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
- if (chopped_off <= pn->bits) {
|
|
||||||
- cindex &= ~(1 << (chopped_off-1));
|
|
||||||
- } else {
|
|
||||||
- struct tnode *parent = node_parent_rcu(pn);
|
|
||||||
- if (!parent)
|
|
||||||
- goto failed;
|
|
||||||
-
|
|
||||||
- /* Get Child's index */
|
|
||||||
- cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits);
|
|
||||||
- pn = parent;
|
|
||||||
- chopped_off = 0;
|
|
||||||
-
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- this_cpu_inc(stats->backtrack);
|
|
||||||
+ if (!n)
|
|
||||||
+ this_cpu_inc(stats->null_node_hit);
|
|
||||||
#endif
|
|
||||||
- goto backtrace;
|
|
||||||
+ /* If we are at cindex 0 there are no more bits for
|
|
||||||
+ * us to strip at this level so we must ascend back
|
|
||||||
+ * up one level to see if there are any more bits to
|
|
||||||
+ * be stripped there.
|
|
||||||
+ */
|
|
||||||
+ while (!cindex) {
|
|
||||||
+ t_key pkey = pn->key;
|
|
||||||
+
|
|
||||||
+ pn = node_parent_rcu(pn);
|
|
||||||
+ if (unlikely(!pn))
|
|
||||||
+ goto failed;
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ this_cpu_inc(stats->backtrack);
|
|
||||||
+#endif
|
|
||||||
+ /* Get Child's index */
|
|
||||||
+ cindex = get_index(pkey, pn);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* strip the least significant bit from the cindex */
|
|
||||||
+ cindex &= cindex - 1;
|
|
||||||
+
|
|
||||||
+ /* grab pointer for next child node */
|
|
||||||
+ cptr = &pn->child[cindex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-failed:
|
|
||||||
- ret = 1;
|
|
||||||
+
|
|
||||||
found:
|
|
||||||
+ /* Step 3: Process the leaf, if that fails fall back to backtracing */
|
|
||||||
+ ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
|
|
||||||
+ if (unlikely(ret > 0))
|
|
||||||
+ goto backtrace;
|
|
||||||
+failed:
|
|
||||||
rcu_read_unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:00 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Optimize fib_find_node
|
|
||||||
|
|
||||||
This patch makes use of the same features I made use of for
|
|
||||||
fib_table_lookup to streamline fib_find_node. The resultant code should be
|
|
||||||
smaller and run faster than the original.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -892,28 +892,34 @@ static void insert_leaf_info(struct hlis
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rcu_read_lock needs to be hold by caller from readside */
|
|
||||||
-
|
|
||||||
static struct tnode *fib_find_node(struct trie *t, u32 key)
|
|
||||||
{
|
|
||||||
struct tnode *n = rcu_dereference_rtnl(t->trie);
|
|
||||||
- int pos = 0;
|
|
||||||
|
|
||||||
- while (n && IS_TNODE(n)) {
|
|
||||||
- if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
|
|
||||||
- pos = n->pos + n->bits;
|
|
||||||
- n = tnode_get_child_rcu(n,
|
|
||||||
- tkey_extract_bits(key,
|
|
||||||
- n->pos,
|
|
||||||
- n->bits));
|
|
||||||
- } else
|
|
||||||
+ while (n) {
|
|
||||||
+ unsigned long index = get_index(key, n);
|
|
||||||
+
|
|
||||||
+ /* This bit of code is a bit tricky but it combines multiple
|
|
||||||
+ * checks into a single check. The prefix consists of the
|
|
||||||
+ * prefix plus zeros for the bits in the cindex. The index
|
|
||||||
+ * is the difference between the key and this value. From
|
|
||||||
+ * this we can actually derive several pieces of data.
|
|
||||||
+ * if !(index >> bits)
|
|
||||||
+ * we know the value is cindex
|
|
||||||
+ * else
|
|
||||||
+ * we have a mismatch in skip bits and failed
|
|
||||||
+ */
|
|
||||||
+ if (index >> n->bits)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ /* we have found a leaf. Prefixes have already been compared */
|
|
||||||
+ if (IS_LEAF(n))
|
|
||||||
break;
|
|
||||||
- }
|
|
||||||
- /* Case we have found a leaf. Compare prefixes */
|
|
||||||
|
|
||||||
- if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))
|
|
||||||
- return n;
|
|
||||||
+ n = rcu_dereference_rtnl(n->child[index]);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- return NULL;
|
|
||||||
+ return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void trie_rebalance(struct trie *t, struct tnode *tn)
|
|
@ -1,276 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:06 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Optimize fib_table_insert
|
|
||||||
|
|
||||||
This patch updates the fib_table_insert function to take advantage of the
|
|
||||||
changes made to improve the performance of fib_table_lookup. As a result
|
|
||||||
the code should be smaller and run faster then the original.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -222,31 +222,6 @@ static inline t_key tkey_extract_bits(t_
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static inline int tkey_equals(t_key a, t_key b)
|
|
||||||
-{
|
|
||||||
- return a == b;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
|
|
||||||
-{
|
|
||||||
- if (bits == 0 || offset >= KEYLENGTH)
|
|
||||||
- return 1;
|
|
||||||
- bits = bits > KEYLENGTH ? KEYLENGTH : bits;
|
|
||||||
- return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-static inline int tkey_mismatch(t_key a, int offset, t_key b)
|
|
||||||
-{
|
|
||||||
- t_key diff = a ^ b;
|
|
||||||
- int i = offset;
|
|
||||||
-
|
|
||||||
- if (!diff)
|
|
||||||
- return 0;
|
|
||||||
- while ((diff << i) >> (KEYLENGTH-1) == 0)
|
|
||||||
- i++;
|
|
||||||
- return i;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
/*
|
|
||||||
To understand this stuff, an understanding of keys and all their bits is
|
|
||||||
necessary. Every node in the trie has a key associated with it, but not
|
|
||||||
@@ -485,6 +460,15 @@ static void tnode_put_child_reorg(struct
|
|
||||||
rcu_assign_pointer(tn->child[i], n);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void put_child_root(struct tnode *tp, struct trie *t,
|
|
||||||
+ t_key key, struct tnode *n)
|
|
||||||
+{
|
|
||||||
+ if (tp)
|
|
||||||
+ put_child(tp, get_index(key, tp), n);
|
|
||||||
+ else
|
|
||||||
+ rcu_assign_pointer(t->trie, n);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#define MAX_WORK 10
|
|
||||||
static struct tnode *resize(struct trie *t, struct tnode *tn)
|
|
||||||
{
|
|
||||||
@@ -959,138 +943,100 @@ static void trie_rebalance(struct trie *
|
|
||||||
|
|
||||||
static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
|
|
||||||
{
|
|
||||||
- int pos, newpos;
|
|
||||||
- struct tnode *tp = NULL, *tn = NULL;
|
|
||||||
- struct tnode *n;
|
|
||||||
- struct tnode *l;
|
|
||||||
- int missbit;
|
|
||||||
struct list_head *fa_head = NULL;
|
|
||||||
+ struct tnode *l, *n, *tp = NULL;
|
|
||||||
struct leaf_info *li;
|
|
||||||
- t_key cindex;
|
|
||||||
|
|
||||||
- pos = 0;
|
|
||||||
+ li = leaf_info_new(plen);
|
|
||||||
+ if (!li)
|
|
||||||
+ return NULL;
|
|
||||||
+ fa_head = &li->falh;
|
|
||||||
+
|
|
||||||
n = rtnl_dereference(t->trie);
|
|
||||||
|
|
||||||
/* If we point to NULL, stop. Either the tree is empty and we should
|
|
||||||
* just put a new leaf in if, or we have reached an empty child slot,
|
|
||||||
* and we should just put our new leaf in that.
|
|
||||||
- * If we point to a T_TNODE, check if it matches our key. Note that
|
|
||||||
- * a T_TNODE might be skipping any number of bits - its 'pos' need
|
|
||||||
- * not be the parent's 'pos'+'bits'!
|
|
||||||
- *
|
|
||||||
- * If it does match the current key, get pos/bits from it, extract
|
|
||||||
- * the index from our key, push the T_TNODE and walk the tree.
|
|
||||||
- *
|
|
||||||
- * If it doesn't, we have to replace it with a new T_TNODE.
|
|
||||||
*
|
|
||||||
- * If we point to a T_LEAF, it might or might not have the same key
|
|
||||||
- * as we do. If it does, just change the value, update the T_LEAF's
|
|
||||||
- * value, and return it.
|
|
||||||
- * If it doesn't, we need to replace it with a T_TNODE.
|
|
||||||
+ * If we hit a node with a key that does't match then we should stop
|
|
||||||
+ * and create a new tnode to replace that node and insert ourselves
|
|
||||||
+ * and the other node into the new tnode.
|
|
||||||
*/
|
|
||||||
+ while (n) {
|
|
||||||
+ unsigned long index = get_index(key, n);
|
|
||||||
|
|
||||||
- while (n && IS_TNODE(n)) {
|
|
||||||
- if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
|
|
||||||
- tp = n;
|
|
||||||
- pos = n->pos + n->bits;
|
|
||||||
- n = tnode_get_child(n,
|
|
||||||
- tkey_extract_bits(key,
|
|
||||||
- n->pos,
|
|
||||||
- n->bits));
|
|
||||||
-
|
|
||||||
- BUG_ON(n && node_parent(n) != tp);
|
|
||||||
- } else
|
|
||||||
+ /* This bit of code is a bit tricky but it combines multiple
|
|
||||||
+ * checks into a single check. The prefix consists of the
|
|
||||||
+ * prefix plus zeros for the "bits" in the prefix. The index
|
|
||||||
+ * is the difference between the key and this value. From
|
|
||||||
+ * this we can actually derive several pieces of data.
|
|
||||||
+ * if !(index >> bits)
|
|
||||||
+ * we know the value is child index
|
|
||||||
+ * else
|
|
||||||
+ * we have a mismatch in skip bits and failed
|
|
||||||
+ */
|
|
||||||
+ if (index >> n->bits)
|
|
||||||
break;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /*
|
|
||||||
- * n ----> NULL, LEAF or TNODE
|
|
||||||
- *
|
|
||||||
- * tp is n's (parent) ----> NULL or TNODE
|
|
||||||
- */
|
|
||||||
|
|
||||||
- BUG_ON(tp && IS_LEAF(tp));
|
|
||||||
-
|
|
||||||
- /* Case 1: n is a leaf. Compare prefixes */
|
|
||||||
-
|
|
||||||
- if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
|
|
||||||
- li = leaf_info_new(plen);
|
|
||||||
-
|
|
||||||
- if (!li)
|
|
||||||
- return NULL;
|
|
||||||
+ /* we have found a leaf. Prefixes have already been compared */
|
|
||||||
+ if (IS_LEAF(n)) {
|
|
||||||
+ /* Case 1: n is a leaf, and prefixes match*/
|
|
||||||
+ insert_leaf_info(&n->list, li);
|
|
||||||
+ return fa_head;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- fa_head = &li->falh;
|
|
||||||
- insert_leaf_info(&n->list, li);
|
|
||||||
- goto done;
|
|
||||||
+ tp = n;
|
|
||||||
+ n = rcu_dereference_rtnl(n->child[index]);
|
|
||||||
}
|
|
||||||
- l = leaf_new(key);
|
|
||||||
-
|
|
||||||
- if (!l)
|
|
||||||
- return NULL;
|
|
||||||
|
|
||||||
- li = leaf_info_new(plen);
|
|
||||||
-
|
|
||||||
- if (!li) {
|
|
||||||
- node_free(l);
|
|
||||||
+ l = leaf_new(key);
|
|
||||||
+ if (!l) {
|
|
||||||
+ free_leaf_info(li);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
- fa_head = &li->falh;
|
|
||||||
insert_leaf_info(&l->list, li);
|
|
||||||
|
|
||||||
- if (t->trie && n == NULL) {
|
|
||||||
- /* Case 2: n is NULL, and will just insert a new leaf */
|
|
||||||
-
|
|
||||||
- node_set_parent(l, tp);
|
|
||||||
-
|
|
||||||
- cindex = tkey_extract_bits(key, tp->pos, tp->bits);
|
|
||||||
- put_child(tp, cindex, l);
|
|
||||||
- } else {
|
|
||||||
- /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
|
|
||||||
- /*
|
|
||||||
- * Add a new tnode here
|
|
||||||
- * first tnode need some special handling
|
|
||||||
- */
|
|
||||||
+ /* Case 2: n is a LEAF or a TNODE and the key doesn't match.
|
|
||||||
+ *
|
|
||||||
+ * Add a new tnode here
|
|
||||||
+ * first tnode need some special handling
|
|
||||||
+ * leaves us in position for handling as case 3
|
|
||||||
+ */
|
|
||||||
+ if (n) {
|
|
||||||
+ struct tnode *tn;
|
|
||||||
+ int newpos;
|
|
||||||
|
|
||||||
- if (n) {
|
|
||||||
- pos = tp ? tp->pos+tp->bits : 0;
|
|
||||||
- newpos = tkey_mismatch(key, pos, n->key);
|
|
||||||
- tn = tnode_new(n->key, newpos, 1);
|
|
||||||
- } else {
|
|
||||||
- newpos = 0;
|
|
||||||
- tn = tnode_new(key, newpos, 1); /* First tnode */
|
|
||||||
- }
|
|
||||||
+ newpos = KEYLENGTH - __fls(n->key ^ key) - 1;
|
|
||||||
|
|
||||||
+ tn = tnode_new(key, newpos, 1);
|
|
||||||
if (!tn) {
|
|
||||||
free_leaf_info(li);
|
|
||||||
node_free(l);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
- node_set_parent(tn, tp);
|
|
||||||
-
|
|
||||||
- missbit = tkey_extract_bits(key, newpos, 1);
|
|
||||||
- put_child(tn, missbit, l);
|
|
||||||
- put_child(tn, 1-missbit, n);
|
|
||||||
-
|
|
||||||
- if (tp) {
|
|
||||||
- cindex = tkey_extract_bits(key, tp->pos, tp->bits);
|
|
||||||
- put_child(tp, cindex, tn);
|
|
||||||
- } else {
|
|
||||||
- rcu_assign_pointer(t->trie, tn);
|
|
||||||
- }
|
|
||||||
+ /* initialize routes out of node */
|
|
||||||
+ NODE_INIT_PARENT(tn, tp);
|
|
||||||
+ put_child(tn, get_index(key, tn) ^ 1, n);
|
|
||||||
+
|
|
||||||
+ /* start adding routes into the node */
|
|
||||||
+ put_child_root(tp, t, key, tn);
|
|
||||||
+ node_set_parent(n, tn);
|
|
||||||
|
|
||||||
+ /* parent now has a NULL spot where the leaf can go */
|
|
||||||
tp = tn;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (tp && tp->pos + tp->bits > 32)
|
|
||||||
- pr_warn("fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
|
|
||||||
- tp, tp->pos, tp->bits, key, plen);
|
|
||||||
-
|
|
||||||
- /* Rebalance the trie */
|
|
||||||
+ /* Case 3: n is NULL, and will just insert a new leaf */
|
|
||||||
+ if (tp) {
|
|
||||||
+ NODE_INIT_PARENT(l, tp);
|
|
||||||
+ put_child(tp, get_index(key, tp), l);
|
|
||||||
+ trie_rebalance(t, tp);
|
|
||||||
+ } else {
|
|
||||||
+ rcu_assign_pointer(t->trie, l);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- trie_rebalance(t, tp);
|
|
||||||
-done:
|
|
||||||
return fa_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1470,11 +1416,11 @@ static void trie_leaf_remove(struct trie
|
|
||||||
pr_debug("entering trie_leaf_remove(%p)\n", l);
|
|
||||||
|
|
||||||
if (tp) {
|
|
||||||
- t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
|
|
||||||
- put_child(tp, cindex, NULL);
|
|
||||||
+ put_child(tp, get_index(l->key, tp), NULL);
|
|
||||||
trie_rebalance(t, tp);
|
|
||||||
- } else
|
|
||||||
+ } else {
|
|
||||||
RCU_INIT_POINTER(t->trie, NULL);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
node_free(l);
|
|
||||||
}
|
|
@ -1,346 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:12 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Update meaning of pos to represent unchecked
|
|
||||||
bits
|
|
||||||
|
|
||||||
This change moves the pos value to the other side of the "bits" field. By
|
|
||||||
doing this it actually simplifies a significant amount of code in the trie.
|
|
||||||
|
|
||||||
For example when halving a tree we know that the bit lost exists at
|
|
||||||
oldnode->pos, and if we inflate the tree the new bit being add is at
|
|
||||||
tn->pos. Previously to find those bits you would have to subtract pos and
|
|
||||||
bits from the keylength or start with a value of (1 << 31) and then shift
|
|
||||||
that.
|
|
||||||
|
|
||||||
There are a number of spots throughout the code that benefit from this. In
|
|
||||||
the case of the hot-path searches the main advantage is that we can drop 2
|
|
||||||
or more operations from the search path as we no longer need to compute the
|
|
||||||
value for the index to be shifted by and can instead just use the raw pos
|
|
||||||
value.
|
|
||||||
|
|
||||||
In addition the tkey_extract_bits is now defunct and can be replaced by
|
|
||||||
get_index since the two operations were doing the same thing, but now
|
|
||||||
get_index does it much more quickly as it is only an xor and shift versus a
|
|
||||||
pair of shifts and a subtraction.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -90,8 +90,7 @@ typedef unsigned int t_key;
|
|
||||||
#define IS_TNODE(n) ((n)->bits)
|
|
||||||
#define IS_LEAF(n) (!(n)->bits)
|
|
||||||
|
|
||||||
-#define get_shift(_kv) (KEYLENGTH - (_kv)->pos - (_kv)->bits)
|
|
||||||
-#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> get_shift(_kv))
|
|
||||||
+#define get_index(_key, _kv) (((_key) ^ (_kv)->key) >> (_kv)->pos)
|
|
||||||
|
|
||||||
struct tnode {
|
|
||||||
t_key key;
|
|
||||||
@@ -209,81 +208,64 @@ static inline struct tnode *tnode_get_ch
|
|
||||||
return rcu_dereference_rtnl(tn->child[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static inline t_key mask_pfx(t_key k, unsigned int l)
|
|
||||||
-{
|
|
||||||
- return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-static inline t_key tkey_extract_bits(t_key a, unsigned int offset, unsigned int bits)
|
|
||||||
-{
|
|
||||||
- if (offset < KEYLENGTH)
|
|
||||||
- return ((t_key)(a << offset)) >> (KEYLENGTH - bits);
|
|
||||||
- else
|
|
||||||
- return 0;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-/*
|
|
||||||
- To understand this stuff, an understanding of keys and all their bits is
|
|
||||||
- necessary. Every node in the trie has a key associated with it, but not
|
|
||||||
- all of the bits in that key are significant.
|
|
||||||
-
|
|
||||||
- Consider a node 'n' and its parent 'tp'.
|
|
||||||
-
|
|
||||||
- If n is a leaf, every bit in its key is significant. Its presence is
|
|
||||||
- necessitated by path compression, since during a tree traversal (when
|
|
||||||
- searching for a leaf - unless we are doing an insertion) we will completely
|
|
||||||
- ignore all skipped bits we encounter. Thus we need to verify, at the end of
|
|
||||||
- a potentially successful search, that we have indeed been walking the
|
|
||||||
- correct key path.
|
|
||||||
-
|
|
||||||
- Note that we can never "miss" the correct key in the tree if present by
|
|
||||||
- following the wrong path. Path compression ensures that segments of the key
|
|
||||||
- that are the same for all keys with a given prefix are skipped, but the
|
|
||||||
- skipped part *is* identical for each node in the subtrie below the skipped
|
|
||||||
- bit! trie_insert() in this implementation takes care of that - note the
|
|
||||||
- call to tkey_sub_equals() in trie_insert().
|
|
||||||
-
|
|
||||||
- if n is an internal node - a 'tnode' here, the various parts of its key
|
|
||||||
- have many different meanings.
|
|
||||||
-
|
|
||||||
- Example:
|
|
||||||
- _________________________________________________________________
|
|
||||||
- | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
|
|
||||||
- -----------------------------------------------------------------
|
|
||||||
- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
|
||||||
-
|
|
||||||
- _________________________________________________________________
|
|
||||||
- | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
|
|
||||||
- -----------------------------------------------------------------
|
|
||||||
- 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
|
||||||
-
|
|
||||||
- tp->pos = 7
|
|
||||||
- tp->bits = 3
|
|
||||||
- n->pos = 15
|
|
||||||
- n->bits = 4
|
|
||||||
-
|
|
||||||
- First, let's just ignore the bits that come before the parent tp, that is
|
|
||||||
- the bits from 0 to (tp->pos-1). They are *known* but at this point we do
|
|
||||||
- not use them for anything.
|
|
||||||
-
|
|
||||||
- The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the
|
|
||||||
- index into the parent's child array. That is, they will be used to find
|
|
||||||
- 'n' among tp's children.
|
|
||||||
-
|
|
||||||
- The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits
|
|
||||||
- for the node n.
|
|
||||||
-
|
|
||||||
- All the bits we have seen so far are significant to the node n. The rest
|
|
||||||
- of the bits are really not needed or indeed known in n->key.
|
|
||||||
-
|
|
||||||
- The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into
|
|
||||||
- n's child array, and will of course be different for each child.
|
|
||||||
-
|
|
||||||
-
|
|
||||||
- The rest of the bits, from (n->pos + n->bits) onward, are completely unknown
|
|
||||||
- at this point.
|
|
||||||
-
|
|
||||||
-*/
|
|
||||||
+/* To understand this stuff, an understanding of keys and all their bits is
|
|
||||||
+ * necessary. Every node in the trie has a key associated with it, but not
|
|
||||||
+ * all of the bits in that key are significant.
|
|
||||||
+ *
|
|
||||||
+ * Consider a node 'n' and its parent 'tp'.
|
|
||||||
+ *
|
|
||||||
+ * If n is a leaf, every bit in its key is significant. Its presence is
|
|
||||||
+ * necessitated by path compression, since during a tree traversal (when
|
|
||||||
+ * searching for a leaf - unless we are doing an insertion) we will completely
|
|
||||||
+ * ignore all skipped bits we encounter. Thus we need to verify, at the end of
|
|
||||||
+ * a potentially successful search, that we have indeed been walking the
|
|
||||||
+ * correct key path.
|
|
||||||
+ *
|
|
||||||
+ * Note that we can never "miss" the correct key in the tree if present by
|
|
||||||
+ * following the wrong path. Path compression ensures that segments of the key
|
|
||||||
+ * that are the same for all keys with a given prefix are skipped, but the
|
|
||||||
+ * skipped part *is* identical for each node in the subtrie below the skipped
|
|
||||||
+ * bit! trie_insert() in this implementation takes care of that.
|
|
||||||
+ *
|
|
||||||
+ * if n is an internal node - a 'tnode' here, the various parts of its key
|
|
||||||
+ * have many different meanings.
|
|
||||||
+ *
|
|
||||||
+ * Example:
|
|
||||||
+ * _________________________________________________________________
|
|
||||||
+ * | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
|
|
||||||
+ * -----------------------------------------------------------------
|
|
||||||
+ * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
|
|
||||||
+ *
|
|
||||||
+ * _________________________________________________________________
|
|
||||||
+ * | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
|
|
||||||
+ * -----------------------------------------------------------------
|
|
||||||
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
|
||||||
+ *
|
|
||||||
+ * tp->pos = 22
|
|
||||||
+ * tp->bits = 3
|
|
||||||
+ * n->pos = 13
|
|
||||||
+ * n->bits = 4
|
|
||||||
+ *
|
|
||||||
+ * First, let's just ignore the bits that come before the parent tp, that is
|
|
||||||
+ * the bits from (tp->pos + tp->bits) to 31. They are *known* but at this
|
|
||||||
+ * point we do not use them for anything.
|
|
||||||
+ *
|
|
||||||
+ * The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the
|
|
||||||
+ * index into the parent's child array. That is, they will be used to find
|
|
||||||
+ * 'n' among tp's children.
|
|
||||||
+ *
|
|
||||||
+ * The bits from (n->pos + n->bits) to (tn->pos - 1) - "S" - are skipped bits
|
|
||||||
+ * for the node n.
|
|
||||||
+ *
|
|
||||||
+ * All the bits we have seen so far are significant to the node n. The rest
|
|
||||||
+ * of the bits are really not needed or indeed known in n->key.
|
|
||||||
+ *
|
|
||||||
+ * The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into
|
|
||||||
+ * n's child array, and will of course be different for each child.
|
|
||||||
+ *
|
|
||||||
+ * The rest of the bits, from 0 to (n->pos + n->bits), are completely unknown
|
|
||||||
+ * at this point.
|
|
||||||
+ */
|
|
||||||
|
|
||||||
static const int halve_threshold = 25;
|
|
||||||
static const int inflate_threshold = 50;
|
|
||||||
@@ -367,7 +349,7 @@ static struct tnode *leaf_new(t_key key)
|
|
||||||
* as the nodes are searched
|
|
||||||
*/
|
|
||||||
l->key = key;
|
|
||||||
- l->pos = KEYLENGTH;
|
|
||||||
+ l->pos = 0;
|
|
||||||
/* set bits to 0 indicating we are not a tnode */
|
|
||||||
l->bits = 0;
|
|
||||||
|
|
||||||
@@ -400,7 +382,7 @@ static struct tnode *tnode_new(t_key key
|
|
||||||
tn->parent = NULL;
|
|
||||||
tn->pos = pos;
|
|
||||||
tn->bits = bits;
|
|
||||||
- tn->key = mask_pfx(key, pos);
|
|
||||||
+ tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0;
|
|
||||||
tn->full_children = 0;
|
|
||||||
tn->empty_children = 1<<bits;
|
|
||||||
}
|
|
||||||
@@ -410,14 +392,12 @@ static struct tnode *tnode_new(t_key key
|
|
||||||
return tn;
|
|
||||||
}
|
|
||||||
|
|
||||||
-/*
|
|
||||||
- * Check whether a tnode 'n' is "full", i.e. it is an internal node
|
|
||||||
+/* Check whether a tnode 'n' is "full", i.e. it is an internal node
|
|
||||||
* and no bits are skipped. See discussion in dyntree paper p. 6
|
|
||||||
*/
|
|
||||||
-
|
|
||||||
static inline int tnode_full(const struct tnode *tn, const struct tnode *n)
|
|
||||||
{
|
|
||||||
- return n && IS_TNODE(n) && (n->pos == (tn->pos + tn->bits));
|
|
||||||
+ return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void put_child(struct tnode *tn, int i,
|
|
||||||
@@ -641,11 +621,12 @@ static struct tnode *inflate(struct trie
|
|
||||||
{
|
|
||||||
int olen = tnode_child_length(oldtnode);
|
|
||||||
struct tnode *tn;
|
|
||||||
+ t_key m;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
pr_debug("In inflate\n");
|
|
||||||
|
|
||||||
- tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
|
|
||||||
+ tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1);
|
|
||||||
|
|
||||||
if (!tn)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
@@ -656,21 +637,18 @@ static struct tnode *inflate(struct trie
|
|
||||||
* fails. In case of failure we return the oldnode and inflate
|
|
||||||
* of tnode is ignored.
|
|
||||||
*/
|
|
||||||
+ for (i = 0, m = 1u << tn->pos; i < olen; i++) {
|
|
||||||
+ struct tnode *inode = tnode_get_child(oldtnode, i);
|
|
||||||
|
|
||||||
- for (i = 0; i < olen; i++) {
|
|
||||||
- struct tnode *inode;
|
|
||||||
-
|
|
||||||
- inode = tnode_get_child(oldtnode, i);
|
|
||||||
- if (tnode_full(oldtnode, inode) && inode->bits > 1) {
|
|
||||||
+ if (tnode_full(oldtnode, inode) && (inode->bits > 1)) {
|
|
||||||
struct tnode *left, *right;
|
|
||||||
- t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos;
|
|
||||||
|
|
||||||
- left = tnode_new(inode->key&(~m), inode->pos + 1,
|
|
||||||
+ left = tnode_new(inode->key & ~m, inode->pos,
|
|
||||||
inode->bits - 1);
|
|
||||||
if (!left)
|
|
||||||
goto nomem;
|
|
||||||
|
|
||||||
- right = tnode_new(inode->key|m, inode->pos + 1,
|
|
||||||
+ right = tnode_new(inode->key | m, inode->pos,
|
|
||||||
inode->bits - 1);
|
|
||||||
|
|
||||||
if (!right) {
|
|
||||||
@@ -694,9 +672,7 @@ static struct tnode *inflate(struct trie
|
|
||||||
|
|
||||||
/* A leaf or an internal node with skipped bits */
|
|
||||||
if (!tnode_full(oldtnode, inode)) {
|
|
||||||
- put_child(tn,
|
|
||||||
- tkey_extract_bits(inode->key, tn->pos, tn->bits),
|
|
||||||
- inode);
|
|
||||||
+ put_child(tn, get_index(inode->key, tn), inode);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -767,7 +743,7 @@ static struct tnode *halve(struct trie *
|
|
||||||
|
|
||||||
pr_debug("In halve\n");
|
|
||||||
|
|
||||||
- tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
|
|
||||||
+ tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1);
|
|
||||||
|
|
||||||
if (!tn)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
@@ -787,7 +763,7 @@ static struct tnode *halve(struct trie *
|
|
||||||
if (left && right) {
|
|
||||||
struct tnode *newn;
|
|
||||||
|
|
||||||
- newn = tnode_new(left->key, tn->pos + tn->bits, 1);
|
|
||||||
+ newn = tnode_new(left->key, oldtnode->pos, 1);
|
|
||||||
|
|
||||||
if (!newn)
|
|
||||||
goto nomem;
|
|
||||||
@@ -915,7 +891,7 @@ static void trie_rebalance(struct trie *
|
|
||||||
key = tn->key;
|
|
||||||
|
|
||||||
while (tn != NULL && (tp = node_parent(tn)) != NULL) {
|
|
||||||
- cindex = tkey_extract_bits(key, tp->pos, tp->bits);
|
|
||||||
+ cindex = get_index(key, tp);
|
|
||||||
wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
|
|
||||||
tn = resize(t, tn);
|
|
||||||
|
|
||||||
@@ -1005,11 +981,8 @@ static struct list_head *fib_insert_node
|
|
||||||
*/
|
|
||||||
if (n) {
|
|
||||||
struct tnode *tn;
|
|
||||||
- int newpos;
|
|
||||||
-
|
|
||||||
- newpos = KEYLENGTH - __fls(n->key ^ key) - 1;
|
|
||||||
|
|
||||||
- tn = tnode_new(key, newpos, 1);
|
|
||||||
+ tn = tnode_new(key, __fls(key ^ n->key), 1);
|
|
||||||
if (!tn) {
|
|
||||||
free_leaf_info(li);
|
|
||||||
node_free(l);
|
|
||||||
@@ -1559,12 +1532,7 @@ static int trie_flush_leaf(struct tnode
|
|
||||||
static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
- t_key idx;
|
|
||||||
-
|
|
||||||
- if (c)
|
|
||||||
- idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1;
|
|
||||||
- else
|
|
||||||
- idx = 0;
|
|
||||||
+ t_key idx = c ? idx = get_index(c->key, p) + 1 : 0;
|
|
||||||
|
|
||||||
while (idx < 1u << p->bits) {
|
|
||||||
c = tnode_get_child_rcu(p, idx++);
|
|
||||||
@@ -1851,7 +1819,7 @@ rescan:
|
|
||||||
/* Current node exhausted, pop back up */
|
|
||||||
p = node_parent_rcu(tn);
|
|
||||||
if (p) {
|
|
||||||
- cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
|
|
||||||
+ cindex = get_index(tn->key, p) + 1;
|
|
||||||
tn = p;
|
|
||||||
--iter->depth;
|
|
||||||
goto rescan;
|
|
||||||
@@ -2186,10 +2154,10 @@ static int fib_trie_seq_show(struct seq_
|
|
||||||
if (IS_TNODE(n)) {
|
|
||||||
__be32 prf = htonl(n->key);
|
|
||||||
|
|
||||||
- seq_indent(seq, iter->depth - 1);
|
|
||||||
- seq_printf(seq, " +-- %pI4/%d %d %d %d\n",
|
|
||||||
- &prf, n->pos, n->bits, n->full_children,
|
|
||||||
- n->empty_children);
|
|
||||||
+ seq_indent(seq, iter->depth-1);
|
|
||||||
+ seq_printf(seq, " +-- %pI4/%zu %u %u %u\n",
|
|
||||||
+ &prf, KEYLENGTH - n->pos - n->bits, n->bits,
|
|
||||||
+ n->full_children, n->empty_children);
|
|
||||||
} else {
|
|
||||||
struct leaf_info *li;
|
|
||||||
__be32 val = htonl(n->key);
|
|
@ -1,186 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:18 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Use unsigned long for anything dealing with a
|
|
||||||
shift by bits
|
|
||||||
|
|
||||||
This change makes it so that anything that can be shifted by, or compared
|
|
||||||
to a value shifted by bits is updated to be an unsigned long. This is
|
|
||||||
mostly a precaution against an insanely huge address space that somehow
|
|
||||||
starts coming close to the 2^32 root node size which would require
|
|
||||||
something like 1.5 billion addresses.
|
|
||||||
|
|
||||||
I chose unsigned long instead of unsigned long long since I do not believe
|
|
||||||
it is possible to allocate a 32 bit tnode on a 32 bit system as the memory
|
|
||||||
consumed would be 16GB + 28B which exceeds the addressible space for any
|
|
||||||
one process.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -146,8 +146,8 @@ struct trie {
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
-static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n,
|
|
||||||
- int wasfull);
|
|
||||||
+static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
|
|
||||||
+ struct tnode *n, int wasfull);
|
|
||||||
static struct tnode *resize(struct trie *t, struct tnode *tn);
|
|
||||||
static struct tnode *inflate(struct trie *t, struct tnode *tn);
|
|
||||||
static struct tnode *halve(struct trie *t, struct tnode *tn);
|
|
||||||
@@ -183,25 +183,23 @@ static inline void node_set_parent(struc
|
|
||||||
/* This provides us with the number of children in this node, in the case of a
|
|
||||||
* leaf this will return 0 meaning none of the children are accessible.
|
|
||||||
*/
|
|
||||||
-static inline int tnode_child_length(const struct tnode *tn)
|
|
||||||
+static inline unsigned long tnode_child_length(const struct tnode *tn)
|
|
||||||
{
|
|
||||||
return (1ul << tn->bits) & ~(1ul);
|
|
||||||
}
|
|
||||||
|
|
||||||
-/*
|
|
||||||
- * caller must hold RTNL
|
|
||||||
- */
|
|
||||||
-static inline struct tnode *tnode_get_child(const struct tnode *tn, unsigned int i)
|
|
||||||
+/* caller must hold RTNL */
|
|
||||||
+static inline struct tnode *tnode_get_child(const struct tnode *tn,
|
|
||||||
+ unsigned long i)
|
|
||||||
{
|
|
||||||
BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
return rtnl_dereference(tn->child[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
-/*
|
|
||||||
- * caller must hold RCU read lock or RTNL
|
|
||||||
- */
|
|
||||||
-static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn, unsigned int i)
|
|
||||||
+/* caller must hold RCU read lock or RTNL */
|
|
||||||
+static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn,
|
|
||||||
+ unsigned long i)
|
|
||||||
{
|
|
||||||
BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
@@ -400,7 +398,7 @@ static inline int tnode_full(const struc
|
|
||||||
return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static inline void put_child(struct tnode *tn, int i,
|
|
||||||
+static inline void put_child(struct tnode *tn, unsigned long i,
|
|
||||||
struct tnode *n)
|
|
||||||
{
|
|
||||||
tnode_put_child_reorg(tn, i, n, -1);
|
|
||||||
@@ -411,13 +409,13 @@ static inline void put_child(struct tnod
|
|
||||||
* Update the value of full_children and empty_children.
|
|
||||||
*/
|
|
||||||
|
|
||||||
-static void tnode_put_child_reorg(struct tnode *tn, int i, struct tnode *n,
|
|
||||||
- int wasfull)
|
|
||||||
+static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
|
|
||||||
+ struct tnode *n, int wasfull)
|
|
||||||
{
|
|
||||||
struct tnode *chi = rtnl_dereference(tn->child[i]);
|
|
||||||
int isfull;
|
|
||||||
|
|
||||||
- BUG_ON(i >= 1<<tn->bits);
|
|
||||||
+ BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
/* update emptyChildren */
|
|
||||||
if (n == NULL && chi != NULL)
|
|
||||||
@@ -607,10 +605,10 @@ no_children:
|
|
||||||
static void tnode_clean_free(struct tnode *tn)
|
|
||||||
{
|
|
||||||
struct tnode *tofree;
|
|
||||||
- int i;
|
|
||||||
+ unsigned long i;
|
|
||||||
|
|
||||||
for (i = 0; i < tnode_child_length(tn); i++) {
|
|
||||||
- tofree = rtnl_dereference(tn->child[i]);
|
|
||||||
+ tofree = tnode_get_child(tn, i);
|
|
||||||
if (tofree)
|
|
||||||
node_free(tofree);
|
|
||||||
}
|
|
||||||
@@ -619,10 +617,10 @@ static void tnode_clean_free(struct tnod
|
|
||||||
|
|
||||||
static struct tnode *inflate(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
- int olen = tnode_child_length(oldtnode);
|
|
||||||
+ unsigned long olen = tnode_child_length(oldtnode);
|
|
||||||
struct tnode *tn;
|
|
||||||
+ unsigned long i;
|
|
||||||
t_key m;
|
|
||||||
- int i;
|
|
||||||
|
|
||||||
pr_debug("In inflate\n");
|
|
||||||
|
|
||||||
@@ -664,7 +662,7 @@ static struct tnode *inflate(struct trie
|
|
||||||
for (i = 0; i < olen; i++) {
|
|
||||||
struct tnode *inode = tnode_get_child(oldtnode, i);
|
|
||||||
struct tnode *left, *right;
|
|
||||||
- int size, j;
|
|
||||||
+ unsigned long size, j;
|
|
||||||
|
|
||||||
/* An empty child */
|
|
||||||
if (inode == NULL)
|
|
||||||
@@ -737,7 +735,7 @@ nomem:
|
|
||||||
|
|
||||||
static struct tnode *halve(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
- int olen = tnode_child_length(oldtnode);
|
|
||||||
+ unsigned long olen = tnode_child_length(oldtnode);
|
|
||||||
struct tnode *tn, *left, *right;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
@@ -1532,9 +1530,9 @@ static int trie_flush_leaf(struct tnode
|
|
||||||
static struct tnode *leaf_walk_rcu(struct tnode *p, struct tnode *c)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
- t_key idx = c ? idx = get_index(c->key, p) + 1 : 0;
|
|
||||||
+ unsigned long idx = c ? idx = get_index(c->key, p) + 1 : 0;
|
|
||||||
|
|
||||||
- while (idx < 1u << p->bits) {
|
|
||||||
+ while (idx < tnode_child_length(p)) {
|
|
||||||
c = tnode_get_child_rcu(p, idx++);
|
|
||||||
if (!c)
|
|
||||||
continue;
|
|
||||||
@@ -1786,8 +1784,8 @@ struct fib_trie_iter {
|
|
||||||
|
|
||||||
static struct tnode *fib_trie_get_next(struct fib_trie_iter *iter)
|
|
||||||
{
|
|
||||||
+ unsigned long cindex = iter->index;
|
|
||||||
struct tnode *tn = iter->tnode;
|
|
||||||
- unsigned int cindex = iter->index;
|
|
||||||
struct tnode *p;
|
|
||||||
|
|
||||||
/* A single entry routing table */
|
|
||||||
@@ -1797,7 +1795,7 @@ static struct tnode *fib_trie_get_next(s
|
|
||||||
pr_debug("get_next iter={node=%p index=%d depth=%d}\n",
|
|
||||||
iter->tnode, iter->index, iter->depth);
|
|
||||||
rescan:
|
|
||||||
- while (cindex < (1<<tn->bits)) {
|
|
||||||
+ while (cindex < tnode_child_length(tn)) {
|
|
||||||
struct tnode *n = tnode_get_child_rcu(tn, cindex);
|
|
||||||
|
|
||||||
if (n) {
|
|
||||||
@@ -1874,15 +1872,16 @@ static void trie_collect_stats(struct tr
|
|
||||||
hlist_for_each_entry_rcu(li, &n->list, hlist)
|
|
||||||
++s->prefixes;
|
|
||||||
} else {
|
|
||||||
- int i;
|
|
||||||
+ unsigned long i;
|
|
||||||
|
|
||||||
s->tnodes++;
|
|
||||||
if (n->bits < MAX_STAT_DEPTH)
|
|
||||||
s->nodesizes[n->bits]++;
|
|
||||||
|
|
||||||
- for (i = 0; i < tnode_child_length(n); i++)
|
|
||||||
+ for (i = 0; i < tnode_child_length(n); i++) {
|
|
||||||
if (!rcu_access_pointer(n->child[i]))
|
|
||||||
s->nullpointers++;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
@ -1,403 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:24 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Push rcu_read_lock/unlock to callers
|
|
||||||
|
|
||||||
This change is to start cleaning up some of the rcu_read_lock/unlock
|
|
||||||
handling. I realized while reviewing the code there are several spots that
|
|
||||||
I don't believe are being handled correctly or are masking warnings by
|
|
||||||
locally calling rcu_read_lock/unlock instead of calling them at the correct
|
|
||||||
level.
|
|
||||||
|
|
||||||
A common example is a call to fib_get_table followed by fib_table_lookup.
|
|
||||||
The rcu_read_lock/unlock ought to wrap both but there are several spots where
|
|
||||||
they were not wrapped.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/include/net/ip_fib.h
|
|
||||||
+++ b/include/net/ip_fib.h
|
|
||||||
@@ -222,16 +222,19 @@ static inline struct fib_table *fib_new_
|
|
||||||
static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
|
|
||||||
struct fib_result *res)
|
|
||||||
{
|
|
||||||
- struct fib_table *table;
|
|
||||||
+ int err = -ENETUNREACH;
|
|
||||||
|
|
||||||
- table = fib_get_table(net, RT_TABLE_LOCAL);
|
|
||||||
- if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
|
|
||||||
- return 0;
|
|
||||||
-
|
|
||||||
- table = fib_get_table(net, RT_TABLE_MAIN);
|
|
||||||
- if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
|
|
||||||
- return 0;
|
|
||||||
- return -ENETUNREACH;
|
|
||||||
+ rcu_read_lock();
|
|
||||||
+
|
|
||||||
+ if (!fib_table_lookup(fib_get_table(net, RT_TABLE_LOCAL), flp, res,
|
|
||||||
+ FIB_LOOKUP_NOREF) ||
|
|
||||||
+ !fib_table_lookup(fib_get_table(net, RT_TABLE_MAIN), flp, res,
|
|
||||||
+ FIB_LOOKUP_NOREF))
|
|
||||||
+ err = 0;
|
|
||||||
+
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* CONFIG_IP_MULTIPLE_TABLES */
|
|
||||||
@@ -247,20 +250,25 @@ static inline int fib_lookup(struct net
|
|
||||||
struct fib_result *res)
|
|
||||||
{
|
|
||||||
if (!net->ipv4.fib_has_custom_rules) {
|
|
||||||
+ int err = -ENETUNREACH;
|
|
||||||
+
|
|
||||||
+ rcu_read_lock();
|
|
||||||
+
|
|
||||||
res->tclassid = 0;
|
|
||||||
- if (net->ipv4.fib_local &&
|
|
||||||
- !fib_table_lookup(net->ipv4.fib_local, flp, res,
|
|
||||||
- FIB_LOOKUP_NOREF))
|
|
||||||
- return 0;
|
|
||||||
- if (net->ipv4.fib_main &&
|
|
||||||
- !fib_table_lookup(net->ipv4.fib_main, flp, res,
|
|
||||||
- FIB_LOOKUP_NOREF))
|
|
||||||
- return 0;
|
|
||||||
- if (net->ipv4.fib_default &&
|
|
||||||
- !fib_table_lookup(net->ipv4.fib_default, flp, res,
|
|
||||||
- FIB_LOOKUP_NOREF))
|
|
||||||
- return 0;
|
|
||||||
- return -ENETUNREACH;
|
|
||||||
+ if ((net->ipv4.fib_local &&
|
|
||||||
+ !fib_table_lookup(net->ipv4.fib_local, flp, res,
|
|
||||||
+ FIB_LOOKUP_NOREF)) ||
|
|
||||||
+ (net->ipv4.fib_main &&
|
|
||||||
+ !fib_table_lookup(net->ipv4.fib_main, flp, res,
|
|
||||||
+ FIB_LOOKUP_NOREF)) ||
|
|
||||||
+ (net->ipv4.fib_default &&
|
|
||||||
+ !fib_table_lookup(net->ipv4.fib_default, flp, res,
|
|
||||||
+ FIB_LOOKUP_NOREF)))
|
|
||||||
+ err = 0;
|
|
||||||
+
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
}
|
|
||||||
return __fib_lookup(net, flp, res);
|
|
||||||
}
|
|
||||||
--- a/net/ipv4/fib_frontend.c
|
|
||||||
+++ b/net/ipv4/fib_frontend.c
|
|
||||||
@@ -109,6 +109,7 @@ struct fib_table *fib_new_table(struct n
|
|
||||||
return tb;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/* caller must hold either rtnl or rcu read lock */
|
|
||||||
struct fib_table *fib_get_table(struct net *net, u32 id)
|
|
||||||
{
|
|
||||||
struct fib_table *tb;
|
|
||||||
@@ -119,15 +120,11 @@ struct fib_table *fib_get_table(struct n
|
|
||||||
id = RT_TABLE_MAIN;
|
|
||||||
h = id & (FIB_TABLE_HASHSZ - 1);
|
|
||||||
|
|
||||||
- rcu_read_lock();
|
|
||||||
head = &net->ipv4.fib_table_hash[h];
|
|
||||||
hlist_for_each_entry_rcu(tb, head, tb_hlist) {
|
|
||||||
- if (tb->tb_id == id) {
|
|
||||||
- rcu_read_unlock();
|
|
||||||
+ if (tb->tb_id == id)
|
|
||||||
return tb;
|
|
||||||
- }
|
|
||||||
}
|
|
||||||
- rcu_read_unlock();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_IP_MULTIPLE_TABLES */
|
|
||||||
@@ -167,16 +164,18 @@ static inline unsigned int __inet_dev_ad
|
|
||||||
if (ipv4_is_multicast(addr))
|
|
||||||
return RTN_MULTICAST;
|
|
||||||
|
|
||||||
+ rcu_read_lock();
|
|
||||||
+
|
|
||||||
local_table = fib_get_table(net, RT_TABLE_LOCAL);
|
|
||||||
if (local_table) {
|
|
||||||
ret = RTN_UNICAST;
|
|
||||||
- rcu_read_lock();
|
|
||||||
if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) {
|
|
||||||
if (!dev || dev == res.fi->fib_dev)
|
|
||||||
ret = res.type;
|
|
||||||
}
|
|
||||||
- rcu_read_unlock();
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -923,7 +922,7 @@ no_promotions:
|
|
||||||
#undef BRD1_OK
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
|
|
||||||
+static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn)
|
|
||||||
{
|
|
||||||
|
|
||||||
struct fib_result res;
|
|
||||||
@@ -933,6 +932,11 @@ static void nl_fib_lookup(struct fib_res
|
|
||||||
.flowi4_tos = frn->fl_tos,
|
|
||||||
.flowi4_scope = frn->fl_scope,
|
|
||||||
};
|
|
||||||
+ struct fib_table *tb;
|
|
||||||
+
|
|
||||||
+ rcu_read_lock();
|
|
||||||
+
|
|
||||||
+ tb = fib_get_table(net, frn->tb_id_in);
|
|
||||||
|
|
||||||
frn->err = -ENOENT;
|
|
||||||
if (tb) {
|
|
||||||
@@ -949,6 +953,8 @@ static void nl_fib_lookup(struct fib_res
|
|
||||||
}
|
|
||||||
local_bh_enable();
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nl_fib_input(struct sk_buff *skb)
|
|
||||||
@@ -956,7 +962,6 @@ static void nl_fib_input(struct sk_buff
|
|
||||||
struct net *net;
|
|
||||||
struct fib_result_nl *frn;
|
|
||||||
struct nlmsghdr *nlh;
|
|
||||||
- struct fib_table *tb;
|
|
||||||
u32 portid;
|
|
||||||
|
|
||||||
net = sock_net(skb->sk);
|
|
||||||
@@ -972,9 +977,7 @@ static void nl_fib_input(struct sk_buff
|
|
||||||
nlh = nlmsg_hdr(skb);
|
|
||||||
|
|
||||||
frn = (struct fib_result_nl *) nlmsg_data(nlh);
|
|
||||||
- tb = fib_get_table(net, frn->tb_id_in);
|
|
||||||
-
|
|
||||||
- nl_fib_lookup(frn, tb);
|
|
||||||
+ nl_fib_lookup(net, frn);
|
|
||||||
|
|
||||||
portid = NETLINK_CB(skb).portid; /* netlink portid */
|
|
||||||
NETLINK_CB(skb).portid = 0; /* from kernel */
|
|
||||||
--- a/net/ipv4/fib_rules.c
|
|
||||||
+++ b/net/ipv4/fib_rules.c
|
|
||||||
@@ -81,27 +81,25 @@ static int fib4_rule_action(struct fib_r
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FR_ACT_UNREACHABLE:
|
|
||||||
- err = -ENETUNREACH;
|
|
||||||
- goto errout;
|
|
||||||
+ return -ENETUNREACH;
|
|
||||||
|
|
||||||
case FR_ACT_PROHIBIT:
|
|
||||||
- err = -EACCES;
|
|
||||||
- goto errout;
|
|
||||||
+ return -EACCES;
|
|
||||||
|
|
||||||
case FR_ACT_BLACKHOLE:
|
|
||||||
default:
|
|
||||||
- err = -EINVAL;
|
|
||||||
- goto errout;
|
|
||||||
+ return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ rcu_read_lock();
|
|
||||||
+
|
|
||||||
tbl = fib_get_table(rule->fr_net, rule->table);
|
|
||||||
- if (!tbl)
|
|
||||||
- goto errout;
|
|
||||||
+ if (tbl)
|
|
||||||
+ err = fib_table_lookup(tbl, &flp->u.ip4,
|
|
||||||
+ (struct fib_result *)arg->result,
|
|
||||||
+ arg->flags);
|
|
||||||
|
|
||||||
- err = fib_table_lookup(tbl, &flp->u.ip4, (struct fib_result *) arg->result, arg->flags);
|
|
||||||
- if (err > 0)
|
|
||||||
- err = -EAGAIN;
|
|
||||||
-errout:
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -1181,72 +1181,6 @@ err:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
-/* should be called with rcu_read_lock */
|
|
||||||
-static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l,
|
|
||||||
- t_key key, const struct flowi4 *flp,
|
|
||||||
- struct fib_result *res, int fib_flags)
|
|
||||||
-{
|
|
||||||
- struct leaf_info *li;
|
|
||||||
- struct hlist_head *hhead = &l->list;
|
|
||||||
-
|
|
||||||
- hlist_for_each_entry_rcu(li, hhead, hlist) {
|
|
||||||
- struct fib_alias *fa;
|
|
||||||
-
|
|
||||||
- if (l->key != (key & li->mask_plen))
|
|
||||||
- continue;
|
|
||||||
-
|
|
||||||
- list_for_each_entry_rcu(fa, &li->falh, fa_list) {
|
|
||||||
- struct fib_info *fi = fa->fa_info;
|
|
||||||
- int nhsel, err;
|
|
||||||
-
|
|
||||||
- if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
|
|
||||||
- continue;
|
|
||||||
- if (fi->fib_dead)
|
|
||||||
- continue;
|
|
||||||
- if (fa->fa_info->fib_scope < flp->flowi4_scope)
|
|
||||||
- continue;
|
|
||||||
- fib_alias_accessed(fa);
|
|
||||||
- err = fib_props[fa->fa_type].error;
|
|
||||||
- if (unlikely(err < 0)) {
|
|
||||||
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- this_cpu_inc(t->stats->semantic_match_passed);
|
|
||||||
-#endif
|
|
||||||
- return err;
|
|
||||||
- }
|
|
||||||
- if (fi->fib_flags & RTNH_F_DEAD)
|
|
||||||
- continue;
|
|
||||||
- for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
|
|
||||||
- const struct fib_nh *nh = &fi->fib_nh[nhsel];
|
|
||||||
-
|
|
||||||
- if (nh->nh_flags & RTNH_F_DEAD)
|
|
||||||
- continue;
|
|
||||||
- if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
|
|
||||||
- continue;
|
|
||||||
-
|
|
||||||
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- this_cpu_inc(t->stats->semantic_match_passed);
|
|
||||||
-#endif
|
|
||||||
- res->prefixlen = li->plen;
|
|
||||||
- res->nh_sel = nhsel;
|
|
||||||
- res->type = fa->fa_type;
|
|
||||||
- res->scope = fi->fib_scope;
|
|
||||||
- res->fi = fi;
|
|
||||||
- res->table = tb;
|
|
||||||
- res->fa_head = &li->falh;
|
|
||||||
- if (!(fib_flags & FIB_LOOKUP_NOREF))
|
|
||||||
- atomic_inc(&fi->fib_clntref);
|
|
||||||
- return 0;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- this_cpu_inc(t->stats->semantic_match_miss);
|
|
||||||
-#endif
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- return 1;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static inline t_key prefix_mismatch(t_key key, struct tnode *n)
|
|
||||||
{
|
|
||||||
t_key prefix = n->key;
|
|
||||||
@@ -1254,6 +1188,7 @@ static inline t_key prefix_mismatch(t_ke
|
|
||||||
return (key ^ prefix) & (prefix | -prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
+/* should be called with rcu_read_lock */
|
|
||||||
int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
|
|
||||||
struct fib_result *res, int fib_flags)
|
|
||||||
{
|
|
||||||
@@ -1263,14 +1198,12 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
#endif
|
|
||||||
const t_key key = ntohl(flp->daddr);
|
|
||||||
struct tnode *n, *pn;
|
|
||||||
+ struct leaf_info *li;
|
|
||||||
t_key cindex;
|
|
||||||
- int ret = 1;
|
|
||||||
-
|
|
||||||
- rcu_read_lock();
|
|
||||||
|
|
||||||
n = rcu_dereference(t->trie);
|
|
||||||
if (!n)
|
|
||||||
- goto failed;
|
|
||||||
+ return -EAGAIN;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
this_cpu_inc(stats->gets);
|
|
||||||
@@ -1350,7 +1283,7 @@ backtrace:
|
|
||||||
|
|
||||||
pn = node_parent_rcu(pn);
|
|
||||||
if (unlikely(!pn))
|
|
||||||
- goto failed;
|
|
||||||
+ return -EAGAIN;
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
this_cpu_inc(stats->backtrack);
|
|
||||||
#endif
|
|
||||||
@@ -1368,12 +1301,62 @@ backtrace:
|
|
||||||
|
|
||||||
found:
|
|
||||||
/* Step 3: Process the leaf, if that fails fall back to backtracing */
|
|
||||||
- ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
|
|
||||||
- if (unlikely(ret > 0))
|
|
||||||
- goto backtrace;
|
|
||||||
-failed:
|
|
||||||
- rcu_read_unlock();
|
|
||||||
- return ret;
|
|
||||||
+ hlist_for_each_entry_rcu(li, &n->list, hlist) {
|
|
||||||
+ struct fib_alias *fa;
|
|
||||||
+
|
|
||||||
+ if ((key ^ n->key) & li->mask_plen)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ list_for_each_entry_rcu(fa, &li->falh, fa_list) {
|
|
||||||
+ struct fib_info *fi = fa->fa_info;
|
|
||||||
+ int nhsel, err;
|
|
||||||
+
|
|
||||||
+ if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
|
|
||||||
+ continue;
|
|
||||||
+ if (fi->fib_dead)
|
|
||||||
+ continue;
|
|
||||||
+ if (fa->fa_info->fib_scope < flp->flowi4_scope)
|
|
||||||
+ continue;
|
|
||||||
+ fib_alias_accessed(fa);
|
|
||||||
+ err = fib_props[fa->fa_type].error;
|
|
||||||
+ if (unlikely(err < 0)) {
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ this_cpu_inc(stats->semantic_match_passed);
|
|
||||||
+#endif
|
|
||||||
+ return err;
|
|
||||||
+ }
|
|
||||||
+ if (fi->fib_flags & RTNH_F_DEAD)
|
|
||||||
+ continue;
|
|
||||||
+ for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
|
|
||||||
+ const struct fib_nh *nh = &fi->fib_nh[nhsel];
|
|
||||||
+
|
|
||||||
+ if (nh->nh_flags & RTNH_F_DEAD)
|
|
||||||
+ continue;
|
|
||||||
+ if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ if (!(fib_flags & FIB_LOOKUP_NOREF))
|
|
||||||
+ atomic_inc(&fi->fib_clntref);
|
|
||||||
+
|
|
||||||
+ res->prefixlen = li->plen;
|
|
||||||
+ res->nh_sel = nhsel;
|
|
||||||
+ res->type = fa->fa_type;
|
|
||||||
+ res->scope = fi->fib_scope;
|
|
||||||
+ res->fi = fi;
|
|
||||||
+ res->table = tb;
|
|
||||||
+ res->fa_head = &li->falh;
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ this_cpu_inc(stats->semantic_match_passed);
|
|
||||||
+#endif
|
|
||||||
+ return err;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ this_cpu_inc(stats->semantic_match_miss);
|
|
||||||
+#endif
|
|
||||||
+ }
|
|
||||||
+ goto backtrace;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(fib_table_lookup);
|
|
||||||
|
|
@ -1,345 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:31 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Move resize to after inflate/halve
|
|
||||||
|
|
||||||
This change consists of a cut/paste of resize to behind inflate and halve
|
|
||||||
so that I could remove the two function prototypes.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -149,8 +149,6 @@ struct trie {
|
|
||||||
static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
|
|
||||||
struct tnode *n, int wasfull);
|
|
||||||
static struct tnode *resize(struct trie *t, struct tnode *tn);
|
|
||||||
-static struct tnode *inflate(struct trie *t, struct tnode *tn);
|
|
||||||
-static struct tnode *halve(struct trie *t, struct tnode *tn);
|
|
||||||
/* tnodes to free after resize(); protected by RTNL */
|
|
||||||
static struct callback_head *tnode_free_head;
|
|
||||||
static size_t tnode_free_size;
|
|
||||||
@@ -447,161 +445,6 @@ static void put_child_root(struct tnode
|
|
||||||
rcu_assign_pointer(t->trie, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
-#define MAX_WORK 10
|
|
||||||
-static struct tnode *resize(struct trie *t, struct tnode *tn)
|
|
||||||
-{
|
|
||||||
- struct tnode *old_tn, *n = NULL;
|
|
||||||
- int inflate_threshold_use;
|
|
||||||
- int halve_threshold_use;
|
|
||||||
- int max_work;
|
|
||||||
-
|
|
||||||
- if (!tn)
|
|
||||||
- return NULL;
|
|
||||||
-
|
|
||||||
- pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
|
|
||||||
- tn, inflate_threshold, halve_threshold);
|
|
||||||
-
|
|
||||||
- /* No children */
|
|
||||||
- if (tn->empty_children > (tnode_child_length(tn) - 1))
|
|
||||||
- goto no_children;
|
|
||||||
-
|
|
||||||
- /* One child */
|
|
||||||
- if (tn->empty_children == (tnode_child_length(tn) - 1))
|
|
||||||
- goto one_child;
|
|
||||||
- /*
|
|
||||||
- * Double as long as the resulting node has a number of
|
|
||||||
- * nonempty nodes that are above the threshold.
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
- /*
|
|
||||||
- * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
|
|
||||||
- * the Helsinki University of Technology and Matti Tikkanen of Nokia
|
|
||||||
- * Telecommunications, page 6:
|
|
||||||
- * "A node is doubled if the ratio of non-empty children to all
|
|
||||||
- * children in the *doubled* node is at least 'high'."
|
|
||||||
- *
|
|
||||||
- * 'high' in this instance is the variable 'inflate_threshold'. It
|
|
||||||
- * is expressed as a percentage, so we multiply it with
|
|
||||||
- * tnode_child_length() and instead of multiplying by 2 (since the
|
|
||||||
- * child array will be doubled by inflate()) and multiplying
|
|
||||||
- * the left-hand side by 100 (to handle the percentage thing) we
|
|
||||||
- * multiply the left-hand side by 50.
|
|
||||||
- *
|
|
||||||
- * The left-hand side may look a bit weird: tnode_child_length(tn)
|
|
||||||
- * - tn->empty_children is of course the number of non-null children
|
|
||||||
- * in the current node. tn->full_children is the number of "full"
|
|
||||||
- * children, that is non-null tnodes with a skip value of 0.
|
|
||||||
- * All of those will be doubled in the resulting inflated tnode, so
|
|
||||||
- * we just count them one extra time here.
|
|
||||||
- *
|
|
||||||
- * A clearer way to write this would be:
|
|
||||||
- *
|
|
||||||
- * to_be_doubled = tn->full_children;
|
|
||||||
- * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
|
|
||||||
- * tn->full_children;
|
|
||||||
- *
|
|
||||||
- * new_child_length = tnode_child_length(tn) * 2;
|
|
||||||
- *
|
|
||||||
- * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
|
|
||||||
- * new_child_length;
|
|
||||||
- * if (new_fill_factor >= inflate_threshold)
|
|
||||||
- *
|
|
||||||
- * ...and so on, tho it would mess up the while () loop.
|
|
||||||
- *
|
|
||||||
- * anyway,
|
|
||||||
- * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
|
|
||||||
- * inflate_threshold
|
|
||||||
- *
|
|
||||||
- * avoid a division:
|
|
||||||
- * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
|
|
||||||
- * inflate_threshold * new_child_length
|
|
||||||
- *
|
|
||||||
- * expand not_to_be_doubled and to_be_doubled, and shorten:
|
|
||||||
- * 100 * (tnode_child_length(tn) - tn->empty_children +
|
|
||||||
- * tn->full_children) >= inflate_threshold * new_child_length
|
|
||||||
- *
|
|
||||||
- * expand new_child_length:
|
|
||||||
- * 100 * (tnode_child_length(tn) - tn->empty_children +
|
|
||||||
- * tn->full_children) >=
|
|
||||||
- * inflate_threshold * tnode_child_length(tn) * 2
|
|
||||||
- *
|
|
||||||
- * shorten again:
|
|
||||||
- * 50 * (tn->full_children + tnode_child_length(tn) -
|
|
||||||
- * tn->empty_children) >= inflate_threshold *
|
|
||||||
- * tnode_child_length(tn)
|
|
||||||
- *
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
- /* Keep root node larger */
|
|
||||||
-
|
|
||||||
- if (!node_parent(tn)) {
|
|
||||||
- inflate_threshold_use = inflate_threshold_root;
|
|
||||||
- halve_threshold_use = halve_threshold_root;
|
|
||||||
- } else {
|
|
||||||
- inflate_threshold_use = inflate_threshold;
|
|
||||||
- halve_threshold_use = halve_threshold;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- max_work = MAX_WORK;
|
|
||||||
- while ((tn->full_children > 0 && max_work-- &&
|
|
||||||
- 50 * (tn->full_children + tnode_child_length(tn)
|
|
||||||
- - tn->empty_children)
|
|
||||||
- >= inflate_threshold_use * tnode_child_length(tn))) {
|
|
||||||
-
|
|
||||||
- old_tn = tn;
|
|
||||||
- tn = inflate(t, tn);
|
|
||||||
-
|
|
||||||
- if (IS_ERR(tn)) {
|
|
||||||
- tn = old_tn;
|
|
||||||
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
-#endif
|
|
||||||
- break;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* Return if at least one inflate is run */
|
|
||||||
- if (max_work != MAX_WORK)
|
|
||||||
- return tn;
|
|
||||||
-
|
|
||||||
- /*
|
|
||||||
- * Halve as long as the number of empty children in this
|
|
||||||
- * node is above threshold.
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
- max_work = MAX_WORK;
|
|
||||||
- while (tn->bits > 1 && max_work-- &&
|
|
||||||
- 100 * (tnode_child_length(tn) - tn->empty_children) <
|
|
||||||
- halve_threshold_use * tnode_child_length(tn)) {
|
|
||||||
-
|
|
||||||
- old_tn = tn;
|
|
||||||
- tn = halve(t, tn);
|
|
||||||
- if (IS_ERR(tn)) {
|
|
||||||
- tn = old_tn;
|
|
||||||
-#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
- this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
-#endif
|
|
||||||
- break;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
-
|
|
||||||
- /* Only one child remains */
|
|
||||||
- if (tn->empty_children == (tnode_child_length(tn) - 1)) {
|
|
||||||
- unsigned long i;
|
|
||||||
-one_child:
|
|
||||||
- for (i = tnode_child_length(tn); !n && i;)
|
|
||||||
- n = tnode_get_child(tn, --i);
|
|
||||||
-no_children:
|
|
||||||
- /* compress one level */
|
|
||||||
- node_set_parent(n, NULL);
|
|
||||||
- tnode_free_safe(tn);
|
|
||||||
- return n;
|
|
||||||
- }
|
|
||||||
- return tn;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-
|
|
||||||
static void tnode_clean_free(struct tnode *tn)
|
|
||||||
{
|
|
||||||
struct tnode *tofree;
|
|
||||||
@@ -804,6 +647,160 @@ nomem:
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
+#define MAX_WORK 10
|
|
||||||
+static struct tnode *resize(struct trie *t, struct tnode *tn)
|
|
||||||
+{
|
|
||||||
+ struct tnode *old_tn, *n = NULL;
|
|
||||||
+ int inflate_threshold_use;
|
|
||||||
+ int halve_threshold_use;
|
|
||||||
+ int max_work;
|
|
||||||
+
|
|
||||||
+ if (!tn)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
|
|
||||||
+ tn, inflate_threshold, halve_threshold);
|
|
||||||
+
|
|
||||||
+ /* No children */
|
|
||||||
+ if (tn->empty_children > (tnode_child_length(tn) - 1))
|
|
||||||
+ goto no_children;
|
|
||||||
+
|
|
||||||
+ /* One child */
|
|
||||||
+ if (tn->empty_children == (tnode_child_length(tn) - 1))
|
|
||||||
+ goto one_child;
|
|
||||||
+ /*
|
|
||||||
+ * Double as long as the resulting node has a number of
|
|
||||||
+ * nonempty nodes that are above the threshold.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
|
|
||||||
+ * the Helsinki University of Technology and Matti Tikkanen of Nokia
|
|
||||||
+ * Telecommunications, page 6:
|
|
||||||
+ * "A node is doubled if the ratio of non-empty children to all
|
|
||||||
+ * children in the *doubled* node is at least 'high'."
|
|
||||||
+ *
|
|
||||||
+ * 'high' in this instance is the variable 'inflate_threshold'. It
|
|
||||||
+ * is expressed as a percentage, so we multiply it with
|
|
||||||
+ * tnode_child_length() and instead of multiplying by 2 (since the
|
|
||||||
+ * child array will be doubled by inflate()) and multiplying
|
|
||||||
+ * the left-hand side by 100 (to handle the percentage thing) we
|
|
||||||
+ * multiply the left-hand side by 50.
|
|
||||||
+ *
|
|
||||||
+ * The left-hand side may look a bit weird: tnode_child_length(tn)
|
|
||||||
+ * - tn->empty_children is of course the number of non-null children
|
|
||||||
+ * in the current node. tn->full_children is the number of "full"
|
|
||||||
+ * children, that is non-null tnodes with a skip value of 0.
|
|
||||||
+ * All of those will be doubled in the resulting inflated tnode, so
|
|
||||||
+ * we just count them one extra time here.
|
|
||||||
+ *
|
|
||||||
+ * A clearer way to write this would be:
|
|
||||||
+ *
|
|
||||||
+ * to_be_doubled = tn->full_children;
|
|
||||||
+ * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
|
|
||||||
+ * tn->full_children;
|
|
||||||
+ *
|
|
||||||
+ * new_child_length = tnode_child_length(tn) * 2;
|
|
||||||
+ *
|
|
||||||
+ * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
|
|
||||||
+ * new_child_length;
|
|
||||||
+ * if (new_fill_factor >= inflate_threshold)
|
|
||||||
+ *
|
|
||||||
+ * ...and so on, tho it would mess up the while () loop.
|
|
||||||
+ *
|
|
||||||
+ * anyway,
|
|
||||||
+ * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
|
|
||||||
+ * inflate_threshold
|
|
||||||
+ *
|
|
||||||
+ * avoid a division:
|
|
||||||
+ * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
|
|
||||||
+ * inflate_threshold * new_child_length
|
|
||||||
+ *
|
|
||||||
+ * expand not_to_be_doubled and to_be_doubled, and shorten:
|
|
||||||
+ * 100 * (tnode_child_length(tn) - tn->empty_children +
|
|
||||||
+ * tn->full_children) >= inflate_threshold * new_child_length
|
|
||||||
+ *
|
|
||||||
+ * expand new_child_length:
|
|
||||||
+ * 100 * (tnode_child_length(tn) - tn->empty_children +
|
|
||||||
+ * tn->full_children) >=
|
|
||||||
+ * inflate_threshold * tnode_child_length(tn) * 2
|
|
||||||
+ *
|
|
||||||
+ * shorten again:
|
|
||||||
+ * 50 * (tn->full_children + tnode_child_length(tn) -
|
|
||||||
+ * tn->empty_children) >= inflate_threshold *
|
|
||||||
+ * tnode_child_length(tn)
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+ /* Keep root node larger */
|
|
||||||
+
|
|
||||||
+ if (!node_parent(tn)) {
|
|
||||||
+ inflate_threshold_use = inflate_threshold_root;
|
|
||||||
+ halve_threshold_use = halve_threshold_root;
|
|
||||||
+ } else {
|
|
||||||
+ inflate_threshold_use = inflate_threshold;
|
|
||||||
+ halve_threshold_use = halve_threshold;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ max_work = MAX_WORK;
|
|
||||||
+ while ((tn->full_children > 0 && max_work-- &&
|
|
||||||
+ 50 * (tn->full_children + tnode_child_length(tn)
|
|
||||||
+ - tn->empty_children)
|
|
||||||
+ >= inflate_threshold_use * tnode_child_length(tn))) {
|
|
||||||
+
|
|
||||||
+ old_tn = tn;
|
|
||||||
+ tn = inflate(t, tn);
|
|
||||||
+
|
|
||||||
+ if (IS_ERR(tn)) {
|
|
||||||
+ tn = old_tn;
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
+#endif
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Return if at least one inflate is run */
|
|
||||||
+ if (max_work != MAX_WORK)
|
|
||||||
+ return tn;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Halve as long as the number of empty children in this
|
|
||||||
+ * node is above threshold.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+ max_work = MAX_WORK;
|
|
||||||
+ while (tn->bits > 1 && max_work-- &&
|
|
||||||
+ 100 * (tnode_child_length(tn) - tn->empty_children) <
|
|
||||||
+ halve_threshold_use * tnode_child_length(tn)) {
|
|
||||||
+
|
|
||||||
+ old_tn = tn;
|
|
||||||
+ tn = halve(t, tn);
|
|
||||||
+ if (IS_ERR(tn)) {
|
|
||||||
+ tn = old_tn;
|
|
||||||
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
+ this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
+#endif
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ /* Only one child remains */
|
|
||||||
+ if (tn->empty_children == (tnode_child_length(tn) - 1)) {
|
|
||||||
+ unsigned long i;
|
|
||||||
+one_child:
|
|
||||||
+ for (i = tnode_child_length(tn); !n && i;)
|
|
||||||
+ n = tnode_get_child(tn, --i);
|
|
||||||
+no_children:
|
|
||||||
+ /* compress one level */
|
|
||||||
+ node_set_parent(n, NULL);
|
|
||||||
+ tnode_free_safe(tn);
|
|
||||||
+ return n;
|
|
||||||
+ }
|
|
||||||
+ return tn;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/* readside must use rcu_read_lock currently dump routines
|
|
||||||
via get_fa_head and dump */
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:37 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Add functions should_inflate and should_halve
|
|
||||||
|
|
||||||
This change pulls the logic for if we should inflate/halve the nodes out
|
|
||||||
into separate functions. It also addresses what I believe is a bug where 1
|
|
||||||
full node is all that is needed to keep a node from ever being halved.
|
|
||||||
|
|
||||||
Simple script to reproduce the issue:
|
|
||||||
modprobe dummy; ifconfig dummy0 up
|
|
||||||
for i in `seq 0 255`; do ifconfig dummy0:$i 10.0.${i}.1/24 up; done
|
|
||||||
ifconfig dummy0:256 10.0.255.33/16 up
|
|
||||||
for i in `seq 0 254`; do ifconfig dummy0:$i down; done
|
|
||||||
|
|
||||||
Results from /proc/net/fib_triestat
|
|
||||||
Before:
|
|
||||||
Local:
|
|
||||||
Aver depth: 3.00
|
|
||||||
Max depth: 4
|
|
||||||
Leaves: 17
|
|
||||||
Prefixes: 18
|
|
||||||
Internal nodes: 11
|
|
||||||
1: 8 2: 2 10: 1
|
|
||||||
Pointers: 1048
|
|
||||||
Null ptrs: 1021
|
|
||||||
Total size: 11 kB
|
|
||||||
After:
|
|
||||||
Local:
|
|
||||||
Aver depth: 3.41
|
|
||||||
Max depth: 5
|
|
||||||
Leaves: 17
|
|
||||||
Prefixes: 18
|
|
||||||
Internal nodes: 12
|
|
||||||
1: 8 2: 3 3: 1
|
|
||||||
Pointers: 36
|
|
||||||
Null ptrs: 8
|
|
||||||
Total size: 3 kB
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -647,12 +647,94 @@ nomem:
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
+/* From "Implementing a dynamic compressed trie" by Stefan Nilsson of
|
|
||||||
+ * the Helsinki University of Technology and Matti Tikkanen of Nokia
|
|
||||||
+ * Telecommunications, page 6:
|
|
||||||
+ * "A node is doubled if the ratio of non-empty children to all
|
|
||||||
+ * children in the *doubled* node is at least 'high'."
|
|
||||||
+ *
|
|
||||||
+ * 'high' in this instance is the variable 'inflate_threshold'. It
|
|
||||||
+ * is expressed as a percentage, so we multiply it with
|
|
||||||
+ * tnode_child_length() and instead of multiplying by 2 (since the
|
|
||||||
+ * child array will be doubled by inflate()) and multiplying
|
|
||||||
+ * the left-hand side by 100 (to handle the percentage thing) we
|
|
||||||
+ * multiply the left-hand side by 50.
|
|
||||||
+ *
|
|
||||||
+ * The left-hand side may look a bit weird: tnode_child_length(tn)
|
|
||||||
+ * - tn->empty_children is of course the number of non-null children
|
|
||||||
+ * in the current node. tn->full_children is the number of "full"
|
|
||||||
+ * children, that is non-null tnodes with a skip value of 0.
|
|
||||||
+ * All of those will be doubled in the resulting inflated tnode, so
|
|
||||||
+ * we just count them one extra time here.
|
|
||||||
+ *
|
|
||||||
+ * A clearer way to write this would be:
|
|
||||||
+ *
|
|
||||||
+ * to_be_doubled = tn->full_children;
|
|
||||||
+ * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
|
|
||||||
+ * tn->full_children;
|
|
||||||
+ *
|
|
||||||
+ * new_child_length = tnode_child_length(tn) * 2;
|
|
||||||
+ *
|
|
||||||
+ * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
|
|
||||||
+ * new_child_length;
|
|
||||||
+ * if (new_fill_factor >= inflate_threshold)
|
|
||||||
+ *
|
|
||||||
+ * ...and so on, tho it would mess up the while () loop.
|
|
||||||
+ *
|
|
||||||
+ * anyway,
|
|
||||||
+ * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
|
|
||||||
+ * inflate_threshold
|
|
||||||
+ *
|
|
||||||
+ * avoid a division:
|
|
||||||
+ * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
|
|
||||||
+ * inflate_threshold * new_child_length
|
|
||||||
+ *
|
|
||||||
+ * expand not_to_be_doubled and to_be_doubled, and shorten:
|
|
||||||
+ * 100 * (tnode_child_length(tn) - tn->empty_children +
|
|
||||||
+ * tn->full_children) >= inflate_threshold * new_child_length
|
|
||||||
+ *
|
|
||||||
+ * expand new_child_length:
|
|
||||||
+ * 100 * (tnode_child_length(tn) - tn->empty_children +
|
|
||||||
+ * tn->full_children) >=
|
|
||||||
+ * inflate_threshold * tnode_child_length(tn) * 2
|
|
||||||
+ *
|
|
||||||
+ * shorten again:
|
|
||||||
+ * 50 * (tn->full_children + tnode_child_length(tn) -
|
|
||||||
+ * tn->empty_children) >= inflate_threshold *
|
|
||||||
+ * tnode_child_length(tn)
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+static bool should_inflate(const struct tnode *tn)
|
|
||||||
+{
|
|
||||||
+ unsigned long used = tnode_child_length(tn);
|
|
||||||
+ unsigned long threshold = used;
|
|
||||||
+
|
|
||||||
+ /* Keep root node larger */
|
|
||||||
+ threshold *= node_parent(tn) ? inflate_threshold :
|
|
||||||
+ inflate_threshold_root;
|
|
||||||
+ used += tn->full_children;
|
|
||||||
+ used -= tn->empty_children;
|
|
||||||
+
|
|
||||||
+ return tn->pos && ((50 * used) >= threshold);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static bool should_halve(const struct tnode *tn)
|
|
||||||
+{
|
|
||||||
+ unsigned long used = tnode_child_length(tn);
|
|
||||||
+ unsigned long threshold = used;
|
|
||||||
+
|
|
||||||
+ /* Keep root node larger */
|
|
||||||
+ threshold *= node_parent(tn) ? halve_threshold :
|
|
||||||
+ halve_threshold_root;
|
|
||||||
+ used -= tn->empty_children;
|
|
||||||
+
|
|
||||||
+ return (tn->bits > 1) && ((100 * used) < threshold);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#define MAX_WORK 10
|
|
||||||
static struct tnode *resize(struct trie *t, struct tnode *tn)
|
|
||||||
{
|
|
||||||
struct tnode *old_tn, *n = NULL;
|
|
||||||
- int inflate_threshold_use;
|
|
||||||
- int halve_threshold_use;
|
|
||||||
int max_work;
|
|
||||||
|
|
||||||
if (!tn)
|
|
||||||
@@ -668,86 +750,12 @@ static struct tnode *resize(struct trie
|
|
||||||
/* One child */
|
|
||||||
if (tn->empty_children == (tnode_child_length(tn) - 1))
|
|
||||||
goto one_child;
|
|
||||||
- /*
|
|
||||||
- * Double as long as the resulting node has a number of
|
|
||||||
- * nonempty nodes that are above the threshold.
|
|
||||||
- */
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
|
|
||||||
- * the Helsinki University of Technology and Matti Tikkanen of Nokia
|
|
||||||
- * Telecommunications, page 6:
|
|
||||||
- * "A node is doubled if the ratio of non-empty children to all
|
|
||||||
- * children in the *doubled* node is at least 'high'."
|
|
||||||
- *
|
|
||||||
- * 'high' in this instance is the variable 'inflate_threshold'. It
|
|
||||||
- * is expressed as a percentage, so we multiply it with
|
|
||||||
- * tnode_child_length() and instead of multiplying by 2 (since the
|
|
||||||
- * child array will be doubled by inflate()) and multiplying
|
|
||||||
- * the left-hand side by 100 (to handle the percentage thing) we
|
|
||||||
- * multiply the left-hand side by 50.
|
|
||||||
- *
|
|
||||||
- * The left-hand side may look a bit weird: tnode_child_length(tn)
|
|
||||||
- * - tn->empty_children is of course the number of non-null children
|
|
||||||
- * in the current node. tn->full_children is the number of "full"
|
|
||||||
- * children, that is non-null tnodes with a skip value of 0.
|
|
||||||
- * All of those will be doubled in the resulting inflated tnode, so
|
|
||||||
- * we just count them one extra time here.
|
|
||||||
- *
|
|
||||||
- * A clearer way to write this would be:
|
|
||||||
- *
|
|
||||||
- * to_be_doubled = tn->full_children;
|
|
||||||
- * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
|
|
||||||
- * tn->full_children;
|
|
||||||
- *
|
|
||||||
- * new_child_length = tnode_child_length(tn) * 2;
|
|
||||||
- *
|
|
||||||
- * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
|
|
||||||
- * new_child_length;
|
|
||||||
- * if (new_fill_factor >= inflate_threshold)
|
|
||||||
- *
|
|
||||||
- * ...and so on, tho it would mess up the while () loop.
|
|
||||||
- *
|
|
||||||
- * anyway,
|
|
||||||
- * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
|
|
||||||
- * inflate_threshold
|
|
||||||
- *
|
|
||||||
- * avoid a division:
|
|
||||||
- * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
|
|
||||||
- * inflate_threshold * new_child_length
|
|
||||||
- *
|
|
||||||
- * expand not_to_be_doubled and to_be_doubled, and shorten:
|
|
||||||
- * 100 * (tnode_child_length(tn) - tn->empty_children +
|
|
||||||
- * tn->full_children) >= inflate_threshold * new_child_length
|
|
||||||
- *
|
|
||||||
- * expand new_child_length:
|
|
||||||
- * 100 * (tnode_child_length(tn) - tn->empty_children +
|
|
||||||
- * tn->full_children) >=
|
|
||||||
- * inflate_threshold * tnode_child_length(tn) * 2
|
|
||||||
- *
|
|
||||||
- * shorten again:
|
|
||||||
- * 50 * (tn->full_children + tnode_child_length(tn) -
|
|
||||||
- * tn->empty_children) >= inflate_threshold *
|
|
||||||
- * tnode_child_length(tn)
|
|
||||||
- *
|
|
||||||
+ /* Double as long as the resulting node has a number of
|
|
||||||
+ * nonempty nodes that are above the threshold.
|
|
||||||
*/
|
|
||||||
-
|
|
||||||
- /* Keep root node larger */
|
|
||||||
-
|
|
||||||
- if (!node_parent(tn)) {
|
|
||||||
- inflate_threshold_use = inflate_threshold_root;
|
|
||||||
- halve_threshold_use = halve_threshold_root;
|
|
||||||
- } else {
|
|
||||||
- inflate_threshold_use = inflate_threshold;
|
|
||||||
- halve_threshold_use = halve_threshold;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
max_work = MAX_WORK;
|
|
||||||
- while ((tn->full_children > 0 && max_work-- &&
|
|
||||||
- 50 * (tn->full_children + tnode_child_length(tn)
|
|
||||||
- - tn->empty_children)
|
|
||||||
- >= inflate_threshold_use * tnode_child_length(tn))) {
|
|
||||||
-
|
|
||||||
+ while (should_inflate(tn) && max_work--) {
|
|
||||||
old_tn = tn;
|
|
||||||
tn = inflate(t, tn);
|
|
||||||
|
|
||||||
@@ -764,16 +772,11 @@ static struct tnode *resize(struct trie
|
|
||||||
if (max_work != MAX_WORK)
|
|
||||||
return tn;
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * Halve as long as the number of empty children in this
|
|
||||||
+ /* Halve as long as the number of empty children in this
|
|
||||||
* node is above threshold.
|
|
||||||
*/
|
|
||||||
-
|
|
||||||
max_work = MAX_WORK;
|
|
||||||
- while (tn->bits > 1 && max_work-- &&
|
|
||||||
- 100 * (tnode_child_length(tn) - tn->empty_children) <
|
|
||||||
- halve_threshold_use * tnode_child_length(tn)) {
|
|
||||||
-
|
|
||||||
+ while (should_halve(tn) && max_work--) {
|
|
||||||
old_tn = tn;
|
|
||||||
tn = halve(t, tn);
|
|
||||||
if (IS_ERR(tn)) {
|
|
@ -1,336 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:43 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Push assignment of child to parent down into
|
|
||||||
inflate/halve
|
|
||||||
|
|
||||||
This change makes it so that the assignment of the tnode to the parent is
|
|
||||||
handled directly within whatever function is currently handling the node be
|
|
||||||
it inflate, halve, or resize. By doing this we can avoid some of the need
|
|
||||||
to set NULL pointers in the tree while we are resizing the subnodes.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -146,9 +146,7 @@ struct trie {
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
-static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
|
|
||||||
- struct tnode *n, int wasfull);
|
|
||||||
-static struct tnode *resize(struct trie *t, struct tnode *tn);
|
|
||||||
+static void resize(struct trie *t, struct tnode *tn);
|
|
||||||
/* tnodes to free after resize(); protected by RTNL */
|
|
||||||
static struct callback_head *tnode_free_head;
|
|
||||||
static size_t tnode_free_size;
|
|
||||||
@@ -396,22 +394,13 @@ static inline int tnode_full(const struc
|
|
||||||
return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static inline void put_child(struct tnode *tn, unsigned long i,
|
|
||||||
- struct tnode *n)
|
|
||||||
-{
|
|
||||||
- tnode_put_child_reorg(tn, i, n, -1);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
- /*
|
|
||||||
- * Add a child at position i overwriting the old value.
|
|
||||||
- * Update the value of full_children and empty_children.
|
|
||||||
- */
|
|
||||||
-
|
|
||||||
-static void tnode_put_child_reorg(struct tnode *tn, unsigned long i,
|
|
||||||
- struct tnode *n, int wasfull)
|
|
||||||
+/* Add a child at position i overwriting the old value.
|
|
||||||
+ * Update the value of full_children and empty_children.
|
|
||||||
+ */
|
|
||||||
+static void put_child(struct tnode *tn, unsigned long i, struct tnode *n)
|
|
||||||
{
|
|
||||||
struct tnode *chi = rtnl_dereference(tn->child[i]);
|
|
||||||
- int isfull;
|
|
||||||
+ int isfull, wasfull;
|
|
||||||
|
|
||||||
BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
@@ -422,10 +411,9 @@ static void tnode_put_child_reorg(struct
|
|
||||||
tn->empty_children--;
|
|
||||||
|
|
||||||
/* update fullChildren */
|
|
||||||
- if (wasfull == -1)
|
|
||||||
- wasfull = tnode_full(tn, chi);
|
|
||||||
-
|
|
||||||
+ wasfull = tnode_full(tn, chi);
|
|
||||||
isfull = tnode_full(tn, n);
|
|
||||||
+
|
|
||||||
if (wasfull && !isfull)
|
|
||||||
tn->full_children--;
|
|
||||||
else if (!wasfull && isfull)
|
|
||||||
@@ -458,9 +446,10 @@ static void tnode_clean_free(struct tnod
|
|
||||||
node_free(tn);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct tnode *inflate(struct trie *t, struct tnode *oldtnode)
|
|
||||||
+static int inflate(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
unsigned long olen = tnode_child_length(oldtnode);
|
|
||||||
+ struct tnode *tp = node_parent(oldtnode);
|
|
||||||
struct tnode *tn;
|
|
||||||
unsigned long i;
|
|
||||||
t_key m;
|
|
||||||
@@ -468,9 +457,8 @@ static struct tnode *inflate(struct trie
|
|
||||||
pr_debug("In inflate\n");
|
|
||||||
|
|
||||||
tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1);
|
|
||||||
-
|
|
||||||
if (!tn)
|
|
||||||
- return ERR_PTR(-ENOMEM);
|
|
||||||
+ return -ENOMEM;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Preallocate and store tnodes before the actual work so we
|
|
||||||
@@ -564,30 +552,36 @@ static struct tnode *inflate(struct trie
|
|
||||||
put_child(left, j, rtnl_dereference(inode->child[j]));
|
|
||||||
put_child(right, j, rtnl_dereference(inode->child[j + size]));
|
|
||||||
}
|
|
||||||
- put_child(tn, 2*i, resize(t, left));
|
|
||||||
- put_child(tn, 2*i+1, resize(t, right));
|
|
||||||
+
|
|
||||||
+ put_child(tn, 2 * i, left);
|
|
||||||
+ put_child(tn, 2 * i + 1, right);
|
|
||||||
|
|
||||||
tnode_free_safe(inode);
|
|
||||||
+
|
|
||||||
+ resize(t, left);
|
|
||||||
+ resize(t, right);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ put_child_root(tp, t, tn->key, tn);
|
|
||||||
tnode_free_safe(oldtnode);
|
|
||||||
- return tn;
|
|
||||||
+ return 0;
|
|
||||||
nomem:
|
|
||||||
tnode_clean_free(tn);
|
|
||||||
- return ERR_PTR(-ENOMEM);
|
|
||||||
+ return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static struct tnode *halve(struct trie *t, struct tnode *oldtnode)
|
|
||||||
+static int halve(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
unsigned long olen = tnode_child_length(oldtnode);
|
|
||||||
+ struct tnode *tp = node_parent(oldtnode);
|
|
||||||
struct tnode *tn, *left, *right;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
pr_debug("In halve\n");
|
|
||||||
|
|
||||||
tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1);
|
|
||||||
-
|
|
||||||
if (!tn)
|
|
||||||
- return ERR_PTR(-ENOMEM);
|
|
||||||
+ return -ENOMEM;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Preallocate and store tnodes before the actual work so we
|
|
||||||
@@ -606,8 +600,10 @@ static struct tnode *halve(struct trie *
|
|
||||||
|
|
||||||
newn = tnode_new(left->key, oldtnode->pos, 1);
|
|
||||||
|
|
||||||
- if (!newn)
|
|
||||||
- goto nomem;
|
|
||||||
+ if (!newn) {
|
|
||||||
+ tnode_clean_free(tn);
|
|
||||||
+ return -ENOMEM;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
put_child(tn, i/2, newn);
|
|
||||||
}
|
|
||||||
@@ -635,16 +631,18 @@ static struct tnode *halve(struct trie *
|
|
||||||
|
|
||||||
/* Two nonempty children */
|
|
||||||
newBinNode = tnode_get_child(tn, i/2);
|
|
||||||
- put_child(tn, i/2, NULL);
|
|
||||||
put_child(newBinNode, 0, left);
|
|
||||||
put_child(newBinNode, 1, right);
|
|
||||||
- put_child(tn, i/2, resize(t, newBinNode));
|
|
||||||
+
|
|
||||||
+ put_child(tn, i / 2, newBinNode);
|
|
||||||
+
|
|
||||||
+ resize(t, newBinNode);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ put_child_root(tp, t, tn->key, tn);
|
|
||||||
tnode_free_safe(oldtnode);
|
|
||||||
- return tn;
|
|
||||||
-nomem:
|
|
||||||
- tnode_clean_free(tn);
|
|
||||||
- return ERR_PTR(-ENOMEM);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* From "Implementing a dynamic compressed trie" by Stefan Nilsson of
|
|
||||||
@@ -704,45 +702,48 @@ nomem:
|
|
||||||
* tnode_child_length(tn)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
-static bool should_inflate(const struct tnode *tn)
|
|
||||||
+static bool should_inflate(const struct tnode *tp, const struct tnode *tn)
|
|
||||||
{
|
|
||||||
unsigned long used = tnode_child_length(tn);
|
|
||||||
unsigned long threshold = used;
|
|
||||||
|
|
||||||
/* Keep root node larger */
|
|
||||||
- threshold *= node_parent(tn) ? inflate_threshold :
|
|
||||||
- inflate_threshold_root;
|
|
||||||
+ threshold *= tp ? inflate_threshold : inflate_threshold_root;
|
|
||||||
used += tn->full_children;
|
|
||||||
used -= tn->empty_children;
|
|
||||||
|
|
||||||
return tn->pos && ((50 * used) >= threshold);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static bool should_halve(const struct tnode *tn)
|
|
||||||
+static bool should_halve(const struct tnode *tp, const struct tnode *tn)
|
|
||||||
{
|
|
||||||
unsigned long used = tnode_child_length(tn);
|
|
||||||
unsigned long threshold = used;
|
|
||||||
|
|
||||||
/* Keep root node larger */
|
|
||||||
- threshold *= node_parent(tn) ? halve_threshold :
|
|
||||||
- halve_threshold_root;
|
|
||||||
+ threshold *= tp ? halve_threshold : halve_threshold_root;
|
|
||||||
used -= tn->empty_children;
|
|
||||||
|
|
||||||
return (tn->bits > 1) && ((100 * used) < threshold);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_WORK 10
|
|
||||||
-static struct tnode *resize(struct trie *t, struct tnode *tn)
|
|
||||||
+static void resize(struct trie *t, struct tnode *tn)
|
|
||||||
{
|
|
||||||
- struct tnode *old_tn, *n = NULL;
|
|
||||||
+ struct tnode *tp = node_parent(tn), *n = NULL;
|
|
||||||
+ struct tnode __rcu **cptr;
|
|
||||||
int max_work;
|
|
||||||
|
|
||||||
- if (!tn)
|
|
||||||
- return NULL;
|
|
||||||
-
|
|
||||||
pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
|
|
||||||
tn, inflate_threshold, halve_threshold);
|
|
||||||
|
|
||||||
+ /* track the tnode via the pointer from the parent instead of
|
|
||||||
+ * doing it ourselves. This way we can let RCU fully do its
|
|
||||||
+ * thing without us interfering
|
|
||||||
+ */
|
|
||||||
+ cptr = tp ? &tp->child[get_index(tn->key, tp)] : &t->trie;
|
|
||||||
+ BUG_ON(tn != rtnl_dereference(*cptr));
|
|
||||||
+
|
|
||||||
/* No children */
|
|
||||||
if (tn->empty_children > (tnode_child_length(tn) - 1))
|
|
||||||
goto no_children;
|
|
||||||
@@ -755,39 +756,35 @@ static struct tnode *resize(struct trie
|
|
||||||
* nonempty nodes that are above the threshold.
|
|
||||||
*/
|
|
||||||
max_work = MAX_WORK;
|
|
||||||
- while (should_inflate(tn) && max_work--) {
|
|
||||||
- old_tn = tn;
|
|
||||||
- tn = inflate(t, tn);
|
|
||||||
-
|
|
||||||
- if (IS_ERR(tn)) {
|
|
||||||
- tn = old_tn;
|
|
||||||
+ while (should_inflate(tp, tn) && max_work--) {
|
|
||||||
+ if (inflate(t, tn)) {
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ tn = rtnl_dereference(*cptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return if at least one inflate is run */
|
|
||||||
if (max_work != MAX_WORK)
|
|
||||||
- return tn;
|
|
||||||
+ return;
|
|
||||||
|
|
||||||
/* Halve as long as the number of empty children in this
|
|
||||||
* node is above threshold.
|
|
||||||
*/
|
|
||||||
max_work = MAX_WORK;
|
|
||||||
- while (should_halve(tn) && max_work--) {
|
|
||||||
- old_tn = tn;
|
|
||||||
- tn = halve(t, tn);
|
|
||||||
- if (IS_ERR(tn)) {
|
|
||||||
- tn = old_tn;
|
|
||||||
+ while (should_halve(tp, tn) && max_work--) {
|
|
||||||
+ if (halve(t, tn)) {
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
- }
|
|
||||||
|
|
||||||
+ tn = rtnl_dereference(*cptr);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* Only one child remains */
|
|
||||||
if (tn->empty_children == (tnode_child_length(tn) - 1)) {
|
|
||||||
@@ -797,11 +794,12 @@ one_child:
|
|
||||||
n = tnode_get_child(tn, --i);
|
|
||||||
no_children:
|
|
||||||
/* compress one level */
|
|
||||||
- node_set_parent(n, NULL);
|
|
||||||
+ put_child_root(tp, t, tn->key, n);
|
|
||||||
+ node_set_parent(n, tp);
|
|
||||||
+
|
|
||||||
+ /* drop dead node */
|
|
||||||
tnode_free_safe(tn);
|
|
||||||
- return n;
|
|
||||||
}
|
|
||||||
- return tn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* readside must use rcu_read_lock currently dump routines
|
|
||||||
@@ -882,34 +880,19 @@ static struct tnode *fib_find_node(struc
|
|
||||||
|
|
||||||
static void trie_rebalance(struct trie *t, struct tnode *tn)
|
|
||||||
{
|
|
||||||
- int wasfull;
|
|
||||||
- t_key cindex, key;
|
|
||||||
struct tnode *tp;
|
|
||||||
|
|
||||||
- key = tn->key;
|
|
||||||
-
|
|
||||||
- while (tn != NULL && (tp = node_parent(tn)) != NULL) {
|
|
||||||
- cindex = get_index(key, tp);
|
|
||||||
- wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
|
|
||||||
- tn = resize(t, tn);
|
|
||||||
-
|
|
||||||
- tnode_put_child_reorg(tp, cindex, tn, wasfull);
|
|
||||||
-
|
|
||||||
- tp = node_parent(tn);
|
|
||||||
- if (!tp)
|
|
||||||
- rcu_assign_pointer(t->trie, tn);
|
|
||||||
+ while ((tp = node_parent(tn)) != NULL) {
|
|
||||||
+ resize(t, tn);
|
|
||||||
|
|
||||||
tnode_free_flush();
|
|
||||||
- if (!tp)
|
|
||||||
- break;
|
|
||||||
tn = tp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle last (top) tnode */
|
|
||||||
if (IS_TNODE(tn))
|
|
||||||
- tn = resize(t, tn);
|
|
||||||
+ resize(t, tn);
|
|
||||||
|
|
||||||
- rcu_assign_pointer(t->trie, tn);
|
|
||||||
tnode_free_flush();
|
|
||||||
}
|
|
||||||
|
|
@ -1,237 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:49 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Push tnode flushing down to inflate/halve
|
|
||||||
|
|
||||||
This change pushes the tnode freeing down into the inflate and halve
|
|
||||||
functions. It makes more sense here as we have a better grasp of what is
|
|
||||||
going on and when a given cluster of nodes is ready to be freed.
|
|
||||||
|
|
||||||
I believe this may address a bug in the freeing logic as well. For some
|
|
||||||
reason if the freelist got to a certain size we would call
|
|
||||||
synchronize_rcu(). I'm assuming that what they meant to do is call
|
|
||||||
synchronize_rcu() after they had handed off that much memory via
|
|
||||||
call_rcu(). As such that is what I have updated the behavior to be.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -147,8 +147,6 @@ struct trie {
|
|
||||||
};
|
|
||||||
|
|
||||||
static void resize(struct trie *t, struct tnode *tn);
|
|
||||||
-/* tnodes to free after resize(); protected by RTNL */
|
|
||||||
-static struct callback_head *tnode_free_head;
|
|
||||||
static size_t tnode_free_size;
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -307,32 +305,6 @@ static struct tnode *tnode_alloc(size_t
|
|
||||||
return vzalloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void tnode_free_safe(struct tnode *tn)
|
|
||||||
-{
|
|
||||||
- BUG_ON(IS_LEAF(tn));
|
|
||||||
- tn->rcu.next = tnode_free_head;
|
|
||||||
- tnode_free_head = &tn->rcu;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-static void tnode_free_flush(void)
|
|
||||||
-{
|
|
||||||
- struct callback_head *head;
|
|
||||||
-
|
|
||||||
- while ((head = tnode_free_head)) {
|
|
||||||
- struct tnode *tn = container_of(head, struct tnode, rcu);
|
|
||||||
-
|
|
||||||
- tnode_free_head = head->next;
|
|
||||||
- tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]);
|
|
||||||
-
|
|
||||||
- node_free(tn);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (tnode_free_size >= PAGE_SIZE * sync_pages) {
|
|
||||||
- tnode_free_size = 0;
|
|
||||||
- synchronize_rcu();
|
|
||||||
- }
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static struct tnode *leaf_new(t_key key)
|
|
||||||
{
|
|
||||||
struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
|
|
||||||
@@ -433,17 +405,33 @@ static void put_child_root(struct tnode
|
|
||||||
rcu_assign_pointer(t->trie, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void tnode_clean_free(struct tnode *tn)
|
|
||||||
+static inline void tnode_free_init(struct tnode *tn)
|
|
||||||
{
|
|
||||||
- struct tnode *tofree;
|
|
||||||
- unsigned long i;
|
|
||||||
+ tn->rcu.next = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline void tnode_free_append(struct tnode *tn, struct tnode *n)
|
|
||||||
+{
|
|
||||||
+ n->rcu.next = tn->rcu.next;
|
|
||||||
+ tn->rcu.next = &n->rcu;
|
|
||||||
+}
|
|
||||||
|
|
||||||
- for (i = 0; i < tnode_child_length(tn); i++) {
|
|
||||||
- tofree = tnode_get_child(tn, i);
|
|
||||||
- if (tofree)
|
|
||||||
- node_free(tofree);
|
|
||||||
+static void tnode_free(struct tnode *tn)
|
|
||||||
+{
|
|
||||||
+ struct callback_head *head = &tn->rcu;
|
|
||||||
+
|
|
||||||
+ while (head) {
|
|
||||||
+ head = head->next;
|
|
||||||
+ tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]);
|
|
||||||
+ node_free(tn);
|
|
||||||
+
|
|
||||||
+ tn = container_of(head, struct tnode, rcu);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (tnode_free_size >= PAGE_SIZE * sync_pages) {
|
|
||||||
+ tnode_free_size = 0;
|
|
||||||
+ synchronize_rcu();
|
|
||||||
}
|
|
||||||
- node_free(tn);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int inflate(struct trie *t, struct tnode *oldtnode)
|
|
||||||
@@ -476,20 +464,23 @@ static int inflate(struct trie *t, struc
|
|
||||||
inode->bits - 1);
|
|
||||||
if (!left)
|
|
||||||
goto nomem;
|
|
||||||
+ tnode_free_append(tn, left);
|
|
||||||
|
|
||||||
right = tnode_new(inode->key | m, inode->pos,
|
|
||||||
inode->bits - 1);
|
|
||||||
|
|
||||||
- if (!right) {
|
|
||||||
- node_free(left);
|
|
||||||
+ if (!right)
|
|
||||||
goto nomem;
|
|
||||||
- }
|
|
||||||
+ tnode_free_append(tn, right);
|
|
||||||
|
|
||||||
put_child(tn, 2*i, left);
|
|
||||||
put_child(tn, 2*i+1, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* prepare oldtnode to be freed */
|
|
||||||
+ tnode_free_init(oldtnode);
|
|
||||||
+
|
|
||||||
for (i = 0; i < olen; i++) {
|
|
||||||
struct tnode *inode = tnode_get_child(oldtnode, i);
|
|
||||||
struct tnode *left, *right;
|
|
||||||
@@ -505,12 +496,13 @@ static int inflate(struct trie *t, struc
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* drop the node in the old tnode free list */
|
|
||||||
+ tnode_free_append(oldtnode, inode);
|
|
||||||
+
|
|
||||||
/* An internal node with two children */
|
|
||||||
if (inode->bits == 1) {
|
|
||||||
put_child(tn, 2*i, rtnl_dereference(inode->child[0]));
|
|
||||||
put_child(tn, 2*i+1, rtnl_dereference(inode->child[1]));
|
|
||||||
-
|
|
||||||
- tnode_free_safe(inode);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -556,17 +548,19 @@ static int inflate(struct trie *t, struc
|
|
||||||
put_child(tn, 2 * i, left);
|
|
||||||
put_child(tn, 2 * i + 1, right);
|
|
||||||
|
|
||||||
- tnode_free_safe(inode);
|
|
||||||
-
|
|
||||||
+ /* resize child nodes */
|
|
||||||
resize(t, left);
|
|
||||||
resize(t, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
put_child_root(tp, t, tn->key, tn);
|
|
||||||
- tnode_free_safe(oldtnode);
|
|
||||||
+
|
|
||||||
+ /* we completed without error, prepare to free old node */
|
|
||||||
+ tnode_free(oldtnode);
|
|
||||||
return 0;
|
|
||||||
nomem:
|
|
||||||
- tnode_clean_free(tn);
|
|
||||||
+ /* all pointers should be clean so we are done */
|
|
||||||
+ tnode_free(tn);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -599,17 +593,20 @@ static int halve(struct trie *t, struct
|
|
||||||
struct tnode *newn;
|
|
||||||
|
|
||||||
newn = tnode_new(left->key, oldtnode->pos, 1);
|
|
||||||
-
|
|
||||||
if (!newn) {
|
|
||||||
- tnode_clean_free(tn);
|
|
||||||
+ tnode_free(tn);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
+ tnode_free_append(tn, newn);
|
|
||||||
|
|
||||||
put_child(tn, i/2, newn);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* prepare oldtnode to be freed */
|
|
||||||
+ tnode_free_init(oldtnode);
|
|
||||||
+
|
|
||||||
for (i = 0; i < olen; i += 2) {
|
|
||||||
struct tnode *newBinNode;
|
|
||||||
|
|
||||||
@@ -636,11 +633,14 @@ static int halve(struct trie *t, struct
|
|
||||||
|
|
||||||
put_child(tn, i / 2, newBinNode);
|
|
||||||
|
|
||||||
+ /* resize child node */
|
|
||||||
resize(t, newBinNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
put_child_root(tp, t, tn->key, tn);
|
|
||||||
- tnode_free_safe(oldtnode);
|
|
||||||
+
|
|
||||||
+ /* all pointers should be clean so we are done */
|
|
||||||
+ tnode_free(oldtnode);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -798,7 +798,8 @@ no_children:
|
|
||||||
node_set_parent(n, tp);
|
|
||||||
|
|
||||||
/* drop dead node */
|
|
||||||
- tnode_free_safe(tn);
|
|
||||||
+ tnode_free_init(tn);
|
|
||||||
+ tnode_free(tn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -884,16 +885,12 @@ static void trie_rebalance(struct trie *
|
|
||||||
|
|
||||||
while ((tp = node_parent(tn)) != NULL) {
|
|
||||||
resize(t, tn);
|
|
||||||
-
|
|
||||||
- tnode_free_flush();
|
|
||||||
tn = tp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle last (top) tnode */
|
|
||||||
if (IS_TNODE(tn))
|
|
||||||
resize(t, tn);
|
|
||||||
-
|
|
||||||
- tnode_free_flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* only used from updater-side */
|
|
@ -1,345 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:56:55 -0800
|
|
||||||
Subject: [PATCH] fib_trie: inflate/halve nodes in a more RCU friendly
|
|
||||||
way
|
|
||||||
|
|
||||||
This change pulls the node_set_parent functionality out of put_child_reorg
|
|
||||||
and instead leaves that to the function to take care of as well. By doing
|
|
||||||
this we can fully construct the new cluster of tnodes and all of the
|
|
||||||
pointers out of it before we start routing pointers into it.
|
|
||||||
|
|
||||||
I am suspecting this will likely fix some concurency issues though I don't
|
|
||||||
have a good test to show as such.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -391,8 +391,6 @@ static void put_child(struct tnode *tn,
|
|
||||||
else if (!wasfull && isfull)
|
|
||||||
tn->full_children++;
|
|
||||||
|
|
||||||
- node_set_parent(n, tn);
|
|
||||||
-
|
|
||||||
rcu_assign_pointer(tn->child[i], n);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -436,10 +434,8 @@ static void tnode_free(struct tnode *tn)
|
|
||||||
|
|
||||||
static int inflate(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
- unsigned long olen = tnode_child_length(oldtnode);
|
|
||||||
- struct tnode *tp = node_parent(oldtnode);
|
|
||||||
- struct tnode *tn;
|
|
||||||
- unsigned long i;
|
|
||||||
+ struct tnode *inode, *node0, *node1, *tn, *tp;
|
|
||||||
+ unsigned long i, j, k;
|
|
||||||
t_key m;
|
|
||||||
|
|
||||||
pr_debug("In inflate\n");
|
|
||||||
@@ -448,43 +444,13 @@ static int inflate(struct trie *t, struc
|
|
||||||
if (!tn)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * Preallocate and store tnodes before the actual work so we
|
|
||||||
- * don't get into an inconsistent state if memory allocation
|
|
||||||
- * fails. In case of failure we return the oldnode and inflate
|
|
||||||
- * of tnode is ignored.
|
|
||||||
+ /* Assemble all of the pointers in our cluster, in this case that
|
|
||||||
+ * represents all of the pointers out of our allocated nodes that
|
|
||||||
+ * point to existing tnodes and the links between our allocated
|
|
||||||
+ * nodes.
|
|
||||||
*/
|
|
||||||
- for (i = 0, m = 1u << tn->pos; i < olen; i++) {
|
|
||||||
- struct tnode *inode = tnode_get_child(oldtnode, i);
|
|
||||||
-
|
|
||||||
- if (tnode_full(oldtnode, inode) && (inode->bits > 1)) {
|
|
||||||
- struct tnode *left, *right;
|
|
||||||
-
|
|
||||||
- left = tnode_new(inode->key & ~m, inode->pos,
|
|
||||||
- inode->bits - 1);
|
|
||||||
- if (!left)
|
|
||||||
- goto nomem;
|
|
||||||
- tnode_free_append(tn, left);
|
|
||||||
-
|
|
||||||
- right = tnode_new(inode->key | m, inode->pos,
|
|
||||||
- inode->bits - 1);
|
|
||||||
-
|
|
||||||
- if (!right)
|
|
||||||
- goto nomem;
|
|
||||||
- tnode_free_append(tn, right);
|
|
||||||
-
|
|
||||||
- put_child(tn, 2*i, left);
|
|
||||||
- put_child(tn, 2*i+1, right);
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* prepare oldtnode to be freed */
|
|
||||||
- tnode_free_init(oldtnode);
|
|
||||||
-
|
|
||||||
- for (i = 0; i < olen; i++) {
|
|
||||||
- struct tnode *inode = tnode_get_child(oldtnode, i);
|
|
||||||
- struct tnode *left, *right;
|
|
||||||
- unsigned long size, j;
|
|
||||||
+ for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) {
|
|
||||||
+ inode = tnode_get_child(oldtnode, --i);
|
|
||||||
|
|
||||||
/* An empty child */
|
|
||||||
if (inode == NULL)
|
|
||||||
@@ -496,65 +462,99 @@ static int inflate(struct trie *t, struc
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* drop the node in the old tnode free list */
|
|
||||||
- tnode_free_append(oldtnode, inode);
|
|
||||||
-
|
|
||||||
/* An internal node with two children */
|
|
||||||
if (inode->bits == 1) {
|
|
||||||
- put_child(tn, 2*i, rtnl_dereference(inode->child[0]));
|
|
||||||
- put_child(tn, 2*i+1, rtnl_dereference(inode->child[1]));
|
|
||||||
+ put_child(tn, 2 * i + 1, tnode_get_child(inode, 1));
|
|
||||||
+ put_child(tn, 2 * i, tnode_get_child(inode, 0));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* An internal node with more than two children */
|
|
||||||
-
|
|
||||||
/* We will replace this node 'inode' with two new
|
|
||||||
- * ones, 'left' and 'right', each with half of the
|
|
||||||
+ * ones, 'node0' and 'node1', each with half of the
|
|
||||||
* original children. The two new nodes will have
|
|
||||||
* a position one bit further down the key and this
|
|
||||||
* means that the "significant" part of their keys
|
|
||||||
* (see the discussion near the top of this file)
|
|
||||||
* will differ by one bit, which will be "0" in
|
|
||||||
- * left's key and "1" in right's key. Since we are
|
|
||||||
+ * node0's key and "1" in node1's key. Since we are
|
|
||||||
* moving the key position by one step, the bit that
|
|
||||||
* we are moving away from - the bit at position
|
|
||||||
- * (inode->pos) - is the one that will differ between
|
|
||||||
- * left and right. So... we synthesize that bit in the
|
|
||||||
- * two new keys.
|
|
||||||
- * The mask 'm' below will be a single "one" bit at
|
|
||||||
- * the position (inode->pos)
|
|
||||||
+ * (tn->pos) - is the one that will differ between
|
|
||||||
+ * node0 and node1. So... we synthesize that bit in the
|
|
||||||
+ * two new keys.
|
|
||||||
*/
|
|
||||||
+ node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1);
|
|
||||||
+ if (!node1)
|
|
||||||
+ goto nomem;
|
|
||||||
+ tnode_free_append(tn, node1);
|
|
||||||
+
|
|
||||||
+ node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1);
|
|
||||||
+ if (!node0)
|
|
||||||
+ goto nomem;
|
|
||||||
+ tnode_free_append(tn, node0);
|
|
||||||
+
|
|
||||||
+ /* populate child pointers in new nodes */
|
|
||||||
+ for (k = tnode_child_length(inode), j = k / 2; j;) {
|
|
||||||
+ put_child(node1, --j, tnode_get_child(inode, --k));
|
|
||||||
+ put_child(node0, j, tnode_get_child(inode, j));
|
|
||||||
+ put_child(node1, --j, tnode_get_child(inode, --k));
|
|
||||||
+ put_child(node0, j, tnode_get_child(inode, j));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* link new nodes to parent */
|
|
||||||
+ NODE_INIT_PARENT(node1, tn);
|
|
||||||
+ NODE_INIT_PARENT(node0, tn);
|
|
||||||
+
|
|
||||||
+ /* link parent to nodes */
|
|
||||||
+ put_child(tn, 2 * i + 1, node1);
|
|
||||||
+ put_child(tn, 2 * i, node0);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* setup the parent pointer into and out of this node */
|
|
||||||
+ tp = node_parent(oldtnode);
|
|
||||||
+ NODE_INIT_PARENT(tn, tp);
|
|
||||||
+ put_child_root(tp, t, tn->key, tn);
|
|
||||||
|
|
||||||
- /* Use the old key, but set the new significant
|
|
||||||
- * bit to zero.
|
|
||||||
- */
|
|
||||||
+ /* prepare oldtnode to be freed */
|
|
||||||
+ tnode_free_init(oldtnode);
|
|
||||||
|
|
||||||
- left = tnode_get_child(tn, 2*i);
|
|
||||||
- put_child(tn, 2*i, NULL);
|
|
||||||
+ /* update all child nodes parent pointers to route to us */
|
|
||||||
+ for (i = tnode_child_length(oldtnode); i;) {
|
|
||||||
+ inode = tnode_get_child(oldtnode, --i);
|
|
||||||
|
|
||||||
- BUG_ON(!left);
|
|
||||||
+ /* A leaf or an internal node with skipped bits */
|
|
||||||
+ if (!tnode_full(oldtnode, inode)) {
|
|
||||||
+ node_set_parent(inode, tn);
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- right = tnode_get_child(tn, 2*i+1);
|
|
||||||
- put_child(tn, 2*i+1, NULL);
|
|
||||||
+ /* drop the node in the old tnode free list */
|
|
||||||
+ tnode_free_append(oldtnode, inode);
|
|
||||||
|
|
||||||
- BUG_ON(!right);
|
|
||||||
+ /* fetch new nodes */
|
|
||||||
+ node1 = tnode_get_child(tn, 2 * i + 1);
|
|
||||||
+ node0 = tnode_get_child(tn, 2 * i);
|
|
||||||
|
|
||||||
- size = tnode_child_length(left);
|
|
||||||
- for (j = 0; j < size; j++) {
|
|
||||||
- put_child(left, j, rtnl_dereference(inode->child[j]));
|
|
||||||
- put_child(right, j, rtnl_dereference(inode->child[j + size]));
|
|
||||||
+ /* bits == 1 then node0 and node1 represent inode's children */
|
|
||||||
+ if (inode->bits == 1) {
|
|
||||||
+ node_set_parent(node1, tn);
|
|
||||||
+ node_set_parent(node0, tn);
|
|
||||||
+ continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
- put_child(tn, 2 * i, left);
|
|
||||||
- put_child(tn, 2 * i + 1, right);
|
|
||||||
+ /* update parent pointers in child node's children */
|
|
||||||
+ for (k = tnode_child_length(inode), j = k / 2; j;) {
|
|
||||||
+ node_set_parent(tnode_get_child(inode, --k), node1);
|
|
||||||
+ node_set_parent(tnode_get_child(inode, --j), node0);
|
|
||||||
+ node_set_parent(tnode_get_child(inode, --k), node1);
|
|
||||||
+ node_set_parent(tnode_get_child(inode, --j), node0);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* resize child nodes */
|
|
||||||
- resize(t, left);
|
|
||||||
- resize(t, right);
|
|
||||||
+ resize(t, node1);
|
|
||||||
+ resize(t, node0);
|
|
||||||
}
|
|
||||||
|
|
||||||
- put_child_root(tp, t, tn->key, tn);
|
|
||||||
-
|
|
||||||
/* we completed without error, prepare to free old node */
|
|
||||||
tnode_free(oldtnode);
|
|
||||||
return 0;
|
|
||||||
@@ -566,10 +566,8 @@ nomem:
|
|
||||||
|
|
||||||
static int halve(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
- unsigned long olen = tnode_child_length(oldtnode);
|
|
||||||
- struct tnode *tp = node_parent(oldtnode);
|
|
||||||
- struct tnode *tn, *left, *right;
|
|
||||||
- int i;
|
|
||||||
+ struct tnode *tn, *tp, *inode, *node0, *node1;
|
|
||||||
+ unsigned long i;
|
|
||||||
|
|
||||||
pr_debug("In halve\n");
|
|
||||||
|
|
||||||
@@ -577,68 +575,64 @@ static int halve(struct trie *t, struct
|
|
||||||
if (!tn)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * Preallocate and store tnodes before the actual work so we
|
|
||||||
- * don't get into an inconsistent state if memory allocation
|
|
||||||
- * fails. In case of failure we return the oldnode and halve
|
|
||||||
- * of tnode is ignored.
|
|
||||||
+ /* Assemble all of the pointers in our cluster, in this case that
|
|
||||||
+ * represents all of the pointers out of our allocated nodes that
|
|
||||||
+ * point to existing tnodes and the links between our allocated
|
|
||||||
+ * nodes.
|
|
||||||
*/
|
|
||||||
+ for (i = tnode_child_length(oldtnode); i;) {
|
|
||||||
+ node1 = tnode_get_child(oldtnode, --i);
|
|
||||||
+ node0 = tnode_get_child(oldtnode, --i);
|
|
||||||
|
|
||||||
- for (i = 0; i < olen; i += 2) {
|
|
||||||
- left = tnode_get_child(oldtnode, i);
|
|
||||||
- right = tnode_get_child(oldtnode, i+1);
|
|
||||||
+ /* At least one of the children is empty */
|
|
||||||
+ if (!node1 || !node0) {
|
|
||||||
+ put_child(tn, i / 2, node1 ? : node0);
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* Two nonempty children */
|
|
||||||
- if (left && right) {
|
|
||||||
- struct tnode *newn;
|
|
||||||
-
|
|
||||||
- newn = tnode_new(left->key, oldtnode->pos, 1);
|
|
||||||
- if (!newn) {
|
|
||||||
- tnode_free(tn);
|
|
||||||
- return -ENOMEM;
|
|
||||||
- }
|
|
||||||
- tnode_free_append(tn, newn);
|
|
||||||
-
|
|
||||||
- put_child(tn, i/2, newn);
|
|
||||||
+ inode = tnode_new(node0->key, oldtnode->pos, 1);
|
|
||||||
+ if (!inode) {
|
|
||||||
+ tnode_free(tn);
|
|
||||||
+ return -ENOMEM;
|
|
||||||
}
|
|
||||||
+ tnode_free_append(tn, inode);
|
|
||||||
|
|
||||||
+ /* initialize pointers out of node */
|
|
||||||
+ put_child(inode, 1, node1);
|
|
||||||
+ put_child(inode, 0, node0);
|
|
||||||
+ NODE_INIT_PARENT(inode, tn);
|
|
||||||
+
|
|
||||||
+ /* link parent to node */
|
|
||||||
+ put_child(tn, i / 2, inode);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* setup the parent pointer out of and back into this node */
|
|
||||||
+ tp = node_parent(oldtnode);
|
|
||||||
+ NODE_INIT_PARENT(tn, tp);
|
|
||||||
+ put_child_root(tp, t, tn->key, tn);
|
|
||||||
+
|
|
||||||
/* prepare oldtnode to be freed */
|
|
||||||
tnode_free_init(oldtnode);
|
|
||||||
|
|
||||||
- for (i = 0; i < olen; i += 2) {
|
|
||||||
- struct tnode *newBinNode;
|
|
||||||
-
|
|
||||||
- left = tnode_get_child(oldtnode, i);
|
|
||||||
- right = tnode_get_child(oldtnode, i+1);
|
|
||||||
-
|
|
||||||
- /* At least one of the children is empty */
|
|
||||||
- if (left == NULL) {
|
|
||||||
- if (right == NULL) /* Both are empty */
|
|
||||||
- continue;
|
|
||||||
- put_child(tn, i/2, right);
|
|
||||||
- continue;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (right == NULL) {
|
|
||||||
- put_child(tn, i/2, left);
|
|
||||||
+ /* update all of the child parent pointers */
|
|
||||||
+ for (i = tnode_child_length(tn); i;) {
|
|
||||||
+ inode = tnode_get_child(tn, --i);
|
|
||||||
+
|
|
||||||
+ /* only new tnodes will be considered "full" nodes */
|
|
||||||
+ if (!tnode_full(tn, inode)) {
|
|
||||||
+ node_set_parent(inode, tn);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Two nonempty children */
|
|
||||||
- newBinNode = tnode_get_child(tn, i/2);
|
|
||||||
- put_child(newBinNode, 0, left);
|
|
||||||
- put_child(newBinNode, 1, right);
|
|
||||||
-
|
|
||||||
- put_child(tn, i / 2, newBinNode);
|
|
||||||
+ node_set_parent(tnode_get_child(inode, 1), inode);
|
|
||||||
+ node_set_parent(tnode_get_child(inode, 0), inode);
|
|
||||||
|
|
||||||
/* resize child node */
|
|
||||||
- resize(t, newBinNode);
|
|
||||||
+ resize(t, inode);
|
|
||||||
}
|
|
||||||
|
|
||||||
- put_child_root(tp, t, tn->key, tn);
|
|
||||||
-
|
|
||||||
/* all pointers should be clean so we are done */
|
|
||||||
tnode_free(oldtnode);
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:57:02 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Remove checks for index >= tnode_child_length
|
|
||||||
from tnode_get_child
|
|
||||||
|
|
||||||
For some reason the compiler doesn't seem to understand that when we are in
|
|
||||||
a loop that runs from tnode_child_length - 1 to 0 we don't expect the value
|
|
||||||
of tn->bits to change. As such every call to tnode_get_child was rerunning
|
|
||||||
tnode_chile_length which ended up consuming quite a bit of space in the
|
|
||||||
resultant assembly code.
|
|
||||||
|
|
||||||
I have gone though and verified that in all cases where tnode_get_child
|
|
||||||
is used we are either winding though a fixed loop from tnode_child_length -
|
|
||||||
1 to 0, or are in a fastpath case where we are verifying the value by
|
|
||||||
either checking for any remaining bits after shifting index by bits and
|
|
||||||
testing for leaf, or by using tnode_child_length.
|
|
||||||
|
|
||||||
size net/ipv4/fib_trie.o
|
|
||||||
Before:
|
|
||||||
text data bss dec hex filename
|
|
||||||
15506 376 8 15890 3e12 net/ipv4/fib_trie.o
|
|
||||||
|
|
||||||
After:
|
|
||||||
text data bss dec hex filename
|
|
||||||
14827 376 8 15211 3b6b net/ipv4/fib_trie.o
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -186,8 +186,6 @@ static inline unsigned long tnode_child_
|
|
||||||
static inline struct tnode *tnode_get_child(const struct tnode *tn,
|
|
||||||
unsigned long i)
|
|
||||||
{
|
|
||||||
- BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
-
|
|
||||||
return rtnl_dereference(tn->child[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -195,8 +193,6 @@ static inline struct tnode *tnode_get_ch
|
|
||||||
static inline struct tnode *tnode_get_child_rcu(const struct tnode *tn,
|
|
||||||
unsigned long i)
|
|
||||||
{
|
|
||||||
- BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
-
|
|
||||||
return rcu_dereference_rtnl(tn->child[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -371,7 +367,7 @@ static inline int tnode_full(const struc
|
|
||||||
*/
|
|
||||||
static void put_child(struct tnode *tn, unsigned long i, struct tnode *n)
|
|
||||||
{
|
|
||||||
- struct tnode *chi = rtnl_dereference(tn->child[i]);
|
|
||||||
+ struct tnode *chi = tnode_get_child(tn, i);
|
|
||||||
int isfull, wasfull;
|
|
||||||
|
|
||||||
BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
@@ -867,7 +863,7 @@ static struct tnode *fib_find_node(struc
|
|
||||||
if (IS_LEAF(n))
|
|
||||||
break;
|
|
||||||
|
|
||||||
- n = rcu_dereference_rtnl(n->child[index]);
|
|
||||||
+ n = tnode_get_child_rcu(n, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
@@ -934,7 +930,7 @@ static struct list_head *fib_insert_node
|
|
||||||
}
|
|
||||||
|
|
||||||
tp = n;
|
|
||||||
- n = rcu_dereference_rtnl(n->child[index]);
|
|
||||||
+ n = tnode_get_child_rcu(n, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
l = leaf_new(key);
|
|
||||||
@@ -1215,7 +1211,7 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
cindex = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
- n = rcu_dereference(n->child[index]);
|
|
||||||
+ n = tnode_get_child_rcu(n, index);
|
|
||||||
if (unlikely(!n))
|
|
||||||
goto backtrace;
|
|
||||||
}
|
|
||||||
@@ -1835,7 +1831,7 @@ static void trie_collect_stats(struct tr
|
|
||||||
if (n->bits < MAX_STAT_DEPTH)
|
|
||||||
s->nodesizes[n->bits]++;
|
|
||||||
|
|
||||||
- for (i = 0; i < tnode_child_length(n); i++) {
|
|
||||||
+ for (i = tnode_child_length(n); i--;) {
|
|
||||||
if (!rcu_access_pointer(n->child[i]))
|
|
||||||
s->nullpointers++;
|
|
||||||
}
|
|
@ -1,234 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Wed, 31 Dec 2014 10:57:08 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Add tracking value for suffix length
|
|
||||||
|
|
||||||
This change adds a tracking value for the maximum suffix length of all
|
|
||||||
prefixes stored in any given tnode. With this value we can determine if we
|
|
||||||
need to backtrace or not based on if the suffix is greater than the pos
|
|
||||||
value.
|
|
||||||
|
|
||||||
By doing this we can reduce the CPU overhead for lookups in the local table
|
|
||||||
as many of the prefixes there are 32b long and have a suffix length of 0
|
|
||||||
meaning we can immediately backtrace to the root node without needing to
|
|
||||||
test any of the nodes between it and where we ended up.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -96,6 +96,7 @@ struct tnode {
|
|
||||||
t_key key;
|
|
||||||
unsigned char bits; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
unsigned char pos; /* 2log(KEYLENGTH) bits needed */
|
|
||||||
+ unsigned char slen;
|
|
||||||
struct tnode __rcu *parent;
|
|
||||||
struct rcu_head rcu;
|
|
||||||
union {
|
|
||||||
@@ -311,6 +312,7 @@ static struct tnode *leaf_new(t_key key)
|
|
||||||
* as the nodes are searched
|
|
||||||
*/
|
|
||||||
l->key = key;
|
|
||||||
+ l->slen = 0;
|
|
||||||
l->pos = 0;
|
|
||||||
/* set bits to 0 indicating we are not a tnode */
|
|
||||||
l->bits = 0;
|
|
||||||
@@ -342,6 +344,7 @@ static struct tnode *tnode_new(t_key key
|
|
||||||
|
|
||||||
if (tn) {
|
|
||||||
tn->parent = NULL;
|
|
||||||
+ tn->slen = pos;
|
|
||||||
tn->pos = pos;
|
|
||||||
tn->bits = bits;
|
|
||||||
tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0;
|
|
||||||
@@ -387,6 +390,9 @@ static void put_child(struct tnode *tn,
|
|
||||||
else if (!wasfull && isfull)
|
|
||||||
tn->full_children++;
|
|
||||||
|
|
||||||
+ if (n && (tn->slen < n->slen))
|
|
||||||
+ tn->slen = n->slen;
|
|
||||||
+
|
|
||||||
rcu_assign_pointer(tn->child[i], n);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -635,6 +641,41 @@ static int halve(struct trie *t, struct
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static unsigned char update_suffix(struct tnode *tn)
|
|
||||||
+{
|
|
||||||
+ unsigned char slen = tn->pos;
|
|
||||||
+ unsigned long stride, i;
|
|
||||||
+
|
|
||||||
+ /* search though the list of children looking for nodes that might
|
|
||||||
+ * have a suffix greater than the one we currently have. This is
|
|
||||||
+ * why we start with a stride of 2 since a stride of 1 would
|
|
||||||
+ * represent the nodes with suffix length equal to tn->pos
|
|
||||||
+ */
|
|
||||||
+ for (i = 0, stride = 0x2ul ; i < tnode_child_length(tn); i += stride) {
|
|
||||||
+ struct tnode *n = tnode_get_child(tn, i);
|
|
||||||
+
|
|
||||||
+ if (!n || (n->slen <= slen))
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ /* update stride and slen based on new value */
|
|
||||||
+ stride <<= (n->slen - slen);
|
|
||||||
+ slen = n->slen;
|
|
||||||
+ i &= ~(stride - 1);
|
|
||||||
+
|
|
||||||
+ /* if slen covers all but the last bit we can stop here
|
|
||||||
+ * there will be nothing longer than that since only node
|
|
||||||
+ * 0 and 1 << (bits - 1) could have that as their suffix
|
|
||||||
+ * length.
|
|
||||||
+ */
|
|
||||||
+ if ((slen + 1) >= (tn->pos + tn->bits))
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ tn->slen = slen;
|
|
||||||
+
|
|
||||||
+ return slen;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/* From "Implementing a dynamic compressed trie" by Stefan Nilsson of
|
|
||||||
* the Helsinki University of Technology and Matti Tikkanen of Nokia
|
|
||||||
* Telecommunications, page 6:
|
|
||||||
@@ -790,6 +831,19 @@ no_children:
|
|
||||||
/* drop dead node */
|
|
||||||
tnode_free_init(tn);
|
|
||||||
tnode_free(tn);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* Return if at least one deflate was run */
|
|
||||||
+ if (max_work != MAX_WORK)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ /* push the suffix length to the parent node */
|
|
||||||
+ if (tn->slen > tn->pos) {
|
|
||||||
+ unsigned char slen = update_suffix(tn);
|
|
||||||
+
|
|
||||||
+ if (tp && (slen > tp->slen))
|
|
||||||
+ tp->slen = slen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -818,8 +872,58 @@ static inline struct list_head *get_fa_h
|
|
||||||
return &li->falh;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new)
|
|
||||||
+static void leaf_pull_suffix(struct tnode *l)
|
|
||||||
+{
|
|
||||||
+ struct tnode *tp = node_parent(l);
|
|
||||||
+
|
|
||||||
+ while (tp && (tp->slen > tp->pos) && (tp->slen > l->slen)) {
|
|
||||||
+ if (update_suffix(tp) > l->slen)
|
|
||||||
+ break;
|
|
||||||
+ tp = node_parent(tp);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void leaf_push_suffix(struct tnode *l)
|
|
||||||
+{
|
|
||||||
+ struct tnode *tn = node_parent(l);
|
|
||||||
+
|
|
||||||
+ /* if this is a new leaf then tn will be NULL and we can sort
|
|
||||||
+ * out parent suffix lengths as a part of trie_rebalance
|
|
||||||
+ */
|
|
||||||
+ while (tn && (tn->slen < l->slen)) {
|
|
||||||
+ tn->slen = l->slen;
|
|
||||||
+ tn = node_parent(tn);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void remove_leaf_info(struct tnode *l, struct leaf_info *old)
|
|
||||||
+{
|
|
||||||
+ struct hlist_node *prev;
|
|
||||||
+
|
|
||||||
+ /* record the location of the pointer to this object */
|
|
||||||
+ prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist));
|
|
||||||
+
|
|
||||||
+ /* remove the leaf info from the list */
|
|
||||||
+ hlist_del_rcu(&old->hlist);
|
|
||||||
+
|
|
||||||
+ /* if we emptied the list this leaf will be freed and we can sort
|
|
||||||
+ * out parent suffix lengths as a part of trie_rebalance
|
|
||||||
+ */
|
|
||||||
+ if (hlist_empty(&l->list))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ /* if we removed the tail then we need to update slen */
|
|
||||||
+ if (!rcu_access_pointer(hlist_next_rcu(prev))) {
|
|
||||||
+ struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist);
|
|
||||||
+
|
|
||||||
+ l->slen = KEYLENGTH - li->plen;
|
|
||||||
+ leaf_pull_suffix(l);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void insert_leaf_info(struct tnode *l, struct leaf_info *new)
|
|
||||||
{
|
|
||||||
+ struct hlist_head *head = &l->list;
|
|
||||||
struct leaf_info *li = NULL, *last = NULL;
|
|
||||||
|
|
||||||
if (hlist_empty(head)) {
|
|
||||||
@@ -836,6 +940,12 @@ static void insert_leaf_info(struct hlis
|
|
||||||
else
|
|
||||||
hlist_add_before_rcu(&new->hlist, &li->hlist);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ /* if we added to the tail node then we need to update slen */
|
|
||||||
+ if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) {
|
|
||||||
+ l->slen = KEYLENGTH - new->plen;
|
|
||||||
+ leaf_push_suffix(l);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rcu_read_lock needs to be hold by caller from readside */
|
|
||||||
@@ -925,7 +1035,7 @@ static struct list_head *fib_insert_node
|
|
||||||
/* we have found a leaf. Prefixes have already been compared */
|
|
||||||
if (IS_LEAF(n)) {
|
|
||||||
/* Case 1: n is a leaf, and prefixes match*/
|
|
||||||
- insert_leaf_info(&n->list, li);
|
|
||||||
+ insert_leaf_info(n, li);
|
|
||||||
return fa_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -939,7 +1049,7 @@ static struct list_head *fib_insert_node
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
- insert_leaf_info(&l->list, li);
|
|
||||||
+ insert_leaf_info(l, li);
|
|
||||||
|
|
||||||
/* Case 2: n is a LEAF or a TNODE and the key doesn't match.
|
|
||||||
*
|
|
||||||
@@ -1206,7 +1316,7 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
/* only record pn and cindex if we are going to be chopping
|
|
||||||
* bits later. Otherwise we are just wasting cycles.
|
|
||||||
*/
|
|
||||||
- if (index) {
|
|
||||||
+ if (n->slen > n->pos) {
|
|
||||||
pn = n;
|
|
||||||
cindex = index;
|
|
||||||
}
|
|
||||||
@@ -1225,7 +1335,7 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
* between the key and the prefix exist in the region of
|
|
||||||
* the lsb and higher in the prefix.
|
|
||||||
*/
|
|
||||||
- if (unlikely(prefix_mismatch(key, n)))
|
|
||||||
+ if (unlikely(prefix_mismatch(key, n)) || (n->slen == n->pos))
|
|
||||||
goto backtrace;
|
|
||||||
|
|
||||||
/* exit out and process leaf */
|
|
||||||
@@ -1425,7 +1535,7 @@ int fib_table_delete(struct fib_table *t
|
|
||||||
tb->tb_num_default--;
|
|
||||||
|
|
||||||
if (list_empty(fa_head)) {
|
|
||||||
- hlist_del_rcu(&li->hlist);
|
|
||||||
+ remove_leaf_info(l, li);
|
|
||||||
free_leaf_info(li);
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Thu, 22 Jan 2015 15:51:08 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Use index & (~0ul << n->bits) instead of index >>
|
|
||||||
n->bits
|
|
||||||
|
|
||||||
In doing performance testing and analysis of the changes I recently found
|
|
||||||
that by shifting the index I had created an unnecessary dependency.
|
|
||||||
|
|
||||||
I have updated the code so that we instead shift a mask by bits and then
|
|
||||||
just test against that as that should save us about 2 CPU cycles since we
|
|
||||||
can generate the mask while the key and pos are being processed.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -961,12 +961,12 @@ static struct tnode *fib_find_node(struc
|
|
||||||
* prefix plus zeros for the bits in the cindex. The index
|
|
||||||
* is the difference between the key and this value. From
|
|
||||||
* this we can actually derive several pieces of data.
|
|
||||||
- * if !(index >> bits)
|
|
||||||
- * we know the value is cindex
|
|
||||||
- * else
|
|
||||||
+ * if (index & (~0ul << bits))
|
|
||||||
* we have a mismatch in skip bits and failed
|
|
||||||
+ * else
|
|
||||||
+ * we know the value is cindex
|
|
||||||
*/
|
|
||||||
- if (index >> n->bits)
|
|
||||||
+ if (index & (~0ul << n->bits))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* we have found a leaf. Prefixes have already been compared */
|
|
||||||
@@ -1301,12 +1301,12 @@ int fib_table_lookup(struct fib_table *t
|
|
||||||
* prefix plus zeros for the "bits" in the prefix. The index
|
|
||||||
* is the difference between the key and this value. From
|
|
||||||
* this we can actually derive several pieces of data.
|
|
||||||
- * if !(index >> bits)
|
|
||||||
- * we know the value is child index
|
|
||||||
- * else
|
|
||||||
+ * if (index & (~0ul << bits))
|
|
||||||
* we have a mismatch in skip bits and failed
|
|
||||||
+ * else
|
|
||||||
+ * we know the value is cindex
|
|
||||||
*/
|
|
||||||
- if (index >> n->bits)
|
|
||||||
+ if (index & (~0ul << n->bits))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* we have found a leaf. Prefixes have already been compared */
|
|
@ -1,267 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Thu, 22 Jan 2015 15:51:14 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Fix RCU bug and merge similar bits of inflate/halve
|
|
||||||
|
|
||||||
This patch addresses two issues.
|
|
||||||
|
|
||||||
The first issue is the fact that I believe I had the RCU freeing sequence
|
|
||||||
slightly out of order. As a result we could get into an issue if a caller
|
|
||||||
went into a child of a child of the new node, then backtraced into the to be
|
|
||||||
freed parent, and then attempted to access a child of a child that may have
|
|
||||||
been consumed in a resize of one of the new nodes children. To resolve this I
|
|
||||||
have moved the resize after we have freed the oldtnode. The only side effect
|
|
||||||
of this is that we will now be calling resize on more nodes in the case of
|
|
||||||
inflate due to the fact that we don't have a good way to test to see if a
|
|
||||||
full_tnode on the new node was there before or after the allocation. This
|
|
||||||
should have minimal impact however since the node should already be
|
|
||||||
correctly size so it is just the cost of calling should_inflate that we
|
|
||||||
will be taking on the node which is only a couple of cycles.
|
|
||||||
|
|
||||||
The second issue is the fact that inflate and halve were essentially doing
|
|
||||||
the same thing after the new node was added to the trie replacing the old
|
|
||||||
one. As such it wasn't really necessary to keep the code in both functions
|
|
||||||
so I have split it out into two other functions, called replace and
|
|
||||||
update_children.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -396,8 +396,30 @@ static void put_child(struct tnode *tn,
|
|
||||||
rcu_assign_pointer(tn->child[i], n);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void put_child_root(struct tnode *tp, struct trie *t,
|
|
||||||
- t_key key, struct tnode *n)
|
|
||||||
+static void update_children(struct tnode *tn)
|
|
||||||
+{
|
|
||||||
+ unsigned long i;
|
|
||||||
+
|
|
||||||
+ /* update all of the child parent pointers */
|
|
||||||
+ for (i = tnode_child_length(tn); i;) {
|
|
||||||
+ struct tnode *inode = tnode_get_child(tn, --i);
|
|
||||||
+
|
|
||||||
+ if (!inode)
|
|
||||||
+ continue;
|
|
||||||
+
|
|
||||||
+ /* Either update the children of a tnode that
|
|
||||||
+ * already belongs to us or update the child
|
|
||||||
+ * to point to ourselves.
|
|
||||||
+ */
|
|
||||||
+ if (node_parent(inode) == tn)
|
|
||||||
+ update_children(inode);
|
|
||||||
+ else
|
|
||||||
+ node_set_parent(inode, tn);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline void put_child_root(struct tnode *tp, struct trie *t,
|
|
||||||
+ t_key key, struct tnode *n)
|
|
||||||
{
|
|
||||||
if (tp)
|
|
||||||
put_child(tp, get_index(key, tp), n);
|
|
||||||
@@ -434,10 +456,35 @@ static void tnode_free(struct tnode *tn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn)
|
|
||||||
+{
|
|
||||||
+ struct tnode *tp = node_parent(oldtnode);
|
|
||||||
+ unsigned long i;
|
|
||||||
+
|
|
||||||
+ /* setup the parent pointer out of and back into this node */
|
|
||||||
+ NODE_INIT_PARENT(tn, tp);
|
|
||||||
+ put_child_root(tp, t, tn->key, tn);
|
|
||||||
+
|
|
||||||
+ /* update all of the child parent pointers */
|
|
||||||
+ update_children(tn);
|
|
||||||
+
|
|
||||||
+ /* all pointers should be clean so we are done */
|
|
||||||
+ tnode_free(oldtnode);
|
|
||||||
+
|
|
||||||
+ /* resize children now that oldtnode is freed */
|
|
||||||
+ for (i = tnode_child_length(tn); i;) {
|
|
||||||
+ struct tnode *inode = tnode_get_child(tn, --i);
|
|
||||||
+
|
|
||||||
+ /* resize child node */
|
|
||||||
+ if (tnode_full(tn, inode))
|
|
||||||
+ resize(t, inode);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int inflate(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
- struct tnode *inode, *node0, *node1, *tn, *tp;
|
|
||||||
- unsigned long i, j, k;
|
|
||||||
+ struct tnode *tn;
|
|
||||||
+ unsigned long i;
|
|
||||||
t_key m;
|
|
||||||
|
|
||||||
pr_debug("In inflate\n");
|
|
||||||
@@ -446,13 +493,18 @@ static int inflate(struct trie *t, struc
|
|
||||||
if (!tn)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
+ /* prepare oldtnode to be freed */
|
|
||||||
+ tnode_free_init(oldtnode);
|
|
||||||
+
|
|
||||||
/* Assemble all of the pointers in our cluster, in this case that
|
|
||||||
* represents all of the pointers out of our allocated nodes that
|
|
||||||
* point to existing tnodes and the links between our allocated
|
|
||||||
* nodes.
|
|
||||||
*/
|
|
||||||
for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) {
|
|
||||||
- inode = tnode_get_child(oldtnode, --i);
|
|
||||||
+ struct tnode *inode = tnode_get_child(oldtnode, --i);
|
|
||||||
+ struct tnode *node0, *node1;
|
|
||||||
+ unsigned long j, k;
|
|
||||||
|
|
||||||
/* An empty child */
|
|
||||||
if (inode == NULL)
|
|
||||||
@@ -464,6 +516,9 @@ static int inflate(struct trie *t, struc
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* drop the node in the old tnode free list */
|
|
||||||
+ tnode_free_append(oldtnode, inode);
|
|
||||||
+
|
|
||||||
/* An internal node with two children */
|
|
||||||
if (inode->bits == 1) {
|
|
||||||
put_child(tn, 2 * i + 1, tnode_get_child(inode, 1));
|
|
||||||
@@ -488,9 +543,9 @@ static int inflate(struct trie *t, struc
|
|
||||||
node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1);
|
|
||||||
if (!node1)
|
|
||||||
goto nomem;
|
|
||||||
- tnode_free_append(tn, node1);
|
|
||||||
+ node0 = tnode_new(inode->key, inode->pos, inode->bits - 1);
|
|
||||||
|
|
||||||
- node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1);
|
|
||||||
+ tnode_free_append(tn, node1);
|
|
||||||
if (!node0)
|
|
||||||
goto nomem;
|
|
||||||
tnode_free_append(tn, node0);
|
|
||||||
@@ -512,53 +567,9 @@ static int inflate(struct trie *t, struc
|
|
||||||
put_child(tn, 2 * i, node0);
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* setup the parent pointer into and out of this node */
|
|
||||||
- tp = node_parent(oldtnode);
|
|
||||||
- NODE_INIT_PARENT(tn, tp);
|
|
||||||
- put_child_root(tp, t, tn->key, tn);
|
|
||||||
+ /* setup the parent pointers into and out of this node */
|
|
||||||
+ replace(t, oldtnode, tn);
|
|
||||||
|
|
||||||
- /* prepare oldtnode to be freed */
|
|
||||||
- tnode_free_init(oldtnode);
|
|
||||||
-
|
|
||||||
- /* update all child nodes parent pointers to route to us */
|
|
||||||
- for (i = tnode_child_length(oldtnode); i;) {
|
|
||||||
- inode = tnode_get_child(oldtnode, --i);
|
|
||||||
-
|
|
||||||
- /* A leaf or an internal node with skipped bits */
|
|
||||||
- if (!tnode_full(oldtnode, inode)) {
|
|
||||||
- node_set_parent(inode, tn);
|
|
||||||
- continue;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* drop the node in the old tnode free list */
|
|
||||||
- tnode_free_append(oldtnode, inode);
|
|
||||||
-
|
|
||||||
- /* fetch new nodes */
|
|
||||||
- node1 = tnode_get_child(tn, 2 * i + 1);
|
|
||||||
- node0 = tnode_get_child(tn, 2 * i);
|
|
||||||
-
|
|
||||||
- /* bits == 1 then node0 and node1 represent inode's children */
|
|
||||||
- if (inode->bits == 1) {
|
|
||||||
- node_set_parent(node1, tn);
|
|
||||||
- node_set_parent(node0, tn);
|
|
||||||
- continue;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* update parent pointers in child node's children */
|
|
||||||
- for (k = tnode_child_length(inode), j = k / 2; j;) {
|
|
||||||
- node_set_parent(tnode_get_child(inode, --k), node1);
|
|
||||||
- node_set_parent(tnode_get_child(inode, --j), node0);
|
|
||||||
- node_set_parent(tnode_get_child(inode, --k), node1);
|
|
||||||
- node_set_parent(tnode_get_child(inode, --j), node0);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* resize child nodes */
|
|
||||||
- resize(t, node1);
|
|
||||||
- resize(t, node0);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* we completed without error, prepare to free old node */
|
|
||||||
- tnode_free(oldtnode);
|
|
||||||
return 0;
|
|
||||||
nomem:
|
|
||||||
/* all pointers should be clean so we are done */
|
|
||||||
@@ -568,7 +579,7 @@ nomem:
|
|
||||||
|
|
||||||
static int halve(struct trie *t, struct tnode *oldtnode)
|
|
||||||
{
|
|
||||||
- struct tnode *tn, *tp, *inode, *node0, *node1;
|
|
||||||
+ struct tnode *tn;
|
|
||||||
unsigned long i;
|
|
||||||
|
|
||||||
pr_debug("In halve\n");
|
|
||||||
@@ -577,14 +588,18 @@ static int halve(struct trie *t, struct
|
|
||||||
if (!tn)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
+ /* prepare oldtnode to be freed */
|
|
||||||
+ tnode_free_init(oldtnode);
|
|
||||||
+
|
|
||||||
/* Assemble all of the pointers in our cluster, in this case that
|
|
||||||
* represents all of the pointers out of our allocated nodes that
|
|
||||||
* point to existing tnodes and the links between our allocated
|
|
||||||
* nodes.
|
|
||||||
*/
|
|
||||||
for (i = tnode_child_length(oldtnode); i;) {
|
|
||||||
- node1 = tnode_get_child(oldtnode, --i);
|
|
||||||
- node0 = tnode_get_child(oldtnode, --i);
|
|
||||||
+ struct tnode *node1 = tnode_get_child(oldtnode, --i);
|
|
||||||
+ struct tnode *node0 = tnode_get_child(oldtnode, --i);
|
|
||||||
+ struct tnode *inode;
|
|
||||||
|
|
||||||
/* At least one of the children is empty */
|
|
||||||
if (!node1 || !node0) {
|
|
||||||
@@ -609,34 +624,8 @@ static int halve(struct trie *t, struct
|
|
||||||
put_child(tn, i / 2, inode);
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* setup the parent pointer out of and back into this node */
|
|
||||||
- tp = node_parent(oldtnode);
|
|
||||||
- NODE_INIT_PARENT(tn, tp);
|
|
||||||
- put_child_root(tp, t, tn->key, tn);
|
|
||||||
-
|
|
||||||
- /* prepare oldtnode to be freed */
|
|
||||||
- tnode_free_init(oldtnode);
|
|
||||||
-
|
|
||||||
- /* update all of the child parent pointers */
|
|
||||||
- for (i = tnode_child_length(tn); i;) {
|
|
||||||
- inode = tnode_get_child(tn, --i);
|
|
||||||
-
|
|
||||||
- /* only new tnodes will be considered "full" nodes */
|
|
||||||
- if (!tnode_full(tn, inode)) {
|
|
||||||
- node_set_parent(inode, tn);
|
|
||||||
- continue;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* Two nonempty children */
|
|
||||||
- node_set_parent(tnode_get_child(inode, 1), inode);
|
|
||||||
- node_set_parent(tnode_get_child(inode, 0), inode);
|
|
||||||
-
|
|
||||||
- /* resize child node */
|
|
||||||
- resize(t, inode);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* all pointers should be clean so we are done */
|
|
||||||
- tnode_free(oldtnode);
|
|
||||||
+ /* setup the parent pointers into and out of this node */
|
|
||||||
+ replace(t, oldtnode, tn);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Thu, 22 Jan 2015 15:51:20 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Fall back to slen update on inflate/halve failure
|
|
||||||
|
|
||||||
This change corrects an issue where if inflate or halve fails we were
|
|
||||||
exiting the resize function without at least updating the slen for the
|
|
||||||
node. To correct this I have moved the update of max_size into the while
|
|
||||||
loop so that it is only decremented on a successful call to either inflate
|
|
||||||
or halve.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -752,7 +752,7 @@ static void resize(struct trie *t, struc
|
|
||||||
{
|
|
||||||
struct tnode *tp = node_parent(tn), *n = NULL;
|
|
||||||
struct tnode __rcu **cptr;
|
|
||||||
- int max_work;
|
|
||||||
+ int max_work = MAX_WORK;
|
|
||||||
|
|
||||||
pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
|
|
||||||
tn, inflate_threshold, halve_threshold);
|
|
||||||
@@ -775,8 +775,7 @@ static void resize(struct trie *t, struc
|
|
||||||
/* Double as long as the resulting node has a number of
|
|
||||||
* nonempty nodes that are above the threshold.
|
|
||||||
*/
|
|
||||||
- max_work = MAX_WORK;
|
|
||||||
- while (should_inflate(tp, tn) && max_work--) {
|
|
||||||
+ while (should_inflate(tp, tn) && max_work) {
|
|
||||||
if (inflate(t, tn)) {
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
@@ -784,6 +783,7 @@ static void resize(struct trie *t, struc
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ max_work--;
|
|
||||||
tn = rtnl_dereference(*cptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -794,8 +794,7 @@ static void resize(struct trie *t, struc
|
|
||||||
/* Halve as long as the number of empty children in this
|
|
||||||
* node is above threshold.
|
|
||||||
*/
|
|
||||||
- max_work = MAX_WORK;
|
|
||||||
- while (should_halve(tp, tn) && max_work--) {
|
|
||||||
+ while (should_halve(tp, tn) && max_work) {
|
|
||||||
if (halve(t, tn)) {
|
|
||||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
|
||||||
this_cpu_inc(t->stats->resize_node_skipped);
|
|
||||||
@@ -803,6 +802,7 @@ static void resize(struct trie *t, struc
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ max_work--;
|
|
||||||
tn = rtnl_dereference(*cptr);
|
|
||||||
}
|
|
||||||
|
|
@ -1,206 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Thu, 22 Jan 2015 15:51:26 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Add collapse() and should_collapse() to resize
|
|
||||||
|
|
||||||
This patch really does two things.
|
|
||||||
|
|
||||||
First it pulls the logic for determining if we should collapse one node out
|
|
||||||
of the tree and the actual code doing the collapse into a separate pair of
|
|
||||||
functions. This helps to make the changes to these areas more readable.
|
|
||||||
|
|
||||||
Second it encodes the upper 32b of the empty_children value onto the
|
|
||||||
full_children value in the case of bits == KEYLENGTH. By doing this we are
|
|
||||||
able to handle the case of a 32b node where empty_children would appear to
|
|
||||||
be 0 when it was actually 1ul << 32.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -83,7 +83,8 @@
|
|
||||||
|
|
||||||
#define MAX_STAT_DEPTH 32
|
|
||||||
|
|
||||||
-#define KEYLENGTH (8*sizeof(t_key))
|
|
||||||
+#define KEYLENGTH (8*sizeof(t_key))
|
|
||||||
+#define KEY_MAX ((t_key)~0)
|
|
||||||
|
|
||||||
typedef unsigned int t_key;
|
|
||||||
|
|
||||||
@@ -102,8 +103,8 @@ struct tnode {
|
|
||||||
union {
|
|
||||||
/* The fields in this struct are valid if bits > 0 (TNODE) */
|
|
||||||
struct {
|
|
||||||
- unsigned int full_children; /* KEYLENGTH bits needed */
|
|
||||||
- unsigned int empty_children; /* KEYLENGTH bits needed */
|
|
||||||
+ t_key empty_children; /* KEYLENGTH bits needed */
|
|
||||||
+ t_key full_children; /* KEYLENGTH bits needed */
|
|
||||||
struct tnode __rcu *child[0];
|
|
||||||
};
|
|
||||||
/* This list pointer if valid if bits == 0 (LEAF) */
|
|
||||||
@@ -302,6 +303,16 @@ static struct tnode *tnode_alloc(size_t
|
|
||||||
return vzalloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static inline void empty_child_inc(struct tnode *n)
|
|
||||||
+{
|
|
||||||
+ ++n->empty_children ? : ++n->full_children;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline void empty_child_dec(struct tnode *n)
|
|
||||||
+{
|
|
||||||
+ n->empty_children-- ? : n->full_children--;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static struct tnode *leaf_new(t_key key)
|
|
||||||
{
|
|
||||||
struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
|
|
||||||
@@ -335,7 +346,7 @@ static struct leaf_info *leaf_info_new(i
|
|
||||||
|
|
||||||
static struct tnode *tnode_new(t_key key, int pos, int bits)
|
|
||||||
{
|
|
||||||
- size_t sz = offsetof(struct tnode, child[1 << bits]);
|
|
||||||
+ size_t sz = offsetof(struct tnode, child[1ul << bits]);
|
|
||||||
struct tnode *tn = tnode_alloc(sz);
|
|
||||||
unsigned int shift = pos + bits;
|
|
||||||
|
|
||||||
@@ -348,8 +359,10 @@ static struct tnode *tnode_new(t_key key
|
|
||||||
tn->pos = pos;
|
|
||||||
tn->bits = bits;
|
|
||||||
tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0;
|
|
||||||
- tn->full_children = 0;
|
|
||||||
- tn->empty_children = 1<<bits;
|
|
||||||
+ if (bits == KEYLENGTH)
|
|
||||||
+ tn->full_children = 1;
|
|
||||||
+ else
|
|
||||||
+ tn->empty_children = 1ul << bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode),
|
|
||||||
@@ -375,11 +388,11 @@ static void put_child(struct tnode *tn,
|
|
||||||
|
|
||||||
BUG_ON(i >= tnode_child_length(tn));
|
|
||||||
|
|
||||||
- /* update emptyChildren */
|
|
||||||
+ /* update emptyChildren, overflow into fullChildren */
|
|
||||||
if (n == NULL && chi != NULL)
|
|
||||||
- tn->empty_children++;
|
|
||||||
- else if (n != NULL && chi == NULL)
|
|
||||||
- tn->empty_children--;
|
|
||||||
+ empty_child_inc(tn);
|
|
||||||
+ if (n != NULL && chi == NULL)
|
|
||||||
+ empty_child_dec(tn);
|
|
||||||
|
|
||||||
/* update fullChildren */
|
|
||||||
wasfull = tnode_full(tn, chi);
|
|
||||||
@@ -630,6 +643,24 @@ static int halve(struct trie *t, struct
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void collapse(struct trie *t, struct tnode *oldtnode)
|
|
||||||
+{
|
|
||||||
+ struct tnode *n, *tp;
|
|
||||||
+ unsigned long i;
|
|
||||||
+
|
|
||||||
+ /* scan the tnode looking for that one child that might still exist */
|
|
||||||
+ for (n = NULL, i = tnode_child_length(oldtnode); !n && i;)
|
|
||||||
+ n = tnode_get_child(oldtnode, --i);
|
|
||||||
+
|
|
||||||
+ /* compress one level */
|
|
||||||
+ tp = node_parent(oldtnode);
|
|
||||||
+ put_child_root(tp, t, oldtnode->key, n);
|
|
||||||
+ node_set_parent(n, tp);
|
|
||||||
+
|
|
||||||
+ /* drop dead node */
|
|
||||||
+ node_free(oldtnode);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static unsigned char update_suffix(struct tnode *tn)
|
|
||||||
{
|
|
||||||
unsigned char slen = tn->pos;
|
|
||||||
@@ -729,10 +760,12 @@ static bool should_inflate(const struct
|
|
||||||
|
|
||||||
/* Keep root node larger */
|
|
||||||
threshold *= tp ? inflate_threshold : inflate_threshold_root;
|
|
||||||
- used += tn->full_children;
|
|
||||||
used -= tn->empty_children;
|
|
||||||
+ used += tn->full_children;
|
|
||||||
|
|
||||||
- return tn->pos && ((50 * used) >= threshold);
|
|
||||||
+ /* if bits == KEYLENGTH then pos = 0, and will fail below */
|
|
||||||
+
|
|
||||||
+ return (used > 1) && tn->pos && ((50 * used) >= threshold);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool should_halve(const struct tnode *tp, const struct tnode *tn)
|
|
||||||
@@ -744,13 +777,29 @@ static bool should_halve(const struct tn
|
|
||||||
threshold *= tp ? halve_threshold : halve_threshold_root;
|
|
||||||
used -= tn->empty_children;
|
|
||||||
|
|
||||||
- return (tn->bits > 1) && ((100 * used) < threshold);
|
|
||||||
+ /* if bits == KEYLENGTH then used = 100% on wrap, and will fail below */
|
|
||||||
+
|
|
||||||
+ return (used > 1) && (tn->bits > 1) && ((100 * used) < threshold);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static bool should_collapse(const struct tnode *tn)
|
|
||||||
+{
|
|
||||||
+ unsigned long used = tnode_child_length(tn);
|
|
||||||
+
|
|
||||||
+ used -= tn->empty_children;
|
|
||||||
+
|
|
||||||
+ /* account for bits == KEYLENGTH case */
|
|
||||||
+ if ((tn->bits == KEYLENGTH) && tn->full_children)
|
|
||||||
+ used -= KEY_MAX;
|
|
||||||
+
|
|
||||||
+ /* One child or none, time to drop us from the trie */
|
|
||||||
+ return used < 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAX_WORK 10
|
|
||||||
static void resize(struct trie *t, struct tnode *tn)
|
|
||||||
{
|
|
||||||
- struct tnode *tp = node_parent(tn), *n = NULL;
|
|
||||||
+ struct tnode *tp = node_parent(tn);
|
|
||||||
struct tnode __rcu **cptr;
|
|
||||||
int max_work = MAX_WORK;
|
|
||||||
|
|
||||||
@@ -764,14 +813,6 @@ static void resize(struct trie *t, struc
|
|
||||||
cptr = tp ? &tp->child[get_index(tn->key, tp)] : &t->trie;
|
|
||||||
BUG_ON(tn != rtnl_dereference(*cptr));
|
|
||||||
|
|
||||||
- /* No children */
|
|
||||||
- if (tn->empty_children > (tnode_child_length(tn) - 1))
|
|
||||||
- goto no_children;
|
|
||||||
-
|
|
||||||
- /* One child */
|
|
||||||
- if (tn->empty_children == (tnode_child_length(tn) - 1))
|
|
||||||
- goto one_child;
|
|
||||||
-
|
|
||||||
/* Double as long as the resulting node has a number of
|
|
||||||
* nonempty nodes that are above the threshold.
|
|
||||||
*/
|
|
||||||
@@ -807,19 +848,8 @@ static void resize(struct trie *t, struc
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only one child remains */
|
|
||||||
- if (tn->empty_children == (tnode_child_length(tn) - 1)) {
|
|
||||||
- unsigned long i;
|
|
||||||
-one_child:
|
|
||||||
- for (i = tnode_child_length(tn); !n && i;)
|
|
||||||
- n = tnode_get_child(tn, --i);
|
|
||||||
-no_children:
|
|
||||||
- /* compress one level */
|
|
||||||
- put_child_root(tp, t, tn->key, n);
|
|
||||||
- node_set_parent(n, tp);
|
|
||||||
-
|
|
||||||
- /* drop dead node */
|
|
||||||
- tnode_free_init(tn);
|
|
||||||
- tnode_free(tn);
|
|
||||||
+ if (should_collapse(tn)) {
|
|
||||||
+ collapse(t, tn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Thu, 22 Jan 2015 15:51:33 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Use empty_children instead of counting empty nodes
|
|
||||||
in stats collection
|
|
||||||
|
|
||||||
It doesn't make much sense to count the pointers ourselves when
|
|
||||||
empty_children already has a count for the number of NULL pointers stored
|
|
||||||
in the tnode. As such save ourselves the cycles and just use
|
|
||||||
empty_children.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -1954,16 +1954,10 @@ static void trie_collect_stats(struct tr
|
|
||||||
hlist_for_each_entry_rcu(li, &n->list, hlist)
|
|
||||||
++s->prefixes;
|
|
||||||
} else {
|
|
||||||
- unsigned long i;
|
|
||||||
-
|
|
||||||
s->tnodes++;
|
|
||||||
if (n->bits < MAX_STAT_DEPTH)
|
|
||||||
s->nodesizes[n->bits]++;
|
|
||||||
-
|
|
||||||
- for (i = tnode_child_length(n); i--;) {
|
|
||||||
- if (!rcu_access_pointer(n->child[i]))
|
|
||||||
- s->nullpointers++;
|
|
||||||
- }
|
|
||||||
+ s->nullpointers += n->empty_children;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
@ -1,79 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Thu, 22 Jan 2015 15:51:39 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Move fib_find_alias to file where it is used
|
|
||||||
|
|
||||||
The function fib_find_alias is only accessed by functions in fib_trie.c as
|
|
||||||
such it makes sense to relocate it and cast it as static so that the
|
|
||||||
compiler can take advantage of optimizations it can do to it as a local
|
|
||||||
function.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_lookup.h
|
|
||||||
+++ b/net/ipv4/fib_lookup.h
|
|
||||||
@@ -32,7 +32,6 @@ int fib_dump_info(struct sk_buff *skb, u
|
|
||||||
unsigned int);
|
|
||||||
void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len,
|
|
||||||
u32 tb_id, const struct nl_info *info, unsigned int nlm_flags);
|
|
||||||
-struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio);
|
|
||||||
|
|
||||||
static inline void fib_result_assign(struct fib_result *res,
|
|
||||||
struct fib_info *fi)
|
|
||||||
--- a/net/ipv4/fib_semantics.c
|
|
||||||
+++ b/net/ipv4/fib_semantics.c
|
|
||||||
@@ -410,24 +410,6 @@ errout:
|
|
||||||
rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
-/* Return the first fib alias matching TOS with
|
|
||||||
- * priority less than or equal to PRIO.
|
|
||||||
- */
|
|
||||||
-struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio)
|
|
||||||
-{
|
|
||||||
- if (fah) {
|
|
||||||
- struct fib_alias *fa;
|
|
||||||
- list_for_each_entry(fa, fah, fa_list) {
|
|
||||||
- if (fa->fa_tos > tos)
|
|
||||||
- continue;
|
|
||||||
- if (fa->fa_info->fib_priority >= prio ||
|
|
||||||
- fa->fa_tos < tos)
|
|
||||||
- return fa;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
- return NULL;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static int fib_detect_death(struct fib_info *fi, int order,
|
|
||||||
struct fib_info **last_resort, int *last_idx,
|
|
||||||
int dflt)
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -998,6 +998,26 @@ static struct tnode *fib_find_node(struc
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/* Return the first fib alias matching TOS with
|
|
||||||
+ * priority less than or equal to PRIO.
|
|
||||||
+ */
|
|
||||||
+static struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio)
|
|
||||||
+{
|
|
||||||
+ struct fib_alias *fa;
|
|
||||||
+
|
|
||||||
+ if (!fah)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ list_for_each_entry(fa, fah, fa_list) {
|
|
||||||
+ if (fa->fa_tos > tos)
|
|
||||||
+ continue;
|
|
||||||
+ if (fa->fa_info->fib_priority >= prio || fa->fa_tos < tos)
|
|
||||||
+ return fa;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void trie_rebalance(struct trie *t, struct tnode *tn)
|
|
||||||
{
|
|
||||||
struct tnode *tp;
|
|
@ -1,116 +0,0 @@
|
|||||||
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Date: Thu, 22 Jan 2015 15:51:45 -0800
|
|
||||||
Subject: [PATCH] fib_trie: Various clean-ups for handling slen
|
|
||||||
|
|
||||||
While doing further work on the fib_trie I noted a few items.
|
|
||||||
|
|
||||||
First I was using calls that were far more complicated than they needed to
|
|
||||||
be for determining when to push/pull the suffix length. I have updated the
|
|
||||||
code to reflect the simplier logic.
|
|
||||||
|
|
||||||
The second issue is that I realised we weren't necessarily handling the
|
|
||||||
case of a leaf_info struct surviving a flush. I have updated the logic so
|
|
||||||
that now we will call pull_suffix in the event of having a leaf info value
|
|
||||||
left in the leaf after flushing it.
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/ipv4/fib_trie.c
|
|
||||||
+++ b/net/ipv4/fib_trie.c
|
|
||||||
@@ -917,27 +917,20 @@ static void leaf_push_suffix(struct tnod
|
|
||||||
|
|
||||||
static void remove_leaf_info(struct tnode *l, struct leaf_info *old)
|
|
||||||
{
|
|
||||||
- struct hlist_node *prev;
|
|
||||||
-
|
|
||||||
- /* record the location of the pointer to this object */
|
|
||||||
- prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist));
|
|
||||||
+ /* record the location of the previous list_info entry */
|
|
||||||
+ struct hlist_node **pprev = old->hlist.pprev;
|
|
||||||
+ struct leaf_info *li = hlist_entry(pprev, typeof(*li), hlist.next);
|
|
||||||
|
|
||||||
/* remove the leaf info from the list */
|
|
||||||
hlist_del_rcu(&old->hlist);
|
|
||||||
|
|
||||||
- /* if we emptied the list this leaf will be freed and we can sort
|
|
||||||
- * out parent suffix lengths as a part of trie_rebalance
|
|
||||||
- */
|
|
||||||
- if (hlist_empty(&l->list))
|
|
||||||
+ /* only access li if it is pointing at the last valid hlist_node */
|
|
||||||
+ if (hlist_empty(&l->list) || (*pprev))
|
|
||||||
return;
|
|
||||||
|
|
||||||
- /* if we removed the tail then we need to update slen */
|
|
||||||
- if (!rcu_access_pointer(hlist_next_rcu(prev))) {
|
|
||||||
- struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist);
|
|
||||||
-
|
|
||||||
- l->slen = KEYLENGTH - li->plen;
|
|
||||||
- leaf_pull_suffix(l);
|
|
||||||
- }
|
|
||||||
+ /* update the trie with the latest suffix length */
|
|
||||||
+ l->slen = KEYLENGTH - li->plen;
|
|
||||||
+ leaf_pull_suffix(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void insert_leaf_info(struct tnode *l, struct leaf_info *new)
|
|
||||||
@@ -961,7 +954,7 @@ static void insert_leaf_info(struct tnod
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we added to the tail node then we need to update slen */
|
|
||||||
- if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) {
|
|
||||||
+ if (l->slen < (KEYLENGTH - new->plen)) {
|
|
||||||
l->slen = KEYLENGTH - new->plen;
|
|
||||||
leaf_push_suffix(l);
|
|
||||||
}
|
|
||||||
@@ -1613,6 +1606,7 @@ static int trie_flush_leaf(struct tnode
|
|
||||||
struct hlist_head *lih = &l->list;
|
|
||||||
struct hlist_node *tmp;
|
|
||||||
struct leaf_info *li = NULL;
|
|
||||||
+ unsigned char plen = KEYLENGTH;
|
|
||||||
|
|
||||||
hlist_for_each_entry_safe(li, tmp, lih, hlist) {
|
|
||||||
found += trie_flush_list(&li->falh);
|
|
||||||
@@ -1620,8 +1614,14 @@ static int trie_flush_leaf(struct tnode
|
|
||||||
if (list_empty(&li->falh)) {
|
|
||||||
hlist_del_rcu(&li->hlist);
|
|
||||||
free_leaf_info(li);
|
|
||||||
+ continue;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ plen = li->plen;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ l->slen = KEYLENGTH - plen;
|
|
||||||
+
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1700,13 +1700,22 @@ int fib_table_flush(struct fib_table *tb
|
|
||||||
for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) {
|
|
||||||
found += trie_flush_leaf(l);
|
|
||||||
|
|
||||||
- if (ll && hlist_empty(&ll->list))
|
|
||||||
- trie_leaf_remove(t, ll);
|
|
||||||
+ if (ll) {
|
|
||||||
+ if (hlist_empty(&ll->list))
|
|
||||||
+ trie_leaf_remove(t, ll);
|
|
||||||
+ else
|
|
||||||
+ leaf_pull_suffix(ll);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
ll = l;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (ll && hlist_empty(&ll->list))
|
|
||||||
- trie_leaf_remove(t, ll);
|
|
||||||
+ if (ll) {
|
|
||||||
+ if (hlist_empty(&ll->list))
|
|
||||||
+ trie_leaf_remove(t, ll);
|
|
||||||
+ else
|
|
||||||
+ leaf_pull_suffix(ll);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
pr_debug("trie_flush found=%d\n", found);
|
|
||||||
return found;
|
|
@ -1,89 +0,0 @@
|
|||||||
From: Simon Farnsworth <simon@farnz.org.uk>
|
|
||||||
Date: Sun, 1 Mar 2015 10:54:39 +0000
|
|
||||||
Subject: [PATCH] pppoe: Use workqueue to die properly when a PADT is received
|
|
||||||
|
|
||||||
When a PADT frame is received, the socket may not be in a good state to
|
|
||||||
close down the PPP interface. The current implementation handles this by
|
|
||||||
simply blocking all further PPP traffic, and hoping that the lack of traffic
|
|
||||||
will trigger the user to investigate.
|
|
||||||
|
|
||||||
Use schedule_work to get to a process context from which we clear down the
|
|
||||||
PPP interface, in a fashion analogous to hangup on a TTY-based PPP
|
|
||||||
interface. This causes pppd to disconnect immediately, and allows tools to
|
|
||||||
take immediate corrective action.
|
|
||||||
|
|
||||||
Note that pppd's rp_pppoe.so plugin has code in it to disable the session
|
|
||||||
when it disconnects; however, as a consequence of this patch, the session is
|
|
||||||
already disabled before rp_pppoe.so is asked to disable the session. The
|
|
||||||
result is a harmless error message:
|
|
||||||
|
|
||||||
Failed to disconnect PPPoE socket: 114 Operation already in progress
|
|
||||||
|
|
||||||
This message is safe to ignore, as long as the error is 114 Operation
|
|
||||||
already in progress; in that specific case, it means that the PPPoE session
|
|
||||||
has already been disabled before pppd tried to disable it.
|
|
||||||
|
|
||||||
Signed-off-by: Simon Farnsworth <simon@farnz.org.uk>
|
|
||||||
Tested-by: Dan Williams <dcbw@redhat.com>
|
|
||||||
Tested-by: Christoph Schulz <develop@kristov.de>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ppp/pppoe.c
|
|
||||||
+++ b/drivers/net/ppp/pppoe.c
|
|
||||||
@@ -454,6 +454,18 @@ out:
|
|
||||||
return NET_RX_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void pppoe_unbind_sock_work(struct work_struct *work)
|
|
||||||
+{
|
|
||||||
+ struct pppox_sock *po = container_of(work, struct pppox_sock,
|
|
||||||
+ proto.pppoe.padt_work);
|
|
||||||
+ struct sock *sk = sk_pppox(po);
|
|
||||||
+
|
|
||||||
+ lock_sock(sk);
|
|
||||||
+ pppox_unbind_sock(sk);
|
|
||||||
+ release_sock(sk);
|
|
||||||
+ sock_put(sk);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/************************************************************************
|
|
||||||
*
|
|
||||||
* Receive a PPPoE Discovery frame.
|
|
||||||
@@ -499,7 +511,8 @@ static int pppoe_disc_rcv(struct sk_buff
|
|
||||||
}
|
|
||||||
|
|
||||||
bh_unlock_sock(sk);
|
|
||||||
- sock_put(sk);
|
|
||||||
+ if (!schedule_work(&po->proto.pppoe.padt_work))
|
|
||||||
+ sock_put(sk);
|
|
||||||
}
|
|
||||||
|
|
||||||
abort:
|
|
||||||
@@ -612,6 +625,8 @@ static int pppoe_connect(struct socket *
|
|
||||||
|
|
||||||
lock_sock(sk);
|
|
||||||
|
|
||||||
+ INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
|
|
||||||
+
|
|
||||||
error = -EINVAL;
|
|
||||||
|
|
||||||
if (sockaddr_len != sizeof(struct sockaddr_pppox))
|
|
||||||
--- a/include/linux/if_pppox.h
|
|
||||||
+++ b/include/linux/if_pppox.h
|
|
||||||
@@ -19,6 +19,7 @@
|
|
||||||
#include <linux/netdevice.h>
|
|
||||||
#include <linux/ppp_channel.h>
|
|
||||||
#include <linux/skbuff.h>
|
|
||||||
+#include <linux/workqueue.h>
|
|
||||||
#include <uapi/linux/if_pppox.h>
|
|
||||||
|
|
||||||
static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb)
|
|
||||||
@@ -32,6 +33,7 @@ struct pppoe_opt {
|
|
||||||
struct pppoe_addr pa; /* what this socket is bound to*/
|
|
||||||
struct sockaddr_pppox relay; /* what socket data will be
|
|
||||||
relayed to (PPPoE relaying) */
|
|
||||||
+ struct work_struct padt_work;/* Work item for handling PADT */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct pptp_opt {
|
|
@ -1,25 +0,0 @@
|
|||||||
From: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
|
|
||||||
Date: Mon, 20 Apr 2015 21:07:48 +0200
|
|
||||||
Subject: [PATCH] pppoe: Lacks DST MAC address check
|
|
||||||
|
|
||||||
A pppoe session is identified by its session ID and MAC address.
|
|
||||||
Currently pppoe does not check if the received pkg has the correct
|
|
||||||
MAC address. This is a problem when the eth I/F is in promisc mode
|
|
||||||
as then any DST MAC address is accepted.
|
|
||||||
|
|
||||||
Signed-off-by: Joakim Tjernlund <joakim.tjernlund@transmode.se>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ppp/pppoe.c
|
|
||||||
+++ b/drivers/net/ppp/pppoe.c
|
|
||||||
@@ -379,6 +379,9 @@ static int pppoe_rcv_core(struct sock *s
|
|
||||||
* can't change.
|
|
||||||
*/
|
|
||||||
|
|
||||||
+ if (skb->pkt_type == PACKET_OTHERHOST)
|
|
||||||
+ goto abort_kfree;
|
|
||||||
+
|
|
||||||
if (sk->sk_state & PPPOX_BOUND) {
|
|
||||||
ppp_input(&po->chan, skb);
|
|
||||||
} else if (sk->sk_state & PPPOX_RELAY) {
|
|
@ -1,28 +0,0 @@
|
|||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sat, 9 May 2015 23:08:38 +0200
|
|
||||||
Subject: [PATCH] pppoe: drop pppoe device in pppoe_unbind_sock_work
|
|
||||||
|
|
||||||
After receiving a PADT and the socket is closed, user space will no
|
|
||||||
longer drop the reference to the pppoe device.
|
|
||||||
This leads to errors like this:
|
|
||||||
|
|
||||||
[ 488.570000] unregister_netdevice: waiting for eth0.2 to become free. Usage count = 2
|
|
||||||
|
|
||||||
Fixes: 287f3a943fe ("pppoe: Use workqueue to die properly when a PADT is received")
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/ppp/pppoe.c
|
|
||||||
+++ b/drivers/net/ppp/pppoe.c
|
|
||||||
@@ -464,6 +464,10 @@ static void pppoe_unbind_sock_work(struc
|
|
||||||
struct sock *sk = sk_pppox(po);
|
|
||||||
|
|
||||||
lock_sock(sk);
|
|
||||||
+ if (po->pppoe_dev) {
|
|
||||||
+ dev_put(po->pppoe_dev);
|
|
||||||
+ po->pppoe_dev = NULL;
|
|
||||||
+ }
|
|
||||||
pppox_unbind_sock(sk);
|
|
||||||
release_sock(sk);
|
|
||||||
sock_put(sk);
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user