diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi index a241219e10704..81e1a3f76aaa3 100644 --- a/arch/arm/boot/dts/mt7623.dtsi +++ b/arch/arm/boot/dts/mt7623.dtsi @@ -837,7 +837,7 @@ clocks = <&mmsys CLK_MM_MDP_BLS_26M>, <&mmsys CLK_MM_DISP_BLS>; clock-names = "main", "mm"; - status = "disabled"; + status = "disabled"; }; color@1400b000 { @@ -1236,5 +1236,6 @@ "syscon"; reg = <0 0x1c000000 0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; }; diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts index 15b2fd2509b47..a803b4d3969f9 100644 --- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts @@ -21,6 +21,10 @@ stdout-path = "serial2:115200n8"; }; + memory { + reg = <0 0x80000000 0 0x80000000>; + }; + cpus { cpu@0 { proc-supply = <&mt6323_vproc_reg>; @@ -111,17 +115,16 @@ }; }; - memory@80000000 { - device_type = "memory"; - reg = <0 0x80000000 0 0x40000000>; - }; - vdd_fixed_vgpu_reg: fixedregulator@0 { compatible = "regulator-fixed"; regulator-name = "vdd_fixed_vgpu"; regulator-min-microvolt = <1150000>; regulator-max-microvolt = <1150000>; }; + + mt7530: switch@0 { + compatible = "mediatek,mt7530"; + }; }; &bls { @@ -158,20 +161,35 @@ }; }; + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "trgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + mdio: mdio-bus { #address-cells = <1>; #size-cells = <0>; - - switch@0 { + }; +}; + &mt7530 { compatible = "mediatek,mt7530"; #address-cells = <1>; #size-cells = <0>; - reg = <0>; + //reg = <0>; pinctrl-names = "default"; reset-gpios = <&pio 33 0>; core-supply = <&mt6323_vpa_reg>; io-supply = <&mt6323_vemc3v3_reg>; + dsa,mii-bus = <&mdio>; + ports { #address-cells = <1>; #size-cells = <0>; @@ -180,29 +198,46 @@ port@0 { reg = <0>; label = "wan"; + cpu = <&cpu_port1>; }; port@1 { reg = <1>; label = "lan0"; + cpu = <&cpu_port0>; }; port@2 { reg = <2>; label = "lan1"; + cpu = <&cpu_port0>; }; port@3 { reg = <3>; label = "lan2"; + cpu = <&cpu_port0>; }; port@4 { reg = <4>; label = "lan3"; + cpu = <&cpu_port0>; + }; + + cpu_port1: port@5 { + reg = <5>; + label = "cpu"; + ethernet = <&gmac1>; + phy-mode = "trgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + }; }; - port@6 { + cpu_port0: port@6 { reg = <6>; label = "cpu"; ethernet = <&gmac0>; @@ -215,8 +250,6 @@ }; }; }; - }; -}; &cec { status = "okay"; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 6f4c98ca6e508..09f157b0693bd 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -797,7 +797,7 @@ static void clk_disable_unused_subtree(struct clk_core *core) clk_core_disable_unprepare(core->parent); } -static bool clk_ignore_unused; +static bool clk_ignore_unused = true; static int __init clk_ignore_unused_setup(char *__unused) { clk_ignore_unused = true; diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index 11d52fb81c92c..7a85e7f2ea0f1 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -770,6 +770,8 @@ static void mtk_infrasys_init_early(struct device_node *node) if (r) pr_err("%s(): could not register clock provider: %d\n", __func__, r); + + mtk_register_reset_controller(node, 2, 0x30); } CLK_OF_DECLARE_DRIVER(mtk_infra, "mediatek,mt2701-infracfg", mtk_infrasys_init_early); diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 3b073e1522373..d8407a72d676a 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -670,10 +670,18 @@ static int mt7530_cpu_port_enable(struct mt7530_priv *priv, int port) { + u8 port_mask = 0; + int i; + /* Enable Mediatek header mode on the cpu port */ mt7530_write(priv, MT7530_PVC_P(port), PORT_SPEC_TAG); + /* Enable Mediatek header mode on the GMAC that the cpu port + * connects to */ + regmap_write_bits(priv->ethernet, MTK_GDMA_FWD_CFG(port), + GDMA_SPEC_TAG, GDMA_SPEC_TAG); + /* Setup the MAC by default for the cpu port */ mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK); @@ -686,8 +694,12 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv, /* CPU port gets connected to all user ports of * the switch */ + for (i = 0; i < MT7530_NUM_PORTS; i++) + if ((priv->ds->enabled_port_mask & BIT(i)) && + (dsa_port_upstream_port(priv->ds, i) == port)) + port_mask |= BIT(i); mt7530_write(priv, MT7530_PCR_P(port), - PCR_MATRIX(priv->ds->enabled_port_mask)); + PCR_MATRIX(port_mask)); return 0; } @@ -697,6 +709,7 @@ mt7530_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy) { struct mt7530_priv *priv = ds->priv; + u8 upstream = dsa_port_upstream_port(ds, port); mutex_lock(&priv->reg_mutex); @@ -707,7 +720,7 @@ mt7530_port_enable(struct dsa_switch *ds, int port, * restore the port matrix if the port is the member of a certain * bridge. */ - priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); + priv->ports[port].pm |= PCR_MATRIX(BIT(upstream)); priv->ports[port].enable = true; mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, priv->ports[port].pm); @@ -770,7 +783,8 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *bridge) { struct mt7530_priv *priv = ds->priv; - u32 port_bitmap = BIT(MT7530_CPU_PORT); + u8 upstream = dsa_port_upstream_port(ds, port); + u32 port_bitmap = BIT(upstream); int i; mutex_lock(&priv->reg_mutex); @@ -808,6 +822,7 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *bridge) { struct mt7530_priv *priv = ds->priv; + u8 upstream = dsa_port_upstream_port(ds, port); int i; mutex_lock(&priv->reg_mutex); @@ -832,8 +847,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, */ if (priv->ports[port].enable) mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, - PCR_MATRIX(BIT(MT7530_CPU_PORT))); - priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); + PCR_MATRIX(BIT(upstream))); + priv->ports[port].pm = PCR_MATRIX(BIT(upstream)); mutex_unlock(&priv->reg_mutex); } @@ -908,15 +923,7 @@ mt7530_port_fdb_dump(struct dsa_switch *ds, int port, static enum dsa_tag_protocol mtk_get_tag_protocol(struct dsa_switch *ds) { - struct mt7530_priv *priv = ds->priv; - - if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) { - dev_warn(priv->dev, - "port not matched with tagging CPU port\n"); - return DSA_TAG_PROTO_NONE; - } else { - return DSA_TAG_PROTO_MTK; - } + return DSA_TAG_PROTO_MTK; } static int @@ -989,8 +996,13 @@ mt7530_setup(struct dsa_switch *ds) /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */ val = mt7530_read(priv, MT7530_MHWTRAP); - val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; + val &= ~MHWTRAP_P5_DIS & ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; val |= MHWTRAP_MANUAL; + if (!dsa_is_cpu_port(ds, 5)) { + val |= MHWTRAP_P5_DIS; + val |= MHWTRAP_P5_MAC_SEL; + val |= MHWTRAP_P5_RGMII_MODE; + } mt7530_write(priv, MT7530_MHWTRAP, val); /* Enable and reset MIB counters */ @@ -1037,10 +1049,10 @@ static const struct dsa_switch_ops mt7530_switch_ops = { }; static int -mt7530_probe(struct mdio_device *mdiodev) +mt7530_probe(struct platform_device *mdiodev) { struct mt7530_priv *priv; - struct device_node *dn; + struct device_node *dn, *mdio; dn = mdiodev->dev.of_node; @@ -1088,7 +1100,12 @@ mt7530_probe(struct mdio_device *mdiodev) } } - priv->bus = mdiodev->bus; + mdio = of_parse_phandle(dn, "dsa,mii-bus", 0); + if (!mdio) + return -EINVAL; + priv->bus = of_mdio_find_bus(mdio); + if (!priv->bus) + return -EPROBE_DEFER; priv->dev = &mdiodev->dev; priv->ds->priv = priv; priv->ds->ops = &mt7530_switch_ops; @@ -1098,8 +1115,8 @@ mt7530_probe(struct mdio_device *mdiodev) return dsa_register_switch(priv->ds); } -static void -mt7530_remove(struct mdio_device *mdiodev) +static int +mt7530_remove(struct platform_device *mdiodev) { struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); int ret = 0; @@ -1116,6 +1133,8 @@ mt7530_remove(struct mdio_device *mdiodev) dsa_unregister_switch(priv->ds); mutex_destroy(&priv->reg_mutex); + + return 0; } static const struct of_device_id mt7530_of_match[] = { @@ -1124,16 +1143,16 @@ static const struct of_device_id mt7530_of_match[] = { }; MODULE_DEVICE_TABLE(of, mt7530_of_match); -static struct mdio_driver mt7530_mdio_driver = { +static struct platform_driver mtk_mt7530_driver = { .probe = mt7530_probe, .remove = mt7530_remove, - .mdiodrv.driver = { + .driver = { .name = "mt7530", .of_match_table = mt7530_of_match, }, }; +module_platform_driver(mtk_mt7530_driver); -mdio_module_driver(mt7530_mdio_driver); MODULE_AUTHOR("Sean Wang "); MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch"); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 74db9822eb404..8fd7d78d785a2 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -22,6 +22,10 @@ #define TRGMII_BASE(x) (0x10000 + (x)) +/* Registers for GDMA configuration access */ +#define MTK_GDMA_FWD_CFG(x) (0x500 + (x * 0x1000)) +#define GDMA_SPEC_TAG BIT(24) + /* Registers to ethsys access */ #define ETHSYS_CLKCFG0 0x2c #define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 2eea47ccffe8c..69b4e2c883694 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -80,7 +80,10 @@ static int mtk_mdio_busy_wait(struct mtk_eth *eth) return 0; if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT)) break; - usleep_range(10, 20); + if (in_atomic()) + udelay(10); + else + usleep_range(10, 20); } dev_err(eth->dev, "mdio: MDIO timeout\n"); @@ -410,6 +413,7 @@ static int mtk_mdio_init(struct mtk_eth *eth) snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name); ret = of_mdiobus_register(eth->mii_bus, mii_np); +printk("%s:%s[%d]%d %p\n", __FILE__, __func__, __LINE__, ret, eth->mii_bus); err_put_node: of_node_put(mii_np); @@ -713,8 +717,8 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, txd4 |= TX_DMA_CHKSUM; /* VLAN header offload */ - if (skb_vlan_tag_present(skb)) - txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); +// if (skb_vlan_tag_present(skb)) +// txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); mapped_addr = dma_map_single(eth->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); @@ -783,7 +787,16 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | (!nr_frags * TX_DMA_LS0))); - netdev_sent_queue(dev, skb->len); + /* we have a single DMA ring so BQL needs to be updated for all devices + * sitting on this ring + */ + for (i = 0; i < MTK_MAC_COUNT; i++) { + if (!eth->netdev[i]) + continue; + + netdev_sent_queue(eth->netdev[i], skb->len); + } + skb_tx_timestamp(skb); ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); @@ -994,10 +1007,16 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, if (!(trxd.rxd2 & RX_DMA_DONE)) break; - /* find out which mac the packet come from. values start at 1 */ - mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & - RX_DMA_FPORT_MASK; - mac--; + /* find out which mac the packet comes from. If the special tag is + * we can assume that the traffic is coming from the builtin mt7530 + * and the DSA driver has loaded. FPORT will be the physical switch + * port in this case rather than the FE forward port id. */ + if (!(trxd.rxd4 & RX_DMA_SP_TAG)) { + /* values start at 1 */ + mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & + RX_DMA_FPORT_MASK; + mac--; + } if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || !eth->netdev[mac])) @@ -1080,20 +1099,17 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget) struct mtk_tx_dma *desc; struct sk_buff *skb; struct mtk_tx_buf *tx_buf; - unsigned int done[MTK_MAX_DEVS]; - unsigned int bytes[MTK_MAX_DEVS]; + int total = 0, done = 0; + unsigned int bytes = 0; u32 cpu, dma; - int total = 0, i; - - memset(done, 0, sizeof(done)); - memset(bytes, 0, sizeof(bytes)); + int i; cpu = mtk_r32(eth, MTK_QTX_CRX_PTR); dma = mtk_r32(eth, MTK_QTX_DRX_PTR); desc = mtk_qdma_phys_to_virt(ring, cpu); - while ((cpu != dma) && budget) { + while ((cpu != dma) && (done < budget)) { u32 next_cpu = desc->txd2; int mac = 0; @@ -1110,9 +1126,8 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget) break; if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { - bytes[mac] += skb->len; - done[mac]++; - budget--; + bytes += skb->len; + done++; } mtk_tx_unmap(eth, tx_buf); @@ -1124,11 +1139,13 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget) mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); + /* we have a single DMA ring so BQL needs to be updated for all devices + * sitting on this ring + */ for (i = 0; i < MTK_MAC_COUNT; i++) { - if (!eth->netdev[i] || !done[i]) + if (!eth->netdev[i]) continue; - netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); - total += done[i]; + netdev_completed_queue(eth->netdev[i], done, bytes); } if (mtk_queue_stopped(eth) && @@ -1460,7 +1477,10 @@ static void mtk_hwlro_rx_uninit(struct mtk_eth *eth) for (i = 0; i < 10; i++) { val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0); if (val & MTK_LRO_RING_RELINQUISH_DONE) { - msleep(20); + if (in_atomic()) + mdelay(20); + else + msleep(20); continue; } break; @@ -1856,7 +1876,10 @@ static void mtk_stop_dma(struct mtk_eth *eth, u32 glo_cfg) for (i = 0; i < 10; i++) { val = mtk_r32(eth, glo_cfg); if (val & (MTK_TX_DMA_BUSY | MTK_RX_DMA_BUSY)) { - msleep(20); + if (in_atomic()) + mdelay(20); + else + msleep(20); continue; } break; @@ -1894,7 +1917,10 @@ static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) reset_bits, reset_bits); - usleep_range(1000, 1100); + if (in_atomic()) + udelay(1000); + else + usleep_range(1000, 1100); regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, reset_bits, ~reset_bits); @@ -1975,12 +2001,18 @@ static int mtk_hw_init(struct mtk_eth *eth) */ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); + val = mtk_r32(eth, MTK_CDMP_IG_CTRL); + mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); /* Enable RX VLan Offloading */ - mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + if (MTK_HW_FEATURES & NETIF_F_HW_VLAN_CTAG_RX) + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + else + mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); /* enable interrupt delay for RX */ mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); + //mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_QDMA_DELAY_INT); /* disable delay and normal interrupt */ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); @@ -2439,7 +2471,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; SET_NETDEV_DEV(eth->netdev[id], eth->dev); - eth->netdev[id]->watchdog_timeo = 5 * HZ; + eth->netdev[id]->watchdog_timeo = 30 * HZ; eth->netdev[id]->netdev_ops = &mtk_netdev_ops; eth->netdev[id]->base_addr = (unsigned long)eth->base; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 3d3c24a281123..5a2c618cc95a1 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -34,8 +34,6 @@ NETIF_MSG_TX_ERR) #define MTK_HW_FEATURES (NETIF_F_IP_CSUM | \ NETIF_F_RXCSUM | \ - NETIF_F_HW_VLAN_CTAG_TX | \ - NETIF_F_HW_VLAN_CTAG_RX | \ NETIF_F_SG | NETIF_F_TSO | \ NETIF_F_TSO6 | \ NETIF_F_IPV6_CSUM) @@ -74,6 +72,10 @@ #define MTK_CDMQ_IG_CTRL 0x1400 #define MTK_CDMQ_STAG_EN BIT(0) +/* CDMP Ingress Control Register */ +#define MTK_CDMP_IG_CTRL 0x400 +#define MTK_CDMP_STAG_EN BIT(0) + /* CDMP Exgress Control Register */ #define MTK_CDMP_EG_CTRL 0x404 @@ -289,6 +291,7 @@ /* QDMA descriptor rxd4 */ #define RX_DMA_L4_VALID BIT(24) +#define RX_DMA_SP_TAG BIT(22) #define RX_DMA_FPORT_SHIFT 19 #define RX_DMA_FPORT_MASK 0x7 diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index a1e7ea4d4b16e..f70ab56051da3 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1923,7 +1923,7 @@ static struct phy_driver genphy_driver = { .config_init = genphy_config_init, .features = PHY_GBIT_FEATURES | SUPPORTED_MII | SUPPORTED_AUI | SUPPORTED_FIBRE | - SUPPORTED_BNC, + SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause, .config_aneg = genphy_config_aneg, .aneg_done = genphy_aneg_done, .read_status = genphy_read_status, diff --git a/include/net/dsa.h b/include/net/dsa.h index dd44d6ce10976..f838032937100 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -185,6 +185,10 @@ struct dsa_port { u8 stp_state; struct net_device *bridge_dev; struct devlink_port devlink_port; + + struct net_device *ethernet; + int upstream; + /* * Original copy of the master netdev ethtool_ops */ @@ -266,6 +270,11 @@ static inline bool dsa_is_normal_port(struct dsa_switch *ds, int p) return !dsa_is_cpu_port(ds, p) && !dsa_is_dsa_port(ds, p); } +static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int p) +{ + return dsa_is_cpu_port(ds, p) || dsa_is_dsa_port(ds, p); +} + static inline u8 dsa_upstream_port(struct dsa_switch *ds) { struct dsa_switch_tree *dst = ds->dst; @@ -282,6 +291,18 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds) return ds->rtable[dst->cpu_dp->ds->index]; } +static inline u8 dsa_port_upstream_port(struct dsa_switch *ds, int port) +{ + /* + * If this port has a specific upstream cpu port, use it, + * otherwise use the switch default. + */ + if (ds->ports[port].upstream) + return ds->ports[port].upstream; + else + return dsa_upstream_port(ds); +} + typedef int dsa_fdb_dump_cb_t(const unsigned char *addr, u16 vid, bool is_static, void *data); struct dsa_switch_ops { diff --git a/net/core/dev.c b/net/core/dev.c index 6ca771f2f25b7..62f90249d9218 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3626,6 +3626,58 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb, return rflow; } +#define RPS_TBL_SIZE_SHIFT 10 +#define RPS_TBL_SIZE (1 << RPS_TBL_SIZE_SHIFT) +struct rps_table { + int core; + struct timer_list expire; +}; +static struct rps_table rps_table[RPS_TBL_SIZE]; +static int rps_table_last_core; + +static void rps_table_expire(unsigned long data) +{ + struct rps_table *entry = (struct rps_table *) data; + + entry->core = -1; +} + +static int rps_table_core(struct rps_map *map) +{ + int i; + + for (i = 0; i < map->len; i++) { + int cpu = map->cpus[(rps_table_last_core + i + 1) % map->len]; + if (cpu_online(cpu)) { + rps_table_last_core = cpu; + return cpu; + } + } + return map->cpus[0]; +} + +static int rps_table_lookup(struct rps_map *map, u32 hash) +{ + int bucket = hash & 0x3ff; + + if (rps_table[bucket].core < 0) + rps_table[bucket].core = rps_table_core(map); + mod_timer(&rps_table[bucket].expire, jiffies + HZ); + + return rps_table[bucket].core; +} + +static void rps_table_init(void) +{ + int i; + + for (i = 0; i < RPS_TBL_SIZE; i++) { + rps_table[i].core = -1; + setup_timer(&rps_table[i].expire, rps_table_expire, + (unsigned long) &rps_table[i]); + } +} + /* * get_rps_cpu is called from netif_receive_skb and returns the target * CPU from the RPS map of the receiving queue for a given skb. @@ -3715,7 +3767,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, try_rps: if (map) { - tcpu = map->cpus[reciprocal_scale(hash, map->len)]; + tcpu = rps_table_lookup(map, hash); if (cpu_online(tcpu)) { cpu = tcpu; goto done; @@ -8752,6 +8804,9 @@ static int __init net_dev_init(void) sd->backlog.weight = weight_p; } + if (IS_ENABLED(CONFIG_RPS)) + rps_table_init(); + dev_boot_phase = 0; /* The loopback device is special if any other network devices diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 045d8a1762793..4be634747794c 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -253,6 +253,8 @@ static int dsa_cpu_port_apply(struct dsa_port *port) memset(&port->devlink_port, 0, sizeof(port->devlink_port)); err = devlink_port_register(ds->devlink, &port->devlink_port, port->index); + if (port->netdev) + port->netdev->dsa_ptr = ds->dst; return err; } @@ -262,6 +264,12 @@ static void dsa_cpu_port_unapply(struct dsa_port *port) dsa_cpu_dsa_destroy(port); port->ds->cpu_port_mask &= ~BIT(port->index); + if (port->netdev) + port->netdev->dsa_ptr = NULL; + if (port->ethernet) { + dev_put(port->ethernet); + port->ethernet = NULL; + } } static int dsa_user_port_apply(struct dsa_port *port) @@ -505,10 +513,9 @@ static int dsa_cpu_parse(struct dsa_port *port, u32 index, dev_put(ethernet_dev); } - if (!dst->cpu_dp) { + if (!dst->cpu_dp) dst->cpu_dp = port; - dst->cpu_dp->netdev = ethernet_dev; - } + port->netdev = ethernet_dev; /* Initialize cpu_port_mask now for drv->setup() * to have access to a correct value, just like what @@ -526,6 +533,29 @@ static int dsa_cpu_parse(struct dsa_port *port, u32 index, dst->rcv = dst->tag_ops->rcv; + dev_hold(ethernet_dev); + ds->ports[index].ethernet = ethernet_dev; + ds->cpu_port_mask |= BIT(index); + + return 0; +} + +static int dsa_user_parse(struct dsa_port *port, u32 index, + struct dsa_switch *ds) +{ + struct device_node *cpu_port; + const unsigned int *cpu_port_reg; + int cpu_port_index; + + cpu_port = of_parse_phandle(port->dn, "cpu", 0); + if (cpu_port) { + cpu_port_reg = of_get_property(cpu_port, "reg", NULL); + if (!cpu_port_reg) + return -EINVAL; + cpu_port_index = be32_to_cpup(cpu_port_reg); + ds->ports[index].upstream = cpu_port_index; + } + return 0; } @@ -533,7 +563,7 @@ static int dsa_ds_parse(struct dsa_switch_tree *dst, struct dsa_switch *ds) { struct dsa_port *port; u32 index; - int err; + int err = 0; for (index = 0; index < ds->num_ports; index++) { port = &ds->ports[index]; @@ -546,6 +576,9 @@ static int dsa_ds_parse(struct dsa_switch_tree *dst, struct dsa_switch *ds) if (err) return err; } else { + err = dsa_user_parse(port, index, ds); + if (err) + return err; /* Initialize enabled_port_mask now for drv->setup() * to have access to a correct value, just like what * net/dsa/dsa.c::dsa_switch_setup_one does. diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 9c3eeb72462d8..03b3f4fde24b4 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -91,6 +91,8 @@ struct dsa_slave_priv { /* TC context */ struct list_head mall_tc_list; + + struct net_device *master; }; /* dsa.c */ @@ -177,6 +179,9 @@ extern const struct dsa_device_ops trailer_netdev_ops; static inline struct net_device *dsa_master_netdev(struct dsa_slave_priv *p) { + if (p->master) + return p->master; + return p->dp->cpu_dp->netdev; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 865e29e62bad8..240bcb8c23e18 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1257,7 +1257,7 @@ int dsa_slave_create(struct dsa_port *port, const char *name) int ret; cpu_dp = ds->dst->cpu_dp; - master = cpu_dp->netdev; + master = ds->ports[port->upstream].ethernet; if (!ds->num_tx_queues) ds->num_tx_queues = 1; @@ -1295,6 +1295,7 @@ int dsa_slave_create(struct dsa_port *port, const char *name) p->dp = port; INIT_LIST_HEAD(&p->mall_tc_list); p->xmit = dst->tag_ops->xmit; + p->master = master; p->old_pause = -1; p->old_link = -1;