diff options
Diffstat (limited to 'target/linux/mediatek/patches-4.19/0001-eth-sync-from-mtk-lede.patch')
-rw-r--r-- | target/linux/mediatek/patches-4.19/0001-eth-sync-from-mtk-lede.patch | 1646 |
1 files changed, 0 insertions, 1646 deletions
diff --git a/target/linux/mediatek/patches-4.19/0001-eth-sync-from-mtk-lede.patch b/target/linux/mediatek/patches-4.19/0001-eth-sync-from-mtk-lede.patch deleted file mode 100644 index 814f66cc4e..0000000000 --- a/target/linux/mediatek/patches-4.19/0001-eth-sync-from-mtk-lede.patch +++ /dev/null @@ -1,1646 +0,0 @@ ---- a/drivers/net/ethernet/mediatek/Kconfig -+++ b/drivers/net/ethernet/mediatek/Kconfig -@@ -1,6 +1,6 @@ - config NET_VENDOR_MEDIATEK - bool "MediaTek ethernet driver" -- depends on ARCH_MEDIATEK -+ depends on ARCH_MEDIATEK || RALINK - ---help--- - If you have a Mediatek SoC with ethernet, say Y. - ---- a/drivers/net/ethernet/mediatek/Makefile -+++ b/drivers/net/ethernet/mediatek/Makefile -@@ -2,4 +2,5 @@ - # Makefile for the Mediatek SoCs built-in ethernet macs - # - --obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o -+obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o mtk_sgmii.o \ -+ mtk_eth_path.o ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c -@@ -0,0 +1,333 @@ -+/* -+ * Copyright (C) 2018 MediaTek Inc. -+ * -+ * 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; version 2 of the License -+ * -+ * 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) 2018 Sean Wang <sean.wang@mediatek.com> -+ */ -+ -+#include <linux/phy.h> -+#include <linux/regmap.h> -+ -+#include "mtk_eth_soc.h" -+ -+struct mtk_eth_muxc { -+ int (*set_path)(struct mtk_eth *eth, int path); -+}; -+ -+static const char * const mtk_eth_mux_name[] = { -+ "mux_gdm1_to_gmac1_esw", "mux_gmac2_gmac0_to_gephy", -+ "mux_u3_gmac2_to_qphy", "mux_gmac1_gmac2_to_sgmii_rgmii", -+ "mux_gmac12_to_gephy_sgmii", -+}; -+ -+static const char * const mtk_eth_path_name[] = { -+ "gmac1_rgmii", "gmac1_trgmii", "gmac1_sgmii", "gmac2_rgmii", -+ "gmac2_sgmii", "gmac2_gephy", "gdm1_esw", -+}; -+ -+static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path) -+{ -+ u32 val, mask, set; -+ bool updated = true; -+ -+ switch (path) { -+ case MTK_ETH_PATH_GMAC1_SGMII: -+ mask = ~(u32)MTK_MUX_TO_ESW; -+ set = 0; -+ break; -+ case MTK_ETH_PATH_GDM1_ESW: -+ mask = ~(u32)MTK_MUX_TO_ESW; -+ set = MTK_MUX_TO_ESW; -+ break; -+ default: -+ updated = false; -+ break; -+ }; -+ -+ if (updated) { -+ val = mtk_r32(eth, MTK_MAC_MISC); -+ val = (val & mask) | set; -+ mtk_w32(eth, val, MTK_MAC_MISC); -+ } -+ -+ dev_info(eth->dev, "path %s in %s updated = %d\n", -+ mtk_eth_path_name[path], __func__, updated); -+ -+ return 0; -+} -+ -+static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path) -+{ -+ unsigned int val = 0; -+ bool updated = true; -+ -+ switch (path) { -+ case MTK_ETH_PATH_GMAC2_GEPHY: -+ val = ~(u32)GEPHY_MAC_SEL; -+ break; -+ default: -+ updated = false; -+ break; -+ } -+ -+ if (updated) -+ regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val); -+ -+ dev_info(eth->dev, "path %s in %s updated = %d\n", -+ mtk_eth_path_name[path], __func__, updated); -+ -+ return 0; -+} -+ -+static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) -+{ -+ unsigned int val = 0; -+ bool updated = true; -+ -+ switch (path) { -+ case MTK_ETH_PATH_GMAC2_SGMII: -+ val = CO_QPHY_SEL; -+ break; -+ default: -+ updated = false; -+ break; -+ } -+ -+ if (updated) -+ regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val); -+ -+ dev_info(eth->dev, "path %s in %s updated = %d\n", -+ mtk_eth_path_name[path], __func__, updated); -+ -+ return 0; -+} -+ -+static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path) -+{ -+ unsigned int val = 0; -+ bool updated = true; -+ -+ switch (path) { -+ case MTK_ETH_PATH_GMAC1_SGMII: -+ val = SYSCFG0_SGMII_GMAC1; -+ break; -+ case MTK_ETH_PATH_GMAC2_SGMII: -+ val = SYSCFG0_SGMII_GMAC2; -+ break; -+ case MTK_ETH_PATH_GMAC1_RGMII: -+ case MTK_ETH_PATH_GMAC2_RGMII: -+ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); -+ val &= SYSCFG0_SGMII_MASK; -+ -+ if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) || -+ (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2)) -+ val = 0; -+ else -+ updated = false; -+ break; -+ default: -+ updated = false; -+ break; -+ }; -+ -+ if (updated) -+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, -+ SYSCFG0_SGMII_MASK, val); -+ -+ dev_info(eth->dev, "path %s in %s updated = %d\n", -+ mtk_eth_path_name[path], __func__, updated); -+ -+ return 0; -+} -+ -+static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path) -+{ -+ unsigned int val = 0; -+ bool updated = true; -+ -+ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); -+ -+ switch (path) { -+ case MTK_ETH_PATH_GMAC1_SGMII: -+ val |= SYSCFG0_SGMII_GMAC1_V2; -+ break; -+ case MTK_ETH_PATH_GMAC2_GEPHY: -+ val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; -+ break; -+ case MTK_ETH_PATH_GMAC2_SGMII: -+ val |= SYSCFG0_SGMII_GMAC2_V2; -+ break; -+ default: -+ updated = false; -+ }; -+ -+ if (updated) -+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, -+ SYSCFG0_SGMII_MASK, val); -+ -+ if (!updated) -+ dev_info(eth->dev, "path %s no needs updatiion in %s\n", -+ mtk_eth_path_name[path], __func__); -+ -+ dev_info(eth->dev, "path %s in %s updated = %d\n", -+ mtk_eth_path_name[path], __func__, updated); -+ -+ return 0; -+} -+ -+static const struct mtk_eth_muxc mtk_eth_muxc[] = { -+ { .set_path = set_mux_gdm1_to_gmac1_esw, }, -+ { .set_path = set_mux_gmac2_gmac0_to_gephy, }, -+ { .set_path = set_mux_u3_gmac2_to_qphy, }, -+ { .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, }, -+ { .set_path = set_mux_gmac12_to_gephy_sgmii, } -+}; -+ -+static int mtk_eth_mux_setup(struct mtk_eth *eth, int path) -+{ -+ int i, err = 0; -+ -+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_PATH_BIT(path))) { -+ dev_info(eth->dev, "path %s isn't support on the SoC\n", -+ mtk_eth_path_name[path]); -+ return -EINVAL; -+ } -+ -+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX)) -+ return 0; -+ -+ /* Setup MUX in path fabric */ -+ for (i = 0; i < MTK_ETH_MUX_MAX; i++) { -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_MUX_BIT(i))) { -+ err = mtk_eth_muxc[i].set_path(eth, path); -+ if (err) -+ goto out; -+ } else { -+ dev_info(eth->dev, "mux %s isn't present on the SoC\n", -+ mtk_eth_mux_name[i]); -+ } -+ } -+ -+out: -+ return err; -+} -+ -+static int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) -+{ -+ unsigned int val = 0; -+ int sid, err, path; -+ -+ path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : -+ MTK_ETH_PATH_GMAC2_SGMII; -+ -+ /* Setup proper MUXes along the path */ -+ err = mtk_eth_mux_setup(eth, path); -+ if (err) -+ return err; -+ -+ /* The path GMAC to SGMII will be enabled once the SGMIISYS is being -+ * setup done. -+ */ -+ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); -+ -+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, -+ SYSCFG0_SGMII_MASK, ~(u32)SYSCFG0_SGMII_MASK); -+ -+ /* Decide how GMAC and SGMIISYS be mapped */ -+ sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 0 : mac_id; -+ -+ /* Setup SGMIISYS with the determined property */ -+ if (MTK_HAS_FLAGS(eth->sgmii->flags[sid], MTK_SGMII_PHYSPEED_AN)) -+ err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); -+ else -+ err = mtk_sgmii_setup_mode_force(eth->sgmii, sid); -+ -+ if (err) -+ return err; -+ -+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, -+ SYSCFG0_SGMII_MASK, val); -+ -+ return 0; -+} -+ -+static int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) -+{ -+ int err, path = 0; -+ -+ if (mac_id == 1) -+ path = MTK_ETH_PATH_GMAC2_GEPHY; -+ -+ if (!path) -+ return -EINVAL; -+ -+ /* Setup proper MUXes along the path */ -+ err = mtk_eth_mux_setup(eth, path); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) -+{ -+ int err, path; -+ -+ path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII : -+ MTK_ETH_PATH_GMAC2_RGMII; -+ -+ /* Setup proper MUXes along the path */ -+ err = mtk_eth_mux_setup(eth, path); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode) -+{ -+ int err; -+ -+ switch (phymode) { -+ case PHY_INTERFACE_MODE_TRGMII: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_MII: -+ case PHY_INTERFACE_MODE_REVMII: -+ case PHY_INTERFACE_MODE_RMII: -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) { -+ err = mtk_gmac_rgmii_path_setup(eth, mac_id); -+ if (err) -+ return err; -+ } -+ break; -+ case PHY_INTERFACE_MODE_SGMII: -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { -+ err = mtk_gmac_sgmii_path_setup(eth, mac_id); -+ if (err) -+ return err; -+ } -+ break; -+ case PHY_INTERFACE_MODE_GMII: -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) { -+ err = mtk_gmac_gephy_path_setup(eth, mac_id); -+ if (err) -+ return err; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -23,6 +23,7 @@ - #include <linux/reset.h> - #include <linux/tcp.h> - #include <linux/interrupt.h> -+#include <linux/mdio.h> - #include <linux/pinctrl/devinfo.h> - - #include "mtk_eth_soc.h" -@@ -54,8 +55,10 @@ static const struct mtk_ethtool_stats { - }; - - static const char * const mtk_clks_source_name[] = { -- "ethif", "esw", "gp0", "gp1", "gp2", "trgpll", "sgmii_tx250m", -- "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll" -+ "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll", -+ "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", -+ "sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb", -+ "sgmii_ck", "eth2pll", - }; - - void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) -@@ -84,8 +87,8 @@ static int mtk_mdio_busy_wait(struct mtk - return -1; - } - --static u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, -- u32 phy_register, u32 write_data) -+u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, -+ u32 phy_register, u32 write_data) - { - if (mtk_mdio_busy_wait(eth)) - return -1; -@@ -103,7 +106,7 @@ static u32 _mtk_mdio_write(struct mtk_et - return 0; - } - --static u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) -+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) - { - u32 d; - -@@ -123,6 +126,34 @@ static u32 _mtk_mdio_read(struct mtk_eth - return d; - } - -+u32 mtk_cl45_ind_read(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 *data) -+{ -+ mutex_lock(ð->mii_bus->mdio_lock); -+ -+ _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad); -+ _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg); -+ _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); -+ *data = _mtk_mdio_read(eth, port, MII_MMD_ADDR_DATA_REG); -+ -+ mutex_unlock(ð->mii_bus->mdio_lock); -+ -+ return 0; -+} -+ -+u32 mtk_cl45_ind_write(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 data) -+{ -+ mutex_lock(ð->mii_bus->mdio_lock); -+ -+ _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad); -+ _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg); -+ _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); -+ _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, data); -+ -+ mutex_unlock(ð->mii_bus->mdio_lock); -+ -+ return 0; -+} -+ - static int mtk_mdio_write(struct mii_bus *bus, int phy_addr, - int phy_reg, u16 val) - { -@@ -165,51 +196,12 @@ static void mtk_gmac0_rgmii_adjust(struc - mtk_w32(eth, val, TRGMII_TCK_CTRL); - } - --static void mtk_gmac_sgmii_hw_setup(struct mtk_eth *eth, int mac_id) --{ -- u32 val; -- -- /* Setup the link timer and QPHY power up inside SGMIISYS */ -- regmap_write(eth->sgmiisys, SGMSYS_PCS_LINK_TIMER, -- SGMII_LINK_TIMER_DEFAULT); -- -- regmap_read(eth->sgmiisys, SGMSYS_SGMII_MODE, &val); -- val |= SGMII_REMOTE_FAULT_DIS; -- regmap_write(eth->sgmiisys, SGMSYS_SGMII_MODE, val); -- -- regmap_read(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, &val); -- val |= SGMII_AN_RESTART; -- regmap_write(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, val); -- -- regmap_read(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, &val); -- val &= ~SGMII_PHYA_PWD; -- regmap_write(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, val); -- -- /* Determine MUX for which GMAC uses the SGMII interface */ -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_DUAL_GMAC_SHARED_SGMII)) { -- regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); -- val &= ~SYSCFG0_SGMII_MASK; -- val |= !mac_id ? SYSCFG0_SGMII_GMAC1 : SYSCFG0_SGMII_GMAC2; -- regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); -- -- dev_info(eth->dev, "setup shared sgmii for gmac=%d\n", -- mac_id); -- } -- -- /* Setup the GMAC1 going through SGMII path when SoC also support -- * ESW on GMAC1 -- */ -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC1_ESW | MTK_GMAC1_SGMII) && -- !mac_id) { -- mtk_w32(eth, 0, MTK_MAC_MISC); -- dev_info(eth->dev, "setup gmac1 going through sgmii"); -- } --} -- - static void mtk_phy_link_adjust(struct net_device *dev) - { - struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_eth *eth = mac->hw; - u16 lcl_adv = 0, rmt_adv = 0; -+ u32 lcl_eee = 0, rmt_eee = 0; - u8 flowctrl; - u32 mcr = MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | - MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | -@@ -229,7 +221,7 @@ static void mtk_phy_link_adjust(struct n - }; - - if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) && -- !mac->id && !mac->trgmii) -+ !mac->id && !mac->trgmii) - mtk_gmac0_rgmii_adjust(mac->hw, dev->phydev->speed); - - if (dev->phydev->link) -@@ -259,7 +251,16 @@ static void mtk_phy_link_adjust(struct n - flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", - flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); - } -+ /*EEE capability*/ -+ mtk_cl45_ind_read(eth, 0, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &lcl_eee); -+ mtk_cl45_ind_read(eth, 0, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &rmt_eee); -+ -+ if ((lcl_eee & rmt_eee & MDIO_EEE_1000T) == MDIO_EEE_1000T) -+ mcr |= MAC_MCR_MDIO_EEE_1000T; -+ if ((lcl_eee & rmt_eee & MDIO_EEE_100TX) == MDIO_EEE_100TX) -+ mcr |= MAC_MCR_MDIO_EEE_100TX; - -+ /*Setup MCR*/ - mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); - - if (dev->phydev->link) -@@ -290,10 +291,10 @@ static int mtk_phy_connect_node(struct m - return -ENODEV; - } - -- dev_info(eth->dev, -- "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", -- mac->id, phydev_name(phydev), phydev->phy_id, -- phydev->drv->name); -+ dev_info(eth->dev, -+ "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", -+ mac->id, phydev_name(phydev), phydev->phy_id, -+ phydev->drv->name); - - return 0; - } -@@ -304,6 +305,7 @@ static int mtk_phy_connect(struct net_de - struct mtk_eth *eth; - struct device_node *np; - u32 val; -+ int err; - - eth = mac->hw; - np = of_parse_phandle(mac->of_node, "phy-handle", 0); -@@ -313,6 +315,10 @@ static int mtk_phy_connect(struct net_de - if (!np) - return -ENODEV; - -+ err = mtk_setup_hw_path(eth, mac->id, of_get_phy_mode(np)); -+ if (err) -+ goto err_phy; -+ - mac->ge_mode = 0; - switch (of_get_phy_mode(np)) { - case PHY_INTERFACE_MODE_TRGMII: -@@ -323,10 +329,9 @@ static int mtk_phy_connect(struct net_de - case PHY_INTERFACE_MODE_RGMII: - break; - case PHY_INTERFACE_MODE_SGMII: -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) -- mtk_gmac_sgmii_hw_setup(eth, mac->id); - break; - case PHY_INTERFACE_MODE_MII: -+ case PHY_INTERFACE_MODE_GMII: - mac->ge_mode = 1; - break; - case PHY_INTERFACE_MODE_REVMII: -@@ -355,7 +360,7 @@ static int mtk_phy_connect(struct net_de - dev->phydev->speed = 0; - dev->phydev->duplex = 0; - -- if (of_phy_is_fixed_link(mac->of_node)) -+ if (!strncmp(dev->phydev->drv->name, "Generic", 7)) - dev->phydev->supported |= - SUPPORTED_Pause | SUPPORTED_Asym_Pause; - -@@ -535,37 +540,37 @@ static void mtk_stats_update(struct mtk_ - } - - static void mtk_get_stats64(struct net_device *dev, -- struct rtnl_link_stats64 *storage) -+ struct rtnl_link_stats64 *storage) - { -- struct mtk_mac *mac = netdev_priv(dev); -- struct mtk_hw_stats *hw_stats = mac->hw_stats; -- unsigned int start; -- -- if (netif_running(dev) && netif_device_present(dev)) { -- if (spin_trylock_bh(&hw_stats->stats_lock)) { -- mtk_stats_update_mac(mac); -- spin_unlock_bh(&hw_stats->stats_lock); -- } -- } -- -- do { -- start = u64_stats_fetch_begin_irq(&hw_stats->syncp); -- storage->rx_packets = hw_stats->rx_packets; -- storage->tx_packets = hw_stats->tx_packets; -- storage->rx_bytes = hw_stats->rx_bytes; -- storage->tx_bytes = hw_stats->tx_bytes; -- storage->collisions = hw_stats->tx_collisions; -- storage->rx_length_errors = hw_stats->rx_short_errors + -- hw_stats->rx_long_errors; -- storage->rx_over_errors = hw_stats->rx_overflow; -- storage->rx_crc_errors = hw_stats->rx_fcs_errors; -- storage->rx_errors = hw_stats->rx_checksum_errors; -- storage->tx_aborted_errors = hw_stats->tx_skip; -- } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); -- -- storage->tx_errors = dev->stats.tx_errors; -- storage->rx_dropped = dev->stats.rx_dropped; -- storage->tx_dropped = dev->stats.tx_dropped; -+ struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_hw_stats *hw_stats = mac->hw_stats; -+ unsigned int start; -+ -+ if (netif_running(dev) && netif_device_present(dev)) { -+ if (spin_trylock_bh(&hw_stats->stats_lock)) { -+ mtk_stats_update_mac(mac); -+ spin_unlock_bh(&hw_stats->stats_lock); -+ } -+ } -+ -+ do { -+ start = u64_stats_fetch_begin_irq(&hw_stats->syncp); -+ storage->rx_packets = hw_stats->rx_packets; -+ storage->tx_packets = hw_stats->tx_packets; -+ storage->rx_bytes = hw_stats->rx_bytes; -+ storage->tx_bytes = hw_stats->tx_bytes; -+ storage->collisions = hw_stats->tx_collisions; -+ storage->rx_length_errors = hw_stats->rx_short_errors + -+ hw_stats->rx_long_errors; -+ storage->rx_over_errors = hw_stats->rx_overflow; -+ storage->rx_crc_errors = hw_stats->rx_fcs_errors; -+ storage->rx_errors = hw_stats->rx_checksum_errors; -+ storage->tx_aborted_errors = hw_stats->tx_skip; -+ } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); -+ -+ storage->tx_errors = dev->stats.tx_errors; -+ storage->rx_dropped = dev->stats.rx_dropped; -+ storage->tx_dropped = dev->stats.tx_dropped; - } - - static inline int mtk_max_frag_size(int mtu) -@@ -605,10 +610,10 @@ static int mtk_init_fq_dma(struct mtk_et - dma_addr_t dma_addr; - int i; - -- eth->scratch_ring = dma_zalloc_coherent(eth->dev, -- cnt * sizeof(struct mtk_tx_dma), -- ð->phy_scratch_ring, -- GFP_ATOMIC); -+ eth->scratch_ring = dma_alloc_coherent(eth->dev, -+ cnt * sizeof(struct mtk_tx_dma), -+ ð->phy_scratch_ring, -+ GFP_ATOMIC | __GFP_ZERO); - if (unlikely(!eth->scratch_ring)) - return -ENOMEM; - -@@ -623,6 +628,7 @@ static int mtk_init_fq_dma(struct mtk_et - if (unlikely(dma_mapping_error(eth->dev, dma_addr))) - return -ENOMEM; - -+ memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt); - phy_ring_tail = eth->phy_scratch_ring + - (sizeof(struct mtk_tx_dma) * (cnt - 1)); - -@@ -673,7 +679,7 @@ static void mtk_tx_unmap(struct mtk_eth - } - tx_buf->flags = 0; - if (tx_buf->skb && -- (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) -+ (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) - dev_kfree_skb_any(tx_buf->skb); - tx_buf->skb = NULL; - } -@@ -689,6 +695,7 @@ static int mtk_tx_map(struct sk_buff *sk - unsigned int nr_frags; - int i, n_desc = 1; - u32 txd4 = 0, fport; -+ u32 qid = 0; - - itxd = ring->next_free; - if (itxd == ring->last_free) -@@ -708,9 +715,10 @@ static int mtk_tx_map(struct sk_buff *sk - if (skb->ip_summed == CHECKSUM_PARTIAL) - txd4 |= TX_DMA_CHKSUM; - -- /* VLAN header offload */ -- if (skb_vlan_tag_present(skb)) -- txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); -+#if defined(CONFIG_NET_MEDIATEK_HW_QOS) -+ qid = skb->mark & (MTK_QDMA_TX_MASK); -+ qid += (!mac->id) ? (MTK_QDMA_TX_MASK + 1) : 0; -+#endif - - mapped_addr = dma_map_single(eth->dev, skb->data, - skb_headlen(skb), DMA_TO_DEVICE); -@@ -727,6 +735,7 @@ static int mtk_tx_map(struct sk_buff *sk - /* TX SG offload */ - txd = itxd; - nr_frags = skb_shinfo(skb)->nr_frags; -+ - for (i = 0; i < nr_frags; i++) { - struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - unsigned int offset = 0; -@@ -753,10 +762,10 @@ static int mtk_tx_map(struct sk_buff *sk - last_frag = true; - - WRITE_ONCE(txd->txd1, mapped_addr); -- WRITE_ONCE(txd->txd3, (TX_DMA_SWC | -+ WRITE_ONCE(txd->txd3, (TX_DMA_SWC | QID_LOW_BITS(qid) | - TX_DMA_PLEN0(frag_map_size) | - last_frag * TX_DMA_LS0)); -- WRITE_ONCE(txd->txd4, fport); -+ WRITE_ONCE(txd->txd4, fport | QID_HIGH_BITS(qid)); - - tx_buf = mtk_desc_to_tx_buf(ring, txd); - memset(tx_buf, 0, sizeof(*tx_buf)); -@@ -775,9 +784,9 @@ static int mtk_tx_map(struct sk_buff *sk - /* store skb to cleanup */ - itx_buf->skb = skb; - -- WRITE_ONCE(itxd->txd4, txd4); - WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | -- (!nr_frags * TX_DMA_LS0))); -+ (!nr_frags * TX_DMA_LS0)) | QID_LOW_BITS(qid)); -+ WRITE_ONCE(itxd->txd4, txd4 | QID_HIGH_BITS(qid)); - - netdev_sent_queue(dev, skb->len); - skb_tx_timestamp(skb); -@@ -922,7 +931,7 @@ drop: - return NETDEV_TX_OK; - } - --static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) -+struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) - { - int i; - struct mtk_rx_ring *ring; -@@ -991,10 +1000,24 @@ static int mtk_poll_rx(struct napi_struc - break; - - /* find out which mac the packet come from. values start at 1 */ -+#if defined(CONFIG_NET_DSA) -+ mac = (trxd.rxd4 >> 22) & 0x1; -+ mac = (mac + 1) % 2; -+#else - mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & -- RX_DMA_FPORT_MASK; -- mac--; -- -+ RX_DMA_FPORT_MASK; -+ /* From QDMA(5). This is a external interface case of HWNAT. -+ * When the incoming frame comes from an external interface -+ * rather than GMAC1/GMAC2, HWNAT driver sends the original -+ * frame to PPE via PPD(ping pong device) for HWNAT RX -+ * frame learning. After learning, PPE transmit the -+ * original frame back to PPD again to run SW NAT path. -+ */ -+ if (mac == 5) -+ mac = 0; -+ else -+ mac--; -+#endif - if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || - !eth->netdev[mac])) - goto release_desc; -@@ -1044,6 +1067,7 @@ static int mtk_poll_rx(struct napi_struc - RX_DMA_VID(trxd.rxd3)) - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), - RX_DMA_VID(trxd.rxd3)); -+ - skb_record_rx_queue(skb, 0); - napi_gro_receive(napi, skb); - -@@ -1128,7 +1152,7 @@ static int mtk_poll_tx(struct mtk_eth *e - } - - if (mtk_queue_stopped(eth) && -- (atomic_read(&ring->free_count) > ring->thresh)) -+ (atomic_read(&ring->free_count) > ring->thresh)) - mtk_wake_queue(eth); - - return total; -@@ -1220,11 +1244,14 @@ static int mtk_tx_alloc(struct mtk_eth * - if (!ring->buf) - goto no_tx_mem; - -- ring->dma = dma_zalloc_coherent(eth->dev, MTK_DMA_SIZE * sz, -- &ring->phys, GFP_ATOMIC); -+ ring->dma = dma_alloc_coherent(eth->dev, -+ MTK_DMA_SIZE * sz, -+ &ring->phys, -+ GFP_ATOMIC | __GFP_ZERO); - if (!ring->dma) - goto no_tx_mem; - -+ memset(ring->dma, 0, MTK_DMA_SIZE * sz); - for (i = 0; i < MTK_DMA_SIZE; i++) { - int next = (i + 1) % MTK_DMA_SIZE; - u32 next_ptr = ring->phys + next * sz; -@@ -1317,9 +1344,10 @@ static int mtk_rx_alloc(struct mtk_eth * - return -ENOMEM; - } - -- ring->dma = dma_zalloc_coherent(eth->dev, -- rx_dma_size * sizeof(*ring->dma), -- &ring->phys, GFP_ATOMIC); -+ ring->dma = dma_alloc_coherent(eth->dev, -+ rx_dma_size * sizeof(*ring->dma), -+ &ring->phys, -+ GFP_ATOMIC | __GFP_ZERO); - if (!ring->dma) - return -ENOMEM; - -@@ -1516,8 +1544,8 @@ static int mtk_hwlro_add_ipaddr(struct n - int hwlro_idx; - - if ((fsp->flow_type != TCP_V4_FLOW) || -- (!fsp->h_u.tcp_ip4_spec.ip4dst) || -- (fsp->location > 1)) -+ (!fsp->h_u.tcp_ip4_spec.ip4dst) || -+ (fsp->location > 1)) - return -EINVAL; - - mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst); -@@ -1744,6 +1772,34 @@ static void mtk_tx_timeout(struct net_de - schedule_work(ð->pending_work); - } - -+static irqreturn_t mtk_handle_irq_tx_rx(int irq, void *_eth) -+{ -+ struct mtk_eth *eth = _eth; -+ u32 tx_status, rx_status; -+ -+ tx_status = mtk_r32(eth, MTK_QMTK_INT_STATUS); -+ -+ if (tx_status & MTK_TX_DONE_INT) { -+ if (likely(napi_schedule_prep(ð->tx_napi))) { -+ mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); -+ __napi_schedule(ð->tx_napi); -+ } -+ mtk_w32(eth, tx_status, MTK_QMTK_INT_STATUS); -+ } -+ -+ rx_status = mtk_r32(eth, MTK_PDMA_INT_STATUS); -+ -+ if (rx_status & MTK_RX_DONE_INT) { -+ if (likely(napi_schedule_prep(ð->rx_napi))) { -+ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); -+ __napi_schedule(ð->rx_napi); -+ } -+ mtk_w32(eth, rx_status, MTK_PDMA_INT_STATUS); -+ } -+ -+ return IRQ_HANDLED; -+} -+ - static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) - { - struct mtk_eth *eth = _eth; -@@ -1784,8 +1840,8 @@ static void mtk_poll_controller(struct n - - static int mtk_start_dma(struct mtk_eth *eth) - { -- u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; - int err; -+ u32 rx_2b_offet = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; - - err = mtk_dma_init(eth); - if (err) { -@@ -1801,7 +1857,7 @@ static int mtk_start_dma(struct mtk_eth - MTK_QDMA_GLO_CFG); - - mtk_w32(eth, -- MTK_RX_DMA_EN | rx_2b_offset | -+ MTK_RX_DMA_EN | rx_2b_offet | - MTK_RX_BT_32DWORDS | MTK_MULTI_EN, - MTK_PDMA_GLO_CFG); - -@@ -1814,7 +1870,7 @@ static int mtk_open(struct net_device *d - struct mtk_eth *eth = mac->hw; - - /* we run 2 netdevs on the same dma ring so we only bring it up once */ -- if (!refcount_read(ð->dma_refcnt)) { -+ if (!atomic_read(ð->dma_refcnt)) { - int err = mtk_start_dma(eth); - - if (err) -@@ -1824,10 +1880,8 @@ static int mtk_open(struct net_device *d - napi_enable(ð->rx_napi); - mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); - mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); -- refcount_set(ð->dma_refcnt, 1); - } -- else -- refcount_inc(ð->dma_refcnt); -+ atomic_inc(ð->dma_refcnt); - - phy_start(dev->phydev); - netif_start_queue(dev); -@@ -1867,7 +1921,7 @@ static int mtk_stop(struct net_device *d - phy_stop(dev->phydev); - - /* only shutdown DMA if this is the last user */ -- if (!refcount_dec_and_test(ð->dma_refcnt)) -+ if (!atomic_dec_and_test(ð->dma_refcnt)) - return 0; - - mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); -@@ -1973,14 +2027,16 @@ static int mtk_hw_init(struct mtk_eth *e - val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); - mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); - -- /* Enable RX VLan Offloading */ -- mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); -+ /* Disable RX VLan Offloading */ -+ mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); -+ -+#if defined(CONFIG_NET_DSA) -+ mtk_w32(eth, 0x81000001, MTK_CDMP_IG_CTRL); -+#endif - -- /* enable interrupt delay for RX */ -- mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); -+ mtk_w32(eth, 0x8f0f8f0f, MTK_PDMA_DELAY_INT); -+ mtk_w32(eth, 0x8f0f8f0f, MTK_QDMA_DELAY_INT); - -- /* disable delay and normal interrupt */ -- mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); - mtk_tx_irq_disable(eth, ~0); - mtk_rx_irq_disable(eth, ~0); - mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); -@@ -2172,27 +2228,27 @@ static int mtk_cleanup(struct mtk_eth *e - } - - static int mtk_get_link_ksettings(struct net_device *ndev, -- struct ethtool_link_ksettings *cmd) -+ struct ethtool_link_ksettings *cmd) - { -- struct mtk_mac *mac = netdev_priv(ndev); -+ struct mtk_mac *mac = netdev_priv(ndev); - -- if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) -- return -EBUSY; -+ if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) -+ return -EBUSY; - -- phy_ethtool_ksettings_get(ndev->phydev, cmd); -+ phy_ethtool_ksettings_get(ndev->phydev, cmd); - -- return 0; -+ return 0; - } - - static int mtk_set_link_ksettings(struct net_device *ndev, -- const struct ethtool_link_ksettings *cmd) -+ const struct ethtool_link_ksettings *cmd) - { -- struct mtk_mac *mac = netdev_priv(ndev); -+ struct mtk_mac *mac = netdev_priv(ndev); - -- if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) -- return -EBUSY; -+ if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) -+ return -EBUSY; - -- return phy_ethtool_ksettings_set(ndev->phydev, cmd); -+ return phy_ethtool_ksettings_set(ndev->phydev, cmd); - } - - static void mtk_get_drvinfo(struct net_device *dev, -@@ -2355,8 +2411,8 @@ static int mtk_set_rxnfc(struct net_devi - } - - static const struct ethtool_ops mtk_ethtool_ops = { -- .get_link_ksettings = mtk_get_link_ksettings, -- .set_link_ksettings = mtk_set_link_ksettings, -+ .get_link_ksettings = mtk_get_link_ksettings, -+ .set_link_ksettings = mtk_set_link_ksettings, - .get_drvinfo = mtk_get_drvinfo, - .get_msglevel = mtk_get_msglevel, - .set_msglevel = mtk_set_msglevel, -@@ -2366,7 +2422,7 @@ static const struct ethtool_ops mtk_etht - .get_sset_count = mtk_get_sset_count, - .get_ethtool_stats = mtk_get_ethtool_stats, - .get_rxnfc = mtk_get_rxnfc, -- .set_rxnfc = mtk_set_rxnfc, -+ .set_rxnfc = mtk_set_rxnfc, - }; - - static const struct net_device_ops mtk_netdev_ops = { -@@ -2463,6 +2519,7 @@ static int mtk_probe(struct platform_dev - { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct device_node *mac_np; -+ const struct of_device_id *match; - struct mtk_eth *eth; - int err; - int i; -@@ -2471,7 +2528,8 @@ static int mtk_probe(struct platform_dev - if (!eth) - return -ENOMEM; - -- eth->soc = of_device_get_match_data(&pdev->dev); -+ match = of_match_device(of_mtk_match, &pdev->dev); -+ eth->soc = (struct mtk_soc_data *)match->data; - - eth->dev = &pdev->dev; - eth->base = devm_ioremap_resource(&pdev->dev, res); -@@ -2489,26 +2547,37 @@ static int mtk_probe(struct platform_dev - return PTR_ERR(eth->ethsys); - } - -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { -- eth->sgmiisys = -- syscon_regmap_lookup_by_phandle(pdev->dev.of_node, -- "mediatek,sgmiisys"); -- if (IS_ERR(eth->sgmiisys)) { -- dev_err(&pdev->dev, "no sgmiisys regmap found\n"); -- return PTR_ERR(eth->sgmiisys); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_INFRA)) { -+ eth->infra = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, -+ "mediatek,infracfg"); -+ if (IS_ERR(eth->infra)) { -+ dev_info(&pdev->dev, "no ethsys regmap found\n"); -+ return PTR_ERR(eth->infra); - } - } - -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { -+ eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), -+ GFP_KERNEL); -+ if (!eth->sgmii) -+ return -ENOMEM; -+ -+ err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node, -+ eth->soc->ana_rgc3); -+ if (err) -+ return err; -+ } -+ - if (eth->soc->required_pctl) { - eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, - "mediatek,pctl"); - if (IS_ERR(eth->pctl)) { -- dev_err(&pdev->dev, "no pctl regmap found\n"); -+ dev_info(&pdev->dev, "no pctl regmap found\n"); - return PTR_ERR(eth->pctl); - } - } - -- for (i = 0; i < 3; i++) { -+ for (i = 0; i < eth->soc->irq_num; i++) { - eth->irq[i] = platform_get_irq(pdev, i); - if (eth->irq[i] < 0) { - dev_err(&pdev->dev, "no IRQ%d resource found\n", i); -@@ -2552,15 +2621,22 @@ static int mtk_probe(struct platform_dev - goto err_deinit_hw; - } - -- err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, -- dev_name(eth->dev), eth); -- if (err) -- goto err_free_dev; -+ if (eth->soc->irq_num > 1) { -+ err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, -+ dev_name(eth->dev), eth); -+ if (err) -+ goto err_free_dev; - -- err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, -- dev_name(eth->dev), eth); -- if (err) -- goto err_free_dev; -+ err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, -+ dev_name(eth->dev), eth); -+ if (err) -+ goto err_free_dev; -+ } else { -+ err = devm_request_irq(eth->dev, eth->irq[0], mtk_handle_irq_tx_rx, 0, -+ dev_name(eth->dev), eth); -+ if (err) -+ goto err_free_dev; -+ } - - err = mtk_mdio_init(eth); - if (err) -@@ -2626,27 +2702,48 @@ static int mtk_remove(struct platform_de - } - - static const struct mtk_soc_data mt2701_data = { -- .caps = MTK_GMAC1_TRGMII | MTK_HWLRO, -+ .caps = MT7623_CAPS | MTK_HWLRO, - .required_clks = MT7623_CLKS_BITMAP, - .required_pctl = true, -+ .irq_num = 3, - }; - - static const struct mtk_soc_data mt7622_data = { -- .caps = MTK_DUAL_GMAC_SHARED_SGMII | MTK_GMAC1_ESW | MTK_HWLRO, -+ .ana_rgc3 = 0x2028, -+ .caps = MT7622_CAPS | MTK_HWLRO, - .required_clks = MT7622_CLKS_BITMAP, - .required_pctl = false, -+ .irq_num = 3, - }; - - static const struct mtk_soc_data mt7623_data = { -- .caps = MTK_GMAC1_TRGMII | MTK_HWLRO, -+ .caps = MT7623_CAPS | MTK_HWLRO, - .required_clks = MT7623_CLKS_BITMAP, - .required_pctl = true, -+ .irq_num = 3, -+}; -+ -+static const struct mtk_soc_data leopard_data = { -+ .ana_rgc3 = 0x128, -+ .caps = LEOPARD_CAPS | MTK_HWLRO, -+ .required_clks = LEOPARD_CLKS_BITMAP, -+ .required_pctl = false, -+ .irq_num = 3, -+}; -+ -+static const struct mtk_soc_data mt7621_data = { -+ .caps = MT7621_CAPS, -+ .required_clks = MT7621_CLKS_BITMAP, -+ .required_pctl = false, -+ .irq_num = 1, - }; - - const struct of_device_id of_mtk_match[] = { - { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data}, - { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, - { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, -+ { .compatible = "mediatek,mt7629-eth", .data = &leopard_data}, -+ { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data}, - {}, - }; - MODULE_DEVICE_TABLE(of, of_mtk_match); ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -15,13 +15,17 @@ - #ifndef MTK_ETH_H - #define MTK_ETH_H - -+#include <linux/dma-mapping.h> -+#include <linux/netdevice.h> -+#include <linux/of_net.h> -+#include <linux/u64_stats_sync.h> - #include <linux/refcount.h> - - #define MTK_QDMA_PAGE_SIZE 2048 - #define MTK_MAX_RX_LENGTH 1536 - #define MTK_TX_DMA_BUF_LEN 0x3fff --#define MTK_DMA_SIZE 256 --#define MTK_NAPI_WEIGHT 64 -+#define MTK_DMA_SIZE 2048 -+#define MTK_NAPI_WEIGHT 256 - #define MTK_MAC_COUNT 2 - #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) - #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN) -@@ -36,8 +40,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) -@@ -76,6 +78,9 @@ - #define MTK_CDMQ_IG_CTRL 0x1400 - #define MTK_CDMQ_STAG_EN BIT(0) - -+/* CDMP Ingress Control Register */ -+#define MTK_CDMP_IG_CTRL 0x400 -+ - /* CDMP Exgress Control Register */ - #define MTK_CDMP_EG_CTRL 0x404 - -@@ -225,8 +230,9 @@ - #define MTK_TX_DONE_INT1 BIT(1) - #define MTK_TX_DONE_INT0 BIT(0) - #define MTK_RX_DONE_INT MTK_RX_DONE_DLY --#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ -- MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) -+#define MTK_TX_DONE_DLY BIT(28) -+#define MTK_TX_DONE_INT MTK_TX_DONE_DLY -+ - - /* QDMA Interrupt grouping registers */ - #define MTK_QDMA_INT_GRP1 0x1a20 -@@ -267,6 +273,12 @@ - #define MTK_GDM1_TX_GBCNT 0x2400 - #define MTK_STAT_OFFSET 0x40 - -+/* QDMA TX NUM */ -+#define MTK_QDMA_TX_NUM 16 -+#define MTK_QDMA_TX_MASK ((MTK_QDMA_TX_NUM / 2) - 1) -+#define QID_LOW_BITS(x) ((x) & 0xf) -+#define QID_HIGH_BITS(x) ((((x) >> 4) & 0x3) & GENMASK(21, 20)) -+ - /* QDMA descriptor txd4 */ - #define TX_DMA_CHKSUM (0x7 << 29) - #define TX_DMA_TSO BIT(28) -@@ -316,6 +328,8 @@ - #define MAC_MCR_RX_EN BIT(13) - #define MAC_MCR_BACKOFF_EN BIT(9) - #define MAC_MCR_BACKPR_EN BIT(8) -+#define MAC_MCR_MDIO_EEE_1000T BIT(7) -+#define MAC_MCR_MDIO_EEE_100TX BIT(6) - #define MAC_MCR_FORCE_RX_FC BIT(5) - #define MAC_MCR_FORCE_TX_FC BIT(4) - #define MAC_MCR_SPEED_1000 BIT(3) -@@ -368,9 +382,11 @@ - #define ETHSYS_SYSCFG0 0x14 - #define SYSCFG0_GE_MASK 0x3 - #define SYSCFG0_GE_MODE(x, y) (x << (12 + (y * 2))) --#define SYSCFG0_SGMII_MASK (3 << 8) --#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & GENMASK(9, 8)) --#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & GENMASK(9, 8)) -+#define SYSCFG0_SGMII_MASK GENMASK(9, 8) -+#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & SYSCFG0_SGMII_MASK) -+#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK) -+#define SYSCFG0_SGMII_GMAC1_V2 BIT(9) -+#define SYSCFG0_SGMII_GMAC2_V2 BIT(8) - - /* ethernet subsystem clock register */ - #define ETHSYS_CLKCFG0 0x2c -@@ -398,6 +414,16 @@ - #define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 - #define SGMII_PHYA_PWD BIT(4) - -+/* Infrasys subsystem config registers */ -+#define INFRA_MISC2 0x70c -+#define CO_QPHY_SEL BIT(0) -+#define GEPHY_MAC_SEL BIT(1) -+ -+/*MDIO control*/ -+#define MII_MMD_ACC_CTL_REG 0x0d -+#define MII_MMD_ADDR_DATA_REG 0x0e -+#define MMD_OP_MODE_DATA BIT(14) -+ - struct mtk_rx_dma { - unsigned int rxd1; - unsigned int rxd2; -@@ -462,15 +488,21 @@ enum mtk_tx_flags { - */ - enum mtk_clks_map { - MTK_CLK_ETHIF, -+ MTK_CLK_SGMIITOP, - MTK_CLK_ESW, - MTK_CLK_GP0, - MTK_CLK_GP1, - MTK_CLK_GP2, -+ MTK_CLK_FE, - MTK_CLK_TRGPLL, - MTK_CLK_SGMII_TX_250M, - MTK_CLK_SGMII_RX_250M, - MTK_CLK_SGMII_CDR_REF, - MTK_CLK_SGMII_CDR_FB, -+ MTK_CLK_SGMII2_TX_250M, -+ MTK_CLK_SGMII2_RX_250M, -+ MTK_CLK_SGMII2_CDR_REF, -+ MTK_CLK_SGMII2_CDR_FB, - MTK_CLK_SGMII_CK, - MTK_CLK_ETH2PLL, - MTK_CLK_MAX -@@ -488,6 +520,22 @@ enum mtk_clks_map { - BIT(MTK_CLK_SGMII_CDR_FB) | \ - BIT(MTK_CLK_SGMII_CK) | \ - BIT(MTK_CLK_ETH2PLL)) -+#define LEOPARD_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \ -+ BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \ -+ BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \ -+ BIT(MTK_CLK_SGMII_TX_250M) | \ -+ BIT(MTK_CLK_SGMII_RX_250M) | \ -+ BIT(MTK_CLK_SGMII_CDR_REF) | \ -+ BIT(MTK_CLK_SGMII_CDR_FB) | \ -+ BIT(MTK_CLK_SGMII2_TX_250M) | \ -+ BIT(MTK_CLK_SGMII2_RX_250M) | \ -+ BIT(MTK_CLK_SGMII2_CDR_REF) | \ -+ BIT(MTK_CLK_SGMII2_CDR_FB) | \ -+ BIT(MTK_CLK_SGMII_CK) | \ -+ BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) -+ -+#define MT7621_CLKS_BITMAP 0 -+ - enum mtk_dev_state { - MTK_HW_INIT, - MTK_RESETTING -@@ -557,35 +605,149 @@ struct mtk_rx_ring { - u32 crx_idx_reg; - }; - --#define MTK_TRGMII BIT(0) --#define MTK_GMAC1_TRGMII (BIT(1) | MTK_TRGMII) --#define MTK_ESW BIT(4) --#define MTK_GMAC1_ESW (BIT(5) | MTK_ESW) --#define MTK_SGMII BIT(8) --#define MTK_GMAC1_SGMII (BIT(9) | MTK_SGMII) --#define MTK_GMAC2_SGMII (BIT(10) | MTK_SGMII) --#define MTK_DUAL_GMAC_SHARED_SGMII (BIT(11) | MTK_GMAC1_SGMII | \ -- MTK_GMAC2_SGMII) -+enum mtk_eth_mux { -+ MTK_ETH_MUX_GDM1_TO_GMAC1_ESW, -+ MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY, -+ MTK_ETH_MUX_U3_GMAC2_TO_QPHY, -+ MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, -+ MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, -+ MTK_ETH_MUX_MAX, -+}; -+ -+enum mtk_eth_path { -+ MTK_ETH_PATH_GMAC1_RGMII, -+ MTK_ETH_PATH_GMAC1_TRGMII, -+ MTK_ETH_PATH_GMAC1_SGMII, -+ MTK_ETH_PATH_GMAC2_RGMII, -+ MTK_ETH_PATH_GMAC2_SGMII, -+ MTK_ETH_PATH_GMAC2_GEPHY, -+ MTK_ETH_PATH_GDM1_ESW, -+ MTK_ETH_PATH_MAX, -+}; -+ -+/* Capability for function group */ -+#define MTK_RGMII BIT(0) -+#define MTK_TRGMII BIT(1) -+#define MTK_SGMII BIT(2) -+#define MTK_ESW BIT(3) -+#define MTK_GEPHY BIT(4) -+#define MTK_MUX BIT(5) -+#define MTK_INFRA BIT(6) -+#define MTK_SHARED_SGMII BIT(7) -+ -+/* Capability for features on SoCs */ -+#define MTK_PATH_BIT(x) BIT((x) + 10) -+ -+#define MTK_GMAC1_RGMII \ -+ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_RGMII) | MTK_RGMII) -+ -+#define MTK_GMAC1_TRGMII \ -+ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_TRGMII) | MTK_TRGMII) -+ -+#define MTK_GMAC1_SGMII \ -+ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_SGMII) | MTK_SGMII) -+ -+#define MTK_GMAC2_RGMII \ -+ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_RGMII) | MTK_RGMII) -+ -+#define MTK_GMAC2_SGMII \ -+ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_SGMII) | MTK_SGMII) -+ -+#define MTK_GMAC2_GEPHY \ -+ (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_GEPHY) | MTK_GEPHY) -+ -+#define MTK_GDM1_ESW \ -+ (MTK_PATH_BIT(MTK_ETH_PATH_GDM1_ESW) | MTK_ESW) -+ -+#define MTK_MUX_BIT(x) BIT((x) + 20) -+ -+/* Capability for MUXes present on SoCs */ -+/* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */ -+#define MTK_MUX_GDM1_TO_GMAC1_ESW \ -+ (MTK_MUX_BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW) | MTK_MUX) -+ -+/* 0: GMAC2 -> GEPHY, 1: GMAC0 -> GePHY */ -+#define MTK_MUX_GMAC2_GMAC0_TO_GEPHY \ -+ (MTK_MUX_BIT(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY) | MTK_MUX | MTK_INFRA) -+ -+/* 0: U3 -> QPHY, 1: GMAC2 -> QPHY */ -+#define MTK_MUX_U3_GMAC2_TO_QPHY \ -+ (MTK_MUX_BIT(MTK_ETH_MUX_U3_GMAC2_TO_QPHY) | MTK_MUX | MTK_INFRA) -+ -+/* 2: GMAC1 -> SGMII, 3: GMAC2 -> SGMII */ -+#define MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ -+ (MTK_MUX_BIT(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII) | MTK_MUX | \ -+ MTK_SHARED_SGMII) -+ -+/* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */ -+#define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ -+ (MTK_MUX_BIT(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII) | MTK_MUX) -+ - #define MTK_HWLRO BIT(12) -+ - #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) - -+#define MT7622_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | MTK_GMAC2_RGMII | \ -+ MTK_GMAC2_SGMII | MTK_GDM1_ESW | \ -+ MTK_MUX_GDM1_TO_GMAC1_ESW | \ -+ MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII) -+ -+#define MT7623_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII) -+ -+#define LEOPARD_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ -+ MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \ -+ MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \ -+ MTK_MUX_U3_GMAC2_TO_QPHY | \ -+ MTK_MUX_GMAC12_TO_GEPHY_SGMII) -+ -+#define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII) -+ - /* struct mtk_eth_data - This is the structure holding all differences - * among various plaforms -+ * @ana_rgc3: The offset for register ANA_RGC3 related to -+ * sgmiisys syscon - * @caps Flags shown the extra capability for the SoC - * @required_clks Flags shown the bitmap for required clocks on - * the target SoC - * @required_pctl A bool value to show whether the SoC requires - * the extra setup for those pins used by GMAC. -+ * @irq_num total eth irq num support in target SoC - */ - struct mtk_soc_data { -+ u32 ana_rgc3; - u32 caps; - u32 required_clks; - bool required_pctl; -+ u32 irq_num; - }; - - /* currently no SoC has more than 2 macs */ - #define MTK_MAX_DEVS 2 - -+struct mtk_eth_debug { -+ struct dentry *root; -+}; -+ -+#define MTK_SGMII_PHYSPEED_AN BIT(31) -+#define MTK_SGMII_PHYSPEED_MASK GENMASK(0, 2) -+#define MTK_SGMII_PHYSPEED_1000 BIT(0) -+#define MTK_SGMII_PHYSPEED_2500 BIT(1) -+#define MTK_HAS_FLAGS(flags, _x) (((flags) & (_x)) == (_x)) -+ -+/* struct mtk_sgmii - This is the structure holding sgmii regmap and its -+ * characteristics -+ * @regmap: The register map pointing at the range used to setup -+ * SGMII modes -+ * @flags: The enum refers to which mode the sgmii wants to run on -+ * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap -+ */ -+ -+struct mtk_sgmii { -+ struct regmap *regmap[MTK_MAX_DEVS]; -+ u32 flags[MTK_MAX_DEVS]; -+ u32 ana_rgc3; -+}; -+ - /* struct mtk_eth - This is the main datasructure for holding the state - * of the driver - * @dev: The device pointer -@@ -601,14 +763,15 @@ struct mtk_soc_data { - * @msg_enable: Ethtool msg level - * @ethsys: The register map pointing at the range used to setup - * MII modes -- * @sgmiisys: The register map pointing at the range used to setup -- * SGMII modes -+ * @infra: The register map pointing at the range used to setup -+ * SGMII and GePHY path - * @pctl: The register map pointing at the range used to setup - * GMAC port drive/slew values - * @dma_refcnt: track how many netdevs are using the DMA engine - * @tx_ring: Pointer to the memory holding info about the TX ring - * @rx_ring: Pointer to the memory holding info about the RX ring -- * @rx_ring_qdma: Pointer to the memory holding info about the QDMA RX ring -+ * @rx_ring_qdma: Pointer to the memory holding info about the QDMA RX -+ * ring - * @tx_napi: The TX NAPI struct - * @rx_napi: The RX NAPI struct - * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring -@@ -619,13 +782,16 @@ struct mtk_soc_data { - * @pending_work: The workqueue used to reset the dma ring - * @state: Initialization and runtime state of the device - * @soc: Holding specific data among vaious SoCs -+ * @debug: Holding specific data for mtk_eth_dbg usage. - */ - - struct mtk_eth { - struct device *dev; - void __iomem *base; - spinlock_t page_lock; -+ /* spin_lock for enable/disable tx irq critial section */ - spinlock_t tx_irq_lock; -+ /* spin_lock for enable/disable rx irq critial section */ - spinlock_t rx_irq_lock; - struct net_device dummy_dev; - struct net_device *netdev[MTK_MAX_DEVS]; -@@ -634,10 +800,11 @@ struct mtk_eth { - u32 msg_enable; - unsigned long sysclk; - struct regmap *ethsys; -- struct regmap *sgmiisys; -+ struct regmap *infra; -+ struct mtk_sgmii *sgmii; - struct regmap *pctl; - bool hwlro; -- refcount_t dma_refcnt; -+ atomic_t dma_refcnt; - struct mtk_tx_ring tx_ring; - struct mtk_rx_ring rx_ring[MTK_MAX_RX_RING_NUM]; - struct mtk_rx_ring rx_ring_qdma; -@@ -653,6 +820,7 @@ struct mtk_eth { - unsigned long state; - - const struct mtk_soc_data *soc; -+ struct mtk_eth_debug debug; - }; - - /* struct mtk_mac - the structure that holds the info about the MACs of the -@@ -664,6 +832,7 @@ struct mtk_eth { - * @hw_stats: Packet statistics counter - * @trgmii Indicate if the MAC uses TRGMII connected to internal - switch -+ * @phy_dev: The attached PHY if available - */ - struct mtk_mac { - int id; -@@ -674,6 +843,7 @@ struct mtk_mac { - __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; - int hwlro_ip_cnt; - bool trgmii; -+ struct phy_device *phy_dev; - }; - - /* the struct describing the SoC. these are declared in the soc_xyz.c files */ -@@ -685,4 +855,10 @@ void mtk_stats_update_mac(struct mtk_mac - void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); - u32 mtk_r32(struct mtk_eth *eth, unsigned reg); - -+int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, -+ u32 ana_rgc3); -+int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); -+int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id); -+int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode); -+ - #endif /* MTK_ETH_H */ ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -0,0 +1,114 @@ -+/* -+ * Copyright (C) 2018 MediaTek Inc. -+ * -+ * 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; version 2 of the License -+ * -+ * 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) 2018 Sean Wang <sean.wang@mediatek.com> -+ */ -+ -+#include <linux/mfd/syscon.h> -+#include <linux/of.h> -+#include <linux/regmap.h> -+ -+#include "mtk_eth_soc.h" -+ -+int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) -+{ -+ struct device_node *np; -+ const char *str; -+ int i, err; -+ -+ ss->ana_rgc3 = ana_rgc3; -+ -+ for (i = 0; i < MTK_MAX_DEVS; i++) { -+ np = of_parse_phandle(r, "mediatek,sgmiisys", i); -+ if (!np) -+ break; -+ -+ ss->regmap[i] = syscon_node_to_regmap(np); -+ if (IS_ERR(ss->regmap[i])) -+ return PTR_ERR(ss->regmap[i]); -+ -+ err = of_property_read_string(np, "mediatek,physpeed", &str); -+ if (err) -+ return err; -+ -+ if (!strcmp(str, "2500")) -+ pr_info("sean debug physpeed = 2500\n"); -+ -+ if (!strcmp(str, "2500")) -+ ss->flags[i] |= MTK_SGMII_PHYSPEED_2500; -+ else if (!strcmp(str, "1000")) -+ ss->flags[i] |= MTK_SGMII_PHYSPEED_1000; -+ else if (!strcmp(str, "auto")) -+ ss->flags[i] |= MTK_SGMII_PHYSPEED_AN; -+ else -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) -+{ -+ unsigned int val; -+ -+ if (!ss->regmap[id]) -+ return -EINVAL; -+ -+ /* Setup the link timer and QPHY power up inside SGMIISYS */ -+ regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER, -+ SGMII_LINK_TIMER_DEFAULT); -+ -+ regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); -+ val |= SGMII_REMOTE_FAULT_DIS; -+ regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); -+ -+ regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); -+ val |= SGMII_AN_RESTART; -+ regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); -+ -+ regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); -+ val &= ~SGMII_PHYA_PWD; -+ regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); -+ -+ return 0; -+} -+ -+int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id) -+{ -+ unsigned int val; -+ int mode; -+ -+ if (!ss->regmap[id]) -+ return -EINVAL; -+ -+ regmap_read(ss->regmap[id], ss->ana_rgc3, &val); -+ val &= ~GENMASK(2, 3); -+ mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK; -+ val |= (mode == MTK_SGMII_PHYSPEED_1000) ? 0 : BIT(2); -+ regmap_write(ss->regmap[id], ss->ana_rgc3, val); -+ -+ /* disable SGMII AN */ -+ regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); -+ val &= ~BIT(12); -+ regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); -+ -+ /* SGMII force mode setting */ -+ val = 0x31120019; -+ regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); -+ -+ /* Release PHYA power down state */ -+ regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); -+ val &= ~SGMII_PHYA_PWD; -+ regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); -+ -+ return 0; -+} |