Commit 21651635 authored by David S. Miller's avatar David S. Miller

Merge branch 'mtk-star-emac-features'

Biao Huang says:

====================
net: add more features for mtk-star-emac

Changes in v4:
1. correct the usage of spin_lock/__napi_schedule.
2. fix coding style as Jakub's comments.

Changes in v3:
1. refractor driver as Jakub's comments in patch
   "net: ethernet: mtk-star-emac: separate tx/rx handling with two NAPIs".
2. add acked-by as Rob's comments.
3. add a new patch for halp-duplex support in driver.

Changes in v2:
1. fix coding style as Bartosz's comments.
2. add reviewed-by as Bartosz's comments.

This series add more features for mtk-star-emac:
1. add reference clock pad selection for RMII;
2. add simple timing adjustment for RMII;
3. add support for MII;
4. add support for new IC MT8365;
5. separate tx/rx interrupt handling.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bfc71514 02e9ce07
...@@ -23,6 +23,7 @@ properties: ...@@ -23,6 +23,7 @@ properties:
- mediatek,mt8516-eth - mediatek,mt8516-eth
- mediatek,mt8518-eth - mediatek,mt8518-eth
- mediatek,mt8175-eth - mediatek,mt8175-eth
- mediatek,mt8365-eth
reg: reg:
maxItems: 1 maxItems: 1
...@@ -47,6 +48,22 @@ properties: ...@@ -47,6 +48,22 @@ properties:
Phandle to the device containing the PERICFG register range. This is used Phandle to the device containing the PERICFG register range. This is used
to control the MII mode. to control the MII mode.
mediatek,rmii-rxc:
type: boolean
description:
If present, indicates that the RMII reference clock, which is from external
PHYs, is connected to RXC pin. Otherwise, is connected to TXC pin.
mediatek,rxc-inverse:
type: boolean
description:
If present, indicates that clock on RXC pad will be inversed.
mediatek,txc-inverse:
type: boolean
description:
If present, indicates that clock on TXC pad will be inversed.
mdio: mdio:
$ref: mdio.yaml# $ref: mdio.yaml#
unevaluatedProperties: false unevaluatedProperties: false
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
#include <linux/of_net.h> #include <linux/of_net.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -32,6 +33,7 @@ ...@@ -32,6 +33,7 @@
#define MTK_STAR_SKB_ALIGNMENT 16 #define MTK_STAR_SKB_ALIGNMENT 16
#define MTK_STAR_HASHTABLE_MC_LIMIT 256 #define MTK_STAR_HASHTABLE_MC_LIMIT 256
#define MTK_STAR_HASHTABLE_SIZE_MAX 512 #define MTK_STAR_HASHTABLE_SIZE_MAX 512
#define MTK_STAR_DESC_NEEDED (MAX_SKB_FRAGS + 4)
/* Normally we'd use NET_IP_ALIGN but on arm64 its value is 0 and it doesn't /* Normally we'd use NET_IP_ALIGN but on arm64 its value is 0 and it doesn't
* work for this controller. * work for this controller.
...@@ -129,6 +131,11 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" }; ...@@ -129,6 +131,11 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
#define MTK_STAR_REG_INT_MASK 0x0054 #define MTK_STAR_REG_INT_MASK 0x0054
#define MTK_STAR_BIT_INT_MASK_FNRC BIT(6) #define MTK_STAR_BIT_INT_MASK_FNRC BIT(6)
/* Delay-Macro Register */
#define MTK_STAR_REG_TEST0 0x0058
#define MTK_STAR_BIT_INV_RX_CLK BIT(30)
#define MTK_STAR_BIT_INV_TX_CLK BIT(31)
/* Misc. Config Register */ /* Misc. Config Register */
#define MTK_STAR_REG_TEST1 0x005c #define MTK_STAR_REG_TEST1 0x005c
#define MTK_STAR_BIT_TEST1_RST_HASH_MBIST BIT(31) #define MTK_STAR_BIT_TEST1_RST_HASH_MBIST BIT(31)
...@@ -149,6 +156,7 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" }; ...@@ -149,6 +156,7 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
#define MTK_STAR_REG_MAC_CLK_CONF 0x00ac #define MTK_STAR_REG_MAC_CLK_CONF 0x00ac
#define MTK_STAR_MSK_MAC_CLK_CONF GENMASK(7, 0) #define MTK_STAR_MSK_MAC_CLK_CONF GENMASK(7, 0)
#define MTK_STAR_BIT_CLK_DIV_10 0x0a #define MTK_STAR_BIT_CLK_DIV_10 0x0a
#define MTK_STAR_BIT_CLK_DIV_50 0x32
/* Counter registers. */ /* Counter registers. */
#define MTK_STAR_REG_C_RXOKPKT 0x0100 #define MTK_STAR_REG_C_RXOKPKT 0x0100
...@@ -181,9 +189,14 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" }; ...@@ -181,9 +189,14 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
#define MTK_STAR_REG_C_RX_TWIST 0x0218 #define MTK_STAR_REG_C_RX_TWIST 0x0218
/* Ethernet CFG Control */ /* Ethernet CFG Control */
#define MTK_PERICFG_REG_NIC_CFG_CON 0x03c4 #define MTK_PERICFG_REG_NIC_CFG0_CON 0x03c4
#define MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII GENMASK(3, 0) #define MTK_PERICFG_REG_NIC_CFG1_CON 0x03c8
#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII BIT(0) #define MTK_PERICFG_REG_NIC_CFG_CON_V2 0x0c10
#define MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF GENMASK(3, 0)
#define MTK_PERICFG_BIT_NIC_CFG_CON_MII 0
#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII 1
#define MTK_PERICFG_BIT_NIC_CFG_CON_CLK BIT(0)
#define MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2 BIT(8)
/* Represents the actual structure of descriptors used by the MAC. We can /* Represents the actual structure of descriptors used by the MAC. We can
* reuse the same structure for both TX and RX - the layout is the same, only * reuse the same structure for both TX and RX - the layout is the same, only
...@@ -216,7 +229,8 @@ struct mtk_star_ring_desc_data { ...@@ -216,7 +229,8 @@ struct mtk_star_ring_desc_data {
struct sk_buff *skb; struct sk_buff *skb;
}; };
#define MTK_STAR_RING_NUM_DESCS 128 #define MTK_STAR_RING_NUM_DESCS 512
#define MTK_STAR_TX_THRESH (MTK_STAR_RING_NUM_DESCS / 4)
#define MTK_STAR_NUM_TX_DESCS MTK_STAR_RING_NUM_DESCS #define MTK_STAR_NUM_TX_DESCS MTK_STAR_RING_NUM_DESCS
#define MTK_STAR_NUM_RX_DESCS MTK_STAR_RING_NUM_DESCS #define MTK_STAR_NUM_RX_DESCS MTK_STAR_RING_NUM_DESCS
#define MTK_STAR_NUM_DESCS_TOTAL (MTK_STAR_RING_NUM_DESCS * 2) #define MTK_STAR_NUM_DESCS_TOTAL (MTK_STAR_RING_NUM_DESCS * 2)
...@@ -231,6 +245,11 @@ struct mtk_star_ring { ...@@ -231,6 +245,11 @@ struct mtk_star_ring {
unsigned int tail; unsigned int tail;
}; };
struct mtk_star_compat {
int (*set_interface_mode)(struct net_device *ndev);
unsigned char bit_clk_div;
};
struct mtk_star_priv { struct mtk_star_priv {
struct net_device *ndev; struct net_device *ndev;
...@@ -246,7 +265,8 @@ struct mtk_star_priv { ...@@ -246,7 +265,8 @@ struct mtk_star_priv {
struct mtk_star_ring rx_ring; struct mtk_star_ring rx_ring;
struct mii_bus *mii; struct mii_bus *mii;
struct napi_struct napi; struct napi_struct tx_napi;
struct napi_struct rx_napi;
struct device_node *phy_node; struct device_node *phy_node;
phy_interface_t phy_intf; phy_interface_t phy_intf;
...@@ -255,6 +275,11 @@ struct mtk_star_priv { ...@@ -255,6 +275,11 @@ struct mtk_star_priv {
int speed; int speed;
int duplex; int duplex;
int pause; int pause;
bool rmii_rxc;
bool rx_inv;
bool tx_inv;
const struct mtk_star_compat *compat_data;
/* Protects against concurrent descriptor access. */ /* Protects against concurrent descriptor access. */
spinlock_t lock; spinlock_t lock;
...@@ -357,19 +382,16 @@ mtk_star_ring_push_head_tx(struct mtk_star_ring *ring, ...@@ -357,19 +382,16 @@ mtk_star_ring_push_head_tx(struct mtk_star_ring *ring,
mtk_star_ring_push_head(ring, desc_data, flags); mtk_star_ring_push_head(ring, desc_data, flags);
} }
static unsigned int mtk_star_ring_num_used_descs(struct mtk_star_ring *ring) static unsigned int mtk_star_tx_ring_avail(struct mtk_star_ring *ring)
{ {
return abs(ring->head - ring->tail); u32 avail;
}
static bool mtk_star_ring_full(struct mtk_star_ring *ring) if (ring->tail > ring->head)
{ avail = ring->tail - ring->head - 1;
return mtk_star_ring_num_used_descs(ring) == MTK_STAR_RING_NUM_DESCS; else
} avail = MTK_STAR_RING_NUM_DESCS - ring->head + ring->tail - 1;
static bool mtk_star_ring_descs_available(struct mtk_star_ring *ring) return avail;
{
return mtk_star_ring_num_used_descs(ring) > 0;
} }
static dma_addr_t mtk_star_dma_map_rx(struct mtk_star_priv *priv, static dma_addr_t mtk_star_dma_map_rx(struct mtk_star_priv *priv,
...@@ -414,6 +436,36 @@ static void mtk_star_nic_disable_pd(struct mtk_star_priv *priv) ...@@ -414,6 +436,36 @@ static void mtk_star_nic_disable_pd(struct mtk_star_priv *priv)
MTK_STAR_BIT_MAC_CFG_NIC_PD); MTK_STAR_BIT_MAC_CFG_NIC_PD);
} }
static void mtk_star_enable_dma_irq(struct mtk_star_priv *priv,
bool rx, bool tx)
{
u32 value;
regmap_read(priv->regs, MTK_STAR_REG_INT_MASK, &value);
if (tx)
value &= ~MTK_STAR_BIT_INT_STS_TNTC;
if (rx)
value &= ~MTK_STAR_BIT_INT_STS_FNRC;
regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, value);
}
static void mtk_star_disable_dma_irq(struct mtk_star_priv *priv,
bool rx, bool tx)
{
u32 value;
regmap_read(priv->regs, MTK_STAR_REG_INT_MASK, &value);
if (tx)
value |= MTK_STAR_BIT_INT_STS_TNTC;
if (rx)
value |= MTK_STAR_BIT_INT_STS_FNRC;
regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, value);
}
/* Unmask the three interrupts we care about, mask all others. */ /* Unmask the three interrupts we care about, mask all others. */
static void mtk_star_intr_enable(struct mtk_star_priv *priv) static void mtk_star_intr_enable(struct mtk_star_priv *priv)
{ {
...@@ -429,20 +481,11 @@ static void mtk_star_intr_disable(struct mtk_star_priv *priv) ...@@ -429,20 +481,11 @@ static void mtk_star_intr_disable(struct mtk_star_priv *priv)
regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, ~0); regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, ~0);
} }
static unsigned int mtk_star_intr_read(struct mtk_star_priv *priv)
{
unsigned int val;
regmap_read(priv->regs, MTK_STAR_REG_INT_STS, &val);
return val;
}
static unsigned int mtk_star_intr_ack_all(struct mtk_star_priv *priv) static unsigned int mtk_star_intr_ack_all(struct mtk_star_priv *priv)
{ {
unsigned int val; unsigned int val;
val = mtk_star_intr_read(priv); regmap_read(priv->regs, MTK_STAR_REG_INT_STS, &val);
regmap_write(priv->regs, MTK_STAR_REG_INT_STS, val); regmap_write(priv->regs, MTK_STAR_REG_INT_STS, val);
return val; return val;
...@@ -714,25 +757,44 @@ static void mtk_star_free_tx_skbs(struct mtk_star_priv *priv) ...@@ -714,25 +757,44 @@ static void mtk_star_free_tx_skbs(struct mtk_star_priv *priv)
mtk_star_ring_free_skbs(priv, ring, mtk_star_dma_unmap_tx); mtk_star_ring_free_skbs(priv, ring, mtk_star_dma_unmap_tx);
} }
/* All processing for TX and RX happens in the napi poll callback. /**
* * mtk_star_handle_irq - Interrupt Handler.
* FIXME: The interrupt handling should be more fine-grained with each * @irq: interrupt number.
* interrupt enabled/disabled independently when needed. Unfortunatly this * @data: pointer to a network interface device structure.
* turned out to impact the driver's stability and until we have something * Description : this is the driver interrupt service routine.
* working properly, we're disabling all interrupts during TX & RX processing * it mainly handles:
* or when resetting the counter registers. * 1. tx complete interrupt for frame transmission.
*/ * 2. rx complete interrupt for frame reception.
* 3. MAC Management Counter interrupt to avoid counter overflow.
**/
static irqreturn_t mtk_star_handle_irq(int irq, void *data) static irqreturn_t mtk_star_handle_irq(int irq, void *data)
{ {
struct mtk_star_priv *priv; struct net_device *ndev = data;
struct net_device *ndev; struct mtk_star_priv *priv = netdev_priv(ndev);
unsigned int intr_status = mtk_star_intr_ack_all(priv);
bool rx, tx;
ndev = data; rx = (intr_status & MTK_STAR_BIT_INT_STS_FNRC) &&
priv = netdev_priv(ndev); napi_schedule_prep(&priv->rx_napi);
tx = (intr_status & MTK_STAR_BIT_INT_STS_TNTC) &&
napi_schedule_prep(&priv->tx_napi);
if (netif_running(ndev)) { if (rx || tx) {
mtk_star_intr_disable(priv); spin_lock(&priv->lock);
napi_schedule(&priv->napi); /* mask Rx and TX Complete interrupt */
mtk_star_disable_dma_irq(priv, rx, tx);
spin_unlock(&priv->lock);
if (rx)
__napi_schedule(&priv->rx_napi);
if (tx)
__napi_schedule(&priv->tx_napi);
}
/* interrupt is triggered once any counters reach 0x8000000 */
if (intr_status & MTK_STAR_REG_INT_STS_MIB_CNT_TH) {
mtk_star_update_stats(priv);
mtk_star_reset_counters(priv);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -821,32 +883,26 @@ static void mtk_star_phy_config(struct mtk_star_priv *priv) ...@@ -821,32 +883,26 @@ static void mtk_star_phy_config(struct mtk_star_priv *priv)
val <<= MTK_STAR_OFF_PHY_CTRL1_FORCE_SPD; val <<= MTK_STAR_OFF_PHY_CTRL1_FORCE_SPD;
val |= MTK_STAR_BIT_PHY_CTRL1_AN_EN; val |= MTK_STAR_BIT_PHY_CTRL1_AN_EN;
if (priv->pause) {
val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX; val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX; val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
/* Only full-duplex supported for now. */
val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX; val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
} else {
val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
}
regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL1, val); regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL1, val);
if (priv->pause) {
val = MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K; val = MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K;
val <<= MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH; val <<= MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH;
val |= MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR; val |= MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR;
} else {
val = 0;
}
regmap_update_bits(priv->regs, MTK_STAR_REG_FC_CFG, regmap_update_bits(priv->regs, MTK_STAR_REG_FC_CFG,
MTK_STAR_MSK_FC_CFG_SEND_PAUSE_TH | MTK_STAR_MSK_FC_CFG_SEND_PAUSE_TH |
MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR, val); MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR, val);
if (priv->pause) {
val = MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K; val = MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
val <<= MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS; val <<= MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS;
} else {
val = 0;
}
regmap_update_bits(priv->regs, MTK_STAR_REG_EXT_CFG, regmap_update_bits(priv->regs, MTK_STAR_REG_EXT_CFG,
MTK_STAR_MSK_EXT_CFG_SND_PAUSE_RLS, val); MTK_STAR_MSK_EXT_CFG_SND_PAUSE_RLS, val);
} }
...@@ -898,14 +954,7 @@ static void mtk_star_init_config(struct mtk_star_priv *priv) ...@@ -898,14 +954,7 @@ static void mtk_star_init_config(struct mtk_star_priv *priv)
regmap_write(priv->regs, MTK_STAR_REG_SYS_CONF, val); regmap_write(priv->regs, MTK_STAR_REG_SYS_CONF, val);
regmap_update_bits(priv->regs, MTK_STAR_REG_MAC_CLK_CONF, regmap_update_bits(priv->regs, MTK_STAR_REG_MAC_CLK_CONF,
MTK_STAR_MSK_MAC_CLK_CONF, MTK_STAR_MSK_MAC_CLK_CONF,
MTK_STAR_BIT_CLK_DIV_10); priv->compat_data->bit_clk_div);
}
static void mtk_star_set_mode_rmii(struct mtk_star_priv *priv)
{
regmap_update_bits(priv->pericfg, MTK_PERICFG_REG_NIC_CFG_CON,
MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII,
MTK_PERICFG_BIT_NIC_CFG_CON_RMII);
} }
static int mtk_star_enable(struct net_device *ndev) static int mtk_star_enable(struct net_device *ndev)
...@@ -951,11 +1000,12 @@ static int mtk_star_enable(struct net_device *ndev) ...@@ -951,11 +1000,12 @@ static int mtk_star_enable(struct net_device *ndev)
/* Request the interrupt */ /* Request the interrupt */
ret = request_irq(ndev->irq, mtk_star_handle_irq, ret = request_irq(ndev->irq, mtk_star_handle_irq,
IRQF_TRIGGER_FALLING, ndev->name, ndev); IRQF_TRIGGER_NONE, ndev->name, ndev);
if (ret) if (ret)
goto err_free_skbs; goto err_free_skbs;
napi_enable(&priv->napi); napi_enable(&priv->tx_napi);
napi_enable(&priv->rx_napi);
mtk_star_intr_ack_all(priv); mtk_star_intr_ack_all(priv);
mtk_star_intr_enable(priv); mtk_star_intr_enable(priv);
...@@ -988,7 +1038,8 @@ static void mtk_star_disable(struct net_device *ndev) ...@@ -988,7 +1038,8 @@ static void mtk_star_disable(struct net_device *ndev)
struct mtk_star_priv *priv = netdev_priv(ndev); struct mtk_star_priv *priv = netdev_priv(ndev);
netif_stop_queue(ndev); netif_stop_queue(ndev);
napi_disable(&priv->napi); napi_disable(&priv->tx_napi);
napi_disable(&priv->rx_napi);
mtk_star_intr_disable(priv); mtk_star_intr_disable(priv);
mtk_star_dma_disable(priv); mtk_star_dma_disable(priv);
mtk_star_intr_ack_all(priv); mtk_star_intr_ack_all(priv);
...@@ -1020,13 +1071,45 @@ static int mtk_star_netdev_ioctl(struct net_device *ndev, ...@@ -1020,13 +1071,45 @@ static int mtk_star_netdev_ioctl(struct net_device *ndev,
return phy_mii_ioctl(ndev->phydev, req, cmd); return phy_mii_ioctl(ndev->phydev, req, cmd);
} }
static int mtk_star_netdev_start_xmit(struct sk_buff *skb, static int __mtk_star_maybe_stop_tx(struct mtk_star_priv *priv, u16 size)
{
netif_stop_queue(priv->ndev);
/* Might race with mtk_star_tx_poll, check again */
smp_mb();
if (likely(mtk_star_tx_ring_avail(&priv->tx_ring) < size))
return -EBUSY;
netif_start_queue(priv->ndev);
return 0;
}
static inline int mtk_star_maybe_stop_tx(struct mtk_star_priv *priv, u16 size)
{
if (likely(mtk_star_tx_ring_avail(&priv->tx_ring) >= size))
return 0;
return __mtk_star_maybe_stop_tx(priv, size);
}
static netdev_tx_t mtk_star_netdev_start_xmit(struct sk_buff *skb,
struct net_device *ndev) struct net_device *ndev)
{ {
struct mtk_star_priv *priv = netdev_priv(ndev); struct mtk_star_priv *priv = netdev_priv(ndev);
struct mtk_star_ring *ring = &priv->tx_ring; struct mtk_star_ring *ring = &priv->tx_ring;
struct device *dev = mtk_star_get_dev(priv); struct device *dev = mtk_star_get_dev(priv);
struct mtk_star_ring_desc_data desc_data; struct mtk_star_ring_desc_data desc_data;
int nfrags = skb_shinfo(skb)->nr_frags;
if (unlikely(mtk_star_tx_ring_avail(ring) < nfrags + 1)) {
if (!netif_queue_stopped(ndev)) {
netif_stop_queue(ndev);
/* This is a hard error, log it. */
pr_err_ratelimited("Tx ring full when queue awake\n");
}
return NETDEV_TX_BUSY;
}
desc_data.dma_addr = mtk_star_dma_map_tx(priv, skb); desc_data.dma_addr = mtk_star_dma_map_tx(priv, skb);
if (dma_mapping_error(dev, desc_data.dma_addr)) if (dma_mapping_error(dev, desc_data.dma_addr))
...@@ -1034,17 +1117,11 @@ static int mtk_star_netdev_start_xmit(struct sk_buff *skb, ...@@ -1034,17 +1117,11 @@ static int mtk_star_netdev_start_xmit(struct sk_buff *skb,
desc_data.skb = skb; desc_data.skb = skb;
desc_data.len = skb->len; desc_data.len = skb->len;
spin_lock_bh(&priv->lock);
mtk_star_ring_push_head_tx(ring, &desc_data); mtk_star_ring_push_head_tx(ring, &desc_data);
netdev_sent_queue(ndev, skb->len); netdev_sent_queue(ndev, skb->len);
if (mtk_star_ring_full(ring)) mtk_star_maybe_stop_tx(priv, MTK_STAR_DESC_NEEDED);
netif_stop_queue(ndev);
spin_unlock_bh(&priv->lock);
mtk_star_dma_resume_tx(priv); mtk_star_dma_resume_tx(priv);
...@@ -1076,31 +1153,40 @@ static int mtk_star_tx_complete_one(struct mtk_star_priv *priv) ...@@ -1076,31 +1153,40 @@ static int mtk_star_tx_complete_one(struct mtk_star_priv *priv)
return ret; return ret;
} }
static void mtk_star_tx_complete_all(struct mtk_star_priv *priv) static int mtk_star_tx_poll(struct napi_struct *napi, int budget)
{ {
struct mtk_star_priv *priv = container_of(napi, struct mtk_star_priv,
tx_napi);
int ret = 0, pkts_compl = 0, bytes_compl = 0, count = 0;
struct mtk_star_ring *ring = &priv->tx_ring; struct mtk_star_ring *ring = &priv->tx_ring;
struct net_device *ndev = priv->ndev; struct net_device *ndev = priv->ndev;
int ret, pkts_compl, bytes_compl; unsigned int head = ring->head;
bool wake = false; unsigned int entry = ring->tail;
spin_lock(&priv->lock);
for (pkts_compl = 0, bytes_compl = 0;;
pkts_compl++, bytes_compl += ret, wake = true) {
if (!mtk_star_ring_descs_available(ring))
break;
while (entry != head && count < (MTK_STAR_RING_NUM_DESCS - 1)) {
ret = mtk_star_tx_complete_one(priv); ret = mtk_star_tx_complete_one(priv);
if (ret < 0) if (ret < 0)
break; break;
count++;
pkts_compl++;
bytes_compl += ret;
entry = ring->tail;
} }
netdev_completed_queue(ndev, pkts_compl, bytes_compl); netdev_completed_queue(ndev, pkts_compl, bytes_compl);
if (wake && netif_queue_stopped(ndev)) if (unlikely(netif_queue_stopped(ndev)) &&
(mtk_star_tx_ring_avail(ring) > MTK_STAR_TX_THRESH))
netif_wake_queue(ndev); netif_wake_queue(ndev);
if (napi_complete(napi)) {
spin_lock(&priv->lock);
mtk_star_enable_dma_irq(priv, false, true);
spin_unlock(&priv->lock); spin_unlock(&priv->lock);
}
return 0;
} }
static void mtk_star_netdev_get_stats64(struct net_device *ndev, static void mtk_star_netdev_get_stats64(struct net_device *ndev,
...@@ -1180,7 +1266,7 @@ static const struct ethtool_ops mtk_star_ethtool_ops = { ...@@ -1180,7 +1266,7 @@ static const struct ethtool_ops mtk_star_ethtool_ops = {
.set_link_ksettings = phy_ethtool_set_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings,
}; };
static int mtk_star_receive_packet(struct mtk_star_priv *priv) static int mtk_star_rx(struct mtk_star_priv *priv, int budget)
{ {
struct mtk_star_ring *ring = &priv->rx_ring; struct mtk_star_ring *ring = &priv->rx_ring;
struct device *dev = mtk_star_get_dev(priv); struct device *dev = mtk_star_get_dev(priv);
...@@ -1188,11 +1274,10 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv) ...@@ -1188,11 +1274,10 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
struct net_device *ndev = priv->ndev; struct net_device *ndev = priv->ndev;
struct sk_buff *curr_skb, *new_skb; struct sk_buff *curr_skb, *new_skb;
dma_addr_t new_dma_addr; dma_addr_t new_dma_addr;
int ret; int ret, count = 0;
spin_lock(&priv->lock); while (count < budget) {
ret = mtk_star_ring_pop_tail(ring, &desc_data); ret = mtk_star_ring_pop_tail(ring, &desc_data);
spin_unlock(&priv->lock);
if (ret) if (ret)
return -1; return -1;
...@@ -1205,8 +1290,8 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv) ...@@ -1205,8 +1290,8 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
goto push_new_skb; goto push_new_skb;
} }
/* Prepare new skb before receiving the current one. Reuse the current /* Prepare new skb before receiving the current one.
* skb if we fail at any point. * Reuse the current skb if we fail at any point.
*/ */
new_skb = mtk_star_alloc_skb(ndev); new_skb = mtk_star_alloc_skb(ndev);
if (!new_skb) { if (!new_skb) {
...@@ -1224,7 +1309,9 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv) ...@@ -1224,7 +1309,9 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
goto push_new_skb; goto push_new_skb;
} }
/* We can't fail anymore at this point: it's safe to unmap the skb. */ /* We can't fail anymore at this point:
* it's safe to unmap the skb.
*/
mtk_star_dma_unmap_rx(priv, &desc_data); mtk_star_dma_unmap_rx(priv, &desc_data);
skb_put(desc_data.skb, desc_data.len); skb_put(desc_data.skb, desc_data.len);
...@@ -1237,58 +1324,35 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv) ...@@ -1237,58 +1324,35 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
desc_data.dma_addr = new_dma_addr; desc_data.dma_addr = new_dma_addr;
push_new_skb: push_new_skb:
count++;
desc_data.len = skb_tailroom(new_skb); desc_data.len = skb_tailroom(new_skb);
desc_data.skb = new_skb; desc_data.skb = new_skb;
spin_lock(&priv->lock);
mtk_star_ring_push_head_rx(ring, &desc_data); mtk_star_ring_push_head_rx(ring, &desc_data);
spin_unlock(&priv->lock); }
return 0;
}
static int mtk_star_process_rx(struct mtk_star_priv *priv, int budget)
{
int received, ret;
for (received = 0, ret = 0; received < budget && ret == 0; received++)
ret = mtk_star_receive_packet(priv);
mtk_star_dma_resume_rx(priv); mtk_star_dma_resume_rx(priv);
return received; return count;
} }
static int mtk_star_poll(struct napi_struct *napi, int budget) static int mtk_star_rx_poll(struct napi_struct *napi, int budget)
{ {
struct mtk_star_priv *priv; struct mtk_star_priv *priv;
unsigned int status; int work_done = 0;
int received = 0;
priv = container_of(napi, struct mtk_star_priv, napi);
status = mtk_star_intr_read(priv);
mtk_star_intr_ack_all(priv);
if (status & MTK_STAR_BIT_INT_STS_TNTC)
/* Clean-up all TX descriptors. */
mtk_star_tx_complete_all(priv);
if (status & MTK_STAR_BIT_INT_STS_FNRC) priv = container_of(napi, struct mtk_star_priv, rx_napi);
/* Receive up to $budget packets. */
received = mtk_star_process_rx(priv, budget);
if (unlikely(status & MTK_STAR_REG_INT_STS_MIB_CNT_TH)) { work_done = mtk_star_rx(priv, budget);
mtk_star_update_stats(priv); if (work_done < budget) {
mtk_star_reset_counters(priv); napi_complete_done(napi, work_done);
spin_lock(&priv->lock);
mtk_star_enable_dma_irq(priv, true, false);
spin_unlock(&priv->lock);
} }
if (received < budget) return work_done;
napi_complete_done(napi, received);
mtk_star_intr_enable(priv);
return received;
} }
static void mtk_star_mdio_rwok_clear(struct mtk_star_priv *priv) static void mtk_star_mdio_rwok_clear(struct mtk_star_priv *priv)
...@@ -1442,6 +1506,25 @@ static void mtk_star_clk_disable_unprepare(void *data) ...@@ -1442,6 +1506,25 @@ static void mtk_star_clk_disable_unprepare(void *data)
clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks); clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
} }
static int mtk_star_set_timing(struct mtk_star_priv *priv)
{
struct device *dev = mtk_star_get_dev(priv);
unsigned int delay_val = 0;
switch (priv->phy_intf) {
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_RMII:
delay_val |= FIELD_PREP(MTK_STAR_BIT_INV_RX_CLK, priv->rx_inv);
delay_val |= FIELD_PREP(MTK_STAR_BIT_INV_TX_CLK, priv->tx_inv);
break;
default:
dev_err(dev, "This interface not supported\n");
return -EINVAL;
}
return regmap_write(priv->regs, MTK_STAR_REG_TEST0, delay_val);
}
static int mtk_star_probe(struct platform_device *pdev) static int mtk_star_probe(struct platform_device *pdev)
{ {
struct device_node *of_node; struct device_node *of_node;
...@@ -1460,6 +1543,7 @@ static int mtk_star_probe(struct platform_device *pdev) ...@@ -1460,6 +1543,7 @@ static int mtk_star_probe(struct platform_device *pdev)
priv = netdev_priv(ndev); priv = netdev_priv(ndev);
priv->ndev = ndev; priv->ndev = ndev;
priv->compat_data = of_device_get_match_data(&pdev->dev);
SET_NETDEV_DEV(ndev, dev); SET_NETDEV_DEV(ndev, dev);
platform_set_drvdata(pdev, ndev); platform_set_drvdata(pdev, ndev);
...@@ -1510,7 +1594,8 @@ static int mtk_star_probe(struct platform_device *pdev) ...@@ -1510,7 +1594,8 @@ static int mtk_star_probe(struct platform_device *pdev)
ret = of_get_phy_mode(of_node, &priv->phy_intf); ret = of_get_phy_mode(of_node, &priv->phy_intf);
if (ret) { if (ret) {
return ret; return ret;
} else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII) { } else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII &&
priv->phy_intf != PHY_INTERFACE_MODE_MII) {
dev_err(dev, "unsupported phy mode: %s\n", dev_err(dev, "unsupported phy mode: %s\n",
phy_modes(priv->phy_intf)); phy_modes(priv->phy_intf));
return -EINVAL; return -EINVAL;
...@@ -1522,7 +1607,23 @@ static int mtk_star_probe(struct platform_device *pdev) ...@@ -1522,7 +1607,23 @@ static int mtk_star_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
mtk_star_set_mode_rmii(priv); priv->rmii_rxc = of_property_read_bool(of_node, "mediatek,rmii-rxc");
priv->rx_inv = of_property_read_bool(of_node, "mediatek,rxc-inverse");
priv->tx_inv = of_property_read_bool(of_node, "mediatek,txc-inverse");
if (priv->compat_data->set_interface_mode) {
ret = priv->compat_data->set_interface_mode(ndev);
if (ret) {
dev_err(dev, "Failed to set phy interface, err = %d\n", ret);
return -EINVAL;
}
}
ret = mtk_star_set_timing(priv);
if (ret) {
dev_err(dev, "Failed to set timing, err = %d\n", ret);
return -EINVAL;
}
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret) { if (ret) {
...@@ -1550,16 +1651,93 @@ static int mtk_star_probe(struct platform_device *pdev) ...@@ -1550,16 +1651,93 @@ static int mtk_star_probe(struct platform_device *pdev)
ndev->netdev_ops = &mtk_star_netdev_ops; ndev->netdev_ops = &mtk_star_netdev_ops;
ndev->ethtool_ops = &mtk_star_ethtool_ops; ndev->ethtool_ops = &mtk_star_ethtool_ops;
netif_napi_add(ndev, &priv->napi, mtk_star_poll, NAPI_POLL_WEIGHT); netif_napi_add(ndev, &priv->rx_napi, mtk_star_rx_poll,
NAPI_POLL_WEIGHT);
netif_tx_napi_add(ndev, &priv->tx_napi, mtk_star_tx_poll,
NAPI_POLL_WEIGHT);
return devm_register_netdev(dev, ndev); return devm_register_netdev(dev, ndev);
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
static int mt8516_set_interface_mode(struct net_device *ndev)
{
struct mtk_star_priv *priv = netdev_priv(ndev);
struct device *dev = mtk_star_get_dev(priv);
unsigned int intf_val, ret, rmii_rxc;
switch (priv->phy_intf) {
case PHY_INTERFACE_MODE_MII:
intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_MII;
rmii_rxc = 0;
break;
case PHY_INTERFACE_MODE_RMII:
intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_RMII;
rmii_rxc = priv->rmii_rxc ? 0 : MTK_PERICFG_BIT_NIC_CFG_CON_CLK;
break;
default:
dev_err(dev, "This interface not supported\n");
return -EINVAL;
}
ret = regmap_update_bits(priv->pericfg,
MTK_PERICFG_REG_NIC_CFG1_CON,
MTK_PERICFG_BIT_NIC_CFG_CON_CLK,
rmii_rxc);
if (ret)
return ret;
return regmap_update_bits(priv->pericfg,
MTK_PERICFG_REG_NIC_CFG0_CON,
MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF,
intf_val);
}
static int mt8365_set_interface_mode(struct net_device *ndev)
{
struct mtk_star_priv *priv = netdev_priv(ndev);
struct device *dev = mtk_star_get_dev(priv);
unsigned int intf_val;
switch (priv->phy_intf) {
case PHY_INTERFACE_MODE_MII:
intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_MII;
break;
case PHY_INTERFACE_MODE_RMII:
intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_RMII;
intf_val |= priv->rmii_rxc ? 0 : MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2;
break;
default:
dev_err(dev, "This interface not supported\n");
return -EINVAL;
}
return regmap_update_bits(priv->pericfg,
MTK_PERICFG_REG_NIC_CFG_CON_V2,
MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF |
MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2,
intf_val);
}
static const struct mtk_star_compat mtk_star_mt8516_compat = {
.set_interface_mode = mt8516_set_interface_mode,
.bit_clk_div = MTK_STAR_BIT_CLK_DIV_10,
};
static const struct mtk_star_compat mtk_star_mt8365_compat = {
.set_interface_mode = mt8365_set_interface_mode,
.bit_clk_div = MTK_STAR_BIT_CLK_DIV_50,
};
static const struct of_device_id mtk_star_of_match[] = { static const struct of_device_id mtk_star_of_match[] = {
{ .compatible = "mediatek,mt8516-eth", }, { .compatible = "mediatek,mt8516-eth",
{ .compatible = "mediatek,mt8518-eth", }, .data = &mtk_star_mt8516_compat },
{ .compatible = "mediatek,mt8175-eth", }, { .compatible = "mediatek,mt8518-eth",
.data = &mtk_star_mt8516_compat },
{ .compatible = "mediatek,mt8175-eth",
.data = &mtk_star_mt8516_compat },
{ .compatible = "mediatek,mt8365-eth",
.data = &mtk_star_mt8365_compat },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, mtk_star_of_match); MODULE_DEVICE_TABLE(of, mtk_star_of_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment