int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_lag_upper_info *info)
{
struct rtl838x_switch_priv *priv = ds->priv;
+ int ret;
int i;
- u32 algomsk = 0;
- u32 algoidx = 0;
for (i = 0; i < priv->ds->num_lag_ids; i++) {
if (priv->lags_port_members[i] & BIT_ULL(port))
return -ENOSPC;
}
- switch (info->hash_type) {
- case NETDEV_LAG_HASH_L2:
- algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
- algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
- break;
- case NETDEV_LAG_HASH_L23:
- algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
- algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
- algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
- algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
- algoidx = 1;
- break;
- case NETDEV_LAG_HASH_L34:
- algomsk |= TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT; /* sport */
- algomsk |= TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT; /* dport */
- algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
- algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
- algoidx = 2;
- break;
- default:
- algomsk |= 0x7f;
+ if (priv->r->lag_setup_algomask) {
+ ret = priv->r->lag_setup_algomask(priv, group, info);
+ if (ret)
+ return ret;
}
- priv->r->set_distribution_algorithm(group, algoidx, algomsk);
- priv->r->mask_port_reg_be(0, BIT_ULL(port), priv->r->trk_mbr_ctr(group));
- priv->lags_port_members[group] |= BIT_ULL(port);
+
+ ret = priv->r->lag_set_port_members(priv, group,
+ priv->lags_port_members[group] | BIT_ULL(port), info);
+ if (ret)
+ return ret;
pr_info("%s: Added port %d to LAG %d. Members now %016llx.\n",
__func__, port, group, priv->lags_port_members[group]);
int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
{
struct rtl838x_switch_priv *priv = ds->priv;
+ int ret;
if (group >= priv->ds->num_lag_ids) {
pr_err("%s: LAG %d invalid.\n", __func__, group);
return -ENOSPC;
}
- /* 0x7f algo mask all */
- priv->r->mask_port_reg_be(BIT_ULL(port), 0, priv->r->trk_mbr_ctr(group));
- priv->lags_port_members[group] &= ~BIT_ULL(port);
+ /* Don't touch hash mask bits, as only the port might be removed from
+ * the LAG group. This means the lag group stays valid with existing
+ * mask algo bits. If there are no lag members left, then
+ * rtl83xx_lag_add will reconfigure hash mask when new LAG group is
+ * created.
+ */
+ ret = priv->r->lag_set_port_members(priv, group,
+ priv->lags_port_members[group] & ~BIT_ULL(port),
+ NULL);
+ if (ret)
+ return ret;
pr_info("%s: Removed port %d from LAG %d. Members now %016llx.\n",
__func__, port, group, priv->lags_port_members[group]);
return 0;
}
+int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
+ struct netdev_lag_upper_info *info)
+{
+ u32 algomsk = 0;
+ u32 algoidx = 0;
+
+ switch (info->hash_type) {
+ case NETDEV_LAG_HASH_L2:
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
+ break;
+ case NETDEV_LAG_HASH_L23:
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
+ algoidx = 1;
+ break;
+ case NETDEV_LAG_HASH_L34:
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT; /* sport */
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT; /* dport */
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
+ algoidx = 2;
+ break;
+ default:
+ algomsk |= TRUNK_DISTRIBUTION_ALGO_MASKALL;
+ }
+
+ return priv->r->lag_set_distribution_algorithm(priv, group, algoidx, algomsk);
+}
+
// Currently Unused
// /* Allocate a 64 bit octet counter located in the LOG HW table */
// static int rtl83xx_octet_cntr_alloc(struct rtl838x_switch_priv *priv)
RTL838X_VLAN_PORT_EGR_FLTR + (((port / 29) << 2)));
}
-static void rtl838x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
+static int rtldsa_838x_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
+ int group, int algoidx, u32 algomsk)
{
algoidx &= 1; /* RTL838X only supports 2 concurrent algorithms */
sw_w32_mask(1 << (group % 8), algoidx << (group % 8),
RTL838X_TRK_HASH_IDX_CTRL + ((group >> 3) << 2));
sw_w32(algomsk, RTL838X_TRK_HASH_CTRL + (algoidx << 2));
+ return 0;
}
static void rtl838x_set_receive_management_action(int port, rma_ctrl_t type, action_type_t action)
p.unkn_mc_fld.pmsks_idx.ip, p.unkn_mc_fld.pmsks_idx.ip6);
}
+static int rtldsa_838x_lag_set_port_members(struct rtl838x_switch_priv *priv, int group,
+ u64 members, struct netdev_lag_upper_info *info)
+{
+ priv->lags_port_members[group] = members;
+
+ priv->r->set_port_reg_be(priv->lags_port_members[group],
+ priv->r->trk_mbr_ctr(group));
+
+ return 0;
+}
+
+int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
+ struct netdev_lag_upper_info *info);
+
const struct rtldsa_config rtldsa_838x_cfg = {
.mask_port_reg_be = rtl838x_mask_port_reg,
.set_port_reg_be = rtl838x_set_port_reg,
.route_read = rtl838x_route_read,
.route_write = rtl838x_route_write,
.l3_setup = rtl838x_l3_setup,
- .set_distribution_algorithm = rtl838x_set_distribution_algorithm,
.set_receive_management_action = rtl838x_set_receive_management_action,
.qos_init = rtldsa_838x_qos_init,
+ .lag_set_distribution_algorithm = rtldsa_838x_set_distribution_algorithm,
+ .lag_set_port_members = rtldsa_838x_lag_set_port_members,
+ .lag_setup_algomask = rtldsa_83xx_lag_setup_algomask,
};
irqreturn_t rtl838x_switch_irq(int irq, void *dev_id)
#define RTL839X_IGR_BWCTRL_CTRL_LB_THR (0x1614)
/* Link aggregation (Trunking) */
-#define TRUNK_DISTRIBUTION_ALGO_SPA_BIT 0x01
-#define TRUNK_DISTRIBUTION_ALGO_SMAC_BIT 0x02
-#define TRUNK_DISTRIBUTION_ALGO_DMAC_BIT 0x04
-#define TRUNK_DISTRIBUTION_ALGO_SIP_BIT 0x08
-#define TRUNK_DISTRIBUTION_ALGO_DIP_BIT 0x10
-#define TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT 0x20
-#define TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT 0x40
-#define TRUNK_DISTRIBUTION_ALGO_MASKALL 0x7F
+#define TRUNK_DISTRIBUTION_ALGO_SPA_BIT BIT(0)
+#define TRUNK_DISTRIBUTION_ALGO_SMAC_BIT BIT(1)
+#define TRUNK_DISTRIBUTION_ALGO_DMAC_BIT BIT(2)
+
+#define TRUNK_DISTRIBUTION_ALGO_SIP_BIT BIT(3)
+#define TRUNK_DISTRIBUTION_ALGO_DIP_BIT BIT(4)
+#define TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT BIT(5)
+#define TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT BIT(6)
+#define TRUNK_DISTRIBUTION_ALGO_VLAN_BIT BIT(7)
+#define TRUNK_DISTRIBUTION_ALGO_MASKALL GENMASK(6, 0)
#define TRUNK_DISTRIBUTION_ALGO_L2_SPA_BIT 0x01
#define TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT 0x02
int n_counters;
int n_pie_blocks;
u8 port_ignore;
+ int trk_ctrl;
+ int trk_hash_ctrl;
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 (*write_l2_entry_using_hash)(u32 hash, u32 pos, struct rtl838x_l2_entry *e);
u64 (*read_cam)(int idx, struct rtl838x_l2_entry *e);
void (*write_cam)(int idx, struct rtl838x_l2_entry *e);
- int (*trk_mbr_ctr)(int group);
int rma_bpdu_fld_pmask;
int spcl_trap_eapol_ctrl;
void (*init_eee)(struct rtl838x_switch_priv *priv, bool enable);
void (*get_l3_router_mac)(u32 idx, struct rtl93xx_rt_mac *m);
void (*set_l3_router_mac)(u32 idx, struct rtl93xx_rt_mac *m);
void (*set_l3_egress_intf)(int idx, struct rtl838x_l3_intf *intf);
- void (*set_distribution_algorithm)(int group, int algoidx, u32 algomask);
void (*set_receive_management_action)(int port, rma_ctrl_t type, action_type_t action);
void (*led_init)(struct rtl838x_switch_priv *priv);
void (*qos_init)(struct rtl838x_switch_priv *priv);
+ int (*trk_mbr_ctr)(int group);
+ int (*lag_set_port_members)(struct rtl838x_switch_priv *priv, int group, u64 members,
+ struct netdev_lag_upper_info *info);
+ int (*lag_setup_algomask)(struct rtl838x_switch_priv *priv, int group,
+ struct netdev_lag_upper_info *info);
+ int (*lag_set_distribution_algorithm)(struct rtl838x_switch_priv *priv,
+ int group, int algoidx,
+ u32 algomask);
};
struct rtl838x_switch_priv {
RTL839X_VLAN_PORT_EGR_FLTR + (((port >> 5) << 2)));
}
-static void rtl839x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
+static int rtldsa_839x_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
+ int group, int algoidx, u32 algomsk)
{
sw_w32_mask(3 << ((group & 0xf) << 1), algoidx << ((group & 0xf) << 1),
RTL839X_TRK_HASH_IDX_CTRL + ((group >> 4) << 2));
sw_w32(algomsk, RTL839X_TRK_HASH_CTRL + (algoidx << 2));
+
+ return 0;
}
static void rtl839x_set_receive_management_action(int port, rma_ctrl_t type, action_type_t action)
}
}
+static int rtldsa_839x_lag_set_port_members(struct rtl838x_switch_priv *priv, int group,
+ u64 members, struct netdev_lag_upper_info *info)
+{
+ priv->lags_port_members[group] = members;
+
+ priv->r->set_port_reg_be(priv->lags_port_members[group],
+ priv->r->trk_mbr_ctr(group));
+
+ return 0;
+}
+
+int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
+ struct netdev_lag_upper_info *info);
+
const struct rtldsa_config rtldsa_839x_cfg = {
.mask_port_reg_be = rtl839x_mask_port_reg_be,
.set_port_reg_be = rtl839x_set_port_reg_be,
.route_read = rtl839x_route_read,
.route_write = rtl839x_route_write,
.l3_setup = rtl839x_l3_setup,
- .set_distribution_algorithm = rtl839x_set_distribution_algorithm,
.set_receive_management_action = rtl839x_set_receive_management_action,
.qos_init = rtldsa_839x_qos_init,
+ .lag_set_distribution_algorithm = rtldsa_839x_set_distribution_algorithm,
+ .lag_set_port_members = rtldsa_839x_lag_set_port_members,
+ .lag_setup_algomask = rtldsa_83xx_lag_setup_algomask,
};
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);
+int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
+ struct netdev_lag_upper_info *info);
+
void rtldsa_838x_qos_init(struct rtl838x_switch_priv *priv);
void rtldsa_839x_qos_init(struct rtl838x_switch_priv *priv);
RTL930X_VLAN_PORT_EGR_FLTR + (((port / 29) << 2)));
}
-static void rtl930x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
+static int rtl930x_set_distribution_algorithm(struct rtl838x_switch_priv *priv, int group,
+ int algoidx, u32 algomsk)
{
u32 l3shift = 0;
u32 newmask = 0;
}
sw_w32(newmask << l3shift, RTL930X_TRK_HASH_CTRL + (algoidx << 2));
+ return 0;
}
static void rtldsa_930x_led_get_forced(const struct device_node *node,
.set_l3_router_mac = rtl930x_set_l3_router_mac,
.set_l3_egress_intf = rtl930x_set_l3_egress_intf,
#endif
- .set_distribution_algorithm = rtl930x_set_distribution_algorithm,
.led_init = rtl930x_led_init,
.enable_learning = rtldsa_930x_enable_learning,
.enable_flood = rtldsa_930x_enable_flood,
.set_receive_management_action = rtldsa_930x_set_receive_management_action,
.qos_init = rtldsa_930x_qos_init,
+ .lag_set_distribution_algorithm = rtl930x_set_distribution_algorithm,
};
RTL931X_VLAN_PORT_EGR_FLTR + (((port >> 5) << 2)));
}
-static void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
+static int rtl931x_set_distribution_algorithm(struct rtl838x_switch_priv *priv, int group,
+ int algoidx, u32 algomsk)
{
u32 l3shift = 0;
u32 newmask = 0;
}
sw_w32(newmask << l3shift, RTL931X_TRK_HASH_CTRL + (algoidx << 2));
+ return 0;
}
static void rtldsa_931x_led_get_forced(const struct device_node *node,
.rma_bpdu_fld_pmask = RTL931X_RMA_BPDU_FLD_PMSK,
.set_vlan_igr_filter = rtl931x_set_igr_filter,
.set_vlan_egr_filter = rtl931x_set_egr_filter,
- .set_distribution_algorithm = rtl931x_set_distribution_algorithm,
.l2_hash_key = rtl931x_l2_hash_key,
.l2_hash_seed = rtldsa_931x_l2_hash_seed,
.read_mcast_pmask = rtl931x_read_mcast_pmask,
.enable_flood = rtldsa_931x_enable_flood,
.set_receive_management_action = rtldsa_931x_set_receive_management_action,
.qos_init = rtldsa_931x_qos_init,
+ .lag_set_distribution_algorithm = rtl931x_set_distribution_algorithm,
};