Skip to content

Commit be17bbe

Browse files
committed
Merge branch 'dsa-MT7530-vlan'
Sean Wang says: ==================== add VLAN support to DSA MT7530 Changes sicne v2: update to the latest code base from net-next and fix up all building errors with -Werror. Changes since v1: - fix up the typo - prefer ordering declarations longest to shortest - update that vlan_prepare callback should not change any state - use lower case letter for function naming The patchset extends DSA MT7530 to VLAN support through filling required callbacks in patch 1 and merging the special tag with VLAN tag in patch 2 for allowing that the hardware can handle these packets with VID from the CPU port. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 5c13e07 + 423d129 commit be17bbe

File tree

4 files changed

+400
-16
lines changed

4 files changed

+400
-16
lines changed

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8728,6 +8728,13 @@ L: [email protected]
87288728
S: Maintained
87298729
F: drivers/net/ethernet/mediatek/
87308730

8731+
MEDIATEK SWITCH DRIVER
8732+
M: Sean Wang <[email protected]>
8733+
8734+
S: Maintained
8735+
F: drivers/net/dsa/mt7530.*
8736+
F: net/dsa/tag_mtk.c
8737+
87318738
MEDIATEK JPEG DRIVER
87328739
M: Rick Chang <[email protected]>
87338740
M: Bin Liu <[email protected]>

drivers/net/dsa/mt7530.c

Lines changed: 287 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,69 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
804804
return 0;
805805
}
806806

807+
static void
808+
mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
809+
{
810+
struct mt7530_priv *priv = ds->priv;
811+
bool all_user_ports_removed = true;
812+
int i;
813+
814+
/* When a port is removed from the bridge, the port would be set up
815+
* back to the default as is at initial boot which is a VLAN-unaware
816+
* port.
817+
*/
818+
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
819+
MT7530_PORT_MATRIX_MODE);
820+
mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
821+
VLAN_ATTR(MT7530_VLAN_TRANSPARENT));
822+
823+
priv->ports[port].vlan_filtering = false;
824+
825+
for (i = 0; i < MT7530_NUM_PORTS; i++) {
826+
if (dsa_is_user_port(ds, i) &&
827+
priv->ports[i].vlan_filtering) {
828+
all_user_ports_removed = false;
829+
break;
830+
}
831+
}
832+
833+
/* CPU port also does the same thing until all user ports belonging to
834+
* the CPU port get out of VLAN filtering mode.
835+
*/
836+
if (all_user_ports_removed) {
837+
mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT),
838+
PCR_MATRIX(dsa_user_ports(priv->ds)));
839+
mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT),
840+
PORT_SPEC_TAG);
841+
}
842+
}
843+
844+
static void
845+
mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)
846+
{
847+
struct mt7530_priv *priv = ds->priv;
848+
849+
/* The real fabric path would be decided on the membership in the
850+
* entry of VLAN table. PCR_MATRIX set up here with ALL_MEMBERS
851+
* means potential VLAN can be consisting of certain subset of all
852+
* ports.
853+
*/
854+
mt7530_rmw(priv, MT7530_PCR_P(port),
855+
PCR_MATRIX_MASK, PCR_MATRIX(MT7530_ALL_MEMBERS));
856+
857+
/* Trapped into security mode allows packet forwarding through VLAN
858+
* table lookup.
859+
*/
860+
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
861+
MT7530_PORT_SECURITY_MODE);
862+
863+
/* Set the port as a user port which is to be able to recognize VID
864+
* from incoming packets before fetching entry within the VLAN table.
865+
*/
866+
mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
867+
VLAN_ATTR(MT7530_VLAN_USER));
868+
}
869+
807870
static void
808871
mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
809872
struct net_device *bridge)
@@ -817,8 +880,11 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
817880
/* Remove this port from the port matrix of the other ports
818881
* in the same bridge. If the port is disabled, port matrix
819882
* is kept and not being setup until the port becomes enabled.
883+
* And the other port's port matrix cannot be broken when the
884+
* other port is still a VLAN-aware port.
820885
*/
821-
if (dsa_is_user_port(ds, i) && i != port) {
886+
if (!priv->ports[i].vlan_filtering &&
887+
dsa_is_user_port(ds, i) && i != port) {
822888
if (dsa_to_port(ds, i)->bridge_dev != bridge)
823889
continue;
824890
if (priv->ports[i].enable)
@@ -836,6 +902,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
836902
PCR_MATRIX(BIT(MT7530_CPU_PORT)));
837903
priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
838904

905+
mt7530_port_set_vlan_unaware(ds, port);
906+
839907
mutex_unlock(&priv->reg_mutex);
840908
}
841909

@@ -906,6 +974,220 @@ mt7530_port_fdb_dump(struct dsa_switch *ds, int port,
906974
return 0;
907975
}
908976

977+
static int
978+
mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
979+
{
980+
struct mt7530_dummy_poll p;
981+
u32 val;
982+
int ret;
983+
984+
val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
985+
mt7530_write(priv, MT7530_VTCR, val);
986+
987+
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
988+
ret = readx_poll_timeout(_mt7530_read, &p, val,
989+
!(val & VTCR_BUSY), 20, 20000);
990+
if (ret < 0) {
991+
dev_err(priv->dev, "poll timeout\n");
992+
return ret;
993+
}
994+
995+
val = mt7530_read(priv, MT7530_VTCR);
996+
if (val & VTCR_INVALID) {
997+
dev_err(priv->dev, "read VTCR invalid\n");
998+
return -EINVAL;
999+
}
1000+
1001+
return 0;
1002+
}
1003+
1004+
static int
1005+
mt7530_port_vlan_filtering(struct dsa_switch *ds, int port,
1006+
bool vlan_filtering)
1007+
{
1008+
struct mt7530_priv *priv = ds->priv;
1009+
1010+
priv->ports[port].vlan_filtering = vlan_filtering;
1011+
1012+
if (vlan_filtering) {
1013+
/* The port is being kept as VLAN-unaware port when bridge is
1014+
* set up with vlan_filtering not being set, Otherwise, the
1015+
* port and the corresponding CPU port is required the setup
1016+
* for becoming a VLAN-aware port.
1017+
*/
1018+
mt7530_port_set_vlan_aware(ds, port);
1019+
mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT);
1020+
}
1021+
1022+
return 0;
1023+
}
1024+
1025+
static int
1026+
mt7530_port_vlan_prepare(struct dsa_switch *ds, int port,
1027+
const struct switchdev_obj_port_vlan *vlan)
1028+
{
1029+
/* nothing needed */
1030+
1031+
return 0;
1032+
}
1033+
1034+
static void
1035+
mt7530_hw_vlan_add(struct mt7530_priv *priv,
1036+
struct mt7530_hw_vlan_entry *entry)
1037+
{
1038+
u8 new_members;
1039+
u32 val;
1040+
1041+
new_members = entry->old_members | BIT(entry->port) |
1042+
BIT(MT7530_CPU_PORT);
1043+
1044+
/* Validate the entry with independent learning, create egress tag per
1045+
* VLAN and joining the port as one of the port members.
1046+
*/
1047+
val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | VLAN_VALID;
1048+
mt7530_write(priv, MT7530_VAWD1, val);
1049+
1050+
/* Decide whether adding tag or not for those outgoing packets from the
1051+
* port inside the VLAN.
1052+
*/
1053+
val = entry->untagged ? MT7530_VLAN_EGRESS_UNTAG :
1054+
MT7530_VLAN_EGRESS_TAG;
1055+
mt7530_rmw(priv, MT7530_VAWD2,
1056+
ETAG_CTRL_P_MASK(entry->port),
1057+
ETAG_CTRL_P(entry->port, val));
1058+
1059+
/* CPU port is always taken as a tagged port for serving more than one
1060+
* VLANs across and also being applied with egress type stack mode for
1061+
* that VLAN tags would be appended after hardware special tag used as
1062+
* DSA tag.
1063+
*/
1064+
mt7530_rmw(priv, MT7530_VAWD2,
1065+
ETAG_CTRL_P_MASK(MT7530_CPU_PORT),
1066+
ETAG_CTRL_P(MT7530_CPU_PORT,
1067+
MT7530_VLAN_EGRESS_STACK));
1068+
}
1069+
1070+
static void
1071+
mt7530_hw_vlan_del(struct mt7530_priv *priv,
1072+
struct mt7530_hw_vlan_entry *entry)
1073+
{
1074+
u8 new_members;
1075+
u32 val;
1076+
1077+
new_members = entry->old_members & ~BIT(entry->port);
1078+
1079+
val = mt7530_read(priv, MT7530_VAWD1);
1080+
if (!(val & VLAN_VALID)) {
1081+
dev_err(priv->dev,
1082+
"Cannot be deleted due to invalid entry\n");
1083+
return;
1084+
}
1085+
1086+
/* If certain member apart from CPU port is still alive in the VLAN,
1087+
* the entry would be kept valid. Otherwise, the entry is got to be
1088+
* disabled.
1089+
*/
1090+
if (new_members && new_members != BIT(MT7530_CPU_PORT)) {
1091+
val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) |
1092+
VLAN_VALID;
1093+
mt7530_write(priv, MT7530_VAWD1, val);
1094+
} else {
1095+
mt7530_write(priv, MT7530_VAWD1, 0);
1096+
mt7530_write(priv, MT7530_VAWD2, 0);
1097+
}
1098+
}
1099+
1100+
static void
1101+
mt7530_hw_vlan_update(struct mt7530_priv *priv, u16 vid,
1102+
struct mt7530_hw_vlan_entry *entry,
1103+
mt7530_vlan_op vlan_op)
1104+
{
1105+
u32 val;
1106+
1107+
/* Fetch entry */
1108+
mt7530_vlan_cmd(priv, MT7530_VTCR_RD_VID, vid);
1109+
1110+
val = mt7530_read(priv, MT7530_VAWD1);
1111+
1112+
entry->old_members = (val >> PORT_MEM_SHFT) & PORT_MEM_MASK;
1113+
1114+
/* Manipulate entry */
1115+
vlan_op(priv, entry);
1116+
1117+
/* Flush result to hardware */
1118+
mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, vid);
1119+
}
1120+
1121+
static void
1122+
mt7530_port_vlan_add(struct dsa_switch *ds, int port,
1123+
const struct switchdev_obj_port_vlan *vlan)
1124+
{
1125+
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1126+
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1127+
struct mt7530_hw_vlan_entry new_entry;
1128+
struct mt7530_priv *priv = ds->priv;
1129+
u16 vid;
1130+
1131+
/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
1132+
* being set.
1133+
*/
1134+
if (!priv->ports[port].vlan_filtering)
1135+
return;
1136+
1137+
mutex_lock(&priv->reg_mutex);
1138+
1139+
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1140+
mt7530_hw_vlan_entry_init(&new_entry, port, untagged);
1141+
mt7530_hw_vlan_update(priv, vid, &new_entry,
1142+
mt7530_hw_vlan_add);
1143+
}
1144+
1145+
if (pvid) {
1146+
mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
1147+
G0_PORT_VID(vlan->vid_end));
1148+
priv->ports[port].pvid = vlan->vid_end;
1149+
}
1150+
1151+
mutex_unlock(&priv->reg_mutex);
1152+
}
1153+
1154+
static int
1155+
mt7530_port_vlan_del(struct dsa_switch *ds, int port,
1156+
const struct switchdev_obj_port_vlan *vlan)
1157+
{
1158+
struct mt7530_hw_vlan_entry target_entry;
1159+
struct mt7530_priv *priv = ds->priv;
1160+
u16 vid, pvid;
1161+
1162+
/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
1163+
* being set.
1164+
*/
1165+
if (!priv->ports[port].vlan_filtering)
1166+
return 0;
1167+
1168+
mutex_lock(&priv->reg_mutex);
1169+
1170+
pvid = priv->ports[port].pvid;
1171+
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1172+
mt7530_hw_vlan_entry_init(&target_entry, port, 0);
1173+
mt7530_hw_vlan_update(priv, vid, &target_entry,
1174+
mt7530_hw_vlan_del);
1175+
1176+
/* PVID is being restored to the default whenever the PVID port
1177+
* is being removed from the VLAN.
1178+
*/
1179+
if (pvid == vid)
1180+
pvid = G0_PORT_VID_DEF;
1181+
}
1182+
1183+
mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, pvid);
1184+
priv->ports[port].pvid = pvid;
1185+
1186+
mutex_unlock(&priv->reg_mutex);
1187+
1188+
return 0;
1189+
}
1190+
9091191
static enum dsa_tag_protocol
9101192
mtk_get_tag_protocol(struct dsa_switch *ds, int port)
9111193
{
@@ -1035,6 +1317,10 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
10351317
.port_fdb_add = mt7530_port_fdb_add,
10361318
.port_fdb_del = mt7530_port_fdb_del,
10371319
.port_fdb_dump = mt7530_port_fdb_dump,
1320+
.port_vlan_filtering = mt7530_port_vlan_filtering,
1321+
.port_vlan_prepare = mt7530_port_vlan_prepare,
1322+
.port_vlan_add = mt7530_port_vlan_add,
1323+
.port_vlan_del = mt7530_port_vlan_del,
10381324
};
10391325

10401326
static int

0 commit comments

Comments
 (0)