| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054 |
- /*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Copyright (C) 2013 John Crispin <[email protected]>
- * Copyright (C) 2016 Vitaly Chekryzhev <[email protected]>
- */
- #include <linux/if.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/list.h>
- #include <linux/if_ether.h>
- #include <linux/skbuff.h>
- #include <linux/netdevice.h>
- #include <linux/netlink.h>
- #include <linux/bitops.h>
- #include <net/genetlink.h>
- #include <linux/switch.h>
- #include <linux/delay.h>
- #include <linux/phy.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/lockdep.h>
- #include <linux/workqueue.h>
- #include <linux/of_device.h>
- #include <linux/of.h>
- #include <asm/byteorder.h>
- #include "mt7530.h"
- #define MT7530_CPU_PORT 6
- #define MT7530_NUM_PORTS 8
- #define MT7530_NUM_VLANS 16
- #define MT7530_MAX_VID 4095
- #define MT7530_MIN_VID 0
- #define MT7530_NUM_ARL_RECORDS 2048
- #define ARL_LINE_LENGTH 30
- #define MT7530_PORT_MIB_TXB_ID 2 /* TxGOC */
- #define MT7530_PORT_MIB_RXB_ID 6 /* RxGOC */
- /* registers */
- #define REG_ESW_WT_MAC_MFC 0x10
- #define REG_ESW_WT_MAC_MFC_MIRROR_ENABLE BIT(3)
- #define REG_ESW_WT_MAC_MFC_MIRROR_DEST_MASK 0x07
- #define REG_ESW_VLAN_VTCR 0x90
- #define REG_ESW_VLAN_VAWD1 0x94
- #define REG_ESW_VLAN_VAWD2 0x98
- #define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2))
- #define REG_ESW_WT_MAC_ATC 0x80
- #define REG_ESW_TABLE_ATRD 0x8C
- #define REG_ESW_TABLE_TSRA1 0x84
- #define REG_ESW_TABLE_TSRA2 0x88
- #define REG_MAC_ATC_START 0x8004
- #define REG_MAC_ATC_NEXT 0x8005
- #define REG_MAC_ATC_BUSY 0x8000U
- #define REG_MAC_ATC_SRCH_HIT 0x2000U
- #define REG_MAC_ATC_SRCH_END 0x4000U
- #define REG_ATRD_VALID 0xff000000U
- #define REG_ATRD_PORT_MASK 0xff0U
- #define REG_ESW_VLAN_VAWD1_IVL_MAC BIT(30)
- #define REG_ESW_VLAN_VAWD1_VTAG_EN BIT(28)
- #define REG_ESW_VLAN_VAWD1_VALID BIT(0)
- /* vlan egress mode */
- enum {
- ETAG_CTRL_UNTAG = 0,
- ETAG_CTRL_TAG = 2,
- ETAG_CTRL_SWAP = 1,
- ETAG_CTRL_STACK = 3,
- };
- #define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8))
- #define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8))
- #define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8))
- #define REG_ESW_PORT_PCR_MIRROR_SRC_RX_BIT BIT(8)
- #define REG_ESW_PORT_PCR_MIRROR_SRC_TX_BIT BIT(9)
- #define REG_ESW_PORT_PCR_MIRROR_SRC_RX_MASK 0x0100
- #define REG_ESW_PORT_PCR_MIRROR_SRC_TX_MASK 0x0200
- #define REG_HWTRAP 0x7804
- #define MIB_DESC(_s , _o, _n) \
- { \
- .size = (_s), \
- .offset = (_o), \
- .name = (_n), \
- }
- struct mt7xxx_mib_desc {
- unsigned int size;
- unsigned int offset;
- const char *name;
- };
- static const struct mt7xxx_mib_desc mt7620_mibs[] = {
- MIB_DESC(1, MT7620_MIB_STATS_PPE_AC_BCNT0, "PPE_AC_BCNT0"),
- MIB_DESC(1, MT7620_MIB_STATS_PPE_AC_PCNT0, "PPE_AC_PCNT0"),
- MIB_DESC(1, MT7620_MIB_STATS_PPE_AC_BCNT63, "PPE_AC_BCNT63"),
- MIB_DESC(1, MT7620_MIB_STATS_PPE_AC_PCNT63, "PPE_AC_PCNT63"),
- MIB_DESC(1, MT7620_MIB_STATS_PPE_MTR_CNT0, "PPE_MTR_CNT0"),
- MIB_DESC(1, MT7620_MIB_STATS_PPE_MTR_CNT63, "PPE_MTR_CNT63"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_TX_GBCNT, "GDM1_TX_GBCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_TX_GPCNT, "GDM1_TX_GPCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_TX_SKIPCNT, "GDM1_TX_SKIPCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_TX_COLCNT, "GDM1_TX_COLCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_GBCNT1, "GDM1_RX_GBCNT1"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_GPCNT1, "GDM1_RX_GPCNT1"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_OERCNT, "GDM1_RX_OERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_FERCNT, "GDM1_RX_FERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_SERCNT, "GDM1_RX_SERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_LERCNT, "GDM1_RX_LERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_CERCNT, "GDM1_RX_CERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM1_RX_FCCNT, "GDM1_RX_FCCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_TX_GBCNT, "GDM2_TX_GBCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_TX_GPCNT, "GDM2_TX_GPCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_TX_SKIPCNT, "GDM2_TX_SKIPCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_TX_COLCNT, "GDM2_TX_COLCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_GBCNT, "GDM2_RX_GBCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_GPCNT, "GDM2_RX_GPCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_OERCNT, "GDM2_RX_OERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_FERCNT, "GDM2_RX_FERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_SERCNT, "GDM2_RX_SERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_LERCNT, "GDM2_RX_LERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_CERCNT, "GDM2_RX_CERCNT"),
- MIB_DESC(1, MT7620_MIB_STATS_GDM2_RX_FCCNT, "GDM2_RX_FCCNT")
- };
- static const struct mt7xxx_mib_desc mt7620_port_mibs[] = {
- MIB_DESC(1, MT7620_MIB_STATS_PORT_TGPCN, "TxGPC"),
- MIB_DESC(1, MT7620_MIB_STATS_PORT_TBOCN, "TxBOC"),
- MIB_DESC(1, MT7620_MIB_STATS_PORT_TGOCN, "TxGOC"),
- MIB_DESC(1, MT7620_MIB_STATS_PORT_TEPCN, "TxEPC"),
- MIB_DESC(1, MT7620_MIB_STATS_PORT_RGPCN, "RxGPC"),
- MIB_DESC(1, MT7620_MIB_STATS_PORT_RBOCN, "RxBOC"),
- MIB_DESC(1, MT7620_MIB_STATS_PORT_RGOCN, "RxGOC"),
- MIB_DESC(1, MT7620_MIB_STATS_PORT_REPC1N, "RxEPC1"),
- MIB_DESC(1, MT7620_MIB_STATS_PORT_REPC2N, "RxEPC2")
- };
- enum {
- /* Global attributes. */
- MT7530_ATTR_ENABLE_VLAN,
- };
- struct mt7530_port_entry {
- u16 pvid;
- bool mirror_rx;
- bool mirror_tx;
- };
- struct mt7530_vlan_entry {
- u16 vid;
- u8 member;
- u8 etags;
- };
- struct mt7530_priv {
- void __iomem *base;
- struct mii_bus *bus;
- struct switch_dev swdev;
- u8 mirror_dest_port;
- bool global_vlan_enable;
- struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS];
- struct mt7530_port_entry port_entries[MT7530_NUM_PORTS];
- char arl_buf[MT7530_NUM_ARL_RECORDS * ARL_LINE_LENGTH + 1];
- };
- struct mt7530_mapping {
- char *name;
- u16 pvids[MT7530_NUM_PORTS];
- u8 members[MT7530_NUM_VLANS];
- u8 etags[MT7530_NUM_VLANS];
- u16 vids[MT7530_NUM_VLANS];
- } mt7530_defaults[] = {
- {
- .name = "llllw",
- .pvids = { 1, 1, 1, 1, 2, 1, 1 },
- .members = { 0, 0x6f, 0x50 },
- .etags = { 0, 0x40, 0x40 },
- .vids = { 0, 1, 2 },
- }, {
- .name = "wllll",
- .pvids = { 2, 1, 1, 1, 1, 1, 1 },
- .members = { 0, 0x7e, 0x41 },
- .etags = { 0, 0x40, 0x40 },
- .vids = { 0, 1, 2 },
- }, {
- .name = "lwlll",
- .pvids = { 1, 2, 1, 1, 1, 1, 1 },
- .members = { 0, 0x7d, 0x42 },
- .etags = { 0, 0x40, 0x40 },
- .vids = { 0, 1, 2 },
- },
- };
- static struct mt7530_mapping*
- mt7530_find_mapping(struct device_node *np)
- {
- const char *map;
- int i;
- if (of_property_read_string(np, "mediatek,portmap", &map))
- return NULL;
- for (i = 0; i < ARRAY_SIZE(mt7530_defaults); i++)
- if (!strcmp(map, mt7530_defaults[i].name))
- return &mt7530_defaults[i];
- return NULL;
- }
- static void
- mt7530_apply_mapping(struct mt7530_priv *mt7530, struct mt7530_mapping *map)
- {
- int i = 0;
- for (i = 0; i < MT7530_NUM_PORTS; i++)
- mt7530->port_entries[i].pvid = map->pvids[i];
- for (i = 0; i < MT7530_NUM_VLANS; i++) {
- mt7530->vlan_entries[i].member = map->members[i];
- mt7530->vlan_entries[i].etags = map->etags[i];
- mt7530->vlan_entries[i].vid = map->vids[i];
- }
- }
- static int
- mt7530_reset_switch(struct switch_dev *dev)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- int i;
- memset(priv->port_entries, 0, sizeof(priv->port_entries));
- memset(priv->vlan_entries, 0, sizeof(priv->vlan_entries));
- /* set default vid of each vlan to the same number of vlan, so the vid
- * won't need be set explicitly.
- */
- for (i = 0; i < MT7530_NUM_VLANS; i++) {
- priv->vlan_entries[i].vid = i;
- }
- return 0;
- }
- static int
- mt7530_get_vlan_enable(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- val->value.i = priv->global_vlan_enable;
- return 0;
- }
- static int
- mt7530_set_vlan_enable(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- priv->global_vlan_enable = val->value.i != 0;
- return 0;
- }
- static u32
- mt7530_r32(struct mt7530_priv *priv, u32 reg)
- {
- u32 val;
- if (priv->bus) {
- u16 high, low;
- mutex_lock(&priv->bus->mdio_lock);
- __mdiobus_write(priv->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
- low = __mdiobus_read(priv->bus, 0x1f, (reg >> 2) & 0xf);
- high = __mdiobus_read(priv->bus, 0x1f, 0x10);
- mutex_unlock(&priv->bus->mdio_lock);
- return (high << 16) | (low & 0xffff);
- }
- val = ioread32(priv->base + reg);
- pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val);
- return val;
- }
- static void
- mt7530_w32(struct mt7530_priv *priv, u32 reg, u32 val)
- {
- if (priv->bus) {
- mutex_lock(&priv->bus->mdio_lock);
- __mdiobus_write(priv->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
- __mdiobus_write(priv->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
- __mdiobus_write(priv->bus, 0x1f, 0x10, val >> 16);
- mutex_unlock(&priv->bus->mdio_lock);
- return;
- }
- pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val);
- iowrite32(val, priv->base + reg);
- }
- static void
- mt7530_vtcr(struct mt7530_priv *priv, u32 cmd, u32 val)
- {
- int i;
- mt7530_w32(priv, REG_ESW_VLAN_VTCR, BIT(31) | (cmd << 12) | val);
- for (i = 0; i < 20; i++) {
- u32 val = mt7530_r32(priv, REG_ESW_VLAN_VTCR);
- if ((val & BIT(31)) == 0)
- break;
- udelay(1000);
- }
- if (i == 20)
- printk("mt7530: vtcr timeout\n");
- }
- static int
- mt7530_get_port_pvid(struct switch_dev *dev, int port, int *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- if (port >= MT7530_NUM_PORTS)
- return -EINVAL;
- *val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(port));
- *val &= 0xfff;
- return 0;
- }
- static int
- mt7530_set_port_pvid(struct switch_dev *dev, int port, int pvid)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- if (port >= MT7530_NUM_PORTS)
- return -EINVAL;
- if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID)
- return -EINVAL;
- priv->port_entries[port].pvid = pvid;
- return 0;
- }
- static int
- mt7530_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- u32 member;
- u32 etags;
- int i;
- val->len = 0;
- if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS)
- return -EINVAL;
- mt7530_vtcr(priv, 0, val->port_vlan);
- member = mt7530_r32(priv, REG_ESW_VLAN_VAWD1);
- member >>= 16;
- member &= 0xff;
- etags = mt7530_r32(priv, REG_ESW_VLAN_VAWD2);
- for (i = 0; i < MT7530_NUM_PORTS; i++) {
- struct switch_port *p;
- int etag;
- if (!(member & BIT(i)))
- continue;
- p = &val->value.ports[val->len++];
- p->id = i;
- etag = (etags >> (i * 2)) & 0x3;
- if (etag == ETAG_CTRL_TAG)
- p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
- else if (etag != ETAG_CTRL_UNTAG)
- printk("vlan %d port %d egress tag control neither untag nor tag: %d.\n",
- val->port_vlan, i, etag);
- }
- return 0;
- }
- static int
- mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- u8 member = 0;
- u8 etags = 0;
- int i;
- if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS ||
- val->len > MT7530_NUM_PORTS)
- return -EINVAL;
- for (i = 0; i < val->len; i++) {
- struct switch_port *p = &val->value.ports[i];
- if (p->id >= MT7530_NUM_PORTS)
- return -EINVAL;
- member |= BIT(p->id);
- if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
- etags |= BIT(p->id);
- }
- priv->vlan_entries[val->port_vlan].member = member;
- priv->vlan_entries[val->port_vlan].etags = etags;
- return 0;
- }
- static int
- mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- int vlan;
- u16 vid;
- vlan = val->port_vlan;
- vid = (u16)val->value.i;
- if (vlan < 0 || vlan >= MT7530_NUM_VLANS)
- return -EINVAL;
- if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID)
- return -EINVAL;
- priv->vlan_entries[vlan].vid = vid;
- return 0;
- }
- static int
- mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- u32 vid;
- int vlan;
- vlan = val->port_vlan;
- vid = mt7530_r32(priv, REG_ESW_VLAN_VTIM(vlan));
- if (vlan & 1)
- vid = vid >> 12;
- vid &= 0xfff;
- val->value.i = vid;
- return 0;
- }
- static int
- mt7530_get_mirror_monitor_port(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- val->value.i = priv->mirror_dest_port;
- return 0;
- }
- static int
- mt7530_set_mirror_monitor_port(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- priv->mirror_dest_port = val->value.i;
- return 0;
- }
- static int
- mt7530_get_port_mirror_rx(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- val->value.i = priv->port_entries[val->port_vlan].mirror_rx;
- return 0;
- }
- static int
- mt7530_set_port_mirror_rx(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- priv->port_entries[val->port_vlan].mirror_rx = val->value.i;
- return 0;
- }
- static int
- mt7530_get_port_mirror_tx(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- val->value.i = priv->port_entries[val->port_vlan].mirror_tx;
- return 0;
- }
- static int
- mt7530_set_port_mirror_tx(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- priv->port_entries[val->port_vlan].mirror_tx = val->value.i;
- return 0;
- }
- static void
- mt7530_write_vlan_entry(struct mt7530_priv *priv, int vlan, u16 vid,
- u8 ports, u8 etags)
- {
- int port;
- u32 val;
- /* vid of vlan */
- val = mt7530_r32(priv, REG_ESW_VLAN_VTIM(vlan));
- if (vlan % 2 == 0) {
- val &= 0xfff000;
- val |= vid;
- } else {
- val &= 0xfff;
- val |= (vid << 12);
- }
- mt7530_w32(priv, REG_ESW_VLAN_VTIM(vlan), val);
- /* vlan port membership */
- if (ports)
- mt7530_w32(priv, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC |
- REG_ESW_VLAN_VAWD1_VTAG_EN | (ports << 16) |
- REG_ESW_VLAN_VAWD1_VALID);
- else
- mt7530_w32(priv, REG_ESW_VLAN_VAWD1, 0);
- /* egress mode */
- val = 0;
- for (port = 0; port < MT7530_NUM_PORTS; port++) {
- if (etags & BIT(port))
- val |= ETAG_CTRL_TAG << (port * 2);
- else
- val |= ETAG_CTRL_UNTAG << (port * 2);
- }
- mt7530_w32(priv, REG_ESW_VLAN_VAWD2, val);
- /* write to vlan table */
- mt7530_vtcr(priv, 1, vlan);
- }
- static int
- mt7530_apply_config(struct switch_dev *dev)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- int i, j;
- u8 tag_ports;
- u8 untag_ports;
- bool is_mirror = false;
- if (!priv->global_vlan_enable) {
- for (i = 0; i < MT7530_NUM_PORTS; i++)
- mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00400000);
- mt7530_w32(priv, REG_ESW_PORT_PCR(MT7530_CPU_PORT), 0x00ff0000);
- for (i = 0; i < MT7530_NUM_PORTS; i++)
- mt7530_w32(priv, REG_ESW_PORT_PVC(i), 0x810000c0);
- return 0;
- }
- /* set all ports as security mode */
- for (i = 0; i < MT7530_NUM_PORTS; i++)
- mt7530_w32(priv, REG_ESW_PORT_PCR(i), 0x00ff0003);
- /* check if a port is used in tag/untag vlan egress mode */
- tag_ports = 0;
- untag_ports = 0;
- for (i = 0; i < MT7530_NUM_VLANS; i++) {
- u8 member = priv->vlan_entries[i].member;
- u8 etags = priv->vlan_entries[i].etags;
- if (!member)
- continue;
- for (j = 0; j < MT7530_NUM_PORTS; j++) {
- if (!(member & BIT(j)))
- continue;
- if (etags & BIT(j))
- tag_ports |= 1u << j;
- else
- untag_ports |= 1u << j;
- }
- }
- /* set all untag-only ports as transparent and the rest as user port */
- for (i = 0; i < MT7530_NUM_PORTS; i++) {
- u32 pvc_mode = 0x81000000;
- if (untag_ports & BIT(i) && !(tag_ports & BIT(i)))
- pvc_mode = 0x810000c0;
- mt7530_w32(priv, REG_ESW_PORT_PVC(i), pvc_mode);
- }
- /* first clear the swtich vlan table */
- for (i = 0; i < MT7530_NUM_VLANS; i++)
- mt7530_write_vlan_entry(priv, i, i, 0, 0);
- /* now program only vlans with members to avoid
- clobbering remapped entries in later iterations */
- for (i = 0; i < MT7530_NUM_VLANS; i++) {
- u16 vid = priv->vlan_entries[i].vid;
- u8 member = priv->vlan_entries[i].member;
- u8 etags = priv->vlan_entries[i].etags;
- if (member)
- mt7530_write_vlan_entry(priv, i, vid, member, etags);
- }
- /* Port Default PVID */
- for (i = 0; i < MT7530_NUM_PORTS; i++) {
- int vlan = priv->port_entries[i].pvid;
- u16 pvid = 0;
- u32 val;
- if (vlan < MT7530_NUM_VLANS && priv->vlan_entries[vlan].member)
- pvid = priv->vlan_entries[vlan].vid;
- val = mt7530_r32(priv, REG_ESW_PORT_PPBV1(i));
- val &= ~0xfff;
- val |= pvid;
- mt7530_w32(priv, REG_ESW_PORT_PPBV1(i), val);
- }
- /* set mirroring source port */
- for (i = 0; i < MT7530_NUM_PORTS; i++) {
- u32 val = mt7530_r32(priv, REG_ESW_PORT_PCR(i));
- if (priv->port_entries[i].mirror_rx) {
- val |= REG_ESW_PORT_PCR_MIRROR_SRC_RX_BIT;
- is_mirror = true;
- }
- if (priv->port_entries[i].mirror_tx) {
- val |= REG_ESW_PORT_PCR_MIRROR_SRC_TX_BIT;
- is_mirror = true;
- }
- mt7530_w32(priv, REG_ESW_PORT_PCR(i), val);
- }
- /* set mirroring monitor port */
- if (is_mirror) {
- u32 val = mt7530_r32(priv, REG_ESW_WT_MAC_MFC);
- val |= REG_ESW_WT_MAC_MFC_MIRROR_ENABLE;
- val &= ~REG_ESW_WT_MAC_MFC_MIRROR_DEST_MASK;
- val |= priv->mirror_dest_port;
- mt7530_w32(priv, REG_ESW_WT_MAC_MFC, val);
- }
- return 0;
- }
- static int
- mt7530_get_port_link(struct switch_dev *dev, int port,
- struct switch_port_link *link)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- u32 speed, pmsr;
- if (port < 0 || port >= MT7530_NUM_PORTS)
- return -EINVAL;
- pmsr = mt7530_r32(priv, 0x3008 + (0x100 * port));
- link->link = pmsr & 1;
- link->duplex = (pmsr >> 1) & 1;
- speed = (pmsr >> 2) & 3;
- switch (speed) {
- case 0:
- link->speed = SWITCH_PORT_SPEED_10;
- break;
- case 1:
- link->speed = SWITCH_PORT_SPEED_100;
- break;
- case 2:
- case 3: /* forced gige speed can be 2 or 3 */
- link->speed = SWITCH_PORT_SPEED_1000;
- break;
- default:
- link->speed = SWITCH_PORT_SPEED_UNKNOWN;
- break;
- }
- return 0;
- }
- static u64 get_mib_counter_7620(struct mt7530_priv *priv, int i)
- {
- return mt7530_r32(priv, MT7620_MIB_COUNTER_BASE + mt7620_mibs[i].offset);
- }
- static u64 get_mib_counter_port_7620(struct mt7530_priv *priv, int i, int port)
- {
- return mt7530_r32(priv,
- MT7620_MIB_COUNTER_BASE_PORT +
- (MT7620_MIB_COUNTER_PORT_OFFSET * port) +
- mt7620_port_mibs[i].offset);
- }
- static int mt7530_sw_get_mib(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- static char buf[4096];
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- int i, len = 0;
- len += snprintf(buf + len, sizeof(buf) - len, "Switch MIB counters\n");
- for (i = 0; i < ARRAY_SIZE(mt7620_mibs); ++i) {
- u64 counter;
- len += snprintf(buf + len, sizeof(buf) - len,
- "%-11s: ", mt7620_mibs[i].name);
- counter = get_mib_counter_7620(priv, i);
- len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
- counter);
- }
- val->value.s = buf;
- val->len = len;
- return 0;
- }
- static char *mt7530_print_arl_table_row(u32 atrd,
- u32 mac1,
- u32 mac2,
- char *buf,
- size_t *size)
- {
- int ret;
- size_t port;
- size_t i;
- u8 port_map;
- u8 mac[ETH_ALEN];
- mac1 = ntohl(mac1);
- mac2 = ntohl(mac2);
- port_map = (u8)((atrd & REG_ATRD_PORT_MASK) >> 4);
- memcpy(mac, &mac1, sizeof(mac1));
- memcpy(mac + sizeof(mac1), &mac2, sizeof(mac) - sizeof(mac1));
- for (port = 0, i = 1; port < MT7530_NUM_PORTS; ++port, i <<= 1) {
- if (port_map & i) {
- ret = snprintf(buf, *size, "Port %d: MAC %pM\n", port, mac);
- if (ret >= *size || ret <= 0) {
- *buf = 0;
- buf = NULL;
- goto out;
- }
- buf += ret;
- *size = *size - ret;
- }
- }
- out:
- return buf;
- }
- static int mt7530_get_arl_table(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- char *buf = priv->arl_buf;
- size_t size = sizeof(priv->arl_buf);
- size_t count = 0;
- size_t retry_times = 100;
- int ret;
- u32 atc;
- ret = snprintf(buf, size, "address resolution table\n");
- if (ret >= size || ret <= 0) {
- priv->arl_buf[0] = 0;
- goto out;
- }
- buf += ret;
- size = size - ret;
- mt7530_w32(priv, REG_ESW_WT_MAC_ATC, REG_MAC_ATC_START);
- do {
- atc = mt7530_r32(priv, REG_ESW_WT_MAC_ATC);
- if (atc & REG_MAC_ATC_SRCH_HIT && !(atc & REG_MAC_ATC_BUSY)) {
- u32 atrd;
- ++count;
- atrd = mt7530_r32(priv, REG_ESW_TABLE_ATRD);
- if (atrd & REG_ATRD_VALID) {
- u32 mac1;
- u32 mac2;
- mac1 = mt7530_r32(priv, REG_ESW_TABLE_TSRA1);
- mac2 = mt7530_r32(priv, REG_ESW_TABLE_TSRA2);
- if (!(atc & REG_MAC_ATC_SRCH_END))
- mt7530_w32(priv, REG_ESW_WT_MAC_ATC, REG_MAC_ATC_NEXT);
- buf = mt7530_print_arl_table_row(atrd, mac1, mac2, buf, &size);
- if (!buf) {
- pr_warn("%s: too many addresses\n", __func__);
- goto out;
- }
- } else if (!(atc & REG_MAC_ATC_SRCH_END)) {
- mt7530_w32(priv, REG_ESW_WT_MAC_ATC, REG_MAC_ATC_NEXT);
- }
- } else {
- --retry_times;
- usleep_range(1000, 5000);
- }
- } while (!(atc & REG_MAC_ATC_SRCH_END) &&
- count < MT7530_NUM_ARL_RECORDS &&
- retry_times > 0);
- out:
- val->value.s = priv->arl_buf;
- val->len = strlen(priv->arl_buf);
- return 0;
- }
- static int mt7530_sw_get_port_mib(struct switch_dev *dev,
- const struct switch_attr *attr,
- struct switch_val *val)
- {
- static char buf[4096];
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- int i, len = 0;
- if (val->port_vlan >= MT7530_NUM_PORTS)
- return -EINVAL;
- len += snprintf(buf + len, sizeof(buf) - len,
- "Port %d MIB counters\n", val->port_vlan);
- for (i = 0; i < ARRAY_SIZE(mt7620_port_mibs); ++i) {
- u64 counter;
- len += snprintf(buf + len, sizeof(buf) - len,
- "%-11s: ", mt7620_port_mibs[i].name);
- counter = get_mib_counter_port_7620(priv, i, val->port_vlan);
- len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
- counter);
- }
- val->value.s = buf;
- val->len = len;
- return 0;
- }
- static int mt7530_get_port_stats(struct switch_dev *dev, int port,
- struct switch_port_stats *stats)
- {
- struct mt7530_priv *priv = container_of(dev, struct mt7530_priv, swdev);
- if (port < 0 || port >= MT7530_NUM_PORTS)
- return -EINVAL;
- stats->tx_bytes = get_mib_counter_port_7620(priv, MT7530_PORT_MIB_TXB_ID, port);
- stats->rx_bytes = get_mib_counter_port_7620(priv, MT7530_PORT_MIB_RXB_ID, port);
- return 0;
- }
- static const struct switch_attr mt7530_global[] = {
- {
- .type = SWITCH_TYPE_INT,
- .name = "enable_vlan",
- .description = "VLAN mode (1:enabled)",
- .max = 1,
- .id = MT7530_ATTR_ENABLE_VLAN,
- .get = mt7530_get_vlan_enable,
- .set = mt7530_set_vlan_enable,
- }, {
- .type = SWITCH_TYPE_STRING,
- .name = "mib",
- .description = "Get MIB counters for switch",
- .get = mt7530_sw_get_mib,
- .set = NULL,
- }, {
- .type = SWITCH_TYPE_INT,
- .name = "mirror_monitor_port",
- .description = "Mirror monitor port",
- .set = mt7530_set_mirror_monitor_port,
- .get = mt7530_get_mirror_monitor_port,
- .max = MT7530_NUM_PORTS - 1
- },
- {
- .type = SWITCH_TYPE_STRING,
- .name = "arl_table",
- .description = "Get ARL table",
- .set = NULL,
- .get = mt7530_get_arl_table,
- },
- };
- static const struct switch_attr mt7530_port[] = {
- {
- .type = SWITCH_TYPE_STRING,
- .name = "mib",
- .description = "Get MIB counters for port",
- .get = mt7530_sw_get_port_mib,
- .set = NULL,
- }, {
- .type = SWITCH_TYPE_INT,
- .name = "enable_mirror_rx",
- .description = "Enable mirroring of RX packets",
- .set = mt7530_set_port_mirror_rx,
- .get = mt7530_get_port_mirror_rx,
- .max = 1,
- }, {
- .type = SWITCH_TYPE_INT,
- .name = "enable_mirror_tx",
- .description = "Enable mirroring of TX packets",
- .set = mt7530_set_port_mirror_tx,
- .get = mt7530_get_port_mirror_tx,
- .max = 1,
- },
- };
- static const struct switch_attr mt7530_vlan[] = {
- {
- .type = SWITCH_TYPE_INT,
- .name = "vid",
- .description = "VLAN ID (0-4094)",
- .set = mt7530_set_vid,
- .get = mt7530_get_vid,
- .max = 4094,
- },
- };
- static const struct switch_dev_ops mt7530_ops = {
- .attr_global = {
- .attr = mt7530_global,
- .n_attr = ARRAY_SIZE(mt7530_global),
- },
- .attr_port = {
- .attr = mt7530_port,
- .n_attr = ARRAY_SIZE(mt7530_port),
- },
- .attr_vlan = {
- .attr = mt7530_vlan,
- .n_attr = ARRAY_SIZE(mt7530_vlan),
- },
- .get_vlan_ports = mt7530_get_vlan_ports,
- .set_vlan_ports = mt7530_set_vlan_ports,
- .get_port_pvid = mt7530_get_port_pvid,
- .set_port_pvid = mt7530_set_port_pvid,
- .get_port_link = mt7530_get_port_link,
- .get_port_stats = mt7530_get_port_stats,
- .apply_config = mt7530_apply_config,
- .reset_switch = mt7530_reset_switch,
- };
- int
- mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan)
- {
- struct switch_dev *swdev;
- struct mt7530_priv *mt7530;
- struct mt7530_mapping *map;
- int ret;
- mt7530 = devm_kzalloc(dev, sizeof(struct mt7530_priv), GFP_KERNEL);
- if (!mt7530)
- return -ENOMEM;
- mt7530->base = base;
- mt7530->bus = bus;
- mt7530->global_vlan_enable = vlan;
- swdev = &mt7530->swdev;
- if (bus) {
- swdev->alias = "mt7530";
- swdev->name = "mt7530";
- } else {
- swdev->alias = "mt7620";
- swdev->name = "mt7620";
- }
- swdev->cpu_port = MT7530_CPU_PORT;
- swdev->ports = MT7530_NUM_PORTS;
- swdev->vlans = MT7530_NUM_VLANS;
- swdev->ops = &mt7530_ops;
- ret = register_switch(swdev, NULL);
- if (ret) {
- dev_err(dev, "failed to register mt7530\n");
- return ret;
- }
- map = mt7530_find_mapping(dev->of_node);
- if (map)
- mt7530_apply_mapping(mt7530, map);
- mt7530_apply_config(swdev);
- /* magic vodoo */
- if (bus && mt7530_r32(mt7530, REG_HWTRAP) != 0x1117edf) {
- dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n");
- mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf);
- }
- dev_info(dev, "loaded %s driver\n", swdev->name);
- return 0;
- }
|