From 297f82fc583ac277f85a8a202c3d672f93ac08f8 Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Sat, 23 Jan 2021 10:20:03 +0000 Subject: [PATCH 01/29] dnsmasq: Update to 2.84test3 dnsmasq v2.83 has a bug in handling duplicate queries which means it may try to reply using the incorrect network socket. This is especially noticeable in dual stack environments where replies may be mis-directed to IPv4 addresses on an IPv6 socket or IPv6 addresses on an IPv4 socket. This results in system log spam such as: dnsmasq[16020]: failed to send packet: Network unreachable dnsmasq[16020]: failed to send packet: Address family not supported by protocol dnsmasq v2.84test3 resolves these issues. Signed-off-by: Kevin Darbyshire-Bryant --- package/network/services/dnsmasq/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile index 7b5af1dd27..2e404dfef3 100644 --- a/package/network/services/dnsmasq/Makefile +++ b/package/network/services/dnsmasq/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dnsmasq -PKG_UPSTREAM_VERSION:=2.83 +PKG_UPSTREAM_VERSION:=2.84test3 PKG_VERSION:=$(subst test,~~test,$(subst rc,~rc,$(PKG_UPSTREAM_VERSION))) PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_UPSTREAM_VERSION).tar.xz -PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq -PKG_HASH:=ffc1f7e8b05e22d910b9a71d09f1128197292766dc7c54cb7018a1b2c3af4aea +PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq/test-releases +PKG_HASH:=20d1109c991ca08778ea20322b8f3245f2e974688d494b59b2e6ae096ec592b1 PKG_LICENSE:=GPL-2.0 PKG_LICENSE_FILES:=COPYING From ca4832fcac83bc375a48648bd77d3283d0742128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sat, 23 Jan 2021 11:08:11 +0100 Subject: [PATCH 02/29] realtek: use vendor-specific magic for ZyXEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stock firmware of the ZyXEL GS1900 series use a non-standard u-image magic. This is not enforced by the stock u-boot, which is why we could boot images with the default magic. The flash management application of the stock firmware will however verify the magic, and refuse any image with another value. Convert to vendor-specific value to get flash management support in stock firmware, including the ability to upgrade to OpenWrt directly from stock web UI. Signed-off-by: Bjørn Mork --- target/linux/realtek/dts/rtl8380_zyxel_gs1900.dtsi | 3 ++- target/linux/realtek/image/Makefile | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/target/linux/realtek/dts/rtl8380_zyxel_gs1900.dtsi b/target/linux/realtek/dts/rtl8380_zyxel_gs1900.dtsi index 5f06339d13..c4441ec30e 100644 --- a/target/linux/realtek/dts/rtl8380_zyxel_gs1900.dtsi +++ b/target/linux/realtek/dts/rtl8380_zyxel_gs1900.dtsi @@ -92,7 +92,8 @@ partition@b260000 { label = "firmware"; reg = <0x260000 0x6d0000>; - compatible = "denx,uimage"; + compatible = "openwrt,uimage", "denx,uimage"; + openwrt,ih-magic = <0x83800000>; }; partition@930000 { label = "runtime2"; diff --git a/target/linux/realtek/image/Makefile b/target/linux/realtek/image/Makefile index 87c616c3f2..c05c504ec4 100644 --- a/target/linux/realtek/image/Makefile +++ b/target/linux/realtek/image/Makefile @@ -69,6 +69,7 @@ define Device/zyxel_gs1900-10hp IMAGE_SIZE := 6976k DEVICE_VENDOR := ZyXEL DEVICE_MODEL := GS1900-10HP + UIMAGE_MAGIC := 0x83800000 endef TARGET_DEVICES += zyxel_gs1900-10hp @@ -79,6 +80,7 @@ define Device/zyxel_gs1900-8hp-v1 DEVICE_MODEL := GS1900-8HP DEVICE_VARIANT := v1 DEVICE_PACKAGES += lua-rs232 + UIMAGE_MAGIC := 0x83800000 endef TARGET_DEVICES += zyxel_gs1900-8hp-v1 @@ -89,6 +91,7 @@ define Device/zyxel_gs1900-8hp-v2 DEVICE_MODEL := GS1900-8HP DEVICE_VARIANT := v2 DEVICE_PACKAGES += lua-rs232 + UIMAGE_MAGIC := 0x83800000 endef TARGET_DEVICES += zyxel_gs1900-8hp-v2 From 1fb413e6579a34a0040b526e681298909dfaa5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sat, 23 Jan 2021 11:08:12 +0100 Subject: [PATCH 03/29] realtek: build ZyXEL vendor firmware compatible initramfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Append a device specific version trailer used by the stock firmware upgrade application to validate firmwares. The trailer contains a list of ZyXEL firmware version numbers, which includes a four letter hardware identifier. The stock web UI requires that the current hardware matches one of the listed versions, and that the version number is larger than a model specific minimum value. The minimum version varies between V1.00 and V2.60 for the currently known GS1900 models. The number is not used anywhere else to our knowlege, and has no direct relation to the version info in the u-image header. We can therefore use an arbitrary value larger than V2.60. The stock firmware upgrade application will only load and flash the part of the file specified in the u-image header, regardless of file size. It can therefore not be used to flash images with an appended rootfs. There is therefore no need to include the trailer in other images than the initramfs. This prevents accidentally bricking by attempts to flash other images from the stock web UI. Stock images support all models in the series, listing all of them in the version trailer. OpenWrt provide model specific images. We therefore only list the single supported hardware identifier for each image. This eliminates the risk of flashing the wrong OpenWrt image from stock web UI. OpenWrt can be installed from stock firmware in two steps: 1) flash OpenWrt initramfs image from stock web gui 2) boot OpenWrt and sysupgrade to a squasfs image The OpenWrt squashfs image depends on a static partition map in the DTS. It can only be installed to the "firmware" partition. This partition is labeled "RUNTIME1" in u-boot and in stock firmware, and is referred to as "image 0" in the stock flash management tool. The OpenWrt initramfs can be installed and run from either partitions. But if you want to keep stock irmware in the spare system partition, then you must make sure stock firmware is installed to the "RUNTIME2" partition referred to as "image 1" in the stock web UI. And the initial OpenWrt initramfs must be flashed to "RUNTIME1"/"image 0". The stock flash management application supports direct selection of both which partition to flash and which partition to boot next. This allows software controlled "dual-boot" between OpenWrt and stock firmware, without using console access to u-boot. u-boot use the "bootpartition" variable stored in the second u-boot environment to select which of the two system partitions to boot. This variable is set by the stock flash management application, by direct user input. It can also be set in OpenWrt using e.g fw_setsys bootpartition 1 to select "RUNTIME2"/"image 1" as default, assuming a stock firmware version is installed in that partition. Signed-off-by: Bjørn Mork --- target/linux/realtek/image/Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target/linux/realtek/image/Makefile b/target/linux/realtek/image/Makefile index c05c504ec4..8ad7ad1b5d 100644 --- a/target/linux/realtek/image/Makefile +++ b/target/linux/realtek/image/Makefile @@ -7,6 +7,14 @@ include $(INCLUDE_DIR)/image.mk KERNEL_LOADADDR = 0x80000000 KERNEL_ENTRY = 0x80000400 +define Build/zyxel-vers + ( echo VERS;\ + for hw in $(1); do\ + echo -n "V9.99($$hw.0) | ";\ + date -d @$(SOURCE_DATE_EPOCH) +%m/%d/%Y;\ + done ) >> $@ +endef + define Device/Default PROFILES = Default KERNEL := kernel-bin | append-dtb | gzip | uImage gzip @@ -70,6 +78,7 @@ define Device/zyxel_gs1900-10hp DEVICE_VENDOR := ZyXEL DEVICE_MODEL := GS1900-10HP UIMAGE_MAGIC := 0x83800000 + KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers AAZI | uImage gzip endef TARGET_DEVICES += zyxel_gs1900-10hp @@ -81,6 +90,7 @@ define Device/zyxel_gs1900-8hp-v1 DEVICE_VARIANT := v1 DEVICE_PACKAGES += lua-rs232 UIMAGE_MAGIC := 0x83800000 + KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers AAHI | uImage gzip endef TARGET_DEVICES += zyxel_gs1900-8hp-v1 @@ -92,6 +102,7 @@ define Device/zyxel_gs1900-8hp-v2 DEVICE_VARIANT := v2 DEVICE_PACKAGES += lua-rs232 UIMAGE_MAGIC := 0x83800000 + KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | zyxel-vers AAHI | uImage gzip endef TARGET_DEVICES += zyxel_gs1900-8hp-v2 From 37752336bdfb361d597b316cd5bb9d8dc6ac1762 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 23 Jan 2021 00:17:31 +0100 Subject: [PATCH 04/29] mac80211: add significant minstrel_ht performance improvements Completely redesign the rate sampling approach Signed-off-by: Felix Fietkau --- ...l_ht-use-bitfields-to-encode-rate-in.patch | 409 ++++++++++ ...l_ht-update-total-packets-counter-in.patch | 54 ++ ...l_ht-reduce-the-need-to-sample-slowe.patch | 102 +++ ...l_ht-significantly-redesign-the-rate.patch | 767 ++++++++++++++++++ ...el_ht-show-sampling-rates-in-debugfs.patch | 59 ++ ...l_ht-remove-sample-rate-switching-co.patch | 279 +++++++ 6 files changed, 1670 insertions(+) create mode 100644 package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch create mode 100644 package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch create mode 100644 package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch create mode 100644 package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch create mode 100644 package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch create mode 100644 package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch diff --git a/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch b/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch new file mode 100644 index 0000000000..a17725d69b --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch @@ -0,0 +1,409 @@ +From: Felix Fietkau +Date: Thu, 21 Jan 2021 18:29:30 +0100 +Subject: [PATCH] mac80211: minstrel_ht: use bitfields to encode rate + indexes + +Get rid of a lot of divisions and modulo operations +Reduces code size and improves performance + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -379,14 +379,14 @@ out: + static inline struct minstrel_rate_stats * + minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) + { +- return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; ++ return &mi->groups[MI_RATE_GROUP(index)].rates[MI_RATE_IDX(index)]; + } + +-static inline int +-minstrel_get_duration(int index) ++static inline int minstrel_get_duration(int index) + { +- const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; +- unsigned int duration = group->duration[index % MCS_GROUP_RATES]; ++ const struct mcs_group *group = &minstrel_mcs_groups[MI_RATE_GROUP(index)]; ++ unsigned int duration = group->duration[MI_RATE_IDX(index)]; ++ + return duration << group->shift; + } + +@@ -398,7 +398,7 @@ minstrel_ht_avg_ampdu_len(struct minstre + if (mi->avg_ampdu_len) + return MINSTREL_TRUNC(mi->avg_ampdu_len); + +- if (minstrel_ht_is_legacy_group(mi->max_tp_rate[0] / MCS_GROUP_RATES)) ++ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_tp_rate[0]))) + return 1; + + duration = minstrel_get_duration(mi->max_tp_rate[0]); +@@ -465,14 +465,14 @@ minstrel_ht_sort_best_tp_rates(struct mi + int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; + int j = MAX_THR_RATES; + +- cur_group = index / MCS_GROUP_RATES; +- cur_idx = index % MCS_GROUP_RATES; ++ cur_group = MI_RATE_GROUP(index); ++ cur_idx = MI_RATE_IDX(index); + cur_prob = mi->groups[cur_group].rates[cur_idx].prob_avg; + cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob); + + do { +- tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; +- tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; ++ tmp_group = MI_RATE_GROUP(tp_list[j - 1]); ++ tmp_idx = MI_RATE_IDX(tp_list[j - 1]); + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; + tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, + tmp_prob); +@@ -504,23 +504,23 @@ minstrel_ht_set_best_prob_rate(struct mi + int max_gpr_group, max_gpr_idx; + int max_gpr_tp_avg, max_gpr_prob; + +- cur_group = index / MCS_GROUP_RATES; +- cur_idx = index % MCS_GROUP_RATES; +- mg = &mi->groups[index / MCS_GROUP_RATES]; +- mrs = &mg->rates[index % MCS_GROUP_RATES]; ++ cur_group = MI_RATE_GROUP(index); ++ cur_idx = MI_RATE_IDX(index); ++ mg = &mi->groups[cur_group]; ++ mrs = &mg->rates[cur_idx]; + +- tmp_group = *dest / MCS_GROUP_RATES; +- tmp_idx = *dest % MCS_GROUP_RATES; ++ tmp_group = MI_RATE_GROUP(*dest); ++ tmp_idx = MI_RATE_IDX(*dest); + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; + tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); + + /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from + * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ +- max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES; +- max_tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES; ++ max_tp_group = MI_RATE_GROUP(mi->max_tp_rate[0]); ++ max_tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]); + max_tp_prob = mi->groups[max_tp_group].rates[max_tp_idx].prob_avg; + +- if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES) && ++ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index)) && + !minstrel_ht_is_legacy_group(max_tp_group)) + return; + +@@ -529,8 +529,8 @@ minstrel_ht_set_best_prob_rate(struct mi + mrs->prob_avg < max_tp_prob) + return; + +- max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; +- max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; ++ max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate); ++ max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate); + max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; + + if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) { +@@ -567,13 +567,13 @@ minstrel_ht_assign_best_tp_rates(struct + unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob; + int i; + +- tmp_group = tmp_legacy_tp_rate[0] / MCS_GROUP_RATES; +- tmp_idx = tmp_legacy_tp_rate[0] % MCS_GROUP_RATES; ++ tmp_group = MI_RATE_GROUP(tmp_legacy_tp_rate[0]); ++ tmp_idx = MI_RATE_IDX(tmp_legacy_tp_rate[0]); + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; + tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); + +- tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; +- tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; ++ tmp_group = MI_RATE_GROUP(tmp_mcs_tp_rate[0]); ++ tmp_idx = MI_RATE_IDX(tmp_mcs_tp_rate[0]); + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; + tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); + +@@ -600,14 +600,14 @@ minstrel_ht_prob_rate_reduce_streams(str + if (!mi->sta->ht_cap.ht_supported) + return; + +- tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / +- MCS_GROUP_RATES].streams; ++ group = MI_RATE_GROUP(mi->max_tp_rate[0]); ++ tmp_max_streams = minstrel_mcs_groups[group].streams; + for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { + mg = &mi->groups[group]; + if (!mi->supported[group] || group == MINSTREL_CCK_GROUP) + continue; + +- tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; ++ tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate); + tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg; + + if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) && +@@ -644,8 +644,8 @@ minstrel_ht_find_probe_rates(struct mins + int i, g, max_dur; + int tp_idx; + +- tp_group = &minstrel_mcs_groups[mi->max_tp_rate[0] / MCS_GROUP_RATES]; +- tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES; ++ tp_group = &minstrel_mcs_groups[MI_RATE_GROUP(mi->max_tp_rate[0])]; ++ tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]); + + max_dur = minstrel_get_duration(mi->max_tp_rate[0]); + if (faster_rate) +@@ -670,7 +670,7 @@ minstrel_ht_find_probe_rates(struct mins + if ((group->duration[i] << group->shift) > max_dur) + continue; + +- idx = g * MCS_GROUP_RATES + i; ++ idx = MI_RATE(g, i); + if (idx == mi->max_tp_rate[0]) + continue; + +@@ -712,10 +712,10 @@ minstrel_ht_rate_sample_switch(struct mi + + /* If no suitable rate was found, try to pick the next one in the group */ + if (!n_rates) { +- int g_idx = mi->max_tp_rate[0] / MCS_GROUP_RATES; ++ int g_idx = MI_RATE_GROUP(mi->max_tp_rate[0]); + u16 supported = mi->supported[g_idx]; + +- supported >>= mi->max_tp_rate[0] % MCS_GROUP_RATES; ++ supported >>= MI_RATE_IDX(mi->max_tp_rate[0]); + for (i = 0; supported; supported >>= 1, i++) { + if (!(supported & 1)) + continue; +@@ -856,22 +856,26 @@ minstrel_ht_update_stats(struct minstrel + + memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); + memset(tmp_legacy_tp_rate, 0, sizeof(tmp_legacy_tp_rate)); ++ + if (mi->supported[MINSTREL_CCK_GROUP]) +- for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) +- tmp_legacy_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; ++ group = MINSTREL_CCK_GROUP; + else if (mi->supported[MINSTREL_OFDM_GROUP]) +- for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) +- tmp_legacy_tp_rate[j] = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES; ++ group = MINSTREL_OFDM_GROUP; ++ ++ index = MI_RATE(group, 0); ++ for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) ++ tmp_legacy_tp_rate[j] = index; + + if (mi->supported[MINSTREL_VHT_GROUP_0]) +- index = MINSTREL_VHT_GROUP_0 * MCS_GROUP_RATES; ++ group = MINSTREL_VHT_GROUP_0; + else if (ht_supported) +- index = MINSTREL_HT_GROUP_0 * MCS_GROUP_RATES; ++ group = MINSTREL_HT_GROUP_0; + else if (mi->supported[MINSTREL_CCK_GROUP]) +- index = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; ++ group = MINSTREL_CCK_GROUP; + else +- index = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES; ++ group = MINSTREL_OFDM_GROUP; + ++ index = MI_RATE(group, 0); + tmp_max_prob_rate = index; + for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++) + tmp_mcs_tp_rate[j] = index; +@@ -888,7 +892,7 @@ minstrel_ht_update_stats(struct minstrel + + /* (re)Initialize group rate indexes */ + for(j = 0; j < MAX_THR_RATES; j++) +- tmp_group_tp_rate[j] = MCS_GROUP_RATES * group; ++ tmp_group_tp_rate[j] = MI_RATE(group, 0); + + if (group == MINSTREL_CCK_GROUP && ht_supported) + tp_rate = tmp_legacy_tp_rate; +@@ -897,7 +901,7 @@ minstrel_ht_update_stats(struct minstrel + if (!(mi->supported[group] & BIT(i))) + continue; + +- index = MCS_GROUP_RATES * group + i; ++ index = MI_RATE(group, i); + + mrs = &mg->rates[i]; + mrs->retry_updated = false; +@@ -929,13 +933,13 @@ minstrel_ht_update_stats(struct minstrel + continue; + + mg = &mi->groups[group]; +- mg->max_group_prob_rate = MCS_GROUP_RATES * group; ++ mg->max_group_prob_rate = MI_RATE(group, 0); + + for (i = 0; i < MCS_GROUP_RATES; i++) { + if (!(mi->supported[group] & BIT(i))) + continue; + +- index = MCS_GROUP_RATES * group + i; ++ index = MI_RATE(group, i); + + /* Find max probability rate per group and global */ + minstrel_ht_set_best_prob_rate(mi, &tmp_max_prob_rate, +@@ -1022,7 +1026,7 @@ minstrel_downgrade_rate(struct minstrel_ + { + int group, orig_group; + +- orig_group = group = *idx / MCS_GROUP_RATES; ++ orig_group = group = MI_RATE_GROUP(*idx); + while (group > 0) { + group--; + +@@ -1206,7 +1210,7 @@ minstrel_calc_retransmit(struct minstrel + ctime += (t_slot * cw) >> 1; + cw = min((cw << 1) | 1, mp->cw_max); + +- if (minstrel_ht_is_legacy_group(index / MCS_GROUP_RATES)) { ++ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index))) { + overhead = mi->overhead_legacy; + overhead_rtscts = mi->overhead_legacy_rtscts; + } else { +@@ -1239,7 +1243,7 @@ static void + minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + struct ieee80211_sta_rates *ratetbl, int offset, int index) + { +- int group_idx = index / MCS_GROUP_RATES; ++ int group_idx = MI_RATE_GROUP(index); + const struct mcs_group *group = &minstrel_mcs_groups[group_idx]; + struct minstrel_rate_stats *mrs; + u8 idx; +@@ -1259,7 +1263,7 @@ minstrel_ht_set_rate(struct minstrel_pri + ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts; + } + +- index %= MCS_GROUP_RATES; ++ index = MI_RATE_IDX(index); + if (group_idx == MINSTREL_CCK_GROUP) + idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; + else if (group_idx == MINSTREL_OFDM_GROUP) +@@ -1289,17 +1293,17 @@ minstrel_ht_set_rate(struct minstrel_pri + static inline int + minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate) + { +- int group = rate / MCS_GROUP_RATES; +- rate %= MCS_GROUP_RATES; ++ int group = MI_RATE_GROUP(rate); ++ rate = MI_RATE_IDX(rate); + return mi->groups[group].rates[rate].prob_avg; + } + + static int + minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) + { +- int group = mi->max_prob_rate / MCS_GROUP_RATES; ++ int group = MI_RATE_GROUP(mi->max_prob_rate); + const struct mcs_group *g = &minstrel_mcs_groups[group]; +- int rate = mi->max_prob_rate % MCS_GROUP_RATES; ++ int rate = MI_RATE_IDX(mi->max_prob_rate); + unsigned int duration; + + /* Disable A-MSDU if max_prob_rate is bad */ +@@ -1405,7 +1409,7 @@ minstrel_get_sample_rate(struct minstrel + return -1; + + mrs = &mg->rates[sample_idx]; +- sample_idx += sample_group * MCS_GROUP_RATES; ++ sample_idx += MI_RATE(sample_group, 0); + + tp_rate1 = mi->max_tp_rate[0]; + +@@ -1455,8 +1459,7 @@ minstrel_get_sample_rate(struct minstrel + * if the link is working perfectly. + */ + +- cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 / +- MCS_GROUP_RATES].streams; ++ cur_max_tp_streams = minstrel_mcs_groups[MI_RATE_GROUP(tp_rate1)].streams; + if (sample_dur >= minstrel_get_duration(tp_rate2) && + (cur_max_tp_streams - 1 < + minstrel_mcs_groups[sample_group].streams || +@@ -1484,7 +1487,7 @@ minstrel_ht_get_rate(void *priv, struct + int sample_idx; + + if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && +- !minstrel_ht_is_legacy_group(mi->max_prob_rate / MCS_GROUP_RATES)) ++ !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate))) + minstrel_aggr_check(sta, txrc->skb); + + info->flags |= mi->tx_flags; +@@ -1512,8 +1515,8 @@ minstrel_ht_get_rate(void *priv, struct + if (sample_idx < 0) + return; + +- sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES]; +- sample_idx %= MCS_GROUP_RATES; ++ sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)]; ++ sample_idx = MI_RATE_IDX(sample_idx); + + if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP] && + (sample_idx >= 4) != txrc->short_preamble) +@@ -1529,7 +1532,7 @@ minstrel_ht_get_rate(void *priv, struct + int idx = sample_idx % ARRAY_SIZE(mp->ofdm_rates[0]); + rate->idx = mp->ofdm_rates[mi->band][idx]; + } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { +- ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES, ++ ieee80211_rate_set_vht(rate, MI_RATE_IDX(sample_idx), + sample_group->streams); + } else { + rate->idx = sample_idx + (sample_group->streams - 1) * 8; +@@ -1898,8 +1901,8 @@ static u32 minstrel_ht_get_expected_thro + struct minstrel_ht_sta *mi = priv_sta; + int i, j, prob, tp_avg; + +- i = mi->max_tp_rate[0] / MCS_GROUP_RATES; +- j = mi->max_tp_rate[0] % MCS_GROUP_RATES; ++ i = MI_RATE_GROUP(mi->max_tp_rate[0]); ++ j = MI_RATE_IDX(mi->max_tp_rate[0]); + prob = mi->groups[i].rates[j].prob_avg; + + /* convert tp_avg from pkt per second in kbps */ +--- a/net/mac80211/rc80211_minstrel_ht.h ++++ b/net/mac80211/rc80211_minstrel_ht.h +@@ -6,6 +6,8 @@ + #ifndef __RC_MINSTREL_HT_H + #define __RC_MINSTREL_HT_H + ++#include ++ + /* number of highest throughput rates to consider*/ + #define MAX_THR_RATES 4 + #define SAMPLE_COLUMNS 10 /* number of columns in sample table */ +@@ -57,6 +59,17 @@ + + #define MCS_GROUP_RATES 10 + ++#define MI_RATE_IDX_MASK GENMASK(3, 0) ++#define MI_RATE_GROUP_MASK GENMASK(15, 4) ++ ++#define MI_RATE(_group, _idx) \ ++ (FIELD_PREP(MI_RATE_GROUP_MASK, _group) | \ ++ FIELD_PREP(MI_RATE_IDX_MASK, _idx)) ++ ++#define MI_RATE_IDX(_rate) FIELD_GET(MI_RATE_IDX_MASK, _rate) ++#define MI_RATE_GROUP(_rate) FIELD_GET(MI_RATE_GROUP_MASK, _rate) ++ ++ + struct minstrel_priv { + struct ieee80211_hw *hw; + bool has_mrr; +--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c ++++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c +@@ -56,7 +56,7 @@ minstrel_ht_stats_dump(struct minstrel_h + + for (j = 0; j < MCS_GROUP_RATES; j++) { + struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; +- int idx = i * MCS_GROUP_RATES + j; ++ int idx = MI_RATE(i, j); + unsigned int duration; + + if (!(mi->supported[i] & BIT(j))) +@@ -201,7 +201,7 @@ minstrel_ht_stats_csv_dump(struct minstr + + for (j = 0; j < MCS_GROUP_RATES; j++) { + struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; +- int idx = i * MCS_GROUP_RATES + j; ++ int idx = MI_RATE(i, j); + unsigned int duration; + + if (!(mi->supported[i] & BIT(j))) diff --git a/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch b/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch new file mode 100644 index 0000000000..a1cdf99e05 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch @@ -0,0 +1,54 @@ +From: Felix Fietkau +Date: Fri, 22 Jan 2021 18:21:13 +0100 +Subject: [PATCH] mac80211: minstrel_ht: update total packets counter in tx + status path + +Keep the update in one place and prepare for further rework + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -1093,6 +1093,16 @@ minstrel_ht_tx_status(void *priv, struct + info->status.ampdu_len = 1; + } + ++ /* wraparound */ ++ if (mi->total_packets >= ~0 - info->status.ampdu_len) { ++ mi->total_packets = 0; ++ mi->sample_packets = 0; ++ } ++ ++ mi->total_packets += info->status.ampdu_len; ++ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ++ mi->sample_packets += info->status.ampdu_len; ++ + mi->ampdu_packets++; + mi->ampdu_len += info->status.ampdu_len; + +@@ -1104,9 +1114,6 @@ minstrel_ht_tx_status(void *priv, struct + mi->sample_count--; + } + +- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) +- mi->sample_packets += info->status.ampdu_len; +- + if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) + rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); + +@@ -1504,14 +1511,6 @@ minstrel_ht_get_rate(void *priv, struct + else + sample_idx = minstrel_get_sample_rate(mp, mi); + +- mi->total_packets++; +- +- /* wraparound */ +- if (mi->total_packets == ~0) { +- mi->total_packets = 0; +- mi->sample_packets = 0; +- } +- + if (sample_idx < 0) + return; + diff --git a/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch b/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch new file mode 100644 index 0000000000..4b0ba3dbe5 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch @@ -0,0 +1,102 @@ +From: Felix Fietkau +Date: Fri, 22 Jan 2021 19:24:59 +0100 +Subject: [PATCH] mac80211: minstrel_ht: reduce the need to sample slower + rates + +In order to more gracefully be able to fall back to lower rates without too +much throughput fluctuations, initialize all untested rates below tested ones +to the maximum probabilty of higher rates. +Usually this leads to untested lower rates getting initialized with a +probability value of 100%, making them better candidates for fallback without +having to rely on random probing + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -791,14 +791,11 @@ minstrel_ht_calc_rate_stats(struct minst + unsigned int cur_prob; + + if (unlikely(mrs->attempts > 0)) { +- mrs->sample_skipped = 0; + cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); + minstrel_filter_avg_add(&mrs->prob_avg, + &mrs->prob_avg_1, cur_prob); + mrs->att_hist += mrs->attempts; + mrs->succ_hist += mrs->success; +- } else { +- mrs->sample_skipped++; + } + + mrs->last_success = mrs->success; +@@ -851,7 +848,6 @@ minstrel_ht_update_stats(struct minstrel + mi->ampdu_packets = 0; + } + +- mi->sample_slow = 0; + mi->sample_count = 0; + + memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); +@@ -883,6 +879,7 @@ minstrel_ht_update_stats(struct minstrel + /* Find best rate sets within all MCS groups*/ + for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { + u16 *tp_rate = tmp_mcs_tp_rate; ++ u16 last_prob = 0; + + mg = &mi->groups[group]; + if (!mi->supported[group]) +@@ -897,7 +894,7 @@ minstrel_ht_update_stats(struct minstrel + if (group == MINSTREL_CCK_GROUP && ht_supported) + tp_rate = tmp_legacy_tp_rate; + +- for (i = 0; i < MCS_GROUP_RATES; i++) { ++ for (i = MCS_GROUP_RATES - 1; i >= 0; i--) { + if (!(mi->supported[group] & BIT(i))) + continue; + +@@ -906,6 +903,11 @@ minstrel_ht_update_stats(struct minstrel + mrs = &mg->rates[i]; + mrs->retry_updated = false; + minstrel_ht_calc_rate_stats(mp, mrs); ++ ++ if (mrs->att_hist) ++ last_prob = max(last_prob, mrs->prob_avg); ++ else ++ mrs->prob_avg = max(last_prob, mrs->prob_avg); + cur_prob = mrs->prob_avg; + + if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) +@@ -1470,13 +1472,9 @@ minstrel_get_sample_rate(struct minstrel + if (sample_dur >= minstrel_get_duration(tp_rate2) && + (cur_max_tp_streams - 1 < + minstrel_mcs_groups[sample_group].streams || +- sample_dur >= minstrel_get_duration(mi->max_prob_rate))) { +- if (mrs->sample_skipped < 20) ++ sample_dur >= minstrel_get_duration(mi->max_prob_rate))) + return -1; + +- if (mi->sample_slow++ > 2) +- return -1; +- } + mi->sample_tries--; + + return sample_idx; +--- a/net/mac80211/rc80211_minstrel_ht.h ++++ b/net/mac80211/rc80211_minstrel_ht.h +@@ -123,7 +123,6 @@ struct minstrel_rate_stats { + u8 retry_count; + u8 retry_count_rtscts; + +- u8 sample_skipped; + bool retry_updated; + }; + +@@ -179,7 +178,6 @@ struct minstrel_ht_sta { + u8 sample_wait; + u8 sample_tries; + u8 sample_count; +- u8 sample_slow; + + enum minstrel_sample_mode sample_mode; + u16 sample_rate; diff --git a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch b/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch new file mode 100644 index 0000000000..6626804eb8 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch @@ -0,0 +1,767 @@ +From: Felix Fietkau +Date: Fri, 22 Jan 2021 23:57:50 +0100 +Subject: [PATCH] mac80211: minstrel_ht: significantly redesign the rate + probing strategy + +The biggest flaw in current minstrel_ht is the fact that it needs way too +many probing packets to be able to quickly find the best rate. +Depending on the wifi hardware and operating mode, this can significantly +reduce throughput when not operating at the highest available data rate. + +In order to be able to significantly reduce the amount of rate sampling, +we need a much smarter selection of probing rates. + +The new approach introduced by this patch maintains a limited set of +available rates to be tested during a statistics window. + +They are split into distinct categories: +- MINSTREL_SAMPLE_TYPE_INC - incremental rate upgrade: + Pick the next rate group and find the first rate that is faster than + the current max. throughput rate +- MINSTREL_SAMPLE_TYPE_JUMP - random testing of higher rates: + Pick a random rate from the next group that is faster than the current + max throughput rate. This allows faster adaptation when the link changes + significantly +- MINSTREL_SAMPLE_TYPE_SLOW - test a rate between max_prob, max_tp2 and + max_tp in order to reduce the gap between them + +In order to prioritize sampling, every 6 attempts are split into 3x INC, +2x JUMP, 1x SLOW. + +Available rates are checked and refilled on every stats window update. + +With this approach, we finally get a very small delta in throughput when +comparing setting the optimal data rate as a fixed rate vs normal rate +control operation. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -266,6 +266,14 @@ const struct mcs_group minstrel_mcs_grou + const s16 minstrel_cck_bitrates[4] = { 10, 20, 55, 110 }; + const s16 minstrel_ofdm_bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 }; + static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; ++static const u8 minstrel_sample_seq[] = { ++ MINSTREL_SAMPLE_TYPE_INC, ++ MINSTREL_SAMPLE_TYPE_JUMP, ++ MINSTREL_SAMPLE_TYPE_INC, ++ MINSTREL_SAMPLE_TYPE_JUMP, ++ MINSTREL_SAMPLE_TYPE_INC, ++ MINSTREL_SAMPLE_TYPE_SLOW, ++}; + + static void + minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); +@@ -620,77 +628,31 @@ minstrel_ht_prob_rate_reduce_streams(str + } + } + +-static bool +-minstrel_ht_probe_group(struct minstrel_ht_sta *mi, const struct mcs_group *tp_group, +- int tp_idx, const struct mcs_group *group) +-{ +- if (group->bw < tp_group->bw) +- return false; +- +- if (group->streams == tp_group->streams) +- return true; +- +- if (tp_idx < 4 && group->streams == tp_group->streams - 1) +- return true; +- +- return group->streams == tp_group->streams + 1; +-} +- +-static void +-minstrel_ht_find_probe_rates(struct minstrel_ht_sta *mi, u16 *rates, int *n_rates, +- bool faster_rate) ++static u16 ++__minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi, ++ enum minstrel_sample_type type) + { +- const struct mcs_group *group, *tp_group; +- int i, g, max_dur; +- int tp_idx; +- +- tp_group = &minstrel_mcs_groups[MI_RATE_GROUP(mi->max_tp_rate[0])]; +- tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]); +- +- max_dur = minstrel_get_duration(mi->max_tp_rate[0]); +- if (faster_rate) +- max_dur -= max_dur / 16; +- +- for (g = 0; g < MINSTREL_GROUPS_NB; g++) { +- u16 supported = mi->supported[g]; +- +- if (!supported) +- continue; ++ u16 *rates = mi->sample[type].sample_rates; ++ u16 cur; ++ int i; + +- group = &minstrel_mcs_groups[g]; +- if (!minstrel_ht_probe_group(mi, tp_group, tp_idx, group)) ++ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) { ++ if (!rates[i]) + continue; + +- for (i = 0; supported; supported >>= 1, i++) { +- int idx; +- +- if (!(supported & 1)) +- continue; +- +- if ((group->duration[i] << group->shift) > max_dur) +- continue; +- +- idx = MI_RATE(g, i); +- if (idx == mi->max_tp_rate[0]) +- continue; +- +- rates[(*n_rates)++] = idx; +- break; +- } ++ cur = rates[i]; ++ rates[i] = 0; ++ return cur; + } ++ ++ return 0; + } + + static void + minstrel_ht_rate_sample_switch(struct minstrel_priv *mp, + struct minstrel_ht_sta *mi) + { +- struct minstrel_rate_stats *mrs; +- u16 rates[MINSTREL_GROUPS_NB]; +- int n_rates = 0; +- int probe_rate = 0; +- bool faster_rate; +- int i; +- u8 random; ++ u16 rate; + + /* + * Use rate switching instead of probing packets for devices with +@@ -699,43 +661,11 @@ minstrel_ht_rate_sample_switch(struct mi + if (mp->hw->max_rates > 1) + return; + +- /* +- * If the current EWMA prob is >75%, look for a rate that's 6.25% +- * faster than the max tp rate. +- * If that fails, look again for a rate that is at least as fast +- */ +- mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); +- faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100); +- minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate); +- if (!n_rates && faster_rate) +- minstrel_ht_find_probe_rates(mi, rates, &n_rates, false); +- +- /* If no suitable rate was found, try to pick the next one in the group */ +- if (!n_rates) { +- int g_idx = MI_RATE_GROUP(mi->max_tp_rate[0]); +- u16 supported = mi->supported[g_idx]; +- +- supported >>= MI_RATE_IDX(mi->max_tp_rate[0]); +- for (i = 0; supported; supported >>= 1, i++) { +- if (!(supported & 1)) +- continue; +- +- probe_rate = mi->max_tp_rate[0] + i; +- goto out; +- } +- ++ rate = __minstrel_ht_get_sample_rate(mi, MINSTREL_SAMPLE_TYPE_INC); ++ if (!rate) + return; +- } + +- i = 0; +- if (n_rates > 1) { +- random = prandom_u32(); +- i = random % n_rates; +- } +- probe_rate = rates[i]; +- +-out: +- mi->sample_rate = probe_rate; ++ mi->sample_rate = rate; + mi->sample_mode = MINSTREL_SAMPLE_ACTIVE; + } + +@@ -804,6 +734,274 @@ minstrel_ht_calc_rate_stats(struct minst + mrs->attempts = 0; + } + ++static bool ++minstrel_ht_find_sample_rate(struct minstrel_ht_sta *mi, int type, int idx) ++{ ++ int i; ++ ++ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) { ++ u16 cur = mi->sample[type].sample_rates[i]; ++ ++ if (cur == idx) ++ return true; ++ ++ if (!cur) ++ break; ++ } ++ ++ return false; ++} ++ ++static int ++minstrel_ht_move_sample_rates(struct minstrel_ht_sta *mi, int type, ++ u32 fast_rate_dur, u32 slow_rate_dur) ++{ ++ u16 *rates = mi->sample[type].sample_rates; ++ int i, j; ++ ++ for (i = 0, j = 0; i < MINSTREL_SAMPLE_RATES; i++) { ++ u32 duration; ++ bool valid = false; ++ u16 cur; ++ ++ cur = rates[i]; ++ if (!cur) ++ continue; ++ ++ duration = minstrel_get_duration(cur); ++ switch (type) { ++ case MINSTREL_SAMPLE_TYPE_SLOW: ++ valid = duration > fast_rate_dur && ++ duration < slow_rate_dur; ++ break; ++ case MINSTREL_SAMPLE_TYPE_INC: ++ case MINSTREL_SAMPLE_TYPE_JUMP: ++ valid = duration < fast_rate_dur; ++ break; ++ default: ++ valid = false; ++ break; ++ } ++ ++ if (!valid) { ++ rates[i] = 0; ++ continue; ++ } ++ ++ if (i == j) ++ continue; ++ ++ rates[j++] = cur; ++ rates[i] = 0; ++ } ++ ++ return j; ++} ++ ++static int ++minstrel_ht_group_min_rate_offset(struct minstrel_ht_sta *mi, int group, ++ u32 max_duration) ++{ ++ u16 supported = mi->supported[group]; ++ int i; ++ ++ for (i = 0; i < MCS_GROUP_RATES && supported; i++, supported >>= 1) { ++ if (!(supported & BIT(0))) ++ continue; ++ ++ if (minstrel_get_duration(MI_RATE(group, i)) >= max_duration) ++ continue; ++ ++ return i; ++ } ++ ++ return -1; ++} ++ ++/* ++ * Incremental update rates: ++ * Flip through groups and pick the first group rate that is faster than the ++ * highest currently selected rate ++ */ ++static u16 ++minstrel_ht_next_inc_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur) ++{ ++ struct minstrel_mcs_group_data *mg; ++ u8 type = MINSTREL_SAMPLE_TYPE_INC; ++ int i, index = 0; ++ u8 group; ++ ++ group = mi->sample[type].sample_group; ++ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { ++ group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups); ++ mg = &mi->groups[group]; ++ ++ index = minstrel_ht_group_min_rate_offset(mi, group, ++ fast_rate_dur); ++ if (index < 0) ++ continue; ++ ++ index = MI_RATE(group, index & 0xf); ++ if (!minstrel_ht_find_sample_rate(mi, type, index)) ++ goto out; ++ } ++ index = 0; ++ ++out: ++ mi->sample[type].sample_group = group; ++ ++ return index; ++} ++ ++static int ++minstrel_ht_next_group_sample_rate(struct minstrel_ht_sta *mi, int group, ++ u16 supported, int offset) ++{ ++ struct minstrel_mcs_group_data *mg = &mi->groups[group]; ++ u16 idx; ++ int i; ++ ++ for (i = 0; i < MCS_GROUP_RATES; i++) { ++ idx = sample_table[mg->column][mg->index]; ++ if (++mg->index >= MCS_GROUP_RATES) { ++ mg->index = 0; ++ if (++mg->column >= ARRAY_SIZE(sample_table)) ++ mg->column = 0; ++ } ++ ++ if (idx < offset) ++ continue; ++ ++ if (!(supported & BIT(idx))) ++ continue; ++ ++ return MI_RATE(group, idx); ++ } ++ ++ return -1; ++} ++ ++/* ++ * Jump rates: ++ * Sample random rates, use those that are faster than the highest ++ * currently selected rate. Rates between the fastest and the slowest ++ * get sorted into the slow sample bucket, but only if it has room ++ */ ++static u16 ++minstrel_ht_next_jump_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur, ++ u32 slow_rate_dur, int *slow_rate_ofs) ++{ ++ struct minstrel_mcs_group_data *mg; ++ struct minstrel_rate_stats *mrs; ++ u32 max_duration = slow_rate_dur; ++ int i, index, offset; ++ u16 *slow_rates; ++ u16 supported; ++ u32 duration; ++ u8 group; ++ ++ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) ++ max_duration = fast_rate_dur; ++ ++ slow_rates = mi->sample[MINSTREL_SAMPLE_TYPE_SLOW].sample_rates; ++ group = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group; ++ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { ++ u8 type; ++ ++ group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups); ++ mg = &mi->groups[group]; ++ ++ supported = mi->supported[group]; ++ if (!supported) ++ continue; ++ ++ offset = minstrel_ht_group_min_rate_offset(mi, group, ++ max_duration); ++ if (offset < 0) ++ continue; ++ ++ index = minstrel_ht_next_group_sample_rate(mi, group, supported, ++ offset); ++ if (index < 0) ++ continue; ++ ++ duration = minstrel_get_duration(index); ++ if (duration < fast_rate_dur) ++ type = MINSTREL_SAMPLE_TYPE_JUMP; ++ else ++ type = MINSTREL_SAMPLE_TYPE_SLOW; ++ ++ if (minstrel_ht_find_sample_rate(mi, type, index)) ++ continue; ++ ++ if (type == MINSTREL_SAMPLE_TYPE_JUMP) ++ goto found; ++ ++ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) ++ continue; ++ ++ if (duration >= slow_rate_dur) ++ continue; ++ ++ /* skip slow rates with high success probability */ ++ mrs = minstrel_get_ratestats(mi, index); ++ if (mrs->prob_avg > MINSTREL_FRAC(95, 100)) ++ continue; ++ ++ slow_rates[(*slow_rate_ofs)++] = index; ++ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) ++ max_duration = fast_rate_dur; ++ } ++ index = 0; ++ ++found: ++ mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group = group; ++ ++ return index; ++} ++ ++static void ++minstrel_ht_refill_sample_rates(struct minstrel_ht_sta *mi) ++{ ++ u32 prob_dur = minstrel_get_duration(mi->max_prob_rate); ++ u32 tp_dur = minstrel_get_duration(mi->max_tp_rate[0]); ++ u32 tp2_dur = minstrel_get_duration(mi->max_tp_rate[1]); ++ u32 fast_rate_dur = min(min(tp_dur, tp2_dur), prob_dur); ++ u32 slow_rate_dur = max(max(tp_dur, tp2_dur), prob_dur); ++ u16 *rates; ++ int i, j; ++ ++ rates = mi->sample[MINSTREL_SAMPLE_TYPE_INC].sample_rates; ++ i = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_INC, ++ fast_rate_dur, slow_rate_dur); ++ while (i < MINSTREL_SAMPLE_RATES) { ++ rates[i] = minstrel_ht_next_inc_rate(mi, tp_dur); ++ if (!rates[i]) ++ break; ++ ++ i++; ++ } ++ ++ rates = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_rates; ++ i = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_JUMP, ++ fast_rate_dur, slow_rate_dur); ++ j = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_SLOW, ++ fast_rate_dur, slow_rate_dur); ++ while (i < MINSTREL_SAMPLE_RATES) { ++ rates[i] = minstrel_ht_next_jump_rate(mi, fast_rate_dur, ++ slow_rate_dur, &j); ++ if (!rates[i]) ++ break; ++ ++ i++; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(mi->sample); i++) ++ memcpy(mi->sample[i].cur_sample_rates, mi->sample[i].sample_rates, ++ sizeof(mi->sample[i].cur_sample_rates)); ++} ++ ++ + /* + * Update rate statistics and select new primary rates + * +@@ -848,8 +1046,6 @@ minstrel_ht_update_stats(struct minstrel + mi->ampdu_packets = 0; + } + +- mi->sample_count = 0; +- + memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); + memset(tmp_legacy_tp_rate, 0, sizeof(tmp_legacy_tp_rate)); + +@@ -885,8 +1081,6 @@ minstrel_ht_update_stats(struct minstrel + if (!mi->supported[group]) + continue; + +- mi->sample_count++; +- + /* (re)Initialize group rate indexes */ + for(j = 0; j < MAX_THR_RATES; j++) + tmp_group_tp_rate[j] = MI_RATE(group, 0); +@@ -953,9 +1147,7 @@ minstrel_ht_update_stats(struct minstrel + + /* Try to increase robustness of max_prob_rate*/ + minstrel_ht_prob_rate_reduce_streams(mi); +- +- /* try to sample half of all available rates during each interval */ +- mi->sample_count *= 4; ++ minstrel_ht_refill_sample_rates(mi); + + if (sample) + minstrel_ht_rate_sample_switch(mp, mi); +@@ -972,6 +1164,7 @@ minstrel_ht_update_stats(struct minstrel + + /* Reset update timer */ + mi->last_stats_update = jiffies; ++ mi->sample_time = jiffies; + } + + static bool +@@ -1002,28 +1195,6 @@ minstrel_ht_txstat_valid(struct minstrel + } + + static void +-minstrel_set_next_sample_idx(struct minstrel_ht_sta *mi) +-{ +- struct minstrel_mcs_group_data *mg; +- +- for (;;) { +- mi->sample_group++; +- mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups); +- mg = &mi->groups[mi->sample_group]; +- +- if (!mi->supported[mi->sample_group]) +- continue; +- +- if (++mg->index >= MCS_GROUP_RATES) { +- mg->index = 0; +- if (++mg->column >= ARRAY_SIZE(sample_table)) +- mg->column = 0; +- } +- break; +- } +-} +- +-static void + minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) + { + int group, orig_group; +@@ -1108,14 +1279,6 @@ minstrel_ht_tx_status(void *priv, struct + mi->ampdu_packets++; + mi->ampdu_len += info->status.ampdu_len; + +- if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { +- int avg_ampdu_len = minstrel_ht_avg_ampdu_len(mi); +- +- mi->sample_wait = 16 + 2 * avg_ampdu_len; +- mi->sample_tries = 1; +- mi->sample_count--; +- } +- + if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) + rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); + +@@ -1387,97 +1550,20 @@ minstrel_ht_update_rates(struct minstrel + rate_control_set_rates(mp->hw, mi->sta, rates); + } + +-static int +-minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) ++static u16 ++minstrel_ht_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) + { +- struct minstrel_rate_stats *mrs; +- struct minstrel_mcs_group_data *mg; +- unsigned int sample_dur, sample_group, cur_max_tp_streams; +- int tp_rate1, tp_rate2; +- int sample_idx = 0; +- +- if (mp->hw->max_rates == 1 && mp->sample_switch && +- (mi->total_packets_cur >= SAMPLE_SWITCH_THR || +- mp->sample_switch == 1)) +- return -1; +- +- if (mi->sample_wait > 0) { +- mi->sample_wait--; +- return -1; +- } +- +- if (!mi->sample_tries) +- return -1; +- +- sample_group = mi->sample_group; +- mg = &mi->groups[sample_group]; +- sample_idx = sample_table[mg->column][mg->index]; +- minstrel_set_next_sample_idx(mi); +- +- if (!(mi->supported[sample_group] & BIT(sample_idx))) +- return -1; +- +- mrs = &mg->rates[sample_idx]; +- sample_idx += MI_RATE(sample_group, 0); +- +- tp_rate1 = mi->max_tp_rate[0]; ++ u8 seq; + +- /* Set tp_rate2 to the second highest max_tp_rate */ +- if (minstrel_get_duration(mi->max_tp_rate[0]) > +- minstrel_get_duration(mi->max_tp_rate[1])) { +- tp_rate2 = mi->max_tp_rate[0]; ++ if (mp->hw->max_rates > 1) { ++ seq = mi->sample_seq; ++ mi->sample_seq = (seq + 1) % ARRAY_SIZE(minstrel_sample_seq); ++ seq = minstrel_sample_seq[seq]; + } else { +- tp_rate2 = mi->max_tp_rate[1]; ++ seq = MINSTREL_SAMPLE_TYPE_INC; + } + +- /* +- * Sampling might add some overhead (RTS, no aggregation) +- * to the frame. Hence, don't use sampling for the highest currently +- * used highest throughput or probability rate. +- */ +- if (sample_idx == mi->max_tp_rate[0] || sample_idx == mi->max_prob_rate) +- return -1; +- +- /* +- * Do not sample if the probability is already higher than 95%, +- * or if the rate is 3 times slower than the current max probability +- * rate, to avoid wasting airtime. +- */ +- sample_dur = minstrel_get_duration(sample_idx); +- if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || +- minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur) +- return -1; +- +- +- /* +- * For devices with no configurable multi-rate retry, skip sampling +- * below the per-group max throughput rate, and only use one sampling +- * attempt per rate +- */ +- if (mp->hw->max_rates == 1 && +- (minstrel_get_duration(mg->max_group_tp_rate[0]) < sample_dur || +- mrs->attempts)) +- return -1; +- +- /* Skip already sampled slow rates */ +- if (sample_dur >= minstrel_get_duration(tp_rate1) && mrs->attempts) +- return -1; +- +- /* +- * Make sure that lower rates get sampled only occasionally, +- * if the link is working perfectly. +- */ +- +- cur_max_tp_streams = minstrel_mcs_groups[MI_RATE_GROUP(tp_rate1)].streams; +- if (sample_dur >= minstrel_get_duration(tp_rate2) && +- (cur_max_tp_streams - 1 < +- minstrel_mcs_groups[sample_group].streams || +- sample_dur >= minstrel_get_duration(mi->max_prob_rate))) +- return -1; +- +- mi->sample_tries--; +- +- return sample_idx; ++ return __minstrel_ht_get_sample_rate(mi, seq); + } + + static void +@@ -1489,7 +1575,7 @@ minstrel_ht_get_rate(void *priv, struct + struct ieee80211_tx_rate *rate = &info->status.rates[0]; + struct minstrel_ht_sta *mi = priv_sta; + struct minstrel_priv *mp = priv; +- int sample_idx; ++ u16 sample_idx; + + if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && + !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate))) +@@ -1505,11 +1591,19 @@ minstrel_ht_get_rate(void *priv, struct + /* Don't use EAPOL frames for sampling on non-mrr hw */ + if (mp->hw->max_rates == 1 && + (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) +- sample_idx = -1; +- else +- sample_idx = minstrel_get_sample_rate(mp, mi); ++ return; + +- if (sample_idx < 0) ++ if (mp->hw->max_rates == 1 && mp->sample_switch && ++ (mi->total_packets_cur >= SAMPLE_SWITCH_THR || ++ mp->sample_switch == 1)) ++ return; ++ ++ if (time_is_before_jiffies(mi->sample_time)) ++ return; ++ ++ mi->sample_time = jiffies + MINSTREL_SAMPLE_INTERVAL; ++ sample_idx = minstrel_ht_get_sample_rate(mp, mi); ++ if (!sample_idx) + return; + + sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)]; +@@ -1630,16 +1724,6 @@ minstrel_ht_update_caps(void *priv, stru + + mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); + +- /* When using MRR, sample more on the first attempt, without delay */ +- if (mp->has_mrr) { +- mi->sample_count = 16; +- mi->sample_wait = 0; +- } else { +- mi->sample_count = 8; +- mi->sample_wait = 8; +- } +- mi->sample_tries = 4; +- + if (!use_vht) { + stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >> + IEEE80211_HT_CAP_RX_STBC_SHIFT; +--- a/net/mac80211/rc80211_minstrel_ht.h ++++ b/net/mac80211/rc80211_minstrel_ht.h +@@ -69,6 +69,8 @@ + #define MI_RATE_IDX(_rate) FIELD_GET(MI_RATE_IDX_MASK, _rate) + #define MI_RATE_GROUP(_rate) FIELD_GET(MI_RATE_GROUP_MASK, _rate) + ++#define MINSTREL_SAMPLE_RATES 5 /* rates per sample type */ ++#define MINSTREL_SAMPLE_INTERVAL (HZ / 50) + + struct minstrel_priv { + struct ieee80211_hw *hw; +@@ -126,6 +128,13 @@ struct minstrel_rate_stats { + bool retry_updated; + }; + ++enum minstrel_sample_type { ++ MINSTREL_SAMPLE_TYPE_INC, ++ MINSTREL_SAMPLE_TYPE_JUMP, ++ MINSTREL_SAMPLE_TYPE_SLOW, ++ __MINSTREL_SAMPLE_TYPE_MAX ++}; ++ + struct minstrel_mcs_group_data { + u8 index; + u8 column; +@@ -144,6 +153,12 @@ enum minstrel_sample_mode { + MINSTREL_SAMPLE_PENDING, + }; + ++struct minstrel_sample_category { ++ u8 sample_group; ++ u16 sample_rates[MINSTREL_SAMPLE_RATES]; ++ u16 cur_sample_rates[MINSTREL_SAMPLE_RATES]; ++}; ++ + struct minstrel_ht_sta { + struct ieee80211_sta *sta; + +@@ -175,16 +190,14 @@ struct minstrel_ht_sta { + /* tx flags to add for frames for this sta */ + u32 tx_flags; + +- u8 sample_wait; +- u8 sample_tries; +- u8 sample_count; ++ unsigned long sample_time; ++ struct minstrel_sample_category sample[__MINSTREL_SAMPLE_TYPE_MAX]; ++ ++ u8 sample_seq; + + enum minstrel_sample_mode sample_mode; + u16 sample_rate; + +- /* current MCS group to be sampled */ +- u8 sample_group; +- + u8 band; + + /* Bitfield of supported MCS rates of all groups */ diff --git a/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch b/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch new file mode 100644 index 0000000000..41910e0d18 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch @@ -0,0 +1,59 @@ +From: Felix Fietkau +Date: Sat, 23 Jan 2021 00:10:34 +0100 +Subject: [PATCH] mac80211: minstrel_ht: show sampling rates in debugfs + +This makes it easier to see what rates are going to be tested next + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c ++++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c +@@ -32,6 +32,18 @@ minstrel_stats_release(struct inode *ino + return 0; + } + ++static bool ++minstrel_ht_is_sample_rate(struct minstrel_ht_sta *mi, int idx) ++{ ++ int type, i; ++ ++ for (type = 0; type < ARRAY_SIZE(mi->sample); type++) ++ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) ++ if (mi->sample[type].cur_sample_rates[i] == idx) ++ return true; ++ return false; ++} ++ + static char * + minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) + { +@@ -84,6 +96,7 @@ minstrel_ht_stats_dump(struct minstrel_h + *(p++) = (idx == mi->max_tp_rate[2]) ? 'C' : ' '; + *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; + *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; ++ *(p++) = minstrel_ht_is_sample_rate(mi, idx) ? 'S' : ' '; + + if (gflags & IEEE80211_TX_RC_MCS) { + p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); +@@ -145,9 +158,9 @@ minstrel_ht_stats_open(struct inode *ino + + p += sprintf(p, "\n"); + p += sprintf(p, +- " best ____________rate__________ ____statistics___ _____last____ ______sum-of________\n"); ++ " best ____________rate__________ ____statistics___ _____last____ ______sum-of________\n"); + p += sprintf(p, +- "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); ++ "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); + + p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); + for (i = 0; i < MINSTREL_CCK_GROUP; i++) +@@ -228,6 +241,8 @@ minstrel_ht_stats_csv_dump(struct minstr + p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[2]) ? "C" : "")); + p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[3]) ? "D" : "")); + p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : "")); ++ p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : "")); ++ p += sprintf(p, "%s", (minstrel_ht_is_sample_rate(mi, idx) ? "S" : "")); + + if (gflags & IEEE80211_TX_RC_MCS) { + p += sprintf(p, ",MCS%-2u,", (mg->streams - 1) * 8 + j); diff --git a/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch b/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch new file mode 100644 index 0000000000..64bd59b852 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch @@ -0,0 +1,279 @@ +From: Felix Fietkau +Date: Sat, 23 Jan 2021 07:18:26 +0100 +Subject: [PATCH] mac80211: minstrel_ht: remove sample rate switching code for + constrained devices + +This was added to mitigate the effects of too much sampling on devices that +use a static global fallback table instead of configurable multi-rate retry. +Now that the sampling algorithm is improved, this code path no longer performs +any better than the standard probing on affected devices. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -648,27 +648,6 @@ __minstrel_ht_get_sample_rate(struct min + return 0; + } + +-static void +-minstrel_ht_rate_sample_switch(struct minstrel_priv *mp, +- struct minstrel_ht_sta *mi) +-{ +- u16 rate; +- +- /* +- * Use rate switching instead of probing packets for devices with +- * little control over retry fallback behavior +- */ +- if (mp->hw->max_rates > 1) +- return; +- +- rate = __minstrel_ht_get_sample_rate(mi, MINSTREL_SAMPLE_TYPE_INC); +- if (!rate) +- return; +- +- mi->sample_rate = rate; +- mi->sample_mode = MINSTREL_SAMPLE_ACTIVE; +-} +- + static inline int + minstrel_ewma(int old, int new, int weight) + { +@@ -1012,8 +991,7 @@ minstrel_ht_refill_sample_rates(struct m + * higher throughput rates, even if the probablity is a bit lower + */ + static void +-minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, +- bool sample) ++minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) + { + struct minstrel_mcs_group_data *mg; + struct minstrel_rate_stats *mrs; +@@ -1023,18 +1001,6 @@ minstrel_ht_update_stats(struct minstrel + u16 index; + bool ht_supported = mi->sta->ht_cap.ht_supported; + +- mi->sample_mode = MINSTREL_SAMPLE_IDLE; +- +- if (sample) { +- mi->total_packets_cur = mi->total_packets - +- mi->total_packets_last; +- mi->total_packets_last = mi->total_packets; +- } +- if (!mp->sample_switch) +- sample = false; +- if (mi->total_packets_cur < SAMPLE_SWITCH_THR && mp->sample_switch != 1) +- sample = false; +- + if (mi->ampdu_packets > 0) { + if (!ieee80211_hw_check(mp->hw, TX_STATUS_NO_AMPDU_LEN)) + mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, +@@ -1149,16 +1115,12 @@ minstrel_ht_update_stats(struct minstrel + minstrel_ht_prob_rate_reduce_streams(mi); + minstrel_ht_refill_sample_rates(mi); + +- if (sample) +- minstrel_ht_rate_sample_switch(mp, mi); +- + #ifdef CPTCFG_MAC80211_DEBUGFS + /* use fixed index if set */ + if (mp->fixed_rate_idx != -1) { + for (i = 0; i < 4; i++) + mi->max_tp_rate[i] = mp->fixed_rate_idx; + mi->max_prob_rate = mp->fixed_rate_idx; +- mi->sample_mode = MINSTREL_SAMPLE_IDLE; + } + #endif + +@@ -1248,11 +1210,10 @@ minstrel_ht_tx_status(void *priv, struct + struct ieee80211_tx_info *info = st->info; + struct minstrel_ht_sta *mi = priv_sta; + struct ieee80211_tx_rate *ar = info->status.rates; +- struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL; ++ struct minstrel_rate_stats *rate, *rate2; + struct minstrel_priv *mp = priv; + u32 update_interval = mp->update_interval; + bool last, update = false; +- bool sample_status = false; + int i; + + /* This packet was aggregated but doesn't carry status info */ +@@ -1279,49 +1240,18 @@ minstrel_ht_tx_status(void *priv, struct + mi->ampdu_packets++; + mi->ampdu_len += info->status.ampdu_len; + +- if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) +- rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); +- + last = !minstrel_ht_txstat_valid(mp, mi, &ar[0]); + for (i = 0; !last; i++) { + last = (i == IEEE80211_TX_MAX_RATES - 1) || + !minstrel_ht_txstat_valid(mp, mi, &ar[i + 1]); + + rate = minstrel_ht_get_stats(mp, mi, &ar[i]); +- if (rate == rate_sample) +- sample_status = true; +- + if (last) + rate->success += info->status.ampdu_ack_len; + + rate->attempts += ar[i].count * info->status.ampdu_len; + } + +- switch (mi->sample_mode) { +- case MINSTREL_SAMPLE_IDLE: +- if (mp->hw->max_rates > 1 || +- mi->total_packets_cur < SAMPLE_SWITCH_THR) +- update_interval /= 2; +- break; +- +- case MINSTREL_SAMPLE_ACTIVE: +- if (!sample_status) +- break; +- +- mi->sample_mode = MINSTREL_SAMPLE_PENDING; +- update = true; +- break; +- +- case MINSTREL_SAMPLE_PENDING: +- if (sample_status) +- break; +- +- update = true; +- minstrel_ht_update_stats(mp, mi, false); +- break; +- } +- +- + if (mp->hw->max_rates > 1) { + /* + * check for sudden death of spatial multiplexing, +@@ -1344,7 +1274,7 @@ minstrel_ht_tx_status(void *priv, struct + + if (time_after(jiffies, mi->last_stats_update + update_interval)) { + update = true; +- minstrel_ht_update_stats(mp, mi, true); ++ minstrel_ht_update_stats(mp, mi); + } + + if (update) +@@ -1523,18 +1453,14 @@ static void + minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) + { + struct ieee80211_sta_rates *rates; +- u16 first_rate = mi->max_tp_rate[0]; + int i = 0; + +- if (mi->sample_mode == MINSTREL_SAMPLE_ACTIVE) +- first_rate = mi->sample_rate; +- + rates = kzalloc(sizeof(*rates), GFP_ATOMIC); + if (!rates) + return; + + /* Start with max_tp_rate[0] */ +- minstrel_ht_set_rate(mp, mi, rates, i++, first_rate); ++ minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]); + + if (mp->hw->max_rates >= 3) { + /* At least 3 tx rates supported, use max_tp_rate[1] next */ +@@ -1593,11 +1519,6 @@ minstrel_ht_get_rate(void *priv, struct + (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) + return; + +- if (mp->hw->max_rates == 1 && mp->sample_switch && +- (mi->total_packets_cur >= SAMPLE_SWITCH_THR || +- mp->sample_switch == 1)) +- return; +- + if (time_is_before_jiffies(mi->sample_time)) + return; + +@@ -1811,7 +1732,7 @@ minstrel_ht_update_caps(void *priv, stru + minstrel_ht_update_ofdm(mp, mi, sband, sta); + + /* create an initial rate table with the lowest supported rates */ +- minstrel_ht_update_stats(mp, mi, true); ++ minstrel_ht_update_stats(mp, mi); + minstrel_ht_update_rates(mp, mi); + } + +@@ -1927,8 +1848,6 @@ minstrel_ht_alloc(struct ieee80211_hw *h + if (!mp) + return NULL; + +- mp->sample_switch = -1; +- + /* contention window settings + * Just an approximation. Using the per-queue values would complicate + * the calculations and is probably unnecessary */ +@@ -1948,7 +1867,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h + mp->has_mrr = true; + + mp->hw = hw; +- mp->update_interval = HZ / 10; ++ mp->update_interval = HZ / 20; + + minstrel_ht_init_cck_rates(mp); + for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++) +@@ -1966,8 +1885,6 @@ static void minstrel_ht_add_debugfs(stru + mp->fixed_rate_idx = (u32) -1; + debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, + &mp->fixed_rate_idx); +- debugfs_create_u32("sample_switch", S_IRUGO | S_IWUSR, debugfsdir, +- &mp->sample_switch); + } + #endif + +--- a/net/mac80211/rc80211_minstrel_ht.h ++++ b/net/mac80211/rc80211_minstrel_ht.h +@@ -75,7 +75,6 @@ + struct minstrel_priv { + struct ieee80211_hw *hw; + bool has_mrr; +- u32 sample_switch; + unsigned int cw_min; + unsigned int cw_max; + unsigned int max_retry; +@@ -147,12 +146,6 @@ struct minstrel_mcs_group_data { + struct minstrel_rate_stats rates[MCS_GROUP_RATES]; + }; + +-enum minstrel_sample_mode { +- MINSTREL_SAMPLE_IDLE, +- MINSTREL_SAMPLE_ACTIVE, +- MINSTREL_SAMPLE_PENDING, +-}; +- + struct minstrel_sample_category { + u8 sample_group; + u16 sample_rates[MINSTREL_SAMPLE_RATES]; +@@ -182,23 +175,19 @@ struct minstrel_ht_sta { + unsigned int overhead_legacy; + unsigned int overhead_legacy_rtscts; + +- unsigned int total_packets_last; +- unsigned int total_packets_cur; + unsigned int total_packets; + unsigned int sample_packets; + + /* tx flags to add for frames for this sta */ + u32 tx_flags; + +- unsigned long sample_time; +- struct minstrel_sample_category sample[__MINSTREL_SAMPLE_TYPE_MAX]; ++ u8 band; + + u8 sample_seq; +- +- enum minstrel_sample_mode sample_mode; + u16 sample_rate; + +- u8 band; ++ unsigned long sample_time; ++ struct minstrel_sample_category sample[__MINSTREL_SAMPLE_TYPE_MAX]; + + /* Bitfield of supported MCS rates of all groups */ + u16 supported[MINSTREL_GROUPS_NB]; From b67d086ef33ecd0f96075203ef5c766581b6c1b9 Mon Sep 17 00:00:00 2001 From: Tony Ambardar Date: Mon, 27 Jul 2020 04:36:21 -0700 Subject: [PATCH 05/29] malta: update target configs and fix build warnings Comment out some conflicting target configs that are set from subtarget configs, which sometimes lead to kernel compile warnings: scripts/kconfig/conf --syncconfig Kconfig net/sched/Kconfig:45: warning: menuconfig statement without prompt .config:1038:warning: override: CPU_MIPS32_R2 changes choice state Signed-off-by: Tony Ambardar --- target/linux/malta/config-5.4 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/linux/malta/config-5.4 b/target/linux/malta/config-5.4 index d480e1de42..2611343f3f 100644 --- a/target/linux/malta/config-5.4 +++ b/target/linux/malta/config-5.4 @@ -56,7 +56,7 @@ CONFIG_CPU_HAS_PREFETCH=y # CONFIG_CPU_HAS_SMARTMIPS is not set CONFIG_CPU_HAS_SYNC=y # CONFIG_CPU_MICROMIPS is not set -CONFIG_CPU_MIPS32=y +# CONFIG_CPU_MIPS32 is not set # CONFIG_CPU_MIPS32_3_5_FEATURES is not set # CONFIG_CPU_MIPS32_R1 is not set # CONFIG_CPU_MIPS32_R2 is not set @@ -65,9 +65,9 @@ CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS64_R2 is not set # CONFIG_CPU_MIPS32_R5_FEATURES is not set # CONFIG_CPU_MIPS64_R6 is not set -CONFIG_CPU_MIPSR1=y -CONFIG_CPU_MIPSR2_IRQ_EI=y -CONFIG_CPU_MIPSR2_IRQ_VI=y +# CONFIG_CPU_MIPSR2 is not set +# CONFIG_CPU_MIPSR2_IRQ_EI is not set +# CONFIG_CPU_MIPSR2_IRQ_VI is not set CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y # CONFIG_CPU_NEVADA is not set CONFIG_CPU_R4K_CACHE_TLB=y From af20332dec3f1ac024cd240f33b065a1928cc6c2 Mon Sep 17 00:00:00 2001 From: Tony Ambardar Date: Wed, 21 Oct 2020 09:24:33 -0700 Subject: [PATCH 06/29] config: drop CONFIG_KPROBE_EVENT unused since kernel 4.9 The config setting was renamed to CONFIG_KPROBE_EVENTS. Fixes: 97d3f800a8 ("config: kernel: Add KPROBE_EVENTS config option) Signed-off-by: Tony Ambardar --- config/Config-kernel.in | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/Config-kernel.in b/config/Config-kernel.in index 8a78e297cb..3350558adb 100644 --- a/config/Config-kernel.in +++ b/config/Config-kernel.in @@ -365,10 +365,6 @@ config KERNEL_KPROBES instrumentation and testing. If in doubt, say "N". -config KERNEL_KPROBE_EVENT - bool - default y if KERNEL_KPROBES - config KERNEL_KPROBE_EVENTS bool default y if KERNEL_KPROBES From 0faa17235669da7f8a7cd7ab922a77b06d6d230a Mon Sep 17 00:00:00 2001 From: Tony Ambardar Date: Wed, 21 Oct 2020 09:13:45 -0700 Subject: [PATCH 07/29] config: limit CONFIG_PERF_EVENTS to top-level generic configs Remove redundant target-level settings. Signed-off-by: Tony Ambardar --- target/linux/archs38/config-5.4 | 1 - target/linux/ipq807x/config-default | 1 - target/linux/layerscape/armv7/config-5.4 | 1 - target/linux/layerscape/armv8_64b/config-5.4 | 1 - target/linux/malta/config-5.4 | 1 - target/linux/mediatek/mt7622/config-5.4 | 1 - target/linux/mediatek/mt7629/config-5.4 | 1 - target/linux/oxnas/config-5.4 | 1 - target/linux/sunxi/config-5.4 | 1 - target/linux/x86/config-5.4 | 1 - target/linux/zynq/config-5.4 | 1 - 11 files changed, 11 deletions(-) diff --git a/target/linux/archs38/config-5.4 b/target/linux/archs38/config-5.4 index d98ba4ce32..57d708e77a 100644 --- a/target/linux/archs38/config-5.4 +++ b/target/linux/archs38/config-5.4 @@ -217,7 +217,6 @@ CONFIG_OF_MDIO=y CONFIG_OF_NET=y CONFIG_PADATA=y CONFIG_PAGE_POOL=y -CONFIG_PERF_EVENTS=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y CONFIG_PHYLINK=y diff --git a/target/linux/ipq807x/config-default b/target/linux/ipq807x/config-default index 9ee84791a1..24f99f4219 100644 --- a/target/linux/ipq807x/config-default +++ b/target/linux/ipq807x/config-default @@ -459,7 +459,6 @@ CONFIG_PCI_DOMAINS_GENERIC=y CONFIG_PCI_LABEL=y CONFIG_PCI_MSI=y CONFIG_PCI_MSI_IRQ_DOMAIN=y -CONFIG_PERF_EVENTS=y CONFIG_PGTABLE_LEVELS=3 CONFIG_PHYLIB=y CONFIG_PHYS_ADDR_T_64BIT=y diff --git a/target/linux/layerscape/armv7/config-5.4 b/target/linux/layerscape/armv7/config-5.4 index 019119d6db..ba64e8fdda 100644 --- a/target/linux/layerscape/armv7/config-5.4 +++ b/target/linux/layerscape/armv7/config-5.4 @@ -549,7 +549,6 @@ CONFIG_PCI_HOST_GENERIC=y CONFIG_PCI_LAYERSCAPE=y CONFIG_PCI_MSI=y CONFIG_PCI_MSI_IRQ_DOMAIN=y -CONFIG_PERF_EVENTS=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=3 CONFIG_PHYLIB=y diff --git a/target/linux/layerscape/armv8_64b/config-5.4 b/target/linux/layerscape/armv8_64b/config-5.4 index cd8ea82e52..75f31e2bc4 100644 --- a/target/linux/layerscape/armv8_64b/config-5.4 +++ b/target/linux/layerscape/armv8_64b/config-5.4 @@ -740,7 +740,6 @@ CONFIG_PCI_IOV=y CONFIG_PCI_LAYERSCAPE=y CONFIG_PCI_MSI=y CONFIG_PCI_MSI_IRQ_DOMAIN=y -CONFIG_PERF_EVENTS=y CONFIG_PGTABLE_LEVELS=4 CONFIG_PHYLIB=y CONFIG_PHYS_ADDR_T_64BIT=y diff --git a/target/linux/malta/config-5.4 b/target/linux/malta/config-5.4 index 2611343f3f..73f6965d01 100644 --- a/target/linux/malta/config-5.4 +++ b/target/linux/malta/config-5.4 @@ -253,7 +253,6 @@ CONFIG_PCI_DOMAINS=y CONFIG_PCI_DRIVERS_LEGACY=y CONFIG_PCI_GT64XXX_PCI0=y CONFIG_PCSPKR_PLATFORM=y -CONFIG_PERF_EVENTS=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_POWER_RESET=y diff --git a/target/linux/mediatek/mt7622/config-5.4 b/target/linux/mediatek/mt7622/config-5.4 index 929a04ce07..ffebc43cb2 100644 --- a/target/linux/mediatek/mt7622/config-5.4 +++ b/target/linux/mediatek/mt7622/config-5.4 @@ -458,7 +458,6 @@ CONFIG_PCI_DOMAINS=y CONFIG_PCI_DOMAINS_GENERIC=y CONFIG_PCI_MSI=y CONFIG_PCI_MSI_IRQ_DOMAIN=y -CONFIG_PERF_EVENTS=y CONFIG_PGTABLE_LEVELS=3 CONFIG_PHYLIB=y CONFIG_PHYLINK=y diff --git a/target/linux/mediatek/mt7629/config-5.4 b/target/linux/mediatek/mt7629/config-5.4 index 7dd04b4e2e..82ef4996af 100644 --- a/target/linux/mediatek/mt7629/config-5.4 +++ b/target/linux/mediatek/mt7629/config-5.4 @@ -290,7 +290,6 @@ CONFIG_PCI_DOMAINS=y CONFIG_PCI_DOMAINS_GENERIC=y CONFIG_PCI_MSI=y CONFIG_PCI_MSI_IRQ_DOMAIN=y -CONFIG_PERF_EVENTS=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y diff --git a/target/linux/oxnas/config-5.4 b/target/linux/oxnas/config-5.4 index d8c87acabf..ed6f03d388 100644 --- a/target/linux/oxnas/config-5.4 +++ b/target/linux/oxnas/config-5.4 @@ -267,7 +267,6 @@ CONFIG_PAGE_POOL=y # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 CONFIG_PANIC_TIMEOUT=0 -CONFIG_PERF_EVENTS=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y diff --git a/target/linux/sunxi/config-5.4 b/target/linux/sunxi/config-5.4 index d34cb4c7ae..7318d5a3e9 100644 --- a/target/linux/sunxi/config-5.4 +++ b/target/linux/sunxi/config-5.4 @@ -396,7 +396,6 @@ CONFIG_PADATA=y CONFIG_PAGE_OFFSET=0xC0000000 CONFIG_PAGE_POOL=y CONFIG_PARTITION_PERCPU=y -CONFIG_PERF_EVENTS=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=3 CONFIG_PHYLIB=y diff --git a/target/linux/x86/config-5.4 b/target/linux/x86/config-5.4 index 83d9cf2e05..f26c20c59d 100644 --- a/target/linux/x86/config-5.4 +++ b/target/linux/x86/config-5.4 @@ -388,7 +388,6 @@ CONFIG_PCI_LOCKLESS_CONFIG=y CONFIG_PCI_MSI=y CONFIG_PCI_MSI_IRQ_DOMAIN=y CONFIG_PCSPKR_PLATFORM=y -CONFIG_PERF_EVENTS=y CONFIG_PERF_EVENTS_INTEL_CSTATE=y CONFIG_PERF_EVENTS_INTEL_RAPL=y CONFIG_PERF_EVENTS_INTEL_UNCORE=y diff --git a/target/linux/zynq/config-5.4 b/target/linux/zynq/config-5.4 index 258c3e14b4..38a6dae36a 100644 --- a/target/linux/zynq/config-5.4 +++ b/target/linux/zynq/config-5.4 @@ -486,7 +486,6 @@ CONFIG_PCI_DOMAINS=y CONFIG_PCI_DOMAINS_GENERIC=y CONFIG_PCI_MSI=y CONFIG_PCI_MSI_IRQ_DOMAIN=y -CONFIG_PERF_EVENTS=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y From 23be333401f06a49d7081b051b2cdf84f8a75149 Mon Sep 17 00:00:00 2001 From: Tony Ambardar Date: Mon, 14 Dec 2020 21:39:19 -0800 Subject: [PATCH 08/29] bpftools: update to 5.10.10 Use the latest stable kernel since the previous 5.8.x series is EOL. Also drop the following patches recently accepted upstream: * 001-libbpf-ensure-no-local-symbols-counted-in-ABI-check.patch * 002-libbpf-fix-build-failure-from-uninitialized-variable.patch * 003-bpftool-allow-passing-BPFTOOL_VERSION-to-make.patch * 004-v5.9-bpftool-use-only-ftw-for-file-tree-parsing.patch Signed-off-by: Tony Ambardar --- package/network/utils/bpftools/Makefile | 4 +- ...o-local-symbols-counted-in-ABI-check.patch | 31 --- ...-failure-from-uninitialized-variable.patch | 41 ---- ...llow-passing-BPFTOOL_VERSION-to-make.patch | 21 -- ...l-use-only-ftw-for-file-tree-parsing.patch | 231 ------------------ 5 files changed, 2 insertions(+), 326 deletions(-) delete mode 100644 package/network/utils/bpftools/patches/001-libbpf-ensure-no-local-symbols-counted-in-ABI-check.patch delete mode 100644 package/network/utils/bpftools/patches/002-libbpf-fix-build-failure-from-uninitialized-variable.patch delete mode 100644 package/network/utils/bpftools/patches/003-bpftool-allow-passing-BPFTOOL_VERSION-to-make.patch delete mode 100644 package/network/utils/bpftools/patches/004-v5.9-bpftool-use-only-ftw-for-file-tree-parsing.patch diff --git a/package/network/utils/bpftools/Makefile b/package/network/utils/bpftools/Makefile index e760d50c5e..06a7a7adfd 100644 --- a/package/network/utils/bpftools/Makefile +++ b/package/network/utils/bpftools/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=bpftools -PKG_VERSION:=5.8.9 +PKG_VERSION:=5.10.10 PKG_RELEASE:=1 PKG_SOURCE:=linux-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/kernel/v5.x -PKG_HASH:=99d8bc1b82f17d7d79f9af4a94af4c0e3772159e9e6e278761bde8569f93e15f +PKG_HASH:=60ed866fa951522a5255ea37ec3ac2006d3f3427d4783a13ef478464f37cdb19 PKG_MAINTAINER:=Tony Ambardar diff --git a/package/network/utils/bpftools/patches/001-libbpf-ensure-no-local-symbols-counted-in-ABI-check.patch b/package/network/utils/bpftools/patches/001-libbpf-ensure-no-local-symbols-counted-in-ABI-check.patch deleted file mode 100644 index 18000b6940..0000000000 --- a/package/network/utils/bpftools/patches/001-libbpf-ensure-no-local-symbols-counted-in-ABI-check.patch +++ /dev/null @@ -1,31 +0,0 @@ -From fafb2e7eaec6d33ce16e28f481edf781219d5d27 Mon Sep 17 00:00:00 2001 -From: Tony Ambardar -Date: Fri, 24 Jul 2020 23:58:17 -0700 -Subject: [PATCH] tools/libbpf: ensure no local symbols counted in ABI check - -This avoids finding versioned local symbols such as _init and _fini in -the libbpf.so file. - -Signed-off-by: Tony Ambardar ---- - tools/lib/bpf/Makefile | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/tools/lib/bpf/Makefile -+++ b/tools/lib/bpf/Makefile -@@ -152,6 +152,7 @@ GLOBAL_SYM_COUNT = $(shell readelf -s -- - awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$NF}' | \ - sort -u | wc -l) - VERSIONED_SYM_COUNT = $(shell readelf --dyn-syms --wide $(OUTPUT)libbpf.so | \ -+ awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$NF}' | \ - grep -Eo '[^ ]+@LIBBPF_' | cut -d@ -f1 | sort -u | wc -l) - - CMD_TARGETS = $(LIB_TARGET) $(PC_FILE) -@@ -219,6 +220,7 @@ check_abi: $(OUTPUT)libbpf.so - awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$NF}'| \ - sort -u > $(OUTPUT)libbpf_global_syms.tmp; \ - readelf --dyn-syms --wide $(OUTPUT)libbpf.so | \ -+ awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$NF}'| \ - grep -Eo '[^ ]+@LIBBPF_' | cut -d@ -f1 | \ - sort -u > $(OUTPUT)libbpf_versioned_syms.tmp; \ - diff -u $(OUTPUT)libbpf_global_syms.tmp \ diff --git a/package/network/utils/bpftools/patches/002-libbpf-fix-build-failure-from-uninitialized-variable.patch b/package/network/utils/bpftools/patches/002-libbpf-fix-build-failure-from-uninitialized-variable.patch deleted file mode 100644 index 96ab2084b7..0000000000 --- a/package/network/utils/bpftools/patches/002-libbpf-fix-build-failure-from-uninitialized-variable.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 74d0dcf7608b1bab116e297468ac51b57eb97ce0 Mon Sep 17 00:00:00 2001 -From: Tony Ambardar -Date: Thu, 20 Aug 2020 10:06:24 -0700 -Subject: [PATCH] libbpf: fix build failure from uninitialized variable warning - -While compiling libbpf, some GCC versions (at least 8.4.0) have difficulty -determining control flow and a emit warning for potentially uninitialized -usage of 'map', which results in a build error if using "-Werror": - -In file included from libbpf.c:56: -libbpf.c: In function '__bpf_object__open': -libbpf_internal.h:59:2: warning: 'map' may be used uninitialized in this function [-Wmaybe-uninitialized] - libbpf_print(level, "libbpf: " fmt, ##__VA_ARGS__); \ - ^~~~~~~~~~~~ -libbpf.c:5032:18: note: 'map' was declared here - struct bpf_map *map, *targ_map; - ^~~ - -The warning/error is false based on code inspection, so silence it with a -NULL initialization. - -Fixes: 646f02ffdd49 ("libbpf: Add BTF-defined map-in-map support") -Ref: 063e68813391 ("libbpf: Fix false uninitialized variable warning") - -Signed-off-by: Tony Ambardar ---- - tools/lib/bpf/libbpf.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/tools/lib/bpf/libbpf.c -+++ b/tools/lib/bpf/libbpf.c -@@ -5030,8 +5030,8 @@ static int bpf_object__collect_map_relos - int i, j, nrels, new_sz; - const struct btf_var_secinfo *vi = NULL; - const struct btf_type *sec, *var, *def; -+ struct bpf_map *map = NULL, *targ_map; - const struct btf_member *member; -- struct bpf_map *map, *targ_map; - const char *name, *mname; - Elf_Data *symbols; - unsigned int moff; diff --git a/package/network/utils/bpftools/patches/003-bpftool-allow-passing-BPFTOOL_VERSION-to-make.patch b/package/network/utils/bpftools/patches/003-bpftool-allow-passing-BPFTOOL_VERSION-to-make.patch deleted file mode 100644 index 1c569afe6b..0000000000 --- a/package/network/utils/bpftools/patches/003-bpftool-allow-passing-BPFTOOL_VERSION-to-make.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 668d1c2951e18512a27aec20b80dea627d01bf04 Mon Sep 17 00:00:00 2001 -From: Tony Ambardar -Date: Thu, 20 Aug 2020 16:05:48 -0700 -Subject: [PATCH] tools/bpftool: allow passing BPFTOOL_VERSION to make - -Signed-off-by: Tony Ambardar ---- - tools/bpf/bpftool/Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/tools/bpf/bpftool/Makefile -+++ b/tools/bpf/bpftool/Makefile -@@ -25,7 +25,7 @@ endif - - LIBBPF = $(LIBBPF_PATH)libbpf.a - --BPFTOOL_VERSION := $(shell make -rR --no-print-directory -sC ../../.. kernelversion) -+BPFTOOL_VERSION ?= $(shell make -rR --no-print-directory -sC ../../.. kernelversion) - - $(LIBBPF): FORCE - $(if $(LIBBPF_OUTPUT),@mkdir -p $(LIBBPF_OUTPUT)) diff --git a/package/network/utils/bpftools/patches/004-v5.9-bpftool-use-only-ftw-for-file-tree-parsing.patch b/package/network/utils/bpftools/patches/004-v5.9-bpftool-use-only-ftw-for-file-tree-parsing.patch deleted file mode 100644 index 99ce513723..0000000000 --- a/package/network/utils/bpftools/patches/004-v5.9-bpftool-use-only-ftw-for-file-tree-parsing.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 6edda7633e4fdf33b91c2e86c05cab805a0dabb3 Mon Sep 17 00:00:00 2001 -From: Tony Ambardar -Date: Mon, 20 Jul 2020 19:48:16 -0700 -Subject: [PATCH] bpftool: Use only nftw for file tree parsing - -The bpftool sources include code to walk file trees, but use multiple -frameworks to do so: nftw and fts. While nftw conforms to POSIX/SUSv3 and -is widely available, fts is not conformant and less common, especially on -non-glibc systems. The inconsistent framework usage hampers maintenance -and portability of bpftool, in particular for embedded systems. - -Standardize code usage by rewriting one fts-based function to use nftw and -clean up some related function warnings by extending use of "const char *" -arguments. This change helps in building bpftool against musl for OpenWrt. - -Also fix an unsafe call to dirname() by duplicating the string to pass, -since some implementations may directly alter it. The same approach is -used in libbpf.c. - -Signed-off-by: Tony Ambardar -Signed-off-by: Daniel Borkmann -Reviewed-by: Quentin Monnet -Link: https://lore.kernel.org/bpf/20200721024817.13701-1-Tony.Ambardar@gmail.com ---- - tools/bpf/bpftool/common.c | 137 ++++++++++++++++++++++--------------- - tools/bpf/bpftool/main.h | 4 +- - 2 files changed, 82 insertions(+), 59 deletions(-) - ---- a/tools/bpf/bpftool/common.c -+++ b/tools/bpf/bpftool/common.c -@@ -1,10 +1,11 @@ - // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) - /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ - -+#define _GNU_SOURCE - #include - #include - #include --#include -+#include - #include - #include - #include -@@ -123,24 +124,35 @@ int mount_tracefs(const char *target) - return err; - } - --int open_obj_pinned(char *path, bool quiet) -+int open_obj_pinned(const char *path, bool quiet) - { -- int fd; -+ char *pname; -+ int fd = -1; - -- fd = bpf_obj_get(path); -+ pname = strdup(path); -+ if (!pname) { -+ if (!quiet) -+ p_err("mem alloc failed"); -+ goto out_ret; -+ } -+ -+ fd = bpf_obj_get(pname); - if (fd < 0) { - if (!quiet) -- p_err("bpf obj get (%s): %s", path, -- errno == EACCES && !is_bpffs(dirname(path)) ? -+ p_err("bpf obj get (%s): %s", pname, -+ errno == EACCES && !is_bpffs(dirname(pname)) ? - "directory not in bpf file system (bpffs)" : - strerror(errno)); -- return -1; -+ goto out_free; - } - -+out_free: -+ free(pname); -+out_ret: - return fd; - } - --int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) -+int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type) - { - enum bpf_obj_type type; - int fd; -@@ -330,71 +342,82 @@ void print_hex_data_json(uint8_t *data, - jsonw_end_array(json_wtr); - } - -+/* extra params for nftw cb */ -+static struct pinned_obj_table *build_fn_table; -+static enum bpf_obj_type build_fn_type; -+ -+static int do_build_table_cb(const char *fpath, const struct stat *sb, -+ int typeflag, struct FTW *ftwbuf) -+{ -+ struct bpf_prog_info pinned_info; -+ __u32 len = sizeof(pinned_info); -+ struct pinned_obj *obj_node; -+ enum bpf_obj_type objtype; -+ int fd, err = 0; -+ -+ if (typeflag != FTW_F) -+ goto out_ret; -+ -+ fd = open_obj_pinned(fpath, true); -+ if (fd < 0) -+ goto out_ret; -+ -+ objtype = get_fd_type(fd); -+ if (objtype != build_fn_type) -+ goto out_close; -+ -+ memset(&pinned_info, 0, sizeof(pinned_info)); -+ if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len)) -+ goto out_close; -+ -+ obj_node = calloc(1, sizeof(*obj_node)); -+ if (!obj_node) { -+ err = -1; -+ goto out_close; -+ } -+ -+ obj_node->id = pinned_info.id; -+ obj_node->path = strdup(fpath); -+ if (!obj_node->path) { -+ err = -1; -+ free(obj_node); -+ goto out_close; -+ } -+ -+ hash_add(build_fn_table->table, &obj_node->hash, obj_node->id); -+out_close: -+ close(fd); -+out_ret: -+ return err; -+} -+ - int build_pinned_obj_table(struct pinned_obj_table *tab, - enum bpf_obj_type type) - { -- struct bpf_prog_info pinned_info = {}; -- struct pinned_obj *obj_node = NULL; -- __u32 len = sizeof(pinned_info); - struct mntent *mntent = NULL; -- enum bpf_obj_type objtype; - FILE *mntfile = NULL; -- FTSENT *ftse = NULL; -- FTS *fts = NULL; -- int fd, err; -+ int flags = FTW_PHYS; -+ int nopenfd = 16; -+ int err = 0; - - mntfile = setmntent("/proc/mounts", "r"); - if (!mntfile) - return -1; - -+ build_fn_table = tab; -+ build_fn_type = type; -+ - while ((mntent = getmntent(mntfile))) { -- char *path[] = { mntent->mnt_dir, NULL }; -+ char *path = mntent->mnt_dir; - - if (strncmp(mntent->mnt_type, "bpf", 3) != 0) - continue; -- -- fts = fts_open(path, 0, NULL); -- if (!fts) -- continue; -- -- while ((ftse = fts_read(fts))) { -- if (!(ftse->fts_info & FTS_F)) -- continue; -- fd = open_obj_pinned(ftse->fts_path, true); -- if (fd < 0) -- continue; -- -- objtype = get_fd_type(fd); -- if (objtype != type) { -- close(fd); -- continue; -- } -- memset(&pinned_info, 0, sizeof(pinned_info)); -- err = bpf_obj_get_info_by_fd(fd, &pinned_info, &len); -- if (err) { -- close(fd); -- continue; -- } -- -- obj_node = malloc(sizeof(*obj_node)); -- if (!obj_node) { -- close(fd); -- fts_close(fts); -- fclose(mntfile); -- return -1; -- } -- -- memset(obj_node, 0, sizeof(*obj_node)); -- obj_node->id = pinned_info.id; -- obj_node->path = strdup(ftse->fts_path); -- hash_add(tab->table, &obj_node->hash, obj_node->id); -- -- close(fd); -- } -- fts_close(fts); -+ err = nftw(path, do_build_table_cb, nopenfd, flags); -+ if (err) -+ break; - } - fclose(mntfile); -- return 0; -+ return err; - } - - void delete_pinned_obj_table(struct pinned_obj_table *tab) ---- a/tools/bpf/bpftool/main.h -+++ b/tools/bpf/bpftool/main.h -@@ -196,8 +196,8 @@ int cmd_select(const struct cmd *cmds, i - int get_fd_type(int fd); - const char *get_fd_type_name(enum bpf_obj_type type); - char *get_fdinfo(int fd, const char *key); --int open_obj_pinned(char *path, bool quiet); --int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type); -+int open_obj_pinned(const char *path, bool quiet); -+int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type); - int mount_bpffs_for_pin(const char *name); - int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***)); - int do_pin_fd(int fd, const char *name); From 9ad912d159f8a6a2907d6cd6c55082765ba2364b Mon Sep 17 00:00:00 2001 From: John Audia Date: Sat, 23 Jan 2021 11:09:03 -0500 Subject: [PATCH 09/29] kernel: bump 5.4 to 5.4.92 All modification made by update_kernel.sh in a fresh clone without existing toolchains. Build system: x86_64 Build-tested: ipq806x/R7800, bcm27xx/bcm2711 Run-tested: ipq806x/R7800 Compile-tested [*]: ath79/{tiny,generic}, ipq40xx, octeon, ramips/mt7621, realtek, x86/64. Run-tested [*]: ath79/generic, octeon, ramips/mt7621, realtek. No dmesg regressions, everything functional Signed-off-by: John Audia Tested-by: Stijn Segers [*] --- include/kernel-version.mk | 4 ++-- target/linux/generic/hack-5.4/721-phy_packets.patch | 6 +++--- target/linux/generic/pending-5.4/655-increase_skb_pad.patch | 2 +- .../patches-5.4/303-core-0001-net-readd-skb_recycle.patch | 2 +- ...t-phylink-propagate-resolved-link-config-via-mac_l.patch | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 5f8614f060..4a61601ce5 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -6,9 +6,9 @@ ifdef CONFIG_TESTING_KERNEL KERNEL_PATCHVER:=$(KERNEL_TESTING_PATCHVER) endif -LINUX_VERSION-5.4 = .91 +LINUX_VERSION-5.4 = .92 -LINUX_KERNEL_HASH-5.4.91 = 0e0161bb034b9ba59e58a20985e49ecfb38104586602f53f37b382f508fc5c17 +LINUX_KERNEL_HASH-5.4.92 = c0937ff98824c4b14cfea68a04340e0beb3c00f1cc02984daf2f3bdf542394fd remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1))))))) diff --git a/target/linux/generic/hack-5.4/721-phy_packets.patch b/target/linux/generic/hack-5.4/721-phy_packets.patch index 407597c896..dba648f8e6 100644 --- a/target/linux/generic/hack-5.4/721-phy_packets.patch +++ b/target/linux/generic/hack-5.4/721-phy_packets.patch @@ -56,7 +56,7 @@ Signed-off-by: Felix Fietkau */ --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -2679,6 +2679,10 @@ static inline int pskb_trim(struct sk_bu +@@ -2684,6 +2684,10 @@ static inline int pskb_trim(struct sk_bu return (len < skb->len) ? __pskb_trim(skb, len) : 0; } @@ -67,7 +67,7 @@ Signed-off-by: Felix Fietkau /** * pskb_trim_unique - remove end from a paged unique (not cloned) buffer * @skb: buffer to alter -@@ -2810,16 +2814,6 @@ static inline struct sk_buff *dev_alloc_ +@@ -2815,16 +2819,6 @@ static inline struct sk_buff *dev_alloc_ } @@ -136,7 +136,7 @@ Signed-off-by: Felix Fietkau #include #include -@@ -540,6 +541,22 @@ skb_fail: +@@ -545,6 +546,22 @@ skb_fail: } EXPORT_SYMBOL(__napi_alloc_skb); diff --git a/target/linux/generic/pending-5.4/655-increase_skb_pad.patch b/target/linux/generic/pending-5.4/655-increase_skb_pad.patch index f7ab7e492f..e325301d3c 100644 --- a/target/linux/generic/pending-5.4/655-increase_skb_pad.patch +++ b/target/linux/generic/pending-5.4/655-increase_skb_pad.patch @@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -2645,7 +2645,7 @@ static inline int pskb_network_may_pull( +@@ -2650,7 +2650,7 @@ static inline int pskb_network_may_pull( * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) */ #ifndef NET_SKB_PAD diff --git a/target/linux/layerscape/patches-5.4/303-core-0001-net-readd-skb_recycle.patch b/target/linux/layerscape/patches-5.4/303-core-0001-net-readd-skb_recycle.patch index cd52f66084..7b257bb17c 100644 --- a/target/linux/layerscape/patches-5.4/303-core-0001-net-readd-skb_recycle.patch +++ b/target/linux/layerscape/patches-5.4/303-core-0001-net-readd-skb_recycle.patch @@ -24,7 +24,7 @@ Signed-off-by: Madalin Bucur --- a/net/core/skbuff.c +++ b/net/core/skbuff.c -@@ -936,6 +936,32 @@ void napi_consume_skb(struct sk_buff *sk +@@ -941,6 +941,32 @@ void napi_consume_skb(struct sk_buff *sk } EXPORT_SYMBOL(napi_consume_skb); diff --git a/target/linux/mediatek/patches-5.4/0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch b/target/linux/mediatek/patches-5.4/0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch index fc987e8e9d..3bf1d0c135 100644 --- a/target/linux/mediatek/patches-5.4/0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch +++ b/target/linux/mediatek/patches-5.4/0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch @@ -95,7 +95,7 @@ Signed-off-by: David S. Miller } netif_tx_start_all_queues(port->dev); -@@ -5139,8 +5143,11 @@ static void mvpp2_mac_config(struct phyl +@@ -5137,8 +5141,11 @@ static void mvpp2_mac_config(struct phyl mvpp2_port_enable(port); } From cb39602399e3c3ee48b4f2c39df7bf759418584e Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 14:07:38 +0100 Subject: [PATCH 10/29] realtek: add detection of RTL930X SoCs and RTL8313 SoC This adds support to detect RTL930X based SoCs and the RTL9313 SoC. Tested on Zyxel XGS1210-10 (RTL9302B SoC) and the Zyxel XS1930-12 (RTL9313 SoC) Signed-off-by: Birger Koblitz --- .../files-5.4/arch/mips/rtl838x/prom.c | 71 +++++++++++++++++-- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c b/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c index 5278afae03..3390c04334 100644 --- a/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c +++ b/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c @@ -66,19 +66,64 @@ static void __init prom_init_cmdline(void) pr_info("Kernel command line: %s\n", arcs_cmdline); } +void __init identify_rtl9302(void) +{ + switch (sw_r32(RTL93XX_MODEL_NAME_INFO) & 0xfffffff0) { + case 0x93020810: + soc_info.name = "RTL9302A 12x2.5G"; + break; + case 0x93021010: + soc_info.name = "RTL9302B 8x2.5G"; + break; + case 0x93021810: + soc_info.name = "RTL9302C 16x2.5G"; + break; + case 0x93022010: + soc_info.name = "RTL9302D 24x2.5G"; + break; + case 0x93020800: + soc_info.name = "RTL9302A"; + break; + case 0x93021000: + soc_info.name = "RTL9302B"; + break; + case 0x93021800: + soc_info.name = "RTL9302C"; + break; + case 0x93022000: + soc_info.name = "RTL9302D"; + break; + case 0x93023001: + soc_info.name = "RTL9302F"; + break; + default: + soc_info.name = "RTL9302"; + } +} + void __init prom_init(void) { uint32_t model; /* uart0 */ - setup_8250_early_printk_port(0xb8002000, 2, 0); + setup_8250_early_printk_port(0xb8002000, 2, 0); - soc_info.sw_base = RTL838X_SW_BASE; + model = sw_r32(RTL838X_MODEL_NAME_INFO); + pr_info("RTL838X model is %x\n", model); + model = model >> 16 & 0xFFFF; - model = sw_r32(RTL838X_MODEL_NAME_INFO) >> 16; - if (model != 0x8328 && model != 0x8330 && model != 0x8332 && - model != 0x8380 && model != 0x8382) - model = sw_r32(RTL839X_MODEL_NAME_INFO) >> 16; + if ((model != 0x8328) && (model != 0x8330) && (model != 0x8332) + && (model != 0x8380) && (model != 0x8382)) { + model = sw_r32(RTL839X_MODEL_NAME_INFO); + pr_info("RTL839X model is %x\n", model); + model = model >> 16 & 0xFFFF; + } + + if ((model & 0x8390) != 0x8380 && (model & 0x8390) != 0x8390) { + model = sw_r32(RTL93XX_MODEL_NAME_INFO); + pr_info("RTL93XX model is %x\n", model); + model = model >> 16 & 0xFFFF; + } soc_info.id = model; @@ -115,10 +160,24 @@ void __init prom_init(void) soc_info.name = "RTL8393"; soc_info.family = RTL8390_FAMILY_ID; break; + case 0x9301: + soc_info.name = "RTL9301"; + soc_info.family = RTL9300_FAMILY_ID; + break; + case 0x9302: + identify_rtl9302(); + soc_info.family = RTL9300_FAMILY_ID; + break; + case 0x9313: + soc_info.name = "RTL9313"; + soc_info.family = RTL9310_FAMILY_ID; + break; default: soc_info.name = "DEFAULT"; soc_info.family = 0; } + pr_info("SoC Type: %s\n", get_system_type()); + prom_init_cmdline(); } From 03c79ca269e612faa55e3decd034c44f9b77c05c Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 14:11:35 +0100 Subject: [PATCH 11/29] realtek: add support for the RTL8390 and RTL9300 SoC IRQs This adds support for the RTL8390 and RTL9300 SoCs it also cleans up unnecessary definitions in mach-rtl83xx.h and moves definitions relevant for irq routing to irq.h Signed-off-by: Birger Koblitz --- target/linux/realtek/dts/rtl838x.dtsi | 9 +- .../arch/mips/include/asm/mach-rtl838x/irq.h | 27 +++ .../include/asm/mach-rtl838x/mach-rtl83xx.h | 217 +++++++----------- .../realtek/files-5.4/arch/mips/rtl838x/irq.c | 71 +++++- 4 files changed, 174 insertions(+), 150 deletions(-) diff --git a/target/linux/realtek/dts/rtl838x.dtsi b/target/linux/realtek/dts/rtl838x.dtsi index 36d8847a15..b59b141f66 100644 --- a/target/linux/realtek/dts/rtl838x.dtsi +++ b/target/linux/realtek/dts/rtl838x.dtsi @@ -101,8 +101,8 @@ clock-frequency = <200000000>; - interrupt-parent = <&cpuintc>; - interrupts = <3>; + interrupt-parent = <&intc>; + interrupts = <31>; reg-io-width = <1>; reg-shift = <2>; @@ -180,9 +180,8 @@ switch0: switch@bb000000 { status = "okay"; - interrupt-parent = <&cpuintc>; - interrupts = <4>; - + interrupt-parent = <&intc>; + interrupts = <20>; compatible = "realtek,rtl83xx-switch"; }; diff --git a/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/irq.h b/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/irq.h index 580c3d8d61..a4e95ab511 100644 --- a/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/irq.h +++ b/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/irq.h @@ -34,6 +34,9 @@ #define UART1_CASCADE 1 #define TC0_CASCADE 5 #define TC1_CASCADE 1 +#define TC2_CASCADE 1 +#define TC3_CASCADE 1 +#define TC4_CASCADE 1 #define OCPTO_CASCADE 1 #define HLXTO_CASCADE 1 #define SLXTO_CASCADE 1 @@ -44,6 +47,7 @@ #define SWCORE_CASCADE 3 #define WDT_IP1_CASCADE 4 #define WDT_IP2_CASCADE 5 +#define USB_H2_CASCADE 1 /* Pack cascade map into interrupt routing registers */ #define RTL83XX_IRR0_SETTING (\ @@ -63,4 +67,27 @@ #define RTL83XX_IRR2_SETTING 0 #define RTL83XX_IRR3_SETTING 0 +/* On the RTL8390 there is no GPIO_EFGH and RTC IRQ */ +#define RTL8390_IRR1_SETTING (\ + (GPIO_ABCD_CASCADE << 28) | \ + (SWCORE_CASCADE << 16)) + +/* The RTL9300 has a different external IRQ numbering scheme */ +#define RTL9300_IRR0_SETTING (\ + (UART1_CASCADE << 28) | \ + (UART0_CASCADE << 24) | \ + (USB_H2_CASCADE << 16) | \ + (NIC_CASCADE << 0)) +#define RTL9300_IRR1_SETTING (\ + (SWCORE_CASCADE << 28)) +#define RTL9300_IRR2_SETTING (\ + (GPIO_ABCD_CASCADE << 20) | \ + (TC4_CASCADE << 12) | \ + (TC3_CASCADE << 8) | \ + (TC2_CASCADE << 4) | \ + (TC1_CASCADE << 0)) +#define RTL9300_IRR3_SETTING (\ + (TC0_CASCADE << 28) | \ + (WDT_IP1_CASCADE << 20)) + #endif /* _RTL83XX_IRQ_H_ */ diff --git a/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h b/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h index b7d2a6f037..fc401e5481 100644 --- a/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h +++ b/target/linux/realtek/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h @@ -47,20 +47,32 @@ #define RTL838X_IRQ_ICTL_BASE (RTL838X_IRQ_CPU_BASE + RTL838X_IRQ_CPU_NUM) #define RTL838X_IRQ_ICTL_NUM 32 -#define RTL83XX_IRQ_UART0 31 -#define RTL83XX_IRQ_UART1 30 -#define RTL83XX_IRQ_TC0 29 -#define RTL83XX_IRQ_TC1 28 -#define RTL83XX_IRQ_OCPTO 27 -#define RTL83XX_IRQ_HLXTO 26 -#define RTL83XX_IRQ_SLXTO 25 -#define RTL83XX_IRQ_NIC 24 -#define RTL83XX_IRQ_GPIO_ABCD 23 -#define RTL83XX_IRQ_GPIO_EFGH 22 -#define RTL83XX_IRQ_RTC 21 -#define RTL83XX_IRQ_SWCORE 20 -#define RTL83XX_IRQ_WDT_IP1 19 -#define RTL83XX_IRQ_WDT_IP2 18 +#define RTL83XX_IRQ_UART0 31 +#define RTL83XX_IRQ_UART1 30 +#define RTL83XX_IRQ_TC0 29 +#define RTL83XX_IRQ_TC1 28 +#define RTL83XX_IRQ_OCPTO 27 +#define RTL83XX_IRQ_HLXTO 26 +#define RTL83XX_IRQ_SLXTO 25 +#define RTL83XX_IRQ_NIC 24 +#define RTL83XX_IRQ_GPIO_ABCD 23 +#define RTL83XX_IRQ_GPIO_EFGH 22 +#define RTL83XX_IRQ_RTC 21 +#define RTL83XX_IRQ_SWCORE 20 +#define RTL83XX_IRQ_WDT_IP1 19 +#define RTL83XX_IRQ_WDT_IP2 18 + +#define RTL9300_UART1_IRQ 31 +#define RTL9300_UART0_IRQ 30 +#define RTL9300_USB_H2_IRQ 28 +#define RTL9300_NIC_IRQ 24 +#define RTL9300_SWCORE_IRQ 23 +#define RTL9300_GPIO_ABC_IRQ 13 +#define RTL9300_TC4_IRQ 11 +#define RTL9300_TC3_IRQ 10 +#define RTL9300_TC2_IRQ 9 +#define RTL9300_TC1_IRQ 8 +#define RTL9300_TC0_IRQ 7 /* @@ -108,32 +120,6 @@ #define WDT_IP1_IP (1 << 19) #define WDT_IP2_IP (1 << 18) -#define IRR0 (0x08) -#define IRR0_SETTING ((UART0_RS << 28) | \ - (UART1_RS << 24) | \ - (TC0_RS << 20) | \ - (TC1_RS << 16) | \ - (OCPTO_RS << 12) | \ - (HLXTO_RS << 8) | \ - (SLXTO_RS << 4) | \ - (NIC_RS << 0) \ - ) - -#define IRR1 (0x0c) -#define IRR1_SETTING_RTL838X ((GPIO_ABCD_RS << 28) | \ - (GPIO_EFGH_RS << 24) | \ - (RTC_RS << 20) | \ - (SWCORE_RS << 16) \ - ) -#define IRR1_SETTING_RTL839X ((GPIO_ABCD_RS << 28) | \ - (SWCORE_RS << 16) \ - ) - -#define IRR2 (0x10) -#define IRR2_SETTING 0 - -#define IRR3 (0x14) -#define IRR3_SETTING 0 /* Interrupt Routing Selection */ #define UART0_RS 2 @@ -200,107 +186,9 @@ #define UART1_DLM (RTL838X_UART1_BASE + 0x004) #define UART1_IIR (RTL838X_UART1_BASE + 0x008) #define UART1_FCR (RTL838X_UART1_BASE + 0x008) - #define FCR_EN 0x01 - #define FCR_RXRST 0x02 - #define XRST 0x02 - #define FCR_TXRST 0x04 - #define TXRST 0x04 - #define FCR_DMA 0x08 - #define FCR_RTRG 0xC0 - #define CHAR_TRIGGER_01 0x00 - #define CHAR_TRIGGER_04 0x40 - #define CHAR_TRIGGER_08 0x80 - #define CHAR_TRIGGER_14 0xC0 #define UART1_LCR (RTL838X_UART1_BASE + 0x00C) - #define LCR_WLN 0x03 - #define CHAR_LEN_5 0x00 - #define CHAR_LEN_6 0x01 - #define CHAR_LEN_7 0x02 - #define CHAR_LEN_8 0x03 - #define LCR_STB 0x04 - #define ONE_STOP 0x00 - #define TWO_STOP 0x04 - #define LCR_PEN 0x08 - #define PARITY_ENABLE 0x01 - #define PARITY_DISABLE 0x00 - #define LCR_EPS 0x30 - #define PARITY_ODD 0x00 - #define PARITY_EVEN 0x10 - #define PARITY_MARK 0x20 - #define PARITY_SPACE 0x30 - #define LCR_BRK 0x40 - #define LCR_DLAB 0x80 - #define DLAB 0x80 #define UART1_MCR (RTL838X_UART1_BASE + 0x010) #define UART1_LSR (RTL838X_UART1_BASE + 0x014) - #define LSR_DR 0x01 - #define RxCHAR_AVAIL 0x01 - #define LSR_OE 0x02 - #define LSR_PE 0x04 - #define LSR_FE 0x08 - #define LSR_BI 0x10 - #define LSR_THRE 0x20 - #define TxCHAR_AVAIL 0x00 - #define TxCHAR_EMPTY 0x20 - #define LSR_TEMT 0x40 - #define LSR_RFE 0x80 - -/* - * Timer/counter for 8390/80/28 TC & MP chip - */ -#define RTL838X_TIMER0_BASE ((volatile void *)(0xb8003100UL)) -#define RTL838X_TIMER0_IRQ RTL838X_TC0_EXT_IRQ - -#define RTL8390TC_TC1DATA (RTL838X_TIMER0_BASE + 0x04) -#define RTL8390TC_TCD_OFFSET 8 -#define RTL8390TC_TC0CNT (RTL838X_TIMER0_BASE + 0x08) -#define RTL8390TC_TC1CNT (RTL838X_TIMER0_BASE + 0x0C) -#define RTL8390TC_TCCNR (RTL838X_TIMER0_BASE + 0x10) -#define RTL8390TC_TC0EN (1 << 31) -#define RTL8390TC_TC0MODE_TIMER (1 << 30) -#define RTL8390TC_TC1EN (1 << 29) -#define RTL8390TC_TC1MODE_TIMER (1 << 28) -#define RTL8390TC_TCIR (RTL838X_TIMER0_BASE + 0x14) -#define RTL8390TC_TC0IE (1 << 31) -#define RTL8390TC_TC1IE (1 << 30) -#define RTL8390TC_TC0IP (1 << 29) -#define RTL8390TC_TC1IP (1 << 28) -#define RTL8390TC_CDBR (RTL838X_TIMER0_BASE + 0x18) -#define RTL8390TC_DIVF_OFFSET 16 -#define RTL8390TC_WDTCNR (RTL838X_TIMER0_BASE + 0x1C) - -#define RTL8390MP_TC1DATA (RTL838X_TIMER0_BASE + 0x10) -#define RTL8390MP_TC0CNT (RTL838X_TIMER0_BASE + 0x04) -#define RTL8390MP_TC1CNT (RTL838X_TIMER0_BASE + 0x14) -#define RTL8390MP_TC0CTL (RTL838X_TIMER0_BASE + 0x08) -#define RTL8390MP_TC1CTL (RTL838X_TIMER0_BASE + 0x18) -#define RTL8390MP_TCEN (1 << 28) -#define RTL8390MP_TCMODE_TIMER (1 << 24) -#define RTL8390MP_TCDIV_FACTOR (0xFFFF << 0) -#define RTL8390MP_TC0INT (RTL838X_TIMER0_BASE + 0xC) -#define RTL8390MP_TC1INT (RTL838X_TIMER0_BASE + 0x1C) -#define RTL8390MP_TCIE (1 << 20) -#define RTL8390MP_TCIP (1 << 16) -#define RTL8390MP_WDTCNR (RTL838X_TIMER0_BASE + 0x50) - -#define RTL8380MP_TC0DATA (RTL838X_TIMER0_BASE + 0x00) -#define RTL8380MP_TC1DATA (RTL838X_TIMER0_BASE + 0x10) -#define RTL8380MP_TC0CNT (RTL838X_TIMER0_BASE + 0x04) -#define RTL8380MP_TC1CNT (RTL838X_TIMER0_BASE + 0x14) -#define RTL8380MP_TC0CTL (RTL838X_TIMER0_BASE + 0x08) -#define RTL8380MP_TC1CTL (RTL838X_TIMER0_BASE + 0x18) -#define RTL8380MP_TCEN (1 << 28) -#define RTL8380MP_TCMODE_TIMER (1 << 24) -#define RTL8380MP_TCDIV_FACTOR (0xFFFF << 0) -#define RTL8380MP_TC0INT (RTL838X_TIMER0_BASE + 0xC) -#define RTL8380MP_TC1INT (RTL838X_TIMER0_BASE + 0x1C) -#define RTL8380MP_TCIE (1 << 20) -#define RTL8380MP_TCIP (1 << 16) -#define RTL8380MP_WDTCNR (RTL838X_TIMER0_BASE + 0x50) - -#define DIVISOR_RTL8390 55 -#define DIVISOR_RTL8380 2500 -#define DIVISOR_MAX 16834 /* * Memory Controller @@ -328,8 +216,14 @@ #define RTL838X_MODEL_NAME_INFO (0x00D4) #define RTL839X_MODEL_NAME_INFO (0x0FF0) +#define RTL93XX_MODEL_NAME_INFO (0x0004) + #define RTL838X_LED_GLB_CTRL (0xA000) #define RTL839X_LED_GLB_CTRL (0x00E4) +#define RTL9302_LED_GLB_CTRL (0xcc00) +#define RTL930X_LED_GLB_CTRL (0xC400) +#define RTL931X_LED_GLB_CTRL (0x0600) + #define RTL838X_EXT_GPIO_DIR (0xA08C) #define RTL839X_EXT_GPIO_DIR (0x0214) #define RTL838X_EXT_GPIO_DATA (0xA094) @@ -377,8 +271,11 @@ * Reset */ #define RGCR (0x1E70) -#define RTL839X_RST_GLB_CTRL (0x0014) +#define RTL838X_RST_GLB_CTRL_0 (0x003c) #define RTL838X_RST_GLB_CTRL_1 (0x0040) +#define RTL839X_RST_GLB_CTRL (0x0014) +#define RTL930X_RST_GLB_CTRL_0 (0x000c) +#define RTL931X_RST_GLB_CTRL (0x0400) /* LED control by switch */ #define RTL838X_LED_MODE_SEL (0x1004) @@ -419,6 +316,24 @@ #define RTL839X_PHYREG_PORT_CTRL(p) (0x03E4 + ((p >> 5) << 2)) #define RTL839X_PHYREG_DATA_CTRL (0x03F0) +#define RTL930X_SMI_GLB_CTRL (0xCA00) +#define RTL930X_SMI_POLL_CTRL (0xca90) +#define RTL930X_SMI_PORT0_15_POLLING_SEL (0xCA08) +#define RTL930X_SMI_PORT16_27_POLLING_SEL (0xCA0C) +#define RTL930X_SMI_PORT0_5_ADDR (0xCB80) +#define RTL930X_SMI_ACCESS_PHY_CTRL_0 (0xCB70) +#define RTL930X_SMI_ACCESS_PHY_CTRL_1 (0xCB74) +#define RTL930X_SMI_ACCESS_PHY_CTRL_2 (0xCB78) +#define RTL930X_SMI_ACCESS_PHY_CTRL_3 (0xCB7C) + +#define RTL931X_SMI_GLB_CTRL1 (0x0CBC) +#define RTL931X_SMI_GLB_CTRL0 (0x0CC0) +#define RTL931X_SMI_PORT_POLLING_CTRL (0x0CCC) +#define RTL931X_SMI_INDRT_ACCESS_CTRL_0 (0x0C00) +#define RTL931X_SMI_INDRT_ACCESS_CTRL_1 (0x0C04) +#define RTL931X_SMI_INDRT_ACCESS_CTRL_2 (0x0C08) +#define RTL931X_SMI_INDRT_ACCESS_CTRL_3 (0x0C10) + /* * Switch interrupts */ @@ -426,11 +341,22 @@ #define RTL838X_IMR_PORT_LINK_STS_CHG (0x1104) #define RTL838X_ISR_GLB_SRC (0x1148) #define RTL838X_ISR_PORT_LINK_STS_CHG (0x114C) + #define RTL839X_IMR_GLB (0x0064) #define RTL839X_IMR_PORT_LINK_STS_CHG (0x0068) #define RTL839X_ISR_GLB_SRC (0x009c) #define RTL839X_ISR_PORT_LINK_STS_CHG (0x00a0) +#define RTL930X_IMR_GLB (0xC628) +#define RTL930X_IMR_PORT_LINK_STS_CHG (0xC62C) +#define RTL930X_ISR_GLB (0xC658) +#define RTL930X_ISR_PORT_LINK_STS_CHG (0xC660) + +// IMR_GLB does not exit on RTL931X +#define RTL931X_IMR_PORT_LINK_STS_CHG (0x126C) +#define RTL931X_ISR_GLB_SRC (0x12B4) +#define RTL931X_ISR_PORT_LINK_STS_CHG (0x12B8) + /* Definition of family IDs */ #define RTL8389_FAMILY_ID (0x8389) #define RTL8328_FAMILY_ID (0x8328) @@ -438,6 +364,14 @@ #define RTL8350_FAMILY_ID (0x8350) #define RTL8380_FAMILY_ID (0x8380) #define RTL8330_FAMILY_ID (0x8330) +#define RTL9300_FAMILY_ID (0x9300) +#define RTL9310_FAMILY_ID (0x9310) + +/* Basic SoC Features */ +#define RTL838X_CPU_PORT 28 +#define RTL839X_CPU_PORT 52 +#define RTL930X_CPU_PORT 28 +#define RTL931X_CPU_PORT 56 struct rtl83xx_soc_info { unsigned char *name; @@ -446,6 +380,7 @@ struct rtl83xx_soc_info { unsigned char *compatible; volatile void *sw_base; volatile void *icu_base; + int cpu_port; }; /* rtl83xx-related functions used across subsystems */ @@ -454,5 +389,9 @@ int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val); int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val); int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val); int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val); +int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val); +int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val); +int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val); +int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val); #endif /* _MACH_RTL838X_H_ */ diff --git a/target/linux/realtek/files-5.4/arch/mips/rtl838x/irq.c b/target/linux/realtek/files-5.4/arch/mips/rtl838x/irq.c index 9057d48543..c0dd2f608c 100644 --- a/target/linux/realtek/files-5.4/arch/mips/rtl838x/irq.c +++ b/target/linux/realtek/files-5.4/arch/mips/rtl838x/irq.c @@ -85,7 +85,8 @@ static const struct irq_domain_ops irq_domain_ops = { static void rtl838x_irq_dispatch(struct irq_desc *desc) { - unsigned int pending = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR)) & rtl83xx_r32(REG(RTL83XX_ICTL_GISR)); + unsigned int pending = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR)) & + rtl83xx_r32(REG(RTL83XX_ICTL_GISR)); if (pending) { struct irq_domain *domain = irq_desc_get_handler_data(desc); @@ -95,7 +96,7 @@ static void rtl838x_irq_dispatch(struct irq_desc *desc) } } -asmlinkage void plat_irq_dispatch(void) +asmlinkage void plat_rtl83xx_irq_dispatch(void) { unsigned int pending; @@ -123,17 +124,27 @@ asmlinkage void plat_irq_dispatch(void) spurious_interrupt(); } -static void __init icu_of_init(struct device_node *node, struct device_node *parent) +static int icu_setup_domain(struct device_node *node) { struct irq_domain *domain; domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL); - irq_set_chained_handler_and_data(2, rtl838x_irq_dispatch, domain); - irq_set_chained_handler_and_data(5, rtl838x_irq_dispatch, domain); + irq_set_chained_handler_and_data(2, rtl838x_irq_dispatch, domain); + irq_set_chained_handler_and_data(3, rtl838x_irq_dispatch, domain); + irq_set_chained_handler_and_data(4, rtl838x_irq_dispatch, domain); + irq_set_chained_handler_and_data(5, rtl838x_irq_dispatch, domain); rtl83xx_ictl_base = of_iomap(node, 0); if (!rtl83xx_ictl_base) + return -EINVAL; + + return 0; +} + +static void __init rtl8380_icu_of_init(struct device_node *node, struct device_node *parent) +{ + if (icu_setup_domain(node)) return; /* Disable all cascaded interrupts */ @@ -155,9 +166,57 @@ static void __init icu_of_init(struct device_node *node, struct device_node *par rtl83xx_w32(BIT(RTL83XX_IRQ_TC0) | BIT(RTL83XX_IRQ_UART0), REG(RTL83XX_ICTL_GIMR)); } +static void __init rtl8390_icu_of_init(struct device_node *node, struct device_node *parent) +{ + if (icu_setup_domain(node)) + return; + + /* Disable all cascaded interrupts */ + rtl83xx_w32(0, REG(RTL83XX_ICTL_GIMR)); + + /* Set up interrupt routing */ + rtl83xx_w32(RTL83XX_IRR0_SETTING, REG(RTL83XX_IRR0)); + rtl83xx_w32(RTL8390_IRR1_SETTING, REG(RTL83XX_IRR1)); + rtl83xx_w32(RTL83XX_IRR2_SETTING, REG(RTL83XX_IRR2)); + rtl83xx_w32(RTL83XX_IRR3_SETTING, REG(RTL83XX_IRR3)); + + /* Clear timer interrupt */ + write_c0_compare(0); + + /* Enable all CPU interrupts */ + write_c0_status(read_c0_status() | ST0_IM); + + /* Enable timer0 and uart0 interrupts */ + rtl83xx_w32(BIT(RTL83XX_IRQ_TC0) | BIT(RTL83XX_IRQ_UART0), REG(RTL83XX_ICTL_GIMR)); +} + +static void __init rtl9300_icu_of_init(struct device_node *node, struct device_node *parent) +{ + pr_info("RTL9300: Setting up IRQs\n"); + if (icu_setup_domain(node)) + return; + + /* Disable all cascaded interrupts */ + rtl83xx_w32(0, REG(RTL83XX_ICTL_GIMR)); + + /* Set up interrupt routing */ + rtl83xx_w32(RTL9300_IRR0_SETTING, REG(RTL83XX_IRR0)); + rtl83xx_w32(RTL9300_IRR1_SETTING, REG(RTL83XX_IRR1)); + rtl83xx_w32(RTL9300_IRR2_SETTING, REG(RTL83XX_IRR2)); + rtl83xx_w32(RTL9300_IRR3_SETTING, REG(RTL83XX_IRR3)); + + /* Clear timer interrupt */ + write_c0_compare(0); + + /* Enable all CPU interrupts */ + write_c0_status(read_c0_status() | ST0_IM); +} + static struct of_device_id __initdata of_irq_ids[] = { { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, - { .compatible = "realtek,rt8380-intc", .data = icu_of_init }, + { .compatible = "realtek,rt8380-intc", .data = rtl8380_icu_of_init }, + { .compatible = "realtek,rt8390-intc", .data = rtl8390_icu_of_init }, + { .compatible = "realtek,rt9300-intc", .data = rtl9300_icu_of_init }, {}, }; From 8faffa00cb6b7121fbdac3d5cff8bab9a253ae93 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 21:38:27 +0100 Subject: [PATCH 12/29] realtek: add support for the RTL9300 timer this adds support for the SoC timer of the RTL9300 chips, it provides 6 independent timer/counters, of which the first one is used as a clocksource and the second one as event timer. Signed-off-by: Birger Koblitz --- target/linux/realtek/config-5.4 | 8 +- .../files-5.4/arch/mips/rtl838x/setup.c | 133 ++++++++++-- .../drivers/clocksource/timer-rtl9300.c | 196 ++++++++++++++++++ .../302-clocksource-add-rtl9300-driver.patch | 34 +++ 4 files changed, 349 insertions(+), 22 deletions(-) create mode 100644 target/linux/realtek/files-5.4/drivers/clocksource/timer-rtl9300.c create mode 100644 target/linux/realtek/patches-5.4/302-clocksource-add-rtl9300-driver.patch diff --git a/target/linux/realtek/config-5.4 b/target/linux/realtek/config-5.4 index 2176a2cf50..2fbd904376 100644 --- a/target/linux/realtek/config-5.4 +++ b/target/linux/realtek/config-5.4 @@ -2,7 +2,6 @@ CONFIG_ARCH_32BIT_OFF_T=y CONFIG_ARCH_CLOCKSOURCE_DATA=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_MMAP_RND_BITS_MAX=15 -CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15 CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 @@ -10,6 +9,10 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_CEVT_R4K=y CONFIG_CLONE_BACKWARDS=y CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_CLK=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_BOSTON=y CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15 CONFIG_CPU_BIG_ENDIAN=y CONFIG_CPU_GENERIC_DUMP_TLB=y @@ -160,6 +163,7 @@ CONFIG_REGMAP=y CONFIG_REGMAP_MMIO=y CONFIG_RESET_CONTROLLER=y CONFIG_RTL838X=y +CONFIG_RTL9300_TIMER=y CONFIG_SERIAL_MCTRL_GPIO=y CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SFP=y @@ -168,7 +172,7 @@ CONFIG_SPI_MASTER=y CONFIG_SPI_MEM=y CONFIG_SPI_RTL838X=y CONFIG_SRCU=y -CONFIG_SWCONFIG=y +CONFIG_SWAP_IO_SPACE=y CONFIG_SWPHY=y CONFIG_SYSCTL_EXCEPTION_TRACE=y CONFIG_SYS_HAS_CPU_MIPS32_R1=y diff --git a/target/linux/realtek/files-5.4/arch/mips/rtl838x/setup.c b/target/linux/realtek/files-5.4/arch/mips/rtl838x/setup.c index 24c70b8274..ef97d485e1 100644 --- a/target/linux/realtek/files-5.4/arch/mips/rtl838x/setup.c +++ b/target/linux/realtek/files-5.4/arch/mips/rtl838x/setup.c @@ -11,23 +11,21 @@ #include #include -#include #include #include +#include +#include #include #include - #include -#include #include -#include /* for mips_hpt_frequency */ +#include #include #include #include "mach-rtl83xx.h" -extern int rtl838x_serial_init(void); extern struct rtl83xx_soc_info soc_info; u32 pll_reset_value; @@ -35,30 +33,109 @@ u32 pll_reset_value; static void rtl838x_restart(char *command) { u32 pll = sw_r32(RTL838X_PLL_CML_CTRL); - /* SoC reset vector (in flash memory): on RTL839x platform preferred way to reset */ - void (*f)(void) = (void *) 0xbfc00000; pr_info("System restart.\n"); - if (soc_info.family == RTL8390_FAMILY_ID) { - f(); - /* If calling reset vector fails, reset entire chip */ - sw_w32(0xFFFFFFFF, RTL839X_RST_GLB_CTRL); - /* If this fails, halt the CPU */ - while - (1); - } - pr_info("PLL control register: %x, applying reset value %x\n", pll, pll_reset_value); + sw_w32(3, RTL838X_INT_RW_CTRL); sw_w32(pll_reset_value, RTL838X_PLL_CML_CTRL); sw_w32(0, RTL838X_INT_RW_CTRL); - pr_info("Resetting RTL838X SoC\n"); /* Reset Global Control1 Register */ sw_w32(1, RTL838X_RST_GLB_CTRL_1); } +static void rtl839x_restart(char *command) +{ + /* SoC reset vector (in flash memory): on RTL839x platform preferred way to reset */ + void (*f)(void) = (void *) 0xbfc00000; + + pr_info("System restart.\n"); + /* Reset SoC */ + sw_w32(0xFFFFFFFF, RTL839X_RST_GLB_CTRL); + /* and call reset vector */ + f(); + /* If this fails, halt the CPU */ + while + (1); +} + +static void rtl930x_restart(char *command) +{ + pr_info("System restart.\n"); + sw_w32(0x1, RTL930X_RST_GLB_CTRL_0); + while + (1); +} + +static void rtl931x_restart(char *command) +{ + u32 v; + + pr_info("System restart.\n"); + sw_w32(1, RTL931X_RST_GLB_CTRL); + v = sw_r32(RTL931X_RST_GLB_CTRL); + sw_w32(0x101, RTL931X_RST_GLB_CTRL); + msleep(15); + sw_w32(v, RTL931X_RST_GLB_CTRL); + msleep(15); + sw_w32(0x101, RTL931X_RST_GLB_CTRL); +} + +static void rtl838x_halt(void) +{ + pr_info("System halted.\n"); + while + (1); +} + +static void __init rtl838x_setup(void) +{ + pr_info("Registering _machine_restart\n"); + _machine_restart = rtl838x_restart; + _machine_halt = rtl838x_halt; + + /* This PLL value needs to be restored before a reset and will then be + * preserved over a SoC reset. A wrong value prevents the SoC from + * connecting to the SPI flash controller at boot and reading the + * reset routine */ + pll_reset_value = sw_r32(RTL838X_PLL_CML_CTRL); + + /* Setup System LED. Bit 15 then allows to toggle it */ + sw_w32_mask(0, 3 << 16, RTL838X_LED_GLB_CTRL); +} + +static void __init rtl839x_setup(void) +{ + pr_info("Registering _machine_restart\n"); + _machine_restart = rtl839x_restart; + _machine_halt = rtl838x_halt; + + /* Setup System LED. Bit 14 of RTL839X_LED_GLB_CTRL then allows to toggle it */ + sw_w32_mask(0, 3 << 15, RTL839X_LED_GLB_CTRL); +} + +static void __init rtl930x_setup(void) +{ + pr_info("Registering _machine_restart\n"); + _machine_restart = rtl930x_restart; + _machine_halt = rtl838x_halt; + + if (soc_info.id == 0x9302) + sw_w32_mask(0, 3 << 13, RTL9302_LED_GLB_CTRL); + else + sw_w32_mask(0, 3 << 13, RTL930X_LED_GLB_CTRL); +} + +static void __init rtl931x_setup(void) +{ + pr_info("Registering _machine_restart\n"); + _machine_restart = rtl931x_restart; + _machine_halt = rtl838x_halt; + sw_w32_mask(0, 3 << 12, RTL931X_LED_GLB_CTRL); +} + void __init plat_mem_setup(void) { void *dtb; @@ -78,6 +155,21 @@ void __init plat_mem_setup(void) * parsed resulting in our memory appearing */ __dt_setup_arch(dtb); + + switch (soc_info.family) { + case RTL8380_FAMILY_ID: + rtl838x_setup(); + break; + case RTL8390_FAMILY_ID: + rtl839x_setup(); + break; + case RTL9300_FAMILY_ID: + rtl930x_setup(); + break; + case RTL9310_FAMILY_ID: + rtl931x_setup(); + break; + } } void __init plat_time_init(void) @@ -85,6 +177,9 @@ void __init plat_time_init(void) struct device_node *np; u32 freq = 500000000; + of_clk_init(NULL); + timer_probe(); + np = of_find_node_by_name(NULL, "cpus"); if (!np) { pr_err("Missing 'cpus' DT node, using default frequency."); @@ -92,11 +187,9 @@ void __init plat_time_init(void) if (of_property_read_u32(np, "frequency", &freq) < 0) pr_err("No 'frequency' property in DT, using default."); else - pr_info("CPU frequency from device tree: %d", freq); + pr_info("CPU frequency from device tree: %dMHz", freq / 1000000); of_node_put(np); } mips_hpt_frequency = freq / 2; - - pll_reset_value = sw_r32(RTL838X_PLL_CML_CTRL); } diff --git a/target/linux/realtek/files-5.4/drivers/clocksource/timer-rtl9300.c b/target/linux/realtek/files-5.4/drivers/clocksource/timer-rtl9300.c new file mode 100644 index 0000000000..9ab1733fe3 --- /dev/null +++ b/target/linux/realtek/files-5.4/drivers/clocksource/timer-rtl9300.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include "timer-of.h" + +#include + +/* + * Timer registers + * the RTL9300/9310 SoCs have 6 timers, each register block 0x10 apart + */ +#define RTL9300_TC_DATA 0x0 +#define RTL9300_TC_CNT 0x4 +#define RTL9300_TC_CTRL 0x8 +#define RTL9300_TC_CTRL_MODE BIT(24) +#define RTL9300_TC_CTRL_EN BIT(28) +#define RTL9300_TC_INT 0xc +#define RTL9300_TC_INT_IP BIT(16) +#define RTL9300_TC_INT_IE BIT(20) + +// Clocksource is using timer 0, clock event uses timer 1 +#define TIMER_CLK_SRC 0 +#define TIMER_CLK_EVT 1 +#define TIMER_BLK_EVT (TIMER_CLK_EVT << 4) + +// Timer modes +#define TIMER_MODE_REPEAT 1 +#define TIMER_MODE_ONCE 0 + +// Minimum divider is 2 +#define DIVISOR_RTL9300 2 + +#define N_BITS 28 + +static void __iomem *rtl9300_sched_reg __read_mostly; + +static u64 notrace rtl9300_sched_clock_read(void) +{ +/* pr_info("In %s: %x\n", __func__, readl_relaxed(rtl9300_sched_reg)); + dump_stack();*/ + return readl_relaxed(rtl9300_sched_reg); +} + +static irqreturn_t rtl9300_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *clk = dev_id; + struct timer_of *to = to_timer_of(clk); + u32 v = readl(timer_of_base(to) + TIMER_BLK_EVT + RTL9300_TC_INT); + + // Acknowledge the IRQ + v |= RTL9300_TC_INT_IP; + writel(v, timer_of_base(to) + TIMER_BLK_EVT + RTL9300_TC_INT); + + clk->event_handler(clk); + return IRQ_HANDLED; +} + +static void rtl9300_timer_stop(struct timer_of *to) +{ + u32 v; + + writel(0, timer_of_base(to) + TIMER_BLK_EVT + RTL9300_TC_CTRL); + + // Acknowledge possibly pending IRQ + v = readl(timer_of_base(to) + TIMER_BLK_EVT + RTL9300_TC_INT); + if (v & RTL9300_TC_INT_IP) + writel(v, timer_of_base(to) + TIMER_BLK_EVT + RTL9300_TC_INT); +} + +static void rtl9300_timer_start(struct timer_of *to, int timer, bool periodic) +{ + u32 v = (periodic ? RTL9300_TC_CTRL_MODE : 0) | RTL9300_TC_CTRL_EN | DIVISOR_RTL9300; + writel(v, timer_of_base(to) + timer * 0x10 + RTL9300_TC_CTRL); +} + +static int rtl9300_set_next_event(unsigned long delta, struct clock_event_device *clk) +{ + struct timer_of *to = to_timer_of(clk); + + rtl9300_timer_stop(to); + writel(delta, timer_of_base(to) + TIMER_BLK_EVT + RTL9300_TC_DATA); + rtl9300_timer_start(to, TIMER_CLK_EVT, TIMER_MODE_ONCE); + return 0; +} + +static int rtl9300_set_state_periodic(struct clock_event_device *clk) +{ + struct timer_of *to = to_timer_of(clk); + + rtl9300_timer_stop(to); + writel(to->of_clk.period, timer_of_base(to) + TIMER_BLK_EVT + RTL9300_TC_DATA); + rtl9300_timer_start(to, TIMER_CLK_EVT, TIMER_MODE_REPEAT); + return 0; +} + +static int rtl9300_set_state_oneshot(struct clock_event_device *clk) +{ + struct timer_of *to = to_timer_of(clk); + + rtl9300_timer_stop(to); + writel(to->of_clk.period, timer_of_base(to) + TIMER_BLK_EVT + RTL9300_TC_DATA); + rtl9300_timer_start(to, TIMER_CLK_EVT, TIMER_MODE_ONCE); + return 0; +} + +static int rtl9300_set_state_shutdown(struct clock_event_device *clk) +{ + struct timer_of *to = to_timer_of(clk); + + rtl9300_timer_stop(to); + return 0; +} + +static struct timer_of t_of = { + .flags = TIMER_OF_BASE | TIMER_OF_IRQ | TIMER_OF_CLOCK, + + .clkevt = { + .name = "rtl9300_timer", + .rating = 350, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = rtl9300_set_next_event, + .set_state_oneshot = rtl9300_set_state_oneshot, + .set_state_periodic = rtl9300_set_state_periodic, + .set_state_shutdown = rtl9300_set_state_shutdown, + }, + + .of_irq = { + .name = "ostimer", + .handler = rtl9300_timer_interrupt, + .flags = IRQF_TIMER, + }, +}; + +static void __init rtl9300_timer_setup(u8 timer) +{ + u32 v; + + // Disable timer + writel(0, timer_of_base(&t_of) + 0x10 * timer + RTL9300_TC_CTRL); + + // Acknowledge possibly pending IRQ + v = readl(timer_of_base(&t_of) + 0x10 * timer + RTL9300_TC_INT); + if (v & RTL9300_TC_INT_IP) + writel(v, timer_of_base(&t_of) + 0x10 * timer + RTL9300_TC_INT); + + // Setup maximum period (for use as clock-source) + writel(0x0fffffff, timer_of_base(&t_of) + 0x10 * timer + RTL9300_TC_DATA); +} + + +static int __init rtl9300_timer_init(struct device_node *node) +{ + int err = 0; + unsigned long rate; + + pr_info("%s: setting up timer\n", __func__); + + err = timer_of_init(node, &t_of); + if (err) + return err; + + rate = timer_of_rate(&t_of) / DIVISOR_RTL9300; + pr_info("Frequency in dts: %ld, my rate is %ld, period %ld\n", + timer_of_rate(&t_of), rate, timer_of_period(&t_of)); + pr_info("With base %08x IRQ: %d\n", (u32)timer_of_base(&t_of), timer_of_irq(&t_of)); + + // Configure clock source and register it for scheduling + rtl9300_timer_setup(TIMER_CLK_SRC); + rtl9300_timer_start(&t_of, TIMER_CLK_SRC, TIMER_MODE_REPEAT); + + rtl9300_sched_reg = timer_of_base(&t_of) + TIMER_CLK_SRC * 0x10 + RTL9300_TC_CNT; + + err = clocksource_mmio_init(rtl9300_sched_reg, node->name, rate , 100, N_BITS, + clocksource_mmio_readl_up); + if (err) + return err; + + sched_clock_register(rtl9300_sched_clock_read, N_BITS, rate); + + // Configure clock event source + rtl9300_timer_setup(TIMER_CLK_EVT); + clockevents_config_and_register(&t_of.clkevt, rate, 100, 0x0fffffff); + + // Enable interrupt + writel(RTL9300_TC_INT_IE, timer_of_base(&t_of) + TIMER_BLK_EVT + RTL9300_TC_INT); + + return err; +} + +TIMER_OF_DECLARE(rtl9300_timer, "realtek,rtl9300-timer", rtl9300_timer_init); diff --git a/target/linux/realtek/patches-5.4/302-clocksource-add-rtl9300-driver.patch b/target/linux/realtek/patches-5.4/302-clocksource-add-rtl9300-driver.patch new file mode 100644 index 0000000000..763f6adc58 --- /dev/null +++ b/target/linux/realtek/patches-5.4/302-clocksource-add-rtl9300-driver.patch @@ -0,0 +1,34 @@ +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -126,6 +126,15 @@ + help + Enables the support for the RDA Micro timer driver. + ++config RTL9300_TIMER ++ bool "Clocksource/timer for the Realtek RTL9300 family of SoCs" ++ depends on MIPS ++ select COMMON_CLK ++ select TIMER_OF ++ select CLKSRC_MMIO ++ help ++ Enables support for the Realtek RTL9300 timer driver. ++ + config SUN4I_TIMER + bool "Sun4i timer driver" if COMPILE_TEST + depends on HAS_IOMEM +@@ -695,5 +704,4 @@ + select IRQ_DOMAIN + help + Support for the timer/counter unit of the Ingenic JZ SoCs. +- + endmenu +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -61,6 +61,7 @@ + obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o + obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o + obj-$(CONFIG_RDA_TIMER) += timer-rda.o ++obj-$(CONFIG_RTL9300_TIMER) += timer-rtl9300.o + + obj-$(CONFIG_ARC_TIMERS) += arc_timer.o + obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o From 4237488cf3de13b56484f728b77bdc746234954b Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 21:41:37 +0100 Subject: [PATCH 13/29] realtek: add dtsi for RTL930X SoCs Add a default dtsi to support RTL930X SoCs. Signed-off-by: Birger Koblitz --- target/linux/realtek/dts/rtl930x.dtsi | 182 ++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 target/linux/realtek/dts/rtl930x.dtsi diff --git a/target/linux/realtek/dts/rtl930x.dtsi b/target/linux/realtek/dts/rtl930x.dtsi new file mode 100644 index 0000000000..5d13fc31b3 --- /dev/null +++ b/target/linux/realtek/dts/rtl930x.dtsi @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +/dts-v1/; + +#define STRINGIZE(s) #s +#define LAN_LABEL(p, s) STRINGIZE(p ## s) +#define SWITCH_PORT_LABEL(n) LAN_LABEL(lan, n) + +#define INTERNAL_PHY(n) \ + phy##n: ethernet-phy@##n { \ + reg = <##n>; \ + compatible = "ethernet-phy-ieee802.3-c22"; \ + phy-is-integrated; \ + }; + +#define EXTERNAL_PHY(n) \ + phy##n: ethernet-phy@##n { \ + reg = <##n>; \ + compatible = "ethernet-phy-ieee802.3-c22"; \ + }; + +#define EXTERNAL_SFP_PHY(n) \ + phy##n: ethernet-phy@##n { \ + compatible = "ethernet-phy-ieee802.3-c22"; \ + sfp; \ + media = "fibre"; \ + reg = <##n>; \ + }; + +#define SWITCH_PORT(n, s, m) \ + port@##n { \ + reg = <##n>; \ + label = SWITCH_PORT_LABEL(s) ; \ + phy-handle = <&phy##n>; \ + phy-mode = #m ; \ + }; + +#define SWITCH_SFP_PORT(n, s, m) \ + port@##n { \ + reg = <##n>; \ + label = SWITCH_PORT_LABEL(s) ; \ + phy-handle = <&phy##n>; \ + phy-mode = #m ; \ + fixed-link { \ + speed = <1000>; \ + full-duplex; \ + }; \ + }; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "realtek,rtl838x-soc"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + frequency = <800000000>; + + cpu@0 { + compatible = "mips,mips34Kc"; + reg = <0>; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x8000000>; + }; + + chosen { + bootargs = "console=ttyS0,38400"; + }; + + cpuintc: cpuintc { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + + intc: rtlintc { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + compatible = "realtek,rt9300-intc"; + reg = <0xb8003000 0x20>; + }; + + osc: oscillator { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <175000000>; + clock-output-names = "osc"; + }; + + timer: timer@b8003200 { + compatible = "realtek,rtl9300-timer"; + reg = <0xb8003200 0x60>; + interrupt-parent = <&intc>; + interrupts = <8>; + interrupt-names = "ostimer"; + clocks = <&osc 0>; + }; + + spi0: spi@b8001200 { + status = "okay"; + + compatible = "realtek,rtl838x-nor"; + reg = <0xb8001200 0x100>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + uart0: uart@b8002000 { + compatible = "ns16550a"; + reg = <0xb8002000 0x100>; + + clock-frequency = <175000000>; + + interrupt-parent = <&intc>; + interrupts = <30>; + + reg-io-width = <1>; + reg-shift = <2>; + fifo-size = <1>; + no-loopback-test; + + status = "okay"; + }; + + uart1: uart@b8002100 { + compatible = "ns16550a"; + reg = <0xb8002100 0x100>; + + clock-frequency = <175000000>; + + interrupt-parent = <&intc>; + interrupts = <31>; + + reg-io-width = <1>; + reg-shift = <2>; + fifo-size = <1>; + no-loopback-test; + + status = "okay"; + }; + + gpio0: gpio-controller@b8003500 { + compatible = "realtek,rtl838x-gpio"; + reg = <0xb8003500 0x20>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <31>; + }; + + ethernet0: ethernet@bb00a300 { + status = "okay"; + compatible = "realtek,rtl838x-eth"; + reg = <0xbb00a300 0x100>; + interrupt-parent = <&intc>; + interrupts = <24>; + #interrupt-cells = <1>; + phy-mode = "internal"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + switch0: switch@bb000000 { + status = "okay"; + + interrupt-parent = <&intc>; + interrupts = <20>; + + compatible = "realtek,rtl83xx-switch"; + }; +}; From dc9cc0d3e2a1ede4bcf2e6b5b0aded4dc50244af Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 14:29:52 +0100 Subject: [PATCH 14/29] realtek: add QoS and rate control This adds support for identifying QoS information in packets and use this and rate control information to submit to multiple egress queues. The ethernet driver is also made to support 2 egress and up to 32 egress queues. Signed-off-by: Birger Koblitz --- .../drivers/net/dsa/rtl83xx/Makefile | 2 +- .../files-5.4/drivers/net/dsa/rtl83xx/qos.c | 576 ++++++++ .../drivers/net/dsa/rtl83xx/rtl838x.h | 265 +++- .../drivers/net/dsa/rtl83xx/rtl839x.c | 315 +++-- .../drivers/net/dsa/rtl83xx/rtl83xx.h | 83 +- .../drivers/net/ethernet/rtl838x_eth.c | 1246 ++++++++++++----- 6 files changed, 1956 insertions(+), 531 deletions(-) create mode 100644 target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile index 52cc151a56..016184c3d9 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_NET_DSA_RTL83XX) += common.o dsa.o \ - rtl838x.o rtl839x.o storm.o debugfs.o + rtl838x.o rtl839x.o rtl930x.o rtl931x.o debugfs.o qos.o diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c new file mode 100644 index 0000000000..2fc8d37f3e --- /dev/null +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +#include +#include "rtl83xx.h" + +static struct rtl838x_switch_priv *switch_priv; +extern struct rtl83xx_soc_info soc_info; + +enum scheduler_type { + WEIGHTED_FAIR_QUEUE = 0, + WEIGHTED_ROUND_ROBIN, +}; + +int max_available_queue[] = {0, 1, 2, 3, 4, 5, 6, 7}; +int default_queue_weights[] = {1, 1, 1, 1, 1, 1, 1, 1}; +int dot1p_priority_remapping[] = {0, 1, 2, 3, 4, 5, 6, 7}; + +static void rtl839x_read_scheduling_table(int port) +{ + u32 cmd = 1 << 9 /* Execute cmd */ + | 0 << 8 /* Read */ + | 0 << 6 /* Table type 0b00 */ + | (port & 0x3f); + rtl839x_exec_tbl2_cmd(cmd); +} + +static void rtl839x_write_scheduling_table(int port) +{ + u32 cmd = 1 << 9 /* Execute cmd */ + | 1 << 8 /* Write */ + | 0 << 6 /* Table type 0b00 */ + | (port & 0x3f); + rtl839x_exec_tbl2_cmd(cmd); +} + +static void rtl839x_read_out_q_table(int port) +{ + u32 cmd = 1 << 9 /* Execute cmd */ + | 0 << 8 /* Read */ + | 2 << 6 /* Table type 0b10 */ + | (port & 0x3f); + rtl839x_exec_tbl2_cmd(cmd); +} + +static void rtl838x_storm_enable(struct rtl838x_switch_priv *priv, int port, bool enable) +{ + // Enable Storm control for that port for UC, MC, and BC + if (enable) + sw_w32(0x7, RTL838X_STORM_CTRL_LB_CTRL(port)); + else + sw_w32(0x0, RTL838X_STORM_CTRL_LB_CTRL(port)); +} + +u32 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port) +{ + u32 rate; + + if (port > priv->cpu_port) + return 0; + rate = sw_r32(RTL838X_SCHED_P_EGR_RATE_CTRL(port)) & 0x3fff; + return rate; +} + +/* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */ +int rtl838x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate) +{ + u32 old_rate; + + if (port > priv->cpu_port) + return -1; + + old_rate = sw_r32(RTL838X_SCHED_P_EGR_RATE_CTRL(port)); + sw_w32(rate, RTL838X_SCHED_P_EGR_RATE_CTRL(port)); + + return old_rate; +} + +/* Set the rate limit for a particular queue in Bits/s + * units of the rate is 16Kbps + */ +void rtl838x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port, + int queue, u32 rate) +{ + if (port > priv->cpu_port) + return; + if (queue > 7) + return; + sw_w32(rate, RTL838X_SCHED_Q_EGR_RATE_CTRL(port, queue)); +} + +static void rtl838x_rate_control_init(struct rtl838x_switch_priv *priv) +{ + int i; + + pr_info("Enabling Storm control\n"); + // TICK_PERIOD_PPS + if (priv->id == 0x8380) + sw_w32_mask(0x3ff << 20, 434 << 20, RTL838X_SCHED_LB_TICK_TKN_CTRL_0); + + // Set burst rate + sw_w32(0x00008000, RTL838X_STORM_CTRL_BURST_0); // UC + sw_w32(0x80008000, RTL838X_STORM_CTRL_BURST_1); // MC and BC + + // Set burst Packets per Second to 32 + sw_w32(0x00000020, RTL838X_STORM_CTRL_BURST_PPS_0); // UC + sw_w32(0x00200020, RTL838X_STORM_CTRL_BURST_PPS_1); // MC and BC + + // Include IFG in storm control, rate based on bytes/s (0 = packets) + sw_w32_mask(0, 1 << 6 | 1 << 5, RTL838X_STORM_CTRL); + // Bandwidth control includes preamble and IFG (10 Bytes) + sw_w32_mask(0, 1, RTL838X_SCHED_CTRL); + + // On SoCs except RTL8382M, set burst size of port egress + if (priv->id != 0x8382) + sw_w32_mask(0xffff, 0x800, RTL838X_SCHED_LB_THR); + + /* Enable storm control on all ports with a PHY and limit rates, + * for UC and MC for both known and unknown addresses */ + for (i = 0; i < priv->cpu_port; i++) { + if (priv->ports[i].phy) { + sw_w32((1 << 18) | 0x8000, RTL838X_STORM_CTRL_PORT_UC(i)); + sw_w32((1 << 18) | 0x8000, RTL838X_STORM_CTRL_PORT_MC(i)); + sw_w32(0x8000, RTL838X_STORM_CTRL_PORT_BC(i)); + rtl838x_storm_enable(priv, i, true); + } + } + + // Attack prevention, enable all attack prevention measures + //sw_w32(0x1ffff, RTL838X_ATK_PRVNT_CTRL); + /* Attack prevention, drop (bit = 0) problematic packets on all ports. + * Setting bit = 1 means: trap to CPU + */ + //sw_w32(0, RTL838X_ATK_PRVNT_ACT); + // Enable attack prevention on all ports + //sw_w32(0x0fffffff, RTL838X_ATK_PRVNT_PORT_EN); +} + +/* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */ +u32 rtl839x_get_egress_rate(struct rtl838x_switch_priv *priv, int port) +{ + u32 rate; + + pr_debug("%s: Getting egress rate on port %d to %d\n", __func__, port, rate); + if (port >= priv->cpu_port) + return 0; + + mutex_lock(&priv->reg_mutex); + + rtl839x_read_scheduling_table(port); + + rate = sw_r32(RTL839X_TBL_ACCESS_DATA_2(7)); + rate <<= 12; + rate |= sw_r32(RTL839X_TBL_ACCESS_DATA_2(8)) >> 20; + + mutex_unlock(&priv->reg_mutex); + + return rate; +} + +/* Sets the rate limit, 10MBit/s is equal to a rate value of 625, returns previous rate */ +int rtl839x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate) +{ + u32 old_rate; + + pr_debug("%s: Setting egress rate on port %d to %d\n", __func__, port, rate); + if (port >= priv->cpu_port) + return -1; + + mutex_lock(&priv->reg_mutex); + + rtl839x_read_scheduling_table(port); + + old_rate = sw_r32(RTL839X_TBL_ACCESS_DATA_2(7)) & 0xff; + old_rate <<= 12; + old_rate |= sw_r32(RTL839X_TBL_ACCESS_DATA_2(8)) >> 20; + sw_w32_mask(0xff, (rate >> 12) & 0xff, RTL839X_TBL_ACCESS_DATA_2(7)); + sw_w32_mask(0xfff << 20, rate << 20, RTL839X_TBL_ACCESS_DATA_2(8)); + + rtl839x_write_scheduling_table(port); + + mutex_unlock(&priv->reg_mutex); + + return old_rate; +} + +/* Set the rate limit for a particular queue in Bits/s + * units of the rate is 16Kbps + */ +void rtl839x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port, + int queue, u32 rate) +{ + int lsb = 128 + queue * 20; + int low_byte = 8 - (lsb >> 5); + int start_bit = lsb - (low_byte << 5); + u32 high_mask = 0xfffff >> (32 - start_bit); + + pr_debug("%s: Setting egress rate on port %d, queue %d to %d\n", + __func__, port, queue, rate); + if (port >= priv->cpu_port) + return; + if (queue > 7) + return; + + mutex_lock(&priv->reg_mutex); + + rtl839x_read_scheduling_table(port); + + sw_w32_mask(0xfffff << start_bit, (rate & 0xfffff) << start_bit, + RTL839X_TBL_ACCESS_DATA_2(low_byte)); + if (high_mask) + sw_w32_mask(high_mask, (rate & 0xfffff) >> (32- start_bit), + RTL839X_TBL_ACCESS_DATA_2(low_byte - 1)); + + rtl839x_write_scheduling_table(port); + + mutex_unlock(&priv->reg_mutex); +} + +static void rtl839x_rate_control_init(struct rtl838x_switch_priv *priv) +{ + int p, q; + + pr_info("%s: enabling rate control\n", __func__); + /* Tick length and token size settings for SoC with 250MHz, + * RTL8350 family would use 50MHz + */ + // Set the special tick period + sw_w32(976563, RTL839X_STORM_CTRL_SPCL_LB_TICK_TKN_CTRL); + // Ingress tick period and token length 10G + sw_w32(18 << 11 | 151, RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_0); + // Ingress tick period and token length 1G + sw_w32(245 << 11 | 129, RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_1); + // Egress tick period 10G, bytes/token 10G and tick period 1G, bytes/token 1G + sw_w32(18 << 24 | 151 << 16 | 185 << 8 | 97, RTL839X_SCHED_LB_TICK_TKN_CTRL); + // Set the tick period of the CPU and the Token Len + sw_w32(3815 << 8 | 1, RTL839X_SCHED_LB_TICK_TKN_PPS_CTRL); + + // Set the Weighted Fair Queueing burst size + sw_w32_mask(0xffff, 4500, RTL839X_SCHED_LB_THR); + + // Storm-rate calculation is based on bytes/sec (bit 5), include IFG (bit 6) + sw_w32_mask(0, 1 << 5 | 1 << 6, RTL839X_STORM_CTRL); + + /* Based on the rate control mode being bytes/s + * set tick period and token length for 10G + */ + sw_w32(18 << 10 | 151, RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_0); + /* and for 1G ports */ + sw_w32(246 << 10 | 129, RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_1); + + /* Set default burst rates on all ports (the same for 1G / 10G) with a PHY + * for UC, MC and BC + * For 1G port, the minimum burst rate is 1700, maximum 65535, + * For 10G ports it is 2650 and 1048575 respectively */ + for (p = 0; p < priv->cpu_port; p++) { + if (priv->ports[p].phy && !priv->ports[p].is10G) { + sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_UC_1(p)); + sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_MC_1(p)); + sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_BC_1(p)); + } + } + + /* Setup ingress/egress per-port rate control */ + for (p = 0; p < priv->cpu_port; p++) { + if (!priv->ports[p].phy) + continue; + + if (priv->ports[p].is10G) + rtl839x_set_egress_rate(priv, p, 625000); // 10GB/s + else + rtl839x_set_egress_rate(priv, p, 62500); // 1GB/s + + // Setup queues: all RTL83XX SoCs have 8 queues, maximum rate + for (q = 0; q < 8; q++) + rtl839x_egress_rate_queue_limit(priv, p, q, 0xfffff); + + if (priv->ports[p].is10G) { + // Set high threshold to maximum + sw_w32_mask(0xffff, 0xffff, RTL839X_IGR_BWCTRL_PORT_CTRL_10G_0(p)); + } else { + // Set high threshold to maximum + sw_w32_mask(0xffff, 0xffff, RTL839X_IGR_BWCTRL_PORT_CTRL_1(p)); + } + } + + // Set global ingress low watermark rate + sw_w32(65532, RTL839X_IGR_BWCTRL_CTRL_LB_THR); +} + + + +void rtl838x_setup_prio2queue_matrix(int *min_queues) +{ + int i; + u32 v; + + pr_info("Current Intprio2queue setting: %08x\n", sw_r32(RTL838X_QM_INTPRI2QID_CTRL)); + for (i = 0; i < MAX_PRIOS; i++) + v |= i << (min_queues[i] * 3); + sw_w32(v, RTL838X_QM_INTPRI2QID_CTRL); +} + +void rtl839x_setup_prio2queue_matrix(int *min_queues) +{ + int i, q; + + pr_info("Current Intprio2queue setting: %08x\n", sw_r32(RTL839X_QM_INTPRI2QID_CTRL(0))); + for (i = 0; i < MAX_PRIOS; i++) { + q = min_queues[i]; + sw_w32(i << (q * 3), RTL839X_QM_INTPRI2QID_CTRL(q)); + } +} + +/* Sets the CPU queue depending on the internal priority of a packet */ +void rtl83xx_setup_prio2queue_cpu_matrix(int *max_queues) +{ + int reg = soc_info.family == RTL8380_FAMILY_ID ? RTL838X_QM_PKT2CPU_INTPRI_MAP + : RTL839X_QM_PKT2CPU_INTPRI_MAP; + int i; + u32 v; + + pr_info("QM_PKT2CPU_INTPRI_MAP: %08x\n", sw_r32(reg)); + for (i = 0; i < MAX_PRIOS; i++) + v |= max_queues[i] << (i * 3); + sw_w32(v, reg); +} + +void rtl83xx_setup_default_prio2queue(void) +{ + if (soc_info.family == RTL8380_FAMILY_ID) { + rtl838x_setup_prio2queue_matrix(max_available_queue); + } else { + rtl839x_setup_prio2queue_matrix(max_available_queue); + } + rtl83xx_setup_prio2queue_cpu_matrix(max_available_queue); +} + +/* Sets the output queue assigned to a port, the port can be the CPU-port */ +void rtl839x_set_egress_queue(int port, int queue) +{ + sw_w32(queue << ((port % 10) *3), RTL839X_QM_PORT_QNUM(port)); +} + +/* Sets the priority assigned of an ingress port, the port can be the CPU-port */ +void rtl83xx_set_ingress_priority(int port, int priority) +{ + if (soc_info.family == RTL8380_FAMILY_ID) + sw_w32(priority << ((port % 10) *3), RTL838X_PRI_SEL_PORT_PRI(port)); + else + sw_w32(priority << ((port % 10) *3), RTL839X_PRI_SEL_PORT_PRI(port)); + +} + +int rtl839x_get_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port) +{ + u32 v; + + mutex_lock(&priv->reg_mutex); + + rtl839x_read_scheduling_table(port); + v = sw_r32(RTL839X_TBL_ACCESS_DATA_2(8)); + + mutex_unlock(&priv->reg_mutex); + + if (v & BIT(19)) + return WEIGHTED_ROUND_ROBIN; + return WEIGHTED_FAIR_QUEUE; +} + +void rtl839x_set_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port, + enum scheduler_type sched) +{ + enum scheduler_type t = rtl839x_get_scheduling_algorithm(priv, port); + u32 v, oam_state, oam_port_state; + u32 count; + int i, egress_rate; + + mutex_lock(&priv->reg_mutex); + /* Check whether we need to empty the egress queue of that port due to Errata E0014503 */ + if (sched == WEIGHTED_FAIR_QUEUE && t == WEIGHTED_ROUND_ROBIN && port != priv->cpu_port) { + // Read Operations, Adminstatrion and Management control register + oam_state = sw_r32(RTL839X_OAM_CTRL); + + // Get current OAM state + oam_port_state = sw_r32(RTL839X_OAM_PORT_ACT_CTRL(port)); + + // Disable OAM to block traffice + v = sw_r32(RTL839X_OAM_CTRL); + sw_w32_mask(0, 1, RTL839X_OAM_CTRL); + v = sw_r32(RTL839X_OAM_CTRL); + + // Set to trap action OAM forward (bits 1, 2) and OAM Mux Action Drop (bit 0) + sw_w32(0x2, RTL839X_OAM_PORT_ACT_CTRL(port)); + + // Set port egress rate to unlimited + egress_rate = rtl839x_set_egress_rate(priv, port, 0xFFFFF); + + // Wait until the egress used page count of that port is 0 + i = 0; + do { + usleep_range(100, 200); + rtl839x_read_out_q_table(port); + count = sw_r32(RTL839X_TBL_ACCESS_DATA_2(6)); + count >>= 20; + i++; + } while (i < 3500 && count > 0); + } + + // Actually set the scheduling algorithm + rtl839x_read_scheduling_table(port); + sw_w32_mask(BIT(19), sched ? BIT(19) : 0, RTL839X_TBL_ACCESS_DATA_2(8)); + rtl839x_write_scheduling_table(port); + + if (sched == WEIGHTED_FAIR_QUEUE && t == WEIGHTED_ROUND_ROBIN && port != priv->cpu_port) { + // Restore OAM state to control register + sw_w32(oam_state, RTL839X_OAM_CTRL); + + // Restore trap action state + sw_w32(oam_port_state, RTL839X_OAM_PORT_ACT_CTRL(port)); + + // Restore port egress rate + rtl839x_set_egress_rate(priv, port, egress_rate); + } + + mutex_unlock(&priv->reg_mutex); +} + +void rtl839x_set_scheduling_queue_weights(struct rtl838x_switch_priv *priv, int port, + int *queue_weights) +{ + int i, lsb, low_byte, start_bit, high_mask; + + mutex_lock(&priv->reg_mutex); + + rtl839x_read_scheduling_table(port); + + for (i = 0; i < 8; i++) { + lsb = 48 + i * 8; + low_byte = 8 - (lsb >> 5); + start_bit = lsb - (low_byte << 5); + high_mask = 0x3ff >> (32 - start_bit); + sw_w32_mask(0x3ff << start_bit, (queue_weights[i] & 0x3ff) << start_bit, + RTL839X_TBL_ACCESS_DATA_2(low_byte)); + if (high_mask) + sw_w32_mask(high_mask, (queue_weights[i] & 0x3ff) >> (32- start_bit), + RTL839X_TBL_ACCESS_DATA_2(low_byte - 1)); + } + + rtl839x_write_scheduling_table(port); + mutex_unlock(&priv->reg_mutex); +} + +void rtl838x_config_qos(void) +{ + int i, p; + u32 v; + + pr_info("Setting up RTL838X QoS\n"); + pr_info("RTL838X_PRI_SEL_TBL_CTRL(i): %08x\n", sw_r32(RTL838X_PRI_SEL_TBL_CTRL(0))); + rtl83xx_setup_default_prio2queue(); + + // Enable inner (bit 12) and outer (bit 13) priority remapping from DSCP + sw_w32_mask(0, BIT(12) | BIT(13), RTL838X_PRI_DSCP_INVLD_CTRL0); + + /* Set default weight for calculating internal priority, in prio selection group 0 + * Port based (prio 3), Port outer-tag (4), DSCP (5), Inner Tag (6), Outer Tag (7) + */ + v = 3 | (4 << 3) | (5 << 6) | (6 << 9) | (7 << 12); + sw_w32(v, RTL838X_PRI_SEL_TBL_CTRL(0)); + + // Set the inner and outer priority one-to-one to re-marked outer dot1p priority + v = 0; + for (p = 0; p < 8; p++) + v |= p << (3 * p); + sw_w32(v, RTL838X_RMK_OPRI_CTRL); + sw_w32(v, RTL838X_RMK_IPRI_CTRL); + + v = 0; + for (p = 0; p < 8; p++) + v |= (dot1p_priority_remapping[p] & 0x7) << (p * 3); + sw_w32(v, RTL838X_PRI_SEL_IPRI_REMAP); + + // On all ports set scheduler type to WFQ + for (i = 0; i <= soc_info.cpu_port; i++) + sw_w32(0, RTL838X_SCHED_P_TYPE_CTRL(i)); + + // Enable egress scheduler for CPU-Port + sw_w32_mask(0, BIT(8), RTL838X_SCHED_LB_CTRL(soc_info.cpu_port)); + + // Enable egress drop allways on + sw_w32_mask(0, BIT(11), RTL838X_FC_P_EGR_DROP_CTRL(soc_info.cpu_port)); + + // Give special trap frames priority 7 (BPDUs) and routing exceptions: + sw_w32_mask(0, 7 << 3 | 7, RTL838X_QM_PKT2CPU_INTPRI_2); + // Give RMA frames priority 7: + sw_w32_mask(0, 7, RTL838X_QM_PKT2CPU_INTPRI_1); +} + +void rtl839x_config_qos(void) +{ + int port, p, q; + u32 v; + struct rtl838x_switch_priv *priv = switch_priv; + + pr_info("Setting up RTL839X QoS\n"); + pr_info("RTL839X_PRI_SEL_TBL_CTRL(i): %08x\n", sw_r32(RTL839X_PRI_SEL_TBL_CTRL(0))); + rtl83xx_setup_default_prio2queue(); + + for (port = 0; port < soc_info.cpu_port; port++) + sw_w32(7, RTL839X_QM_PORT_QNUM(port)); + + // CPU-port gets queue number 7 + sw_w32(7, RTL839X_QM_PORT_QNUM(soc_info.cpu_port)); + + for (port = 0; port <= soc_info.cpu_port; port++) { + rtl83xx_set_ingress_priority(port, 0); + rtl839x_set_scheduling_algorithm(priv, port, WEIGHTED_FAIR_QUEUE); + rtl839x_set_scheduling_queue_weights(priv, port, default_queue_weights); + // Do re-marking based on outer tag + sw_w32_mask(0, BIT(port % 32), RTL839X_RMK_PORT_DEI_TAG_CTRL(port)); + } + + // Remap dot1p priorities to internal priority, for this the outer tag needs be re-marked + v = 0; + for (p = 0; p < 8; p++) + v |= (dot1p_priority_remapping[p] & 0x7) << (p * 3); + sw_w32(v, RTL839X_PRI_SEL_IPRI_REMAP); + + /* Configure Drop Precedence for Drop Eligible Indicator (DEI) + * Index 0: 0 + * Index 1: 2 + * Each indicator is 2 bits long + */ + sw_w32(2 << 2, RTL839X_PRI_SEL_DEI2DP_REMAP); + + // Re-mark DEI: 4 bit-fields of 2 bits each, field 0 is bits 0-1, ... + sw_w32((0x1 << 2) | (0x1 << 4), RTL839X_RMK_DEI_CTRL); + + /* Set Congestion avoidance drop probability to 0 for drop precedences 0-2 (bits 24-31) + * low threshold (bits 0-11) to 4095 and high threshold (bits 12-23) to 4095 + * Weighted Random Early Detection (WRED) is used + */ + sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(0)); + sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(1)); + sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(2)); + + /* Set queue-based congestion avoidance properties, register fields are as + * for forward RTL839X_WRED_PORT_THR_CTRL + */ + for (q = 0; q < 8; q++) { + sw_w32(255 << 24 | 78 << 12 | 68, RTL839X_WRED_QUEUE_THR_CTRL(q, 0)); + sw_w32(255 << 24 | 74 << 12 | 64, RTL839X_WRED_QUEUE_THR_CTRL(q, 0)); + sw_w32(255 << 24 | 70 << 12 | 60, RTL839X_WRED_QUEUE_THR_CTRL(q, 0)); + } +} + +void __init rtl83xx_setup_qos(struct rtl838x_switch_priv *priv) +{ + switch_priv = priv; + + pr_info("In %s\n", __func__); + + if (priv->family_id == RTL8380_FAMILY_ID) + return rtl838x_config_qos(); + else if (priv->family_id == RTL8390_FAMILY_ID) + return rtl839x_config_qos(); + + if (priv->family_id == RTL8380_FAMILY_ID) + rtl838x_rate_control_init(priv); + else if (priv->family_id == RTL8390_FAMILY_ID) + rtl839x_rate_control_init(priv); + +} diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h index 1ebb4dff72..d5ca153a10 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.h @@ -8,14 +8,18 @@ /* * Register definition */ -#define RTL838X_CPU_PORT 28 -#define RTL839X_CPU_PORT 52 - #define RTL838X_MAC_PORT_CTRL(port) (0xd560 + (((port) << 7))) #define RTL839X_MAC_PORT_CTRL(port) (0x8004 + (((port) << 7))) +#define RTL930X_MAC_PORT_CTRL(port) (0x3260 + (((port) << 6))) +#define RTL930X_MAC_L2_PORT_CTRL(port) (0x3268 + (((port) << 6))) +#define RTL931X_MAC_PORT_CTRL(port) (0x6004 + (((port) << 7))) + #define RTL838X_RST_GLB_CTRL_0 (0x003c) + #define RTL838X_MAC_FORCE_MODE_CTRL (0xa104) #define RTL839X_MAC_FORCE_MODE_CTRL (0x02bc) +#define RTL930X_MAC_FORCE_MODE_CTRL (0xCA1C) +#define RTL931X_MAC_FORCE_MODE_CTRL (0x0DCC) #define RTL838X_DMY_REG31 (0x3b28) #define RTL838X_SDS_MODE_SEL (0x0028) @@ -23,20 +27,25 @@ #define RTL838X_INT_MODE_CTRL (0x005c) #define RTL838X_CHIP_INFO (0x00d8) #define RTL839X_CHIP_INFO (0x0ff4) -#define RTL838X_SDS4_REG28 (0xef80) -#define RTL838X_SDS4_DUMMY0 (0xef8c) -#define RTL838X_SDS5_EXT_REG6 (0xf18c) #define RTL838X_PORT_ISO_CTRL(port) (0x4100 + ((port) << 2)) #define RTL839X_PORT_ISO_CTRL(port) (0x1400 + ((port) << 3)) -#define RTL8380_SDS4_FIB_REG0 (0xF800) + +/* Packet statistics */ #define RTL838X_STAT_PORT_STD_MIB (0x1200) #define RTL839X_STAT_PORT_STD_MIB (0xC000) +#define RTL930X_STAT_PORT_MIB_CNTR (0x0664) #define RTL838X_STAT_RST (0x3100) #define RTL839X_STAT_RST (0xF504) +#define RTL930X_STAT_RST (0x3240) +#define RTL931X_STAT_RST (0x7ef4) #define RTL838X_STAT_PORT_RST (0x3104) #define RTL839X_STAT_PORT_RST (0xF508) +#define RTL930X_STAT_PORT_RST (0x3244) +#define RTL931X_STAT_PORT_RST (0x7ef8) #define RTL838X_STAT_CTRL (0x3108) #define RTL839X_STAT_CTRL (0x04cc) +#define RTL930X_STAT_CTRL (0x3248) +#define RTL931X_STAT_CTRL (0x5720) /* Registers of the internal Serdes of the 8390 */ #define RTL8390_SDS0_1_XSG0 (0xA000) @@ -47,53 +56,95 @@ #define RTL839X_SDS12_13_PWR1 (0xb980) /* Registers of the internal Serdes of the 8380 */ -#define MAPLE_SDS4_REG0r RTL838X_SDS4_REG28 -#define MAPLE_SDS5_REG0r (RTL838X_SDS4_REG28 + 0x100) -#define MAPLE_SDS4_REG3r RTL838X_SDS4_DUMMY0 -#define MAPLE_SDS5_REG3r (RTL838X_SDS4_REG28 + 0x100) -#define MAPLE_SDS4_FIB_REG0r (RTL838X_SDS4_REG28 + 0x880) -#define MAPLE_SDS5_FIB_REG0r (RTL838X_SDS4_REG28 + 0x980) +#define RTL838X_SDS4_FIB_REG0 (0xF800) +#define RTL838X_SDS4_REG28 (0xef80) +#define RTL838X_SDS4_DUMMY0 (0xef8c) +#define RTL838X_SDS5_EXT_REG6 (0xf18c) /* VLAN registers */ +#define RTL838X_VLAN_CTRL (0x3A74) #define RTL838X_VLAN_PROFILE(idx) (0x3A88 + ((idx) << 2)) #define RTL838X_VLAN_PORT_EGR_FLTR (0x3A84) -#define RTL838X_VLAN_PORT_PB_VLAN(port) (0x3C00 + ((port) << 2)) +#define RTL838X_VLAN_PORT_PB_VLAN (0x3C00) #define RTL838X_VLAN_PORT_IGR_FLTR(port) (0x3A7C + (((port >> 4) << 2))) #define RTL838X_VLAN_PORT_IGR_FLTR_0 (0x3A7C) #define RTL838X_VLAN_PORT_IGR_FLTR_1 (0x3A7C + 4) -#define RTL838X_VLAN_PORT_TAG_STS_CTRL(port) (0xA530 + (((port) << 2))) +#define RTL838X_VLAN_PORT_TAG_STS_CTRL (0xA530) + #define RTL839X_VLAN_PROFILE(idx) (0x25C0 + (((idx) << 3))) #define RTL839X_VLAN_CTRL (0x26D4) -#define RTL839X_VLAN_PORT_PB_VLAN(port) (0x26D8 + (((port) << 2))) +#define RTL839X_VLAN_PORT_PB_VLAN (0x26D8) #define RTL839X_VLAN_PORT_IGR_FLTR(port) (0x27B4 + (((port >> 4) << 2))) #define RTL839X_VLAN_PORT_EGR_FLTR(port) (0x27C4 + (((port >> 5) << 2))) -#define RTL839X_VLAN_PORT_TAG_STS_CTRL(port) (0x6828 + (((port) << 2))) +#define RTL839X_VLAN_PORT_TAG_STS_CTRL (0x6828) -/* Table 0/1 access registers */ +#define RTL930X_VLAN_PROFILE_SET(idx) (0x9c60 + (((idx) * 20))) +#define RTL930X_VLAN_CTRL (0x82D4) +#define RTL930X_VLAN_PORT_PB_VLAN (0x82D8) +#define RTL930X_VLAN_PORT_IGR_FLTR(port) (0x83C0 + (((port >> 4) << 2))) +#define RTL930X_VLAN_PORT_EGR_FLTR (0x83C8) +#define RTL930X_VLAN_PORT_TAG_STS_CTRL (0xCE24) + +#define RTL931X_VLAN_PROFILE_SET(idx) (0x9800 + (((idx) * 28))) +#define RTL931X_VLAN_CTRL (0x94E4) +#define RTL931X_VLAN_PORT_IGR_FLTR(port) (0x96B4 + (((port >> 4) << 2))) +#define RTL931X_VLAN_PORT_EGR_FLTR(port) (0x96C4 + (((port >> 5) << 2))) +#define RTL931X_VLAN_PORT_TAG_CTRL (0x4860) + +/* Table access registers */ #define RTL838X_TBL_ACCESS_CTRL_0 (0x6914) #define RTL838X_TBL_ACCESS_DATA_0(idx) (0x6918 + ((idx) << 2)) #define RTL838X_TBL_ACCESS_CTRL_1 (0xA4C8) #define RTL838X_TBL_ACCESS_DATA_1(idx) (0xA4CC + ((idx) << 2)) + #define RTL839X_TBL_ACCESS_CTRL_0 (0x1190) #define RTL839X_TBL_ACCESS_DATA_0(idx) (0x1194 + ((idx) << 2)) #define RTL839X_TBL_ACCESS_CTRL_1 (0x6b80) #define RTL839X_TBL_ACCESS_DATA_1(idx) (0x6b84 + ((idx) << 2)) +#define RTL839X_TBL_ACCESS_CTRL_2 (0x611C) +#define RTL839X_TBL_ACCESS_DATA_2(i) (0x6120 + (((i) << 2))) + +#define RTL930X_TBL_ACCESS_CTRL_0 (0xB340) +#define RTL930X_TBL_ACCESS_DATA_0(idx) (0xB344 + ((idx) << 2)) +#define RTL930X_TBL_ACCESS_CTRL_1 (0xB3A0) +#define RTL930X_TBL_ACCESS_DATA_1(idx) (0xB3A4 + ((idx) << 2)) +#define RTL930X_TBL_ACCESS_CTRL_2 (0xCE04) +#define RTL930X_TBL_ACCESS_DATA_2(i) (0xCE08 + (((i) << 2))) + +#define RTL931X_TBL_ACCESS_CTRL_0 (0x8500) +#define RTL931X_TBL_ACCESS_DATA_0(idx) (0x8508 + ((idx) << 2)) +#define RTL931X_TBL_ACCESS_CTRL_1 (0x40C0) +#define RTL931X_TBL_ACCESS_DATA_1(idx) (0x40C4 + ((idx) << 2)) +#define RTL931X_TBL_ACCESS_CTRL_2 (0x8528) +#define RTL931X_TBL_ACCESS_DATA_2(i) (0x852C + (((i) << 2))) +#define RTL931X_TBL_ACCESS_CTRL_3 (0x0200) +#define RTL931X_TBL_ACCESS_DATA_3(i) (0x0204 + (((i) << 2))) +#define RTL931X_TBL_ACCESS_CTRL_4 (0x20DC) +#define RTL931X_TBL_ACCESS_DATA_4(i) (0x20E0 + (((i) << 2))) +#define RTL931X_TBL_ACCESS_CTRL_5 (0x7E1C) +#define RTL931X_TBL_ACCESS_DATA_5(i) (0x7E20 + (((i) << 2))) /* MAC handling */ #define RTL838X_MAC_LINK_STS (0xa188) #define RTL839X_MAC_LINK_STS (0x0390) -#define RTL838X_MAC_LINK_SPD_STS(port) (0xa190 + (((port >> 4) << 2))) -#define RTL839X_MAC_LINK_SPD_STS(port) (0x03a0 + (((port >> 4) << 2))) +#define RTL930X_MAC_LINK_STS (0xCB10) +#define RTL931X_MAC_LINK_STS (0x0EC0) +#define RTL838X_MAC_LINK_SPD_STS(p) (0xa190 + (((p >> 4) << 2))) +#define RTL839X_MAC_LINK_SPD_STS(p) (0x03a0 + (((p >> 4) << 2))) +#define RTL930X_MAC_LINK_SPD_STS(p) (0xCB18 + (((p >> 3) << 2))) +#define RTL931X_MAC_LINK_SPD_STS(p) (0x0ED0 + (((p >> 3) << 2))) #define RTL838X_MAC_LINK_DUP_STS (0xa19c) #define RTL839X_MAC_LINK_DUP_STS (0x03b0) +#define RTL930X_MAC_LINK_DUP_STS (0xCB28) +#define RTL931X_MAC_LINK_DUP_STS (0x0EF0) #define RTL838X_MAC_TX_PAUSE_STS (0xa1a0) #define RTL839X_MAC_TX_PAUSE_STS (0x03b8) +#define RTL930X_MAC_TX_PAUSE_STS (0xCB2C) +#define RTL931X_MAC_TX_PAUSE_STS (0x0EF8) #define RTL838X_MAC_RX_PAUSE_STS (0xa1a4) #define RTL839X_MAC_RX_PAUSE_STS (0x03c0) -#define RTL838X_EEE_TX_TIMER_GIGA_CTRL (0xaa04) -#define RTL838X_EEE_TX_TIMER_GELITE_CTRL (0xaa08) - -#define RTL838X_DMA_IF_CTRL (0x9f58) +#define RTL930X_MAC_RX_PAUSE_STS (0xCB30) +#define RTL931X_MAC_RX_PAUSE_STS (0x0F00) /* MAC link state bits */ #define FORCE_EN (1 << 0) @@ -108,36 +159,71 @@ #define RTL838X_EEE_PORT_TX_EN (0x014c) #define RTL838X_EEE_PORT_RX_EN (0x0150) #define RTL838X_EEE_CLK_STOP_CTRL (0x0148) +#define RTL838X_EEE_TX_TIMER_GIGA_CTRL (0xaa04) +#define RTL838X_EEE_TX_TIMER_GELITE_CTRL (0xaa08) /* L2 functionality */ #define RTL838X_L2_CTRL_0 (0x3200) #define RTL839X_L2_CTRL_0 (0x3800) +#define RTL930X_L2_CTRL (0x8FD8) +#define RTL931X_L2_CTRL (0xC800) #define RTL838X_L2_CTRL_1 (0x3204) #define RTL839X_L2_CTRL_1 (0x3804) +#define RTL930X_L2_AGE_CTRL (0x8FDC) +#define RTL931X_L2_AGE_CTRL (0xC804) #define RTL838X_L2_PORT_AGING_OUT (0x3358) #define RTL839X_L2_PORT_AGING_OUT (0x3b74) +#define RTL930X_L2_PORT_AGE_CTRL (0x8FE0) +#define RTL931X_L2_PORT_AGE_CTRL (0xc808) #define RTL838X_TBL_ACCESS_L2_CTRL (0x6900) #define RTL839X_TBL_ACCESS_L2_CTRL (0x1180) +#define RTL930X_TBL_ACCESS_L2_CTRL (0xB320) +#define RTL930X_TBL_ACCESS_L2_METHOD_CTRL (0xB324) #define RTL838X_TBL_ACCESS_L2_DATA(idx) (0x6908 + ((idx) << 2)) #define RTL839X_TBL_ACCESS_L2_DATA(idx) (0x1184 + ((idx) << 2)) +#define RTL930X_TBL_ACCESS_L2_DATA(idx) (0xab08 + ((idx) << 2)) #define RTL838X_L2_TBL_FLUSH_CTRL (0x3370) #define RTL839X_L2_TBL_FLUSH_CTRL (0x3ba0) +#define RTL930X_L2_TBL_FLUSH_CTRL (0x9404) +#define RTL931X_L2_TBL_FLUSH_CTRL (0xCD9C) + #define RTL838X_L2_PORT_NEW_SALRN(p) (0x328c + (((p >> 4) << 2))) #define RTL839X_L2_PORT_NEW_SALRN(p) (0x38F0 + (((p >> 4) << 2))) +#define RTL930X_L2_PORT_SALRN(p) (0x8FEC + (((p >> 4) << 2))) +#define RTL931X_L2_PORT_NEW_SALRN(p) (0xC820 + (((p >> 4) << 2))) #define RTL838X_L2_PORT_NEW_SA_FWD(p) (0x3294 + (((p >> 4) << 2))) #define RTL839X_L2_PORT_NEW_SA_FWD(p) (0x3900 + (((p >> 4) << 2))) -#define RTL838X_L2_PORT_SALRN(p) (0x328c + (((p >> 4) << 2))) -#define RTL839X_L2_PORT_SALRN(p) (0x38F0 + (((p >> 4) << 2))) +#define RTL930X_L2_PORT_NEW_SA_FWD(p) (0x8FF4 + (((p / 10) << 2))) +#define RTL931X_L2_PORT_NEW_SA_FWD(p) (0xC830 + (((p / 10) << 2))) + +#define RTL930X_ST_CTRL (0x8798) + +#define RTL930X_L2_PORT_SABLK_CTRL (0x905c) +#define RTL930X_L2_PORT_DABLK_CTRL (0x9060) + +#define RTL838X_RMA_BPDU_FLD_PMSK (0x4348) +#define RTL930X_RMA_BPDU_FLD_PMSK (0x9F18) +#define RTL931X_RMA_BPDU_FLD_PMSK (0x8950) +#define RTL839X_RMA_BPDU_FLD_PMSK (0x125C) /* Port Mirroring */ -#define RTL838X_MIR_CTRL(grp) (0x5D00 + (((grp) << 2))) -#define RTL838X_MIR_DPM_CTRL(grp) (0x5D20 + (((grp) << 2))) -#define RTL838X_MIR_SPM_CTRL(grp) (0x5D10 + (((grp) << 2))) -#define RTL839X_MIR_CTRL(grp) (0x2500 + (((grp) << 2))) -#define RTL839X_MIR_DPM_CTRL(grp) (0x2530 + (((grp) << 2))) -#define RTL839X_MIR_SPM_CTRL(grp) (0x2510 + (((grp) << 2))) +#define RTL838X_MIR_CTRL (0x5D00) +#define RTL838X_MIR_DPM_CTRL (0x5D20) +#define RTL838X_MIR_SPM_CTRL (0x5D10) -/* Storm control */ +#define RTL839X_MIR_CTRL (0x2500) +#define RTL839X_MIR_DPM_CTRL (0x2530) +#define RTL839X_MIR_SPM_CTRL (0x2510) + +#define RTL930X_MIR_CTRL (0xA2A0) +#define RTL930X_MIR_DPM_CTRL (0xA2C0) +#define RTL930X_MIR_SPM_CTRL (0xA2B0) + +#define RTL931X_MIR_CTRL (0xAF00) +#define RTL931X_MIR_DPM_CTRL (0xAF30) +#define RTL931X_MIR_SPM_CTRL (0xAF10) + +/* Storm/rate control and scheduling */ #define RTL838X_STORM_CTRL (0x4700) #define RTL839X_STORM_CTRL (0x1800) #define RTL838X_STORM_CTRL_LB_CTRL(p) (0x4884 + (((p) << 2))) @@ -145,12 +231,23 @@ #define RTL838X_STORM_CTRL_BURST_PPS_1 (0x4878) #define RTL838X_STORM_CTRL_BURST_0 (0x487c) #define RTL838X_STORM_CTRL_BURST_1 (0x4880) +#define RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_0 (0x1804) +#define RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_1 (0x1808) #define RTL838X_SCHED_CTRL (0xB980) +#define RTL839X_SCHED_CTRL (0x60F4) #define RTL838X_SCHED_LB_TICK_TKN_CTRL_0 (0xAD58) #define RTL838X_SCHED_LB_TICK_TKN_CTRL_1 (0xAD5C) #define RTL839X_SCHED_LB_TICK_TKN_CTRL_0 (0x1804) #define RTL839X_SCHED_LB_TICK_TKN_CTRL_1 (0x1808) +#define RTL839X_STORM_CTRL_SPCL_LB_TICK_TKN_CTRL (0x2000) +#define RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_0 (0x1604) +#define RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_1 (0x1608) +#define RTL839X_SCHED_LB_TICK_TKN_CTRL (0x60F8) +#define RTL839X_SCHED_LB_TICK_TKN_PPS_CTRL (0x6200) #define RTL838X_SCHED_LB_THR (0xB984) +#define RTL839X_SCHED_LB_THR (0x60FC) +#define RTL838X_SCHED_P_EGR_RATE_CTRL(p) (0xC008 + (((p) << 7))) +#define RTL838X_SCHED_Q_EGR_RATE_CTRL(p, q) (0xC00C + (p << 7) + (((q) << 2))) #define RTL838X_STORM_CTRL_PORT_BC_EXCEED (0x470C) #define RTL838X_STORM_CTRL_PORT_MC_EXCEED (0x4710) #define RTL838X_STORM_CTRL_PORT_UC_EXCEED (0x4714) @@ -160,6 +257,25 @@ #define RTL838X_STORM_CTRL_PORT_UC(p) (0x4718 + (((p) << 2))) #define RTL838X_STORM_CTRL_PORT_MC(p) (0x478c + (((p) << 2))) #define RTL838X_STORM_CTRL_PORT_BC(p) (0x4800 + (((p) << 2))) +#define RTL839X_STORM_CTRL_PORT_UC_0(p) (0x185C + (((p) << 3))) +#define RTL839X_STORM_CTRL_PORT_UC_1(p) (0x1860 + (((p) << 3))) +#define RTL839X_STORM_CTRL_PORT_MC_0(p) (0x19FC + (((p) << 3))) +#define RTL839X_STORM_CTRL_PORT_MC_1(p) (0x1a00 + (((p) << 3))) +#define RTL839X_STORM_CTRL_PORT_BC_0(p) (0x1B9C + (((p) << 3))) +#define RTL839X_STORM_CTRL_PORT_BC_1(p) (0x1BA0 + (((p) << 3))) +#define RTL839X_TBL_ACCESS_CTRL_2 (0x611C) +#define RTL839X_TBL_ACCESS_DATA_2(i) (0x6120 + (((i) << 2))) +#define RTL839X_IGR_BWCTRL_PORT_CTRL_10G_0(p) (0x1618 + (((p) << 3))) +#define RTL839X_IGR_BWCTRL_PORT_CTRL_10G_1(p) (0x161C + (((p) << 3))) +#define RTL839X_IGR_BWCTRL_PORT_CTRL_0(p) (0x1640 + (((p) << 3))) +#define RTL839X_IGR_BWCTRL_PORT_CTRL_1(p) (0x1644 + (((p) << 3))) +#define RTL839X_IGR_BWCTRL_CTRL_LB_THR (0x1614) + +/* Link aggregation (Trunking) */ +#define RTL839X_TRK_MBR_CTR (0x2200) +#define RTL838X_TRK_MBR_CTR (0x3E00) +#define RTL930X_TRK_MBR_CTRL (0xA41C) +#define RTL931X_TRK_MBR_CTRL (0xB8D0) /* Attack prevention */ #define RTL838X_ATK_PRVNT_PORT_EN (0x5B00) @@ -167,6 +283,48 @@ #define RTL838X_ATK_PRVNT_ACT (0x5B08) #define RTL838X_ATK_PRVNT_STS (0x5B1C) +/* 802.1X */ +#define RTL838X_SPCL_TRAP_EAPOL_CTRL (0x6988) +#define RTL839X_SPCL_TRAP_EAPOL_CTRL (0x105C) + +/* QoS */ +#define RTL838X_QM_INTPRI2QID_CTRL (0x5F00) +#define RTL839X_QM_INTPRI2QID_CTRL(q) (0x1110 + (q << 2)) +#define RTL839X_QM_PORT_QNUM(p) (0x1130 + (((p / 10) << 2))) +#define RTL838X_PRI_SEL_PORT_PRI(p) (0x5FB8 + (((p / 10) << 2))) +#define RTL839X_PRI_SEL_PORT_PRI(p) (0x10A8 + (((p / 10) << 2))) +#define RTL838X_QM_PKT2CPU_INTPRI_MAP (0x5F10) +#define RTL839X_QM_PKT2CPU_INTPRI_MAP (0x1154) +#define RTL838X_PRI_SEL_CTRL (0x10E0) +#define RTL839X_PRI_SEL_CTRL (0x10E0) +#define RTL838X_PRI_SEL_TBL_CTRL(i) (0x5FD8 + (((i) << 2))) +#define RTL839X_PRI_SEL_TBL_CTRL(i) (0x10D0 + (((i) << 2))) +#define RTL838X_QM_PKT2CPU_INTPRI_0 (0x5F04) +#define RTL838X_QM_PKT2CPU_INTPRI_1 (0x5F08) +#define RTL838X_QM_PKT2CPU_INTPRI_2 (0x5F0C) +#define RTL839X_OAM_CTRL (0x2100) +#define RTL839X_OAM_PORT_ACT_CTRL(p) (0x2104 + (((p) << 2))) +#define RTL839X_RMK_PORT_DEI_TAG_CTRL(p) (0x6A9C + (((p >> 5) << 2))) +#define RTL839X_PRI_SEL_IPRI_REMAP (0x1080) +#define RTL838X_PRI_SEL_IPRI_REMAP (0x5F8C) +#define RTL839X_PRI_SEL_DEI2DP_REMAP (0x10EC) +#define RTL839X_PRI_SEL_DSCP2DP_REMAP_ADDR(i) (0x10F0 + (((i >> 4) << 2))) +#define RTL839X_RMK_DEI_CTRL (0x6AA4) +#define RTL839X_WRED_PORT_THR_CTRL(i) (0x6084 + ((i) << 2)) +#define RTL839X_WRED_QUEUE_THR_CTRL(q, i) (0x6090 + ((q) * 12) + ((i) << 2)) +#define RTL838X_PRI_DSCP_INVLD_CTRL0 (0x5FE8) +#define RTL838X_RMK_IPRI_CTRL (0xA460) +#define RTL838X_RMK_OPRI_CTRL (0xA464) +#define RTL838X_SCHED_P_TYPE_CTRL(p) (0xC04C + (((p) << 7))) +#define RTL838X_SCHED_LB_CTRL(p) (0xC004 + (((p) << 7))) +#define RTL838X_FC_P_EGR_DROP_CTRL(p) (0x6B1C + (((p) << 2))) + +/* Debug features */ +#define RTL930X_STAT_PRVTE_DROP_COUNTER0 (0xB5B8) + +#define MAX_LAGS 16 +#define MAX_PRIOS 8 + enum phy_type { PHY_NONE = 0, PHY_RTL838X_SDS = 1, @@ -182,6 +340,9 @@ struct rtl838x_port { u16 pvid; bool eee_enabled; enum phy_type phy; + bool is10G; + bool is2G5; + u8 sds_num; const struct dsa_port *dp; }; @@ -217,6 +378,8 @@ struct rtl838x_l2_entry { bool suspended; bool next_hop; int age; + u8 trunk; + u8 stackDev; u16 mc_portmask_index; }; @@ -231,8 +394,12 @@ struct rtl838x_reg { u64 (*get_port_reg_le)(int reg); int stat_port_rst; int stat_rst; - int (*stat_port_std_mib)(int p); + int stat_port_std_mib; int (*port_iso_ctrl)(int p); + void (*traffic_enable)(int source, int dest); + void (*traffic_disable)(int source, int dest); + void (*traffic_set)(int source, u64 dest_matrix); + u64 (*traffic_get)(int source); int l2_ctrl_0; int l2_ctrl_1; int l2_port_aging_out; @@ -248,13 +415,16 @@ struct rtl838x_reg { void (*vlan_tables_read)(u32 vlan, struct rtl838x_vlan_info *info); void (*vlan_set_tagged)(u32 vlan, struct rtl838x_vlan_info *info); void (*vlan_set_untagged)(u32 vlan, u64 portmask); + void (*vlan_profile_dump)(int index); + void (*stp_get)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); + void (*stp_set)(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]); int (*mac_force_mode_ctrl)(int port); int (*mac_port_ctrl)(int port); int (*l2_port_new_salrn)(int port); int (*l2_port_new_sa_fwd)(int port); - int (*mir_ctrl)(int group); - int (*mir_dpm)(int group); - int (*mir_spm)(int group); + int mir_ctrl; + int mir_dpm; + int mir_spm; int mac_link_sts; int mac_link_dup_sts; int (*mac_link_spd_sts)(int port); @@ -262,11 +432,14 @@ struct rtl838x_reg { int mac_tx_pause_sts; u64 (*read_l2_entry_using_hash)(u32 hash, u32 position, struct rtl838x_l2_entry *e); u64 (*read_cam)(int idx, struct rtl838x_l2_entry *e); - int (*vlan_profile)(int profile); - int (*vlan_port_egr_filter)(int port); - int (*vlan_port_igr_filter)(int port); - int (*vlan_port_pb)(int port); - int (*vlan_port_tag_sts_ctrl)(int port); + int vlan_port_egr_filter; + int vlan_port_igr_filter; + int vlan_port_pb; + int vlan_port_tag_sts_ctrl; + int (*rtl838x_vlan_port_tag_sts_ctrl)(int port); + int (*trk_mbr_ctr)(int group); + int rma_bpdu_fld_pmask; + int spcl_trap_eapol_ctrl; }; struct rtl838x_switch_priv { @@ -276,7 +449,7 @@ struct rtl838x_switch_priv { u16 id; u16 family_id; char version; - struct rtl838x_port ports[54]; /* TODO: correct size! */ + struct rtl838x_port ports[57]; struct mutex reg_mutex; int link_state_irq; int mirror_group_ports[4]; @@ -284,8 +457,14 @@ struct rtl838x_switch_priv { const struct rtl838x_reg *r; u8 cpu_port; u8 port_mask; + u8 port_width; + u64 irq_mask; u32 fib_entries; struct dentry *dbgfs_dir; + int n_lags; + u64 lags_port_members[MAX_LAGS]; + struct net_device *lag_devs[MAX_LAGS]; + struct notifier_block nb; }; void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv); diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c index 8dd123f609..5106bd2e9d 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl839x.c @@ -4,53 +4,18 @@ #include "rtl83xx.h" extern struct mutex smi_lock; +extern struct rtl83xx_soc_info soc_info; - -static inline void rtl839x_mask_port_reg_be(u64 clear, u64 set, int reg) +void rtl839x_print_matrix(void) { - sw_w32_mask((u32)(clear >> 32), (u32)(set >> 32), reg); - sw_w32_mask((u32)(clear & 0xffffffff), (u32)(set & 0xffffffff), reg + 4); -} + volatile u64 *ptr9; + int i; -static inline u64 rtl839x_get_port_reg_be(int reg) -{ - u64 v = sw_r32(reg); - - v <<= 32; - v |= sw_r32(reg + 4); - return v; -} - -static inline void rtl839x_set_port_reg_be(u64 set, int reg) -{ - sw_w32(set >> 32, reg); - sw_w32(set & 0xffffffff, reg + 4); -} - -static inline void rtl839x_mask_port_reg_le(u64 clear, u64 set, int reg) -{ - sw_w32_mask((u32)clear, (u32)set, reg); - sw_w32_mask((u32)(clear >> 32), (u32)(set >> 32), reg + 4); -} - -static inline void rtl839x_set_port_reg_le(u64 set, int reg) -{ - sw_w32(set, reg); - sw_w32(set >> 32, reg + 4); -} - -static inline u64 rtl839x_get_port_reg_le(int reg) -{ - u64 v = sw_r32(reg + 4); - - v <<= 32; - v |= sw_r32(reg); - return v; -} - -static inline int rtl839x_stat_port_std_mib(int p) -{ - return RTL839X_STAT_PORT_STD_MIB + (p << 8); + ptr9 = RTL838X_SW_BASE + RTL839X_PORT_ISO_CTRL(0); + for (i = 0; i < 52; i += 4) + pr_debug("> %16llx %16llx %16llx %16llx\n", + ptr9[i + 0], ptr9[i + 1], ptr9[i + 2], ptr9[i + 3]); + pr_debug("CPU_PORT> %16llx\n", ptr9[52]); } static inline int rtl839x_port_iso_ctrl(int p) @@ -70,6 +35,12 @@ static inline void rtl839x_exec_tbl1_cmd(u32 cmd) do { } while (sw_r32(RTL839X_TBL_ACCESS_CTRL_1) & BIT(16)); } +inline void rtl839x_exec_tbl2_cmd(u32 cmd) +{ + sw_w32(cmd, RTL839X_TBL_ACCESS_CTRL_2); + do { } while (sw_r32(RTL839X_TBL_ACCESS_CTRL_2) & (1 << 9)); +} + static inline int rtl839x_tbl_access_data_0(int i) { return RTL839X_TBL_ACCESS_DATA_0(i); @@ -81,33 +52,33 @@ static void rtl839x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info) u64 v; u32 u, w; - cmd = BIT(16) /* Execute cmd */ + cmd = 1 << 16 /* Execute cmd */ | 0 << 15 /* Read */ | 0 << 12 /* Table type 0b000 */ | (vlan & 0xfff); rtl839x_exec_tbl0_cmd(cmd); - v = sw_r32(RTL838X_TBL_ACCESS_DATA_0(0)); + v = sw_r32(RTL839X_TBL_ACCESS_DATA_0(0)); v <<= 32; - u = sw_r32(RTL838X_TBL_ACCESS_DATA_0(1)); + u = sw_r32(RTL839X_TBL_ACCESS_DATA_0(1)); v |= u; info->tagged_ports = v >> 11; - w = sw_r32(RTL838X_TBL_ACCESS_DATA_0(2)); + w = sw_r32(RTL839X_TBL_ACCESS_DATA_0(2)); info->profile_id = w >> 30 | ((u & 1) << 2); info->hash_mc_fid = !!(u & 2); info->hash_uc_fid = !!(u & 4); info->fid = (u >> 3) & 0xff; - cmd = BIT(16) /* Execute cmd */ - | 0 << 15 /* Read */ - | 0 << 12 /* Table type 0b000 */ + cmd = 1 << 15 /* Execute cmd */ + | 0 << 14 /* Read */ + | 0 << 12 /* Table type 0b00 */ | (vlan & 0xfff); rtl839x_exec_tbl1_cmd(cmd); - v = sw_r32(RTL838X_TBL_ACCESS_DATA_1(0)); + v = sw_r32(RTL839X_TBL_ACCESS_DATA_1(0)); v <<= 32; - v |= sw_r32(RTL838X_TBL_ACCESS_DATA_1(1)); + v |= sw_r32(RTL839X_TBL_ACCESS_DATA_1(1)); info->untagged_ports = v >> 11; } @@ -161,45 +132,18 @@ static inline int rtl839x_l2_port_new_sa_fwd(int p) return RTL839X_L2_PORT_NEW_SA_FWD(p); } -static inline int rtl839x_mir_ctrl(int group) -{ - return RTL839X_MIR_CTRL(group); -} - -static inline int rtl839x_mir_dpm(int group) -{ - return RTL839X_MIR_DPM_CTRL(group); -} - -static inline int rtl839x_mir_spm(int group) -{ - return RTL839X_MIR_SPM_CTRL(group); -} - static inline int rtl839x_mac_link_spd_sts(int p) { return RTL839X_MAC_LINK_SPD_STS(p); } -static u64 rtl839x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e) +static inline int rtl839x_trk_mbr_ctr(int group) { - u64 entry; - u32 r[3]; - - /* Search in SRAM, with hash and at position in hash bucket (0-3) */ - u32 idx = (0 << 14) | (hash << 2) | position; - - u32 cmd = BIT(17) /* Execute cmd */ - | 0 << 16 /* Read */ - | 0 << 14 /* Table type 0b00 */ - | (idx & 0x3fff); - - sw_w32(cmd, RTL839X_TBL_ACCESS_L2_CTRL); - do { } while (sw_r32(RTL839X_TBL_ACCESS_L2_CTRL) & BIT(17)); - r[0] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(0)); - r[1] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(1)); - r[2] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(2)); + return RTL839X_TRK_MBR_CTR + (group << 3); +} +static void rtl839x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e) +{ /* Table contains different entry types, we need to identify the right one: * Check for MC entries, first */ @@ -220,12 +164,12 @@ static u64 rtl839x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl83 e->vid = (r[2] >> 4) & 0xfff; e->rvid = (r[0] >> 20) & 0xfff; e->port = (r[2] >> 24) & 0x3f; - e->block_da = !!(r[2] & BIT(19)); - e->block_sa = !!(r[2] & BIT(20)); - e->suspended = !!(r[2] & BIT(17)); - e->next_hop = !!(r[2] & BIT(16)); + e->block_da = !!(r[2] & (1 << 19)); + e->block_sa = !!(r[2] & (1 << 20)); + e->suspended = !!(r[2] & (1 << 17)); + e->next_hop = !!(r[2] & (1 << 16)); if (e->next_hop) - pr_debug("Found next hop entry, need to read data\n"); + pr_info("Found next hop entry, need to read data\n"); e->age = (r[2] >> 21) & 3; e->valid = true; if (!(r[2] & 0xc0fd0000)) /* Check for valid entry */ @@ -246,6 +190,28 @@ static u64 rtl839x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl83 e->valid = true; e->type = IP6_MULTICAST; } +} + +static u64 rtl839x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e) +{ + u64 entry; + u32 r[3]; + + /* Search in SRAM, with hash and at position in hash bucket (0-3) */ + u32 idx = (0 << 14) | (hash << 2) | position; + + u32 cmd = 1 << 17 /* Execute cmd */ + | 0 << 16 /* Read */ + | 0 << 14 /* Table type 0b00 */ + | (idx & 0x3fff); + + sw_w32(cmd, RTL839X_TBL_ACCESS_L2_CTRL); + do { } while (sw_r32(RTL839X_TBL_ACCESS_L2_CTRL) & (1 << 17)); + r[0] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(0)); + r[1] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(1)); + r[2] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(2)); + + rtl839x_fill_l2_entry(r, e); entry = (((u64) r[0]) << 12) | ((r[1] & 0xfffffff0) << 12) | ((r[2] >> 4) & 0xfff); return entry; @@ -256,33 +222,22 @@ static u64 rtl839x_read_cam(int idx, struct rtl838x_l2_entry *e) u64 entry; u32 r[3]; - u32 cmd = BIT(17) /* Execute cmd */ + u32 cmd = 1 << 17 /* Execute cmd */ | 0 << 16 /* Read */ - | BIT(14) /* Table type 0b01 */ + | 1 << 14 /* Table type 0b01 */ | (idx & 0x3f); sw_w32(cmd, RTL839X_TBL_ACCESS_L2_CTRL); - do { } while (sw_r32(RTL839X_TBL_ACCESS_L2_CTRL) & BIT(17)); + do { } while (sw_r32(RTL839X_TBL_ACCESS_L2_CTRL) & (1 << 17)); r[0] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(0)); r[1] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(1)); r[2] = sw_r32(RTL839X_TBL_ACCESS_L2_DATA(2)); - e->mac[0] = (r[0] >> 12); - e->mac[1] = (r[0] >> 4); - e->mac[2] = ((r[1] >> 28) | (r[0] << 4)); - e->mac[3] = (r[1] >> 20); - e->mac[4] = (r[1] >> 12); - e->mac[5] = (r[1] >> 4); - e->is_static = !!((r[2] >> 18) & 1); - e->vid = (r[2] >> 4) & 0xfff; - e->rvid = (r[0] >> 20) & 0xfff; - e->port = (r[2] >> 24) & 0x3f; - - e->valid = true; - if (!(r[2] & 0x10fd0000)) /* Check for invalid entry */ - e->valid = false; + rtl839x_fill_l2_entry(r, e); if (e->valid) - pr_debug("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]); + pr_info("Found in CAM: R1 %x R2 %x R3 %x\n", r[0], r[1], r[2]); + else + return 0; entry = (((u64) r[0]) << 12) | ((r[1] & 0xfffffff0) << 12) | ((r[2] >> 4) & 0xfff); return entry; @@ -303,62 +258,25 @@ static inline int rtl839x_vlan_port_igr_filter(int port) return RTL839X_VLAN_PORT_IGR_FLTR(port); } -static inline int rtl839x_vlan_port_pb(int port) +u64 rtl839x_traffic_get(int source) { - return RTL839X_VLAN_PORT_PB_VLAN(port); + return rtl839x_get_port_reg_be(rtl839x_port_iso_ctrl(source)); } -static inline int rtl839x_vlan_port_tag_sts_ctrl(int port) +void rtl839x_traffic_set(int source, u64 dest_matrix) { - return RTL839X_VLAN_PORT_TAG_STS_CTRL(port); + rtl839x_set_port_reg_be(dest_matrix, rtl839x_port_iso_ctrl(source)); } -const struct rtl838x_reg rtl839x_reg = { - .mask_port_reg_be = rtl839x_mask_port_reg_be, - .set_port_reg_be = rtl839x_set_port_reg_be, - .get_port_reg_be = rtl839x_get_port_reg_be, - .mask_port_reg_le = rtl839x_mask_port_reg_le, - .set_port_reg_le = rtl839x_set_port_reg_le, - .get_port_reg_le = rtl839x_get_port_reg_le, - .stat_port_rst = RTL839X_STAT_PORT_RST, - .stat_rst = RTL839X_STAT_RST, - .stat_port_std_mib = rtl839x_stat_port_std_mib, - .port_iso_ctrl = rtl839x_port_iso_ctrl, - .l2_ctrl_0 = RTL839X_L2_CTRL_0, - .l2_ctrl_1 = RTL839X_L2_CTRL_1, - .l2_port_aging_out = RTL839X_L2_PORT_AGING_OUT, - .smi_poll_ctrl = RTL839X_SMI_PORT_POLLING_CTRL, - .l2_tbl_flush_ctrl = RTL839X_L2_TBL_FLUSH_CTRL, - .exec_tbl0_cmd = rtl839x_exec_tbl0_cmd, - .exec_tbl1_cmd = rtl839x_exec_tbl1_cmd, - .tbl_access_data_0 = rtl839x_tbl_access_data_0, - .isr_glb_src = RTL839X_ISR_GLB_SRC, - .isr_port_link_sts_chg = RTL839X_ISR_PORT_LINK_STS_CHG, - .imr_port_link_sts_chg = RTL839X_IMR_PORT_LINK_STS_CHG, - .imr_glb = RTL839X_IMR_GLB, - .vlan_tables_read = rtl839x_vlan_tables_read, - .vlan_set_tagged = rtl839x_vlan_set_tagged, - .vlan_set_untagged = rtl839x_vlan_set_untagged, - .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, - .mac_port_ctrl = rtl839x_mac_port_ctrl, - .l2_port_new_salrn = rtl839x_l2_port_new_salrn, - .l2_port_new_sa_fwd = rtl839x_l2_port_new_sa_fwd, - .mir_ctrl = rtl839x_mir_ctrl, - .mir_dpm = rtl839x_mir_dpm, - .mir_spm = rtl839x_mir_spm, - .mac_link_sts = RTL839X_MAC_LINK_STS, - .mac_link_dup_sts = RTL839X_MAC_LINK_DUP_STS, - .mac_link_spd_sts = rtl839x_mac_link_spd_sts, - .mac_rx_pause_sts = RTL839X_MAC_RX_PAUSE_STS, - .mac_tx_pause_sts = RTL839X_MAC_TX_PAUSE_STS, - .read_l2_entry_using_hash = rtl839x_read_l2_entry_using_hash, - .read_cam = rtl839x_read_cam, - .vlan_profile = rtl839x_vlan_profile, - .vlan_port_egr_filter = rtl839x_vlan_port_egr_filter, - .vlan_port_igr_filter = rtl839x_vlan_port_igr_filter, - .vlan_port_pb = rtl839x_vlan_port_pb, - .vlan_port_tag_sts_ctrl = rtl839x_vlan_port_tag_sts_ctrl, -}; +void rtl839x_traffic_enable(int source, int dest) +{ + rtl839x_mask_port_reg_be(0, BIT_ULL(dest), rtl839x_port_iso_ctrl(source)); +} + +void rtl839x_traffic_disable(int source, int dest) +{ + rtl839x_mask_port_reg_be(BIT(dest), 0, rtl839x_port_iso_ctrl(source)); +} irqreturn_t rtl839x_switch_irq(int irq, void *dev_id) { @@ -512,3 +430,84 @@ void rtl839x_vlan_profile_dump(int index) index, profile & 1, (profile >> 1) & 0xfff, (profile >> 13) & 0xfff, (profile1) & 0xfff); } + +static void rtl839x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) +{ + int i; + u32 cmd = 1 << 16 /* Execute cmd */ + | 0 << 15 /* Read */ + | 5 << 12 /* Table type 0b101 */ + | (msti & 0xfff); + priv->r->exec_tbl0_cmd(cmd); + + for (i = 0; i < 4; i++) + port_state[i] = sw_r32(priv->r->tbl_access_data_0(i)); +} + +static void rtl839x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) +{ + int i; + u32 cmd = 1 << 16 /* Execute cmd */ + | 1 << 15 /* Write */ + | 5 << 12 /* Table type 0b101 */ + | (msti & 0xfff); + for (i = 0; i < 4; i++) + sw_w32(port_state[i], priv->r->tbl_access_data_0(i)); + priv->r->exec_tbl0_cmd(cmd); +} + +const struct rtl838x_reg rtl839x_reg = { + .mask_port_reg_be = rtl839x_mask_port_reg_be, + .set_port_reg_be = rtl839x_set_port_reg_be, + .get_port_reg_be = rtl839x_get_port_reg_be, + .mask_port_reg_le = rtl839x_mask_port_reg_le, + .set_port_reg_le = rtl839x_set_port_reg_le, + .get_port_reg_le = rtl839x_get_port_reg_le, + .stat_port_rst = RTL839X_STAT_PORT_RST, + .stat_rst = RTL839X_STAT_RST, + .stat_port_std_mib = RTL839X_STAT_PORT_STD_MIB, + .traffic_enable = rtl839x_traffic_enable, + .traffic_disable = rtl839x_traffic_disable, + .traffic_get = rtl839x_traffic_get, + .traffic_set = rtl839x_traffic_set, + .port_iso_ctrl = rtl839x_port_iso_ctrl, + .l2_ctrl_0 = RTL839X_L2_CTRL_0, + .l2_ctrl_1 = RTL839X_L2_CTRL_1, + .l2_port_aging_out = RTL839X_L2_PORT_AGING_OUT, + .smi_poll_ctrl = RTL839X_SMI_PORT_POLLING_CTRL, + .l2_tbl_flush_ctrl = RTL839X_L2_TBL_FLUSH_CTRL, + .exec_tbl0_cmd = rtl839x_exec_tbl0_cmd, + .exec_tbl1_cmd = rtl839x_exec_tbl1_cmd, + .tbl_access_data_0 = rtl839x_tbl_access_data_0, + .isr_glb_src = RTL839X_ISR_GLB_SRC, + .isr_port_link_sts_chg = RTL839X_ISR_PORT_LINK_STS_CHG, + .imr_port_link_sts_chg = RTL839X_IMR_PORT_LINK_STS_CHG, + .imr_glb = RTL839X_IMR_GLB, + .vlan_tables_read = rtl839x_vlan_tables_read, + .vlan_set_tagged = rtl839x_vlan_set_tagged, + .vlan_set_untagged = rtl839x_vlan_set_untagged, + .vlan_profile_dump = rtl839x_vlan_profile_dump, + .stp_get = rtl839x_stp_get, + .stp_set = rtl839x_stp_set, + .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, + .mac_port_ctrl = rtl839x_mac_port_ctrl, + .l2_port_new_salrn = rtl839x_l2_port_new_salrn, + .l2_port_new_sa_fwd = rtl839x_l2_port_new_sa_fwd, + .mir_ctrl = RTL839X_MIR_CTRL, + .mir_dpm = RTL839X_MIR_DPM_CTRL, + .mir_spm = RTL839X_MIR_SPM_CTRL, + .mac_link_sts = RTL839X_MAC_LINK_STS, + .mac_link_dup_sts = RTL839X_MAC_LINK_DUP_STS, + .mac_link_spd_sts = rtl839x_mac_link_spd_sts, + .mac_rx_pause_sts = RTL839X_MAC_RX_PAUSE_STS, + .mac_tx_pause_sts = RTL839X_MAC_TX_PAUSE_STS, + .read_l2_entry_using_hash = rtl839x_read_l2_entry_using_hash, + .read_cam = rtl839x_read_cam, + .vlan_port_egr_filter = RTL839X_VLAN_PORT_EGR_FLTR(0), + .vlan_port_igr_filter = RTL839X_VLAN_PORT_IGR_FLTR(0), + .vlan_port_pb = RTL839X_VLAN_PORT_PB_VLAN, + .vlan_port_tag_sts_ctrl = RTL839X_VLAN_PORT_TAG_STS_CTRL, + .trk_mbr_ctr = rtl839x_trk_mbr_ctr, + .rma_bpdu_fld_pmask = RTL839X_RMA_BPDU_FLD_PMSK, + .spcl_trap_eapol_ctrl = RTL839X_SPCL_TRAP_EAPOL_CTRL, +}; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h index 3953512525..fd0455a6cd 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl83xx.h @@ -24,7 +24,71 @@ struct rtl83xx_mib_desc { const char *name; }; -void __init rtl83xx_storm_control_init(struct rtl838x_switch_priv *priv); +/* API for switch table access */ +struct table_reg { + u16 addr; + u16 data; + u8 max_data; + u8 c_bit; + u8 t_bit; + u8 rmode; + u8 tbl; + struct mutex lock; +}; + +#define TBL_DESC(_addr, _data, _max_data, _c_bit, _t_bit, _rmode) \ + { .addr = _addr, .data = _data, .max_data = _max_data, .c_bit = _c_bit, \ + .t_bit = _t_bit, .rmode = _rmode \ + } + +typedef enum { + RTL8380_TBL_L2 = 0, + RTL8380_TBL_0, + RTL8380_TBL_1, + RTL8390_TBL_L2, + RTL8390_TBL_0, + RTL8390_TBL_1, + RTL8390_TBL_2, + RTL9300_TBL_L2, + RTL9300_TBL_0, + RTL9300_TBL_1, + RTL9300_TBL_2, + RTL9300_TBL_HSB, + RTL9300_TBL_HSA, + RTL9310_TBL_0, + RTL9310_TBL_1, + RTL9310_TBL_2, + RTL9310_TBL_3, + RTL9310_TBL_4, + RTL9310_TBL_5, + RTL_TBL_END +} rtl838x_tbl_reg_t; + +void rtl_table_init(void); +struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t); +void rtl_table_release(struct table_reg *r); +void rtl_table_read(struct table_reg *r, int idx); +void rtl_table_write(struct table_reg *r, int idx); +inline u16 rtl_table_data(struct table_reg *r, int i); +inline u32 rtl_table_data_r(struct table_reg *r, int i); +inline void rtl_table_data_w(struct table_reg *r, u32 v, int i); + +void __init rtl83xx_setup_qos(struct rtl838x_switch_priv *priv); +int read_phy(u32 port, u32 page, u32 reg, u32 *val); +int write_phy(u32 port, u32 page, u32 reg, u32 val); + +/* Port register accessor functions for the RTL839x and RTL931X SoCs */ +void rtl839x_mask_port_reg_be(u64 clear, u64 set, int reg); +u64 rtl839x_get_port_reg_be(int reg); +void rtl839x_set_port_reg_be(u64 set, int reg); +void rtl839x_mask_port_reg_le(u64 clear, u64 set, int reg); +void rtl839x_set_port_reg_le(u64 set, int reg); +u64 rtl839x_get_port_reg_le(int reg); + +/* Port register accessor functions for the RTL838x and RTL930X SoCs */ +void rtl838x_mask_port_reg(u64 clear, u64 set, int reg); +void rtl838x_set_port_reg(u64 set, int reg); +u64 rtl838x_get_port_reg(int reg); /* RTL838x-specific */ u32 rtl838x_hash(struct rtl838x_switch_priv *priv, u64 seed); @@ -32,6 +96,9 @@ irqreturn_t rtl838x_switch_irq(int irq, void *dev_id); void rtl8380_get_version(struct rtl838x_switch_priv *priv); void rtl838x_vlan_profile_dump(int index); int rtl83xx_dsa_phy_read(struct dsa_switch *ds, int phy_addr, int phy_reg); +void rtl8380_sds_rst(int mac); +int rtl8380_sds_power(int mac, int val); +void rtl838x_print_matrix(void); /* RTL839x-specific */ u32 rtl839x_hash(struct rtl838x_switch_priv *priv, u64 seed); @@ -39,6 +106,20 @@ irqreturn_t rtl839x_switch_irq(int irq, void *dev_id); void rtl8390_get_version(struct rtl838x_switch_priv *priv); void rtl839x_vlan_profile_dump(int index); int rtl83xx_dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_reg, u16 val); +void rtl839x_exec_tbl2_cmd(u32 cmd); +void rtl839x_print_matrix(void); + +/* RTL930x-specific */ +u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed); +irqreturn_t rtl930x_switch_irq(int irq, void *dev_id); +irqreturn_t rtl839x_switch_irq(int irq, void *dev_id); +void rtl930x_vlan_profile_dump(int index); +int rtl9300_sds_power(int mac, int val); +void rtl9300_sds_rst(int sds_num, u32 mode); +void rtl930x_print_matrix(void); + +/* RTL931x-specific */ +irqreturn_t rtl931x_switch_irq(int irq, void *dev_id); #endif /* _NET_DSA_RTL83XX_H */ diff --git a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c index fec842674e..7931daff07 100644 --- a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -26,20 +27,24 @@ extern struct rtl83xx_soc_info soc_info; /* - * Maximum number of RX rings is 8, assigned by switch based on - * packet/port priortity (not implemented) - * Maximum number of TX rings is 2 (only ring 0 used) - * RX ringlength needs to be at least 200, otherwise CPU and Switch - * may gridlock. + * Maximum number of RX rings is 8 on RTL83XX and 32 on the 93XX + * The ring is assigned by switch based on packet/port priortity + * Maximum number of TX rings is 2, Ring 2 being the high priority + * ring on the RTL93xx SoCs. MAX_RING_SIZE * RING_BUFFER gives + * the memory used for the ring buffer. */ -#define RXRINGS 8 -#define RXRINGLEN 300 +#define MAX_RXRINGS 32 +#define MAX_RXLEN 100 +#define MAX_ENTRIES (200 * 8) #define TXRINGS 2 -#define TXRINGLEN 160 +// BUG: TXRINGLEN can be 160 +#define TXRINGLEN 16 #define NOTIFY_EVENTS 10 #define NOTIFY_BLOCKS 10 #define TX_EN 0x8 #define RX_EN 0x4 +#define TX_EN_93XX 0x20 +#define RX_EN_93XX 0x10 #define TX_DO 0x2 #define WRAP 0x2 @@ -53,11 +58,10 @@ extern struct rtl83xx_soc_info soc_info; struct p_hdr { uint8_t *buf; uint16_t reserved; - uint16_t size; /* buffer size */ + uint16_t size; /* buffer size */ uint16_t offset; - uint16_t len; /* pkt len */ - uint16_t reserved2; - uint16_t cpu_tag[5]; + uint16_t len; /* pkt len */ + uint16_t cpu_tag[10]; } __packed __aligned(1); struct n_event { @@ -70,14 +74,14 @@ struct n_event { } __packed __aligned(1); struct ring_b { - uint32_t rx_r[RXRINGS][RXRINGLEN]; + uint32_t rx_r[MAX_RXRINGS][MAX_RXLEN]; uint32_t tx_r[TXRINGS][TXRINGLEN]; - struct p_hdr rx_header[RXRINGS][RXRINGLEN]; + struct p_hdr rx_header[MAX_RXRINGS][MAX_RXLEN]; struct p_hdr tx_header[TXRINGS][TXRINGLEN]; - uint32_t c_rx[RXRINGS]; + uint32_t c_rx[MAX_RXRINGS]; uint32_t c_tx[TXRINGS]; - uint8_t rx_space[RXRINGS*RXRINGLEN*RING_BUFFER]; - uint8_t tx_space[TXRINGLEN*RING_BUFFER]; + uint8_t tx_space[TXRINGS * TXRINGLEN * RING_BUFFER]; + uint8_t *rx_space; }; struct notify_block { @@ -91,132 +95,230 @@ struct notify_b { u32 reserved2[8]; }; -inline void rtl838x_create_tx_header(struct p_hdr *h, int dest_port) +void rtl838x_create_tx_header(struct p_hdr *h, int dest_port, int prio) { + prio &= 0x7; + if (dest_port > 0) { - h->cpu_tag[0] = 0x0400; - h->cpu_tag[1] = 0x0200; - h->cpu_tag[2] = 0x0000; - h->cpu_tag[3] = (1 << dest_port) >> 16; - h->cpu_tag[4] = (1 << dest_port) & 0xffff; - } else { - h->cpu_tag[0] = 0; - h->cpu_tag[1] = 0; - h->cpu_tag[2] = 0; - h->cpu_tag[3] = 0; - h->cpu_tag[4] = 0; + // cpu_tag[0] is reserved on the RTL83XX SoCs + h->cpu_tag[1] = 0x0400; + h->cpu_tag[2] = 0x0200; + h->cpu_tag[3] = 0x0000; + h->cpu_tag[4] = BIT(dest_port) >> 16; + h->cpu_tag[5] = BIT(dest_port) & 0xffff; + // Set internal priority and AS_PRIO + if (prio >= 0) + h->cpu_tag[2] |= (prio | 0x8) << 12; } } -inline void rtl839x_create_tx_header(struct p_hdr *h, int dest_port) +void rtl839x_create_tx_header(struct p_hdr *h, int dest_port, int prio) { + prio &= 0x7; + if (dest_port > 0) { - h->cpu_tag[0] = 0x0100; - h->cpu_tag[1] = ((1 << (dest_port - 32)) >> 16) | (1 << 21); - h->cpu_tag[2] = (1 << (dest_port - 32)) & 0xffff; - h->cpu_tag[3] = (1 << dest_port) >> 16; - h->cpu_tag[4] = (1 << dest_port) & 0xffff; - } else { - h->cpu_tag[0] = 0; - h->cpu_tag[1] = 0; - h->cpu_tag[2] = 0; - h->cpu_tag[3] = 0; - h->cpu_tag[4] = 0; + // cpu_tag[0] is reserved on the RTL83XX SoCs + h->cpu_tag[1] = 0x0100; + h->cpu_tag[2] = h->cpu_tag[3] = h->cpu_tag[4] = h->cpu_tag[5] = 0; + if (dest_port >= 32) { + dest_port -= 32; + h->cpu_tag[2] = BIT(dest_port) >> 16; + h->cpu_tag[3] = BIT(dest_port) & 0xffff; + } else { + h->cpu_tag[4] = BIT(dest_port) >> 16; + h->cpu_tag[5] = BIT(dest_port) & 0xffff; + } + h->cpu_tag[6] |= BIT(21); // Enable destination port mask use + // Set internal priority and AS_PRIO + if (prio >= 0) + h->cpu_tag[1] |= prio | BIT(3); } } +void rtl930x_create_tx_header(struct p_hdr *h, int dest_port, int prio) +{ + h->cpu_tag[0] = 0x8000; + h->cpu_tag[1] = 0; // TODO: Fill port and prio + h->cpu_tag[2] = 0; + h->cpu_tag[3] = 0; + h->cpu_tag[4] = 0; + h->cpu_tag[5] = 0; + h->cpu_tag[6] = 0; + h->cpu_tag[7] = 0xffff; +} + +void rtl931x_create_tx_header(struct p_hdr *h, int dest_port, int prio) +{ + h->cpu_tag[0] = 0x8000; + h->cpu_tag[1] = 0; // TODO: Fill port and prio + h->cpu_tag[2] = 0; + h->cpu_tag[3] = 0; + h->cpu_tag[4] = 0; + h->cpu_tag[5] = 0; + h->cpu_tag[6] = 0; + h->cpu_tag[7] = 0xffff; +} + +struct rtl838x_rx_q { + int id; + struct rtl838x_eth_priv *priv; + struct napi_struct napi; +}; + struct rtl838x_eth_priv { struct net_device *netdev; struct platform_device *pdev; void *membase; spinlock_t lock; struct mii_bus *mii_bus; - struct napi_struct napi; + struct rtl838x_rx_q rx_qs[MAX_RXRINGS]; struct phylink *phylink; struct phylink_config phylink_config; u16 id; u16 family_id; const struct rtl838x_reg *r; u8 cpu_port; - u8 port_mask; u32 lastEvent; -}; - -static const struct rtl838x_reg rtl838x_reg = { - .mac_port_ctrl = rtl838x_mac_port_ctrl, - .dma_if_intr_sts = RTL838X_DMA_IF_INTR_STS, - .dma_if_intr_msk = RTL838X_DMA_IF_INTR_MSK, - .dma_if_ctrl = RTL838X_DMA_IF_CTRL, - .mac_force_mode_ctrl = rtl838x_mac_force_mode_ctrl, - .dma_rx_base = rtl838x_dma_rx_base, - .dma_tx_base = rtl838x_dma_tx_base, - .dma_if_rx_ring_size = rtl838x_dma_if_rx_ring_size, - .dma_if_rx_ring_cntr = rtl838x_dma_if_rx_ring_cntr, - .dma_if_rx_cur = rtl838x_dma_if_rx_cur, - .rst_glb_ctrl = RTL838X_RST_GLB_CTRL_0, - .get_mac_link_sts = rtl838x_get_mac_link_sts, - .get_mac_link_dup_sts = rtl838x_get_mac_link_dup_sts, - .get_mac_link_spd_sts = rtl838x_get_mac_link_spd_sts, - .get_mac_rx_pause_sts = rtl838x_get_mac_rx_pause_sts, - .get_mac_tx_pause_sts = rtl838x_get_mac_tx_pause_sts, - .mac = RTL838X_MAC, - .l2_tbl_flush_ctrl = RTL838X_L2_TBL_FLUSH_CTRL, -}; - -static const struct rtl838x_reg rtl839x_reg = { - .mac_port_ctrl = rtl839x_mac_port_ctrl, - .dma_if_intr_sts = RTL839X_DMA_IF_INTR_STS, - .dma_if_intr_msk = RTL839X_DMA_IF_INTR_MSK, - .dma_if_ctrl = RTL839X_DMA_IF_CTRL, - .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, - .dma_rx_base = rtl839x_dma_rx_base, - .dma_tx_base = rtl839x_dma_tx_base, - .dma_if_rx_ring_size = rtl839x_dma_if_rx_ring_size, - .dma_if_rx_ring_cntr = rtl839x_dma_if_rx_ring_cntr, - .dma_if_rx_cur = rtl839x_dma_if_rx_cur, - .rst_glb_ctrl = RTL839X_RST_GLB_CTRL, - .get_mac_link_sts = rtl839x_get_mac_link_sts, - .get_mac_link_dup_sts = rtl839x_get_mac_link_dup_sts, - .get_mac_link_spd_sts = rtl839x_get_mac_link_spd_sts, - .get_mac_rx_pause_sts = rtl839x_get_mac_rx_pause_sts, - .get_mac_tx_pause_sts = rtl839x_get_mac_tx_pause_sts, - .mac = RTL839X_MAC, - .l2_tbl_flush_ctrl = RTL839X_L2_TBL_FLUSH_CTRL, + u16 rxrings; + u16 rxringlen; }; extern int rtl838x_phy_init(struct rtl838x_eth_priv *priv); extern int rtl838x_read_sds_phy(int phy_addr, int phy_reg); extern int rtl839x_read_sds_phy(int phy_addr, int phy_reg); extern int rtl839x_write_sds_phy(int phy_addr, int phy_reg, u16 v); +extern int rtl930x_read_sds_phy(int phy_addr, int page, int phy_reg); +extern int rtl930x_write_sds_phy(int phy_addr, int page, int phy_reg, u16 v); +extern int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); +extern int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val); + +/* + * On the RTL93XX, the RTL93XX_DMA_IF_RX_RING_CNTR track the fill level of + * the rings. Writing x into these registers substracts x from its content. + * When the content reaches the ring size, the ASIC no longer adds + * packets to this receive queue. + */ +void rtl838x_update_cntr(int r, int released) +{ + // This feature is not available on RTL838x SoCs +} + +void rtl839x_update_cntr(int r, int released) +{ + // This feature is not available on RTL839x SoCs +} + +void rtl930x_update_cntr(int r, int released) +{ + int pos = (r % 3) * 10; + u32 reg = RTL930X_DMA_IF_RX_RING_CNTR + ((r / 3) << 2); + u32 v = sw_r32(reg); + + v = (v >> pos) & 0x3ff; + pr_debug("RX: Work done %d, old value: %d, pos %d, reg %04x\n", released, v, pos, reg); + sw_w32_mask(0x3ff << pos, released << pos, reg); + sw_w32(v, reg); +} + +void rtl931x_update_cntr(int r, int released) +{ + int pos = (r % 3) * 10; + u32 reg = RTL931X_DMA_IF_RX_RING_CNTR + ((r / 3) << 2); + + sw_w32_mask(0x3ff << pos, released << pos, reg); +} + +struct dsa_tag { + u8 reason; + u8 queue; + u16 port; + u8 l2_offloaded; + u8 prio; +}; + +bool rtl838x_decode_tag(struct p_hdr *h, struct dsa_tag *t) +{ + t->reason = h->cpu_tag[3] & 0xf; + if (t->reason != 15) + pr_debug("Reason: %d\n", t->reason); + t->queue = (h->cpu_tag[0] & 0xe0) >> 5; + if (t->reason != 4) // NIC_RX_REASON_SPECIAL_TRAP + t->l2_offloaded = 1; + else + t->l2_offloaded = 0; + t->port = h->cpu_tag[1] & 0x1f; + + return t->l2_offloaded; +} + +bool rtl839x_decode_tag(struct p_hdr *h, struct dsa_tag *t) +{ + t->reason = h->cpu_tag[4] & 0x1f; + if (t->reason != 31) + pr_debug("Reason: %d\n", t->reason); + t->queue = (h->cpu_tag[3] & 0xe000) >> 13; + if ((t->reason != 7) && (t->reason != 8)) // NIC_RX_REASON_RMA_USR + t->l2_offloaded = 1; + else + t->l2_offloaded = 0; + + t->port = h->cpu_tag[1] & 0x3f; + + return t->l2_offloaded; +} + +bool rtl931x_decode_tag(struct p_hdr *h, struct dsa_tag *t) +{ + t->reason = h->cpu_tag[7] & 0x3f; + pr_debug("Reason %d\n", t->reason); + t->queue = (h->cpu_tag[2] >> 11) & 0x1f; + if (t->reason >= 19 && t->reason <= 27) + t->l2_offloaded = 0; + else + t->l2_offloaded = 1; + t->port = (h->cpu_tag[0] >> 8) & 0x3f; + + return t->l2_offloaded; +} + +bool rtl930x_decode_tag(struct p_hdr *h, struct dsa_tag *t) +{ + rtl931x_decode_tag(h, t); + t->port &= 0x1f; + return t->l2_offloaded; +} /* * Discard the RX ring-buffers, called as part of the net-ISR * when the buffer runs over * Caller needs to hold priv->lock */ -static void rtl838x_rb_cleanup(struct rtl838x_eth_priv *priv) +static void rtl838x_rb_cleanup(struct rtl838x_eth_priv *priv, int status) { int r; u32 *last; struct p_hdr *h; struct ring_b *ring = priv->membase; - for (r = 0; r < RXRINGS; r++) { - last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur(r))); + for (r = 0; r < priv->rxrings; r++) { + pr_debug("In %s working on r: %d\n", __func__, r); + last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4)); do { if ((ring->rx_r[r][ring->c_rx[r]] & 0x1)) break; + pr_debug("Got something: %d\n", ring->c_rx[r]); h = &ring->rx_header[r][ring->c_rx[r]]; + memset(h, 0, sizeof(struct p_hdr)); h->buf = (u8 *)KSEG1ADDR(ring->rx_space - + r * ring->c_rx[r] * RING_BUFFER); + + r * priv->rxringlen * RING_BUFFER + + ring->c_rx[r] * RING_BUFFER); h->size = RING_BUFFER; - h->len = 0; /* make sure the header is visible to the ASIC */ mb(); ring->rx_r[r][ring->c_rx[r]] = KSEG1ADDR(h) | 0x1 - | (ring->c_rx[r] == (RXRINGLEN - 1) ? WRAP : 0x1); - ring->c_rx[r] = (ring->c_rx[r] + 1) % RXRINGLEN; + | (ring->c_rx[r] == (priv->rxringlen - 1) ? WRAP : 0x1); + ring->c_rx[r] = (ring->c_rx[r] + 1) % priv->rxringlen; } while (&ring->rx_r[r][ring->c_rx[r]] != last); } } @@ -229,25 +331,25 @@ struct fdb_update_work { void rtl838x_fdb_sync(struct work_struct *work) { - const struct fdb_update_work *uw = - container_of(work, struct fdb_update_work, work); - struct switchdev_notifier_fdb_info info; - u8 addr[ETH_ALEN]; - int i = 0; - int action; + const struct fdb_update_work *uw = + container_of(work, struct fdb_update_work, work); + struct switchdev_notifier_fdb_info info; + u8 addr[ETH_ALEN]; + int i = 0; + int action; - while (uw->macs[i]) { - action = (uw->macs[i] & (1ULL << 63)) ? SWITCHDEV_FDB_ADD_TO_BRIDGE - : SWITCHDEV_FDB_DEL_TO_BRIDGE; - u64_to_ether_addr(uw->macs[i] & 0xffffffffffffULL, addr); - info.addr = &addr[0]; - info.vid = 0; - info.offloaded = 1; - pr_debug("FDB entry %d: %llx, action %d\n", i, uw->macs[0], action); - call_switchdev_notifiers(action, uw->ndev, &info.info, NULL); - i++; - } - kfree(work); + while (uw->macs[i]) { + action = (uw->macs[i] & (1ULL << 63)) ? SWITCHDEV_FDB_ADD_TO_BRIDGE + : SWITCHDEV_FDB_DEL_TO_BRIDGE; + u64_to_ether_addr(uw->macs[i] & 0xffffffffffffULL, addr); + info.addr = &addr[0]; + info.vid = 0; + info.offloaded = 1; + pr_debug("FDB entry %d: %llx, action %d\n", i, uw->macs[0], action); + call_switchdev_notifiers(action, uw->ndev, &info.info, NULL); + i++; + } + kfree(work); } static void rtl839x_l2_notification_handler(struct rtl838x_eth_priv *priv) @@ -288,19 +390,20 @@ static void rtl839x_l2_notification_handler(struct rtl838x_eth_priv *priv) priv->lastEvent = e; } -static irqreturn_t rtl838x_net_irq(int irq, void *dev_id) +static irqreturn_t rtl83xx_net_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; struct rtl838x_eth_priv *priv = netdev_priv(dev); u32 status = sw_r32(priv->r->dma_if_intr_sts); bool triggered = false; u32 atk = sw_r32(RTL838X_ATK_PRVNT_STS); + int i; u32 storm_uc = sw_r32(RTL838X_STORM_CTRL_PORT_UC_EXCEED); u32 storm_mc = sw_r32(RTL838X_STORM_CTRL_PORT_MC_EXCEED); u32 storm_bc = sw_r32(RTL838X_STORM_CTRL_PORT_BC_EXCEED); + pr_debug("IRQ: %08x\n", status); if (storm_uc || storm_mc || storm_bc) { - pr_warn("Storm control UC: %08x, MC: %08x, BC: %08x\n", storm_uc, storm_mc, storm_bc); @@ -325,20 +428,23 @@ static irqreturn_t rtl838x_net_irq(int irq, void *dev_id) /* RX interrupt */ if (status & 0x0ff00) { - /* Disable RX interrupt */ - if (triggered) - pr_info("RX\n"); - sw_w32_mask(0xff00, 0, priv->r->dma_if_intr_msk); - sw_w32(0x0000ff00, priv->r->dma_if_intr_sts); - napi_schedule(&priv->napi); + /* ACK and disable RX interrupt for this ring */ + sw_w32_mask(0xff00 & status, 0, priv->r->dma_if_intr_msk); + sw_w32(0x0000ff00 & status, priv->r->dma_if_intr_sts); + for (i = 0; i < priv->rxrings; i++) { + if (status & BIT(i + 8)) { + pr_debug("Scheduling queue: %d\n", i); + napi_schedule(&priv->rx_qs[i].napi); + } + } } /* RX buffer overrun */ if (status & 0x000ff) { pr_info("RX buffer overrun: status %x, mask: %x\n", status, sw_r32(priv->r->dma_if_intr_msk)); - sw_w32(0x000000ff, priv->r->dma_if_intr_sts); - rtl838x_rb_cleanup(priv); + sw_w32(status, priv->r->dma_if_intr_sts); + rtl838x_rb_cleanup(priv, status & 0xff); } if (priv->family_id == RTL8390_FAMILY_ID && status & 0x00100000) { @@ -360,14 +466,185 @@ static irqreturn_t rtl838x_net_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t rtl93xx_net_irq(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct rtl838x_eth_priv *priv = netdev_priv(dev); + u32 status_rx_r = sw_r32(priv->r->dma_if_intr_rx_runout_sts); + u32 status_rx = sw_r32(priv->r->dma_if_intr_rx_done_sts); + u32 status_tx = sw_r32(priv->r->dma_if_intr_tx_done_sts); + int i; + + pr_debug("In %s, status_tx: %08x, status_rx: %08x, status_rx_r: %08x\n", + __func__, status_tx, status_rx, status_rx_r); + spin_lock(&priv->lock); + + /* Ignore TX interrupt */ + if (status_tx) { + /* Clear ISR */ + pr_debug("TX done\n"); + sw_w32(status_tx, priv->r->dma_if_intr_tx_done_sts); + } + + /* RX interrupt */ + if (status_rx) { + pr_debug("RX IRQ\n"); + /* ACK and disable RX interrupt for given rings */ + sw_w32(status_rx, priv->r->dma_if_intr_rx_done_sts); + sw_w32_mask(status_rx, 0, priv->r->dma_if_intr_rx_done_msk); + for (i = 0; i < priv->rxrings; i++) { + if (status_rx & BIT(i)) { + pr_debug("Scheduling queue: %d\n", i); + napi_schedule(&priv->rx_qs[i].napi); + } + } + } + + /* RX buffer overrun */ + if (status_rx_r) { + pr_debug("RX buffer overrun: status %x, mask: %x\n", + status_rx_r, sw_r32(priv->r->dma_if_intr_rx_runout_msk)); + sw_w32(status_rx_r, priv->r->dma_if_intr_rx_runout_sts); + rtl838x_rb_cleanup(priv, status_rx_r); + } + + spin_unlock(&priv->lock); + return IRQ_HANDLED; +} + +static const struct rtl838x_reg rtl838x_reg = { + .net_irq = rtl83xx_net_irq, + .mac_port_ctrl = rtl838x_mac_port_ctrl, + .dma_if_intr_sts = RTL838X_DMA_IF_INTR_STS, + .dma_if_intr_msk = RTL838X_DMA_IF_INTR_MSK, + .dma_if_ctrl = RTL838X_DMA_IF_CTRL, + .mac_force_mode_ctrl = RTL838X_MAC_FORCE_MODE_CTRL, + .dma_rx_base = RTL838X_DMA_RX_BASE, + .dma_tx_base = RTL838X_DMA_TX_BASE, + .dma_if_rx_ring_size = rtl838x_dma_if_rx_ring_size, + .dma_if_rx_ring_cntr = rtl838x_dma_if_rx_ring_cntr, + .dma_if_rx_cur = RTL838X_DMA_IF_RX_CUR, + .rst_glb_ctrl = RTL838X_RST_GLB_CTRL_0, + .get_mac_link_sts = rtl838x_get_mac_link_sts, + .get_mac_link_dup_sts = rtl838x_get_mac_link_dup_sts, + .get_mac_link_spd_sts = rtl838x_get_mac_link_spd_sts, + .get_mac_rx_pause_sts = rtl838x_get_mac_rx_pause_sts, + .get_mac_tx_pause_sts = rtl838x_get_mac_tx_pause_sts, + .mac = RTL838X_MAC, + .l2_tbl_flush_ctrl = RTL838X_L2_TBL_FLUSH_CTRL, + .update_cntr = rtl838x_update_cntr, + .create_tx_header = rtl838x_create_tx_header, + .decode_tag = rtl838x_decode_tag, +}; + +static const struct rtl838x_reg rtl839x_reg = { + .net_irq = rtl83xx_net_irq, + .mac_port_ctrl = rtl839x_mac_port_ctrl, + .dma_if_intr_sts = RTL839X_DMA_IF_INTR_STS, + .dma_if_intr_msk = RTL839X_DMA_IF_INTR_MSK, + .dma_if_ctrl = RTL839X_DMA_IF_CTRL, + .mac_force_mode_ctrl = RTL839X_MAC_FORCE_MODE_CTRL, + .dma_rx_base = RTL839X_DMA_RX_BASE, + .dma_tx_base = RTL839X_DMA_TX_BASE, + .dma_if_rx_ring_size = rtl839x_dma_if_rx_ring_size, + .dma_if_rx_ring_cntr = rtl839x_dma_if_rx_ring_cntr, + .dma_if_rx_cur = RTL839X_DMA_IF_RX_CUR, + .rst_glb_ctrl = RTL839X_RST_GLB_CTRL, + .get_mac_link_sts = rtl839x_get_mac_link_sts, + .get_mac_link_dup_sts = rtl839x_get_mac_link_dup_sts, + .get_mac_link_spd_sts = rtl839x_get_mac_link_spd_sts, + .get_mac_rx_pause_sts = rtl839x_get_mac_rx_pause_sts, + .get_mac_tx_pause_sts = rtl839x_get_mac_tx_pause_sts, + .mac = RTL839X_MAC, + .l2_tbl_flush_ctrl = RTL839X_L2_TBL_FLUSH_CTRL, + .update_cntr = rtl839x_update_cntr, + .create_tx_header = rtl839x_create_tx_header, + .decode_tag = rtl839x_decode_tag, +}; + +static const struct rtl838x_reg rtl930x_reg = { + .net_irq = rtl93xx_net_irq, + .mac_port_ctrl = rtl930x_mac_port_ctrl, + .dma_if_intr_rx_runout_sts = RTL930X_DMA_IF_INTR_RX_RUNOUT_STS, + .dma_if_intr_rx_done_sts = RTL930X_DMA_IF_INTR_RX_DONE_STS, + .dma_if_intr_tx_done_sts = RTL930X_DMA_IF_INTR_TX_DONE_STS, + .dma_if_intr_rx_runout_msk = RTL930X_DMA_IF_INTR_RX_RUNOUT_MSK, + .dma_if_intr_rx_done_msk = RTL930X_DMA_IF_INTR_RX_DONE_MSK, + .dma_if_intr_tx_done_msk = RTL930X_DMA_IF_INTR_TX_DONE_MSK, + .l2_ntfy_if_intr_sts = RTL930X_L2_NTFY_IF_INTR_STS, + .l2_ntfy_if_intr_msk = RTL930X_L2_NTFY_IF_INTR_MSK, + .dma_if_ctrl = RTL930X_DMA_IF_CTRL, + .mac_force_mode_ctrl = RTL930X_MAC_FORCE_MODE_CTRL, + .dma_rx_base = RTL930X_DMA_RX_BASE, + .dma_tx_base = RTL930X_DMA_TX_BASE, + .dma_if_rx_ring_size = rtl930x_dma_if_rx_ring_size, + .dma_if_rx_ring_cntr = rtl930x_dma_if_rx_ring_cntr, + .dma_if_rx_cur = RTL930X_DMA_IF_RX_CUR, + .rst_glb_ctrl = RTL930X_RST_GLB_CTRL_0, + .get_mac_link_sts = rtl930x_get_mac_link_sts, + .get_mac_link_dup_sts = rtl930x_get_mac_link_dup_sts, + .get_mac_link_spd_sts = rtl930x_get_mac_link_spd_sts, + .get_mac_rx_pause_sts = rtl930x_get_mac_rx_pause_sts, + .get_mac_tx_pause_sts = rtl930x_get_mac_tx_pause_sts, + .mac = RTL930X_MAC_L2_ADDR_CTRL, + .l2_tbl_flush_ctrl = RTL930X_L2_TBL_FLUSH_CTRL, + .update_cntr = rtl930x_update_cntr, + .create_tx_header = rtl930x_create_tx_header, + .decode_tag = rtl930x_decode_tag, +}; + +static const struct rtl838x_reg rtl931x_reg = { + .net_irq = rtl93xx_net_irq, + .mac_port_ctrl = rtl931x_mac_port_ctrl, + .dma_if_intr_rx_runout_sts = RTL931X_DMA_IF_INTR_RX_RUNOUT_STS, + .dma_if_intr_rx_done_sts = RTL931X_DMA_IF_INTR_RX_DONE_STS, + .dma_if_intr_tx_done_sts = RTL931X_DMA_IF_INTR_TX_DONE_STS, + .dma_if_intr_rx_runout_msk = RTL931X_DMA_IF_INTR_RX_RUNOUT_MSK, + .dma_if_intr_rx_done_msk = RTL931X_DMA_IF_INTR_RX_DONE_MSK, + .dma_if_intr_tx_done_msk = RTL931X_DMA_IF_INTR_TX_DONE_MSK, + .l2_ntfy_if_intr_sts = RTL931X_L2_NTFY_IF_INTR_STS, + .l2_ntfy_if_intr_msk = RTL931X_L2_NTFY_IF_INTR_MSK, + .dma_if_ctrl = RTL931X_DMA_IF_CTRL, + .mac_force_mode_ctrl = RTL931X_MAC_FORCE_MODE_CTRL, + .dma_rx_base = RTL931X_DMA_RX_BASE, + .dma_tx_base = RTL931X_DMA_TX_BASE, + .dma_if_rx_ring_size = rtl931x_dma_if_rx_ring_size, + .dma_if_rx_ring_cntr = rtl931x_dma_if_rx_ring_cntr, + .dma_if_rx_cur = RTL931X_DMA_IF_RX_CUR, + .rst_glb_ctrl = RTL931X_RST_GLB_CTRL, + .get_mac_link_sts = rtl931x_get_mac_link_sts, + .get_mac_link_dup_sts = rtl931x_get_mac_link_dup_sts, + .get_mac_link_spd_sts = rtl931x_get_mac_link_spd_sts, + .get_mac_rx_pause_sts = rtl931x_get_mac_rx_pause_sts, + .get_mac_tx_pause_sts = rtl931x_get_mac_tx_pause_sts, + .mac = RTL931X_MAC_L2_ADDR_CTRL, + .l2_tbl_flush_ctrl = RTL931X_L2_TBL_FLUSH_CTRL, + .update_cntr = rtl931x_update_cntr, + .create_tx_header = rtl931x_create_tx_header, + .decode_tag = rtl931x_decode_tag, +}; + static void rtl838x_hw_reset(struct rtl838x_eth_priv *priv) { u32 int_saved, nbuf; - + int i, pos; + pr_info("RESETTING %x, CPU_PORT %d\n", priv->family_id, priv->cpu_port); - /* Stop TX/RX */ sw_w32_mask(0x3, 0, priv->r->mac_port_ctrl(priv->cpu_port)); - mdelay(500); + mdelay(100); + + /* Disable and clear interrupts */ + if (priv->family_id == RTL9300_FAMILY_ID || priv->family_id == RTL9310_FAMILY_ID) { + sw_w32(0x00000000, priv->r->dma_if_intr_rx_runout_msk); + sw_w32(0xffffffff, priv->r->dma_if_intr_rx_runout_sts); + sw_w32(0x00000000, priv->r->dma_if_intr_rx_done_msk); + sw_w32(0xffffffff, priv->r->dma_if_intr_rx_done_sts); + sw_w32(0x00000000, priv->r->dma_if_intr_tx_done_msk); + sw_w32(0x0000000f, priv->r->dma_if_intr_tx_done_sts); + } else { + sw_w32(0x00000000, priv->r->dma_if_intr_msk); + sw_w32(0xffffffff, priv->r->dma_if_intr_sts); + } if (priv->family_id == RTL8390_FAMILY_ID) { /* Preserve L2 notification and NBUF settings */ @@ -382,17 +659,30 @@ static void rtl838x_hw_reset(struct rtl838x_eth_priv *priv) sw_w32(0xffffffff, priv->r->dma_if_intr_sts); } - /* Reset NIC and Queue */ - sw_w32(0x08, priv->r->rst_glb_ctrl); + /* Reset NIC */ + if (priv->family_id == RTL9300_FAMILY_ID || priv->family_id == RTL9310_FAMILY_ID) + sw_w32(0x4, priv->r->rst_glb_ctrl); + else + sw_w32(0x8, priv->r->rst_glb_ctrl); + + do { /* Wait for reset of NIC and Queues done */ + udelay(20); + } while (sw_r32(priv->r->rst_glb_ctrl) & 0xc); + mdelay(100); + + /* Setup Head of Line */ + if (priv->family_id == RTL8380_FAMILY_ID) + sw_w32(0, RTL838X_DMA_IF_RX_RING_SIZE); // Disabled on RTL8380 if (priv->family_id == RTL8390_FAMILY_ID) sw_w32(0xffffffff, RTL839X_DMA_IF_RX_RING_CNTR); - do { /* Reset NIC */ - udelay(20); - } while (sw_r32(priv->r->rst_glb_ctrl) & 0x08); - do { /* Reset Queues */ - udelay(20); - } while (sw_r32(priv->r->rst_glb_ctrl) & 0x04); - mdelay(100); + if (priv->family_id == RTL9300_FAMILY_ID) { + for (i = 0; i < priv->rxrings; i++) { + pos = (i % 3) * 10; + sw_w32_mask(0x3ff << pos, 0, priv->r->dma_if_rx_ring_size(i)); + sw_w32_mask(0x3ff << pos, priv->rxringlen, + priv->r->dma_if_rx_ring_cntr(i)); + } + } /* Re-enable link change interrupt */ if (priv->family_id == RTL8390_FAMILY_ID) { @@ -405,32 +695,6 @@ static void rtl838x_hw_reset(struct rtl838x_eth_priv *priv) sw_w32_mask(7 << 20, int_saved & (7 << 20), priv->r->dma_if_intr_msk); sw_w32(nbuf, RTL839X_DMA_IF_NBUF_BASE_DESC_ADDR_CTRL); } - - /* Restart TX/RX to CPU port */ - sw_w32_mask(0x0, 0x3, priv->r->mac_port_ctrl(priv->cpu_port)); - - if (priv->family_id == RTL8380_FAMILY_ID) { - /* Set Speed, duplex, flow control - * FORCE_EN | LINK_EN | NWAY_EN | DUP_SEL - * | SPD_SEL = 0b10 | FORCE_FC_EN | PHY_MASTER_SLV_MANUAL_EN - * | MEDIA_SEL - */ - sw_w32(0x6192F, priv->r->mac_force_mode_ctrl(priv->cpu_port)); - /* allow CRC errors on CPU-port */ - sw_w32_mask(0, 0x8, priv->r->mac_port_ctrl(priv->cpu_port)); - } else { - /* CPU port joins Lookup Miss Flooding Portmask */ - sw_w32(0x28000, RTL839X_TBL_ACCESS_L2_CTRL); - sw_w32_mask(0, 0x80000000, RTL839X_TBL_ACCESS_L2_DATA(0)); - sw_w32(0x38000, RTL839X_TBL_ACCESS_L2_CTRL); - - /* Force CPU port link up */ - sw_w32_mask(0, 3, priv->r->mac_force_mode_ctrl(priv->cpu_port)); - } - - /* Disable and clear interrupts */ - sw_w32(0x00000000, priv->r->dma_if_intr_msk); - sw_w32(0xffffffff, priv->r->dma_if_intr_sts); } static void rtl838x_hw_ring_setup(struct rtl838x_eth_priv *priv) @@ -438,11 +702,11 @@ static void rtl838x_hw_ring_setup(struct rtl838x_eth_priv *priv) int i; struct ring_b *ring = priv->membase; - for (i = 0; i < RXRINGS; i++) - sw_w32(KSEG1ADDR(&ring->rx_r[i]), priv->r->dma_rx_base(i)); + for (i = 0; i < priv->rxrings; i++) + sw_w32(KSEG1ADDR(&ring->rx_r[i]), priv->r->dma_rx_base + i * 4); for (i = 0; i < TXRINGS; i++) - sw_w32(KSEG1ADDR(&ring->tx_r[i]), priv->r->dma_tx_base(i)); + sw_w32(KSEG1ADDR(&ring->tx_r[i]), priv->r->dma_tx_base + i * 4); } static void rtl838x_hw_en_rxtx(struct rtl838x_eth_priv *priv) @@ -456,8 +720,19 @@ static void rtl838x_hw_en_rxtx(struct rtl838x_eth_priv *priv) /* Enable RX done, RX overflow and TX done interrupts */ sw_w32(0xfffff, priv->r->dma_if_intr_msk); - /* Enable traffic, engine expects empty FCS field */ + /* Enable DMA, engine expects empty FCS field */ sw_w32_mask(0, RX_EN | TX_EN, priv->r->dma_if_ctrl); + + /* Restart TX/RX to CPU port */ + sw_w32_mask(0x0, 0x3, priv->r->mac_port_ctrl(priv->cpu_port)); + /* Set Speed, duplex, flow control + * FORCE_EN | LINK_EN | NWAY_EN | DUP_SEL + * | SPD_SEL = 0b10 | FORCE_FC_EN | PHY_MASTER_SLV_MANUAL_EN + * | MEDIA_SEL + */ + sw_w32(0x6192F, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); + /* allow CRC errors on CPU-port */ + sw_w32_mask(0, 0x8, priv->r->mac_port_ctrl(priv->cpu_port)); } static void rtl839x_hw_en_rxtx(struct rtl838x_eth_priv *priv) @@ -468,27 +743,71 @@ static void rtl839x_hw_en_rxtx(struct rtl838x_eth_priv *priv) /* Enable Notify, RX done, RX overflow and TX done interrupts */ sw_w32(0x007fffff, priv->r->dma_if_intr_msk); // Notify IRQ! - /* Enable traffic */ + /* Enable DMA */ sw_w32_mask(0, RX_EN | TX_EN, priv->r->dma_if_ctrl); + + /* Restart TX/RX to CPU port */ + sw_w32_mask(0x0, 0x3, priv->r->mac_port_ctrl(priv->cpu_port)); + + /* CPU port joins Lookup Miss Flooding Portmask */ + // TODO: The code below should also work for the RTL838x + sw_w32(0x28000, RTL839X_TBL_ACCESS_L2_CTRL); + sw_w32_mask(0, 0x80000000, RTL839X_TBL_ACCESS_L2_DATA(0)); + sw_w32(0x38000, RTL839X_TBL_ACCESS_L2_CTRL); + + /* Force CPU port link up */ + sw_w32_mask(0, 3, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); } -static void rtl838x_setup_ring_buffer(struct ring_b *ring) +static void rtl93xx_hw_en_rxtx(struct rtl838x_eth_priv *priv) +{ + int i, pos; + u32 v; + + /* Setup CPU-Port: RX Buffer truncated at 1600 Bytes */ + sw_w32(0x06400040, priv->r->dma_if_ctrl); + + for (i = 0; i < priv->rxrings; i++) { + pos = (i % 3) * 10; + sw_w32_mask(0x3ff << pos, priv->rxringlen << pos, priv->r->dma_if_rx_ring_size(i)); + + // Some SoCs have issues with missing underflow protection + v = (sw_r32(priv->r->dma_if_rx_ring_cntr(i)) >> pos) & 0x3ff; + sw_w32_mask(0x3ff << pos, v, priv->r->dma_if_rx_ring_cntr(i)); + } + + /* Enable Notify, RX done, RX overflow and TX done interrupts */ + sw_w32(0xffffffff, priv->r->dma_if_intr_rx_runout_msk); + sw_w32(0xffffffff, priv->r->dma_if_intr_rx_done_msk); + sw_w32(0x0000000f, priv->r->dma_if_intr_tx_done_msk); + + /* Enable DMA */ + sw_w32_mask(0, RX_EN_93XX | TX_EN_93XX, priv->r->dma_if_ctrl); + + /* Restart TX/RX to CPU port */ + sw_w32_mask(0x0, 0x3, priv->r->mac_port_ctrl(priv->cpu_port)); + + sw_w32_mask(0, BIT(priv->cpu_port), RTL930X_L2_UNKN_UC_FLD_PMSK); + sw_w32(0x217, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); +} + +static void rtl838x_setup_ring_buffer(struct rtl838x_eth_priv *priv, struct ring_b *ring) { int i, j; struct p_hdr *h; - for (i = 0; i < RXRINGS; i++) { - for (j = 0; j < RXRINGLEN; j++) { + for (i = 0; i < priv->rxrings; i++) { + for (j = 0; j < priv->rxringlen; j++) { h = &ring->rx_header[i][j]; - h->buf = (u8 *)KSEG1ADDR(ring->rx_space + i * j * RING_BUFFER); - h->reserved = 0; + memset(h, 0, sizeof(struct p_hdr)); + h->buf = (u8 *)KSEG1ADDR(ring->rx_space + + i * priv->rxringlen * RING_BUFFER + + j * RING_BUFFER); h->size = RING_BUFFER; - h->offset = 0; - h->len = 0; - memset(&h->cpu_tag, 0, sizeof(uint16_t[5])); /* All rings owned by switch, last one wraps */ - ring->rx_r[i][j] = KSEG1ADDR(h) | 1 | (j == (RXRINGLEN - 1) ? WRAP : 0); + ring->rx_r[i][j] = KSEG1ADDR(h) | 1 + | (j == (priv->rxringlen - 1) ? WRAP : 0); } ring->c_rx[i] = 0; } @@ -496,12 +815,11 @@ static void rtl838x_setup_ring_buffer(struct ring_b *ring) for (i = 0; i < TXRINGS; i++) { for (j = 0; j < TXRINGLEN; j++) { h = &ring->tx_header[i][j]; - h->buf = (u8 *)KSEG1ADDR(ring->tx_space + i * j * RING_BUFFER); - h->reserved = 0; + memset(h, 0, sizeof(struct p_hdr)); + h->buf = (u8 *)KSEG1ADDR(ring->tx_space + + i * TXRINGLEN * RING_BUFFER + + j * RING_BUFFER); h->size = RING_BUFFER; - h->offset = 0; - h->len = 0; - memset(&h->cpu_tag, 0, sizeof(uint16_t[5])); ring->tx_r[i][j] = KSEG1ADDR(&ring->tx_header[i][j]); } /* Last header is wrapping around */ @@ -535,13 +853,14 @@ static int rtl838x_eth_open(struct net_device *ndev) unsigned long flags; struct rtl838x_eth_priv *priv = netdev_priv(ndev); struct ring_b *ring = priv->membase; - int err; + int i, err; - pr_info("%s called: RX rings %d, TX rings %d\n", __func__, RXRINGS, TXRINGS); + pr_info("%s called: RX rings %d(length %d), TX rings %d(length %d)\n", + __func__, priv->rxrings, priv->rxringlen, TXRINGS, TXRINGLEN); spin_lock_irqsave(&priv->lock, flags); rtl838x_hw_reset(priv); - rtl838x_setup_ring_buffer(ring); + rtl838x_setup_ring_buffer(priv, ring); if (priv->family_id == RTL8390_FAMILY_ID) { rtl839x_setup_notify_ring_buffer(priv); /* Make sure the ring structure is visible to the ASIC */ @@ -550,8 +869,7 @@ static int rtl838x_eth_open(struct net_device *ndev) } rtl838x_hw_ring_setup(priv); - err = request_irq(ndev->irq, rtl838x_net_irq, IRQF_SHARED, - ndev->name, ndev); + err = request_irq(ndev->irq, priv->r->net_irq, IRQF_SHARED, ndev->name, ndev); if (err) { netdev_err(ndev, "%s: could not acquire interrupt: %d\n", __func__, err); @@ -559,21 +877,39 @@ static int rtl838x_eth_open(struct net_device *ndev) } phylink_start(priv->phylink); - napi_enable(&priv->napi); - netif_start_queue(ndev); + for (i = 0; i < priv->rxrings; i++) + napi_enable(&priv->rx_qs[i].napi); - if (priv->family_id == RTL8380_FAMILY_ID) { + switch (priv->family_id) { + case RTL8380_FAMILY_ID: rtl838x_hw_en_rxtx(priv); /* Trap IGMP traffic to CPU-Port */ sw_w32(0x3, RTL838X_SPCL_TRAP_IGMP_CTRL); /* Flush learned FDB entries on link down of a port */ - sw_w32_mask(0, 1 << 7, RTL838X_L2_CTRL_0); - } else { + sw_w32_mask(0, BIT(7), RTL838X_L2_CTRL_0); + break; + case RTL8390_FAMILY_ID: rtl839x_hw_en_rxtx(priv); sw_w32(0x3, RTL839X_SPCL_TRAP_IGMP_CTRL); - sw_w32_mask(0, 1 << 7, RTL839X_L2_CTRL_0); + /* Flush learned FDB entries on link down of a port */ + sw_w32_mask(0, BIT(7), RTL839X_L2_CTRL_0); + break; + case RTL9300_FAMILY_ID: + rtl93xx_hw_en_rxtx(priv); + /* Flush learned FDB entries on link down of a port */ + sw_w32_mask(0, BIT(7), RTL930X_L2_CTRL); + sw_w32_mask(BIT(28), 0, RTL930X_L2_PORT_SABLK_CTRL); + sw_w32_mask(BIT(28), 0, RTL930X_L2_PORT_DABLK_CTRL); + break; + + case RTL9310_FAMILY_ID: + rtl93xx_hw_en_rxtx(priv); +// TODO: Add trapping of IGMP frames to CPU-port + break; } + netif_tx_start_all_queues(ndev); + spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -581,10 +917,20 @@ static int rtl838x_eth_open(struct net_device *ndev) static void rtl838x_hw_stop(struct rtl838x_eth_priv *priv) { - u32 force_mac = priv->family_id == RTL8380_FAMILY_ID ? 0x6192D : 0x75; + u32 force_mac = priv->family_id == RTL8380_FAMILY_ID ? 0x6192C : 0x75; u32 clear_irq = priv->family_id == RTL8380_FAMILY_ID ? 0x000fffff : 0x007fffff; int i; + // Disable RX/TX from/to CPU-port + sw_w32_mask(0x3, 0, priv->r->mac_port_ctrl(priv->cpu_port)); + + /* Disable traffic */ + if (priv->family_id == RTL9300_FAMILY_ID || priv->family_id == RTL9310_FAMILY_ID) + sw_w32_mask(RX_EN_93XX | TX_EN_93XX, 0, priv->r->dma_if_ctrl); + else + sw_w32_mask(RX_EN | TX_EN, 0, priv->r->dma_if_ctrl); + mdelay(200); // Test, whether this is needed + /* Block all ports */ if (priv->family_id == RTL8380_FAMILY_ID) { sw_w32(0x03000000, RTL838X_TBL_ACCESS_DATA_0(0)); @@ -598,24 +944,33 @@ static void rtl838x_hw_stop(struct rtl838x_eth_priv *priv) sw_w32(1 << 26 | 1 << 23 | i << 5, priv->r->l2_tbl_flush_ctrl); do { } while (sw_r32(priv->r->l2_tbl_flush_ctrl) & (1 << 26)); } - } else { + } else if (priv->family_id == RTL8390_FAMILY_ID) { for (i = 0; i <= priv->cpu_port; i++) { sw_w32(1 << 28 | 1 << 25 | i << 5, priv->r->l2_tbl_flush_ctrl); do { } while (sw_r32(priv->r->l2_tbl_flush_ctrl) & (1 << 28)); } } + // TODO: L2 flush register is 64 bit on RTL931X and 930X /* CPU-Port: Link down */ - sw_w32(force_mac, priv->r->mac_force_mode_ctrl(priv->cpu_port)); + if (priv->family_id == RTL8380_FAMILY_ID || priv->family_id == RTL8390_FAMILY_ID) + sw_w32(force_mac, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); + else + sw_w32_mask(0x3, 0, priv->r->mac_force_mode_ctrl + priv->cpu_port *4); mdelay(100); - /* Disable traffic */ - sw_w32_mask(RX_EN | TX_EN, 0, priv->r->dma_if_ctrl); - mdelay(200); // Test, whether this is needed - /* Disable all TX/RX interrupts */ - sw_w32(0x00000000, priv->r->dma_if_intr_msk); - sw_w32(clear_irq, priv->r->dma_if_intr_sts); + if (priv->family_id == RTL9300_FAMILY_ID || priv->family_id == RTL9310_FAMILY_ID) { + sw_w32(0x00000000, priv->r->dma_if_intr_rx_runout_msk); + sw_w32(0xffffffff, priv->r->dma_if_intr_rx_runout_sts); + sw_w32(0x00000000, priv->r->dma_if_intr_rx_done_msk); + sw_w32(0xffffffff, priv->r->dma_if_intr_rx_done_sts); + sw_w32(0x00000000, priv->r->dma_if_intr_tx_done_msk); + sw_w32(0x0000000f, priv->r->dma_if_intr_tx_done_sts); + } else { + sw_w32(0x00000000, priv->r->dma_if_intr_msk); + sw_w32(clear_irq, priv->r->dma_if_intr_sts); + } /* Disable TX/RX DMA */ sw_w32(0x00000000, priv->r->dma_if_ctrl); @@ -625,6 +980,7 @@ static void rtl838x_hw_stop(struct rtl838x_eth_priv *priv) static int rtl838x_eth_stop(struct net_device *ndev) { unsigned long flags; + int i; struct rtl838x_eth_priv *priv = netdev_priv(ndev); pr_info("in %s\n", __func__); @@ -633,8 +989,12 @@ static int rtl838x_eth_stop(struct net_device *ndev) phylink_stop(priv->phylink); rtl838x_hw_stop(priv); free_irq(ndev->irq, ndev); - napi_disable(&priv->napi); - netif_stop_queue(ndev); + + for (i = 0; i < priv->rxrings; i++) + napi_disable(&priv->rx_qs[i].napi); + + netif_tx_stop_all_queues(ndev); + spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -680,12 +1040,50 @@ static void rtl838x_eth_set_multicast_list(struct net_device *ndev) } } +static void rtl930x_eth_set_multicast_list(struct net_device *ndev) +{ + if (!(ndev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { + sw_w32(0x0, RTL930X_RMA_CTRL_0); + sw_w32(0x0, RTL930X_RMA_CTRL_1); + sw_w32(0x0, RTL930X_RMA_CTRL_2); + } + if (ndev->flags & IFF_ALLMULTI) { + sw_w32(0x7fffffff, RTL930X_RMA_CTRL_0); + sw_w32(0x7fffffff, RTL930X_RMA_CTRL_1); + sw_w32(0x7fffffff, RTL930X_RMA_CTRL_2); + } + if (ndev->flags & IFF_PROMISC) { + sw_w32(0x7fffffff, RTL930X_RMA_CTRL_0); + sw_w32(0x7fffffff, RTL930X_RMA_CTRL_1); + sw_w32(0x7fffffff, RTL930X_RMA_CTRL_2); + } +} + +static void rtl931x_eth_set_multicast_list(struct net_device *ndev) +{ + if (!(ndev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { + sw_w32(0x0, RTL931X_RMA_CTRL_0); + sw_w32(0x0, RTL931X_RMA_CTRL_1); + sw_w32(0x0, RTL931X_RMA_CTRL_2); + } + if (ndev->flags & IFF_ALLMULTI) { + sw_w32(0x7fffffff, RTL931X_RMA_CTRL_0); + sw_w32(0x7fffffff, RTL931X_RMA_CTRL_1); + sw_w32(0x7fffffff, RTL931X_RMA_CTRL_2); + } + if (ndev->flags & IFF_PROMISC) { + sw_w32(0x7fffffff, RTL931X_RMA_CTRL_0); + sw_w32(0x7fffffff, RTL931X_RMA_CTRL_1); + sw_w32(0x7fffffff, RTL931X_RMA_CTRL_2); + } +} + static void rtl838x_eth_tx_timeout(struct net_device *ndev) { unsigned long flags; struct rtl838x_eth_priv *priv = netdev_priv(ndev); - pr_info("in %s\n", __func__); + pr_warn("%s\n", __func__); spin_lock_irqsave(&priv->lock, flags); rtl838x_hw_stop(priv); rtl838x_hw_ring_setup(priv); @@ -705,6 +1103,10 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev) unsigned long flags; struct p_hdr *h; int dest_port = -1; + int q = skb_get_queue_mapping(skb) % TXRINGS; + + if (q) // Check for high prio queue + pr_debug("SKB priority: %d\n", skb->priority); spin_lock_irqsave(&priv->lock, flags); len = skb->len; @@ -729,44 +1131,48 @@ static int rtl838x_eth_tx(struct sk_buff *skb, struct net_device *dev) } /* We can send this packet if CPU owns the descriptor */ - if (!(ring->tx_r[0][ring->c_tx[0]] & 0x1)) { - /* Set descriptor for tx */ - h = &ring->tx_header[0][ring->c_tx[0]]; + if (!(ring->tx_r[q][ring->c_tx[q]] & 0x1)) { - h->buf = (u8 *)KSEG1ADDR(ring->tx_space); + /* Set descriptor for tx */ + h = &ring->tx_header[q][ring->c_tx[q]]; h->size = len; h->len = len; - /* Create cpu_tag */ - if (priv->family_id == RTL8380_FAMILY_ID) - rtl838x_create_tx_header(h, dest_port); - else - rtl839x_create_tx_header(h, dest_port); + priv->r->create_tx_header(h, dest_port, skb->priority >> 1); /* Copy packet data to tx buffer */ memcpy((void *)KSEG1ADDR(h->buf), skb->data, len); /* Make sure packet data is visible to ASIC */ - mb(); /* wmb() probably works, too */ + wmb(); /* Hand over to switch */ - ring->tx_r[0][ring->c_tx[0]] = ring->tx_r[0][ring->c_tx[0]] | 0x1; + ring->tx_r[q][ring->c_tx[q]] |= 1; - /* BUG: before tx fetch, need to make sure right data is accessed - * This might not be necessary on newer RTL839x, though. - */ - for (i = 0; i < 10; i++) { - val = sw_r32(priv->r->dma_if_ctrl); - if ((val & 0xc) == 0xc) - break; + // Before starting TX, prevent a Lextra bus bug on RTL8380 SoCs + if (priv->family_id == RTL8380_FAMILY_ID) { + for (i = 0; i < 10; i++) { + val = sw_r32(priv->r->dma_if_ctrl); + if ((val & 0xc) == 0xc) + break; + } } /* Tell switch to send data */ - sw_w32_mask(0, TX_DO, priv->r->dma_if_ctrl); + if (priv->family_id == RTL9310_FAMILY_ID + || priv->family_id == RTL9300_FAMILY_ID) { + // Ring ID q == 0: Low priority, Ring ID = 1: High prio queue + if (!q) + sw_w32_mask(0, BIT(2), priv->r->dma_if_ctrl); + else + sw_w32_mask(0, BIT(3), priv->r->dma_if_ctrl); + } else { + sw_w32_mask(0, TX_DO, priv->r->dma_if_ctrl); + } dev->stats.tx_packets++; dev->stats.tx_bytes += len; dev_kfree_skb(skb); - ring->c_tx[0] = (ring->c_tx[0] + 1) % TXRINGLEN; + ring->c_tx[q] = (ring->c_tx[q] + 1) % TXRINGLEN; ret = NETDEV_TX_OK; } else { dev_warn(&priv->pdev->dev, "Data is owned by switch\n"); @@ -777,6 +1183,30 @@ txdone: return ret; } +/* + * Return queue number for TX. On the RTL83XX, these queues have equal priority + * so we do round-robin + */ +u16 rtl83xx_pick_tx_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev) +{ + static u8 last = 0; + + last++; + return last % TXRINGS; +} + +/* + * Return queue number for TX. On the RTL93XX, queue 1 is the high priority queue + */ +u16 rtl93xx_pick_tx_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev) +{ + if (skb->priority >= TC_PRIO_CONTROL) + return 1; + return 0; +} + static int rtl838x_hw_receive(struct net_device *dev, int r, int budget) { struct rtl838x_eth_priv *priv = netdev_priv(dev); @@ -789,27 +1219,24 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget) u32 *last; struct p_hdr *h; bool dsa = netdev_uses_dsa(dev); + struct dsa_tag tag; spin_lock_irqsave(&priv->lock, flags); - last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur(r))); + last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4)); + pr_debug("---------------------------------------------------------- RX - %d\n", r); - if (&ring->rx_r[r][ring->c_rx[r]] == last) { - spin_unlock_irqrestore(&priv->lock, flags); - return 0; - } do { if ((ring->rx_r[r][ring->c_rx[r]] & 0x1)) { - netdev_warn(dev, "WARNING Ring contention: ring %x, last %x, current %x, cPTR %x, ISR %x\n", r, (uint32_t)last, - (u32) &ring->rx_r[r][ring->c_rx[r]], - ring->rx_r[r][ring->c_rx[r]], - sw_r32(priv->r->dma_if_intr_sts)); + if (&ring->rx_r[r][ring->c_rx[r]] != last) { + netdev_warn(dev, "Ring contention: r: %x, last %x, cur %x\n", + r, (uint32_t)last, (u32) &ring->rx_r[r][ring->c_rx[r]]); + } break; } h = &ring->rx_header[r][ring->c_rx[r]]; data = (u8 *)KSEG1ADDR(h->buf); len = h->len; - if (!len) break; work_done++; @@ -826,7 +1253,7 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget) /* BUG: Prevent bug on RTL838x SoCs*/ if (priv->family_id == RTL8380_FAMILY_ID) { sw_w32(0xffffffff, priv->r->dma_if_rx_ring_size(0)); - for (i = 0; i < RXRINGS; i++) { + for (i = 0; i < priv->rxrings; i++) { /* Update each ring cnt */ val = sw_r32(priv->r->dma_if_rx_ring_cntr(i)); sw_w32(val, priv->r->dma_if_rx_ring_cntr(i)); @@ -839,12 +1266,19 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget) memcpy(skb->data, (u8 *)KSEG1ADDR(data), len); /* Overwrite CRC with cpu_tag */ if (dsa) { + priv->r->decode_tag(h, &tag); skb->data[len-4] = 0x80; - skb->data[len-3] = h->cpu_tag[0] & priv->port_mask; + skb->data[len-3] = tag.port; skb->data[len-2] = 0x10; skb->data[len-1] = 0x00; + if (tag.l2_offloaded) + skb->data[len-3] |= 0x40; } + if (tag.queue >= 0) + pr_debug("Queue: %d, len: %d, reason %d port %d\n", + tag.queue, len, tag.reason, tag.port); + skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_packets++; dev->stats.rx_bytes += len; @@ -856,35 +1290,47 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget) dev->stats.rx_dropped++; } - h->buf = (u8 *)KSEG1ADDR(ring->rx_space - + r * ring->c_rx[r] * RING_BUFFER); + /* Reset header structure */ + memset(h, 0, sizeof(struct p_hdr)); + h->buf = data; h->size = RING_BUFFER; - h->len = 0; - memset(&h->cpu_tag, 0, sizeof(uint16_t[5])); - ring->rx_r[r][ring->c_rx[r]] - = KSEG1ADDR(h) | 0x1 | (ring->c_rx[r] == (RXRINGLEN-1) ? WRAP : 0x1); - ring->c_rx[r] = (ring->c_rx[r] + 1) % RXRINGLEN; + ring->rx_r[r][ring->c_rx[r]] = KSEG1ADDR(h) | 0x1 + | (ring->c_rx[r] == (priv->rxringlen - 1) ? WRAP : 0x1); + ring->c_rx[r] = (ring->c_rx[r] + 1) % priv->rxringlen; + last = (u32 *)KSEG1ADDR(sw_r32(priv->r->dma_if_rx_cur + r * 4)); } while (&ring->rx_r[r][ring->c_rx[r]] != last && work_done < budget); + // Update counters + priv->r->update_cntr(r, 0); + spin_unlock_irqrestore(&priv->lock, flags); return work_done; } static int rtl838x_poll_rx(struct napi_struct *napi, int budget) { - struct rtl838x_eth_priv *priv = container_of(napi, struct rtl838x_eth_priv, napi); - int work_done = 0, r = 0; + struct rtl838x_rx_q *rx_q = container_of(napi, struct rtl838x_rx_q, napi); + struct rtl838x_eth_priv *priv = rx_q->priv; + int work_done = 0; + int r = rx_q->id; + int work; - while (work_done < budget && r < RXRINGS) { - work_done += rtl838x_hw_receive(priv->netdev, r, budget - work_done); - r++; + while (work_done < budget) { + work = rtl838x_hw_receive(priv->netdev, r, budget - work_done); + if (!work) + break; + work_done += work; } if (work_done < budget) { napi_complete_done(napi, work_done); + /* Enable RX interrupt */ - sw_w32_mask(0, 0xfffff, priv->r->dma_if_intr_msk); + if (priv->family_id == RTL9300_FAMILY_ID || priv->family_id == RTL9310_FAMILY_ID) + sw_w32(0xffffffff, priv->r->dma_if_intr_rx_done_msk); + else + sw_w32_mask(0, 0xf00ff | BIT(r + 8), priv->r->dma_if_intr_msk); } return work_done; } @@ -960,9 +1406,9 @@ static void rtl838x_mac_an_restart(struct phylink_config *config) pr_info("In %s\n", __func__); /* Restart by disabling and re-enabling link */ - sw_w32(0x6192D, priv->r->mac_force_mode_ctrl(priv->cpu_port)); + sw_w32(0x6192D, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); mdelay(20); - sw_w32(0x6192F, priv->r->mac_force_mode_ctrl(priv->cpu_port)); + sw_w32(0x6192F, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); } static int rtl838x_mac_pcs_get_state(struct phylink_config *config, @@ -1114,70 +1560,6 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev, return phylink_ethtool_ksettings_set(priv->phylink, cmd); } -int rtl839x_read_sds_phy(int phy_addr, int phy_reg) -{ - int offset = 0; - int reg; - u32 val; - - if (phy_addr == 49) - offset = 0x100; - - /* For the RTL8393 internal SerDes, we simulate a PHY ID in registers 2/3 - * which would otherwise read as 0 - */ - if (soc_info.id == 0x8393) { - if (phy_reg == 2) - return 0x1c; - if (phy_reg == 3) - return 0x8393; - } - - reg = (phy_reg << 1) & 0xfc; - val = sw_r32(RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg); - - if (phy_reg & 1) - val = (val >> 16) & 0xffff; - else - val &= 0xffff; - return val; -} - -int rtl838x_read_sds_phy(int phy_addr, int phy_reg) -{ - int offset = 0; - u32 val; - - if (phy_addr == 26) - offset = 0x100; - val = sw_r32(MAPLE_SDS4_FIB_REG0r + offset + (phy_reg << 2)) & 0xffff; - - return val; -} - -int rtl839x_write_sds_phy(int phy_addr, int phy_reg, u16 v) -{ - int offset = 0; - int reg; - u32 val; - - if (phy_addr == 49) - offset = 0x100; - - reg = (phy_reg << 1) & 0xfc; - val = v; - if (phy_reg & 1) { - val = val << 16; - sw_w32_mask(0xffff0000, val, - RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg); - } else { - sw_w32_mask(0xffff, val, - RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg); - } - - return 0; -} - static int rtl838x_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { u32 val; @@ -1207,6 +1589,41 @@ static int rtl839x_mdio_read(struct mii_bus *bus, int mii_id, int regnum) return val; } +static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + u32 val; + int err; + + // TODO: These are hard-coded for the 2 Fibre Ports of the XGS1210 + if (mii_id >= 26 && mii_id <= 27) + return rtl930x_read_sds_phy(mii_id - 18, 0, regnum); + + if (regnum & MII_ADDR_C45) { + regnum &= ~MII_ADDR_C45; + err = rtl930x_read_mmd_phy(mii_id, regnum >> 16, regnum & 0xffff, &val); + } else { + err = rtl930x_read_phy(mii_id, 0, regnum, &val); + } + if (err) + return err; + return val; +} + +static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + u32 val; + int err; +// struct rtl838x_eth_priv *priv = bus->priv; + +// if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393) +// return rtl839x_read_sds_phy(mii_id, regnum); + + err = rtl931x_read_phy(mii_id, 0, regnum, &val); + if (err) + return err; + return val; +} + static int rtl838x_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { @@ -1216,7 +1633,7 @@ static int rtl838x_mdio_write(struct mii_bus *bus, int mii_id, if (mii_id >= 24 && mii_id <= 27 && priv->id == 0x8380) { if (mii_id == 26) offset = 0x100; - sw_w32(value, MAPLE_SDS4_FIB_REG0r + offset + (regnum << 2)); + sw_w32(value, RTL838X_SDS4_FIB_REG0 + offset + (regnum << 2)); return 0; } return rtl838x_write_phy(mii_id, 0, regnum, value); @@ -1233,6 +1650,32 @@ static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id, return rtl839x_write_phy(mii_id, 0, regnum, value); } +static int rtl930x_mdio_write(struct mii_bus *bus, int mii_id, + int regnum, u16 value) +{ +// struct rtl838x_eth_priv *priv = bus->priv; + +// if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393) +// return rtl839x_write_sds_phy(mii_id, regnum, value); + if (regnum & MII_ADDR_C45) { + regnum &= ~MII_ADDR_C45; + return rtl930x_write_mmd_phy(mii_id, regnum >> 16, regnum & 0xffff, value); + } + + return rtl930x_write_phy(mii_id, 0, regnum, value); +} + +static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id, + int regnum, u16 value) +{ +// struct rtl838x_eth_priv *priv = bus->priv; + +// if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393) +// return rtl839x_write_sds_phy(mii_id, regnum, value); + + return rtl931x_write_phy(mii_id, 0, regnum, value); +} + static int rtl838x_mdio_reset(struct mii_bus *bus) { pr_info("%s called\n", __func__); @@ -1262,6 +1705,62 @@ static int rtl839x_mdio_reset(struct mii_bus *bus) return 0; } +static int rtl931x_mdio_reset(struct mii_bus *bus) +{ + sw_w32(0x00000000, RTL931X_SMI_PORT_POLLING_CTRL); + sw_w32(0x00000000, RTL931X_SMI_PORT_POLLING_CTRL + 4); + + pr_info("%s called\n", __func__); + + return 0; +} + +static int rtl930x_mdio_reset(struct mii_bus *bus) +{ + int i; + int pos; + + pr_info("RTL930X_SMI_PORT0_15_POLLING_SEL %08x 16-27: %08x\n", + sw_r32(RTL930X_SMI_PORT0_15_POLLING_SEL), + sw_r32(RTL930X_SMI_PORT16_27_POLLING_SEL)); + + pr_info("%s: Enable SMI polling on SMI bus 0, SMI1, SMI2, disable on SMI3\n", __func__); + sw_w32_mask(BIT(20) | BIT(21) | BIT(22), BIT(23), RTL930X_SMI_GLB_CTRL); + + pr_info("RTL9300 Powering on SerDes ports\n"); + rtl9300_sds_power(24, 1); + rtl9300_sds_power(25, 1); + rtl9300_sds_power(26, 1); + rtl9300_sds_power(27, 1); + mdelay(200); + + // RTL930X_SMI_PORT0_15_POLLING_SEL 55550000 16-27: 00f9aaaa + // i.e SMI=0 for all ports + for (i = 0; i < 5; i++) + pr_info("port phy: %08x\n", sw_r32(RTL930X_SMI_PORT0_5_ADDR + i *4)); + + // 1-to-1 mapping of port to phy-address + for (i = 0; i < 24; i++) { + pos = (i % 6) * 5; + sw_w32_mask(0x1f << pos, i << pos, RTL930X_SMI_PORT0_5_ADDR + (i / 6) * 4); + } + + // ports 24 and 25 have PHY addresses 8 and 9, ports 26/27 PHY 26/27 + sw_w32(8 | 9 << 5 | 26 << 10 | 27 << 15, RTL930X_SMI_PORT0_5_ADDR + 4 * 4); + + // Ports 24 and 25 live on SMI bus 1 and 2 + sw_w32_mask(0x3 << 16, 0x1 << 16, RTL930X_SMI_PORT16_27_POLLING_SEL); + sw_w32_mask(0x3 << 18, 0x2 << 18, RTL930X_SMI_PORT16_27_POLLING_SEL); + + // SMI bus 1 and 2 speak Clause 45 TODO: Configure from .dts + sw_w32_mask(0, BIT(17) | BIT(18), RTL930X_SMI_GLB_CTRL); + + // Ports 24 and 25 are 2.5 Gig, set this type (1) + sw_w32_mask(0x7 << 12, 1 << 12, RTL930X_SMI_MAC_TYPE_CTRL); + sw_w32_mask(0x7 << 15, 1 << 15, RTL930X_SMI_MAC_TYPE_CTRL); + + return 0; +} static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) { @@ -1287,16 +1786,33 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) goto err_put_node; } - if (priv->family_id == RTL8380_FAMILY_ID) { + switch(priv->family_id) { + case RTL8380_FAMILY_ID: priv->mii_bus->name = "rtl838x-eth-mdio"; priv->mii_bus->read = rtl838x_mdio_read; priv->mii_bus->write = rtl838x_mdio_write; priv->mii_bus->reset = rtl838x_mdio_reset; - } else { + break; + case RTL8390_FAMILY_ID: priv->mii_bus->name = "rtl839x-eth-mdio"; priv->mii_bus->read = rtl839x_mdio_read; priv->mii_bus->write = rtl839x_mdio_write; priv->mii_bus->reset = rtl839x_mdio_reset; + break; + case RTL9300_FAMILY_ID: + priv->mii_bus->name = "rtl930x-eth-mdio"; + priv->mii_bus->read = rtl930x_mdio_read; + priv->mii_bus->write = rtl930x_mdio_write; + priv->mii_bus->reset = rtl930x_mdio_reset; + // priv->mii_bus->probe_capabilities = MDIOBUS_C22_C45; TODO for linux 5.9 + break; + case RTL9310_FAMILY_ID: + priv->mii_bus->name = "rtl931x-eth-mdio"; + priv->mii_bus->read = rtl931x_mdio_read; + priv->mii_bus->write = rtl931x_mdio_write; + priv->mii_bus->reset = rtl931x_mdio_reset; +// priv->mii_bus->probe_capabilities = MDIOBUS_C22_C45; TODO for linux 5.9 + break; } priv->mii_bus->priv = priv; priv->mii_bus->parent = &priv->pdev->dev; @@ -1325,12 +1841,46 @@ static const struct net_device_ops rtl838x_eth_netdev_ops = { .ndo_open = rtl838x_eth_open, .ndo_stop = rtl838x_eth_stop, .ndo_start_xmit = rtl838x_eth_tx, + .ndo_select_queue = rtl83xx_pick_tx_queue, .ndo_set_mac_address = rtl838x_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_set_rx_mode = rtl838x_eth_set_multicast_list, .ndo_tx_timeout = rtl838x_eth_tx_timeout, }; +static const struct net_device_ops rtl839x_eth_netdev_ops = { + .ndo_open = rtl838x_eth_open, + .ndo_stop = rtl838x_eth_stop, + .ndo_start_xmit = rtl838x_eth_tx, + .ndo_select_queue = rtl83xx_pick_tx_queue, + .ndo_set_mac_address = rtl838x_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = rtl839x_eth_set_multicast_list, + .ndo_tx_timeout = rtl838x_eth_tx_timeout, +}; + +static const struct net_device_ops rtl930x_eth_netdev_ops = { + .ndo_open = rtl838x_eth_open, + .ndo_stop = rtl838x_eth_stop, + .ndo_start_xmit = rtl838x_eth_tx, + .ndo_select_queue = rtl93xx_pick_tx_queue, + .ndo_set_mac_address = rtl838x_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = rtl930x_eth_set_multicast_list, + .ndo_tx_timeout = rtl838x_eth_tx_timeout, +}; + +static const struct net_device_ops rtl931x_eth_netdev_ops = { + .ndo_open = rtl838x_eth_open, + .ndo_stop = rtl838x_eth_stop, + .ndo_start_xmit = rtl838x_eth_tx, + .ndo_select_queue = rtl93xx_pick_tx_queue, + .ndo_set_mac_address = rtl838x_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = rtl931x_eth_set_multicast_list, + .ndo_tx_timeout = rtl838x_eth_tx_timeout, +}; + static const struct phylink_mac_ops rtl838x_phylink_ops = { .validate = rtl838x_validate, .mac_link_state = rtl838x_mac_pcs_get_state, @@ -1354,7 +1904,8 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) const void *mac; phy_interface_t phy_mode; struct phylink *phylink; - int err = 0; + int err = 0, i, rxrings, rxringlen; + struct ring_b *ring; pr_info("Probing RTL838X eth device pdev: %x, dev: %x\n", (u32)pdev, (u32)(&(pdev->dev))); @@ -1364,7 +1915,13 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) return -EINVAL; } - dev = alloc_etherdev(sizeof(struct rtl838x_eth_priv)); + rxrings = (soc_info.family == RTL8380_FAMILY_ID + || soc_info.family == RTL8390_FAMILY_ID) ? 8 : 32; + rxrings = rxrings > MAX_RXRINGS ? MAX_RXRINGS : rxrings; + rxringlen = MAX_ENTRIES / rxrings; + rxringlen = rxringlen > MAX_RXLEN ? MAX_RXLEN : rxringlen; + + dev = alloc_etherdev_mqs(sizeof(struct rtl838x_eth_priv), TXRINGS, rxrings); if (!dev) { err = -ENOMEM; goto err_free; @@ -1392,8 +1949,8 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) } /* Allocate buffer memory */ - priv->membase = dmam_alloc_coherent(&pdev->dev, - sizeof(struct ring_b) + sizeof(struct notify_b), + priv->membase = dmam_alloc_coherent(&pdev->dev, rxrings * rxringlen * RING_BUFFER + + sizeof(struct ring_b) + sizeof(struct notify_b), (void *)&dev->mem_start, GFP_KERNEL); if (!priv->membase) { dev_err(&pdev->dev, "cannot allocate DMA buffer\n"); @@ -1401,6 +1958,10 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) goto err_free; } + // Allocate ring-buffer space at the end of the allocated memory + ring = priv->membase; + ring->rx_space = priv->membase + sizeof(struct ring_b) + sizeof(struct notify_b); + spin_lock_init(&priv->lock); /* obtain device IRQ number */ @@ -1412,6 +1973,8 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) dev->irq = res->start; } dev->ethtool_ops = &rtl838x_ethtool_ops; + dev->min_mtu = ETH_ZLEN; + dev->max_mtu = 1536; priv->id = soc_info.id; priv->family_id = soc_info.family; @@ -1423,15 +1986,33 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) return -ENODEV; } - if (priv->family_id == 0x8390) { - priv->cpu_port = RTL839X_CPU_PORT; - priv->r = &rtl839x_reg; - priv->port_mask = 0x3f; - } else { + switch (priv->family_id) { + case RTL8380_FAMILY_ID: priv->cpu_port = RTL838X_CPU_PORT; priv->r = &rtl838x_reg; - priv->port_mask = 0x1f; + dev->netdev_ops = &rtl838x_eth_netdev_ops; + break; + case RTL8390_FAMILY_ID: + priv->cpu_port = RTL839X_CPU_PORT; + priv->r = &rtl839x_reg; + dev->netdev_ops = &rtl839x_eth_netdev_ops; + break; + case RTL9300_FAMILY_ID: + priv->cpu_port = RTL930X_CPU_PORT; + priv->r = &rtl930x_reg; + dev->netdev_ops = &rtl930x_eth_netdev_ops; + break; + case RTL9310_FAMILY_ID: + priv->cpu_port = RTL931X_CPU_PORT; + priv->r = &rtl931x_reg; + dev->netdev_ops = &rtl931x_eth_netdev_ops; + break; + default: + pr_err("Unknown SoC family\n"); + return -ENODEV; } + priv->rxringlen = rxringlen; + priv->rxrings = rxrings; rtl8380_init_mac(priv); @@ -1464,7 +2045,6 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) pr_info("Using MAC %08x%08x\n", sw_r32(priv->r->mac), sw_r32(priv->r->mac + 4)); strcpy(dev->name, "eth%d"); - dev->netdev_ops = &rtl838x_eth_netdev_ops; priv->pdev = pdev; priv->netdev = dev; @@ -1476,7 +2056,12 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) if (err) goto err_free; - netif_napi_add(dev, &priv->napi, rtl838x_poll_rx, 64); + for (i = 0; i < priv->rxrings; i++) { + priv->rx_qs[i].id = i; + priv->rx_qs[i].priv = priv; + netif_napi_add(dev, &priv->rx_qs[i].napi, rtl838x_poll_rx, 64); + } + platform_set_drvdata(pdev, dev); phy_mode = of_get_phy_mode(dn); @@ -1508,13 +2093,18 @@ static int rtl838x_eth_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct rtl838x_eth_priv *priv = netdev_priv(dev); + int i; if (dev) { pr_info("Removing platform driver for rtl838x-eth\n"); rtl838x_mdio_remove(priv); rtl838x_hw_stop(priv); - netif_stop_queue(dev); - netif_napi_del(&priv->napi); + + netif_tx_stop_all_queues(dev); + + for (i = 0; i < priv->rxrings; i++) + netif_napi_del(&priv->rx_qs[i].napi); + unregister_netdev(dev); free_netdev(dev); } From 56ac4fced086c74c73cc05a6af750ee236910811 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 14:32:44 +0100 Subject: [PATCH 15/29] realtek: correct l2 offloading tag handling Makes sure the DSA trailer information on any L2 offloading done by the switch is honoured by the bridge layer Signed-off-by: Birger Koblitz --- ...-net-dsa-add-rtl838x-support-for-tag-trailer.patch | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch b/target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch index c8a09c50d3..7bfbd0a5f6 100644 --- a/target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch +++ b/target/linux/realtek/patches-5.4/701-net-dsa-add-rtl838x-support-for-tag-trailer.patch @@ -9,21 +9,24 @@ + trailer[1] = dp->index; +#else trailer[1] = 1 << dp->index; -+#endif /* CONFIG_NET_DSA_RTL83XX */ ++#endif /* CONFIG_NET_DSA_RTL838X */ trailer[2] = 0x10; trailer[3] = 0x00; -@@ -61,12 +66,20 @@ static struct sk_buff *trailer_rcv(struc +@@ -61,12 +69,23 @@ static struct sk_buff *trailer_rcv(struc return NULL; trailer = skb_tail_pointer(skb) - 4; + +#ifdef CONFIG_NET_DSA_RTL83XX -+ if (trailer[0] != 0x80 || (trailer[1] & 0xe0) != 0x00 || ++ if (trailer[0] != 0x80 || (trailer[1] & 0x80) != 0x00 || + (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) + return NULL; + -+ source_port = trailer[1] & 0x1f; ++ if (trailer[1] & 0x40) ++ skb->offload_fwd_mark = 1; ++ ++ source_port = trailer[1] & 0x3f; +#else if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 || (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) From 6aac20bc0187e0934a9c167f21960202be182546 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 14:35:26 +0100 Subject: [PATCH 16/29] realtek: enable default rate limiting and qos settings Enable default rate limiting and QoS support. Remove previous storm control code. Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/net/dsa/rtl83xx/storm.c | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/storm.c diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/storm.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/storm.c deleted file mode 100644 index de0af033f3..0000000000 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/storm.c +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include -#include "rtl83xx.h" - - -static void rtl83xx_storm_enable(struct rtl838x_switch_priv *priv, int port, bool enable) -{ - // Enable Storm control for that port for UC, MC, and BC - if (enable) - sw_w32(0x7, RTL838X_STORM_CTRL_LB_CTRL(port)); - else - sw_w32(0x0, RTL838X_STORM_CTRL_LB_CTRL(port)); -} - -void __init rtl83xx_storm_control_init(struct rtl838x_switch_priv *priv) -{ - int i; - - pr_debug("Enabling Storm control\n"); - // TICK_PERIOD_PPS - if (priv->id == 0x8380) - sw_w32_mask(0x3ff << 20, 434 << 20, RTL838X_SCHED_LB_TICK_TKN_CTRL_0); - - // Set burst rate - sw_w32(0x00008000, RTL838X_STORM_CTRL_BURST_0); // UC - sw_w32(0x80008000, RTL838X_STORM_CTRL_BURST_1); // MC and BC - - // Set burst Packets per Second to 32 - sw_w32(0x00000020, RTL838X_STORM_CTRL_BURST_PPS_0); // UC - sw_w32(0x00200020, RTL838X_STORM_CTRL_BURST_PPS_1); // MC and BC - - // Include IFG in storm control - sw_w32_mask(0, BIT(6), RTL838X_STORM_CTRL); - // Rate control is based on bytes/s (0 = packets) - sw_w32_mask(0, BIT(5), RTL838X_STORM_CTRL); - // Bandwidth control includes preamble and IFG (10 Bytes) - sw_w32_mask(0, 1, RTL838X_SCHED_CTRL); - - // On SoCs except RTL8382M, set burst size of port egress - if (priv->id != 0x8382) - sw_w32_mask(0xffff, 0x800, RTL838X_SCHED_LB_THR); - - /* Enable storm control on all ports with a PHY and limit rates, - * for UC and MC for both known and unknown addresses */ - for (i = 0; i < priv->cpu_port; i++) { - if (priv->ports[i].phy) { - sw_w32(BIT(18) | 0x8000, RTL838X_STORM_CTRL_PORT_UC(i)); - sw_w32(BIT(18) | 0x8000, RTL838X_STORM_CTRL_PORT_MC(i)); - sw_w32(0x000, RTL838X_STORM_CTRL_PORT_BC(i)); - rtl83xx_storm_enable(priv, i, true); - } - } - - // Attack prevention, enable all attack prevention measures - //sw_w32(0x1ffff, RTL838X_ATK_PRVNT_CTRL); - /* Attack prevention, drop (bit = 0) problematic packets on all ports. - * Setting bit = 1 means: trap to CPU - */ - //sw_w32(0, RTL838X_ATK_PRVNT_ACT); - // Enable attack prevention on all ports - //sw_w32(0x0fffffff, RTL838X_ATK_PRVNT_PORT_EN); -} - From e1bca7c77d80b3f35f5045cd8983349819165f1e Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 15:09:47 +0100 Subject: [PATCH 17/29] realtek: fix RTL8231 gpio expander usage with RTL839X SoC This fixes the usage of the RTL8231 GPIO extender chip when used with the RTL839X SoCs. Specifically, the PHY addresses may be different from 0. Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/gpio/gpio-rtl8231.c | 64 ++++++++++++------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/gpio/gpio-rtl8231.c b/target/linux/realtek/files-5.4/drivers/gpio/gpio-rtl8231.c index be5efc2997..031f60f530 100644 --- a/target/linux/realtek/files-5.4/drivers/gpio/gpio-rtl8231.c +++ b/target/linux/realtek/files-5.4/drivers/gpio/gpio-rtl8231.c @@ -12,6 +12,8 @@ #define RTL8231_GPIO_DIR(gpio) ((0x0005) + ((gpio) >> 4)) #define RTL8231_GPIO_DATA(gpio) ((0x001C) + ((gpio) >> 4)) +#define USEC_TIMEOUT 5000 + struct rtl8231_gpios { struct gpio_chip gc; struct device *dev; @@ -27,7 +29,7 @@ extern struct rtl83xx_soc_info soc_info; static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg) { - u32 t = 0; + u32 t = 0, n = 0; u8 bus_id = gpios->smi_bus_id; reg &= 0x1f; @@ -38,10 +40,18 @@ static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg) /* Set execution bit: cleared when operation completed */ t |= 1; + + // Start execution sw_w32(t, gpios->ext_gpio_indrt_access); - do { /* TODO: Return 0x80000000 if timeout */ + do { + udelay(1); t = sw_r32(gpios->ext_gpio_indrt_access); - } while (t & 1); + n++; + } while ((t & 1) && (n < USEC_TIMEOUT)); + + if (n >= USEC_TIMEOUT) + return 0x80000000; + pr_debug("%s: %x, %x, %x\n", __func__, bus_id, reg, (t & 0xffff0000) >> 16); return (t & 0xffff0000) >> 16; @@ -49,7 +59,7 @@ static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg) static int rtl8231_write(struct rtl8231_gpios *gpios, u32 reg, u32 data) { - u32 t = 0; + u32 t = 0, n = 0; u8 bus_id = gpios->smi_bus_id; pr_debug("%s: %x, %x, %x\n", __func__, bus_id, reg, data); @@ -62,10 +72,16 @@ static int rtl8231_write(struct rtl8231_gpios *gpios, u32 reg, u32 data) /* Set execution bit: cleared when operation completed */ t |= 1; + + // Start execution sw_w32(t, gpios->ext_gpio_indrt_access); - do { /* TODO: Return -1 if timeout */ + do { + udelay(1); t = sw_r32(gpios->ext_gpio_indrt_access); - } while (t & 1); + } while ((t & 1) && (n < USEC_TIMEOUT)); + + if (n >= USEC_TIMEOUT) + return -1; return 0; } @@ -94,7 +110,7 @@ static int rtl8231_pin_dir(struct rtl8231_gpios *gpios, u32 gpio, u32 dir) int dpin = pin; if (gpio > 31) { - pr_info("WARNING: HIGH pin\n"); + pr_debug("WARNING: HIGH pin\n"); dpin = pin << 5; pin_dir_addr = pin_sel_addr; } @@ -226,26 +242,21 @@ int rtl8231_init(struct rtl8231_gpios *gpios) { pr_info("%s called, MDIO bus ID: %d\n", __func__, gpios->smi_bus_id); + gpios->reg_cached = 0; + if (soc_info.family == RTL8390_FAMILY_ID) { + // RTL8390: Enable external gpio in global led control register sw_w32_mask(0x7 << 18, 0x4 << 18, RTL839X_LED_GLB_CTRL); - return 0; + } else if (soc_info.family == RTL8380_FAMILY_ID) { + // RTL8380: Enable RTL8231 indirect access mode + sw_w32_mask(0, 1, RTL838X_EXTRA_GPIO_CTRL); + sw_w32_mask(3, 1, RTL838X_DMY_REG5); } - /* Enable RTL8231 indirect access mode */ - sw_w32_mask(0, 1, RTL838X_EXTRA_GPIO_CTRL); - sw_w32_mask(3, 1, RTL838X_DMY_REG5); - - /* Enable RTL8231 via GPIO_A1 line - rtl838x_w32_mask(0, 1 << RTL838X_GPIO_A1, RTL838X_GPIO_PABC_DIR); - rtl838x_w32_mask(0, 1 << RTL838X_GPIO_A1, RTL838X_GPIO_PABC_DATA); */ - mdelay(50); /* wait 50ms for reset */ - /*Select GPIO functionality for pins 0-15, 16-31 and 32-37 */ rtl8231_write(gpios, RTL8231_GPIO_PIN_SEL(0), 0xffff); rtl8231_write(gpios, RTL8231_GPIO_PIN_SEL(16), 0xffff); - gpios->reg_cached = 0; - return 0; } @@ -262,7 +273,7 @@ static int rtl8231_gpio_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct rtl8231_gpios *gpios; int err; - u8 indirect_bus_id; + u32 indirect_bus_id; pr_info("Probing RTL8231 GPIOs\n"); @@ -284,10 +295,15 @@ static int rtl8231_gpio_probe(struct platform_device *pdev) gpios->ext_gpio_indrt_access = RTL839X_EXT_GPIO_INDRT_ACCESS; } - if (!of_property_read_u8(np, "indirect-access-bus-id", &indirect_bus_id)) { - gpios->smi_bus_id = indirect_bus_id; - rtl8231_init(gpios); - } + /* + * We use a default MDIO bus ID for the 8231 of 0, which can be overriden + * by the indirect-access-bus-id property in the dts. + */ + gpios->smi_bus_id = 0; + of_property_read_u32(np, "indirect-access-bus-id", &indirect_bus_id); + gpios->smi_bus_id = indirect_bus_id; + + rtl8231_init(gpios); gpios->dev = dev; gpios->gc.base = 160; From d140b9fc23f6b58ce6be696844e216c91e62b4c5 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 15:12:36 +0100 Subject: [PATCH 18/29] realtek: add internal and external SDS/PHYs of RTL9300 devices This adds support for the internal SerDes of the RTL9300 SoC and for the RTL8218D and RTL8226B phys found in combination with this SoC in switches. Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/net/phy/rtl83xx-phy.c | 529 +++++++++++++++++- .../files-5.4/drivers/net/phy/rtl83xx-phy.h | 22 +- 2 files changed, 523 insertions(+), 28 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.c b/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.c index eba416934f..78953c6d17 100644 --- a/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.c +++ b/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.c @@ -22,35 +22,50 @@ static const struct firmware rtl838x_8380_fw; static const struct firmware rtl838x_8214fc_fw; static const struct firmware rtl838x_8218b_fw; +int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); +int rtl930x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val); static int read_phy(u32 port, u32 page, u32 reg, u32 *val) -{ - if (soc_info.family == RTL8390_FAMILY_ID) - return rtl839x_read_phy(port, page, reg, val); - else +{ switch (soc_info.family) { + case RTL8380_FAMILY_ID: return rtl838x_read_phy(port, page, reg, val); + case RTL8390_FAMILY_ID: + return rtl839x_read_phy(port, page, reg, val); + case RTL9300_FAMILY_ID: + return rtl930x_read_phy(port, page, reg, val); + case RTL9310_FAMILY_ID: + return rtl931x_read_phy(port, page, reg, val); + } + return -1; } static int write_phy(u32 port, u32 page, u32 reg, u32 val) { - if (soc_info.family == RTL8390_FAMILY_ID) - return rtl839x_write_phy(port, page, reg, val); - else + switch (soc_info.family) { + case RTL8380_FAMILY_ID: return rtl838x_write_phy(port, page, reg, val); + case RTL8390_FAMILY_ID: + return rtl839x_write_phy(port, page, reg, val); + case RTL9300_FAMILY_ID: + return rtl930x_write_phy(port, page, reg, val); + case RTL9310_FAMILY_ID: + return rtl931x_write_phy(port, page, reg, val); + } + return -1; } -static void int_phy_on_off(int mac, bool on) +static void rtl8380_int_phy_on_off(int mac, bool on) { u32 val; read_phy(mac, 0, 0, &val); if (on) - write_phy(mac, 0, 0, val & ~(1 << 11)); + write_phy(mac, 0, 0, val & ~BIT(11)); else - write_phy(mac, 0, 0, val | (1 << 11)); + write_phy(mac, 0, 0, val | BIT(11)); } -static void rtl8214fc_on_off(int mac, bool on) +static void rtl8380_rtl8214fc_on_off(int mac, bool on) { u32 val; @@ -58,25 +73,194 @@ static void rtl8214fc_on_off(int mac, bool on) write_phy(mac, 4095, 30, 3); read_phy(mac, 0, 16, &val); if (on) - write_phy(mac, 0, 16, val & ~(1 << 11)); + write_phy(mac, 0, 16, val & ~BIT(11)); else - write_phy(mac, 0, 16, val | (1 << 11)); + write_phy(mac, 0, 16, val | BIT(11)); /* copper ports */ write_phy(mac, 4095, 30, 1); read_phy(mac, 0, 16, &val); if (on) - write_phy(mac, 0xa40, 16, val & ~(1 << 11)); + write_phy(mac, 0xa40, 16, val & ~BIT(11)); else - write_phy(mac, 0xa40, 16, val | (1 << 11)); + write_phy(mac, 0xa40, 16, val | BIT(11)); } -static void phy_reset(int mac) +static void rtl8380_phy_reset(int mac) { u32 val; read_phy(mac, 0, 0, &val); - write_phy(mac, 0, 0, val | (0x1 << 15)); + write_phy(mac, 0, 0, val | BIT(15)); +} + +static void rtl8380_sds_rst(int mac) +{ + u32 offset = (mac == 24) ? 0 : 0x100; + + sw_w32_mask(1 << 11, 0, RTL8380_SDS4_FIB_REG0 + offset); + sw_w32_mask(0x3, 0, RTL838X_SDS4_REG28 + offset); + sw_w32_mask(0x3, 0x3, RTL838X_SDS4_REG28 + offset); + sw_w32_mask(0, 0x1 << 6, RTL838X_SDS4_DUMMY0 + offset); + sw_w32_mask(0x1 << 6, 0, RTL838X_SDS4_DUMMY0 + offset); + pr_info("SERDES reset: %d\n", mac); +} + +/* + * Reset the SerDes by powering it off and set a new operations mode + * of the SerDes. 0x1f is off. Other modes are + * 0x01: QSGMII 0x04: 1000BX_FIBER 0x05: FIBER100 + * 0x06: QSGMII 0x09: RSGMII 0x0d: USXGMII + * 0x10: XSGMII 0x12: HISGMII 0x16: 2500Base_X + * 0x17: RXAUI_LITE 0x19: RXAUI_PLUS 0x1a: 10G Base-R + * 0x1b: 10GR1000BX_AUTO 0x1f: OFF + */ +void rtl9300_sds_rst(int sds_num, u32 mode) +{ + // The access registers for SDS_MODE_SEL and the LSB for each SDS within + u16 regs[] = { 0x0194, 0x0194, 0x0194, 0x0194, 0x02a0, 0x02a0, 0x02a0, 0x02a0, + 0x02A4, 0x02A4, 0x0198, 0x0198 }; + u8 lsb[] = { 0, 6, 12, 18, 0, 6, 12, 18, 0, 6, 0, 6}; + + pr_info("SerDes: %s %d\n", __func__, mode); + if (sds_num < 0 || sds_num > 11) { + pr_err("Wrong SerDes number: %d\n", sds_num); + return; + } + + sw_w32_mask(0x1f << lsb[sds_num], 0x1f << lsb[sds_num], regs[sds_num]); + mdelay(10); + + sw_w32_mask(0x1f << lsb[sds_num], mode << lsb[sds_num], regs[sds_num]); + mdelay(10); + + pr_info("SDS: 194:%08x 198:%08x 2a0:%08x 2a4:%08x\n", + sw_r32(0x194), sw_r32(0x198), sw_r32(0x2a0), sw_r32(0x2a4)); +} + +/* + * On the RTL839x family of SoCs with inbuilt SerDes, these SerDes are accessed through + * a 2048 bit register that holds the contents of the PHY being simulated by the SoC. + */ +int rtl839x_read_sds_phy(int phy_addr, int phy_reg) +{ + int offset = 0; + int reg; + u32 val; + + if (phy_addr == 49) + offset = 0x100; + + /* + * For the RTL8393 internal SerDes, we simulate a PHY ID in registers 2/3 + * which would otherwise read as 0. + */ + if (soc_info.id == 0x8393) { + if (phy_reg == 2) + return 0x1c; + if (phy_reg == 3) + return 0x8393; + } + + /* + * Register RTL839X_SDS12_13_XSG0 is 2048 bit broad, the MSB (bit 15) of the + * 0th PHY register is bit 1023 (in byte 0x80). Because PHY-registers are 16 + * bit broad, we offset by reg << 1. In the SoC 2 registers are stored in + * one 32 bit register. + */ + reg = (phy_reg << 1) & 0xfc; + val = sw_r32(RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg); + + if (phy_reg & 1) + val = (val >> 16) & 0xffff; + else + val &= 0xffff; + return val; +} + +/* + * On the RTL930x family of SoCs, the internal SerDes are accessed through an IO + * register which simulates commands to an internal MDIO bus. + */ +int rtl930x_read_sds_phy(int phy_addr, int page, int phy_reg) +{ + int i; + u32 cmd = phy_addr << 2 | page << 7 | phy_reg << 13 | 1; + + pr_info("%s: phy_addr %d, phy_reg: %d\n", __func__, phy_addr, phy_reg); + sw_w32(cmd, RTL930X_SDS_INDACS_CMD); + + for (i = 0; i < 100; i++) { + if (!(sw_r32(RTL930X_SDS_INDACS_CMD) & 0x1)) + break; + mdelay(1); + } + + if (i >= 100) + return -EIO; + + pr_info("%s: returning %04x\n", __func__, sw_r32(RTL930X_SDS_INDACS_DATA) & 0xffff); + return sw_r32(RTL930X_SDS_INDACS_DATA) & 0xffff; +} + +int rtl930x_write_sds_phy(int phy_addr, int page, int phy_reg, u16 v) +{ + int i; + u32 cmd; + + sw_w32(v, RTL930X_SDS_INDACS_DATA); + cmd = phy_addr << 2 | page << 7 | phy_reg << 13 | 0x3; + + for (i = 0; i < 100; i++) { + if (!(sw_r32(RTL930X_SDS_INDACS_CMD) & 0x1)) + break; + mdelay(1); + } + + if (i >= 100) + return -EIO; + + return 0; +} + +/* + * On the RTL838x SoCs, the internal SerDes is accessed through direct access to + * standard PHY registers, where a 32 bit register holds a 16 bit word as found + * in a standard page 0 of a PHY + */ +int rtl838x_read_sds_phy(int phy_addr, int phy_reg) +{ + int offset = 0; + u32 val; + + if (phy_addr == 26) + offset = 0x100; + val = sw_r32(RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2)) & 0xffff; + + return val; +} + +int rtl839x_write_sds_phy(int phy_addr, int phy_reg, u16 v) +{ + int offset = 0; + int reg; + u32 val; + + if (phy_addr == 49) + offset = 0x100; + + reg = (phy_reg << 1) & 0xfc; + val = v; + if (phy_reg & 1) { + val = val << 16; + sw_w32_mask(0xffff0000, val, + RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg); + } else { + sw_w32_mask(0xffff, val, + RTL839X_SDS12_13_XSG0 + offset + 0x80 + reg); + } + + return 0; } /* Read the link and speed status of the 2 internal SGMII/1000Base-X @@ -123,6 +307,149 @@ static int rtl8393_read_status(struct phy_device *phydev) return err; } +static int rtl8226_read_page(struct phy_device *phydev) +{ + return __phy_read(phydev, 0x1f); +} + +static int rtl8226_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, 0x1f, page); +} + +static int rtl8226_read_status(struct phy_device *phydev) +{ + int ret = 0, i; + u32 val; + int port = phydev->mdio.addr; + +// TODO: ret = genphy_read_status(phydev); +// if (ret < 0) { +// pr_info("%s: genphy_read_status failed\n", __func__); +// return ret; +// } + + // Link status must be read twice + for (i = 0; i < 2; i++) { + rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA402, &val); + } + phydev->link = val & BIT(2) ? 1 : 0; + if (!phydev->link) + goto out; + + // Read duplex status + ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA434, &val); + if (ret) + goto out; + phydev->duplex = !!(val & BIT(3)); + + // Read speed + ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA434, &val); + switch (val & 0x0630) { + case 0x0000: + phydev->speed = SPEED_10; + break; + case 0x0010: + phydev->speed = SPEED_100; + break; + case 0x0020: + phydev->speed = SPEED_1000; + break; + case 0x0200: + phydev->speed = SPEED_10000; + break; + case 0x0210: + phydev->speed = SPEED_2500; + break; + case 0x0220: + phydev->speed = SPEED_5000; + break; + default: + break; + } +out: + return ret; +} + +static int rtl8266_advertise_aneg(struct phy_device *phydev) +{ + int ret = 0; + u32 v; + int port = phydev->mdio.addr; + + pr_info("In %s\n", __func__); + + ret = rtl930x_read_mmd_phy(port, MMD_AN, 16, &v); + if (ret) + goto out; + + v |= BIT(5); // HD 10M + v |= BIT(6); // FD 10M + v |= BIT(7); // HD 100M + v |= BIT(8); // FD 100M + + ret = rtl930x_write_mmd_phy(port, MMD_AN, 16, v); + + // Allow 1GBit + ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA412, &v); + if (ret) + goto out; + v |= BIT(9); // FD 1000M + + ret = rtl930x_write_mmd_phy(port, MMD_VEND2, 0xA412, v); + if (ret) + goto out; + + // Allow 2.5G + ret = rtl930x_read_mmd_phy(port, MMD_AN, 32, &v); + if (ret) + goto out; + + v |= BIT(7); + ret = rtl930x_write_mmd_phy(port, MMD_AN, 32, v); + +out: + return ret; +} + + +static int rtl8226_config_aneg(struct phy_device *phydev) +{ + int ret = 0; + u32 v; + int port = phydev->mdio.addr; + + pr_info("In %s\n", __func__); + if (phydev->autoneg == AUTONEG_ENABLE) { + ret = rtl8266_advertise_aneg(phydev); + if (ret) + goto out; + // AutoNegotiationEnable + ret = rtl930x_read_mmd_phy(port, MMD_AN, 0, &v); + if (ret) + goto out; + + v |= BIT(12); // Enable AN + ret = rtl930x_write_mmd_phy(port, MMD_AN, 0, v); + if (ret) + goto out; + + // RestartAutoNegotiation + ret = rtl930x_read_mmd_phy(port, MMD_VEND2, 0xA400, &v); + if (ret) + goto out; + v |= BIT(9); + + ret = rtl930x_write_mmd_phy(port, MMD_VEND2, 0xA400, v); + } + + pr_info("%s: Ret is already: %d\n", __func__, ret); +// TODO: ret = __genphy_config_aneg(phydev, ret); + +out: + pr_info("%s: And ret is now: %d\n", __func__, ret); + return ret; +} static struct fw_header *rtl838x_request_fw(struct phy_device *phydev, const struct firmware *fw, @@ -234,9 +561,9 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev) read_phy(mac, 0, 0, &val); if (val & (1 << 11)) - int_phy_on_off(mac, true); + rtl8380_int_phy_on_off(mac, true); else - phy_reset(mac); + rtl8380_phy_reset(mac); msleep(100); /* Ready PHY for patch */ @@ -326,9 +653,9 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev) read_phy(mac, 0, 0, &val); if (val & (1 << 11)) - int_phy_on_off(mac, true); + rtl8380_int_phy_on_off(mac, true); else - phy_reset(mac); + rtl8380_phy_reset(mac); msleep(100); /* Get Chip revision */ @@ -517,6 +844,26 @@ static int rtl8218b_write_mmd(struct phy_device *phydev, return rtl838x_write_mmd_phy(addr, devnum, regnum, val); } +static int rtl8226_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) +{ + int port = phydev->mdio.addr; // the SoC translates port addresses to PHY addr + int err; + u32 val; + + err = rtl930x_read_mmd_phy(port, devnum, regnum, &val); + + if (err) + return err; + return val; +} + +static int rtl8226_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, u16 val) +{ + int port = phydev->mdio.addr; // the SoC translates port addresses to PHY addr + + return rtl930x_write_mmd_phy(port, devnum, regnum, val); +} + static void rtl8380_rtl8214fc_media_set(int mac, bool set_fibre) { int base = mac - (mac % 4); @@ -654,7 +1001,7 @@ static void rtl8218b_eee_set_u_boot(int port, bool enable) } // TODO: unused -static void rtl8380_rtl8218b_eee_set(int port, bool enable) +void rtl8380_rtl8218b_eee_set(int port, bool enable) { u32 val; bool an_enabled; @@ -720,7 +1067,7 @@ static int rtl8218b_get_eee(struct phy_device *phydev, } // TODO: unused -static void rtl8380_rtl8218b_green_set(int mac, bool enable) +void rtl8380_rtl8218b_green_set(int mac, bool enable) { u32 val; @@ -744,7 +1091,7 @@ static void rtl8380_rtl8218b_green_set(int mac, bool enable) } // TODO: unused -static int rtl8380_rtl8214fc_get_green(struct phy_device *phydev, struct ethtool_eee *e) +int rtl8380_rtl8214fc_get_green(struct phy_device *phydev, struct ethtool_eee *e) { u32 val; int addr = phydev->mdio.addr; @@ -886,9 +1233,9 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev) read_phy(mac, 0, 16, &val); if (val & (1 << 11)) - rtl8214fc_on_off(mac, true); + rtl8380_rtl8214fc_on_off(mac, true); else - phy_reset(mac); + rtl8380_phy_reset(mac); msleep(100); write_phy(mac, 0, 30, 0x0001); @@ -1143,6 +1490,45 @@ static int rtl8390_configure_serdes(struct phy_device *phydev) return 0; } +int rtl9300_configure_serdes(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + int phy_addr = phydev->mdio.addr; + int sds_num = 0; + int v; + + phydev_info(phydev, "Configuring internal RTL9300 SERDES\n"); + + switch (phy_addr) { + case 26: + sds_num = 8; + break; + case 27: + sds_num = 9; + break; + default: + dev_err(dev, "Not a SerDes PHY\n"); + return -EINVAL; + } + + /* Set default Medium to fibre */ + v = rtl930x_read_sds_phy(sds_num, 0x1f, 11); + if (v < 0) { + dev_err(dev, "Cannot access SerDes PHY %d\n", phy_addr); + return -EINVAL; + } + v |= BIT(2); + rtl930x_write_sds_phy(sds_num, 0x1f, 11, v); + + // TODO: this needs to be configurable via ethtool/.dts + pr_info("Setting 10G/1000BX auto fibre medium\n"); + rtl9300_sds_rst(sds_num, 0x1b); + + // TODO: Apply patch set for fibre type + + return 0; +} + static int rtl8214fc_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -1232,6 +1618,43 @@ static int rtl8218b_int_phy_probe(struct phy_device *phydev) return 0; } +static int rtl8218d_phy_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct rtl838x_phy_priv *priv; + int addr = phydev->mdio.addr; + + pr_info("%s: id: %d\n", __func__, addr); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->name = "RTL8218D"; + + /* All base addresses of the PHYs start at multiples of 8 */ + if (!(addr % 8)) { + /* Configuration must be done while patching still possible */ +// TODO: return configure_rtl8218d(phydev); + } + return 0; +} + +static int rtl8226_phy_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct rtl838x_phy_priv *priv; + int addr = phydev->mdio.addr; + + pr_info("%s: id: %d\n", __func__, addr); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->name = "RTL8226"; + + return 0; +} + static int rtl838x_serdes_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -1299,6 +1722,26 @@ static int rtl8390_serdes_probe(struct phy_device *phydev) return rtl8390_configure_generic(phydev); } +static int rtl9300_serdes_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct rtl838x_phy_priv *priv; + int addr = phydev->mdio.addr; + + if (soc_info.family != RTL9300_FAMILY_ID) + return -ENODEV; + + if (addr < 24) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->name = "RTL9300 Serdes"; + return rtl9300_configure_serdes(phydev); +} + static struct phy_driver rtl83xx_phy_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_RTL8214C), @@ -1340,6 +1783,29 @@ static struct phy_driver rtl83xx_phy_driver[] = { .set_eee = rtl8218b_set_eee, .get_eee = rtl8218b_get_eee, }, + { + PHY_ID_MATCH_MODEL(PHY_ID_RTL8218D), + .name = "REALTEK RTL8218D", + .features = PHY_GBIT_FEATURES, + .probe = rtl8218d_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .set_loopback = genphy_loopback, + }, { + PHY_ID_MATCH_MODEL(PHY_ID_RTL8226), + .name = "REALTEK RTL8226", + .features = PHY_GBIT_FEATURES, + .probe = rtl8226_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .set_loopback = genphy_loopback, + .read_mmd = rtl8226_read_mmd, + .write_mmd = rtl8226_write_mmd, + .read_page = rtl8226_read_page, + .write_page = rtl8226_write_page, + .read_status = rtl8226_read_status, + .config_aneg = rtl8226_config_aneg, + }, { PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I), .name = "Realtek RTL8218B (internal)", @@ -1383,7 +1849,16 @@ static struct phy_driver rtl83xx_phy_driver[] = { .suspend = genphy_suspend, .resume = genphy_resume, .set_loopback = genphy_loopback, - } + }, + { + PHY_ID_MATCH_MODEL(PHY_ID_RTL9300_I), + .name = "REALTEK RTL9300 SERDES", + .features = PHY_GBIT_FIBRE_FEATURES, + .probe = rtl9300_serdes_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .set_loopback = genphy_loopback, + }, }; module_phy_driver(rtl83xx_phy_driver); diff --git a/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.h b/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.h index 7af35a3583..031ec8a0e9 100644 --- a/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.h +++ b/target/linux/realtek/files-5.4/drivers/net/phy/rtl83xx-phy.h @@ -28,13 +28,33 @@ struct __attribute__ ((__packed__)) fw_header { #define PHY_ID_RTL8214C 0x001cc942 #define PHY_ID_RTL8214FC 0x001cc981 #define PHY_ID_RTL8218B_E 0x001cc981 +#define PHY_ID_RTL8218D 0x001cc983 #define PHY_ID_RTL8218B_I 0x001cca40 +#define PHY_ID_RTL8226 0x001cc838 #define PHY_ID_RTL8390_GENERIC 0x001ccab0 #define PHY_ID_RTL8393_I 0x001c8393 +#define PHY_ID_RTL9300_I 0x70d03106 -#define RTL839X_SDS12_13_XSG0 (0xB800) +// PHY MMD devices +#define MMD_AN 7 +#define MMD_VEND2 31 +/* Registers of the internal Serdes of the 8380 */ #define RTL838X_SDS_MODE_SEL (0x0028) #define RTL838X_SDS_CFG_REG (0x0034) #define RTL838X_INT_MODE_CTRL (0x005c) #define RTL838X_DMY_REG31 (0x3b28) + +#define RTL8380_SDS4_FIB_REG0 (0xF800) +#define RTL838X_SDS4_REG28 (0xef80) +#define RTL838X_SDS4_DUMMY0 (0xef8c) +#define RTL838X_SDS5_EXT_REG6 (0xf18c) +#define RTL838X_SDS4_FIB_REG0 (RTL838X_SDS4_REG28 + 0x880) +#define RTL838X_SDS5_FIB_REG0 (RTL838X_SDS4_REG28 + 0x980) + +/* Registers of the internal SerDes of the RTL8390 */ +#define RTL839X_SDS12_13_XSG0 (0xB800) + +/* Registers of the internal Serdes of the 9300 */ +#define RTL930X_SDS_INDACS_CMD (0x03B0) +#define RTL930X_SDS_INDACS_DATA (0x03B4) From 27029277f98ddd0006175bdc5beec8b0b150f187 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 15:14:56 +0100 Subject: [PATCH 19/29] realtek: add switch driver support for the RTL93XX based switches Adds support for the RTL9300 and RTL9310 series of switches with 10GBit per port and up to 56 ports. Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/net/dsa/rtl83xx/dsa.c | 395 ++++++++---- .../drivers/net/dsa/rtl83xx/rtl838x.c | 150 +++-- .../drivers/net/dsa/rtl83xx/rtl930x.c | 607 ++++++++++++++++++ .../drivers/net/dsa/rtl83xx/rtl931x.c | 326 ++++++++++ .../drivers/net/ethernet/rtl838x_eth.h | 299 ++++++--- 5 files changed, 1527 insertions(+), 250 deletions(-) create mode 100644 target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c create mode 100644 target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c index a0717e1d9a..e0832c42b8 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/dsa.c @@ -10,29 +10,6 @@ extern struct rtl83xx_soc_info soc_info; -static void rtl83xx_print_matrix(void) -{ - unsigned volatile int *ptr8; - volatile u64 *ptr9; - int i; - - if (soc_info.family == RTL8380_FAMILY_ID) { - ptr8 = RTL838X_SW_BASE + RTL838X_PORT_ISO_CTRL(0); - for (i = 0; i < 28; i += 8) - pr_debug("> %8x %8x %8x %8x %8x %8x %8x %8x\n", - ptr8[i + 0], ptr8[i + 1], ptr8[i + 2], ptr8[i + 3], - ptr8[i + 4], ptr8[i + 5], ptr8[i + 6], ptr8[i + 7]); - pr_debug("CPU_PORT> %8x\n", ptr8[28]); - } else { - ptr9 = RTL838X_SW_BASE + RTL839X_PORT_ISO_CTRL(0); - for (i = 0; i < 52; i += 4) - pr_debug("> %16llx %16llx %16llx %16llx\n", - ptr9[i + 0], ptr9[i + 1], ptr9[i + 2], ptr9[i + 3]); - pr_debug("CPU_PORT> %16llx\n", ptr9[52]); - } - -} - static void rtl83xx_init_stats(struct rtl838x_switch_priv *priv) { mutex_lock(&priv->reg_mutex); @@ -66,10 +43,17 @@ static void rtl83xx_write_cam(int idx, u32 *r) static u64 rtl83xx_hash_key(struct rtl838x_switch_priv *priv, u64 mac, u32 vid) { - if (priv->family_id == RTL8380_FAMILY_ID) + switch (priv->family_id) { + case RTL8380_FAMILY_ID: return rtl838x_hash(priv, mac << 12 | vid); - else + case RTL8390_FAMILY_ID: return rtl839x_hash(priv, mac << 12 | vid); + case RTL9300_FAMILY_ID: + return rtl930x_hash(priv, ((u64)vid) << 48 | mac); + default: + pr_err("Hash not implemented\n"); + } + return 0; } static void rtl83xx_write_hash(int idx, u32 *r) @@ -101,10 +85,10 @@ static void rtl83xx_enable_phy_polling(struct rtl838x_switch_priv *priv) pr_debug("%s: %16llx\n", __func__, v); priv->r->set_port_reg_le(v, priv->r->smi_poll_ctrl); - /* PHY update complete */ + /* PHY update complete, there is no global PHY polling enable bit on the 9300 */ if (priv->family_id == RTL8390_FAMILY_ID) sw_w32_mask(0, BIT(7), RTL839X_SMI_GLB_CTRL); - else + else if(priv->family_id == RTL9300_FAMILY_ID) sw_w32_mask(0, 0x8000, RTL838X_SMI_GLB_CTRL); } @@ -197,7 +181,10 @@ static int rtl83xx_setup(struct dsa_switch *ds) } priv->r->set_port_reg_be(port_bitmap, priv->r->port_iso_ctrl(priv->cpu_port)); - rtl83xx_print_matrix(); + if (priv->family_id == RTL8380_FAMILY_ID) + rtl838x_print_matrix(); + else + rtl839x_print_matrix(); rtl83xx_init_stats(priv); @@ -210,6 +197,44 @@ static int rtl83xx_setup(struct dsa_switch *ds) return 0; } +static int rtl930x_setup(struct dsa_switch *ds) +{ + int i; + struct rtl838x_switch_priv *priv = ds->priv; + u32 port_bitmap = BIT(priv->cpu_port); + + pr_info("%s called\n", __func__); + + // Enable CSTI STP mode +// sw_w32(1, RTL930X_ST_CTRL); + + /* Disable MAC polling the PHY so that we can start configuration */ + sw_w32(0, RTL930X_SMI_POLL_CTRL); + + // Disable all ports except CPU port + for (i = 0; i < ds->num_ports; i++) + priv->ports[i].enable = false; + priv->ports[priv->cpu_port].enable = true; + + for (i = 0; i < priv->cpu_port; i++) { + if (priv->ports[i].phy) { + priv->r->traffic_set(i, BIT(priv->cpu_port) | BIT(i)); + port_bitmap |= 1ULL << i; + } + } + priv->r->traffic_set(priv->cpu_port, port_bitmap); + + rtl930x_print_matrix(); + + // TODO: Initialize statistics + + ds->configure_vlan_while_not_filtering = true; + + rtl83xx_enable_phy_polling(priv); + + return 0; +} + static void rtl83xx_phylink_validate(struct dsa_switch *ds, int port, unsigned long *supported, struct phylink_link_state *state) @@ -269,13 +294,24 @@ static int rtl83xx_phylink_mac_link_state(struct dsa_switch *ds, int port, { struct rtl838x_switch_priv *priv = ds->priv; u64 speed; + u64 link; if (port < 0 || port > priv->cpu_port) return -EINVAL; + /* + * On the RTL9300 for at least the RTL8226B PHY, the MAC-side link + * state needs to be read twice in order to read a correct result. + * This would not be necessary for ports connected e.g. to RTL8218D + * PHYs. + */ state->link = 0; - if (priv->r->get_port_reg_le(priv->r->mac_link_sts) & BIT_ULL(port)) + link = priv->r->get_port_reg_le(priv->r->mac_link_sts); + link = priv->r->get_port_reg_le(priv->r->mac_link_sts); + if (link & BIT_ULL(port)) state->link = 1; + pr_info("%s: link state: %llx\n", __func__, link & BIT_ULL(port)); + state->duplex = 0; if (priv->r->get_port_reg_le(priv->r->mac_link_dup_sts) & BIT_ULL(port)) state->duplex = 1; @@ -317,6 +353,10 @@ static void rtl83xx_phylink_mac_config(struct dsa_switch *ds, int port, pr_debug("%s port %d, mode %x\n", __func__, port, mode); + // BUG: Make this work on RTL93XX + if (priv->family_id >= RTL9300_FAMILY_ID) + return; + if (port == priv->cpu_port) { /* Set Speed, duplex, flow control * FORCE_EN | LINK_EN | NWAY_EN | DUP_SEL @@ -422,15 +462,15 @@ static void rtl83xx_get_ethtool_stats(struct dsa_switch *ds, int port, struct rtl838x_switch_priv *priv = ds->priv; const struct rtl83xx_mib_desc *mib; int i; - u64 high; + u64 h; for (i = 0; i < ARRAY_SIZE(rtl83xx_mib); i++) { mib = &rtl83xx_mib[i]; - data[i] = sw_r32(priv->r->stat_port_std_mib(port) + 252 - mib->offset); + data[i] = sw_r32(priv->r->stat_port_std_mib + (port << 8) + 252 - mib->offset); if (mib->size == 2) { - high = sw_r32(priv->r->stat_port_std_mib(port) + 252 - mib->offset - 4); - data[i] |= high << 32; + h = sw_r32(priv->r->stat_port_std_mib + (port << 8) + 248 - mib->offset); + data[i] |= h << 32; } } } @@ -447,21 +487,30 @@ static int rtl83xx_port_enable(struct dsa_switch *ds, int port, struct phy_device *phydev) { struct rtl838x_switch_priv *priv = ds->priv; + u64 v; pr_debug("%s: %x %d", __func__, (u32) priv, port); priv->ports[port].enable = true; /* enable inner tagging on egress, do not keep any tags */ - sw_w32(1, priv->r->vlan_port_tag_sts_ctrl(port)); + if (priv->family_id == RTL9310_FAMILY_ID) + sw_w32(BIT(4), priv->r->vlan_port_tag_sts_ctrl + (port << 2)); + else + sw_w32(1, priv->r->vlan_port_tag_sts_ctrl + (port << 2)); if (dsa_is_cpu_port(ds, port)) return 0; /* add port to switch mask of CPU_PORT */ - priv->r->mask_port_reg_be(0ULL, BIT_ULL(port), priv->r->port_iso_ctrl(priv->cpu_port)); + priv->r->traffic_enable(priv->cpu_port, port); /* add all other ports in the same bridge to switch mask of port */ - priv->r->mask_port_reg_be(0ULL, priv->ports[port].pm, priv->r->port_iso_ctrl(port)); + v = priv->r->traffic_get(port); + v |= priv->ports[port].pm; + priv->r->traffic_set(port, v); + + sw_w32_mask(0, BIT(port), RTL930X_L2_PORT_SABLK_CTRL); + sw_w32_mask(0, BIT(port), RTL930X_L2_PORT_DABLK_CTRL); return 0; } @@ -469,17 +518,21 @@ static int rtl83xx_port_enable(struct dsa_switch *ds, int port, static void rtl83xx_port_disable(struct dsa_switch *ds, int port) { struct rtl838x_switch_priv *priv = ds->priv; + u64 v; pr_debug("%s %x: %d", __func__, (u32)priv, port); /* you can only disable user ports */ if (!dsa_is_user_port(ds, port)) return; + // BUG: This does not work on RTL931X /* remove port from switch mask of CPU_PORT */ - priv->r->mask_port_reg_be(BIT_ULL(port), 0, priv->r->port_iso_ctrl(priv->cpu_port)); + priv->r->traffic_disable(priv->cpu_port, port); /* remove all other ports in the same bridge from switch mask of port */ - priv->r->mask_port_reg_be(priv->ports[port].pm, 0LL, priv->r->port_iso_ctrl(port)); + v = priv->r->traffic_get(port); + v &= ~priv->ports[port].pm; + priv->r->traffic_set(port, v); priv->ports[port].enable = false; } @@ -565,7 +618,7 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *bridge) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = BIT_ULL(priv->cpu_port); + u64 port_bitmap = 1ULL << priv->cpu_port, v; int i; pr_debug("%s %x: %d %llx", __func__, (u32)priv, port, port_bitmap); @@ -579,20 +632,19 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, if (dsa_to_port(ds, i)->bridge_dev != bridge) continue; if (priv->ports[i].enable) - priv->r->mask_port_reg_be(0, BIT_ULL(port), - priv->r->port_iso_ctrl(i)); - priv->ports[i].pm |= BIT_ULL(port); + priv->r->traffic_enable(i, port); - port_bitmap |= BIT_ULL(i); + priv->ports[i].pm |= 1ULL << port; + port_bitmap |= 1ULL << i; } } /* Add all other ports to this port matrix. */ if (priv->ports[port].enable) { - priv->r->mask_port_reg_be(0, BIT_ULL(port), - priv->r->port_iso_ctrl(priv->cpu_port)); - priv->r->mask_port_reg_be(0, port_bitmap, - priv->r->port_iso_ctrl(port)); + priv->r->traffic_enable(priv->cpu_port, port); + v = priv->r->traffic_get(port); + v |= port_bitmap; + priv->r->traffic_set(port, v); } priv->ports[port].pm |= port_bitmap; mutex_unlock(&priv->reg_mutex); @@ -604,7 +656,7 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *bridge) { struct rtl838x_switch_priv *priv = ds->priv; - u64 port_bitmap = BIT_ULL(priv->cpu_port); + u64 port_bitmap = 1ULL << priv->cpu_port, v; int i; pr_debug("%s %x: %d", __func__, (u32)priv, port); @@ -620,62 +672,53 @@ static void rtl83xx_port_bridge_leave(struct dsa_switch *ds, int port, if (dsa_to_port(ds, i)->bridge_dev != bridge) continue; if (priv->ports[i].enable) - priv->r->mask_port_reg_be(BIT_ULL(port), 0, - priv->r->port_iso_ctrl(i)); - priv->ports[i].pm &= ~BIT_ULL(port); + priv->r->traffic_disable(i, port); + priv->ports[i].pm |= 1ULL << port; port_bitmap &= ~BIT_ULL(i); } } /* Add all other ports to this port matrix. */ - if (priv->ports[port].enable) - priv->r->mask_port_reg_be(0, port_bitmap, priv->r->port_iso_ctrl(port)); + if (priv->ports[port].enable) { + v = priv->r->traffic_get(port); + v |= port_bitmap; + priv->r->traffic_set(port, v); + } priv->ports[port].pm &= ~port_bitmap; mutex_unlock(&priv->reg_mutex); } -static void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, - u8 state) +void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) { - u32 cmd, msti = 0; + u32 msti = 0; u32 port_state[4]; - int index, bit, i; + int index, bit; int pos = port; struct rtl838x_switch_priv *priv = ds->priv; - int n = priv->family_id == RTL8380_FAMILY_ID ? 2 : 4; + int n = priv->port_width << 1; - pr_debug("%s: port %d state %2x\n", __func__, port, state); - - /* CPU PORT can only be configured on RTL838x */ - if (port >= priv->cpu_port || port > 51) + /* Ports above or equal CPU port can never be configured */ + if (port >= priv->cpu_port) return; mutex_lock(&priv->reg_mutex); - /* For the RTL839x, the bits are left-aligned in the 128 bit field */ + /* For the RTL839x and following, the bits are left-aligned, 838x and 930x + * have 64 bit fields, 839x and 931x have 128 bit fields + */ if (priv->family_id == RTL8390_FAMILY_ID) pos += 12; + if (priv->family_id == RTL9300_FAMILY_ID) + pos += 3; + if (priv->family_id == RTL9310_FAMILY_ID) + pos += 8; index = n - (pos >> 4) - 1; bit = (pos << 1) % 32; - if (priv->family_id == RTL8380_FAMILY_ID) { - cmd = BIT(15) /* Execute cmd */ - | BIT(14) /* Read */ - | 2 << 12 /* Table type 0b10 */ - | (msti & 0xfff); - } else { - cmd = BIT(16) /* Execute cmd */ - | 0 << 15 /* Read */ - | 5 << 12 /* Table type 0b101 */ - | (msti & 0xfff); - } - priv->r->exec_tbl0_cmd(cmd); - - for (i = 0; i < n; i++) - port_state[i] = sw_r32(priv->r->tbl_access_data_0(i)); + priv->r->stp_get(priv, msti, port_state); pr_debug("Current state, port %d: %d\n", port, (port_state[index] >> bit) & 3); port_state[index] &= ~(3 << bit); @@ -697,25 +740,12 @@ static void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, break; } - if (priv->family_id == RTL8380_FAMILY_ID) { - cmd = BIT(15) /* Execute cmd */ - | 0 << 14 /* Write */ - | 2 << 12 /* Table type 0b10 */ - | (msti & 0xfff); - } else { - cmd = 1 << 16 /* Execute cmd */ - | BIT(15) /* Write */ - | 5 << 12 /* Table type 0b101 */ - | (msti & 0xfff); - } - for (i = 0; i < n; i++) - sw_w32(port_state[i], priv->r->tbl_access_data_0(i)); - priv->r->exec_tbl0_cmd(cmd); + priv->r->stp_set(priv, msti, port_state); mutex_unlock(&priv->reg_mutex); } -static void rtl83xx_fast_age(struct dsa_switch *ds, int port) +void rtl83xx_fast_age(struct dsa_switch *ds, int port) { struct rtl838x_switch_priv *priv = ds->priv; int s = priv->family_id == RTL8390_FAMILY_ID ? 2 : 0; @@ -735,7 +765,22 @@ static void rtl83xx_fast_age(struct dsa_switch *ds, int port) */ sw_w32(1 << (26 + s) | 1 << (23 + s) | port << (5 + (s / 2)), priv->r->l2_tbl_flush_ctrl); - do { } while (sw_r32(priv->r->l2_tbl_flush_ctrl) & (1 << (26 + s))); + do { } while (sw_r32(priv->r->l2_tbl_flush_ctrl) & BIT(26 + s)); + + mutex_unlock(&priv->reg_mutex); +} + +void rtl930x_fast_age(struct dsa_switch *ds, int port) +{ + struct rtl838x_switch_priv *priv = ds->priv; + + pr_debug("FAST AGE port %d\n", port); + mutex_lock(&priv->reg_mutex); + sw_w32(port << 11, RTL930X_L2_TBL_FLUSH_CTRL + 4); + + sw_w32(BIT(26) | BIT(30), RTL930X_L2_TBL_FLUSH_CTRL); + + do { } while (sw_r32(priv->r->l2_tbl_flush_ctrl) & BIT(30)); mutex_unlock(&priv->reg_mutex); } @@ -749,17 +794,24 @@ static int rtl83xx_vlan_filtering(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); if (vlan_filtering) { - /* Enable ingress and egress filtering */ + /* Enable ingress and egress filtering + * The VLAN_PORT_IGR_FILTER register uses 2 bits for each port to define + * the filter action: + * 0: Always Forward + * 1: Drop packet + * 2: Trap packet to CPU port + * The Egress filter used 1 bit per state (0: DISABLED, 1: ENABLED) + */ if (port != priv->cpu_port) sw_w32_mask(0b10 << ((port % 16) << 1), 0b01 << ((port % 16) << 1), - priv->r->vlan_port_igr_filter(port)); - sw_w32_mask(0, 1 << (port % 32), priv->r->vlan_port_egr_filter(port)); + priv->r->vlan_port_igr_filter + ((port >> 5) << 2)); + sw_w32_mask(0, BIT(port % 32), priv->r->vlan_port_egr_filter + ((port >> 4) << 2)); } else { /* Disable ingress and egress filtering */ if (port != priv->cpu_port) sw_w32_mask(0b11 << ((port % 16) << 1), 0, - priv->r->vlan_port_igr_filter(port)); - sw_w32_mask(1 << (port % 32), 0, priv->r->vlan_port_egr_filter(port)); + priv->r->vlan_port_igr_filter + ((port >> 5) << 2)); + sw_w32_mask(BIT(port % 32), 0, priv->r->vlan_port_egr_filter + ((port >> 4) << 2)); } /* Do we need to do something to the CPU-Port, too? */ @@ -774,21 +826,23 @@ static int rtl83xx_vlan_prepare(struct dsa_switch *ds, int port, struct rtl838x_vlan_info info; struct rtl838x_switch_priv *priv = ds->priv; - pr_debug("%s: port %d\n", __func__, port); + pr_info("%s: port %d\n", __func__, port); mutex_lock(&priv->reg_mutex); - if (priv->family_id == RTL8380_FAMILY_ID) - rtl838x_vlan_profile_dump(0); - else - rtl839x_vlan_profile_dump(0); + priv->r->vlan_profile_dump(1); + priv->r->vlan_tables_read(1, &info); - priv->r->vlan_tables_read(0, &info); - - pr_debug("Tagged ports %llx, untag %llx, prof %x, MC# %d, UC# %d, FID %x\n", + pr_info("Tagged ports %llx, untag %llx, prof %x, MC# %d, UC# %d, FID %x\n", info.tagged_ports, info.untagged_ports, info.profile_id, info.hash_mc_fid, info.hash_uc_fid, info.fid); + priv->r->vlan_set_untagged(1, info.untagged_ports); + pr_debug("SET: Untagged ports, VLAN %d: %llx\n", 1, info.untagged_ports); + + priv->r->vlan_set_tagged(1, &info); + pr_debug("SET: Tagged ports, VLAN %d: %llx\n", 1, info.tagged_ports); + mutex_unlock(&priv->reg_mutex); return 0; } @@ -796,11 +850,11 @@ static int rtl83xx_vlan_prepare(struct dsa_switch *ds, int port, static void rtl83xx_vlan_add(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan) { - struct rtl838x_vlan_info info = {}; + struct rtl838x_vlan_info info; struct rtl838x_switch_priv *priv = ds->priv; int v; - pr_debug("%s port %d, vid_end %d, vid_end %d, flags %x\n", __func__, + pr_info("%s port %d, vid_end %d, vid_end %d, flags %x\n", __func__, port, vlan->vid_begin, vlan->vid_end, vlan->flags); if (vlan->vid_begin > 4095 || vlan->vid_end > 4095) { @@ -812,12 +866,19 @@ static void rtl83xx_vlan_add(struct dsa_switch *ds, int port, mutex_lock(&priv->reg_mutex); if (vlan->flags & BRIDGE_VLAN_INFO_PVID) { - /* Set both inner and outer PVID of the port */ - sw_w32((vlan->vid_end << 16) | vlan->vid_end << 2, priv->r->vlan_port_pb(port)); - priv->ports[port].pvid = vlan->vid_end; + for (v = vlan->vid_begin; v <= vlan->vid_end; v++) { + if (!v) + continue; + /* Set both inner and outer PVID of the port */ + sw_w32((v << 16) | v << 2, priv->r->vlan_port_pb + (port << 2)); + priv->ports[port].pvid = vlan->vid_end; + } } for (v = vlan->vid_begin; v <= vlan->vid_end; v++) { + if (!v) + continue; + /* Get port memberships of this vlan */ priv->r->vlan_tables_read(v, &info); @@ -838,10 +899,10 @@ static void rtl83xx_vlan_add(struct dsa_switch *ds, int port, info.untagged_ports |= BIT_ULL(port); priv->r->vlan_set_untagged(v, info.untagged_ports); - pr_debug("Untagged ports, VLAN %d: %llx\n", v, info.untagged_ports); + pr_info("Untagged ports, VLAN %d: %llx\n", v, info.untagged_ports); priv->r->vlan_set_tagged(v, &info); - pr_debug("Tagged ports, VLAN %d: %llx\n", v, info.tagged_ports); + pr_info("Tagged ports, VLAN %d: %llx\n", v, info.tagged_ports); } mutex_unlock(&priv->reg_mutex); @@ -870,7 +931,7 @@ static int rtl83xx_vlan_del(struct dsa_switch *ds, int port, for (v = vlan->vid_begin; v <= vlan->vid_end; v++) { /* Reset to default if removing the current PVID */ if (v == pvid) - sw_w32(0, priv->r->vlan_port_pb(port)); + sw_w32(0, priv->r->vlan_port_pb + (port << 2)); /* Get port memberships of this vlan */ priv->r->vlan_tables_read(v, &info); @@ -962,7 +1023,7 @@ static int rtl83xx_port_fdb_del(struct dsa_switch *ds, int port, u64 entry; int idx = -1, err = 0, i; - pr_debug("In %s, mac %llx, vid: %d, key: %x\n", __func__, mac, vid, key); + pr_debug("In %s, mac %llx, vid: %d, key: %x08x\n", __func__, mac, vid, key); mutex_lock(&priv->reg_mutex); for (i = 0; i < 4; i++) { entry = priv->r->read_l2_entry_using_hash(key, i, &e); @@ -1048,6 +1109,7 @@ static int rtl83xx_port_mirror_add(struct dsa_switch *ds, int port, /* We support 4 mirror groups, one destination port per group */ int group; struct rtl838x_switch_priv *priv = ds->priv; + int ctrl_reg, dpm_reg, spm_reg; pr_debug("In %s\n", __func__); @@ -1065,30 +1127,34 @@ static int rtl83xx_port_mirror_add(struct dsa_switch *ds, int port, if (group >= 4) return -ENOSPC; + ctrl_reg = priv->r->mir_ctrl + group * 4; + dpm_reg = priv->r->mir_dpm + group * 4 * priv->port_width; + spm_reg = priv->r->mir_spm + group * 4 * priv->port_width; + pr_debug("Using group %d\n", group); mutex_lock(&priv->reg_mutex); if (priv->family_id == RTL8380_FAMILY_ID) { /* Enable mirroring to port across VLANs (bit 11) */ - sw_w32(1 << 11 | (mirror->to_local_port << 4) | 1, RTL838X_MIR_CTRL(group)); + sw_w32(1 << 11 | (mirror->to_local_port << 4) | 1, ctrl_reg); } else { /* Enable mirroring to destination port */ - sw_w32((mirror->to_local_port << 4) | 1, RTL839X_MIR_CTRL(group)); + sw_w32((mirror->to_local_port << 4) | 1, ctrl_reg); } - if (ingress && (priv->r->get_port_reg_be(priv->r->mir_spm(group)) & (1ULL << port))) { + if (ingress && (priv->r->get_port_reg_be(spm_reg) & (1ULL << port))) { mutex_unlock(&priv->reg_mutex); return -EEXIST; } - if ((!ingress) && (priv->r->get_port_reg_be(priv->r->mir_dpm(group)) & (1ULL << port))) { + if ((!ingress) && (priv->r->get_port_reg_be(dpm_reg) & (1ULL << port))) { mutex_unlock(&priv->reg_mutex); return -EEXIST; } if (ingress) - priv->r->mask_port_reg_be(0, 1ULL << port, priv->r->mir_spm(group)); + priv->r->mask_port_reg_be(0, 1ULL << port, spm_reg); else - priv->r->mask_port_reg_be(0, 1ULL << port, priv->r->mir_dpm(group)); + priv->r->mask_port_reg_be(0, 1ULL << port, dpm_reg); priv->mirror_group_ports[group] = mirror->to_local_port; mutex_unlock(&priv->reg_mutex); @@ -1100,6 +1166,7 @@ static void rtl83xx_port_mirror_del(struct dsa_switch *ds, int port, { int group = 0; struct rtl838x_switch_priv *priv = ds->priv; + int ctrl_reg, dpm_reg, spm_reg; pr_debug("In %s\n", __func__); for (group = 0; group < 4; group++) { @@ -1109,29 +1176,66 @@ static void rtl83xx_port_mirror_del(struct dsa_switch *ds, int port, if (group >= 4) return; + ctrl_reg = priv->r->mir_ctrl + group * 4; + dpm_reg = priv->r->mir_dpm + group * 4 * priv->port_width; + spm_reg = priv->r->mir_spm + group * 4 * priv->port_width; + mutex_lock(&priv->reg_mutex); if (mirror->ingress) { /* Ingress, clear source port matrix */ - priv->r->mask_port_reg_be(1ULL << port, 0, priv->r->mir_spm(group)); + priv->r->mask_port_reg_be(1ULL << port, 0, spm_reg); } else { /* Egress, clear destination port matrix */ - priv->r->mask_port_reg_be(1ULL << port, 0, priv->r->mir_dpm(group)); + priv->r->mask_port_reg_be(1ULL << port, 0, dpm_reg); } - if (!(sw_r32(priv->r->mir_spm(group)) || sw_r32(priv->r->mir_dpm(group)))) { + if (!(sw_r32(spm_reg) || sw_r32(dpm_reg))) { priv->mirror_group_ports[group] = -1; - sw_w32(0, priv->r->mir_ctrl(group)); + sw_w32(0, ctrl_reg); } mutex_unlock(&priv->reg_mutex); } +int dsa_phy_read(struct dsa_switch *ds, int phy_addr, int phy_reg) +{ + u32 val; + u32 offset = 0; + struct rtl838x_switch_priv *priv = ds->priv; + + if (phy_addr >= 24 && phy_addr <= 27 + && priv->ports[24].phy == PHY_RTL838X_SDS) { + if (phy_addr == 26) + offset = 0x100; + val = sw_r32(RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2)) & 0xffff; + return val; + } + + read_phy(phy_addr, 0, phy_reg, &val); + return val; +} + +int dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_reg, u16 val) +{ + u32 offset = 0; + struct rtl838x_switch_priv *priv = ds->priv; + + if (phy_addr >= 24 && phy_addr <= 27 + && priv->ports[24].phy == PHY_RTL838X_SDS) { + if (phy_addr == 26) + offset = 0x100; + sw_w32(val, RTL838X_SDS4_FIB_REG0 + offset + (phy_reg << 2)); + return 0; + } + return write_phy(phy_addr, 0, phy_reg, val); +} + const struct dsa_switch_ops rtl83xx_switch_ops = { .get_tag_protocol = rtl83xx_get_tag_protocol, .setup = rtl83xx_setup, - .phy_read = rtl83xx_dsa_phy_read, - .phy_write = rtl83xx_dsa_phy_write, + .phy_read = dsa_phy_read, + .phy_write = dsa_phy_write, .phylink_validate = rtl83xx_phylink_validate, .phylink_mac_link_state = rtl83xx_phylink_mac_link_state, @@ -1168,3 +1272,38 @@ const struct dsa_switch_ops rtl83xx_switch_ops = { .port_mirror_del = rtl83xx_port_mirror_del, }; +const struct dsa_switch_ops rtl930x_switch_ops = { + .get_tag_protocol = rtl83xx_get_tag_protocol, + .setup = rtl930x_setup, + + .phy_read = dsa_phy_read, + .phy_write = dsa_phy_write, + + .phylink_validate = rtl83xx_phylink_validate, + .phylink_mac_link_state = rtl83xx_phylink_mac_link_state, + .phylink_mac_config = rtl83xx_phylink_mac_config, + .phylink_mac_link_down = rtl83xx_phylink_mac_link_down, + .phylink_mac_link_up = rtl83xx_phylink_mac_link_up, + + .get_strings = rtl83xx_get_strings, + .get_ethtool_stats = rtl83xx_get_ethtool_stats, + .get_sset_count = rtl83xx_get_sset_count, + + .port_enable = rtl83xx_port_enable, + .port_disable = rtl83xx_port_disable, + + .set_ageing_time = rtl83xx_set_l2aging, + .port_bridge_join = rtl83xx_port_bridge_join, + .port_bridge_leave = rtl83xx_port_bridge_leave, + .port_stp_state_set = rtl83xx_port_stp_state_set, + .port_fast_age = rtl930x_fast_age, + + .port_vlan_filtering = rtl83xx_vlan_filtering, + .port_vlan_prepare = rtl83xx_vlan_prepare, + .port_vlan_add = rtl83xx_vlan_add, + .port_vlan_del = rtl83xx_vlan_del, + + .port_fdb_add = rtl83xx_port_fdb_add, + .port_fdb_del = rtl83xx_port_fdb_del, + .port_fdb_dump = rtl83xx_port_fdb_dump, +}; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c index c7b5873e99..de9e83bb8d 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl838x.c @@ -5,25 +5,17 @@ extern struct mutex smi_lock; - -static inline void rtl838x_mask_port_reg(u64 clear, u64 set, int reg) +void rtl838x_print_matrix(void) { - sw_w32_mask((u32)clear, (u32)set, reg); -} + unsigned volatile int *ptr8; + int i; -static inline void rtl838x_set_port_reg(u64 set, int reg) -{ - sw_w32(set, reg); -} - -static inline u64 rtl838x_get_port_reg(int reg) -{ - return ((u64) sw_r32(reg)); -} - -static inline int rtl838x_stat_port_std_mib(int p) -{ - return RTL838X_STAT_PORT_STD_MIB + (p << 8); + ptr8 = RTL838X_SW_BASE + RTL838X_PORT_ISO_CTRL(0); + for (i = 0; i < 28; i += 8) + pr_info("> %8x %8x %8x %8x %8x %8x %8x %8x\n", + ptr8[i + 0], ptr8[i + 1], ptr8[i + 2], ptr8[i + 3], + ptr8[i + 4], ptr8[i + 5], ptr8[i + 6], ptr8[i + 7]); + pr_info("CPU_PORT> %8x\n", ptr8[28]); } static inline int rtl838x_port_iso_ctrl(int p) @@ -122,26 +114,16 @@ static inline int rtl838x_l2_port_new_sa_fwd(int p) return RTL838X_L2_PORT_NEW_SA_FWD(p); } -static inline int rtl838x_mir_ctrl(int group) -{ - return RTL838X_MIR_CTRL(group); -} - -static inline int rtl838x_mir_dpm(int group) -{ - return RTL838X_MIR_DPM_CTRL(group); -} - -static inline int rtl838x_mir_spm(int group) -{ - return RTL838X_MIR_SPM_CTRL(group); -} - static inline int rtl838x_mac_link_spd_sts(int p) { return RTL838X_MAC_LINK_SPD_STS(p); } +inline static int rtl838x_trk_mbr_ctr(int group) +{ + return RTL838X_TRK_MBR_CTR + (group << 2); +} + static u64 rtl838x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e) { u64 entry; @@ -235,14 +217,50 @@ static inline int rtl838x_vlan_port_igr_filter(int port) return RTL838X_VLAN_PORT_IGR_FLTR(port); } -static inline int rtl838x_vlan_port_pb(int port) +static void rtl838x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) { - return RTL838X_VLAN_PORT_PB_VLAN(port); + int i; + u32 cmd = 1 << 15 /* Execute cmd */ + | 1 << 14 /* Read */ + | 2 << 12 /* Table type 0b10 */ + | (msti & 0xfff); + priv->r->exec_tbl0_cmd(cmd); + + for (i = 0; i < 2; i++) + port_state[i] = sw_r32(priv->r->tbl_access_data_0(i)); } -static inline int rtl838x_vlan_port_tag_sts_ctrl(int port) +static void rtl838x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) { - return RTL838X_VLAN_PORT_TAG_STS_CTRL(port); + int i; + u32 cmd = 1 << 15 /* Execute cmd */ + | 0 << 14 /* Write */ + | 2 << 12 /* Table type 0b10 */ + | (msti & 0xfff); + + for (i = 0; i < 2; i++) + sw_w32(port_state[i], priv->r->tbl_access_data_0(i)); + priv->r->exec_tbl0_cmd(cmd); +} + +u64 rtl838x_traffic_get(int source) +{ + return rtl838x_get_port_reg(rtl838x_port_iso_ctrl(source)); +} + +void rtl838x_traffic_set(int source, u64 dest_matrix) +{ + rtl838x_set_port_reg(dest_matrix, rtl838x_port_iso_ctrl(source)); +} + +void rtl838x_traffic_enable(int source, int dest) +{ + rtl838x_mask_port_reg(0, BIT(dest), rtl838x_port_iso_ctrl(source)); +} + +void rtl838x_traffic_disable(int source, int dest) +{ + rtl838x_mask_port_reg(BIT(dest), 0, rtl838x_port_iso_ctrl(source)); } const struct rtl838x_reg rtl838x_reg = { @@ -254,8 +272,12 @@ const struct rtl838x_reg rtl838x_reg = { .get_port_reg_le = rtl838x_get_port_reg, .stat_port_rst = RTL838X_STAT_PORT_RST, .stat_rst = RTL838X_STAT_RST, - .stat_port_std_mib = rtl838x_stat_port_std_mib, + .stat_port_std_mib = RTL838X_STAT_PORT_STD_MIB, .port_iso_ctrl = rtl838x_port_iso_ctrl, + .traffic_enable = rtl838x_traffic_enable, + .traffic_disable = rtl838x_traffic_disable, + .traffic_get = rtl838x_traffic_get, + .traffic_set = rtl838x_traffic_set, .l2_ctrl_0 = RTL838X_L2_CTRL_0, .l2_ctrl_1 = RTL838X_L2_CTRL_1, .l2_port_aging_out = RTL838X_L2_PORT_AGING_OUT, @@ -272,12 +294,15 @@ const struct rtl838x_reg rtl838x_reg = { .vlan_set_tagged = rtl838x_vlan_set_tagged, .vlan_set_untagged = rtl838x_vlan_set_untagged, .mac_force_mode_ctrl = rtl838x_mac_force_mode_ctrl, + .vlan_profile_dump = rtl838x_vlan_profile_dump, + .stp_get = rtl838x_stp_get, + .stp_set = rtl838x_stp_set, .mac_port_ctrl = rtl838x_mac_port_ctrl, .l2_port_new_salrn = rtl838x_l2_port_new_salrn, .l2_port_new_sa_fwd = rtl838x_l2_port_new_sa_fwd, - .mir_ctrl = rtl838x_mir_ctrl, - .mir_dpm = rtl838x_mir_dpm, - .mir_spm = rtl838x_mir_spm, + .mir_ctrl = RTL838X_MIR_CTRL, + .mir_dpm = RTL838X_MIR_DPM_CTRL, + .mir_spm = RTL838X_MIR_SPM_CTRL, .mac_link_sts = RTL838X_MAC_LINK_STS, .mac_link_dup_sts = RTL838X_MAC_LINK_DUP_STS, .mac_link_spd_sts = rtl838x_mac_link_spd_sts, @@ -285,11 +310,13 @@ const struct rtl838x_reg rtl838x_reg = { .mac_tx_pause_sts = RTL838X_MAC_TX_PAUSE_STS, .read_l2_entry_using_hash = rtl838x_read_l2_entry_using_hash, .read_cam = rtl838x_read_cam, - .vlan_profile = rtl838x_vlan_profile, - .vlan_port_egr_filter = rtl838x_vlan_port_egr_filter, - .vlan_port_igr_filter = rtl838x_vlan_port_igr_filter, - .vlan_port_pb = rtl838x_vlan_port_pb, - .vlan_port_tag_sts_ctrl = rtl838x_vlan_port_tag_sts_ctrl, + .vlan_port_egr_filter = RTL838X_VLAN_PORT_EGR_FLTR, + .vlan_port_igr_filter = RTL838X_VLAN_PORT_IGR_FLTR(0), + .vlan_port_pb = RTL838X_VLAN_PORT_PB_VLAN, + .vlan_port_tag_sts_ctrl = RTL838X_VLAN_PORT_TAG_STS_CTRL, + .trk_mbr_ctr = rtl838x_trk_mbr_ctr, + .rma_bpdu_fld_pmask = RTL838X_RMA_BPDU_FLD_PMSK, + .spcl_trap_eapol_ctrl = RTL838X_SPCL_TRAP_EAPOL_CTRL, }; irqreturn_t rtl838x_switch_irq(int irq, void *dev_id) @@ -302,7 +329,7 @@ irqreturn_t rtl838x_switch_irq(int irq, void *dev_id) /* Clear status */ sw_w32(ports, RTL838X_ISR_PORT_LINK_STS_CHG); - pr_debug("RTL8380 Link change: status: %x, ports %x\n", status, ports); + pr_info("RTL8380 Link change: status: %x, ports %x\n", status, ports); for (i = 0; i < 28; i++) { if (ports & BIT(i)) { @@ -469,8 +496,37 @@ void rtl838x_vlan_profile_dump(int index) profile = sw_r32(RTL838X_VLAN_PROFILE(index)); - pr_debug("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %x, \ + pr_info("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %x, \ IPv4 Unknown MultiCast Field %x, IPv6 Unknown MultiCast Field: %x", index, profile & 1, (profile >> 1) & 0x1ff, (profile >> 10) & 0x1ff, (profile >> 19) & 0x1ff); } + +void rtl8380_sds_rst(int mac) +{ + u32 offset = (mac == 24) ? 0 : 0x100; + + sw_w32_mask(1 << 11, 0, RTL838X_SDS4_FIB_REG0 + offset); + sw_w32_mask(0x3, 0, RTL838X_SDS4_REG28 + offset); + sw_w32_mask(0x3, 0x3, RTL838X_SDS4_REG28 + offset); + sw_w32_mask(0, 0x1 << 6, RTL838X_SDS4_DUMMY0 + offset); + sw_w32_mask(0x1 << 6, 0, RTL838X_SDS4_DUMMY0 + offset); + pr_debug("SERDES reset: %d\n", mac); +} + +int rtl8380_sds_power(int mac, int val) +{ + u32 mode = (val == 1) ? 0x4 : 0x9; + u32 offset = (mac == 24) ? 5 : 0; + + if ((mac != 24) && (mac != 26)) { + pr_err("%s: not a fibre port: %d\n", __func__, mac); + return -1; + } + + sw_w32_mask(0x1f << offset, mode << offset, RTL838X_SDS_MODE_SEL); + + rtl8380_sds_rst(mac); + + return 0; +} diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c new file mode 100644 index 0000000000..59c283903b --- /dev/null +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c @@ -0,0 +1,607 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include "rtl83xx.h" + +extern struct mutex smi_lock; +extern struct rtl83xx_soc_info soc_info; + +void rtl930x_print_matrix(void) +{ + int i; + struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6); + + for (i = 0; i < 29; i++) { + rtl_table_read(r, i); + pr_debug("> %08x\n", sw_r32(rtl_table_data(r, 0))); + } + rtl_table_release(r); +} + +inline void rtl930x_exec_tbl0_cmd(u32 cmd) +{ + sw_w32(cmd, RTL930X_TBL_ACCESS_CTRL_0); + do { } while (sw_r32(RTL930X_TBL_ACCESS_CTRL_0) & (1 << 17)); +} + +inline void rtl930x_exec_tbl1_cmd(u32 cmd) +{ + sw_w32(cmd, RTL930X_TBL_ACCESS_CTRL_1); + do { } while (sw_r32(RTL930X_TBL_ACCESS_CTRL_1) & (1 << 17)); +} + +inline int rtl930x_tbl_access_data_0(int i) +{ + return RTL930X_TBL_ACCESS_DATA_0(i); +} + +static inline int rtl930x_l2_port_new_salrn(int p) +{ + return RTL930X_L2_PORT_SALRN(p); +} + +static inline int rtl930x_l2_port_new_sa_fwd(int p) +{ + // TODO: The definition of the fields changed, because of the master-cpu in a stack + return RTL930X_L2_PORT_NEW_SA_FWD(p); +} + +inline static int rtl930x_trk_mbr_ctr(int group) +{ + return RTL930X_TRK_MBR_CTRL + (group << 2); +} + +static void rtl930x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info) +{ + u32 v, w; + // Read VLAN table (0) via register 0 + struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 1); + + rtl_table_read(r, vlan); + v = sw_r32(rtl_table_data(r, 0)); + w = sw_r32(rtl_table_data(r, 1)); + pr_debug("VLAN_READ %d: %08x %08x\n", vlan, v, w); + rtl_table_release(r); + + info->tagged_ports = v >> 3; + info->profile_id = (w >> 24) & 7; + info->hash_mc_fid = !!(w & BIT(27)); + info->hash_uc_fid = !!(w & BIT(28)); + info->fid = ((v & 0x7) << 3) | ((w >> 29) & 0x7); + + // Read UNTAG table via table register 2 + r = rtl_table_get(RTL9300_TBL_2, 0); + rtl_table_read(r, vlan); + v = sw_r32(rtl_table_data(r, 0)); + rtl_table_release(r); + + info->untagged_ports = v >> 3; +} + +static void rtl930x_vlan_set_tagged(u32 vlan, struct rtl838x_vlan_info *info) +{ + u32 v, w; + // Access VLAN table (1) via register 0 + struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 1); + + v = info->tagged_ports << 3; + v |= ((u32)info->fid) >> 3; + + w = ((u32)info->fid) << 29; + w |= info->hash_mc_fid ? BIT(27) : 0; + w |= info->hash_uc_fid ? BIT(28) : 0; + w |= info->profile_id << 24; + + sw_w32(v, rtl_table_data(r, 0)); + sw_w32(w, rtl_table_data(r, 1)); + + rtl_table_write(r, vlan); + rtl_table_release(r); +} + +void rtl930x_vlan_profile_dump(int index) +{ + u32 profile[5]; + + if (index < 0 || index > 7) + return; + + profile[0] = sw_r32(RTL930X_VLAN_PROFILE_SET(index)); + profile[1] = sw_r32(RTL930X_VLAN_PROFILE_SET(index) + 4); + profile[2] = sw_r32(RTL930X_VLAN_PROFILE_SET(index) + 8) & 0x1FFFFFFF; + profile[3] = sw_r32(RTL930X_VLAN_PROFILE_SET(index) + 12) & 0x1FFFFFFF; + profile[4] = sw_r32(RTL930X_VLAN_PROFILE_SET(index) + 16) & 0x1FFFFFFF; + + pr_debug("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %x, \ + IPv4 Unknown MultiCast Field %x, IPv6 Unknown MultiCast Field: %x", + index, profile[0] & (3 << 21), profile[2], profile[3], profile[4]); +} + +static void rtl930x_vlan_set_untagged(u32 vlan, u64 portmask) +{ + struct table_reg *r = rtl_table_get(RTL9300_TBL_2, 0); + + sw_w32(portmask << 3, rtl_table_data(r, 0)); + rtl_table_write(r, vlan); + rtl_table_release(r); +} + +static void rtl930x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) +{ + int i; + u32 cmd = 1 << 17 /* Execute cmd */ + | 0 << 16 /* Read */ + | 4 << 12 /* Table type 0b10 */ + | (msti & 0xfff); + priv->r->exec_tbl0_cmd(cmd); + + for (i = 0; i < 2; i++) + port_state[i] = sw_r32(RTL930X_TBL_ACCESS_DATA_0(i)); + pr_debug("MSTI: %d STATE: %08x, %08x\n", msti, port_state[0], port_state[1]); +} + +static void rtl930x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) +{ + int i; + u32 cmd = 1 << 17 /* Execute cmd */ + | 1 << 16 /* Write */ + | 4 << 12 /* Table type 4 */ + | (msti & 0xfff); + + for (i = 0; i < 2; i++) + sw_w32(port_state[i], RTL930X_TBL_ACCESS_DATA_0(i)); + priv->r->exec_tbl0_cmd(cmd); +} + +static inline int rtl930x_mac_force_mode_ctrl(int p) +{ + return RTL930X_MAC_FORCE_MODE_CTRL + (p << 2); +} + +static inline int rtl930x_mac_port_ctrl(int p) +{ + return RTL930X_MAC_L2_PORT_CTRL(p); +} + +static inline int rtl930x_mac_link_spd_sts(int p) +{ + return RTL930X_MAC_LINK_SPD_STS(p); +} + +static void rtl930x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e) +{ + e->valid = !!(r[2] & BIT(31)); + if (!e->valid) + return; + + // TODO: Is there not a function to copy directly MAC memory? + e->mac[0] = (r[0] >> 24); + e->mac[1] = (r[0] >> 16); + e->mac[2] = (r[0] >> 8); + e->mac[3] = r[0]; + e->mac[4] = (r[1] >> 24); + e->mac[5] = (r[1] >> 16); + + /* Is it a unicast entry? check multicast bit */ + if (!(e->mac[0] & 1)) { + e->type = L2_UNICAST; + e->is_static = !!(r[2] & BIT(14)); + e->vid = r[2] & 0xfff; + e->rvid = r[1] & 0xfff; + e->port = (r[2] >> 20) & 0x3ff; + // Check for trunk port + if (r[2] & BIT(30)) { + e->stackDev = (e->port >> 9) & 1; + e->trunk = e->port & 0x3f; + } else { + e->stackDev = (e->port >> 6) & 0xf; + e->port = e->port & 0x3f; + } + + e->block_da = !!(r[2] & BIT(15)); + e->block_sa = !!(r[2] & BIT(16)); + e->suspended = !!(r[2] & BIT(13)); + e->next_hop = !!(r[2] & BIT(12)); + e->age = (r[2] >> 17) & 3; + e->valid = true; + + } else { + e->valid = true; + e->type = L2_MULTICAST; + e->mc_portmask_index = (r[2]>>6) & 0xfff; + } +} + +static u64 rtl930x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e) +{ + u64 entry; + u32 r[3]; + struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 0); + u32 idx = (0 << 14) | (hash << 2) | position; + int i; + + rtl_table_read(q, idx); + for (i= 0; i < 3; i++) + r[i] = sw_r32(rtl_table_data(q, i)); + + rtl_table_release(q); + + rtl930x_fill_l2_entry(r, e); + if (!e->valid) + return 0; + + entry = ((u64)r[0] << 32) | (r[1] & 0xffff0000) | e->vid; + return entry; +} + +static u64 rtl930x_read_cam(int idx, struct rtl838x_l2_entry *e) +{ + u64 entry; + u32 r[3]; + struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 1); + int i; + + rtl_table_read(q, idx); + for (i= 0; i < 3; i++) + r[i] = sw_r32(rtl_table_data(q, i)); + + rtl_table_release(q); + + rtl930x_fill_l2_entry(r, e); + if (!e->valid) + return 0; + + entry = ((u64)r[0] << 32) | (r[1] & 0xffff0000) | e->vid; + + return entry; +} + +u64 rtl930x_traffic_get(int source) +{ + u32 v; + struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6); + + rtl_table_read(r, source); + v = sw_r32(rtl_table_data(r, 0)); + rtl_table_release(r); + return v >> 3; +} + +/* + * Enable traffic between a source port and a destination port matrix + */ +void rtl930x_traffic_set(int source, u64 dest_matrix) +{ + struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6); + + sw_w32((dest_matrix << 3), rtl_table_data(r, 0)); + rtl_table_write(r, source); + rtl_table_release(r); +} + +void rtl930x_traffic_enable(int source, int dest) +{ + struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6); + rtl_table_read(r, source); + sw_w32_mask(0, BIT(dest + 3), rtl_table_data(r, 0)); + rtl_table_write(r, source); + rtl_table_release(r); +} + +void rtl930x_traffic_disable(int source, int dest) +{ + struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6); + rtl_table_read(r, source); + sw_w32_mask(BIT(dest + 3), 0, rtl_table_data(r, 0)); + rtl_table_write(r, source); + rtl_table_release(r); +} + +void rtl9300_dump_debug(void) +{ + int i; + u16 r = RTL930X_STAT_PRVTE_DROP_COUNTER0; + + for (i = 0; i < 10; i ++) { + pr_info("# %d %08x %08x %08x %08x %08x %08x %08x %08x\n", i * 8, + sw_r32(r), sw_r32(r + 4), sw_r32(r + 8), sw_r32(r + 12), + sw_r32(r + 16), sw_r32(r + 20), sw_r32(r + 24), sw_r32(r + 28)); + r += 32; + } + pr_info("# %08x %08x %08x %08x %08x\n", + sw_r32(r), sw_r32(r + 4), sw_r32(r + 8), sw_r32(r + 12), sw_r32(r + 16)); + rtl930x_print_matrix(); + pr_info("RTL930X_L2_PORT_SABLK_CTRL: %08x, RTL930X_L2_PORT_DABLK_CTRL %08x\n", + sw_r32(RTL930X_L2_PORT_SABLK_CTRL), sw_r32(RTL930X_L2_PORT_DABLK_CTRL) + + ); +} + +irqreturn_t rtl930x_switch_irq(int irq, void *dev_id) +{ + struct dsa_switch *ds = dev_id; + u32 status = sw_r32(RTL930X_ISR_GLB); + u32 ports = sw_r32(RTL930X_ISR_PORT_LINK_STS_CHG); + u32 link; + int i; + + /* Clear status */ + sw_w32(ports, RTL930X_ISR_PORT_LINK_STS_CHG); + pr_info("RTL9300 Link change: status: %x, ports %x\n", status, ports); + + rtl9300_dump_debug(); + + for (i = 0; i < 28; i++) { + if (ports & BIT(i)) { + /* Read the register twice because of issues with latency at least + * with the external RTL8226 PHY on the XGS1210 */ + link = sw_r32(RTL930X_MAC_LINK_STS); + link = sw_r32(RTL930X_MAC_LINK_STS); + if (link & BIT(i)) + dsa_port_phylink_mac_change(ds, i, true); + else + dsa_port_phylink_mac_change(ds, i, false); + } + } + + return IRQ_HANDLED; +} + +int rtl9300_sds_power(int mac, int val) +{ + int sds_num; + u32 mode; + + // TODO: these numbers are hard-coded for the Zyxel XGS1210 12 Switch + pr_info("SerDes: %s %d\n", __func__, mac); + switch (mac) { + case 24: + sds_num = 6; + mode = 0x12; // HISGMII + break; + case 25: + sds_num = 7; + mode = 0x12; // HISGMII + break; + case 26: + sds_num = 8; + mode = 0x1b; // 10GR/1000BX auto + break; + case 27: + sds_num = 9; + mode = 0x1b; // 10GR/1000BX auto + break; + default: + return -1; + } + if (!val) + mode = 0x1f; // OFF + + rtl9300_sds_rst(sds_num, mode); + + return 0; +} + + +int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val) +{ + u32 v; + int err = 0; + + pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, val); + + if (port > 63 || page > 4095 || reg > 31) + return -ENOTSUPP; + + val &= 0xffff; + mutex_lock(&smi_lock); + + sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0); + sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); + v = reg << 20 | page << 3 | 0x1f << 15 | BIT(2) | BIT(0); + sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); + + do { + v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); + } while (v & 0x1); + + if (v & 0x2) + err = -EIO; + + mutex_unlock(&smi_lock); + + return err; +} + +int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val) +{ + u32 v; + int err = 0; + +// pr_info("In %s\n", __func__); + if (port > 63 || page > 4095 || reg > 31) + return -ENOTSUPP; + + mutex_lock(&smi_lock); + + sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); + v = reg << 20 | page << 3 | 0x1f << 15 | 1; + sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); + + do { + v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); + } while ( v & 0x1); + + if (v & BIT(25)) { + pr_debug("Error reading phy %d, register %d\n", port, reg); + err = -EIO; + } + *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff); + + pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, *val); + + mutex_unlock(&smi_lock); + + return err; +} + + +/* + * Write to an mmd register of the PHY + */ +int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val) +{ + int err = 0; + u32 v; + + mutex_lock(&smi_lock); + + // Set PHY to access + sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0); + + // Set data to write + sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); + + // Set MMD device number and register to write to + sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3); + + v = BIT(2)| BIT(1)| BIT(0); // WRITE | MMD-access | EXEC + sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); + + do { + v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); + } while ( v & BIT(0)); + + pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err); + mutex_unlock(&smi_lock); + return err; +} + +/* + * Read an mmd register of the PHY + */ +int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) +{ + int err = 0; + u32 v; + + mutex_lock(&smi_lock); + + // Set PHY to access + sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); + + // Set MMD device number and register to write to + sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3); + + v = BIT(1)| BIT(0); // MMD-access | EXEC + sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); + + do { + v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); + } while ( v & 0x1); + // There is no error-checking via BIT 25 of v, as it does not seem to be set correctly + *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff); + pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err); + + mutex_unlock(&smi_lock); + + return err; +} + + +/* + * Calculate both the block 0 and the block 1 hash, and return in + * lower and higher word of the return value since only 12 bit of + * the hash are significant + */ +u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed) +{ + u32 k0, k1, h1, h2, h; + + k0 = (u32) (((seed >> 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) + ^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff) + ^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff)); + + h1 = (seed >> 11) & 0x7ff; + h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f); + + h2 = (seed >> 33) & 0x7ff; + h2 = ((h2 & 0x3f) << 5)| ((h2 >> 6) & 0x3f); + + k1 = (u32) (((seed << 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) ^ h2 + ^ ((seed >> 22) & 0x7ff) ^ h1 + ^ (seed & 0x7ff)); + + // Algorithm choice for block 0 + if (sw_r32(RTL930X_L2_CTRL) & BIT(0)) + h = k1; + else + h = k0; + + /* Algorithm choice for block 1 + * Since k0 and k1 are < 2048, adding 2048 will offset the hash into the second + * half of hash-space + * 2048 is in fact the hash-table size 16384 divided by 4 hashes per bucket + * divided by 2 to divide the hash space in 2 + */ + if (sw_r32(RTL930X_L2_CTRL) & BIT(1)) + h |= (k1 + 2048) << 16; + else + h |= (k0 + 2048) << 16; + + return h; +} + +const struct rtl838x_reg rtl930x_reg = { + .mask_port_reg_be = rtl838x_mask_port_reg, + .set_port_reg_be = rtl838x_set_port_reg, + .get_port_reg_be = rtl838x_get_port_reg, + .mask_port_reg_le = rtl838x_mask_port_reg, + .set_port_reg_le = rtl838x_set_port_reg, + .get_port_reg_le = rtl838x_get_port_reg, + .stat_port_rst = RTL930X_STAT_PORT_RST, + .stat_rst = RTL930X_STAT_RST, + .stat_port_std_mib = RTL930X_STAT_PORT_MIB_CNTR, + .traffic_enable = rtl930x_traffic_enable, + .traffic_disable = rtl930x_traffic_disable, + .traffic_get = rtl930x_traffic_get, + .traffic_set = rtl930x_traffic_set, + .l2_ctrl_0 = RTL930X_L2_CTRL, + .l2_ctrl_1 = RTL930X_L2_AGE_CTRL, + .l2_port_aging_out = RTL930X_L2_PORT_AGE_CTRL, + .smi_poll_ctrl = RTL930X_SMI_POLL_CTRL, // TODO: Difference to RTL9300_SMI_PRVTE_POLLING_CTRL + .l2_tbl_flush_ctrl = RTL930X_L2_TBL_FLUSH_CTRL, + .exec_tbl0_cmd = rtl930x_exec_tbl0_cmd, + .exec_tbl1_cmd = rtl930x_exec_tbl1_cmd, + .tbl_access_data_0 = rtl930x_tbl_access_data_0, + .isr_glb_src = RTL930X_ISR_GLB, + .isr_port_link_sts_chg = RTL930X_ISR_PORT_LINK_STS_CHG, + .imr_port_link_sts_chg = RTL930X_IMR_PORT_LINK_STS_CHG, + .imr_glb = RTL930X_IMR_GLB, + .vlan_tables_read = rtl930x_vlan_tables_read, + .vlan_set_tagged = rtl930x_vlan_set_tagged, + .vlan_set_untagged = rtl930x_vlan_set_untagged, + .vlan_profile_dump = rtl930x_vlan_profile_dump, + .stp_get = rtl930x_stp_get, + .stp_set = rtl930x_stp_set, + .mac_force_mode_ctrl = rtl930x_mac_force_mode_ctrl, + .mac_port_ctrl = rtl930x_mac_port_ctrl, + .l2_port_new_salrn = rtl930x_l2_port_new_salrn, + .l2_port_new_sa_fwd = rtl930x_l2_port_new_sa_fwd, + .mir_ctrl = RTL930X_MIR_CTRL, + .mir_dpm = RTL930X_MIR_DPM_CTRL, + .mir_spm = RTL930X_MIR_SPM_CTRL, + .mac_link_sts = RTL930X_MAC_LINK_STS, + .mac_link_dup_sts = RTL930X_MAC_LINK_DUP_STS, + .mac_link_spd_sts = rtl930x_mac_link_spd_sts, + .mac_rx_pause_sts = RTL930X_MAC_RX_PAUSE_STS, + .mac_tx_pause_sts = RTL930X_MAC_TX_PAUSE_STS, + .read_l2_entry_using_hash = rtl930x_read_l2_entry_using_hash, + .read_cam = rtl930x_read_cam, + .vlan_port_egr_filter = RTL930X_VLAN_PORT_EGR_FLTR, + .vlan_port_igr_filter = RTL930X_VLAN_PORT_IGR_FLTR(0), + .vlan_port_pb = RTL930X_VLAN_PORT_PB_VLAN, + .vlan_port_tag_sts_ctrl = RTL930X_VLAN_PORT_TAG_STS_CTRL, + .trk_mbr_ctr = rtl930x_trk_mbr_ctr, + .rma_bpdu_fld_pmask = RTL930X_RMA_BPDU_FLD_PMSK, +}; diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c new file mode 100644 index 0000000000..a33941a0eb --- /dev/null +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include "rtl83xx.h" + +extern struct mutex smi_lock; +extern struct rtl83xx_soc_info soc_info; + +inline void rtl931x_exec_tbl0_cmd(u32 cmd) +{ + sw_w32(cmd, RTL931X_TBL_ACCESS_CTRL_0); + do { } while (sw_r32(RTL931X_TBL_ACCESS_CTRL_0) & (1 << 20)); +} + +inline void rtl931x_exec_tbl1_cmd(u32 cmd) +{ + sw_w32(cmd, RTL931X_TBL_ACCESS_CTRL_1); + do { } while (sw_r32(RTL931X_TBL_ACCESS_CTRL_1) & (1 << 17)); +} + +inline int rtl931x_tbl_access_data_0(int i) +{ + return RTL931X_TBL_ACCESS_DATA_0(i); +} + +void rtl931x_vlan_profile_dump(int index) +{ + u64 profile[4]; + + if (index < 0 || index > 15) + return; + + profile[0] = sw_r32(RTL931X_VLAN_PROFILE_SET(index)); + profile[1] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 4) & 0x1FFFFFFFULL) << 32 + | (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 8) & 0xFFFFFFFF); + profile[2] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 16) & 0xFFFFFFFFULL) << 32 + | (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 12) & 0x1FFFFFFULL); + profile[3] = (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 20) & 0x1FFFFFFFULL) << 32 + | (sw_r32(RTL931X_VLAN_PROFILE_SET(index) + 24) & 0xFFFFFFFF); + + pr_info("VLAN %d: L2 learning: %d, L2 Unknown MultiCast Field %llx, \ + IPv4 Unknown MultiCast Field %llx, IPv6 Unknown MultiCast Field: %llx", + index, (u32) (profile[0] & (3 << 14)), profile[1], profile[2], profile[3]); +} + +static void rtl931x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) +{ + int i; + u32 cmd = 1 << 20 /* Execute cmd */ + | 0 << 19 /* Read */ + | 2 << 15 /* Table type 0b10 */ + | (msti & 0x3fff); + priv->r->exec_tbl0_cmd(cmd); + + for (i = 0; i < 4; i++) + port_state[i] = sw_r32(priv->r->tbl_access_data_0(i)); +} + +static void rtl931x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[]) +{ + int i; + u32 cmd = 1 << 20 /* Execute cmd */ + | 1 << 19 /* Write */ + | 5 << 15 /* Table type 0b101 */ + | (msti & 0x3fff); + for (i = 0; i < 4; i++) + sw_w32(port_state[i], priv->r->tbl_access_data_0(i)); + priv->r->exec_tbl0_cmd(cmd); +} + +inline static int rtl931x_trk_mbr_ctr(int group) +{ + return RTL931X_TRK_MBR_CTRL + (group << 2); +} + +static void rtl931x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info) +{ + u32 v, w, x, y; + // Read VLAN table (3) via register 0 + struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 3); + + rtl_table_read(r, vlan); + v = sw_r32(rtl_table_data(r, 0)); + w = sw_r32(rtl_table_data(r, 1)); + x = sw_r32(rtl_table_data(r, 2)); + y = sw_r32(rtl_table_data(r, 3)); + pr_debug("VLAN_READ %d: %08x %08x\n", vlan, v, w); + rtl_table_release(r); + + info->tagged_ports = ((u64) v) << 25 | (w >> 7); + info->profile_id = (x >> 16) & 0xf; + info->hash_mc_fid = !!(x & BIT(30)); + info->hash_uc_fid = !!(x & BIT(31)); + info->fid = w & 0x7f; + // TODO: use also info in 4th register + + // Read UNTAG table via table register 3 + r = rtl_table_get(RTL9310_TBL_3, 0); + rtl_table_read(r, vlan); + v = ((u64)sw_r32(rtl_table_data(r, 0))) << 25; + v |= sw_r32(rtl_table_data(r, 1)) >> 7; + rtl_table_release(r); + + info->untagged_ports = v; +} + +static void rtl931x_vlan_set_tagged(u32 vlan, struct rtl838x_vlan_info *info) +{ + u32 v, w, x; + // Access VLAN table (1) via register 0 + struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 3); + + v = info->tagged_ports << 7; + w = (info->tagged_ports & 0x7f000000) << 25; + w |= (u32)info->fid; + x = info->profile_id << 16; + w |= info->hash_mc_fid ? BIT(30) : 0; + w |= info->hash_uc_fid ? BIT(31) : 0; + // TODO: use also info in 4th register + + sw_w32(v, rtl_table_data(r, 0)); + sw_w32(w, rtl_table_data(r, 1)); + sw_w32(x, rtl_table_data(r, 2)); + + rtl_table_write(r, vlan); + rtl_table_release(r); +} + +static void rtl931x_vlan_set_untagged(u32 vlan, u64 portmask) +{ + struct table_reg *r = rtl_table_get(RTL9310_TBL_3, 0); + + rtl839x_set_port_reg_be(portmask << 7, rtl_table_data(r, 0)); + rtl_table_write(r, vlan); + rtl_table_release(r); +} + +static inline int rtl931x_mac_force_mode_ctrl(int p) +{ + return RTL931X_MAC_FORCE_MODE_CTRL + (p << 2); +} + +static inline int rtl931x_mac_link_spd_sts(int p) +{ + return RTL931X_MAC_LINK_SPD_STS(p); +} + +static inline int rtl931x_mac_port_ctrl(int p) +{ + return RTL931X_MAC_PORT_CTRL(p); +} + +static inline int rtl931x_l2_port_new_salrn(int p) +{ + return RTL931X_L2_PORT_NEW_SALRN(p); +} + +static inline int rtl931x_l2_port_new_sa_fwd(int p) +{ + return RTL931X_L2_PORT_NEW_SA_FWD(p); +} + +static u64 rtl931x_read_l2_entry_using_hash(u32 hash, u32 position, struct rtl838x_l2_entry *e) +{ + u64 entry = 0; + + // TODO: Implement + return entry; +} + +static u64 rtl931x_read_cam(int idx, struct rtl838x_l2_entry *e) +{ + u64 entry = 0; + + // TODO: Implement + return entry; +} +irqreturn_t rtl931x_switch_irq(int irq, void *dev_id) +{ + struct dsa_switch *ds = dev_id; + u32 status = sw_r32(RTL931X_ISR_GLB_SRC); + u64 ports = rtl839x_get_port_reg_le(RTL931X_ISR_PORT_LINK_STS_CHG); + u64 link; + int i; + + /* Clear status */ + rtl839x_set_port_reg_le(ports, RTL931X_ISR_PORT_LINK_STS_CHG); + pr_info("RTL9310 Link change: status: %x, ports %llx\n", status, ports); + + for (i = 0; i < 56; i++) { + if (ports & BIT_ULL(i)) { + link = rtl839x_get_port_reg_le(RTL931X_MAC_LINK_STS); + if (link & BIT_ULL(i)) + dsa_port_phylink_mac_change(ds, i, true); + else + dsa_port_phylink_mac_change(ds, i, false); + } + } + return IRQ_HANDLED; +} + + +int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val) +{ + u32 v; + int err = 0; + + val &= 0xffff; + if (port > 63 || page > 4095 || reg > 31) + return -ENOTSUPP; + + mutex_lock(&smi_lock); + /* Clear both port registers */ + sw_w32(0, RTL931X_SMI_INDRT_ACCESS_CTRL_2); + sw_w32(0, RTL931X_SMI_INDRT_ACCESS_CTRL_2 + 4); + sw_w32_mask(0, BIT(port), RTL931X_SMI_INDRT_ACCESS_CTRL_2+ (port % 32) * 4); + + sw_w32_mask(0xffff0000, val << 16, RTL931X_SMI_INDRT_ACCESS_CTRL_3); + + v = reg << 6 | page << 11 ; + sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0); + + sw_w32(0x1ff, RTL931X_SMI_INDRT_ACCESS_CTRL_1); + + v |= 1 << 3 | 1; /* Write operation and execute */ + sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0); + + do { + } while (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0) & 0x1); + + if (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0) & 0x2) + err = -EIO; + + mutex_unlock(&smi_lock); + return err; +} + +int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val) +{ + u32 v; + + if (port > 63 || page > 4095 || reg > 31) + return -ENOTSUPP; + + mutex_lock(&smi_lock); + + sw_w32_mask(0xffff, port, RTL931X_SMI_INDRT_ACCESS_CTRL_3); + v = reg << 6 | page << 11; // TODO: ACCESS Offset? Park page + sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0); + + sw_w32(0x1ff, RTL931X_SMI_INDRT_ACCESS_CTRL_1); + + v |= 1; + sw_w32(v, RTL931X_SMI_INDRT_ACCESS_CTRL_0); + + do { + } while (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_0) & 0x1); + + *val = (sw_r32(RTL931X_SMI_INDRT_ACCESS_CTRL_3) & 0xffff0000) >> 16; + + pr_info("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, *val); + + mutex_unlock(&smi_lock); + return 0; +} + +void rtl931x_print_matrix(void) +{ + volatile u64 *ptr = RTL838X_SW_BASE + RTL839X_PORT_ISO_CTRL(0); + int i; + + for (i = 0; i < 52; i += 4) + pr_info("> %16llx %16llx %16llx %16llx\n", + ptr[i + 0], ptr[i + 1], ptr[i + 2], ptr[i + 3]); + pr_info("CPU_PORT> %16llx\n", ptr[52]); +} + +const struct rtl838x_reg rtl931x_reg = { + .mask_port_reg_be = rtl839x_mask_port_reg_be, + .set_port_reg_be = rtl839x_set_port_reg_be, + .get_port_reg_be = rtl839x_get_port_reg_be, + .mask_port_reg_le = rtl839x_mask_port_reg_le, + .set_port_reg_le = rtl839x_set_port_reg_le, + .get_port_reg_le = rtl839x_get_port_reg_le, + .stat_port_rst = RTL931X_STAT_PORT_RST, + .stat_rst = RTL931X_STAT_RST, + .stat_port_std_mib = 0, // Not defined + .l2_ctrl_0 = RTL931X_L2_CTRL, + .l2_ctrl_1 = RTL931X_L2_AGE_CTRL, + .l2_port_aging_out = RTL931X_L2_PORT_AGE_CTRL, + // .smi_poll_ctrl does not exist + .l2_tbl_flush_ctrl = RTL931X_L2_TBL_FLUSH_CTRL, + .exec_tbl0_cmd = rtl931x_exec_tbl0_cmd, + .exec_tbl1_cmd = rtl931x_exec_tbl1_cmd, + .tbl_access_data_0 = rtl931x_tbl_access_data_0, + .isr_glb_src = RTL931X_ISR_GLB_SRC, + .isr_port_link_sts_chg = RTL931X_ISR_PORT_LINK_STS_CHG, + .imr_port_link_sts_chg = RTL931X_IMR_PORT_LINK_STS_CHG, + // imr_glb does not exist on RTL931X + .vlan_tables_read = rtl931x_vlan_tables_read, + .vlan_set_tagged = rtl931x_vlan_set_tagged, + .vlan_set_untagged = rtl931x_vlan_set_untagged, + .vlan_profile_dump = rtl931x_vlan_profile_dump, + .stp_get = rtl931x_stp_get, + .stp_set = rtl931x_stp_set, + .mac_force_mode_ctrl = rtl931x_mac_force_mode_ctrl, + .mac_port_ctrl = rtl931x_mac_port_ctrl, + .l2_port_new_salrn = rtl931x_l2_port_new_salrn, + .l2_port_new_sa_fwd = rtl931x_l2_port_new_sa_fwd, + .mir_ctrl = RTL931X_MIR_CTRL, + .mir_dpm = RTL931X_MIR_DPM_CTRL, + .mir_spm = RTL931X_MIR_SPM_CTRL, + .mac_link_sts = RTL931X_MAC_LINK_STS, + .mac_link_dup_sts = RTL931X_MAC_LINK_DUP_STS, + .mac_link_spd_sts = rtl931x_mac_link_spd_sts, + .mac_rx_pause_sts = RTL931X_MAC_RX_PAUSE_STS, + .mac_tx_pause_sts = RTL931X_MAC_TX_PAUSE_STS, + .read_l2_entry_using_hash = rtl931x_read_l2_entry_using_hash, + .read_cam = rtl931x_read_cam, + .vlan_port_egr_filter = RTL931X_VLAN_PORT_EGR_FLTR(0), + .vlan_port_igr_filter = RTL931X_VLAN_PORT_IGR_FLTR(0), +// .vlan_port_pb = does not exist + .vlan_port_tag_sts_ctrl = RTL931X_VLAN_PORT_TAG_CTRL, + .trk_mbr_ctr = rtl931x_trk_mbr_ctr, +}; + diff --git a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.h b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.h index 4366e6b64f..d7b4317cbb 100644 --- a/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.h +++ b/target/linux/realtek/files-5.4/drivers/net/ethernet/rtl838x_eth.h @@ -7,37 +7,85 @@ * Register definition */ -#define RTL838X_CPU_PORT 28 -#define RTL839X_CPU_PORT 52 - +/* Per port MAC control */ #define RTL838X_MAC_PORT_CTRL (0xd560) #define RTL839X_MAC_PORT_CTRL (0x8004) -#define RTL838X_DMA_IF_INTR_STS (0x9f54) -#define RTL839X_DMA_IF_INTR_STS (0x7868) -#define RTL838X_DMA_IF_INTR_MSK (0x9f50) -#define RTL839X_DMA_IF_INTR_MSK (0x7864) +#define RTL930X_MAC_L2_PORT_CTRL (0x3268) +#define RTL930X_MAC_PORT_CTRL (0x3260) +#define RTL931X_MAC_L2_PORT_CTRL (0x6000) +#define RTL931X_MAC_PORT_CTRL (0x6004) + +/* DMA interrupt control and status registers */ #define RTL838X_DMA_IF_CTRL (0x9f58) +#define RTL838X_DMA_IF_INTR_STS (0x9f54) +#define RTL838X_DMA_IF_INTR_MSK (0x9f50) + #define RTL839X_DMA_IF_CTRL (0x786c) -#define RTL838X_RST_GLB_CTRL_0 (0x003c) +#define RTL839X_DMA_IF_INTR_STS (0x7868) +#define RTL839X_DMA_IF_INTR_MSK (0x7864) + +#define RTL930X_DMA_IF_CTRL (0xe028) +#define RTL930X_DMA_IF_INTR_RX_RUNOUT_STS (0xe01C) +#define RTL930X_DMA_IF_INTR_RX_DONE_STS (0xe020) +#define RTL930X_DMA_IF_INTR_TX_DONE_STS (0xe024) +#define RTL930X_DMA_IF_INTR_RX_RUNOUT_MSK (0xe010) +#define RTL930X_DMA_IF_INTR_RX_DONE_MSK (0xe014) +#define RTL930X_DMA_IF_INTR_TX_DONE_MSK (0xe018) +#define RTL930X_L2_NTFY_IF_INTR_MSK (0xe04C) +#define RTL930X_L2_NTFY_IF_INTR_STS (0xe050) + +/* TODO: RTL931X_DMA_IF_CTRL has different bits meanings */ +#define RTL931X_DMA_IF_CTRL (0x0928) +#define RTL931X_DMA_IF_INTR_RX_RUNOUT_STS (0x091c) +#define RTL931X_DMA_IF_INTR_RX_DONE_STS (0x0920) +#define RTL931X_DMA_IF_INTR_TX_DONE_STS (0x0924) +#define RTL931X_DMA_IF_INTR_RX_RUNOUT_MSK (0x0910) +#define RTL931X_DMA_IF_INTR_RX_DONE_MSK (0x0914) +#define RTL931X_DMA_IF_INTR_TX_DONE_MSK (0x0918) +#define RTL931X_L2_NTFY_IF_INTR_MSK (0x09E4) +#define RTL931X_L2_NTFY_IF_INTR_STS (0x09E8) + #define RTL838X_MAC_FORCE_MODE_CTRL (0xa104) #define RTL839X_MAC_FORCE_MODE_CTRL (0x02bc) +#define RTL930X_MAC_FORCE_MODE_CTRL (0xCA1C) +#define RTL931X_MAC_FORCE_MODE_CTRL (0x0ddc) /* MAC address settings */ #define RTL838X_MAC (0xa9ec) #define RTL839X_MAC (0x02b4) #define RTL838X_MAC_ALE (0x6b04) #define RTL838X_MAC2 (0xa320) +#define RTL930X_MAC_L2_ADDR_CTRL (0xC714) +#define RTL931X_MAC_L2_ADDR_CTRL (0x135c) +/* Ringbuffer setup */ #define RTL838X_DMA_RX_BASE (0x9f00) #define RTL839X_DMA_RX_BASE (0x780c) +#define RTL930X_DMA_RX_BASE (0xdf00) +#define RTL931X_DMA_RX_BASE (0x0800) + #define RTL838X_DMA_TX_BASE (0x9f40) #define RTL839X_DMA_TX_BASE (0x784c) +#define RTL930X_DMA_TX_BASE (0xe000) +#define RTL931X_DMA_TX_BASE (0x0900) + #define RTL838X_DMA_IF_RX_RING_SIZE (0xB7E4) #define RTL839X_DMA_IF_RX_RING_SIZE (0x6038) +#define RTL930X_DMA_IF_RX_RING_SIZE (0x7C60) +#define RTL931X_DMA_IF_RX_RING_SIZE (0x2080) + #define RTL838X_DMA_IF_RX_RING_CNTR (0xB7E8) #define RTL839X_DMA_IF_RX_RING_CNTR (0x603c) +#define RTL930X_DMA_IF_RX_RING_CNTR (0x7C8C) +#define RTL931X_DMA_IF_RX_RING_CNTR (0x20AC) + #define RTL838X_DMA_IF_RX_CUR (0x9F20) #define RTL839X_DMA_IF_RX_CUR (0x782c) +#define RTL930X_DMA_IF_RX_CUR (0xdf80) +#define RTL931X_DMA_IF_RX_CUR (0x0880) + +#define RTL838X_DMA_IF_TX_CUR_DESC_ADDR_CTRL (0x9F48) +#define RTL930X_DMA_IF_TX_CUR_DESC_ADDR_CTRL (0xE008) #define RTL838X_DMY_REG31 (0x3b28) #define RTL838X_SDS_MODE_SEL (0x0028) @@ -47,50 +95,56 @@ #define RTL838X_SDS4_REG28 (0xef80) #define RTL838X_SDS4_DUMMY0 (0xef8c) #define RTL838X_SDS5_EXT_REG6 (0xf18c) -#define RTL838X_PORT_ISO_CTRL(port) (0x4100 + ((port) << 2)) -#define RTL838X_STAT_PORT_STD_MIB(port) (0x1200 + (((port) << 8))) -#define RTL838X_STAT_RST (0x3100) -#define RTL838X_STAT_CTRL (0x3108) -/* Registers of the internal Serdes of the 8380 */ -#define MAPLE_SDS4_REG0r RTL838X_SDS4_REG28 -#define MAPLE_SDS5_REG0r (RTL838X_SDS4_REG28 + 0x100) -#define MAPLE_SDS4_REG3r RTL838X_SDS4_DUMMY0 -#define MAPLE_SDS5_REG3r (RTL838X_SDS4_REG28 + 0x100) -#define MAPLE_SDS4_FIB_REG0r (RTL838X_SDS4_REG28 + 0x880) -#define MAPLE_SDS5_FIB_REG0r (RTL838X_SDS4_REG28 + 0x980) - -/* VLAN registers */ -#define RTL838X_VLAN_PROFILE(idx) (0x3A88 + ((idx) << 2)) -#define RTL838X_VLAN_PORT_EGR_FLTR (0x3A84) -#define RTL838X_VLAN_PORT_PB_VLAN(port) (0x3C00 + ((port) << 2)) -#define RTL838X_VLAN_PORT_IGR_FLTR_0 (0x3A7C) -#define RTL838X_VLAN_PORT_IGR_FLTR_1 (0x3A7C + 4) -#define RTL838X_TBL_ACCESS_CTRL_0 (0x6914) -#define RTL838X_TBL_ACCESS_DATA_0(idx) (0x6918 + ((idx) << 2)) -#define RTL838X_TBL_ACCESS_CTRL_1 (0xA4C8) -#define RTL838X_TBL_ACCESS_DATA_1(idx) (0xA4CC + ((idx) << 2)) +/* L2 features */ #define RTL839X_TBL_ACCESS_L2_CTRL (0x1180) #define RTL839X_TBL_ACCESS_L2_DATA(idx) (0x1184 + ((idx) << 2)) -/* MAC handling */ +#define RTL838X_TBL_ACCESS_CTRL_0 (0x6914) +#define RTL838X_TBL_ACCESS_DATA_0(idx) (0x6918 + ((idx) << 2)) + +/* MAC-side link state handling */ #define RTL838X_MAC_LINK_STS (0xa188) #define RTL839X_MAC_LINK_STS (0x0390) +#define RTL930X_MAC_LINK_STS (0xCB10) +#define RTL931X_MAC_LINK_STS (0x0ec0) + #define RTL838X_MAC_LINK_SPD_STS (0xa190) #define RTL839X_MAC_LINK_SPD_STS (0x03a0) +#define RTL930X_MAC_LINK_SPD_STS (0xCB18) +#define RTL931X_MAC_LINK_SPD_STS (0x0ed0) + #define RTL838X_MAC_LINK_DUP_STS (0xa19c) #define RTL839X_MAC_LINK_DUP_STS (0x03b0) +#define RTL930X_MAC_LINK_DUP_STS (0xCB28) +#define RTL931X_MAC_LINK_DUP_STS (0x0ef0) + // TODO: RTL8390_MAC_LINK_MEDIA_STS_ADDR ??? + #define RTL838X_MAC_TX_PAUSE_STS (0xa1a0) #define RTL839X_MAC_TX_PAUSE_STS (0x03b8) +#define RTL930X_MAC_TX_PAUSE_STS (0xCB2C) +#define RTL931X_MAC_TX_PAUSE_STS (0x0ef8) + #define RTL838X_MAC_RX_PAUSE_STS (0xa1a4) -#define RTL839X_MAC_RX_PAUSE_STS (0x03c0) +#define RTL839X_MAC_RX_PAUSE_STS (0xCB30) +#define RTL930X_MAC_RX_PAUSE_STS (0xC2F8) +#define RTL931X_MAC_RX_PAUSE_STS (0x0f00) + #define RTL838X_EEE_TX_TIMER_GIGA_CTRL (0xaa04) #define RTL838X_EEE_TX_TIMER_GELITE_CTRL (0xaa08) + +#define RTL930X_L2_UNKN_UC_FLD_PMSK (0x9064) + #define RTL839X_MAC_GLB_CTRL (0x02a8) #define RTL839X_SCHED_LB_TICK_TKN_CTRL (0x60f8) #define RTL838X_L2_TBL_FLUSH_CTRL (0x3370) #define RTL839X_L2_TBL_FLUSH_CTRL (0x3ba0) +#define RTL930X_L2_TBL_FLUSH_CTRL (0x9404) +#define RTL931X_L2_TBL_FLUSH_CTRL (0xCD9C) + +#define RTL930X_L2_PORT_SABLK_CTRL (0x905c) +#define RTL930X_L2_PORT_DABLK_CTRL (0x9060) /* MAC link state bits */ #define FORCE_EN (1 << 0) @@ -100,25 +154,48 @@ #define TX_PAUSE_EN (1 << 6) #define RX_PAUSE_EN (1 << 7) -/* RTL839X L2 Notification DMA interface */ +/* L2 Notification DMA interface */ #define RTL839X_DMA_IF_NBUF_BASE_DESC_ADDR_CTRL (0x785C) #define RTL839X_L2_NOTIFICATION_CTRL (0x7808) +#define RTL931X_L2_NTFY_RING_BASE_ADDR (0x09DC) +#define RTL931X_L2_NTFY_RING_CUR_ADDR (0x09E0) +#define RTL839X_L2_NOTIFICATION_CTRL (0x7808) +#define RTL931X_L2_NTFY_CTRL (0xCDC8) #define RTL838X_L2_CTRL_0 (0x3200) #define RTL839X_L2_CTRL_0 (0x3800) +#define RTL930X_L2_CTRL (0x8FD8) +#define RTL931X_L2_CTRL (0xC800) /* TRAPPING to CPU-PORT */ #define RTL838X_SPCL_TRAP_IGMP_CTRL (0x6984) -#define RTL839X_SPCL_TRAP_IGMP_CTRL (0x1058) #define RTL838X_RMA_CTRL_0 (0x4300) #define RTL838X_RMA_CTRL_1 (0x4304) #define RTL839X_RMA_CTRL_0 (0x1200) + +#define RTL839X_SPCL_TRAP_IGMP_CTRL (0x1058) #define RTL839X_RMA_CTRL_1 (0x1204) #define RTL839X_RMA_CTRL_2 (0x1208) #define RTL839X_RMA_CTRL_3 (0x120C) +#define RTL930X_RMA_CTRL_0 (0x9E60) +#define RTL930X_RMA_CTRL_1 (0x9E64) +#define RTL930X_RMA_CTRL_2 (0x9E68) + +#define RTL931X_RMA_CTRL_0 (0x8800) +#define RTL931X_RMA_CTRL_1 (0x8804) +#define RTL931X_RMA_CTRL_2 (0x8808) + +/* Advanced SMI control for clause 45 PHYs */ +#define RTL930X_SMI_MAC_TYPE_CTRL (0xCA04) +#define RTL930X_SMI_PORT24_27_ADDR_CTRL (0xCB90) +#define RTL930X_SMI_PORT0_15_POLLING_SEL (0xCA08) +#define RTL930X_SMI_PORT16_27_POLLING_SEL (0xCA0C) + /* Registers of the internal Serdes of the 8390 */ #define RTL839X_SDS12_13_XSG0 (0xB800) +/* Registers of the internal Serdes of the 8380 */ +#define RTL838X_SDS4_FIB_REG0 (0xF800) inline int rtl838x_mac_port_ctrl(int p) { @@ -130,34 +207,19 @@ inline int rtl839x_mac_port_ctrl(int p) return RTL839X_MAC_PORT_CTRL + (p << 7); } -static inline int rtl838x_mac_force_mode_ctrl(int p) +/* On the RTL931XX, the functionality of the MAC port control register is split up + * into RTL931X_MAC_L2_PORT_CTRL and RTL931X_MAC_PORT_CTRL the functionality used + * by the Ethernet driver is in the same bits now in RTL931X_MAC_L2_PORT_CTRL + */ + +inline int rtl930x_mac_port_ctrl(int p) { - return RTL838X_MAC_FORCE_MODE_CTRL + (p << 2); + return RTL930X_MAC_L2_PORT_CTRL + (p << 6); } -static inline int rtl839x_mac_force_mode_ctrl(int p) +inline int rtl931x_mac_port_ctrl(int p) { - return RTL839X_MAC_FORCE_MODE_CTRL + (p << 2); -} - -inline int rtl838x_dma_rx_base(int i) -{ - return RTL838X_DMA_RX_BASE + (i << 2); -} - -inline int rtl839x_dma_rx_base(int i) -{ - return RTL839X_DMA_RX_BASE + (i << 2); -} - -inline int rtl838x_dma_tx_base(int i) -{ - return RTL838X_DMA_TX_BASE + (i << 2); -} - -inline int rtl839x_dma_tx_base(int i) -{ - return RTL839X_DMA_TX_BASE + (i << 2); + return RTL931X_MAC_L2_PORT_CTRL + (p << 7); } inline int rtl838x_dma_if_rx_ring_size(int i) @@ -170,6 +232,16 @@ inline int rtl839x_dma_if_rx_ring_size(int i) return RTL839X_DMA_IF_RX_RING_SIZE + ((i >> 3) << 2); } +inline int rtl930x_dma_if_rx_ring_size(int i) +{ + return RTL930X_DMA_IF_RX_RING_SIZE + ((i / 3) << 2); +} + +inline int rtl931x_dma_if_rx_ring_size(int i) +{ + return RTL931X_DMA_IF_RX_RING_SIZE + ((i / 3) << 2); +} + inline int rtl838x_dma_if_rx_ring_cntr(int i) { return RTL838X_DMA_IF_RX_RING_CNTR + ((i >> 3) << 2); @@ -180,35 +252,54 @@ inline int rtl839x_dma_if_rx_ring_cntr(int i) return RTL839X_DMA_IF_RX_RING_CNTR + ((i >> 3) << 2); } - -inline int rtl838x_dma_if_rx_cur(int i) +inline int rtl930x_dma_if_rx_ring_cntr(int i) { - return RTL838X_DMA_IF_RX_CUR + (i << 2); + return RTL930X_DMA_IF_RX_RING_CNTR + ((i / 3) << 2); } -inline int rtl839x_dma_if_rx_cur(int i) +inline int rtl931x_dma_if_rx_ring_cntr(int i) { - return RTL839X_DMA_IF_RX_CUR + (i << 2); + return RTL931X_DMA_IF_RX_RING_CNTR + ((i / 3) << 2); } inline u32 rtl838x_get_mac_link_sts(int port) { - return (sw_r32(RTL838X_MAC_LINK_STS) & (1 << port)); + return (sw_r32(RTL838X_MAC_LINK_STS) & BIT(port)); } inline u32 rtl839x_get_mac_link_sts(int p) { - return (sw_r32(RTL839X_MAC_LINK_STS + ((p >> 5) << 2)) & (1 << p)); + return (sw_r32(RTL839X_MAC_LINK_STS + ((p >> 5) << 2)) & BIT(p % 32)); +} + +inline u32 rtl930x_get_mac_link_sts(int port) +{ + return (sw_r32(RTL930X_MAC_LINK_STS) & BIT(port)); +} + +inline u32 rtl931x_get_mac_link_sts(int p) +{ + return (sw_r32(RTL931X_MAC_LINK_STS + ((p >> 5) << 2)) & BIT(p % 32)); } inline u32 rtl838x_get_mac_link_dup_sts(int port) { - return (sw_r32(RTL838X_MAC_LINK_DUP_STS) & (1 << port)); + return (sw_r32(RTL838X_MAC_LINK_DUP_STS) & BIT(port)); } inline u32 rtl839x_get_mac_link_dup_sts(int p) { - return (sw_r32(RTL839X_MAC_LINK_DUP_STS + ((p >> 5) << 2)) & (1 << p)); + return (sw_r32(RTL839X_MAC_LINK_DUP_STS + ((p >> 5) << 2)) & BIT(p % 32)); +} + +inline u32 rtl930x_get_mac_link_dup_sts(int port) +{ + return (sw_r32(RTL930X_MAC_LINK_DUP_STS) & BIT(port)); +} + +inline u32 rtl931x_get_mac_link_dup_sts(int p) +{ + return (sw_r32(RTL931X_MAC_LINK_DUP_STS + ((p >> 5) << 2)) & BIT(p % 32)); } inline u32 rtl838x_get_mac_link_spd_sts(int port) @@ -229,6 +320,25 @@ inline u32 rtl839x_get_mac_link_spd_sts(int port) return (speed & 0x3); } + +inline u32 rtl930x_get_mac_link_spd_sts(int port) +{ + int r = RTL930X_MAC_LINK_SPD_STS + ((port / 10) << 2); + u32 speed = sw_r32(r); + + speed >>= (port % 10) * 3; + return (speed & 0x7); +} + +inline u32 rtl931x_get_mac_link_spd_sts(int port) +{ + int r = RTL931X_MAC_LINK_SPD_STS + ((port >> 3) << 2); + u32 speed = sw_r32(r); + + speed >>= (port % 8) << 2; + return (speed & 0xf); +} + inline u32 rtl838x_get_mac_rx_pause_sts(int port) { return (sw_r32(RTL838X_MAC_RX_PAUSE_STS) & (1 << port)); @@ -236,7 +346,17 @@ inline u32 rtl838x_get_mac_rx_pause_sts(int port) inline u32 rtl839x_get_mac_rx_pause_sts(int p) { - return (sw_r32(RTL839X_MAC_RX_PAUSE_STS + ((p >> 5) << 2)) & (1 << p)); + return (sw_r32(RTL839X_MAC_RX_PAUSE_STS + ((p >> 5) << 2)) & BIT(p % 32)); +} + +inline u32 rtl930x_get_mac_rx_pause_sts(int port) +{ + return (sw_r32(RTL930X_MAC_RX_PAUSE_STS) & (1 << port)); +} + +inline u32 rtl931x_get_mac_rx_pause_sts(int p) +{ + return (sw_r32(RTL931X_MAC_RX_PAUSE_STS + ((p >> 5) << 2)) & BIT(p % 32)); } inline u32 rtl838x_get_mac_tx_pause_sts(int port) @@ -246,21 +366,42 @@ inline u32 rtl838x_get_mac_tx_pause_sts(int port) inline u32 rtl839x_get_mac_tx_pause_sts(int p) { - return (sw_r32(RTL839X_MAC_TX_PAUSE_STS + ((p >> 5) << 2)) & (1 << p)); + return (sw_r32(RTL839X_MAC_TX_PAUSE_STS + ((p >> 5) << 2)) & BIT(p % 32)); } +inline u32 rtl930x_get_mac_tx_pause_sts(int port) +{ + return (sw_r32(RTL930X_MAC_TX_PAUSE_STS) & (1 << port)); +} + +inline u32 rtl931x_get_mac_tx_pause_sts(int p) +{ + return (sw_r32(RTL931X_MAC_TX_PAUSE_STS + ((p >> 5) << 2)) & BIT(p % 32)); +} + +struct p_hdr; +struct dsa_tag; struct rtl838x_reg { + irqreturn_t (*net_irq)(int irq, void *dev_id); int (*mac_port_ctrl)(int port); int dma_if_intr_sts; int dma_if_intr_msk; + int dma_if_intr_rx_runout_sts; + int dma_if_intr_rx_done_sts; + int dma_if_intr_tx_done_sts; + int dma_if_intr_rx_runout_msk; + int dma_if_intr_rx_done_msk; + int dma_if_intr_tx_done_msk; + int l2_ntfy_if_intr_sts; + int l2_ntfy_if_intr_msk; int dma_if_ctrl; - int (*mac_force_mode_ctrl)(int port); - int (*dma_rx_base)(int ring); - int (*dma_tx_base)(int ring); - int (*dma_if_rx_ring_size)(int ring); - int (*dma_if_rx_ring_cntr)(int ring); - int (*dma_if_rx_cur)(int ring); + int mac_force_mode_ctrl; + int dma_rx_base; + int dma_tx_base; + int (*dma_if_rx_ring_size)(int ring); + int (*dma_if_rx_ring_cntr)(int ring); + int dma_if_rx_cur; int rst_glb_ctrl; u32 (*get_mac_link_sts)(int port); u32 (*get_mac_link_dup_sts)(int port); @@ -269,11 +410,19 @@ struct rtl838x_reg { u32 (*get_mac_tx_pause_sts)(int port); int mac; int l2_tbl_flush_ctrl; + void (*update_cntr)(int r, int work_done); + void (*create_tx_header)(struct p_hdr *h, int dest_port, int prio); + bool (*decode_tag)(struct p_hdr *h, struct dsa_tag *tag); }; int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val); int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val); int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val); int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val); +int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val); +int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val); +int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val); +int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val); +void rtl9300_sds_power(int sds_num, int val); #endif /* _RTL838X_ETH_H */ From 6f67c079e61a01d599af34dbb852a4fe99d0f52d Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 15:16:24 +0100 Subject: [PATCH 20/29] realtek: add API for the hw tables of RTL83XX/93XX SoCs Add a table API that has per accss register locking and uses register description information to handle all table access through a single set of api calls. Signed-off-by: Birger Koblitz --- .../drivers/net/dsa/rtl83xx/common.c | 574 ++++++++++++++---- 1 file changed, 455 insertions(+), 119 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c index 1b57ddc92c..698f2892ea 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/common.c @@ -10,11 +10,14 @@ extern struct rtl83xx_soc_info soc_info; extern const struct rtl838x_reg rtl838x_reg; extern const struct rtl838x_reg rtl839x_reg; +extern const struct rtl838x_reg rtl930x_reg; +extern const struct rtl838x_reg rtl931x_reg; + extern const struct dsa_switch_ops rtl83xx_switch_ops; +extern const struct dsa_switch_ops rtl930x_switch_ops; DEFINE_MUTEX(smi_lock); - // TODO: unused static void dump_fdb(struct rtl838x_switch_priv *priv) { @@ -36,130 +39,237 @@ static void dump_fdb(struct rtl838x_switch_priv *priv) mutex_unlock(&priv->reg_mutex); } -// TODO: unused -static void rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port) +int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port) { - u32 cmd, msti = 0; + u32 msti = 0; u32 port_state[4]; - int index, bit, i; + int index, bit; int pos = port; - int n = priv->family_id == RTL8380_FAMILY_ID ? 2 : 4; + int n = priv->port_width << 1; - /* CPU PORT can only be configured on RTL838x */ - if (port >= priv->cpu_port || port > 51) - return; + /* Ports above or equal CPU port can never be configured */ + if (port >= priv->cpu_port) + return -1; mutex_lock(&priv->reg_mutex); - /* For the RTL839x, the bits are left-aligned in the 128 bit field */ + /* For the RTL839x and following, the bits are left-aligned in the 64/128 bit field */ if (priv->family_id == RTL8390_FAMILY_ID) pos += 12; + if (priv->family_id == RTL9300_FAMILY_ID) + pos += 3; + if (priv->family_id == RTL9310_FAMILY_ID) + pos += 8; index = n - (pos >> 4) - 1; bit = (pos << 1) % 32; - if (priv->family_id == RTL8380_FAMILY_ID) { - cmd = BIT(15) /* Execute cmd */ - | BIT(14) /* Read */ - | 2 << 12 /* Table type 0b10 */ - | (msti & 0xfff); - } else { - cmd = BIT(16) /* Execute cmd */ - | 0 << 15 /* Read */ - | 5 << 12 /* Table type 0b101 */ - | (msti & 0xfff); - } - priv->r->exec_tbl0_cmd(cmd); - - for (i = 0; i < n; i++) - port_state[i] = sw_r32(priv->r->tbl_access_data_0(i)); + priv->r->stp_get(priv, msti, port_state); mutex_unlock(&priv->reg_mutex); + + return (port_state[index] >> bit) & 3; } -int rtl83xx_dsa_phy_read(struct dsa_switch *ds, int phy_addr, int phy_reg) -{ - u32 val; - u32 offset = 0; - struct rtl838x_switch_priv *priv = ds->priv; +static struct table_reg rtl838x_tbl_regs[] = { + TBL_DESC(0x6900, 0x6908, 3, 15, 13, 1), // RTL8380_TBL_L2 + TBL_DESC(0x6914, 0x6918, 18, 14, 12, 1), // RTL8380_TBL_0 + TBL_DESC(0xA4C8, 0xA4CC, 6, 14, 12, 1), // RTL8380_TBL_1 - if (phy_addr >= 24 && phy_addr <= 27 - && priv->ports[24].phy == PHY_RTL838X_SDS) { - if (phy_addr == 26) - offset = 0x100; - val = sw_r32(MAPLE_SDS4_FIB_REG0r + offset + (phy_reg << 2)) & 0xffff; - return val; + TBL_DESC(0x1180, 0x1184, 3, 16, 14, 0), // RTL8390_TBL_L2 + TBL_DESC(0x1190, 0x1194, 17, 15, 12, 0), // RTL8390_TBL_0 + TBL_DESC(0x6B80, 0x6B84, 4, 14, 12, 0), // RTL8390_TBL_1 + TBL_DESC(0x611C, 0x6120, 9, 8, 6, 0), // RTL8390_TBL_2 + + TBL_DESC(0xB320, 0xB334, 3, 18, 16, 0), // RTL9300_TBL_L2 + TBL_DESC(0xB340, 0xB344, 19, 16, 12, 0), // RTL9300_TBL_0 + TBL_DESC(0xB3A0, 0xB3A4, 20, 16, 13, 0), // RTL9300_TBL_1 + TBL_DESC(0xCE04, 0xCE08, 6, 14, 12, 0), // RTL9300_TBL_2 + TBL_DESC(0xD600, 0xD604, 30, 7, 6, 0), // RTL9300_TBL_HSB + TBL_DESC(0x7880, 0x7884, 22, 9, 8, 0), // RTL9300_TBL_HSA + + TBL_DESC(0x8500, 0x8508, 8, 19, 15, 0), // RTL9310_TBL_0 + TBL_DESC(0x40C0, 0x40C4, 22, 16, 14, 0), // RTL9310_TBL_1 + TBL_DESC(0x8528, 0x852C, 6, 18, 14, 0), // RTL9310_TBL_2 + TBL_DESC(0x0200, 0x0204, 9, 15, 12, 0), // RTL9310_TBL_3 + TBL_DESC(0x20dc, 0x20e0, 29, 7, 6, 0), // RTL9310_TBL_4 + TBL_DESC(0x7e1c, 0x7e20, 53, 8, 6, 0), // RTL9310_TBL_5 +}; + +void rtl_table_init(void) +{ + int i; + + for (i = 0; i < RTL_TBL_END; i++) + mutex_init(&rtl838x_tbl_regs[i].lock); +} + +/* + * Request access to table t in table access register r + * Returns a handle to a lock for that table + */ +struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t) +{ + if (r >= RTL_TBL_END) + return NULL; + + if (t >= BIT(rtl838x_tbl_regs[r].c_bit-rtl838x_tbl_regs[r].t_bit)) + return NULL; + + mutex_lock(&rtl838x_tbl_regs[r].lock); + rtl838x_tbl_regs[r].tbl = t; + + return &rtl838x_tbl_regs[r]; +} + +/* + * Release a table r, unlock the corresponding lock + */ +void rtl_table_release(struct table_reg *r) +{ + if (!r) + return; + +// pr_info("Unlocking %08x\n", (u32)r); + mutex_unlock(&r->lock); +// pr_info("Unlock done\n"); +} + +/* + * Reads table index idx into the data registers of the table + */ +void rtl_table_read(struct table_reg *r, int idx) +{ + u32 cmd = r->rmode ? BIT(r->c_bit) : 0; + + cmd |= BIT(r->c_bit + 1) | (r->tbl << r->t_bit) | (idx & (BIT(r->t_bit) - 1)); + sw_w32(cmd, r->addr); + pr_debug("Writing %08x to %x for read\n", cmd, r->addr); + do { } while (sw_r32(r->addr) & BIT(r->c_bit + 1)); +} + +/* + * Writes the content of the table data registers into the table at index idx + */ +void rtl_table_write(struct table_reg *r, int idx) +{ + u32 cmd = r->rmode ? 0 : BIT(r->c_bit); + + cmd |= BIT(r->c_bit + 1) | (r->tbl << r->t_bit) | (idx & (BIT(r->t_bit) - 1)); + pr_debug("Writing %08x to %x for write, value %08x\n", + cmd, r->addr, sw_r32(0xb344)); + sw_w32(cmd, r->addr); + do { } while (sw_r32(r->addr) & BIT(r->c_bit + 1)); +} + +/* + * Returns the address of the ith data register of table register r + * the address is relative to the beginning of the Switch-IO block at 0xbb000000 + */ +inline u16 rtl_table_data(struct table_reg *r, int i) +{ + if (i >= r->max_data) + i = r->max_data - 1; + return r->data + i * 4; +} + +inline u32 rtl_table_data_r(struct table_reg *r, int i) +{ + return sw_r32(rtl_table_data(r, i)); +} + +inline void rtl_table_data_w(struct table_reg *r, u32 v, int i) +{ + sw_w32(v, rtl_table_data(r, i)); +} + +/* Port register accessor functions for the RTL838x and RTL930X SoCs */ +void rtl838x_mask_port_reg(u64 clear, u64 set, int reg) +{ + sw_w32_mask((u32)clear, (u32)set, reg); +} + +void rtl838x_set_port_reg(u64 set, int reg) +{ + sw_w32((u32)set, reg); +} + +u64 rtl838x_get_port_reg(int reg) +{ + return ((u64) sw_r32(reg)); +} + +/* Port register accessor functions for the RTL839x and RTL931X SoCs */ +void rtl839x_mask_port_reg_be(u64 clear, u64 set, int reg) +{ + sw_w32_mask((u32)(clear >> 32), (u32)(set >> 32), reg); + sw_w32_mask((u32)(clear & 0xffffffff), (u32)(set & 0xffffffff), reg + 4); +} + +u64 rtl839x_get_port_reg_be(int reg) +{ + u64 v = sw_r32(reg); + + v <<= 32; + v |= sw_r32(reg + 4); + return v; +} + +void rtl839x_set_port_reg_be(u64 set, int reg) +{ + sw_w32(set >> 32, reg); + sw_w32(set & 0xffffffff, reg + 4); +} + +void rtl839x_mask_port_reg_le(u64 clear, u64 set, int reg) +{ + sw_w32_mask((u32)clear, (u32)set, reg); + sw_w32_mask((u32)(clear >> 32), (u32)(set >> 32), reg + 4); +} + +void rtl839x_set_port_reg_le(u64 set, int reg) +{ + sw_w32(set, reg); + sw_w32(set >> 32, reg + 4); +} + +u64 rtl839x_get_port_reg_le(int reg) +{ + u64 v = sw_r32(reg + 4); + + v <<= 32; + v |= sw_r32(reg); + return v; +} + +int read_phy(u32 port, u32 page, u32 reg, u32 *val) +{ + switch (soc_info.family) { + case RTL8380_FAMILY_ID: + return rtl838x_read_phy(port, page, reg, val); + case RTL8390_FAMILY_ID: + return rtl839x_read_phy(port, page, reg, val); + case RTL9300_FAMILY_ID: + return rtl930x_read_phy(port, page, reg, val); + case RTL9310_FAMILY_ID: + return rtl931x_read_phy(port, page, reg, val); } - - if (soc_info.family == RTL8390_FAMILY_ID) - rtl839x_read_phy(phy_addr, 0, phy_reg, &val); - else - rtl838x_read_phy(phy_addr, 0, phy_reg, &val); - return val; + return -1; } -int rtl83xx_dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_reg, u16 val) +int write_phy(u32 port, u32 page, u32 reg, u32 val) { - u32 offset = 0; - struct rtl838x_switch_priv *priv = ds->priv; - - if (phy_addr >= 24 && phy_addr <= 27 - && priv->ports[24].phy == PHY_RTL838X_SDS) { - if (phy_addr == 26) - offset = 0x100; - sw_w32(val, MAPLE_SDS4_FIB_REG0r + offset + (phy_reg << 2)); - return 0; + switch (soc_info.family) { + case RTL8380_FAMILY_ID: + return rtl838x_write_phy(port, page, reg, val); + case RTL8390_FAMILY_ID: + return rtl839x_write_phy(port, page, reg, val); + case RTL9300_FAMILY_ID: + return rtl930x_write_phy(port, page, reg, val); + case RTL9310_FAMILY_ID: + return rtl931x_write_phy(port, page, reg, val); } - if (soc_info.family == RTL8390_FAMILY_ID) - return rtl839x_write_phy(phy_addr, 0, phy_reg, val); - else - return rtl838x_write_phy(phy_addr, 0, phy_reg, val); -} - -static int rtl83xx_mdio_read(struct mii_bus *bus, int addr, int regnum) -{ - int ret; - struct rtl838x_switch_priv *priv = bus->priv; - - ret = rtl83xx_dsa_phy_read(priv->ds, addr, regnum); - return ret; -} - -static int rtl83xx_mdio_write(struct mii_bus *bus, int addr, int regnum, - u16 val) -{ - struct rtl838x_switch_priv *priv = bus->priv; - - return rtl83xx_dsa_phy_write(priv->ds, addr, regnum, val); -} - -static void rtl8380_sds_rst(int mac) -{ - u32 offset = (mac == 24) ? 0 : 0x100; - - sw_w32_mask(1 << 11, 0, RTL8380_SDS4_FIB_REG0 + offset); - sw_w32_mask(0x3, 0, RTL838X_SDS4_REG28 + offset); - sw_w32_mask(0x3, 0x3, RTL838X_SDS4_REG28 + offset); - sw_w32_mask(0, 0x1 << 6, RTL838X_SDS4_DUMMY0 + offset); - sw_w32_mask(0x1 << 6, 0, RTL838X_SDS4_DUMMY0 + offset); - pr_debug("SERDES reset: %d\n", mac); -} - -static int __init rtl8380_sds_power(int mac, int val) -{ - u32 mode = (val == 1) ? 0x4 : 0x9; - u32 offset = (mac == 24) ? 5 : 0; - - if ((mac != 24) && (mac != 26)) { - pr_err("%s: not a fibre port: %d\n", __func__, mac); - return -1; - } - - sw_w32_mask(0x1f << offset, mode << offset, RTL838X_SDS_MODE_SEL); - - rtl8380_sds_rst(mac); - - return 0; + return -1; } static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) @@ -192,9 +302,15 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) return -ENOMEM; bus->name = "rtl838x slave mii"; - bus->read = &rtl83xx_mdio_read; - bus->write = &rtl83xx_mdio_write; + + /* + * Since the NIC driver is loaded first, we can use the mdio rw functions + * assigned there. + */ + bus->read = priv->mii_bus->read; + bus->write = priv->mii_bus->write; snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", bus->name, dev->id); + bus->parent = dev; priv->ds->slave_mii_bus = bus; priv->ds->slave_mii_bus->priv = priv; @@ -239,6 +355,14 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) } } + // TODO: Do this needs to come from the .dts, at least the SerDes number + if (priv->family_id == RTL9300_FAMILY_ID) { + priv->ports[24].is2G5 = true; + priv->ports[25].is2G5 = true; + priv->ports[24].sds_num = 1; + priv->ports[24].sds_num = 2; + } + /* Disable MAC polling the PHY so that we can start configuration */ priv->r->set_port_reg_le(0ULL, priv->r->smi_poll_ctrl); @@ -258,6 +382,15 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) rtl8380_sds_power(26, 1); } + // TODO: Only power on SerDes with external PHYs connected + if (priv->family_id == RTL9300_FAMILY_ID) { + pr_info("RTL9300 Powering on SerDes ports\n"); + rtl9300_sds_power(24, 1); + rtl9300_sds_power(25, 1); + rtl9300_sds_power(26, 1); + rtl9300_sds_power(27, 1); + } + pr_debug("%s done\n", __func__); return 0; } @@ -278,12 +411,152 @@ static int __init rtl83xx_get_l2aging(struct rtl838x_switch_priv *priv) return t; } +/* Caller must hold priv->reg_mutex */ +int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port) +{ + struct rtl838x_switch_priv *priv = ds->priv; + int i; + + pr_info("%s: Adding port %d to LA-group %d\n", __func__, port, group); + if (group >= priv->n_lags) { + pr_err("Link Agrregation group too large.\n"); + return -EINVAL; + } + + if (port >= priv->cpu_port) { + pr_err("Invalid port number.\n"); + return -EINVAL; + } + + for (i = 0; i < priv->n_lags; i++) { + if (priv->lags_port_members[i] & BIT_ULL(i)) + break; + } + if (i != priv->n_lags) { + pr_err("%s: Port already member of LAG: %d\n", __func__, i); + return -ENOSPC; + } + + priv->r->mask_port_reg_be(0, BIT_ULL(port), priv->r->trk_mbr_ctr(group)); + priv->lags_port_members[group] |= BIT_ULL(port); + + pr_info("lags_port_members %d now %016llx\n", group, priv->lags_port_members[group]); + return 0; +} + +/* Caller must hold priv->reg_mutex */ +int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port) +{ + struct rtl838x_switch_priv *priv = ds->priv; + + pr_info("%s: Removing port %d from LA-group %d\n", __func__, port, group); + + if (group >= priv->n_lags) { + pr_err("Link Agrregation group too large.\n"); + return -EINVAL; + } + + if (port >= priv->cpu_port) { + pr_err("Invalid port number.\n"); + return -EINVAL; + } + + + if (!(priv->lags_port_members[group] & BIT_ULL(port))) { + pr_err("%s: Port not member of LAG: %d\n", __func__, group + ); + return -ENOSPC; + } + + priv->r->mask_port_reg_be(BIT_ULL(port), 0, priv->r->trk_mbr_ctr(group)); + priv->lags_port_members[group] &= ~BIT_ULL(port); + + pr_info("lags_port_members %d now %016llx\n", group, priv->lags_port_members[group]); + return 0; +} + +static int rtl83xx_handle_changeupper(struct rtl838x_switch_priv *priv, + struct net_device *ndev, + struct netdev_notifier_changeupper_info *info) +{ + struct net_device *upper = info->upper_dev; + int i, j, err; + + if (!netif_is_lag_master(upper)) + return 0; + + mutex_lock(&priv->reg_mutex); + + for (i = 0; i < priv->n_lags; i++) { + if ((!priv->lag_devs[i]) || (priv->lag_devs[i] == upper)) + break; + } + for (j = 0; j < priv->cpu_port; j++) { + if (priv->ports[j].dp->slave == ndev) + break; + } + if (j >= priv->cpu_port) { + err = -EINVAL; + goto out; + } + + if (info->linking) { + if (!priv->lag_devs[i]) + priv->lag_devs[i] = upper; + err = rtl83xx_lag_add(priv->ds, i, priv->ports[j].dp->index); + if (err) { + err = -EINVAL; + goto out; + } + } else { + if (!priv->lag_devs[i]) + err = -EINVAL; + err = rtl83xx_lag_del(priv->ds, i, priv->ports[j].dp->index); + if (err) { + err = -EINVAL; + goto out; + } + if (!priv->lags_port_members[i]) + priv->lag_devs[i] = NULL; + } + +out: + mutex_unlock(&priv->reg_mutex); + return 0; +} + +static int rtl83xx_netdevice_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + struct rtl838x_switch_priv *priv; + int err; + + pr_debug("In: %s, event: %lu\n", __func__, event); + + if ((event != NETDEV_CHANGEUPPER) && (event != NETDEV_CHANGELOWERSTATE)) + return NOTIFY_DONE; + + priv = container_of(this, struct rtl838x_switch_priv, nb); + switch (event) { + case NETDEV_CHANGEUPPER: + err = rtl83xx_handle_changeupper(priv, ndev, ptr); + break; + } + + if (err) + return err; + + return NOTIFY_DONE; +} + static int __init rtl83xx_sw_probe(struct platform_device *pdev) { int err = 0, i; struct rtl838x_switch_priv *priv; struct device *dev = &pdev->dev; u64 irq_mask; + u64 bpdu_mask; pr_debug("Probing RTL838X switch device\n"); if (!pdev->dev.of_node) { @@ -291,6 +564,9 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev) return -EINVAL; } + // Initialize access to RTL switch tables + rtl_table_init(); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -306,20 +582,56 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev) priv->family_id = soc_info.family; priv->id = soc_info.id; - if (soc_info.family == RTL8380_FAMILY_ID) { + switch(soc_info.family) { + case RTL8380_FAMILY_ID: + priv->ds->ops = &rtl83xx_switch_ops; priv->cpu_port = RTL838X_CPU_PORT; priv->port_mask = 0x1f; + priv->port_width = 1; + priv->irq_mask = 0x0FFFFFFF; priv->r = &rtl838x_reg; - priv->ds->num_ports = 30; + priv->ds->num_ports = 29; priv->fib_entries = 8192; rtl8380_get_version(priv); - } else { + priv->n_lags = 8; + break; + case RTL8390_FAMILY_ID: + priv->ds->ops = &rtl83xx_switch_ops; priv->cpu_port = RTL839X_CPU_PORT; priv->port_mask = 0x3f; + priv->port_width = 2; + priv->irq_mask = 0xFFFFFFFFFFFFFULL; priv->r = &rtl839x_reg; priv->ds->num_ports = 53; priv->fib_entries = 16384; rtl8390_get_version(priv); + priv->n_lags = 16; + break; + case RTL9300_FAMILY_ID: + priv->ds->ops = &rtl930x_switch_ops; + priv->cpu_port = RTL930X_CPU_PORT; + priv->port_mask = 0x1f; + priv->port_width = 1; + priv->irq_mask = 0x0FFFFFFF; + priv->r = &rtl930x_reg; + priv->ds->num_ports = 29; + priv->fib_entries = 16384; + priv->version = RTL8390_VERSION_A; + priv->n_lags = 16; + sw_w32(1, RTL930X_ST_CTRL); + break; + case RTL9310_FAMILY_ID: + priv->ds->ops = &rtl930x_switch_ops; + priv->cpu_port = RTL931X_CPU_PORT; + priv->port_mask = 0x3f; + priv->port_width = 2; + priv->irq_mask = 0xFFFFFFFFFFFFFULL; + priv->r = &rtl931x_reg; + priv->ds->num_ports = 57; + priv->fib_entries = 16384; + priv->version = RTL8390_VERSION_A; + priv->n_lags = 16; + break; } pr_debug("Chip version %c\n", priv->version); @@ -338,39 +650,63 @@ static int __init rtl83xx_sw_probe(struct platform_device *pdev) /* Enable link and media change interrupts. Are the SERDES masks needed? */ sw_w32_mask(0, 3, priv->r->isr_glb_src); - /* ... for all ports */ - irq_mask = soc_info.family == RTL8380_FAMILY_ID ? 0x0FFFFFFF : 0xFFFFFFFFFFFFFULL; + priv->r->set_port_reg_le(irq_mask, priv->r->isr_port_link_sts_chg); priv->r->set_port_reg_le(irq_mask, priv->r->imr_port_link_sts_chg); - priv->link_state_irq = platform_get_irq(pdev, 0);; - if (priv->family_id == RTL8380_FAMILY_ID) { + priv->link_state_irq = platform_get_irq(pdev, 0); + pr_info("LINK state irq: %d\n", priv->link_state_irq); + switch (priv->family_id) { + case RTL8380_FAMILY_ID: err = request_irq(priv->link_state_irq, rtl838x_switch_irq, IRQF_SHARED, "rtl838x-link-state", priv->ds); - } else { + break; + case RTL8390_FAMILY_ID: err = request_irq(priv->link_state_irq, rtl839x_switch_irq, IRQF_SHARED, "rtl839x-link-state", priv->ds); + break; + case RTL9300_FAMILY_ID: + err = request_irq(priv->link_state_irq, rtl930x_switch_irq, + IRQF_SHARED, "rtl930x-link-state", priv->ds); + break; + case RTL9310_FAMILY_ID: + err = request_irq(priv->link_state_irq, rtl931x_switch_irq, + IRQF_SHARED, "rtl931x-link-state", priv->ds); + break; } if (err) { dev_err(dev, "Error setting up switch interrupt.\n"); /* Need to free allocated switch here */ } - /* Enable interrupts for switch */ - sw_w32(0x1, priv->r->imr_glb); + /* Enable interrupts for switch, on RTL931x, the IRQ is always on globally */ + if (soc_info.family != RTL9310_FAMILY_ID) + sw_w32(0x1, priv->r->imr_glb); rtl83xx_get_l2aging(priv); -/* - if (priv->family_id == RTL8380_FAMILY_ID) - rtl83xx_storm_control_init(priv); -*/ + rtl83xx_setup_qos(priv); /* Clear all destination ports for mirror groups */ for (i = 0; i < 4; i++) priv->mirror_group_ports[i] = -1; - rtl838x_dbgfs_init(priv); + priv->nb.notifier_call = rtl83xx_netdevice_event; + if (register_netdevice_notifier(&priv->nb)) { + priv->nb.notifier_call = NULL; + dev_err(dev, "Failed to register LAG netdev notifier\n"); + } + + // Flood BPDUs to all ports including cpu-port + if (soc_info.family != RTL9300_FAMILY_ID) { // TODO: Port this functionality + bpdu_mask = soc_info.family == RTL8380_FAMILY_ID ? 0x1FFFFFFF : 0x1FFFFFFFFFFFFF; + priv->r->set_port_reg_be(bpdu_mask, priv->r->rma_bpdu_fld_pmask); + + // TRAP 802.1X frames (EAPOL) to the CPU-Port, bypass STP and VLANs + sw_w32(7, priv->r->spcl_trap_eapol_ctrl); + + rtl838x_dbgfs_init(priv); + } return err; } From 1b1bb6bf19ff1ae4d31910f2326404597a7e8470 Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 15:18:24 +0100 Subject: [PATCH 21/29] realtek: add debugfs support for mirroring This adds debugfs support to monitor mirroring via debugfs Signed-off-by: Birger Koblitz --- .../drivers/net/dsa/rtl83xx/debugfs.c | 405 +++++++++++++++++- 1 file changed, 391 insertions(+), 14 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c index af24e8fa42..4f81408453 100644 --- a/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c +++ b/target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/debugfs.c @@ -1,12 +1,219 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include -#include "rtl838x.h" +#include "rtl83xx.h" #define RTL838X_DRIVER_NAME "rtl838x" +#define RTL8380_LED_GLB_CTRL (0xA000) +#define RTL8380_LED_MODE_SEL (0x1004) +#define RTL8380_LED_MODE_CTRL (0xA004) +#define RTL8380_LED_P_EN_CTRL (0xA008) +#define RTL8380_LED_SW_CTRL (0xA00C) +#define RTL8380_LED0_SW_P_EN_CTRL (0xA010) +#define RTL8380_LED1_SW_P_EN_CTRL (0xA014) +#define RTL8380_LED2_SW_P_EN_CTRL (0xA018) +#define RTL8380_LED_SW_P_CTRL(p) (0xA01C + (((p) << 2))) + +#define RTL8390_LED_GLB_CTRL (0x00E4) +#define RTL8390_LED_SET_2_3_CTRL (0x00E8) +#define RTL8390_LED_SET_0_1_CTRL (0x00EC) +#define RTL8390_LED_COPR_SET_SEL_CTRL(p) (0x00F0 + (((p >> 4) << 2))) +#define RTL8390_LED_FIB_SET_SEL_CTRL(p) (0x0100 + (((p >> 4) << 2))) +#define RTL8390_LED_COPR_PMASK_CTRL(p) (0x0110 + (((p >> 5) << 2))) +#define RTL8390_LED_FIB_PMASK_CTRL(p) (0x00118 + (((p >> 5) << 2))) +#define RTL8390_LED_COMBO_CTRL(p) (0x0120 + (((p >> 5) << 2))) +#define RTL8390_LED_SW_CTRL (0x0128) +#define RTL8390_LED_SW_P_EN_CTRL(p) (0x012C + (((p / 10) << 2))) +#define RTL8390_LED_SW_P_CTRL(p) (0x0144 + (((p) << 2))) + +#define RTL838X_MIR_QID_CTRL(grp) (0xAD44 + (((grp) << 2))) +#define RTL838X_MIR_RSPAN_VLAN_CTRL(grp) (0xA340 + (((grp) << 2))) +#define RTL838X_MIR_RSPAN_VLAN_CTRL_MAC(grp) (0xAA70 + (((grp) << 2))) +#define RTL838X_MIR_RSPAN_TX_CTRL (0xA350) +#define RTL838X_MIR_RSPAN_TX_TAG_RM_CTRL (0xAA80) +#define RTL838X_MIR_RSPAN_TX_TAG_EN_CTRL (0xAA84) +#define RTL839X_MIR_RSPAN_VLAN_CTRL(grp) (0xA340 + (((grp) << 2))) +#define RTL839X_MIR_RSPAN_TX_CTRL (0x69b0) +#define RTL839X_MIR_RSPAN_TX_TAG_RM_CTRL (0x2550) +#define RTL839X_MIR_RSPAN_TX_TAG_EN_CTRL (0x2554) +#define RTL839X_MIR_SAMPLE_RATE_CTRL (0x2558) + +int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port); +void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); +void rtl83xx_fast_age(struct dsa_switch *ds, int port); +u32 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port); +u32 rtl839x_get_egress_rate(struct rtl838x_switch_priv *priv, int port); +int rtl838x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate); +int rtl839x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate); + +static ssize_t rtl838x_common_read(char __user *buffer, size_t count, + loff_t *ppos, unsigned int value) +{ + char *buf; + ssize_t len; + + if (*ppos != 0) + return 0; + + buf = kasprintf(GFP_KERNEL, "0x%08x\n", value); + if (!buf) + return -ENOMEM; + + if (count < strlen(buf)) { + kfree(buf); + return -ENOSPC; + } + + len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); + kfree(buf); + + return len; +} + +static ssize_t rtl838x_common_write(const char __user *buffer, size_t count, + loff_t *ppos, unsigned int *value) +{ + char b[32]; + ssize_t len; + int ret; + + if (*ppos != 0) + return -EINVAL; + + if (count >= sizeof(b)) + return -ENOSPC; + + len = simple_write_to_buffer(b, sizeof(b) - 1, ppos, + buffer, count); + if (len < 0) + return len; + + b[len] = '\0'; + ret = kstrtouint(b, 16, value); + if (ret) + return -EIO; + + return len; +} + +static ssize_t stp_state_read(struct file *filp, char __user *buffer, size_t count, + loff_t *ppos) +{ + struct rtl838x_port *p = filp->private_data; + struct dsa_switch *ds = p->dp->ds; + int value = rtl83xx_port_get_stp_state(ds->priv, p->dp->index); + + if (value < 0) + return -EINVAL; + + return rtl838x_common_read(buffer, count, ppos, (u32)value); +} + +static ssize_t stp_state_write(struct file *filp, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct rtl838x_port *p = filp->private_data; + u32 value; + size_t res = rtl838x_common_write(buffer, count, ppos, &value); + if (res < 0) + return res; + + rtl83xx_port_stp_state_set(p->dp->ds, p->dp->index, (u8)value); + + return res; +} + +static const struct file_operations stp_state_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = stp_state_read, + .write = stp_state_write, +}; + +static ssize_t age_out_read(struct file *filp, char __user *buffer, size_t count, + loff_t *ppos) +{ + struct rtl838x_port *p = filp->private_data; + struct dsa_switch *ds = p->dp->ds; + struct rtl838x_switch_priv *priv = ds->priv; + int value = sw_r32(priv->r->l2_port_aging_out); + + if (value < 0) + return -EINVAL; + + return rtl838x_common_read(buffer, count, ppos, (u32)value); +} + +static ssize_t age_out_write(struct file *filp, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct rtl838x_port *p = filp->private_data; + u32 value; + size_t res = rtl838x_common_write(buffer, count, ppos, &value); + if (res < 0) + return res; + + rtl83xx_fast_age(p->dp->ds, p->dp->index); + + return res; +} + +static const struct file_operations age_out_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = age_out_read, + .write = age_out_write, +}; + +static ssize_t port_egress_rate_read(struct file *filp, char __user *buffer, size_t count, + loff_t *ppos) +{ + struct rtl838x_port *p = filp->private_data; + struct dsa_switch *ds = p->dp->ds; + struct rtl838x_switch_priv *priv = ds->priv; + int value; + if (priv->family_id == RTL8380_FAMILY_ID) + value = rtl838x_get_egress_rate(priv, p->dp->index); + else + value = rtl839x_get_egress_rate(priv, p->dp->index); + + if (value < 0) + return -EINVAL; + + return rtl838x_common_read(buffer, count, ppos, (u32)value); +} + +static ssize_t port_egress_rate_write(struct file *filp, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct rtl838x_port *p = filp->private_data; + struct dsa_switch *ds = p->dp->ds; + struct rtl838x_switch_priv *priv = ds->priv; + u32 value; + size_t res = rtl838x_common_write(buffer, count, ppos, &value); + if (res < 0) + return res; + + if (priv->family_id == RTL8380_FAMILY_ID) + rtl838x_set_egress_rate(priv, p->dp->index, value); + else + rtl839x_set_egress_rate(priv, p->dp->index, value); + + return res; +} + +static const struct file_operations port_egress_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = port_egress_rate_read, + .write = port_egress_rate_write, +}; + + static const struct debugfs_reg32 port_ctrl_regs[] = { { .name = "port_isolation", .offset = RTL838X_PORT_ISO_CTRL(0), }, { .name = "mac_force_mode", .offset = RTL838X_MAC_FORCE_MODE_CTRL, }, @@ -27,20 +234,35 @@ static int rtl838x_dbgfs_port_init(struct dentry *parent, struct rtl838x_switch_ port_dir = debugfs_create_dir(priv->ports[port].dp->name, parent); - debugfs_create_x32("rate_uc", 0644, port_dir, - (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_UC(port))); + if (priv->family_id == RTL8380_FAMILY_ID) { + debugfs_create_x32("storm_rate_uc", 0644, port_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_UC(port))); - debugfs_create_x32("rate_mc", 0644, port_dir, - (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_BC(port))); + debugfs_create_x32("storm_rate_mc", 0644, port_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_MC(port))); - debugfs_create_x32("rate_bc", 0644, port_dir, - (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_BC(port))); + debugfs_create_x32("storm_rate_bc", 0644, port_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_BC(port))); - debugfs_create_u32("id", 0444, port_dir, &priv->ports[port].dp->index); + debugfs_create_x32("vlan_port_tag_sts_ctrl", 0644, port_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_VLAN_PORT_TAG_STS_CTRL + + (port << 2))); + } else { + debugfs_create_x32("storm_rate_uc", 0644, port_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_UC_0(port))); + debugfs_create_x32("storm_rate_mc", 0644, port_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_MC_0(port))); - debugfs_create_x32("vlan_port_tag_sts_ctrl", 0644, port_dir, - (u32 *)(RTL838X_SW_BASE + RTL838X_VLAN_PORT_TAG_STS_CTRL(port))); + debugfs_create_x32("storm_rate_bc", 0644, port_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_BC_0(port))); + + debugfs_create_x32("vlan_port_tag_sts_ctrl", 0644, port_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_VLAN_PORT_TAG_STS_CTRL + + (port << 2))); + } + + debugfs_create_u32("id", 0444, port_dir, (u32 *)&priv->ports[port].dp->index); port_ctrl_regset = devm_kzalloc(priv->dev, sizeof(*port_ctrl_regset), GFP_KERNEL); if (!port_ctrl_regset) @@ -48,9 +270,88 @@ static int rtl838x_dbgfs_port_init(struct dentry *parent, struct rtl838x_switch_ port_ctrl_regset->regs = port_ctrl_regs; port_ctrl_regset->nregs = ARRAY_SIZE(port_ctrl_regs); - port_ctrl_regset->base = RTL838X_SW_BASE + (port << 2); + port_ctrl_regset->base = (void *)(RTL838X_SW_BASE + (port << 2)); debugfs_create_regset32("port_ctrl", 0400, port_dir, port_ctrl_regset); + debugfs_create_file("stp_state", 0600, port_dir, &priv->ports[port], &stp_state_fops); + debugfs_create_file("age_out", 0600, port_dir, &priv->ports[port], &age_out_fops); + debugfs_create_file("port_egress_rate", 0600, port_dir, &priv->ports[port], + &port_egress_fops); + return 0; +} + +static int rtl838x_dbgfs_leds(struct dentry *parent, struct rtl838x_switch_priv *priv) +{ + struct dentry *led_dir; + int p; + char led_sw_p_ctrl_name[20]; + char port_led_name[20]; + + led_dir = debugfs_create_dir("led", parent); + + if (priv->family_id == RTL8380_FAMILY_ID) { + debugfs_create_x32("led_glb_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED_GLB_CTRL)); + debugfs_create_x32("led_mode_sel", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED_MODE_SEL)); + debugfs_create_x32("led_mode_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED_MODE_CTRL)); + debugfs_create_x32("led_p_en_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED_P_EN_CTRL)); + debugfs_create_x32("led_sw_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED_SW_CTRL)); + debugfs_create_x32("led0_sw_p_en_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED0_SW_P_EN_CTRL)); + debugfs_create_x32("led1_sw_p_en_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED1_SW_P_EN_CTRL)); + debugfs_create_x32("led2_sw_p_en_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED2_SW_P_EN_CTRL)); + for (p = 0; p < 28; p++) { + snprintf(led_sw_p_ctrl_name, sizeof(led_sw_p_ctrl_name), + "led_sw_p_ctrl.%02d", p); + debugfs_create_x32(led_sw_p_ctrl_name, 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8380_LED_SW_P_CTRL(p))); + } + } else if (priv->family_id == RTL8390_FAMILY_ID) { + debugfs_create_x32("led_glb_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_GLB_CTRL)); + debugfs_create_x32("led_set_2_3", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SET_2_3_CTRL)); + debugfs_create_x32("led_set_0_1", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SET_0_1_CTRL)); + for (p = 0; p < 4; p++) { + snprintf(port_led_name, sizeof(port_led_name), "led_copr_set_sel.%1d", p); + debugfs_create_x32(port_led_name, 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_SET_SEL_CTRL(p << 4))); + snprintf(port_led_name, sizeof(port_led_name), "led_fib_set_sel.%1d", p); + debugfs_create_x32(port_led_name, 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_SET_SEL_CTRL(p << 4))); + } + debugfs_create_x32("led_copr_pmask_ctrl_0", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_PMASK_CTRL(0))); + debugfs_create_x32("led_copr_pmask_ctrl_1", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_PMASK_CTRL(32))); + debugfs_create_x32("led_fib_pmask_ctrl_0", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_PMASK_CTRL(0))); + debugfs_create_x32("led_fib_pmask_ctrl_1", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_PMASK_CTRL(32))); + debugfs_create_x32("led_combo_ctrl_0", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COMBO_CTRL(0))); + debugfs_create_x32("led_combo_ctrl_1", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_COMBO_CTRL(32))); + debugfs_create_x32("led_sw_ctrl", 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_CTRL)); + for (p = 0; p < 5; p++) { + snprintf(port_led_name, sizeof(port_led_name), "led_sw_p_en_ctrl.%1d", p); + debugfs_create_x32(port_led_name, 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_P_EN_CTRL(p * 10))); + } + for (p = 0; p < 28; p++) { + snprintf(port_led_name, sizeof(port_led_name), "led_sw_p_ctrl.%02d", p); + debugfs_create_x32(port_led_name, 0644, led_dir, + (u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_P_CTRL(p))); + } + } return 0; } @@ -58,9 +359,13 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv) { struct dentry *rtl838x_dir; struct dentry *port_dir; + struct dentry *mirror_dir; struct debugfs_regset32 *port_ctrl_regset; int ret, i; + char lag_name[10]; + char mirror_name[10]; + pr_info("%s called\n", __func__); rtl838x_dir = debugfs_lookup(RTL838X_DRIVER_NAME, NULL); if (!rtl838x_dir) rtl838x_dir = debugfs_create_dir(RTL838X_DRIVER_NAME, NULL); @@ -73,7 +378,6 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv) /* Create one directory per port */ for (i = 0; i < priv->cpu_port; i++) { if (priv->ports[i].phy) { - pr_debug("debugfs, port %d\n", i); ret = rtl838x_dbgfs_port_init(rtl838x_dir, priv, i); if (ret) goto err; @@ -81,7 +385,8 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv) } /* Create directory for CPU-port */ - port_dir = debugfs_create_dir("cpu_port", rtl838x_dir); port_ctrl_regset = devm_kzalloc(priv->dev, sizeof(*port_ctrl_regset), GFP_KERNEL); + port_dir = debugfs_create_dir("cpu_port", rtl838x_dir); + port_ctrl_regset = devm_kzalloc(priv->dev, sizeof(*port_ctrl_regset), GFP_KERNEL); if (!port_ctrl_regset) { ret = -ENOMEM; goto err; @@ -89,10 +394,82 @@ void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv) port_ctrl_regset->regs = port_ctrl_regs; port_ctrl_regset->nregs = ARRAY_SIZE(port_ctrl_regs); - port_ctrl_regset->base = RTL838X_SW_BASE + (priv->cpu_port << 2); + port_ctrl_regset->base = (void *)(RTL838X_SW_BASE + (priv->cpu_port << 2)); debugfs_create_regset32("port_ctrl", 0400, port_dir, port_ctrl_regset); debugfs_create_u8("id", 0444, port_dir, &priv->cpu_port); + /* Create entries for LAGs */ + for (i = 0; i < priv->n_lags; i++) { + snprintf(lag_name, sizeof(lag_name), "lag.%02d", i); + if (priv->family_id == RTL8380_FAMILY_ID) + debugfs_create_x32(lag_name, 0644, rtl838x_dir, + (u32 *)(RTL838X_SW_BASE + priv->r->trk_mbr_ctr(i))); + else + debugfs_create_x64(lag_name, 0644, rtl838x_dir, + (u64 *)(RTL838X_SW_BASE + priv->r->trk_mbr_ctr(i))); + } + + /* Create directories for mirror groups */ + for (i = 0; i < 4; i++) { + snprintf(mirror_name, sizeof(mirror_name), "mirror.%1d", i); + mirror_dir = debugfs_create_dir(mirror_name, rtl838x_dir); + if (priv->family_id == RTL8380_FAMILY_ID) { + debugfs_create_x32("ctrl", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_CTRL + i * 4)); + debugfs_create_x32("ingress_pm", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + priv->r->mir_spm + i * 4)); + debugfs_create_x32("egress_pm", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + priv->r->mir_dpm + i * 4)); + debugfs_create_x32("qid", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_QID_CTRL(i))); + debugfs_create_x32("rspan_vlan", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_VLAN_CTRL(i))); + debugfs_create_x32("rspan_vlan_mac", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_VLAN_CTRL_MAC(i))); + debugfs_create_x32("rspan_tx", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_CTRL)); + debugfs_create_x32("rspan_tx_tag_rm", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_TAG_RM_CTRL)); + debugfs_create_x32("rspan_tx_tag_en", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_TAG_EN_CTRL)); + } else { + debugfs_create_x32("ctrl", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_CTRL + i * 4)); + debugfs_create_x64("ingress_pm", 0644, mirror_dir, + (u64 *)(RTL838X_SW_BASE + priv->r->mir_spm + i * 8)); + debugfs_create_x64("egress_pm", 0644, mirror_dir, + (u64 *)(RTL838X_SW_BASE + priv->r->mir_dpm + i * 8)); + debugfs_create_x32("rspan_vlan", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_VLAN_CTRL(i))); + debugfs_create_x32("rspan_tx", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_CTRL)); + debugfs_create_x32("rspan_tx_tag_rm", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_TAG_RM_CTRL)); + debugfs_create_x32("rspan_tx_tag_en", 0644, mirror_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_TAG_EN_CTRL)); + debugfs_create_x64("sample_rate", 0644, mirror_dir, + (u64 *)(RTL838X_SW_BASE + RTL839X_MIR_SAMPLE_RATE_CTRL)); + } + } + + if (priv->family_id == RTL8380_FAMILY_ID) + debugfs_create_x32("bpdu_flood_mask", 0644, rtl838x_dir, + (u32 *)(RTL838X_SW_BASE + priv->r->rma_bpdu_fld_pmask)); + else + debugfs_create_x64("bpdu_flood_mask", 0644, rtl838x_dir, + (u64 *)(RTL838X_SW_BASE + priv->r->rma_bpdu_fld_pmask)); + + if (priv->family_id == RTL8380_FAMILY_ID) + debugfs_create_x32("vlan_ctrl", 0644, rtl838x_dir, + (u32 *)(RTL838X_SW_BASE + RTL838X_VLAN_CTRL)); + else + debugfs_create_x32("vlan_ctrl", 0644, rtl838x_dir, + (u32 *)(RTL838X_SW_BASE + RTL839X_VLAN_CTRL)); + + ret = rtl838x_dbgfs_leds(rtl838x_dir, priv); + if (ret) + goto err; + return; err: rtl838x_dbgfs_cleanup(priv); From 1fdbb8779aab8d64263ea4f5302175bdedfb7bfe Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 25 Jan 2021 18:22:30 +0100 Subject: [PATCH 22/29] mac80211: remove accidentally duplicated line in minstrel_ht patch Signed-off-by: Felix Fietkau --- ...0-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch b/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch index 41910e0d18..041ba31a37 100644 --- a/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch +++ b/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch @@ -48,11 +48,10 @@ Signed-off-by: Felix Fietkau p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); for (i = 0; i < MINSTREL_CCK_GROUP; i++) -@@ -228,6 +241,8 @@ minstrel_ht_stats_csv_dump(struct minstr +@@ -228,6 +241,7 @@ minstrel_ht_stats_csv_dump(struct minstr p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[2]) ? "C" : "")); p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[3]) ? "D" : "")); p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : "")); -+ p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : "")); + p += sprintf(p, "%s", (minstrel_ht_is_sample_rate(mi, idx) ? "S" : "")); if (gflags & IEEE80211_TX_RC_MCS) { From 56c20f0a5ab037ba7dee71ce3d7e05197b2cccf7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 26 Jan 2021 16:46:19 +0100 Subject: [PATCH 23/29] mac80211: minstrel_ht: fix regression in the max_prob_rate fix Signed-off-by: Felix Fietkau --- ...l_ht-fix-regression-in-the-max_prob_.patch | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch diff --git a/package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch b/package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch new file mode 100644 index 0000000000..a366a921d4 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch @@ -0,0 +1,23 @@ +From: Felix Fietkau +Date: Tue, 26 Jan 2021 16:40:52 +0100 +Subject: [PATCH] mac80211: minstrel_ht: fix regression in the max_prob_rate + fix + +Since mi->max_prob_rate is overwritten after the loop that calls +minstrel_ht_set_best_prob_rate, the new best rate needs to be written to *dest + +Fixes: a7fca4e4037f ("mac80211: minstrel_ht: fix max probability rate selection") +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -545,7 +545,7 @@ minstrel_ht_set_best_prob_rate(struct mi + cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, + mrs->prob_avg); + if (cur_tp_avg > tmp_tp_avg) +- mi->max_prob_rate = index; ++ *dest = index; + + max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group, + max_gpr_idx, From 7ca75a2d01a10711e58a92ae4ed747e23c030814 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 26 Jan 2021 19:25:10 +0100 Subject: [PATCH 24/29] mac80211: fix an uninitialized variable warning Signed-off-by: Felix Fietkau --- ...l_ht-use-bitfields-to-encode-rate-in.patch | 39 ++++++++++--------- ...l_ht-update-total-packets-counter-in.patch | 6 +-- ...l_ht-reduce-the-need-to-sample-slowe.patch | 10 ++--- ...l_ht-significantly-redesign-the-rate.patch | 24 ++++++------ ...l_ht-remove-sample-rate-switching-co.patch | 20 +++++----- 5 files changed, 51 insertions(+), 48 deletions(-) diff --git a/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch b/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch index a17725d69b..6aa6f0ed93 100644 --- a/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch +++ b/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch @@ -172,11 +172,12 @@ Signed-off-by: Felix Fietkau for (i = 0; supported; supported >>= 1, i++) { if (!(supported & 1)) continue; -@@ -856,22 +856,26 @@ minstrel_ht_update_stats(struct minstrel +@@ -854,24 +854,27 @@ minstrel_ht_update_stats(struct minstrel + mi->sample_slow = 0; + mi->sample_count = 0; - memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); - memset(tmp_legacy_tp_rate, 0, sizeof(tmp_legacy_tp_rate)); -+ +- memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); +- memset(tmp_legacy_tp_rate, 0, sizeof(tmp_legacy_tp_rate)); if (mi->supported[MINSTREL_CCK_GROUP]) - for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) - tmp_legacy_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; @@ -185,6 +186,8 @@ Signed-off-by: Felix Fietkau - for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) - tmp_legacy_tp_rate[j] = MINSTREL_OFDM_GROUP * MCS_GROUP_RATES; + group = MINSTREL_OFDM_GROUP; ++ else ++ group = 0; + + index = MI_RATE(group, 0); + for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) @@ -207,7 +210,7 @@ Signed-off-by: Felix Fietkau tmp_max_prob_rate = index; for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++) tmp_mcs_tp_rate[j] = index; -@@ -888,7 +892,7 @@ minstrel_ht_update_stats(struct minstrel +@@ -888,7 +891,7 @@ minstrel_ht_update_stats(struct minstrel /* (re)Initialize group rate indexes */ for(j = 0; j < MAX_THR_RATES; j++) @@ -216,7 +219,7 @@ Signed-off-by: Felix Fietkau if (group == MINSTREL_CCK_GROUP && ht_supported) tp_rate = tmp_legacy_tp_rate; -@@ -897,7 +901,7 @@ minstrel_ht_update_stats(struct minstrel +@@ -897,7 +900,7 @@ minstrel_ht_update_stats(struct minstrel if (!(mi->supported[group] & BIT(i))) continue; @@ -225,7 +228,7 @@ Signed-off-by: Felix Fietkau mrs = &mg->rates[i]; mrs->retry_updated = false; -@@ -929,13 +933,13 @@ minstrel_ht_update_stats(struct minstrel +@@ -929,13 +932,13 @@ minstrel_ht_update_stats(struct minstrel continue; mg = &mi->groups[group]; @@ -241,7 +244,7 @@ Signed-off-by: Felix Fietkau /* Find max probability rate per group and global */ minstrel_ht_set_best_prob_rate(mi, &tmp_max_prob_rate, -@@ -1022,7 +1026,7 @@ minstrel_downgrade_rate(struct minstrel_ +@@ -1022,7 +1025,7 @@ minstrel_downgrade_rate(struct minstrel_ { int group, orig_group; @@ -250,7 +253,7 @@ Signed-off-by: Felix Fietkau while (group > 0) { group--; -@@ -1206,7 +1210,7 @@ minstrel_calc_retransmit(struct minstrel +@@ -1206,7 +1209,7 @@ minstrel_calc_retransmit(struct minstrel ctime += (t_slot * cw) >> 1; cw = min((cw << 1) | 1, mp->cw_max); @@ -259,7 +262,7 @@ Signed-off-by: Felix Fietkau overhead = mi->overhead_legacy; overhead_rtscts = mi->overhead_legacy_rtscts; } else { -@@ -1239,7 +1243,7 @@ static void +@@ -1239,7 +1242,7 @@ static void minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, struct ieee80211_sta_rates *ratetbl, int offset, int index) { @@ -268,7 +271,7 @@ Signed-off-by: Felix Fietkau const struct mcs_group *group = &minstrel_mcs_groups[group_idx]; struct minstrel_rate_stats *mrs; u8 idx; -@@ -1259,7 +1263,7 @@ minstrel_ht_set_rate(struct minstrel_pri +@@ -1259,7 +1262,7 @@ minstrel_ht_set_rate(struct minstrel_pri ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts; } @@ -277,7 +280,7 @@ Signed-off-by: Felix Fietkau if (group_idx == MINSTREL_CCK_GROUP) idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; else if (group_idx == MINSTREL_OFDM_GROUP) -@@ -1289,17 +1293,17 @@ minstrel_ht_set_rate(struct minstrel_pri +@@ -1289,17 +1292,17 @@ minstrel_ht_set_rate(struct minstrel_pri static inline int minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate) { @@ -299,7 +302,7 @@ Signed-off-by: Felix Fietkau unsigned int duration; /* Disable A-MSDU if max_prob_rate is bad */ -@@ -1405,7 +1409,7 @@ minstrel_get_sample_rate(struct minstrel +@@ -1405,7 +1408,7 @@ minstrel_get_sample_rate(struct minstrel return -1; mrs = &mg->rates[sample_idx]; @@ -308,7 +311,7 @@ Signed-off-by: Felix Fietkau tp_rate1 = mi->max_tp_rate[0]; -@@ -1455,8 +1459,7 @@ minstrel_get_sample_rate(struct minstrel +@@ -1455,8 +1458,7 @@ minstrel_get_sample_rate(struct minstrel * if the link is working perfectly. */ @@ -318,7 +321,7 @@ Signed-off-by: Felix Fietkau if (sample_dur >= minstrel_get_duration(tp_rate2) && (cur_max_tp_streams - 1 < minstrel_mcs_groups[sample_group].streams || -@@ -1484,7 +1487,7 @@ minstrel_ht_get_rate(void *priv, struct +@@ -1484,7 +1486,7 @@ minstrel_ht_get_rate(void *priv, struct int sample_idx; if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && @@ -327,7 +330,7 @@ Signed-off-by: Felix Fietkau minstrel_aggr_check(sta, txrc->skb); info->flags |= mi->tx_flags; -@@ -1512,8 +1515,8 @@ minstrel_ht_get_rate(void *priv, struct +@@ -1512,8 +1514,8 @@ minstrel_ht_get_rate(void *priv, struct if (sample_idx < 0) return; @@ -338,7 +341,7 @@ Signed-off-by: Felix Fietkau if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP] && (sample_idx >= 4) != txrc->short_preamble) -@@ -1529,7 +1532,7 @@ minstrel_ht_get_rate(void *priv, struct +@@ -1529,7 +1531,7 @@ minstrel_ht_get_rate(void *priv, struct int idx = sample_idx % ARRAY_SIZE(mp->ofdm_rates[0]); rate->idx = mp->ofdm_rates[mi->band][idx]; } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { @@ -347,7 +350,7 @@ Signed-off-by: Felix Fietkau sample_group->streams); } else { rate->idx = sample_idx + (sample_group->streams - 1) * 8; -@@ -1898,8 +1901,8 @@ static u32 minstrel_ht_get_expected_thro +@@ -1898,8 +1900,8 @@ static u32 minstrel_ht_get_expected_thro struct minstrel_ht_sta *mi = priv_sta; int i, j, prob, tp_avg; diff --git a/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch b/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch index a1cdf99e05..dce8104934 100644 --- a/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch +++ b/package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -1093,6 +1093,16 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1092,6 +1092,16 @@ minstrel_ht_tx_status(void *priv, struct info->status.ampdu_len = 1; } @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau mi->ampdu_packets++; mi->ampdu_len += info->status.ampdu_len; -@@ -1104,9 +1114,6 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1103,9 +1113,6 @@ minstrel_ht_tx_status(void *priv, struct mi->sample_count--; } @@ -37,7 +37,7 @@ Signed-off-by: Felix Fietkau if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); -@@ -1504,14 +1511,6 @@ minstrel_ht_get_rate(void *priv, struct +@@ -1503,14 +1510,6 @@ minstrel_ht_get_rate(void *priv, struct else sample_idx = minstrel_get_sample_rate(mp, mi); diff --git a/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch b/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch index 4b0ba3dbe5..dc6f11e4b9 100644 --- a/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch +++ b/package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch @@ -37,8 +37,8 @@ Signed-off-by: Felix Fietkau - mi->sample_slow = 0; mi->sample_count = 0; - memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); -@@ -883,6 +879,7 @@ minstrel_ht_update_stats(struct minstrel + if (mi->supported[MINSTREL_CCK_GROUP]) +@@ -882,6 +878,7 @@ minstrel_ht_update_stats(struct minstrel /* Find best rate sets within all MCS groups*/ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { u16 *tp_rate = tmp_mcs_tp_rate; @@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau mg = &mi->groups[group]; if (!mi->supported[group]) -@@ -897,7 +894,7 @@ minstrel_ht_update_stats(struct minstrel +@@ -896,7 +893,7 @@ minstrel_ht_update_stats(struct minstrel if (group == MINSTREL_CCK_GROUP && ht_supported) tp_rate = tmp_legacy_tp_rate; @@ -55,7 +55,7 @@ Signed-off-by: Felix Fietkau if (!(mi->supported[group] & BIT(i))) continue; -@@ -906,6 +903,11 @@ minstrel_ht_update_stats(struct minstrel +@@ -905,6 +902,11 @@ minstrel_ht_update_stats(struct minstrel mrs = &mg->rates[i]; mrs->retry_updated = false; minstrel_ht_calc_rate_stats(mp, mrs); @@ -67,7 +67,7 @@ Signed-off-by: Felix Fietkau cur_prob = mrs->prob_avg; if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) -@@ -1470,13 +1472,9 @@ minstrel_get_sample_rate(struct minstrel +@@ -1469,13 +1471,9 @@ minstrel_get_sample_rate(struct minstrel if (sample_dur >= minstrel_get_duration(tp_rate2) && (cur_max_tp_streams - 1 < minstrel_mcs_groups[sample_group].streams || diff --git a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch b/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch index 6626804eb8..7af13661a8 100644 --- a/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch +++ b/package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch @@ -474,10 +474,10 @@ Signed-off-by: Felix Fietkau - mi->sample_count = 0; - - memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); - memset(tmp_legacy_tp_rate, 0, sizeof(tmp_legacy_tp_rate)); - -@@ -885,8 +1081,6 @@ minstrel_ht_update_stats(struct minstrel + if (mi->supported[MINSTREL_CCK_GROUP]) + group = MINSTREL_CCK_GROUP; + else if (mi->supported[MINSTREL_OFDM_GROUP]) +@@ -884,8 +1080,6 @@ minstrel_ht_update_stats(struct minstrel if (!mi->supported[group]) continue; @@ -486,7 +486,7 @@ Signed-off-by: Felix Fietkau /* (re)Initialize group rate indexes */ for(j = 0; j < MAX_THR_RATES; j++) tmp_group_tp_rate[j] = MI_RATE(group, 0); -@@ -953,9 +1147,7 @@ minstrel_ht_update_stats(struct minstrel +@@ -952,9 +1146,7 @@ minstrel_ht_update_stats(struct minstrel /* Try to increase robustness of max_prob_rate*/ minstrel_ht_prob_rate_reduce_streams(mi); @@ -497,7 +497,7 @@ Signed-off-by: Felix Fietkau if (sample) minstrel_ht_rate_sample_switch(mp, mi); -@@ -972,6 +1164,7 @@ minstrel_ht_update_stats(struct minstrel +@@ -971,6 +1163,7 @@ minstrel_ht_update_stats(struct minstrel /* Reset update timer */ mi->last_stats_update = jiffies; @@ -505,7 +505,7 @@ Signed-off-by: Felix Fietkau } static bool -@@ -1002,28 +1195,6 @@ minstrel_ht_txstat_valid(struct minstrel +@@ -1001,28 +1194,6 @@ minstrel_ht_txstat_valid(struct minstrel } static void @@ -534,7 +534,7 @@ Signed-off-by: Felix Fietkau minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) { int group, orig_group; -@@ -1108,14 +1279,6 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1107,14 +1278,6 @@ minstrel_ht_tx_status(void *priv, struct mi->ampdu_packets++; mi->ampdu_len += info->status.ampdu_len; @@ -549,7 +549,7 @@ Signed-off-by: Felix Fietkau if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); -@@ -1387,97 +1550,20 @@ minstrel_ht_update_rates(struct minstrel +@@ -1386,97 +1549,20 @@ minstrel_ht_update_rates(struct minstrel rate_control_set_rates(mp->hw, mi->sta, rates); } @@ -656,7 +656,7 @@ Signed-off-by: Felix Fietkau } static void -@@ -1489,7 +1575,7 @@ minstrel_ht_get_rate(void *priv, struct +@@ -1488,7 +1574,7 @@ minstrel_ht_get_rate(void *priv, struct struct ieee80211_tx_rate *rate = &info->status.rates[0]; struct minstrel_ht_sta *mi = priv_sta; struct minstrel_priv *mp = priv; @@ -665,7 +665,7 @@ Signed-off-by: Felix Fietkau if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate))) -@@ -1505,11 +1591,19 @@ minstrel_ht_get_rate(void *priv, struct +@@ -1504,11 +1590,19 @@ minstrel_ht_get_rate(void *priv, struct /* Don't use EAPOL frames for sampling on non-mrr hw */ if (mp->hw->max_rates == 1 && (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) @@ -689,7 +689,7 @@ Signed-off-by: Felix Fietkau return; sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)]; -@@ -1630,16 +1724,6 @@ minstrel_ht_update_caps(void *priv, stru +@@ -1629,16 +1723,6 @@ minstrel_ht_update_caps(void *priv, stru mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); diff --git a/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch b/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch index 64bd59b852..8170ff85f8 100644 --- a/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch +++ b/package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch @@ -70,7 +70,7 @@ Signed-off-by: Felix Fietkau if (mi->ampdu_packets > 0) { if (!ieee80211_hw_check(mp->hw, TX_STATUS_NO_AMPDU_LEN)) mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, -@@ -1149,16 +1115,12 @@ minstrel_ht_update_stats(struct minstrel +@@ -1148,16 +1114,12 @@ minstrel_ht_update_stats(struct minstrel minstrel_ht_prob_rate_reduce_streams(mi); minstrel_ht_refill_sample_rates(mi); @@ -87,7 +87,7 @@ Signed-off-by: Felix Fietkau } #endif -@@ -1248,11 +1210,10 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1247,11 +1209,10 @@ minstrel_ht_tx_status(void *priv, struct struct ieee80211_tx_info *info = st->info; struct minstrel_ht_sta *mi = priv_sta; struct ieee80211_tx_rate *ar = info->status.rates; @@ -100,7 +100,7 @@ Signed-off-by: Felix Fietkau int i; /* This packet was aggregated but doesn't carry status info */ -@@ -1279,49 +1240,18 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1278,49 +1239,18 @@ minstrel_ht_tx_status(void *priv, struct mi->ampdu_packets++; mi->ampdu_len += info->status.ampdu_len; @@ -150,7 +150,7 @@ Signed-off-by: Felix Fietkau if (mp->hw->max_rates > 1) { /* * check for sudden death of spatial multiplexing, -@@ -1344,7 +1274,7 @@ minstrel_ht_tx_status(void *priv, struct +@@ -1343,7 +1273,7 @@ minstrel_ht_tx_status(void *priv, struct if (time_after(jiffies, mi->last_stats_update + update_interval)) { update = true; @@ -159,7 +159,7 @@ Signed-off-by: Felix Fietkau } if (update) -@@ -1523,18 +1453,14 @@ static void +@@ -1522,18 +1452,14 @@ static void minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) { struct ieee80211_sta_rates *rates; @@ -179,7 +179,7 @@ Signed-off-by: Felix Fietkau if (mp->hw->max_rates >= 3) { /* At least 3 tx rates supported, use max_tp_rate[1] next */ -@@ -1593,11 +1519,6 @@ minstrel_ht_get_rate(void *priv, struct +@@ -1592,11 +1518,6 @@ minstrel_ht_get_rate(void *priv, struct (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) return; @@ -191,7 +191,7 @@ Signed-off-by: Felix Fietkau if (time_is_before_jiffies(mi->sample_time)) return; -@@ -1811,7 +1732,7 @@ minstrel_ht_update_caps(void *priv, stru +@@ -1810,7 +1731,7 @@ minstrel_ht_update_caps(void *priv, stru minstrel_ht_update_ofdm(mp, mi, sband, sta); /* create an initial rate table with the lowest supported rates */ @@ -200,7 +200,7 @@ Signed-off-by: Felix Fietkau minstrel_ht_update_rates(mp, mi); } -@@ -1927,8 +1848,6 @@ minstrel_ht_alloc(struct ieee80211_hw *h +@@ -1926,8 +1847,6 @@ minstrel_ht_alloc(struct ieee80211_hw *h if (!mp) return NULL; @@ -209,7 +209,7 @@ Signed-off-by: Felix Fietkau /* contention window settings * Just an approximation. Using the per-queue values would complicate * the calculations and is probably unnecessary */ -@@ -1948,7 +1867,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h +@@ -1947,7 +1866,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h mp->has_mrr = true; mp->hw = hw; @@ -218,7 +218,7 @@ Signed-off-by: Felix Fietkau minstrel_ht_init_cck_rates(mp); for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++) -@@ -1966,8 +1885,6 @@ static void minstrel_ht_add_debugfs(stru +@@ -1965,8 +1884,6 @@ static void minstrel_ht_add_debugfs(stru mp->fixed_rate_idx = (u32) -1; debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx); From 7b63d89b5289b2c08d5542f60a1c71a29d45c51f Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Tue, 26 Jan 2021 09:49:14 -1000 Subject: [PATCH 25/29] umdns: bump to 2021-01-26 * i78aa36b umdns: fix 64-bit time format string * start using $(AUTORELEASE) * Update Copyright Signed-off-by: Paul Spooren --- package/network/services/umdns/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package/network/services/umdns/Makefile b/package/network/services/umdns/Makefile index 41945ce007..9a5f46a705 100644 --- a/package/network/services/umdns/Makefile +++ b/package/network/services/umdns/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2014 OpenWrt.org +# Copyright (C) 2014-2021 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=umdns -PKG_RELEASE:=4 +PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_URL=$(PROJECT_GIT)/project/mdnsd.git PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2020-10-26 -PKG_SOURCE_VERSION:=59e4fc98162d253b4e5ecd110f7bc5ea3962e221 -PKG_MIRROR_HASH:=35fefc76d84c963ccb0aa72ac738065649f361d2946d3bc45fbd205d1dfc3d9f +PKG_SOURCE_DATE:=2021-01-26 +PKG_SOURCE_VERSION:=78aa36b0e9808e801c527c6dc47320e593309522 +PKG_MIRROR_HASH:=241833f2bf2f3366f356703159be386862ef747d9b253af6c13555f252cc970d PKG_MAINTAINER:=John Crispin PKG_LICENSE:=LGPL-2.1 From 01e4274c2117863603363c22f403af159c71cbfd Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 20 Jan 2021 20:51:45 -0800 Subject: [PATCH 26/29] toolchain/libstdcpp: disable dual ABI and default to new GCC 5.1 changed the std::string ABI in order to properly support C++11. For compatibility with libraries compiled with the older ABI, that is, linking between old-abi.so and new-abi.bin, both ABIs are enabled. In terms of OpenWrt, all packages are compiled with the same toolchain, which means these issues do not need to be handled. Most importantly, this results in a significant size reduction of libstdpp: Before: 450794 bytes After: 327752 bytes Tested with all OpenWrt packages. Signed-off-by: Rosen Penev --- toolchain/gcc/common.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/toolchain/gcc/common.mk b/toolchain/gcc/common.mk index aaddb74642..55fad1fcc4 100644 --- a/toolchain/gcc/common.mk +++ b/toolchain/gcc/common.mk @@ -117,7 +117,9 @@ GCC_CONFIGURE:= \ --with-mpc=$(TOPDIR)/staging_dir/host \ --disable-decimal-float \ --with-diagnostics-color=auto-if-env \ - --enable-__cxa_atexit + --enable-__cxa_atexit \ + --disable-libstdcxx-dual-abi \ + --with-default-libstdcxx-abi=new ifneq ($(CONFIG_mips)$(CONFIG_mipsel),) GCC_CONFIGURE += --with-mips-plt endif From ff2087d9a9db86c6c5a7fec258fec66bff8e4f9c Mon Sep 17 00:00:00 2001 From: Jeffrey Elms Date: Tue, 26 Jan 2021 18:28:14 -0800 Subject: [PATCH 27/29] px5g-wolfssl: Fix certificate signature Certificate signature algorithm was being set after call to `wc_MakeCert`, resulting in a mismatch between specified signature in certificate and the actual signature type. Signed-off-by: Jeffrey Elms [fix commit subject, use COMMITCOUNT] Signed-off-by: Paul Spooren --- package/utils/px5g-wolfssl/Makefile | 2 +- package/utils/px5g-wolfssl/px5g-wolfssl.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package/utils/px5g-wolfssl/Makefile b/package/utils/px5g-wolfssl/Makefile index be36f9f33d..90296008d6 100644 --- a/package/utils/px5g-wolfssl/Makefile +++ b/package/utils/px5g-wolfssl/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=px5g-wolfssl -PKG_RELEASE:=1 +PKG_RELEASE:=$(COMMITCOUNT) PKG_LICENSE:=GPL-2.0-or-later PKG_USE_MIPS16:=0 diff --git a/package/utils/px5g-wolfssl/px5g-wolfssl.c b/package/utils/px5g-wolfssl/px5g-wolfssl.c index b937d220ca..763d7b4b71 100644 --- a/package/utils/px5g-wolfssl/px5g-wolfssl.c +++ b/package/utils/px5g-wolfssl/px5g-wolfssl.c @@ -232,8 +232,10 @@ int selfsigned(WC_RNG *rng, char **arg) { subject, fstr, tstr); if (type == EC_KEY_TYPE) { + newCert.sigType = CTC_SHA256wECDSA; ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), NULL, &ecKey, rng); } else { + newCert.sigType = CTC_SHA256wRSA; ret = wc_MakeCert(&newCert, derBuf, sizeof(derBuf), &rsaKey, NULL, rng); } if (ret <= 0) { @@ -242,11 +244,9 @@ int selfsigned(WC_RNG *rng, char **arg) { } if (type == EC_KEY_TYPE) { - newCert.sigType = CTC_SHA256wECDSA; ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf), NULL, &ecKey, rng); } else { - newCert.sigType = CTC_SHA256wRSA; ret = wc_SignCert(newCert.bodySz, newCert.sigType, derBuf, sizeof(derBuf), &rsaKey, NULL, rng); } From 513f7171a3e509bba54ecc2af2d6259c7cbff221 Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Tue, 26 Jan 2021 17:16:36 -1000 Subject: [PATCH 28/29] rules: fix COMMITCOUNT logic The newly added $(COMMITCOUNT) variable was wrongly increased by plus one. The addition should have been only added to $(AUTORELEASE) as OpenWrt traditionally starts counting at one rather than zero. $(AUTORELEASE) counts the commits since the last bump, which is zero on the version bump commit itself. This commit increases $(AUTORELEASE) by one while leaving $(COMMITCOUNT) as is. The base-files package is the only package using $(COMMITCOUNT) so far and requires a pseudo commit to keep the PKG_RELEASE correct. A non functional change (Copyright bump) is done in the next commit. Signed-off-by: Paul Spooren --- rules.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.mk b/rules.mk index cf4aa30d21..b1b69eabf9 100644 --- a/rules.mk +++ b/rules.mk @@ -421,7 +421,7 @@ $(shell \ if [ -n "$$last_bump" ]; then \ echo -n $$(($$(git rev-list --count "$$last_bump..HEAD" .) + 1)); \ else \ - echo -n $$(($$(git rev-list --count HEAD .) + 1)); \ + git rev-list --count HEAD .; \ fi; \ else \ secs="$$(($(SOURCE_DATE_EPOCH) % 86400))"; \ From 2d72be766d0b709436affeb0bceae698503d0c3b Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Tue, 26 Jan 2021 17:21:48 -1000 Subject: [PATCH 29/29] base-files: bump Copyright to 2021 This commit is only added to keep the PKG_RELEASE correct after fixing the $(COMMITCOUNT) logic in the previous commit. This way the PKG_RELEASE stays the same while the compiled packages content isn't changed. Signed-off-by: Paul Spooren --- package/base-files/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/base-files/Makefile b/package/base-files/Makefile index d134641cb9..8a1ddf96f5 100644 --- a/package/base-files/Makefile +++ b/package/base-files/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2007-2016 OpenWrt.org +# Copyright (C) 2007-2021 OpenWrt.org # Copyright (C) 2010 Vertical Communications # # This is free software, licensed under the GNU General Public License v2.