mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Merge branch 'net-dsa-yt921x-add-port-police-support'
David Yang says: ==================== net: dsa: yt921x: Add port police support ==================== Link: https://patch.msgid.link/20260430114529.3536911-1-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
cdfe0d92c4
|
|
@ -2001,7 +2001,8 @@ static int felix_cls_flower_stats(struct dsa_switch *ds, int port,
|
|||
}
|
||||
|
||||
static int felix_port_policer_add(struct dsa_switch *ds, int port,
|
||||
const struct flow_action_police *policer)
|
||||
const struct flow_action_police *policer,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct ocelot *ocelot = ds->priv;
|
||||
struct ocelot_policer pol = {
|
||||
|
|
|
|||
|
|
@ -2847,7 +2847,8 @@ static void sja1105_mirror_del(struct dsa_switch *ds, int port,
|
|||
}
|
||||
|
||||
static int sja1105_port_policer_add(struct dsa_switch *ds, int port,
|
||||
const struct flow_action_police *policer)
|
||||
const struct flow_action_police *policer,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct sja1105_l2_policing_entry *policing;
|
||||
struct sja1105_private *priv = ds->priv;
|
||||
|
|
|
|||
|
|
@ -255,63 +255,136 @@ yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
|
|||
return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
|
||||
}
|
||||
|
||||
/* Some registers, like VLANn_CTRL, should always be written in 64-bit, even if
|
||||
* you are to write only the lower / upper 32 bits.
|
||||
/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
|
||||
* long register. More specifically, writes to parts of its words won't become
|
||||
* visible, until the last word is written.
|
||||
*
|
||||
* There is no such restriction for reading, but we still provide 64-bit read
|
||||
* wrappers so that we always handle u64 values.
|
||||
* Here we require full read and write operations over these registers to
|
||||
* eliminate potential issues, although partial reads/writes are also possible.
|
||||
*/
|
||||
|
||||
static int yt921x_reg64_read(struct yt921x_priv *priv, u32 reg, u64 *valp)
|
||||
static void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
|
||||
{
|
||||
u32 lo;
|
||||
u32 hi;
|
||||
int res;
|
||||
|
||||
res = yt921x_reg_read(priv, reg, &lo);
|
||||
if (res)
|
||||
return res;
|
||||
res = yt921x_reg_read(priv, reg + 4, &hi);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
*valp = ((u64)hi << 32) | lo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, u64 val)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = yt921x_reg_write(priv, reg, (u32)val);
|
||||
if (res)
|
||||
return res;
|
||||
return yt921x_reg_write(priv, reg + 4, (u32)(val >> 32));
|
||||
*lo &= ~lower_32_bits(mask);
|
||||
*hi &= ~upper_32_bits(mask);
|
||||
*lo |= lower_32_bits(val);
|
||||
*hi |= upper_32_bits(val);
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, u64 mask, u64 val)
|
||||
yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
|
||||
unsigned int num_regs)
|
||||
{
|
||||
int res;
|
||||
u64 v;
|
||||
u64 u;
|
||||
|
||||
res = yt921x_reg64_read(priv, reg, &v);
|
||||
for (unsigned int i = 0; i < num_regs; i++) {
|
||||
res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
|
||||
unsigned int num_regs)
|
||||
{
|
||||
int res;
|
||||
|
||||
for (unsigned int i = 0; i < num_regs; i++) {
|
||||
res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
|
||||
const u32 *vals, unsigned int num_regs)
|
||||
{
|
||||
bool changed = false;
|
||||
u32 vs[4];
|
||||
int res;
|
||||
|
||||
BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
|
||||
|
||||
res = yt921x_regs_read(priv, reg, vs, num_regs);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
u = v;
|
||||
u &= ~mask;
|
||||
u |= val;
|
||||
if (u == v)
|
||||
for (unsigned int i = 0; i < num_regs; i++) {
|
||||
u32 u = vs[i];
|
||||
|
||||
u &= ~masks[i];
|
||||
u |= vals[i];
|
||||
if (u != vs[i])
|
||||
changed = true;
|
||||
|
||||
vs[i] = u;
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
return 0;
|
||||
|
||||
return yt921x_reg64_write(priv, reg, u);
|
||||
return yt921x_regs_write(priv, reg, vs, num_regs);
|
||||
}
|
||||
|
||||
static int yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, u64 mask)
|
||||
static int
|
||||
yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
|
||||
unsigned int num_regs)
|
||||
{
|
||||
return yt921x_reg64_update_bits(priv, reg, mask, 0);
|
||||
bool changed = false;
|
||||
u32 vs[4];
|
||||
int res;
|
||||
|
||||
BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
|
||||
|
||||
res = yt921x_regs_read(priv, reg, vs, num_regs);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
for (unsigned int i = 0; i < num_regs; i++) {
|
||||
u32 u = vs[i];
|
||||
|
||||
u &= ~masks[i];
|
||||
if (u != vs[i])
|
||||
changed = true;
|
||||
|
||||
vs[i] = u;
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
return 0;
|
||||
|
||||
return yt921x_regs_write(priv, reg, vs, num_regs);
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
|
||||
{
|
||||
return yt921x_regs_write(priv, reg, vals, 2);
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
|
||||
const u32 *vals)
|
||||
{
|
||||
return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
|
||||
{
|
||||
return yt921x_regs_clear_bits(priv, reg, masks, 2);
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
|
||||
{
|
||||
return yt921x_regs_write(priv, reg, vals, 3);
|
||||
}
|
||||
|
||||
static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)
|
||||
|
|
@ -1007,6 +1080,13 @@ yt921x_dsa_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e)
|
|||
return res;
|
||||
}
|
||||
|
||||
static int yt921x_mtu_fetch(struct yt921x_priv *priv, int port)
|
||||
{
|
||||
struct dsa_port *dp = dsa_to_port(&priv->ds, port);
|
||||
|
||||
return dp->user ? READ_ONCE(dp->user->mtu) : ETH_DATA_LEN;
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_dsa_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
|
||||
{
|
||||
|
|
@ -1038,6 +1118,266 @@ static int yt921x_dsa_port_max_mtu(struct dsa_switch *ds, int port)
|
|||
return YT921X_FRAME_SIZE_MAX - ETH_HLEN - ETH_FCS_LEN - YT921X_TAG_LEN;
|
||||
}
|
||||
|
||||
/* v * 2^e */
|
||||
static u64 ldexpu64(u64 v, int e)
|
||||
{
|
||||
return e >= 0 ? v << e : v >> -e;
|
||||
}
|
||||
|
||||
/* slot (ns) * rate (/s) / 10^9 (ns/s) = 2^C * token * 4^unit */
|
||||
static u32 rate2token(u64 rate, unsigned int slot_ns, int unit, int C)
|
||||
{
|
||||
int e = 2 * unit + C + YT921X_TOKEN_RATE_C;
|
||||
|
||||
return div_u64(ldexpu64(slot_ns * rate, -e), 1000000000);
|
||||
}
|
||||
|
||||
static u64 token2rate(u32 token, unsigned int slot_ns, int unit, int C)
|
||||
{
|
||||
int e = 2 * unit + C + YT921X_TOKEN_RATE_C;
|
||||
|
||||
return div_u64(ldexpu64(mul_u32_u32(1000000000, token), e), slot_ns);
|
||||
}
|
||||
|
||||
/* burst = 2^C * token * 4^unit */
|
||||
static u32 burst2token(u64 burst, int unit, int C)
|
||||
{
|
||||
return ldexpu64(burst, -(2 * unit + C));
|
||||
}
|
||||
|
||||
static u64 token2burst(u32 token, int unit, int C)
|
||||
{
|
||||
return ldexpu64(token, 2 * unit + C);
|
||||
}
|
||||
|
||||
struct yt921x_marker {
|
||||
u32 cir;
|
||||
u32 cbs;
|
||||
u32 ebs;
|
||||
int unit;
|
||||
bool pkt_mode;
|
||||
};
|
||||
|
||||
#define YT921X_MARKER_PKT_MODE BIT(0)
|
||||
#define YT921X_MARKER_SINGLE_BUCKET BIT(1)
|
||||
|
||||
static int
|
||||
yt921x_marker_tfm(struct yt921x_marker *marker, u64 rate, u64 burst,
|
||||
unsigned int flags, unsigned int slot_ns, u32 cir_max,
|
||||
u32 cbs_max, int unit_max, struct yt921x_priv *priv, int port,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const int C = flags & YT921X_MARKER_PKT_MODE ? YT921X_TOKEN_PKT_C :
|
||||
YT921X_TOKEN_BYTE_C;
|
||||
struct device *dev = to_device(priv);
|
||||
struct yt921x_marker m;
|
||||
u64 burst_est;
|
||||
u64 burst_sug;
|
||||
u64 burst_max;
|
||||
u64 rate_max;
|
||||
|
||||
m.unit = unit_max;
|
||||
rate_max = token2rate(cir_max, slot_ns, m.unit, C);
|
||||
burst_max = token2burst(cbs_max, m.unit, C);
|
||||
|
||||
/* Check for unusual values */
|
||||
if (rate > rate_max || burst > burst_max) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unexpected tremendous rate");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Check for matching burst */
|
||||
burst_est = div_u64(slot_ns * rate, 1000000000);
|
||||
burst_sug = burst_est;
|
||||
if (flags & YT921X_MARKER_PKT_MODE)
|
||||
burst_sug++;
|
||||
else
|
||||
burst_sug += ETH_HLEN + yt921x_mtu_fetch(priv, port) +
|
||||
ETH_FCS_LEN;
|
||||
if (burst_sug > burst)
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack,
|
||||
"Consider match rate %llu with burst at least %llu",
|
||||
rate, burst_sug);
|
||||
|
||||
/* Select unit */
|
||||
for (; m.unit > 0; m.unit--) {
|
||||
if (rate > (rate_max >> 2) || burst > (burst_max >> 2))
|
||||
break;
|
||||
rate_max >>= 2;
|
||||
burst_max >>= 2;
|
||||
}
|
||||
|
||||
/* Calculate information rate and bucket size */
|
||||
m.cir = rate2token(rate, slot_ns, m.unit, C);
|
||||
if (!m.cir)
|
||||
m.cir = 1;
|
||||
else if (WARN_ON(m.cir > cir_max))
|
||||
m.cir = cir_max;
|
||||
m.cbs = burst2token(burst, m.unit, C);
|
||||
if (!m.cbs)
|
||||
m.cbs = 1;
|
||||
else if (WARN_ON(m.cbs > cbs_max))
|
||||
m.cbs = cbs_max;
|
||||
|
||||
/* Cut EBS */
|
||||
m.ebs = 0;
|
||||
if (!(flags & YT921X_MARKER_SINGLE_BUCKET)) {
|
||||
/* We don't have a chance to adjust rate when MTU is changed */
|
||||
if (flags & YT921X_MARKER_PKT_MODE)
|
||||
burst_est++;
|
||||
else
|
||||
burst_est += YT921X_FRAME_SIZE_MAX;
|
||||
|
||||
if (burst_est < burst) {
|
||||
u32 pbs = m.cbs;
|
||||
|
||||
m.cbs = burst2token(burst_est, m.unit, C);
|
||||
if (!m.cbs)
|
||||
m.cbs = 1;
|
||||
else if (WARN_ON(m.cbs > cbs_max))
|
||||
m.cbs = cbs_max;
|
||||
|
||||
if (pbs > m.cbs)
|
||||
m.ebs = pbs - m.cbs;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(dev,
|
||||
"slot %u ns, rate %llu, burst %llu -> unit %d, cir %u, cbs %u, ebs %u\n",
|
||||
slot_ns, rate, burst, m.unit, m.cir, m.cbs, m.ebs);
|
||||
|
||||
m.pkt_mode = flags & YT921X_MARKER_PKT_MODE;
|
||||
*marker = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_marker_tfm_police(struct yt921x_marker *marker,
|
||||
const struct flow_action_police *police,
|
||||
unsigned int flags, struct yt921x_priv *priv, int port,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
bool pkt_mode = !!police->rate_pkt_ps;
|
||||
u64 burst;
|
||||
u64 rate;
|
||||
|
||||
rate = pkt_mode ? police->rate_pkt_ps : police->rate_bytes_ps;
|
||||
burst = pkt_mode ? police->burst_pkt : police->burst;
|
||||
if (pkt_mode)
|
||||
flags |= YT921X_MARKER_PKT_MODE;
|
||||
|
||||
return yt921x_marker_tfm(marker, rate, burst, flags,
|
||||
priv->meter_slot_ns, YT921X_METER_CIR_MAX,
|
||||
YT921X_METER_CBS_MAX, YT921X_METER_UNIT_MAX,
|
||||
priv, port, extack);
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_police_validate(const struct flow_action_police *police,
|
||||
const struct flow_action *action,
|
||||
const struct flow_action_entry *act,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (police->exceed.act_id != FLOW_ACTION_DROP) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Offload not supported when exceed action is not drop");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (police->notexceed.act_id != FLOW_ACTION_PIPE &&
|
||||
police->notexceed.act_id != FLOW_ACTION_ACCEPT) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Offload not supported when conform action is not pipe or ok");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (police->notexceed.act_id == FLOW_ACTION_ACCEPT && action && act &&
|
||||
!flow_action_is_last_entry(action, act)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Offload not supported when conform action is ok, but action is not last");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* mtu defaults to unlimited but we got 2040 here, don't know why */
|
||||
if (police->peakrate_bytes_ps || police->avrate || police->overhead) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Offload not supported when peakrate/avrate/overhead is configured");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_meter_config(struct yt921x_priv *priv, unsigned int id,
|
||||
const struct yt921x_marker *marker)
|
||||
{
|
||||
u32 ctrls[3];
|
||||
|
||||
ctrls[0] = 0;
|
||||
ctrls[1] = YT921X_METER_CTRLb_CIR(marker->cir);
|
||||
ctrls[2] = YT921X_METER_CTRLc_UNIT(marker->unit) |
|
||||
YT921X_METER_CTRLc_DROP_R |
|
||||
YT921X_METER_CTRLc_TOKEN_OVERFLOW_EN |
|
||||
YT921X_METER_CTRLc_METER_EN;
|
||||
if (marker->pkt_mode)
|
||||
ctrls[2] |= YT921X_METER_CTRLc_PKT_MODE;
|
||||
update_ctrls_unaligned(&ctrls[0], &ctrls[1],
|
||||
YT921X_METER_CTRLab_EBS_M,
|
||||
YT921X_METER_CTRLab_EBS(marker->ebs));
|
||||
update_ctrls_unaligned(&ctrls[1], &ctrls[2],
|
||||
YT921X_METER_CTRLbc_CBS_M,
|
||||
YT921X_METER_CTRLbc_CBS(marker->cbs));
|
||||
|
||||
return yt921x_reg96_write(priv, YT921X_METERn_CTRL(id), ctrls);
|
||||
}
|
||||
|
||||
static void yt921x_dsa_port_policer_del(struct dsa_switch *ds, int port)
|
||||
{
|
||||
struct yt921x_priv *priv = to_yt921x_priv(ds);
|
||||
struct device *dev = to_device(priv);
|
||||
int res;
|
||||
|
||||
mutex_lock(&priv->reg_lock);
|
||||
res = yt921x_reg_write(priv, YT921X_PORTn_METER(port), 0);
|
||||
mutex_unlock(&priv->reg_lock);
|
||||
|
||||
if (res)
|
||||
dev_err(dev, "Failed to %s port %d: %i\n", "delete policer on",
|
||||
port, res);
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_dsa_port_policer_add(struct dsa_switch *ds, int port,
|
||||
const struct flow_action_police *police,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct yt921x_priv *priv = to_yt921x_priv(ds);
|
||||
struct yt921x_marker marker;
|
||||
u32 ctrl;
|
||||
int res;
|
||||
|
||||
res = yt921x_police_validate(police, NULL, NULL, extack);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
res = yt921x_marker_tfm_police(&marker, police, 0, priv, port, extack);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
mutex_lock(&priv->reg_lock);
|
||||
res = yt921x_meter_config(priv, port + YT921X_METER_NUM, &marker);
|
||||
if (res)
|
||||
goto end;
|
||||
|
||||
ctrl = YT921X_PORT_METER_ID(port) | YT921X_PORT_METER_EN;
|
||||
res = yt921x_reg_write(priv, YT921X_PORTn_METER(port), ctrl);
|
||||
end:
|
||||
mutex_unlock(&priv->reg_lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_mirror_del(struct yt921x_priv *priv, int port, bool ingress)
|
||||
{
|
||||
|
|
@ -1844,33 +2184,31 @@ yt921x_vlan_filtering(struct yt921x_priv *priv, int port, bool vlan_filtering)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_vlan_del(struct yt921x_priv *priv, int port, u16 vid)
|
||||
static int yt921x_vlan_del(struct yt921x_priv *priv, int port, u16 vid)
|
||||
{
|
||||
u64 mask64;
|
||||
u32 masks[2];
|
||||
|
||||
mask64 = YT921X_VLAN_CTRL_PORTS(port) |
|
||||
YT921X_VLAN_CTRL_UNTAG_PORTn(port);
|
||||
masks[0] = YT921X_VLAN_CTRLa_PORTn(port);
|
||||
masks[1] = YT921X_VLAN_CTRLb_UNTAG_PORTn(port);
|
||||
|
||||
return yt921x_reg64_clear_bits(priv, YT921X_VLANn_CTRL(vid), mask64);
|
||||
return yt921x_reg64_clear_bits(priv, YT921X_VLANn_CTRL(vid), masks);
|
||||
}
|
||||
|
||||
static int
|
||||
yt921x_vlan_add(struct yt921x_priv *priv, int port, u16 vid, bool untagged)
|
||||
{
|
||||
u64 mask64;
|
||||
u64 ctrl64;
|
||||
u32 masks[2];
|
||||
u32 ctrls[2];
|
||||
|
||||
mask64 = YT921X_VLAN_CTRL_PORTn(port) |
|
||||
YT921X_VLAN_CTRL_PORTS(priv->cpu_ports_mask);
|
||||
ctrl64 = mask64;
|
||||
masks[0] = YT921X_VLAN_CTRLa_PORTn(port) |
|
||||
YT921X_VLAN_CTRLa_PORTS(priv->cpu_ports_mask);
|
||||
ctrls[0] = masks[0];
|
||||
|
||||
mask64 |= YT921X_VLAN_CTRL_UNTAG_PORTn(port);
|
||||
if (untagged)
|
||||
ctrl64 |= YT921X_VLAN_CTRL_UNTAG_PORTn(port);
|
||||
masks[1] = YT921X_VLAN_CTRLb_UNTAG_PORTn(port);
|
||||
ctrls[1] = untagged ? masks[1] : 0;
|
||||
|
||||
return yt921x_reg64_update_bits(priv, YT921X_VLANn_CTRL(vid),
|
||||
mask64, ctrl64);
|
||||
masks, ctrls);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -2318,8 +2656,8 @@ yt921x_dsa_vlan_msti_set(struct dsa_switch *ds, struct dsa_bridge bridge,
|
|||
const struct switchdev_vlan_msti *msti)
|
||||
{
|
||||
struct yt921x_priv *priv = to_yt921x_priv(ds);
|
||||
u64 mask64;
|
||||
u64 ctrl64;
|
||||
u32 masks[2];
|
||||
u32 ctrls[2];
|
||||
int res;
|
||||
|
||||
if (!msti->vid)
|
||||
|
|
@ -2327,12 +2665,14 @@ yt921x_dsa_vlan_msti_set(struct dsa_switch *ds, struct dsa_bridge bridge,
|
|||
if (!msti->msti || msti->msti >= YT921X_MSTI_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
mask64 = YT921X_VLAN_CTRL_STP_ID_M;
|
||||
ctrl64 = YT921X_VLAN_CTRL_STP_ID(msti->msti);
|
||||
masks[0] = 0;
|
||||
ctrls[0] = 0;
|
||||
masks[1] = YT921X_VLAN_CTRLb_STP_ID_M;
|
||||
ctrls[1] = YT921X_VLAN_CTRLb_STP_ID(msti->msti);
|
||||
|
||||
mutex_lock(&priv->reg_lock);
|
||||
res = yt921x_reg64_update_bits(priv, YT921X_VLANn_CTRL(msti->vid),
|
||||
mask64, ctrl64);
|
||||
masks, ctrls);
|
||||
mutex_unlock(&priv->reg_lock);
|
||||
|
||||
return res;
|
||||
|
|
@ -2992,6 +3332,7 @@ static int yt921x_chip_detect(struct yt921x_priv *priv)
|
|||
u32 chipid;
|
||||
u32 major;
|
||||
u32 mode;
|
||||
u32 val;
|
||||
int res;
|
||||
|
||||
res = yt921x_reg_read(priv, YT921X_CHIP_ID, &chipid);
|
||||
|
|
@ -3026,12 +3367,27 @@ static int yt921x_chip_detect(struct yt921x_priv *priv)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
res = yt921x_reg_read(priv, YT921X_SYS_CLK, &val);
|
||||
if (res)
|
||||
return res;
|
||||
switch (FIELD_GET(YT921X_SYS_CLK_SEL_M, val)) {
|
||||
case 0:
|
||||
priv->cycle_ns = info->major == YT9215_MAJOR ? 8 : 6;
|
||||
break;
|
||||
case YT921X_SYS_CLK_143M:
|
||||
priv->cycle_ns = 7;
|
||||
break;
|
||||
default:
|
||||
priv->cycle_ns = 8;
|
||||
}
|
||||
|
||||
/* Print chipid here since we are interested in lower 16 bits */
|
||||
dev_info(dev,
|
||||
"Motorcomm %s ethernet switch, chipid: 0x%x, chipmode: 0x%x 0x%x\n",
|
||||
info->name, chipid, mode, extmode);
|
||||
|
||||
priv->info = info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3083,7 +3439,7 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
|
|||
{
|
||||
struct dsa_switch *ds = &priv->ds;
|
||||
unsigned long cpu_ports_mask;
|
||||
u64 ctrl64;
|
||||
u32 ctrls[2];
|
||||
u32 ctrl;
|
||||
int port;
|
||||
int res;
|
||||
|
|
@ -3144,14 +3500,32 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
|
|||
/* Tagged VID 0 should be treated as untagged, which confuses the
|
||||
* hardware a lot
|
||||
*/
|
||||
ctrl64 = YT921X_VLAN_CTRL_LEARN_DIS | YT921X_VLAN_CTRL_PORTS_M;
|
||||
res = yt921x_reg64_write(priv, YT921X_VLANn_CTRL(0), ctrl64);
|
||||
ctrls[0] = YT921X_VLAN_CTRLa_LEARN_DIS | YT921X_VLAN_CTRLa_PORTS_M;
|
||||
ctrls[1] = 0;
|
||||
res = yt921x_reg64_write(priv, YT921X_VLANn_CTRL(0), ctrls);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int yt921x_chip_setup_tc(struct yt921x_priv *priv)
|
||||
{
|
||||
unsigned int op_ns;
|
||||
u32 ctrl;
|
||||
int res;
|
||||
|
||||
op_ns = 8 * priv->cycle_ns;
|
||||
|
||||
ctrl = max(priv->meter_slot_ns / op_ns, YT921X_METER_SLOT_MIN);
|
||||
res = yt921x_reg_write(priv, YT921X_METER_SLOT, ctrl);
|
||||
if (res)
|
||||
return res;
|
||||
priv->meter_slot_ns = ctrl * op_ns;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused yt921x_chip_setup_qos(struct yt921x_priv *priv)
|
||||
{
|
||||
u32 ctrl;
|
||||
|
|
@ -3198,7 +3572,7 @@ static int yt921x_chip_setup(struct yt921x_priv *priv)
|
|||
u32 ctrl;
|
||||
int res;
|
||||
|
||||
ctrl = YT921X_FUNC_MIB;
|
||||
ctrl = YT921X_FUNC_MIB | YT921X_FUNC_METER;
|
||||
res = yt921x_reg_set_bits(priv, YT921X_FUNC, ctrl);
|
||||
if (res)
|
||||
return res;
|
||||
|
|
@ -3207,6 +3581,10 @@ static int yt921x_chip_setup(struct yt921x_priv *priv)
|
|||
if (res)
|
||||
return res;
|
||||
|
||||
res = yt921x_chip_setup_tc(priv);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DCB)
|
||||
res = yt921x_chip_setup_qos(priv);
|
||||
if (res)
|
||||
|
|
@ -3298,6 +3676,9 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {
|
|||
/* mtu */
|
||||
.port_change_mtu = yt921x_dsa_port_change_mtu,
|
||||
.port_max_mtu = yt921x_dsa_port_max_mtu,
|
||||
/* rate */
|
||||
.port_policer_del = yt921x_dsa_port_policer_del,
|
||||
.port_policer_add = yt921x_dsa_port_policer_add,
|
||||
/* hsr */
|
||||
.port_hsr_leave = dsa_port_simple_hsr_leave,
|
||||
.port_hsr_join = dsa_port_simple_hsr_join,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#define YT921X_RST_HW BIT(31)
|
||||
#define YT921X_RST_SW BIT(1)
|
||||
#define YT921X_FUNC 0x80004
|
||||
#define YT921X_FUNC_METER BIT(4)
|
||||
#define YT921X_FUNC_MIB BIT(1)
|
||||
#define YT921X_CHIP_ID 0x80008
|
||||
#define YT921X_CHIP_ID_MAJOR GENMASK(31, 16)
|
||||
|
|
@ -239,6 +240,11 @@
|
|||
#define YT921X_EDATA_DATA_STATUS_M GENMASK(3, 0)
|
||||
#define YT921X_EDATA_DATA_STATUS(x) FIELD_PREP(YT921X_EDATA_DATA_STATUS_M, (x))
|
||||
#define YT921X_EDATA_DATA_IDLE YT921X_EDATA_DATA_STATUS(3)
|
||||
#define YT921X_SYS_CLK 0xe0040
|
||||
#define YT921X_SYS_CLK_SEL_M GENMASK(1, 0) /* unknown: 167M */
|
||||
#define YT9215_SYS_CLK_125M 0
|
||||
#define YT9218_SYS_CLK_167M 0
|
||||
#define YT921X_SYS_CLK_143M 1
|
||||
|
||||
#define YT921X_EXT_MBUS_OP 0x6a000
|
||||
#define YT921X_INT_MBUS_OP 0xf0000
|
||||
|
|
@ -429,24 +435,24 @@ enum yt921x_app_selector {
|
|||
#define YT921X_FDB_HW_FLUSH_ON_LINKDOWN BIT(0)
|
||||
|
||||
#define YT921X_VLANn_CTRL(vlan) (0x188000 + 8 * (vlan))
|
||||
#define YT921X_VLAN_CTRL_UNTAG_PORTS_M GENMASK_ULL(50, 40)
|
||||
#define YT921X_VLAN_CTRL_UNTAG_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_UNTAG_PORTS_M, (x))
|
||||
#define YT921X_VLAN_CTRL_UNTAG_PORTn(port) BIT_ULL((port) + 40)
|
||||
#define YT921X_VLAN_CTRL_STP_ID_M GENMASK_ULL(39, 36)
|
||||
#define YT921X_VLAN_CTRL_STP_ID(x) FIELD_PREP(YT921X_VLAN_CTRL_STP_ID_M, (x))
|
||||
#define YT921X_VLAN_CTRL_SVLAN_EN BIT_ULL(35)
|
||||
#define YT921X_VLAN_CTRL_FID_M GENMASK_ULL(34, 23)
|
||||
#define YT921X_VLAN_CTRL_FID(x) FIELD_PREP(YT921X_VLAN_CTRL_FID_M, (x))
|
||||
#define YT921X_VLAN_CTRL_LEARN_DIS BIT_ULL(22)
|
||||
#define YT921X_VLAN_CTRL_PRIO_EN BIT_ULL(21)
|
||||
#define YT921X_VLAN_CTRL_PRIO_M GENMASK_ULL(20, 18)
|
||||
#define YT921X_VLAN_CTRL_PRIO(x) FIELD_PREP(YT921X_VLAN_CTRL_PRIO_M, (x))
|
||||
#define YT921X_VLAN_CTRL_PORTS_M GENMASK_ULL(17, 7)
|
||||
#define YT921X_VLAN_CTRL_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_PORTS_M, (x))
|
||||
#define YT921X_VLAN_CTRL_PORTn(port) BIT_ULL((port) + 7)
|
||||
#define YT921X_VLAN_CTRL_BYPASS_1X_AC BIT_ULL(6)
|
||||
#define YT921X_VLAN_CTRL_METER_EN BIT_ULL(5)
|
||||
#define YT921X_VLAN_CTRL_METER_ID_M GENMASK_ULL(4, 0)
|
||||
#define YT921X_VLAN_CTRLb_UNTAG_PORTS_M GENMASK(18, 8)
|
||||
#define YT921X_VLAN_CTRLb_UNTAG_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRLb_UNTAG_PORTS_M, (x))
|
||||
#define YT921X_VLAN_CTRLb_UNTAG_PORTn(port) BIT((port) + 8)
|
||||
#define YT921X_VLAN_CTRLb_STP_ID_M GENMASK(7, 4)
|
||||
#define YT921X_VLAN_CTRLb_STP_ID(x) FIELD_PREP(YT921X_VLAN_CTRLb_STP_ID_M, (x))
|
||||
#define YT921X_VLAN_CTRLb_SVLAN_EN BIT(3)
|
||||
#define YT921X_VLAN_CTRLab_FID_M GENMASK_ULL(34, 23)
|
||||
#define YT921X_VLAN_CTRLab_FID(x) FIELD_PREP(YT921X_VLAN_CTRLab_FID_M, (x))
|
||||
#define YT921X_VLAN_CTRLa_LEARN_DIS BIT(22)
|
||||
#define YT921X_VLAN_CTRLa_PRIO_EN BIT(21)
|
||||
#define YT921X_VLAN_CTRLa_PRIO_M GENMASK(20, 18)
|
||||
#define YT921X_VLAN_CTRLa_PRIO(x) FIELD_PREP(YT921X_VLAN_CTRLa_PRIO_M, (x))
|
||||
#define YT921X_VLAN_CTRLa_PORTS_M GENMASK(17, 7)
|
||||
#define YT921X_VLAN_CTRLa_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRLa_PORTS_M, (x))
|
||||
#define YT921X_VLAN_CTRLa_PORTn(port) BIT((port) + 7)
|
||||
#define YT921X_VLAN_CTRLa_BYPASS_1X_AC BIT(6)
|
||||
#define YT921X_VLAN_CTRLa_METER_EN BIT(5)
|
||||
#define YT921X_VLAN_CTRLa_METER_ID_M GENMASK(4, 0)
|
||||
|
||||
#define YT921X_TPID_IGRn(x) (0x210000 + 4 * (x)) /* [0, 3] */
|
||||
#define YT921X_TPID_IGR_TPID_M GENMASK(15, 0)
|
||||
|
|
@ -465,6 +471,39 @@ enum yt921x_app_selector {
|
|||
#define YT921X_LAG_HASH_MAC_DA BIT(1)
|
||||
#define YT921X_LAG_HASH_SRC_PORT BIT(0)
|
||||
|
||||
#define YT921X_PORTn_RATE(port) (0x220000 + 4 * (port))
|
||||
#define YT921X_PORT_RATE_GAP_VALUE GENMASK(4, 0) /* default 20 */
|
||||
#define YT921X_METER_SLOT 0x220104
|
||||
#define YT921X_METER_SLOT_SLOT_M GENMASK(11, 0)
|
||||
#define YT921X_PORTn_METER(port) (0x220108 + 4 * (port))
|
||||
#define YT921X_PORT_METER_EN BIT(4)
|
||||
#define YT921X_PORT_METER_ID_M GENMASK(3, 0)
|
||||
#define YT921X_PORT_METER_ID(x) FIELD_PREP(YT921X_PORT_METER_ID_M, (x))
|
||||
#define YT921X_METERn_CTRL(x) (0x220800 + 0x10 * (x))
|
||||
#define YT921X_METER_CTRLc_METER_EN BIT(14)
|
||||
#define YT921X_METER_CTRLc_TOKEN_OVERFLOW_EN BIT(13) /* RFC4115: yellow use unused green bw */
|
||||
#define YT921X_METER_CTRLc_DROP_M GENMASK(12, 11)
|
||||
#define YT921X_METER_CTRLc_DROP(x) FIELD_PREP(YT921X_METER_CTRLc_DROP_M, (x))
|
||||
#define YT921X_METER_CTRLc_DROP_GYR YT921X_METER_CTRLc_DROP(0)
|
||||
#define YT921X_METER_CTRLc_DROP_YR YT921X_METER_CTRLc_DROP(1)
|
||||
#define YT921X_METER_CTRLc_DROP_R YT921X_METER_CTRLc_DROP(2)
|
||||
#define YT921X_METER_CTRLc_DROP_NONE YT921X_METER_CTRLc_DROP(3)
|
||||
#define YT921X_METER_CTRLc_COLOR_BLIND BIT(10)
|
||||
#define YT921X_METER_CTRLc_UNIT_M GENMASK(9, 7)
|
||||
#define YT921X_METER_CTRLc_UNIT(x) FIELD_PREP(YT921X_METER_CTRLc_UNIT_M, (x))
|
||||
#define YT921X_METER_CTRLc_BYTE_MODE_INCLUDE_GAP BIT(6) /* +GAP_VALUE bytes each packet */
|
||||
#define YT921X_METER_CTRLc_PKT_MODE BIT(5) /* 0: byte rate mode */
|
||||
#define YT921X_METER_CTRLc_RFC2698 BIT(4) /* 0: RFC4115 */
|
||||
#define YT921X_METER_CTRLbc_CBS_M GENMASK_ULL(35, 20)
|
||||
#define YT921X_METER_CTRLbc_CBS(x) FIELD_PREP(YT921X_METER_CTRLbc_CBS_M, (x))
|
||||
#define YT921X_METER_CTRLb_CIR_M GENMASK(19, 2)
|
||||
#define YT921X_METER_CTRLb_CIR(x) FIELD_PREP(YT921X_METER_CTRLb_CIR_M, (x))
|
||||
#define YT921X_METER_CTRLab_EBS_M GENMASK_ULL(33, 18)
|
||||
#define YT921X_METER_CTRLab_EBS(x) FIELD_PREP(YT921X_METER_CTRLab_EBS_M, (x))
|
||||
#define YT921X_METER_CTRLa_EIR_M GENMASK(17, 0)
|
||||
#define YT921X_METER_CTRLa_EIR(x) FIELD_PREP(YT921X_METER_CTRLa_EIR_M, (x))
|
||||
#define YT921X_METERn_STAT(x) (0x221000 + 8 * (x))
|
||||
|
||||
#define YT921X_PORTn_VLAN_CTRL(port) (0x230010 + 4 * (port))
|
||||
#define YT921X_PORT_VLAN_CTRL_SVLAN_PRIO_EN BIT(31)
|
||||
#define YT921X_PORT_VLAN_CTRL_CVLAN_PRIO_EN BIT(30)
|
||||
|
|
@ -508,6 +547,16 @@ enum yt921x_fdb_entry_status {
|
|||
|
||||
#define YT921X_MSTI_NUM 16
|
||||
|
||||
#define YT921X_TOKEN_BYTE_C 1 /* 1 token = 2^1 byte */
|
||||
#define YT921X_TOKEN_PKT_C -6 /* 1 token = 2^-6 packets */
|
||||
#define YT921X_TOKEN_RATE_C -15
|
||||
/* Custom meters only, not including dedicated port meters (11) */
|
||||
#define YT921X_METER_NUM 64
|
||||
#define YT921X_METER_SLOT_MIN 80
|
||||
#define YT921X_METER_UNIT_MAX ((1 << 3) - 1)
|
||||
#define YT921X_METER_CIR_MAX ((1 << 18) - 1)
|
||||
#define YT921X_METER_CBS_MAX ((1 << 16) - 1)
|
||||
|
||||
#define YT921X_LAG_NUM 2
|
||||
#define YT921X_LAG_PORT_NUM 4
|
||||
|
||||
|
|
@ -602,8 +651,10 @@ struct yt921x_priv {
|
|||
struct dsa_switch ds;
|
||||
|
||||
const struct yt921x_info *info;
|
||||
unsigned int meter_slot_ns;
|
||||
/* cache of dsa_cpu_ports(ds) */
|
||||
u16 cpu_ports_mask;
|
||||
unsigned char cycle_ns;
|
||||
|
||||
/* protect the access to the switch registers */
|
||||
struct mutex reg_lock;
|
||||
|
|
|
|||
|
|
@ -1122,7 +1122,8 @@ struct dsa_switch_ops {
|
|||
void (*port_mirror_del)(struct dsa_switch *ds, int port,
|
||||
struct dsa_mall_mirror_tc_entry *mirror);
|
||||
int (*port_policer_add)(struct dsa_switch *ds, int port,
|
||||
const struct flow_action_police *policer);
|
||||
const struct flow_action_police *policer,
|
||||
struct netlink_ext_ack *extack);
|
||||
void (*port_policer_del)(struct dsa_switch *ds, int port);
|
||||
int (*port_setup_tc)(struct dsa_switch *ds, int port,
|
||||
enum tc_setup_type type, void *type_data);
|
||||
|
|
|
|||
|
|
@ -1499,7 +1499,7 @@ dsa_user_add_cls_matchall_police(struct net_device *dev,
|
|||
policer = &mall_tc_entry->policer;
|
||||
*policer = act->police;
|
||||
|
||||
err = ds->ops->port_policer_add(ds, dp->index, policer);
|
||||
err = ds->ops->port_policer_add(ds, dp->index, policer, extack);
|
||||
if (err) {
|
||||
kfree(mall_tc_entry);
|
||||
return err;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user