create mode 100644 drivers/net/ethernet/ralink/soc_rt305x.c
create mode 100644 drivers/net/ethernet/ralink/soc_rt3883.c
-Index: linux-3.10.13/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h 2013-10-02 21:40:50.192369358 +0200
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h
@@ -0,0 +1,27 @@
+/*
+ * Ralink RT305x SoC platform device registration
+};
+
+#endif /* _RT305X_ESW_PLATFORM_H */
-Index: linux-3.10.13/arch/mips/ralink/rt305x.c
-===================================================================
---- linux-3.10.13.orig/arch/mips/ralink/rt305x.c 2013-10-02 21:12:59.896297955 +0200
-+++ linux-3.10.13/arch/mips/ralink/rt305x.c 2013-10-06 13:27:24.076279369 +0200
-@@ -221,6 +221,7 @@
+--- a/arch/mips/ralink/rt305x.c
++++ b/arch/mips/ralink/rt305x.c
+@@ -221,6 +221,7 @@ void __init ralink_clk_init(void)
}
ralink_clk_add("cpu", cpu_rate);
ralink_clk_add("10000b00.spi", sys_rate);
ralink_clk_add("10000100.timer", wdt_rate);
ralink_clk_add("10000120.watchdog", wdt_rate);
-Index: linux-3.10.13/drivers/net/ethernet/Kconfig
-===================================================================
---- linux-3.10.13.orig/drivers/net/ethernet/Kconfig 2013-10-02 21:12:59.896297955 +0200
-+++ linux-3.10.13/drivers/net/ethernet/Kconfig 2013-10-02 21:40:50.192369358 +0200
-@@ -135,6 +135,7 @@
+--- a/drivers/net/ethernet/Kconfig
++++ b/drivers/net/ethernet/Kconfig
+@@ -135,6 +135,7 @@ config ETHOC
source "drivers/net/ethernet/packetengines/Kconfig"
source "drivers/net/ethernet/pasemi/Kconfig"
source "drivers/net/ethernet/qlogic/Kconfig"
source "drivers/net/ethernet/realtek/Kconfig"
source "drivers/net/ethernet/renesas/Kconfig"
source "drivers/net/ethernet/rdc/Kconfig"
-Index: linux-3.10.13/drivers/net/ethernet/Makefile
-===================================================================
---- linux-3.10.13.orig/drivers/net/ethernet/Makefile 2013-10-02 21:12:59.896297955 +0200
-+++ linux-3.10.13/drivers/net/ethernet/Makefile 2013-10-02 21:40:50.192369358 +0200
-@@ -53,6 +53,7 @@
+--- a/drivers/net/ethernet/Makefile
++++ b/drivers/net/ethernet/Makefile
+@@ -53,6 +53,7 @@ obj-$(CONFIG_ETHOC) += ethoc.o
obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/
obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
obj-$(CONFIG_SH_ETH) += renesas/
obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
-Index: linux-3.10.13/drivers/net/ethernet/ralink/Kconfig
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/Kconfig 2013-10-02 21:40:50.196369356 +0200
-@@ -0,0 +1,31 @@
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/Kconfig
+@@ -0,0 +1,32 @@
+config NET_RALINK
+ tristate "Ralink RT288X/RT3X5X/RT3662/RT3883/MT7620 ethernet driver"
+ depends on RALINK
+config NET_RALINK_GSW_MT7620
+ def_bool NET_RALINK
+ depends on SOC_MT7620
++ select INET_LRO
+ select NET_RALINK_MDIO
+ select PHYLIB
+ select SWCONFIG
+endif
-Index: linux-3.10.13/drivers/net/ethernet/ralink/Makefile
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/Makefile 2013-10-03 23:14:02.777666985 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the Ralink SoCs built-in ethernet macs
+ralink-eth-$(CONFIG_SOC_MT7620) += soc_mt7620.o
+
+obj-$(CONFIG_NET_RALINK) += ralink-eth.o
-Index: linux-3.10.13/drivers/net/ethernet/ralink/esw_rt3052.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/esw_rt3052.c 2013-10-02 21:40:50.196369356 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/esw_rt3052.c
@@ -0,0 +1,1463 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+{
+ platform_driver_unregister(&esw_driver);
+}
-Index: linux-3.10.13/drivers/net/ethernet/ralink/esw_rt3052.h
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/esw_rt3052.h 2013-10-02 21:40:50.196369356 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/esw_rt3052.h
@@ -0,0 +1,32 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+
+#endif
+#endif
-Index: linux-3.10.13/drivers/net/ethernet/ralink/gsw_mt7620a.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/gsw_mt7620a.c 2013-10-04 17:31:46.468886115 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/gsw_mt7620a.c
@@ -0,0 +1,566 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+
+ return 0;
+}
-Index: linux-3.10.13/drivers/net/ethernet/ralink/gsw_mt7620a.h
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/gsw_mt7620a.h 2013-10-04 02:20:43.226145788 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/gsw_mt7620a.h
@@ -0,0 +1,30 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+extern int mt7620a_has_carrier(struct fe_priv *priv);
+
+#endif
-Index: linux-3.10.13/drivers/net/ethernet/ralink/mdio.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/mdio.c 2013-10-04 01:57:11.854085410 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/mdio.c
@@ -0,0 +1,244 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ of_node_put(priv->mii_bus->dev.of_node);
+ kfree(priv->mii_bus);
+}
-Index: linux-3.10.13/drivers/net/ethernet/ralink/mdio.h
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/mdio.h 2013-10-02 21:40:50.200369354 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/mdio.h
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+static inline void fe_mdio_cleanup(struct fe_priv *priv) {}
+#endif
+#endif
-Index: linux-3.10.13/drivers/net/ethernet/ralink/mdio_rt2880.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/mdio_rt2880.c 2013-10-02 21:40:50.200369354 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/mdio_rt2880.c
@@ -0,0 +1,232 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+
+ return;
+}
-Index: linux-3.10.13/drivers/net/ethernet/ralink/mdio_rt2880.h
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/mdio_rt2880.h 2013-10-02 21:40:50.204369354 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/mdio_rt2880.h
@@ -0,0 +1,26 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+void rt2880_port_init(struct fe_priv *priv, struct device_node *np);
+
+#endif
-Index: linux-3.10.13/drivers/net/ethernet/ralink/ralink_soc_eth.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/ralink_soc_eth.c 2013-10-04 02:18:27.242139979 +0200
-@@ -0,0 +1,738 @@
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/ralink_soc_eth.c
+@@ -0,0 +1,846 @@
+/*
+ * 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
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/if_vlan.h>
++#include <linux/reset.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#include "esw_rt3052.h"
+#include "mdio.h"
+
-+#define TX_TIMEOUT (20 * HZ / 100)
++#define TX_TIMEOUT (2 * HZ)
+#define MAX_RX_LENGTH 1536
++#define DMA_DUMMY_DESC 0xffffffff
+
+static const u32 fe_reg_table_default[FE_REG_COUNT] = {
+ [FE_REG_PDMA_GLO_CFG] = FE_PDMA_GLO_CFG,
+
+ for (i = 0; i < NUM_DMA_DESC; i++) {
+ if (priv->soc->tx_dma) {
-+ priv->soc->tx_dma(priv, i, 0);
++ priv->soc->tx_dma(priv, i, NULL);
+ continue;
+ }
+
+ netdev_reset_queue(priv->netdev);
+}
+
++static void fe_start_tso(struct sk_buff *skb, struct net_device *dev, unsigned int nr_frags, int idx)
++{
++ struct fe_priv *priv = netdev_priv(dev);
++ struct skb_frag_struct *frag;
++ int i;
++
++ for (i = 0; i < nr_frags; i++) {
++ dma_addr_t mapped_addr;
++
++ frag = &skb_shinfo(skb)->frags[i];
++ mapped_addr = skb_frag_dma_map(&dev->dev, frag, 0, skb_frag_size(frag), DMA_TO_DEVICE);
++ if (i % 2) {
++ idx = (idx + 1) % NUM_DMA_DESC;
++ priv->tx_dma[idx].txd1 = mapped_addr;
++ if (i == nr_frags - 1)
++ priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_PLEN0(frag->size);
++ else
++ priv->tx_dma[idx].txd2 = TX_DMA_PLEN0(frag->size);
++ } else {
++ priv->tx_dma[idx].txd3 = mapped_addr;
++ if (i == nr_frags - 1)
++ priv->tx_dma[idx].txd2 |= TX_DMA_LS1 | TX_DMA_PLEN1(frag->size);
++ else
++ priv->tx_dma[idx].txd2 |= TX_DMA_PLEN1(frag->size);
++ }
++ }
++}
++
+static int fe_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
++ unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+ struct fe_priv *priv = netdev_priv(dev);
+ dma_addr_t mapped_addr;
-+ u32 tx_next;
-+ u32 tx;
++ u32 tx_next, tx, tx_num = 1;
++ int i;
+
+ if (priv->soc->min_pkt_len) {
+ if (skb->len < priv->soc->min_pkt_len) {
+ spin_lock(&priv->page_lock);
+
+ tx = fe_reg_r32(FE_REG_TX_CTX_IDX0);
-+ tx_next = (tx + 1) % NUM_DMA_DESC;
-+
++ if (priv->soc->tso && nr_frags)
++ tx_num += nr_frags >> 1;
++ tx_next = (tx + tx_num) % NUM_DMA_DESC;
+ if ((priv->tx_skb[tx]) || (priv->tx_skb[tx_next]) ||
+ !(priv->tx_dma[tx].txd2 & TX_DMA_DONE) ||
+ !(priv->tx_dma[tx_next].txd2 & TX_DMA_DONE))
+ return NETDEV_TX_OK;
+ }
+
-+ priv->tx_skb[tx] = skb;
++ if (priv->soc->tso) {
++ int t = tx_num;
++
++ priv->tx_skb[(tx + t - 1) % NUM_DMA_DESC] = skb;
++ while (--t)
++ priv->tx_skb[(tx + t - 1) % NUM_DMA_DESC] = (struct sk_buff *) DMA_DUMMY_DESC;
++ } else {
++ priv->tx_skb[tx] = skb;
++ }
+ priv->tx_dma[tx].txd1 = (unsigned int) mapped_addr;
+ wmb();
++
++ priv->tx_dma[tx].txd4 &= ~0x80;
+ if (priv->soc->tx_dma)
-+ priv->soc->tx_dma(priv, tx, skb->len);
++ priv->soc->tx_dma(priv, tx, skb);
+ else
+ priv->tx_dma[tx].txd2 = TX_DMA_LSO | TX_DMA_PLEN0(skb->len);
+
+ else
+ priv->tx_dma[tx].txd4 &= ~TX_DMA_CHKSUM;
+
-+ priv->tx_dma[tx].txd4 &= ~0x80;
++ if (priv->soc->tso)
++ fe_start_tso(skb, dev, nr_frags, tx);
++
++ if (skb_shinfo(skb)->gso_segs > 1) {
++ struct iphdr *iph = NULL;
++ struct tcphdr *th = NULL;
++ struct ipv6hdr *ip6h = NULL;
++
++ ip6h = (struct ipv6hdr *) skb_network_header(skb);
++ iph = (struct iphdr *) skb_network_header(skb);
++ if ((iph->version == 4) && (iph->protocol == IPPROTO_TCP)) {
++ th = (struct tcphdr *)skb_transport_header(skb);
++ priv->tx_dma[tx].txd4 |= BIT(28);
++ th->check = htons(skb_shinfo(skb)->gso_size);
++ dma_cache_sync(NULL, th, sizeof(struct tcphdr), DMA_TO_DEVICE);
++ } else if ((ip6h->version == 6) && (ip6h->nexthdr == NEXTHDR_TCP)) {
++ th = (struct tcphdr *)skb_transport_header(skb);
++ priv->tx_dma[tx].txd4 |= BIT(28);
++ th->check = htons(skb_shinfo(skb)->gso_size);
++ dma_cache_sync(NULL, th, sizeof(struct tcphdr), DMA_TO_DEVICE);
++ }
++ }
++
++ for (i = 0; i < tx_num; i++)
++ dma_cache_sync(NULL, &priv->tx_dma[tx + i], sizeof(struct fe_tx_dma), DMA_TO_DEVICE);
+
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+
++ wmb();
+ fe_reg_w32(tx_next, FE_REG_TX_CTX_IDX0);
+ netdev_sent_queue(dev, skb->len);
+
+ priv->rx_skb[idx]->ip_summed = CHECKSUM_NONE;
+ priv->netdev->stats.rx_packets++;
+ priv->netdev->stats.rx_bytes += pktlen;
-+ netif_receive_skb(priv->rx_skb[idx]);
++
++#ifdef CONFIG_INET_LRO
++ if (priv->soc->get_skb_header && priv->rx_skb[idx]->ip_summed == CHECKSUM_UNNECESSARY)
++ lro_receive_skb(&priv->lro_mgr, priv->rx_skb[idx], NULL);
++ else
++#endif
++ netif_receive_skb(priv->rx_skb[idx]);
+
+ priv->rx_skb[idx] = new_skb;
+
+ }
+ }
+
++#ifdef CONFIG_INET_LRO
++ if (priv->soc->get_skb_header)
++ lro_flush_all(&priv->lro_mgr);
++#endif
+ if (complete) {
+ napi_complete(&priv->rx_napi);
+ fe_int_enable(priv->soc->rx_dly_int);
+ if (!(txd->txd2 & TX_DMA_DONE) || !(priv->tx_skb[priv->tx_free_idx]))
+ break;
+
-+ bytes_compl += priv->tx_skb[priv->tx_free_idx]->len;
++ if (priv->tx_skb[priv->tx_free_idx] != (struct sk_buff *) DMA_DUMMY_DESC) {
++ bytes_compl += priv->tx_skb[priv->tx_free_idx]->len;
++ dev_kfree_skb_irq(priv->tx_skb[priv->tx_free_idx]);
++ }
+ pkts_compl++;
-+
-+ dev_kfree_skb_irq(priv->tx_skb[priv->tx_free_idx]);
+ priv->tx_skb[priv->tx_free_idx] = NULL;
+ priv->tx_free_idx++;
+ if (priv->tx_free_idx >= NUM_DMA_DESC)
+ struct clk *sysclk;
+ int err;
+
++ device_reset(&pdev->dev);
++
+ match = of_match_device(of_fe_match, &pdev->dev);
+ soc = (struct fe_soc_data *) match->data;
++
++ if (soc->init_data)
++ soc->init_data(soc);
+ if (soc->reg_table)
+ fe_reg_table = soc->reg_table;
+
+ netdev->watchdog_timeo = TX_TIMEOUT;
+ netdev->features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+
++ if (fe_reg_table[FE_REG_FE_DMA_VID_BASE])
++ netdev->features |= NETIF_F_HW_VLAN_CTAG_TX;
++
++ if (soc->tso) {
++ dev_info(&pdev->dev, "Enabling TSO\n");
++ netdev->features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_IPV6_CSUM;
++ }
++
++ netdev->hw_features = netdev->vlan_features = netdev->features;
++
+ netdev->irq = platform_get_irq(pdev, 0);
+ if (netdev->irq < 0) {
+ dev_err(&pdev->dev, "no IRQ resource found\n");
+ }
+ netif_napi_add(netdev, &priv->rx_napi, fe_poll_rx, 32);
+
++#ifdef CONFIG_INET_LRO
++ if (priv->soc->get_skb_header) {
++ priv->lro_mgr.dev = netdev;
++ memset(&priv->lro_mgr.stats, 0, sizeof(priv->lro_mgr.stats));
++ priv->lro_mgr.features = LRO_F_NAPI;
++ priv->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
++ priv->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
++ priv->lro_mgr.max_desc = ARRAY_SIZE(priv->lro_arr);
++ priv->lro_mgr.max_aggr = 64;
++ priv->lro_mgr.frag_align_pad = 0;
++ priv->lro_mgr.lro_arr = priv->lro_arr;
++ priv->lro_mgr.get_skb_header = priv->soc->get_skb_header;
++ }
++#endif
++
+ platform_set_drvdata(pdev, netdev);
+
+ netdev_info(netdev, "done loading\n");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Ethernet driver for Ralink SoC");
-Index: linux-3.10.13/drivers/net/ethernet/ralink/ralink_soc_eth.h
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/ralink_soc_eth.h 2013-10-04 02:18:45.454140650 +0200
-@@ -0,0 +1,375 @@
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/ralink_soc_eth.h
+@@ -0,0 +1,384 @@
+/*
+ * 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
+#include <linux/netdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/phy.h>
++#include <linux/inet_lro.h>
+
+
+enum fe_reg {
+
+#define TX_DMA_PLEN0_MASK ((0x3fff) << 16)
+#define TX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16)
++#define TX_DMA_PLEN1(_x) ((_x) & 0x3fff)
++#define TX_DMA_LS1 BIT(14)
+#define TX_DMA_LSO BIT(30)
+#define TX_DMA_DONE BIT(31)
+#define TX_DMA_QN(_x) ((_x) << 16)
+ unsigned char mac[6];
+ const u32 *reg_table;
+
++ void (*init_data)(struct fe_soc_data *data);
+ void (*reset_fe)(void);
+ void (*set_mac)(struct fe_priv *priv, unsigned char *mac);
+ void (*fwd_config)(struct fe_priv *priv);
-+ void (*tx_dma)(struct fe_priv *priv, int idx, int len);
++ void (*tx_dma)(struct fe_priv *priv, int idx, struct sk_buff *skb);
+ void (*rx_dma)(struct fe_priv *priv, int idx, int len);
+ int (*switch_init)(struct fe_priv *priv);
+ int (*switch_config)(struct fe_priv *priv);
+ int (*mdio_write)(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val);
+ int (*mdio_read)(struct mii_bus *bus, int phy_addr, int phy_reg);
+ void (*mdio_adjust_link)(struct fe_priv *priv, int port);
++ int (*get_skb_header)(struct sk_buff *skb, void **iphdr, void **tcph, u64 *hdr_flags, void *priv);
+
+ void *swpriv;
+ u32 pdma_glo_cfg;
+ u32 rx_dly_int;
+ u32 tx_dly_int;
+ u32 checksum_bit;
++ u32 tso;
+
+ int min_pkt_len;
+};
+ int mii_irq[PHY_MAX_ADDR];
+
+ int link[8];
++
++ struct net_lro_mgr lro_mgr;
++ struct net_lro_desc lro_arr[8];
+};
+
+extern const struct of_device_id of_fe_match[];
+u32 fe_r32(unsigned reg);
+
+#endif /* FE_ETH_H */
-Index: linux-3.10.13/drivers/net/ethernet/ralink/soc_mt7620.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/soc_mt7620.c 2013-10-04 02:21:02.450146612 +0200
-@@ -0,0 +1,112 @@
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/soc_mt7620.c
+@@ -0,0 +1,172 @@
+/*
+ * 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
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
++#include <linux/if_vlan.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
++#include <mt7620.h>
+#include "ralink_soc_eth.h"
+#include "gsw_mt7620a.h"
+
+
+static void mt7620_fwd_config(struct fe_priv *priv)
+{
++ int i;
++
++ /* frame engine will push VLAN tag regarding to VIDX feild in Tx desc. */
++ for (i = 0; i < 16; i += 2)
++ fe_w32(((i + 1) << 16) + i, MT7620_DMA_VID + (i * 2));
++
+ fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) & ~7, MT7620A_GDMA1_FWD_CFG);
+ fe_w32(fe_r32(MT7620A_GDMA1_FWD_CFG) | (GDMA_ICS_EN | GDMA_TCS_EN | GDMA_UCS_EN), MT7620A_GDMA1_FWD_CFG);
+ fe_w32(fe_r32(MT7620A_CDMA_CSG_CFG) | (CDMA_ICS_EN | CDMA_UCS_EN | CDMA_TCS_EN), MT7620A_CDMA_CSG_CFG);
+}
+
-+static void mt7620_tx_dma(struct fe_priv *priv, int idx, int len)
++static void mt7620_tx_dma(struct fe_priv *priv, int idx, struct sk_buff *skb)
+{
-+ if (len)
++ unsigned int nr_frags = 0;
++ unsigned int len = 0;
++
++ if (skb) {
++ nr_frags = skb_shinfo(skb)->nr_frags;
++ len = skb->len - skb->data_len;
++ }
++
++ if (!skb)
++ priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_DONE;
++ else if (!nr_frags)
+ priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_PLEN0(len);
+ else
-+ priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_DONE;
++ priv->tx_dma[idx].txd2 = TX_DMA_PLEN0(len);
++
++ if(skb && vlan_tx_tag_present(skb))
++ priv->tx_dma[idx].txd4 = 0x80 | (vlan_tx_tag_get(skb) >> 13) << 4 | (vlan_tx_tag_get(skb) & 0xF);
++ else
++ priv->tx_dma[idx].txd4 = 0;
+}
+
+static void mt7620_rx_dma(struct fe_priv *priv, int idx, int len)
+ priv->rx_dma[idx].rxd2 = RX_DMA_PLEN0(len);
+}
+
++#ifdef CONFIG_INET_LRO
++static int
++mt7620_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph,
++ u64 *hdr_flags, void *_priv)
++{
++ struct iphdr *iph = NULL;
++ int vhdr_len = 0;
++
++ /*
++ * Make sure that this packet is Ethernet II, is not VLAN
++ * tagged, is IPv4, has a valid IP header, and is TCP.
++ */
++ if (skb->protocol == 0x0081)
++ vhdr_len = VLAN_HLEN;
++
++ iph = (struct iphdr *)(skb->data + vhdr_len);
++ if(iph->protocol != IPPROTO_TCP)
++ return -1;
++
++ *iphdr = iph;
++ *tcph = skb->data + (iph->ihl << 2) + vhdr_len;
++ *hdr_flags = LRO_IPV4 | LRO_TCP;
++
++ return 0;
++}
++#endif
++
++static void mt7620_init_data(struct fe_soc_data *data)
++{
++ if (mt7620_get_eco() >= 5)
++ data->tso = 1;
++}
++
+static struct fe_soc_data mt7620_data = {
+ .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 },
++ .init_data = mt7620_init_data,
+ .reset_fe = mt7620_fe_reset,
+ .set_mac = mt7620_set_mac,
+ .fwd_config = mt7620_fwd_config,
+ .mdio_read = mt7620_mdio_read,
+ .mdio_write = mt7620_mdio_write,
+ .mdio_adjust_link = mt7620_mdio_link_adjust,
++#ifdef CONFIG_INET_LRO
++ .get_skb_header = mt7620_get_skb_header,
++#endif
+};
+
+const struct of_device_id of_fe_match[] = {
+};
+
+MODULE_DEVICE_TABLE(of, of_fe_match);
-Index: linux-3.10.13/drivers/net/ethernet/ralink/soc_rt2880.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/soc_rt2880.c 2013-10-02 21:40:50.204369354 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/soc_rt2880.c
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+};
+
+MODULE_DEVICE_TABLE(of, of_fe_match);
-Index: linux-3.10.13/drivers/net/ethernet/ralink/soc_rt305x.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/soc_rt305x.c 2013-10-02 21:40:50.208369356 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/soc_rt305x.c
@@ -0,0 +1,113 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+};
+
+MODULE_DEVICE_TABLE(of, of_fe_match);
-Index: linux-3.10.13/drivers/net/ethernet/ralink/soc_rt3883.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/soc_rt3883.c 2013-10-02 21:40:50.208369356 +0200
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/soc_rt3883.c
@@ -0,0 +1,60 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+
+MODULE_DEVICE_TABLE(of, of_fe_match);
+
-Index: linux-3.10.13/drivers/net/ethernet/ralink/mt7530.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.13/drivers/net/ethernet/ralink/mt7530.c 2013-10-04 19:37:31.585208659 +0200
-@@ -0,0 +1,462 @@
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/mt7530.c
+@@ -0,0 +1,467 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ {
+ .name = "llllw",
+ .pvids = { 1, 1, 1, 1, 2, 1 },
-+ .vlans = { 0, 0x4f, 0x50 },
++ .vlans = { 0, 0x6f, 0x50 },
+ }, {
+ .name = "wllll",
+ .pvids = { 2, 1, 1, 1, 1, 1 },
-+ .vlans = { 0, 0x5e, 0x41 },
++ .vlans = { 0, 0x7e, 0x41 },
+ },
+};
+
+ mt7530_w32(priv, 0x2310, 0x810000c0);
+ mt7530_w32(priv, 0x2410, 0x810000c0);
+ mt7530_w32(priv, 0x2510, 0x810000c0);
++
+ // set CPU/P7 port as user port
+ mt7530_w32(priv, 0x2610, 0x81000000);
+ mt7530_w32(priv, 0x2710, 0x81000000);
+
+ for (i = 0; i < MT7530_NUM_VLANS; i++) {
+ u8 ports = priv->vlans[i].ports;
++ u32 val = mt7530_r32(priv, 0x100 + 4 * (i / 2));
++
++ if (i % 2 == 0) {
++ val &= 0xfff000;
++ val |= i;
++ } else {
++ val &= 0xfff;
++ val |= (i << 12);
++ }
++ mt7530_w32(priv, 0x100 + 4 * (i / 2), val);
+
+ if (ports)
+ mt7530_w32(priv, REG_ESW_VLAN_VAWD1, BIT(30) | (ports << 16) | BIT(0));
+
+ return 0;
+}
+--- /dev/null
++++ b/drivers/net/ethernet/ralink/mt7530.h
+@@ -0,0 +1,20 @@
++/*
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
+
-+int
-+mt7530_probe_mmio(struct device *dev, void __iomem *base)
-+{
-+ return 0;
-+}
++#ifndef _MT7530_H__
++#define _MT7530_H__
++
++int mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus);
++
++#endif