mirror of
https://github.com/hanwckf/immortalwrt-mt798x.git
synced 2025-01-07 01:53:34 +08:00
Merge Official Source
This commit is contained in:
commit
4c352b55ac
@ -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
|
||||
|
@ -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)))))))
|
||||
|
@ -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.
|
||||
|
@ -0,0 +1,412 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
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 <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- 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;
|
||||
@@ -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));
|
||||
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;
|
||||
+ else
|
||||
+ group = 0;
|
||||
+
|
||||
+ 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 +891,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 +900,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 +932,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 +1025,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 +1209,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 +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)
|
||||
{
|
||||
- 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 +1262,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 +1292,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 +1408,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 +1458,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 +1486,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 +1514,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 +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) {
|
||||
- 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 +1900,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 <linux/bitfield.h>
|
||||
+
|
||||
/* 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)))
|
@ -0,0 +1,54 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
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 <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||
@@ -1092,6 +1092,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;
|
||||
|
||||
@@ -1103,9 +1113,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);
|
||||
|
||||
@@ -1503,14 +1510,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;
|
||||
|
@ -0,0 +1,102 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
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 <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- 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;
|
||||
|
||||
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;
|
||||
+ u16 last_prob = 0;
|
||||
|
||||
mg = &mi->groups[group];
|
||||
if (!mi->supported[group])
|
||||
@@ -896,7 +893,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;
|
||||
|
||||
@@ -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);
|
||||
+
|
||||
+ 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)
|
||||
@@ -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 ||
|
||||
- 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;
|
@ -0,0 +1,767 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
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 <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- 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;
|
||||
-
|
||||
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;
|
||||
|
||||
- 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);
|
||||
@@ -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);
|
||||
-
|
||||
- /* 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);
|
||||
@@ -971,6 +1163,7 @@ minstrel_ht_update_stats(struct minstrel
|
||||
|
||||
/* Reset update timer */
|
||||
mi->last_stats_update = jiffies;
|
||||
+ mi->sample_time = jiffies;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -1001,28 +1194,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;
|
||||
@@ -1107,14 +1278,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);
|
||||
|
||||
@@ -1386,97 +1549,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
|
||||
@@ -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;
|
||||
- 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)))
|
||||
@@ -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))
|
||||
- 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)];
|
||||
@@ -1629,16 +1723,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 */
|
@ -0,0 +1,58 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
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 <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- 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,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", (minstrel_ht_is_sample_rate(mi, idx) ? "S" : ""));
|
||||
|
||||
if (gflags & IEEE80211_TX_RC_MCS) {
|
||||
p += sprintf(p, ",MCS%-2u,", (mg->streams - 1) * 8 + j);
|
@ -0,0 +1,279 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
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 <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- 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,
|
||||
@@ -1148,16 +1114,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
|
||||
|
||||
@@ -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;
|
||||
- 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 */
|
||||
@@ -1278,49 +1239,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,
|
||||
@@ -1343,7 +1273,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)
|
||||
@@ -1522,18 +1452,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 */
|
||||
@@ -1592,11 +1518,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;
|
||||
|
||||
@@ -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 */
|
||||
- minstrel_ht_update_stats(mp, mi, true);
|
||||
+ minstrel_ht_update_stats(mp, mi);
|
||||
minstrel_ht_update_rates(mp, mi);
|
||||
}
|
||||
|
||||
@@ -1926,8 +1847,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 */
|
||||
@@ -1947,7 +1866,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++)
|
||||
@@ -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);
|
||||
- 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];
|
@ -0,0 +1,23 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
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 <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- 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,
|
@ -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
|
||||
|
@ -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 <john@phrozen.org>
|
||||
PKG_LICENSE:=LGPL-2.1
|
||||
|
@ -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 <itugrok@yahoo.com>
|
||||
|
||||
|
@ -1,31 +0,0 @@
|
||||
From fafb2e7eaec6d33ce16e28f481edf781219d5d27 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Ambardar <Tony.Ambardar@gmail.com>
|
||||
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 <Tony.Ambardar@gmail.com>
|
||||
---
|
||||
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 \
|
@ -1,41 +0,0 @@
|
||||
From 74d0dcf7608b1bab116e297468ac51b57eb97ce0 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Ambardar <Tony.Ambardar@gmail.com>
|
||||
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 <Tony.Ambardar@gmail.com>
|
||||
---
|
||||
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;
|
@ -1,21 +0,0 @@
|
||||
From 668d1c2951e18512a27aec20b80dea627d01bf04 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Ambardar <Tony.Ambardar@gmail.com>
|
||||
Date: Thu, 20 Aug 2020 16:05:48 -0700
|
||||
Subject: [PATCH] tools/bpftool: allow passing BPFTOOL_VERSION to make
|
||||
|
||||
Signed-off-by: Tony Ambardar <Tony.Ambardar@gmail.com>
|
||||
---
|
||||
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))
|
@ -1,231 +0,0 @@
|
||||
From 6edda7633e4fdf33b91c2e86c05cab805a0dabb3 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Ambardar <tony.ambardar@gmail.com>
|
||||
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 <Tony.Ambardar@gmail.com>
|
||||
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
|
||||
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
|
||||
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 <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
-#include <fts.h>
|
||||
+#include <ftw.h>
|
||||
#include <libgen.h>
|
||||
#include <mntent.h>
|
||||
#include <stdbool.h>
|
||||
@@ -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);
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
2
rules.mk
2
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))"; \
|
||||
|
@ -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
|
||||
|
@ -56,7 +56,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
*/
|
||||
--- 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 <nbd@nbd.name>
|
||||
/**
|
||||
* 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 <nbd@nbd.name>
|
||||
|
||||
#include <net/protocol.h>
|
||||
#include <net/dst.h>
|
||||
@@ -540,6 +541,22 @@ skb_fail:
|
||||
@@ -545,6 +546,22 @@ skb_fail:
|
||||
}
|
||||
EXPORT_SYMBOL(__napi_alloc_skb);
|
||||
|
||||
|
@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -24,7 +24,7 @@ Signed-off-by: Madalin Bucur <madalin.bucur@freescale.com>
|
||||
|
||||
--- 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);
|
||||
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -95,7 +95,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
};
|
||||
|
182
target/linux/realtek/dts/rtl930x.dtsi
Normal file
182
target/linux/realtek/dts/rtl930x.dtsi
Normal file
@ -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";
|
||||
};
|
||||
};
|
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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 },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -11,23 +11,21 @@
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_fdt.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/time.h> /* for mips_hpt_frequency */
|
||||
#include <asm/time.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/smp-ops.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -0,0 +1,196 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/time.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include "timer-of.h"
|
||||
|
||||
#include <mach-rtl83xx.h>
|
||||
|
||||
/*
|
||||
* 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);
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,12 +1,219 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <asm/mach-rtl838x/mach-rtl83xx.h>
|
||||
#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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
576
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c
Normal file
576
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/qos.c
Normal file
@ -0,0 +1,576 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <net/dsa.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/mach-rtl838x/mach-rtl83xx.h>
|
||||
#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);
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 */
|
||||
|
||||
|
607
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c
Normal file
607
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl930x.c
Normal file
@ -0,0 +1,607 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <asm/mach-rtl838x/mach-rtl83xx.h>
|
||||
#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,
|
||||
};
|
326
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c
Normal file
326
target/linux/realtek/files-5.4/drivers/net/dsa/rtl83xx/rtl931x.c
Normal file
@ -0,0 +1,326 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <asm/mach-rtl838x/mach-rtl83xx.h>
|
||||
#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,
|
||||
};
|
||||
|
@ -1,64 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <asm/mach-rtl838x/mach-rtl83xx.h>
|
||||
#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);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
@ -69,6 +77,8 @@ define Device/zyxel_gs1900-10hp
|
||||
IMAGE_SIZE := 6976k
|
||||
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
|
||||
|
||||
@ -79,6 +89,8 @@ define Device/zyxel_gs1900-8hp-v1
|
||||
DEVICE_MODEL := GS1900-8HP
|
||||
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
|
||||
|
||||
@ -89,6 +101,8 @@ define Device/zyxel_gs1900-8hp-v2
|
||||
DEVICE_MODEL := GS1900-8HP
|
||||
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
|
||||
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user