diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index eff87a344566..3fec84fa0997 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1061,6 +1061,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ mt6580-evbp1.dtb \ mt6589-aquaris5.dtb \ mt6592-evb.dtb \ + mt7623a-rfb-emmc.dtb \ mt7623n-rfb-nand.dtb \ mt7623n-bananapi-bpi-r2.dtb \ mt8127-moose.dtb \ diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi index d3b3f2e7d773..ae3a80ac19f0 100644 --- a/arch/arm/boot/dts/mt7623.dtsi +++ b/arch/arm/boot/dts/mt7623.dtsi @@ -1221,6 +1221,7 @@ "syscon"; reg = <0 0x1b000000 0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; eth: ethernet@1b100000 { diff --git a/arch/arm/boot/dts/mt7623a-rfb-emmc.dts b/arch/arm/boot/dts/mt7623a-rfb-emmc.dts new file mode 100644 index 000000000000..ed4236fa78cb --- /dev/null +++ b/arch/arm/boot/dts/mt7623a-rfb-emmc.dts @@ -0,0 +1,449 @@ +/* + * Copyright 2017 Sean Wang + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +/dts-v1/; +#include +#include "mt7623.dtsi" +#include "mt6323.dtsi" + +/ { + model = "MediaTek MT7623N NAND reference board"; + compatible = "mediatek,mt7623a-rfb-emmc", "mediatek,mt7623"; + + aliases { + serial2 = &uart2; + }; + + chosen { + bootargs = "earlyprintk block2mtd.block2mtd=/dev/mmcblk0,65536,eMMC,5 mtdparts=eMMC:256k(mbr)ro,512k(uboot)ro,256k(config)ro,256k(factory)ro,32M(kernel),32M(recovery),1024M(rootfs),2048M(usrdata),-(bmtpool) rootfstype=squashfs,jffs2"; + + stdout-path = "serial2:115200n8"; + }; + + memory { + reg = <0 0x80000000 0 0x20000000>; + }; + + cpus { + cpu@0 { + proc-supply = <&mt6323_vproc_reg>; + }; + + cpu@1 { + proc-supply = <&mt6323_vproc_reg>; + }; + + cpu@2 { + proc-supply = <&mt6323_vproc_reg>; + }; + + cpu@3 { + proc-supply = <&mt6323_vproc_reg>; + }; + }; + + memory@80000000 { + reg = <0 0x80000000 0 0x40000000>; + }; + + mt7530: switch@0 { + compatible = "mediatek,mt7530"; + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&crypto { + status = "okay"; +}; + +ð { + status = "okay"; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "trgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "rgmiii-rxid"; + phy-handle = <&phy5>; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + phy5: ethernet-phy@5 { + reg = <5>; + phy-mode = "rgmii-rxid"; + }; + }; +}; + +&mt7530 { + compatible = "mediatek,mt7530"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + pinctrl-names = "default"; + mediatek,mcm; + resets = <ðsys 2>; + reset-names = "mcm"; + core-supply = <&mt6323_vpa_reg>; + io-supply = <&mt6323_vemc3v3_reg>; + + dsa,mii-bus = <&mdio>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + port@0 { + reg = <0>; + label = "lan0"; + cpu = <&cpu_port0>; + }; + + port@1 { + reg = <1>; + label = "lan1"; + cpu = <&cpu_port0>; + }; + + port@2 { + reg = <2>; + label = "lan2"; + cpu = <&cpu_port0>; + }; + + port@3 { + reg = <3>; + label = "lan3"; + cpu = <&cpu_port0>; + }; + + cpu_port0: port@6 { + reg = <6>; + label = "cpu"; + ethernet = <&gmac0>; + phy-mode = "trgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins_a>; + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_default>; + pinctrl-1 = <&mmc0_pins_uhs>; + status = "okay"; + bus-width = <8>; + max-frequency = <50000000>; + cap-mmc-highspeed; + vmmc-supply = <&mt6323_vemc3v3_reg>; + vqmmc-supply = <&mt6323_vio18_reg>; + non-removable; +}; + +&mmc1 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc1_pins_default>; + pinctrl-1 = <&mmc1_pins_uhs>; + status = "okay"; + bus-width = <4>; + max-frequency = <50000000>; + cap-sd-highspeed; + cd-gpios = <&pio 261 0>; + vmmc-supply = <&mt6323_vmch_reg>; + vqmmc-supply = <&mt6323_vio18_reg>; +}; + +&pio { + cir_pins_a:cir@0 { + pins_cir { + pinmux = ; + bias-disable; + }; + }; + + i2c0_pins_a: i2c@0 { + pins_i2c0 { + pinmux = , + ; + bias-disable; + }; + }; + + i2c1_pins_a: i2c@1 { + pin_i2c1 { + pinmux = , + ; + bias-disable; + }; + }; + + i2s0_pins_a: i2s@0 { + pin_i2s0 { + pinmux = , + , + , + , + ; + drive-strength = ; + bias-pull-down; + }; + }; + + i2s1_pins_a: i2s@1 { + pin_i2s1 { + pinmux = , + , + , + , + ; + drive-strength = ; + bias-pull-down; + }; + }; + + mmc0_pins_default: mmc0default { + pins_cmd_dat { + pinmux = , + , + , + , + , + , + , + , + ; + input-enable; + bias-pull-up; + }; + + pins_clk { + pinmux = ; + bias-pull-down; + }; + + pins_rst { + pinmux = ; + bias-pull-up; + }; + }; + + mmc0_pins_uhs: mmc0 { + pins_cmd_dat { + pinmux = , + , + , + , + , + , + , + , + ; + input-enable; + drive-strength = ; + bias-pull-up = ; + }; + + pins_clk { + pinmux = ; + drive-strength = ; + bias-pull-down = ; + }; + + pins_rst { + pinmux = ; + bias-pull-up; + }; + }; + + mmc1_pins_default: mmc1default { + pins_cmd_dat { + pinmux = , + , + , + , + ; + input-enable; + drive-strength = ; + bias-pull-up = ; + }; + + pins_clk { + pinmux = ; + bias-pull-down; + drive-strength = ; + }; + + pins_wp { + pinmux = ; + input-enable; + bias-pull-up; + }; + + pins_insert { + pinmux = ; + bias-pull-up; + }; + }; + + mmc1_pins_uhs: mmc1 { + pins_cmd_dat { + pinmux = , + , + , + , + ; + input-enable; + drive-strength = ; + bias-pull-up = ; + }; + + pins_clk { + pinmux = ; + drive-strength = ; + bias-pull-down = ; + }; + }; + + pwm_pins_a: pwm@0 { + pins_pwm { + pinmux = , + , + , + , + ; + }; + }; + + spi0_pins_a: spi@0 { + pins_spi { + pinmux = , + , + , + ; + bias-disable; + }; + }; + + uart0_pins_a: uart@0 { + pins_dat { + pinmux = , + ; + }; + }; + + uart1_pins_a: uart@1 { + pins_dat { + pinmux = , + ; + }; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_pins_a>; + status = "okay"; +}; + +&pwrap { + mt6323 { + mt6323led: led { + compatible = "mediatek,mt6323-led"; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + label = "bpi-r2:isink:green"; + default-state = "off"; + }; + + led@1 { + reg = <1>; + label = "bpi-r2:isink:red"; + default-state = "off"; + }; + + led@2 { + reg = <2>; + label = "bpi-r2:isink:blue"; + default-state = "off"; + }; + }; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins_a>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins_a>; + status = "disabled"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins_a>; + status = "disabled"; +}; + +&uart2 { + status = "okay"; +}; + +&usb1 { + vusb33-supply = <&mt6323_vusb_reg>; + status = "okay"; +}; + +&usb2 { + vusb33-supply = <&mt6323_vusb_reg>; + status = "okay"; +}; + +&u3phy1 { + status = "okay"; +}; + +&u3phy2 { + status = "okay"; +}; + diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts index 62309133a2c5..61816bff084c 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 0x20000000>; + }; + cpus { cpu@0 { proc-supply = <&mt6323_vproc_reg>; @@ -92,17 +96,21 @@ default-state = "off"; }; }; - +/* memory@80000000 { 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"; + }; }; &cir { @@ -130,20 +138,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>; @@ -152,29 +175,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>; @@ -187,8 +227,6 @@ }; }; }; - }; -}; &hdmi0 { status = "okay"; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index c8d83acda006..46059bae9604 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -796,7 +796,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 9598889f972b..aec2bb1c53e5 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -771,6 +771,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 c142b97add2c..f59cf631f121 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[] = { @@ -1123,16 +1142,16 @@ static const struct of_device_id mt7530_of_match[] = { { /* sentinel */ }, }; -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 74db9822eb40..8fd7d78d785a 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 0a222612cbd8..762f59e738b1 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); @@ -1974,12 +2000,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); @@ -2438,7 +2470,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 3d3c24a28112..5a2c618cc95a 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 67f25ac29025..24430b170757 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1906,7 +1906,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 dd44d6ce1097..f83803293710 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 ffee085f0357..1fec2f9c72c3 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3611,6 +3611,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. @@ -3700,7 +3752,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; @@ -8737,6 +8789,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 045d8a176279..4be634747794 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 9c3eeb72462d..03b3f4fde24b 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 865e29e62bad..240bcb8c23e1 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;