From: Sean Wang <sean.wang@mediatek.com>
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.
Sean Wang (3):
net: dsa: mediatek: add VLAN support for MT7530
net: dsa: mediatek: combine MediaTek tag with VLAN tag
net: dsa: mediatek: update MAINTAINERS entry with MediaTek switch
driver
MAINTAINERS | 7 ++
drivers/net/dsa/mt7530.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++-
drivers/net/dsa/mt7530.h | 83 +++++++++++++-
net/dsa/tag_mtk.c | 38 +++++--
4 files changed, 403 insertions(+), 16 deletions(-)
--
2.7.4
From: Sean Wang <sean.wang@mediatek.com>
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 <sean.wang@mediatek.com>
---
drivers/net/dsa/mt7530.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++-
drivers/net/dsa/mt7530.h | 83 +++++++++++++-
2 files changed, 367 insertions(+), 7 deletions(-)
@@ -805,6 +805,69 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,}staticvoid+mt7530_port_set_vlan_unaware(structdsa_switch*ds,intport)+{+structmt7530_priv*priv=ds->priv;+boolall_user_ports_removed=true;+inti;++/* When a port is removed from the bridge, the port would be set up+*backtothedefaultasisatinitialbootwhichisaVLAN-unaware+*port.+*/+mt7530_rmw(priv,MT7530_PCR_P(port),PCR_PORT_VLAN_MASK,+MT7530_PORT_MATRIX_MODE);+mt7530_rmw(priv,MT7530_PVC_P(port),VLAN_ATTR_MASK,+VLAN_ATTR(MT7530_VLAN_TRANSPARENT));++priv->ports[port].vlan_filtering=false;++for(i=0;i<MT7530_NUM_PORTS;i++){+if(dsa_is_user_port(ds,i)&&+priv->ports[i].vlan_filtering){+all_user_ports_removed=false;+break;+}+}++/* CPU port also does the same thing until all user ports belonging to+*theCPUportgetoutofVLANfilteringmode.+*/+if(all_user_ports_removed){+mt7530_write(priv,MT7530_PCR_P(MT7530_CPU_PORT),+PCR_MATRIX(dsa_user_ports(priv->ds)));+mt7530_write(priv,MT7530_PVC_P(MT7530_CPU_PORT),+PORT_SPEC_TAG);+}+}++staticvoid+mt7530_port_set_vlan_aware(structdsa_switch*ds,intport)+{+structmt7530_priv*priv=ds->priv;++/* The real fabric path would be decided on the membership in the+*entryofVLANtable.PCR_MATRIXsetupherewithALL_MEMBERS+*meanspotentialVLANcanbeconsistingofcertainsubsetofall+*ports.+*/+mt7530_rmw(priv,MT7530_PCR_P(port),+PCR_MATRIX_MASK,PCR_MATRIX(MT7530_ALL_MEMBERS));++/* Trapped into security mode allows packet forwarding through VLAN+*tablelookup.+*/+mt7530_rmw(priv,MT7530_PCR_P(port),PCR_PORT_VLAN_MASK,+MT7530_PORT_SECURITY_MODE);++/* Set the port as a user port which is to be able to recognize VID+*fromincomingpacketsbeforefetchingentrywithintheVLANtable.+*/+mt7530_rmw(priv,MT7530_PVC_P(port),VLAN_ATTR_MASK,+VLAN_ATTR(MT7530_VLAN_USER));+}++staticvoidmt7530_port_bridge_leave(structdsa_switch*ds,intport,structnet_device*bridge){
@@ -817,8 +880,11 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,/* Remove this port from the port matrix of the other ports*inthesamebridge.Iftheportisdisabled,portmatrix*iskeptandnotbeingsetupuntiltheportbecomesenabled.+*Andtheotherport'sportmatrixcannotbebrokenwhenthe+*otherportisstillaVLAN-awareport.*/-if(dsa_is_user_port(ds,i)&&i!=port){+if(!priv->ports[i].vlan_filtering&&+dsa_is_user_port(ds,i)&&i!=port){if(dsa_to_port(ds,i)->bridge_dev!=bridge)continue;if(priv->ports[i].enable)
@@ -836,6 +902,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,PCR_MATRIX(BIT(MT7530_CPU_PORT)));priv->ports[port].pm=PCR_MATRIX(BIT(MT7530_CPU_PORT));+mt7530_port_set_vlan_unaware(ds,port);+mutex_unlock(&priv->reg_mutex);}
@@ -906,6 +974,223 @@ mt7530_port_fdb_dump(struct dsa_switch *ds, int port,return0;}+staticint+mt7530_vlan_cmd(structmt7530_priv*priv,enummt7530_vlan_cmdcmd,u16vid)+{+structmt7530_dummy_pollp;+u32val;+intret;++val=VTCR_BUSY|VTCR_FUNC(cmd)|vid;+mt7530_write(priv,MT7530_VTCR,val);++INIT_MT7530_DUMMY_POLL(&p,priv,MT7530_VTCR);+ret=readx_poll_timeout(_mt7530_read,&p,val,+!(val&VTCR_BUSY),20,20000);+if(ret<0){+dev_err(priv->dev,"poll timeout\n");+returnret;+}++val=mt7530_read(priv,MT7530_VTCR);+if(val&VTCR_INVALID){+dev_err(priv->dev,"read VTCR invalid\n");+return-EINVAL;+}++return0;+}++staticint+mt7530_port_vlan_filtering(structdsa_switch*ds,intport,+boolvlan_filtering)+{+structmt7530_priv*priv=ds->priv;++priv->ports[port].vlan_filtering=vlan_filtering;++if(vlan_filtering){+/* The port is being kept as VLAN-unaware port when bridge is+*setupwithvlan_filteringnotbeingset,Otherwise,the+*portandthecorrespondingCPUportisrequiredthesetup+*forbecomingaVLAN-awareport.+*/+mt7530_port_set_vlan_aware(ds,port);+mt7530_port_set_vlan_aware(ds,MT7530_CPU_PORT);+}++return0;+}++staticint+mt7530_port_vlan_prepare(structdsa_switch*ds,intport,+conststructswitchdev_obj_port_vlan*vlan,+structswitchdev_trans*trans)+{+/* nothing needed */++return0;+}++staticvoid+mt7530_hw_vlan_add(structmt7530_priv*priv,+structmt7530_hw_vlan_entry*entry)+{+u8new_members;+u32val;++new_members=entry->old_members|BIT(entry->port)|+BIT(MT7530_CPU_PORT);++/* Validate the entry with independent learning, create egress tag per+*VLANandjoiningtheportasoneoftheportmembers.+*/+val=IVL_MAC|VTAG_EN|PORT_MEM(new_members)|VLAN_VALID;+mt7530_write(priv,MT7530_VAWD1,val);++/* Decide whether adding tag or not for those outgoing packets from the+*portinsidetheVLAN.+*/+val=entry->untagged?MT7530_VLAN_EGRESS_UNTAG:+MT7530_VLAN_EGRESS_TAG;+mt7530_rmw(priv,MT7530_VAWD2,+ETAG_CTRL_P_MASK(entry->port),+ETAG_CTRL_P(entry->port,val));++/* CPU port is always taken as a tagged port for serving more than one+*VLANsacrossandalsobeingappliedwithegresstypestackmodefor+*thatVLANtagswouldbeappendedafterhardwarespecialtagusedas+*DSAtag.+*/+mt7530_rmw(priv,MT7530_VAWD2,+ETAG_CTRL_P_MASK(MT7530_CPU_PORT),+ETAG_CTRL_P(MT7530_CPU_PORT,+MT7530_VLAN_EGRESS_STACK));+}++staticvoid+mt7530_hw_vlan_del(structmt7530_priv*priv,+structmt7530_hw_vlan_entry*entry)+{+u8new_members;+u32val;++new_members=entry->old_members&~BIT(entry->port);++val=mt7530_read(priv,MT7530_VAWD1);+if(!(val&VLAN_VALID)){+dev_err(priv->dev,+"Cannot be deleted due to invalid entry\n");+return;+}++/* If certain member apart from CPU port is still alive in the VLAN,+*theentrywouldbekeptvalid.Otherwise,theentryisgottobe+*disabled.+*/+if(new_members&&new_members!=BIT(MT7530_CPU_PORT)){+val=IVL_MAC|VTAG_EN|PORT_MEM(new_members)|+VLAN_VALID;+mt7530_write(priv,MT7530_VAWD1,val);+}else{+mt7530_write(priv,MT7530_VAWD1,0);+mt7530_write(priv,MT7530_VAWD2,0);+}+}++staticvoid+mt7530_hw_vlan_update(structmt7530_priv*priv,u16vid,+structmt7530_hw_vlan_entry*entry,+mt7530_vlan_opvlan_op)+{+u32val;++/* Fetch entry */+mt7530_vlan_cmd(priv,MT7530_VTCR_RD_VID,vid);++val=mt7530_read(priv,MT7530_VAWD1);++entry->old_members=(val>>PORT_MEM_SHFT)&PORT_MEM_MASK;++/* Manipulate entry */+vlan_op(priv,entry);++/* Flush result to hardware */+mt7530_vlan_cmd(priv,MT7530_VTCR_WR_VID,vid);+}++staticvoid+mt7530_port_vlan_add(structdsa_switch*ds,intport,+conststructswitchdev_obj_port_vlan*vlan,+structswitchdev_trans*trans)+{+booluntagged=vlan->flags&BRIDGE_VLAN_INFO_UNTAGGED;+boolpvid=vlan->flags&BRIDGE_VLAN_INFO_PVID;+structmt7530_hw_vlan_entrynew_entry;+structmt7530_priv*priv=ds->priv;+intret;+u16vid;++/* The port is kept as VLAN-unaware if bridge with vlan_filtering not+*beingset.+*/+if(!priv->ports[port].vlan_filtering)+return;++mutex_lock(&priv->reg_mutex);++for(vid=vlan->vid_begin;vid<=vlan->vid_end;++vid){+mt7530_hw_vlan_entry_init(&new_entry,port,untagged);+mt7530_hw_vlan_update(priv,vid,&new_entry,+mt7530_hw_vlan_add);+}++if(pvid){+mt7530_rmw(priv,MT7530_PPBV1_P(port),G0_PORT_VID_MASK,+G0_PORT_VID(vlan->vid_end));+priv->ports[port].pvid=vlan->vid_end;+}++mutex_unlock(&priv->reg_mutex);+}++staticint+mt7530_port_vlan_del(structdsa_switch*ds,intport,+conststructswitchdev_obj_port_vlan*vlan)+{+structmt7530_hw_vlan_entrytarget_entry;+structmt7530_priv*priv=ds->priv;+u16vid,pvid;++/* The port is kept as VLAN-unaware if bridge with vlan_filtering not+*beingset.+*/+if(!priv->ports[port].vlan_filtering)+return0;++mutex_lock(&priv->reg_mutex);++pvid=priv->ports[port].pvid;+for(vid=vlan->vid_begin;vid<=vlan->vid_end;++vid){+mt7530_hw_vlan_entry_init(&target_entry,port,0);+mt7530_hw_vlan_update(priv,vid,&target_entry,+mt7530_hw_vlan_del);++/* PVID is being restored to the default whenever the PVID port+*isbeingremovedfromtheVLAN.+*/+if(pvid==vid)+pvid=G0_PORT_VID_DEF;+}++mt7530_rmw(priv,MT7530_PPBV1_P(port),G0_PORT_VID_MASK,pvid);+priv->ports[port].pvid=pvid;++mutex_unlock(&priv->reg_mutex);++return0;+}+staticenumdsa_tag_protocolmtk_get_tag_protocol(structdsa_switch*ds,intport){
@@ -88,21 +89,42 @@ enum mt7530_fdb_cmd {/* Register for vlan table control */#define MT7530_VTCR 0x90#define VTCR_BUSY BIT(31)-#define VTCR_FUNC (((x) & 0xf) << 12)-#define VTCR_FUNC_RD_VID 0x1-#define VTCR_FUNC_WR_VID 0x2-#define VTCR_FUNC_INV_VID 0x3-#define VTCR_FUNC_VAL_VID 0x4+#define VTCR_INVALID BIT(16)+#define VTCR_FUNC(x) (((x) & 0xf) << 12)#define VTCR_VID ((x) & 0xfff)+enummt7530_vlan_cmd{+/* Read/Write the specified VID entry from VAWD register based+*onVID.+*/+MT7530_VTCR_RD_VID=0,+MT7530_VTCR_WR_VID=1,+};+/* Register for setup vlan and acl write data */#define MT7530_VAWD1 0x94#define PORT_STAG BIT(31)+/* Independent VLAN Learning */#define IVL_MAC BIT(30)+/* Per VLAN Egress Tag Control */+#define VTAG_EN BIT(28)+/* VLAN Member Control */#define PORT_MEM(x) (((x) & 0xff) << 16)-#define VALID BIT(1)+/* VLAN Entry Valid */+#define VLAN_VALID BIT(0)+#define PORT_MEM_SHFT 16+#define PORT_MEM_MASK 0xff#define MT7530_VAWD2 0x98+/* Egress Tag Control */+#define ETAG_CTRL_P(p, x) (((x) & 0x3) << ((p) << 1))+#define ETAG_CTRL_P_MASK(p) ETAG_CTRL_P(p, 3)++enummt7530_vlan_egress_attr{+MT7530_VLAN_EGRESS_UNTAG=0,+MT7530_VLAN_EGRESS_TAG=2,+MT7530_VLAN_EGRESS_STACK=3,+};/* Register for port STP state control */#define MT7530_SSP_P(x) (0x2000 + ((x) * 0x100))
@@ -120,11 +142,23 @@ enum mt7530_stp_state {/* Register for port control */#define MT7530_PCR_P(x) (0x2004 + ((x) * 0x100))#define PORT_VLAN(x) ((x) & 0x3)++enummt7530_port_mode{+/* Port Matrix Mode: Frames are forwarded by the PCR_MATRIX members. */+MT7530_PORT_MATRIX_MODE=PORT_VLAN(0),++/* Security Mode: Discard any frame due to ingress membership+*violationorVIDmissedontheVLANtable.+*/+MT7530_PORT_SECURITY_MODE=PORT_VLAN(3),+};+#define PCR_MATRIX(x) (((x) & 0xff) << 16)#define PORT_PRI(x) (((x) & 0x7) << 24)#define EG_TAG(x) (((x) & 0x3) << 28)#define PCR_MATRIX_MASK PCR_MATRIX(0xff)#define PCR_MATRIX_CLR PCR_MATRIX(0)+#define PCR_PORT_VLAN_MASK PORT_VLAN(3)/* Register for port security control */#define MT7530_PSC_P(x) (0x200c + ((x) * 0x100))
@@ -134,10 +168,20 @@ enum mt7530_stp_state {#define MT7530_PVC_P(x) (0x2010 + ((x) * 0x100))#define PORT_SPEC_TAG BIT(5)#define VLAN_ATTR(x) (((x) & 0x3) << 6)+#define VLAN_ATTR_MASK VLAN_ATTR(3)++enummt7530_vlan_port_attr{+MT7530_VLAN_USER=0,+MT7530_VLAN_TRANSPARENT=3,+};+#define STAG_VPID (((x) & 0xffff) << 16)/* Register for port port-and-protocol based vlan 1 control */#define MT7530_PPBV1_P(x) (0x2014 + ((x) * 0x100))+#define G0_PORT_VID(x) (((x) & 0xfff) << 0)+#define G0_PORT_VID_MASK G0_PORT_VID(0xfff)+#define G0_PORT_VID_DEF G0_PORT_VID(1)/* Register for port MAC control register */#define MT7530_PMCR_P(x) (0x3000 + ((x) * 0x100))
@@ -345,9 +389,20 @@ struct mt7530_fdb {boolnoarp;};+/* struct mt7530_port - This is the main data structure for holding the state+*oftheport.+*@enable:Thestatususedforshowportisenabledornot.+*@pm:Thematrixusedtoshowallconnectionswiththeport.+*@pvid:TheVLANspecifiedistobeconsideredaPVIDatingress.Any+*untaggedframeswillbeassignedtotherelatedVLAN.+*@vlan_filtering:Theflagsindicatingwhethertheportthatcanrecognize+*VLAN-taggedframes.+*/structmt7530_port{boolenable;u32pm;+u16pvid;+boolvlan_filtering;};/* struct mt7530_priv - This is the main data structure for holding the state
From: Sean Wang <sean.wang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
I work for MediaTek and maintain SoC targeting to home gateway and
also will keep extending and testing the function from MediaTek
switch.
Signed-off-by: Sean Wang <sean.wang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Reviewed-by: Andrew Lunn <redacted>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
From: Sean Wang <sean.wang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
In order to let MT7530 switch can recognize well those egress packets
having both special tag and VLAN tag, the information about the special
tag should be carried on the existing VLAN tag. On the other hand, it's
unnecessary for extra handling for ingress packets when VLAN tag is
present since it is able to put the VLAN tag after the special tag and
then follow the existing way to parse.
Signed-off-by: Sean Wang <sean.wang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
net/dsa/tag_mtk.c | 38 +++++++++++++++++++++++++++++---------
1 file changed, 29 insertions(+), 9 deletions(-)
@@ -25,20 +28,37 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,{structdsa_port*dp=dsa_slave_to_port(dev);u8*mtk_tag;+boolis_vlan_skb=true;-if(skb_cow_head(skb,MTK_HDR_LEN)<0)-returnNULL;--skb_push(skb,MTK_HDR_LEN);+/* Build the special tag after the MAC Source Address. If VLAN header+*ispresent,it'srequiredthatVLANheaderandspecialtagis+*beingcombined.Onlyinthiswaywecanallowtheswitchcanparse+*thebothspecialandVLANtagatthesametimeandthenlookupVLAN+*tablewithVID.+*/+if(!skb_vlan_tagged(skb)){+if(skb_cow_head(skb,MTK_HDR_LEN)<0)+returnNULL;-memmove(skb->data,skb->data+MTK_HDR_LEN,2*ETH_ALEN);+skb_push(skb,MTK_HDR_LEN);+memmove(skb->data,skb->data+MTK_HDR_LEN,2*ETH_ALEN);+is_vlan_skb=false;+}-/* Build the tag after the MAC Source Address */mtk_tag=skb->data+2*ETH_ALEN;-mtk_tag[0]=0;++/* Mark tag attribute on special tag insertion to notify hardware+*whetherthat'sacombinedspecialtagwith802.1Qheader.+*/+mtk_tag[0]=is_vlan_skb?MTK_HDR_XMIT_TAGGED_TPID_8100:+MTK_HDR_XMIT_UNTAGGED;mtk_tag[1]=(1<<dp->index)&MTK_HDR_XMIT_DP_BIT_MASK;-mtk_tag[2]=0;-mtk_tag[3]=0;++/* Tag control information is kept for 802.1Q */+if(!is_vlan_skb){+mtk_tag[2]=0;+mtk_tag[3]=0;+}returnskb;}
From: David Miller <davem@davemloft.net> Date: 2017-12-14 18:30:06
From: <sean.wang@mediatek.com>
Date: Wed, 13 Dec 2017 12:01:10 +0800
From: Sean Wang <sean.wang@mediatek.com>
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.
This doesn't even compile:
drivers/net/dsa/mt7530.c: In function ‘mt7530_port_vlan_add’:
drivers/net/dsa/mt7530.c:1131:6: warning: unused variable ‘ret’ [-Wunused-variable]
int ret;
^~~
drivers/net/dsa/mt7530.c: At top level:
drivers/net/dsa/mt7530.c:1324:23: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.port_vlan_prepare = mt7530_port_vlan_prepare,
^~~~~~~~~~~~~~~~~~~~~~~~
drivers/net/dsa/mt7530.c:1324:23: note: (near initialization for ‘mt7530_switch_ops.port_vlan_prepare’)
drivers/net/dsa/mt7530.c:1325:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.port_vlan_add = mt7530_port_vlan_add,
^~~~~~~~~~~~~~~~~~~~
drivers/net/dsa/mt7530.c:1325:20: note: (near initialization for ‘mt7530_switch_ops.port_vlan_add’)
cc1: some warnings being treated as errors
From: kbuild test robot <hidden> Date: 2017-12-15 14:14:18
Hi Sean,
I love your patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/sean-wang-mediatek-com/add-VLAN-support-to-DSA-MT7530/20171215-214450
config: i386-randconfig-x019-201750 (attached as .config)
compiler: gcc-7 (Debian 7.2.0-12) 7.2.1 20171025
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All errors (new ones prefixed by >>):
drivers/net/dsa/mt7530.c: In function 'mt7530_port_vlan_add':
drivers/net/dsa/mt7530.c:1131:6: warning: unused variable 'ret' [-Wunused-variable]
int ret;
^~~
drivers/net/dsa/mt7530.c: At top level:
quoted
drivers/net/dsa/mt7530.c:1324:23: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.port_vlan_prepare = mt7530_port_vlan_prepare,
^~~~~~~~~~~~~~~~~~~~~~~~
drivers/net/dsa/mt7530.c:1324:23: note: (near initialization for 'mt7530_switch_ops.port_vlan_prepare')
drivers/net/dsa/mt7530.c:1325:20: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
.port_vlan_add = mt7530_port_vlan_add,
^~~~~~~~~~~~~~~~~~~~
drivers/net/dsa/mt7530.c:1325:20: note: (near initialization for 'mt7530_switch_ops.port_vlan_add')
cc1: some warnings being treated as errors
vim +1324 drivers/net/dsa/mt7530.c
1121
1122 static void
1123 mt7530_port_vlan_add(struct dsa_switch *ds, int port,
1124 const struct switchdev_obj_port_vlan *vlan,
1125 struct switchdev_trans *trans)
1126 {
1127 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1128 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1129 struct mt7530_hw_vlan_entry new_entry;
1130 struct mt7530_priv *priv = ds->priv;
1131 int ret;
1132 u16 vid;
1133
1134 /* The port is kept as VLAN-unaware if bridge with vlan_filtering not
1135 * being set.
1136 */
1137 if (!priv->ports[port].vlan_filtering)
1138 return;
1139
1140 mutex_lock(&priv->reg_mutex);
1141
1142 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1143 mt7530_hw_vlan_entry_init(&new_entry, port, untagged);
1144 mt7530_hw_vlan_update(priv, vid, &new_entry,
1145 mt7530_hw_vlan_add);
1146 }
1147
1148 if (pvid) {
1149 mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK,
1150 G0_PORT_VID(vlan->vid_end));
1151 priv->ports[port].pvid = vlan->vid_end;
1152 }
1153
1154 mutex_unlock(&priv->reg_mutex);
1155 }
1156
1157 static int
1158 mt7530_port_vlan_del(struct dsa_switch *ds, int port,
1159 const struct switchdev_obj_port_vlan *vlan)
1160 {
1161 struct mt7530_hw_vlan_entry target_entry;
1162 struct mt7530_priv *priv = ds->priv;
1163 u16 vid, pvid;
1164
1165 /* The port is kept as VLAN-unaware if bridge with vlan_filtering not
1166 * being set.
1167 */
1168 if (!priv->ports[port].vlan_filtering)
1169 return 0;
1170
1171 mutex_lock(&priv->reg_mutex);
1172
1173 pvid = priv->ports[port].pvid;
1174 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1175 mt7530_hw_vlan_entry_init(&target_entry, port, 0);
1176 mt7530_hw_vlan_update(priv, vid, &target_entry,
1177 mt7530_hw_vlan_del);
1178
1179 /* PVID is being restored to the default whenever the PVID port
1180 * is being removed from the VLAN.
1181 */
1182 if (pvid == vid)
1183 pvid = G0_PORT_VID_DEF;
1184 }
1185
1186 mt7530_rmw(priv, MT7530_PPBV1_P(port), G0_PORT_VID_MASK, pvid);
1187 priv->ports[port].pvid = pvid;
1188
1189 mutex_unlock(&priv->reg_mutex);
1190
1191 return 0;
1192 }
1193
1194 static enum dsa_tag_protocol
1195 mtk_get_tag_protocol(struct dsa_switch *ds, int port)
1196 {
1197 struct mt7530_priv *priv = ds->priv;
1198
1199 if (port != MT7530_CPU_PORT) {
1200 dev_warn(priv->dev,
1201 "port not matched with tagging CPU port\n");
1202 return DSA_TAG_PROTO_NONE;
1203 } else {
1204 return DSA_TAG_PROTO_MTK;
1205 }
1206 }
1207
1208 static int
1209 mt7530_setup(struct dsa_switch *ds)
1210 {
1211 struct mt7530_priv *priv = ds->priv;
1212 int ret, i;
1213 u32 id, val;
1214 struct device_node *dn;
1215 struct mt7530_dummy_poll p;
1216
1217 /* The parent node of master netdev which holds the common system
1218 * controller also is the container for two GMACs nodes representing
1219 * as two netdev instances.
1220 */
1221 dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent;
1222 priv->ethernet = syscon_node_to_regmap(dn);
1223 if (IS_ERR(priv->ethernet))
1224 return PTR_ERR(priv->ethernet);
1225
1226 regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
1227 ret = regulator_enable(priv->core_pwr);
1228 if (ret < 0) {
1229 dev_err(priv->dev,
1230 "Failed to enable core power: %d\n", ret);
1231 return ret;
1232 }
1233
1234 regulator_set_voltage(priv->io_pwr, 3300000, 3300000);
1235 ret = regulator_enable(priv->io_pwr);
1236 if (ret < 0) {
1237 dev_err(priv->dev, "Failed to enable io pwr: %d\n",
1238 ret);
1239 return ret;
1240 }
1241
1242 /* Reset whole chip through gpio pin or memory-mapped registers for
1243 * different type of hardware
1244 */
1245 if (priv->mcm) {
1246 reset_control_assert(priv->rstc);
1247 usleep_range(1000, 1100);
1248 reset_control_deassert(priv->rstc);
1249 } else {
1250 gpiod_set_value_cansleep(priv->reset, 0);
1251 usleep_range(1000, 1100);
1252 gpiod_set_value_cansleep(priv->reset, 1);
1253 }
1254
1255 /* Waiting for MT7530 got to stable */
1256 INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP);
1257 ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
1258 20, 1000000);
1259 if (ret < 0) {
1260 dev_err(priv->dev, "reset timeout\n");
1261 return ret;
1262 }
1263
1264 id = mt7530_read(priv, MT7530_CREV);
1265 id >>= CHIP_NAME_SHIFT;
1266 if (id != MT7530_ID) {
1267 dev_err(priv->dev, "chip %x can't be supported\n", id);
1268 return -ENODEV;
1269 }
1270
1271 /* Reset the switch through internal reset */
1272 mt7530_write(priv, MT7530_SYS_CTRL,
1273 SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
1274 SYS_CTRL_REG_RST);
1275
1276 /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
1277 val = mt7530_read(priv, MT7530_MHWTRAP);
1278 val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
1279 val |= MHWTRAP_MANUAL;
1280 mt7530_write(priv, MT7530_MHWTRAP, val);
1281
1282 /* Enable and reset MIB counters */
1283 mt7530_mib_reset(ds);
1284
1285 mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
1286
1287 for (i = 0; i < MT7530_NUM_PORTS; i++) {
1288 /* Disable forwarding by default on all ports */
1289 mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
1290 PCR_MATRIX_CLR);
1291
1292 if (dsa_is_cpu_port(ds, i))
1293 mt7530_cpu_port_enable(priv, i);
1294 else
1295 mt7530_port_disable(ds, i, NULL);
1296 }
1297
1298 /* Flush the FDB table */
1299 ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0);
1300 if (ret < 0)
1301 return ret;
1302
1303 return 0;
1304 }
1305
1306 static const struct dsa_switch_ops mt7530_switch_ops = {
1307 .get_tag_protocol = mtk_get_tag_protocol,
1308 .setup = mt7530_setup,
1309 .get_strings = mt7530_get_strings,
1310 .phy_read = mt7530_phy_read,
1311 .phy_write = mt7530_phy_write,
1312 .get_ethtool_stats = mt7530_get_ethtool_stats,
1313 .get_sset_count = mt7530_get_sset_count,
1314 .adjust_link = mt7530_adjust_link,
1315 .port_enable = mt7530_port_enable,
1316 .port_disable = mt7530_port_disable,
1317 .port_stp_state_set = mt7530_stp_state_set,
1318 .port_bridge_join = mt7530_port_bridge_join,
1319 .port_bridge_leave = mt7530_port_bridge_leave,
1320 .port_fdb_add = mt7530_port_fdb_add,
1321 .port_fdb_del = mt7530_port_fdb_del,
1322 .port_fdb_dump = mt7530_port_fdb_dump,
1323 .port_vlan_filtering = mt7530_port_vlan_filtering,
From: kbuild test robot <hidden> Date: 2017-12-15 17:38:46
Hi Sean,
I love your patch! Perhaps something to improve:
[auto build test WARNING on net-next/master]
url: https://github.com/0day-ci/linux/commits/sean-wang-mediatek-com/add-VLAN-support-to-DSA-MT7530/20171215-214450
config: x86_64-randconfig-g0-12151942 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All warnings (new ones prefixed by >>):
drivers/net/dsa/mt7530.c: In function 'mt7530_port_vlan_add':
drivers/net/dsa/mt7530.c:1131:6: warning: unused variable 'ret' [-Wunused-variable]
int ret;
^
drivers/net/dsa/mt7530.c: At top level:
quoted
drivers/net/dsa/mt7530.c:1324:2: warning: initialization from incompatible pointer type