diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index a429c9750add1..67742fbd80409 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -68,6 +70,8 @@ static const struct qca8k_mib_desc ar8327_mib[] = { MIB_DESC(1, 0x9c, "TxExcDefer"), MIB_DESC(1, 0xa0, "TxDefer"), MIB_DESC(1, 0xa4, "TxLateCol"), + MIB_DESC(1, 0xa8, "RXUnicast"), + MIB_DESC(1, 0xac, "TXUnicast"), }; /* The 32bit switch registers are accessed indirectly. To achieve this we need @@ -151,6 +155,25 @@ qca8k_set_page(struct mii_bus *bus, u16 page) static int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) { + return regmap_read(priv->regmap, reg, val); +} + +static int +qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) +{ + return regmap_write(priv->regmap, reg, val); +} + +static int +qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) +{ + return regmap_update_bits(priv->regmap, reg, mask, write_val); +} + +static int +qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) +{ + struct qca8k_priv *priv = (struct qca8k_priv *)ctx; struct mii_bus *bus = priv->bus; u16 r1, r2, page; int ret; @@ -171,8 +194,9 @@ qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) } static int -qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) +qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) { + struct qca8k_priv *priv = (struct qca8k_priv *)ctx; struct mii_bus *bus = priv->bus; u16 r1, r2, page; int ret; @@ -193,8 +217,9 @@ qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) } static int -qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) +qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) { + struct qca8k_priv *priv = (struct qca8k_priv *)ctx; struct mii_bus *bus = priv->bus; u16 r1, r2, page; u32 val; @@ -222,34 +247,6 @@ qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) return ret; } -static int -qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val) -{ - return qca8k_rmw(priv, reg, 0, val); -} - -static int -qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val) -{ - return qca8k_rmw(priv, reg, val, 0); -} - -static int -qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) -{ - struct qca8k_priv *priv = (struct qca8k_priv *)ctx; - - return qca8k_read(priv, reg, val); -} - -static int -qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) -{ - struct qca8k_priv *priv = (struct qca8k_priv *)ctx; - - return qca8k_write(priv, reg, val); -} - static const struct regmap_range qca8k_readable_ranges[] = { regmap_reg_range(0x0000, 0x00e4), /* Global control */ regmap_reg_range(0x0100, 0x0168), /* EEE control */ @@ -281,26 +278,19 @@ static struct regmap_config qca8k_regmap_config = { .max_register = 0x16ac, /* end MIB - Port6 range */ .reg_read = qca8k_regmap_read, .reg_write = qca8k_regmap_write, + .reg_update_bits = qca8k_regmap_update_bits, .rd_table = &qca8k_readable_table, + .disable_locking = true, /* Locking is handled by qca8k read/write */ + .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ }; static int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) { - int ret, ret1; u32 val; - ret = read_poll_timeout(qca8k_read, ret1, !(val & mask), - 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, - priv, reg, &val); - - /* Check if qca8k_read has failed for a different reason - * before returning -ETIMEDOUT - */ - if (ret < 0 && ret1 < 0) - return ret1; - - return ret; + return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, + QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); } static int @@ -319,18 +309,18 @@ qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) } /* vid - 83:72 */ - fdb->vid = (reg[2] >> QCA8K_ATU_VID_S) & QCA8K_ATU_VID_M; + fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); /* aging - 67:64 */ - fdb->aging = reg[2] & QCA8K_ATU_STATUS_M; + fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); /* portmask - 54:48 */ - fdb->port_mask = (reg[1] >> QCA8K_ATU_PORT_S) & QCA8K_ATU_PORT_M; + fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); /* mac - 47:0 */ - fdb->mac[0] = (reg[1] >> QCA8K_ATU_ADDR0_S) & 0xff; - fdb->mac[1] = reg[1] & 0xff; - fdb->mac[2] = (reg[0] >> QCA8K_ATU_ADDR2_S) & 0xff; - fdb->mac[3] = (reg[0] >> QCA8K_ATU_ADDR3_S) & 0xff; - fdb->mac[4] = (reg[0] >> QCA8K_ATU_ADDR4_S) & 0xff; - fdb->mac[5] = reg[0] & 0xff; + fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); + fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); + fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); + fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); + fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); + fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); return 0; } @@ -343,18 +333,18 @@ qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, int i; /* vid - 83:72 */ - reg[2] = (vid & QCA8K_ATU_VID_M) << QCA8K_ATU_VID_S; + reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); /* aging - 67:64 */ - reg[2] |= aging & QCA8K_ATU_STATUS_M; + reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); /* portmask - 54:48 */ - reg[1] = (port_mask & QCA8K_ATU_PORT_M) << QCA8K_ATU_PORT_S; + reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); /* mac - 47:0 */ - reg[1] |= mac[0] << QCA8K_ATU_ADDR0_S; - reg[1] |= mac[1]; - reg[0] |= mac[2] << QCA8K_ATU_ADDR2_S; - reg[0] |= mac[3] << QCA8K_ATU_ADDR3_S; - reg[0] |= mac[4] << QCA8K_ATU_ADDR4_S; - reg[0] |= mac[5]; + reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); + reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); /* load the array into the ARL table */ for (i = 0; i < 3; i++) @@ -372,7 +362,7 @@ qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) reg |= cmd; if (port >= 0) { reg |= QCA8K_ATU_FUNC_PORT_EN; - reg |= (port & QCA8K_ATU_FUNC_PORT_M) << QCA8K_ATU_FUNC_PORT_S; + reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); } /* Write the function register triggering the table access */ @@ -445,6 +435,81 @@ qca8k_fdb_flush(struct qca8k_priv *priv) mutex_unlock(&priv->reg_mutex); } +static int +qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, + const u8 *mac, u16 vid) +{ + struct qca8k_fdb fdb = { 0 }; + int ret; + + mutex_lock(&priv->reg_mutex); + + qca8k_fdb_write(priv, vid, 0, mac, 0); + ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); + if (ret < 0) + goto exit; + + ret = qca8k_fdb_read(priv, &fdb); + if (ret < 0) + goto exit; + + /* Rule exist. Delete first */ + if (!fdb.aging) { + ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); + if (ret) + goto exit; + } + + /* Add port to fdb portmask */ + fdb.port_mask |= port_mask; + + qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); + ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); + +exit: + mutex_unlock(&priv->reg_mutex); + return ret; +} + +static int +qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, + const u8 *mac, u16 vid) +{ + struct qca8k_fdb fdb = { 0 }; + int ret; + + mutex_lock(&priv->reg_mutex); + + qca8k_fdb_write(priv, vid, 0, mac, 0); + ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); + if (ret < 0) + goto exit; + + /* Rule doesn't exist. Why delete? */ + if (!fdb.aging) { + ret = -EINVAL; + goto exit; + } + + ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); + if (ret) + goto exit; + + /* Only port in the rule is this port. Don't re insert */ + if (fdb.port_mask == port_mask) + goto exit; + + /* Remove port from port mask */ + fdb.port_mask &= ~port_mask; + + qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); + ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); + +exit: + mutex_unlock(&priv->reg_mutex); + return ret; +} + static int qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) { @@ -454,7 +519,7 @@ qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) /* Set the command and VLAN index */ reg = QCA8K_VTU_FUNC1_BUSY; reg |= cmd; - reg |= vid << QCA8K_VTU_FUNC1_VID_S; + reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); /* Write the function register triggering the table access */ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); @@ -500,13 +565,11 @@ qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) if (ret < 0) goto out; reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; - reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port)); + reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); if (untagged) - reg |= QCA8K_VTU_FUNC0_EG_MODE_UNTAG << - QCA8K_VTU_FUNC0_EG_MODE_S(port); + reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); else - reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG << - QCA8K_VTU_FUNC0_EG_MODE_S(port); + reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); if (ret) @@ -534,15 +597,13 @@ qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); if (ret < 0) goto out; - reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port)); - reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT << - QCA8K_VTU_FUNC0_EG_MODE_S(port); + reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); + reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); /* Check if we're the last member to be removed */ del = true; for (i = 0; i < QCA8K_NUM_PORTS; i++) { - mask = QCA8K_VTU_FUNC0_EG_MODE_NOT; - mask <<= QCA8K_VTU_FUNC0_EG_MODE_S(i); + mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); if ((reg & mask) != mask) { del = false; @@ -571,7 +632,7 @@ qca8k_mib_init(struct qca8k_priv *priv) int ret; mutex_lock(&priv->reg_mutex); - ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); + ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); if (ret) goto exit; @@ -579,7 +640,7 @@ qca8k_mib_init(struct qca8k_priv *priv) if (ret) goto exit; - ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); + ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); if (ret) goto exit; @@ -600,9 +661,9 @@ qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) mask |= QCA8K_PORT_STATUS_LINK_AUTO; if (enable) - qca8k_reg_set(priv, QCA8K_REG_PORT_STATUS(port), mask); + regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); else - qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); + regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); } static u32 @@ -864,8 +925,8 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv) * a dt-overlay and driver reload changed the configuration */ - return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL, - QCA8K_MDIO_MASTER_EN); + return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, + QCA8K_MDIO_MASTER_EN); } /* Check if the devicetree declare the port:phy mapping */ @@ -983,7 +1044,7 @@ qca8k_parse_port_config(struct qca8k_priv *priv) u32 delay; /* We have 2 CPU port. Check them */ - for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) { + for (port = 0; port < QCA8K_NUM_PORTS; port++) { /* Skip every other port */ if (port != 0 && port != 6) continue; @@ -1014,7 +1075,7 @@ qca8k_parse_port_config(struct qca8k_priv *priv) mode == PHY_INTERFACE_MODE_RGMII_TXID) delay = 1; - if (delay > QCA8K_MAX_DELAY) { + if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); delay = 3; } @@ -1030,7 +1091,7 @@ qca8k_parse_port_config(struct qca8k_priv *priv) mode == PHY_INTERFACE_MODE_RGMII_RXID) delay = 2; - if (delay > QCA8K_MAX_DELAY) { + if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); delay = 3; } @@ -1089,14 +1150,6 @@ qca8k_setup(struct dsa_switch *ds) if (ret) return ret; - mutex_init(&priv->reg_mutex); - - /* Start by setting up the register mapping */ - priv->regmap = devm_regmap_init(ds->dev, NULL, priv, - &qca8k_regmap_config); - if (IS_ERR(priv->regmap)) - dev_warn(priv->dev, "regmap initialization failed"); - ret = qca8k_setup_mdio_bus(priv); if (ret) return ret; @@ -1110,16 +1163,16 @@ qca8k_setup(struct dsa_switch *ds) return ret; /* Make sure MAC06 is disabled */ - ret = qca8k_reg_clear(priv, QCA8K_REG_PORT0_PAD_CTRL, - QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); + ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, + QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); if (ret) { dev_err(priv->dev, "failed disabling MAC06 exchange"); return ret; } /* Enable CPU Port */ - ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, - QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); + ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, + QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); if (ret) { dev_err(priv->dev, "failed enabling CPU port"); return ret; @@ -1141,8 +1194,8 @@ qca8k_setup(struct dsa_switch *ds) /* Enable QCA header mode on all cpu ports */ if (dsa_is_cpu_port(ds, i)) { ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), - QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | - QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); + FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | + FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); if (ret) { dev_err(priv->dev, "failed enabling QCA header mode"); return ret; @@ -1159,10 +1212,10 @@ qca8k_setup(struct dsa_switch *ds) * for igmp, unknown, multicast and broadcast packet */ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, - BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | - BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | - BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | - BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); if (ret) return ret; @@ -1180,8 +1233,6 @@ qca8k_setup(struct dsa_switch *ds) /* Individual user ports get connected to CPU port only */ if (dsa_is_user_port(ds, i)) { - int shift = 16 * (i % 2); - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); @@ -1189,8 +1240,8 @@ qca8k_setup(struct dsa_switch *ds) return ret; /* Enable ARP Auto-learning by default */ - ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i), - QCA8K_PORT_LOOKUP_LEARN); + ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), + QCA8K_PORT_LOOKUP_LEARN); if (ret) return ret; @@ -1198,8 +1249,8 @@ qca8k_setup(struct dsa_switch *ds) * default egress vid */ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), - 0xfff << shift, - QCA8K_PORT_VID_DEF << shift); + QCA8K_EGREES_VLAN_PORT_MASK(i), + QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); if (ret) return ret; @@ -1246,7 +1297,7 @@ qca8k_setup(struct dsa_switch *ds) QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | QCA8K_PORT_HOL_CTRL1_WRED_EN; qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), - QCA8K_PORT_HOL_CTRL1_ING_BUF | + QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | QCA8K_PORT_HOL_CTRL1_WRED_EN, @@ -1265,8 +1316,8 @@ qca8k_setup(struct dsa_switch *ds) mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, - QCA8K_GLOBAL_FC_GOL_XON_THRES_S | - QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S, + QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | + QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, mask); } @@ -1281,6 +1332,10 @@ qca8k_setup(struct dsa_switch *ds) /* We don't have interrupts for link changes, so we need to poll */ ds->pcs_poll = true; + /* Set min a max ageing value supported */ + ds->ageing_time_min = 7000; + ds->ageing_time_max = 458745000; + return 0; } @@ -1627,12 +1682,16 @@ qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, static void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) { + const struct qca8k_match_data *match_data; + struct qca8k_priv *priv = ds->priv; int i; if (stringset != ETH_SS_STATS) return; - for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) + match_data = of_device_get_match_data(priv->dev); + + for (i = 0; i < match_data->mib_count; i++) strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, ETH_GSTRING_LEN); } @@ -1642,12 +1701,15 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) { struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + const struct qca8k_match_data *match_data; const struct qca8k_mib_desc *mib; u32 reg, i, val; u32 hi = 0; int ret; - for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) { + match_data = of_device_get_match_data(priv->dev); + + for (i = 0; i < match_data->mib_count; i++) { mib = &ar8327_mib[i]; reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; @@ -1670,10 +1732,15 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, static int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) { + const struct qca8k_match_data *match_data; + struct qca8k_priv *priv = ds->priv; + if (sset != ETH_SS_STATS) return 0; - return ARRAY_SIZE(ar8327_mib); + match_data = of_device_get_match_data(priv->dev); + + return match_data->mib_count; } static int @@ -1754,9 +1821,9 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) /* Add this port to the portvlan mask of the other ports * in the bridge */ - ret = qca8k_reg_set(priv, - QCA8K_PORT_LOOKUP_CTRL(i), - BIT(port)); + ret = regmap_set_bits(priv->regmap, + QCA8K_PORT_LOOKUP_CTRL(i), + BIT(port)); if (ret) return ret; if (i != port) @@ -1786,9 +1853,9 @@ qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) /* Remove this port to the portvlan mask of the other ports * in the bridge */ - qca8k_reg_clear(priv, - QCA8K_PORT_LOOKUP_CTRL(i), - BIT(port)); + regmap_clear_bits(priv->regmap, + QCA8K_PORT_LOOKUP_CTRL(i), + BIT(port)); } /* Set the cpu port to be the only one in the portvlan mask of @@ -1798,6 +1865,36 @@ qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); } +static void +qca8k_port_fast_age(struct dsa_switch *ds, int port) +{ + struct qca8k_priv *priv = ds->priv; + + mutex_lock(&priv->reg_mutex); + qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); + mutex_unlock(&priv->reg_mutex); +} + +static int +qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) +{ + struct qca8k_priv *priv = ds->priv; + unsigned int secs = msecs / 1000; + u32 val; + + /* AGE_TIME reg is set in 7s step */ + val = secs / 7; + + /* Handle case with 0 as val to NOT disable + * learning + */ + if (!val) + val = 1; + + return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, + QCA8K_ATU_AGE_TIME(val)); +} + static int qca8k_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy) @@ -1903,6 +2000,28 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port, return 0; } +static int +qca8k_port_mdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct qca8k_priv *priv = ds->priv; + const u8 *addr = mdb->addr; + u16 vid = mdb->vid; + + return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); +} + +static int +qca8k_port_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct qca8k_priv *priv = ds->priv; + const u8 *addr = mdb->addr; + u16 vid = mdb->vid; + + return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); +} + static int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, struct netlink_ext_ack *extack) @@ -1912,11 +2031,11 @@ qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, if (vlan_filtering) { ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), - QCA8K_PORT_LOOKUP_VLAN_MODE, + QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); } else { ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), - QCA8K_PORT_LOOKUP_VLAN_MODE, + QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); } @@ -1940,10 +2059,9 @@ qca8k_port_vlan_add(struct dsa_switch *ds, int port, } if (pvid) { - int shift = 16 * (port % 2); - ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), - 0xfff << shift, vlan->vid << shift); + QCA8K_EGREES_VLAN_PORT_MASK(port), + QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); if (ret) return ret; @@ -1998,6 +2116,7 @@ static const struct dsa_switch_ops qca8k_switch_ops = { .get_strings = qca8k_get_strings, .get_ethtool_stats = qca8k_get_ethtool_stats, .get_sset_count = qca8k_get_sset_count, + .set_ageing_time = qca8k_set_ageing_time, .get_mac_eee = qca8k_get_mac_eee, .set_mac_eee = qca8k_set_mac_eee, .port_enable = qca8k_port_enable, @@ -2007,9 +2126,12 @@ static const struct dsa_switch_ops qca8k_switch_ops = { .port_stp_state_set = qca8k_port_stp_state_set, .port_bridge_join = qca8k_port_bridge_join, .port_bridge_leave = qca8k_port_bridge_leave, + .port_fast_age = qca8k_port_fast_age, .port_fdb_add = qca8k_port_fdb_add, .port_fdb_del = qca8k_port_fdb_del, .port_fdb_dump = qca8k_port_fdb_dump, + .port_mdb_add = qca8k_port_mdb_add, + .port_mdb_del = qca8k_port_mdb_del, .port_vlan_filtering = qca8k_port_vlan_filtering, .port_vlan_add = qca8k_port_vlan_add, .port_vlan_del = qca8k_port_vlan_del, @@ -2037,7 +2159,7 @@ static int qca8k_read_switch_id(struct qca8k_priv *priv) if (ret < 0) return -ENODEV; - id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK); + id = QCA8K_MASK_CTRL_DEVICE_ID(val); if (id != data->id) { dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); return -ENODEV; @@ -2046,7 +2168,7 @@ static int qca8k_read_switch_id(struct qca8k_priv *priv) priv->switch_id = id; /* Save revision to communicate to the internal PHY driver */ - priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK); + priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); return 0; } @@ -2081,6 +2203,14 @@ qca8k_sw_probe(struct mdio_device *mdiodev) gpiod_set_value_cansleep(priv->reset_gpio, 0); } + /* Start by setting up the register mapping */ + priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, + &qca8k_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(priv->dev, "regmap initialization failed"); + return PTR_ERR(priv->regmap); + } + /* Check the detected switch id */ ret = qca8k_read_switch_id(priv); if (ret) @@ -2169,14 +2299,17 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, static const struct qca8k_match_data qca8327 = { .id = QCA8K_ID_QCA8327, .reduced_package = true, + .mib_count = QCA8K_QCA832X_MIB_COUNT, }; static const struct qca8k_match_data qca8328 = { .id = QCA8K_ID_QCA8327, + .mib_count = QCA8K_QCA832X_MIB_COUNT, }; static const struct qca8k_match_data qca833x = { .id = QCA8K_ID_QCA8337, + .mib_count = QCA8K_QCA833X_MIB_COUNT, }; static const struct of_device_id qca8k_of_match[] = { diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h index 128b8cf85e080..40ec8012622f7 100644 --- a/drivers/net/dsa/qca8k.h +++ b/drivers/net/dsa/qca8k.h @@ -21,6 +21,9 @@ #define PHY_ID_QCA8337 0x004dd036 #define QCA8K_ID_QCA8337 0x13 +#define QCA8K_QCA832X_MIB_COUNT 39 +#define QCA8K_QCA833X_MIB_COUNT 41 + #define QCA8K_BUSY_WAIT_TIMEOUT 2000 #define QCA8K_NUM_FDB_RECORDS 2048 @@ -30,9 +33,9 @@ /* Global control registers */ #define QCA8K_REG_MASK_CTRL 0x000 #define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0) -#define QCA8K_MASK_CTRL_REV_ID(x) ((x) >> 0) +#define QCA8K_MASK_CTRL_REV_ID(x) FIELD_GET(QCA8K_MASK_CTRL_REV_ID_MASK, x) #define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) -#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8) +#define QCA8K_MASK_CTRL_DEVICE_ID(x) FIELD_GET(QCA8K_MASK_CTRL_DEVICE_ID_MASK, x) #define QCA8K_REG_PORT0_PAD_CTRL 0x004 #define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) #define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) @@ -41,12 +44,11 @@ #define QCA8K_REG_PORT6_PAD_CTRL 0x00c #define QCA8K_PORT_PAD_RGMII_EN BIT(26) #define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) -#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22) +#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, x) #define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) -#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20) +#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, x) #define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) -#define QCA8K_MAX_DELAY 3 #define QCA8K_PORT_PAD_SGMII_EN BIT(7) #define QCA8K_REG_PWS 0x010 #define QCA8K_PWS_POWER_ON_SEL BIT(31) @@ -68,10 +70,12 @@ #define QCA8K_MDIO_MASTER_READ BIT(27) #define QCA8K_MDIO_MASTER_WRITE 0 #define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) -#define QCA8K_MDIO_MASTER_PHY_ADDR(x) ((x) << 21) -#define QCA8K_MDIO_MASTER_REG_ADDR(x) ((x) << 16) -#define QCA8K_MDIO_MASTER_DATA(x) (x) +#define QCA8K_MDIO_MASTER_PHY_ADDR_MASK GENMASK(25, 21) +#define QCA8K_MDIO_MASTER_PHY_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_PHY_ADDR_MASK, x) +#define QCA8K_MDIO_MASTER_REG_ADDR_MASK GENMASK(20, 16) +#define QCA8K_MDIO_MASTER_REG_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_REG_ADDR_MASK, x) #define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) +#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x) #define QCA8K_MDIO_MASTER_MAX_PORTS 5 #define QCA8K_MDIO_MASTER_MAX_REG 32 #define QCA8K_GOL_MAC_ADDR0 0x60 @@ -93,9 +97,7 @@ #define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12) #define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) #define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) -#define QCA8K_PORT_HDR_CTRL_RX_S 2 #define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0) -#define QCA8K_PORT_HDR_CTRL_TX_S 0 #define QCA8K_PORT_HDR_CTRL_ALL 2 #define QCA8K_PORT_HDR_CTRL_MGMT 1 #define QCA8K_PORT_HDR_CTRL_NONE 0 @@ -105,10 +107,11 @@ #define QCA8K_SGMII_EN_TX BIT(3) #define QCA8K_SGMII_EN_SD BIT(4) #define QCA8K_SGMII_CLK125M_DELAY BIT(7) -#define QCA8K_SGMII_MODE_CTRL_MASK (BIT(22) | BIT(23)) -#define QCA8K_SGMII_MODE_CTRL_BASEX (0 << 22) -#define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22) -#define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22) +#define QCA8K_SGMII_MODE_CTRL_MASK GENMASK(23, 22) +#define QCA8K_SGMII_MODE_CTRL(x) FIELD_PREP(QCA8K_SGMII_MODE_CTRL_MASK, x) +#define QCA8K_SGMII_MODE_CTRL_BASEX QCA8K_SGMII_MODE_CTRL(0x0) +#define QCA8K_SGMII_MODE_CTRL_PHY QCA8K_SGMII_MODE_CTRL(0x1) +#define QCA8K_SGMII_MODE_CTRL_MAC QCA8K_SGMII_MODE_CTRL(0x2) /* MAC_PWR_SEL registers */ #define QCA8K_REG_MAC_PWR_SEL 0x0e4 @@ -121,100 +124,118 @@ /* ACL registers */ #define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) -#define QCA8K_PORT_VLAN_CVID(x) (x << 16) -#define QCA8K_PORT_VLAN_SVID(x) x +#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) +#define QCA8K_PORT_VLAN_CVID(x) FIELD_PREP(QCA8K_PORT_VLAN_CVID_MASK, x) +#define QCA8K_PORT_VLAN_SVID_MASK GENMASK(11, 0) +#define QCA8K_PORT_VLAN_SVID(x) FIELD_PREP(QCA8K_PORT_VLAN_SVID_MASK, x) #define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8)) #define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470 #define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474 /* Lookup registers */ #define QCA8K_REG_ATU_DATA0 0x600 -#define QCA8K_ATU_ADDR2_S 24 -#define QCA8K_ATU_ADDR3_S 16 -#define QCA8K_ATU_ADDR4_S 8 +#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24) +#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16) +#define QCA8K_ATU_ADDR4_MASK GENMASK(15, 8) +#define QCA8K_ATU_ADDR5_MASK GENMASK(7, 0) #define QCA8K_REG_ATU_DATA1 0x604 -#define QCA8K_ATU_PORT_M 0x7f -#define QCA8K_ATU_PORT_S 16 -#define QCA8K_ATU_ADDR0_S 8 +#define QCA8K_ATU_PORT_MASK GENMASK(22, 16) +#define QCA8K_ATU_ADDR0_MASK GENMASK(15, 8) +#define QCA8K_ATU_ADDR1_MASK GENMASK(7, 0) #define QCA8K_REG_ATU_DATA2 0x608 -#define QCA8K_ATU_VID_M 0xfff -#define QCA8K_ATU_VID_S 8 -#define QCA8K_ATU_STATUS_M 0xf +#define QCA8K_ATU_VID_MASK GENMASK(19, 8) +#define QCA8K_ATU_STATUS_MASK GENMASK(3, 0) #define QCA8K_ATU_STATUS_STATIC 0xf #define QCA8K_REG_ATU_FUNC 0x60c #define QCA8K_ATU_FUNC_BUSY BIT(31) #define QCA8K_ATU_FUNC_PORT_EN BIT(14) #define QCA8K_ATU_FUNC_MULTI_EN BIT(13) #define QCA8K_ATU_FUNC_FULL BIT(12) -#define QCA8K_ATU_FUNC_PORT_M 0xf -#define QCA8K_ATU_FUNC_PORT_S 8 +#define QCA8K_ATU_FUNC_PORT_MASK GENMASK(11, 8) #define QCA8K_REG_VTU_FUNC0 0x610 #define QCA8K_VTU_FUNC0_VALID BIT(20) #define QCA8K_VTU_FUNC0_IVL_EN BIT(19) -#define QCA8K_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) -#define QCA8K_VTU_FUNC0_EG_MODE_MASK 3 -#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD 0 -#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG 1 -#define QCA8K_VTU_FUNC0_EG_MODE_TAG 2 -#define QCA8K_VTU_FUNC0_EG_MODE_NOT 3 +/* QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(17, 4) + * It does contain VLAN_MODE for each port [5:4] for port0, + * [7:6] for port1 ... [17:16] for port6. Use virtual port + * define to handle this. + */ +#define QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i) (4 + (_i) * 2) +#define QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(1, 0) +#define QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(_i) (GENMASK(1, 0) << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x0) +#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNMOD(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNMOD << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x1) +#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNTAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +#define QCA8K_VTU_FUNC0_EG_MODE_TAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x2) +#define QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_TAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +#define QCA8K_VTU_FUNC0_EG_MODE_NOT FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x3) +#define QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(_i) (QCA8K_VTU_FUNC0_EG_MODE_NOT << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) #define QCA8K_REG_VTU_FUNC1 0x614 #define QCA8K_VTU_FUNC1_BUSY BIT(31) -#define QCA8K_VTU_FUNC1_VID_S 16 +#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) #define QCA8K_VTU_FUNC1_FULL BIT(4) +#define QCA8K_REG_ATU_CTRL 0x618 +#define QCA8K_ATU_AGE_TIME_MASK GENMASK(15, 0) +#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) #define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 #define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) #define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 -#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S 24 -#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_S 16 -#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_S 8 -#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_S 0 +#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) +#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) +#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8) +#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0) #define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) #define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) -#define QCA8K_PORT_LOOKUP_VLAN_MODE GENMASK(9, 8) -#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE (0 << 8) -#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK (1 << 8) -#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK (2 << 8) -#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE (3 << 8) +#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8) +#define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x) +#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE QCA8K_PORT_LOOKUP_VLAN_MODE(0x0) +#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK QCA8K_PORT_LOOKUP_VLAN_MODE(0x1) +#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK QCA8K_PORT_LOOKUP_VLAN_MODE(0x2) +#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE QCA8K_PORT_LOOKUP_VLAN_MODE(0x3) #define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) -#define QCA8K_PORT_LOOKUP_STATE_DISABLED (0 << 16) -#define QCA8K_PORT_LOOKUP_STATE_BLOCKING (1 << 16) -#define QCA8K_PORT_LOOKUP_STATE_LISTENING (2 << 16) -#define QCA8K_PORT_LOOKUP_STATE_LEARNING (3 << 16) -#define QCA8K_PORT_LOOKUP_STATE_FORWARD (4 << 16) -#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16) +#define QCA8K_PORT_LOOKUP_STATE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_STATE_MASK, x) +#define QCA8K_PORT_LOOKUP_STATE_DISABLED QCA8K_PORT_LOOKUP_STATE(0x0) +#define QCA8K_PORT_LOOKUP_STATE_BLOCKING QCA8K_PORT_LOOKUP_STATE(0x1) +#define QCA8K_PORT_LOOKUP_STATE_LISTENING QCA8K_PORT_LOOKUP_STATE(0x2) +#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) +#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) #define QCA8K_PORT_LOOKUP_LEARN BIT(20) #define QCA8K_REG_GLOBAL_FC_THRESH 0x800 -#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) ((x) << 16) -#define QCA8K_GLOBAL_FC_GOL_XON_THRES_S GENMASK(24, 16) -#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) ((x) << 0) -#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S GENMASK(8, 0) +#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) +#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) +#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK GENMASK(8, 0) +#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, x) #define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF GENMASK(7, 4) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) ((x) << 4) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF GENMASK(11, 8) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) ((x) << 8) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF GENMASK(15, 12) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) ((x) << 12) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF GENMASK(19, 16) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) ((x) << 16) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF GENMASK(23, 20) -#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) ((x) << 20) -#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF GENMASK(29, 24) -#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) ((x) << 24) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK GENMASK(3, 0) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK, x) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK GENMASK(7, 4) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK, x) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK GENMASK(11, 8) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK, x) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK GENMASK(15, 12) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK, x) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK GENMASK(19, 16) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK, x) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK GENMASK(23, 20) +#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK, x) +#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK GENMASK(29, 24) +#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK, x) #define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) -#define QCA8K_PORT_HOL_CTRL1_ING_BUF GENMASK(3, 0) -#define QCA8K_PORT_HOL_CTRL1_ING(x) ((x) << 0) +#define QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK GENMASK(3, 0) +#define QCA8K_PORT_HOL_CTRL1_ING(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK, x) #define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6) #define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7) #define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8) #define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) /* Pkt edit registers */ +#define QCA8K_EGREES_VLAN_PORT_SHIFT(_i) (16 * ((_i) % 2)) +#define QCA8K_EGREES_VLAN_PORT_MASK(_i) (GENMASK(11, 0) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) +#define QCA8K_EGREES_VLAN_PORT(_i, x) ((x) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) #define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2))) /* L3 registers */ @@ -244,6 +265,7 @@ enum qca8k_fdb_cmd { QCA8K_FDB_FLUSH = 1, QCA8K_FDB_LOAD = 2, QCA8K_FDB_PURGE = 3, + QCA8K_FDB_FLUSH_PORT = 5, QCA8K_FDB_NEXT = 6, QCA8K_FDB_SEARCH = 7, }; @@ -264,6 +286,7 @@ struct ar8xxx_port_status { struct qca8k_match_data { u8 id; bool reduced_package; + u8 mib_count; }; enum {