diff options
Diffstat (limited to 'target/linux/mediatek/patches-4.9/0059-eth-fixes.patch')
-rw-r--r-- | target/linux/mediatek/patches-4.9/0059-eth-fixes.patch | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/target/linux/mediatek/patches-4.9/0059-eth-fixes.patch b/target/linux/mediatek/patches-4.9/0059-eth-fixes.patch new file mode 100644 index 0000000000..61b4b2615c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0059-eth-fixes.patch @@ -0,0 +1,531 @@ +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -24,6 +24,7 @@ + #include <linux/tcp.h> + + #if defined(CONFIG_NET_MEDIATEK_HW_QOS) ++ + struct mtk_ioctl_reg { + unsigned int off; + unsigned int val; +@@ -32,6 +33,13 @@ struct mtk_ioctl_reg { + #define REG_HQOS_MAX 0x3FFF + #define RAETH_QDMA_REG_READ 0x89F8 + #define RAETH_QDMA_REG_WRITE 0x89F9 ++#define RAETH_QDMA_QUEUE_MAPPING 0x89FA ++ ++unsigned int M2Q_table[16] = {0}; ++unsigned int lan_wan_separate = 0; ++ ++EXPORT_SYMBOL_GPL(M2Q_table); ++ + #endif + + #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) +@@ -225,7 +233,7 @@ static void mtk_phy_link_adjust(struct n + if (flowctrl & FLOW_CTRL_RX) + mcr |= MAC_MCR_FORCE_RX_FC; + +- netif_dbg(mac->hw, link, dev, "rx pause %s, tx pause %s\n", ++ netif_info(mac->hw, link, dev, "rx pause %s, tx pause %s\n", + flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", + flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); + } +@@ -508,9 +516,9 @@ static struct rtnl_link_stats64 * mtk_ge + unsigned int start; + + if (netif_running(dev) && netif_device_present(dev)) { +- if (spin_trylock_bh(&hw_stats->stats_lock)) { ++ if (spin_trylock(&hw_stats->stats_lock)) { + mtk_stats_update_mac(mac); +- spin_unlock_bh(&hw_stats->stats_lock); ++ spin_unlock(&hw_stats->stats_lock); + } + } + +@@ -690,6 +698,7 @@ static int mtk_tx_map(struct sk_buff *sk + txd3 |= skb->mark & 0x7; + if (mac->id) + txd3 += 8; ++ txd3 = 0; + #endif + + mapped_addr = dma_map_single(eth->dev, skb->data, +@@ -760,16 +769,7 @@ static int mtk_tx_map(struct sk_buff *sk + WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | + (!nr_frags * TX_DMA_LS0))); + +- /* 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); +- } +- ++ netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb); + + ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); +@@ -980,20 +980,9 @@ static int mtk_poll_rx(struct napi_struc + if (!(trxd.rxd2 & RX_DMA_DONE)) + break; + +- /* 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])) +- goto release_desc; ++ /* find out which mac the packet come from. values start at 1 */ ++ mac = (trxd.rxd4 >> 22) & 0x1; ++ mac = (mac + 1) % 2; + + netdev = eth->netdev[mac]; + +@@ -1017,6 +1006,9 @@ static int mtk_poll_rx(struct napi_struc + } + + /* receive data */ ++ if (mac < 0 || mac > 2) ++ mac = 0; ++ + skb = build_skb(data, ring->frag_size); + if (unlikely(!skb)) { + skb_free_frag(new_data); +@@ -1076,18 +1068,21 @@ static int mtk_poll_tx(struct mtk_eth *e + struct mtk_tx_dma *desc; + struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; +- int total = 0, done = 0; +- unsigned int bytes = 0; ++ unsigned int done[MTK_MAX_DEVS]; ++ unsigned int bytes[MTK_MAX_DEVS]; + u32 cpu, dma; + static int condition; +- int i; ++ int total = 0, i; ++ ++ memset(done, 0, sizeof(done)); ++ memset(bytes, 0, sizeof(bytes)); + + 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) && done < budget) { ++ while ((cpu != dma) && budget) { + u32 next_cpu = desc->txd2; + int mac = 0; + +@@ -1106,8 +1101,9 @@ static int mtk_poll_tx(struct mtk_eth *e + } + + if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { +- bytes += skb->len; +- done++; ++ bytes[mac] += skb->len; ++ done[mac]++; ++ budget--; + } + mtk_tx_unmap(eth, tx_buf); + +@@ -1119,13 +1115,11 @@ static int mtk_poll_tx(struct mtk_eth *e + + 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]) ++ if (!eth->netdev[i] || !done[i]) + continue; +- netdev_completed_queue(eth->netdev[i], done, bytes); ++ netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); ++ total += done[i]; + } + + if (mtk_queue_stopped(eth) && +@@ -1286,21 +1280,11 @@ static void mtk_tx_clean(struct mtk_eth + + static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) + { +- struct mtk_rx_ring *ring; ++ struct mtk_rx_ring *ring = ð->rx_ring[ring_no]; + int rx_data_len, rx_dma_size; + int i; +- u32 offset = 0; +- +- if (rx_flag & MTK_RX_FLAGS_QDMA) { +- if (ring_no) +- return -EINVAL; +- ring = ð->rx_ring_qdma; +- offset = 0x1000; +- } else { +- ring = ð->rx_ring[ring_no]; +- } + +- if (rx_flag & MTK_RX_FLAGS_HWLRO) { ++ if (rx_flag == MTK_RX_FLAGS_HWLRO) { + rx_data_len = MTK_MAX_LRO_RX_LENGTH; + rx_dma_size = MTK_HW_LRO_DMA_SIZE; + } else { +@@ -1348,16 +1332,104 @@ static int mtk_rx_alloc(struct mtk_eth * + */ + wmb(); + +- mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no) + offset); +- mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no) + offset); +- mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset); +- mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX + offset); ++ mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no)); ++ mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no)); ++ mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); ++ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX); + + return 0; + } + +-static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring) ++static int mtk_rx_alloc_qdma(struct mtk_eth *eth, int rx_flag) + { ++ struct mtk_rx_ring *ring = ð->rx_ring_qdma; ++ int rx_data_len, rx_dma_size; ++ int i; ++ ++ rx_data_len = ETH_DATA_LEN; ++ rx_dma_size = MTK_DMA_SIZE; ++ ++ ring->frag_size = mtk_max_frag_size(rx_data_len); ++ ring->buf_size = mtk_max_buf_size(ring->frag_size); ++ ring->data = kcalloc(rx_dma_size, sizeof(*ring->data), ++ GFP_KERNEL); ++ if (!ring->data) ++ return -ENOMEM; ++ ++ for (i = 0; i < rx_dma_size; i++) { ++ ring->data[i] = netdev_alloc_frag(ring->frag_size); ++ if (!ring->data[i]) ++ return -ENOMEM; ++ } ++ ++ ring->dma = dma_alloc_coherent(eth->dev, ++ rx_dma_size * sizeof(*ring->dma), ++ &ring->phys, ++ GFP_ATOMIC | __GFP_ZERO); ++ if (!ring->dma) ++ return -ENOMEM; ++ ++ for (i = 0; i < rx_dma_size; i++) { ++ dma_addr_t dma_addr = dma_map_single(eth->dev, ++ ring->data[i] + NET_SKB_PAD, ++ ring->buf_size, ++ DMA_FROM_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dev, dma_addr))) ++ return -ENOMEM; ++ ring->dma[i].rxd1 = (unsigned int)dma_addr; ++ ++ ring->dma[i].rxd2 = RX_DMA_PLEN0(ring->buf_size); ++ } ++ ring->dma_size = rx_dma_size; ++ ring->calc_idx_update = false; ++ ring->calc_idx = rx_dma_size - 1; ++ ring->crx_idx_reg = MTK_QRX_CRX_IDX_CFG(0); ++ /* make sure that all changes to the dma ring are flushed before we ++ * continue ++ */ ++ wmb(); ++ ++ mtk_w32(eth, ring->phys, MTK_QRX_BASE_PTR_CFG(0)); ++ mtk_w32(eth, rx_dma_size, MTK_QRX_MAX_CNT_CFG(0)); ++ mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); ++ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(0), MTK_QDMA_RST_IDX); ++ ++ return 0; ++} ++ ++static void mtk_rx_clean(struct mtk_eth *eth, int ring_no) ++{ ++ struct mtk_rx_ring *ring = ð->rx_ring[ring_no]; ++ int i; ++ ++ if (ring->data && ring->dma) { ++ for (i = 0; i < ring->dma_size; i++) { ++ if (!ring->data[i]) ++ continue; ++ if (!ring->dma[i].rxd1) ++ continue; ++ dma_unmap_single(eth->dev, ++ ring->dma[i].rxd1, ++ ring->buf_size, ++ DMA_FROM_DEVICE); ++ skb_free_frag(ring->data[i]); ++ } ++ kfree(ring->data); ++ ring->data = NULL; ++ } ++ ++ if (ring->dma) { ++ dma_free_coherent(eth->dev, ++ ring->dma_size * sizeof(*ring->dma), ++ ring->dma, ++ ring->phys); ++ ring->dma = NULL; ++ } ++} ++ ++static void mtk_rx_clean_qdma(struct mtk_eth *eth) ++{ ++ struct mtk_rx_ring *ring = ð->rx_ring_qdma; + int i; + + if (ring->data && ring->dma) { +@@ -1683,7 +1755,7 @@ static int mtk_dma_init(struct mtk_eth * + if (err) + return err; + +- err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_QDMA); ++ err = mtk_rx_alloc_qdma(eth, MTK_RX_FLAGS_NORMAL); + if (err) + return err; + +@@ -1702,6 +1774,7 @@ static int mtk_dma_init(struct mtk_eth * + return err; + } + ++ + /* Enable random early drop and set drop threshold automatically */ + mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN | FC_THRES_MIN, + MTK_QDMA_FC_THRES); +@@ -1726,13 +1799,13 @@ static void mtk_dma_free(struct mtk_eth + eth->phy_scratch_ring = 0; + } + mtk_tx_clean(eth); +- mtk_rx_clean(eth, ð->rx_ring[0]); +- mtk_rx_clean(eth, ð->rx_ring_qdma); ++ mtk_rx_clean(eth, 0); ++ mtk_rx_clean_qdma(eth); + + if (eth->hwlro) { + mtk_hwlro_rx_uninit(eth); + for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) +- mtk_rx_clean(eth, ð->rx_ring[i]); ++ mtk_rx_clean(eth, i); + } + + kfree(eth->scratch_head); +@@ -1947,20 +2020,14 @@ 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); + +- /* Indicates CDM to parse the MTK special tag from CPU +- * which also is working out for untag packets. +- */ +- 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 */ + 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); + ++ mtk_w32(eth, 0x81000001, MTK_CDMP_IG_CTRL); ++ + /* disable delay and normal interrupt */ + #ifdef MTK_IRQ_DLY + mtk_w32(eth, 0x84048404, MTK_PDMA_DELAY_INT); +@@ -1990,6 +2057,9 @@ static int mtk_hw_init(struct mtk_eth *e + /* Enable RX checksum */ + val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN; + ++ if (!i) ++ val |= BIT(24); ++ + /* setup the mac dma */ + mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); + } +@@ -2069,7 +2139,18 @@ static int mtk_do_ioctl(struct net_devic + if (reg.off > REG_HQOS_MAX) + return -EINVAL; + mtk_w32(eth, reg.val, 0x1800 + reg.off); +-// printk("write reg off:%x val:%x\n", reg.off, reg.val); ++ printk("write reg off:%x val:%x\n", reg.off, reg.val); ++ return 0; ++ ++ case RAETH_QDMA_QUEUE_MAPPING: ++ copy_from_user(®, ifr->ifr_data, sizeof(reg)); ++ if ((reg.off & 0x100) == 0x100) { ++ lan_wan_separate = 1; ++ reg.off &= 0xff; ++ } else { ++ lan_wan_separate = 0; ++ } ++ M2Q_table[reg.off] = reg.val; + return 0; + #endif + case SIOCGMIIPHY: +@@ -2288,9 +2369,9 @@ static void mtk_get_ethtool_stats(struct + return; + + if (netif_running(dev) && netif_device_present(dev)) { +- if (spin_trylock_bh(&hwstats->stats_lock)) { ++ if (spin_trylock(&hwstats->stats_lock)) { + mtk_stats_update_mac(mac); +- spin_unlock_bh(&hwstats->stats_lock); ++ spin_unlock(&hwstats->stats_lock); + } + } + +@@ -2443,7 +2524,7 @@ static int mtk_add_mac(struct mtk_eth *e + mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; + + SET_NETDEV_DEV(eth->netdev[id], eth->dev); +- eth->netdev[id]->watchdog_timeo = 30 * HZ; ++ eth->netdev[id]->watchdog_timeo = 15 * HZ; + eth->netdev[id]->netdev_ops = &mtk_netdev_ops; + eth->netdev[id]->base_addr = (unsigned long)eth->base; + +@@ -2584,15 +2665,19 @@ static int mtk_probe(struct platform_dev + goto err_deinit_hw; + } + ++ cpumask_set_cpu(1, ð->affinity_mask[1]); ++ cpumask_set_cpu(0, ð->affinity_mask[2]); + 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; ++ irq_set_affinity_hint(eth->irq[1], ð->affinity_mask[1]); + + 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; ++ irq_set_affinity_hint(eth->irq[2], ð->affinity_mask[2]); + + err = mtk_mdio_init(eth); + if (err) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -80,7 +80,6 @@ + + /* 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 +@@ -91,12 +90,27 @@ + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) + ++/* GDMA Ingress Control Register */ ++#define MTK_GDMA1_IG_CTRL(x) (0x500 + (x * 0x1000)) ++ + /* Unicast Filter MAC Address Register - Low */ + #define MTK_GDMA_MAC_ADRL(x) (0x508 + (x * 0x1000)) + + /* Unicast Filter MAC Address Register - High */ + #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) + ++/* QDMA RX Base Pointer Register */ ++#define MTK_QRX_BASE_PTR0 0x1900 ++#define MTK_QRX_BASE_PTR_CFG(x) (MTK_QRX_BASE_PTR0 + (x * 0x10)) ++ ++/* QDMA RX Maximum Count Register */ ++#define MTK_QRX_MAX_CNT0 0x1904 ++#define MTK_QRX_MAX_CNT_CFG(x) (MTK_QRX_MAX_CNT0 + (x * 0x10)) ++ ++/* QDMA RX CPU Pointer Register */ ++#define MTK_QRX_CRX_IDX0 0x1908 ++#define MTK_QRX_CRX_IDX_CFG(x) (MTK_QRX_CRX_IDX0 + (x * 0x10)) ++ + /* PDMA RX Base Pointer Register */ + #define MTK_PRX_BASE_PTR0 0x900 + #define MTK_PRX_BASE_PTR_CFG(x) (MTK_PRX_BASE_PTR0 + (x * 0x10)) +@@ -240,7 +254,10 @@ + #define MTK_QDMA_INT_MASK 0x1A1C + + /* QDMA Interrupt Mask Register */ ++#define MTK_QDMA_HRED1 0x1A40 + #define MTK_QDMA_HRED2 0x1A44 ++#define MTK_QDMA_SRED1 0x1A48 ++#define MTK_QDMA_SRED2 0x1A4c + + /* QDMA TX Forward CPU Pointer Register */ + #define MTK_QTX_CTX_PTR 0x1B00 +@@ -275,6 +292,7 @@ + #define TX_DMA_TSO BIT(28) + #define TX_DMA_FPORT_SHIFT 25 + #define TX_DMA_FPORT_MASK 0x7 ++#define TX_DMA_VQID0 BIT(17) + #define TX_DMA_INS_VLAN BIT(16) + + /* QDMA descriptor txd3 */ +@@ -294,7 +312,6 @@ + + /* 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 + +@@ -310,6 +327,7 @@ + + /* Mac control registers */ + #define MTK_MAC_MCR(x) (0x10100 + (x * 0x100)) ++#define MTK_MAC_MSR(x) (0x10108 + (x * 0x100)) + #define MAC_MCR_MAX_RX_1536 BIT(24) + #define MAC_MCR_IPG_CFG (BIT(18) | BIT(16)) + #define MAC_MCR_FORCE_MODE BIT(15) +@@ -495,7 +513,6 @@ struct mtk_tx_ring { + enum mtk_rx_flags { + MTK_RX_FLAGS_NORMAL = 0, + MTK_RX_FLAGS_HWLRO, +- MTK_RX_FLAGS_QDMA, + }; + + /* struct mtk_rx_ring - This struct holds info describing a RX ring +@@ -539,9 +556,9 @@ struct mtk_rx_ring { + * @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 ++ * @tx_ring: Pointer to the memore holding info about the TX ring ++ * @rx_ring: Pointer to the memore holding info about the RX ring ++ * @rx_ring_qdma: Pointer to the memore holding info about the RX ring (QDMA) + * @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 +@@ -563,6 +580,7 @@ struct mtk_eth { + struct net_device *netdev[MTK_MAX_DEVS]; + struct mtk_mac *mac[MTK_MAX_DEVS]; + int irq[3]; ++ cpumask_t affinity_mask[3]; + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; +@@ -615,4 +633,6 @@ 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); + ++extern unsigned int M2Q_table[16]; ++ + #endif /* MTK_ETH_H */ |