diff --git a/.circleci/config.yml b/.circleci/config.yml index c2138d56..b9f93aef 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -79,14 +79,22 @@ jobs: name: Build ath79/nand command: make MAINTARGET=ath79 SUBTARGET=nand no_output_timeout: 1h + - run: + name: Build ipq40xx/generic + command: make MAINTARGET=ipq40xx SUBTARGET=generic + no_output_timeout: 2h - run: name: Build ipq40xx/mikrotik command: make MAINTARGET=ipq40xx SUBTARGET=mikrotik - no_output_timeout: 2h + no_output_timeout: 1h - run: name: Build x64/64 command: make MAINTARGET=x86 SUBTARGET=64 no_output_timeout: 2h + - run: + name: Build ramips/mt7621 + command: make MAINTARGET=ipq40xx SUBTARGET=mt7621 + no_output_timeout: 2h - run: name: Compress build files command: tar -cjf ~/${CIRCLE_BRANCH}_${ARTIFACTS_FILE} -C ${MY_WORKING_DIRECTORY}/${ARTIFACTS_DIR} . @@ -126,14 +134,22 @@ jobs: name: Build ath79/nand command: make MAINTARGET=ath79 SUBTARGET=nand no_output_timeout: 1h + - run: + name: Build ipq40xx/generic + command: make MAINTARGET=ipq40xx SUBTARGET=generic + no_output_timeout: 2h - run: name: Build ipq40xx/mikrotik command: make MAINTARGET=ipq40xx SUBTARGET=mikrotik - no_output_timeout: 2h + no_output_timeout: 1h - run: name: Build x64/64 command: make MAINTARGET=x86 SUBTARGET=64 no_output_timeout: 2h + - run: + name: Build ramips/mt7621 + command: make MAINTARGET=ipq40xx SUBTARGET=mt7621 + no_output_timeout: 2h - run: name: Compress build files command: tar -cjf ~/${CIRCLE_BRANCH}_${ARTIFACTS_FILE} -C ${MY_WORKING_DIRECTORY}/${ARTIFACTS_DIR} . diff --git a/Makefile b/Makefile index 8c06940e..3f04e84f 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,7 @@ feeds-update: stamp-clean-feeds-updated .stamp-feeds-updated cd $(OPENWRT_DIR); ./scripts/feeds install curl cd $(OPENWRT_DIR); ./scripts/feeds install ntpclient cd $(OPENWRT_DIR); ./scripts/feeds install socat - cd $(OPENWRT_DIR); ./scripts/feeds install luci-base + cd $(OPENWRT_DIR); ./scripts/feeds install luci-lib-base cd $(OPENWRT_DIR); ./scripts/feeds install luci-lib-nixio cd $(OPENWRT_DIR); ./scripts/feeds install luci-lib-ip cd $(OPENWRT_DIR); ./scripts/feeds install luci-lib-jsonc diff --git a/SUPPORTED_DEVICES.md b/SUPPORTED_DEVICES.md index fa3ed8cc..de9f13a4 100644 --- a/SUPPORTED_DEVICES.md +++ b/SUPPORTED_DEVICES.md @@ -15,9 +15,9 @@ The 'target' and 'subtarget' identify the directory in which to find the image o ## Mikrotik Model | SKUs | Band | Target | Subtarget | Image | RAM | Stability | Status :------ | :----: | :----: | :------: | :---------: | :-----: | :---: | :---------: | :------ -hAP ac lite hAP ac lite TC | RB952Ui-5ac2nD RB952Ui-5ac2nD-TC | 2 | ath79 | mikrotik | mikrotik-952ui-5ac2nd | 64MB | stable | released -hAP ac² | RBD52G-5HacD2HnD-TC | 2 | ipq40xx | mikrotik | mikrotik_hap-ac2 | 128MB | stable | released -hAP ac³ | RBD53iG-5HacD2HnD | 2 | ipq40xx | mikrotik | mikrotik_hap-ac3 | 256MB | stable | released +hAP ac lite hAP ac lite TC | RB952Ui-5ac2nD RB952Ui-5ac2nD-TC | 2 & 5 | ath79 | mikrotik | mikrotik-952ui-5ac2nd | 64MB | stable | released +hAP ac² | RBD52G-5HacD2HnD-TC | 2 & 5 | ipq40xx | mikrotik | mikrotik_hap-ac2 | 128MB | stable | released +hAP ac³ | RBD53iG-5HacD2HnD | 2 & 5 | ipq40xx | mikrotik | mikrotik_hap-ac3 | 256MB | stable | released SXTsq Lite2 | RBSXTsq2nD | 2 | ath79 | mikrotik | mikrotik-sxt-2nd | 64MB | stable | released SXTsq Lite5 | RBSXTsq5nD | 5 | ath79 | mikrotik | mikrotik-sxt-5nd | 64MB | stable | released SXTsq 5 High Power | RBSXTsq5HPnD | 5 | ath79 | mikrotik | mikrotik-sxt-5hpnd | 64MB | stable | released @@ -47,6 +47,7 @@ Bullet M2 XW || 2 | ath79 | generic | ubnt_bullet-m-xw | 64MB | untested | relea LiteAP 5AC | LAP-120 LAP-120-US LBE-5AC-16-120 LBE-5AC-16-120-US | 5 | ath79 | generic | ubnt_lap-120 | 64MB | stable | released LiteBeam AC5 Gen2 | LBE-5AC LBE-5AC-US | 5 | ath79 | generic | ubnt_litebeam-ac-gen2 | 64MB | stable | released LiteBeam M5 || 5 | ath79 | - | - | 64MB | untested | released +NanoBeam 2AC 13 (2WA) || 2 | ath79 | generic | ubnt_nanobeam-2ac-13 | 64MB | stable | nightly NanoBeam AC 5 (WA) || 5 | ath79 | generic | ubnt_nanobeam-ac | 64MB | untested | released NanoBeam AC 5 (XC) || 5 | ath79 | generic | ubnt_nanobeam-ac-xc | 64MB | stable | released NanoBeam AC 5 Gen 2 (WA) || 5 | ath79 | generic | ubnt_nanobeam-ac-gen2 | 128MB | stable | released @@ -131,6 +132,8 @@ Model | SKUs | Band | Target | Subtarget | Image | RAM | Stability | Status Shadow (16MB NOR) | GL-AR300M16 GL-AR300M16-Ext | 2 | ath79 | generic | glinet_gl-ar300m16 | 64MB | stable | released Shadow (128MB NAND) | GL-AR300M GL-AR300M-Ext | 2 | ath79 | nand | gl-ar300m | 64MB | untested | released Mudi | GL-E750 | 2 | ath79 | nand | gl-e750 | 128MB | untested | released +Convexa-B | GL-B1300 | 2 & 5 | ipq40xx | generic | gl-b1300 | 256MB | untested | nightly +Beryl | GL-MT1300 | 2 & 5 | ramips | mt7621 | gl-mt1300 | 256MB | untested | nightly (4) **Sunset Devices** | | | | | | | | White | GL-AR150 | 2 | ath79 | generic | glinet_gl-ar150 | 64MB | stable | sunset (3) Microuter | GL-USB150 | 2 | ath79 | generic | glinet_gl-usb150 | 64MB | stable | sunset (3) @@ -146,6 +149,7 @@ Meraki MR-16 | MR16-HW | 5 | ath79 | - | - | 64MB | unsupported | **brick** 1. This device is supported for new installs. It can also be upgraded from 3.22.12.0 after first installing the [DangerousUpgrade package](https://github.com/kn6plv/DangerousUpgrade/raw/main/dangerousupgrade_0.1_all.ipk) to disable the firmware compatibility checks. Proceed carefully. 2. Tiny builds exclude support for *tunnels* and *WiFi AP* mode due to lack of resources. The relevant packages can be installed separately but this is not recommended. 3. These devices are no longer being manufactured by GL-iNET. They may not reboot reliably and you may need to power cycle them (several times) during an update. + 4. 20MHz channels only. Latest installation instructions are found at: https://docs.arednmesh.org/en/latest/ diff --git a/configs/ath79-generic.config b/configs/ath79-generic.config index 9fdb8e1f..c6a55310 100644 --- a/configs/ath79-generic.config +++ b/configs/ath79-generic.config @@ -20,11 +20,11 @@ CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_tplink_wbs210-v1=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_tplink_wbs210-v2=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_tplink_wbs510-v1=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_tplink_wbs510-v2=y -CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_bullet-m-xw=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_bullet-ac=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_bullet-m-xw=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_lap-120=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_litebeam-ac-gen2=y +CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_nanobeam-2ac-13=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_nanobeam-ac-gen2=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_nanobeam-ac=y CONFIG_TARGET_DEVICE_ath79_generic_DEVICE_ubnt_nanobeam-ac-xc=y diff --git a/configs/ath79-tiny.config b/configs/ath79-tiny.config index 338bce5e..765edea2 100644 --- a/configs/ath79-tiny.config +++ b/configs/ath79-tiny.config @@ -11,9 +11,11 @@ CONFIG_TARGET_DEVICE_ath79_tiny_DEVICE_ubnt_picostation-m=y CONFIG_KERNEL_CC_STACKPROTECTOR_NONE=y CONFIG_KERNEL_PRINTK=n CONFIG_PACKAGE_ATH_SPECTRAL=n -CONFIG_PACKAGE_wpad-mini=m -CONFIG_PACKAGE_vtun=m CONFIG_PACKAGE_ethtool=m CONFIG_PACKAGE_iperf3=m +CONFIG_PACKAGE_libustream-mbedtls=m +CONFIG_PACKAGE_vtun=m +CONFIG_PACKAGE_wireguard=m +CONFIG_PACKAGE_wireguard-tools=m CONFIG_PKG_CC_STACKPROTECTOR_NONE=y CONFIG_PKG_FORTIFY_SOURCE_NONE=y diff --git a/configs/common.config b/configs/common.config index 9ae75f6d..bbbadf2b 100644 --- a/configs/common.config +++ b/configs/common.config @@ -115,7 +115,6 @@ CONFIG_PACKAGE_lua-bit32=y CONFIG_PACKAGE_luaposix=n CONFIG_PACKAGE_luasocket=y CONFIG_PACKAGE_lua=y -CONFIG_PACKAGE_luci-base=n CONFIG_PACKAGE_luci-lib-base=y CONFIG_PACKAGE_luci-lib-ip=y CONFIG_PACKAGE_luci-lib-jsonc=y @@ -157,6 +156,8 @@ CONFIG_PACKAGE_wpad-mini=y CONFIG_PACKAGE_xinetd=n CONFIG_PACKAGE_zlib=m CONFIG_PACKAGE_zram-swap=n +CONFIG_PKG_ASLR_PIE_NONE=y +CONFIG_PKG_RELRO_NONE=y CONFIG_PREINITOPT=y CONFIG_SECCOMP=n CONFIG_STRIP_KERNEL_EXPORTS=y diff --git a/configs/ipq40xx-generic.config b/configs/ipq40xx-generic.config new file mode 100755 index 00000000..99dbbd26 --- /dev/null +++ b/configs/ipq40xx-generic.config @@ -0,0 +1,3 @@ +CONFIG_TARGET_ipq40xx=y +CONFIG_TARGET_ipq40xx_generic=y +CONFIG_TARGET_DEVICE_ipq40xx_generic_DEVICE_glinet_gl-b1300=y diff --git a/configs/ramips-mt7621.config b/configs/ramips-mt7621.config new file mode 100755 index 00000000..77b79631 --- /dev/null +++ b/configs/ramips-mt7621.config @@ -0,0 +1,3 @@ +CONFIG_TARGET_ramips=y +CONFIG_TARGET_ramips_mt7621=y +CONFIG_TARGET_DEVICE_ramips_mt7621_DEVICE_glinet_gl-mt1300=y diff --git a/feeds.conf b/feeds.conf index c4e5ef47..f5711628 100644 --- a/feeds.conf +++ b/feeds.conf @@ -1 +1 @@ -src-git arednpackages https://github.com/aredn/aredn_packages;develop +src-git arednpackages https://github.com/kn6plv/aredn_packages;working diff --git a/files/etc/config.mesh/network b/files/etc/config.mesh/network index 7d231807..bb822a3b 100644 --- a/files/etc/config.mesh/network +++ b/files/etc/config.mesh/network @@ -1,3 +1,7 @@ +#### Globals +config globals 'globals' + option packet_steering '1' + #### Loopback configuration config interface loopback option device "lo" diff --git a/files/etc/config/dhcp b/files/etc/config/dhcp index 9944f991..73d54c2d 100644 --- a/files/etc/config/dhcp +++ b/files/etc/config/dhcp @@ -3,6 +3,7 @@ config dhcp option start 5 option limit 20 option leasetime 12h + option force 1 config dhcp option interface wan diff --git a/files/etc/mesh-release b/files/etc/mesh-release index fd640a29..f87245c8 100644 --- a/files/etc/mesh-release +++ b/files/etc/mesh-release @@ -1 +1 @@ -KN6PLV-lz77decompression-d708f8c +KN6PLV-main-cdeb1b1d diff --git a/files/etc/permpkg b/files/etc/permpkg index 3526939d..30e7d748 100644 --- a/files/etc/permpkg +++ b/files/etc/permpkg @@ -4,6 +4,7 @@ ath10k-firmware-qca4019-ct ath10k-firmware-qca9887-ct ath10k-firmware-qca988x-ct base-files +bnx2-firmware busybox ca-bundle curl @@ -14,6 +15,9 @@ firewall4 fstools fwtool getrandom +grub2 +grub2-bios-setup +grub2-efi hostapd-common iperf3 iw @@ -22,12 +26,17 @@ jansson4 jshn jsonfilter kernel +kmod-amazon-ena +kmod-amd-xgbe kmod-ath kmod-ath10k-ct kmod-ath10k-ct-smallbuffers kmod-ath9k kmod-ath9k-common +kmod-bnx2 +kmod-button-hotplug kmod-cfg80211 +kmod-crypto-acompress kmod-crypto-aead kmod-crypto-ccm kmod-crypto-cmac @@ -43,42 +52,72 @@ kmod-crypto-null kmod-crypto-rng kmod-crypto-seqiv kmod-crypto-sha256 +kmod-crypto-sha512 +kmod-e1000 +kmod-e1000e +kmod-forcedeth +kmod-fs-vfat kmod-gpio-button-hotplug kmod-hwmon-core +kmod-i2c-algo-bit +kmod-i2c-core +kmod-igb +kmod-igc +kmod-input-core kmod-ipip kmod-iptunnel kmod-iptunnel4 +kmod-ixgbe kmod-leds-gpio kmod-ledtrig-gpio kmod-lib-crc32c +kmod-lib-lzo +kmod-libphy kmod-mac80211 +kmod-mdio +kmod-mdio-devres +kmod-mii kmod-nf-conntrack kmod-nf-flow kmod-nf-log kmod-nf-nat -kmod-nf-reject kmod-nfnetlink +kmod-nf-reject kmod-nft-core kmod-nft-fib kmod-nft-nat kmod-nft-offload kmod-nls-base +kmod-nls-cp437 +kmod-nls-iso8859-1 +kmod-nls-utf8 +kmod-phy-realtek +kmod-pps +kmod-ptp +kmod-r8169 +kmod-tg3 kmod-tun kmod-usb-core kmod-usb-dwc3 kmod-usb-dwc3-qcom +libblkid1 libblobmsg-json20220515 +libblobmsg-json20230523 libc libcurl4 +libf2fs6 libgcc1 +libiperf3 +libiwinfo20210430 +libiwinfo20230701 libiwinfo-data libiwinfo-lua -libiwinfo20210430 libjson-c5 libjson-script20220515 +libjson-script20230523 liblua5.1.5 -liblucihttp-lua liblucihttp0 +liblucihttp-lua liblzo2 libmbedtls12 libmnl0 @@ -86,13 +125,18 @@ libnftnl11 libnl-tiny1 libpthread librt +libsmartcols1 libubox20220515 -libubus-lua +libubox20230523 libubus20220601 -libuci-lua +libubus20230605 +libubus-lua libuci20130104 +libuci-lua libuclient20201210 libucode20220812 +libustream-mbedtls20201210 +libuuid1 libxtables12 logd lua @@ -101,6 +145,7 @@ luci-lib-base luci-lib-ip luci-lib-jsonc luci-lib-nixio +mkf2fs mtd netifd nftables-json @@ -114,8 +159,10 @@ olsrd-mod-txtinfo olsrd-mod-watchdog openwrt-keyring opkg +partx-utils procd prometheus-exporter +r8169-firmware rpcd rpcd-mod-file rpcd-mod-luci @@ -130,8 +177,11 @@ uci uclient-fetch ucode ucode-mod-fs +ucode-mod-nl80211 +ucode-mod-rtnl ucode-mod-ubus ucode-mod-uci +ucode-mod-uloop uhttpd urandom-seed urngd diff --git a/files/etc/radios.json b/files/etc/radios.json index 215c2c23..176e4996 100644 --- a/files/etc/radios.json +++ b/files/etc/radios.json @@ -20,6 +20,16 @@ "gl.inet gl-ar750s (nor/nand)": { "maxpower": "23" }, + "gl.inet gl-b1300": { + }, + "gl.inet gl-mt1300": { + "wlan0": { + "bandwidths": [ 20 ] + }, + "wlan1": { + "bandwidths": [ 20 ] + } + }, "tp-link cpe210 v1": { "maxpower": "23", "chanpower": { @@ -555,6 +565,14 @@ "maxpower": "22", "pwroffset": "4" }, + "0xe4f2": { + "name": "Ubiquiti NanoBeam 2AC 13 (2WA)", + "wlan0": { + "bandwidths": [ 10, 20 ], + "maxpower": 21, + "pwroffset": 6 + } + }, "0xe4f5": { "name": "Ubiquiti NanoBeam AC (XC)", "maxpower": "23", diff --git a/files/etc/uci-defaults/11_compat_version b/files/etc/uci-defaults/11_compat_version index ad2ed533..a8c86eba 100644 --- a/files/etc/uci-defaults/11_compat_version +++ b/files/etc/uci-defaults/11_compat_version @@ -1,15 +1,8 @@ #! /bin/sh -case "$(/usr/local/bin/get_boardid)" in - MikroTik\ hAP\ ac2|\ - MikroTik\ hAP\ ac3|\ - MikroTik\ SXTsq\ 5\ ac*|\ - MikroTik\ LDF\ 5\ ac*|\ - MikroTik\ LHG\ 5\ ac*) - sed -i "s/^compat_version = 1.0/compat_version = 1.1/" /etc/config.mesh/_setup - sed -i "s/^compat_version = 1.0/compat_version = 1.1/" /etc/config.mesh/_setup.default - /sbin/uci -q set system.@system[0].compat_version=1.1 - /sbin/uci -q commit system - ;; - *) - ;; -esac +VER=$(jsonfilter -e '@.system.compat_version' < /etc/board.json) +if [ "${VER}" != "" ]; then + sed -i "s/^compat_version = 1.0/compat_version = ${VER}/" /etc/config.mesh/_setup + sed -i "s/^compat_version = 1.0/compat_version = ${VER}/" /etc/config.mesh/_setup.default + uci -q set system.@system[0].compat_version=${VER} + uci -q commit system +fi diff --git a/files/etc/uci-defaults/94_update_permpkg b/files/etc/uci-defaults/94_update_permpkg new file mode 100755 index 00000000..76622a2e --- /dev/null +++ b/files/etc/uci-defaults/94_update_permpkg @@ -0,0 +1,4 @@ +#! /bin/sh +# Update the permanent package list so we can't uninstall any of the standard system + +opkg list-installed | sed s/\ .*// > /etc/permpkg diff --git a/files/usr/lib/lua/aredn/hardware.lua b/files/usr/lib/lua/aredn/hardware.lua index 44774527..0ede5101 100644 --- a/files/usr/lib/lua/aredn/hardware.lua +++ b/files/usr/lib/lua/aredn/hardware.lua @@ -71,6 +71,28 @@ function hardware.get_radio() return radio_json end +function hardware.get_radio_count() + local radio = hardware.get_radio() + if not radio then + return 0 + elseif radio.wlan0 then + if radio.wlan1 then + return 2 + else + return 1 + end + else + local count = 0 + if nixio.fs.stat("/sys/class/ieee80211") then + for file in nixio.fs.dir("/sys/class/ieee80211") + do + count = count + 1 + end + end + return count + end +end + function hardware.get_radio_intf(wifiintf) local radio = hardware.get_radio() if radio and radio[wifiintf] then @@ -277,19 +299,25 @@ function hardware.get_default_channel(wifiintf) for _, channel in ipairs(hardware.get_rfchannels(wifiintf)) do if channel.frequency == 912 then - return { channel = 5, bandwidth = 5, rfband = "900MHz" } + return { channel = 5, bandwidth = 5, band = "900MHz" } end + local bws = {} + for _, v in ipairs(hardware.get_rfbandwidths(wifiintf)) + do + bws[v] = v + end + local bw = bws[10] or bws[20] or bws[5] or 0 if channel.frequency == 2397 then - return { channel = -2, bandwidth = 10, rfband = "2.4GHz" } + return { channel = -2, bandwidth = bw, band = "2.4GHz" } end if channel.frequency == 2412 then - return { channel = 1, bandwidth = 10, rfband = "2.4GHz" } + return { channel = 1, bandwidth = bw, band = "2.4GHz" } end if channel.frequency == 3420 then - return { channel = 84, bandwidth = 10, rfband = "3GHz" } + return { channel = 84, bandwidth = bw, band = "3GHz" } end if channel.frequency == 5745 then - return { channel = 149, bandwidth = 10, rfband = "5GHz" } + return { channel = 149, bandwidth = bw, band = "5GHz" } end end return nil @@ -320,7 +348,7 @@ function hardware.get_rfchannels(wifiintf) end for line in f:lines() do - local freq, num = line:match("(%d+%.%d+) GHz %(Channel (%-?%d+)%)") + local freq, num = line:match("(%d+%.%d+) GHz %(Band: .*, Channel (%-?%d+)%)") if freq and not line:match("restricted") and not line:match("disabled") then freq = tonumber("" .. freq:gsub("%.", "")) + freq_adjust if freq >= freq_min and freq <= freq_max then diff --git a/files/usr/lib/lua/aredn/utils.lua b/files/usr/lib/lua/aredn/utils.lua index 10889003..d2650caa 100755 --- a/files/usr/lib/lua/aredn/utils.lua +++ b/files/usr/lib/lua/aredn/utils.lua @@ -37,7 +37,7 @@ local nxo = require("nixio") local ipc = require("luci.ip") -require("luci.http") +require('luci.ohttp') require("uci") function round2(num, idp) diff --git a/files/usr/lib/lua/luci/ohttp.lua b/files/usr/lib/lua/luci/ohttp.lua new file mode 100755 index 00000000..20b55f28 --- /dev/null +++ b/files/usr/lib/lua/luci/ohttp.lua @@ -0,0 +1,554 @@ +-- Copyright 2008 Steven Barth +-- Copyright 2010-2018 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +local util = require "luci.util" +local coroutine = require "coroutine" +local table = require "table" +local lhttp = require "lucihttp" +local nixio = require "nixio" +local ltn12 = require "luci.ltn12" + +local table, ipairs, pairs, type, tostring, tonumber, error = + table, ipairs, pairs, type, tostring, tonumber, error + +module "luci.http" + +HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size + +context = util.threadlocal() + +Request = util.class() +function Request.__init__(self, env, sourcein, sinkerr) + self.input = sourcein + self.error = sinkerr + + + -- File handler nil by default to let .content() work + self.filehandler = nil + + -- HTTP-Message table + self.message = { + env = env, + headers = {}, + params = urldecode_params(env.QUERY_STRING or ""), + } + + self.parsed_input = false +end + +function Request.formvalue(self, name, noparse) + if not noparse and not self.parsed_input then + self:_parse_input() + end + + if name then + return self.message.params[name] + else + return self.message.params + end +end + +function Request.formvaluetable(self, prefix) + local vals = {} + prefix = prefix and prefix .. "." or "." + + if not self.parsed_input then + self:_parse_input() + end + + local void = self.message.params[nil] + for k, v in pairs(self.message.params) do + if k:find(prefix, 1, true) == 1 then + vals[k:sub(#prefix + 1)] = tostring(v) + end + end + + return vals +end + +function Request.content(self) + if not self.parsed_input then + self:_parse_input() + end + + return self.message.content, self.message.content_length +end + +function Request.getcookie(self, name) + return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name) +end + +function Request.getenv(self, name) + if name then + return self.message.env[name] + else + return self.message.env + end +end + +function Request.setfilehandler(self, callback) + self.filehandler = callback + + if not self.parsed_input then + return + end + + -- If input has already been parsed then uploads are stored as unlinked + -- temporary files pointed to by open file handles in the parameter + -- value table. Loop all params, and invoke the file callback for any + -- param with an open file handle. + local name, value + for name, value in pairs(self.message.params) do + if type(value) == "table" then + while value.fd do + local data = value.fd:read(1024) + local eof = (not data or data == "") + + callback(value, data, eof) + + if eof then + value.fd:close() + value.fd = nil + end + end + end + end +end + +function Request._parse_input(self) + parse_message_body( + self.input, + self.message, + self.filehandler + ) + self.parsed_input = true +end + +function close() + if not context.eoh then + context.eoh = true + coroutine.yield(3) + end + + if not context.closed then + context.closed = true + coroutine.yield(5) + end +end + +function content() + return context.request:content() +end + +function formvalue(name, noparse) + return context.request:formvalue(name, noparse) +end + +function formvaluetable(prefix) + return context.request:formvaluetable(prefix) +end + +function getcookie(name) + return context.request:getcookie(name) +end + +-- or the environment table itself. +function getenv(name) + return context.request:getenv(name) +end + +function setfilehandler(callback) + return context.request:setfilehandler(callback) +end + +function header(key, value) + if not context.headers then + context.headers = {} + end + context.headers[key:lower()] = value + coroutine.yield(2, key, value) +end + +function prepare_content(mime) + if not context.headers or not context.headers["content-type"] then + if mime == "application/xhtml+xml" then + if not getenv("HTTP_ACCEPT") or + not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then + mime = "text/html; charset=UTF-8" + end + header("Vary", "Accept") + end + header("Content-Type", mime) + end +end + +function source() + return context.request.input +end + +function status(code, message) + code = code or 200 + message = message or "OK" + context.status = code + coroutine.yield(1, code, message) +end + +-- This function is as a valid LTN12 sink. +-- If the content chunk is nil this function will automatically invoke close. +function write(content, src_err) + if not content then + if src_err then + error(src_err) + else + close() + end + return true + elseif #content == 0 then + return true + else + if not context.eoh then + if not context.status then + status() + end + if not context.headers or not context.headers["content-type"] then + header("Content-Type", "text/html; charset=utf-8") + end + if not context.headers["cache-control"] then + header("Cache-Control", "no-cache") + header("Expires", "0") + end + if not context.headers["x-frame-options"] then + header("X-Frame-Options", "SAMEORIGIN") + end + if not context.headers["x-xss-protection"] then + header("X-XSS-Protection", "1; mode=block") + end + if not context.headers["x-content-type-options"] then + header("X-Content-Type-Options", "nosniff") + end + + context.eoh = true + coroutine.yield(3) + end + coroutine.yield(4, content) + return true + end +end + +function splice(fd, size) + coroutine.yield(6, fd, size) +end + +function redirect(url) + if url == "" then url = "/" end + status(302, "Found") + header("Location", url) + close() +end + +function build_querystring(q) + local s, n, k, v = {}, 1, nil, nil + + for k, v in pairs(q) do + s[n+0] = (n == 1) and "?" or "&" + s[n+1] = util.urlencode(k) + s[n+2] = "=" + s[n+3] = util.urlencode(v) + n = n + 4 + end + + return table.concat(s, "") +end + +urldecode = util.urldecode + +urlencode = util.urlencode + +function write_json(x) + util.serialize_json(x, write) +end + +-- from given url or string. Returns a table with urldecoded values. +-- Simple parameters are stored as string values associated with the parameter +-- name within the table. Parameters with multiple values are stored as array +-- containing the corresponding values. +function urldecode_params(url, tbl) + local parser, name + local params = tbl or { } + + parser = lhttp.urlencoded_parser(function (what, buffer, length) + if what == parser.TUPLE then + name, value = nil, nil + elseif what == parser.NAME then + name = lhttp.urldecode(buffer) + elseif what == parser.VALUE and name then + params[name] = lhttp.urldecode(buffer) or "" + end + + return true + end) + + if parser then + parser:parse((url or ""):match("[^?]*$")) + parser:parse(nil) + end + + return params +end + +-- separated by "&". Tables are encoded as parameters with multiple values by +-- repeating the parameter name with each value. +function urlencode_params(tbl) + local k, v + local n, enc = 1, {} + for k, v in pairs(tbl) do + if type(v) == "table" then + local i, v2 + for i, v2 in ipairs(v) do + if enc[1] then + enc[n] = "&" + n = n + 1 + end + + enc[n+0] = lhttp.urlencode(k) + enc[n+1] = "=" + enc[n+2] = lhttp.urlencode(v2) + n = n + 3 + end + else + if enc[1] then + enc[n] = "&" + n = n + 1 + end + + enc[n+0] = lhttp.urlencode(k) + enc[n+1] = "=" + enc[n+2] = lhttp.urlencode(v) + n = n + 3 + end + end + + return table.concat(enc, "") +end + +-- Content-Type. Stores all extracted data associated with its parameter name +-- in the params table within the given message object. Multiple parameter +-- values are stored as tables, ordinary ones as strings. +-- If an optional file callback function is given then it is fed with the +-- file contents chunk by chunk and only the extracted file name is stored +-- within the params table. The callback function will be called subsequently +-- with three arguments: +-- o Table containing decoded (name, file) and raw (headers) mime header data +-- o String value containing a chunk of the file data +-- o Boolean which indicates whether the current chunk is the last one (eof) +function mimedecode_message_body(src, msg, file_cb) + local parser, header, field + local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) + + parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length) + if what == parser.PART_INIT then + field = { } + + elseif what == parser.HEADER_NAME then + header = buffer:lower() + + elseif what == parser.HEADER_VALUE and header then + if header:lower() == "content-disposition" and + lhttp.header_attribute(buffer, nil) == "form-data" + then + field.name = lhttp.header_attribute(buffer, "name") + field.file = lhttp.header_attribute(buffer, "filename") + field[1] = field.file + end + + if field.headers then + field.headers[header] = buffer + else + field.headers = { [header] = buffer } + end + + elseif what == parser.PART_BEGIN then + return not field.file + + elseif what == parser.PART_DATA and field.name and length > 0 then + if field.file then + if file_cb then + file_cb(field, buffer, false) + msg.params[field.name] = msg.params[field.name] or field + else + if not field.fd then + field.fd = nixio.mkstemp(field.name) + end + + if field.fd then + field.fd:write(buffer) + msg.params[field.name] = msg.params[field.name] or field + end + end + else + field.value = buffer + end + + elseif what == parser.PART_END and field.name then + if field.file and msg.params[field.name] then + if file_cb then + file_cb(field, "", true) + elseif field.fd then + field.fd:seek(0, "set") + end + else + local val = msg.params[field.name] + + if type(val) == "table" then + val[#val+1] = field.value or "" + elseif val ~= nil then + msg.params[field.name] = { val, field.value or "" } + else + msg.params[field.name] = field.value or "" + end + end + + field = nil + + elseif what == parser.ERROR then + err = buffer + end + + return true + end, HTTP_MAX_CONTENT) + + return ltn12.pump.all(src, function (chunk) + len = len + (chunk and #chunk or 0) + + if maxlen and len > maxlen + 2 then + return nil, "Message body size exceeds Content-Length" + end + + if not parser or not parser:parse(chunk) then + return nil, err + end + + return true + end) +end + +-- Content-Type. Stores all extracted data associated with its parameter name +-- in the params table within the given message object. Multiple parameter +-- values are stored as tables, ordinary ones as strings. +function urldecode_message_body(src, msg) + local err, name, value, parser + local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) + + parser = lhttp.urlencoded_parser(function (what, buffer, length) + if what == parser.TUPLE then + name, value = nil, nil + elseif what == parser.NAME then + name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) + elseif what == parser.VALUE and name then + local val = msg.params[name] + + if type(val) == "table" then + val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" + elseif val ~= nil then + msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" } + else + msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" + end + elseif what == parser.ERROR then + err = buffer + end + + return true + end, HTTP_MAX_CONTENT) + + return ltn12.pump.all(src, function (chunk) + len = len + (chunk and #chunk or 0) + + if maxlen and len > maxlen + 2 then + return nil, "Message body size exceeds Content-Length" + elseif len > HTTP_MAX_CONTENT then + return nil, "Message body size exceeds maximum allowed length" + end + + if not parser or not parser:parse(chunk) then + return nil, err + end + + return true + end) +end + +-- This function will examine the Content-Type within the given message object +-- to select the appropriate content decoder. +-- Currently the application/x-www-urlencoded and application/form-data +-- mime types are supported. If the encountered content encoding can't be +-- handled then the whole message body will be stored unaltered as "content" +-- property within the given message object. +function parse_message_body(src, msg, filecb) + if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then + local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil) + + -- Is it multipart/mime ? + if ctype == "multipart/form-data" then + return mimedecode_message_body(src, msg, filecb) + + -- Is it application/x-www-form-urlencoded ? + elseif ctype == "application/x-www-form-urlencoded" then + return urldecode_message_body(src, msg) + + end + + -- Unhandled encoding + -- If a file callback is given then feed it chunk by chunk, else + -- store whole buffer in message.content + local sink + + -- If we have a file callback then feed it + if type(filecb) == "function" then + local meta = { + name = "raw", + encoding = msg.env.CONTENT_TYPE + } + sink = function( chunk ) + if chunk then + return filecb(meta, chunk, false) + else + return filecb(meta, nil, true) + end + end + -- ... else append to .content + else + msg.content = "" + msg.content_length = 0 + + sink = function( chunk ) + if chunk then + if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then + msg.content = msg.content .. chunk + msg.content_length = msg.content_length + #chunk + return true + else + return nil, "POST data exceeds maximum allowed length" + end + end + return true + end + end + + -- Pump data... + while true do + local ok, err = ltn12.pump.step( src, sink ) + + if not ok and err then + return nil, err + elseif not ok then -- eof + return true + end + end + + return true + end + + return false +end diff --git a/files/usr/local/bin/mgr/watchdog.lua b/files/usr/local/bin/mgr/watchdog.lua index 4fbd7b42..42c0f9a9 100644 --- a/files/usr/local/bin/mgr/watchdog.lua +++ b/files/usr/local/bin/mgr/watchdog.lua @@ -65,7 +65,7 @@ end function watchdog() while true do - wait_for_ticks(21) + wait_for_ticks(223) local pid = read_all(pidfile) if pid and nixio.fs.stat("/proc/" .. pid) then diff --git a/files/usr/local/bin/mgr/wireless_monitor.lua b/files/usr/local/bin/mgr/wireless_monitor.lua index 89f5e452..14c53c1d 100755 --- a/files/usr/local/bin/mgr/wireless_monitor.lua +++ b/files/usr/local/bin/mgr/wireless_monitor.lua @@ -104,12 +104,6 @@ function M.reset_network(mode) elseif mode == "scan-all" then os.execute(IW .. " " .. wifi .. " scan > /dev/null 2>&1") os.execute(IW .. " " .. wifi .. " scan passive > /dev/null 2>&1") - elseif mode == "reset" then - if chipset == "ath9k" then - write_all("/sys/kernel/debug/ieee80211/" .. phy .. "/ath9k/reset", "1") - else - write_all("/sys/kernel/debug/ieee80211/" .. phy .. "/ath10k/simulate_fw_crash", "hw-restart") - end else log:write("-- unknown") end diff --git a/files/usr/local/bin/node-setup b/files/usr/local/bin/node-setup index 55f01a6d..00b47dbd 100755 --- a/files/usr/local/bin/node-setup +++ b/files/usr/local/bin/node-setup @@ -764,6 +764,7 @@ c:commit("dhcp") local config = "" local ifacenum = 0 local ifacecount = 0 +local devpaths = {} if nixio.fs.stat(ieee80211) then for devname in nixio.fs.dir(ieee80211) do @@ -778,6 +779,11 @@ if nixio.fs.stat(ieee80211) then if devpath:match("^platform.*/pci.*") then devpath = devpath:match("^platform/(.*)") end + local devpathc = devpaths[devpath] or 0 + devpaths[devpath] = devpathc + 1 + if devpathc > 0 then + devpath = devpath .. "+" .. devpathc + end local is_mesh_rf = false local htmode = "HT20" local disabled = "0" diff --git a/files/www/cgi-bin/admin b/files/www/cgi-bin/admin index 75ab656b..8b621a71 100755 --- a/files/www/cgi-bin/admin +++ b/files/www/cgi-bin/admin @@ -169,7 +169,7 @@ end local parms = {} local firmfile = "" if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/advancedconfig b/files/www/cgi-bin/advancedconfig index 04554824..f576ed0f 100755 --- a/files/www/cgi-bin/advancedconfig +++ b/files/www/cgi-bin/advancedconfig @@ -765,7 +765,7 @@ end -- read_postdata local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/advancednetwork b/files/www/cgi-bin/advancednetwork index ddac3722..19296ccf 100755 --- a/files/www/cgi-bin/advancednetwork +++ b/files/www/cgi-bin/advancednetwork @@ -300,7 +300,7 @@ local layout = layouts[get_board_type] local configs = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/mesh b/files/www/cgi-bin/mesh index 753b0a7d..a761877d 100755 --- a/files/www/cgi-bin/mesh +++ b/files/www/cgi-bin/mesh @@ -90,7 +90,7 @@ end -- post data if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/ports b/files/www/cgi-bin/ports index bddfd204..94515080 100755 --- a/files/www/cgi-bin/ports +++ b/files/www/cgi-bin/ports @@ -60,7 +60,7 @@ end -- post_data local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/scan b/files/www/cgi-bin/scan index f1e62e74..a97263fd 100755 --- a/files/www/cgi-bin/scan +++ b/files/www/cgi-bin/scan @@ -149,7 +149,7 @@ end -- scan end if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/setup b/files/www/cgi-bin/setup index f386b51a..207d0cf1 100755 --- a/files/www/cgi-bin/setup +++ b/files/www/cgi-bin/setup @@ -41,7 +41,7 @@ require("aredn.http") require("aredn.utils") require("aredn.hardware") require("uci") -require('luci.http') +require('luci.ohttp') local html = require("aredn.html") local aredn_info = require("aredn.info") @@ -176,7 +176,7 @@ passwd1 = "" passwd2 = "" wifi_intf = "" -local phycount = tonumber(capture("ls -1d /sys/class/ieee80211/* | wc -l"):chomp()) +local phycount = aredn.hardware.get_radio_count() local radio_name = (aredn.hardware.get_radio() or {}).name or "" local M9model = radio_name:match("M9") local M3model = radio_name:match("M3") @@ -428,48 +428,53 @@ if (parms.button_apply or parms.button_save) and wifi_enable == "1" then os.execute("iw dev " .. wifi_intf .. " set txpower fixed " .. wifi_txpower .. "00 >/dev/null 2>&1") end -if parms.button_updatelocation then +if (parms.button_updatelocation or parms.button_save) then -- process gridsquare local cursora = uci.cursor(); local cursorb = uci.cursor("/etc/config.mesh") - if parms.gridsquare ~= "" then - if parms.gridsquare:match("^[A-Z][A-Z]%d%d[a-z][a-z]$") then - cursora:set("aredn", "@location[0]", "gridsquare", parms.gridsquare) - cursorb:set("aredn", "@location[0]", "gridsquare", parms.gridsquare) - out("Gridsquare updated.") + if (cursora:get("aredn", "@location[0]", "gridsquare") or "") ~= parms.gridsquare then + if parms.gridsquare ~= "" then + if parms.gridsquare:match("^[A-Z][A-Z]%d%d[a-z][a-z]$") then + cursora:set("aredn", "@location[0]", "gridsquare", parms.gridsquare) + cursorb:set("aredn", "@location[0]", "gridsquare", parms.gridsquare) + out("Gridsquare updated.") + else + err("ERROR: Gridsquare format is: 2-uppercase letters, 2-digits, 2-lowercase letters. (AB12cd)") + end else - err("ERROR: Gridsquare format is: 2-uppercase letters, 2-digits, 2-lowercase letters. (AB12cd)") + cursora:set("aredn", "@location[0]", "gridsquare", "") + cursorb:set("aredn", "@location[0]", "gridsquare", "") + out("Gridsquare purged.") end - else - cursora:set("aredn", "@location[0]", "gridsquare", "") - cursorb:set("aredn", "@location[0]", "gridsquare", "") - out("Gridsquare purged.") end -- process lat/lng - if parms.latitude ~= "" and parms.longitude ~= "" then - if parms.latitude:match("^[-+]?%d%d?%.%d+$") and parms.longitude:match("^[-+]?%d%d?%d?%.%d+$") then - if tonumber(parms.latitude) >= -90 and tonumber(parms.latitude) <= 90 and tonumber(parms.longitude) >= -180 and tonumber(parms.longitude) <= 180 then - cursora:set("aredn", "@location[0]", "lat", parms.latitude) - cursorb:set("aredn", "@location[0]", "lat", parms.latitude) - cursora:set("aredn", "@location[0]", "lon", parms.longitude) - cursorb:set("aredn", "@location[0]", "lon", parms.longitude) - out("Lat/lon updated.") + if (cursora:get("aredn", "@location[0]", "lat") or "") ~= parms.latitude or (cursora:get("aredn", "@location[0]", "lon") or "") ~= parms.longitude then + if parms.latitude ~= "" and parms.longitude ~= "" then + if parms.latitude:match("^[-+]?%d%d?%.%d+$") and parms.longitude:match("^[-+]?%d%d?%d?%.%d+$") then + if tonumber(parms.latitude) >= -90 and tonumber(parms.latitude) <= 90 and tonumber(parms.longitude) >= -180 and tonumber(parms.longitude) <= 180 then + cursora:set("aredn", "@location[0]", "lat", parms.latitude) + cursorb:set("aredn", "@location[0]", "lat", parms.latitude) + cursora:set("aredn", "@location[0]", "lon", parms.longitude) + cursorb:set("aredn", "@location[0]", "lon", parms.longitude) + out("Lat/lon updated.") + else + err("ERROR: Lat/lon values must be between -90/90 and -180/180, respectively.") + end else - err("ERROR: Lat/lon values must be between -90/90 and -180/180, respectively.") + err("ERROR: Lat/lon format is decimal: (ex. 30.121456 or -95.911154).") end else - err("ERROR: Lat/lon format is decimal: (ex. 30.121456 or -95.911154).") + cursora:set("aredn", "@location[0]", "lat", "") + cursorb:set("aredn", "@location[0]", "lat", "") + cursora:set("aredn", "@location[0]", "lon", "") + cursorb:set("aredn", "@location[0]", "lon", "") + out("Lat/lon purged.") end - else - cursora:set("aredn", "@location[0]", "lat", "") - cursorb:set("aredn", "@location[0]", "lat", "") - cursora:set("aredn", "@location[0]", "lon", "") - cursorb:set("aredn", "@location[0]", "lon", "") - out("Lat/lon purged.") end cursora:commit("aredn") cursorb:commit("aredn") + cursor = cursora end -- retrieve location data @@ -909,7 +914,19 @@ function foundLocation(position) { } function noLocation() { - alert('Could not find location. Try pinning it on the map.'); + const req = new XMLHttpRequest(); + req.addEventListener("load", function() { + try { + const json = JSON.parse(this.responseText); + foundLocation({ coords: { latitude: json.lat, longitude: json.lon }}) + return; + } + catch (_) { + } + alert('Could not find location. Try pinning it on the map.'); + }); + req.open("GET", "http://ip-api.com/json"); + req.send(); } function updDist(x) { @@ -1441,14 +1458,11 @@ html.print("Optional Settings") html.print("Latitude") html.print("") -html.print("Find Me! ") +local locdisabled = pingOK and "" or "disabled" +html.print("Find Me! ") html.print("") -html.print(" Show Map ") -if pingOK then - html.print(" ") -else - html.print("Upload data to AREDN Servers ") -end +html.print(" Show Map ") +html.print(" ") html.print("LongitudeGrid Square ") html.print("Timezone ") diff --git a/files/www/cgi-bin/signal b/files/www/cgi-bin/signal index 25c755c8..deecbe4b 100755 --- a/files/www/cgi-bin/signal +++ b/files/www/cgi-bin/signal @@ -52,7 +52,7 @@ local dmode = "Realtime" -- query string local query = os.getenv("QUERY_STRING") if query then - require('luci.http') + require('luci.ohttp') local params = luci.http.urldecode_params(query) if params.realtime then dmode = "Realtime" diff --git a/files/www/cgi-bin/status b/files/www/cgi-bin/status index ead817d3..95f4c535 100755 --- a/files/www/cgi-bin/status +++ b/files/www/cgi-bin/status @@ -218,7 +218,7 @@ end -- post data if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/vpn b/files/www/cgi-bin/vpn index 3571863b..4c89a64a 100755 --- a/files/www/cgi-bin/vpn +++ b/files/www/cgi-bin/vpn @@ -57,7 +57,7 @@ local VPNVER = "1.1" -- post_data local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/cgi-bin/vpnc b/files/www/cgi-bin/vpnc index 2720ad42..4e38139f 100755 --- a/files/www/cgi-bin/vpnc +++ b/files/www/cgi-bin/vpnc @@ -61,7 +61,7 @@ local VPNVER = "1.0" -- post_data local parms = {} if os.getenv("REQUEST_METHOD") == "POST" then - require('luci.http') + require('luci.ohttp') local request = luci.http.Request(nixio.getenv(), function() local v = io.read(1024) diff --git a/files/www/dot.png b/files/www/dot.png old mode 100644 new mode 100755 index ac2a043b..7e9bd1a5 Binary files a/files/www/dot.png and b/files/www/dot.png differ diff --git a/openwrt.mk b/openwrt.mk index 71d025e0..31cac6e7 100644 --- a/openwrt.mk +++ b/openwrt.mk @@ -2,5 +2,5 @@ OPENWRT_SRC=https://github.com/openwrt/openwrt.git # what branch, tag or commit in this repo? -OPENWRT_COMMIT=v22.03.5 +OPENWRT_COMMIT=v23.05.0 diff --git a/patches/0001-ath79-add-support-for-TP-Link-CPE605-v1.patch b/patches/0001-ath79-add-support-for-TP-Link-CPE605-v1.patch deleted file mode 100644 index c100db61..00000000 --- a/patches/0001-ath79-add-support-for-TP-Link-CPE605-v1.patch +++ /dev/null @@ -1,189 +0,0 @@ -From d51e261e893451f9d0958a5ac39989d10b275e86 Mon Sep 17 00:00:00 2001 -From: Andrew Cameron -Date: Sun, 6 Nov 2022 14:43:37 +0000 -Subject: [PATCH 1/1] ath79: add support for TP-Link CPE605-v1 TP-Link - CPE605-v1 is an outdoor wireless CPE for 5 GHz with one Ethernet port based - on Atheros AR9344 - -Specifications: - - 560/450/225 MHz (CPU/DDR/AHB) - - 1x 10/100 Mbps Ethernet - - 64 MB of DDR2 RAM - - 8 MB of SPI-NOR Flash - - 23dBi high-gain directional antenna and a dedicated metal reflector - - Power, LAN, WLAN5G green LEDs - - 3x green RSSI LEDs - -Flashing instructions: - Flash factory image through stock firmware WEB UI or through TFTP - To get to TFTP recovery just hold reset button while powering on for - around 4-5 seconds and release. - Rename factory image to recovery.bin - Stock TFTP server IP:192.168.0.100 - Stock device TFTP adress:192.168.0.254 - -Signed-off-by: Andrew Cameron ---- - .../ath79/dts/ar9344_tplink_cpe605-v1.dts | 33 +++++++++++++++++++ - .../generic/base-files/etc/board.d/01_leds | 1 + - .../generic/base-files/etc/board.d/02_network | 1 + - target/linux/ath79/image/generic-tp-link.mk | 10 ++++++ - 4 files changed, 45 insertions(+) - create mode 100644 target/linux/ath79/dts/ar9344_tplink_cpe605-v1.dts - -diff --git a/target/linux/ath79/dts/ar9344_tplink_cpe605-v1.dts b/target/linux/ath79/dts/ar9344_tplink_cpe605-v1.dts -new file mode 100644 -index 0000000000..0c6eee7ba6 ---- /dev/null -+++ b/target/linux/ath79/dts/ar9344_tplink_cpe605-v1.dts -@@ -0,0 +1,33 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT -+ -+#include "ar9344_tplink_cpe.dtsi" -+ -+/ { -+ model = "TP-Link CPE605 v1"; -+ compatible = "tplink,cpe605-v1", "qca,ar9344"; -+ -+ aliases { -+ led-boot = &led_lan; -+ led-failsafe = &led_lan; -+ led-upgrade = &led_lan; -+ }; -+ -+ leds { -+ compatible = "gpio-leds"; -+ -+ led_lan: lan { -+ label = "green:lan"; -+ gpios = <&gpio 11 GPIO_ACTIVE_LOW>; -+ }; -+ -+ wlan5g { -+ label = "green:wlan5g"; -+ gpios = <&gpio 13 GPIO_ACTIVE_LOW>; -+ linux,default-trigger = "phy0tpt"; -+ }; -+ }; -+}; -+ -+ð1 { -+ compatible = "syscon", "simple-mfd"; -+}; -diff --git a/target/linux/ath79/generic/base-files/etc/board.d/01_leds b/target/linux/ath79/generic/base-files/etc/board.d/01_leds -index 606a194f7e..54d764f907 100644 ---- a/target/linux/ath79/generic/base-files/etc/board.d/01_leds -+++ b/target/linux/ath79/generic/base-files/etc/board.d/01_leds -@@ -18,6 +18,7 @@ glinet,6416|\ - glinet,gl-ar300m-lite|\ - glinet,gl-ar300m16|\ - pcs,cap324|\ -+tplink,cpe605-v1|\ - tplink,cpe610-v1|\ - tplink,cpe610-v2|\ - tplink,tl-wa1201-v2) -diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network -index e47f66c2f2..2fa0487981 100644 ---- a/target/linux/ath79/generic/base-files/etc/board.d/02_network -+++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network -@@ -76,6 +76,7 @@ ath79_setup_interfaces() - tplink,cpe210-v3|\ - tplink,cpe510-v2|\ - tplink,cpe510-v3|\ -+ tplink,cpe605-v1|\ - tplink,cpe610-v1|\ - tplink,cpe610-v2|\ - tplink,cpe710-v1|\ -diff --git a/target/linux/ath79/image/generic-tp-link.mk b/target/linux/ath79/image/generic-tp-link.mk -index 598085e50b..314ece1e03 100644 ---- a/target/linux/ath79/image/generic-tp-link.mk -+++ b/target/linux/ath79/image/generic-tp-link.mk -@@ -350,6 +350,16 @@ define Device/tplink_cpe510-v3 - endef - TARGET_DEVICES += tplink_cpe510-v3 - -+define Device/tplink_cpe605-v1 -+ $(Device/tplink-safeloader-okli) -+ SOC := ar9344 -+ IMAGE_SIZE := 7680k -+ DEVICE_MODEL := CPE605 -+ DEVICE_VARIANT := v1 -+ TPLINK_BOARD_ID := CPE605V1 -+endef -+TARGET_DEVICES += tplink_cpe605-v1 -+ - define Device/tplink_cpe610-v1 - $(Device/tplink-safeloader-okli) - SOC := ar9344 --- -2.30.2 - -Index: openwrt/tools/firmware-utils/patches/0001-tplink-safeloader-add-TP-Link-CPE605-v1-Support.patch -=================================================================== ---- /dev/null -+++ openwrt/tools/firmware-utils/patches/0001-tplink-safeloader-add-TP-Link-CPE605-v1-Support.patch -@@ -0,0 +1,64 @@ -+From 2b43d1376a6945d07b2a87e48e3645eaa4f24d5a Mon Sep 17 00:00:00 2001 -+From: Andrew Cameron -+Date: Wed, 9 Nov 2022 13:07:11 +0000 -+Subject: [PATCH 1/1] tplink-safeloader: add TP-Link CPE605 v1 Support -+ -+Enable creating images compatible with the TP-Link CPE605 v1 Router -+ -+Signed-off-by: Andrew Cameron -+--- -+ src/tplink-safeloader.c | 38 ++++++++++++++++++++++++++++++++++++++ -+ 1 file changed, 38 insertions(+) -+ -+diff --git a/src/tplink-safeloader.c b/src/tplink-safeloader.c -+index 7f9081d..b920191 100644 -+--- a/src/tplink-safeloader.c -++++ b/src/tplink-safeloader.c -+@@ -468,6 +468,44 @@ static struct device_info boards[] = { -+ .last_sysupgrade_partition = "support-list", -+ }, -+ -++ /** Firmware layout for the CPE605V1 */ -++ { -++ .id = "CPE605V1", -++ .vendor = "CPE605(TP-LINK|UN|N150-5):1.0\r\n", -++ .support_list = -++ "SupportList:\r\n" -++ "CPE605(TP-LINK|UN|N150-5|00000000):1.0\r\n" -++ "CPE605(TP-LINK|EU|N150-5|45550000):1.0\r\n" -++ "CPE605(TP-LINK|US|N150-5|55530000):1.0\r\n" -++ "CPE605(TP-LINK|UN|N150-5):1.0\r\n" -++ "CPE605(TP-LINK|EU|N150-5):1.0\r\n" -++ "CPE605(TP-LINK|US|N150-5):1.0\r\n", -++ .part_trail = 0xff, -++ .soft_ver = SOFT_VER_DEFAULT, -++ -++ .partitions = { -++ {"fs-uboot", 0x00000, 0x20000}, -++ {"partition-table", 0x20000, 0x02000}, -++ {"default-mac", 0x30000, 0x00020}, -++ {"serial-number", 0x30100, 0x00020}, -++ {"product-info", 0x31100, 0x00100}, -++ {"device-info", 0x31400, 0x00400}, -++ {"signature", 0x32000, 0x00400}, -++ {"device-id", 0x33000, 0x00100}, -++ {"firmware", 0x40000, 0x770000}, -++ {"soft-version", 0x7b0000, 0x00100}, -++ {"support-list", 0x7b1000, 0x01000}, -++ {"user-config", 0x7c0000, 0x10000}, -++ {"default-config", 0x7d0000, 0x10000}, -++ {"log", 0x7e0000, 0x10000}, -++ {"radio", 0x7f0000, 0x10000}, -++ {NULL, 0, 0} -++ }, -++ -++ .first_sysupgrade_partition = "os-image", -++ .last_sysupgrade_partition = "support-list", -++ }, -++ -+ /** Firmware layout for the CPE610V1 */ -+ { -+ .id = "CPE610V1", -+-- -+2.30.2 -+ diff --git a/patches/001-ath79-cpe220v3-sysupgrade-supported.patch b/patches/001-ath79-cpe220v3-sysupgrade-supported.patch index c7901975..96d54483 100644 --- a/patches/001-ath79-cpe220v3-sysupgrade-supported.patch +++ b/patches/001-ath79-cpe220v3-sysupgrade-supported.patch @@ -1,10 +1,9 @@ --- a/target/linux/ath79/image/generic-tp-link.mk +++ b/target/linux/ath79/image/generic-tp-link.mk -@@ -312,6 +312,7 @@ define Device/tplink_cpe220-v3 +@@ -312,6 +312,7 @@ DEVICE_PACKAGES := rssileds TPLINK_BOARD_ID := CPE220V3 LOADER_TYPE := elf + SUPPORTED_DEVICES += cpe220-v3 endef TARGET_DEVICES += tplink_cpe220-v3 - diff --git a/patches/001-ath79-reverse-wpad-basic-wolfssl.patch b/patches/001-ath79-reverse-wpad-basic-mbedtls.patch old mode 100644 new mode 100755 similarity index 82% rename from patches/001-ath79-reverse-wpad-basic-wolfssl.patch rename to patches/001-ath79-reverse-wpad-basic-mbedtls.patch index 9f0b58d6..5fba6675 --- a/patches/001-ath79-reverse-wpad-basic-wolfssl.patch +++ b/patches/001-ath79-reverse-wpad-basic-mbedtls.patch @@ -3,7 +3,7 @@ @@ -1,6 +1,6 @@ BOARDNAME:=Generic --DEFAULT_PACKAGES += wpad-basic-wolfssl +-DEFAULT_PACKAGES += wpad-basic-mbedtls +DEFAULT_PACKAGES += wpad-mini define Target/Description @@ -14,8 +14,8 @@ KERNELNAME := vmlinux vmlinuz IMAGES_DIR := ../../.. --DEFAULT_PACKAGES += wpad-basic-wolfssl -+DEFAULT_PACKAGES += wpad-mini +-DEFAULT_PACKAGES += wpad-basic-mbedtls yafut ++DEFAULT_PACKAGES += wpad-mini yafut define Target/Description Build firmware images for MikroTik devices based on Qualcomm Atheros @@ -25,7 +25,7 @@ FEATURES += nand --DEFAULT_PACKAGES += wpad-basic-wolfssl +-DEFAULT_PACKAGES += wpad-basic-mbedtls +DEFAULT_PACKAGES += wpad-mini define Target/Description @@ -36,7 +36,7 @@ BOARDNAME:=Devices with small flash FEATURES += small_flash --DEFAULT_PACKAGES += wpad-basic-wolfssl +-DEFAULT_PACKAGES += wpad-basic-mbedtls +DEFAULT_PACKAGES += wpad-mini define Target/Description @@ -47,8 +47,8 @@ @@ -17,7 +17,7 @@ DEFAULT_PACKAGES += \ kmod-usb-dwc3-qcom \ - kmod-leds-gpio kmod-gpio-button-hotplug swconfig \ -- kmod-ath10k-ct wpad-basic-wolfssl \ + kmod-leds-gpio kmod-gpio-button-hotplug \ +- kmod-ath10k-ct wpad-basic-mbedtls \ + kmod-ath10k-ct wpad-mini \ kmod-usb3 kmod-usb-dwc3 ath10k-firmware-qca4019-ct \ uboot-envtools diff --git a/patches/006-flash-fixes.patch b/patches/006-flash-fixes.patch new file mode 100644 index 00000000..ecc4a640 --- /dev/null +++ b/patches/006-flash-fixes.patch @@ -0,0 +1,28 @@ +--- a/target/linux/generic/config-5.15 ++++ b/target/linux/generic/config-5.15 +@@ -3853,8 +3853,8 @@ + # CONFIG_MTD_SPINAND_MT29F is not set + # CONFIG_MTD_SPI_NAND is not set + # CONFIG_MTD_SPI_NOR is not set +-# CONFIG_MTD_SPI_NOR_SWP_DISABLE is not set +-CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE=y ++CONFIG_MTD_SPI_NOR_SWP_DISABLE=y ++# CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE is not set + # CONFIG_MTD_SPI_NOR_SWP_KEEP is not set + # CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set + # CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE is not set + +--- /dev/null ++++ b/target/linux/generic/backport-5.15/420-flash-fixes.patch +@@ -0,0 +1,11 @@ ++--- a/drivers/mtd/spi-nor/spansion.c +++++ b/drivers/mtd/spi-nor/spansion.c ++@@ -254,7 +254,7 @@ ++ { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, ++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, ++- SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, ++ { "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32, ++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, diff --git a/patches/006-rocket-m-flash-fix.patch b/patches/006-rocket-m-flash-fix.patch deleted file mode 100644 index 4cfbdb3b..00000000 --- a/patches/006-rocket-m-flash-fix.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- /dev/null -+++ b/target/linux/generic/backport-5.10/420-spansion-flash.patch -@@ -0,0 +1,12 @@ -+--- a/drivers/mtd/spi-nor/spansion.c -++++ b/drivers/mtd/spi-nor/spansion.c -+@@ -83,8 +83,7 @@ -+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -+ { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, -+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -+- { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, -+- SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -++ { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK) }, -+ { "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32, -+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -+ { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, diff --git a/patches/010-lz77-decompression-support.patch b/patches/010-lz77-decompression-support.patch index e9f37a0b..f61ec3a7 100644 --- a/patches/010-lz77-decompression-support.patch +++ b/patches/010-lz77-decompression-support.patch @@ -106,7 +106,7 @@ new file mode 100644 index 0000000000000..8e8b7a1689c87 --- /dev/null +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig_lz77.c -@@ -0,0 +1,437 @@ +@@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 John Thomson @@ -461,6 +461,7 @@ index 0000000000000..8e8b7a1689c87 + fallthrough; + case INSTR_LONG: + if (opcode->offset == 0) { ++ unsigned int i; + /* this is a non-matching group */ + pr_debug(" non-match, len: 0x%x\n", + opcode->length); @@ -479,7 +480,7 @@ index 0000000000000..8e8b7a1689c87 + } + } + -+ unsigned int i; for (i = opcode->length; i > 0; --i) { ++ for (i = opcode->length; i > 0; --i) { + *output_ptr = lz77_mikrotik_wlan_get_byte(in, input_bit); + ++output_ptr; + input_bit += 8; diff --git a/patches/701-ath9k-reset.patch b/patches/701-ath9k-reset.patch deleted file mode 100755 index c799c487..00000000 --- a/patches/701-ath9k-reset.patch +++ /dev/null @@ -1,99 +0,0 @@ ---- /dev/null -+++ b/package/kernel/mac80211/patches/ath/301-ath-reset.patch -@@ -0,0 +1,96 @@ -+diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c -+index 4c81b1d7f417..fb7a2952d0ce 100644 -+--- a/drivers/net/wireless/ath/ath9k/debug.c -++++ b/drivers/net/wireless/ath/ath9k/debug.c -+@@ -749,9 +749,9 @@ static int read_file_misc(struct seq_file *file, void *data) -+ -+ static int read_file_reset(struct seq_file *file, void *data) -+ { -+- struct ieee80211_hw *hw = dev_get_drvdata(file->private); -+- struct ath_softc *sc = hw->priv; -++ struct ath_softc *sc = file->private; -+ static const char * const reset_cause[__RESET_TYPE_MAX] = { -++ [RESET_TYPE_USER] = "User reset", -+ [RESET_TYPE_BB_HANG] = "Baseband Hang", -+ [RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog", -+ [RESET_TYPE_FATAL_INT] = "Fatal HW Error", -+@@ -779,6 +779,55 @@ static int read_file_reset(struct seq_file *file, void *data) -+ return 0; -+ } -+ -++static int open_file_reset(struct inode *inode, struct file *f) -++{ -++ return single_open(f, read_file_reset, inode->i_private); -++} -++ -++static ssize_t write_file_reset(struct file *file, -++ const char __user *user_buf, -++ size_t count, loff_t *ppos) -++{ -++ struct ath_softc *sc = file_inode(file)->i_private; -++ struct ath_hw *ah = sc->sc_ah; -++ struct ath_common *common = ath9k_hw_common(ah); -++ unsigned long val; -++ char buf[32]; -++ ssize_t len; -++ -++ len = min(count, sizeof(buf) - 1); -++ if (copy_from_user(buf, user_buf, len)) -++ return -EFAULT; -++ -++ buf[len] = '\0'; -++ if (kstrtoul(buf, 0, &val)) -++ return -EINVAL; -++ -++ if (val != 1) -++ return -EINVAL; -++ -++ /* avoid rearming hw_reset_work on shutdown */ -++ mutex_lock(&sc->mutex); -++ if (test_bit(ATH_OP_INVALID, &common->op_flags)) { -++ mutex_unlock(&sc->mutex); -++ return -EBUSY; -++ } -++ -++ ath9k_queue_reset(sc, RESET_TYPE_USER); -++ mutex_unlock(&sc->mutex); -++ -++ return count; -++} -++ -++static const struct file_operations fops_reset = { -++ .read = seq_read, -++ .write = write_file_reset, -++ .open = open_file_reset, -++ .owner = THIS_MODULE, -++ .llseek = seq_lseek, -++ .release = single_release, -++}; -++ -+ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, -+ struct ath_tx_status *ts, struct ath_txq *txq, -+ unsigned int flags) -+@@ -1393,8 +1442,8 @@ int ath9k_init_debug(struct ath_hw *ah) -+ read_file_queues); -+ debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy, -+ read_file_misc); -+- debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy, -+- read_file_reset); -++ debugfs_create_file("reset", 0600, sc->debug.debugfs_phy, -++ sc, &fops_reset); -+ -+ ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); -+ ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); -+diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h -+index 33826aa13687..389459c04d14 100644 -+--- a/drivers/net/wireless/ath/ath9k/debug.h -++++ b/drivers/net/wireless/ath/ath9k/debug.h -+@@ -39,6 +39,7 @@ struct fft_sample_tlv; -+ #endif -+ -+ enum ath_reset_type { -++ RESET_TYPE_USER, -+ RESET_TYPE_BB_HANG, -+ RESET_TYPE_BB_WATCHDOG, -+ RESET_TYPE_FATAL_INT, -+ diff --git a/patches/701-extended-spectrum.patch b/patches/701-extended-spectrum.patch index 7b837ea8..f150e5cf 100644 --- a/patches/701-extended-spectrum.patch +++ b/patches/701-extended-spectrum.patch @@ -58,10 +58,10 @@ +=================================================================== +--- a/net/wireless/util.c ++++ b/net/wireless/util.c -+@@ -76,13 +76,16 @@ int ieee80211_channel_to_frequency(int c -+ return 0; /* not supported */ ++@@ -81,13 +81,16 @@ int ieee80211_channel_to_frequency(int c + switch (band) { + case NL80211_BAND_2GHZ: ++ case NL80211_BAND_LC: ++ chan = (int)(unsigned char)chan; + if (chan == 14) + return MHZ_TO_KHZ(2484); @@ -406,7 +406,7 @@ + */ + if (channel >= 1 && channel <= 14) { + status->band = NL80211_BAND_2GHZ; -++ } else if (channel >= -4 && channel <= -1) { +++ } else if ((s8)channel >= -4 && (s8)channel <= -1) { ++ status->band = NL80211_BAND_2GHZ; + } else if (channel >= 36 && channel <= ATH10K_MAX_5G_CHAN) { + status->band = NL80211_BAND_5GHZ; diff --git a/patches/706-MeshNode-SSID.patch b/patches/706-MeshNode-SSID.patch index 1f7ce543..307b0d19 100644 --- a/patches/706-MeshNode-SSID.patch +++ b/patches/706-MeshNode-SSID.patch @@ -13,18 +13,19 @@ uci -q batch <<-EOF set wireless.radio${devidx}=wifi-device set wireless.radio${devidx}.type=mac80211 -@@ -174,13 +180,12 @@ - set wireless.radio${devidx}.channel=${channel} - set wireless.radio${devidx}.band=${mode_band} - set wireless.radio${devidx}.htmode=$htmode -- set wireless.radio${devidx}.disabled=1 +@@ -203,13 +203,13 @@ + set wireless.${name}.channel=${channel} + set wireless.${name}.band=${mode_band} + set wireless.${name}.htmode=$htmode +- set wireless.${name}.disabled=1 - set wireless.default_radio${devidx}=wifi-iface - set wireless.default_radio${devidx}.device=radio${devidx} - set wireless.default_radio${devidx}.network=lan - set wireless.default_radio${devidx}.mode=ap -- set wireless.default_radio${devidx}.ssid=OpenWrt -+ set wireless.default_radio${devidx}.ssid=${arednssid} - set wireless.default_radio${devidx}.encryption=none + set wireless.default_${name}=wifi-iface + set wireless.default_${name}.device=${name} + set wireless.default_${name}.network=lan + set wireless.default_${name}.mode=ap +- set wireless.default_${name}.ssid=OpenWrt ++ set wireless.default_${name}.ssid=${arednssid} ++ set wireless.default_${name}.ifname=$(echo ${name} | sed s/radio/wlan/) + set wireless.default_${name}.encryption=none EOF uci -q commit wireless diff --git a/patches/708-define-aredn-ath79-networks.patch b/patches/708-define-aredn-ath79-networks.patch index b8e6c669..292877f5 100644 --- a/patches/708-define-aredn-ath79-networks.patch +++ b/patches/708-define-aredn-ath79-networks.patch @@ -1,9 +1,9 @@ --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network -@@ -113,7 +113,9 @@ ath79_setup_interfaces() - ubnt,unifi|\ - wd,mynet-wifi-rangeextender|\ - winchannel,wb2000) +@@ -126,7 +126,9 @@ ath79_setup_interfaces() + zyxel,nwa1121-ni|\ + zyxel,nwa1123-ac|\ + zyxel,nwa1123-ni) - ucidef_set_interface_lan "eth0" + ucidef_set_interfaces_lan_wan "eth0" "eth0.1" + ucidef_set_interface "wifi" device "wlan0" protocol "static" @@ -186,9 +186,9 @@ --- a/target/linux/ath79/nand/base-files/etc/board.d/02_network +++ b/target/linux/ath79/nand/base-files/etc/board.d/02_network @@ -9,7 +9,9 @@ ath79_setup_interfaces() - case "$board" in aerohive,hiveap-121|\ - glinet,gl-e750) + glinet,gl-e750|\ + meraki,mr18) - ucidef_set_interface_lan "eth0" + ucidef_set_interfaces_lan_wan "eth0" "eth0.1" + ucidef_set_interface "dtdlink" device "eth0.2" protocol "static" @@ -223,7 +223,7 @@ --- a/target/linux/ath79/mikrotik/base-files/etc/board.d/02_network +++ b/target/linux/ath79/mikrotik/base-files/etc/board.d/02_network -@@ -22,14 +22,21 @@ +@@ -23,15 +23,22 @@ mikrotik,routerboard-wap-2nd|\ mikrotik,routerboard-wap-g-5hact2hnd|\ mikrotik,routerboard-wapr-2nd) @@ -232,6 +232,7 @@ + ucidef_set_interface "dtdlink" device "eth0.2 eth1.2" protocol "static" + ucidef_set_interface "wifi" device "wlan0" protocol "static" ;; + mikrotik,routerboard-951ui-2hnd|\ - mikrotik,routerboard-951ui-2nd|\ - mikrotik,routerboard-952ui-5ac2nd) + mikrotik,routerboard-951ui-2nd) @@ -275,9 +276,9 @@ + ucidef_set_interface "dtdlink" device "eth0.2 eth1.2" protocol "static" + ucidef_set_interface "wifi" device "wlan0" protocol "static" + ;; + mikrotik,routerboard-951ui-2hnd|\ mikrotik,routerboard-951ui-2nd) ucidef_set_interface_wan "eth1" - ucidef_add_switch "switch0" \ --- a/target/linux/ath79/mikrotik/base-files/etc/board.d/02_network +++ b/target/linux/ath79/mikrotik/base-files/etc/board.d/02_network @@ -305,6 +306,19 @@ --- a/target/linux/ath79/tiny/base-files/etc/board.d/02_network +++ b/target/linux/ath79/tiny/base-files/etc/board.d/02_network +@@ -55,7 +55,9 @@ + ubnt,nanobridge-m|\ + ubnt,picostation-m|\ + ubnt,nanostation-loco-m) +- ucidef_set_interface_lan "eth0" ++ ucidef_set_interfaces_lan_wan "eth0" "eth0.1" ++ ucidef_set_interface "dtdlink" device "eth0.2" protocol "static" ++ ucidef_set_interface "wifi" device "wlan0" protocol "static" + ;; + engenius,enh202-v1) + ucidef_set_interface_lan "eth0" +--- a/target/linux/ath79/tiny/base-files/etc/board.d/02_network ++++ b/target/linux/ath79/tiny/base-files/etc/board.d/02_network @@ -111,7 +111,10 @@ "0@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" ;; diff --git a/patches/708-define-aredn-ipq40xx-networks.patch b/patches/708-define-aredn-ipq40xx-networks.patch index 09096e66..3d225a87 100644 --- a/patches/708-define-aredn-ipq40xx-networks.patch +++ b/patches/708-define-aredn-ipq40xx-networks.patch @@ -1,36 +1,41 @@ --- a/target/linux/ipq40xx/base-files/etc/board.d/02_network +++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network -@@ -30,12 +30,16 @@ - engenius,emd1|\ +@@ -26,7 +26,9 @@ + pakedge,wr-1|\ + teltonika,rutx50|\ + zyxel,nbg6617) +- ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "wan" ++ ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan" ++ ucidef_set_interface "dtdlink" device "lan4.2" protocol "static" ++ ucidef_set_interface "wifi" device "wlan0" protocol "static" + ;; + 8dev,jalapeno|\ + alfa-network,ap120c-ac|\ +@@ -54,11 +56,15 @@ meraki,mr33|\ + meraki,mr74|\ mikrotik,lhgg-60ad|\ - mikrotik,sxtsq-5-ac|\ netgear,ex6100v2|\ - netgear,ex6150v2|\ - zyxel,wre6606) - ucidef_set_interface_lan "eth0" + netgear,ex6150v2) + ucidef_set_interface_lan "lan" ;; + mikrotik,sxtsq-5-ac) + ucidef_set_interfaces_lan_wan "lan" "lan.1" + ucidef_set_interface "wifi" device "wlan0" protocol "static" + ucidef_set_interface "dtdlink" device "lan.2" protocol "static" + ;; - aruba,ap-303h|\ - teltonika,rutx10) - ucidef_set_interfaces_lan_wan "eth0" "eth1" - ---- a/target/linux/ipq40xx/base-files/etc/board.d/02_network -+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network -@@ -61,9 +61,9 @@ - p2w,r619ac-64m|\ - p2w,r619ac-128m|\ - zyxel,nbg6617) -- ucidef_set_interfaces_lan_wan "eth0" "eth1" -- ucidef_add_switch "switch0" \ -- "0u@eth0" "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" -+ ucidef_set_interfaces_lan_wan "lan1 lan2 lan3" "wan" -+ ucidef_set_interface "dtdlink" device "lan4.2" protocol "static" + avm,fritzbox-7530) + ucidef_set_interface_lan "lan1 lan2 lan3 lan4" + ;; +@@ -83,7 +83,9 @@ + glinet,gl-a1300|\ + glinet,gl-b1300|\ + mobipromo,cm520-79f) +- ucidef_set_interfaces_lan_wan "lan1 lan2" "wan" ++ ucidef_set_interfaces_lan_wan "lan1" "wan" ++ ucidef_set_interface "dtdlink" device "lan2.2" protocol "static" + ucidef_set_interface "wifi" device "wlan0" protocol "static" ;; - avm,fritzbox-4040|\ - linksys,ea6350v3|\ + mikrotik,wap-ac|\ + mikrotik,wap-ac-lte|\ diff --git a/patches/708-define-aredn-ramips-networks.patch b/patches/708-define-aredn-ramips-networks.patch new file mode 100755 index 00000000..b54ac4cb --- /dev/null +++ b/patches/708-define-aredn-ramips-networks.patch @@ -0,0 +1,13 @@ +--- a/target/linux/ramips/mt7621/base-files/etc/board.d/02_network ++++ b/target/linux/ramips/mt7621/base-files/etc/board.d/02_network +@@ -80,7 +80,9 @@ + xiaomi,mi-router-4|\ + xiaomi,mi-router-4a-gigabit|\ + xiaomi,mi-router-4a-gigabit-v2) +- ucidef_set_interfaces_lan_wan "lan1 lan2" "wan" ++ ucidef_set_interfaces_lan_wan "lan2" "wan" ++ ucidef_set_interface "dtdlink" device "lan1.2" protocol "static" ++ ucidef_set_interface "wifi" device "wlan0" protocol "static" + ;; + bolt,arion) + ucidef_set_interfaces_lan_wan "lan" "wan" diff --git a/patches/708-define-aredn-rocket-m-networks.patch b/patches/708-define-aredn-rocket-m-networks.patch deleted file mode 100644 index f62b796c..00000000 --- a/patches/708-define-aredn-rocket-m-networks.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- a/target/linux/ath79/tiny/base-files/etc/board.d/02_network -+++ b/target/linux/ath79/tiny/base-files/etc/board.d/02_network -@@ -57,7 +57,9 @@ - ubnt,nanostation-loco-m|\ - ubnt,powerbridge-m|\ - ubnt,rocket-m) -- ucidef_set_interface_lan "eth0" -+ ucidef_set_interfaces_lan_wan "eth0" "eth0.1" -+ ucidef_set_interface "dtdlink" device "eth0.2" protocol "static" -+ ucidef_set_interface "wifi" device "wlan0" protocol "static" - ;; - engenius,enh202-v1) - ucidef_set_interface_lan "eth0" diff --git a/patches/709-iperf-fw-restart.patch b/patches/709-iperf-fw-restart.patch index 4ba6c764..78e711e0 100644 --- a/patches/709-iperf-fw-restart.patch +++ b/patches/709-iperf-fw-restart.patch @@ -5,7 +5,7 @@ Index: openwrt/feeds/packages/net/iperf3/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=iperf - PKG_VERSION:=3.11 + PKG_VERSION:=3.15 -PKG_RELEASE:=1 +PKG_RELEASE:=1AREDN diff --git a/patches/711-aredn-ports-dumbswitch-ar8216.patch b/patches/711-aredn-ports-dumbswitch-ar8216.patch index 7ffb7f43..2cf37f1e 100644 --- a/patches/711-aredn-ports-dumbswitch-ar8216.patch +++ b/patches/711-aredn-ports-dumbswitch-ar8216.patch @@ -1,5 +1,5 @@ --- /dev/null -+++ b/target/linux/ath79/patches-5.10/903-phy-ar8216-no-van-ports.patch ++++ b/target/linux/ath79/patches-5.15/903-phy-ar8216-no-van-ports.patch @@ -0,0 +1,13 @@ +--- a/drivers/net/phy/ar8216.c ++++ b/drivers/net/phy/ar8216.c @@ -8,9 +8,9 @@ + continue; + +- portmask[i] = 1 << AR8216_PORT_CPU; -++ for (j = 0; j < dev->ports; j++) { -++ portmask[i] |= (1 << j); -++ } +++ for (j = 0; j < dev->ports; j++) { +++ portmask[i] |= (1 << j); +++ } + portmask[AR8216_PORT_CPU] |= (1 << i); + } + } diff --git a/patches/712-auto-distance-settings.patch b/patches/712-auto-distance-settings.patch index 21e39307..0bc2195a 100644 --- a/patches/712-auto-distance-settings.patch +++ b/patches/712-auto-distance-settings.patch @@ -1,15 +1,15 @@ --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh -@@ -1096,7 +1096,11 @@ drv_mac80211_setup() { +@@ -1102,7 +1102,11 @@ + wireless_set_data phy="$phy" txantenna="$txantenna" rxantenna="$rxantenna" iw phy "$phy" set antenna $txantenna $rxantenna >/dev/null 2>&1 - iw phy "$phy" set antenna_gain $antenna_gain >/dev/null 2>&1 - iw phy "$phy" set distance "$distance" >/dev/null 2>&1 -+ if [ $distance -eq 0 -a -d /sys/kernel/debug/ieee80211/$phy/ath9k ]; then -+ iw phy "$phy" set distance auto -+ else -+ iw phy "$phy" set distance "$distance" -+ fi ++ if [ $distance -eq 0 -a -d /sys/kernel/debug/ieee80211/$phy/ath9k ]; then ++ iw phy "$phy" set distance auto ++ else ++ iw phy "$phy" set distance "$distance" ++ fi if [ -n "$txpower" ]; then iw phy "$phy" set txpower fixed "${txpower%%.*}00" diff --git a/patches/719-disable-ipv6.patch b/patches/719-disable-ipv6.patch index 14178fbf..45d7cf47 100644 --- a/patches/719-disable-ipv6.patch +++ b/patches/719-disable-ipv6.patch @@ -1,14 +1,14 @@ --- a/config/Config-build.in +++ b/config/Config-build.in -@@ -156,7 +156,7 @@ +@@ -160,7 +160,7 @@ + Packages can choose to opt-out via setting PKG_BUILD_FLAGS:=no-lto + config IPV6 - bool - prompt "Enable IPv6 support in packages" -- default y -+ default n - help - Enables IPv6 support in kernel (builtin) and packages. - +- def_bool y ++ def_bool n + + comment "Stripping options" + --- a/include/netfilter.mk +++ b/include/netfilter.mk @@ -325,7 +325,7 @@ @@ -46,7 +46,7 @@ --- /dev/null +++ b/package/network/config/firewall4/patches/001-disable-ipv6.patch -@@ -0,0 +1,119 @@ +@@ -0,0 +1,139 @@ +--- a/root/usr/share/firewall4/main.uc ++++ b/root/usr/share/firewall4/main.uc +@@ -33,14 +33,14 @@ function reload_sets() { @@ -166,3 +166,23 @@ + {%+ include("zone-match.uc", { egress, rule }) -%} + {%+ if (zone.counter): -%} + counter {%+ endif -%} ++--- a/root/usr/share/firewall4/templates/mangle-rule.uc ++--- a/root/usr/share/firewall4/templates/mangle-rule.uc ++@@ -1,7 +1,7 @@ ++ {%+ for (let src_devices in rule.src?.zone) } ++ ++ {%+ if (rule.family && !rule.has_addrs): -%} ++- meta nfproto {{ fw4.nfproto(rule.family) }} {%+ endif -%} +++ {%+ endif -%} ++ {%+ if (!rule.proto.any && !rule.has_ports && !rule.icmp_types && !rule.icmp_codes): -%} ++ meta l4proto {{ ++ (rule.proto.name == 'icmp' && rule.family == 6) ? 'ipv6-icmp' : rule.proto.name ++--- a/root/usr/share/firewall4/templates/zone-drop-invalid.uc +++++ a/root/usr/share/firewall4/templates/zone-drop-invalid.uc ++@@ -1,5 +1,5 @@ ++ {%+ if (zone.masq ^ zone.masq6): -%} ++- meta nfproto {{ fw4.nfproto(zone.masq ? 4 : 6) }} {%+ endif -%} +++ {%+ endif -%} ++ {%+ include("zone-match.uc", { egress: true, rule }) -%} ++ ct state invalid {%+ if (zone.counter): -%} ++ counter {%+ endif -%} diff --git a/patches/730-ipq40xx-dsa.patch b/patches/730-ipq40xx-dsa.patch deleted file mode 100644 index 428073c0..00000000 --- a/patches/730-ipq40xx-dsa.patch +++ /dev/null @@ -1,19078 +0,0 @@ ---- a/target/linux/ipq40xx/Makefile -+++ b/target/linux/ipq40xx/Makefile -@@ -15,7 +15,7 @@ KERNELNAME:=zImage Image dtbs - include $(INCLUDE_DIR)/target.mk - DEFAULT_PACKAGES += \ - kmod-usb-dwc3-qcom \ -- kmod-leds-gpio kmod-gpio-button-hotplug swconfig \ -+ kmod-leds-gpio kmod-gpio-button-hotplug \ - kmod-ath10k-ct wpad-mini \ - kmod-usb3 kmod-usb-dwc3 ath10k-firmware-qca4019-ct \ - uboot-envtools ---- a/target/linux/ipq40xx/config-5.10 -+++ b/target/linux/ipq40xx/config-5.10 -@@ -1,7 +1,6 @@ - CONFIG_ALIGNMENT_TRAP=y - # CONFIG_APQ_GCC_8084 is not set - # CONFIG_APQ_MMCC_8084 is not set --CONFIG_AR40XX_PHY=y - CONFIG_ARCH_32BIT_OFF_T=y - CONFIG_ARCH_HIBERNATION_POSSIBLE=y - CONFIG_ARCH_IPQ40XX=y ---- a/target/linux/ipq40xx/config-5.10 -+++ b/target/linux/ipq40xx/config-5.10 -@@ -148,7 +147,6 @@ CONFIG_DYNAMIC_DEBUG=y - CONFIG_EDAC_ATOMIC_SCRUB=y - CONFIG_EDAC_SUPPORT=y - CONFIG_EEPROM_AT24=y --CONFIG_ESSEDMA=y - CONFIG_EXTCON=y - CONFIG_FIXED_PHY=y - CONFIG_FIX_EARLYCON_MEM=y ---- a/target/linux/ipq40xx/config-5.10 -+++ b/target/linux/ipq40xx/config-5.10 -@@ -457,8 +455,6 @@ CONFIG_SPMI=y - CONFIG_SPMI_MSM_PMIC_ARB=y - # CONFIG_SPMI_PMIC_CLKDIV is not set - CONFIG_SRCU=y --CONFIG_SWCONFIG=y --CONFIG_SWCONFIG_LEDS=y - CONFIG_SWPHY=y - CONFIG_SWP_EMULATE=y - CONFIG_SYS_SUPPORTS_APM_EMULATION=y ---- a/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/essedma/Makefile -+++ /dev/null -@@ -1,9 +0,0 @@ --# --## Makefile for the Qualcomm Atheros ethernet edma driver --# -- -- --obj-$(CONFIG_ESSEDMA) += essedma.o -- --essedma-objs := edma_axi.o edma.o edma_ethtool.o -- ---- a/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/essedma/edma.c -+++ /dev/null -@@ -1,2177 +0,0 @@ --/* -- * Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved. -- * -- * Permission to use, copy, modify, and/or distribute this software for -- * any purpose with or without fee is hereby granted, provided that the -- * above copyright notice and this permission notice appear in all copies. -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- */ -- --#include --#include --#include "ess_edma.h" --#include "edma.h" -- --extern struct net_device *edma_netdev[EDMA_MAX_PORTID_SUPPORTED]; --bool edma_stp_rstp; --u16 edma_ath_eth_type; -- --/* edma_skb_priority_offset() -- * get edma skb priority -- */ --static unsigned int edma_skb_priority_offset(struct sk_buff *skb) --{ -- return (skb->priority >> 2) & 1; --} -- --/* edma_alloc_tx_ring() -- * Allocate Tx descriptors ring -- */ --static int edma_alloc_tx_ring(struct edma_common_info *edma_cinfo, -- struct edma_tx_desc_ring *etdr) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- -- /* Initialize ring */ -- etdr->size = sizeof(struct edma_sw_desc) * etdr->count; -- etdr->sw_next_to_fill = 0; -- etdr->sw_next_to_clean = 0; -- -- /* Allocate SW descriptors */ -- etdr->sw_desc = vzalloc(etdr->size); -- if (!etdr->sw_desc) { -- dev_err(&pdev->dev, "buffer alloc of tx ring failed=%p", etdr); -- return -ENOMEM; -- } -- -- /* Allocate HW descriptors */ -- etdr->hw_desc = dma_alloc_coherent(&pdev->dev, etdr->size, &etdr->dma, -- GFP_KERNEL); -- if (!etdr->hw_desc) { -- dev_err(&pdev->dev, "descriptor allocation for tx ring failed"); -- vfree(etdr->sw_desc); -- return -ENOMEM; -- } -- -- return 0; --} -- --/* edma_free_tx_ring() -- * Free tx rings allocated by edma_alloc_tx_rings -- */ --static void edma_free_tx_ring(struct edma_common_info *edma_cinfo, -- struct edma_tx_desc_ring *etdr) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- -- if (likely(etdr->dma)) -- dma_free_coherent(&pdev->dev, etdr->size, etdr->hw_desc, -- etdr->dma); -- -- vfree(etdr->sw_desc); -- etdr->sw_desc = NULL; --} -- --/* edma_alloc_rx_ring() -- * allocate rx descriptor ring -- */ --static int edma_alloc_rx_ring(struct edma_common_info *edma_cinfo, -- struct edma_rfd_desc_ring *erxd) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- -- erxd->size = sizeof(struct edma_sw_desc) * erxd->count; -- erxd->sw_next_to_fill = 0; -- erxd->sw_next_to_clean = 0; -- -- /* Allocate SW descriptors */ -- erxd->sw_desc = vzalloc(erxd->size); -- if (!erxd->sw_desc) -- return -ENOMEM; -- -- /* Alloc HW descriptors */ -- erxd->hw_desc = dma_alloc_coherent(&pdev->dev, erxd->size, &erxd->dma, -- GFP_KERNEL); -- if (!erxd->hw_desc) { -- vfree(erxd->sw_desc); -- return -ENOMEM; -- } -- -- /* Initialize pending_fill */ -- erxd->pending_fill = 0; -- -- return 0; --} -- --/* edma_free_rx_ring() -- * Free rx ring allocated by alloc_rx_ring -- */ --static void edma_free_rx_ring(struct edma_common_info *edma_cinfo, -- struct edma_rfd_desc_ring *rxdr) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- -- if (likely(rxdr->dma)) -- dma_free_coherent(&pdev->dev, rxdr->size, rxdr->hw_desc, -- rxdr->dma); -- -- vfree(rxdr->sw_desc); -- rxdr->sw_desc = NULL; --} -- --/* edma_configure_tx() -- * Configure transmission control data -- */ --static void edma_configure_tx(struct edma_common_info *edma_cinfo) --{ -- u32 txq_ctrl_data; -- -- txq_ctrl_data = (EDMA_TPD_BURST << EDMA_TXQ_NUM_TPD_BURST_SHIFT); -- txq_ctrl_data |= EDMA_TXQ_CTRL_TPD_BURST_EN; -- txq_ctrl_data |= (EDMA_TXF_BURST << EDMA_TXQ_TXF_BURST_NUM_SHIFT); -- edma_write_reg(EDMA_REG_TXQ_CTRL, txq_ctrl_data); --} -- -- --/* edma_configure_rx() -- * configure reception control data -- */ --static void edma_configure_rx(struct edma_common_info *edma_cinfo) --{ -- struct edma_hw *hw = &edma_cinfo->hw; -- u32 rss_type, rx_desc1, rxq_ctrl_data; -- -- /* Set RSS type */ -- rss_type = hw->rss_type; -- edma_write_reg(EDMA_REG_RSS_TYPE, rss_type); -- -- /* Set RFD burst number */ -- rx_desc1 = (EDMA_RFD_BURST << EDMA_RXQ_RFD_BURST_NUM_SHIFT); -- -- /* Set RFD prefetch threshold */ -- rx_desc1 |= (EDMA_RFD_THR << EDMA_RXQ_RFD_PF_THRESH_SHIFT); -- -- /* Set RFD in host ring low threshold to generte interrupt */ -- rx_desc1 |= (EDMA_RFD_LTHR << EDMA_RXQ_RFD_LOW_THRESH_SHIFT); -- edma_write_reg(EDMA_REG_RX_DESC1, rx_desc1); -- -- /* Set Rx FIFO threshold to start to DMA data to host */ -- rxq_ctrl_data = EDMA_FIFO_THRESH_128_BYTE; -- -- /* Set RX remove vlan bit */ -- rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN; -- -- edma_write_reg(EDMA_REG_RXQ_CTRL, rxq_ctrl_data); --} -- --/* edma_alloc_rx_buf() -- * does skb allocation for the received packets. -- */ --static int edma_alloc_rx_buf(struct edma_common_info -- *edma_cinfo, -- struct edma_rfd_desc_ring *erdr, -- int cleaned_count, int queue_id) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- struct edma_rx_free_desc *rx_desc; -- struct edma_sw_desc *sw_desc; -- struct sk_buff *skb; -- unsigned int i; -- u16 prod_idx, length; -- u32 reg_data; -- -- if (cleaned_count > erdr->count) -- cleaned_count = erdr->count - 1; -- -- i = erdr->sw_next_to_fill; -- -- while (cleaned_count) { -- sw_desc = &erdr->sw_desc[i]; -- length = edma_cinfo->rx_head_buffer_len; -- -- if (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_REUSE) { -- skb = sw_desc->skb; -- -- /* Clear REUSE Flag */ -- sw_desc->flags &= ~EDMA_SW_DESC_FLAG_SKB_REUSE; -- } else { -- /* alloc skb */ -- skb = netdev_alloc_skb_ip_align(edma_netdev[0], length); -- if (!skb) { -- /* Better luck next round */ -- break; -- } -- } -- -- if (edma_cinfo->page_mode) { -- struct page *pg = alloc_page(GFP_ATOMIC); -- -- if (!pg) { -- dev_kfree_skb_any(skb); -- break; -- } -- -- sw_desc->dma = dma_map_page(&pdev->dev, pg, 0, -- edma_cinfo->rx_page_buffer_len, -- DMA_FROM_DEVICE); -- if (dma_mapping_error(&pdev->dev, -- sw_desc->dma)) { -- __free_page(pg); -- dev_kfree_skb_any(skb); -- break; -- } -- -- skb_fill_page_desc(skb, 0, pg, 0, -- edma_cinfo->rx_page_buffer_len); -- sw_desc->flags = EDMA_SW_DESC_FLAG_SKB_FRAG; -- sw_desc->length = edma_cinfo->rx_page_buffer_len; -- } else { -- sw_desc->dma = dma_map_single(&pdev->dev, skb->data, -- length, DMA_FROM_DEVICE); -- if (dma_mapping_error(&pdev->dev, -- sw_desc->dma)) { -- dev_kfree_skb_any(skb); -- break; -- } -- -- sw_desc->flags = EDMA_SW_DESC_FLAG_SKB_HEAD; -- sw_desc->length = length; -- } -- -- /* Update the buffer info */ -- sw_desc->skb = skb; -- rx_desc = (&((struct edma_rx_free_desc *)(erdr->hw_desc))[i]); -- rx_desc->buffer_addr = cpu_to_le64(sw_desc->dma); -- if (++i == erdr->count) -- i = 0; -- cleaned_count--; -- } -- -- erdr->sw_next_to_fill = i; -- -- if (i == 0) -- prod_idx = erdr->count - 1; -- else -- prod_idx = i - 1; -- -- /* Update the producer index */ -- edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), ®_data); -- reg_data &= ~EDMA_RFD_PROD_IDX_BITS; -- reg_data |= prod_idx; -- edma_write_reg(EDMA_REG_RFD_IDX_Q(queue_id), reg_data); -- -- /* If we couldn't allocate all the buffers -- * we increment the alloc failure counters -- */ -- if (cleaned_count) -- edma_cinfo->edma_ethstats.rx_alloc_fail_ctr++; -- -- return cleaned_count; --} -- --/* edma_init_desc() -- * update descriptor ring size, buffer and producer/consumer index -- */ --static void edma_init_desc(struct edma_common_info *edma_cinfo) --{ -- struct edma_rfd_desc_ring *rfd_ring; -- struct edma_tx_desc_ring *etdr; -- int i = 0, j = 0; -- u32 data = 0; -- u16 hw_cons_idx = 0; -- -- /* Set the base address of every TPD ring. */ -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) { -- etdr = edma_cinfo->tpd_ring[i]; -- -- /* Update descriptor ring base address */ -- edma_write_reg(EDMA_REG_TPD_BASE_ADDR_Q(i), (u32)etdr->dma); -- edma_read_reg(EDMA_REG_TPD_IDX_Q(i), &data); -- -- /* Calculate hardware consumer index */ -- hw_cons_idx = (data >> EDMA_TPD_CONS_IDX_SHIFT) & 0xffff; -- etdr->sw_next_to_fill = hw_cons_idx; -- etdr->sw_next_to_clean = hw_cons_idx; -- data &= ~(EDMA_TPD_PROD_IDX_MASK << EDMA_TPD_PROD_IDX_SHIFT); -- data |= hw_cons_idx; -- -- /* update producer index */ -- edma_write_reg(EDMA_REG_TPD_IDX_Q(i), data); -- -- /* update SW consumer index register */ -- edma_write_reg(EDMA_REG_TX_SW_CONS_IDX_Q(i), hw_cons_idx); -- -- /* Set TPD ring size */ -- edma_write_reg(EDMA_REG_TPD_RING_SIZE, -- edma_cinfo->tx_ring_count & -- EDMA_TPD_RING_SIZE_MASK); -- } -- -- for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { -- rfd_ring = edma_cinfo->rfd_ring[j]; -- /* Update Receive Free descriptor ring base address */ -- edma_write_reg(EDMA_REG_RFD_BASE_ADDR_Q(j), -- (u32)(rfd_ring->dma)); -- j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); -- } -- -- data = edma_cinfo->rx_head_buffer_len; -- if (edma_cinfo->page_mode) -- data = edma_cinfo->rx_page_buffer_len; -- -- data &= EDMA_RX_BUF_SIZE_MASK; -- data <<= EDMA_RX_BUF_SIZE_SHIFT; -- -- /* Update RFD ring size and RX buffer size */ -- data |= (edma_cinfo->rx_ring_count & EDMA_RFD_RING_SIZE_MASK) -- << EDMA_RFD_RING_SIZE_SHIFT; -- -- edma_write_reg(EDMA_REG_RX_DESC0, data); -- -- /* Disable TX FIFO low watermark and high watermark */ -- edma_write_reg(EDMA_REG_TXF_WATER_MARK, 0); -- -- /* Load all of base address above */ -- edma_read_reg(EDMA_REG_TX_SRAM_PART, &data); -- data |= 1 << EDMA_LOAD_PTR_SHIFT; -- edma_write_reg(EDMA_REG_TX_SRAM_PART, data); --} -- --/* edma_receive_checksum -- * Api to check checksum on receive packets -- */ --static void edma_receive_checksum(struct edma_rx_return_desc *rd, -- struct sk_buff *skb) --{ -- skb_checksum_none_assert(skb); -- -- /* check the RRD IP/L4 checksum bit to see if -- * its set, which in turn indicates checksum -- * failure. -- */ -- if (rd->rrd6 & EDMA_RRD_CSUM_FAIL_MASK) -- return; -- -- skb->ip_summed = CHECKSUM_UNNECESSARY; --} -- --/* edma_clean_rfd() -- * clean up rx resourcers on error -- */ --static void edma_clean_rfd(struct edma_rfd_desc_ring *erdr, u16 index) --{ -- struct edma_rx_free_desc *rx_desc; -- struct edma_sw_desc *sw_desc; -- -- rx_desc = (&((struct edma_rx_free_desc *)(erdr->hw_desc))[index]); -- sw_desc = &erdr->sw_desc[index]; -- if (sw_desc->skb) { -- dev_kfree_skb_any(sw_desc->skb); -- sw_desc->skb = NULL; -- } -- -- memset(rx_desc, 0, sizeof(struct edma_rx_free_desc)); --} -- --/* edma_rx_complete_fraglist() -- * Complete Rx processing for fraglist skbs -- */ --static void edma_rx_complete_stp_rstp(struct sk_buff *skb, int port_id, struct edma_rx_return_desc *rd) --{ -- int i; -- u32 priority; -- u16 port_type; -- u8 mac_addr[EDMA_ETH_HDR_LEN]; -- -- port_type = (rd->rrd1 >> EDMA_RRD_PORT_TYPE_SHIFT) -- & EDMA_RRD_PORT_TYPE_MASK; -- /* if port type is 0x4, then only proceed with -- * other stp/rstp calculation -- */ -- if (port_type == EDMA_RX_ATH_HDR_RSTP_PORT_TYPE) { -- u8 bpdu_mac[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}; -- -- /* calculate the frame priority */ -- priority = (rd->rrd1 >> EDMA_RRD_PRIORITY_SHIFT) -- & EDMA_RRD_PRIORITY_MASK; -- -- for (i = 0; i < EDMA_ETH_HDR_LEN; i++) -- mac_addr[i] = skb->data[i]; -- -- /* Check if destination mac addr is bpdu addr */ -- if (!memcmp(mac_addr, bpdu_mac, 6)) { -- /* destination mac address is BPDU -- * destination mac address, then add -- * atheros header to the packet. -- */ -- u16 athr_hdr = (EDMA_RX_ATH_HDR_VERSION << EDMA_RX_ATH_HDR_VERSION_SHIFT) | -- (priority << EDMA_RX_ATH_HDR_PRIORITY_SHIFT) | -- (EDMA_RX_ATH_HDR_RSTP_PORT_TYPE << EDMA_RX_ATH_PORT_TYPE_SHIFT) | port_id; -- skb_push(skb, 4); -- memcpy(skb->data, mac_addr, EDMA_ETH_HDR_LEN); -- *(uint16_t *)&skb->data[12] = htons(edma_ath_eth_type); -- *(uint16_t *)&skb->data[14] = htons(athr_hdr); -- } -- } --} -- --/* -- * edma_rx_complete_fraglist() -- * Complete Rx processing for fraglist skbs -- */ --static int edma_rx_complete_fraglist(struct sk_buff *skb, u16 num_rfds, u16 length, u32 sw_next_to_clean, -- u16 *cleaned_count, struct edma_rfd_desc_ring *erdr, struct edma_common_info *edma_cinfo) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- struct edma_hw *hw = &edma_cinfo->hw; -- struct sk_buff *skb_temp; -- struct edma_sw_desc *sw_desc; -- int i; -- u16 size_remaining; -- -- skb->data_len = 0; -- skb->tail += (hw->rx_head_buff_size - 16); -- skb->len = skb->truesize = length; -- size_remaining = length - (hw->rx_head_buff_size - 16); -- -- /* clean-up all related sw_descs */ -- for (i = 1; i < num_rfds; i++) { -- struct sk_buff *skb_prev; -- sw_desc = &erdr->sw_desc[sw_next_to_clean]; -- skb_temp = sw_desc->skb; -- -- dma_unmap_single(&pdev->dev, sw_desc->dma, -- sw_desc->length, DMA_FROM_DEVICE); -- -- if (size_remaining < hw->rx_head_buff_size) -- skb_put(skb_temp, size_remaining); -- else -- skb_put(skb_temp, hw->rx_head_buff_size); -- -- /* -- * If we are processing the first rfd, we link -- * skb->frag_list to the skb corresponding to the -- * first RFD -- */ -- if (i == 1) -- skb_shinfo(skb)->frag_list = skb_temp; -- else -- skb_prev->next = skb_temp; -- skb_prev = skb_temp; -- skb_temp->next = NULL; -- -- skb->data_len += skb_temp->len; -- size_remaining -= skb_temp->len; -- -- /* Increment SW index */ -- sw_next_to_clean = (sw_next_to_clean + 1) & (erdr->count - 1); -- (*cleaned_count)++; -- } -- -- return sw_next_to_clean; --} -- --/* edma_rx_complete_paged() -- * Complete Rx processing for paged skbs -- */ --static int edma_rx_complete_paged(struct sk_buff *skb, u16 num_rfds, u16 length, u32 sw_next_to_clean, -- u16 *cleaned_count, struct edma_rfd_desc_ring *erdr, struct edma_common_info *edma_cinfo) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- struct sk_buff *skb_temp; -- struct edma_sw_desc *sw_desc; -- int i; -- u16 size_remaining; -- -- skb_frag_t *frag = &skb_shinfo(skb)->frags[0]; -- -- /* Setup skbuff fields */ -- skb->len = length; -- -- if (likely(num_rfds <= 1)) { -- skb->data_len = length; -- skb->truesize += edma_cinfo->rx_page_buffer_len; -- skb_fill_page_desc(skb, 0, skb_frag_page(frag), -- 16, length); -- } else { -- skb_frag_size_sub(frag, 16); -- skb->data_len = skb_frag_size(frag); -- skb->truesize += edma_cinfo->rx_page_buffer_len; -- size_remaining = length - skb_frag_size(frag); -- -- skb_fill_page_desc(skb, 0, skb_frag_page(frag), -- 16, skb_frag_size(frag)); -- -- /* clean-up all related sw_descs */ -- for (i = 1; i < num_rfds; i++) { -- sw_desc = &erdr->sw_desc[sw_next_to_clean]; -- skb_temp = sw_desc->skb; -- frag = &skb_shinfo(skb_temp)->frags[0]; -- dma_unmap_page(&pdev->dev, sw_desc->dma, -- sw_desc->length, DMA_FROM_DEVICE); -- -- if (size_remaining < edma_cinfo->rx_page_buffer_len) -- skb_frag_size_set(frag, size_remaining); -- -- skb_fill_page_desc(skb, i, skb_frag_page(frag), -- 0, skb_frag_size(frag)); -- -- skb_shinfo(skb_temp)->nr_frags = 0; -- dev_kfree_skb_any(skb_temp); -- -- skb->data_len += skb_frag_size(frag); -- skb->truesize += edma_cinfo->rx_page_buffer_len; -- size_remaining -= skb_frag_size(frag); -- -- /* Increment SW index */ -- sw_next_to_clean = (sw_next_to_clean + 1) & (erdr->count - 1); -- (*cleaned_count)++; -- } -- } -- -- return sw_next_to_clean; --} -- --/* -- * edma_rx_complete() -- * Main api called from the poll function to process rx packets. -- */ --static u16 edma_rx_complete(struct edma_common_info *edma_cinfo, -- int *work_done, int work_to_do, int queue_id, -- struct napi_struct *napi) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- struct edma_rfd_desc_ring *erdr = edma_cinfo->rfd_ring[queue_id]; -- struct net_device *netdev; -- struct edma_adapter *adapter; -- struct edma_sw_desc *sw_desc; -- struct sk_buff *skb; -- struct edma_rx_return_desc *rd; -- u16 hash_type, rrd[8], cleaned_count = 0, length = 0, num_rfds = 1, -- sw_next_to_clean, hw_next_to_clean = 0, vlan = 0, ret_count = 0; -- u32 data = 0; -- u8 *vaddr; -- int port_id, i, drop_count = 0; -- u32 priority; -- u16 count = erdr->count, rfd_avail; -- u8 queue_to_rxid[8] = {0, 0, 1, 1, 2, 2, 3, 3}; -- -- cleaned_count = erdr->pending_fill; -- sw_next_to_clean = erdr->sw_next_to_clean; -- -- edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), &data); -- hw_next_to_clean = (data >> EDMA_RFD_CONS_IDX_SHIFT) & -- EDMA_RFD_CONS_IDX_MASK; -- -- do { -- while (sw_next_to_clean != hw_next_to_clean) { -- if (!work_to_do) -- break; -- -- sw_desc = &erdr->sw_desc[sw_next_to_clean]; -- skb = sw_desc->skb; -- -- /* Unmap the allocated buffer */ -- if (likely(sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_HEAD)) -- dma_unmap_single(&pdev->dev, sw_desc->dma, -- sw_desc->length, DMA_FROM_DEVICE); -- else -- dma_unmap_page(&pdev->dev, sw_desc->dma, -- sw_desc->length, DMA_FROM_DEVICE); -- -- /* Get RRD */ -- if (edma_cinfo->page_mode) { -- vaddr = kmap_atomic(skb_frag_page(&skb_shinfo(skb)->frags[0])); -- memcpy((uint8_t *)&rrd[0], vaddr, 16); -- rd = (struct edma_rx_return_desc *)rrd; -- kunmap_atomic(vaddr); -- } else { -- rd = (struct edma_rx_return_desc *)skb->data; -- } -- -- /* Check if RRD is valid */ -- if (!(rd->rrd7 & EDMA_RRD_DESC_VALID)) { -- edma_clean_rfd(erdr, sw_next_to_clean); -- sw_next_to_clean = (sw_next_to_clean + 1) & -- (erdr->count - 1); -- cleaned_count++; -- continue; -- } -- -- /* Get the number of RFDs from RRD */ -- num_rfds = rd->rrd1 & EDMA_RRD_NUM_RFD_MASK; -- -- /* Get Rx port ID from switch */ -- port_id = (rd->rrd1 >> EDMA_PORT_ID_SHIFT) & EDMA_PORT_ID_MASK; -- if ((!port_id) || (port_id > EDMA_MAX_PORTID_SUPPORTED)) { -- dev_err(&pdev->dev, "Invalid RRD source port bit set"); -- for (i = 0; i < num_rfds; i++) { -- edma_clean_rfd(erdr, sw_next_to_clean); -- sw_next_to_clean = (sw_next_to_clean + 1) & (erdr->count - 1); -- cleaned_count++; -- } -- continue; -- } -- -- /* check if we have a sink for the data we receive. -- * If the interface isn't setup, we have to drop the -- * incoming data for now. -- */ -- netdev = edma_cinfo->portid_netdev_lookup_tbl[port_id]; -- if (!netdev) { -- edma_clean_rfd(erdr, sw_next_to_clean); -- sw_next_to_clean = (sw_next_to_clean + 1) & -- (erdr->count - 1); -- cleaned_count++; -- continue; -- } -- adapter = netdev_priv(netdev); -- -- /* This code is added to handle a usecase where high -- * priority stream and a low priority stream are -- * received simultaneously on DUT. The problem occurs -- * if one of the Rx rings is full and the corresponding -- * core is busy with other stuff. This causes ESS CPU -- * port to backpressure all incoming traffic including -- * high priority one. We monitor free descriptor count -- * on each CPU and whenever it reaches threshold (< 80), -- * we drop all low priority traffic and let only high -- * priotiy traffic pass through. We can hence avoid -- * ESS CPU port to send backpressure on high priroity -- * stream. -- */ -- priority = (rd->rrd1 >> EDMA_RRD_PRIORITY_SHIFT) -- & EDMA_RRD_PRIORITY_MASK; -- if (likely(!priority && !edma_cinfo->page_mode && (num_rfds <= 1))) { -- rfd_avail = (count + sw_next_to_clean - hw_next_to_clean - 1) & (count - 1); -- if (rfd_avail < EDMA_RFD_AVAIL_THR) { -- sw_desc->flags = EDMA_SW_DESC_FLAG_SKB_REUSE; -- sw_next_to_clean = (sw_next_to_clean + 1) & (erdr->count - 1); -- adapter->stats.rx_dropped++; -- cleaned_count++; -- drop_count++; -- if (drop_count == 3) { -- work_to_do--; -- (*work_done)++; -- drop_count = 0; -- } -- if (cleaned_count >= EDMA_RX_BUFFER_WRITE) { -- /* If buffer clean count reaches 16, we replenish HW buffers. */ -- ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id); -- edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id), -- sw_next_to_clean); -- cleaned_count = ret_count; -- erdr->pending_fill = ret_count; -- } -- continue; -- } -- } -- -- work_to_do--; -- (*work_done)++; -- -- /* Increment SW index */ -- sw_next_to_clean = (sw_next_to_clean + 1) & -- (erdr->count - 1); -- -- cleaned_count++; -- -- /* Get the packet size and allocate buffer */ -- length = rd->rrd6 & EDMA_RRD_PKT_SIZE_MASK; -- -- if (edma_cinfo->page_mode) { -- /* paged skb */ -- sw_next_to_clean = edma_rx_complete_paged(skb, num_rfds, length, sw_next_to_clean, &cleaned_count, erdr, edma_cinfo); -- if (!pskb_may_pull(skb, ETH_HLEN)) { -- dev_kfree_skb_any(skb); -- continue; -- } -- } else { -- /* single or fraglist skb */ -- -- /* Addition of 16 bytes is required, as in the packet -- * first 16 bytes are rrd descriptors, so actual data -- * starts from an offset of 16. -- */ -- skb_reserve(skb, 16); -- if (likely((num_rfds <= 1) || !edma_cinfo->fraglist_mode)) { -- skb_put(skb, length); -- } else { -- sw_next_to_clean = edma_rx_complete_fraglist(skb, num_rfds, length, sw_next_to_clean, &cleaned_count, erdr, edma_cinfo); -- } -- } -- -- if (edma_stp_rstp) { -- edma_rx_complete_stp_rstp(skb, port_id, rd); -- } -- -- skb->protocol = eth_type_trans(skb, netdev); -- -- /* Record Rx queue for RFS/RPS and fill flow hash from HW */ -- skb_record_rx_queue(skb, queue_to_rxid[queue_id]); -- if (netdev->features & NETIF_F_RXHASH) { -- hash_type = (rd->rrd5 >> EDMA_HASH_TYPE_SHIFT); -- if ((hash_type > EDMA_HASH_TYPE_START) && (hash_type < EDMA_HASH_TYPE_END)) -- skb_set_hash(skb, rd->rrd2, PKT_HASH_TYPE_L4); -- } -- --#ifdef CONFIG_NF_FLOW_COOKIE -- skb->flow_cookie = rd->rrd3 & EDMA_RRD_FLOW_COOKIE_MASK; --#endif -- edma_receive_checksum(rd, skb); -- -- /* Process VLAN HW acceleration indication provided by HW */ -- if (unlikely(adapter->default_vlan_tag != rd->rrd4)) { -- vlan = rd->rrd4; -- if (likely(rd->rrd7 & EDMA_RRD_CVLAN)) -- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); -- else if (rd->rrd1 & EDMA_RRD_SVLAN) -- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), vlan); -- } -- -- /* Update rx statistics */ -- adapter->stats.rx_packets++; -- adapter->stats.rx_bytes += length; -- -- /* Check if we reached refill threshold */ -- if (cleaned_count >= EDMA_RX_BUFFER_WRITE) { -- ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id); -- edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id), -- sw_next_to_clean); -- cleaned_count = ret_count; -- erdr->pending_fill = ret_count; -- } -- -- /* At this point skb should go to stack */ -- napi_gro_receive(napi, skb); -- } -- -- /* Check if we still have NAPI budget */ -- if (!work_to_do) -- break; -- -- /* Read index once again since we still have NAPI budget */ -- edma_read_reg(EDMA_REG_RFD_IDX_Q(queue_id), &data); -- hw_next_to_clean = (data >> EDMA_RFD_CONS_IDX_SHIFT) & -- EDMA_RFD_CONS_IDX_MASK; -- } while (hw_next_to_clean != sw_next_to_clean); -- -- erdr->sw_next_to_clean = sw_next_to_clean; -- -- /* Refill here in case refill threshold wasn't reached */ -- if (likely(cleaned_count)) { -- ret_count = edma_alloc_rx_buf(edma_cinfo, erdr, cleaned_count, queue_id); -- erdr->pending_fill = ret_count; -- if (ret_count) { -- if (net_ratelimit()) -- dev_dbg(&pdev->dev, "Not all buffers was reallocated"); -- } -- -- edma_write_reg(EDMA_REG_RX_SW_CONS_IDX_Q(queue_id), -- erdr->sw_next_to_clean); -- } -- -- return erdr->pending_fill; --} -- --/* edma_delete_rfs_filter() -- * Remove RFS filter from switch -- */ --static int edma_delete_rfs_filter(struct edma_adapter *adapter, -- struct edma_rfs_filter_node *filter_node) --{ -- int res = -1; -- -- struct flow_keys *keys = &filter_node->keys; -- -- if (likely(adapter->set_rfs_rule)) -- res = (*adapter->set_rfs_rule)(adapter->netdev, -- flow_get_u32_src(keys), flow_get_u32_dst(keys), -- keys->ports.src, keys->ports.dst, -- keys->basic.ip_proto, filter_node->rq_id, 0); -- -- return res; --} -- --/* edma_add_rfs_filter() -- * Add RFS filter to switch -- */ --static int edma_add_rfs_filter(struct edma_adapter *adapter, -- struct flow_keys *keys, u16 rq, -- struct edma_rfs_filter_node *filter_node) --{ -- int res = -1; -- -- struct flow_keys *dest_keys = &filter_node->keys; -- -- memcpy(dest_keys, &filter_node->keys, sizeof(*dest_keys)); --/* -- dest_keys->control = keys->control; -- dest_keys->basic = keys->basic; -- dest_keys->addrs = keys->addrs; -- dest_keys->ports = keys->ports; -- dest_keys.ip_proto = keys->ip_proto; --*/ -- /* Call callback registered by ESS driver */ -- if (likely(adapter->set_rfs_rule)) -- res = (*adapter->set_rfs_rule)(adapter->netdev, flow_get_u32_src(keys), -- flow_get_u32_dst(keys), keys->ports.src, keys->ports.dst, -- keys->basic.ip_proto, rq, 1); -- -- return res; --} -- --/* edma_rfs_key_search() -- * Look for existing RFS entry -- */ --static struct edma_rfs_filter_node *edma_rfs_key_search(struct hlist_head *h, -- struct flow_keys *key) --{ -- struct edma_rfs_filter_node *p; -- -- hlist_for_each_entry(p, h, node) -- if (flow_get_u32_src(&p->keys) == flow_get_u32_src(key) && -- flow_get_u32_dst(&p->keys) == flow_get_u32_dst(key) && -- p->keys.ports.src == key->ports.src && -- p->keys.ports.dst == key->ports.dst && -- p->keys.basic.ip_proto == key->basic.ip_proto) -- return p; -- return NULL; --} -- --/* edma_initialise_rfs_flow_table() -- * Initialise EDMA RFS flow table -- */ --static void edma_initialise_rfs_flow_table(struct edma_adapter *adapter) --{ -- int i; -- -- spin_lock_init(&adapter->rfs.rfs_ftab_lock); -- -- /* Initialize EDMA flow hash table */ -- for (i = 0; i < EDMA_RFS_FLOW_ENTRIES; i++) -- INIT_HLIST_HEAD(&adapter->rfs.hlist_head[i]); -- -- adapter->rfs.max_num_filter = EDMA_RFS_FLOW_ENTRIES; -- adapter->rfs.filter_available = adapter->rfs.max_num_filter; -- adapter->rfs.hashtoclean = 0; -- -- /* Add timer to get periodic RFS updates from OS */ -- timer_setup(&adapter->rfs.expire_rfs, edma_flow_may_expire, 0); -- mod_timer(&adapter->rfs.expire_rfs, jiffies + HZ / 4); --} -- --/* edma_free_rfs_flow_table() -- * Free EDMA RFS flow table -- */ --static void edma_free_rfs_flow_table(struct edma_adapter *adapter) --{ -- int i; -- -- /* Remove sync timer */ -- del_timer_sync(&adapter->rfs.expire_rfs); -- spin_lock_bh(&adapter->rfs.rfs_ftab_lock); -- -- /* Free EDMA RFS table entries */ -- adapter->rfs.filter_available = 0; -- -- /* Clean-up EDMA flow hash table */ -- for (i = 0; i < EDMA_RFS_FLOW_ENTRIES; i++) { -- struct hlist_head *hhead; -- struct hlist_node *tmp; -- struct edma_rfs_filter_node *filter_node; -- int res; -- -- hhead = &adapter->rfs.hlist_head[i]; -- hlist_for_each_entry_safe(filter_node, tmp, hhead, node) { -- res = edma_delete_rfs_filter(adapter, filter_node); -- if (res < 0) -- dev_warn(&adapter->netdev->dev, -- "EDMA going down but RFS entry %d not allowed to be flushed by Switch", -- filter_node->flow_id); -- hlist_del(&filter_node->node); -- kfree(filter_node); -- } -- } -- spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); --} -- --/* edma_tx_unmap_and_free() -- * clean TX buffer -- */ --static inline void edma_tx_unmap_and_free(struct platform_device *pdev, -- struct edma_sw_desc *sw_desc) --{ -- struct sk_buff *skb = sw_desc->skb; -- -- if (likely((sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_HEAD) || -- (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_FRAGLIST))) -- /* unmap_single for skb head area */ -- dma_unmap_single(&pdev->dev, sw_desc->dma, -- sw_desc->length, DMA_TO_DEVICE); -- else if (sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_FRAG) -- /* unmap page for paged fragments */ -- dma_unmap_page(&pdev->dev, sw_desc->dma, -- sw_desc->length, DMA_TO_DEVICE); -- -- if (likely(sw_desc->flags & EDMA_SW_DESC_FLAG_LAST)) -- dev_kfree_skb_any(skb); -- -- sw_desc->flags = 0; --} -- --/* edma_tx_complete() -- * Used to clean tx queues and update hardware and consumer index -- */ --static void edma_tx_complete(struct edma_common_info *edma_cinfo, int queue_id) --{ -- struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; -- struct edma_sw_desc *sw_desc; -- struct platform_device *pdev = edma_cinfo->pdev; -- int i; -- -- u16 sw_next_to_clean = etdr->sw_next_to_clean; -- u16 hw_next_to_clean; -- u32 data = 0; -- -- edma_read_reg(EDMA_REG_TPD_IDX_Q(queue_id), &data); -- hw_next_to_clean = (data >> EDMA_TPD_CONS_IDX_SHIFT) & EDMA_TPD_CONS_IDX_MASK; -- -- /* clean the buffer here */ -- while (sw_next_to_clean != hw_next_to_clean) { -- sw_desc = &etdr->sw_desc[sw_next_to_clean]; -- edma_tx_unmap_and_free(pdev, sw_desc); -- sw_next_to_clean = (sw_next_to_clean + 1) & (etdr->count - 1); -- } -- -- etdr->sw_next_to_clean = sw_next_to_clean; -- -- /* update the TPD consumer index register */ -- edma_write_reg(EDMA_REG_TX_SW_CONS_IDX_Q(queue_id), sw_next_to_clean); -- -- /* Wake the queue if queue is stopped and netdev link is up */ -- for (i = 0; i < EDMA_MAX_NETDEV_PER_QUEUE && etdr->nq[i] ; i++) { -- if (netif_tx_queue_stopped(etdr->nq[i])) { -- if ((etdr->netdev[i]) && netif_carrier_ok(etdr->netdev[i])) -- netif_tx_wake_queue(etdr->nq[i]); -- } -- } --} -- --/* edma_get_tx_buffer() -- * Get sw_desc corresponding to the TPD -- */ --static struct edma_sw_desc *edma_get_tx_buffer(struct edma_common_info *edma_cinfo, -- struct edma_tx_desc *tpd, int queue_id) --{ -- struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; -- return &etdr->sw_desc[tpd - (struct edma_tx_desc *)etdr->hw_desc]; --} -- --/* edma_get_next_tpd() -- * Return a TPD descriptor for transfer -- */ --static struct edma_tx_desc *edma_get_next_tpd(struct edma_common_info *edma_cinfo, -- int queue_id) --{ -- struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; -- u16 sw_next_to_fill = etdr->sw_next_to_fill; -- struct edma_tx_desc *tpd_desc = -- (&((struct edma_tx_desc *)(etdr->hw_desc))[sw_next_to_fill]); -- -- etdr->sw_next_to_fill = (etdr->sw_next_to_fill + 1) & (etdr->count - 1); -- -- return tpd_desc; --} -- --/* edma_tpd_available() -- * Check number of free TPDs -- */ --static inline u16 edma_tpd_available(struct edma_common_info *edma_cinfo, -- int queue_id) --{ -- struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; -- -- u16 sw_next_to_fill; -- u16 sw_next_to_clean; -- u16 count = 0; -- -- sw_next_to_clean = etdr->sw_next_to_clean; -- sw_next_to_fill = etdr->sw_next_to_fill; -- -- if (likely(sw_next_to_clean <= sw_next_to_fill)) -- count = etdr->count; -- -- return count + sw_next_to_clean - sw_next_to_fill - 1; --} -- --/* edma_tx_queue_get() -- * Get the starting number of the queue -- */ --static inline int edma_tx_queue_get(struct edma_adapter *adapter, -- struct sk_buff *skb, int txq_id) --{ -- /* skb->priority is used as an index to skb priority table -- * and based on packet priority, correspong queue is assigned. -- */ -- return adapter->tx_start_offset[txq_id] + edma_skb_priority_offset(skb); --} -- --/* edma_tx_update_hw_idx() -- * update the producer index for the ring transmitted -- */ --static void edma_tx_update_hw_idx(struct edma_common_info *edma_cinfo, -- struct sk_buff *skb, int queue_id) --{ -- struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[queue_id]; -- u32 tpd_idx_data; -- -- /* Read and update the producer index */ -- edma_read_reg(EDMA_REG_TPD_IDX_Q(queue_id), &tpd_idx_data); -- tpd_idx_data &= ~EDMA_TPD_PROD_IDX_BITS; -- tpd_idx_data |= (etdr->sw_next_to_fill & EDMA_TPD_PROD_IDX_MASK) -- << EDMA_TPD_PROD_IDX_SHIFT; -- -- edma_write_reg(EDMA_REG_TPD_IDX_Q(queue_id), tpd_idx_data); --} -- --/* edma_rollback_tx() -- * Function to retrieve tx resources in case of error -- */ --static void edma_rollback_tx(struct edma_adapter *adapter, -- struct edma_tx_desc *start_tpd, int queue_id) --{ -- struct edma_tx_desc_ring *etdr = adapter->edma_cinfo->tpd_ring[queue_id]; -- struct edma_sw_desc *sw_desc; -- struct edma_tx_desc *tpd = NULL; -- u16 start_index, index; -- -- start_index = start_tpd - (struct edma_tx_desc *)(etdr->hw_desc); -- -- index = start_index; -- while (index != etdr->sw_next_to_fill) { -- tpd = (&((struct edma_tx_desc *)(etdr->hw_desc))[index]); -- sw_desc = &etdr->sw_desc[index]; -- edma_tx_unmap_and_free(adapter->pdev, sw_desc); -- memset(tpd, 0, sizeof(struct edma_tx_desc)); -- if (++index == etdr->count) -- index = 0; -- } -- etdr->sw_next_to_fill = start_index; --} -- --/* edma_tx_map_and_fill() -- * gets called from edma_xmit_frame -- * -- * This is where the dma of the buffer to be transmitted -- * gets mapped -- */ --static int edma_tx_map_and_fill(struct edma_common_info *edma_cinfo, -- struct edma_adapter *adapter, struct sk_buff *skb, int queue_id, -- unsigned int flags_transmit, u16 from_cpu, u16 dp_bitmap, -- bool packet_is_rstp, int nr_frags) --{ -- struct edma_sw_desc *sw_desc = NULL; -- struct platform_device *pdev = edma_cinfo->pdev; -- struct edma_tx_desc *tpd = NULL, *start_tpd = NULL; -- struct sk_buff *iter_skb; -- int i = 0; -- u32 word1 = 0, word3 = 0, lso_word1 = 0, svlan_tag = 0; -- u16 buf_len, lso_desc_len = 0; -- -- /* It should either be a nr_frags skb or fraglist skb but not both */ -- BUG_ON(nr_frags && skb_has_frag_list(skb)); -- -- if (skb_is_gso(skb)) { -- /* TODO: What additional checks need to be performed here */ -- if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) { -- lso_word1 |= EDMA_TPD_IPV4_EN; -- ip_hdr(skb)->check = 0; -- tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, -- ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); -- } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { -- lso_word1 |= EDMA_TPD_LSO_V2_EN; -- ipv6_hdr(skb)->payload_len = 0; -- tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, -- &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); -- } else -- return -EINVAL; -- -- lso_word1 |= EDMA_TPD_LSO_EN | ((skb_shinfo(skb)->gso_size & EDMA_TPD_MSS_MASK) << EDMA_TPD_MSS_SHIFT) | -- (skb_transport_offset(skb) << EDMA_TPD_HDR_SHIFT); -- } else if (flags_transmit & EDMA_HW_CHECKSUM) { -- u8 css, cso; -- cso = skb_checksum_start_offset(skb); -- css = cso + skb->csum_offset; -- -- word1 |= (EDMA_TPD_CUSTOM_CSUM_EN); -- word1 |= (cso >> 1) << EDMA_TPD_HDR_SHIFT; -- word1 |= ((css >> 1) << EDMA_TPD_CUSTOM_CSUM_SHIFT); -- } -- -- if (skb->protocol == htons(ETH_P_PPP_SES)) -- word1 |= EDMA_TPD_PPPOE_EN; -- -- if (flags_transmit & EDMA_VLAN_TX_TAG_INSERT_FLAG) { -- switch(skb->vlan_proto) { -- case htons(ETH_P_8021Q): -- word3 |= (1 << EDMA_TX_INS_CVLAN); -- word3 |= skb_vlan_tag_get(skb) << EDMA_TX_CVLAN_TAG_SHIFT; -- break; -- case htons(ETH_P_8021AD): -- word1 |= (1 << EDMA_TX_INS_SVLAN); -- svlan_tag = skb_vlan_tag_get(skb) << EDMA_TX_SVLAN_TAG_SHIFT; -- break; -- default: -- dev_err(&pdev->dev, "no ctag or stag present\n"); -- goto vlan_tag_error; -- } -- } else if (flags_transmit & EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG) { -- word3 |= (1 << EDMA_TX_INS_CVLAN); -- word3 |= (adapter->default_vlan_tag) << EDMA_TX_CVLAN_TAG_SHIFT; -- } -- -- if (packet_is_rstp) { -- word3 |= dp_bitmap << EDMA_TPD_PORT_BITMAP_SHIFT; -- word3 |= from_cpu << EDMA_TPD_FROM_CPU_SHIFT; -- } else { -- word3 |= adapter->dp_bitmap << EDMA_TPD_PORT_BITMAP_SHIFT; -- } -- -- buf_len = skb_headlen(skb); -- -- if (lso_word1) { -- if (lso_word1 & EDMA_TPD_LSO_V2_EN) { -- -- /* IPv6 LSOv2 descriptor */ -- start_tpd = tpd = edma_get_next_tpd(edma_cinfo, queue_id); -- sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); -- sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_NONE; -- -- /* LSOv2 descriptor overrides addr field to pass length */ -- tpd->addr = cpu_to_le16(skb->len); -- tpd->svlan_tag = svlan_tag; -- tpd->word1 = word1 | lso_word1; -- tpd->word3 = word3; -- } -- -- tpd = edma_get_next_tpd(edma_cinfo, queue_id); -- if (!start_tpd) -- start_tpd = tpd; -- sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); -- -- /* The last buffer info contain the skb address, -- * so skb will be freed after unmap -- */ -- sw_desc->length = lso_desc_len; -- sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_HEAD; -- -- sw_desc->dma = dma_map_single(&adapter->pdev->dev, -- skb->data, buf_len, DMA_TO_DEVICE); -- if (dma_mapping_error(&pdev->dev, sw_desc->dma)) -- goto dma_error; -- -- tpd->addr = cpu_to_le32(sw_desc->dma); -- tpd->len = cpu_to_le16(buf_len); -- -- tpd->svlan_tag = svlan_tag; -- tpd->word1 = word1 | lso_word1; -- tpd->word3 = word3; -- -- /* The last buffer info contain the skb address, -- * so it will be freed after unmap -- */ -- sw_desc->length = lso_desc_len; -- sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_HEAD; -- -- buf_len = 0; -- } -- -- if (likely(buf_len)) { -- -- /* TODO Do not dequeue descriptor if there is a potential error */ -- tpd = edma_get_next_tpd(edma_cinfo, queue_id); -- -- if (!start_tpd) -- start_tpd = tpd; -- -- sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); -- -- /* The last buffer info contain the skb address, -- * so it will be free after unmap -- */ -- sw_desc->length = buf_len; -- sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_HEAD; -- sw_desc->dma = dma_map_single(&adapter->pdev->dev, -- skb->data, buf_len, DMA_TO_DEVICE); -- if (dma_mapping_error(&pdev->dev, sw_desc->dma)) -- goto dma_error; -- -- tpd->addr = cpu_to_le32(sw_desc->dma); -- tpd->len = cpu_to_le16(buf_len); -- -- tpd->svlan_tag = svlan_tag; -- tpd->word1 = word1 | lso_word1; -- tpd->word3 = word3; -- } -- -- /* Walk through all paged fragments */ -- while (nr_frags--) { -- skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; -- buf_len = skb_frag_size(frag); -- tpd = edma_get_next_tpd(edma_cinfo, queue_id); -- sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); -- sw_desc->length = buf_len; -- sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_FRAG; -- -- sw_desc->dma = skb_frag_dma_map(&pdev->dev, frag, 0, buf_len, DMA_TO_DEVICE); -- -- if (dma_mapping_error(NULL, sw_desc->dma)) -- goto dma_error; -- -- tpd->addr = cpu_to_le32(sw_desc->dma); -- tpd->len = cpu_to_le16(buf_len); -- -- tpd->svlan_tag = svlan_tag; -- tpd->word1 = word1 | lso_word1; -- tpd->word3 = word3; -- i++; -- } -- -- /* Walk through all fraglist skbs */ -- skb_walk_frags(skb, iter_skb) { -- buf_len = iter_skb->len; -- tpd = edma_get_next_tpd(edma_cinfo, queue_id); -- sw_desc = edma_get_tx_buffer(edma_cinfo, tpd, queue_id); -- sw_desc->length = buf_len; -- sw_desc->dma = dma_map_single(&adapter->pdev->dev, -- iter_skb->data, buf_len, DMA_TO_DEVICE); -- -- if (dma_mapping_error(NULL, sw_desc->dma)) -- goto dma_error; -- -- tpd->addr = cpu_to_le32(sw_desc->dma); -- tpd->len = cpu_to_le16(buf_len); -- tpd->svlan_tag = svlan_tag; -- tpd->word1 = word1 | lso_word1; -- tpd->word3 = word3; -- sw_desc->flags |= EDMA_SW_DESC_FLAG_SKB_FRAGLIST; -- } -- -- if (tpd) -- tpd->word1 |= 1 << EDMA_TPD_EOP_SHIFT; -- -- sw_desc->skb = skb; -- sw_desc->flags |= EDMA_SW_DESC_FLAG_LAST; -- -- return 0; -- --dma_error: -- edma_rollback_tx(adapter, start_tpd, queue_id); -- dev_err(&pdev->dev, "TX DMA map failed\n"); --vlan_tag_error: -- return -ENOMEM; --} -- --/* edma_check_link() -- * check Link status -- */ --static int edma_check_link(struct edma_adapter *adapter) --{ -- struct phy_device *phydev = adapter->phydev; -- -- if (!(adapter->poll_required)) -- return __EDMA_LINKUP; -- -- if (phydev->link) -- return __EDMA_LINKUP; -- -- return __EDMA_LINKDOWN; --} -- --/* edma_adjust_link() -- * check for edma link status -- */ --void edma_adjust_link(struct net_device *netdev) --{ -- int status; -- struct edma_adapter *adapter = netdev_priv(netdev); -- struct phy_device *phydev = adapter->phydev; -- -- if (!test_bit(__EDMA_UP, &adapter->state_flags)) -- return; -- -- status = edma_check_link(adapter); -- -- if (status == __EDMA_LINKUP && adapter->link_state == __EDMA_LINKDOWN) { -- phy_print_status(phydev); -- adapter->link_state = __EDMA_LINKUP; -- if (adapter->edma_cinfo->is_single_phy) { -- ess_set_port_status_speed(adapter->edma_cinfo, phydev, -- ffs(adapter->dp_bitmap) - 1); -- } -- netif_carrier_on(netdev); -- if (netif_running(netdev)) -- netif_tx_wake_all_queues(netdev); -- } else if (status == __EDMA_LINKDOWN && adapter->link_state == __EDMA_LINKUP) { -- phy_print_status(phydev); -- adapter->link_state = __EDMA_LINKDOWN; -- netif_carrier_off(netdev); -- netif_tx_stop_all_queues(netdev); -- } --} -- --/* edma_get_stats() -- * Statistics api used to retreive the tx/rx statistics -- */ --struct net_device_stats *edma_get_stats(struct net_device *netdev) --{ -- struct edma_adapter *adapter = netdev_priv(netdev); -- -- return &adapter->stats; --} -- --/* edma_xmit() -- * Main api to be called by the core for packet transmission -- */ --netdev_tx_t edma_xmit(struct sk_buff *skb, -- struct net_device *net_dev) --{ -- struct edma_adapter *adapter = netdev_priv(net_dev); -- struct edma_common_info *edma_cinfo = adapter->edma_cinfo; -- struct edma_tx_desc_ring *etdr; -- u16 from_cpu, dp_bitmap, txq_id; -- int ret, nr_frags = 0, num_tpds_needed = 1, queue_id; -- unsigned int flags_transmit = 0; -- bool packet_is_rstp = false; -- struct netdev_queue *nq = NULL; -- -- if (skb_shinfo(skb)->nr_frags) { -- nr_frags = skb_shinfo(skb)->nr_frags; -- num_tpds_needed += nr_frags; -- } else if (skb_has_frag_list(skb)) { -- struct sk_buff *iter_skb; -- -- skb_walk_frags(skb, iter_skb) -- num_tpds_needed++; -- } -- -- if (num_tpds_needed > EDMA_MAX_SKB_FRAGS) { -- dev_err(&net_dev->dev, -- "skb received with fragments %d which is more than %lu", -- num_tpds_needed, EDMA_MAX_SKB_FRAGS); -- dev_kfree_skb_any(skb); -- adapter->stats.tx_errors++; -- return NETDEV_TX_OK; -- } -- -- if (edma_stp_rstp) { -- u16 ath_hdr, ath_eth_type; -- u8 mac_addr[EDMA_ETH_HDR_LEN]; -- ath_eth_type = ntohs(*(uint16_t *)&skb->data[12]); -- if (ath_eth_type == edma_ath_eth_type) { -- packet_is_rstp = true; -- ath_hdr = htons(*(uint16_t *)&skb->data[14]); -- dp_bitmap = ath_hdr & EDMA_TX_ATH_HDR_PORT_BITMAP_MASK; -- from_cpu = (ath_hdr & EDMA_TX_ATH_HDR_FROM_CPU_MASK) >> EDMA_TX_ATH_HDR_FROM_CPU_SHIFT; -- memcpy(mac_addr, skb->data, EDMA_ETH_HDR_LEN); -- -- skb_pull(skb, 4); -- -- memcpy(skb->data, mac_addr, EDMA_ETH_HDR_LEN); -- } -- } -- -- /* this will be one of the 4 TX queues exposed to linux kernel */ -- txq_id = skb_get_queue_mapping(skb); -- queue_id = edma_tx_queue_get(adapter, skb, txq_id); -- etdr = edma_cinfo->tpd_ring[queue_id]; -- nq = netdev_get_tx_queue(net_dev, txq_id); -- -- local_bh_disable(); -- /* Tx is not handled in bottom half context. Hence, we need to protect -- * Tx from tasks and bottom half -- */ -- -- if (num_tpds_needed > edma_tpd_available(edma_cinfo, queue_id)) { -- /* not enough descriptor, just stop queue */ -- netif_tx_stop_queue(nq); -- local_bh_enable(); -- dev_dbg(&net_dev->dev, "Not enough descriptors available"); -- edma_cinfo->edma_ethstats.tx_desc_error++; -- return NETDEV_TX_BUSY; -- } -- -- /* Check and mark VLAN tag offload */ -- if (unlikely(skb_vlan_tag_present(skb))) -- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG; -- else if (!adapter->edma_cinfo->is_single_phy && adapter->default_vlan_tag) -- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG; -- -- /* Check and mark checksum offload */ -- if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) -- flags_transmit |= EDMA_HW_CHECKSUM; -- -- /* Map and fill descriptor for Tx */ -- ret = edma_tx_map_and_fill(edma_cinfo, adapter, skb, queue_id, -- flags_transmit, from_cpu, dp_bitmap, packet_is_rstp, nr_frags); -- if (ret) { -- dev_kfree_skb_any(skb); -- adapter->stats.tx_errors++; -- goto netdev_okay; -- } -- -- /* Update SW producer index */ -- edma_tx_update_hw_idx(edma_cinfo, skb, queue_id); -- -- /* update tx statistics */ -- adapter->stats.tx_packets++; -- adapter->stats.tx_bytes += skb->len; -- --netdev_okay: -- local_bh_enable(); -- return NETDEV_TX_OK; --} -- --/* -- * edma_flow_may_expire() -- * Timer function called periodically to delete the node -- */ --void edma_flow_may_expire(struct timer_list *t) --{ -- struct edma_rfs_flow_table *table = from_timer(table, t, expire_rfs); -- struct edma_adapter *adapter = -- container_of(table, typeof(*adapter), rfs); -- int j; -- -- spin_lock_bh(&adapter->rfs.rfs_ftab_lock); -- for (j = 0; j < EDMA_RFS_EXPIRE_COUNT_PER_CALL; j++) { -- struct hlist_head *hhead; -- struct hlist_node *tmp; -- struct edma_rfs_filter_node *n; -- bool res; -- -- hhead = &adapter->rfs.hlist_head[adapter->rfs.hashtoclean++]; -- hlist_for_each_entry_safe(n, tmp, hhead, node) { -- res = rps_may_expire_flow(adapter->netdev, n->rq_id, -- n->flow_id, n->filter_id); -- if (res) { -- int ret; -- ret = edma_delete_rfs_filter(adapter, n); -- if (ret < 0) -- dev_dbg(&adapter->netdev->dev, -- "RFS entry %d not allowed to be flushed by Switch", -- n->flow_id); -- else { -- hlist_del(&n->node); -- kfree(n); -- adapter->rfs.filter_available++; -- } -- } -- } -- } -- -- adapter->rfs.hashtoclean = adapter->rfs.hashtoclean & (EDMA_RFS_FLOW_ENTRIES - 1); -- spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); -- mod_timer(&adapter->rfs.expire_rfs, jiffies + HZ / 4); --} -- --/* edma_rx_flow_steer() -- * Called by core to to steer the flow to CPU -- */ --int edma_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, -- u16 rxq, u32 flow_id) --{ -- struct flow_keys keys; -- struct edma_rfs_filter_node *filter_node; -- struct edma_adapter *adapter = netdev_priv(dev); -- u16 hash_tblid; -- int res; -- -- if (skb->protocol == htons(ETH_P_IPV6)) { -- dev_err(&adapter->pdev->dev, "IPv6 not supported\n"); -- res = -EINVAL; -- goto no_protocol_err; -- } -- -- /* Dissect flow parameters -- * We only support IPv4 + TCP/UDP -- */ -- res = skb_flow_dissect_flow_keys(skb, &keys, 0); -- if (!((keys.basic.ip_proto == IPPROTO_TCP) || (keys.basic.ip_proto == IPPROTO_UDP))) { -- res = -EPROTONOSUPPORT; -- goto no_protocol_err; -- } -- -- /* Check if table entry exists */ -- hash_tblid = skb_get_hash_raw(skb) & EDMA_RFS_FLOW_ENTRIES_MASK; -- -- spin_lock_bh(&adapter->rfs.rfs_ftab_lock); -- filter_node = edma_rfs_key_search(&adapter->rfs.hlist_head[hash_tblid], &keys); -- -- if (filter_node) { -- if (rxq == filter_node->rq_id) { -- res = -EEXIST; -- goto out; -- } else { -- res = edma_delete_rfs_filter(adapter, filter_node); -- if (res < 0) -- dev_warn(&adapter->netdev->dev, -- "Cannot steer flow %d to different queue", -- filter_node->flow_id); -- else { -- adapter->rfs.filter_available++; -- res = edma_add_rfs_filter(adapter, &keys, rxq, filter_node); -- if (res < 0) { -- dev_warn(&adapter->netdev->dev, -- "Cannot steer flow %d to different queue", -- filter_node->flow_id); -- } else { -- adapter->rfs.filter_available--; -- filter_node->rq_id = rxq; -- filter_node->filter_id = res; -- } -- } -- } -- } else { -- if (adapter->rfs.filter_available == 0) { -- res = -EBUSY; -- goto out; -- } -- -- filter_node = kmalloc(sizeof(*filter_node), GFP_ATOMIC); -- if (!filter_node) { -- res = -ENOMEM; -- goto out; -- } -- -- res = edma_add_rfs_filter(adapter, &keys, rxq, filter_node); -- if (res < 0) { -- kfree(filter_node); -- goto out; -- } -- -- adapter->rfs.filter_available--; -- filter_node->rq_id = rxq; -- filter_node->filter_id = res; -- filter_node->flow_id = flow_id; -- filter_node->keys = keys; -- INIT_HLIST_NODE(&filter_node->node); -- hlist_add_head(&filter_node->node, &adapter->rfs.hlist_head[hash_tblid]); -- } -- --out: -- spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); --no_protocol_err: -- return res; --} -- --/* edma_register_rfs_filter() -- * Add RFS filter callback -- */ --int edma_register_rfs_filter(struct net_device *netdev, -- set_rfs_filter_callback_t set_filter) --{ -- struct edma_adapter *adapter = netdev_priv(netdev); -- -- spin_lock_bh(&adapter->rfs.rfs_ftab_lock); -- -- if (adapter->set_rfs_rule) { -- spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); -- return -1; -- } -- -- adapter->set_rfs_rule = set_filter; -- spin_unlock_bh(&adapter->rfs.rfs_ftab_lock); -- -- return 0; --} -- --/* edma_alloc_tx_rings() -- * Allocate rx rings -- */ --int edma_alloc_tx_rings(struct edma_common_info *edma_cinfo) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- int i, err = 0; -- -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) { -- err = edma_alloc_tx_ring(edma_cinfo, edma_cinfo->tpd_ring[i]); -- if (err) { -- dev_err(&pdev->dev, "Tx Queue alloc %u failed\n", i); -- return err; -- } -- } -- -- return 0; --} -- --/* edma_free_tx_rings() -- * Free tx rings -- */ --void edma_free_tx_rings(struct edma_common_info *edma_cinfo) --{ -- int i; -- -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) -- edma_free_tx_ring(edma_cinfo, edma_cinfo->tpd_ring[i]); --} -- --/* edma_free_tx_resources() -- * Free buffers associated with tx rings -- */ --void edma_free_tx_resources(struct edma_common_info *edma_cinfo) --{ -- struct edma_tx_desc_ring *etdr; -- struct edma_sw_desc *sw_desc; -- struct platform_device *pdev = edma_cinfo->pdev; -- int i, j; -- -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) { -- etdr = edma_cinfo->tpd_ring[i]; -- for (j = 0; j < EDMA_TX_RING_SIZE; j++) { -- sw_desc = &etdr->sw_desc[j]; -- if (sw_desc->flags & (EDMA_SW_DESC_FLAG_SKB_HEAD | -- EDMA_SW_DESC_FLAG_SKB_FRAG | EDMA_SW_DESC_FLAG_SKB_FRAGLIST)) -- edma_tx_unmap_and_free(pdev, sw_desc); -- } -- } --} -- --/* edma_alloc_rx_rings() -- * Allocate rx rings -- */ --int edma_alloc_rx_rings(struct edma_common_info *edma_cinfo) --{ -- struct platform_device *pdev = edma_cinfo->pdev; -- int i, j, err = 0; -- -- for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { -- err = edma_alloc_rx_ring(edma_cinfo, edma_cinfo->rfd_ring[j]); -- if (err) { -- dev_err(&pdev->dev, "Rx Queue alloc%u failed\n", i); -- return err; -- } -- j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); -- } -- -- return 0; --} -- --/* edma_free_rx_rings() -- * free rx rings -- */ --void edma_free_rx_rings(struct edma_common_info *edma_cinfo) --{ -- int i, j; -- -- for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { -- edma_free_rx_ring(edma_cinfo, edma_cinfo->rfd_ring[j]); -- j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); -- } --} -- --/* edma_free_queues() -- * Free the queues allocaated -- */ --void edma_free_queues(struct edma_common_info *edma_cinfo) --{ -- int i , j; -- -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) { -- if (edma_cinfo->tpd_ring[i]) -- kfree(edma_cinfo->tpd_ring[i]); -- edma_cinfo->tpd_ring[i] = NULL; -- } -- -- for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { -- if (edma_cinfo->rfd_ring[j]) -- kfree(edma_cinfo->rfd_ring[j]); -- edma_cinfo->rfd_ring[j] = NULL; -- j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); -- } -- -- edma_cinfo->num_rx_queues = 0; -- edma_cinfo->num_tx_queues = 0; -- -- return; --} -- --/* edma_free_rx_resources() -- * Free buffers associated with tx rings -- */ --void edma_free_rx_resources(struct edma_common_info *edma_cinfo) --{ -- struct edma_rfd_desc_ring *erdr; -- struct edma_sw_desc *sw_desc; -- struct platform_device *pdev = edma_cinfo->pdev; -- int i, j, k; -- -- for (i = 0, k = 0; i < edma_cinfo->num_rx_queues; i++) { -- erdr = edma_cinfo->rfd_ring[k]; -- for (j = 0; j < EDMA_RX_RING_SIZE; j++) { -- sw_desc = &erdr->sw_desc[j]; -- if (likely(sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_HEAD)) { -- dma_unmap_single(&pdev->dev, sw_desc->dma, -- sw_desc->length, DMA_FROM_DEVICE); -- edma_clean_rfd(erdr, j); -- } else if ((sw_desc->flags & EDMA_SW_DESC_FLAG_SKB_FRAG)) { -- dma_unmap_page(&pdev->dev, sw_desc->dma, -- sw_desc->length, DMA_FROM_DEVICE); -- edma_clean_rfd(erdr, j); -- } -- } -- k += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); -- -- } --} -- --/* edma_alloc_queues_tx() -- * Allocate memory for all rings -- */ --int edma_alloc_queues_tx(struct edma_common_info *edma_cinfo) --{ -- int i; -- -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) { -- struct edma_tx_desc_ring *etdr; -- etdr = kzalloc(sizeof(struct edma_tx_desc_ring), GFP_KERNEL); -- if (!etdr) -- goto err; -- etdr->count = edma_cinfo->tx_ring_count; -- edma_cinfo->tpd_ring[i] = etdr; -- } -- -- return 0; --err: -- edma_free_queues(edma_cinfo); -- return -1; --} -- --/* edma_alloc_queues_rx() -- * Allocate memory for all rings -- */ --int edma_alloc_queues_rx(struct edma_common_info *edma_cinfo) --{ -- int i, j; -- -- for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { -- struct edma_rfd_desc_ring *rfd_ring; -- rfd_ring = kzalloc(sizeof(struct edma_rfd_desc_ring), -- GFP_KERNEL); -- if (!rfd_ring) -- goto err; -- rfd_ring->count = edma_cinfo->rx_ring_count; -- edma_cinfo->rfd_ring[j] = rfd_ring; -- j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); -- } -- return 0; --err: -- edma_free_queues(edma_cinfo); -- return -1; --} -- --/* edma_clear_irq_status() -- * Clear interrupt status -- */ --void edma_clear_irq_status() --{ -- edma_write_reg(EDMA_REG_RX_ISR, 0xff); -- edma_write_reg(EDMA_REG_TX_ISR, 0xffff); -- edma_write_reg(EDMA_REG_MISC_ISR, 0x1fff); -- edma_write_reg(EDMA_REG_WOL_ISR, 0x1); --}; -- --/* edma_configure() -- * Configure skb, edma interrupts and control register. -- */ --int edma_configure(struct edma_common_info *edma_cinfo) --{ -- struct edma_hw *hw = &edma_cinfo->hw; -- u32 intr_modrt_data; -- u32 intr_ctrl_data = 0; -- int i, j, ret_count; -- -- edma_read_reg(EDMA_REG_INTR_CTRL, &intr_ctrl_data); -- intr_ctrl_data &= ~(1 << EDMA_INTR_SW_IDX_W_TYP_SHIFT); -- intr_ctrl_data |= hw->intr_sw_idx_w << EDMA_INTR_SW_IDX_W_TYP_SHIFT; -- edma_write_reg(EDMA_REG_INTR_CTRL, intr_ctrl_data); -- -- edma_clear_irq_status(); -- -- /* Clear any WOL status */ -- edma_write_reg(EDMA_REG_WOL_CTRL, 0); -- intr_modrt_data = (EDMA_TX_IMT << EDMA_IRQ_MODRT_TX_TIMER_SHIFT); -- intr_modrt_data |= (EDMA_RX_IMT << EDMA_IRQ_MODRT_RX_TIMER_SHIFT); -- edma_write_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, intr_modrt_data); -- edma_configure_tx(edma_cinfo); -- edma_configure_rx(edma_cinfo); -- -- /* Allocate the RX buffer */ -- for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { -- struct edma_rfd_desc_ring *ring = edma_cinfo->rfd_ring[j]; -- ret_count = edma_alloc_rx_buf(edma_cinfo, ring, ring->count, j); -- if (ret_count) { -- dev_dbg(&edma_cinfo->pdev->dev, "not all rx buffers allocated\n"); -- } -- j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); -- } -- -- /* Configure descriptor Ring */ -- edma_init_desc(edma_cinfo); -- return 0; --} -- --/* edma_irq_enable() -- * Enable default interrupt generation settings -- */ --void edma_irq_enable(struct edma_common_info *edma_cinfo) --{ -- struct edma_hw *hw = &edma_cinfo->hw; -- int i, j; -- -- edma_write_reg(EDMA_REG_RX_ISR, 0xff); -- for (i = 0, j = 0; i < edma_cinfo->num_rx_queues; i++) { -- edma_write_reg(EDMA_REG_RX_INT_MASK_Q(j), hw->rx_intr_mask); -- j += ((edma_cinfo->num_rx_queues == 4) ? 2 : 1); -- } -- edma_write_reg(EDMA_REG_TX_ISR, 0xffff); -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) -- edma_write_reg(EDMA_REG_TX_INT_MASK_Q(i), hw->tx_intr_mask); --} -- --/* edma_irq_disable() -- * Disable Interrupt -- */ --void edma_irq_disable(struct edma_common_info *edma_cinfo) --{ -- int i; -- -- for (i = 0; i < EDMA_MAX_RECEIVE_QUEUE; i++) -- edma_write_reg(EDMA_REG_RX_INT_MASK_Q(i), 0x0); -- -- for (i = 0; i < EDMA_MAX_TRANSMIT_QUEUE; i++) -- edma_write_reg(EDMA_REG_TX_INT_MASK_Q(i), 0x0); -- edma_write_reg(EDMA_REG_MISC_IMR, 0); -- edma_write_reg(EDMA_REG_WOL_IMR, 0); --} -- --/* edma_free_irqs() -- * Free All IRQs -- */ --void edma_free_irqs(struct edma_adapter *adapter) --{ -- struct edma_common_info *edma_cinfo = adapter->edma_cinfo; -- int i, j; -- int k = ((edma_cinfo->num_rx_queues == 4) ? 1 : 2); -- -- for (i = 0; i < CONFIG_NR_CPUS; i++) { -- for (j = edma_cinfo->edma_percpu_info[i].tx_start; j < (edma_cinfo->edma_percpu_info[i].tx_start + 4); j++) -- free_irq(edma_cinfo->tx_irq[j], &edma_cinfo->edma_percpu_info[i]); -- -- for (j = edma_cinfo->edma_percpu_info[i].rx_start; j < (edma_cinfo->edma_percpu_info[i].rx_start + k); j++) -- free_irq(edma_cinfo->rx_irq[j], &edma_cinfo->edma_percpu_info[i]); -- } --} -- --/* edma_enable_rx_ctrl() -- * Enable RX queue control -- */ --void edma_enable_rx_ctrl(struct edma_hw *hw) --{ -- u32 data; -- -- edma_read_reg(EDMA_REG_RXQ_CTRL, &data); -- data |= EDMA_RXQ_CTRL_EN; -- edma_write_reg(EDMA_REG_RXQ_CTRL, data); --} -- -- --/* edma_enable_tx_ctrl() -- * Enable TX queue control -- */ --void edma_enable_tx_ctrl(struct edma_hw *hw) --{ -- u32 data; -- -- edma_read_reg(EDMA_REG_TXQ_CTRL, &data); -- data |= EDMA_TXQ_CTRL_TXQ_EN; -- edma_write_reg(EDMA_REG_TXQ_CTRL, data); --} -- --/* edma_stop_rx_tx() -- * Disable RX/TQ Queue control -- */ --void edma_stop_rx_tx(struct edma_hw *hw) --{ -- u32 data; -- -- edma_read_reg(EDMA_REG_RXQ_CTRL, &data); -- data &= ~EDMA_RXQ_CTRL_EN; -- edma_write_reg(EDMA_REG_RXQ_CTRL, data); -- edma_read_reg(EDMA_REG_TXQ_CTRL, &data); -- data &= ~EDMA_TXQ_CTRL_TXQ_EN; -- edma_write_reg(EDMA_REG_TXQ_CTRL, data); --} -- --/* edma_reset() -- * Reset the EDMA -- */ --int edma_reset(struct edma_common_info *edma_cinfo) --{ -- struct edma_hw *hw = &edma_cinfo->hw; -- -- edma_irq_disable(edma_cinfo); -- -- edma_clear_irq_status(); -- -- edma_stop_rx_tx(hw); -- -- return 0; --} -- --/* edma_fill_netdev() -- * Fill netdev for each etdr -- */ --int edma_fill_netdev(struct edma_common_info *edma_cinfo, int queue_id, -- int dev, int txq_id) --{ -- struct edma_tx_desc_ring *etdr; -- int i = 0; -- -- etdr = edma_cinfo->tpd_ring[queue_id]; -- -- while (etdr->netdev[i]) -- i++; -- -- if (i >= EDMA_MAX_NETDEV_PER_QUEUE) -- return -1; -- -- /* Populate the netdev associated with the tpd ring */ -- etdr->netdev[i] = edma_netdev[dev]; -- etdr->nq[i] = netdev_get_tx_queue(edma_netdev[dev], txq_id); -- -- return 0; --} -- --/* edma_set_mac() -- * Change the Ethernet Address of the NIC -- */ --int edma_set_mac_addr(struct net_device *netdev, void *p) --{ -- struct sockaddr *addr = p; -- -- if (!is_valid_ether_addr(addr->sa_data)) -- return -EINVAL; -- -- if (netif_running(netdev)) -- return -EBUSY; -- -- memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); -- return 0; --} -- --/* edma_set_stp_rstp() -- * set stp/rstp -- */ --void edma_set_stp_rstp(bool rstp) --{ -- edma_stp_rstp = rstp; --} -- --/* edma_assign_ath_hdr_type() -- * assign atheros header eth type -- */ --void edma_assign_ath_hdr_type(int eth_type) --{ -- edma_ath_eth_type = eth_type & EDMA_ETH_TYPE_MASK; --} -- --/* edma_get_default_vlan_tag() -- * Used by other modules to get the default vlan tag -- */ --int edma_get_default_vlan_tag(struct net_device *netdev) --{ -- struct edma_adapter *adapter = netdev_priv(netdev); -- -- if (adapter->default_vlan_tag) -- return adapter->default_vlan_tag; -- -- return 0; --} -- --/* edma_open() -- * gets called when netdevice is up, start the queue. -- */ --int edma_open(struct net_device *netdev) --{ -- struct edma_adapter *adapter = netdev_priv(netdev); -- struct platform_device *pdev = adapter->edma_cinfo->pdev; -- -- netif_tx_start_all_queues(netdev); -- edma_initialise_rfs_flow_table(adapter); -- set_bit(__EDMA_UP, &adapter->state_flags); -- -- /* if Link polling is enabled, in our case enabled for WAN, then -- * do a phy start, else always set link as UP -- */ -- if (adapter->poll_required) { -- if (!IS_ERR(adapter->phydev)) { -- /* AR40xx calibration will leave the PHY in unwanted state, -- * so a soft reset is required before phy_start() -- */ -- genphy_soft_reset(adapter->phydev); -- phy_start(adapter->phydev); -- phy_start_aneg(adapter->phydev); -- adapter->link_state = __EDMA_LINKDOWN; -- } else { -- dev_dbg(&pdev->dev, "Invalid PHY device for a link polled interface\n"); -- } -- } else { -- adapter->link_state = __EDMA_LINKUP; -- netif_carrier_on(netdev); -- } -- -- return 0; --} -- -- --/* edma_close() -- * gets called when netdevice is down, stops the queue. -- */ --int edma_close(struct net_device *netdev) --{ -- struct edma_adapter *adapter = netdev_priv(netdev); -- -- edma_free_rfs_flow_table(adapter); -- netif_carrier_off(netdev); -- netif_tx_stop_all_queues(netdev); -- -- if (adapter->poll_required) { -- if (!IS_ERR(adapter->phydev)) -- phy_stop(adapter->phydev); -- } -- -- adapter->link_state = __EDMA_LINKDOWN; -- -- /* Set GMAC state to UP before link state is checked -- */ -- clear_bit(__EDMA_UP, &adapter->state_flags); -- -- return 0; --} -- --/* edma_poll -- * polling function that gets called when the napi gets scheduled. -- * -- * Main sequence of task performed in this api -- * is clear irq status -> clear_tx_irq -> clean_rx_irq-> -- * enable interrupts. -- */ --int edma_poll(struct napi_struct *napi, int budget) --{ -- struct edma_per_cpu_queues_info *edma_percpu_info = container_of(napi, -- struct edma_per_cpu_queues_info, napi); -- struct edma_common_info *edma_cinfo = edma_percpu_info->edma_cinfo; -- u32 reg_data; -- u32 shadow_rx_status, shadow_tx_status; -- int queue_id; -- int i, work_done = 0; -- u16 rx_pending_fill; -- -- /* Store the Rx/Tx status by ANDing it with -- * appropriate CPU RX?TX mask -- */ -- edma_read_reg(EDMA_REG_RX_ISR, ®_data); -- edma_percpu_info->rx_status |= reg_data & edma_percpu_info->rx_mask; -- shadow_rx_status = edma_percpu_info->rx_status; -- edma_read_reg(EDMA_REG_TX_ISR, ®_data); -- edma_percpu_info->tx_status |= reg_data & edma_percpu_info->tx_mask; -- shadow_tx_status = edma_percpu_info->tx_status; -- -- /* Every core will have a start, which will be computed -- * in probe and stored in edma_percpu_info->tx_start variable. -- * We will shift the status bit by tx_start to obtain -- * status bits for the core on which the current processing -- * is happening. Since, there are 4 tx queues per core, -- * we will run the loop till we get the correct queue to clear. -- */ -- while (edma_percpu_info->tx_status) { -- queue_id = ffs(edma_percpu_info->tx_status) - 1; -- edma_tx_complete(edma_cinfo, queue_id); -- edma_percpu_info->tx_status &= ~(1 << queue_id); -- } -- -- /* Every core will have a start, which will be computed -- * in probe and stored in edma_percpu_info->tx_start variable. -- * We will shift the status bit by tx_start to obtain -- * status bits for the core on which the current processing -- * is happening. Since, there are 4 tx queues per core, we -- * will run the loop till we get the correct queue to clear. -- */ -- while (edma_percpu_info->rx_status) { -- queue_id = ffs(edma_percpu_info->rx_status) - 1; -- rx_pending_fill = edma_rx_complete(edma_cinfo, &work_done, -- budget, queue_id, napi); -- -- if (likely(work_done < budget)) { -- if (rx_pending_fill) { -- /* reschedule poll() to refill rx buffer deficit */ -- work_done = budget; -- break; -- } -- edma_percpu_info->rx_status &= ~(1 << queue_id); -- } else { -- break; -- } -- } -- -- /* Clear the status register, to avoid the interrupts to -- * reoccur.This clearing of interrupt status register is -- * done here as writing to status register only takes place -- * once the producer/consumer index has been updated to -- * reflect that the packet transmission/reception went fine. -- */ -- edma_write_reg(EDMA_REG_RX_ISR, shadow_rx_status); -- edma_write_reg(EDMA_REG_TX_ISR, shadow_tx_status); -- -- /* If budget not fully consumed, exit the polling mode */ -- if (likely(work_done < budget)) { -- napi_complete(napi); -- -- /* re-enable the interrupts */ -- for (i = 0; i < edma_cinfo->num_rxq_per_core; i++) -- edma_write_reg(EDMA_REG_RX_INT_MASK_Q(edma_percpu_info->rx_start + i), 0x1); -- for (i = 0; i < edma_cinfo->num_txq_per_core; i++) -- edma_write_reg(EDMA_REG_TX_INT_MASK_Q(edma_percpu_info->tx_start + i), 0x1); -- } -- -- return work_done; --} -- --/* edma interrupt() -- * interrupt handler -- */ --irqreturn_t edma_interrupt(int irq, void *dev) --{ -- struct edma_per_cpu_queues_info *edma_percpu_info = (struct edma_per_cpu_queues_info *) dev; -- struct edma_common_info *edma_cinfo = edma_percpu_info->edma_cinfo; -- int i; -- -- /* Unmask the TX/RX interrupt register */ -- for (i = 0; i < edma_cinfo->num_rxq_per_core; i++) -- edma_write_reg(EDMA_REG_RX_INT_MASK_Q(edma_percpu_info->rx_start + i), 0x0); -- -- for (i = 0; i < edma_cinfo->num_txq_per_core; i++) -- edma_write_reg(EDMA_REG_TX_INT_MASK_Q(edma_percpu_info->tx_start + i), 0x0); -- -- napi_schedule(&edma_percpu_info->napi); -- -- return IRQ_HANDLED; --} ---- a/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/essedma/edma.h -+++ /dev/null -@@ -1,455 +0,0 @@ --/* -- * Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved. -- * -- * Permission to use, copy, modify, and/or distribute this software for -- * any purpose with or without fee is hereby granted, provided that the -- * above copyright notice and this permission notice appear in all copies. -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- */ -- --#ifndef _EDMA_H_ --#define _EDMA_H_ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include "ess_edma.h" -- --#define EDMA_CPU_CORES_SUPPORTED 4 --#define EDMA_MAX_PORTID_SUPPORTED 5 --#define EDMA_MAX_VLAN_SUPPORTED EDMA_MAX_PORTID_SUPPORTED --#define EDMA_MAX_PORTID_BITMAP_INDEX (EDMA_MAX_PORTID_SUPPORTED + 1) --#define EDMA_MAX_PORTID_BITMAP_SUPPORTED 0x1f /* 0001_1111 = 0x1f */ --#define EDMA_MAX_NETDEV_PER_QUEUE 4 /* 3 Netdev per queue, 1 space for indexing */ -- --#define EDMA_MAX_RECEIVE_QUEUE 8 --#define EDMA_MAX_TRANSMIT_QUEUE 16 -- --/* WAN/LAN adapter number */ --#define EDMA_WAN 0 --#define EDMA_LAN 1 -- --/* VLAN tag */ --#define EDMA_LAN_DEFAULT_VLAN 1 --#define EDMA_WAN_DEFAULT_VLAN 2 -- --#define EDMA_DEFAULT_GROUP1_VLAN 1 --#define EDMA_DEFAULT_GROUP2_VLAN 2 --#define EDMA_DEFAULT_GROUP3_VLAN 3 --#define EDMA_DEFAULT_GROUP4_VLAN 4 --#define EDMA_DEFAULT_GROUP5_VLAN 5 -- --/* Queues exposed to linux kernel */ --#define EDMA_NETDEV_TX_QUEUE 4 --#define EDMA_NETDEV_RX_QUEUE 4 -- --/* Number of queues per core */ --#define EDMA_NUM_TXQ_PER_CORE 4 --#define EDMA_NUM_RXQ_PER_CORE 2 -- --#define EDMA_TPD_EOP_SHIFT 31 -- --#define EDMA_PORT_ID_SHIFT 12 --#define EDMA_PORT_ID_MASK 0x7 -- --/* tpd word 3 bit 18-28 */ --#define EDMA_TPD_PORT_BITMAP_SHIFT 18 -- --#define EDMA_TPD_FROM_CPU_SHIFT 25 -- --#define EDMA_FROM_CPU_MASK 0x80 --#define EDMA_SKB_PRIORITY_MASK 0x38 -- --/* TX/RX descriptor ring count */ --/* should be a power of 2 */ --#define EDMA_RX_RING_SIZE 128 --#define EDMA_TX_RING_SIZE 128 -- --/* Flags used in paged/non paged mode */ --#define EDMA_RX_HEAD_BUFF_SIZE_JUMBO 256 --#define EDMA_RX_HEAD_BUFF_SIZE 1540 -- --/* MAX frame size supported by switch */ --#define EDMA_MAX_JUMBO_FRAME_SIZE 9216 -- --/* Configurations */ --#define EDMA_INTR_CLEAR_TYPE 0 --#define EDMA_INTR_SW_IDX_W_TYPE 0 --#define EDMA_FIFO_THRESH_TYPE 0 --#define EDMA_RSS_TYPE 0 --#define EDMA_RX_IMT 0x0020 --#define EDMA_TX_IMT 0x0050 --#define EDMA_TPD_BURST 5 --#define EDMA_TXF_BURST 0x100 --#define EDMA_RFD_BURST 8 --#define EDMA_RFD_THR 16 --#define EDMA_RFD_LTHR 0 -- --/* RX/TX per CPU based mask/shift */ --#define EDMA_TX_PER_CPU_MASK 0xF --#define EDMA_RX_PER_CPU_MASK 0x3 --#define EDMA_TX_PER_CPU_MASK_SHIFT 0x2 --#define EDMA_RX_PER_CPU_MASK_SHIFT 0x1 --#define EDMA_TX_CPU_START_SHIFT 0x2 --#define EDMA_RX_CPU_START_SHIFT 0x1 -- --/* FLags used in transmit direction */ --#define EDMA_HW_CHECKSUM 0x00000001 --#define EDMA_VLAN_TX_TAG_INSERT_FLAG 0x00000002 --#define EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG 0x00000004 -- --#define EDMA_SW_DESC_FLAG_LAST 0x1 --#define EDMA_SW_DESC_FLAG_SKB_HEAD 0x2 --#define EDMA_SW_DESC_FLAG_SKB_FRAG 0x4 --#define EDMA_SW_DESC_FLAG_SKB_FRAGLIST 0x8 --#define EDMA_SW_DESC_FLAG_SKB_NONE 0x10 --#define EDMA_SW_DESC_FLAG_SKB_REUSE 0x20 -- -- --#define EDMA_MAX_SKB_FRAGS (MAX_SKB_FRAGS + 1) -- --/* Ethtool specific list of EDMA supported features */ --#define EDMA_SUPPORTED_FEATURES (SUPPORTED_10baseT_Half \ -- | SUPPORTED_10baseT_Full \ -- | SUPPORTED_100baseT_Half \ -- | SUPPORTED_100baseT_Full \ -- | SUPPORTED_1000baseT_Full) -- --/* Recevie side atheros Header */ --#define EDMA_RX_ATH_HDR_VERSION 0x2 --#define EDMA_RX_ATH_HDR_VERSION_SHIFT 14 --#define EDMA_RX_ATH_HDR_PRIORITY_SHIFT 11 --#define EDMA_RX_ATH_PORT_TYPE_SHIFT 6 --#define EDMA_RX_ATH_HDR_RSTP_PORT_TYPE 0x4 -- --/* Transmit side atheros Header */ --#define EDMA_TX_ATH_HDR_PORT_BITMAP_MASK 0x7F --#define EDMA_TX_ATH_HDR_FROM_CPU_MASK 0x80 --#define EDMA_TX_ATH_HDR_FROM_CPU_SHIFT 7 -- --#define EDMA_TXQ_START_CORE0 8 --#define EDMA_TXQ_START_CORE1 12 --#define EDMA_TXQ_START_CORE2 0 --#define EDMA_TXQ_START_CORE3 4 -- --#define EDMA_TXQ_IRQ_MASK_CORE0 0x0F00 --#define EDMA_TXQ_IRQ_MASK_CORE1 0xF000 --#define EDMA_TXQ_IRQ_MASK_CORE2 0x000F --#define EDMA_TXQ_IRQ_MASK_CORE3 0x00F0 -- --#define EDMA_ETH_HDR_LEN 12 --#define EDMA_ETH_TYPE_MASK 0xFFFF -- --#define EDMA_RX_BUFFER_WRITE 16 --#define EDMA_RFD_AVAIL_THR 80 -- --#define EDMA_GMAC_NO_MDIO_PHY PHY_MAX_ADDR -- --extern int ssdk_rfs_ipct_rule_set(__be32 ip_src, __be32 ip_dst, -- __be16 sport, __be16 dport, -- uint8_t proto, u16 loadbalance, bool action); --struct edma_ethtool_statistics { -- u32 tx_q0_pkt; -- u32 tx_q1_pkt; -- u32 tx_q2_pkt; -- u32 tx_q3_pkt; -- u32 tx_q4_pkt; -- u32 tx_q5_pkt; -- u32 tx_q6_pkt; -- u32 tx_q7_pkt; -- u32 tx_q8_pkt; -- u32 tx_q9_pkt; -- u32 tx_q10_pkt; -- u32 tx_q11_pkt; -- u32 tx_q12_pkt; -- u32 tx_q13_pkt; -- u32 tx_q14_pkt; -- u32 tx_q15_pkt; -- u32 tx_q0_byte; -- u32 tx_q1_byte; -- u32 tx_q2_byte; -- u32 tx_q3_byte; -- u32 tx_q4_byte; -- u32 tx_q5_byte; -- u32 tx_q6_byte; -- u32 tx_q7_byte; -- u32 tx_q8_byte; -- u32 tx_q9_byte; -- u32 tx_q10_byte; -- u32 tx_q11_byte; -- u32 tx_q12_byte; -- u32 tx_q13_byte; -- u32 tx_q14_byte; -- u32 tx_q15_byte; -- u32 rx_q0_pkt; -- u32 rx_q1_pkt; -- u32 rx_q2_pkt; -- u32 rx_q3_pkt; -- u32 rx_q4_pkt; -- u32 rx_q5_pkt; -- u32 rx_q6_pkt; -- u32 rx_q7_pkt; -- u32 rx_q0_byte; -- u32 rx_q1_byte; -- u32 rx_q2_byte; -- u32 rx_q3_byte; -- u32 rx_q4_byte; -- u32 rx_q5_byte; -- u32 rx_q6_byte; -- u32 rx_q7_byte; -- u32 tx_desc_error; -- u32 rx_alloc_fail_ctr; --}; -- --struct edma_mdio_data { -- struct mii_bus *mii_bus; -- void __iomem *membase; -- int phy_irq[PHY_MAX_ADDR]; --}; -- --/* EDMA LINK state */ --enum edma_link_state { -- __EDMA_LINKUP, /* Indicate link is UP */ -- __EDMA_LINKDOWN /* Indicate link is down */ --}; -- --/* EDMA GMAC state */ --enum edma_gmac_state { -- __EDMA_UP /* use to indicate GMAC is up */ --}; -- --/* edma transmit descriptor */ --struct edma_tx_desc { -- __le16 len; /* full packet including CRC */ -- __le16 svlan_tag; /* vlan tag */ -- __le32 word1; /* byte 4-7 */ -- __le32 addr; /* address of buffer */ -- __le32 word3; /* byte 12 */ --}; -- --/* edma receive return descriptor */ --struct edma_rx_return_desc { -- u16 rrd0; -- u16 rrd1; -- u16 rrd2; -- u16 rrd3; -- u16 rrd4; -- u16 rrd5; -- u16 rrd6; -- u16 rrd7; --}; -- --/* RFD descriptor */ --struct edma_rx_free_desc { -- __le32 buffer_addr; /* buffer address */ --}; -- --/* edma hw specific data */ --struct edma_hw { -- u32 __iomem *hw_addr; /* inner register address */ -- struct edma_adapter *adapter; /* netdevice adapter */ -- u32 rx_intr_mask; /*rx interrupt mask */ -- u32 tx_intr_mask; /* tx interrupt nask */ -- u32 misc_intr_mask; /* misc interrupt mask */ -- u32 wol_intr_mask; /* wake on lan interrupt mask */ -- bool intr_clear_type; /* interrupt clear */ -- bool intr_sw_idx_w; /* interrupt software index */ -- u32 rx_head_buff_size; /* Rx buffer size */ -- u8 rss_type; /* rss protocol type */ --}; -- --/* edma_sw_desc stores software descriptor -- * SW descriptor has 1:1 map with HW descriptor -- */ --struct edma_sw_desc { -- struct sk_buff *skb; -- dma_addr_t dma; /* dma address */ -- u16 length; /* Tx/Rx buffer length */ -- u32 flags; --}; -- --/* per core related information */ --struct edma_per_cpu_queues_info { -- struct napi_struct napi; /* napi associated with the core */ -- u32 tx_mask; /* tx interrupt mask */ -- u32 rx_mask; /* rx interrupt mask */ -- u32 tx_status; /* tx interrupt status */ -- u32 rx_status; /* rx interrupt status */ -- u32 tx_start; /* tx queue start */ -- u32 rx_start; /* rx queue start */ -- struct edma_common_info *edma_cinfo; /* edma common info */ --}; -- --/* edma specific common info */ --struct edma_common_info { -- struct edma_tx_desc_ring *tpd_ring[16]; /* 16 Tx queues */ -- struct edma_rfd_desc_ring *rfd_ring[8]; /* 8 Rx queues */ -- struct platform_device *pdev; /* device structure */ -- struct net_device *netdev[EDMA_MAX_PORTID_SUPPORTED]; -- struct net_device *portid_netdev_lookup_tbl[EDMA_MAX_PORTID_BITMAP_INDEX]; -- struct ctl_table_header *edma_ctl_table_hdr; -- int num_gmac; -- struct edma_ethtool_statistics edma_ethstats; /* ethtool stats */ -- int num_rx_queues; /* number of rx queue */ -- u32 num_tx_queues; /* number of tx queue */ -- u32 tx_irq[16]; /* number of tx irq */ -- u32 rx_irq[8]; /* number of rx irq */ -- u32 from_cpu; /* from CPU TPD field */ -- u32 num_rxq_per_core; /* Rx queues per core */ -- u32 num_txq_per_core; /* Tx queues per core */ -- u16 tx_ring_count; /* Tx ring count */ -- u16 rx_ring_count; /* Rx ring*/ -- u16 rx_head_buffer_len; /* rx buffer length */ -- u16 rx_page_buffer_len; /* rx buffer length */ -- u32 page_mode; /* Jumbo frame supported flag */ -- u32 fraglist_mode; /* fraglist supported flag */ -- struct edma_hw hw; /* edma hw specific structure */ -- struct edma_per_cpu_queues_info edma_percpu_info[CONFIG_NR_CPUS]; /* per cpu information */ -- spinlock_t stats_lock; /* protect edma stats area for updation */ -- struct timer_list edma_stats_timer; -- bool is_single_phy; -- void __iomem *ess_hw_addr; -- struct clk *ess_clk; --}; -- --/* transimit packet descriptor (tpd) ring */ --struct edma_tx_desc_ring { -- struct netdev_queue *nq[EDMA_MAX_NETDEV_PER_QUEUE]; /* Linux queue index */ -- struct net_device *netdev[EDMA_MAX_NETDEV_PER_QUEUE]; -- /* Array of netdevs associated with the tpd ring */ -- void *hw_desc; /* descriptor ring virtual address */ -- struct edma_sw_desc *sw_desc; /* buffer associated with ring */ -- int netdev_bmp; /* Bitmap for per-ring netdevs */ -- u32 size; /* descriptor ring length in bytes */ -- u16 count; /* number of descriptors in the ring */ -- dma_addr_t dma; /* descriptor ring physical address */ -- u16 sw_next_to_fill; /* next Tx descriptor to fill */ -- u16 sw_next_to_clean; /* next Tx descriptor to clean */ --}; -- --/* receive free descriptor (rfd) ring */ --struct edma_rfd_desc_ring { -- void *hw_desc; /* descriptor ring virtual address */ -- struct edma_sw_desc *sw_desc; /* buffer associated with ring */ -- u16 size; /* bytes allocated to sw_desc */ -- u16 count; /* number of descriptors in the ring */ -- dma_addr_t dma; /* descriptor ring physical address */ -- u16 sw_next_to_fill; /* next descriptor to fill */ -- u16 sw_next_to_clean; /* next descriptor to clean */ -- u16 pending_fill; /* fill pending from previous iteration */ --}; -- --/* edma_rfs_flter_node - rfs filter node in hash table */ --struct edma_rfs_filter_node { -- struct flow_keys keys; -- u32 flow_id; /* flow_id of filter provided by kernel */ -- u16 filter_id; /* filter id of filter returned by adaptor */ -- u16 rq_id; /* desired rq index */ -- struct hlist_node node; /* edma rfs list node */ --}; -- --/* edma_rfs_flow_tbl - rfs flow table */ --struct edma_rfs_flow_table { -- u16 max_num_filter; /* Maximum number of filters edma supports */ -- u16 hashtoclean; /* hash table index to clean next */ -- int filter_available; /* Number of free filters available */ -- struct hlist_head hlist_head[EDMA_RFS_FLOW_ENTRIES]; -- spinlock_t rfs_ftab_lock; -- struct timer_list expire_rfs; /* timer function for edma_rps_may_expire_flow */ --}; -- --/* EDMA net device structure */ --struct edma_adapter { -- struct net_device *netdev; /* netdevice */ -- struct platform_device *pdev; /* platform device */ -- struct edma_common_info *edma_cinfo; /* edma common info */ -- struct phy_device *phydev; /* Phy device */ -- struct edma_rfs_flow_table rfs; /* edma rfs flow table */ -- struct net_device_stats stats; /* netdev statistics */ -- set_rfs_filter_callback_t set_rfs_rule; -- u32 flags;/* status flags */ -- unsigned long state_flags; /* GMAC up/down flags */ -- u32 forced_speed; /* link force speed */ -- u32 forced_duplex; /* link force duplex */ -- u32 link_state; /* phy link state */ -- u32 phy_mdio_addr; /* PHY device address on MII interface */ -- u32 poll_required; /* check if link polling is required */ -- u32 tx_start_offset[CONFIG_NR_CPUS]; /* tx queue start */ -- u32 default_vlan_tag; /* vlan tag */ -- u32 dp_bitmap; -- uint8_t phy_id[MII_BUS_ID_SIZE + 3]; --}; -- --int edma_alloc_queues_tx(struct edma_common_info *edma_cinfo); --int edma_alloc_queues_rx(struct edma_common_info *edma_cinfo); --int edma_open(struct net_device *netdev); --int edma_close(struct net_device *netdev); --void edma_free_tx_resources(struct edma_common_info *edma_c_info); --void edma_free_rx_resources(struct edma_common_info *edma_c_info); --int edma_alloc_tx_rings(struct edma_common_info *edma_cinfo); --int edma_alloc_rx_rings(struct edma_common_info *edma_cinfo); --void edma_free_tx_rings(struct edma_common_info *edma_cinfo); --void edma_free_rx_rings(struct edma_common_info *edma_cinfo); --void edma_free_queues(struct edma_common_info *edma_cinfo); --void edma_irq_disable(struct edma_common_info *edma_cinfo); --int edma_reset(struct edma_common_info *edma_cinfo); --int edma_poll(struct napi_struct *napi, int budget); --netdev_tx_t edma_xmit(struct sk_buff *skb, -- struct net_device *netdev); --int edma_configure(struct edma_common_info *edma_cinfo); --void edma_irq_enable(struct edma_common_info *edma_cinfo); --void edma_enable_tx_ctrl(struct edma_hw *hw); --void edma_enable_rx_ctrl(struct edma_hw *hw); --void edma_stop_rx_tx(struct edma_hw *hw); --void edma_free_irqs(struct edma_adapter *adapter); --irqreturn_t edma_interrupt(int irq, void *dev); --void edma_write_reg(u16 reg_addr, u32 reg_value); --void edma_read_reg(u16 reg_addr, volatile u32 *reg_value); --struct net_device_stats *edma_get_stats(struct net_device *netdev); --int edma_set_mac_addr(struct net_device *netdev, void *p); --int edma_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, -- u16 rxq, u32 flow_id); --int edma_register_rfs_filter(struct net_device *netdev, -- set_rfs_filter_callback_t set_filter); --void edma_flow_may_expire(struct timer_list *t); --void edma_set_ethtool_ops(struct net_device *netdev); --void edma_set_stp_rstp(bool tag); --void edma_assign_ath_hdr_type(int tag); --int edma_get_default_vlan_tag(struct net_device *netdev); --void edma_adjust_link(struct net_device *netdev); --int edma_fill_netdev(struct edma_common_info *edma_cinfo, int qid, int num, int txq_id); --void edma_read_append_stats(struct edma_common_info *edma_cinfo); --void edma_change_tx_coalesce(int usecs); --void edma_change_rx_coalesce(int usecs); --void edma_get_tx_rx_coalesce(u32 *reg_val); --void edma_clear_irq_status(void); --void ess_set_port_status_speed(struct edma_common_info *edma_cinfo, -- struct phy_device *phydev, uint8_t port_id); --#endif /* _EDMA_H_ */ ---- a/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/essedma/edma_axi.c -+++ /dev/null -@@ -1,1346 +0,0 @@ --/* -- * Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved. -- * -- * Permission to use, copy, modify, and/or distribute this software for -- * any purpose with or without fee is hereby granted, provided that the -- * above copyright notice and this permission notice appear in all copies. -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include "edma.h" --#include "ess_edma.h" -- --/* Weight round robin and virtual QID mask */ --#define EDMA_WRR_VID_SCTL_MASK 0xffff -- --/* Weight round robin and virtual QID shift */ --#define EDMA_WRR_VID_SCTL_SHIFT 16 -- --char edma_axi_driver_name[] = "ess_edma"; --static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | -- NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP; -- --static u32 edma_hw_addr; -- --char edma_tx_irq[16][64]; --char edma_rx_irq[8][64]; --struct net_device *edma_netdev[EDMA_MAX_PORTID_SUPPORTED]; --static u16 tx_start[4] = {EDMA_TXQ_START_CORE0, EDMA_TXQ_START_CORE1, -- EDMA_TXQ_START_CORE2, EDMA_TXQ_START_CORE3}; --static u32 tx_mask[4] = {EDMA_TXQ_IRQ_MASK_CORE0, EDMA_TXQ_IRQ_MASK_CORE1, -- EDMA_TXQ_IRQ_MASK_CORE2, EDMA_TXQ_IRQ_MASK_CORE3}; -- --static u32 edma_default_ltag __read_mostly = EDMA_LAN_DEFAULT_VLAN; --static u32 edma_default_wtag __read_mostly = EDMA_WAN_DEFAULT_VLAN; --static u32 edma_default_group1_vtag __read_mostly = EDMA_DEFAULT_GROUP1_VLAN; --static u32 edma_default_group2_vtag __read_mostly = EDMA_DEFAULT_GROUP2_VLAN; --static u32 edma_default_group3_vtag __read_mostly = EDMA_DEFAULT_GROUP3_VLAN; --static u32 edma_default_group4_vtag __read_mostly = EDMA_DEFAULT_GROUP4_VLAN; --static u32 edma_default_group5_vtag __read_mostly = EDMA_DEFAULT_GROUP5_VLAN; --static u32 edma_rss_idt_val = EDMA_RSS_IDT_VALUE; --static u32 edma_rss_idt_idx; -- --static int edma_weight_assigned_to_q __read_mostly; --static int edma_queue_to_virtual_q __read_mostly; --static bool edma_enable_rstp __read_mostly; --static int edma_athr_hdr_eth_type __read_mostly; -- --static int page_mode; --module_param(page_mode, int, 0); --MODULE_PARM_DESC(page_mode, "enable page mode"); -- --static int overwrite_mode; --module_param(overwrite_mode, int, 0); --MODULE_PARM_DESC(overwrite_mode, "overwrite default page_mode setting"); -- --static int jumbo_mru = EDMA_RX_HEAD_BUFF_SIZE; --module_param(jumbo_mru, int, 0); --MODULE_PARM_DESC(jumbo_mru, "enable fraglist support"); -- --static int num_rxq = 4; --module_param(num_rxq, int, 0); --MODULE_PARM_DESC(num_rxq, "change the number of rx queues"); -- --void edma_write_reg(u16 reg_addr, u32 reg_value) --{ -- writel(reg_value, ((void __iomem *)(edma_hw_addr + reg_addr))); --} -- --void edma_read_reg(u16 reg_addr, volatile u32 *reg_value) --{ -- *reg_value = readl((void __iomem *)(edma_hw_addr + reg_addr)); --} -- --static void ess_write_reg(struct edma_common_info *edma, u16 reg_addr, u32 reg_value) --{ -- writel(reg_value, ((void __iomem *) -- ((unsigned long)edma->ess_hw_addr + reg_addr))); --} -- --static void ess_read_reg(struct edma_common_info *edma, u16 reg_addr, -- volatile u32 *reg_value) --{ -- *reg_value = readl((void __iomem *) -- ((unsigned long)edma->ess_hw_addr + reg_addr)); --} -- --static int ess_reset(struct edma_common_info *edma) --{ -- struct device_node *switch_node = NULL; -- struct reset_control *ess_rst; -- u32 regval; -- -- switch_node = of_find_node_by_name(NULL, "ess-switch"); -- if (!switch_node) { -- pr_err("switch-node not found\n"); -- return -EINVAL; -- } -- -- ess_rst = of_reset_control_get(switch_node, "ess_rst"); -- of_node_put(switch_node); -- -- if (IS_ERR(ess_rst)) { -- pr_err("failed to find ess_rst!\n"); -- return -ENOENT; -- } -- -- reset_control_assert(ess_rst); -- msleep(10); -- reset_control_deassert(ess_rst); -- msleep(100); -- reset_control_put(ess_rst); -- -- /* Enable only port 5 <--> port 0 -- * bits 0:6 bitmap of ports it can fwd to */ --#define SET_PORT_BMP(r,v) \ -- ess_read_reg(edma, r, ®val); \ -- ess_write_reg(edma, r, ((regval & ~0x3F) | v)); -- -- SET_PORT_BMP(ESS_PORT0_LOOKUP_CTRL,0x20); -- SET_PORT_BMP(ESS_PORT1_LOOKUP_CTRL,0x00); -- SET_PORT_BMP(ESS_PORT2_LOOKUP_CTRL,0x00); -- SET_PORT_BMP(ESS_PORT3_LOOKUP_CTRL,0x00); -- SET_PORT_BMP(ESS_PORT4_LOOKUP_CTRL,0x00); -- SET_PORT_BMP(ESS_PORT5_LOOKUP_CTRL,0x01); -- ess_write_reg(edma, ESS_RGMII_CTRL, 0x400); -- ess_write_reg(edma, ESS_PORT0_STATUS, ESS_PORT_1G_FDX); -- ess_write_reg(edma, ESS_PORT5_STATUS, ESS_PORT_1G_FDX); -- ess_write_reg(edma, ESS_PORT0_HEADER_CTRL, 0); --#undef SET_PORT_BMP -- -- /* forward multicast and broadcast frames to CPU */ -- ess_write_reg(edma, ESS_FWD_CTRL1, -- (ESS_PORTS_ALL << ESS_FWD_CTRL1_UC_FLOOD_S) | -- (ESS_PORTS_ALL << ESS_FWD_CTRL1_MC_FLOOD_S) | -- (ESS_PORTS_ALL << ESS_FWD_CTRL1_BC_FLOOD_S)); -- -- return 0; --} -- --void ess_set_port_status_speed(struct edma_common_info *edma, -- struct phy_device *phydev, uint8_t port_id) --{ -- uint16_t reg_off = ESS_PORT0_STATUS + (4 * port_id); -- uint32_t reg_val = 0; -- -- ess_read_reg(edma, reg_off, ®_val); -- -- /* reset the speed bits [0:1] */ -- reg_val &= ~ESS_PORT_STATUS_SPEED_INV; -- -- /* set the new speed */ -- switch(phydev->speed) { -- case SPEED_1000: reg_val |= ESS_PORT_STATUS_SPEED_1000; break; -- case SPEED_100: reg_val |= ESS_PORT_STATUS_SPEED_100; break; -- case SPEED_10: reg_val |= ESS_PORT_STATUS_SPEED_10; break; -- default: reg_val |= ESS_PORT_STATUS_SPEED_INV; break; -- } -- -- /* check full/half duplex */ -- if (phydev->duplex) { -- reg_val |= ESS_PORT_STATUS_DUPLEX_MODE; -- } else { -- reg_val &= ~ESS_PORT_STATUS_DUPLEX_MODE; -- } -- -- ess_write_reg(edma, reg_off, reg_val); --} -- --/* edma_change_tx_coalesce() -- * change tx interrupt moderation timer -- */ --void edma_change_tx_coalesce(int usecs) --{ -- u32 reg_value; -- -- /* Here, we right shift the value from the user by 1, this is -- * done because IMT resolution timer is 2usecs. 1 count -- * of this register corresponds to 2 usecs. -- */ -- edma_read_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, ®_value); -- reg_value = ((reg_value & 0xffff) | ((usecs >> 1) << 16)); -- edma_write_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, reg_value); --} -- --/* edma_change_rx_coalesce() -- * change rx interrupt moderation timer -- */ --void edma_change_rx_coalesce(int usecs) --{ -- u32 reg_value; -- -- /* Here, we right shift the value from the user by 1, this is -- * done because IMT resolution timer is 2usecs. 1 count -- * of this register corresponds to 2 usecs. -- */ -- edma_read_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, ®_value); -- reg_value = ((reg_value & 0xffff0000) | (usecs >> 1)); -- edma_write_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, reg_value); --} -- --/* edma_get_tx_rx_coalesce() -- * Get tx/rx interrupt moderation value -- */ --void edma_get_tx_rx_coalesce(u32 *reg_val) --{ -- edma_read_reg(EDMA_REG_IRQ_MODRT_TIMER_INIT, reg_val); --} -- --void edma_read_append_stats(struct edma_common_info *edma_cinfo) --{ -- uint32_t *p; -- int i; -- u32 stat; -- -- spin_lock_bh(&edma_cinfo->stats_lock); -- p = (uint32_t *)&(edma_cinfo->edma_ethstats); -- -- for (i = 0; i < EDMA_MAX_TRANSMIT_QUEUE; i++) { -- edma_read_reg(EDMA_REG_TX_STAT_PKT_Q(i), &stat); -- *p += stat; -- p++; -- } -- -- for (i = 0; i < EDMA_MAX_TRANSMIT_QUEUE; i++) { -- edma_read_reg(EDMA_REG_TX_STAT_BYTE_Q(i), &stat); -- *p += stat; -- p++; -- } -- -- for (i = 0; i < EDMA_MAX_RECEIVE_QUEUE; i++) { -- edma_read_reg(EDMA_REG_RX_STAT_PKT_Q(i), &stat); -- *p += stat; -- p++; -- } -- -- for (i = 0; i < EDMA_MAX_RECEIVE_QUEUE; i++) { -- edma_read_reg(EDMA_REG_RX_STAT_BYTE_Q(i), &stat); -- *p += stat; -- p++; -- } -- -- spin_unlock_bh(&edma_cinfo->stats_lock); --} -- --static void edma_statistics_timer(struct timer_list *t) --{ -- struct edma_common_info *edma_cinfo = -- from_timer(edma_cinfo, t, edma_stats_timer); -- -- edma_read_append_stats(edma_cinfo); -- -- mod_timer(&edma_cinfo->edma_stats_timer, jiffies + 1*HZ); --} -- --static int edma_enable_stp_rstp(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- int ret; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- if (write) -- edma_set_stp_rstp(edma_enable_rstp); -- -- return ret; --} -- --static int edma_ath_hdr_eth_type(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- int ret; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- if (write) -- edma_assign_ath_hdr_type(edma_athr_hdr_eth_type); -- -- return ret; --} -- --static int edma_change_default_lan_vlan(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- struct edma_adapter *adapter; -- int ret; -- -- if (!edma_netdev[1]) { -- pr_err("Netdevice for default_lan does not exist\n"); -- return -1; -- } -- -- adapter = netdev_priv(edma_netdev[1]); -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- -- if (write) -- adapter->default_vlan_tag = edma_default_ltag; -- -- return ret; --} -- --static int edma_change_default_wan_vlan(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- struct edma_adapter *adapter; -- int ret; -- -- if (!edma_netdev[0]) { -- pr_err("Netdevice for default_wan does not exist\n"); -- return -1; -- } -- -- adapter = netdev_priv(edma_netdev[0]); -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- -- if (write) -- adapter->default_vlan_tag = edma_default_wtag; -- -- return ret; --} -- --static int edma_change_group1_vtag(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- struct edma_adapter *adapter; -- struct edma_common_info *edma_cinfo; -- int ret; -- -- if (!edma_netdev[0]) { -- pr_err("Netdevice for Group 1 does not exist\n"); -- return -1; -- } -- -- adapter = netdev_priv(edma_netdev[0]); -- edma_cinfo = adapter->edma_cinfo; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- -- if (write) -- adapter->default_vlan_tag = edma_default_group1_vtag; -- -- return ret; --} -- --static int edma_change_group2_vtag(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- struct edma_adapter *adapter; -- struct edma_common_info *edma_cinfo; -- int ret; -- -- if (!edma_netdev[1]) { -- pr_err("Netdevice for Group 2 does not exist\n"); -- return -1; -- } -- -- adapter = netdev_priv(edma_netdev[1]); -- edma_cinfo = adapter->edma_cinfo; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- -- if (write) -- adapter->default_vlan_tag = edma_default_group2_vtag; -- -- return ret; --} -- --static int edma_change_group3_vtag(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- struct edma_adapter *adapter; -- struct edma_common_info *edma_cinfo; -- int ret; -- -- if (!edma_netdev[2]) { -- pr_err("Netdevice for Group 3 does not exist\n"); -- return -1; -- } -- -- adapter = netdev_priv(edma_netdev[2]); -- edma_cinfo = adapter->edma_cinfo; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- -- if (write) -- adapter->default_vlan_tag = edma_default_group3_vtag; -- -- return ret; --} -- --static int edma_change_group4_vtag(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- struct edma_adapter *adapter; -- struct edma_common_info *edma_cinfo; -- int ret; -- -- if (!edma_netdev[3]) { -- pr_err("Netdevice for Group 4 does not exist\n"); -- return -1; -- } -- -- adapter = netdev_priv(edma_netdev[3]); -- edma_cinfo = adapter->edma_cinfo; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- -- if (write) -- adapter->default_vlan_tag = edma_default_group4_vtag; -- -- return ret; --} -- --static int edma_change_group5_vtag(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- struct edma_adapter *adapter; -- struct edma_common_info *edma_cinfo; -- int ret; -- -- if (!edma_netdev[4]) { -- pr_err("Netdevice for Group 5 does not exist\n"); -- return -1; -- } -- -- adapter = netdev_priv(edma_netdev[4]); -- edma_cinfo = adapter->edma_cinfo; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- -- if (write) -- adapter->default_vlan_tag = edma_default_group5_vtag; -- -- return ret; --} -- --static int edma_set_rss_idt_value(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- int ret; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- if (write && !ret) -- edma_write_reg(EDMA_REG_RSS_IDT(edma_rss_idt_idx), -- edma_rss_idt_val); -- return ret; --} -- --static int edma_set_rss_idt_idx(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- int ret; -- u32 old_value = edma_rss_idt_idx; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- if (!write || ret) -- return ret; -- -- if (edma_rss_idt_idx >= EDMA_NUM_IDT) { -- pr_err("Invalid RSS indirection table index %d\n", -- edma_rss_idt_idx); -- edma_rss_idt_idx = old_value; -- return -EINVAL; -- } -- return ret; --} -- --static int edma_weight_assigned_to_queues(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- int ret, queue_id, weight; -- u32 reg_data, data, reg_addr; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- if (write) { -- queue_id = edma_weight_assigned_to_q & EDMA_WRR_VID_SCTL_MASK; -- if (queue_id < 0 || queue_id > 15) { -- pr_err("queue_id not within desired range\n"); -- return -EINVAL; -- } -- -- weight = edma_weight_assigned_to_q >> EDMA_WRR_VID_SCTL_SHIFT; -- if (weight < 0 || weight > 0xF) { -- pr_err("queue_id not within desired range\n"); -- return -EINVAL; -- } -- -- data = weight << EDMA_WRR_SHIFT(queue_id); -- -- reg_addr = EDMA_REG_WRR_CTRL_Q0_Q3 + (queue_id & ~0x3); -- edma_read_reg(reg_addr, ®_data); -- reg_data &= ~(1 << EDMA_WRR_SHIFT(queue_id)); -- edma_write_reg(reg_addr, data | reg_data); -- } -- -- return ret; --} -- --static int edma_queue_to_virtual_queue_map(struct ctl_table *table, int write, -- void __user *buffer, size_t *lenp, -- loff_t *ppos) --{ -- int ret, queue_id, virtual_qid; -- u32 reg_data, data, reg_addr; -- -- ret = proc_dointvec(table, write, buffer, lenp, ppos); -- if (write) { -- queue_id = edma_queue_to_virtual_q & EDMA_WRR_VID_SCTL_MASK; -- if (queue_id < 0 || queue_id > 15) { -- pr_err("queue_id not within desired range\n"); -- return -EINVAL; -- } -- -- virtual_qid = edma_queue_to_virtual_q >> -- EDMA_WRR_VID_SCTL_SHIFT; -- if (virtual_qid < 0 || virtual_qid > 8) { -- pr_err("queue_id not within desired range\n"); -- return -EINVAL; -- } -- -- data = virtual_qid << EDMA_VQ_ID_SHIFT(queue_id); -- -- reg_addr = EDMA_REG_VQ_CTRL0 + (queue_id & ~0x3); -- edma_read_reg(reg_addr, ®_data); -- reg_data &= ~(1 << EDMA_VQ_ID_SHIFT(queue_id)); -- edma_write_reg(reg_addr, data | reg_data); -- } -- -- return ret; --} -- --static struct ctl_table edma_table[] = { -- { -- .procname = "default_lan_tag", -- .data = &edma_default_ltag, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_change_default_lan_vlan -- }, -- { -- .procname = "default_wan_tag", -- .data = &edma_default_wtag, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_change_default_wan_vlan -- }, -- { -- .procname = "weight_assigned_to_queues", -- .data = &edma_weight_assigned_to_q, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_weight_assigned_to_queues -- }, -- { -- .procname = "queue_to_virtual_queue_map", -- .data = &edma_queue_to_virtual_q, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_queue_to_virtual_queue_map -- }, -- { -- .procname = "enable_stp_rstp", -- .data = &edma_enable_rstp, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_enable_stp_rstp -- }, -- { -- .procname = "athr_hdr_eth_type", -- .data = &edma_athr_hdr_eth_type, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_ath_hdr_eth_type -- }, -- { -- .procname = "default_group1_vlan_tag", -- .data = &edma_default_group1_vtag, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_change_group1_vtag -- }, -- { -- .procname = "default_group2_vlan_tag", -- .data = &edma_default_group2_vtag, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_change_group2_vtag -- }, -- { -- .procname = "default_group3_vlan_tag", -- .data = &edma_default_group3_vtag, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_change_group3_vtag -- }, -- { -- .procname = "default_group4_vlan_tag", -- .data = &edma_default_group4_vtag, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_change_group4_vtag -- }, -- { -- .procname = "default_group5_vlan_tag", -- .data = &edma_default_group5_vtag, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_change_group5_vtag -- }, -- { -- .procname = "edma_rss_idt_value", -- .data = &edma_rss_idt_val, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_set_rss_idt_value -- }, -- { -- .procname = "edma_rss_idt_idx", -- .data = &edma_rss_idt_idx, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = edma_set_rss_idt_idx -- }, -- {} --}; -- --static int ess_parse(struct edma_common_info *edma) --{ -- struct device_node *switch_node; -- int ret = -EINVAL; -- -- switch_node = of_find_node_by_name(NULL, "ess-switch"); -- if (!switch_node) { -- pr_err("cannot find ess-switch node\n"); -- goto out; -- } -- -- edma->ess_hw_addr = of_io_request_and_map(switch_node, -- 0, KBUILD_MODNAME); -- if (!edma->ess_hw_addr) { -- pr_err("%s ioremap fail.", __func__); -- goto out; -- } -- -- edma->ess_clk = of_clk_get_by_name(switch_node, "ess_clk"); -- ret = clk_prepare_enable(edma->ess_clk); --out: -- of_node_put(switch_node); -- return ret; --} -- --/* edma_axi_netdev_ops -- * Describe the operations supported by registered netdevices -- * -- * static const struct net_device_ops edma_axi_netdev_ops = { -- * .ndo_open = edma_open, -- * .ndo_stop = edma_close, -- * .ndo_start_xmit = edma_xmit_frame, -- * .ndo_set_mac_address = edma_set_mac_addr, -- * } -- */ --static const struct net_device_ops edma_axi_netdev_ops = { -- .ndo_open = edma_open, -- .ndo_stop = edma_close, -- .ndo_start_xmit = edma_xmit, -- .ndo_set_mac_address = edma_set_mac_addr, --#ifdef CONFIG_RFS_ACCEL -- .ndo_rx_flow_steer = edma_rx_flow_steer, -- .ndo_register_rfs_filter = edma_register_rfs_filter, -- .ndo_get_default_vlan_tag = edma_get_default_vlan_tag, --#endif -- .ndo_get_stats = edma_get_stats, --}; -- --/* edma_axi_probe() -- * Initialise an adapter identified by a platform_device structure. -- * -- * The OS initialization, configuring of the adapter private structure, -- * and a hardware reset occur in the probe. -- */ --static int edma_axi_probe(struct platform_device *pdev) --{ -- struct edma_common_info *edma_cinfo; -- struct edma_hw *hw; -- struct edma_adapter *adapter[EDMA_MAX_PORTID_SUPPORTED]; -- struct resource *res; -- struct device_node *np = pdev->dev.of_node; -- struct device_node *pnp; -- struct device_node *mdio_node = NULL; -- struct mii_bus *miibus = NULL; -- int i, j, k, err = 0; -- int portid_bmp; -- int idx = 0, idx_mac = 0; -- -- if (CONFIG_NR_CPUS != EDMA_CPU_CORES_SUPPORTED) { -- dev_err(&pdev->dev, "Invalid CPU Cores\n"); -- return -EINVAL; -- } -- -- if ((num_rxq != 4) && (num_rxq != 8)) { -- dev_err(&pdev->dev, "Invalid RX queue, edma probe failed\n"); -- return -EINVAL; -- } -- edma_cinfo = kzalloc(sizeof(struct edma_common_info), GFP_KERNEL); -- if (!edma_cinfo) { -- err = -ENOMEM; -- goto err_alloc; -- } -- -- edma_cinfo->pdev = pdev; -- -- of_property_read_u32(np, "qcom,num_gmac", &edma_cinfo->num_gmac); -- if (edma_cinfo->num_gmac > EDMA_MAX_PORTID_SUPPORTED) { -- pr_err("Invalid DTSI Entry for qcom,num_gmac\n"); -- err = -EINVAL; -- goto err_cinfo; -- } -- -- /* Initialize the netdev array before allocation -- * to avoid double free -- */ -- for (i = 0 ; i < edma_cinfo->num_gmac ; i++) -- edma_netdev[i] = NULL; -- -- for (i = 0 ; i < edma_cinfo->num_gmac ; i++) { -- edma_netdev[i] = alloc_etherdev_mqs(sizeof(struct edma_adapter), -- EDMA_NETDEV_TX_QUEUE, EDMA_NETDEV_RX_QUEUE); -- -- if (!edma_netdev[i]) { -- dev_err(&pdev->dev, -- "net device alloc fails for index=%d\n", i); -- err = -ENODEV; -- goto err_ioremap; -- } -- -- SET_NETDEV_DEV(edma_netdev[i], &pdev->dev); -- platform_set_drvdata(pdev, edma_netdev[i]); -- edma_cinfo->netdev[i] = edma_netdev[i]; -- } -- -- /* Fill ring details */ -- edma_cinfo->num_tx_queues = EDMA_MAX_TRANSMIT_QUEUE; -- edma_cinfo->num_txq_per_core = (EDMA_MAX_TRANSMIT_QUEUE / 4); -- edma_cinfo->tx_ring_count = EDMA_TX_RING_SIZE; -- -- /* Update num rx queues based on module parameter */ -- edma_cinfo->num_rx_queues = num_rxq; -- edma_cinfo->num_rxq_per_core = ((num_rxq == 4) ? 1 : 2); -- -- edma_cinfo->rx_ring_count = EDMA_RX_RING_SIZE; -- -- hw = &edma_cinfo->hw; -- -- /* Fill HW defaults */ -- hw->tx_intr_mask = EDMA_TX_IMR_NORMAL_MASK; -- hw->rx_intr_mask = EDMA_RX_IMR_NORMAL_MASK; -- -- of_property_read_u32(np, "qcom,page-mode", &edma_cinfo->page_mode); -- of_property_read_u32(np, "qcom,rx_head_buf_size", -- &hw->rx_head_buff_size); -- -- if (overwrite_mode) { -- dev_info(&pdev->dev, "page mode overwritten"); -- edma_cinfo->page_mode = page_mode; -- } -- -- if (jumbo_mru) -- edma_cinfo->fraglist_mode = 1; -- -- if (edma_cinfo->page_mode) -- hw->rx_head_buff_size = EDMA_RX_HEAD_BUFF_SIZE_JUMBO; -- else if (edma_cinfo->fraglist_mode) -- hw->rx_head_buff_size = jumbo_mru; -- else if (!hw->rx_head_buff_size) -- hw->rx_head_buff_size = EDMA_RX_HEAD_BUFF_SIZE; -- -- hw->misc_intr_mask = 0; -- hw->wol_intr_mask = 0; -- -- hw->intr_clear_type = EDMA_INTR_CLEAR_TYPE; -- hw->intr_sw_idx_w = EDMA_INTR_SW_IDX_W_TYPE; -- -- /* configure RSS type to the different protocol that can be -- * supported -- */ -- hw->rss_type = EDMA_RSS_TYPE_IPV4TCP | EDMA_RSS_TYPE_IPV6_TCP | -- EDMA_RSS_TYPE_IPV4_UDP | EDMA_RSS_TYPE_IPV6UDP | -- EDMA_RSS_TYPE_IPV4 | EDMA_RSS_TYPE_IPV6; -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- -- edma_cinfo->hw.hw_addr = devm_ioremap_resource(&pdev->dev, res); -- if (IS_ERR(edma_cinfo->hw.hw_addr)) { -- err = PTR_ERR(edma_cinfo->hw.hw_addr); -- goto err_ioremap; -- } -- -- edma_hw_addr = (u32)edma_cinfo->hw.hw_addr; -- -- /* Parse tx queue interrupt number from device tree */ -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) -- edma_cinfo->tx_irq[i] = platform_get_irq(pdev, i); -- -- /* Parse rx queue interrupt number from device tree -- * Here we are setting j to point to the point where we -- * left tx interrupt parsing(i.e 16) and run run the loop -- * from 0 to 7 to parse rx interrupt number. -- */ -- for (i = 0, j = edma_cinfo->num_tx_queues, k = 0; -- i < edma_cinfo->num_rx_queues; i++) { -- edma_cinfo->rx_irq[k] = platform_get_irq(pdev, j); -- k += ((num_rxq == 4) ? 2 : 1); -- j += ((num_rxq == 4) ? 2 : 1); -- } -- -- edma_cinfo->rx_head_buffer_len = edma_cinfo->hw.rx_head_buff_size; -- edma_cinfo->rx_page_buffer_len = PAGE_SIZE; -- -- err = edma_alloc_queues_tx(edma_cinfo); -- if (err) { -- dev_err(&pdev->dev, "Allocation of TX queue failed\n"); -- goto err_tx_qinit; -- } -- -- err = edma_alloc_queues_rx(edma_cinfo); -- if (err) { -- dev_err(&pdev->dev, "Allocation of RX queue failed\n"); -- goto err_rx_qinit; -- } -- -- err = edma_alloc_tx_rings(edma_cinfo); -- if (err) { -- dev_err(&pdev->dev, "Allocation of TX resources failed\n"); -- goto err_tx_rinit; -- } -- -- err = edma_alloc_rx_rings(edma_cinfo); -- if (err) { -- dev_err(&pdev->dev, "Allocation of RX resources failed\n"); -- goto err_rx_rinit; -- } -- -- /* Initialize netdev and netdev bitmap for transmit descriptor rings */ -- for (i = 0; i < edma_cinfo->num_tx_queues; i++) { -- struct edma_tx_desc_ring *etdr = edma_cinfo->tpd_ring[i]; -- int j; -- -- etdr->netdev_bmp = 0; -- for (j = 0; j < EDMA_MAX_NETDEV_PER_QUEUE; j++) { -- etdr->netdev[j] = NULL; -- etdr->nq[j] = NULL; -- } -- } -- -- if (of_property_read_bool(np, "qcom,mdio_supported")) { -- mdio_node = of_find_compatible_node(NULL, NULL, -- "qcom,ipq4019-mdio"); -- if (!mdio_node) { -- dev_err(&pdev->dev, "cannot find mdio node by phandle"); -- err = -EIO; -- goto err_mdiobus_init_fail; -- } -- -- miibus = of_mdio_find_bus(mdio_node); -- if (!miibus) -- return -EINVAL; -- } -- -- if (of_property_read_bool(np, "qcom,single-phy") && -- edma_cinfo->num_gmac == 1) { -- err = ess_parse(edma_cinfo); -- if (!err) -- err = ess_reset(edma_cinfo); -- if (err) -- goto err_single_phy_init; -- else -- edma_cinfo->is_single_phy = true; -- } -- -- for_each_available_child_of_node(np, pnp) { -- /* this check is needed if parent and daughter dts have -- * different number of gmac nodes -- */ -- if (idx_mac == edma_cinfo->num_gmac) { -- of_node_put(np); -- break; -- } -- -- of_get_mac_address(pnp, edma_netdev[idx_mac]->dev_addr); -- -- idx_mac++; -- } -- -- /* Populate the adapter structure register the netdevice */ -- for (i = 0; i < edma_cinfo->num_gmac; i++) { -- int k, m; -- -- adapter[i] = netdev_priv(edma_netdev[i]); -- adapter[i]->netdev = edma_netdev[i]; -- adapter[i]->pdev = pdev; -- for (j = 0; j < CONFIG_NR_CPUS; j++) { -- m = i % 2; -- adapter[i]->tx_start_offset[j] = -- ((j << EDMA_TX_CPU_START_SHIFT) + (m << 1)); -- /* Share the queues with available net-devices. -- * For instance , with 5 net-devices -- * eth0/eth2/eth4 will share q0,q1,q4,q5,q8,q9,q12,q13 -- * and eth1/eth3 will get the remaining. -- */ -- for (k = adapter[i]->tx_start_offset[j]; k < -- (adapter[i]->tx_start_offset[j] + 2); k++) { -- if (edma_fill_netdev(edma_cinfo, k, i, j)) { -- pr_err("Netdev overflow Error\n"); -- goto err_register; -- } -- } -- } -- -- adapter[i]->edma_cinfo = edma_cinfo; -- edma_netdev[i]->netdev_ops = &edma_axi_netdev_ops; -- edma_netdev[i]->max_mtu = 9000; -- edma_netdev[i]->features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM -- | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_SG | -- NETIF_F_TSO | NETIF_F_GRO | NETIF_F_HW_VLAN_CTAG_TX; -- edma_netdev[i]->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | -- NETIF_F_HW_VLAN_CTAG_RX -- | NETIF_F_SG | NETIF_F_TSO | NETIF_F_GRO; -- edma_netdev[i]->vlan_features = NETIF_F_HW_CSUM | NETIF_F_SG | -- NETIF_F_TSO | NETIF_F_GRO; -- edma_netdev[i]->wanted_features = NETIF_F_HW_CSUM | NETIF_F_SG | -- NETIF_F_TSO | NETIF_F_GRO; -- --#ifdef CONFIG_RFS_ACCEL -- edma_netdev[i]->features |= NETIF_F_NTUPLE | NETIF_F_RXHASH; -- edma_netdev[i]->hw_features |= NETIF_F_NTUPLE | NETIF_F_RXHASH; -- edma_netdev[i]->vlan_features |= NETIF_F_NTUPLE | NETIF_F_RXHASH; -- edma_netdev[i]->wanted_features |= NETIF_F_NTUPLE | NETIF_F_RXHASH; --#endif -- edma_set_ethtool_ops(edma_netdev[i]); -- -- /* This just fill in some default MAC address -- */ -- if (!is_valid_ether_addr(edma_netdev[i]->dev_addr)) { -- random_ether_addr(edma_netdev[i]->dev_addr); -- pr_info("EDMA using MAC@ - using"); -- pr_info("%02x:%02x:%02x:%02x:%02x:%02x\n", -- *(edma_netdev[i]->dev_addr), -- *(edma_netdev[i]->dev_addr + 1), -- *(edma_netdev[i]->dev_addr + 2), -- *(edma_netdev[i]->dev_addr + 3), -- *(edma_netdev[i]->dev_addr + 4), -- *(edma_netdev[i]->dev_addr + 5)); -- } -- -- err = register_netdev(edma_netdev[i]); -- if (err) -- goto err_register; -- -- /* carrier off reporting is important to -- * ethtool even BEFORE open -- */ -- netif_carrier_off(edma_netdev[i]); -- -- /* Allocate reverse irq cpu mapping structure for -- * receive queues -- */ --#ifdef CONFIG_RFS_ACCEL -- edma_netdev[i]->rx_cpu_rmap = -- alloc_irq_cpu_rmap(EDMA_NETDEV_RX_QUEUE); -- if (!edma_netdev[i]->rx_cpu_rmap) { -- err = -ENOMEM; -- goto err_rmap_alloc_fail; -- } --#endif -- } -- -- for (i = 0; i < EDMA_MAX_PORTID_BITMAP_INDEX; i++) -- edma_cinfo->portid_netdev_lookup_tbl[i] = NULL; -- -- for_each_available_child_of_node(np, pnp) { -- const uint32_t *vlan_tag = NULL; -- int len; -- -- /* this check is needed if parent and daughter dts have -- * different number of gmac nodes -- */ -- if (idx == edma_cinfo->num_gmac) -- break; -- -- /* Populate port-id to netdev lookup table */ -- vlan_tag = of_get_property(pnp, "vlan_tag", &len); -- if (!vlan_tag) { -- pr_err("Vlan tag parsing Failed.\n"); -- goto err_rmap_alloc_fail; -- } -- -- adapter[idx]->default_vlan_tag = of_read_number(vlan_tag, 1); -- vlan_tag++; -- portid_bmp = of_read_number(vlan_tag, 1); -- adapter[idx]->dp_bitmap = portid_bmp; -- -- portid_bmp = portid_bmp >> 1; /* We ignore CPU Port bit 0 */ -- while (portid_bmp) { -- int port_bit = ffs(portid_bmp); -- -- if (port_bit > EDMA_MAX_PORTID_SUPPORTED) -- goto err_rmap_alloc_fail; -- edma_cinfo->portid_netdev_lookup_tbl[port_bit] = -- edma_netdev[idx]; -- portid_bmp &= ~(1 << (port_bit - 1)); -- } -- -- if (!of_property_read_u32(pnp, "qcom,poll_required", -- &adapter[idx]->poll_required)) { -- if (adapter[idx]->poll_required) { -- of_property_read_u32(pnp, "qcom,phy_mdio_addr", -- &adapter[idx]->phy_mdio_addr); -- of_property_read_u32(pnp, "qcom,forced_speed", -- &adapter[idx]->forced_speed); -- of_property_read_u32(pnp, "qcom,forced_duplex", -- &adapter[idx]->forced_duplex); -- -- /* create a phyid using MDIO bus id -- * and MDIO bus address -- */ -- snprintf(adapter[idx]->phy_id, -- MII_BUS_ID_SIZE + 3, PHY_ID_FMT, -- miibus->id, -- adapter[idx]->phy_mdio_addr); -- } -- } else { -- adapter[idx]->poll_required = 0; -- adapter[idx]->forced_speed = SPEED_1000; -- adapter[idx]->forced_duplex = DUPLEX_FULL; -- } -- -- idx++; -- } -- -- edma_cinfo->edma_ctl_table_hdr = register_net_sysctl(&init_net, -- "net/edma", -- edma_table); -- if (!edma_cinfo->edma_ctl_table_hdr) { -- dev_err(&pdev->dev, "edma sysctl table hdr not registered\n"); -- goto err_unregister_sysctl_tbl; -- } -- -- /* Disable all 16 Tx and 8 rx irqs */ -- edma_irq_disable(edma_cinfo); -- -- err = edma_reset(edma_cinfo); -- if (err) { -- err = -EIO; -- goto err_reset; -- } -- -- /* populate per_core_info, do a napi_Add, request 16 TX irqs, -- * 8 RX irqs, do a napi enable -- */ -- for (i = 0; i < CONFIG_NR_CPUS; i++) { -- u8 rx_start; -- -- edma_cinfo->edma_percpu_info[i].napi.state = 0; -- -- netif_napi_add(edma_netdev[0], -- &edma_cinfo->edma_percpu_info[i].napi, -- edma_poll, 64); -- napi_enable(&edma_cinfo->edma_percpu_info[i].napi); -- edma_cinfo->edma_percpu_info[i].tx_mask = tx_mask[i]; -- edma_cinfo->edma_percpu_info[i].rx_mask = EDMA_RX_PER_CPU_MASK -- << (i << EDMA_RX_PER_CPU_MASK_SHIFT); -- edma_cinfo->edma_percpu_info[i].tx_start = tx_start[i]; -- edma_cinfo->edma_percpu_info[i].rx_start = -- i << EDMA_RX_CPU_START_SHIFT; -- rx_start = i << EDMA_RX_CPU_START_SHIFT; -- edma_cinfo->edma_percpu_info[i].tx_status = 0; -- edma_cinfo->edma_percpu_info[i].rx_status = 0; -- edma_cinfo->edma_percpu_info[i].edma_cinfo = edma_cinfo; -- -- /* Request irq per core */ -- for (j = edma_cinfo->edma_percpu_info[i].tx_start; -- j < tx_start[i] + 4; j++) { -- sprintf(&edma_tx_irq[j][0], "edma_eth_tx%d", j); -- err = request_irq(edma_cinfo->tx_irq[j], -- edma_interrupt, -- 0, -- &edma_tx_irq[j][0], -- &edma_cinfo->edma_percpu_info[i]); -- if (err) -- goto err_reset; -- } -- -- for (j = edma_cinfo->edma_percpu_info[i].rx_start; -- j < (rx_start + -- ((edma_cinfo->num_rx_queues == 4) ? 1 : 2)); -- j++) { -- sprintf(&edma_rx_irq[j][0], "edma_eth_rx%d", j); -- err = request_irq(edma_cinfo->rx_irq[j], -- edma_interrupt, -- 0, -- &edma_rx_irq[j][0], -- &edma_cinfo->edma_percpu_info[i]); -- if (err) -- goto err_reset; -- } -- --#ifdef CONFIG_RFS_ACCEL -- for (j = edma_cinfo->edma_percpu_info[i].rx_start; -- j < rx_start + 2; j += 2) { -- err = irq_cpu_rmap_add(edma_netdev[0]->rx_cpu_rmap, -- edma_cinfo->rx_irq[j]); -- if (err) -- goto err_rmap_add_fail; -- } --#endif -- } -- -- /* Used to clear interrupt status, allocate rx buffer, -- * configure edma descriptors registers -- */ -- err = edma_configure(edma_cinfo); -- if (err) { -- err = -EIO; -- goto err_configure; -- } -- -- /* Configure RSS indirection table. -- * 128 hash will be configured in the following -- * pattern: hash{0,1,2,3} = {Q0,Q2,Q4,Q6} respectively -- * and so on -- */ -- for (i = 0; i < EDMA_NUM_IDT; i++) -- edma_write_reg(EDMA_REG_RSS_IDT(i), EDMA_RSS_IDT_VALUE); -- -- /* Configure load balance mapping table. -- * 4 table entry will be configured according to the -- * following pattern: load_balance{0,1,2,3} = {Q0,Q1,Q3,Q4} -- * respectively. -- */ -- edma_write_reg(EDMA_REG_LB_RING, EDMA_LB_REG_VALUE); -- -- /* Configure Virtual queue for Tx rings -- * User can also change this value runtime through -- * a sysctl -- */ -- edma_write_reg(EDMA_REG_VQ_CTRL0, EDMA_VQ_REG_VALUE); -- edma_write_reg(EDMA_REG_VQ_CTRL1, EDMA_VQ_REG_VALUE); -- -- /* Configure Max AXI Burst write size to 128 bytes*/ -- edma_write_reg(EDMA_REG_AXIW_CTRL_MAXWRSIZE, -- EDMA_AXIW_MAXWRSIZE_VALUE); -- -- /* Enable All 16 tx and 8 rx irq mask */ -- edma_irq_enable(edma_cinfo); -- edma_enable_tx_ctrl(&edma_cinfo->hw); -- edma_enable_rx_ctrl(&edma_cinfo->hw); -- -- for (i = 0; i < edma_cinfo->num_gmac; i++) { -- if (adapter[i]->poll_required) { --#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) -- phy_interface_t phy_mode; -- -- err = of_get_phy_mode(np, &phy_mode); -- if (err) -- phy_mode = PHY_INTERFACE_MODE_SGMII; --#else -- int phy_mode = of_get_phy_mode(np); -- if (phy_mode < 0) -- phy_mode = PHY_INTERFACE_MODE_SGMII; --#endif -- adapter[i]->phydev = -- phy_connect(edma_netdev[i], -- (const char *)adapter[i]->phy_id, -- &edma_adjust_link, -- phy_mode); -- if (IS_ERR(adapter[i]->phydev)) { -- dev_dbg(&pdev->dev, "PHY attach FAIL"); -- err = -EIO; -- goto edma_phy_attach_fail; -- } else { -- linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, -- adapter[i]->phydev->advertising); -- linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, -- adapter[i]->phydev->advertising); -- linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, -- adapter[i]->phydev->supported); -- linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, -- adapter[i]->phydev->supported); -- } -- } else { -- adapter[i]->phydev = NULL; -- } -- } -- -- spin_lock_init(&edma_cinfo->stats_lock); -- -- timer_setup(&edma_cinfo->edma_stats_timer, edma_statistics_timer, 0); -- mod_timer(&edma_cinfo->edma_stats_timer, jiffies + 1*HZ); -- -- return 0; -- --edma_phy_attach_fail: -- miibus = NULL; --err_configure: --#ifdef CONFIG_RFS_ACCEL -- for (i = 0; i < edma_cinfo->num_gmac; i++) { -- free_irq_cpu_rmap(adapter[i]->netdev->rx_cpu_rmap); -- adapter[i]->netdev->rx_cpu_rmap = NULL; -- } --#endif --err_rmap_add_fail: -- edma_free_irqs(adapter[0]); -- for (i = 0; i < CONFIG_NR_CPUS; i++) -- napi_disable(&edma_cinfo->edma_percpu_info[i].napi); --err_reset: --err_unregister_sysctl_tbl: --err_rmap_alloc_fail: -- for (i = 0; i < edma_cinfo->num_gmac; i++) -- unregister_netdev(edma_netdev[i]); --err_register: --err_single_phy_init: -- iounmap(edma_cinfo->ess_hw_addr); -- clk_disable_unprepare(edma_cinfo->ess_clk); --err_mdiobus_init_fail: -- edma_free_rx_rings(edma_cinfo); --err_rx_rinit: -- edma_free_tx_rings(edma_cinfo); --err_tx_rinit: -- edma_free_queues(edma_cinfo); --err_rx_qinit: --err_tx_qinit: -- iounmap(edma_cinfo->hw.hw_addr); --err_ioremap: -- for (i = 0; i < edma_cinfo->num_gmac; i++) { -- if (edma_netdev[i]) -- free_netdev(edma_netdev[i]); -- } --err_cinfo: -- kfree(edma_cinfo); --err_alloc: -- return err; --} -- --/* edma_axi_remove() -- * Device Removal Routine -- * -- * edma_axi_remove is called by the platform subsystem to alert the driver -- * that it should release a platform device. -- */ --static int edma_axi_remove(struct platform_device *pdev) --{ -- struct edma_adapter *adapter = netdev_priv(edma_netdev[0]); -- struct edma_common_info *edma_cinfo = adapter->edma_cinfo; -- struct edma_hw *hw = &edma_cinfo->hw; -- int i; -- -- for (i = 0; i < edma_cinfo->num_gmac; i++) -- unregister_netdev(edma_netdev[i]); -- -- edma_stop_rx_tx(hw); -- for (i = 0; i < CONFIG_NR_CPUS; i++) -- napi_disable(&edma_cinfo->edma_percpu_info[i].napi); -- -- edma_irq_disable(edma_cinfo); -- edma_write_reg(EDMA_REG_RX_ISR, 0xff); -- edma_write_reg(EDMA_REG_TX_ISR, 0xffff); --#ifdef CONFIG_RFS_ACCEL -- for (i = 0; i < edma_cinfo->num_gmac; i++) { -- free_irq_cpu_rmap(edma_netdev[i]->rx_cpu_rmap); -- edma_netdev[i]->rx_cpu_rmap = NULL; -- } --#endif -- -- for (i = 0; i < edma_cinfo->num_gmac; i++) { -- struct edma_adapter *adapter = netdev_priv(edma_netdev[i]); -- -- if (adapter->phydev) -- phy_disconnect(adapter->phydev); -- } -- -- del_timer_sync(&edma_cinfo->edma_stats_timer); -- edma_free_irqs(adapter); -- unregister_net_sysctl_table(edma_cinfo->edma_ctl_table_hdr); -- iounmap(edma_cinfo->ess_hw_addr); -- clk_disable_unprepare(edma_cinfo->ess_clk); -- edma_free_tx_resources(edma_cinfo); -- edma_free_rx_resources(edma_cinfo); -- edma_free_tx_rings(edma_cinfo); -- edma_free_rx_rings(edma_cinfo); -- edma_free_queues(edma_cinfo); -- for (i = 0; i < edma_cinfo->num_gmac; i++) -- free_netdev(edma_netdev[i]); -- -- kfree(edma_cinfo); -- -- return 0; --} -- --static const struct of_device_id edma_of_mtable[] = { -- {.compatible = "qcom,ess-edma" }, -- {} --}; --MODULE_DEVICE_TABLE(of, edma_of_mtable); -- --static struct platform_driver edma_axi_driver = { -- .driver = { -- .name = edma_axi_driver_name, -- .of_match_table = edma_of_mtable, -- }, -- .probe = edma_axi_probe, -- .remove = edma_axi_remove, --}; -- --module_platform_driver(edma_axi_driver); -- --MODULE_AUTHOR("Qualcomm Atheros Inc"); --MODULE_DESCRIPTION("QCA ESS EDMA driver"); --MODULE_LICENSE("GPL"); ---- a/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/essedma/ess_edma.h -+++ /dev/null -@@ -1,389 +0,0 @@ --/* -- * Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved. -- * -- * Permission to use, copy, modify, and/or distribute this software for -- * any purpose with or without fee is hereby granted, provided that the -- * above copyright notice and this permission notice appear in all copies. -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- */ -- --#ifndef _ESS_EDMA_H_ --#define _ESS_EDMA_H_ -- --#include -- --struct edma_adapter; --struct edma_hw; -- --/* register definition */ --#define EDMA_REG_MAS_CTRL 0x0 --#define EDMA_REG_TIMEOUT_CTRL 0x004 --#define EDMA_REG_DBG0 0x008 --#define EDMA_REG_DBG1 0x00C --#define EDMA_REG_SW_CTRL0 0x100 --#define EDMA_REG_SW_CTRL1 0x104 -- --/* Interrupt Status Register */ --#define EDMA_REG_RX_ISR 0x200 --#define EDMA_REG_TX_ISR 0x208 --#define EDMA_REG_MISC_ISR 0x210 --#define EDMA_REG_WOL_ISR 0x218 -- --#define EDMA_MISC_ISR_RX_URG_Q(x) (1 << x) -- --#define EDMA_MISC_ISR_AXIR_TIMEOUT 0x00000100 --#define EDMA_MISC_ISR_AXIR_ERR 0x00000200 --#define EDMA_MISC_ISR_TXF_DEAD 0x00000400 --#define EDMA_MISC_ISR_AXIW_ERR 0x00000800 --#define EDMA_MISC_ISR_AXIW_TIMEOUT 0x00001000 -- --#define EDMA_WOL_ISR 0x00000001 -- --/* Interrupt Mask Register */ --#define EDMA_REG_MISC_IMR 0x214 --#define EDMA_REG_WOL_IMR 0x218 -- --#define EDMA_RX_IMR_NORMAL_MASK 0x1 --#define EDMA_TX_IMR_NORMAL_MASK 0x1 --#define EDMA_MISC_IMR_NORMAL_MASK 0x80001FFF --#define EDMA_WOL_IMR_NORMAL_MASK 0x1 -- --/* Edma receive consumer index */ --#define EDMA_REG_RX_SW_CONS_IDX_Q(x) (0x220 + ((x) << 2)) /* x is the queue id */ --/* Edma transmit consumer index */ --#define EDMA_REG_TX_SW_CONS_IDX_Q(x) (0x240 + ((x) << 2)) /* x is the queue id */ -- --/* IRQ Moderator Initial Timer Register */ --#define EDMA_REG_IRQ_MODRT_TIMER_INIT 0x280 --#define EDMA_IRQ_MODRT_TIMER_MASK 0xFFFF --#define EDMA_IRQ_MODRT_RX_TIMER_SHIFT 0 --#define EDMA_IRQ_MODRT_TX_TIMER_SHIFT 16 -- --/* Interrupt Control Register */ --#define EDMA_REG_INTR_CTRL 0x284 --#define EDMA_INTR_CLR_TYP_SHIFT 0 --#define EDMA_INTR_SW_IDX_W_TYP_SHIFT 1 --#define EDMA_INTR_CLEAR_TYPE_W1 0 --#define EDMA_INTR_CLEAR_TYPE_R 1 -- --/* RX Interrupt Mask Register */ --#define EDMA_REG_RX_INT_MASK_Q(x) (0x300 + ((x) << 2)) /* x = queue id */ -- --/* TX Interrupt mask register */ --#define EDMA_REG_TX_INT_MASK_Q(x) (0x340 + ((x) << 2)) /* x = queue id */ -- --/* Load Ptr Register -- * Software sets this bit after the initialization of the head and tail -- */ --#define EDMA_REG_TX_SRAM_PART 0x400 --#define EDMA_LOAD_PTR_SHIFT 16 -- --/* TXQ Control Register */ --#define EDMA_REG_TXQ_CTRL 0x404 --#define EDMA_TXQ_CTRL_IP_OPTION_EN 0x10 --#define EDMA_TXQ_CTRL_TXQ_EN 0x20 --#define EDMA_TXQ_CTRL_ENH_MODE 0x40 --#define EDMA_TXQ_CTRL_LS_8023_EN 0x80 --#define EDMA_TXQ_CTRL_TPD_BURST_EN 0x100 --#define EDMA_TXQ_CTRL_LSO_BREAK_EN 0x200 --#define EDMA_TXQ_NUM_TPD_BURST_MASK 0xF --#define EDMA_TXQ_TXF_BURST_NUM_MASK 0xFFFF --#define EDMA_TXQ_NUM_TPD_BURST_SHIFT 0 --#define EDMA_TXQ_TXF_BURST_NUM_SHIFT 16 -- --#define EDMA_REG_TXF_WATER_MARK 0x408 /* In 8-bytes */ --#define EDMA_TXF_WATER_MARK_MASK 0x0FFF --#define EDMA_TXF_LOW_WATER_MARK_SHIFT 0 --#define EDMA_TXF_HIGH_WATER_MARK_SHIFT 16 --#define EDMA_TXQ_CTRL_BURST_MODE_EN 0x80000000 -- --/* WRR Control Register */ --#define EDMA_REG_WRR_CTRL_Q0_Q3 0x40c --#define EDMA_REG_WRR_CTRL_Q4_Q7 0x410 --#define EDMA_REG_WRR_CTRL_Q8_Q11 0x414 --#define EDMA_REG_WRR_CTRL_Q12_Q15 0x418 -- --/* Weight round robin(WRR), it takes queue as input, and computes -- * starting bits where we need to write the weight for a particular -- * queue -- */ --#define EDMA_WRR_SHIFT(x) (((x) * 5) % 20) -- --/* Tx Descriptor Control Register */ --#define EDMA_REG_TPD_RING_SIZE 0x41C --#define EDMA_TPD_RING_SIZE_SHIFT 0 --#define EDMA_TPD_RING_SIZE_MASK 0xFFFF -- --/* Transmit descriptor base address */ --#define EDMA_REG_TPD_BASE_ADDR_Q(x) (0x420 + ((x) << 2)) /* x = queue id */ -- --/* TPD Index Register */ --#define EDMA_REG_TPD_IDX_Q(x) (0x460 + ((x) << 2)) /* x = queue id */ -- --#define EDMA_TPD_PROD_IDX_BITS 0x0000FFFF --#define EDMA_TPD_CONS_IDX_BITS 0xFFFF0000 --#define EDMA_TPD_PROD_IDX_MASK 0xFFFF --#define EDMA_TPD_CONS_IDX_MASK 0xFFFF --#define EDMA_TPD_PROD_IDX_SHIFT 0 --#define EDMA_TPD_CONS_IDX_SHIFT 16 -- --/* TX Virtual Queue Mapping Control Register */ --#define EDMA_REG_VQ_CTRL0 0x4A0 --#define EDMA_REG_VQ_CTRL1 0x4A4 -- --/* Virtual QID shift, it takes queue as input, and computes -- * Virtual QID position in virtual qid control register -- */ --#define EDMA_VQ_ID_SHIFT(i) (((i) * 3) % 24) -- --/* Virtual Queue Default Value */ --#define EDMA_VQ_REG_VALUE 0x240240 -- --/* Tx side Port Interface Control Register */ --#define EDMA_REG_PORT_CTRL 0x4A8 --#define EDMA_PAD_EN_SHIFT 15 -- --/* Tx side VLAN Configuration Register */ --#define EDMA_REG_VLAN_CFG 0x4AC -- --#define EDMA_TX_CVLAN 16 --#define EDMA_TX_INS_CVLAN 17 --#define EDMA_TX_CVLAN_TAG_SHIFT 0 -- --#define EDMA_TX_SVLAN 14 --#define EDMA_TX_INS_SVLAN 15 --#define EDMA_TX_SVLAN_TAG_SHIFT 16 -- --/* Tx Queue Packet Statistic Register */ --#define EDMA_REG_TX_STAT_PKT_Q(x) (0x700 + ((x) << 3)) /* x = queue id */ -- --#define EDMA_TX_STAT_PKT_MASK 0xFFFFFF -- --/* Tx Queue Byte Statistic Register */ --#define EDMA_REG_TX_STAT_BYTE_Q(x) (0x704 + ((x) << 3)) /* x = queue id */ -- --/* Load Balance Based Ring Offset Register */ --#define EDMA_REG_LB_RING 0x800 --#define EDMA_LB_RING_ENTRY_MASK 0xff --#define EDMA_LB_RING_ID_MASK 0x7 --#define EDMA_LB_RING_PROFILE_ID_MASK 0x3 --#define EDMA_LB_RING_ENTRY_BIT_OFFSET 8 --#define EDMA_LB_RING_ID_OFFSET 0 --#define EDMA_LB_RING_PROFILE_ID_OFFSET 3 --#define EDMA_LB_REG_VALUE 0x6040200 -- --/* Load Balance Priority Mapping Register */ --#define EDMA_REG_LB_PRI_START 0x804 --#define EDMA_REG_LB_PRI_END 0x810 --#define EDMA_LB_PRI_REG_INC 4 --#define EDMA_LB_PRI_ENTRY_BIT_OFFSET 4 --#define EDMA_LB_PRI_ENTRY_MASK 0xf -- --/* RSS Priority Mapping Register */ --#define EDMA_REG_RSS_PRI 0x820 --#define EDMA_RSS_PRI_ENTRY_MASK 0xf --#define EDMA_RSS_RING_ID_MASK 0x7 --#define EDMA_RSS_PRI_ENTRY_BIT_OFFSET 4 -- --/* RSS Indirection Register */ --#define EDMA_REG_RSS_IDT(x) (0x840 + ((x) << 2)) /* x = No. of indirection table */ --#define EDMA_NUM_IDT 16 --#define EDMA_RSS_IDT_VALUE 0x64206420 -- --/* Default RSS Ring Register */ --#define EDMA_REG_DEF_RSS 0x890 --#define EDMA_DEF_RSS_MASK 0x7 -- --/* RSS Hash Function Type Register */ --#define EDMA_REG_RSS_TYPE 0x894 --#define EDMA_RSS_TYPE_NONE 0x01 --#define EDMA_RSS_TYPE_IPV4TCP 0x02 --#define EDMA_RSS_TYPE_IPV6_TCP 0x04 --#define EDMA_RSS_TYPE_IPV4_UDP 0x08 --#define EDMA_RSS_TYPE_IPV6UDP 0x10 --#define EDMA_RSS_TYPE_IPV4 0x20 --#define EDMA_RSS_TYPE_IPV6 0x40 --#define EDMA_RSS_HASH_MODE_MASK 0x7f -- --#define EDMA_REG_RSS_HASH_VALUE 0x8C0 -- --#define EDMA_REG_RSS_TYPE_RESULT 0x8C4 -- --#define EDMA_HASH_TYPE_START 0 --#define EDMA_HASH_TYPE_END 5 --#define EDMA_HASH_TYPE_SHIFT 12 -- --#define EDMA_RFS_FLOW_ENTRIES 1024 --#define EDMA_RFS_FLOW_ENTRIES_MASK (EDMA_RFS_FLOW_ENTRIES - 1) --#define EDMA_RFS_EXPIRE_COUNT_PER_CALL 128 -- --/* RFD Base Address Register */ --#define EDMA_REG_RFD_BASE_ADDR_Q(x) (0x950 + ((x) << 2)) /* x = queue id */ -- --/* RFD Index Register */ --#define EDMA_REG_RFD_IDX_Q(x) (0x9B0 + ((x) << 2)) -- --#define EDMA_RFD_PROD_IDX_BITS 0x00000FFF --#define EDMA_RFD_CONS_IDX_BITS 0x0FFF0000 --#define EDMA_RFD_PROD_IDX_MASK 0xFFF --#define EDMA_RFD_CONS_IDX_MASK 0xFFF --#define EDMA_RFD_PROD_IDX_SHIFT 0 --#define EDMA_RFD_CONS_IDX_SHIFT 16 -- --/* Rx Descriptor Control Register */ --#define EDMA_REG_RX_DESC0 0xA10 --#define EDMA_RFD_RING_SIZE_MASK 0xFFF --#define EDMA_RX_BUF_SIZE_MASK 0xFFFF --#define EDMA_RFD_RING_SIZE_SHIFT 0 --#define EDMA_RX_BUF_SIZE_SHIFT 16 -- --#define EDMA_REG_RX_DESC1 0xA14 --#define EDMA_RXQ_RFD_BURST_NUM_MASK 0x3F --#define EDMA_RXQ_RFD_PF_THRESH_MASK 0x1F --#define EDMA_RXQ_RFD_LOW_THRESH_MASK 0xFFF --#define EDMA_RXQ_RFD_BURST_NUM_SHIFT 0 --#define EDMA_RXQ_RFD_PF_THRESH_SHIFT 8 --#define EDMA_RXQ_RFD_LOW_THRESH_SHIFT 16 -- --/* RXQ Control Register */ --#define EDMA_REG_RXQ_CTRL 0xA18 --#define EDMA_FIFO_THRESH_TYPE_SHIF 0 --#define EDMA_FIFO_THRESH_128_BYTE 0x0 --#define EDMA_FIFO_THRESH_64_BYTE 0x1 --#define EDMA_RXQ_CTRL_RMV_VLAN 0x00000002 --#define EDMA_RXQ_CTRL_EN 0x0000FF00 -- --/* AXI Burst Size Config */ --#define EDMA_REG_AXIW_CTRL_MAXWRSIZE 0xA1C --#define EDMA_AXIW_MAXWRSIZE_VALUE 0x0 -- --/* Rx Statistics Register */ --#define EDMA_REG_RX_STAT_BYTE_Q(x) (0xA30 + ((x) << 2)) /* x = queue id */ --#define EDMA_REG_RX_STAT_PKT_Q(x) (0xA50 + ((x) << 2)) /* x = queue id */ -- --/* WoL Pattern Length Register */ --#define EDMA_REG_WOL_PATTERN_LEN0 0xC00 --#define EDMA_WOL_PT_LEN_MASK 0xFF --#define EDMA_WOL_PT0_LEN_SHIFT 0 --#define EDMA_WOL_PT1_LEN_SHIFT 8 --#define EDMA_WOL_PT2_LEN_SHIFT 16 --#define EDMA_WOL_PT3_LEN_SHIFT 24 -- --#define EDMA_REG_WOL_PATTERN_LEN1 0xC04 --#define EDMA_WOL_PT4_LEN_SHIFT 0 --#define EDMA_WOL_PT5_LEN_SHIFT 8 --#define EDMA_WOL_PT6_LEN_SHIFT 16 -- --/* WoL Control Register */ --#define EDMA_REG_WOL_CTRL 0xC08 --#define EDMA_WOL_WK_EN 0x00000001 --#define EDMA_WOL_MG_EN 0x00000002 --#define EDMA_WOL_PT0_EN 0x00000004 --#define EDMA_WOL_PT1_EN 0x00000008 --#define EDMA_WOL_PT2_EN 0x00000010 --#define EDMA_WOL_PT3_EN 0x00000020 --#define EDMA_WOL_PT4_EN 0x00000040 --#define EDMA_WOL_PT5_EN 0x00000080 --#define EDMA_WOL_PT6_EN 0x00000100 -- --/* MAC Control Register */ --#define EDMA_REG_MAC_CTRL0 0xC20 --#define EDMA_REG_MAC_CTRL1 0xC24 -- --/* WoL Pattern Register */ --#define EDMA_REG_WOL_PATTERN_START 0x5000 --#define EDMA_PATTERN_PART_REG_OFFSET 0x40 -- -- --/* TX descriptor fields */ --#define EDMA_TPD_HDR_SHIFT 0 --#define EDMA_TPD_PPPOE_EN 0x00000100 --#define EDMA_TPD_IP_CSUM_EN 0x00000200 --#define EDMA_TPD_TCP_CSUM_EN 0x0000400 --#define EDMA_TPD_UDP_CSUM_EN 0x00000800 --#define EDMA_TPD_CUSTOM_CSUM_EN 0x00000C00 --#define EDMA_TPD_LSO_EN 0x00001000 --#define EDMA_TPD_LSO_V2_EN 0x00002000 --#define EDMA_TPD_IPV4_EN 0x00010000 --#define EDMA_TPD_MSS_MASK 0x1FFF --#define EDMA_TPD_MSS_SHIFT 18 --#define EDMA_TPD_CUSTOM_CSUM_SHIFT 18 -- --/* RRD descriptor fields */ --#define EDMA_RRD_NUM_RFD_MASK 0x000F --#define EDMA_RRD_SVLAN 0x8000 --#define EDMA_RRD_FLOW_COOKIE_MASK 0x07FF; -- --#define EDMA_RRD_PKT_SIZE_MASK 0x3FFF --#define EDMA_RRD_CSUM_FAIL_MASK 0xC000 --#define EDMA_RRD_CVLAN 0x0001 --#define EDMA_RRD_DESC_VALID 0x8000 -- --#define EDMA_RRD_PRIORITY_SHIFT 4 --#define EDMA_RRD_PRIORITY_MASK 0x7 --#define EDMA_RRD_PORT_TYPE_SHIFT 7 --#define EDMA_RRD_PORT_TYPE_MASK 0x1F -- --#define ESS_RGMII_CTRL 0x0004 -- --/* Port status registers */ --#define ESS_PORT0_STATUS 0x007C --#define ESS_PORT1_STATUS 0x0080 --#define ESS_PORT2_STATUS 0x0084 --#define ESS_PORT3_STATUS 0x0088 --#define ESS_PORT4_STATUS 0x008C --#define ESS_PORT5_STATUS 0x0090 -- --#define ESS_PORT_STATUS_HDX_FLOW_CTL 0x80 --#define ESS_PORT_STATUS_DUPLEX_MODE 0x40 --#define ESS_PORT_STATUS_RX_FLOW_EN 0x20 --#define ESS_PORT_STATUS_TX_FLOW_EN 0x10 --#define ESS_PORT_STATUS_RX_MAC_EN 0x08 --#define ESS_PORT_STATUS_TX_MAC_EN 0x04 --#define ESS_PORT_STATUS_SPEED_INV 0x03 --#define ESS_PORT_STATUS_SPEED_1000 0x02 --#define ESS_PORT_STATUS_SPEED_100 0x01 --#define ESS_PORT_STATUS_SPEED_10 0x00 -- --#define ESS_PORT_1G_FDX (ESS_PORT_STATUS_DUPLEX_MODE | ESS_PORT_STATUS_RX_FLOW_EN | \ -- ESS_PORT_STATUS_TX_FLOW_EN | ESS_PORT_STATUS_RX_MAC_EN | \ -- ESS_PORT_STATUS_TX_MAC_EN | ESS_PORT_STATUS_SPEED_1000) -- --#define PHY_STATUS_REG 0x11 --#define PHY_STATUS_SPEED 0xC000 --#define PHY_STATUS_SPEED_SHIFT 14 --#define PHY_STATUS_DUPLEX 0x2000 --#define PHY_STATUS_DUPLEX_SHIFT 13 --#define PHY_STATUS_SPEED_DUPLEX_RESOLVED 0x0800 --#define PHY_STATUS_CARRIER 0x0400 --#define PHY_STATUS_CARRIER_SHIFT 10 -- --/* Port lookup control registers */ --#define ESS_PORT0_LOOKUP_CTRL 0x0660 --#define ESS_PORT1_LOOKUP_CTRL 0x066C --#define ESS_PORT2_LOOKUP_CTRL 0x0678 --#define ESS_PORT3_LOOKUP_CTRL 0x0684 --#define ESS_PORT4_LOOKUP_CTRL 0x0690 --#define ESS_PORT5_LOOKUP_CTRL 0x069C -- --#define ESS_PORT0_HEADER_CTRL 0x009C -- --#define ESS_PORTS_ALL 0x3f -- --#define ESS_FWD_CTRL1 0x0624 --#define ESS_FWD_CTRL1_UC_FLOOD BITS(0, 7) --#define ESS_FWD_CTRL1_UC_FLOOD_S 0 --#define ESS_FWD_CTRL1_MC_FLOOD BITS(8, 7) --#define ESS_FWD_CTRL1_MC_FLOOD_S 8 --#define ESS_FWD_CTRL1_BC_FLOOD BITS(16, 7) --#define ESS_FWD_CTRL1_BC_FLOOD_S 16 --#define ESS_FWD_CTRL1_IGMP BITS(24, 7) --#define ESS_FWD_CTRL1_IGMP_S 24 -- --#endif /* _ESS_EDMA_H_ */ ---- a/target/linux/ipq40xx/files-5.10/drivers/net/mdio/ar40xx.c -+++ /dev/null -@@ -1,1893 +0,0 @@ --/* -- * Copyright (c) 2016, The Linux Foundation. All rights reserved. -- * -- * Permission to use, copy, modify, and/or distribute this software for -- * any purpose with or without fee is hereby granted, provided that the -- * above copyright notice and this permission notice appear in all copies. -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include "ar40xx.h" -- --static struct ar40xx_priv *ar40xx_priv; -- --#define MIB_DESC(_s , _o, _n) \ -- { \ -- .size = (_s), \ -- .offset = (_o), \ -- .name = (_n), \ -- } -- --static const struct ar40xx_mib_desc ar40xx_mibs[] = { -- MIB_DESC(1, AR40XX_STATS_RXBROAD, "RxBroad"), -- MIB_DESC(1, AR40XX_STATS_RXPAUSE, "RxPause"), -- MIB_DESC(1, AR40XX_STATS_RXMULTI, "RxMulti"), -- MIB_DESC(1, AR40XX_STATS_RXFCSERR, "RxFcsErr"), -- MIB_DESC(1, AR40XX_STATS_RXALIGNERR, "RxAlignErr"), -- MIB_DESC(1, AR40XX_STATS_RXRUNT, "RxRunt"), -- MIB_DESC(1, AR40XX_STATS_RXFRAGMENT, "RxFragment"), -- MIB_DESC(1, AR40XX_STATS_RX64BYTE, "Rx64Byte"), -- MIB_DESC(1, AR40XX_STATS_RX128BYTE, "Rx128Byte"), -- MIB_DESC(1, AR40XX_STATS_RX256BYTE, "Rx256Byte"), -- MIB_DESC(1, AR40XX_STATS_RX512BYTE, "Rx512Byte"), -- MIB_DESC(1, AR40XX_STATS_RX1024BYTE, "Rx1024Byte"), -- MIB_DESC(1, AR40XX_STATS_RX1518BYTE, "Rx1518Byte"), -- MIB_DESC(1, AR40XX_STATS_RXMAXBYTE, "RxMaxByte"), -- MIB_DESC(1, AR40XX_STATS_RXTOOLONG, "RxTooLong"), -- MIB_DESC(2, AR40XX_STATS_RXGOODBYTE, "RxGoodByte"), -- MIB_DESC(2, AR40XX_STATS_RXBADBYTE, "RxBadByte"), -- MIB_DESC(1, AR40XX_STATS_RXOVERFLOW, "RxOverFlow"), -- MIB_DESC(1, AR40XX_STATS_FILTERED, "Filtered"), -- MIB_DESC(1, AR40XX_STATS_TXBROAD, "TxBroad"), -- MIB_DESC(1, AR40XX_STATS_TXPAUSE, "TxPause"), -- MIB_DESC(1, AR40XX_STATS_TXMULTI, "TxMulti"), -- MIB_DESC(1, AR40XX_STATS_TXUNDERRUN, "TxUnderRun"), -- MIB_DESC(1, AR40XX_STATS_TX64BYTE, "Tx64Byte"), -- MIB_DESC(1, AR40XX_STATS_TX128BYTE, "Tx128Byte"), -- MIB_DESC(1, AR40XX_STATS_TX256BYTE, "Tx256Byte"), -- MIB_DESC(1, AR40XX_STATS_TX512BYTE, "Tx512Byte"), -- MIB_DESC(1, AR40XX_STATS_TX1024BYTE, "Tx1024Byte"), -- MIB_DESC(1, AR40XX_STATS_TX1518BYTE, "Tx1518Byte"), -- MIB_DESC(1, AR40XX_STATS_TXMAXBYTE, "TxMaxByte"), -- MIB_DESC(1, AR40XX_STATS_TXOVERSIZE, "TxOverSize"), -- MIB_DESC(2, AR40XX_STATS_TXBYTE, "TxByte"), -- MIB_DESC(1, AR40XX_STATS_TXCOLLISION, "TxCollision"), -- MIB_DESC(1, AR40XX_STATS_TXABORTCOL, "TxAbortCol"), -- MIB_DESC(1, AR40XX_STATS_TXMULTICOL, "TxMultiCol"), -- MIB_DESC(1, AR40XX_STATS_TXSINGLECOL, "TxSingleCol"), -- MIB_DESC(1, AR40XX_STATS_TXEXCDEFER, "TxExcDefer"), -- MIB_DESC(1, AR40XX_STATS_TXDEFER, "TxDefer"), -- MIB_DESC(1, AR40XX_STATS_TXLATECOL, "TxLateCol"), --}; -- --static u32 --ar40xx_read(struct ar40xx_priv *priv, int reg) --{ -- return readl(priv->hw_addr + reg); --} -- --static u32 --ar40xx_psgmii_read(struct ar40xx_priv *priv, int reg) --{ -- return readl(priv->psgmii_hw_addr + reg); --} -- --static void --ar40xx_write(struct ar40xx_priv *priv, int reg, u32 val) --{ -- writel(val, priv->hw_addr + reg); --} -- --static u32 --ar40xx_rmw(struct ar40xx_priv *priv, int reg, u32 mask, u32 val) --{ -- u32 ret; -- -- ret = ar40xx_read(priv, reg); -- ret &= ~mask; -- ret |= val; -- ar40xx_write(priv, reg, ret); -- return ret; --} -- --static void --ar40xx_psgmii_write(struct ar40xx_priv *priv, int reg, u32 val) --{ -- writel(val, priv->psgmii_hw_addr + reg); --} -- --static void --ar40xx_phy_dbg_write(struct ar40xx_priv *priv, int phy_addr, -- u16 dbg_addr, u16 dbg_data) --{ -- struct mii_bus *bus = priv->mii_bus; -- -- mutex_lock(&bus->mdio_lock); -- bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_ADDR, dbg_addr); -- bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_DATA, dbg_data); -- mutex_unlock(&bus->mdio_lock); --} -- --static void --ar40xx_phy_dbg_read(struct ar40xx_priv *priv, int phy_addr, -- u16 dbg_addr, u16 *dbg_data) --{ -- struct mii_bus *bus = priv->mii_bus; -- -- mutex_lock(&bus->mdio_lock); -- bus->write(bus, phy_addr, AR40XX_MII_ATH_DBG_ADDR, dbg_addr); -- *dbg_data = bus->read(bus, phy_addr, AR40XX_MII_ATH_DBG_DATA); -- mutex_unlock(&bus->mdio_lock); --} -- --static void --ar40xx_phy_mmd_write(struct ar40xx_priv *priv, u32 phy_id, -- u16 mmd_num, u16 reg_id, u16 reg_val) --{ -- struct mii_bus *bus = priv->mii_bus; -- -- mutex_lock(&bus->mdio_lock); -- bus->write(bus, phy_id, -- AR40XX_MII_ATH_MMD_ADDR, mmd_num); -- bus->write(bus, phy_id, -- AR40XX_MII_ATH_MMD_DATA, reg_id); -- bus->write(bus, phy_id, -- AR40XX_MII_ATH_MMD_ADDR, -- 0x4000 | mmd_num); -- bus->write(bus, phy_id, -- AR40XX_MII_ATH_MMD_DATA, reg_val); -- mutex_unlock(&bus->mdio_lock); --} -- --static u16 --ar40xx_phy_mmd_read(struct ar40xx_priv *priv, u32 phy_id, -- u16 mmd_num, u16 reg_id) --{ -- u16 value; -- struct mii_bus *bus = priv->mii_bus; -- -- mutex_lock(&bus->mdio_lock); -- bus->write(bus, phy_id, -- AR40XX_MII_ATH_MMD_ADDR, mmd_num); -- bus->write(bus, phy_id, -- AR40XX_MII_ATH_MMD_DATA, reg_id); -- bus->write(bus, phy_id, -- AR40XX_MII_ATH_MMD_ADDR, -- 0x4000 | mmd_num); -- value = bus->read(bus, phy_id, AR40XX_MII_ATH_MMD_DATA); -- mutex_unlock(&bus->mdio_lock); -- return value; --} -- --/* Start of swconfig support */ -- --static void --ar40xx_phy_poll_reset(struct ar40xx_priv *priv) --{ -- u32 i, in_reset, retries = 500; -- struct mii_bus *bus = priv->mii_bus; -- -- /* Assume RESET was recently issued to some or all of the phys */ -- in_reset = GENMASK(AR40XX_NUM_PHYS - 1, 0); -- -- while (retries--) { -- /* 1ms should be plenty of time. -- * 802.3 spec allows for a max wait time of 500ms -- */ -- usleep_range(1000, 2000); -- -- for (i = 0; i < AR40XX_NUM_PHYS; i++) { -- int val; -- -- /* skip devices which have completed reset */ -- if (!(in_reset & BIT(i))) -- continue; -- -- val = mdiobus_read(bus, i, MII_BMCR); -- if (val < 0) -- continue; -- -- /* mark when phy is no longer in reset state */ -- if (!(val & BMCR_RESET)) -- in_reset &= ~BIT(i); -- } -- -- if (!in_reset) -- return; -- } -- -- dev_warn(&bus->dev, "Failed to reset all phys! (in_reset: 0x%x)\n", -- in_reset); --} -- --static void --ar40xx_phy_init(struct ar40xx_priv *priv) --{ -- int i; -- struct mii_bus *bus; -- u16 val; -- -- bus = priv->mii_bus; -- for (i = 0; i < AR40XX_NUM_PORTS - 1; i++) { -- ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_0, &val); -- val &= ~AR40XX_PHY_MANU_CTRL_EN; -- ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_0, val); -- mdiobus_write(bus, i, -- MII_ADVERTISE, ADVERTISE_ALL | -- ADVERTISE_PAUSE_CAP | -- ADVERTISE_PAUSE_ASYM); -- mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL); -- mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); -- } -- -- ar40xx_phy_poll_reset(priv); --} -- --static void --ar40xx_port_phy_linkdown(struct ar40xx_priv *priv) --{ -- struct mii_bus *bus; -- int i; -- u16 val; -- -- bus = priv->mii_bus; -- for (i = 0; i < AR40XX_NUM_PORTS - 1; i++) { -- mdiobus_write(bus, i, MII_CTRL1000, 0); -- mdiobus_write(bus, i, MII_ADVERTISE, 0); -- mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); -- ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_0, &val); -- val |= AR40XX_PHY_MANU_CTRL_EN; -- ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_0, val); -- /* disable transmit */ -- ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_2, &val); -- val &= 0xf00f; -- ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_2, val); -- } --} -- --static void --ar40xx_set_mirror_regs(struct ar40xx_priv *priv) --{ -- int port; -- -- /* reset all mirror registers */ -- ar40xx_rmw(priv, AR40XX_REG_FWD_CTRL0, -- AR40XX_FWD_CTRL0_MIRROR_PORT, -- (0xF << AR40XX_FWD_CTRL0_MIRROR_PORT_S)); -- for (port = 0; port < AR40XX_NUM_PORTS; port++) { -- ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(port), -- AR40XX_PORT_LOOKUP_ING_MIRROR_EN, 0); -- -- ar40xx_rmw(priv, AR40XX_REG_PORT_HOL_CTRL1(port), -- AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN, 0); -- } -- -- /* now enable mirroring if necessary */ -- if (priv->source_port >= AR40XX_NUM_PORTS || -- priv->monitor_port >= AR40XX_NUM_PORTS || -- priv->source_port == priv->monitor_port) { -- return; -- } -- -- ar40xx_rmw(priv, AR40XX_REG_FWD_CTRL0, -- AR40XX_FWD_CTRL0_MIRROR_PORT, -- (priv->monitor_port << AR40XX_FWD_CTRL0_MIRROR_PORT_S)); -- -- if (priv->mirror_rx) -- ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(priv->source_port), 0, -- AR40XX_PORT_LOOKUP_ING_MIRROR_EN); -- -- if (priv->mirror_tx) -- ar40xx_rmw(priv, AR40XX_REG_PORT_HOL_CTRL1(priv->source_port), -- 0, AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN); --} -- --static int --ar40xx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- u8 ports = priv->vlan_table[val->port_vlan]; -- int i; -- -- val->len = 0; -- for (i = 0; i < dev->ports; i++) { -- struct switch_port *p; -- -- if (!(ports & BIT(i))) -- continue; -- -- p = &val->value.ports[val->len++]; -- p->id = i; -- if ((priv->vlan_tagged & BIT(i)) || -- (priv->pvid[i] != val->port_vlan)) -- p->flags = BIT(SWITCH_PORT_FLAG_TAGGED); -- else -- p->flags = 0; -- } -- return 0; --} -- --static int --ar40xx_sw_set_ports(struct switch_dev *dev, struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- u8 *vt = &priv->vlan_table[val->port_vlan]; -- int i; -- -- *vt = 0; -- for (i = 0; i < val->len; i++) { -- struct switch_port *p = &val->value.ports[i]; -- -- if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED)) { -- if (val->port_vlan == priv->pvid[p->id]) -- priv->vlan_tagged |= BIT(p->id); -- } else { -- priv->vlan_tagged &= ~BIT(p->id); -- priv->pvid[p->id] = val->port_vlan; -- } -- -- *vt |= BIT(p->id); -- } -- return 0; --} -- --static int --ar40xx_reg_wait(struct ar40xx_priv *priv, u32 reg, u32 mask, u32 val, -- unsigned timeout) --{ -- int i; -- -- for (i = 0; i < timeout; i++) { -- u32 t; -- -- t = ar40xx_read(priv, reg); -- if ((t & mask) == val) -- return 0; -- -- usleep_range(1000, 2000); -- } -- -- return -ETIMEDOUT; --} -- --static int --ar40xx_mib_op(struct ar40xx_priv *priv, u32 op) --{ -- int ret; -- -- lockdep_assert_held(&priv->mib_lock); -- -- /* Capture the hardware statistics for all ports */ -- ar40xx_rmw(priv, AR40XX_REG_MIB_FUNC, -- AR40XX_MIB_FUNC, (op << AR40XX_MIB_FUNC_S)); -- -- /* Wait for the capturing to complete. */ -- ret = ar40xx_reg_wait(priv, AR40XX_REG_MIB_FUNC, -- AR40XX_MIB_BUSY, 0, 10); -- -- return ret; --} -- --static void --ar40xx_mib_fetch_port_stat(struct ar40xx_priv *priv, int port, bool flush) --{ -- unsigned int base; -- u64 *mib_stats; -- int i; -- u32 num_mibs = ARRAY_SIZE(ar40xx_mibs); -- -- WARN_ON(port >= priv->dev.ports); -- -- lockdep_assert_held(&priv->mib_lock); -- -- base = AR40XX_REG_PORT_STATS_START + -- AR40XX_REG_PORT_STATS_LEN * port; -- -- mib_stats = &priv->mib_stats[port * num_mibs]; -- if (flush) { -- u32 len; -- -- len = num_mibs * sizeof(*mib_stats); -- memset(mib_stats, 0, len); -- return; -- } -- for (i = 0; i < num_mibs; i++) { -- const struct ar40xx_mib_desc *mib; -- u64 t; -- -- mib = &ar40xx_mibs[i]; -- t = ar40xx_read(priv, base + mib->offset); -- if (mib->size == 2) { -- u64 hi; -- -- hi = ar40xx_read(priv, base + mib->offset + 4); -- t |= hi << 32; -- } -- -- mib_stats[i] += t; -- } --} -- --static int --ar40xx_mib_capture(struct ar40xx_priv *priv) --{ -- return ar40xx_mib_op(priv, AR40XX_MIB_FUNC_CAPTURE); --} -- --static int --ar40xx_mib_flush(struct ar40xx_priv *priv) --{ -- return ar40xx_mib_op(priv, AR40XX_MIB_FUNC_FLUSH); --} -- --static int --ar40xx_sw_set_reset_mibs(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- unsigned int len; -- int ret; -- u32 num_mibs = ARRAY_SIZE(ar40xx_mibs); -- -- mutex_lock(&priv->mib_lock); -- -- len = priv->dev.ports * num_mibs * sizeof(*priv->mib_stats); -- memset(priv->mib_stats, 0, len); -- ret = ar40xx_mib_flush(priv); -- -- mutex_unlock(&priv->mib_lock); -- return ret; --} -- --static int --ar40xx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- priv->vlan = !!val->value.i; -- return 0; --} -- --static int --ar40xx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- val->value.i = priv->vlan; -- return 0; --} -- --static int --ar40xx_sw_set_mirror_rx_enable(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- mutex_lock(&priv->reg_mutex); -- priv->mirror_rx = !!val->value.i; -- ar40xx_set_mirror_regs(priv); -- mutex_unlock(&priv->reg_mutex); -- -- return 0; --} -- --static int --ar40xx_sw_get_mirror_rx_enable(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- mutex_lock(&priv->reg_mutex); -- val->value.i = priv->mirror_rx; -- mutex_unlock(&priv->reg_mutex); -- return 0; --} -- --static int --ar40xx_sw_set_mirror_tx_enable(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- mutex_lock(&priv->reg_mutex); -- priv->mirror_tx = !!val->value.i; -- ar40xx_set_mirror_regs(priv); -- mutex_unlock(&priv->reg_mutex); -- -- return 0; --} -- --static int --ar40xx_sw_get_mirror_tx_enable(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- mutex_lock(&priv->reg_mutex); -- val->value.i = priv->mirror_tx; -- mutex_unlock(&priv->reg_mutex); -- return 0; --} -- --static int --ar40xx_sw_set_mirror_monitor_port(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- mutex_lock(&priv->reg_mutex); -- priv->monitor_port = val->value.i; -- ar40xx_set_mirror_regs(priv); -- mutex_unlock(&priv->reg_mutex); -- -- return 0; --} -- --static int --ar40xx_sw_get_mirror_monitor_port(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- mutex_lock(&priv->reg_mutex); -- val->value.i = priv->monitor_port; -- mutex_unlock(&priv->reg_mutex); -- return 0; --} -- --static int --ar40xx_sw_set_mirror_source_port(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- mutex_lock(&priv->reg_mutex); -- priv->source_port = val->value.i; -- ar40xx_set_mirror_regs(priv); -- mutex_unlock(&priv->reg_mutex); -- -- return 0; --} -- --static int --ar40xx_sw_get_mirror_source_port(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- mutex_lock(&priv->reg_mutex); -- val->value.i = priv->source_port; -- mutex_unlock(&priv->reg_mutex); -- return 0; --} -- --static int --ar40xx_sw_set_linkdown(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- if (val->value.i == 1) -- ar40xx_port_phy_linkdown(priv); -- else -- ar40xx_phy_init(priv); -- -- return 0; --} -- --static int --ar40xx_sw_set_port_reset_mib(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- int port; -- int ret; -- -- port = val->port_vlan; -- if (port >= dev->ports) -- return -EINVAL; -- -- mutex_lock(&priv->mib_lock); -- ret = ar40xx_mib_capture(priv); -- if (ret) -- goto unlock; -- -- ar40xx_mib_fetch_port_stat(priv, port, true); -- --unlock: -- mutex_unlock(&priv->mib_lock); -- return ret; --} -- --static int --ar40xx_sw_get_port_mib(struct switch_dev *dev, -- const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- u64 *mib_stats; -- int port; -- int ret; -- char *buf = priv->buf; -- int i, len = 0; -- u32 num_mibs = ARRAY_SIZE(ar40xx_mibs); -- -- port = val->port_vlan; -- if (port >= dev->ports) -- return -EINVAL; -- -- mutex_lock(&priv->mib_lock); -- ret = ar40xx_mib_capture(priv); -- if (ret) -- goto unlock; -- -- ar40xx_mib_fetch_port_stat(priv, port, false); -- -- len += snprintf(buf + len, sizeof(priv->buf) - len, -- "Port %d MIB counters\n", -- port); -- -- mib_stats = &priv->mib_stats[port * num_mibs]; -- for (i = 0; i < num_mibs; i++) -- len += snprintf(buf + len, sizeof(priv->buf) - len, -- "%-12s: %llu\n", -- ar40xx_mibs[i].name, -- mib_stats[i]); -- -- val->value.s = buf; -- val->len = len; -- --unlock: -- mutex_unlock(&priv->mib_lock); -- return ret; --} -- --static int --ar40xx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- priv->vlan_id[val->port_vlan] = val->value.i; -- return 0; --} -- --static int --ar40xx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr, -- struct switch_val *val) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- val->value.i = priv->vlan_id[val->port_vlan]; -- return 0; --} -- --static int --ar40xx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- *vlan = priv->pvid[port]; -- return 0; --} -- --static int --ar40xx_sw_set_pvid(struct switch_dev *dev, int port, int vlan) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- /* make sure no invalid PVIDs get set */ -- if (vlan >= dev->vlans) -- return -EINVAL; -- -- priv->pvid[port] = vlan; -- return 0; --} -- --static void --ar40xx_read_port_link(struct ar40xx_priv *priv, int port, -- struct switch_port_link *link) --{ -- u32 status; -- u32 speed; -- -- memset(link, 0, sizeof(*link)); -- -- status = ar40xx_read(priv, AR40XX_REG_PORT_STATUS(port)); -- -- link->aneg = !!(status & AR40XX_PORT_AUTO_LINK_EN); -- if (link->aneg || (port != AR40XX_PORT_CPU)) -- link->link = !!(status & AR40XX_PORT_STATUS_LINK_UP); -- else -- link->link = true; -- -- if (!link->link) -- return; -- -- link->duplex = !!(status & AR40XX_PORT_DUPLEX); -- link->tx_flow = !!(status & AR40XX_PORT_STATUS_TXFLOW); -- link->rx_flow = !!(status & AR40XX_PORT_STATUS_RXFLOW); -- -- speed = (status & AR40XX_PORT_SPEED) >> -- AR40XX_PORT_STATUS_SPEED_S; -- -- switch (speed) { -- case AR40XX_PORT_SPEED_10M: -- link->speed = SWITCH_PORT_SPEED_10; -- break; -- case AR40XX_PORT_SPEED_100M: -- link->speed = SWITCH_PORT_SPEED_100; -- break; -- case AR40XX_PORT_SPEED_1000M: -- link->speed = SWITCH_PORT_SPEED_1000; -- break; -- default: -- link->speed = SWITCH_PORT_SPEED_UNKNOWN; -- break; -- } --} -- --static int --ar40xx_sw_get_port_link(struct switch_dev *dev, int port, -- struct switch_port_link *link) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- -- ar40xx_read_port_link(priv, port, link); -- return 0; --} -- --static const struct switch_attr ar40xx_sw_attr_globals[] = { -- { -- .type = SWITCH_TYPE_INT, -- .name = "enable_vlan", -- .description = "Enable VLAN mode", -- .set = ar40xx_sw_set_vlan, -- .get = ar40xx_sw_get_vlan, -- .max = 1 -- }, -- { -- .type = SWITCH_TYPE_NOVAL, -- .name = "reset_mibs", -- .description = "Reset all MIB counters", -- .set = ar40xx_sw_set_reset_mibs, -- }, -- { -- .type = SWITCH_TYPE_INT, -- .name = "enable_mirror_rx", -- .description = "Enable mirroring of RX packets", -- .set = ar40xx_sw_set_mirror_rx_enable, -- .get = ar40xx_sw_get_mirror_rx_enable, -- .max = 1 -- }, -- { -- .type = SWITCH_TYPE_INT, -- .name = "enable_mirror_tx", -- .description = "Enable mirroring of TX packets", -- .set = ar40xx_sw_set_mirror_tx_enable, -- .get = ar40xx_sw_get_mirror_tx_enable, -- .max = 1 -- }, -- { -- .type = SWITCH_TYPE_INT, -- .name = "mirror_monitor_port", -- .description = "Mirror monitor port", -- .set = ar40xx_sw_set_mirror_monitor_port, -- .get = ar40xx_sw_get_mirror_monitor_port, -- .max = AR40XX_NUM_PORTS - 1 -- }, -- { -- .type = SWITCH_TYPE_INT, -- .name = "mirror_source_port", -- .description = "Mirror source port", -- .set = ar40xx_sw_set_mirror_source_port, -- .get = ar40xx_sw_get_mirror_source_port, -- .max = AR40XX_NUM_PORTS - 1 -- }, -- { -- .type = SWITCH_TYPE_INT, -- .name = "linkdown", -- .description = "Link down all the PHYs", -- .set = ar40xx_sw_set_linkdown, -- .max = 1 -- }, --}; -- --static const struct switch_attr ar40xx_sw_attr_port[] = { -- { -- .type = SWITCH_TYPE_NOVAL, -- .name = "reset_mib", -- .description = "Reset single port MIB counters", -- .set = ar40xx_sw_set_port_reset_mib, -- }, -- { -- .type = SWITCH_TYPE_STRING, -- .name = "mib", -- .description = "Get port's MIB counters", -- .set = NULL, -- .get = ar40xx_sw_get_port_mib, -- }, --}; -- --const struct switch_attr ar40xx_sw_attr_vlan[] = { -- { -- .type = SWITCH_TYPE_INT, -- .name = "vid", -- .description = "VLAN ID (0-4094)", -- .set = ar40xx_sw_set_vid, -- .get = ar40xx_sw_get_vid, -- .max = 4094, -- }, --}; -- --/* End of swconfig support */ -- --static int --ar40xx_wait_bit(struct ar40xx_priv *priv, int reg, u32 mask, u32 val) --{ -- int timeout = 20; -- u32 t; -- -- while (1) { -- t = ar40xx_read(priv, reg); -- if ((t & mask) == val) -- return 0; -- -- if (timeout-- <= 0) -- break; -- -- usleep_range(10, 20); -- } -- -- pr_err("ar40xx: timeout for reg %08x: %08x & %08x != %08x\n", -- (unsigned int)reg, t, mask, val); -- return -ETIMEDOUT; --} -- --static int --ar40xx_atu_flush(struct ar40xx_priv *priv) --{ -- int ret; -- -- ret = ar40xx_wait_bit(priv, AR40XX_REG_ATU_FUNC, -- AR40XX_ATU_FUNC_BUSY, 0); -- if (!ret) -- ar40xx_write(priv, AR40XX_REG_ATU_FUNC, -- AR40XX_ATU_FUNC_OP_FLUSH | -- AR40XX_ATU_FUNC_BUSY); -- -- return ret; --} -- --static void --ar40xx_ess_reset(struct ar40xx_priv *priv) --{ -- reset_control_assert(priv->ess_rst); -- mdelay(10); -- reset_control_deassert(priv->ess_rst); -- /* Waiting for all inner tables init done. -- * It cost 5~10ms. -- */ -- mdelay(10); -- -- pr_info("ESS reset ok!\n"); --} -- --/* Start of psgmii self test */ -- --static void --ar40xx_malibu_psgmii_ess_reset(struct ar40xx_priv *priv) --{ -- u32 n; -- struct mii_bus *bus = priv->mii_bus; -- /* reset phy psgmii */ -- /* fix phy psgmii RX 20bit */ -- mdiobus_write(bus, 5, 0x0, 0x005b); -- /* reset phy psgmii */ -- mdiobus_write(bus, 5, 0x0, 0x001b); -- /* release reset phy psgmii */ -- mdiobus_write(bus, 5, 0x0, 0x005b); -- -- for (n = 0; n < AR40XX_PSGMII_CALB_NUM; n++) { -- u16 status; -- -- status = ar40xx_phy_mmd_read(priv, 5, 1, 0x28); -- if (status & BIT(0)) -- break; -- /* Polling interval to check PSGMII PLL in malibu is ready -- * the worst time is 8.67ms -- * for 25MHz reference clock -- * [512+(128+2048)*49]*80ns+100us -- */ -- mdelay(2); -- } -- mdelay(50); -- -- /*check malibu psgmii calibration done end..*/ -- -- /*freeze phy psgmii RX CDR*/ -- mdiobus_write(bus, 5, 0x1a, 0x2230); -- -- ar40xx_ess_reset(priv); -- -- /*check psgmii calibration done start*/ -- for (n = 0; n < AR40XX_PSGMII_CALB_NUM; n++) { -- u32 status; -- -- status = ar40xx_psgmii_read(priv, 0xa0); -- if (status & BIT(0)) -- break; -- /* Polling interval to check PSGMII PLL in ESS is ready */ -- mdelay(2); -- } -- mdelay(50); -- -- /* check dakota psgmii calibration done end..*/ -- -- /* relesae phy psgmii RX CDR */ -- mdiobus_write(bus, 5, 0x1a, 0x3230); -- /* release phy psgmii RX 20bit */ -- mdiobus_write(bus, 5, 0x0, 0x005f); -- mdelay(200); --} -- --static void --ar40xx_psgmii_single_phy_testing(struct ar40xx_priv *priv, int phy) --{ -- int j; -- u32 tx_ok, tx_error; -- u32 rx_ok, rx_error; -- u32 tx_ok_high16; -- u32 rx_ok_high16; -- u32 tx_all_ok, rx_all_ok; -- struct mii_bus *bus = priv->mii_bus; -- -- mdiobus_write(bus, phy, 0x0, 0x9000); -- mdiobus_write(bus, phy, 0x0, 0x4140); -- -- for (j = 0; j < AR40XX_PSGMII_CALB_NUM; j++) { -- u16 status; -- -- status = mdiobus_read(bus, phy, 0x11); -- if (status & AR40XX_PHY_SPEC_STATUS_LINK) -- break; -- /* the polling interval to check if the PHY link up or not -- * maxwait_timer: 750 ms +/-10 ms -- * minwait_timer : 1 us +/- 0.1us -- * time resides in minwait_timer ~ maxwait_timer -- * see IEEE 802.3 section 40.4.5.2 -- */ -- mdelay(8); -- } -- -- /* enable check */ -- ar40xx_phy_mmd_write(priv, phy, 7, 0x8029, 0x0000); -- ar40xx_phy_mmd_write(priv, phy, 7, 0x8029, 0x0003); -- -- /* start traffic */ -- ar40xx_phy_mmd_write(priv, phy, 7, 0x8020, 0xa000); -- /* wait for all traffic end -- * 4096(pkt num)*1524(size)*8ns(125MHz)=49.9ms -- */ -- mdelay(50); -- -- /* check counter */ -- tx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802e); -- tx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802d); -- tx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802f); -- rx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802b); -- rx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802a); -- rx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802c); -- tx_all_ok = tx_ok + (tx_ok_high16 << 16); -- rx_all_ok = rx_ok + (rx_ok_high16 << 16); -- if (tx_all_ok == 0x1000 && tx_error == 0) { -- /* success */ -- priv->phy_t_status &= (~BIT(phy)); -- } else { -- pr_info("PHY %d single test PSGMII issue happen!\n", phy); -- priv->phy_t_status |= BIT(phy); -- } -- -- mdiobus_write(bus, phy, 0x0, 0x1840); --} -- --static void --ar40xx_psgmii_all_phy_testing(struct ar40xx_priv *priv) --{ -- int phy, j; -- struct mii_bus *bus = priv->mii_bus; -- -- mdiobus_write(bus, 0x1f, 0x0, 0x9000); -- mdiobus_write(bus, 0x1f, 0x0, 0x4140); -- -- for (j = 0; j < AR40XX_PSGMII_CALB_NUM; j++) { -- for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) { -- u16 status; -- -- status = mdiobus_read(bus, phy, 0x11); -- if (!(status & BIT(10))) -- break; -- } -- -- if (phy >= (AR40XX_NUM_PORTS - 1)) -- break; -- /* The polling interva to check if the PHY link up or not */ -- mdelay(8); -- } -- /* enable check */ -- ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0000); -- ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0003); -- -- /* start traffic */ -- ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8020, 0xa000); -- /* wait for all traffic end -- * 4096(pkt num)*1524(size)*8ns(125MHz)=49.9ms -- */ -- mdelay(50); -- -- for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) { -- u32 tx_ok, tx_error; -- u32 rx_ok, rx_error; -- u32 tx_ok_high16; -- u32 rx_ok_high16; -- u32 tx_all_ok, rx_all_ok; -- -- /* check counter */ -- tx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802e); -- tx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802d); -- tx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802f); -- rx_ok = ar40xx_phy_mmd_read(priv, phy, 7, 0x802b); -- rx_ok_high16 = ar40xx_phy_mmd_read(priv, phy, 7, 0x802a); -- rx_error = ar40xx_phy_mmd_read(priv, phy, 7, 0x802c); -- tx_all_ok = tx_ok + (tx_ok_high16<<16); -- rx_all_ok = rx_ok + (rx_ok_high16<<16); -- if (tx_all_ok == 0x1000 && tx_error == 0) { -- /* success */ -- priv->phy_t_status &= ~BIT(phy + 8); -- } else { -- pr_info("PHY%d test see issue!\n", phy); -- priv->phy_t_status |= BIT(phy + 8); -- } -- } -- -- pr_debug("PHY all test 0x%x \r\n", priv->phy_t_status); --} -- --void --ar40xx_psgmii_self_test(struct ar40xx_priv *priv) --{ -- u32 i, phy; -- struct mii_bus *bus = priv->mii_bus; -- -- ar40xx_malibu_psgmii_ess_reset(priv); -- -- /* switch to access MII reg for copper */ -- mdiobus_write(bus, 4, 0x1f, 0x8500); -- for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) { -- /*enable phy mdio broadcast write*/ -- ar40xx_phy_mmd_write(priv, phy, 7, 0x8028, 0x801f); -- } -- /* force no link by power down */ -- mdiobus_write(bus, 0x1f, 0x0, 0x1840); -- /*packet number*/ -- ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8021, 0x1000); -- ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8062, 0x05e0); -- -- /*fix mdi status */ -- mdiobus_write(bus, 0x1f, 0x10, 0x6800); -- for (i = 0; i < AR40XX_PSGMII_CALB_NUM; i++) { -- priv->phy_t_status = 0; -- -- for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) { -- ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(phy + 1), -- AR40XX_PORT_LOOKUP_LOOPBACK, -- AR40XX_PORT_LOOKUP_LOOPBACK); -- } -- -- for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) -- ar40xx_psgmii_single_phy_testing(priv, phy); -- -- ar40xx_psgmii_all_phy_testing(priv); -- -- if (priv->phy_t_status) -- ar40xx_malibu_psgmii_ess_reset(priv); -- else -- break; -- } -- -- if (i >= AR40XX_PSGMII_CALB_NUM) -- pr_info("PSGMII cannot recover\n"); -- else -- pr_debug("PSGMII recovered after %d times reset\n", i); -- -- /* configuration recover */ -- /* packet number */ -- ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8021, 0x0); -- /* disable check */ -- ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8029, 0x0); -- /* disable traffic */ -- ar40xx_phy_mmd_write(priv, 0x1f, 7, 0x8020, 0x0); --} -- --void --ar40xx_psgmii_self_test_clean(struct ar40xx_priv *priv) --{ -- int phy; -- struct mii_bus *bus = priv->mii_bus; -- -- /* disable phy internal loopback */ -- mdiobus_write(bus, 0x1f, 0x10, 0x6860); -- mdiobus_write(bus, 0x1f, 0x0, 0x9040); -- -- for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) { -- /* disable mac loop back */ -- ar40xx_rmw(priv, AR40XX_REG_PORT_LOOKUP(phy + 1), -- AR40XX_PORT_LOOKUP_LOOPBACK, 0); -- /* disable phy mdio broadcast write */ -- ar40xx_phy_mmd_write(priv, phy, 7, 0x8028, 0x001f); -- } -- -- /* clear fdb entry */ -- ar40xx_atu_flush(priv); --} -- --/* End of psgmii self test */ -- --static void --ar40xx_mac_mode_init(struct ar40xx_priv *priv, u32 mode) --{ -- if (mode == PORT_WRAPPER_PSGMII) { -- ar40xx_psgmii_write(priv, AR40XX_PSGMII_MODE_CONTROL, 0x2200); -- ar40xx_psgmii_write(priv, AR40XX_PSGMIIPHY_TX_CONTROL, 0x8380); -- } --} -- --static --int ar40xx_cpuport_setup(struct ar40xx_priv *priv) --{ -- u32 t; -- -- t = AR40XX_PORT_STATUS_TXFLOW | -- AR40XX_PORT_STATUS_RXFLOW | -- AR40XX_PORT_TXHALF_FLOW | -- AR40XX_PORT_DUPLEX | -- AR40XX_PORT_SPEED_1000M; -- ar40xx_write(priv, AR40XX_REG_PORT_STATUS(0), t); -- usleep_range(10, 20); -- -- t |= AR40XX_PORT_TX_EN | -- AR40XX_PORT_RX_EN; -- ar40xx_write(priv, AR40XX_REG_PORT_STATUS(0), t); -- -- return 0; --} -- --static void --ar40xx_init_port(struct ar40xx_priv *priv, int port) --{ -- u32 t; -- -- ar40xx_write(priv, AR40XX_REG_PORT_STATUS(port), 0); -- -- ar40xx_write(priv, AR40XX_REG_PORT_HEADER(port), 0); -- -- ar40xx_write(priv, AR40XX_REG_PORT_VLAN0(port), 0); -- -- t = AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH << AR40XX_PORT_VLAN1_OUT_MODE_S; -- ar40xx_write(priv, AR40XX_REG_PORT_VLAN1(port), t); -- -- t = AR40XX_PORT_LOOKUP_LEARN; -- t |= AR40XX_PORT_STATE_FORWARD << AR40XX_PORT_LOOKUP_STATE_S; -- ar40xx_write(priv, AR40XX_REG_PORT_LOOKUP(port), t); --} -- --void --ar40xx_init_globals(struct ar40xx_priv *priv) --{ -- u32 t; -- -- /* enable CPU port and disable mirror port */ -- t = AR40XX_FWD_CTRL0_CPU_PORT_EN | -- AR40XX_FWD_CTRL0_MIRROR_PORT; -- ar40xx_write(priv, AR40XX_REG_FWD_CTRL0, t); -- -- /* forward multicast and broadcast frames to CPU */ -- t = (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_UC_FLOOD_S) | -- (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_MC_FLOOD_S) | -- (AR40XX_PORTS_ALL << AR40XX_FWD_CTRL1_BC_FLOOD_S); -- ar40xx_write(priv, AR40XX_REG_FWD_CTRL1, t); -- -- /* enable jumbo frames */ -- ar40xx_rmw(priv, AR40XX_REG_MAX_FRAME_SIZE, -- AR40XX_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); -- -- /* Enable MIB counters */ -- ar40xx_rmw(priv, AR40XX_REG_MODULE_EN, 0, -- AR40XX_MODULE_EN_MIB); -- -- /* Disable AZ */ -- ar40xx_write(priv, AR40XX_REG_EEE_CTRL, 0); -- -- /* set flowctrl thershold for cpu port */ -- t = (AR40XX_PORT0_FC_THRESH_ON_DFLT << 16) | -- AR40XX_PORT0_FC_THRESH_OFF_DFLT; -- ar40xx_write(priv, AR40XX_REG_PORT_FLOWCTRL_THRESH(0), t); --} -- --static int --ar40xx_hw_init(struct ar40xx_priv *priv) --{ -- u32 i; -- -- ar40xx_ess_reset(priv); -- -- if (!priv->mii_bus) -- return -1; -- -- ar40xx_psgmii_self_test(priv); -- ar40xx_psgmii_self_test_clean(priv); -- -- ar40xx_mac_mode_init(priv, priv->mac_mode); -- -- for (i = 0; i < priv->dev.ports; i++) -- ar40xx_init_port(priv, i); -- -- ar40xx_init_globals(priv); -- -- return 0; --} -- --/* Start of qm error WAR */ -- --static --int ar40xx_force_1g_full(struct ar40xx_priv *priv, u32 port_id) --{ -- u32 reg; -- -- if (port_id < 0 || port_id > 6) -- return -1; -- -- reg = AR40XX_REG_PORT_STATUS(port_id); -- return ar40xx_rmw(priv, reg, AR40XX_PORT_SPEED, -- (AR40XX_PORT_SPEED_1000M | AR40XX_PORT_DUPLEX)); --} -- --static --int ar40xx_get_qm_status(struct ar40xx_priv *priv, -- u32 port_id, u32 *qm_buffer_err) --{ -- u32 reg; -- u32 qm_val; -- -- if (port_id < 1 || port_id > 5) { -- *qm_buffer_err = 0; -- return -1; -- } -- -- if (port_id < 4) { -- reg = AR40XX_REG_QM_PORT0_3_QNUM; -- ar40xx_write(priv, AR40XX_REG_QM_DEBUG_ADDR, reg); -- qm_val = ar40xx_read(priv, AR40XX_REG_QM_DEBUG_VALUE); -- /* every 8 bits for each port */ -- *qm_buffer_err = (qm_val >> (port_id * 8)) & 0xFF; -- } else { -- reg = AR40XX_REG_QM_PORT4_6_QNUM; -- ar40xx_write(priv, AR40XX_REG_QM_DEBUG_ADDR, reg); -- qm_val = ar40xx_read(priv, AR40XX_REG_QM_DEBUG_VALUE); -- /* every 8 bits for each port */ -- *qm_buffer_err = (qm_val >> ((port_id-4) * 8)) & 0xFF; -- } -- -- return 0; --} -- --static void --ar40xx_sw_mac_polling_task(struct ar40xx_priv *priv) --{ -- static int task_count; -- u32 i; -- u32 reg, value; -- u32 link, speed, duplex; -- u32 qm_buffer_err; -- u16 port_phy_status[AR40XX_NUM_PORTS]; -- static u32 qm_err_cnt[AR40XX_NUM_PORTS] = {0, 0, 0, 0, 0, 0}; -- static u32 link_cnt[AR40XX_NUM_PORTS] = {0, 0, 0, 0, 0, 0}; -- struct mii_bus *bus = NULL; -- -- if (!priv || !priv->mii_bus) -- return; -- -- bus = priv->mii_bus; -- -- ++task_count; -- -- for (i = 1; i < AR40XX_NUM_PORTS; ++i) { -- port_phy_status[i] = -- mdiobus_read(bus, i-1, AR40XX_PHY_SPEC_STATUS); -- -- speed = FIELD_GET(AR40XX_PHY_SPEC_STATUS_SPEED, -- port_phy_status[i]); -- link = FIELD_GET(AR40XX_PHY_SPEC_STATUS_LINK, -- port_phy_status[i]); -- duplex = FIELD_GET(AR40XX_PHY_SPEC_STATUS_DUPLEX, -- port_phy_status[i]); -- -- if (link != priv->ar40xx_port_old_link[i]) { -- ++link_cnt[i]; -- /* Up --> Down */ -- if ((priv->ar40xx_port_old_link[i] == -- AR40XX_PORT_LINK_UP) && -- (link == AR40XX_PORT_LINK_DOWN)) { -- /* LINK_EN disable(MAC force mode)*/ -- reg = AR40XX_REG_PORT_STATUS(i); -- ar40xx_rmw(priv, reg, -- AR40XX_PORT_AUTO_LINK_EN, 0); -- -- /* Check queue buffer */ -- qm_err_cnt[i] = 0; -- ar40xx_get_qm_status(priv, i, &qm_buffer_err); -- if (qm_buffer_err) { -- priv->ar40xx_port_qm_buf[i] = -- AR40XX_QM_NOT_EMPTY; -- } else { -- u16 phy_val = 0; -- -- priv->ar40xx_port_qm_buf[i] = -- AR40XX_QM_EMPTY; -- ar40xx_force_1g_full(priv, i); -- /* Ref:QCA8337 Datasheet,Clearing -- * MENU_CTRL_EN prevents phy to -- * stuck in 100BT mode when -- * bringing up the link -- */ -- ar40xx_phy_dbg_read(priv, i-1, -- AR40XX_PHY_DEBUG_0, -- &phy_val); -- phy_val &= (~AR40XX_PHY_MANU_CTRL_EN); -- ar40xx_phy_dbg_write(priv, i-1, -- AR40XX_PHY_DEBUG_0, -- phy_val); -- } -- priv->ar40xx_port_old_link[i] = link; -- } else if ((priv->ar40xx_port_old_link[i] == -- AR40XX_PORT_LINK_DOWN) && -- (link == AR40XX_PORT_LINK_UP)) { -- /* Down --> Up */ -- if (priv->port_link_up[i] < 1) { -- ++priv->port_link_up[i]; -- } else { -- /* Change port status */ -- reg = AR40XX_REG_PORT_STATUS(i); -- value = ar40xx_read(priv, reg); -- priv->port_link_up[i] = 0; -- -- value &= ~(AR40XX_PORT_DUPLEX | -- AR40XX_PORT_SPEED); -- value |= speed | (duplex ? BIT(6) : 0); -- ar40xx_write(priv, reg, value); -- /* clock switch need such time -- * to avoid glitch -- */ -- usleep_range(100, 200); -- -- value |= AR40XX_PORT_AUTO_LINK_EN; -- ar40xx_write(priv, reg, value); -- /* HW need such time to make sure link -- * stable before enable MAC -- */ -- usleep_range(100, 200); -- -- if (speed == AR40XX_PORT_SPEED_100M) { -- u16 phy_val = 0; -- /* Enable @100M, if down to 10M -- * clock will change smoothly -- */ -- ar40xx_phy_dbg_read(priv, i-1, -- 0, -- &phy_val); -- phy_val |= -- AR40XX_PHY_MANU_CTRL_EN; -- ar40xx_phy_dbg_write(priv, i-1, -- 0, -- phy_val); -- } -- priv->ar40xx_port_old_link[i] = link; -- } -- } -- } -- -- if (priv->ar40xx_port_qm_buf[i] == AR40XX_QM_NOT_EMPTY) { -- /* Check QM */ -- ar40xx_get_qm_status(priv, i, &qm_buffer_err); -- if (qm_buffer_err) { -- ++qm_err_cnt[i]; -- } else { -- priv->ar40xx_port_qm_buf[i] = -- AR40XX_QM_EMPTY; -- qm_err_cnt[i] = 0; -- ar40xx_force_1g_full(priv, i); -- } -- } -- } --} -- --static void --ar40xx_qm_err_check_work_task(struct work_struct *work) --{ -- struct ar40xx_priv *priv = container_of(work, struct ar40xx_priv, -- qm_dwork.work); -- -- mutex_lock(&priv->qm_lock); -- -- ar40xx_sw_mac_polling_task(priv); -- -- mutex_unlock(&priv->qm_lock); -- -- schedule_delayed_work(&priv->qm_dwork, -- msecs_to_jiffies(AR40XX_QM_WORK_DELAY)); --} -- --static int --ar40xx_qm_err_check_work_start(struct ar40xx_priv *priv) --{ -- mutex_init(&priv->qm_lock); -- -- INIT_DELAYED_WORK(&priv->qm_dwork, ar40xx_qm_err_check_work_task); -- -- schedule_delayed_work(&priv->qm_dwork, -- msecs_to_jiffies(AR40XX_QM_WORK_DELAY)); -- -- return 0; --} -- --/* End of qm error WAR */ -- --static int --ar40xx_vlan_init(struct ar40xx_priv *priv) --{ -- int port; -- unsigned long bmp; -- -- /* By default Enable VLAN */ -- priv->vlan = 1; -- priv->vlan_table[AR40XX_LAN_VLAN] = priv->cpu_bmp | priv->lan_bmp; -- priv->vlan_table[AR40XX_WAN_VLAN] = priv->cpu_bmp | priv->wan_bmp; -- priv->vlan_tagged = priv->cpu_bmp; -- bmp = priv->lan_bmp; -- for_each_set_bit(port, &bmp, AR40XX_NUM_PORTS) -- priv->pvid[port] = AR40XX_LAN_VLAN; -- -- bmp = priv->wan_bmp; -- for_each_set_bit(port, &bmp, AR40XX_NUM_PORTS) -- priv->pvid[port] = AR40XX_WAN_VLAN; -- -- return 0; --} -- --static void --ar40xx_mib_work_func(struct work_struct *work) --{ -- struct ar40xx_priv *priv; -- int err; -- -- priv = container_of(work, struct ar40xx_priv, mib_work.work); -- -- mutex_lock(&priv->mib_lock); -- -- err = ar40xx_mib_capture(priv); -- if (err) -- goto next_port; -- -- ar40xx_mib_fetch_port_stat(priv, priv->mib_next_port, false); -- --next_port: -- priv->mib_next_port++; -- if (priv->mib_next_port >= priv->dev.ports) -- priv->mib_next_port = 0; -- -- mutex_unlock(&priv->mib_lock); -- -- schedule_delayed_work(&priv->mib_work, -- msecs_to_jiffies(AR40XX_MIB_WORK_DELAY)); --} -- --static void --ar40xx_setup_port(struct ar40xx_priv *priv, int port, u32 members) --{ -- u32 t; -- u32 egress, ingress; -- u32 pvid = priv->vlan_id[priv->pvid[port]]; -- -- if (priv->vlan) { -- egress = AR40XX_PORT_VLAN1_OUT_MODE_UNMOD; -- -- ingress = AR40XX_IN_SECURE; -- } else { -- egress = AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH; -- ingress = AR40XX_IN_PORT_ONLY; -- } -- -- t = pvid << AR40XX_PORT_VLAN0_DEF_SVID_S; -- t |= pvid << AR40XX_PORT_VLAN0_DEF_CVID_S; -- ar40xx_write(priv, AR40XX_REG_PORT_VLAN0(port), t); -- -- t = AR40XX_PORT_VLAN1_PORT_VLAN_PROP; -- t |= egress << AR40XX_PORT_VLAN1_OUT_MODE_S; -- -- ar40xx_write(priv, AR40XX_REG_PORT_VLAN1(port), t); -- -- t = members; -- t |= AR40XX_PORT_LOOKUP_LEARN; -- t |= ingress << AR40XX_PORT_LOOKUP_IN_MODE_S; -- t |= AR40XX_PORT_STATE_FORWARD << AR40XX_PORT_LOOKUP_STATE_S; -- ar40xx_write(priv, AR40XX_REG_PORT_LOOKUP(port), t); --} -- --static void --ar40xx_vtu_op(struct ar40xx_priv *priv, u32 op, u32 val) --{ -- if (ar40xx_wait_bit(priv, AR40XX_REG_VTU_FUNC1, -- AR40XX_VTU_FUNC1_BUSY, 0)) -- return; -- -- if ((op & AR40XX_VTU_FUNC1_OP) == AR40XX_VTU_FUNC1_OP_LOAD) -- ar40xx_write(priv, AR40XX_REG_VTU_FUNC0, val); -- -- op |= AR40XX_VTU_FUNC1_BUSY; -- ar40xx_write(priv, AR40XX_REG_VTU_FUNC1, op); --} -- --static void --ar40xx_vtu_load_vlan(struct ar40xx_priv *priv, u32 vid, u32 port_mask) --{ -- u32 op; -- u32 val; -- int i; -- -- op = AR40XX_VTU_FUNC1_OP_LOAD | (vid << AR40XX_VTU_FUNC1_VID_S); -- val = AR40XX_VTU_FUNC0_VALID | AR40XX_VTU_FUNC0_IVL; -- for (i = 0; i < AR40XX_NUM_PORTS; i++) { -- u32 mode; -- -- if ((port_mask & BIT(i)) == 0) -- mode = AR40XX_VTU_FUNC0_EG_MODE_NOT; -- else if (priv->vlan == 0) -- mode = AR40XX_VTU_FUNC0_EG_MODE_KEEP; -- else if ((priv->vlan_tagged & BIT(i)) || -- (priv->vlan_id[priv->pvid[i]] != vid)) -- mode = AR40XX_VTU_FUNC0_EG_MODE_TAG; -- else -- mode = AR40XX_VTU_FUNC0_EG_MODE_UNTAG; -- -- val |= mode << AR40XX_VTU_FUNC0_EG_MODE_S(i); -- } -- ar40xx_vtu_op(priv, op, val); --} -- --static void --ar40xx_vtu_flush(struct ar40xx_priv *priv) --{ -- ar40xx_vtu_op(priv, AR40XX_VTU_FUNC1_OP_FLUSH, 0); --} -- --static int --ar40xx_sw_hw_apply(struct switch_dev *dev) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- u8 portmask[AR40XX_NUM_PORTS]; -- int i, j; -- -- mutex_lock(&priv->reg_mutex); -- /* flush all vlan entries */ -- ar40xx_vtu_flush(priv); -- -- memset(portmask, 0, sizeof(portmask)); -- if (priv->vlan) { -- for (j = 0; j < AR40XX_MAX_VLANS; j++) { -- u8 vp = priv->vlan_table[j]; -- -- if (!vp) -- continue; -- -- for (i = 0; i < dev->ports; i++) { -- u8 mask = BIT(i); -- -- if (vp & mask) -- portmask[i] |= vp & ~mask; -- } -- -- ar40xx_vtu_load_vlan(priv, priv->vlan_id[j], -- priv->vlan_table[j]); -- } -- } else { -- /* 8021q vlan disabled */ -- for (i = 0; i < dev->ports; i++) { -- if (i == AR40XX_PORT_CPU) -- continue; -- -- portmask[i] = BIT(AR40XX_PORT_CPU); -- portmask[AR40XX_PORT_CPU] |= BIT(i); -- } -- } -- -- /* update the port destination mask registers and tag settings */ -- for (i = 0; i < dev->ports; i++) -- ar40xx_setup_port(priv, i, portmask[i]); -- -- ar40xx_set_mirror_regs(priv); -- -- mutex_unlock(&priv->reg_mutex); -- return 0; --} -- --static int --ar40xx_sw_reset_switch(struct switch_dev *dev) --{ -- struct ar40xx_priv *priv = swdev_to_ar40xx(dev); -- int i, rv; -- -- mutex_lock(&priv->reg_mutex); -- memset(&priv->vlan, 0, sizeof(struct ar40xx_priv) - -- offsetof(struct ar40xx_priv, vlan)); -- -- for (i = 0; i < AR40XX_MAX_VLANS; i++) -- priv->vlan_id[i] = i; -- -- ar40xx_vlan_init(priv); -- -- priv->mirror_rx = false; -- priv->mirror_tx = false; -- priv->source_port = 0; -- priv->monitor_port = 0; -- -- mutex_unlock(&priv->reg_mutex); -- -- rv = ar40xx_sw_hw_apply(dev); -- return rv; --} -- --static int --ar40xx_start(struct ar40xx_priv *priv) --{ -- int ret; -- -- ret = ar40xx_hw_init(priv); -- if (ret) -- return ret; -- -- ret = ar40xx_sw_reset_switch(&priv->dev); -- if (ret) -- return ret; -- -- /* at last, setup cpu port */ -- ret = ar40xx_cpuport_setup(priv); -- if (ret) -- return ret; -- -- schedule_delayed_work(&priv->mib_work, -- msecs_to_jiffies(AR40XX_MIB_WORK_DELAY)); -- -- ar40xx_qm_err_check_work_start(priv); -- -- return 0; --} -- --static const struct switch_dev_ops ar40xx_sw_ops = { -- .attr_global = { -- .attr = ar40xx_sw_attr_globals, -- .n_attr = ARRAY_SIZE(ar40xx_sw_attr_globals), -- }, -- .attr_port = { -- .attr = ar40xx_sw_attr_port, -- .n_attr = ARRAY_SIZE(ar40xx_sw_attr_port), -- }, -- .attr_vlan = { -- .attr = ar40xx_sw_attr_vlan, -- .n_attr = ARRAY_SIZE(ar40xx_sw_attr_vlan), -- }, -- .get_port_pvid = ar40xx_sw_get_pvid, -- .set_port_pvid = ar40xx_sw_set_pvid, -- .get_vlan_ports = ar40xx_sw_get_ports, -- .set_vlan_ports = ar40xx_sw_set_ports, -- .apply_config = ar40xx_sw_hw_apply, -- .reset_switch = ar40xx_sw_reset_switch, -- .get_port_link = ar40xx_sw_get_port_link, --}; -- --/* Platform driver probe function */ -- --static int ar40xx_probe(struct platform_device *pdev) --{ -- struct device_node *switch_node; -- struct device_node *psgmii_node; -- struct device_node *mdio_node; -- const __be32 *mac_mode; -- struct clk *ess_clk; -- struct switch_dev *swdev; -- struct ar40xx_priv *priv; -- u32 len; -- u32 num_mibs; -- struct resource psgmii_base = {0}; -- struct resource switch_base = {0}; -- int ret; -- -- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -- if (!priv) -- return -ENOMEM; -- -- platform_set_drvdata(pdev, priv); -- ar40xx_priv = priv; -- -- switch_node = of_node_get(pdev->dev.of_node); -- if (of_address_to_resource(switch_node, 0, &switch_base) != 0) -- return -EIO; -- -- priv->hw_addr = devm_ioremap_resource(&pdev->dev, &switch_base); -- if (IS_ERR(priv->hw_addr)) { -- dev_err(&pdev->dev, "Failed to ioremap switch_base!\n"); -- return PTR_ERR(priv->hw_addr); -- } -- -- /*psgmii dts get*/ -- psgmii_node = of_find_node_by_name(NULL, "ess-psgmii"); -- if (!psgmii_node) { -- dev_err(&pdev->dev, "Failed to find ess-psgmii node!\n"); -- return -EINVAL; -- } -- -- if (of_address_to_resource(psgmii_node, 0, &psgmii_base) != 0) -- return -EIO; -- -- priv->psgmii_hw_addr = devm_ioremap_resource(&pdev->dev, &psgmii_base); -- if (IS_ERR(priv->psgmii_hw_addr)) { -- dev_err(&pdev->dev, "psgmii ioremap fail!\n"); -- return PTR_ERR(priv->psgmii_hw_addr); -- } -- -- mac_mode = of_get_property(switch_node, "switch_mac_mode", &len); -- if (!mac_mode) { -- dev_err(&pdev->dev, "Failed to read switch_mac_mode\n"); -- return -EINVAL; -- } -- priv->mac_mode = be32_to_cpup(mac_mode); -- -- ess_clk = of_clk_get_by_name(switch_node, "ess_clk"); -- if (ess_clk) -- clk_prepare_enable(ess_clk); -- -- priv->ess_rst = devm_reset_control_get(&pdev->dev, "ess_rst"); -- if (IS_ERR(priv->ess_rst)) { -- dev_err(&pdev->dev, "Failed to get ess_rst control!\n"); -- return PTR_ERR(priv->ess_rst); -- } -- -- if (of_property_read_u32(switch_node, "switch_cpu_bmp", -- &priv->cpu_bmp) || -- of_property_read_u32(switch_node, "switch_lan_bmp", -- &priv->lan_bmp) || -- of_property_read_u32(switch_node, "switch_wan_bmp", -- &priv->wan_bmp)) { -- dev_err(&pdev->dev, "Failed to read port properties\n"); -- return -EIO; -- } -- -- mutex_init(&priv->reg_mutex); -- mutex_init(&priv->mib_lock); -- INIT_DELAYED_WORK(&priv->mib_work, ar40xx_mib_work_func); -- -- /* register switch */ -- swdev = &priv->dev; -- -- mdio_node = of_find_compatible_node(NULL, NULL, "qcom,ipq4019-mdio"); -- if (!mdio_node) { -- dev_err(&pdev->dev, "Probe failed - Cannot find mdio node by phandle!\n"); -- ret = -ENODEV; -- goto err_missing_phy; -- } -- -- priv->mii_bus = of_mdio_find_bus(mdio_node); -- -- if (priv->mii_bus == NULL) { -- dev_err(&pdev->dev, "Probe failed - Missing PHYs!\n"); -- ret = -ENODEV; -- goto err_missing_phy; -- } -- -- swdev->alias = dev_name(&priv->mii_bus->dev); -- -- swdev->cpu_port = AR40XX_PORT_CPU; -- swdev->name = "QCA AR40xx"; -- swdev->vlans = AR40XX_MAX_VLANS; -- swdev->ports = AR40XX_NUM_PORTS; -- swdev->ops = &ar40xx_sw_ops; -- ret = register_switch(swdev, NULL); -- if (ret < 0) { -- dev_err(&pdev->dev, "Switch registration failed!\n"); -- return ret; -- } -- -- num_mibs = ARRAY_SIZE(ar40xx_mibs); -- len = priv->dev.ports * num_mibs * -- sizeof(*priv->mib_stats); -- priv->mib_stats = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); -- if (!priv->mib_stats) { -- ret = -ENOMEM; -- goto err_unregister_switch; -- } -- -- ar40xx_start(priv); -- -- return 0; -- --err_unregister_switch: -- unregister_switch(&priv->dev); --err_missing_phy: -- platform_set_drvdata(pdev, NULL); -- return ret; --} -- --static int ar40xx_remove(struct platform_device *pdev) --{ -- struct ar40xx_priv *priv = platform_get_drvdata(pdev); -- -- cancel_delayed_work_sync(&priv->qm_dwork); -- cancel_delayed_work_sync(&priv->mib_work); -- -- unregister_switch(&priv->dev); -- -- return 0; --} -- --static const struct of_device_id ar40xx_of_mtable[] = { -- {.compatible = "qcom,ess-switch" }, -- {} --}; -- --struct platform_driver ar40xx_drv = { -- .probe = ar40xx_probe, -- .remove = ar40xx_remove, -- .driver = { -- .name = "ar40xx", -- .of_match_table = ar40xx_of_mtable, -- }, --}; -- --module_platform_driver(ar40xx_drv); -- --MODULE_DESCRIPTION("IPQ40XX ESS driver"); --MODULE_LICENSE("Dual BSD/GPL"); ---- a/target/linux/ipq40xx/files-5.10/drivers/net/mdio/ar40xx.h -+++ /dev/null -@@ -1,342 +0,0 @@ --/* -- * Copyright (c) 2016, The Linux Foundation. All rights reserved. -- * -- * Permission to use, copy, modify, and/or distribute this software for -- * any purpose with or without fee is hereby granted, provided that the -- * above copyright notice and this permission notice appear in all copies. -- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- */ -- -- #ifndef __AR40XX_H --#define __AR40XX_H -- --#define AR40XX_MAX_VLANS 128 --#define AR40XX_NUM_PORTS 6 --#define AR40XX_NUM_PHYS 5 -- --#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s) -- --struct ar40xx_priv { -- struct switch_dev dev; -- -- u8 __iomem *hw_addr; -- u8 __iomem *psgmii_hw_addr; -- u32 mac_mode; -- struct reset_control *ess_rst; -- u32 cpu_bmp; -- u32 lan_bmp; -- u32 wan_bmp; -- -- struct mii_bus *mii_bus; -- struct phy_device *phy; -- -- /* mutex for qm task */ -- struct mutex qm_lock; -- struct delayed_work qm_dwork; -- u32 port_link_up[AR40XX_NUM_PORTS]; -- u32 ar40xx_port_old_link[AR40XX_NUM_PORTS]; -- u32 ar40xx_port_qm_buf[AR40XX_NUM_PORTS]; -- -- u32 phy_t_status; -- -- /* mutex for switch reg access */ -- struct mutex reg_mutex; -- -- /* mutex for mib task */ -- struct mutex mib_lock; -- struct delayed_work mib_work; -- int mib_next_port; -- u64 *mib_stats; -- -- char buf[2048]; -- -- /* all fields below will be cleared on reset */ -- bool vlan; -- u16 vlan_id[AR40XX_MAX_VLANS]; -- u8 vlan_table[AR40XX_MAX_VLANS]; -- u8 vlan_tagged; -- u16 pvid[AR40XX_NUM_PORTS]; -- -- /* mirror */ -- bool mirror_rx; -- bool mirror_tx; -- int source_port; -- int monitor_port; --}; -- --#define AR40XX_PORT_LINK_UP 1 --#define AR40XX_PORT_LINK_DOWN 0 --#define AR40XX_QM_NOT_EMPTY 1 --#define AR40XX_QM_EMPTY 0 -- --#define AR40XX_LAN_VLAN 1 --#define AR40XX_WAN_VLAN 2 -- --enum ar40xx_port_wrapper_cfg { -- PORT_WRAPPER_PSGMII = 0, --}; -- --struct ar40xx_mib_desc { -- u32 size; -- u32 offset; -- const char *name; --}; -- --#define AR40XX_PORT_CPU 0 -- --#define AR40XX_PSGMII_MODE_CONTROL 0x1b4 --#define AR40XX_PSGMII_ATHR_CSCO_MODE_25M BIT(0) -- --#define AR40XX_PSGMIIPHY_TX_CONTROL 0x288 -- --#define AR40XX_MII_ATH_MMD_ADDR 0x0d --#define AR40XX_MII_ATH_MMD_DATA 0x0e --#define AR40XX_MII_ATH_DBG_ADDR 0x1d --#define AR40XX_MII_ATH_DBG_DATA 0x1e -- --#define AR40XX_STATS_RXBROAD 0x00 --#define AR40XX_STATS_RXPAUSE 0x04 --#define AR40XX_STATS_RXMULTI 0x08 --#define AR40XX_STATS_RXFCSERR 0x0c --#define AR40XX_STATS_RXALIGNERR 0x10 --#define AR40XX_STATS_RXRUNT 0x14 --#define AR40XX_STATS_RXFRAGMENT 0x18 --#define AR40XX_STATS_RX64BYTE 0x1c --#define AR40XX_STATS_RX128BYTE 0x20 --#define AR40XX_STATS_RX256BYTE 0x24 --#define AR40XX_STATS_RX512BYTE 0x28 --#define AR40XX_STATS_RX1024BYTE 0x2c --#define AR40XX_STATS_RX1518BYTE 0x30 --#define AR40XX_STATS_RXMAXBYTE 0x34 --#define AR40XX_STATS_RXTOOLONG 0x38 --#define AR40XX_STATS_RXGOODBYTE 0x3c --#define AR40XX_STATS_RXBADBYTE 0x44 --#define AR40XX_STATS_RXOVERFLOW 0x4c --#define AR40XX_STATS_FILTERED 0x50 --#define AR40XX_STATS_TXBROAD 0x54 --#define AR40XX_STATS_TXPAUSE 0x58 --#define AR40XX_STATS_TXMULTI 0x5c --#define AR40XX_STATS_TXUNDERRUN 0x60 --#define AR40XX_STATS_TX64BYTE 0x64 --#define AR40XX_STATS_TX128BYTE 0x68 --#define AR40XX_STATS_TX256BYTE 0x6c --#define AR40XX_STATS_TX512BYTE 0x70 --#define AR40XX_STATS_TX1024BYTE 0x74 --#define AR40XX_STATS_TX1518BYTE 0x78 --#define AR40XX_STATS_TXMAXBYTE 0x7c --#define AR40XX_STATS_TXOVERSIZE 0x80 --#define AR40XX_STATS_TXBYTE 0x84 --#define AR40XX_STATS_TXCOLLISION 0x8c --#define AR40XX_STATS_TXABORTCOL 0x90 --#define AR40XX_STATS_TXMULTICOL 0x94 --#define AR40XX_STATS_TXSINGLECOL 0x98 --#define AR40XX_STATS_TXEXCDEFER 0x9c --#define AR40XX_STATS_TXDEFER 0xa0 --#define AR40XX_STATS_TXLATECOL 0xa4 -- --#define AR40XX_REG_MODULE_EN 0x030 --#define AR40XX_MODULE_EN_MIB BIT(0) -- --#define AR40XX_REG_MIB_FUNC 0x034 --#define AR40XX_MIB_BUSY BIT(17) --#define AR40XX_MIB_CPU_KEEP BIT(20) --#define AR40XX_MIB_FUNC BITS(24, 3) --#define AR40XX_MIB_FUNC_S 24 --#define AR40XX_MIB_FUNC_NO_OP 0x0 --#define AR40XX_MIB_FUNC_FLUSH 0x1 -- --#define AR40XX_ESS_SERVICE_TAG 0x48 --#define AR40XX_ESS_SERVICE_TAG_STAG BIT(17) -- --#define AR40XX_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) --#define AR40XX_PORT_SPEED BITS(0, 2) --#define AR40XX_PORT_STATUS_SPEED_S 0 --#define AR40XX_PORT_TX_EN BIT(2) --#define AR40XX_PORT_RX_EN BIT(3) --#define AR40XX_PORT_STATUS_TXFLOW BIT(4) --#define AR40XX_PORT_STATUS_RXFLOW BIT(5) --#define AR40XX_PORT_DUPLEX BIT(6) --#define AR40XX_PORT_TXHALF_FLOW BIT(7) --#define AR40XX_PORT_STATUS_LINK_UP BIT(8) --#define AR40XX_PORT_AUTO_LINK_EN BIT(9) --#define AR40XX_PORT_STATUS_FLOW_CONTROL BIT(12) -- --#define AR40XX_REG_MAX_FRAME_SIZE 0x078 --#define AR40XX_MAX_FRAME_SIZE_MTU BITS(0, 14) -- --#define AR40XX_REG_PORT_HEADER(_i) (0x09c + (_i) * 4) -- --#define AR40XX_REG_EEE_CTRL 0x100 --#define AR40XX_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2) -- --#define AR40XX_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8) --#define AR40XX_PORT_VLAN0_DEF_SVID BITS(0, 12) --#define AR40XX_PORT_VLAN0_DEF_SVID_S 0 --#define AR40XX_PORT_VLAN0_DEF_CVID BITS(16, 12) --#define AR40XX_PORT_VLAN0_DEF_CVID_S 16 -- --#define AR40XX_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8) --#define AR40XX_PORT_VLAN1_CORE_PORT BIT(9) --#define AR40XX_PORT_VLAN1_PORT_TLS_MODE BIT(7) --#define AR40XX_PORT_VLAN1_PORT_VLAN_PROP BIT(6) --#define AR40XX_PORT_VLAN1_OUT_MODE BITS(12, 2) --#define AR40XX_PORT_VLAN1_OUT_MODE_S 12 --#define AR40XX_PORT_VLAN1_OUT_MODE_UNMOD 0 --#define AR40XX_PORT_VLAN1_OUT_MODE_UNTAG 1 --#define AR40XX_PORT_VLAN1_OUT_MODE_TAG 2 --#define AR40XX_PORT_VLAN1_OUT_MODE_UNTOUCH 3 -- --#define AR40XX_REG_VTU_FUNC0 0x0610 --#define AR40XX_VTU_FUNC0_EG_MODE BITS(4, 14) --#define AR40XX_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) --#define AR40XX_VTU_FUNC0_EG_MODE_KEEP 0 --#define AR40XX_VTU_FUNC0_EG_MODE_UNTAG 1 --#define AR40XX_VTU_FUNC0_EG_MODE_TAG 2 --#define AR40XX_VTU_FUNC0_EG_MODE_NOT 3 --#define AR40XX_VTU_FUNC0_IVL BIT(19) --#define AR40XX_VTU_FUNC0_VALID BIT(20) -- --#define AR40XX_REG_VTU_FUNC1 0x0614 --#define AR40XX_VTU_FUNC1_OP BITS(0, 3) --#define AR40XX_VTU_FUNC1_OP_NOOP 0 --#define AR40XX_VTU_FUNC1_OP_FLUSH 1 --#define AR40XX_VTU_FUNC1_OP_LOAD 2 --#define AR40XX_VTU_FUNC1_OP_PURGE 3 --#define AR40XX_VTU_FUNC1_OP_REMOVE_PORT 4 --#define AR40XX_VTU_FUNC1_OP_GET_NEXT 5 --#define AR40XX7_VTU_FUNC1_OP_GET_ONE 6 --#define AR40XX_VTU_FUNC1_FULL BIT(4) --#define AR40XX_VTU_FUNC1_PORT BIT(8, 4) --#define AR40XX_VTU_FUNC1_PORT_S 8 --#define AR40XX_VTU_FUNC1_VID BIT(16, 12) --#define AR40XX_VTU_FUNC1_VID_S 16 --#define AR40XX_VTU_FUNC1_BUSY BIT(31) -- --#define AR40XX_REG_FWD_CTRL0 0x620 --#define AR40XX_FWD_CTRL0_CPU_PORT_EN BIT(10) --#define AR40XX_FWD_CTRL0_MIRROR_PORT BITS(4, 4) --#define AR40XX_FWD_CTRL0_MIRROR_PORT_S 4 -- --#define AR40XX_REG_FWD_CTRL1 0x624 --#define AR40XX_FWD_CTRL1_UC_FLOOD BITS(0, 7) --#define AR40XX_FWD_CTRL1_UC_FLOOD_S 0 --#define AR40XX_FWD_CTRL1_MC_FLOOD BITS(8, 7) --#define AR40XX_FWD_CTRL1_MC_FLOOD_S 8 --#define AR40XX_FWD_CTRL1_BC_FLOOD BITS(16, 7) --#define AR40XX_FWD_CTRL1_BC_FLOOD_S 16 --#define AR40XX_FWD_CTRL1_IGMP BITS(24, 7) --#define AR40XX_FWD_CTRL1_IGMP_S 24 -- --#define AR40XX_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc) --#define AR40XX_PORT_LOOKUP_MEMBER BITS(0, 7) --#define AR40XX_PORT_LOOKUP_IN_MODE BITS(8, 2) --#define AR40XX_PORT_LOOKUP_IN_MODE_S 8 --#define AR40XX_PORT_LOOKUP_STATE BITS(16, 3) --#define AR40XX_PORT_LOOKUP_STATE_S 16 --#define AR40XX_PORT_LOOKUP_LEARN BIT(20) --#define AR40XX_PORT_LOOKUP_LOOPBACK BIT(21) --#define AR40XX_PORT_LOOKUP_ING_MIRROR_EN BIT(25) -- --#define AR40XX_REG_ATU_FUNC 0x60c --#define AR40XX_ATU_FUNC_OP BITS(0, 4) --#define AR40XX_ATU_FUNC_OP_NOOP 0x0 --#define AR40XX_ATU_FUNC_OP_FLUSH 0x1 --#define AR40XX_ATU_FUNC_OP_LOAD 0x2 --#define AR40XX_ATU_FUNC_OP_PURGE 0x3 --#define AR40XX_ATU_FUNC_OP_FLUSH_LOCKED 0x4 --#define AR40XX_ATU_FUNC_OP_FLUSH_UNICAST 0x5 --#define AR40XX_ATU_FUNC_OP_GET_NEXT 0x6 --#define AR40XX_ATU_FUNC_OP_SEARCH_MAC 0x7 --#define AR40XX_ATU_FUNC_OP_CHANGE_TRUNK 0x8 --#define AR40XX_ATU_FUNC_BUSY BIT(31) -- --#define AR40XX_REG_QM_DEBUG_ADDR 0x820 --#define AR40XX_REG_QM_DEBUG_VALUE 0x824 --#define AR40XX_REG_QM_PORT0_3_QNUM 0x1d --#define AR40XX_REG_QM_PORT4_6_QNUM 0x1e -- --#define AR40XX_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) --#define AR40XX_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) -- --#define AR40XX_REG_PORT_FLOWCTRL_THRESH(_i) (0x9b0 + (_i) * 0x4) --#define AR40XX_PORT0_FC_THRESH_ON_DFLT 0x60 --#define AR40XX_PORT0_FC_THRESH_OFF_DFLT 0x90 -- --#define AR40XX_PHY_DEBUG_0 0 --#define AR40XX_PHY_MANU_CTRL_EN BIT(12) -- --#define AR40XX_PHY_DEBUG_2 2 -- --#define AR40XX_PHY_SPEC_STATUS 0x11 --#define AR40XX_PHY_SPEC_STATUS_LINK BIT(10) --#define AR40XX_PHY_SPEC_STATUS_DUPLEX BIT(13) --#define AR40XX_PHY_SPEC_STATUS_SPEED BITS(14, 2) -- --/* port forwarding state */ --enum { -- AR40XX_PORT_STATE_DISABLED = 0, -- AR40XX_PORT_STATE_BLOCK = 1, -- AR40XX_PORT_STATE_LISTEN = 2, -- AR40XX_PORT_STATE_LEARN = 3, -- AR40XX_PORT_STATE_FORWARD = 4 --}; -- --/* ingress 802.1q mode */ --enum { -- AR40XX_IN_PORT_ONLY = 0, -- AR40XX_IN_PORT_FALLBACK = 1, -- AR40XX_IN_VLAN_ONLY = 2, -- AR40XX_IN_SECURE = 3 --}; -- --/* egress 802.1q mode */ --enum { -- AR40XX_OUT_KEEP = 0, -- AR40XX_OUT_STRIP_VLAN = 1, -- AR40XX_OUT_ADD_VLAN = 2 --}; -- --/* port speed */ --enum { -- AR40XX_PORT_SPEED_10M = 0, -- AR40XX_PORT_SPEED_100M = 1, -- AR40XX_PORT_SPEED_1000M = 2, -- AR40XX_PORT_SPEED_ERR = 3, --}; -- --#define AR40XX_MIB_WORK_DELAY 2000 /* msecs */ -- --#define AR40XX_QM_WORK_DELAY 100 -- --#define AR40XX_MIB_FUNC_CAPTURE 0x3 -- --#define AR40XX_REG_PORT_STATS_START 0x1000 --#define AR40XX_REG_PORT_STATS_LEN 0x100 -- --#define AR40XX_PORTS_ALL 0x3f -- --#define AR40XX_PSGMII_ID 5 --#define AR40XX_PSGMII_CALB_NUM 100 --#define AR40XX_MALIBU_PSGMII_MODE_CTRL 0x6d --#define AR40XX_MALIBU_PHY_PSGMII_MODE_CTRL_ADJUST_VAL 0x220c --#define AR40XX_MALIBU_PHY_MMD7_DAC_CTRL 0x801a --#define AR40XX_MALIBU_DAC_CTRL_MASK 0x380 --#define AR40XX_MALIBU_DAC_CTRL_VALUE 0x280 --#define AR40XX_MALIBU_PHY_RLP_CTRL 0x805a --#define AR40XX_PSGMII_TX_DRIVER_1_CTRL 0xb --#define AR40XX_MALIBU_PHY_PSGMII_REDUCE_SERDES_TX_AMP 0x8a --#define AR40XX_MALIBU_PHY_LAST_ADDR 4 -- --static inline struct ar40xx_priv * --swdev_to_ar40xx(struct switch_dev *swdev) --{ -- return container_of(swdev, struct ar40xx_priv, dev); --} -- --#endif -- ---- a/target/linux/ipq40xx/patches-5.10/702-dts-ipq4019-add-PHY-switch-nodes.patch -+++ /dev/null -@@ -1,46 +0,0 @@ --From 9deeec35dd3b628b95624e41d4e04acf728991ba Mon Sep 17 00:00:00 2001 --From: Christian Lamparter --Date: Sun, 20 Nov 2016 02:20:54 +0100 --Subject: [PATCH] dts: ipq4019: add PHY/switch nodes -- --This patch adds both the "qcom,ess-switch" and "qcom,ess-psgmii" --nodes which are needed for the ar40xx.c driver to initialize the --switch. -- --Signed-off-by: Christian Lamparter ----- -- arch/arm/boot/dts/qcom-ipq4019.dtsi | 23 +++++++++++++++++++++++ -- 1 file changed, 23 insertions(+) -- ----- a/arch/arm/boot/dts/qcom-ipq4019.dtsi --+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi --@@ -617,6 +617,29 @@ -- }; -- }; -- --+ ess-switch@c000000 { --+ compatible = "qcom,ess-switch"; --+ reg = <0xc000000 0x80000>; --+ switch_access_mode = "local bus"; --+ resets = <&gcc ESS_RESET>; --+ reset-names = "ess_rst"; --+ clocks = <&gcc GCC_ESS_CLK>; --+ clock-names = "ess_clk"; --+ switch_cpu_bmp = <0x1>; --+ switch_lan_bmp = <0x1e>; --+ switch_wan_bmp = <0x20>; --+ switch_mac_mode = <0>; /* PORT_WRAPPER_PSGMII */ --+ switch_initvlas = <0x7c 0x54>; --+ status = "disabled"; --+ }; --+ --+ ess-psgmii@98000 { --+ compatible = "qcom,ess-psgmii"; --+ reg = <0x98000 0x800>; --+ psgmii_access_mode = "local bus"; --+ status = "disabled"; --+ }; --+ -- usb3_ss_phy: ssphy@9a000 { -- compatible = "qcom,usb-ss-ipq4019-phy"; -- #phy-cells = <0>; - ---- a/target/linux/ipq40xx/patches-5.10/703-net-IPQ4019-needs-rfs-vlan_tag-callbacks-in.patch -+++ /dev/null -@@ -1,53 +0,0 @@ --From 7c129254adb1093d10a62ed7bf7b956fcc6ffe34 Mon Sep 17 00:00:00 2001 --From: Rakesh Nair --Date: Wed, 20 Jul 2016 15:02:01 +0530 --Subject: [PATCH] net: IPQ4019 needs rfs/vlan_tag callbacks in -- netdev_ops -- --Add callback support to get default vlan tag and register --receive flow steering filter. -- --Used by IPQ4019 ess-edma driver. -- --BUG=chrome-os-partner:33096 --TEST=none -- --Change-Id: I266070e4a0fbe4a0d9966fe79a71e50ec4f26c75 --Signed-off-by: Rakesh Nair --Reviewed-on: https://chromium-review.googlesource.com/362203 --Commit-Ready: Grant Grundler --Tested-by: Grant Grundler --Reviewed-by: Grant Grundler ----- -- include/linux/netdevice.h | 13 +++++++++++++ -- 1 file changed, 13 insertions(+) -- ----- a/include/linux/netdevice.h --+++ b/include/linux/netdevice.h --@@ -788,6 +788,16 @@ struct xps_map { -- #define XPS_MIN_MAP_ALLOC ((L1_CACHE_ALIGN(offsetof(struct xps_map, queues[1])) \ -- - sizeof(struct xps_map)) / sizeof(u16)) -- --+#ifdef CONFIG_RFS_ACCEL --+typedef int (*set_rfs_filter_callback_t)(struct net_device *dev, --+ __be32 src, --+ __be32 dst, --+ __be16 sport, --+ __be16 dport, --+ u8 proto, --+ u16 rxq_index, --+ u32 action); --+#endif -- /* -- * This structure holds all XPS maps for device. Maps are indexed by CPU. -- */ --@@ -1475,6 +1485,9 @@ struct net_device_ops { -- const struct sk_buff *skb, -- u16 rxq_index, -- u32 flow_id); --+ int (*ndo_register_rfs_filter)(struct net_device *dev, --+ set_rfs_filter_callback_t set_filter); --+ int (*ndo_get_default_vlan_tag)(struct net_device *net); -- #endif -- int (*ndo_add_slave)(struct net_device *dev, -- struct net_device *slave_dev, ---- a/target/linux/ipq40xx/patches-5.10/705-net-add-qualcomm-ar40xx-phy.patch -+++ /dev/null -@@ -1,27 +0,0 @@ ----- a/drivers/net/mdio/Kconfig --+++ b/drivers/net/mdio/Kconfig --@@ -27,6 +27,13 @@ config OF_MDIO -- help -- OpenFirmware MDIO bus (Ethernet PHY) accessors -- --+config AR40XX_PHY --+ tristate "Driver for Qualcomm Atheros IPQ40XX switches" --+ depends on HAS_IOMEM && OF && OF_MDIO --+ select SWCONFIG --+ help --+ This is the driver for Qualcomm Atheros IPQ40XX ESS switches. --+ -- if MDIO_BUS -- -- config MDIO_DEVRES ----- a/drivers/net/mdio/Makefile --+++ b/drivers/net/mdio/Makefile --@@ -21,6 +21,8 @@ obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i. -- obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o -- obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o -- --+obj-$(CONFIG_AR40XX_PHY) += ar40xx.o --+ -- obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o -- obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC) += mdio-mux-bcm-iproc.o -- obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o ---- a/target/linux/ipq40xx/patches-5.10/710-net-add-qualcomm-essedma-ethernet-driver.patch -+++ /dev/null -@@ -1,37 +0,0 @@ --From 12e9319da1adacac92930c899c99f0e1970cac11 Mon Sep 17 00:00:00 2001 --From: Christian Lamparter --Date: Thu, 19 Jan 2017 02:01:31 +0100 --Subject: [PATCH 33/38] NET: add qualcomm essedma ethernet driver -- --Signed-off-by: Christian Lamparter ----- -- drivers/net/ethernet/qualcomm/Kconfig | 9 +++++++++ -- drivers/net/ethernet/qualcomm/Makefile | 1 + -- 2 files changed, 10 insertions(+) -- ----- a/drivers/net/ethernet/qualcomm/Kconfig --+++ b/drivers/net/ethernet/qualcomm/Kconfig --@@ -62,4 +62,14 @@ config QCOM_EMAC -- -- source "drivers/net/ethernet/qualcomm/rmnet/Kconfig" -- --+config ESSEDMA --+ tristate "Qualcomm Atheros ESS Edma support" --+ depends on OF_MDIO --+ help --+ This driver supports ethernet edma adapter. --+ Say Y to build this driver. --+ --+ To compile this driver as a module, choose M here. The module --+ will be called essedma.ko. --+ -- endif # NET_VENDOR_QUALCOMM ----- a/drivers/net/ethernet/qualcomm/Makefile --+++ b/drivers/net/ethernet/qualcomm/Makefile --@@ -10,5 +10,6 @@ obj-$(CONFIG_QCA7000_UART) += qcauart.o -- qcauart-objs := qca_uart.o -- -- obj-y += emac/ --+obj-$(CONFIG_ESSEDMA) += essedma/ -- -- obj-$(CONFIG_RMNET) += rmnet/ ---- a/target/linux/ipq40xx/patches-5.10/711-dts-ipq4019-add-ethernet-essedma-node.patch -+++ /dev/null -@@ -1,92 +0,0 @@ --From c611d3780fa101662a822d10acf8feb04ca97409 Mon Sep 17 00:00:00 2001 --From: Christian Lamparter --Date: Sun, 20 Nov 2016 01:01:10 +0100 --Subject: [PATCH] dts: ipq4019: add ethernet essedma node -- --This patch adds the device-tree node for the ethernet --interfaces. -- --Note: The driver isn't anywhere close to be upstream, --so the info might change. -- --Signed-off-by: Christian Lamparter ----- -- arch/arm/boot/dts/qcom-ipq4019.dtsi | 60 +++++++++++++++++++++++++++++++++++++ -- 1 file changed, 60 insertions(+) -- ----- a/arch/arm/boot/dts/qcom-ipq4019.dtsi --+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi --@@ -39,6 +39,8 @@ -- spi1 = &blsp1_spi2; -- i2c0 = &blsp1_i2c3; -- i2c1 = &blsp1_i2c4; --+ ethernet0 = &gmac0; --+ ethernet1 = &gmac1; -- }; -- -- cpus { --@@ -658,6 +660,64 @@ -- status = "disabled"; -- }; -- --+ edma@c080000 { --+ compatible = "qcom,ess-edma"; --+ reg = <0xc080000 0x8000>; --+ qcom,page-mode = <0>; --+ qcom,rx_head_buf_size = <1540>; --+ qcom,mdio_supported; --+ qcom,poll_required = <1>; --+ qcom,num_gmac = <2>; --+ interrupts = <0 65 IRQ_TYPE_EDGE_RISING --+ 0 66 IRQ_TYPE_EDGE_RISING --+ 0 67 IRQ_TYPE_EDGE_RISING --+ 0 68 IRQ_TYPE_EDGE_RISING --+ 0 69 IRQ_TYPE_EDGE_RISING --+ 0 70 IRQ_TYPE_EDGE_RISING --+ 0 71 IRQ_TYPE_EDGE_RISING --+ 0 72 IRQ_TYPE_EDGE_RISING --+ 0 73 IRQ_TYPE_EDGE_RISING --+ 0 74 IRQ_TYPE_EDGE_RISING --+ 0 75 IRQ_TYPE_EDGE_RISING --+ 0 76 IRQ_TYPE_EDGE_RISING --+ 0 77 IRQ_TYPE_EDGE_RISING --+ 0 78 IRQ_TYPE_EDGE_RISING --+ 0 79 IRQ_TYPE_EDGE_RISING --+ 0 80 IRQ_TYPE_EDGE_RISING --+ 0 240 IRQ_TYPE_EDGE_RISING --+ 0 241 IRQ_TYPE_EDGE_RISING --+ 0 242 IRQ_TYPE_EDGE_RISING --+ 0 243 IRQ_TYPE_EDGE_RISING --+ 0 244 IRQ_TYPE_EDGE_RISING --+ 0 245 IRQ_TYPE_EDGE_RISING --+ 0 246 IRQ_TYPE_EDGE_RISING --+ 0 247 IRQ_TYPE_EDGE_RISING --+ 0 248 IRQ_TYPE_EDGE_RISING --+ 0 249 IRQ_TYPE_EDGE_RISING --+ 0 250 IRQ_TYPE_EDGE_RISING --+ 0 251 IRQ_TYPE_EDGE_RISING --+ 0 252 IRQ_TYPE_EDGE_RISING --+ 0 253 IRQ_TYPE_EDGE_RISING --+ 0 254 IRQ_TYPE_EDGE_RISING --+ 0 255 IRQ_TYPE_EDGE_RISING>; --+ --+ status = "disabled"; --+ --+ gmac0: gmac0 { --+ local-mac-address = [00 00 00 00 00 00]; --+ vlan_tag = <1 0x1f>; --+ }; --+ --+ gmac1: gmac1 { --+ local-mac-address = [00 00 00 00 00 00]; --+ qcom,phy_mdio_addr = <4>; --+ qcom,poll_required = <1>; --+ qcom,forced_speed = <1000>; --+ qcom,forced_duplex = <1>; --+ vlan_tag = <2 0x20>; --+ }; --+ }; --+ -- usb3_ss_phy: ssphy@9a000 { -- compatible = "qcom,usb-ss-ipq4019-phy"; -- #phy-cells = <0>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-a42.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-a42.dts -@@ -21,10 +21,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@194b000 { - /* select hostmode */ - compatible = "qcom,tcsr"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-a42.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-a42.dts -@@ -62,14 +58,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-a42.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-a42.dts -@@ -174,22 +162,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <2 0x20>; --}; -- --&gmac1 { -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x10>; --}; -- - &usb2_hs_phy { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts -@@ -65,10 +65,6 @@ - pinctrl-names = "default"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - counter@4a1000 { - compatible = "qcom,qca-gcnt"; - reg = <0x4a1000 0x4>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts -@@ -118,17 +114,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- -- switch_lan_bmp = <0x10>; -- switch_wan_bmp = <0x20>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - }; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ap120c-ac.dts -@@ -277,22 +262,6 @@ - #gpio-cells = <2>; - }; - --&gmac0 { -- qcom,forced_duplex = <1>; -- qcom,forced_speed = <1000>; -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- vlan_tag = <1 0x10>; --}; -- --&gmac1 { -- qcom,forced_duplex = <1>; -- qcom,forced_speed = <1000>; -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- vlan_tag = <2 0x20>; --}; -- - &tlmm { - i2c0_pins: i2c0_pinmux { - mux_i2c { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cap-ac.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cap-ac.dts -@@ -61,16 +61,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- qcom,poll_required = <0>; -- qcom,num_gmac = <1>; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cap-ac.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cap-ac.dts -@@ -222,10 +212,6 @@ - status = "okay"; - }; - --&gmac0 { -- vlan_tag = <0 0x3f>; --}; -- - ðphy3 { - gpio-controller; - #gpio-cells = <2>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts -@@ -29,10 +29,6 @@ - reset-delay-us = <5000>; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts -@@ -64,14 +60,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - leds { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts -@@ -264,13 +252,3 @@ - nvmem-cell-names = "pre-calibration"; - nvmem-cells = <&precal_art_5000>; - }; -- --&gmac0 { -- nvmem-cell-names = "mac-address"; -- nvmem-cells = <&macaddr_art_6>; --}; -- --&gmac1 { -- nvmem-cell-names = "mac-address"; -- nvmem-cells = <&macaddr_art_0>; --}; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-dap-2610.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-dap-2610.dts -@@ -17,11 +17,6 @@ - }; - - soc { -- edma@c080000 { -- qcom,num_gmac = <1>; -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-dap-2610.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-dap-2610.dts -@@ -51,16 +46,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x20>; -- switch_wan_bmp = <0x00>; -- }; -- -- ess-psgmii@98000 { -- status = "okay"; -- }; - }; - - leds { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-dap-2610.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-dap-2610.dts -@@ -192,14 +177,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x20>; --}; -- - &mdio { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts -@@ -25,10 +25,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ea6350v3.dts -@@ -68,14 +64,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts -@@ -18,10 +18,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts -@@ -47,14 +43,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-eap1300.dts -@@ -227,14 +215,6 @@ - status = "okay"; - }; - --&gmac0 { -- vlan_tag = <2 0x20>; --}; -- --&gmac1 { -- vlan_tag = <1 0x10>; --}; -- - &wifi0 { - status = "okay"; - nvmem-cell-names = "pre-calibration"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ecw5211.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ecw5211.dts -@@ -14,7 +14,6 @@ - led-failsafe = &led_power; - led-running = &led_power; - led-upgrade = &led_power; -- label-mac-device = &gmac0; - }; - - chosen { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ecw5211.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ecw5211.dts -@@ -57,10 +56,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - counter@4a1000 { - compatible = "qcom,qca-gcnt"; - reg = <0x4a1000 0x4>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ecw5211.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ecw5211.dts -@@ -110,17 +105,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- -- switch_lan_bmp = <0x10>; -- switch_wan_bmp = <0x20>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - }; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ecw5211.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ecw5211.dts -@@ -303,18 +287,6 @@ - pinctrl-names = "default"; - }; - --&gmac0 { -- qcom,poll_required = <1>; -- qcom,phy_mdio_addr = <4>; -- vlan_tag = <2 0x20>; --}; -- --&gmac1 { -- qcom,poll_required = <1>; -- qcom,phy_mdio_addr = <3>; -- vlan_tag = <1 0x10>; --}; -- - &wifi0 { - status = "okay"; - nvmem-cell-names = "pre-calibration"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emd1.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emd1.dts -@@ -25,10 +25,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emd1.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emd1.dts -@@ -54,17 +50,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x20>; -- switch_wan_bmp = <0x00>; -- }; -- -- edma@c080000 { -- status = "okay"; -- qcom,num_gmac = <1>; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emd1.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emd1.dts -@@ -210,14 +195,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x20>; --}; -- - &cryptobam { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emr3500.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emr3500.dts -@@ -18,10 +18,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emr3500.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emr3500.dts -@@ -51,14 +47,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emr3500.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-emr3500.dts -@@ -212,14 +200,6 @@ - status = "okay"; - }; - --&gmac0 { -- vlan_tag = <1 0x10>; --}; -- --&gmac1 { -- vlan_tag = <2 0x20>; --}; -- - &usb2_hs_phy { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ens620ext.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ens620ext.dts -@@ -26,14 +26,6 @@ - status = "okay"; - }; - -- mdio@90000 { -- status = "okay"; -- }; -- -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ens620ext.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ens620ext.dts -@@ -60,14 +52,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; -- - /* - * Disable the broken restart as a workaround for the buggy - * 3.0.0/3.0.1 U-boots that ship with the device. ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi -@@ -33,10 +33,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi -@@ -62,15 +58,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- qcom,num_gmac = <1>; -- }; - }; - - aliases { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-ex61x0v2.dtsi -@@ -78,7 +65,6 @@ - led-failsafe = &power_amber; - led-running = &power_green; - led-upgrade = &power_amber; -- label-mac-device = &gmac0; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-fritzbox-4040.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-fritzbox-4040.dts -@@ -14,7 +14,6 @@ - led-failsafe = &flash; - led-running = &power; - led-upgrade = &flash; -- label-mac-device = &gmac0; - }; - - soc { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-fritzbox-4040.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-fritzbox-4040.dts -@@ -26,10 +25,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-fritzbox-4040.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-fritzbox-4040.dts -@@ -69,14 +64,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-gl-ap1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-gl-ap1300.dts -@@ -34,10 +34,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-gl-ap1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-gl-ap1300.dts -@@ -79,16 +75,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x18>; -- switch_wan_bmp = <0x20>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-hap-ac2.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-hap-ac2.dts -@@ -78,14 +78,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dtsi -@@ -19,10 +19,6 @@ - pinctrl-names = "default"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - counter@4a1000 { - compatible = "qcom,qca-gcnt"; - reg = <0x4a1000 0x4>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dtsi -@@ -69,16 +65,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- -- switch_lan_bmp = <0x10>; /* lan port bitmap */ -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - }; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-jalapeno.dtsi -@@ -241,20 +227,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,poll_required = <1>; -- qcom,poll_required_dynamic = <1>; -- qcom,phy_mdio_addr = <3>; -- vlan_tag = <1 0x10>; --}; -- --&gmac1 { -- qcom,poll_required = <1>; -- qcom,poll_required_dynamic = <1>; -- qcom,phy_mdio_addr = <4>; -- vlan_tag = <2 0x20>; --}; -- - &wifi0 { - status = "okay"; - nvmem-cell-names = "pre-calibration"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-magic-2-wifi-next.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-magic-2-wifi-next.dts -@@ -29,10 +29,6 @@ - /delete-node/ ethernet-phy@1; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - crypto@8e3a000 { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-magic-2-wifi-next.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-magic-2-wifi-next.dts -@@ -41,42 +37,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x3e>; -- switch_wan_bmp = <0x0>; -- }; -- -- edma@c080000 { -- status = "okay"; -- qcom,num_gmac = <3>; -- -- gmac0 { -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- /delete-property/ qcom,forced_speed; -- /delete-property/ qcom,forced_duplex; -- vlan_tag = <1 0x10>; -- }; -- -- gmac1 { -- qcom,phy_mdio_addr = <2>; -- qcom,poll_required = <1>; -- /delete-property/ qcom,forced_speed; -- /delete-property/ qcom,forced_duplex; -- vlan_tag = <1 0x08>; -- }; -- -- gmac2 { -- local-mac-address = [00 00 00 00 00 00]; -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- /delete-property/ qcom,forced_speed; -- /delete-property/ qcom,forced_duplex; -- vlan_tag = <1 0x20>; -- }; -- }; -- - gpio_export { - compatible = "gpio-export"; - #size-cells = <0>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts -@@ -35,10 +35,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-nbg6617.dts -@@ -103,14 +99,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts -@@ -21,10 +21,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@194b000 { - /* select hostmode */ - compatible = "qcom,tcsr"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts -@@ -62,14 +58,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts -@@ -166,22 +154,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <2 0x20>; --}; -- --&gmac1 { -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x10>; --}; -- - &usb2_hs_phy { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts -@@ -30,10 +30,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-rt-ac58u.dts -@@ -84,14 +80,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-rutx.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-rutx.dtsi -@@ -6,10 +6,6 @@ - #include - - / { -- aliases { -- label-mac-device = &gmac0; -- }; -- - memory { - device_type = "memory"; - reg = <0x80000000 0x10000000>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-sxtsq-5-ac.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-sxtsq-5-ac.dts -@@ -65,17 +65,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-psgmii@98000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- phy-mode = "rgmii"; -- qcom,num_gmac = <1>; -- qcom,single-phy; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-sxtsq-5-ac.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-sxtsq-5-ac.dts -@@ -228,14 +217,6 @@ - qcom,ath10k-calibration-variant = "MikroTik-SXTsq-5-ac"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x20>; --}; -- - &mdio { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wac510.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wac510.dts -@@ -16,7 +16,6 @@ - led-failsafe = &led_power_amber; - led-running = &led_power_green; - led-upgrade = &led_power_amber; -- label-mac-device = &gmac0; - }; - - chosen { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wac510.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wac510.dts -@@ -28,10 +27,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - counter@4a1000 { - compatible = "qcom,qca-gcnt"; - reg = <0x4a1000 0x4>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wac510.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wac510.dts -@@ -62,14 +57,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wac510.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wac510.dts -@@ -358,14 +345,6 @@ - reset-delay-us = <2000>; - }; - --&gmac0 { -- qcom,forced_duplex = <1>; -- qcom,forced_speed = <1000>; -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- vlan_tag = <1 0x10>; --}; -- - &wifi0 { - status = "okay"; - nvmem-cell-names = "pre-calibration", "mac-address"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts -@@ -44,10 +44,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wre6606.dts -@@ -73,15 +69,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- qcom,num_gmac = <1>; -- }; - }; - - leds { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -@@ -53,10 +53,6 @@ - /delete-node/ ethernet-phy@3; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -@@ -96,17 +92,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- -- switch_lan_bmp = <0x1e>; -- switch_wan_bmp = <0x20>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - }; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -@@ -224,16 +209,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <2>; -- qcom,poll_required = <1>; --}; -- --&gmac1 { -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; --}; -- - &tlmm { - serial0_pins: serial0_pinmux { - mux { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-a62.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-a62.dts -@@ -21,10 +21,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@194b000 { - /* select hostmode */ - compatible = "qcom,tcsr"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-a62.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-a62.dts -@@ -62,17 +58,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- switch_lan_bmp = <0x10>; -- switch_wan_bmp = <0x20>; -- -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-a62.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-a62.dts -@@ -184,14 +169,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x10>; --}; -- - &usb2_hs_phy { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-cm520-79f.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-cm520-79f.dts -@@ -29,10 +29,6 @@ - reset-delay-us = <1000>; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-cm520-79f.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-cm520-79f.dts -@@ -97,14 +93,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - led_spi { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-cm520-79f.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-cm520-79f.dts -@@ -196,16 +184,6 @@ - status = "okay"; - }; - --&gmac0 { -- nvmem-cells = <&macaddr_art_1006>; -- nvmem-cell-names = "mac-address"; --}; -- --&gmac1 { -- nvmem-cells = <&macaddr_art_5006>; -- nvmem-cell-names = "mac-address"; --}; -- - &nand { - pinctrl-0 = <&nand_pins>; - pinctrl-names = "default"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-e2600ac.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-e2600ac.dtsi -@@ -30,10 +30,6 @@ - pinctrl-names = "default"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-e2600ac.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-e2600ac.dtsi -@@ -120,14 +116,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; -- - leds { - compatible = "gpio-leds"; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-eap2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-eap2200.dts -@@ -76,10 +76,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - crypto@8e3a000 { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-eap2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-eap2200.dts -@@ -87,15 +83,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x10>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - }; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-eap2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-eap2200.dts -@@ -189,10 +176,6 @@ - status = "okay"; - }; - --&gmac0 { -- vlan_tag = <1 0x10>; --}; -- - &nand { - pinctrl-0 = <&nand_pins>; - pinctrl-names = "default"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzbox-7530.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzbox-7530.dts -@@ -25,10 +25,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzbox-7530.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzbox-7530.dts -@@ -64,15 +60,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- qcom,num_gmac = <1>; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -@@ -59,19 +59,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- switch_mac_mode = <0x3>; /* mac mode for RGMII RMII */ -- switch_lan_bmp = <0x0>; /* lan port bitmap */ -- switch_wan_bmp = <0x10>; /* wan port bitmap */ -- }; -- -- edma@c080000 { -- status = "okay"; -- phy-mode = "rgmii-id"; -- qcom,num_gmac = <1>; -- qcom,single-phy; -- }; - }; - - key { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -@@ -265,9 +252,3 @@ - status = "okay"; - qcom,ath10k-calibration-variant = "AVM-FRITZRepeater-1200"; - }; -- --&gmac0 { -- qcom,phy_mdio_addr = <0>; -- qcom,poll_required = <1>; -- vlan_tag = <0 0x20>; --}; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-3000.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-3000.dts -@@ -25,10 +25,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-3000.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-3000.dts -@@ -54,18 +50,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- -- switch_lan_bmp = <0x30>; -- switch_wan_bmp = <0x02>; -- }; -- -- edma@c080000 { -- status = "okay"; -- qcom,num_gmac = <1>; -- }; - }; - - key { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-3000.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-3000.dts -@@ -210,10 +194,6 @@ - }; - }; - --&gmac0 { -- vlan_tag = <1 0x30>; --}; -- - &cryptobam { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gl-b2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gl-b2200.dts -@@ -27,10 +27,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gl-b2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gl-b2200.dts -@@ -60,16 +56,6 @@ - crypto@8e3a000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x2e>; -- switch_wan_bmp = <0x10>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gl-b2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-gl-b2200.dts -@@ -113,18 +99,6 @@ - }; - }; - --&gmac1 { -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <2 0x10>; --}; -- --&gmac0 { -- vlan_tag = <1 0x2e>; --}; -- - &vqmmc { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-habanero-dvk.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-habanero-dvk.dts -@@ -29,10 +29,6 @@ - pinctrl-names = "default"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - counter@4a1000 { - compatible = "qcom,qca-gcnt"; - reg = <0x4a1000 0x4>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-habanero-dvk.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-habanero-dvk.dts -@@ -79,14 +75,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-hap-ac3.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-hap-ac3.dts -@@ -73,14 +73,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-lhgg-60ad.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-lhgg-60ad.dts -@@ -85,19 +85,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- switch_mac_mode = <0x3>; /* mac mode for RGMII RMII */ -- switch_lan_bmp = <0x0>; /* lan port bitmap */ -- switch_wan_bmp = <0x10>; /* wan port bitmap */ -- }; -- -- edma@c080000 { -- status = "okay"; -- phy-mode = "rgmii-id"; -- qcom,num_gmac = <1>; -- qcom,single-phy; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-lhgg-60ad.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-lhgg-60ad.dts -@@ -260,9 +247,3 @@ - }; - }; - }; -- --&gmac0 { -- qcom,phy_mdio_addr = <0>; -- qcom,poll_required = <1>; -- vlan_tag = <0 0x20>; --}; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts -@@ -26,10 +26,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-map-ac2200.dts -@@ -59,14 +55,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-mf286d.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-mf286d.dts -@@ -130,14 +130,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - }; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-mf286d.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-mf286d.dts -@@ -225,17 +217,6 @@ - status = "okay"; - }; - --&gmac0 { -- nvmem-cell-names = "mac-address"; -- nvmem-cells = <&macaddr_config_0>; --}; -- --&gmac1 { -- nvmem-cell-names = "mac-address"; -- nvmem-cells = <&macaddr_config_0>; -- mac-address-increment = <1>; --}; -- - &nand { - pinctrl-0 = <&nand_pins>; - pinctrl-names = "default"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-oap100.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-oap100.dts -@@ -27,10 +27,6 @@ - pinctrl-names = "default"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-oap100.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-oap100.dts -@@ -97,17 +93,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- switch_mac_mode = <0x0>; /* mac mode for RGMII RMII */ -- switch_initvlas = <0x0007c 0x54>; /* port0 status */ -- switch_lan_bmp = <0x10>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - key { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-orbi.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-orbi.dtsi -@@ -25,10 +25,6 @@ - pinctrl-names = "default"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - counter@4a1000 { - compatible = "qcom,qca-gcnt"; - reg = <0x4a1000 0x4>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-orbi.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-orbi.dtsi -@@ -67,17 +63,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- -- switch_lan_bmp = <0x1c>; -- switch_wan_bmp = <0x02>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-orbi.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-orbi.dtsi -@@ -281,15 +266,6 @@ - status = "okay"; - }; - --&gmac0 { -- vlan_tag = <1 0x1c>; --}; -- --&gmac1 { -- qcom,phy_mdio_addr = <0>; -- vlan_tag = <2 0x02>; --}; -- - &pcie0 { - status = "okay"; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts -@@ -21,10 +21,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts -@@ -50,17 +46,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- switch_lan_bmp = <0x10>; -- switch_wan_bmp = <0x20>; -- -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts -@@ -169,14 +154,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x10>; --}; -- - &pcie0 { - status = "okay"; - perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi -@@ -16,7 +16,6 @@ - led-failsafe = &led_sys; - led-running = &led_sys; - led-upgrade = &led_sys; -- label-mac-device = &gmac0; - }; - - soc { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi -@@ -30,10 +29,6 @@ - pinctrl-names = "default"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-r619ac.dtsi -@@ -73,14 +68,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - leds { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-rtl30vw.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-rtl30vw.dts -@@ -142,10 +142,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-rtl30vw.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-rtl30vw.dts -@@ -187,14 +183,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - }; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-u4019.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-u4019.dtsi -@@ -21,10 +21,6 @@ - reset-delay-us = <2000>; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-u4019.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-u4019.dtsi -@@ -87,14 +83,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; -- - aliases { - led-boot = &led_status; - led-failsafe = &led_status; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wpj419.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wpj419.dts -@@ -253,10 +253,6 @@ - reset-delay-us = <5000>; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@194b000 { - /* select hostmode */ - compatible = "qcom,tcsr"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wpj419.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wpj419.dts -@@ -333,16 +329,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- switch_lan_bmp = <0x1e>; -- switch_wan_bmp = <0x20>; -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; -- - qpic_bam: dma@7984000 { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wpj419.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wpj419.dts -@@ -371,22 +357,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <2 0x20>; --}; -- --&gmac1 { -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x10>; --}; -- - &wifi0 { - status = "okay"; - nvmem-cell-names = "pre-calibration"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wtr-m2133hp.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wtr-m2133hp.dts -@@ -32,7 +32,6 @@ - led-failsafe = &led_power_orange; - led-running = &led_power_white; - led-upgrade = &led_power_blue; -- label-mac-device = &gmac0; - }; - - soc { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wtr-m2133hp.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wtr-m2133hp.dts -@@ -73,19 +72,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x1c>; -- }; -- -- ess-psgmii@98000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; -- - usb3@8af8800 { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wtr-m2133hp.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-wtr-m2133hp.dts -@@ -438,16 +424,6 @@ - reset-gpios = <&tlmm 47 GPIO_ACTIVE_LOW>; - }; - --&gmac0 { -- nvmem-cells = <&macaddr_orgdata_20>; -- nvmem-cell-names = "mac-address"; --}; -- --&gmac1 { -- nvmem-cells = <&macaddr_orgdata_20>; -- nvmem-cell-names = "mac-address"; --}; -- - &usb3_ss_phy { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-x1pro.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-x1pro.dts -@@ -87,17 +87,3 @@ - }; - }; - }; -- --&gmac0 { -- status = "okay"; -- -- mtd-mac-address = <&art 0x5006>; -- mtd-mac-address-increment = <2>; --}; -- --&gmac1 { -- status = "okay"; -- -- mtd-mac-address = <&art 0x5006>; -- mtd-mac-address-increment = <3>; --}; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-x1pro.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-x1pro.dtsi -@@ -30,10 +30,6 @@ - reset-delay-us = <2000>; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-x1pro.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-x1pro.dtsi -@@ -96,14 +92,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; -- - leds { - compatible = "gpio-leds"; - pinctrl-0 = <&led_pins>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-xx8300.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-xx8300.dtsi -@@ -35,10 +35,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-xx8300.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-xx8300.dtsi -@@ -103,14 +99,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - }; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts -@@ -38,10 +38,6 @@ - reset-delay-us = <2000>; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@194b000 { - /* select hostmode */ - compatible = "qcom,tcsr"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts -@@ -83,17 +79,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- switch_lan_bmp = <0x10>; -- switch_wan_bmp = <0x20>; -- -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4028-wpj428.dts -@@ -262,22 +247,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <4>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <2 0x20>; --}; -- --&gmac1 { -- qcom,phy_mdio_addr = <3>; -- qcom,poll_required = <1>; -- qcom,forced_speed = <1000>; -- qcom,forced_duplex = <1>; -- vlan_tag = <1 0x10>; --}; -- - &usb3_ss_phy { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-ap-303h.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-ap-303h.dts -@@ -76,14 +76,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- status = "okay"; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; -- - i2c_0: i2c@78b7000 { - pinctrl-0 = <&i2c_0_pins>; - pinctrl-names = "default"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-aruba-glenmorangie.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-aruba-glenmorangie.dtsi -@@ -64,19 +64,6 @@ - status = "okay"; - }; - -- ess-switch@c000000 { -- switch_mac_mode = <0x3>; /* mac mode for RGMII RMII */ -- switch_lan_bmp = <0x0>; /* lan port bitmap */ -- switch_wan_bmp = <0x10>; /* wan port bitmap */ -- }; -- -- edma@c080000 { -- qcom,single-phy; -- qcom,num_gmac = <1>; -- phy-mode = "rgmii-id"; -- status = "okay"; -- }; -- - i2c_0: i2c@78b7000 { - pinctrl-0 = <&i2c_0_pins>; - pinctrl-names = "default"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-aruba-glenmorangie.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-aruba-glenmorangie.dtsi -@@ -123,12 +110,6 @@ - status = "okay"; - }; - --&gmac0 { -- qcom,phy_mdio_addr = <5>; -- qcom,poll_required = <1>; -- vlan_tag = <0 0x20>; --}; -- - &qpic_bam { - status = "okay"; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts -@@ -44,10 +44,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-gl-b1300.dts -@@ -89,16 +85,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x18>; -- switch_wan_bmp = <0x20>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-gl-s1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-gl-s1300.dts -@@ -30,10 +30,6 @@ - status = "okay"; - }; - -- ess-psgmii@98000 { -- status = "okay"; -- }; -- - tcsr@1949000 { - compatible = "qcom,tcsr"; - reg = <0x1949000 0x100>; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-gl-s1300.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-gl-s1300.dts -@@ -75,16 +71,6 @@ - watchdog@b017000 { - status = "okay"; - }; -- -- ess-switch@c000000 { -- status = "okay"; -- switch_lan_bmp = <0x18>; -- switch_wan_bmp = <0x20>; -- }; -- -- edma@c080000 { -- status = "okay"; -- }; - }; - - keys { ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -64,6 +64,8 @@ - - #define QCA807X_CHIP_CONFIGURATION 0x1f - #define QCA807X_BT_BX_REG_SEL BIT(15) -+#define QCA807X_BT_BX_REG_SEL_FIBER 0 -+#define QCA807X_BT_BX_REG_SEL_COPPER 1 - #define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0) - #define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4 - #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3 ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -400,19 +402,9 @@ static int qca807x_gpio(struct phy_device *phydev) - } - #endif - --static int qca807x_read_copper_status(struct phy_device *phydev, bool combo_port) -+static int qca807x_read_copper_status(struct phy_device *phydev) - { -- int ss, err, page, old_link = phydev->link; -- -- /* Only combo port has dual pages */ -- if (combo_port) { -- /* Check whether copper page is set and set if needed */ -- page = phy_read(phydev, QCA807X_CHIP_CONFIGURATION); -- if (!(page & QCA807X_BT_BX_REG_SEL)) { -- page |= QCA807X_BT_BX_REG_SEL; -- phy_write(phydev, QCA807X_CHIP_CONFIGURATION, page); -- } -- } -+ int ss, err, old_link = phydev->link; - - /* Update the link, but return if there was an error */ - err = genphy_update_link(phydev); ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -487,16 +479,9 @@ static int qca807x_read_copper_status(struct phy_device *phydev, bool combo_port - return 0; - } - --static int qca807x_read_fiber_status(struct phy_device *phydev, bool combo_port) -+static int qca807x_read_fiber_status(struct phy_device *phydev) - { -- int ss, err, page, lpa, old_link = phydev->link; -- -- /* Check whether fiber page is set and set if needed */ -- page = phy_read(phydev, QCA807X_CHIP_CONFIGURATION); -- if (page & QCA807X_BT_BX_REG_SEL) { -- page &= ~QCA807X_BT_BX_REG_SEL; -- phy_write(phydev, QCA807X_CHIP_CONFIGURATION, page); -- } -+ int ss, err, lpa, old_link = phydev->link; - - /* Update the link, but return if there was an error */ - err = genphy_update_link(phydev); ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -559,28 +544,17 @@ static int qca807x_read_fiber_status(struct phy_device *phydev, bool combo_port) - - static int qca807x_read_status(struct phy_device *phydev) - { -- int val; -- -- /* Check for Combo port */ -- if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { -- /* Check for fiber mode first */ -- if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { -- /* Check for actual detected media */ -- val = phy_read(phydev, QCA807X_MEDIA_SELECT_STATUS); -- if (val & QCA807X_MEDIA_DETECTED_COPPER) { -- qca807x_read_copper_status(phydev, true); -- } else if ((val & QCA807X_MEDIA_DETECTED_1000_BASE_X) || -- (val & QCA807X_MEDIA_DETECTED_100_BASE_FX)) { -- qca807x_read_fiber_status(phydev, true); -- } -- } else { -- qca807x_read_copper_status(phydev, true); -+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { -+ switch (phydev->port) { -+ case PORT_FIBRE: -+ return qca807x_read_fiber_status(phydev); -+ case PORT_TP: -+ return qca807x_read_copper_status(phydev); -+ default: -+ return -EINVAL; - } -- } else { -- qca807x_read_copper_status(phydev, false); -- } -- -- return 0; -+ } else -+ return qca807x_read_copper_status(phydev); - } - - static int qca807x_config_intr(struct phy_device *phydev) ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -683,9 +657,63 @@ static int qca807x_led_config(struct phy_device *phydev) - return 0; - } - -+static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -+{ -+ struct phy_device *phydev = upstream; -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; -+ phy_interface_t iface; -+ int ret; -+ -+ sfp_parse_support(phydev->sfp_bus, id, support); -+ iface = sfp_select_interface(phydev->sfp_bus, support); -+ -+ dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface)); -+ -+ switch (iface) { -+ case PHY_INTERFACE_MODE_1000BASEX: -+ case PHY_INTERFACE_MODE_100BASEX: -+ /* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */ -+ ret = phy_modify(phydev, -+ QCA807X_CHIP_CONFIGURATION, -+ QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK, -+ QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER); -+ /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */ -+ ret = phy_set_bits_mmd(phydev, -+ MDIO_MMD_AN, -+ QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION, -+ QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN); -+ /* Select fiber page */ -+ ret = phy_clear_bits(phydev, -+ QCA807X_CHIP_CONFIGURATION, -+ QCA807X_BT_BX_REG_SEL); -+ -+ phydev->port = PORT_FIBRE; -+ break; -+ default: -+ dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n"); -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static void qca807x_sfp_remove(void *upstream) -+{ -+ struct phy_device *phydev = upstream; -+ -+ /* Select copper page */ -+ phy_set_bits(phydev, -+ QCA807X_CHIP_CONFIGURATION, -+ QCA807X_BT_BX_REG_SEL); -+ -+ phydev->port = PORT_TP; -+} -+ - static const struct sfp_upstream_ops qca807x_sfp_ops = { - .attach = phy_sfp_attach, - .detach = phy_sfp_detach, -+ .module_insert = qca807x_sfp_insert, -+ .module_remove = qca807x_sfp_remove, - }; - - static int qca807x_config(struct phy_device *phydev) ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -696,28 +724,7 @@ static int qca807x_config(struct phy_device *phydev) - - /* Check for Combo port */ - if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { -- int fiber_mode_autodect; - int psgmii_serdes; -- int chip_config; -- -- if (of_property_read_bool(node, "qcom,fiber-enable")) { -- /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */ -- fiber_mode_autodect = phy_read_mmd(phydev, MDIO_MMD_AN, -- QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION); -- fiber_mode_autodect |= QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN; -- phy_write_mmd(phydev, MDIO_MMD_AN, QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION, -- fiber_mode_autodect); -- -- /* Enable 4 copper + combo port mode */ -- chip_config = phy_read(phydev, QCA807X_CHIP_CONFIGURATION); -- chip_config &= ~QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK; -- chip_config |= FIELD_PREP(QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK, -- QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER); -- phy_write(phydev, QCA807X_CHIP_CONFIGURATION, chip_config); -- -- linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); -- linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising); -- } - - /* Prevent PSGMII going into hibernation via PSGMII self test */ - psgmii_serdes = phy_read_mmd(phydev, MDIO_MMD_PCS, PSGMII_MMD3_SERDES_CONTROL); ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -761,9 +768,10 @@ static int qca807x_probe(struct phy_device *phydev) - } - - /* Attach SFP bus on combo port*/ -- if (of_property_read_bool(node, "qcom,fiber-enable")) { -- if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) -- ret = phy_sfp_probe(phydev, &qca807x_sfp_ops); -+ if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { -+ ret = phy_sfp_probe(phydev, &qca807x_sfp_ops); -+ linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); -+ linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising); - } - - return ret; - ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-magic-2-wifi-next.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-magic-2-wifi-next.dts -@@ -24,9 +24,6 @@ - pinctrl-names = "default"; - reset-gpios = <&tlmm 59 GPIO_ACTIVE_LOW>; - reset-delay-us = <2000>; -- -- /delete-node/ ethernet-phy@0; -- /delete-node/ ethernet-phy@1; - }; - - crypto@8e3a000 { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-magic-2-wifi-next.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-magic-2-wifi-next.dts -@@ -152,6 +149,14 @@ - status = "okay"; - }; - -+ðphy0 { -+ status = "disabled"; -+}; -+ -+ðphy1 { -+ status = "disabled"; -+}; -+ - &wifi0 { - status = "okay"; - qcom,ath10k-calibration-variant = "devolo,magic-2-wifi-next"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -@@ -47,10 +47,6 @@ - - mdio@90000 { - status = "okay"; -- -- /delete-node/ ethernet-phy@0; -- /delete-node/ ethernet-phy@1; -- /delete-node/ ethernet-phy@3; - }; - - tcsr@1949000 { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-wrtq-329acn.dts -@@ -248,6 +244,18 @@ - status = "okay"; - }; - -+ðphy0 { -+ status = "disabled"; -+}; -+ -+ðphy1 { -+ status = "disabled"; -+}; -+ -+ðphy3 { -+ status = "disabled"; -+}; -+ - &wifi0 { - status = "okay"; - nvmem-cell-names = "pre-calibration"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -@@ -26,12 +26,6 @@ - status = "okay"; - pinctrl-0 = <&mdio_pins>; - pinctrl-names = "default"; -- -- /delete-node/ ethernet-phy@1; -- /delete-node/ ethernet-phy@2; -- /delete-node/ ethernet-phy@3; -- /delete-node/ ethernet-phy@4; -- /delete-node/ psgmii-phy@5; - }; - - tcsr@1949000 { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-fritzrepeater-1200.dts -@@ -243,6 +237,30 @@ - status = "okay"; - }; - -+ðphy0 { -+ status = "disabled"; -+}; -+ -+ðphy1 { -+ status = "disabled"; -+}; -+ -+ðphy2 { -+ status = "disabled"; -+}; -+ -+ðphy3 { -+ status = "disabled"; -+}; -+ -+ðphy4 { -+ status = "disabled"; -+}; -+ -+&psgmiiphy { -+ status = "disabled"; -+}; -+ - &wifi0 { - status = "okay"; - qcom,ath10k-calibration-variant = "AVM-FRITZRepeater-1200"; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-lhgg-60ad.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-lhgg-60ad.dts -@@ -47,12 +47,6 @@ - - mdio@90000 { - status = "okay"; -- -- /delete-node/ ethernet-phy@1; -- /delete-node/ ethernet-phy@2; -- /delete-node/ ethernet-phy@3; -- /delete-node/ ethernet-phy@4; -- /delete-node/ psgmii-phy@5; - }; - - counter@4a1000 { ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-lhgg-60ad.dts -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-lhgg-60ad.dts -@@ -247,3 +241,23 @@ - }; - }; - }; -+ -+ðphy1 { -+ status = "disabled"; -+}; -+ -+ðphy2 { -+ status = "disabled"; -+}; -+ -+ðphy3 { -+ status = "disabled"; -+}; -+ -+ðphy4 { -+ status = "disabled"; -+}; -+ -+&psgmiiphy { -+ status = "disabled"; -+}; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-aruba-glenmorangie.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-aruba-glenmorangie.dtsi -@@ -21,13 +21,6 @@ - pinctrl-0 = <&mdio_pins>; - pinctrl-names = "default"; - -- /delete-node/ ethernet-phy@0; -- /delete-node/ ethernet-phy@1; -- /delete-node/ ethernet-phy@2; -- /delete-node/ ethernet-phy@3; -- /delete-node/ ethernet-phy@4; -- /delete-node/ psgmii-phy@5; -- - ethernet-phy@5 { - reg = <0x5>; - }; ---- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-aruba-glenmorangie.dtsi -+++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4029-aruba-glenmorangie.dtsi -@@ -221,6 +214,30 @@ - }; - }; - -+ðphy0 { -+ status = "disabled"; -+}; -+ -+ðphy1 { -+ status = "disabled"; -+}; -+ -+ðphy2 { -+ status = "disabled"; -+}; -+ -+ðphy3 { -+ status = "disabled"; -+}; -+ -+ðphy4 { -+ status = "disabled"; -+}; -+ -+&psgmiiphy { -+ status = "disabled"; -+}; -+ - &wifi0 { - status = "okay"; - nvmem-cell-names = "pre-calibration", "mac-address"; - ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.10/700-skbuff-add-DSA-specific-data-to-struct-skb_shared_in.patch -@@ -0,0 +1,43 @@ -+From da75807ac41175e9db8c95f7a172b4133763b744 Mon Sep 17 00:00:00 2001 -+From: Gabor Juhos -+Date: Mon, 11 Jan 2021 17:49:36 +0100 -+Subject: [PATCH] skbuff: add DSA specific data to struct skb_shared_info -+ -+All of the already existing DSA tagging protocol drivers -+are storing the tagging data directly into the skb. In most -+cases that is the only way to send the required information -+to the underlying ethernet switch. -+ -+However on certain platforms (like the Qualcomm IPQ40xx -+SoCs) the built-in ethernet switch is connected directly -+to an ethernet MAC, and the tagging information must be -+sent out-of-band which is done directly via the hardware -+TX descriptors of the ethernet MAC. -+ -+In such cases, putting the information into the skb causes -+unneccesary overhead, because the ethernet driver must -+remove that before sending the ethernet frame towards to -+the hardware. -+ -+This change adds two new DSA specific fields to struct -+skb_shared_info which makes it possible to send the -+tagging information via skb->shinfo. With this approach, -+the twofold modifications of the skb data can be avoided. -+ -+Signed-off-by: Gabor Juhos -+--- -+ include/linux/skbuff.h | 3 +++ -+ 1 file changed, 3 insertions(+) -+ -+--- a/include/linux/skbuff.h -++++ b/include/linux/skbuff.h -+@@ -522,6 +522,9 @@ struct skb_shared_info { -+ unsigned int gso_type; -+ u32 tskey; -+ -++ unsigned int dsa_tag_proto; -++ unsigned char dsa_tag_data[8]; -++ -+ /* -+ * Warning : all fields before dataref are cleared in __alloc_skb() -+ */ ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.10/701-net-dsa-tag_ipq4019-add-shinfo-based-tagging-driver-.patch -@@ -0,0 +1,188 @@ -+From 29a0c2fae991cab142575c92276c0afdeb260ebe Mon Sep 17 00:00:00 2001 -+From: Gabor Juhos -+Date: Thu, 28 Oct 2021 21:44:52 +0200 -+Subject: [PATCH] net: dsa: tag_ipq4019: add shinfo based tagging driver for -+ IPQ40xx -+ -+This change adds a tagging protocol driver for the built-in -+ethernet switch of the Qualcomm Atheros IPQ4019 SoCs. -+ -+In comparison to the existing tagging protocols this hardware -+requires a slightly different approach because the switch does -+not use in-band tags. -+ -+On the receive path, the source port information is embedded -+into the RX descriptors of the ethernet MAC hardware. Similarly, -+the destination port mask must be sent via the TX descriptors -+of the ethernet MAC when a packet is sent towards the switch. -+ -+In order to support this special requirements, this patch -+adds a new tagging protocol driver. -+ -+The driver extracts the source port information directly -+from the 'receive return descriptor' of the ethernet MAC. -+It is possible because that descriptor is part of the skb -+received from the ethernet driver. -+ -+Unfortunatley, it is not possible to put the destination -+port information directly to the TX descriptors, because -+those are handled internally by the driver of the ethernet -+hardware. -+ -+To overcome this limitation, this tagging driver uses the -+DSA specific fields in skb->shinfo to send the destination -+port information to the ethernet driver. -+ -+A similar tagging driver is exist but that uses skb -+extensions which causes unnecessary overhead. -+ -+Signed-off-by: Gabor Juhos -+--- -+ include/linux/dsa/ipq4019.h | 11 ++++++ -+ include/net/dsa.h | 2 + -+ net/dsa/Kconfig | 6 +++ -+ net/dsa/Makefile | 1 + -+ net/dsa/tag_ipq4019.c | 79 +++++++++++++++++++++++++++++++++++++ -+ 5 files changed, 99 insertions(+) -+ create mode 100644 include/linux/dsa/ipq4019.h -+ create mode 100644 net/dsa/tag_ipq4019.c -+ -+--- /dev/null -++++ b/include/linux/dsa/ipq4019.h -+@@ -0,0 +1,11 @@ -++/* SPDX-License-Identifier: GPL-2.0-only */ -++ -++#ifndef DSA_IPQ40XX_H -++#define DSA_IPQ40XX_H -++ -++struct ipq40xx_dsa_tag_data { -++ u8 from_cpu; -++ u8 dp; -++}; -++ -++#endif /* DSA_IPQ40XX_H */ -+--- a/include/net/dsa.h -++++ b/include/net/dsa.h -+@@ -46,6 +46,7 @@ struct phylink_link_state; -+ #define DSA_TAG_PROTO_AR9331_VALUE 16 -+ #define DSA_TAG_PROTO_RTL4_A_VALUE 17 -+ #define DSA_TAG_PROTO_BRCM_LEGACY_VALUE 22 -++#define DSA_TAG_PROTO_IPQ4019_VALUE 24 -+ -+ enum dsa_tag_protocol { -+ DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, -+@@ -67,6 +68,7 @@ enum dsa_tag_protocol { -+ DSA_TAG_PROTO_OCELOT = DSA_TAG_PROTO_OCELOT_VALUE, -+ DSA_TAG_PROTO_AR9331 = DSA_TAG_PROTO_AR9331_VALUE, -+ DSA_TAG_PROTO_RTL4_A = DSA_TAG_PROTO_RTL4_A_VALUE, -++ DSA_TAG_PROTO_IPQ4019 = DSA_TAG_PROTO_IPQ4019_VALUE, -+ }; -+ -+ struct packet_type; -+--- a/net/dsa/Kconfig -++++ b/net/dsa/Kconfig -+@@ -63,6 +63,12 @@ config NET_DSA_TAG_BRCM_PREPEND -+ Broadcom switches which places the tag before the Ethernet header -+ (prepended). -+ -++config NET_DSA_TAG_IPQ4019 -++ tristate "Tag driver for Qualcomm Atheros IPQ4019 SoC built-in switch" -++ help -++ Say Y or M if you want to enable support for tagging frames for -++ the built-in switch of the Qualcomm Atheros IPQ4019 SoC-s. -++ -+ config NET_DSA_TAG_GSWIP -+ tristate "Tag driver for Lantiq / Intel GSWIP switches" -+ help -+--- a/net/dsa/Makefile -++++ b/net/dsa/Makefile -+@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += -+ obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o -+ obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o -+ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o -++obj-$(CONFIG_NET_DSA_TAG_IPQ4019) += tag_ipq4019.o -+ obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o -+ obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o -+ obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o -+--- /dev/null -++++ b/net/dsa/tag_ipq4019.c -+@@ -0,0 +1,79 @@ -++// SPDX-License-Identifier: GPL-2.0-only -++ -++/* Copyright (c) 2021, Gabor Juhos */ -++ -++#include -++#include -++ -++#include "dsa_priv.h" -++ -++/* Receive Return Descriptor */ -++struct edma_rrd { -++ u16 rrd0; -++ u16 rrd1; -++ u16 rrd2; -++ u16 rrd3; -++ u16 rrd4; -++ u16 rrd5; -++ u16 rrd6; -++ u16 rrd7; -++} __packed; -++ -++#define EDMA_RRD_SIZE sizeof(struct edma_rrd) -++ -++#define EDMA_RRD1_PORT_ID_MASK GENMASK(14, 12) -++ -++static struct sk_buff *ipq4019_sh_tag_xmit(struct sk_buff *skb, -++ struct net_device *dev) -++{ -++ struct dsa_port *dp = dsa_slave_to_port(dev); -++ struct ipq40xx_dsa_tag_data *tag_data; -++ -++ BUILD_BUG_ON(sizeof_field(struct skb_shared_info, dsa_tag_data) < -++ sizeof(struct ipq40xx_dsa_tag_data)); -++ -++ skb_shinfo(skb)->dsa_tag_proto = DSA_TAG_PROTO_IPQ4019; -++ tag_data = (struct ipq40xx_dsa_tag_data *)skb_shinfo(skb)->dsa_tag_data; -++ -++ tag_data->from_cpu = 1; -++ /* set the destination port information */ -++ tag_data->dp = BIT(dp->index); -++ -++ return skb; -++} -++ -++static struct sk_buff *ipq4019_sh_tag_rcv(struct sk_buff *skb, -++ struct net_device *dev, -++ struct packet_type *pt) -++{ -++ struct edma_rrd *rrd; -++ int offset; -++ int port; -++ -++ offset = EDMA_RRD_SIZE + ETH_HLEN; -++ if (unlikely(skb_headroom(skb) < offset)) -++ return NULL; -++ -++ rrd = (struct edma_rrd *)(skb->data - offset); -++ port = FIELD_GET(EDMA_RRD1_PORT_ID_MASK, rrd->rrd1); -++ -++ skb->dev = dsa_master_find_slave(dev, 0, port); -++ if (!skb->dev) -++ return NULL; -++ -++ return skb; -++} -++ -++const struct dsa_device_ops ipq4019_sh_tag_dsa_ops = { -++ .name = "ipq4019-sh", -++ .proto = DSA_TAG_PROTO_IPQ4019, -++ .xmit = ipq4019_sh_tag_xmit, -++ .rcv = ipq4019_sh_tag_rcv, -++}; -++ -++MODULE_LICENSE("GPL v2"); -++MODULE_DESCRIPTION("DSA tag driver for the IPQ4019 SoC built-in ethernet switch"); -++MODULE_AUTHOR("Gabor Juhos "); -++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_IPQ4019); -++ -++module_dsa_tag_driver(ipq4019_sh_tag_dsa_ops); ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.15/700-skbuff-add-DSA-specific-data-to-struct-skb_shared_in.patch -@@ -0,0 +1,43 @@ -+From da75807ac41175e9db8c95f7a172b4133763b744 Mon Sep 17 00:00:00 2001 -+From: Gabor Juhos -+Date: Mon, 11 Jan 2021 17:49:36 +0100 -+Subject: [PATCH] skbuff: add DSA specific data to struct skb_shared_info -+ -+All of the already existing DSA tagging protocol drivers -+are storing the tagging data directly into the skb. In most -+cases that is the only way to send the required information -+to the underlying ethernet switch. -+ -+However on certain platforms (like the Qualcomm IPQ40xx -+SoCs) the built-in ethernet switch is connected directly -+to an ethernet MAC, and the tagging information must be -+sent out-of-band which is done directly via the hardware -+TX descriptors of the ethernet MAC. -+ -+In such cases, putting the information into the skb causes -+unneccesary overhead, because the ethernet driver must -+remove that before sending the ethernet frame towards to -+the hardware. -+ -+This change adds two new DSA specific fields to struct -+skb_shared_info which makes it possible to send the -+tagging information via skb->shinfo. With this approach, -+the twofold modifications of the skb data can be avoided. -+ -+Signed-off-by: Gabor Juhos -+--- -+ include/linux/skbuff.h | 3 +++ -+ 1 file changed, 3 insertions(+) -+ -+--- a/include/linux/skbuff.h -++++ b/include/linux/skbuff.h -+@@ -528,6 +528,9 @@ struct skb_shared_info { -+ unsigned int gso_type; -+ u32 tskey; -+ -++ unsigned int dsa_tag_proto; -++ unsigned char dsa_tag_data[8]; -++ -+ /* -+ * Warning : all fields before dataref are cleared in __alloc_skb() -+ */ ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.15/701-net-dsa-tag_ipq4019-add-shinfo-based-tagging-driver-.patch -@@ -0,0 +1,187 @@ -+From 29a0c2fae991cab142575c92276c0afdeb260ebe Mon Sep 17 00:00:00 2001 -+From: Gabor Juhos -+Date: Thu, 28 Oct 2021 21:44:52 +0200 -+Subject: [PATCH] net: dsa: tag_ipq4019: add shinfo based tagging driver for -+ IPQ40xx -+ -+This change adds a tagging protocol driver for the built-in -+ethernet switch of the Qualcomm Atheros IPQ4019 SoCs. -+ -+In comparison to the existing tagging protocols this hardware -+requires a slightly different approach because the switch does -+not use in-band tags. -+ -+On the receive path, the source port information is embedded -+into the RX descriptors of the ethernet MAC hardware. Similarly, -+the destination port mask must be sent via the TX descriptors -+of the ethernet MAC when a packet is sent towards the switch. -+ -+In order to support this special requirements, this patch -+adds a new tagging protocol driver. -+ -+The driver extracts the source port information directly -+from the 'receive return descriptor' of the ethernet MAC. -+It is possible because that descriptor is part of the skb -+received from the ethernet driver. -+ -+Unfortunatley, it is not possible to put the destination -+port information directly to the TX descriptors, because -+those are handled internally by the driver of the ethernet -+hardware. -+ -+To overcome this limitation, this tagging driver uses the -+DSA specific fields in skb->shinfo to send the destination -+port information to the ethernet driver. -+ -+A similar tagging driver is exist but that uses skb -+extensions which causes unnecessary overhead. -+ -+Signed-off-by: Gabor Juhos -+--- -+ include/linux/dsa/ipq4019.h | 11 ++++++ -+ include/net/dsa.h | 2 + -+ net/dsa/Kconfig | 6 +++ -+ net/dsa/Makefile | 1 + -+ net/dsa/tag_ipq4019.c | 79 +++++++++++++++++++++++++++++++++++++ -+ 5 files changed, 99 insertions(+) -+ create mode 100644 include/linux/dsa/ipq4019.h -+ create mode 100644 net/dsa/tag_ipq4019.c -+ -+--- /dev/null -++++ b/include/linux/dsa/ipq4019.h -+@@ -0,0 +1,11 @@ -++/* SPDX-License-Identifier: GPL-2.0-only */ -++ -++#ifndef DSA_IPQ40XX_H -++#define DSA_IPQ40XX_H -++ -++struct ipq40xx_dsa_tag_data { -++ u8 from_cpu; -++ u8 dp; -++}; -++ -++#endif /* DSA_IPQ40XX_H */ -+--- a/include/net/dsa.h -++++ b/include/net/dsa.h -+@@ -51,6 +51,7 @@ struct phylink_link_state; -+ #define DSA_TAG_PROTO_SEVILLE_VALUE 21 -+ #define DSA_TAG_PROTO_BRCM_LEGACY_VALUE 22 -+ #define DSA_TAG_PROTO_SJA1110_VALUE 23 -++#define DSA_TAG_PROTO_IPQ4019_VALUE 24 -+ -+ enum dsa_tag_protocol { -+ DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, -+@@ -77,6 +78,7 @@ enum dsa_tag_protocol { -+ DSA_TAG_PROTO_OCELOT_8021Q = DSA_TAG_PROTO_OCELOT_8021Q_VALUE, -+ DSA_TAG_PROTO_SEVILLE = DSA_TAG_PROTO_SEVILLE_VALUE, -+ DSA_TAG_PROTO_SJA1110 = DSA_TAG_PROTO_SJA1110_VALUE, -++ DSA_TAG_PROTO_IPQ4019 = DSA_TAG_PROTO_IPQ4019_VALUE, -+ }; -+ -+ struct dsa_switch; -+--- a/net/dsa/Kconfig -++++ b/net/dsa/Kconfig -+@@ -57,6 +57,12 @@ config NET_DSA_TAG_HELLCREEK -+ Say Y or M if you want to enable support for tagging frames -+ for the Hirschmann Hellcreek TSN switches. -+ -++config NET_DSA_TAG_IPQ4019 -++ tristate "Tag driver for Qualcomm Atheros IPQ4019 SoC built-in switch" -++ help -++ Say Y or M if you want to enable support for tagging frames for -++ the built-in switch of the Qualcomm Atheros IPQ4019 SoC-s. -++ -+ config NET_DSA_TAG_GSWIP -+ tristate "Tag driver for Lantiq / Intel GSWIP switches" -+ help -+--- a/net/dsa/Makefile -++++ b/net/dsa/Makefile -+@@ -8,6 +8,7 @@ obj-$(CONFIG_NET_DSA_TAG_AR9331) += tag_ -+ obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o -+ obj-$(CONFIG_NET_DSA_TAG_DSA_COMMON) += tag_dsa.o -+ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o -++obj-$(CONFIG_NET_DSA_TAG_IPQ4019) += tag_ipq4019.o -+ obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o -+ obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o -+ obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o -+--- /dev/null -++++ b/net/dsa/tag_ipq4019.c -+@@ -0,0 +1,78 @@ -++// SPDX-License-Identifier: GPL-2.0-only -++ -++/* Copyright (c) 2021, Gabor Juhos */ -++ -++#include -++#include -++ -++#include "dsa_priv.h" -++ -++/* Receive Return Descriptor */ -++struct edma_rrd { -++ u16 rrd0; -++ u16 rrd1; -++ u16 rrd2; -++ u16 rrd3; -++ u16 rrd4; -++ u16 rrd5; -++ u16 rrd6; -++ u16 rrd7; -++} __packed; -++ -++#define EDMA_RRD_SIZE sizeof(struct edma_rrd) -++ -++#define EDMA_RRD1_PORT_ID_MASK GENMASK(14, 12) -++ -++static struct sk_buff *ipq4019_sh_tag_xmit(struct sk_buff *skb, -++ struct net_device *dev) -++{ -++ struct dsa_port *dp = dsa_slave_to_port(dev); -++ struct ipq40xx_dsa_tag_data *tag_data; -++ -++ BUILD_BUG_ON(sizeof_field(struct skb_shared_info, dsa_tag_data) < -++ sizeof(struct ipq40xx_dsa_tag_data)); -++ -++ skb_shinfo(skb)->dsa_tag_proto = DSA_TAG_PROTO_IPQ4019; -++ tag_data = (struct ipq40xx_dsa_tag_data *)skb_shinfo(skb)->dsa_tag_data; -++ -++ tag_data->from_cpu = 1; -++ /* set the destination port information */ -++ tag_data->dp = BIT(dp->index); -++ -++ return skb; -++} -++ -++static struct sk_buff *ipq4019_sh_tag_rcv(struct sk_buff *skb, -++ struct net_device *dev) -++{ -++ struct edma_rrd *rrd; -++ int offset; -++ int port; -++ -++ offset = EDMA_RRD_SIZE + ETH_HLEN; -++ if (unlikely(skb_headroom(skb) < offset)) -++ return NULL; -++ -++ rrd = (struct edma_rrd *)(skb->data - offset); -++ port = FIELD_GET(EDMA_RRD1_PORT_ID_MASK, rrd->rrd1); -++ -++ skb->dev = dsa_master_find_slave(dev, 0, port); -++ if (!skb->dev) -++ return NULL; -++ -++ return skb; -++} -++ -++const struct dsa_device_ops ipq4019_sh_tag_dsa_ops = { -++ .name = "ipq4019-sh", -++ .proto = DSA_TAG_PROTO_IPQ4019, -++ .xmit = ipq4019_sh_tag_xmit, -++ .rcv = ipq4019_sh_tag_rcv, -++}; -++ -++MODULE_LICENSE("GPL v2"); -++MODULE_DESCRIPTION("DSA tag driver for the IPQ4019 SoC built-in ethernet switch"); -++MODULE_AUTHOR("Gabor Juhos "); -++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_IPQ4019); -++ -++module_dsa_tag_driver(ipq4019_sh_tag_dsa_ops); - ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -121,7 +121,7 @@ - #define PSGMII_QSGMII_DRIVE_CONTROL_1 0xb - #define PSGMII_QSGMII_TX_DRIVER_MASK GENMASK(7, 4) - #define PSGMII_MODE_CTRL 0x6d --#define PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK GENMASK(3, 0) -+#define PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK BIT(0) - #define PSGMII_MMD3_SERDES_CONTROL 0x805a - - struct qca807x_gpio_priv { ---- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -+++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c -@@ -780,17 +780,14 @@ static int qca807x_probe(struct phy_device *phydev) - static int qca807x_psgmii_config(struct phy_device *phydev) - { - struct device_node *node = phydev->mdio.dev.of_node; -- int psgmii_az, tx_amp, ret = 0; -+ int tx_amp, ret = 0; - u32 tx_driver_strength; - - /* Workaround to enable AZ transmitting ability */ -- if (of_property_read_bool(node, "qcom,psgmii-az")) { -- psgmii_az = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PSGMII_MODE_CTRL); -- psgmii_az &= ~PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK; -- psgmii_az |= FIELD_PREP(PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK, 0xc); -- ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, PSGMII_MODE_CTRL, psgmii_az); -- psgmii_az = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PSGMII_MODE_CTRL); -- } -+ ret = phy_clear_bits_mmd(phydev, -+ MDIO_MMD_PMAPMD, -+ PSGMII_MODE_CTRL, -+ PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK); - - /* PSGMII/QSGMII TX amp set to DT defined value instead of default 600mV */ - if (!of_property_read_u32(node, "qcom,tx-driver-strength", &tx_driver_strength)) { ---- a/target/linux/ipq40xx/patches-5.10/708-arm-dts-ipq4019-QCA807x-properties.patch -+++ b/target/linux/ipq40xx/patches-5.10/708-arm-dts-ipq4019-QCA807x-properties.patch -@@ -56,7 +56,6 @@ Signed-off-by: Robert Marko - + reg = <5>; - + - + qcom,tx-driver-strength = ; --+ qcom,psgmii-az; - }; - }; - ---- /dev/null -+++ b/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/ipqess/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+# -+# Makefile for the IPQ ESS driver -+# -+ -+obj-$(CONFIG_QCOM_IPQ4019_ESS_EDMA) += ipq_ess.o -+ -+ipq_ess-objs := ipqess.o ipqess_ethtool.o ---- /dev/null -+++ b/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/ipqess/ipqess.c -@@ -0,0 +1,1334 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR ISC) -+/* Copyright (c) 2014 - 2017, The Linux Foundation. All rights reserved. -+ * Copyright (c) 2017 - 2018, John Crispin -+ * Copyright (c) 2018 - 2019, Christian Lamparter -+ * Copyright (c) 2020 - 2021, Gabor Juhos -+ * -+ * Permission to use, copy, modify, and/or distribute this software for -+ * any purpose with or without fee is hereby granted, provided that the -+ * above copyright notice and this permission notice appear in all copies. -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ipqess.h" -+ -+#define IPQESS_RRD_SIZE 16 -+#define IPQESS_NEXT_IDX(X, Y) (((X) + 1) & ((Y) - 1)) -+#define IPQESS_TX_DMA_BUF_LEN 0x3fff -+ -+static void ipqess_w32(struct ipqess *ess, u32 reg, u32 val) -+{ -+ writel(val, ess->hw_addr + reg); -+} -+ -+static u32 ipqess_r32(struct ipqess *ess, u16 reg) -+{ -+ return readl(ess->hw_addr + reg); -+} -+ -+static void ipqess_m32(struct ipqess *ess, u32 mask, u32 val, u16 reg) -+{ -+ u32 _val = ipqess_r32(ess, reg); -+ _val &= ~mask; -+ _val |= val; -+ ipqess_w32(ess, reg, _val); -+} -+ -+void ipqess_update_hw_stats(struct ipqess *ess) -+{ -+ uint32_t *p; -+ u32 stat; -+ int i; -+ -+ lockdep_assert_held(&ess->stats_lock); -+ -+ p = (uint32_t *)&(ess->ipqessstats); -+ for (i = 0; i < IPQESS_MAX_TX_QUEUE; i++) { -+ stat = ipqess_r32(ess, IPQESS_REG_TX_STAT_PKT_Q(i)); -+ *p += stat; -+ p++; -+ } -+ -+ for (i = 0; i < IPQESS_MAX_TX_QUEUE; i++) { -+ stat = ipqess_r32(ess, IPQESS_REG_TX_STAT_BYTE_Q(i)); -+ *p += stat; -+ p++; -+ } -+ -+ for (i = 0; i < IPQESS_MAX_RX_QUEUE; i++) { -+ stat = ipqess_r32(ess, IPQESS_REG_RX_STAT_PKT_Q(i)); -+ *p += stat; -+ p++; -+ } -+ -+ for (i = 0; i < IPQESS_MAX_RX_QUEUE; i++) { -+ stat = ipqess_r32(ess, IPQESS_REG_RX_STAT_BYTE_Q(i)); -+ *p += stat; -+ p++; -+ } -+} -+ -+static int ipqess_tx_ring_alloc(struct ipqess *ess) -+{ -+ struct device *dev = &ess->pdev->dev; -+ int i; -+ -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ struct ipqess_tx_ring *tx_ring = &ess->tx_ring[i]; -+ size_t size; -+ u32 idx; -+ -+ tx_ring->ess = ess; -+ tx_ring->ring_id = i; -+ tx_ring->idx = i * 4; -+ tx_ring->count = IPQESS_TX_RING_SIZE; -+ tx_ring->nq = netdev_get_tx_queue(ess->netdev, i); -+ -+ size = sizeof(struct ipqess_buf) * IPQESS_TX_RING_SIZE; -+ tx_ring->buf = devm_kzalloc(dev, size, GFP_KERNEL); -+ if (!tx_ring->buf) { -+ netdev_err(ess->netdev, "buffer alloc of tx ring failed"); -+ return -ENOMEM; -+ } -+ -+ size = sizeof(struct ipqess_tx_desc) * IPQESS_TX_RING_SIZE; -+ tx_ring->hw_desc = dmam_alloc_coherent(dev, size, &tx_ring->dma, -+ GFP_KERNEL | __GFP_ZERO); -+ if (!tx_ring->hw_desc) { -+ netdev_err(ess->netdev, "descriptor allocation for tx ring failed"); -+ return -ENOMEM; -+ } -+ -+ ipqess_w32(ess, IPQESS_REG_TPD_BASE_ADDR_Q(tx_ring->idx), -+ (u32)tx_ring->dma); -+ -+ idx = ipqess_r32(ess, IPQESS_REG_TPD_IDX_Q(tx_ring->idx)); -+ idx >>= IPQESS_TPD_CONS_IDX_SHIFT; /* need u32 here */ -+ idx &= 0xffff; -+ tx_ring->head = tx_ring->tail = idx; -+ -+ ipqess_m32(ess, IPQESS_TPD_PROD_IDX_MASK << IPQESS_TPD_PROD_IDX_SHIFT, -+ idx, IPQESS_REG_TPD_IDX_Q(tx_ring->idx)); -+ ipqess_w32(ess, IPQESS_REG_TX_SW_CONS_IDX_Q(tx_ring->idx), idx); -+ ipqess_w32(ess, IPQESS_REG_TPD_RING_SIZE, IPQESS_TX_RING_SIZE); -+ } -+ -+ return 0; -+} -+ -+static int ipqess_tx_unmap_and_free(struct device *dev, struct ipqess_buf *buf) -+{ -+ int len = 0; -+ -+ if (buf->flags & IPQESS_DESC_SINGLE) -+ dma_unmap_single(dev, buf->dma, buf->length, DMA_TO_DEVICE); -+ else if (buf->flags & IPQESS_DESC_PAGE) -+ dma_unmap_page(dev, buf->dma, buf->length, DMA_TO_DEVICE); -+ -+ if (buf->flags & IPQESS_DESC_LAST) { -+ len = buf->skb->len; -+ dev_kfree_skb_any(buf->skb); -+ } -+ -+ buf->flags = 0; -+ -+ return len; -+} -+ -+static void ipqess_tx_ring_free(struct ipqess *ess) -+{ -+ int i; -+ -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ int j; -+ -+ if (ess->tx_ring[i].hw_desc) -+ continue; -+ -+ for (j = 0; j < IPQESS_TX_RING_SIZE; j++) { -+ struct ipqess_buf *buf = &ess->tx_ring[i].buf[j]; -+ -+ ipqess_tx_unmap_and_free(&ess->pdev->dev, buf); -+ } -+ -+ ess->tx_ring[i].buf = NULL; -+ } -+} -+ -+static int ipqess_rx_buf_prepare(struct ipqess_buf *buf, -+ struct ipqess_rx_ring *rx_ring) -+{ -+ /* Clean the HW DESC header, otherwise we might end up -+ * with a spurious desc because of random garbage */ -+ memset(buf->skb->data, 0, sizeof(struct ipqess_rx_desc)); -+ -+ buf->dma = dma_map_single(rx_ring->ppdev, buf->skb->data, -+ IPQESS_RX_HEAD_BUFF_SIZE, DMA_FROM_DEVICE); -+ if (dma_mapping_error(rx_ring->ppdev, buf->dma)) { -+ dev_err_once(rx_ring->ppdev, -+ "IPQESS DMA mapping failed for linear address %x", -+ buf->dma); -+ dev_kfree_skb_any(buf->skb); -+ buf->skb = NULL; -+ return -EFAULT; -+ } -+ -+ buf->length = IPQESS_RX_HEAD_BUFF_SIZE; -+ rx_ring->hw_desc[rx_ring->head] = (struct ipqess_rx_desc *)buf->dma; -+ rx_ring->head = (rx_ring->head + 1) % IPQESS_RX_RING_SIZE; -+ -+ ipqess_m32(rx_ring->ess, IPQESS_RFD_PROD_IDX_BITS, -+ (rx_ring->head + IPQESS_RX_RING_SIZE - 1) % IPQESS_RX_RING_SIZE, -+ IPQESS_REG_RFD_IDX_Q(rx_ring->idx)); -+ -+ return 0; -+} -+ -+/* locking is handled by the caller */ -+static int ipqess_rx_buf_alloc_napi(struct ipqess_rx_ring *rx_ring) -+{ -+ struct ipqess_buf *buf = &rx_ring->buf[rx_ring->head]; -+ -+ buf->skb = napi_alloc_skb(&rx_ring->napi_rx, -+ IPQESS_RX_HEAD_BUFF_SIZE); -+ if (!buf->skb) -+ return -ENOMEM; -+ -+ return ipqess_rx_buf_prepare(buf, rx_ring); -+} -+ -+static int ipqess_rx_buf_alloc(struct ipqess_rx_ring *rx_ring) -+{ -+ struct ipqess_buf *buf = &rx_ring->buf[rx_ring->head]; -+ -+ buf->skb = netdev_alloc_skb_ip_align(rx_ring->ess->netdev, -+ IPQESS_RX_HEAD_BUFF_SIZE); -+ if (!buf->skb) -+ return -ENOMEM; -+ -+ return ipqess_rx_buf_prepare(buf, rx_ring); -+} -+ -+static void ipqess_refill_work(struct work_struct *work) -+{ -+ struct ipqess_rx_ring_refill *rx_refill = container_of(work, -+ struct ipqess_rx_ring_refill, refill_work); -+ struct ipqess_rx_ring *rx_ring = rx_refill->rx_ring; -+ int refill = 0; -+ -+ /* don't let this loop by accident. */ -+ while (atomic_dec_and_test(&rx_ring->refill_count)) { -+ napi_disable(&rx_ring->napi_rx); -+ if (ipqess_rx_buf_alloc(rx_ring)) { -+ refill++; -+ dev_dbg(rx_ring->ppdev, -+ "Not all buffers were reallocated"); -+ } -+ napi_enable(&rx_ring->napi_rx); -+ } -+ -+ if (atomic_add_return(refill, &rx_ring->refill_count)) -+ schedule_work(&rx_refill->refill_work); -+} -+ -+ -+static int ipqess_rx_ring_alloc(struct ipqess *ess) -+{ -+ int i; -+ -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ int j; -+ -+ ess->rx_ring[i].ess = ess; -+ ess->rx_ring[i].ppdev = &ess->pdev->dev; -+ ess->rx_ring[i].ring_id = i; -+ ess->rx_ring[i].idx = i * 2; -+ -+ ess->rx_ring[i].buf = devm_kzalloc(&ess->pdev->dev, -+ sizeof(struct ipqess_buf) * IPQESS_RX_RING_SIZE, -+ GFP_KERNEL); -+ if (!ess->rx_ring[i].buf) -+ return -ENOMEM; -+ -+ ess->rx_ring[i].hw_desc = dmam_alloc_coherent(&ess->pdev->dev, -+ sizeof(struct ipqess_rx_desc) * IPQESS_RX_RING_SIZE, -+ &ess->rx_ring[i].dma, GFP_KERNEL); -+ if (!ess->rx_ring[i].hw_desc) -+ return -ENOMEM; -+ -+ for (j = 0; j < IPQESS_RX_RING_SIZE; j++) -+ if (ipqess_rx_buf_alloc(&ess->rx_ring[i]) < 0) -+ return -ENOMEM; -+ -+ ess->rx_refill[i].rx_ring = &ess->rx_ring[i]; -+ INIT_WORK(&ess->rx_refill[i].refill_work, ipqess_refill_work); -+ -+ ipqess_w32(ess, IPQESS_REG_RFD_BASE_ADDR_Q(ess->rx_ring[i].idx), -+ (u32)(ess->rx_ring[i].dma)); -+ } -+ -+ ipqess_w32(ess, IPQESS_REG_RX_DESC0, -+ (IPQESS_RX_HEAD_BUFF_SIZE << IPQESS_RX_BUF_SIZE_SHIFT) | -+ (IPQESS_RX_RING_SIZE << IPQESS_RFD_RING_SIZE_SHIFT)); -+ -+ return 0; -+} -+ -+static void ipqess_rx_ring_free(struct ipqess *ess) -+{ -+ int i; -+ -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ int j; -+ -+ atomic_set(&ess->rx_ring[i].refill_count, 0); -+ cancel_work_sync(&ess->rx_refill[i].refill_work); -+ -+ for (j = 0; j < IPQESS_RX_RING_SIZE; j++) { -+ dma_unmap_single(&ess->pdev->dev, -+ ess->rx_ring[i].buf[j].dma, -+ ess->rx_ring[i].buf[j].length, -+ DMA_FROM_DEVICE); -+ dev_kfree_skb_any(ess->rx_ring[i].buf[j].skb); -+ } -+ } -+} -+ -+static struct net_device_stats *ipqess_get_stats(struct net_device *netdev) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ -+ spin_lock(&ess->stats_lock); -+ ipqess_update_hw_stats(ess); -+ spin_unlock(&ess->stats_lock); -+ -+ return &ess->stats; -+} -+ -+static int ipqess_rx_poll(struct ipqess_rx_ring *rx_ring, int budget) -+{ -+ u32 length = 0, num_desc, tail, rx_ring_tail; -+ int done = 0; -+ -+ rx_ring_tail = rx_ring->tail; -+ -+ tail = ipqess_r32(rx_ring->ess, IPQESS_REG_RFD_IDX_Q(rx_ring->idx)); -+ tail >>= IPQESS_RFD_CONS_IDX_SHIFT; -+ tail &= IPQESS_RFD_CONS_IDX_MASK; -+ -+ while (done < budget) { -+ struct sk_buff *skb; -+ struct ipqess_rx_desc *rd; -+ -+ if (rx_ring_tail == tail) -+ break; -+ -+ dma_unmap_single(rx_ring->ppdev, -+ rx_ring->buf[rx_ring_tail].dma, -+ rx_ring->buf[rx_ring_tail].length, -+ DMA_FROM_DEVICE); -+ -+ skb = xchg(&rx_ring->buf[rx_ring_tail].skb, NULL); -+ rd = (struct ipqess_rx_desc *)skb->data; -+ rx_ring_tail = IPQESS_NEXT_IDX(rx_ring_tail, IPQESS_RX_RING_SIZE); -+ -+ /* Check if RRD is valid */ -+ if (!(rd->rrd7 & IPQESS_RRD_DESC_VALID)) { -+ num_desc = 1; -+ dev_kfree_skb_any(skb); -+ goto skip; -+ } -+ -+ num_desc = rd->rrd1 & IPQESS_RRD_NUM_RFD_MASK; -+ length = rd->rrd6 & IPQESS_RRD_PKT_SIZE_MASK; -+ -+ skb_reserve(skb, IPQESS_RRD_SIZE); -+ if (num_desc > 1) { -+ /* can we use build_skb here ? */ -+ struct sk_buff *skb_prev = NULL; -+ int size_remaining; -+ int i; -+ -+ skb->data_len = 0; -+ skb->tail += (IPQESS_RX_HEAD_BUFF_SIZE - IPQESS_RRD_SIZE); -+ skb->len = skb->truesize = length; -+ size_remaining = length - (IPQESS_RX_HEAD_BUFF_SIZE - IPQESS_RRD_SIZE); -+ -+ for (i = 1; i < num_desc; i++) { -+ /* TODO: use build_skb ? */ -+ struct sk_buff *skb_temp = rx_ring->buf[rx_ring_tail].skb; -+ -+ dma_unmap_single(rx_ring->ppdev, -+ rx_ring->buf[rx_ring_tail].dma, -+ rx_ring->buf[rx_ring_tail].length, -+ DMA_FROM_DEVICE); -+ -+ skb_put(skb_temp, min(size_remaining, IPQESS_RX_HEAD_BUFF_SIZE)); -+ if (skb_prev) -+ skb_prev->next = rx_ring->buf[rx_ring_tail].skb; -+ else -+ skb_shinfo(skb)->frag_list = rx_ring->buf[rx_ring_tail].skb; -+ skb_prev = rx_ring->buf[rx_ring_tail].skb; -+ rx_ring->buf[rx_ring_tail].skb->next = NULL; -+ -+ skb->data_len += rx_ring->buf[rx_ring_tail].skb->len; -+ size_remaining -= rx_ring->buf[rx_ring_tail].skb->len; -+ -+ rx_ring_tail = IPQESS_NEXT_IDX(rx_ring_tail, IPQESS_RX_RING_SIZE); -+ } -+ -+ } else { -+ skb_put(skb, length); -+ } -+ -+ skb->dev = rx_ring->ess->netdev; -+ skb->protocol = eth_type_trans(skb, rx_ring->ess->netdev); -+ skb_record_rx_queue(skb, rx_ring->ring_id); -+ -+ if (rd->rrd6 & IPQESS_RRD_CSUM_FAIL_MASK) -+ skb_checksum_none_assert(skb); -+ else -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ -+ if (rd->rrd7 & IPQESS_RRD_CVLAN) { -+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rd->rrd4); -+ } else if (rd->rrd1 & IPQESS_RRD_SVLAN) { -+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), rd->rrd4); -+ } -+ napi_gro_receive(&rx_ring->napi_rx, skb); -+ -+ /* TODO: do we need to have these here ? */ -+ rx_ring->ess->stats.rx_packets++; -+ rx_ring->ess->stats.rx_bytes += length; -+ -+ done++; -+skip: -+ -+ num_desc += atomic_xchg(&rx_ring->refill_count, 0); -+ while (num_desc) { -+ if (ipqess_rx_buf_alloc_napi(rx_ring)) { -+ num_desc = atomic_add_return(num_desc, -+ &rx_ring->refill_count); -+ if (num_desc >= ((4 * IPQESS_RX_RING_SIZE + 6) / 7)) -+ schedule_work(&rx_ring->ess->rx_refill[rx_ring->ring_id].refill_work); -+ break; -+ } -+ num_desc--; -+ } -+ } -+ -+ ipqess_w32(rx_ring->ess, IPQESS_REG_RX_SW_CONS_IDX_Q(rx_ring->idx), -+ rx_ring_tail); -+ rx_ring->tail = rx_ring_tail; -+ -+ return done; -+} -+ -+static int ipqess_tx_complete(struct ipqess_tx_ring *tx_ring, int budget) -+{ -+ u32 tail; -+ int done = 0; -+ int total = 0, ret; -+ -+ tail = ipqess_r32(tx_ring->ess, IPQESS_REG_TPD_IDX_Q(tx_ring->idx)); -+ tail >>= IPQESS_TPD_CONS_IDX_SHIFT; -+ tail &= IPQESS_TPD_CONS_IDX_MASK; -+ -+ while ((tx_ring->tail != tail) && (done < budget)) { -+ //pr_info("freeing txq:%d tail:%d tailbuf:%p\n", tx_ring->idx, tx_ring->tail, &tx_ring->buf[tx_ring->tail]); -+ ret = ipqess_tx_unmap_and_free(&tx_ring->ess->pdev->dev, -+ &tx_ring->buf[tx_ring->tail]); -+ tx_ring->tail = IPQESS_NEXT_IDX(tx_ring->tail, tx_ring->count); -+ if (ret) { -+ total += ret; -+ done++; -+ } -+ } -+ -+ ipqess_w32(tx_ring->ess, -+ IPQESS_REG_TX_SW_CONS_IDX_Q(tx_ring->idx), -+ tx_ring->tail); -+ -+ if (netif_tx_queue_stopped(tx_ring->nq)) { -+ netdev_dbg(tx_ring->ess->netdev, "waking up tx queue %d\n", -+ tx_ring->idx); -+ netif_tx_wake_queue(tx_ring->nq); -+ } -+ -+ netdev_tx_completed_queue(tx_ring->nq, done, total); -+ -+ return done; -+} -+ -+static int ipqess_tx_napi(struct napi_struct *napi, int budget) -+{ -+ struct ipqess_tx_ring *tx_ring = container_of(napi, struct ipqess_tx_ring, -+ napi_tx); -+ u32 tx_status; -+ int work_done = 0; -+ -+ tx_status = ipqess_r32(tx_ring->ess, IPQESS_REG_TX_ISR); -+ tx_status &= BIT(tx_ring->idx); -+ -+ work_done = ipqess_tx_complete(tx_ring, budget); -+ -+ ipqess_w32(tx_ring->ess, IPQESS_REG_TX_ISR, tx_status); -+ -+ if (likely(work_done < budget)) { -+ if (napi_complete_done(napi, work_done)) -+ ipqess_w32(tx_ring->ess, -+ IPQESS_REG_TX_INT_MASK_Q(tx_ring->idx), 0x1); -+ } -+ -+ return work_done; -+} -+ -+static int ipqess_rx_napi(struct napi_struct *napi, int budget) -+{ -+ struct ipqess_rx_ring *rx_ring = container_of(napi, struct ipqess_rx_ring, -+ napi_rx); -+ struct ipqess *ess = rx_ring->ess; -+ int remain_budget = budget; -+ int rx_done; -+ u32 rx_mask = BIT(rx_ring->idx); -+ u32 status; -+ -+poll_again: -+ ipqess_w32(ess, IPQESS_REG_RX_ISR, rx_mask); -+ rx_done = ipqess_rx_poll(rx_ring, remain_budget); -+ -+ if (rx_done == remain_budget) -+ return budget; -+ -+ status = ipqess_r32(ess, IPQESS_REG_RX_ISR); -+ if (status & rx_mask) { -+ remain_budget -= rx_done; -+ goto poll_again; -+ } -+ -+ if (napi_complete_done(napi, rx_done + budget - remain_budget)) -+ ipqess_w32(ess, IPQESS_REG_RX_INT_MASK_Q(rx_ring->idx), 0x1); -+ -+ return rx_done + budget - remain_budget; -+} -+ -+static irqreturn_t ipqess_interrupt_tx(int irq, void *priv) -+{ -+ struct ipqess_tx_ring *tx_ring = (struct ipqess_tx_ring *) priv; -+ -+ if (likely(napi_schedule_prep(&tx_ring->napi_tx))) { -+ __napi_schedule(&tx_ring->napi_tx); -+ ipqess_w32(tx_ring->ess, -+ IPQESS_REG_TX_INT_MASK_Q(tx_ring->idx), -+ 0x0); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t ipqess_interrupt_rx(int irq, void *priv) -+{ -+ struct ipqess_rx_ring *rx_ring = (struct ipqess_rx_ring *) priv; -+ -+ if (likely(napi_schedule_prep(&rx_ring->napi_rx))) { -+ __napi_schedule(&rx_ring->napi_rx); -+ ipqess_w32(rx_ring->ess, -+ IPQESS_REG_RX_INT_MASK_Q(rx_ring->idx), -+ 0x0); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void ipqess_irq_enable(struct ipqess *ess) -+{ -+ int i; -+ -+ ipqess_w32(ess, IPQESS_REG_RX_ISR, 0xff); -+ ipqess_w32(ess, IPQESS_REG_TX_ISR, 0xffff); -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ ipqess_w32(ess, IPQESS_REG_RX_INT_MASK_Q(ess->rx_ring[i].idx), 1); -+ ipqess_w32(ess, IPQESS_REG_TX_INT_MASK_Q(ess->tx_ring[i].idx), 1); -+ } -+} -+ -+static void ipqess_irq_disable(struct ipqess *ess) -+{ -+ int i; -+ -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ ipqess_w32(ess, IPQESS_REG_RX_INT_MASK_Q(ess->rx_ring[i].idx), 0); -+ ipqess_w32(ess, IPQESS_REG_TX_INT_MASK_Q(ess->tx_ring[i].idx), 0); -+ } -+} -+ -+static int __init ipqess_init(struct net_device *netdev) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ struct device_node *of_node = ess->pdev->dev.of_node; -+ return phylink_of_phy_connect(ess->phylink, of_node, 0); -+} -+ -+static void ipqess_uninit(struct net_device *netdev) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ -+ phylink_disconnect_phy(ess->phylink); -+} -+ -+static int ipqess_open(struct net_device *netdev) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ int i; -+ -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ napi_enable(&ess->tx_ring[i].napi_tx); -+ napi_enable(&ess->rx_ring[i].napi_rx); -+ } -+ ipqess_irq_enable(ess); -+ phylink_start(ess->phylink); -+ netif_tx_start_all_queues(netdev); -+ -+ return 0; -+} -+ -+static int ipqess_stop(struct net_device *netdev) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ int i; -+ -+ netif_tx_stop_all_queues(netdev); -+ phylink_stop(ess->phylink); -+ ipqess_irq_disable(ess); -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ napi_disable(&ess->tx_ring[i].napi_tx); -+ napi_disable(&ess->rx_ring[i].napi_rx); -+ } -+ -+ return 0; -+} -+ -+static int ipqess_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ -+ switch (cmd) { -+ case SIOCGMIIPHY: -+ case SIOCGMIIREG: -+ case SIOCSMIIREG: -+ return phylink_mii_ioctl(ess->phylink, ifr, cmd); -+ default: -+ break; -+ } -+ -+ return -EOPNOTSUPP; -+} -+ -+ -+static inline u16 ipqess_tx_desc_available(struct ipqess_tx_ring *tx_ring) -+{ -+ u16 count = 0; -+ -+ if (tx_ring->tail <= tx_ring->head) -+ count = IPQESS_TX_RING_SIZE; -+ -+ count += tx_ring->tail - tx_ring->head - 1; -+ -+ return count; -+} -+ -+static inline int ipqess_cal_txd_req(struct sk_buff *skb) -+{ -+ int tpds; -+ -+ /* one TPD for the header, and one for each fragments */ -+ tpds = 1 + skb_shinfo(skb)->nr_frags; -+ if (skb_is_gso(skb) && skb_is_gso_v6(skb)) { -+ /* for LSOv2 one extra TPD is needed */ -+ tpds++; -+ } -+ -+ return tpds; -+} -+ -+static struct ipqess_buf *ipqess_get_tx_buffer(struct ipqess_tx_ring *tx_ring, -+ struct ipqess_tx_desc *desc) -+{ -+ return &tx_ring->buf[desc - tx_ring->hw_desc]; -+} -+ -+static struct ipqess_tx_desc *ipqess_tx_desc_next(struct ipqess_tx_ring *tx_ring) -+{ -+ struct ipqess_tx_desc *desc; -+ -+ desc = &tx_ring->hw_desc[tx_ring->head]; -+ tx_ring->head = IPQESS_NEXT_IDX(tx_ring->head, tx_ring->count); -+ -+ return desc; -+} -+ -+static void ipqess_rollback_tx(struct ipqess *eth, -+ struct ipqess_tx_desc *first_desc, int ring_id) -+{ -+ struct ipqess_tx_ring *tx_ring = ð->tx_ring[ring_id]; -+ struct ipqess_buf *buf; -+ struct ipqess_tx_desc *desc = NULL; -+ u16 start_index, index; -+ -+ start_index = first_desc - tx_ring->hw_desc; -+ -+ index = start_index; -+ while (index != tx_ring->head) { -+ desc = &tx_ring->hw_desc[index]; -+ buf = &tx_ring->buf[index]; -+ ipqess_tx_unmap_and_free(ð->pdev->dev, buf); -+ memset(desc, 0, sizeof(struct ipqess_tx_desc)); -+ if (++index == tx_ring->count) -+ index = 0; -+ } -+ tx_ring->head = start_index; -+} -+ -+static bool ipqess_process_dsa_tag_sh(struct sk_buff *skb, u32 *word3) -+{ -+ struct skb_shared_info *shinfo = skb_shinfo(skb); -+ struct ipq40xx_dsa_tag_data *tag_data; -+ -+ if (shinfo->dsa_tag_proto != DSA_TAG_PROTO_IPQ4019) -+ return false; -+ -+ tag_data = (struct ipq40xx_dsa_tag_data *)shinfo->dsa_tag_data; -+ -+ pr_debug("SH tag @ %08x, dp:%02x from_cpu:%u\n", -+ (u32)tag_data, tag_data->dp, tag_data->from_cpu); -+ -+ *word3 |= tag_data->dp << IPQESS_TPD_PORT_BITMAP_SHIFT; -+ if (tag_data->from_cpu) -+ *word3 |= BIT(IPQESS_TPD_FROM_CPU_SHIFT); -+ -+ return true; -+} -+ -+static void ipqess_get_dp_info(struct ipqess *ess, struct sk_buff *skb, -+ u32 *word3) -+{ -+ if (netdev_uses_dsa(ess->netdev)) { -+ -+ if (ipqess_process_dsa_tag_sh(skb, word3)) -+ return; -+ } -+ -+ *word3 |= 0x3e << IPQESS_TPD_PORT_BITMAP_SHIFT; -+} -+ -+static int ipqess_tx_map_and_fill(struct ipqess_tx_ring *tx_ring, struct sk_buff *skb) -+{ -+ struct ipqess_buf *buf = NULL; -+ struct platform_device *pdev = tx_ring->ess->pdev; -+ struct ipqess_tx_desc *desc = NULL, *first_desc = NULL; -+ u32 word1 = 0, word3 = 0, lso_word1 = 0, svlan_tag = 0; -+ u16 len; -+ int i; -+ -+ ipqess_get_dp_info(tx_ring->ess, skb, &word3); -+ -+ if (skb_is_gso(skb)) { -+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) { -+ lso_word1 |= IPQESS_TPD_IPV4_EN; -+ ip_hdr(skb)->check = 0; -+ tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, -+ ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); -+ } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { -+ lso_word1 |= IPQESS_TPD_LSO_V2_EN; -+ ipv6_hdr(skb)->payload_len = 0; -+ tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, -+ &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); -+ } -+ -+ lso_word1 |= IPQESS_TPD_LSO_EN | -+ ((skb_shinfo(skb)->gso_size & IPQESS_TPD_MSS_MASK) << IPQESS_TPD_MSS_SHIFT) | -+ (skb_transport_offset(skb) << IPQESS_TPD_HDR_SHIFT); -+ } else if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { -+ u8 css, cso; -+ cso = skb_checksum_start_offset(skb); -+ css = cso + skb->csum_offset; -+ -+ word1 |= (IPQESS_TPD_CUSTOM_CSUM_EN); -+ word1 |= (cso >> 1) << IPQESS_TPD_HDR_SHIFT; -+ word1 |= ((css >> 1) << IPQESS_TPD_CUSTOM_CSUM_SHIFT); -+ } -+ -+ if (skb_vlan_tag_present(skb)) { -+ switch (skb->vlan_proto) { -+ case htons(ETH_P_8021Q): -+ word3 |= BIT(IPQESS_TX_INS_CVLAN); -+ word3 |= skb_vlan_tag_get(skb) << IPQESS_TX_CVLAN_TAG_SHIFT; -+ break; -+ case htons(ETH_P_8021AD): -+ word1 |= BIT(IPQESS_TX_INS_SVLAN); -+ svlan_tag = skb_vlan_tag_get(skb); -+ break; -+ default: -+ dev_err(&pdev->dev, "no ctag or stag present\n"); -+ goto vlan_tag_error; -+ } -+ } -+ -+ if (eth_type_vlan(skb->protocol)) -+ word1 |= IPQESS_TPD_VLAN_TAGGED; -+ -+ if (skb->protocol == htons(ETH_P_PPP_SES)) -+ word1 |= IPQESS_TPD_PPPOE_EN; -+ -+ len = skb_headlen(skb); -+ -+ first_desc = desc = ipqess_tx_desc_next(tx_ring); -+ if (lso_word1 & IPQESS_TPD_LSO_V2_EN) { -+ desc->addr = cpu_to_le16(skb->len); -+ desc->word1 = word1 | lso_word1; -+ desc->svlan_tag = svlan_tag; -+ desc->word3 = word3; -+ desc = ipqess_tx_desc_next(tx_ring); -+ } -+ -+ buf = ipqess_get_tx_buffer(tx_ring, desc); -+ buf->length = len; -+ buf->dma = dma_map_single(&pdev->dev, -+ skb->data, len, DMA_TO_DEVICE); -+ if (dma_mapping_error(&pdev->dev, buf->dma)) -+ goto dma_error; -+ -+ desc->addr = cpu_to_le32(buf->dma); -+ desc->len = cpu_to_le16(len); -+ -+ buf->flags |= IPQESS_DESC_SINGLE; -+ desc->word1 = word1 | lso_word1; -+ desc->svlan_tag = svlan_tag; -+ desc->word3 = word3; -+ -+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { -+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; -+ len = skb_frag_size(frag); -+ desc = ipqess_tx_desc_next(tx_ring); -+ buf = ipqess_get_tx_buffer(tx_ring, desc); -+ buf->length = len; -+ buf->flags |= IPQESS_DESC_PAGE; -+ buf->dma = skb_frag_dma_map(&pdev->dev, frag, 0, len, DMA_TO_DEVICE); -+ if (dma_mapping_error(&pdev->dev, buf->dma)) -+ goto dma_error; -+ -+ desc->addr = cpu_to_le32(buf->dma); -+ desc->len = cpu_to_le16(len); -+ desc->svlan_tag = svlan_tag; -+ desc->word1 = word1 | lso_word1; -+ desc->word3 = word3; -+ } -+ desc->word1 |= 1 << IPQESS_TPD_EOP_SHIFT; -+ buf->skb = skb; -+ buf->flags |= IPQESS_DESC_LAST; -+ -+ return 0; -+ -+dma_error: -+ ipqess_rollback_tx(tx_ring->ess, first_desc, tx_ring->ring_id); -+ dev_err(&pdev->dev, "TX DMA map failed\n"); -+ -+vlan_tag_error: -+ return -ENOMEM; -+} -+ -+static inline void ipqess_kick_tx(struct ipqess_tx_ring *tx_ring) -+{ -+ /* Ensure that all TPDs has been written completely */ -+ dma_wmb(); -+ -+ /* update software producer index */ -+ ipqess_w32(tx_ring->ess, IPQESS_REG_TPD_IDX_Q(tx_ring->idx), -+ tx_ring->head); -+} -+ -+static netdev_tx_t ipqess_xmit(struct sk_buff *skb, -+ struct net_device *netdev) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ struct ipqess_tx_ring *tx_ring; -+ int avail; -+ int tx_num; -+ int ret; -+ -+ tx_ring = &ess->tx_ring[skb_get_queue_mapping(skb)]; -+ tx_num = ipqess_cal_txd_req(skb); -+ avail = ipqess_tx_desc_available(tx_ring); -+ if (avail < tx_num) { -+ netdev_dbg(netdev, -+ "stopping tx queue %d, avail=%d req=%d im=%x\n", -+ tx_ring->idx, avail, tx_num, -+ ipqess_r32(tx_ring->ess, -+ IPQESS_REG_TX_INT_MASK_Q(tx_ring->idx))); -+ netif_tx_stop_queue(tx_ring->nq); -+ ipqess_w32(tx_ring->ess, IPQESS_REG_TX_INT_MASK_Q(tx_ring->idx), 0x1); -+ ipqess_kick_tx(tx_ring); -+ return NETDEV_TX_BUSY; -+ } -+ -+ ret = ipqess_tx_map_and_fill(tx_ring, skb); -+ if (ret) { -+ dev_kfree_skb_any(skb); -+ ess->stats.tx_errors++; -+ goto err_out; -+ } -+ -+ ess->stats.tx_packets++; -+ ess->stats.tx_bytes += skb->len; -+ netdev_tx_sent_queue(tx_ring->nq, skb->len); -+ -+ if (!netdev_xmit_more() || netif_xmit_stopped(tx_ring->nq)) -+ ipqess_kick_tx(tx_ring); -+ -+err_out: -+ return NETDEV_TX_OK; -+} -+ -+static int ipqess_set_mac_address(struct net_device *netdev, void *p) -+{ -+ int ret = eth_mac_addr(netdev, p); -+ struct ipqess *ess = netdev_priv(netdev); -+ const char *macaddr = netdev->dev_addr; -+ -+ if (ret) -+ return ret; -+ -+// spin_lock_bh(&mac->hw->page_lock); -+ ipqess_w32(ess, IPQESS_REG_MAC_CTRL1, -+ (macaddr[0] << 8) | macaddr[1]); -+ ipqess_w32(ess, IPQESS_REG_MAC_CTRL0, -+ (macaddr[2] << 24) | (macaddr[3] << 16) | -+ (macaddr[4] << 8) | macaddr[5]); -+// spin_unlock_bh(&mac->hw->page_lock); -+ -+ return 0; -+} -+ -+static void ipqess_tx_timeout(struct net_device *netdev, unsigned int txq_id) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ struct ipqess_tx_ring *tr = &ess->tx_ring[txq_id]; -+ -+ netdev_warn(netdev, "hardware queue %d is in stuck?\n", -+ tr->idx); -+ -+ /* TODO: dump hardware queue */ -+} -+ -+static const struct net_device_ops ipqess_axi_netdev_ops = { -+ .ndo_init = ipqess_init, -+ .ndo_uninit = ipqess_uninit, -+ .ndo_open = ipqess_open, -+ .ndo_stop = ipqess_stop, -+ .ndo_do_ioctl = ipqess_do_ioctl, -+ .ndo_start_xmit = ipqess_xmit, -+ .ndo_get_stats = ipqess_get_stats, -+ .ndo_set_mac_address = ipqess_set_mac_address, -+ .ndo_tx_timeout = ipqess_tx_timeout, -+}; -+ -+static void ipqess_hw_stop(struct ipqess *ess) -+{ -+ int i; -+ -+ /* disable all RX queue IRQs */ -+ for (i = 0; i < IPQESS_MAX_RX_QUEUE; i++) -+ ipqess_w32(ess, IPQESS_REG_RX_INT_MASK_Q(i), 0); -+ -+ /* disable all TX queue IRQs */ -+ for (i = 0; i < IPQESS_MAX_TX_QUEUE; i++) -+ ipqess_w32(ess, IPQESS_REG_TX_INT_MASK_Q(i), 0); -+ -+ /* disable all other IRQs */ -+ ipqess_w32(ess, IPQESS_REG_MISC_IMR, 0); -+ ipqess_w32(ess, IPQESS_REG_WOL_IMR, 0); -+ -+ /* clear the IRQ status registers */ -+ ipqess_w32(ess, IPQESS_REG_RX_ISR, 0xff); -+ ipqess_w32(ess, IPQESS_REG_TX_ISR, 0xffff); -+ ipqess_w32(ess, IPQESS_REG_MISC_ISR, 0x1fff); -+ ipqess_w32(ess, IPQESS_REG_WOL_ISR, 0x1); -+ ipqess_w32(ess, IPQESS_REG_WOL_CTRL, 0); -+ -+ /* disable RX and TX queues */ -+ ipqess_m32(ess, IPQESS_RXQ_CTRL_EN_MASK, 0, IPQESS_REG_RXQ_CTRL); -+ ipqess_m32(ess, IPQESS_TXQ_CTRL_TXQ_EN, 0, IPQESS_REG_TXQ_CTRL); -+} -+ -+static int ipqess_hw_init(struct ipqess *ess) -+{ -+ u32 tmp; -+ int i, err; -+ -+ ipqess_hw_stop(ess); -+ -+ ipqess_m32(ess, BIT(IPQESS_INTR_SW_IDX_W_TYP_SHIFT), -+ IPQESS_INTR_SW_IDX_W_TYPE << IPQESS_INTR_SW_IDX_W_TYP_SHIFT, -+ IPQESS_REG_INTR_CTRL); -+ -+ /* enable IRQ delay slot */ -+ ipqess_w32(ess, IPQESS_REG_IRQ_MODRT_TIMER_INIT, -+ (IPQESS_TX_IMT << IPQESS_IRQ_MODRT_TX_TIMER_SHIFT) | -+ (IPQESS_RX_IMT << IPQESS_IRQ_MODRT_RX_TIMER_SHIFT)); -+ -+ /* Set Customer and Service VLAN TPIDs */ -+ ipqess_w32(ess, IPQESS_REG_VLAN_CFG, -+ (ETH_P_8021Q << IPQESS_VLAN_CFG_CVLAN_TPID_SHIFT) | -+ (ETH_P_8021AD << IPQESS_VLAN_CFG_SVLAN_TPID_SHIFT)); -+ -+ /* Configure the TX Queue bursting */ -+ ipqess_w32(ess, IPQESS_REG_TXQ_CTRL, -+ (IPQESS_TPD_BURST << IPQESS_TXQ_NUM_TPD_BURST_SHIFT) | -+ (IPQESS_TXF_BURST << IPQESS_TXQ_TXF_BURST_NUM_SHIFT) | -+ IPQESS_TXQ_CTRL_TPD_BURST_EN); -+ -+ /* Set RSS type */ -+ ipqess_w32(ess, IPQESS_REG_RSS_TYPE, -+ IPQESS_RSS_TYPE_IPV4TCP | IPQESS_RSS_TYPE_IPV6_TCP | -+ IPQESS_RSS_TYPE_IPV4_UDP | IPQESS_RSS_TYPE_IPV6UDP | -+ IPQESS_RSS_TYPE_IPV4 | IPQESS_RSS_TYPE_IPV6); -+ -+ /* Set RFD ring burst and threshold */ -+ ipqess_w32(ess, IPQESS_REG_RX_DESC1, -+ (IPQESS_RFD_BURST << IPQESS_RXQ_RFD_BURST_NUM_SHIFT) | -+ (IPQESS_RFD_THR << IPQESS_RXQ_RFD_PF_THRESH_SHIFT) | -+ (IPQESS_RFD_LTHR << IPQESS_RXQ_RFD_LOW_THRESH_SHIFT)); -+ -+ /* Set Rx FIFO -+ * - threshold to start to DMA data to host -+ */ -+ ipqess_w32(ess, IPQESS_REG_RXQ_CTRL, -+ IPQESS_FIFO_THRESH_128_BYTE | IPQESS_RXQ_CTRL_RMV_VLAN); -+ -+ err = ipqess_rx_ring_alloc(ess); -+ if (err) -+ return err; -+ -+ err = ipqess_tx_ring_alloc(ess); -+ if (err) -+ return err; -+ -+ /* Load all of ring base addresses above into the dma engine */ -+ ipqess_m32(ess, 0, BIT(IPQESS_LOAD_PTR_SHIFT), -+ IPQESS_REG_TX_SRAM_PART); -+ -+ /* Disable TX FIFO low watermark and high watermark */ -+ ipqess_w32(ess, IPQESS_REG_TXF_WATER_MARK, 0); -+ -+ /* Configure RSS indirection table. -+ * 128 hash will be configured in the following -+ * pattern: hash{0,1,2,3} = {Q0,Q2,Q4,Q6} respectively -+ * and so on -+ */ -+ for (i = 0; i < IPQESS_NUM_IDT; i++) -+ ipqess_w32(ess, IPQESS_REG_RSS_IDT(i), IPQESS_RSS_IDT_VALUE); -+ -+ /* Configure load balance mapping table. -+ * 4 table entry will be configured according to the -+ * following pattern: load_balance{0,1,2,3} = {Q0,Q1,Q3,Q4} -+ * respectively. -+ */ -+ ipqess_w32(ess, IPQESS_REG_LB_RING, IPQESS_LB_REG_VALUE); -+ -+ /* Configure Virtual queue for Tx rings */ -+ ipqess_w32(ess, IPQESS_REG_VQ_CTRL0, IPQESS_VQ_REG_VALUE); -+ ipqess_w32(ess, IPQESS_REG_VQ_CTRL1, IPQESS_VQ_REG_VALUE); -+ -+ /* Configure Max AXI Burst write size to 128 bytes*/ -+ ipqess_w32(ess, IPQESS_REG_AXIW_CTRL_MAXWRSIZE, -+ IPQESS_AXIW_MAXWRSIZE_VALUE); -+ -+ /* Enable TX queues */ -+ ipqess_m32(ess, 0, IPQESS_TXQ_CTRL_TXQ_EN, IPQESS_REG_TXQ_CTRL); -+ -+ /* Enable RX queues */ -+ tmp = 0; -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) -+ tmp |= IPQESS_RXQ_CTRL_EN(ess->rx_ring[i].idx); -+ -+ ipqess_m32(ess, IPQESS_RXQ_CTRL_EN_MASK, tmp, IPQESS_REG_RXQ_CTRL); -+ -+ return 0; -+} -+ -+static void ipqess_validate(struct phylink_config *config, -+ unsigned long *supported, -+ struct phylink_link_state *state) -+{ -+ struct ipqess *ess = container_of(config, struct ipqess, phylink_config); -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -+ -+ if (state->interface != PHY_INTERFACE_MODE_INTERNAL) { -+ dev_err(&ess->pdev->dev, "unsupported interface mode: %d\n", -+ state->interface); -+ linkmode_zero(supported); -+ return; -+ } -+ -+ phylink_set_port_modes(mask); -+ phylink_set(mask, 1000baseT_Full); -+ phylink_set(mask, Pause); -+ phylink_set(mask, Asym_Pause); -+ -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); -+} -+ -+static void ipqess_mac_config(struct phylink_config *config, unsigned int mode, -+ const struct phylink_link_state *state) -+{ -+ /* TODO */ -+} -+ -+static void ipqess_mac_link_down(struct phylink_config *config, -+ unsigned int mode, -+ phy_interface_t interface) -+{ -+ /* TODO */ -+} -+ -+static void ipqess_mac_link_up(struct phylink_config *config, -+ struct phy_device *phy, unsigned int mode, -+ phy_interface_t interface, -+ int speed, int duplex, -+ bool tx_pause, bool rx_pause) -+{ -+ /* TODO */ -+} -+ -+static struct phylink_mac_ops ipqess_phylink_mac_ops = { -+ .validate = ipqess_validate, -+ .mac_config = ipqess_mac_config, -+ .mac_link_up = ipqess_mac_link_up, -+ .mac_link_down = ipqess_mac_link_down, -+}; -+ -+static void ipqess_cleanup(struct ipqess *ess) -+{ -+ ipqess_hw_stop(ess); -+ unregister_netdev(ess->netdev); -+ -+ ipqess_tx_ring_free(ess); -+ ipqess_rx_ring_free(ess); -+ -+ if (!IS_ERR_OR_NULL(ess->phylink)) -+ phylink_destroy(ess->phylink); -+} -+ -+static void ess_reset(struct ipqess *ess) -+{ -+ reset_control_assert(ess->ess_rst); -+ -+ mdelay(10); -+ -+ reset_control_deassert(ess->ess_rst); -+ -+ /* Waiting for all inner tables to be flushed and reinitialized. -+ * This takes between 5 and 10ms. -+ */ -+ mdelay(10); -+} -+ -+static int ipqess_axi_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct ipqess *ess; -+ struct net_device *netdev; -+ struct resource *res; -+ int i, err = 0; -+ -+ netdev = devm_alloc_etherdev_mqs(&pdev->dev, sizeof(struct ipqess), -+ IPQESS_NETDEV_QUEUES, -+ IPQESS_NETDEV_QUEUES); -+ if (!netdev) -+ return -ENOMEM; -+ -+ ess = netdev_priv(netdev); -+ ess->netdev = netdev; -+ ess->pdev = pdev; -+ spin_lock_init(&ess->stats_lock); -+ SET_NETDEV_DEV(netdev, &pdev->dev); -+ platform_set_drvdata(pdev, netdev); -+ -+ err = of_get_mac_address(np, netdev->dev_addr); -+ if (err == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ -+ if (err) { -+ -+ random_ether_addr(netdev->dev_addr); -+ dev_info(&ess->pdev->dev, "generated random MAC address %pM\n", -+ netdev->dev_addr); -+ netdev->addr_assign_type = NET_ADDR_RANDOM; -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ ess->hw_addr = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(ess->hw_addr)) { -+ err = PTR_ERR(ess->hw_addr); -+ goto err_out; -+ } -+ -+ ess->ess_clk = of_clk_get_by_name(np, "ess_clk"); -+ if (IS_ERR(ess->ess_clk)) { -+ dev_err(&pdev->dev, "Failed to get ess_clk\n"); -+ return PTR_ERR(ess->ess_clk); -+ } -+ -+ ess->ess_rst = devm_reset_control_get(&pdev->dev, "ess_rst"); -+ if (IS_ERR(ess->ess_rst)) { -+ dev_err(&pdev->dev, "Failed to get ess_rst control!\n"); -+ return PTR_ERR(ess->ess_rst); -+ } -+ -+ clk_prepare_enable(ess->ess_clk); -+ -+ ess_reset(ess); -+ -+ ess->phylink_config.dev = &netdev->dev; -+ ess->phylink_config.type = PHYLINK_NETDEV; -+ ess->phylink_config.pcs_poll = true; -+ -+ ess->phylink = phylink_create(&ess->phylink_config, -+ of_fwnode_handle(np), -+ PHY_INTERFACE_MODE_INTERNAL, -+ &ipqess_phylink_mac_ops); -+ if (IS_ERR(ess->phylink)) { -+ err = PTR_ERR(ess->phylink); -+ goto err_out; -+ } -+ -+ for (i = 0; i < IPQESS_MAX_TX_QUEUE; i++) { -+ ess->tx_irq[i] = platform_get_irq(pdev, i); -+ scnprintf(ess->tx_irq_names[i], sizeof(ess->tx_irq_names[i]), -+ "%s:txq%d", pdev->name, i); -+ } -+ -+ for (i = 0; i < IPQESS_MAX_RX_QUEUE; i++) { -+ ess->rx_irq[i] = platform_get_irq(pdev, i + IPQESS_MAX_TX_QUEUE); -+ scnprintf(ess->rx_irq_names[i], sizeof(ess->rx_irq_names[i]), -+ "%s:rxq%d", pdev->name, i); -+ } -+ -+#undef NETIF_F_TSO6 -+#define NETIF_F_TSO6 0 -+ -+ netdev->netdev_ops = &ipqess_axi_netdev_ops; -+ netdev->features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | -+ NETIF_F_HW_VLAN_CTAG_RX | -+ NETIF_F_HW_VLAN_CTAG_TX | -+ NETIF_F_TSO | NETIF_F_TSO6 | -+ NETIF_F_GRO | NETIF_F_SG; -+ /* feature change is not supported yet */ -+ netdev->hw_features = 0; -+ netdev->vlan_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_RXCSUM | -+ NETIF_F_TSO | NETIF_F_TSO6 | -+ NETIF_F_GRO; -+ netdev->watchdog_timeo = 5 * HZ; -+ netdev->base_addr = (u32) ess->hw_addr; -+ netdev->max_mtu = 9000; -+ netdev->gso_max_segs = IPQESS_TX_RING_SIZE / 2; -+ -+ ipqess_set_ethtool_ops(netdev); -+ -+ err = register_netdev(netdev); -+ if (err) -+ goto err_out; -+ -+ err = ipqess_hw_init(ess); -+ if (err) -+ goto err_out; -+ -+ for (i = 0; i < IPQESS_NETDEV_QUEUES; i++) { -+ int qid; -+ -+ netif_tx_napi_add(netdev, &ess->tx_ring[i].napi_tx, -+ ipqess_tx_napi, 64); -+ netif_napi_add(netdev, -+ &ess->rx_ring[i].napi_rx, -+ ipqess_rx_napi, 64); -+ -+ qid = ess->tx_ring[i].idx; -+ err = devm_request_irq(&ess->netdev->dev, ess->tx_irq[qid], -+ ipqess_interrupt_tx, 0, ess->tx_irq_names[qid], -+ &ess->tx_ring[i]); -+ if (err) -+ goto err_out; -+ -+ qid = ess->rx_ring[i].idx; -+ err = devm_request_irq(&ess->netdev->dev, ess->rx_irq[qid], -+ ipqess_interrupt_rx, 0, ess->rx_irq_names[qid], -+ &ess->rx_ring[i]); -+ if (err) -+ goto err_out; -+ } -+ -+ return 0; -+ -+err_out: -+ ipqess_cleanup(ess); -+ return err; -+} -+ -+static int ipqess_axi_remove(struct platform_device *pdev) -+{ -+ const struct net_device *netdev = platform_get_drvdata(pdev); -+ struct ipqess *ess = netdev_priv(netdev); -+ -+ ipqess_cleanup(ess); -+ -+ return 0; -+} -+ -+static const struct of_device_id ipqess_of_mtable[] = { -+ {.compatible = "qcom,ipq4019-ess-edma" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, ipqess_of_mtable); -+ -+static struct platform_driver ipqess_axi_driver = { -+ .driver = { -+ .name = "ipqess-edma", -+ .of_match_table = ipqess_of_mtable, -+ }, -+ .probe = ipqess_axi_probe, -+ .remove = ipqess_axi_remove, -+}; -+ -+module_platform_driver(ipqess_axi_driver); -+ -+MODULE_AUTHOR("Qualcomm Atheros Inc"); -+MODULE_AUTHOR("John Crispin "); -+MODULE_AUTHOR("Christian Lamparter "); -+MODULE_AUTHOR("Gabor Juhos "); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/ipqess/ipqess.h -@@ -0,0 +1,530 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR ISC) -+/* Copyright (c) 2014 - 2016, The Linux Foundation. All rights reserved. -+ * Copyright (c) 2017 - 2018, John Crispin -+ * Copyright (c) 2018 - 2019, Christian Lamparter -+ * Copyright (c) 2020 - 2021, Gabor Juhos -+ * -+ * Permission to use, copy, modify, and/or distribute this software for -+ * any purpose with or without fee is hereby granted, provided that the -+ * above copyright notice and this permission notice appear in all copies. -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+#ifndef _IPQESS_H_ -+#define _IPQESS_H_ -+ -+#define IPQESS_NETDEV_QUEUES 4 -+ -+#define IPQESS_TPD_EOP_SHIFT 31 -+ -+#define IPQESS_PORT_ID_SHIFT 12 -+#define IPQESS_PORT_ID_MASK 0x7 -+ -+/* tpd word 3 bit 18-28 */ -+#define IPQESS_TPD_PORT_BITMAP_SHIFT 18 -+ -+#define IPQESS_TPD_FROM_CPU_SHIFT 25 -+ -+#define IPQESS_RX_RING_SIZE 128 -+#define IPQESS_RX_HEAD_BUFF_SIZE 1540 -+#define IPQESS_TX_RING_SIZE 128 -+#define IPQESS_MAX_RX_QUEUE 8 -+#define IPQESS_MAX_TX_QUEUE 16 -+ -+ -+/* Configurations */ -+#define IPQESS_INTR_CLEAR_TYPE 0 -+#define IPQESS_INTR_SW_IDX_W_TYPE 0 -+#define IPQESS_FIFO_THRESH_TYPE 0 -+#define IPQESS_RSS_TYPE 0 -+#define IPQESS_RX_IMT 0x0020 -+#define IPQESS_TX_IMT 0x0050 -+#define IPQESS_TPD_BURST 5 -+#define IPQESS_TXF_BURST 0x100 -+#define IPQESS_RFD_BURST 8 -+#define IPQESS_RFD_THR 16 -+#define IPQESS_RFD_LTHR 0 -+ -+/* Flags used in transmit direction */ -+#define IPQESS_DESC_LAST 0x1 -+#define IPQESS_DESC_SINGLE 0x2 -+#define IPQESS_DESC_PAGE 0x4 -+ -+struct ipqesstool_statistics { -+ u32 tx_q0_pkt; -+ u32 tx_q1_pkt; -+ u32 tx_q2_pkt; -+ u32 tx_q3_pkt; -+ u32 tx_q4_pkt; -+ u32 tx_q5_pkt; -+ u32 tx_q6_pkt; -+ u32 tx_q7_pkt; -+ u32 tx_q8_pkt; -+ u32 tx_q9_pkt; -+ u32 tx_q10_pkt; -+ u32 tx_q11_pkt; -+ u32 tx_q12_pkt; -+ u32 tx_q13_pkt; -+ u32 tx_q14_pkt; -+ u32 tx_q15_pkt; -+ u32 tx_q0_byte; -+ u32 tx_q1_byte; -+ u32 tx_q2_byte; -+ u32 tx_q3_byte; -+ u32 tx_q4_byte; -+ u32 tx_q5_byte; -+ u32 tx_q6_byte; -+ u32 tx_q7_byte; -+ u32 tx_q8_byte; -+ u32 tx_q9_byte; -+ u32 tx_q10_byte; -+ u32 tx_q11_byte; -+ u32 tx_q12_byte; -+ u32 tx_q13_byte; -+ u32 tx_q14_byte; -+ u32 tx_q15_byte; -+ u32 rx_q0_pkt; -+ u32 rx_q1_pkt; -+ u32 rx_q2_pkt; -+ u32 rx_q3_pkt; -+ u32 rx_q4_pkt; -+ u32 rx_q5_pkt; -+ u32 rx_q6_pkt; -+ u32 rx_q7_pkt; -+ u32 rx_q0_byte; -+ u32 rx_q1_byte; -+ u32 rx_q2_byte; -+ u32 rx_q3_byte; -+ u32 rx_q4_byte; -+ u32 rx_q5_byte; -+ u32 rx_q6_byte; -+ u32 rx_q7_byte; -+ u32 tx_desc_error; -+}; -+ -+struct ipqess_tx_desc { -+ __le16 len; -+ __le16 svlan_tag; -+ __le32 word1; -+ __le32 addr; -+ __le32 word3; -+} __aligned(16) __packed; -+ -+struct ipqess_rx_desc { -+ u16 rrd0; -+ u16 rrd1; -+ u16 rrd2; -+ u16 rrd3; -+ u16 rrd4; -+ u16 rrd5; -+ u16 rrd6; -+ u16 rrd7; -+} __aligned(16) __packed; -+ -+struct ipqess_buf { -+ struct sk_buff *skb; -+ dma_addr_t dma; -+ u32 flags; -+ u16 length; -+}; -+ -+struct ipqess_tx_ring { -+ struct napi_struct napi_tx; -+ u32 idx; -+ int ring_id; -+ struct ipqess *ess; -+ struct netdev_queue *nq; -+ struct ipqess_tx_desc *hw_desc; -+ struct ipqess_buf *buf; -+ dma_addr_t dma; -+ u16 count; -+ u16 head; -+ u16 tail; -+}; -+ -+struct ipqess_rx_ring { -+ struct napi_struct napi_rx; -+ u32 idx; -+ int ring_id; -+ struct ipqess *ess; -+ struct device *ppdev; -+ struct ipqess_rx_desc **hw_desc; -+ struct ipqess_buf *buf; -+ dma_addr_t dma; -+ u16 head; -+ u16 tail; -+ atomic_t refill_count; -+}; -+ -+struct ipqess_rx_ring_refill { -+ struct ipqess_rx_ring *rx_ring; -+ struct work_struct refill_work; -+}; -+ -+#define IPQESS_IRQ_NAME_LEN 32 -+ -+struct ipqess { -+ struct net_device *netdev; -+ void __iomem *hw_addr; -+ struct clk *ess_clk; -+ struct reset_control *ess_rst; -+ -+ struct ipqess_rx_ring rx_ring[IPQESS_NETDEV_QUEUES]; -+ -+ struct platform_device *pdev; -+ struct phylink *phylink; -+ struct phylink_config phylink_config; -+ struct ipqess_tx_ring tx_ring[IPQESS_NETDEV_QUEUES]; -+ -+ struct ipqesstool_statistics ipqessstats; -+ spinlock_t stats_lock; -+ struct net_device_stats stats; -+ -+ struct ipqess_rx_ring_refill rx_refill[IPQESS_NETDEV_QUEUES]; -+ u32 tx_irq[IPQESS_MAX_TX_QUEUE]; -+ char tx_irq_names[IPQESS_MAX_TX_QUEUE][IPQESS_IRQ_NAME_LEN]; -+ u32 rx_irq[IPQESS_MAX_RX_QUEUE]; -+ char rx_irq_names[IPQESS_MAX_TX_QUEUE][IPQESS_IRQ_NAME_LEN]; -+}; -+ -+static inline void build_test(void) -+{ -+ struct ipqess *ess; -+ BUILD_BUG_ON(ARRAY_SIZE(ess->rx_ring) != ARRAY_SIZE(ess->rx_refill)); -+} -+ -+void ipqess_set_ethtool_ops(struct net_device *netdev); -+void ipqess_update_hw_stats(struct ipqess *ess); -+ -+/* register definition */ -+#define IPQESS_REG_MAS_CTRL 0x0 -+#define IPQESS_REG_TIMEOUT_CTRL 0x004 -+#define IPQESS_REG_DBG0 0x008 -+#define IPQESS_REG_DBG1 0x00C -+#define IPQESS_REG_SW_CTRL0 0x100 -+#define IPQESS_REG_SW_CTRL1 0x104 -+ -+/* Interrupt Status Register */ -+#define IPQESS_REG_RX_ISR 0x200 -+#define IPQESS_REG_TX_ISR 0x208 -+#define IPQESS_REG_MISC_ISR 0x210 -+#define IPQESS_REG_WOL_ISR 0x218 -+ -+#define IPQESS_MISC_ISR_RX_URG_Q(x) (1 << x) -+ -+#define IPQESS_MISC_ISR_AXIR_TIMEOUT 0x00000100 -+#define IPQESS_MISC_ISR_AXIR_ERR 0x00000200 -+#define IPQESS_MISC_ISR_TXF_DEAD 0x00000400 -+#define IPQESS_MISC_ISR_AXIW_ERR 0x00000800 -+#define IPQESS_MISC_ISR_AXIW_TIMEOUT 0x00001000 -+ -+#define IPQESS_WOL_ISR 0x00000001 -+ -+/* Interrupt Mask Register */ -+#define IPQESS_REG_MISC_IMR 0x214 -+#define IPQESS_REG_WOL_IMR 0x218 -+ -+#define IPQESS_RX_IMR_NORMAL_MASK 0x1 -+#define IPQESS_TX_IMR_NORMAL_MASK 0x1 -+#define IPQESS_MISC_IMR_NORMAL_MASK 0x80001FFF -+#define IPQESS_WOL_IMR_NORMAL_MASK 0x1 -+ -+/* Edma receive consumer index */ -+#define IPQESS_REG_RX_SW_CONS_IDX_Q(x) (0x220 + ((x) << 2)) /* x is the queue id */ -+ -+/* Edma transmit consumer index */ -+#define IPQESS_REG_TX_SW_CONS_IDX_Q(x) (0x240 + ((x) << 2)) /* x is the queue id */ -+ -+/* IRQ Moderator Initial Timer Register */ -+#define IPQESS_REG_IRQ_MODRT_TIMER_INIT 0x280 -+#define IPQESS_IRQ_MODRT_TIMER_MASK 0xFFFF -+#define IPQESS_IRQ_MODRT_RX_TIMER_SHIFT 0 -+#define IPQESS_IRQ_MODRT_TX_TIMER_SHIFT 16 -+ -+/* Interrupt Control Register */ -+#define IPQESS_REG_INTR_CTRL 0x284 -+#define IPQESS_INTR_CLR_TYP_SHIFT 0 -+#define IPQESS_INTR_SW_IDX_W_TYP_SHIFT 1 -+#define IPQESS_INTR_CLEAR_TYPE_W1 0 -+#define IPQESS_INTR_CLEAR_TYPE_R 1 -+ -+/* RX Interrupt Mask Register */ -+#define IPQESS_REG_RX_INT_MASK_Q(x) (0x300 + ((x) << 2)) /* x = queue id */ -+ -+/* TX Interrupt mask register */ -+#define IPQESS_REG_TX_INT_MASK_Q(x) (0x340 + ((x) << 2)) /* x = queue id */ -+ -+/* Load Ptr Register -+ * Software sets this bit after the initialization of the head and tail -+ */ -+#define IPQESS_REG_TX_SRAM_PART 0x400 -+#define IPQESS_LOAD_PTR_SHIFT 16 -+ -+/* TXQ Control Register */ -+#define IPQESS_REG_TXQ_CTRL 0x404 -+#define IPQESS_TXQ_CTRL_IP_OPTION_EN 0x10 -+#define IPQESS_TXQ_CTRL_TXQ_EN 0x20 -+#define IPQESS_TXQ_CTRL_ENH_MODE 0x40 -+#define IPQESS_TXQ_CTRL_LS_8023_EN 0x80 -+#define IPQESS_TXQ_CTRL_TPD_BURST_EN 0x100 -+#define IPQESS_TXQ_CTRL_LSO_BREAK_EN 0x200 -+#define IPQESS_TXQ_NUM_TPD_BURST_MASK 0xF -+#define IPQESS_TXQ_TXF_BURST_NUM_MASK 0xFFFF -+#define IPQESS_TXQ_NUM_TPD_BURST_SHIFT 0 -+#define IPQESS_TXQ_TXF_BURST_NUM_SHIFT 16 -+ -+#define IPQESS_REG_TXF_WATER_MARK 0x408 /* In 8-bytes */ -+#define IPQESS_TXF_WATER_MARK_MASK 0x0FFF -+#define IPQESS_TXF_LOW_WATER_MARK_SHIFT 0 -+#define IPQESS_TXF_HIGH_WATER_MARK_SHIFT 16 -+#define IPQESS_TXQ_CTRL_BURST_MODE_EN 0x80000000 -+ -+/* WRR Control Register */ -+#define IPQESS_REG_WRR_CTRL_Q0_Q3 0x40c -+#define IPQESS_REG_WRR_CTRL_Q4_Q7 0x410 -+#define IPQESS_REG_WRR_CTRL_Q8_Q11 0x414 -+#define IPQESS_REG_WRR_CTRL_Q12_Q15 0x418 -+ -+/* Weight round robin(WRR), it takes queue as input, and computes -+ * starting bits where we need to write the weight for a particular -+ * queue -+ */ -+#define IPQESS_WRR_SHIFT(x) (((x) * 5) % 20) -+ -+/* Tx Descriptor Control Register */ -+#define IPQESS_REG_TPD_RING_SIZE 0x41C -+#define IPQESS_TPD_RING_SIZE_SHIFT 0 -+#define IPQESS_TPD_RING_SIZE_MASK 0xFFFF -+ -+/* Transmit descriptor base address */ -+#define IPQESS_REG_TPD_BASE_ADDR_Q(x) (0x420 + ((x) << 2)) /* x = queue id */ -+ -+/* TPD Index Register */ -+#define IPQESS_REG_TPD_IDX_Q(x) (0x460 + ((x) << 2)) /* x = queue id */ -+ -+#define IPQESS_TPD_PROD_IDX_BITS 0x0000FFFF -+#define IPQESS_TPD_CONS_IDX_BITS 0xFFFF0000 -+#define IPQESS_TPD_PROD_IDX_MASK 0xFFFF -+#define IPQESS_TPD_CONS_IDX_MASK 0xFFFF -+#define IPQESS_TPD_PROD_IDX_SHIFT 0 -+#define IPQESS_TPD_CONS_IDX_SHIFT 16 -+ -+/* TX Virtual Queue Mapping Control Register */ -+#define IPQESS_REG_VQ_CTRL0 0x4A0 -+#define IPQESS_REG_VQ_CTRL1 0x4A4 -+ -+/* Virtual QID shift, it takes queue as input, and computes -+ * Virtual QID position in virtual qid control register -+ */ -+#define IPQESS_VQ_ID_SHIFT(i) (((i) * 3) % 24) -+ -+/* Virtual Queue Default Value */ -+#define IPQESS_VQ_REG_VALUE 0x240240 -+ -+/* Tx side Port Interface Control Register */ -+#define IPQESS_REG_PORT_CTRL 0x4A8 -+#define IPQESS_PAD_EN_SHIFT 15 -+ -+/* Tx side VLAN Configuration Register */ -+#define IPQESS_REG_VLAN_CFG 0x4AC -+ -+#define IPQESS_VLAN_CFG_SVLAN_TPID_SHIFT 0 -+#define IPQESS_VLAN_CFG_SVLAN_TPID_MASK 0xffff -+#define IPQESS_VLAN_CFG_CVLAN_TPID_SHIFT 16 -+#define IPQESS_VLAN_CFG_CVLAN_TPID_MASK 0xffff -+ -+#define IPQESS_TX_CVLAN 16 -+#define IPQESS_TX_INS_CVLAN 17 -+#define IPQESS_TX_CVLAN_TAG_SHIFT 0 -+ -+#define IPQESS_TX_SVLAN 14 -+#define IPQESS_TX_INS_SVLAN 15 -+#define IPQESS_TX_SVLAN_TAG_SHIFT 16 -+ -+/* Tx Queue Packet Statistic Register */ -+#define IPQESS_REG_TX_STAT_PKT_Q(x) (0x700 + ((x) << 3)) /* x = queue id */ -+ -+#define IPQESS_TX_STAT_PKT_MASK 0xFFFFFF -+ -+/* Tx Queue Byte Statistic Register */ -+#define IPQESS_REG_TX_STAT_BYTE_Q(x) (0x704 + ((x) << 3)) /* x = queue id */ -+ -+/* Load Balance Based Ring Offset Register */ -+#define IPQESS_REG_LB_RING 0x800 -+#define IPQESS_LB_RING_ENTRY_MASK 0xff -+#define IPQESS_LB_RING_ID_MASK 0x7 -+#define IPQESS_LB_RING_PROFILE_ID_MASK 0x3 -+#define IPQESS_LB_RING_ENTRY_BIT_OFFSET 8 -+#define IPQESS_LB_RING_ID_OFFSET 0 -+#define IPQESS_LB_RING_PROFILE_ID_OFFSET 3 -+#define IPQESS_LB_REG_VALUE 0x6040200 -+ -+/* Load Balance Priority Mapping Register */ -+#define IPQESS_REG_LB_PRI_START 0x804 -+#define IPQESS_REG_LB_PRI_END 0x810 -+#define IPQESS_LB_PRI_REG_INC 4 -+#define IPQESS_LB_PRI_ENTRY_BIT_OFFSET 4 -+#define IPQESS_LB_PRI_ENTRY_MASK 0xf -+ -+/* RSS Priority Mapping Register */ -+#define IPQESS_REG_RSS_PRI 0x820 -+#define IPQESS_RSS_PRI_ENTRY_MASK 0xf -+#define IPQESS_RSS_RING_ID_MASK 0x7 -+#define IPQESS_RSS_PRI_ENTRY_BIT_OFFSET 4 -+ -+/* RSS Indirection Register */ -+#define IPQESS_REG_RSS_IDT(x) (0x840 + ((x) << 2)) /* x = No. of indirection table */ -+#define IPQESS_NUM_IDT 16 -+#define IPQESS_RSS_IDT_VALUE 0x64206420 -+ -+/* Default RSS Ring Register */ -+#define IPQESS_REG_DEF_RSS 0x890 -+#define IPQESS_DEF_RSS_MASK 0x7 -+ -+/* RSS Hash Function Type Register */ -+#define IPQESS_REG_RSS_TYPE 0x894 -+#define IPQESS_RSS_TYPE_NONE 0x01 -+#define IPQESS_RSS_TYPE_IPV4TCP 0x02 -+#define IPQESS_RSS_TYPE_IPV6_TCP 0x04 -+#define IPQESS_RSS_TYPE_IPV4_UDP 0x08 -+#define IPQESS_RSS_TYPE_IPV6UDP 0x10 -+#define IPQESS_RSS_TYPE_IPV4 0x20 -+#define IPQESS_RSS_TYPE_IPV6 0x40 -+#define IPQESS_RSS_HASH_MODE_MASK 0x7f -+ -+#define IPQESS_REG_RSS_HASH_VALUE 0x8C0 -+ -+#define IPQESS_REG_RSS_TYPE_RESULT 0x8C4 -+ -+#define IPQESS_HASH_TYPE_START 0 -+#define IPQESS_HASH_TYPE_END 5 -+#define IPQESS_HASH_TYPE_SHIFT 12 -+ -+#define IPQESS_RFS_FLOW_ENTRIES 1024 -+#define IPQESS_RFS_FLOW_ENTRIES_MASK (IPQESS_RFS_FLOW_ENTRIES - 1) -+#define IPQESS_RFS_EXPIRE_COUNT_PER_CALL 128 -+ -+/* RFD Base Address Register */ -+#define IPQESS_REG_RFD_BASE_ADDR_Q(x) (0x950 + ((x) << 2)) /* x = queue id */ -+ -+/* RFD Index Register */ -+#define IPQESS_REG_RFD_IDX_Q(x) (0x9B0 + ((x) << 2)) /* x = queue id */ -+ -+#define IPQESS_RFD_PROD_IDX_BITS 0x00000FFF -+#define IPQESS_RFD_CONS_IDX_BITS 0x0FFF0000 -+#define IPQESS_RFD_PROD_IDX_MASK 0xFFF -+#define IPQESS_RFD_CONS_IDX_MASK 0xFFF -+#define IPQESS_RFD_PROD_IDX_SHIFT 0 -+#define IPQESS_RFD_CONS_IDX_SHIFT 16 -+ -+/* Rx Descriptor Control Register */ -+#define IPQESS_REG_RX_DESC0 0xA10 -+#define IPQESS_RFD_RING_SIZE_MASK 0xFFF -+#define IPQESS_RX_BUF_SIZE_MASK 0xFFFF -+#define IPQESS_RFD_RING_SIZE_SHIFT 0 -+#define IPQESS_RX_BUF_SIZE_SHIFT 16 -+ -+#define IPQESS_REG_RX_DESC1 0xA14 -+#define IPQESS_RXQ_RFD_BURST_NUM_MASK 0x3F -+#define IPQESS_RXQ_RFD_PF_THRESH_MASK 0x1F -+#define IPQESS_RXQ_RFD_LOW_THRESH_MASK 0xFFF -+#define IPQESS_RXQ_RFD_BURST_NUM_SHIFT 0 -+#define IPQESS_RXQ_RFD_PF_THRESH_SHIFT 8 -+#define IPQESS_RXQ_RFD_LOW_THRESH_SHIFT 16 -+ -+/* RXQ Control Register */ -+#define IPQESS_REG_RXQ_CTRL 0xA18 -+#define IPQESS_FIFO_THRESH_TYPE_SHIF 0 -+#define IPQESS_FIFO_THRESH_128_BYTE 0x0 -+#define IPQESS_FIFO_THRESH_64_BYTE 0x1 -+#define IPQESS_RXQ_CTRL_RMV_VLAN 0x00000002 -+#define IPQESS_RXQ_CTRL_EN_MASK GENMASK(15, 8) -+#define IPQESS_RXQ_CTRL_EN(__qid) BIT(8 + (__qid)) -+ -+/* AXI Burst Size Config */ -+#define IPQESS_REG_AXIW_CTRL_MAXWRSIZE 0xA1C -+#define IPQESS_AXIW_MAXWRSIZE_VALUE 0x0 -+ -+/* Rx Statistics Register */ -+#define IPQESS_REG_RX_STAT_BYTE_Q(x) (0xA30 + ((x) << 2)) /* x = queue id */ -+#define IPQESS_REG_RX_STAT_PKT_Q(x) (0xA50 + ((x) << 2)) /* x = queue id */ -+ -+/* WoL Pattern Length Register */ -+#define IPQESS_REG_WOL_PATTERN_LEN0 0xC00 -+#define IPQESS_WOL_PT_LEN_MASK 0xFF -+#define IPQESS_WOL_PT0_LEN_SHIFT 0 -+#define IPQESS_WOL_PT1_LEN_SHIFT 8 -+#define IPQESS_WOL_PT2_LEN_SHIFT 16 -+#define IPQESS_WOL_PT3_LEN_SHIFT 24 -+ -+#define IPQESS_REG_WOL_PATTERN_LEN1 0xC04 -+#define IPQESS_WOL_PT4_LEN_SHIFT 0 -+#define IPQESS_WOL_PT5_LEN_SHIFT 8 -+#define IPQESS_WOL_PT6_LEN_SHIFT 16 -+ -+/* WoL Control Register */ -+#define IPQESS_REG_WOL_CTRL 0xC08 -+#define IPQESS_WOL_WK_EN 0x00000001 -+#define IPQESS_WOL_MG_EN 0x00000002 -+#define IPQESS_WOL_PT0_EN 0x00000004 -+#define IPQESS_WOL_PT1_EN 0x00000008 -+#define IPQESS_WOL_PT2_EN 0x00000010 -+#define IPQESS_WOL_PT3_EN 0x00000020 -+#define IPQESS_WOL_PT4_EN 0x00000040 -+#define IPQESS_WOL_PT5_EN 0x00000080 -+#define IPQESS_WOL_PT6_EN 0x00000100 -+ -+/* MAC Control Register */ -+#define IPQESS_REG_MAC_CTRL0 0xC20 -+#define IPQESS_REG_MAC_CTRL1 0xC24 -+ -+/* WoL Pattern Register */ -+#define IPQESS_REG_WOL_PATTERN_START 0x5000 -+#define IPQESS_PATTERN_PART_REG_OFFSET 0x40 -+ -+ -+/* TX descriptor fields */ -+#define IPQESS_TPD_HDR_SHIFT 0 -+#define IPQESS_TPD_PPPOE_EN 0x00000100 -+#define IPQESS_TPD_IP_CSUM_EN 0x00000200 -+#define IPQESS_TPD_TCP_CSUM_EN 0x0000400 -+#define IPQESS_TPD_UDP_CSUM_EN 0x00000800 -+#define IPQESS_TPD_CUSTOM_CSUM_EN 0x00000C00 -+#define IPQESS_TPD_LSO_EN 0x00001000 -+#define IPQESS_TPD_LSO_V2_EN 0x00002000 -+/* The VLAN_TAGGED bit is not used in the publicly available -+ * drivers. The definition has been stolen from the Atheros -+ * 'alx' driver (drivers/net/ethernet/atheros/alx/hw.h). It -+ * seems that it has the same meaning in regard to the EDMA -+ * hardware. -+ */ -+#define IPQESS_TPD_VLAN_TAGGED 0x00004000 -+#define IPQESS_TPD_IPV4_EN 0x00010000 -+#define IPQESS_TPD_MSS_MASK 0x1FFF -+#define IPQESS_TPD_MSS_SHIFT 18 -+#define IPQESS_TPD_CUSTOM_CSUM_SHIFT 18 -+ -+/* RRD descriptor fields */ -+#define IPQESS_RRD_NUM_RFD_MASK 0x000F -+#define IPQESS_RRD_PKT_SIZE_MASK 0x3FFF -+#define IPQESS_RRD_SRC_PORT_NUM_MASK 0x4000 -+#define IPQESS_RRD_SVLAN 0x8000 -+#define IPQESS_RRD_FLOW_COOKIE_MASK 0x07FF; -+ -+#define IPQESS_RRD_PKT_SIZE_MASK 0x3FFF -+#define IPQESS_RRD_CSUM_FAIL_MASK 0xC000 -+#define IPQESS_RRD_CVLAN 0x0001 -+#define IPQESS_RRD_DESC_VALID 0x8000 -+ -+#define IPQESS_RRD_PRIORITY_SHIFT 4 -+#define IPQESS_RRD_PRIORITY_MASK 0x7 -+#define IPQESS_RRD_PORT_TYPE_SHIFT 7 -+#define IPQESS_RRD_PORT_TYPE_MASK 0x1F -+ -+#endif ---- /dev/null -+++ b/target/linux/ipq40xx/files/drivers/net/ethernet/qualcomm/ipqess/ipqess_ethtool.c -@@ -0,0 +1,175 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR ISC) -+/* Copyright (c) 2015 - 2016, The Linux Foundation. All rights reserved. -+ * Copyright (c) 2017 - 2018, John Crispin -+ * -+ * Permission to use, copy, modify, and/or distribute this software for -+ * any purpose with or without fee is hereby granted, provided that the -+ * above copyright notice and this permission notice appear in all copies. -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "ipqess.h" -+ -+struct ipqesstool_stats { -+ uint8_t string[ETH_GSTRING_LEN]; -+ uint32_t offset; -+}; -+ -+#define IPQESS_STAT(m) offsetof(struct ipqesstool_statistics, m) -+#define DRVINFO_LEN 32 -+ -+static const struct ipqesstool_stats ipqess_stats[] = { -+ {"tx_q0_pkt", IPQESS_STAT(tx_q0_pkt)}, -+ {"tx_q1_pkt", IPQESS_STAT(tx_q1_pkt)}, -+ {"tx_q2_pkt", IPQESS_STAT(tx_q2_pkt)}, -+ {"tx_q3_pkt", IPQESS_STAT(tx_q3_pkt)}, -+ {"tx_q4_pkt", IPQESS_STAT(tx_q4_pkt)}, -+ {"tx_q5_pkt", IPQESS_STAT(tx_q5_pkt)}, -+ {"tx_q6_pkt", IPQESS_STAT(tx_q6_pkt)}, -+ {"tx_q7_pkt", IPQESS_STAT(tx_q7_pkt)}, -+ {"tx_q8_pkt", IPQESS_STAT(tx_q8_pkt)}, -+ {"tx_q9_pkt", IPQESS_STAT(tx_q9_pkt)}, -+ {"tx_q10_pkt", IPQESS_STAT(tx_q10_pkt)}, -+ {"tx_q11_pkt", IPQESS_STAT(tx_q11_pkt)}, -+ {"tx_q12_pkt", IPQESS_STAT(tx_q12_pkt)}, -+ {"tx_q13_pkt", IPQESS_STAT(tx_q13_pkt)}, -+ {"tx_q14_pkt", IPQESS_STAT(tx_q14_pkt)}, -+ {"tx_q15_pkt", IPQESS_STAT(tx_q15_pkt)}, -+ {"tx_q0_byte", IPQESS_STAT(tx_q0_byte)}, -+ {"tx_q1_byte", IPQESS_STAT(tx_q1_byte)}, -+ {"tx_q2_byte", IPQESS_STAT(tx_q2_byte)}, -+ {"tx_q3_byte", IPQESS_STAT(tx_q3_byte)}, -+ {"tx_q4_byte", IPQESS_STAT(tx_q4_byte)}, -+ {"tx_q5_byte", IPQESS_STAT(tx_q5_byte)}, -+ {"tx_q6_byte", IPQESS_STAT(tx_q6_byte)}, -+ {"tx_q7_byte", IPQESS_STAT(tx_q7_byte)}, -+ {"tx_q8_byte", IPQESS_STAT(tx_q8_byte)}, -+ {"tx_q9_byte", IPQESS_STAT(tx_q9_byte)}, -+ {"tx_q10_byte", IPQESS_STAT(tx_q10_byte)}, -+ {"tx_q11_byte", IPQESS_STAT(tx_q11_byte)}, -+ {"tx_q12_byte", IPQESS_STAT(tx_q12_byte)}, -+ {"tx_q13_byte", IPQESS_STAT(tx_q13_byte)}, -+ {"tx_q14_byte", IPQESS_STAT(tx_q14_byte)}, -+ {"tx_q15_byte", IPQESS_STAT(tx_q15_byte)}, -+ {"rx_q0_pkt", IPQESS_STAT(rx_q0_pkt)}, -+ {"rx_q1_pkt", IPQESS_STAT(rx_q1_pkt)}, -+ {"rx_q2_pkt", IPQESS_STAT(rx_q2_pkt)}, -+ {"rx_q3_pkt", IPQESS_STAT(rx_q3_pkt)}, -+ {"rx_q4_pkt", IPQESS_STAT(rx_q4_pkt)}, -+ {"rx_q5_pkt", IPQESS_STAT(rx_q5_pkt)}, -+ {"rx_q6_pkt", IPQESS_STAT(rx_q6_pkt)}, -+ {"rx_q7_pkt", IPQESS_STAT(rx_q7_pkt)}, -+ {"rx_q0_byte", IPQESS_STAT(rx_q0_byte)}, -+ {"rx_q1_byte", IPQESS_STAT(rx_q1_byte)}, -+ {"rx_q2_byte", IPQESS_STAT(rx_q2_byte)}, -+ {"rx_q3_byte", IPQESS_STAT(rx_q3_byte)}, -+ {"rx_q4_byte", IPQESS_STAT(rx_q4_byte)}, -+ {"rx_q5_byte", IPQESS_STAT(rx_q5_byte)}, -+ {"rx_q6_byte", IPQESS_STAT(rx_q6_byte)}, -+ {"rx_q7_byte", IPQESS_STAT(rx_q7_byte)}, -+ {"tx_desc_error", IPQESS_STAT(tx_desc_error)}, -+}; -+ -+static int ipqess_get_strset_count(struct net_device *netdev, int sset) -+{ -+ switch (sset) { -+ case ETH_SS_STATS: -+ return ARRAY_SIZE(ipqess_stats); -+ default: -+ netdev_dbg(netdev, "%s: Invalid string set", __func__); -+ return -EOPNOTSUPP; -+ } -+} -+ -+static void ipqess_get_strings(struct net_device *netdev, uint32_t stringset, -+ uint8_t *data) -+{ -+ uint8_t *p = data; -+ uint32_t i; -+ -+ switch (stringset) { -+ case ETH_SS_STATS: -+ for (i = 0; i < ARRAY_SIZE(ipqess_stats); i++) { -+ memcpy(p, ipqess_stats[i].string, -+ min((size_t)ETH_GSTRING_LEN, -+ strlen(ipqess_stats[i].string) + 1)); -+ p += ETH_GSTRING_LEN; -+ } -+ break; -+ } -+} -+ -+static void ipqess_get_ethtool_stats(struct net_device *netdev, -+ struct ethtool_stats *stats, -+ uint64_t *data) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ u32 *essstats = (u32 *)&ess->ipqessstats; -+ int i; -+ -+ spin_lock(&ess->stats_lock); -+ -+ ipqess_update_hw_stats(ess); -+ -+ for (i = 0; i < ARRAY_SIZE(ipqess_stats); i++) -+ data[i] = *(u32 *)(essstats + (ipqess_stats[i].offset / sizeof(u32))); -+ -+ spin_unlock(&ess->stats_lock); -+} -+ -+static void ipqess_get_drvinfo(struct net_device *dev, -+ struct ethtool_drvinfo *info) -+{ -+ strlcpy(info->driver, "qca_ipqess", DRVINFO_LEN); -+ strlcpy(info->bus_info, "axi", ETHTOOL_BUSINFO_LEN); -+} -+ -+static int ipqess_get_settings(struct net_device *netdev, -+ struct ethtool_link_ksettings *cmd) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ -+ return phylink_ethtool_ksettings_get(ess->phylink, cmd); -+} -+ -+static int ipqess_set_settings(struct net_device *netdev, -+ const struct ethtool_link_ksettings *cmd) -+{ -+ struct ipqess *ess = netdev_priv(netdev); -+ -+ return phylink_ethtool_ksettings_set(ess->phylink, cmd); -+} -+ -+static void ipqess_get_ringparam(struct net_device *netdev, -+ struct ethtool_ringparam *ring) -+{ -+ ring->tx_max_pending = IPQESS_TX_RING_SIZE; -+ ring->rx_max_pending = IPQESS_RX_RING_SIZE; -+} -+ -+static const struct ethtool_ops ipqesstool_ops = { -+ .get_drvinfo = &ipqess_get_drvinfo, -+ .get_link = ðtool_op_get_link, -+ .get_link_ksettings = &ipqess_get_settings, -+ .set_link_ksettings = &ipqess_set_settings, -+ .get_strings = &ipqess_get_strings, -+ .get_sset_count = &ipqess_get_strset_count, -+ .get_ethtool_stats = &ipqess_get_ethtool_stats, -+ .get_ringparam = ipqess_get_ringparam, -+}; -+ -+void ipqess_set_ethtool_ops(struct net_device *netdev) -+{ -+ netdev->ethtool_ops = &ipqesstool_ops; -+} ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.10/702-net-ethernet-qualcomm-add-IPQESS-support.patch -@@ -0,0 +1,43 @@ -+From 4f488235f498db43f2412116dea6e02c7fb20216 Mon Sep 17 00:00:00 2001 -+From: Robert Marko -+Date: Mon, 1 Nov 2021 12:36:51 +0100 -+Subject: [PATCH] net: ethernet: qualcomm: add IPQESS support -+ -+Allow compiling the IPQESS driver that supports the -+Qualcomm IPQ40xx SoC built-in ethernet controller. -+ -+Signed-off-by: Robert Marko -+--- -+ drivers/net/ethernet/qualcomm/Kconfig | 11 +++++++++++ -+ drivers/net/ethernet/qualcomm/Makefile | 1 + -+ 2 files changed, 12 insertions(+) -+ -+--- a/drivers/net/ethernet/qualcomm/Kconfig -++++ b/drivers/net/ethernet/qualcomm/Kconfig -+@@ -60,6 +60,17 @@ config QCOM_EMAC -+ low power, Receive-Side Scaling (RSS), and IEEE 1588-2008 -+ Precision Clock Synchronization Protocol. -+ -++config QCOM_IPQ4019_ESS_EDMA -++ tristate "Qualcomm Atheros IPQ4019 ESS EDMA support" -++ depends on OF -++ select PHYLINK -++ help -++ This driver supports the Qualcomm Atheros IPQ40xx built-in -++ ESS EDMA ethernet controller. -++ -++ To compile this driver as a module, choose M here: the -++ module will be called ipqess. -++ -+ source "drivers/net/ethernet/qualcomm/rmnet/Kconfig" -+ -+ endif # NET_VENDOR_QUALCOMM -+--- a/drivers/net/ethernet/qualcomm/Makefile -++++ b/drivers/net/ethernet/qualcomm/Makefile -+@@ -10,5 +10,6 @@ obj-$(CONFIG_QCA7000_UART) += qcauart.o -+ qcauart-objs := qca_uart.o -+ -+ obj-y += emac/ -++obj-y += ipqess/ -+ -+ obj-$(CONFIG_RMNET) += rmnet/ ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.10/703-arm-dts-ipq4019-add-ethernet-controller-DT-node.patch -@@ -0,0 +1,81 @@ -+From 44327d7098d4f32c24ec8c528e5aff6e030956bc Mon Sep 17 00:00:00 2001 -+From: Robert Marko -+Date: Wed, 20 Oct 2021 13:21:45 +0200 -+Subject: [PATCH] arm: dts: ipq4019: add ethernet controller DT node -+ -+Since IPQ40xx SoC built-in ethernet controller now has a driver, -+add its DT node so it can be used. -+ -+Signed-off-by: Robert Marko -+--- -+ arch/arm/boot/dts/qcom-ipq4019.dtsi | 48 +++++++++++++++++++++++++++++ -+ 1 file changed, 48 insertions(+) -+ -+--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi -++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi -+@@ -38,6 +38,7 @@ -+ spi1 = &blsp1_spi2; -+ i2c0 = &blsp1_i2c3; -+ i2c1 = &blsp1_i2c4; -++ ethernet0 = &gmac0; -+ }; -+ -+ cpus { -+@@ -589,6 +590,57 @@ -+ status = "disabled"; -+ }; -+ -++ gmac0: ethernet@c080000 { -++ compatible = "qcom,ipq4019-ess-edma"; -++ reg = <0xc080000 0x8000>; -++ resets = <&gcc ESS_RESET>; -++ reset-names = "ess_rst"; -++ clocks = <&gcc GCC_ESS_CLK>; -++ clock-names = "ess_clk"; -++ interrupts = , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ ; -++ -++ status = "disabled"; -++ -++ phy-mode = "internal"; -++ fixed-link { -++ speed = <1000>; -++ full-duplex; -++ pause; -++ asym-pause; -++ }; -++ }; -++ -+ mdio: mdio@90000 { -+ #address-cells = <1>; -+ #size-cells = <0>; ---- a/target/linux/ipq40xx/patches-5.10/708-arm-dts-ipq4019-QCA807x-properties.patch -+++ b/target/linux/ipq40xx/patches-5.10/708-arm-dts-ipq4019-QCA807x-properties.patch -@@ -20,7 +20,7 @@ Signed-off-by: Robert Marko - - / { - #address-cells = <1>; --@@ -598,22 +599,39 @@ -+@@ -645,22 +646,39 @@ - - ethphy0: ethernet-phy@0 { - reg = <0>; ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.15/702-net-ethernet-qualcomm-add-IPQESS-support.patch -@@ -0,0 +1,43 @@ -+From 4f488235f498db43f2412116dea6e02c7fb20216 Mon Sep 17 00:00:00 2001 -+From: Robert Marko -+Date: Mon, 1 Nov 2021 12:36:51 +0100 -+Subject: [PATCH] net: ethernet: qualcomm: add IPQESS support -+ -+Allow compiling the IPQESS driver that supports the -+Qualcomm IPQ40xx SoC built-in ethernet controller. -+ -+Signed-off-by: Robert Marko -+--- -+ drivers/net/ethernet/qualcomm/Kconfig | 11 +++++++++++ -+ drivers/net/ethernet/qualcomm/Makefile | 1 + -+ 2 files changed, 12 insertions(+) -+ -+--- a/drivers/net/ethernet/qualcomm/Kconfig -++++ b/drivers/net/ethernet/qualcomm/Kconfig -+@@ -60,6 +60,17 @@ config QCOM_EMAC -+ low power, Receive-Side Scaling (RSS), and IEEE 1588-2008 -+ Precision Clock Synchronization Protocol. -+ -++config QCOM_IPQ4019_ESS_EDMA -++ tristate "Qualcomm Atheros IPQ4019 ESS EDMA support" -++ depends on OF -++ select PHYLINK -++ help -++ This driver supports the Qualcomm Atheros IPQ40xx built-in -++ ESS EDMA ethernet controller. -++ -++ To compile this driver as a module, choose M here: the -++ module will be called ipqess. -++ -+ source "drivers/net/ethernet/qualcomm/rmnet/Kconfig" -+ -+ endif # NET_VENDOR_QUALCOMM -+--- a/drivers/net/ethernet/qualcomm/Makefile -++++ b/drivers/net/ethernet/qualcomm/Makefile -+@@ -10,5 +10,6 @@ obj-$(CONFIG_QCA7000_UART) += qcauart.o -+ qcauart-objs := qca_uart.o -+ -+ obj-y += emac/ -++obj-y += ipqess/ -+ -+ obj-$(CONFIG_RMNET) += rmnet/ ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.15/703-arm-dts-ipq4019-add-ethernet-controller-DT-node.patch -@@ -0,0 +1,81 @@ -+From 44327d7098d4f32c24ec8c528e5aff6e030956bc Mon Sep 17 00:00:00 2001 -+From: Robert Marko -+Date: Wed, 20 Oct 2021 13:21:45 +0200 -+Subject: [PATCH] arm: dts: ipq4019: add ethernet controller DT node -+ -+Since IPQ40xx SoC built-in ethernet controller now has a driver, -+add its DT node so it can be used. -+ -+Signed-off-by: Robert Marko -+--- -+ arch/arm/boot/dts/qcom-ipq4019.dtsi | 48 +++++++++++++++++++++++++++++ -+ 1 file changed, 48 insertions(+) -+ -+--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi -++++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi -+@@ -38,6 +38,7 @@ -+ spi1 = &blsp1_spi2; -+ i2c0 = &blsp1_i2c3; -+ i2c1 = &blsp1_i2c4; -++ ethernet0 = &gmac0; -+ }; -+ -+ cpus { -+@@ -589,6 +590,57 @@ -+ status = "disabled"; -+ }; -+ -++ gmac0: ethernet@c080000 { -++ compatible = "qcom,ipq4019-ess-edma"; -++ reg = <0xc080000 0x8000>; -++ resets = <&gcc ESS_RESET>; -++ reset-names = "ess_rst"; -++ clocks = <&gcc GCC_ESS_CLK>; -++ clock-names = "ess_clk"; -++ interrupts = , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ , -++ ; -++ -++ status = "disabled"; -++ -++ phy-mode = "internal"; -++ fixed-link { -++ speed = <1000>; -++ full-duplex; -++ pause; -++ asym-pause; -++ }; -++ }; -++ -+ mdio: mdio@90000 { -+ #address-cells = <1>; -+ #size-cells = <0>; - ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.10/704-net-phy-define-PSGMII-PHY-interface-mode.patch -@@ -0,0 +1,61 @@ -+From 3e1825e00dafb68eec25df389b63f3ab3d905b59 Mon Sep 17 00:00:00 2001 -+From: Gabor Juhos -+Date: Fri, 25 Dec 2020 08:02:47 +0100 -+Subject: [PATCH] net: phy: define PSGMII PHY interface mode -+ -+The PSGMII interface is similar to QSGMII. The main difference -+is that the PSGMII interface combines five SGMII lines into a -+single link while in QSGMII only four lines are combined. -+ -+Similarly to the QSGMII, this interface mode might also needs -+special handling within the MAC driver. -+ -+Add definitions for the PHY layer to allow to express this type -+of connection between the MAC and PHY. -+ -+Signed-off-by: Gabor Juhos -+--- -+ Documentation/devicetree/bindings/net/ethernet-controller.yaml | 1 + -+ drivers/net/phy/phylink.c | 1 + -+ include/linux/phy.h | 3 +++ -+ 3 files changed, 5 insertions(+) -+ -+--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml -++++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml -+@@ -64,6 +64,7 @@ properties: -+ - mii -+ - gmii -+ - sgmii -++ - psgmii -+ - qsgmii -+ - tbi -+ - rev-mii -+--- a/drivers/net/phy/phylink.c -++++ b/drivers/net/phy/phylink.c -+@@ -289,6 +289,7 @@ static int phylink_parse_mode(struct phy -+ -+ switch (pl->link_config.interface) { -+ case PHY_INTERFACE_MODE_SGMII: -++ case PHY_INTERFACE_MODE_PSGMII: -+ case PHY_INTERFACE_MODE_QSGMII: -+ phylink_set(pl->supported, 10baseT_Half); -+ phylink_set(pl->supported, 10baseT_Full); -+--- a/include/linux/phy.h -++++ b/include/linux/phy.h -+@@ -134,6 +134,7 @@ typedef enum { -+ PHY_INTERFACE_MODE_XGMII, -+ PHY_INTERFACE_MODE_XLGMII, -+ PHY_INTERFACE_MODE_MOCA, -++ PHY_INTERFACE_MODE_PSGMII, -+ PHY_INTERFACE_MODE_QSGMII, -+ PHY_INTERFACE_MODE_TRGMII, -+ PHY_INTERFACE_MODE_100BASEX, -+@@ -201,6 +202,8 @@ static inline const char *phy_modes(phy_ -+ return "xlgmii"; -+ case PHY_INTERFACE_MODE_MOCA: -+ return "moca"; -++ case PHY_INTERFACE_MODE_PSGMII: -++ return "psgmii"; -+ case PHY_INTERFACE_MODE_QSGMII: -+ return "qsgmii"; -+ case PHY_INTERFACE_MODE_TRGMII: ---- /dev/null -+++ b/target/linux/ipq40xx/patches-5.15/704-net-phy-define-PSGMII-PHY-interface-mode.patch -@@ -0,0 +1,61 @@ -+From 3e1825e00dafb68eec25df389b63f3ab3d905b59 Mon Sep 17 00:00:00 2001 -+From: Gabor Juhos -+Date: Fri, 25 Dec 2020 08:02:47 +0100 -+Subject: [PATCH] net: phy: define PSGMII PHY interface mode -+ -+The PSGMII interface is similar to QSGMII. The main difference -+is that the PSGMII interface combines five SGMII lines into a -+single link while in QSGMII only four lines are combined. -+ -+Similarly to the QSGMII, this interface mode might also needs -+special handling within the MAC driver. -+ -+Add definitions for the PHY layer to allow to express this type -+of connection between the MAC and PHY. -+ -+Signed-off-by: Gabor Juhos -+--- -+ Documentation/devicetree/bindings/net/ethernet-controller.yaml | 1 + -+ drivers/net/phy/phylink.c | 1 + -+ include/linux/phy.h | 3 +++ -+ 3 files changed, 5 insertions(+) -+ -+--- a/Documentation/devicetree/bindings/net/ethernet-controller.yaml -++++ b/Documentation/devicetree/bindings/net/ethernet-controller.yaml -+@@ -64,6 +64,7 @@ properties: -+ - mii -+ - gmii -+ - sgmii -++ - psgmii -+ - qsgmii -+ - tbi -+ - rev-mii -+--- a/drivers/net/phy/phylink.c -++++ b/drivers/net/phy/phylink.c -+@@ -293,6 +293,7 @@ static int phylink_parse_mode(struct phy -+ -+ switch (pl->link_config.interface) { -+ case PHY_INTERFACE_MODE_SGMII: -++ case PHY_INTERFACE_MODE_PSGMII: -+ case PHY_INTERFACE_MODE_QSGMII: -+ phylink_set(pl->supported, 10baseT_Half); -+ phylink_set(pl->supported, 10baseT_Full); -+--- a/include/linux/phy.h -++++ b/include/linux/phy.h -+@@ -138,6 +138,7 @@ typedef enum { -+ PHY_INTERFACE_MODE_XGMII, -+ PHY_INTERFACE_MODE_XLGMII, -+ PHY_INTERFACE_MODE_MOCA, -++ PHY_INTERFACE_MODE_PSGMII, -+ PHY_INTERFACE_MODE_QSGMII, -+ PHY_INTERFACE_MODE_TRGMII, -+ PHY_INTERFACE_MODE_100BASEX, -+@@ -209,6 +210,8 @@ static inline const char *phy_modes(phy_ -+ return "xlgmii"; -+ case PHY_INTERFACE_MODE_MOCA: -+ return "moca"; -++ case PHY_INTERFACE_MODE_PSGMII: -++ return "psgmii"; -+ case PHY_INTERFACE_MODE_QSGMII: -+ return "qsgmii"; -+ case PHY_INTERFACE_MODE_TRGMII: - ---- /dev/null -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -0,0 +1,2190 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2009 Felix Fietkau -+ * Copyright (C) 2011-2012 Gabor Juhos -+ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. -+ * Copyright (c) 2016 John Crispin -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "qca8k.h" -+ -+#define MIB_DESC(_s, _o, _n) \ -+ { \ -+ .size = (_s), \ -+ .offset = (_o), \ -+ .name = (_n), \ -+ } -+ -+static const struct qca8k_mib_desc ar8327_mib[] = { -+ MIB_DESC(1, 0x00, "RxBroad"), -+ MIB_DESC(1, 0x04, "RxPause"), -+ MIB_DESC(1, 0x08, "RxMulti"), -+ MIB_DESC(1, 0x0c, "RxFcsErr"), -+ MIB_DESC(1, 0x10, "RxAlignErr"), -+ MIB_DESC(1, 0x14, "RxRunt"), -+ MIB_DESC(1, 0x18, "RxFragment"), -+ MIB_DESC(1, 0x1c, "Rx64Byte"), -+ MIB_DESC(1, 0x20, "Rx128Byte"), -+ MIB_DESC(1, 0x24, "Rx256Byte"), -+ MIB_DESC(1, 0x28, "Rx512Byte"), -+ MIB_DESC(1, 0x2c, "Rx1024Byte"), -+ MIB_DESC(1, 0x30, "Rx1518Byte"), -+ MIB_DESC(1, 0x34, "RxMaxByte"), -+ MIB_DESC(1, 0x38, "RxTooLong"), -+ MIB_DESC(2, 0x3c, "RxGoodByte"), -+ MIB_DESC(2, 0x44, "RxBadByte"), -+ MIB_DESC(1, 0x4c, "RxOverFlow"), -+ MIB_DESC(1, 0x50, "Filtered"), -+ MIB_DESC(1, 0x54, "TxBroad"), -+ MIB_DESC(1, 0x58, "TxPause"), -+ MIB_DESC(1, 0x5c, "TxMulti"), -+ MIB_DESC(1, 0x60, "TxUnderRun"), -+ MIB_DESC(1, 0x64, "Tx64Byte"), -+ MIB_DESC(1, 0x68, "Tx128Byte"), -+ MIB_DESC(1, 0x6c, "Tx256Byte"), -+ MIB_DESC(1, 0x70, "Tx512Byte"), -+ MIB_DESC(1, 0x74, "Tx1024Byte"), -+ MIB_DESC(1, 0x78, "Tx1518Byte"), -+ MIB_DESC(1, 0x7c, "TxMaxByte"), -+ MIB_DESC(1, 0x80, "TxOverSize"), -+ MIB_DESC(2, 0x84, "TxByte"), -+ MIB_DESC(1, 0x8c, "TxCollision"), -+ MIB_DESC(1, 0x90, "TxAbortCol"), -+ MIB_DESC(1, 0x94, "TxMultiCol"), -+ MIB_DESC(1, 0x98, "TxSingleCol"), -+ MIB_DESC(1, 0x9c, "TxExcDefer"), -+ MIB_DESC(1, 0xa0, "TxDefer"), -+ MIB_DESC(1, 0xa4, "TxLateCol"), -+}; -+ -+/* The 32bit switch registers are accessed indirectly. To achieve this we need -+ * to set the page of the register. Track the last page that was set to reduce -+ * mdio writes -+ */ -+static u16 qca8k_current_page = 0xffff; -+ -+static void -+qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) -+{ -+ regaddr >>= 1; -+ *r1 = regaddr & 0x1e; -+ -+ regaddr >>= 5; -+ *r2 = regaddr & 0x7; -+ -+ regaddr >>= 3; -+ *page = regaddr & 0x3ff; -+} -+ -+static int -+qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) -+{ -+ int ret; -+ -+ ret = bus->read(bus, phy_id, regnum); -+ if (ret >= 0) { -+ *val = ret; -+ ret = bus->read(bus, phy_id, regnum + 1); -+ *val |= ret << 16; -+ } -+ -+ if (ret < 0) { -+ dev_err_ratelimited(&bus->dev, -+ "failed to read qca8k 32bit register\n"); -+ *val = 0; -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void -+qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) -+{ -+ u16 lo, hi; -+ int ret; -+ -+ lo = val & 0xffff; -+ hi = (u16)(val >> 16); -+ -+ ret = bus->write(bus, phy_id, regnum, lo); -+ if (ret >= 0) -+ ret = bus->write(bus, phy_id, regnum + 1, hi); -+ if (ret < 0) -+ dev_err_ratelimited(&bus->dev, -+ "failed to write qca8k 32bit register\n"); -+} -+ -+static int -+qca8k_set_page(struct mii_bus *bus, u16 page) -+{ -+ int ret; -+ -+ if (page == qca8k_current_page) -+ return 0; -+ -+ ret = bus->write(bus, 0x18, 0, page); -+ if (ret < 0) { -+ dev_err_ratelimited(&bus->dev, -+ "failed to set qca8k page\n"); -+ return ret; -+ } -+ -+ qca8k_current_page = page; -+ usleep_range(1000, 2000); -+ return 0; -+} -+ -+static int -+qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ int ret; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(bus, page); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ return ret; -+} -+ -+static int -+qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ int ret; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(bus, page); -+ if (ret < 0) -+ goto exit; -+ -+ qca8k_mii_write32(bus, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ return ret; -+} -+ -+static int -+qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(bus, page); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -+ if (ret < 0) -+ goto exit; -+ -+ val &= ~mask; -+ val |= write_val; -+ qca8k_mii_write32(bus, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ -+ return ret; -+} -+ -+static int -+qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val) -+{ -+ return qca8k_rmw(priv, reg, 0, val); -+} -+ -+static int -+qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val) -+{ -+ return qca8k_rmw(priv, reg, val, 0); -+} -+ -+static int -+qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -+ -+ return qca8k_read(priv, reg, val); -+} -+ -+static int -+qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -+ -+ return qca8k_write(priv, reg, val); -+} -+ -+static const struct regmap_range qca8k_readable_ranges[] = { -+ regmap_reg_range(0x0000, 0x00e4), /* Global control */ -+ regmap_reg_range(0x0100, 0x0168), /* EEE control */ -+ regmap_reg_range(0x0200, 0x0270), /* Parser control */ -+ regmap_reg_range(0x0400, 0x0454), /* ACL */ -+ regmap_reg_range(0x0600, 0x0718), /* Lookup */ -+ regmap_reg_range(0x0800, 0x0b70), /* QM */ -+ regmap_reg_range(0x0c00, 0x0c80), /* PKT */ -+ regmap_reg_range(0x0e00, 0x0e98), /* L3 */ -+ regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ -+ regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ -+ regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ -+ regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ -+ regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ -+ regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ -+ regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ -+ -+}; -+ -+static const struct regmap_access_table qca8k_readable_table = { -+ .yes_ranges = qca8k_readable_ranges, -+ .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), -+}; -+ -+static struct regmap_config qca8k_regmap_config = { -+ .reg_bits = 16, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = 0x16ac, /* end MIB - Port6 range */ -+ .reg_read = qca8k_regmap_read, -+ .reg_write = qca8k_regmap_write, -+ .rd_table = &qca8k_readable_table, -+}; -+ -+static int -+qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) -+{ -+ int ret, ret1; -+ u32 val; -+ -+ ret = read_poll_timeout(qca8k_read, ret1, !(val & mask), -+ 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -+ priv, reg, &val); -+ -+ /* Check if qca8k_read has failed for a different reason -+ * before returning -ETIMEDOUT -+ */ -+ if (ret < 0 && ret1 < 0) -+ return ret1; -+ -+ return ret; -+} -+ -+static int -+qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) -+{ -+ u32 reg[4], val; -+ int i, ret; -+ -+ /* load the ARL table into an array */ -+ for (i = 0; i < 4; i++) { -+ ret = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4), &val); -+ if (ret < 0) -+ return ret; -+ -+ reg[i] = val; -+ } -+ -+ /* vid - 83:72 */ -+ fdb->vid = (reg[2] >> QCA8K_ATU_VID_S) & QCA8K_ATU_VID_M; -+ /* aging - 67:64 */ -+ fdb->aging = reg[2] & QCA8K_ATU_STATUS_M; -+ /* portmask - 54:48 */ -+ fdb->port_mask = (reg[1] >> QCA8K_ATU_PORT_S) & QCA8K_ATU_PORT_M; -+ /* mac - 47:0 */ -+ fdb->mac[0] = (reg[1] >> QCA8K_ATU_ADDR0_S) & 0xff; -+ fdb->mac[1] = reg[1] & 0xff; -+ fdb->mac[2] = (reg[0] >> QCA8K_ATU_ADDR2_S) & 0xff; -+ fdb->mac[3] = (reg[0] >> QCA8K_ATU_ADDR3_S) & 0xff; -+ fdb->mac[4] = (reg[0] >> QCA8K_ATU_ADDR4_S) & 0xff; -+ fdb->mac[5] = reg[0] & 0xff; -+ -+ return 0; -+} -+ -+static void -+qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, -+ u8 aging) -+{ -+ u32 reg[3] = { 0 }; -+ int i; -+ -+ /* vid - 83:72 */ -+ reg[2] = (vid & QCA8K_ATU_VID_M) << QCA8K_ATU_VID_S; -+ /* aging - 67:64 */ -+ reg[2] |= aging & QCA8K_ATU_STATUS_M; -+ /* portmask - 54:48 */ -+ reg[1] = (port_mask & QCA8K_ATU_PORT_M) << QCA8K_ATU_PORT_S; -+ /* mac - 47:0 */ -+ reg[1] |= mac[0] << QCA8K_ATU_ADDR0_S; -+ reg[1] |= mac[1]; -+ reg[0] |= mac[2] << QCA8K_ATU_ADDR2_S; -+ reg[0] |= mac[3] << QCA8K_ATU_ADDR3_S; -+ reg[0] |= mac[4] << QCA8K_ATU_ADDR4_S; -+ reg[0] |= mac[5]; -+ -+ /* load the array into the ARL table */ -+ for (i = 0; i < 3; i++) -+ qca8k_write(priv, QCA8K_REG_ATU_DATA0 + (i * 4), reg[i]); -+} -+ -+static int -+qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) -+{ -+ u32 reg; -+ int ret; -+ -+ /* Set the command and FDB index */ -+ reg = QCA8K_ATU_FUNC_BUSY; -+ reg |= cmd; -+ if (port >= 0) { -+ reg |= QCA8K_ATU_FUNC_PORT_EN; -+ reg |= (port & QCA8K_ATU_FUNC_PORT_M) << QCA8K_ATU_FUNC_PORT_S; -+ } -+ -+ /* Write the function register triggering the table access */ -+ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); -+ if (ret) -+ return ret; -+ -+ /* wait for completion */ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); -+ if (ret) -+ return ret; -+ -+ /* Check for table full violation when adding an entry */ -+ if (cmd == QCA8K_FDB_LOAD) { -+ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); -+ if (ret < 0) -+ return ret; -+ if (reg & QCA8K_ATU_FUNC_FULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) -+{ -+ int ret; -+ -+ qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); -+ if (ret < 0) -+ return ret; -+ -+ return qca8k_fdb_read(priv, fdb); -+} -+ -+static int -+qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, -+ u16 vid, u8 aging) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_write(priv, vid, port_mask, mac, aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_write(priv, vid, port_mask, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static void -+qca8k_fdb_flush(struct qca8k_priv *priv) -+{ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static int -+qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) -+{ -+ u32 reg; -+ int ret; -+ -+ /* Set the command and VLAN index */ -+ reg = QCA8K_VTU_FUNC1_BUSY; -+ reg |= cmd; -+ reg |= vid << QCA8K_VTU_FUNC1_VID_S; -+ -+ /* Write the function register triggering the table access */ -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); -+ if (ret) -+ return ret; -+ -+ /* wait for completion */ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); -+ if (ret) -+ return ret; -+ -+ /* Check for table full violation when adding an entry */ -+ if (cmd == QCA8K_VLAN_LOAD) { -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); -+ if (ret < 0) -+ return ret; -+ if (reg & QCA8K_VTU_FUNC1_FULL) -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) -+{ -+ u32 reg; -+ int ret; -+ -+ /* -+ We do the right thing with VLAN 0 and treat it as untagged while -+ preserving the tag on egress. -+ */ -+ if (vid == 0) -+ return 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -+ if (ret < 0) -+ goto out; -+ -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -+ if (ret < 0) -+ goto out; -+ reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; -+ reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port)); -+ if (untagged) -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_UNTAG << -+ QCA8K_VTU_FUNC0_EG_MODE_S(port); -+ else -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG << -+ QCA8K_VTU_FUNC0_EG_MODE_S(port); -+ -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -+ if (ret) -+ goto out; -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -+ -+out: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) -+{ -+ u32 reg, mask; -+ int ret, i; -+ bool del; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -+ if (ret < 0) -+ goto out; -+ -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -+ if (ret < 0) -+ goto out; -+ reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port)); -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT << -+ QCA8K_VTU_FUNC0_EG_MODE_S(port); -+ -+ /* Check if we're the last member to be removed */ -+ del = true; -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ mask = QCA8K_VTU_FUNC0_EG_MODE_NOT; -+ mask <<= QCA8K_VTU_FUNC0_EG_MODE_S(i); -+ -+ if ((reg & mask) != mask) { -+ del = false; -+ break; -+ } -+ } -+ -+ if (del) { -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); -+ } else { -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -+ if (ret) -+ goto out; -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -+ } -+ -+out: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_mib_init(struct qca8k_priv *priv) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static void -+qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) -+{ -+ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -+ -+ /* Port 0 and 6 have no internal PHY */ -+ if (port > 0 && port < 6) -+ mask |= QCA8K_PORT_STATUS_LINK_AUTO; -+ -+ if (enable) -+ qca8k_reg_set(priv, QCA8K_REG_PORT_STATUS(port), mask); -+ else -+ qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); -+} -+ -+static u32 -+qca8k_port_to_phy(int port) -+{ -+ /* From Andrew Lunn: -+ * Port 0 has no internal phy. -+ * Port 1 has an internal PHY at MDIO address 0. -+ * Port 2 has an internal PHY at MDIO address 1. -+ * ... -+ * Port 5 has an internal PHY at MDIO address 4. -+ * Port 6 has no internal PHY. -+ */ -+ -+ return port - 1; -+} -+ -+static int -+qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) -+{ -+ u16 r1, r2, page; -+ u32 val; -+ int ret, ret1; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -+ bus, 0x10 | r2, r1, &val); -+ -+ /* Check if qca8k_read has failed for a different reason -+ * before returnting -ETIMEDOUT -+ */ -+ if (ret < 0 && ret1 < 0) -+ return ret1; -+ -+ return ret; -+} -+ -+static int -+qca8k_mdio_write(struct mii_bus *bus, int phy, int regnum, u16 data) -+{ -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum) | -+ QCA8K_MDIO_MASTER_DATA(data); -+ -+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(bus, page); -+ if (ret) -+ goto exit; -+ -+ qca8k_mii_write32(bus, 0x10 | r2, r1, val); -+ -+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_BUSY); -+ -+exit: -+ /* even if the busy_wait timeouts try to clear the MASTER_EN */ -+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ return ret; -+} -+ -+static int -+qca8k_mdio_read(struct mii_bus *bus, int phy, int regnum) -+{ -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum); -+ -+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(bus, page); -+ if (ret) -+ goto exit; -+ -+ qca8k_mii_write32(bus, 0x10 | r2, r1, val); -+ -+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -+ -+exit: -+ /* even if the busy_wait timeouts try to clear the MASTER_EN */ -+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ if (ret >= 0) -+ ret = val & QCA8K_MDIO_MASTER_DATA_MASK; -+ -+ return ret; -+} -+ -+static int -+qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) -+{ -+ struct qca8k_priv *priv = slave_bus->priv; -+ struct mii_bus *bus = priv->bus; -+ -+ return qca8k_mdio_write(bus, phy, regnum, data); -+} -+ -+static int -+qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) -+{ -+ struct qca8k_priv *priv = slave_bus->priv; -+ struct mii_bus *bus = priv->bus; -+ -+ return qca8k_mdio_read(bus, phy, regnum); -+} -+ -+static int -+qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Check if the legacy mapping should be used and the -+ * port is not correctly mapped to the right PHY in the -+ * devicetree -+ */ -+ if (priv->legacy_phy_port_mapping) -+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -+ -+ return qca8k_mdio_write(priv->bus, port, regnum, data); -+} -+ -+static int -+qca8k_phy_read(struct dsa_switch *ds, int port, int regnum) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ /* Check if the legacy mapping should be used and the -+ * port is not correctly mapped to the right PHY in the -+ * devicetree -+ */ -+ if (priv->legacy_phy_port_mapping) -+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -+ -+ ret = qca8k_mdio_read(priv->bus, port, regnum); -+ -+ if (ret < 0) -+ return 0xffff; -+ -+ return ret; -+} -+ -+static int -+qca8k_mdio_register(struct qca8k_priv *priv, struct device_node *mdio) -+{ -+ struct dsa_switch *ds = priv->ds; -+ struct mii_bus *bus; -+ -+ bus = devm_mdiobus_alloc(ds->dev); -+ -+ if (!bus) -+ return -ENOMEM; -+ -+ bus->priv = (void *)priv; -+ bus->name = "qca8k slave mii"; -+ bus->read = qca8k_internal_mdio_read; -+ bus->write = qca8k_internal_mdio_write; -+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", -+ ds->index); -+ -+ bus->parent = ds->dev; -+ bus->phy_mask = ~ds->phys_mii_mask; -+ -+ ds->slave_mii_bus = bus; -+ -+ return devm_of_mdiobus_register(priv->dev, bus, mdio); -+} -+ -+static int -+qca8k_setup_mdio_bus(struct qca8k_priv *priv) -+{ -+ u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; -+ struct device_node *ports, *port, *mdio; -+ phy_interface_t mode; -+ int err; -+ -+ ports = of_get_child_by_name(priv->dev->of_node, "ports"); -+ if (!ports) -+ ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); -+ -+ if (!ports) -+ return -EINVAL; -+ -+ for_each_available_child_of_node(ports, port) { -+ err = of_property_read_u32(port, "reg", ®); -+ if (err) { -+ of_node_put(port); -+ of_node_put(ports); -+ return err; -+ } -+ -+ if (!dsa_is_user_port(priv->ds, reg)) -+ continue; -+ -+ of_get_phy_mode(port, &mode); -+ -+ if (of_property_read_bool(port, "phy-handle") && -+ mode != PHY_INTERFACE_MODE_INTERNAL) -+ external_mdio_mask |= BIT(reg); -+ else -+ internal_mdio_mask |= BIT(reg); -+ } -+ -+ of_node_put(ports); -+ if (!external_mdio_mask && !internal_mdio_mask) { -+ dev_err(priv->dev, "no PHYs are defined.\n"); -+ return -EINVAL; -+ } -+ -+ /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through -+ * the MDIO_MASTER register also _disconnects_ the external MDC -+ * passthrough to the internal PHYs. It's not possible to use both -+ * configurations at the same time! -+ * -+ * Because this came up during the review process: -+ * If the external mdio-bus driver is capable magically disabling -+ * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's -+ * accessors for the time being, it would be possible to pull this -+ * off. -+ */ -+ if (!!external_mdio_mask && !!internal_mdio_mask) { -+ dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); -+ return -EINVAL; -+ } -+ -+ if (external_mdio_mask) { -+ /* Make sure to disable the internal mdio bus in cases -+ * a dt-overlay and driver reload changed the configuration -+ */ -+ -+ return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_EN); -+ } -+ -+ /* Check if the devicetree declare the port:phy mapping */ -+ mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); -+ if (of_device_is_available(mdio)) { -+ err = qca8k_mdio_register(priv, mdio); -+ if (err) -+ of_node_put(mdio); -+ -+ return err; -+ } -+ -+ /* If a mapping can't be found the legacy mapping is used, -+ * using the qca8k_port_to_phy function -+ */ -+ priv->legacy_phy_port_mapping = true; -+ priv->ops.phy_read = qca8k_phy_read; -+ priv->ops.phy_write = qca8k_phy_write; -+ -+ return 0; -+} -+ -+static int -+qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) -+{ -+ u32 mask = 0; -+ int ret = 0; -+ -+ /* SoC specific settings for ipq8064. -+ * If more device require this consider adding -+ * a dedicated binding. -+ */ -+ if (of_machine_is_compatible("qcom,ipq8064")) -+ mask |= QCA8K_MAC_PWR_RGMII0_1_8V; -+ -+ /* SoC specific settings for ipq8065 */ -+ if (of_machine_is_compatible("qcom,ipq8065")) -+ mask |= QCA8K_MAC_PWR_RGMII1_1_8V; -+ -+ if (mask) { -+ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, -+ QCA8K_MAC_PWR_RGMII0_1_8V | -+ QCA8K_MAC_PWR_RGMII1_1_8V, -+ mask); -+ } -+ -+ return ret; -+} -+ -+static int qca8k_find_cpu_port(struct dsa_switch *ds) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Find the connected cpu port. Valid port are 0 or 6 */ -+ if (dsa_is_cpu_port(ds, 0)) -+ return 0; -+ -+ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); -+ -+ if (dsa_is_cpu_port(ds, 6)) -+ return 6; -+ -+ return -EINVAL; -+} -+ -+static int -+qca8k_setup_of_pws_reg(struct qca8k_priv *priv) -+{ -+ struct device_node *node = priv->dev->of_node; -+ const struct qca8k_match_data *data; -+ u32 val = 0; -+ int ret; -+ -+ /* QCA8327 require to set to the correct mode. -+ * His bigger brother QCA8328 have the 172 pin layout. -+ * Should be applied by default but we set this just to make sure. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ data = of_device_get_match_data(priv->dev); -+ -+ /* Set the correct package of 148 pin for QCA8327 */ -+ if (data->reduced_package) -+ val |= QCA8327_PWS_PACKAGE148_EN; -+ -+ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, -+ val); -+ if (ret) -+ return ret; -+ } -+ -+ if (of_property_read_bool(node, "qca,ignore-power-on-sel")) -+ val |= QCA8K_PWS_POWER_ON_SEL; -+ -+ if (of_property_read_bool(node, "qca,led-open-drain")) { -+ if (!(val & QCA8K_PWS_POWER_ON_SEL)) { -+ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); -+ return -EINVAL; -+ } -+ -+ val |= QCA8K_PWS_LED_OPEN_EN_CSR; -+ } -+ -+ return qca8k_rmw(priv, QCA8K_REG_PWS, -+ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, -+ val); -+} -+ -+static int -+qca8k_parse_port_config(struct qca8k_priv *priv) -+{ -+ int port, cpu_port_index = -1, ret; -+ struct device_node *port_dn; -+ phy_interface_t mode; -+ struct dsa_port *dp; -+ u32 delay; -+ -+ /* We have 2 CPU port. Check them */ -+ for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) { -+ /* Skip every other port */ -+ if (port != 0 && port != 6) -+ continue; -+ -+ dp = dsa_to_port(priv->ds, port); -+ port_dn = dp->dn; -+ cpu_port_index++; -+ -+ if (!of_device_is_available(port_dn)) -+ continue; -+ -+ ret = of_get_phy_mode(port_dn, &mode); -+ if (ret) -+ continue; -+ -+ switch (mode) { -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_SGMII: -+ delay = 0; -+ -+ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) -+ /* Switch regs accept value in ns, convert ps to ns */ -+ delay = delay / 1000; -+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_TXID) -+ delay = 1; -+ -+ if (delay > QCA8K_MAX_DELAY) { -+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -+ delay = 3; -+ } -+ -+ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; -+ -+ delay = 0; -+ -+ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) -+ /* Switch regs accept value in ns, convert ps to ns */ -+ delay = delay / 1000; -+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_RXID) -+ delay = 2; -+ -+ if (delay > QCA8K_MAX_DELAY) { -+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -+ delay = 3; -+ } -+ -+ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; -+ -+ /* Skip sgmii parsing for rgmii* mode */ -+ if (mode == PHY_INTERFACE_MODE_RGMII || -+ mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_TXID || -+ mode == PHY_INTERFACE_MODE_RGMII_RXID) -+ break; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) -+ priv->ports_config.sgmii_tx_clk_falling_edge = true; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) -+ priv->ports_config.sgmii_rx_clk_falling_edge = true; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { -+ priv->ports_config.sgmii_enable_pll = true; -+ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); -+ priv->ports_config.sgmii_enable_pll = false; -+ } -+ -+ if (priv->switch_revision < 2) -+ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); -+ } -+ -+ break; -+ default: -+ continue; -+ } -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_setup(struct dsa_switch *ds) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int cpu_port, ret, i; -+ u32 mask; -+ -+ cpu_port = qca8k_find_cpu_port(ds); -+ if (cpu_port < 0) { -+ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); -+ return cpu_port; -+ } -+ -+ /* Parse CPU port config to be later used in phy_link mac_config */ -+ ret = qca8k_parse_port_config(priv); -+ if (ret) -+ return ret; -+ -+ mutex_init(&priv->reg_mutex); -+ -+ /* Start by setting up the register mapping */ -+ priv->regmap = devm_regmap_init(ds->dev, NULL, priv, -+ &qca8k_regmap_config); -+ if (IS_ERR(priv->regmap)) -+ dev_warn(priv->dev, "regmap initialization failed"); -+ -+ ret = qca8k_setup_mdio_bus(priv); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_setup_of_pws_reg(priv); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_setup_mac_pwr_sel(priv); -+ if (ret) -+ return ret; -+ -+ /* Enable CPU Port */ -+ ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); -+ if (ret) { -+ dev_err(priv->dev, "failed enabling CPU port"); -+ return ret; -+ } -+ -+ /* Enable MIB counters */ -+ ret = qca8k_mib_init(priv); -+ if (ret) -+ dev_warn(priv->dev, "mib init failed"); -+ -+ /* Initial setup of all ports */ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ /* Disable forwarding by default on all ports */ -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, 0); -+ if (ret) -+ return ret; -+ -+ /* Enable QCA header mode on all cpu ports */ -+ if (dsa_is_cpu_port(ds, i)) { -+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), -+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | -+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); -+ if (ret) { -+ dev_err(priv->dev, "failed enabling QCA header mode"); -+ return ret; -+ } -+ } -+ -+ /* Disable MAC by default on all user ports */ -+ if (dsa_is_user_port(ds, i)) -+ qca8k_port_set_status(priv, i, 0); -+ } -+ -+ /* Forward all unknown frames to CPU port for Linux processing -+ * Notice that in multi-cpu config only one port should be set -+ * for igmp, unknown, multicast and broadcast packet -+ */ -+ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | -+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | -+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | -+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); -+ if (ret) -+ return ret; -+ -+ /* Setup connection between CPU port & user ports -+ * Configure specific switch configuration for ports -+ */ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ /* CPU port gets connected to all user ports of the switch */ -+ if (dsa_is_cpu_port(ds, i)) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); -+ if (ret) -+ return ret; -+ } -+ -+ /* Individual user ports get connected to CPU port only */ -+ if (dsa_is_user_port(ds, i)) { -+ int shift = 16 * (i % 2); -+ -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, -+ BIT(cpu_port)); -+ if (ret) -+ return ret; -+ -+ /* Enable ARP Auto-learning by default */ -+ ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_LEARN); -+ if (ret) -+ return ret; -+ -+ /* For port based vlans to work we need to set the -+ * default egress vid -+ */ -+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), -+ 0xfff << shift, -+ QCA8K_PORT_VID_DEF << shift); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), -+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | -+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); -+ if (ret) -+ return ret; -+ } -+ -+ /* The port 5 of the qca8337 have some problem in flood condition. The -+ * original legacy driver had some specific buffer and priority settings -+ * for the different port suggested by the QCA switch team. Add this -+ * missing settings to improve switch stability under load condition. -+ * This problem is limited to qca8337 and other qca8k switch are not affected. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8337) { -+ switch (i) { -+ /* The 2 CPU port and port 5 requires some different -+ * priority than any other ports. -+ */ -+ case 0: -+ case 5: -+ case 6: -+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | -+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); -+ break; -+ default: -+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | -+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); -+ } -+ qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); -+ -+ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | -+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_WRED_EN; -+ qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), -+ QCA8K_PORT_HOL_CTRL1_ING_BUF | -+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_WRED_EN, -+ mask); -+ } -+ -+ /* Set initial MTU for every port. -+ * We have only have a general MTU setting. So track -+ * every port and set the max across all port. -+ */ -+ priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; -+ } -+ -+ /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | -+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); -+ qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, -+ QCA8K_GLOBAL_FC_GOL_XON_THRES_S | -+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S, -+ mask); -+ } -+ -+ /* Setup our port MTUs to match power on defaults */ -+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); -+ if (ret) -+ dev_warn(priv->dev, "failed setting MTU settings"); -+ -+ /* Flush the FDB table */ -+ qca8k_fdb_flush(priv); -+ -+ /* We don't have interrupts for link changes, so we need to poll */ -+ ds->pcs_poll = true; -+ -+ return 0; -+} -+ -+static void -+qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, -+ u32 reg) -+{ -+ u32 delay, val = 0; -+ int ret; -+ -+ /* Delay can be declared in 3 different way. -+ * Mode to rgmii and internal-delay standard binding defined -+ * rgmii-id or rgmii-tx/rx phy mode set. -+ * The parse logic set a delay different than 0 only when one -+ * of the 3 different way is used. In all other case delay is -+ * not enabled. With ID or TX/RXID delay is enabled and set -+ * to the default and recommended value. -+ */ -+ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { -+ delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -+ } -+ -+ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { -+ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -+ } -+ -+ /* Set RGMII delay based on the selected values */ -+ ret = qca8k_rmw(priv, reg, -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, -+ val); -+ if (ret) -+ dev_err(priv->dev, "Failed to set internal delay for CPU port%d", -+ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); -+} -+ -+static void -+qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, -+ const struct phylink_link_state *state) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int cpu_port_index, ret; -+ u32 reg, val; -+ -+ switch (port) { -+ case 0: /* 1st CPU port */ -+ if (state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII) -+ return; -+ -+ reg = QCA8K_REG_PORT0_PAD_CTRL; -+ cpu_port_index = QCA8K_CPU_PORT0; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ case 5: -+ /* Internal PHY, nothing to do */ -+ return; -+ case 6: /* 2nd CPU port / external PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII && -+ state->interface != PHY_INTERFACE_MODE_1000BASEX) -+ return; -+ -+ reg = QCA8K_REG_PORT6_PAD_CTRL; -+ cpu_port_index = QCA8K_CPU_PORT6; -+ break; -+ default: -+ dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); -+ return; -+ } -+ -+ if (port != 6 && phylink_autoneg_inband(mode)) { -+ dev_err(ds->dev, "%s: in-band negotiation unsupported\n", -+ __func__); -+ return; -+ } -+ -+ switch (state->interface) { -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); -+ -+ /* Configure rgmii delay */ -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -+ -+ /* QCA8337 requires to set rgmii rx delay for all ports. -+ * This is enabled through PORT5_PAD_CTRL for all ports, -+ * rather than individual port registers. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8337) -+ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); -+ break; -+ case PHY_INTERFACE_MODE_SGMII: -+ case PHY_INTERFACE_MODE_1000BASEX: -+ /* Enable SGMII on the port */ -+ qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); -+ -+ /* Enable/disable SerDes auto-negotiation as necessary */ -+ ret = qca8k_read(priv, QCA8K_REG_PWS, &val); -+ if (ret) -+ return; -+ if (phylink_autoneg_inband(mode)) -+ val &= ~QCA8K_PWS_SERDES_AEN_DIS; -+ else -+ val |= QCA8K_PWS_SERDES_AEN_DIS; -+ qca8k_write(priv, QCA8K_REG_PWS, val); -+ -+ /* Configure the SGMII parameters */ -+ ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); -+ if (ret) -+ return; -+ -+ val |= QCA8K_SGMII_EN_SD; -+ -+ if (priv->ports_config.sgmii_enable_pll) -+ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -+ QCA8K_SGMII_EN_TX; -+ -+ if (dsa_is_cpu_port(ds, port)) { -+ /* CPU port, we're talking to the CPU MAC, be a PHY */ -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_PHY; -+ } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_MAC; -+ } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_BASEX; -+ } -+ -+ qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); -+ -+ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and -+ * falling edge is set writing in the PORT0 PAD reg -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8327 || -+ priv->switch_id == QCA8K_ID_QCA8337) -+ reg = QCA8K_REG_PORT0_PAD_CTRL; -+ -+ val = 0; -+ -+ /* SGMII Clock phase configuration */ -+ if (priv->ports_config.sgmii_rx_clk_falling_edge) -+ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; -+ -+ if (priv->ports_config.sgmii_tx_clk_falling_edge) -+ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; -+ -+ if (val) -+ ret = qca8k_rmw(priv, reg, -+ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | -+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, -+ val); -+ -+ /* From original code is reported port instability as SGMII also -+ * require delay set. Apply advised values here or take them from DT. -+ */ -+ if (state->interface == PHY_INTERFACE_MODE_SGMII) -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -+ -+ break; -+ default: -+ dev_err(ds->dev, "xMII mode %s not supported for port %d\n", -+ phy_modes(state->interface), port); -+ return; -+ } -+} -+ -+static void -+qca8k_phylink_validate(struct dsa_switch *ds, int port, -+ unsigned long *supported, -+ struct phylink_link_state *state) -+{ -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -+ -+ switch (port) { -+ case 0: /* 1st CPU port */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII) -+ goto unsupported; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ case 5: -+ /* Internal PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_GMII && -+ state->interface != PHY_INTERFACE_MODE_INTERNAL) -+ goto unsupported; -+ break; -+ case 6: /* 2nd CPU port / external PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII && -+ state->interface != PHY_INTERFACE_MODE_1000BASEX) -+ goto unsupported; -+ break; -+ default: -+unsupported: -+ linkmode_zero(supported); -+ return; -+ } -+ -+ phylink_set_port_modes(mask); -+ phylink_set(mask, Autoneg); -+ -+ phylink_set(mask, 1000baseT_Full); -+ phylink_set(mask, 10baseT_Half); -+ phylink_set(mask, 10baseT_Full); -+ phylink_set(mask, 100baseT_Half); -+ phylink_set(mask, 100baseT_Full); -+ -+ if (state->interface == PHY_INTERFACE_MODE_1000BASEX) -+ phylink_set(mask, 1000baseX_Full); -+ -+ phylink_set(mask, Pause); -+ phylink_set(mask, Asym_Pause); -+ -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); -+} -+ -+static int -+qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, -+ struct phylink_link_state *state) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg; -+ int ret; -+ -+ ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); -+ if (ret < 0) -+ return ret; -+ -+ state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); -+ state->an_complete = state->link; -+ state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); -+ state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : -+ DUPLEX_HALF; -+ -+ switch (reg & QCA8K_PORT_STATUS_SPEED) { -+ case QCA8K_PORT_STATUS_SPEED_10: -+ state->speed = SPEED_10; -+ break; -+ case QCA8K_PORT_STATUS_SPEED_100: -+ state->speed = SPEED_100; -+ break; -+ case QCA8K_PORT_STATUS_SPEED_1000: -+ state->speed = SPEED_1000; -+ break; -+ default: -+ state->speed = SPEED_UNKNOWN; -+ break; -+ } -+ -+ state->pause = MLO_PAUSE_NONE; -+ if (reg & QCA8K_PORT_STATUS_RXFLOW) -+ state->pause |= MLO_PAUSE_RX; -+ if (reg & QCA8K_PORT_STATUS_TXFLOW) -+ state->pause |= MLO_PAUSE_TX; -+ -+ return 1; -+} -+ -+static void -+qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, -+ phy_interface_t interface) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ qca8k_port_set_status(priv, port, 0); -+} -+ -+static void -+qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, -+ phy_interface_t interface, struct phy_device *phydev, -+ int speed, int duplex, bool tx_pause, bool rx_pause) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg; -+ -+ if (phylink_autoneg_inband(mode)) { -+ reg = QCA8K_PORT_STATUS_LINK_AUTO; -+ } else { -+ switch (speed) { -+ case SPEED_10: -+ reg = QCA8K_PORT_STATUS_SPEED_10; -+ break; -+ case SPEED_100: -+ reg = QCA8K_PORT_STATUS_SPEED_100; -+ break; -+ case SPEED_1000: -+ reg = QCA8K_PORT_STATUS_SPEED_1000; -+ break; -+ default: -+ reg = QCA8K_PORT_STATUS_LINK_AUTO; -+ break; -+ } -+ -+ if (duplex == DUPLEX_FULL) -+ reg |= QCA8K_PORT_STATUS_DUPLEX; -+ -+ if (rx_pause || dsa_is_cpu_port(ds, port)) -+ reg |= QCA8K_PORT_STATUS_RXFLOW; -+ -+ if (tx_pause || dsa_is_cpu_port(ds, port)) -+ reg |= QCA8K_PORT_STATUS_TXFLOW; -+ } -+ -+ reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -+ -+ qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); -+} -+ -+static void -+qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) -+{ -+ int i; -+ -+ if (stringset != ETH_SS_STATS) -+ return; -+ -+ for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) -+ strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, -+ ETH_GSTRING_LEN); -+} -+ -+static void -+qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, -+ uint64_t *data) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ const struct qca8k_mib_desc *mib; -+ u32 reg, i, val; -+ u32 hi = 0; -+ int ret; -+ -+ for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) { -+ mib = &ar8327_mib[i]; -+ reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; -+ -+ ret = qca8k_read(priv, reg, &val); -+ if (ret < 0) -+ continue; -+ -+ if (mib->size == 2) { -+ ret = qca8k_read(priv, reg + 4, &hi); -+ if (ret < 0) -+ continue; -+ } -+ -+ data[i] = val; -+ if (mib->size == 2) -+ data[i] |= (u64)hi << 32; -+ } -+} -+ -+static int -+qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) -+{ -+ if (sset != ETH_SS_STATS) -+ return 0; -+ -+ return ARRAY_SIZE(ar8327_mib); -+} -+ -+static int -+qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); -+ u32 reg; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); -+ if (ret < 0) -+ goto exit; -+ -+ if (eee->eee_enabled) -+ reg |= lpi_en; -+ else -+ reg &= ~lpi_en; -+ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int -+qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) -+{ -+ /* Nothing to do on the port's MAC */ -+ return 0; -+} -+ -+static void -+qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u32 stp_state; -+ -+ switch (state) { -+ case BR_STATE_DISABLED: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; -+ break; -+ case BR_STATE_BLOCKING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; -+ break; -+ case BR_STATE_LISTENING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; -+ break; -+ case BR_STATE_LEARNING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; -+ break; -+ case BR_STATE_FORWARDING: -+ default: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; -+ break; -+ } -+ -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); -+} -+ -+static int -+qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int port_mask, cpu_port; -+ int i, ret; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ port_mask = BIT(cpu_port); -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; -+ if (dsa_to_port(ds, i)->bridge_dev != br) -+ continue; -+ /* Add this port to the portvlan mask of the other ports -+ * in the bridge -+ */ -+ ret = qca8k_reg_set(priv, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); -+ if (ret) -+ return ret; -+ if (i != port) -+ port_mask |= BIT(i); -+ } -+ -+ /* Add all other ports to this ports portvlan mask */ -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, port_mask); -+ -+ return ret; -+} -+ -+static void -+qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int cpu_port, i; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; -+ if (dsa_to_port(ds, i)->bridge_dev != br) -+ continue; -+ /* Remove this port to the portvlan mask of the other ports -+ * in the bridge -+ */ -+ qca8k_reg_clear(priv, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); -+ } -+ -+ /* Set the cpu port to be the only one in the portvlan mask of -+ * this port -+ */ -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); -+} -+ -+static int -+qca8k_port_enable(struct dsa_switch *ds, int port, -+ struct phy_device *phy) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ -+ qca8k_port_set_status(priv, port, 1); -+ priv->port_sts[port].enabled = 1; -+ -+ if (dsa_is_user_port(ds, port)) -+ phy_support_asym_pause(phy); -+ -+ return 0; -+} -+ -+static void -+qca8k_port_disable(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ -+ qca8k_port_set_status(priv, port, 0); -+ priv->port_sts[port].enabled = 0; -+} -+ -+static int -+qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int i, mtu = 0; -+ -+ priv->port_mtu[port] = new_mtu; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) -+ if (priv->port_mtu[i] > mtu) -+ mtu = priv->port_mtu[i]; -+ -+ /* Include L2 header / FCS length */ -+ return qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN); -+} -+ -+static int -+qca8k_port_max_mtu(struct dsa_switch *ds, int port) -+{ -+ return QCA8K_MAX_MTU; -+} -+ -+static int -+qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, -+ u16 port_mask, u16 vid) -+{ -+ /* Set the vid to the port vlan id if no vid is set */ -+ if (!vid) -+ vid = QCA8K_PORT_VID_DEF; -+ -+ return qca8k_fdb_add(priv, addr, port_mask, vid, -+ QCA8K_ATU_STATUS_STATIC); -+} -+ -+static int -+qca8k_port_fdb_add(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u16 port_mask = BIT(port); -+ -+ return qca8k_port_fdb_insert(priv, addr, port_mask, vid); -+} -+ -+static int -+qca8k_port_fdb_del(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u16 port_mask = BIT(port); -+ -+ if (!vid) -+ vid = QCA8K_PORT_VID_DEF; -+ -+ return qca8k_fdb_del(priv, addr, port_mask, vid); -+} -+ -+static int -+qca8k_port_fdb_dump(struct dsa_switch *ds, int port, -+ dsa_fdb_dump_cb_t *cb, void *data) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ struct qca8k_fdb _fdb = { 0 }; -+ int cnt = QCA8K_NUM_FDB_RECORDS; -+ bool is_static; -+ int ret = 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { -+ if (!_fdb.aging) -+ break; -+ is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); -+ ret = cb(_fdb.mac, _fdb.vid, is_static, data); -+ if (ret) -+ break; -+ } -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+static int -+qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -+ struct switchdev_trans *trans) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ if (switchdev_trans_ph_prepare(trans)) -+ return 0; -+ -+ if (vlan_filtering) { -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_VLAN_MODE, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); -+ } else { -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_VLAN_MODE, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_port_vlan_prepare(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan) -+{ -+ return 0; -+} -+ -+static void -+qca8k_port_vlan_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan) -+{ -+ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; -+ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; -+ struct qca8k_priv *priv = ds->priv; -+ int ret = 0; -+ u16 vid; -+ -+ for (vid = vlan->vid_begin; vid <= vlan->vid_end && !ret; ++vid) -+ ret = qca8k_vlan_add(priv, port, vid, untagged); -+ -+ if (ret) -+ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -+ -+ if (pvid) { -+ int shift = 16 * (port % 2); -+ -+ qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -+ 0xfff << shift, -+ vlan->vid_end << shift); -+ qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -+ QCA8K_PORT_VLAN_CVID(vlan->vid_end) | -+ QCA8K_PORT_VLAN_SVID(vlan->vid_end)); -+ } -+} -+ -+static int -+qca8k_port_vlan_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret = 0; -+ u16 vid; -+ -+ for (vid = vlan->vid_begin; vid <= vlan->vid_end && !ret; ++vid) -+ ret = qca8k_vlan_del(priv, port, vid); -+ -+ if (ret) -+ dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); -+ -+ return ret; -+} -+ -+static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Communicate to the phy internal driver the switch revision. -+ * Based on the switch revision different values needs to be -+ * set to the dbg and mmd reg on the phy. -+ * The first 2 bit are used to communicate the switch revision -+ * to the phy driver. -+ */ -+ if (port > 0 && port < 6) -+ return priv->switch_revision; -+ -+ return 0; -+} -+ -+static enum dsa_tag_protocol -+qca8k_get_tag_protocol(struct dsa_switch *ds, int port, -+ enum dsa_tag_protocol mp) -+{ -+ return DSA_TAG_PROTO_QCA; -+} -+ -+static const struct dsa_switch_ops qca8k_switch_ops = { -+ .get_tag_protocol = qca8k_get_tag_protocol, -+ .setup = qca8k_setup, -+ .get_strings = qca8k_get_strings, -+ .get_ethtool_stats = qca8k_get_ethtool_stats, -+ .get_sset_count = qca8k_get_sset_count, -+ .get_mac_eee = qca8k_get_mac_eee, -+ .set_mac_eee = qca8k_set_mac_eee, -+ .port_enable = qca8k_port_enable, -+ .port_disable = qca8k_port_disable, -+ .port_change_mtu = qca8k_port_change_mtu, -+ .port_max_mtu = qca8k_port_max_mtu, -+ .port_stp_state_set = qca8k_port_stp_state_set, -+ .port_bridge_join = qca8k_port_bridge_join, -+ .port_bridge_leave = qca8k_port_bridge_leave, -+ .port_fdb_add = qca8k_port_fdb_add, -+ .port_fdb_del = qca8k_port_fdb_del, -+ .port_fdb_dump = qca8k_port_fdb_dump, -+ .port_vlan_filtering = qca8k_port_vlan_filtering, -+ .port_vlan_prepare = qca8k_port_vlan_prepare, -+ .port_vlan_add = qca8k_port_vlan_add, -+ .port_vlan_del = qca8k_port_vlan_del, -+ .phylink_validate = qca8k_phylink_validate, -+ .phylink_mac_link_state = qca8k_phylink_mac_link_state, -+ .phylink_mac_config = qca8k_phylink_mac_config, -+ .phylink_mac_link_down = qca8k_phylink_mac_link_down, -+ .phylink_mac_link_up = qca8k_phylink_mac_link_up, -+ .get_phy_flags = qca8k_get_phy_flags, -+}; -+ -+static int qca8k_read_switch_id(struct qca8k_priv *priv) -+{ -+ const struct qca8k_match_data *data; -+ u32 val; -+ u8 id; -+ int ret; -+ -+ /* get the switches ID from the compatible */ -+ data = of_device_get_match_data(priv->dev); -+ if (!data) -+ return -ENODEV; -+ -+ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -+ if (ret < 0) -+ return -ENODEV; -+ -+ id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK); -+ if (id != data->id) { -+ dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); -+ return -ENODEV; -+ } -+ -+ priv->switch_id = id; -+ -+ /* Save revision to communicate to the internal PHY driver */ -+ priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK); -+ -+ return 0; -+} -+ -+static int -+qca8k_sw_probe(struct mdio_device *mdiodev) -+{ -+ struct qca8k_priv *priv; -+ int ret; -+ -+ /* allocate the private data struct so that we can probe the switches -+ * ID register -+ */ -+ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->bus = mdiodev->bus; -+ priv->dev = &mdiodev->dev; -+ -+ priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", -+ GPIOD_ASIS); -+ if (IS_ERR(priv->reset_gpio)) -+ return PTR_ERR(priv->reset_gpio); -+ -+ if (priv->reset_gpio) { -+ gpiod_set_value_cansleep(priv->reset_gpio, 1); -+ /* The active low duration must be greater than 10 ms -+ * and checkpatch.pl wants 20 ms. -+ */ -+ msleep(20); -+ gpiod_set_value_cansleep(priv->reset_gpio, 0); -+ } -+ -+ /* Check the detected switch id */ -+ ret = qca8k_read_switch_id(priv); -+ if (ret) -+ return ret; -+ -+ priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); -+ if (!priv->ds) -+ return -ENOMEM; -+ -+ priv->ds->dev = &mdiodev->dev; -+ priv->ds->num_ports = QCA8K_NUM_PORTS; -+ priv->ds->configure_vlan_while_not_filtering = true; -+ priv->ds->priv = priv; -+ priv->ops = qca8k_switch_ops; -+ priv->ds->ops = &priv->ops; -+ mutex_init(&priv->reg_mutex); -+ dev_set_drvdata(&mdiodev->dev, priv); -+ -+ return dsa_register_switch(priv->ds); -+} -+ -+static void -+qca8k_sw_remove(struct mdio_device *mdiodev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -+ int i; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) -+ qca8k_port_set_status(priv, i, 0); -+ -+ dsa_unregister_switch(priv->ds); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static void -+qca8k_set_pm(struct qca8k_priv *priv, int enable) -+{ -+ int i; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (!priv->port_sts[i].enabled) -+ continue; -+ -+ qca8k_port_set_status(priv, i, enable); -+ } -+} -+ -+static int qca8k_suspend(struct device *dev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(dev); -+ -+ qca8k_set_pm(priv, 0); -+ -+ return dsa_switch_suspend(priv->ds); -+} -+ -+static int qca8k_resume(struct device *dev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(dev); -+ -+ qca8k_set_pm(priv, 1); -+ -+ return dsa_switch_resume(priv->ds); -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, -+ qca8k_suspend, qca8k_resume); -+ -+static const struct qca8k_match_data qca8327 = { -+ .id = QCA8K_ID_QCA8327, -+ .reduced_package = true, -+}; -+ -+static const struct qca8k_match_data qca8328 = { -+ .id = QCA8K_ID_QCA8327, -+}; -+ -+static const struct qca8k_match_data qca833x = { -+ .id = QCA8K_ID_QCA8337, -+}; -+ -+static const struct of_device_id qca8k_of_match[] = { -+ { .compatible = "qca,qca8327", .data = &qca8327 }, -+ { .compatible = "qca,qca8328", .data = &qca8328 }, -+ { .compatible = "qca,qca8334", .data = &qca833x }, -+ { .compatible = "qca,qca8337", .data = &qca833x }, -+ { /* sentinel */ }, -+}; -+ -+static struct mdio_driver qca8kmdio_driver = { -+ .probe = qca8k_sw_probe, -+ .remove = qca8k_sw_remove, -+ .mdiodrv.driver = { -+ .name = "qca8k", -+ .of_match_table = qca8k_of_match, -+ .pm = &qca8k_pm_ops, -+ }, -+}; -+ -+mdio_module_driver(qca8kmdio_driver); -+ -+MODULE_AUTHOR("Mathieu Olivari, John Crispin "); -+MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:qca8k"); ---- /dev/null -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.h -@@ -0,0 +1,310 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Copyright (C) 2009 Felix Fietkau -+ * Copyright (C) 2011-2012 Gabor Juhos -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ */ -+ -+#ifndef __QCA8K_H -+#define __QCA8K_H -+ -+#include -+#include -+#include -+ -+#define QCA8K_NUM_PORTS 7 -+#define QCA8K_NUM_CPU_PORTS 2 -+#define QCA8K_MAX_MTU 9000 -+ -+#define PHY_ID_QCA8327 0x004dd034 -+#define QCA8K_ID_QCA8327 0x12 -+#define PHY_ID_QCA8337 0x004dd036 -+#define QCA8K_ID_QCA8337 0x13 -+ -+#define QCA8K_BUSY_WAIT_TIMEOUT 2000 -+ -+#define QCA8K_NUM_FDB_RECORDS 2048 -+ -+#define QCA8K_PORT_VID_DEF 1 -+ -+/* Global control registers */ -+#define QCA8K_REG_MASK_CTRL 0x000 -+#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0) -+#define QCA8K_MASK_CTRL_REV_ID(x) ((x) >> 0) -+#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) -+#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8) -+#define QCA8K_REG_PORT0_PAD_CTRL 0x004 -+#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) -+#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) -+#define QCA8K_REG_PORT5_PAD_CTRL 0x008 -+#define QCA8K_REG_PORT6_PAD_CTRL 0x00c -+#define QCA8K_PORT_PAD_RGMII_EN BIT(26) -+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) -+#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22) -+#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) -+#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20) -+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) -+#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) -+#define QCA8K_MAX_DELAY 3 -+#define QCA8K_PORT_PAD_SGMII_EN BIT(7) -+#define QCA8K_REG_PWS 0x010 -+#define QCA8K_PWS_POWER_ON_SEL BIT(31) -+/* This reg is only valid for QCA832x and toggle the package -+ * type from 176 pin (by default) to 148 pin used on QCA8327 -+ */ -+#define QCA8327_PWS_PACKAGE148_EN BIT(30) -+#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24) -+#define QCA8K_PWS_SERDES_AEN_DIS BIT(7) -+#define QCA8K_REG_MODULE_EN 0x030 -+#define QCA8K_MODULE_EN_MIB BIT(0) -+#define QCA8K_REG_MIB 0x034 -+#define QCA8K_MIB_FLUSH BIT(24) -+#define QCA8K_MIB_CPU_KEEP BIT(20) -+#define QCA8K_MIB_BUSY BIT(17) -+#define QCA8K_MDIO_MASTER_CTRL 0x3c -+#define QCA8K_MDIO_MASTER_BUSY BIT(31) -+#define QCA8K_MDIO_MASTER_EN BIT(30) -+#define QCA8K_MDIO_MASTER_READ BIT(27) -+#define QCA8K_MDIO_MASTER_WRITE 0 -+#define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) -+#define QCA8K_MDIO_MASTER_PHY_ADDR(x) ((x) << 21) -+#define QCA8K_MDIO_MASTER_REG_ADDR(x) ((x) << 16) -+#define QCA8K_MDIO_MASTER_DATA(x) (x) -+#define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) -+#define QCA8K_MDIO_MASTER_MAX_PORTS 5 -+#define QCA8K_MDIO_MASTER_MAX_REG 32 -+#define QCA8K_GOL_MAC_ADDR0 0x60 -+#define QCA8K_GOL_MAC_ADDR1 0x64 -+#define QCA8K_MAX_FRAME_SIZE 0x78 -+#define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) -+#define QCA8K_PORT_STATUS_SPEED GENMASK(1, 0) -+#define QCA8K_PORT_STATUS_SPEED_10 0 -+#define QCA8K_PORT_STATUS_SPEED_100 0x1 -+#define QCA8K_PORT_STATUS_SPEED_1000 0x2 -+#define QCA8K_PORT_STATUS_TXMAC BIT(2) -+#define QCA8K_PORT_STATUS_RXMAC BIT(3) -+#define QCA8K_PORT_STATUS_TXFLOW BIT(4) -+#define QCA8K_PORT_STATUS_RXFLOW BIT(5) -+#define QCA8K_PORT_STATUS_DUPLEX BIT(6) -+#define QCA8K_PORT_STATUS_LINK_UP BIT(8) -+#define QCA8K_PORT_STATUS_LINK_AUTO BIT(9) -+#define QCA8K_PORT_STATUS_LINK_PAUSE BIT(10) -+#define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12) -+#define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) -+#define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) -+#define QCA8K_PORT_HDR_CTRL_RX_S 2 -+#define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0) -+#define QCA8K_PORT_HDR_CTRL_TX_S 0 -+#define QCA8K_PORT_HDR_CTRL_ALL 2 -+#define QCA8K_PORT_HDR_CTRL_MGMT 1 -+#define QCA8K_PORT_HDR_CTRL_NONE 0 -+#define QCA8K_REG_SGMII_CTRL 0x0e0 -+#define QCA8K_SGMII_EN_PLL BIT(1) -+#define QCA8K_SGMII_EN_RX BIT(2) -+#define QCA8K_SGMII_EN_TX BIT(3) -+#define QCA8K_SGMII_EN_SD BIT(4) -+#define QCA8K_SGMII_CLK125M_DELAY BIT(7) -+#define QCA8K_SGMII_MODE_CTRL_MASK (BIT(22) | BIT(23)) -+#define QCA8K_SGMII_MODE_CTRL_BASEX (0 << 22) -+#define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22) -+#define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22) -+ -+/* MAC_PWR_SEL registers */ -+#define QCA8K_REG_MAC_PWR_SEL 0x0e4 -+#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18) -+#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19) -+ -+/* EEE control registers */ -+#define QCA8K_REG_EEE_CTRL 0x100 -+#define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) -+ -+/* ACL registers */ -+#define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) -+#define QCA8K_PORT_VLAN_CVID(x) (x << 16) -+#define QCA8K_PORT_VLAN_SVID(x) x -+#define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8)) -+#define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470 -+#define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474 -+ -+/* Lookup registers */ -+#define QCA8K_REG_ATU_DATA0 0x600 -+#define QCA8K_ATU_ADDR2_S 24 -+#define QCA8K_ATU_ADDR3_S 16 -+#define QCA8K_ATU_ADDR4_S 8 -+#define QCA8K_REG_ATU_DATA1 0x604 -+#define QCA8K_ATU_PORT_M 0x7f -+#define QCA8K_ATU_PORT_S 16 -+#define QCA8K_ATU_ADDR0_S 8 -+#define QCA8K_REG_ATU_DATA2 0x608 -+#define QCA8K_ATU_VID_M 0xfff -+#define QCA8K_ATU_VID_S 8 -+#define QCA8K_ATU_STATUS_M 0xf -+#define QCA8K_ATU_STATUS_STATIC 0xf -+#define QCA8K_REG_ATU_FUNC 0x60c -+#define QCA8K_ATU_FUNC_BUSY BIT(31) -+#define QCA8K_ATU_FUNC_PORT_EN BIT(14) -+#define QCA8K_ATU_FUNC_MULTI_EN BIT(13) -+#define QCA8K_ATU_FUNC_FULL BIT(12) -+#define QCA8K_ATU_FUNC_PORT_M 0xf -+#define QCA8K_ATU_FUNC_PORT_S 8 -+#define QCA8K_REG_VTU_FUNC0 0x610 -+#define QCA8K_VTU_FUNC0_VALID BIT(20) -+#define QCA8K_VTU_FUNC0_IVL_EN BIT(19) -+#define QCA8K_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) -+#define QCA8K_VTU_FUNC0_EG_MODE_MASK 3 -+#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD 0 -+#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG 1 -+#define QCA8K_VTU_FUNC0_EG_MODE_TAG 2 -+#define QCA8K_VTU_FUNC0_EG_MODE_NOT 3 -+#define QCA8K_REG_VTU_FUNC1 0x614 -+#define QCA8K_VTU_FUNC1_BUSY BIT(31) -+#define QCA8K_VTU_FUNC1_VID_S 16 -+#define QCA8K_VTU_FUNC1_FULL BIT(4) -+#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 -+#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) -+#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 -+#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S 24 -+#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_S 16 -+#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_S 8 -+#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_S 0 -+#define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) -+#define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE GENMASK(9, 8) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE (0 << 8) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK (1 << 8) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK (2 << 8) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE (3 << 8) -+#define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) -+#define QCA8K_PORT_LOOKUP_STATE_DISABLED (0 << 16) -+#define QCA8K_PORT_LOOKUP_STATE_BLOCKING (1 << 16) -+#define QCA8K_PORT_LOOKUP_STATE_LISTENING (2 << 16) -+#define QCA8K_PORT_LOOKUP_STATE_LEARNING (3 << 16) -+#define QCA8K_PORT_LOOKUP_STATE_FORWARD (4 << 16) -+#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16) -+#define QCA8K_PORT_LOOKUP_LEARN BIT(20) -+ -+#define QCA8K_REG_GLOBAL_FC_THRESH 0x800 -+#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) ((x) << 16) -+#define QCA8K_GLOBAL_FC_GOL_XON_THRES_S GENMASK(24, 16) -+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) ((x) << 0) -+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S GENMASK(8, 0) -+ -+#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF GENMASK(7, 4) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) ((x) << 4) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF GENMASK(11, 8) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) ((x) << 8) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF GENMASK(15, 12) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) ((x) << 12) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF GENMASK(19, 16) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) ((x) << 16) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF GENMASK(23, 20) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) ((x) << 20) -+#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF GENMASK(29, 24) -+#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) ((x) << 24) -+ -+#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) -+#define QCA8K_PORT_HOL_CTRL1_ING_BUF GENMASK(3, 0) -+#define QCA8K_PORT_HOL_CTRL1_ING(x) ((x) << 0) -+#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6) -+#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7) -+#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8) -+#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) -+ -+/* Pkt edit registers */ -+#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2))) -+ -+/* L3 registers */ -+#define QCA8K_HROUTER_CONTROL 0xe00 -+#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_M GENMASK(17, 16) -+#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_S 16 -+#define QCA8K_HROUTER_CONTROL_ARP_AGE_MODE 1 -+#define QCA8K_HROUTER_PBASED_CONTROL1 0xe08 -+#define QCA8K_HROUTER_PBASED_CONTROL2 0xe0c -+#define QCA8K_HNAT_CONTROL 0xe38 -+ -+/* MIB registers */ -+#define QCA8K_PORT_MIB_COUNTER(_i) (0x1000 + (_i) * 0x100) -+ -+/* QCA specific MII registers */ -+#define MII_ATH_MMD_ADDR 0x0d -+#define MII_ATH_MMD_DATA 0x0e -+ -+enum { -+ QCA8K_PORT_SPEED_10M = 0, -+ QCA8K_PORT_SPEED_100M = 1, -+ QCA8K_PORT_SPEED_1000M = 2, -+ QCA8K_PORT_SPEED_ERR = 3, -+}; -+ -+enum qca8k_fdb_cmd { -+ QCA8K_FDB_FLUSH = 1, -+ QCA8K_FDB_LOAD = 2, -+ QCA8K_FDB_PURGE = 3, -+ QCA8K_FDB_NEXT = 6, -+ QCA8K_FDB_SEARCH = 7, -+}; -+ -+enum qca8k_vlan_cmd { -+ QCA8K_VLAN_FLUSH = 1, -+ QCA8K_VLAN_LOAD = 2, -+ QCA8K_VLAN_PURGE = 3, -+ QCA8K_VLAN_REMOVE_PORT = 4, -+ QCA8K_VLAN_NEXT = 5, -+ QCA8K_VLAN_READ = 6, -+}; -+ -+struct ar8xxx_port_status { -+ int enabled; -+}; -+ -+struct qca8k_match_data { -+ u8 id; -+ bool reduced_package; -+}; -+ -+enum { -+ QCA8K_CPU_PORT0, -+ QCA8K_CPU_PORT6, -+}; -+ -+struct qca8k_ports_config { -+ bool sgmii_rx_clk_falling_edge; -+ bool sgmii_tx_clk_falling_edge; -+ bool sgmii_enable_pll; -+ u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ -+ u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ -+}; -+ -+struct qca8k_priv { -+ u8 switch_id; -+ u8 switch_revision; -+ bool legacy_phy_port_mapping; -+ struct qca8k_ports_config ports_config; -+ struct regmap *regmap; -+ struct mii_bus *bus; -+ struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS]; -+ struct dsa_switch *ds; -+ struct mutex reg_mutex; -+ struct device *dev; -+ struct dsa_switch_ops ops; -+ struct gpio_desc *reset_gpio; -+ unsigned int port_mtu[QCA8K_NUM_PORTS]; -+}; -+ -+struct qca8k_mib_desc { -+ unsigned int size; -+ unsigned int offset; -+ const char *name; -+}; -+ -+struct qca8k_fdb { -+ u16 vid; -+ u8 port_mask; -+ u8 aging; -+ u8 mac[6]; -+}; -+ -+#endif /* __QCA8K_H */ - ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1,25 +1,28 @@ - // SPDX-License-Identifier: GPL-2.0 - /* - * Copyright (C) 2009 Felix Fietkau -- * Copyright (C) 2011-2012 Gabor Juhos -+ * Copyright (C) 2011-2012, 2020-2021 Gabor Juhos - * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. - * Copyright (c) 2016 John Crispin -+ * Copyright (c) 2021 Robert Marko - */ - -+#include -+#include -+#include -+#include -+#include - #include --#include - #include --#include --#include - #include -+#include - #include --#include --#include -+#include - #include --#include --#include -+#include -+#include - --#include "qca8k.h" -+#include "qca8k-ipq4019.h" - - #define MIB_DESC(_s, _o, _n) \ - { \ ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -68,186 +71,38 @@ static const struct qca8k_mib_desc ar8327_mib[] = { - MIB_DESC(1, 0x9c, "TxExcDefer"), - MIB_DESC(1, 0xa0, "TxDefer"), - MIB_DESC(1, 0xa4, "TxLateCol"), -+ MIB_DESC(1, 0xa8, "RXUnicast"), -+ MIB_DESC(1, 0xac, "TXunicast"), - }; - --/* The 32bit switch registers are accessed indirectly. To achieve this we need -- * to set the page of the register. Track the last page that was set to reduce -- * mdio writes -- */ --static u16 qca8k_current_page = 0xffff; -- --static void --qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) --{ -- regaddr >>= 1; -- *r1 = regaddr & 0x1e; -- -- regaddr >>= 5; -- *r2 = regaddr & 0x7; -- -- regaddr >>= 3; -- *page = regaddr & 0x3ff; --} -- --static int --qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) --{ -- int ret; -- -- ret = bus->read(bus, phy_id, regnum); -- if (ret >= 0) { -- *val = ret; -- ret = bus->read(bus, phy_id, regnum + 1); -- *val |= ret << 16; -- } -- -- if (ret < 0) { -- dev_err_ratelimited(&bus->dev, -- "failed to read qca8k 32bit register\n"); -- *val = 0; -- return ret; -- } -- -- return 0; --} -- --static void --qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) --{ -- u16 lo, hi; -- int ret; -- -- lo = val & 0xffff; -- hi = (u16)(val >> 16); -- -- ret = bus->write(bus, phy_id, regnum, lo); -- if (ret >= 0) -- ret = bus->write(bus, phy_id, regnum + 1, hi); -- if (ret < 0) -- dev_err_ratelimited(&bus->dev, -- "failed to write qca8k 32bit register\n"); --} -- --static int --qca8k_set_page(struct mii_bus *bus, u16 page) --{ -- int ret; -- -- if (page == qca8k_current_page) -- return 0; -- -- ret = bus->write(bus, 0x18, 0, page); -- if (ret < 0) { -- dev_err_ratelimited(&bus->dev, -- "failed to set qca8k page\n"); -- return ret; -- } -- -- qca8k_current_page = page; -- usleep_range(1000, 2000); -- return 0; --} -- - static int - qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) - { -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- int ret; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(bus, page); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- return ret; -+ return regmap_read(priv->regmap, reg, val); - } - - static int - qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) - { -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- int ret; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(bus, page); -- if (ret < 0) -- goto exit; -- -- qca8k_mii_write32(bus, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- return ret; -+ return regmap_write(priv->regmap, reg, val); - } - - static int - qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) - { -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(bus, page); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -- if (ret < 0) -- goto exit; -- -- val &= ~mask; -- val |= write_val; -- qca8k_mii_write32(bus, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- -- return ret; -+ return regmap_update_bits(priv->regmap, reg, mask, write_val); - } - - static int - qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val) - { -- return qca8k_rmw(priv, reg, 0, val); -+ return regmap_set_bits(priv->regmap, reg, val); - } - - static int - qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val) - { -- return qca8k_rmw(priv, reg, val, 0); --} -- --static int --qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- -- return qca8k_read(priv, reg, val); --} -- --static int --qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- -- return qca8k_write(priv, reg, val); -+ return regmap_clear_bits(priv->regmap, reg, val); - } - - static const struct regmap_range qca8k_readable_ranges[] = { ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -274,33 +129,31 @@ static const struct regmap_access_table qca8k_readable_table = { - .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), - }; - --static struct regmap_config qca8k_regmap_config = { -- .reg_bits = 16, -+static struct regmap_config qca8k_ipq4019_regmap_config = { -+ .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = 0x16ac, /* end MIB - Port6 range */ -- .reg_read = qca8k_regmap_read, -- .reg_write = qca8k_regmap_write, - .rd_table = &qca8k_readable_table, - }; - -+static struct regmap_config qca8k_ipq4019_psgmii_phy_regmap_config = { -+ .name = "psgmii-phy", -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = 0x7fc, -+}; -+ - static int - qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) - { -- int ret, ret1; - u32 val; - -- ret = read_poll_timeout(qca8k_read, ret1, !(val & mask), -- 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -- priv, reg, &val); -- -- /* Check if qca8k_read has failed for a different reason -- * before returning -ETIMEDOUT -- */ -- if (ret < 0 && ret1 < 0) -- return ret1; -- -- return ret; -+ return regmap_read_poll_timeout(priv->regmap, reg, val, -+ !(val & mask), -+ 0, -+ QCA8K_BUSY_WAIT_TIMEOUT); - } - - static int ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -595,8 +448,11 @@ qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) - { - u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; - -- /* Port 0 and 6 have no internal PHY */ -- if (port > 0 && port < 6) -+ /* Port 0 is internally connected to the CPU -+ * TODO: Probably check for RGMII as well if it doesnt work -+ * in RGMII mode. -+ */ -+ if (port > QCA8K_CPU_PORT) - mask |= QCA8K_PORT_STATUS_LINK_AUTO; - - if (enable) ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -605,467 +461,56 @@ qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) - qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); - } - --static u32 --qca8k_port_to_phy(int port) --{ -- /* From Andrew Lunn: -- * Port 0 has no internal phy. -- * Port 1 has an internal PHY at MDIO address 0. -- * Port 2 has an internal PHY at MDIO address 1. -- * ... -- * Port 5 has an internal PHY at MDIO address 4. -- * Port 6 has no internal PHY. -- */ -- -- return port - 1; --} -- --static int --qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) --{ -- u16 r1, r2, page; -- u32 val; -- int ret, ret1; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, -- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -- bus, 0x10 | r2, r1, &val); -- -- /* Check if qca8k_read has failed for a different reason -- * before returnting -ETIMEDOUT -- */ -- if (ret < 0 && ret1 < 0) -- return ret1; -- -- return ret; --} -- --static int --qca8k_mdio_write(struct mii_bus *bus, int phy, int regnum, u16 data) --{ -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -- return -EINVAL; -- -- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -- QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -- QCA8K_MDIO_MASTER_REG_ADDR(regnum) | -- QCA8K_MDIO_MASTER_DATA(data); -- -- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(bus, page); -- if (ret) -- goto exit; -- -- qca8k_mii_write32(bus, 0x10 | r2, r1, val); -- -- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_BUSY); -- --exit: -- /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(bus, 0x10 | r2, r1, 0); -- -- mutex_unlock(&bus->mdio_lock); -- -- return ret; --} -- --static int --qca8k_mdio_read(struct mii_bus *bus, int phy, int regnum) --{ -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -- return -EINVAL; -- -- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -- QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -- QCA8K_MDIO_MASTER_REG_ADDR(regnum); -- -- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(bus, page); -- if (ret) -- goto exit; -- -- qca8k_mii_write32(bus, 0x10 | r2, r1, val); -- -- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_BUSY); -- if (ret) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -- --exit: -- /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(bus, 0x10 | r2, r1, 0); -- -- mutex_unlock(&bus->mdio_lock); -- -- if (ret >= 0) -- ret = val & QCA8K_MDIO_MASTER_DATA_MASK; -- -- return ret; --} -- --static int --qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) --{ -- struct qca8k_priv *priv = slave_bus->priv; -- struct mii_bus *bus = priv->bus; -- -- return qca8k_mdio_write(bus, phy, regnum, data); --} -- --static int --qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) --{ -- struct qca8k_priv *priv = slave_bus->priv; -- struct mii_bus *bus = priv->bus; -- -- return qca8k_mdio_read(bus, phy, regnum); --} -- --static int --qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data) --{ -- struct qca8k_priv *priv = ds->priv; -- -- /* Check if the legacy mapping should be used and the -- * port is not correctly mapped to the right PHY in the -- * devicetree -- */ -- if (priv->legacy_phy_port_mapping) -- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -- -- return qca8k_mdio_write(priv->bus, port, regnum, data); --} -- - static int --qca8k_phy_read(struct dsa_switch *ds, int port, int regnum) -+qca8k_setup_port(struct dsa_switch *ds, int port) - { -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- /* Check if the legacy mapping should be used and the -- * port is not correctly mapped to the right PHY in the -- * devicetree -- */ -- if (priv->legacy_phy_port_mapping) -- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -- -- ret = qca8k_mdio_read(priv->bus, port, regnum); -- -- if (ret < 0) -- return 0xffff; -- -- return ret; --} -- --static int --qca8k_mdio_register(struct qca8k_priv *priv, struct device_node *mdio) --{ -- struct dsa_switch *ds = priv->ds; -- struct mii_bus *bus; -- -- bus = devm_mdiobus_alloc(ds->dev); -- -- if (!bus) -- return -ENOMEM; -- -- bus->priv = (void *)priv; -- bus->name = "qca8k slave mii"; -- bus->read = qca8k_internal_mdio_read; -- bus->write = qca8k_internal_mdio_write; -- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", -- ds->index); -- -- bus->parent = ds->dev; -- bus->phy_mask = ~ds->phys_mii_mask; -- -- ds->slave_mii_bus = bus; -- -- return devm_of_mdiobus_register(priv->dev, bus, mdio); --} -- --static int --qca8k_setup_mdio_bus(struct qca8k_priv *priv) --{ -- u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; -- struct device_node *ports, *port, *mdio; -- phy_interface_t mode; -- int err; -- -- ports = of_get_child_by_name(priv->dev->of_node, "ports"); -- if (!ports) -- ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); -- -- if (!ports) -- return -EINVAL; -- -- for_each_available_child_of_node(ports, port) { -- err = of_property_read_u32(port, "reg", ®); -- if (err) { -- of_node_put(port); -- of_node_put(ports); -- return err; -- } -- -- if (!dsa_is_user_port(priv->ds, reg)) -- continue; -- -- of_get_phy_mode(port, &mode); -- -- if (of_property_read_bool(port, "phy-handle") && -- mode != PHY_INTERFACE_MODE_INTERNAL) -- external_mdio_mask |= BIT(reg); -- else -- internal_mdio_mask |= BIT(reg); -- } -- -- of_node_put(ports); -- if (!external_mdio_mask && !internal_mdio_mask) { -- dev_err(priv->dev, "no PHYs are defined.\n"); -- return -EINVAL; -- } -- -- /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through -- * the MDIO_MASTER register also _disconnects_ the external MDC -- * passthrough to the internal PHYs. It's not possible to use both -- * configurations at the same time! -- * -- * Because this came up during the review process: -- * If the external mdio-bus driver is capable magically disabling -- * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's -- * accessors for the time being, it would be possible to pull this -- * off. -- */ -- if (!!external_mdio_mask && !!internal_mdio_mask) { -- dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); -- return -EINVAL; -- } -- -- if (external_mdio_mask) { -- /* Make sure to disable the internal mdio bus in cases -- * a dt-overlay and driver reload changed the configuration -- */ -- -- return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_EN); -- } -- -- /* Check if the devicetree declare the port:phy mapping */ -- mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); -- if (of_device_is_available(mdio)) { -- err = qca8k_mdio_register(priv, mdio); -- if (err) -- of_node_put(mdio); -- -- return err; -- } -- -- /* If a mapping can't be found the legacy mapping is used, -- * using the qca8k_port_to_phy function -- */ -- priv->legacy_phy_port_mapping = true; -- priv->ops.phy_read = qca8k_phy_read; -- priv->ops.phy_write = qca8k_phy_write; -- -- return 0; --} -- --static int --qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) --{ -- u32 mask = 0; -- int ret = 0; -- -- /* SoC specific settings for ipq8064. -- * If more device require this consider adding -- * a dedicated binding. -- */ -- if (of_machine_is_compatible("qcom,ipq8064")) -- mask |= QCA8K_MAC_PWR_RGMII0_1_8V; -- -- /* SoC specific settings for ipq8065 */ -- if (of_machine_is_compatible("qcom,ipq8065")) -- mask |= QCA8K_MAC_PWR_RGMII1_1_8V; -- -- if (mask) { -- ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, -- QCA8K_MAC_PWR_RGMII0_1_8V | -- QCA8K_MAC_PWR_RGMII1_1_8V, -- mask); -- } -- -- return ret; --} -- --static int qca8k_find_cpu_port(struct dsa_switch *ds) --{ -- struct qca8k_priv *priv = ds->priv; -- -- /* Find the connected cpu port. Valid port are 0 or 6 */ -- if (dsa_is_cpu_port(ds, 0)) -- return 0; -- -- dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); -- -- if (dsa_is_cpu_port(ds, 6)) -- return 6; -- -- return -EINVAL; --} -- --static int --qca8k_setup_of_pws_reg(struct qca8k_priv *priv) --{ -- struct device_node *node = priv->dev->of_node; -- const struct qca8k_match_data *data; -- u32 val = 0; -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; - int ret; - -- /* QCA8327 require to set to the correct mode. -- * His bigger brother QCA8328 have the 172 pin layout. -- * Should be applied by default but we set this just to make sure. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- data = of_device_get_match_data(priv->dev); -- -- /* Set the correct package of 148 pin for QCA8327 */ -- if (data->reduced_package) -- val |= QCA8327_PWS_PACKAGE148_EN; -- -- ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, -- val); -+ /* CPU port gets connected to all user ports of the switch */ -+ if (dsa_is_cpu_port(ds, port)) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT), -+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); - if (ret) - return ret; -- } -- -- if (of_property_read_bool(node, "qca,ignore-power-on-sel")) -- val |= QCA8K_PWS_POWER_ON_SEL; -- -- if (of_property_read_bool(node, "qca,led-open-drain")) { -- if (!(val & QCA8K_PWS_POWER_ON_SEL)) { -- dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); -- return -EINVAL; -- } - -- val |= QCA8K_PWS_LED_OPEN_EN_CSR; -+ /* Disable CPU ARP Auto-learning by default */ -+ ret = qca8k_reg_clear(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT), -+ QCA8K_PORT_LOOKUP_LEARN); -+ if (ret) -+ return ret; - } - -- return qca8k_rmw(priv, QCA8K_REG_PWS, -- QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, -- val); --} -- --static int --qca8k_parse_port_config(struct qca8k_priv *priv) --{ -- int port, cpu_port_index = -1, ret; -- struct device_node *port_dn; -- phy_interface_t mode; -- struct dsa_port *dp; -- u32 delay; -- -- /* We have 2 CPU port. Check them */ -- for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) { -- /* Skip every other port */ -- if (port != 0 && port != 6) -- continue; -- -- dp = dsa_to_port(priv->ds, port); -- port_dn = dp->dn; -- cpu_port_index++; -+ /* Individual user ports get connected to CPU port only */ -+ if (dsa_is_user_port(ds, port)) { -+ int shift = 16 * (port % 2); - -- if (!of_device_is_available(port_dn)) -- continue; -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, -+ BIT(QCA8K_CPU_PORT)); -+ if (ret) -+ return ret; - -- ret = of_get_phy_mode(port_dn, &mode); -+ /* Enable ARP Auto-learning by default */ -+ ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_LEARN); - if (ret) -- continue; -+ return ret; - -- switch (mode) { -- case PHY_INTERFACE_MODE_RGMII: -- case PHY_INTERFACE_MODE_RGMII_ID: -- case PHY_INTERFACE_MODE_RGMII_TXID: -- case PHY_INTERFACE_MODE_RGMII_RXID: -- case PHY_INTERFACE_MODE_SGMII: -- delay = 0; -- -- if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) -- /* Switch regs accept value in ns, convert ps to ns */ -- delay = delay / 1000; -- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_TXID) -- delay = 1; -- -- if (delay > QCA8K_MAX_DELAY) { -- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -- delay = 3; -- } -- -- priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; -- -- delay = 0; -- -- if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) -- /* Switch regs accept value in ns, convert ps to ns */ -- delay = delay / 1000; -- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_RXID) -- delay = 2; -- -- if (delay > QCA8K_MAX_DELAY) { -- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -- delay = 3; -- } -- -- priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; -- -- /* Skip sgmii parsing for rgmii* mode */ -- if (mode == PHY_INTERFACE_MODE_RGMII || -- mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_TXID || -- mode == PHY_INTERFACE_MODE_RGMII_RXID) -- break; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) -- priv->ports_config.sgmii_tx_clk_falling_edge = true; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) -- priv->ports_config.sgmii_rx_clk_falling_edge = true; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { -- priv->ports_config.sgmii_enable_pll = true; -- -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); -- priv->ports_config.sgmii_enable_pll = false; -- } -- -- if (priv->switch_revision < 2) -- dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); -- } -+ /* For port based vlans to work we need to set the -+ * default egress vid -+ */ -+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -+ 0xfff << shift, -+ QCA8K_PORT_VID_DEF << shift); -+ if (ret) -+ return ret; - -- break; -- default: -- continue; -- } -+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | -+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); -+ if (ret) -+ return ret; - } - - return 0; ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1075,40 +520,14 @@ static int - qca8k_setup(struct dsa_switch *ds) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int cpu_port, ret, i; -- u32 mask; -+ int ret, i; - -- cpu_port = qca8k_find_cpu_port(ds); -- if (cpu_port < 0) { -- dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); -- return cpu_port; -+ /* Make sure that port 0 is the cpu port */ -+ if (!dsa_is_cpu_port(ds, 0)) { -+ dev_err(priv->dev, "port 0 is not the CPU port"); -+ return -EINVAL; - } - -- /* Parse CPU port config to be later used in phy_link mac_config */ -- ret = qca8k_parse_port_config(priv); -- if (ret) -- return ret; -- -- mutex_init(&priv->reg_mutex); -- -- /* Start by setting up the register mapping */ -- priv->regmap = devm_regmap_init(ds->dev, NULL, priv, -- &qca8k_regmap_config); -- if (IS_ERR(priv->regmap)) -- dev_warn(priv->dev, "regmap initialization failed"); -- -- ret = qca8k_setup_mdio_bus(priv); -- if (ret) -- return ret; -- -- ret = qca8k_setup_of_pws_reg(priv); -- if (ret) -- return ret; -- -- ret = qca8k_setup_mac_pwr_sel(priv); -- if (ret) -- return ret; -- - /* Enable CPU Port */ - ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, - QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1120,149 +539,53 @@ qca8k_setup(struct dsa_switch *ds) - /* Enable MIB counters */ - ret = qca8k_mib_init(priv); - if (ret) -- dev_warn(priv->dev, "mib init failed"); -+ dev_warn(priv->dev, "MIB init failed"); -+ -+ /* Enable QCA header mode on the cpu port */ -+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT), -+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | -+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); -+ if (ret) { -+ dev_err(priv->dev, "failed enabling QCA header mode"); -+ return ret; -+ } - -- /* Initial setup of all ports */ -+ /* Disable forwarding by default on all ports */ - for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- /* Disable forwarding by default on all ports */ - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), - QCA8K_PORT_LOOKUP_MEMBER, 0); - if (ret) - return ret; -- -- /* Enable QCA header mode on all cpu ports */ -- if (dsa_is_cpu_port(ds, i)) { -- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), -- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | -- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); -- if (ret) { -- dev_err(priv->dev, "failed enabling QCA header mode"); -- return ret; -- } -- } -- -- /* Disable MAC by default on all user ports */ -- if (dsa_is_user_port(ds, i)) -- qca8k_port_set_status(priv, i, 0); - } - -- /* Forward all unknown frames to CPU port for Linux processing -- * Notice that in multi-cpu config only one port should be set -- * for igmp, unknown, multicast and broadcast packet -- */ -+ /* Disable MAC by default on all ports */ -+ for (i = 1; i < QCA8K_NUM_PORTS; i++) -+ qca8k_port_set_status(priv, i, 0); -+ -+ /* Forward all unknown frames to CPU port for Linux processing */ - ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | -- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | -- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | -- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); -+ BIT(QCA8K_CPU_PORT) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | -+ BIT(QCA8K_CPU_PORT) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | -+ BIT(QCA8K_CPU_PORT) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | -+ BIT(QCA8K_CPU_PORT) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); - if (ret) - return ret; - -- /* Setup connection between CPU port & user ports -- * Configure specific switch configuration for ports -- */ -+ /* Setup connection between CPU port & user ports */ - for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- /* CPU port gets connected to all user ports of the switch */ -- if (dsa_is_cpu_port(ds, i)) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); -- if (ret) -- return ret; -- } -- -- /* Individual user ports get connected to CPU port only */ -- if (dsa_is_user_port(ds, i)) { -- int shift = 16 * (i % 2); -- -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_MEMBER, -- BIT(cpu_port)); -- if (ret) -- return ret; -- -- /* Enable ARP Auto-learning by default */ -- ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_LEARN); -- if (ret) -- return ret; -- -- /* For port based vlans to work we need to set the -- * default egress vid -- */ -- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), -- 0xfff << shift, -- QCA8K_PORT_VID_DEF << shift); -- if (ret) -- return ret; -- -- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), -- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | -- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); -- if (ret) -- return ret; -- } -- -- /* The port 5 of the qca8337 have some problem in flood condition. The -- * original legacy driver had some specific buffer and priority settings -- * for the different port suggested by the QCA switch team. Add this -- * missing settings to improve switch stability under load condition. -- * This problem is limited to qca8337 and other qca8k switch are not affected. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8337) { -- switch (i) { -- /* The 2 CPU port and port 5 requires some different -- * priority than any other ports. -- */ -- case 0: -- case 5: -- case 6: -- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | -- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); -- break; -- default: -- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | -- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); -- } -- qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); -- -- mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | -- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_WRED_EN; -- qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), -- QCA8K_PORT_HOL_CTRL1_ING_BUF | -- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_WRED_EN, -- mask); -- } -- -- /* Set initial MTU for every port. -- * We have only have a general MTU setting. So track -- * every port and set the max across all port. -- */ -- priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; -- } -- -- /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | -- QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); -- qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, -- QCA8K_GLOBAL_FC_GOL_XON_THRES_S | -- QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S, -- mask); -+ ret = qca8k_setup_port(ds, i); -+ if (ret) -+ return ret; - } - - /* Setup our port MTUs to match power on defaults */ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) -+ /* Set per port MTU to 1500 as the MTU change function -+ * will add the overhead and if its set to 1518 then it -+ * will apply the overhead again and we will end up with -+ * MTU of 1536 instead of 1518 -+ */ -+ priv->port_mtu[i] = ETH_DATA_LEN; - ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); - if (ret) - dev_warn(priv->dev, "failed setting MTU settings"); ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1273,48 +596,87 @@ qca8k_setup(struct dsa_switch *ds) - /* We don't have interrupts for link changes, so we need to poll */ - ds->pcs_poll = true; - -+ /* CPU port HW learning doesnt work correctly, so let DSA handle it */ -+ ds->assisted_learning_on_cpu_port = true; -+ - return 0; - } - --static void --qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, -- u32 reg) -+static int psgmii_vco_calibrate(struct dsa_switch *ds) - { -- u32 delay, val = 0; -- int ret; -+ struct qca8k_priv *priv = ds->priv; -+ int val, ret; - -- /* Delay can be declared in 3 different way. -- * Mode to rgmii and internal-delay standard binding defined -- * rgmii-id or rgmii-tx/rx phy mode set. -- * The parse logic set a delay different than 0 only when one -- * of the 3 different way is used. In all other case delay is -- * not enabled. With ID or TX/RXID delay is enabled and set -- * to the default and recommended value. -- */ -- if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { -- delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; -+ if (!priv->psgmii_ethphy) { -+ dev_err(ds->dev, "PSGMII eth PHY missing, calibration failed!\n"); -+ return -ENODEV; -+ } - -- val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -+ /* Fix PSGMII RX 20bit */ -+ ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5b); -+ /* Reset PSGMII PHY */ -+ ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x1b); -+ /* Release reset */ -+ ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5b); -+ -+ /* Poll for VCO PLL calibration finish */ -+ ret = phy_read_mmd_poll_timeout(priv->psgmii_ethphy, -+ MDIO_MMD_PMAPMD, -+ 0x28, val, -+ (val & BIT(0)), -+ 10000, 1000000, -+ false); -+ if (ret) { -+ dev_err(ds->dev, "QCA807x PSGMII VCO calibration PLL not ready\n"); -+ return ret; - } - -- if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { -- delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; -+ /* Freeze PSGMII RX CDR */ -+ ret = phy_write(priv->psgmii_ethphy, MII_RESV2, 0x2230); - -- val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -+ /* Start PSGMIIPHY VCO PLL calibration */ -+ ret = regmap_set_bits(priv->psgmii, -+ PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_1, -+ PSGMIIPHY_REG_PLL_VCO_CALIB_RESTART); -+ -+ /* Poll for PSGMIIPHY PLL calibration finish */ -+ ret = regmap_read_poll_timeout(priv->psgmii, -+ PSGMIIPHY_VCO_CALIBRATION_CONTROL_REGISTER_2, -+ val, val & PSGMIIPHY_REG_PLL_VCO_CALIB_READY, -+ 10000, 1000000); -+ if (ret) { -+ dev_err(ds->dev, "PSGMIIPHY VCO calibration PLL not ready\n"); -+ return ret; - } - -- /* Set RGMII delay based on the selected values */ -- ret = qca8k_rmw(priv, reg, -- QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | -- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, -- val); -- if (ret) -- dev_err(priv->dev, "Failed to set internal delay for CPU port%d", -- cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); -+ /* Release PSGMII RX CDR */ -+ ret = phy_write(priv->psgmii_ethphy, MII_RESV2, 0x3230); -+ -+ /* Release PSGMII RX 20bit */ -+ ret = phy_write(priv->psgmii_ethphy, MII_BMCR, 0x5f); -+ -+ return ret; -+} -+ -+static int ipq4019_psgmii_configure(struct dsa_switch *ds) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ if (!priv->psgmii_calibrated) { -+ ret = psgmii_vco_calibrate(ds); -+ -+ ret = regmap_clear_bits(priv->psgmii, PSGMIIPHY_MODE_CONTROL, -+ PSGMIIPHY_MODE_ATHR_CSCO_MODE_25M); -+ ret = regmap_write(priv->psgmii, PSGMIIPHY_TX_CONTROL, -+ PSGMIIPHY_TX_CONTROL_MAGIC_VALUE); -+ -+ priv->psgmii_calibrated = true; -+ -+ return ret; -+ } -+ -+ return 0; - } - - static void ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1322,141 +684,33 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, - const struct phylink_link_state *state) - { - struct qca8k_priv *priv = ds->priv; -- int cpu_port_index, ret; -- u32 reg, val; - - switch (port) { -- case 0: /* 1st CPU port */ -- if (state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII) -- return; -- -- reg = QCA8K_REG_PORT0_PAD_CTRL; -- cpu_port_index = QCA8K_CPU_PORT0; -- break; -+ case 0: -+ /* CPU port, no configuration needed */ -+ return; - case 1: - case 2: - case 3: -+ if (state->interface == PHY_INTERFACE_MODE_PSGMII) -+ if (ipq4019_psgmii_configure(ds)) -+ dev_err(ds->dev, "PSGMII configuration failed!\n"); -+ return; - case 4: - case 5: -- /* Internal PHY, nothing to do */ -- return; -- case 6: /* 2nd CPU port / external PHY */ -- if (state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII && -- state->interface != PHY_INTERFACE_MODE_1000BASEX) -- return; -- -- reg = QCA8K_REG_PORT6_PAD_CTRL; -- cpu_port_index = QCA8K_CPU_PORT6; -- break; -- default: -- dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); -- return; -- } -- -- if (port != 6 && phylink_autoneg_inband(mode)) { -- dev_err(ds->dev, "%s: in-band negotiation unsupported\n", -- __func__); -- return; -- } -- -- switch (state->interface) { -- case PHY_INTERFACE_MODE_RGMII: -- case PHY_INTERFACE_MODE_RGMII_ID: -- case PHY_INTERFACE_MODE_RGMII_TXID: -- case PHY_INTERFACE_MODE_RGMII_RXID: -- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); -- -- /* Configure rgmii delay */ -- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -- -- /* QCA8337 requires to set rgmii rx delay for all ports. -- * This is enabled through PORT5_PAD_CTRL for all ports, -- * rather than individual port registers. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8337) -- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); -- break; -- case PHY_INTERFACE_MODE_SGMII: -- case PHY_INTERFACE_MODE_1000BASEX: -- /* Enable SGMII on the port */ -- qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); -- -- /* Enable/disable SerDes auto-negotiation as necessary */ -- ret = qca8k_read(priv, QCA8K_REG_PWS, &val); -- if (ret) -- return; -- if (phylink_autoneg_inband(mode)) -- val &= ~QCA8K_PWS_SERDES_AEN_DIS; -- else -- val |= QCA8K_PWS_SERDES_AEN_DIS; -- qca8k_write(priv, QCA8K_REG_PWS, val); -- -- /* Configure the SGMII parameters */ -- ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); -- if (ret) -- return; -- -- val |= QCA8K_SGMII_EN_SD; -- -- if (priv->ports_config.sgmii_enable_pll) -- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -- QCA8K_SGMII_EN_TX; -- -- if (dsa_is_cpu_port(ds, port)) { -- /* CPU port, we're talking to the CPU MAC, be a PHY */ -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_PHY; -- } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_MAC; -- } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_BASEX; -+ if (state->interface == PHY_INTERFACE_MODE_RGMII || -+ state->interface == PHY_INTERFACE_MODE_RGMII_ID || -+ state->interface == PHY_INTERFACE_MODE_RGMII_RXID || -+ state->interface == PHY_INTERFACE_MODE_RGMII_TXID) { -+ qca8k_reg_set(priv, QCA8K_REG_RGMII_CTRL, QCA8K_RGMII_CTRL_CLK); - } - -- qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); -- -- /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and -- * falling edge is set writing in the PORT0 PAD reg -- */ -- if (priv->switch_id == QCA8K_ID_QCA8327 || -- priv->switch_id == QCA8K_ID_QCA8337) -- reg = QCA8K_REG_PORT0_PAD_CTRL; -- -- val = 0; -- -- /* SGMII Clock phase configuration */ -- if (priv->ports_config.sgmii_rx_clk_falling_edge) -- val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; -- -- if (priv->ports_config.sgmii_tx_clk_falling_edge) -- val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; -- -- if (val) -- ret = qca8k_rmw(priv, reg, -- QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | -- QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, -- val); -- -- /* From original code is reported port instability as SGMII also -- * require delay set. Apply advised values here or take them from DT. -- */ -- if (state->interface == PHY_INTERFACE_MODE_SGMII) -- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -- -- break; -+ if (state->interface == PHY_INTERFACE_MODE_PSGMII) -+ if (ipq4019_psgmii_configure(ds)) -+ dev_err(ds->dev, "PSGMII configuration failed!\n"); -+ return; - default: -- dev_err(ds->dev, "xMII mode %s not supported for port %d\n", -- phy_modes(state->interface), port); -+ dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); - return; - } - } ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1469,59 +723,49 @@ qca8k_phylink_validate(struct dsa_switch *ds, int port, - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - - switch (port) { -- case 0: /* 1st CPU port */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII) -+ case 0: /* CPU port */ -+ if (state->interface != PHY_INTERFACE_MODE_INTERNAL) - goto unsupported; - break; - case 1: - case 2: - case 3: -- case 4: -- case 5: -- /* Internal PHY */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_GMII && -- state->interface != PHY_INTERFACE_MODE_INTERNAL) -+ /* Only PSGMII mode is supported */ -+ if (state->interface != PHY_INTERFACE_MODE_PSGMII) - goto unsupported; - break; -- case 6: /* 2nd CPU port / external PHY */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -+ case 4: -+ case 5: -+ /* PSGMII and RGMII modes are supported */ -+ if (state->interface != PHY_INTERFACE_MODE_PSGMII && - state->interface != PHY_INTERFACE_MODE_RGMII && - state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && - state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII && -- state->interface != PHY_INTERFACE_MODE_1000BASEX) -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID) - goto unsupported; - break; - default: - unsupported: -+ dev_warn(ds->dev, "interface '%s' (%d) on port %d is not supported\n", -+ phy_modes(state->interface), state->interface, port); - linkmode_zero(supported); - return; - } - -- phylink_set_port_modes(mask); -- phylink_set(mask, Autoneg); -- -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 10baseT_Half); -- phylink_set(mask, 10baseT_Full); -- phylink_set(mask, 100baseT_Half); -- phylink_set(mask, 100baseT_Full); -+ if (port == 0) { -+ phylink_set_port_modes(mask); - -- if (state->interface == PHY_INTERFACE_MODE_1000BASEX) -- phylink_set(mask, 1000baseX_Full); -+ phylink_set(mask, 1000baseT_Full); - -- phylink_set(mask, Pause); -- phylink_set(mask, Asym_Pause); -+ phylink_set(mask, Pause); -+ phylink_set(mask, Asym_Pause); - -- linkmode_and(supported, supported, mask); -- linkmode_and(state->advertising, state->advertising, mask); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); -+ } else { -+ /* Simply copy what PHYs tell us */ -+ linkmode_copy(state->advertising, supported); -+ } - } - - static int ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1895,14 +1139,22 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port, - return 0; - } - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - static int - qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - struct switchdev_trans *trans) -+#else -+static int -+qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -+ struct netlink_ext_ack *extack) -+#endif - { - struct qca8k_priv *priv = ds->priv; - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - if (switchdev_trans_ph_prepare(trans)) - return 0; -+#endif - - if (vlan_filtering) { - qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1917,39 +1169,70 @@ qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - return 0; - } - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - static int - qca8k_port_vlan_prepare(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) - { - return 0; - } -+#endif - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - static void - qca8k_port_vlan_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) -+#else -+static int -+qca8k_port_vlan_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan, -+ struct netlink_ext_ack *extack) -+#endif - { - bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; - bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; - struct qca8k_priv *priv = ds->priv; - int ret = 0; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - u16 vid; - - for (vid = vlan->vid_begin; vid <= vlan->vid_end && !ret; ++vid) - ret = qca8k_vlan_add(priv, port, vid, untagged); -- -+#else -+ ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); -+#endif -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - if (ret) - dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -+#else -+ if (ret) { -+ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -+ return ret; -+ } -+#endif - - if (pvid) { - int shift = 16 * (port % 2); - - qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - 0xfff << shift, - vlan->vid_end << shift); -+#else -+ 0xfff << shift, vlan->vid << shift); -+#endif - qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - QCA8K_PORT_VLAN_CVID(vlan->vid_end) | - QCA8K_PORT_VLAN_SVID(vlan->vid_end)); -+#else -+ QCA8K_PORT_VLAN_CVID(vlan->vid) | -+ QCA8K_PORT_VLAN_SVID(vlan->vid)); -+#endif - } -+#if LINUX_VERSION_CODE > KERNEL_VERSION(5,12,0) -+ return 0; -+#endif - } - - static int ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -1958,38 +1241,25 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port, - { - struct qca8k_priv *priv = ds->priv; - int ret = 0; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - u16 vid; - - for (vid = vlan->vid_begin; vid <= vlan->vid_end && !ret; ++vid) - ret = qca8k_vlan_del(priv, port, vid); -- -+#else -+ ret = qca8k_vlan_del(priv, port, vlan->vid); -+#endif - if (ret) - dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); - - return ret; - } - --static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = ds->priv; -- -- /* Communicate to the phy internal driver the switch revision. -- * Based on the switch revision different values needs to be -- * set to the dbg and mmd reg on the phy. -- * The first 2 bit are used to communicate the switch revision -- * to the phy driver. -- */ -- if (port > 0 && port < 6) -- return priv->switch_revision; -- -- return 0; --} -- - static enum dsa_tag_protocol - qca8k_get_tag_protocol(struct dsa_switch *ds, int port, - enum dsa_tag_protocol mp) - { -- return DSA_TAG_PROTO_QCA; -+ return DSA_TAG_PROTO_IPQ4019; - } - - static const struct dsa_switch_ops qca8k_switch_ops = { ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -2011,7 +1281,9 @@ static const struct dsa_switch_ops qca8k_switch_ops = { - .port_fdb_del = qca8k_port_fdb_del, - .port_fdb_dump = qca8k_port_fdb_dump, - .port_vlan_filtering = qca8k_port_vlan_filtering, -+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - .port_vlan_prepare = qca8k_port_vlan_prepare, -+#endif - .port_vlan_add = qca8k_port_vlan_add, - .port_vlan_del = qca8k_port_vlan_del, - .phylink_validate = qca8k_phylink_validate, ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c -@@ -2019,172 +1291,127 @@ static const struct dsa_switch_ops qca8k_switch_ops = { - .phylink_mac_config = qca8k_phylink_mac_config, - .phylink_mac_link_down = qca8k_phylink_mac_link_down, - .phylink_mac_link_up = qca8k_phylink_mac_link_up, -- .get_phy_flags = qca8k_get_phy_flags, - }; - --static int qca8k_read_switch_id(struct qca8k_priv *priv) --{ -- const struct qca8k_match_data *data; -- u32 val; -- u8 id; -- int ret; -- -- /* get the switches ID from the compatible */ -- data = of_device_get_match_data(priv->dev); -- if (!data) -- return -ENODEV; -- -- ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -- if (ret < 0) -- return -ENODEV; -- -- id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK); -- if (id != data->id) { -- dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); -- return -ENODEV; -- } -- -- priv->switch_id = id; -- -- /* Save revision to communicate to the internal PHY driver */ -- priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK); -- -- return 0; --} -- - static int --qca8k_sw_probe(struct mdio_device *mdiodev) -+qca8k_ipq4019_probe(struct platform_device *pdev) - { - struct qca8k_priv *priv; -+ void __iomem *base, *psgmii; -+ struct device_node *np = pdev->dev.of_node, *mdio_np, *psgmii_ethphy_np; - int ret; - -- /* allocate the private data struct so that we can probe the switches -- * ID register -- */ -- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - -- priv->bus = mdiodev->bus; -- priv->dev = &mdiodev->dev; -+ priv->dev = &pdev->dev; - -- priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", -- GPIOD_ASIS); -- if (IS_ERR(priv->reset_gpio)) -- return PTR_ERR(priv->reset_gpio); -+ base = devm_platform_ioremap_resource_byname(pdev, "base"); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); - -- if (priv->reset_gpio) { -- gpiod_set_value_cansleep(priv->reset_gpio, 1); -- /* The active low duration must be greater than 10 ms -- * and checkpatch.pl wants 20 ms. -- */ -- msleep(20); -- gpiod_set_value_cansleep(priv->reset_gpio, 0); -+ priv->regmap = devm_regmap_init_mmio(priv->dev, base, -+ &qca8k_ipq4019_regmap_config); -+ if (IS_ERR(priv->regmap)) { -+ ret = PTR_ERR(priv->regmap); -+ dev_err(priv->dev, "base regmap initialization failed, %d\n", ret); -+ return ret; - } - -- /* Check the detected switch id */ -- ret = qca8k_read_switch_id(priv); -- if (ret) -+ psgmii = devm_platform_ioremap_resource_byname(pdev, "psgmii_phy"); -+ if (IS_ERR(psgmii)) -+ return PTR_ERR(psgmii); -+ -+ priv->psgmii = devm_regmap_init_mmio(priv->dev, psgmii, -+ &qca8k_ipq4019_psgmii_phy_regmap_config); -+ if (IS_ERR(priv->psgmii)) { -+ ret = PTR_ERR(priv->psgmii); -+ dev_err(priv->dev, "PSGMII regmap initialization failed, %d\n", ret); - return ret; -+ } -+ -+ mdio_np = of_parse_phandle(np, "mdio", 0); -+ if (!mdio_np) { -+ dev_err(&pdev->dev, "unable to get MDIO bus phandle\n"); -+ of_node_put(mdio_np); -+ return -EINVAL; -+ } -+ -+ priv->bus = of_mdio_find_bus(mdio_np); -+ of_node_put(mdio_np); -+ if (!priv->bus) { -+ dev_err(&pdev->dev, "unable to find MDIO bus\n"); -+ return -EPROBE_DEFER; -+ } - -- priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); -+ psgmii_ethphy_np = of_parse_phandle(np, "psgmii-ethphy", 0); -+ if (!psgmii_ethphy_np) { -+ dev_dbg(&pdev->dev, "unable to get PSGMII eth PHY phandle\n"); -+ of_node_put(psgmii_ethphy_np); -+ } -+ -+ if (psgmii_ethphy_np) { -+ priv->psgmii_ethphy = of_phy_find_device(psgmii_ethphy_np); -+ of_node_put(psgmii_ethphy_np); -+ if (!priv->psgmii_ethphy) { -+ dev_err(&pdev->dev, "unable to get PSGMII eth PHY\n"); -+ return -ENODEV; -+ } -+ } -+ -+ priv->ds = devm_kzalloc(priv->dev, sizeof(*priv->ds), GFP_KERNEL); - if (!priv->ds) - return -ENOMEM; - -- priv->ds->dev = &mdiodev->dev; -+ priv->ds->dev = priv->dev; - priv->ds->num_ports = QCA8K_NUM_PORTS; -- priv->ds->configure_vlan_while_not_filtering = true; - priv->ds->priv = priv; - priv->ops = qca8k_switch_ops; - priv->ds->ops = &priv->ops; -+ - mutex_init(&priv->reg_mutex); -- dev_set_drvdata(&mdiodev->dev, priv); -+ platform_set_drvdata(pdev, priv); - - return dsa_register_switch(priv->ds); - } - --static void --qca8k_sw_remove(struct mdio_device *mdiodev) -+static int -+qca8k_ipq4019_remove(struct platform_device *pdev) - { -- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -+ struct qca8k_priv *priv = dev_get_drvdata(&pdev->dev); - int i; - -+ if (!priv) -+ return 0; -+ - for (i = 0; i < QCA8K_NUM_PORTS; i++) - qca8k_port_set_status(priv, i, 0); - - dsa_unregister_switch(priv->ds); --} -- --#ifdef CONFIG_PM_SLEEP --static void --qca8k_set_pm(struct qca8k_priv *priv, int enable) --{ -- int i; -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- if (!priv->port_sts[i].enabled) -- continue; -- -- qca8k_port_set_status(priv, i, enable); -- } --} - --static int qca8k_suspend(struct device *dev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(dev); -- -- qca8k_set_pm(priv, 0); -- -- return dsa_switch_suspend(priv->ds); --} -+ dev_set_drvdata(&pdev->dev, NULL); - --static int qca8k_resume(struct device *dev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(dev); -- -- qca8k_set_pm(priv, 1); -- -- return dsa_switch_resume(priv->ds); -+ return 0; - } --#endif /* CONFIG_PM_SLEEP */ -- --static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, -- qca8k_suspend, qca8k_resume); -- --static const struct qca8k_match_data qca8327 = { -- .id = QCA8K_ID_QCA8327, -- .reduced_package = true, --}; -- --static const struct qca8k_match_data qca8328 = { -- .id = QCA8K_ID_QCA8327, --}; -- --static const struct qca8k_match_data qca833x = { -- .id = QCA8K_ID_QCA8337, --}; - --static const struct of_device_id qca8k_of_match[] = { -- { .compatible = "qca,qca8327", .data = &qca8327 }, -- { .compatible = "qca,qca8328", .data = &qca8328 }, -- { .compatible = "qca,qca8334", .data = &qca833x }, -- { .compatible = "qca,qca8337", .data = &qca833x }, -+static const struct of_device_id qca8k_ipq4019_of_match[] = { -+ { .compatible = "qca,ipq4019-qca8337n" }, - { /* sentinel */ }, - }; - --static struct mdio_driver qca8kmdio_driver = { -- .probe = qca8k_sw_probe, -- .remove = qca8k_sw_remove, -- .mdiodrv.driver = { -- .name = "qca8k", -- .of_match_table = qca8k_of_match, -- .pm = &qca8k_pm_ops, -+static struct platform_driver qca8k_ipq4019_driver = { -+ .probe = qca8k_ipq4019_probe, -+ .remove = qca8k_ipq4019_remove, -+ .driver = { -+ .name = "qca8k-ipq4019", -+ .of_match_table = qca8k_ipq4019_of_match, - }, - }; - --mdio_module_driver(qca8kmdio_driver); -+module_platform_driver(qca8k_ipq4019_driver); - - MODULE_AUTHOR("Mathieu Olivari, John Crispin "); --MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); -+MODULE_AUTHOR("Gabor Juhos , Robert Marko "); -+MODULE_DESCRIPTION("Qualcomm IPQ4019 built-in switch driver"); - MODULE_LICENSE("GPL v2"); --MODULE_ALIAS("platform:qca8k"); ---- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.h -+++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.h -@@ -8,19 +8,12 @@ - #ifndef __QCA8K_H - #define __QCA8K_H - --#include - #include