Skip to content

Commit 83163f7

Browse files
moore-brosdavem330
authored andcommitted
net: dsa: mediatek: add VLAN support for MT7530
MT7530 can treat each port as either VLAN-unaware port or VLAN-aware port through the implementation of port matrix mode or port security mode on the ingress port, respectively. On one hand, Each port has been acting as the VLAN-unaware one whenever the device is created in the initial or certain port joins or leaves into/from the bridge at the runtime. On the other hand, the patch just filling the required callbacks for VLAN operations is achieved via extending the port to be into port security mode when the port is configured as VLAN-aware port. Which mode can make the port be able to recognize VID from incoming packets and look up VLAN table to validate and judge which port it should be going to. And the range for VID from 1 to 4094 is valid for the hardware. Signed-off-by: Sean Wang <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5c13e07 commit 83163f7

File tree

2 files changed

+364
-7
lines changed

2 files changed

+364
-7
lines changed

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)