Implement the fxgmac_start function to connect phy and init phy lib, enable napi
, phy and msix irq.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
---
.../ethernet/motorcomm/yt6801/yt6801_net.c | 242 ++++++++++++++++++
1 file changed, 242 insertions(+)
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_net.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_net.c
index 39b91cc26..eedf4dcb0 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_net.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_net.c
@@ -11,6 +11,8 @@
#include "yt6801_desc.h"
#include "yt6801_net.h"
+static void fxgmac_napi_enable(struct fxgmac_pdata *pdata);
+
static int fxgmac_calc_rx_buf_size(struct fxgmac_pdata *pdata, unsigned int mtu)
{
u32 rx_buf_size, max_mtu;
@@ -31,6 +33,26 @@ static int fxgmac_calc_rx_buf_size(struct fxgmac_pdata *pdata, unsigned int mtu)
return rx_buf_size;
}
+static void fxgmac_enable_rx_tx_ints(struct fxgmac_pdata *pdata)
+{
+ struct fxgmac_channel *channel = pdata->channel_head;
+ struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
+ enum fxgmac_int int_id;
+
+ for (u32 i = 0; i < pdata->channel_count; i++, channel++) {
+ if (channel->tx_ring && channel->rx_ring)
+ int_id = FXGMAC_INT_DMA_CH_SR_TI_RI;
+ else if (channel->tx_ring)
+ int_id = FXGMAC_INT_DMA_CH_SR_TI;
+ else if (channel->rx_ring)
+ int_id = FXGMAC_INT_DMA_CH_SR_RI;
+ else
+ continue;
+
+ hw_ops->enable_channel_irq(channel, int_id);
+ }
+}
+
#define FXGMAC_NAPI_ENABLE 0x1
#define FXGMAC_NAPI_DISABLE 0x0
static void fxgmac_napi_disable(struct fxgmac_pdata *pdata)
@@ -180,6 +202,160 @@ void fxgmac_free_rx_data(struct fxgmac_pdata *pdata)
}
}
+static void fxgmac_phylink_handler(struct net_device *ndev)
+{
+ struct fxgmac_pdata *pdata = netdev_priv(ndev);
+ struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
+
+ pdata->phy_link = pdata->phydev->link;
+ pdata->phy_speed = pdata->phydev->speed;
+ pdata->phy_duplex = pdata->phydev->duplex;
+
+ yt_dbg(pdata, "EPHY_CTRL:%x, link:%d, speed:%d, duplex:%x.\n",
+ rd32_mem(pdata, EPHY_CTRL), pdata->phy_link, pdata->phy_speed,
+ pdata->phy_duplex);
+
+ if (pdata->phy_link) {
+ hw_ops->config_mac_speed(pdata);
+ hw_ops->enable_rx(pdata);
+ hw_ops->enable_tx(pdata);
+ netif_carrier_on(pdata->netdev);
+ if (netif_running(pdata->netdev)) {
+ netif_tx_wake_all_queues(pdata->netdev);
+ yt_dbg(pdata, "%s now is link up, mac_speed=%d.\n",
+ netdev_name(pdata->netdev), pdata->phy_speed);
+ }
+ } else {
+ netif_carrier_off(pdata->netdev);
+ netif_tx_stop_all_queues(pdata->netdev);
+ hw_ops->disable_rx(pdata);
+ hw_ops->disable_tx(pdata);
+ yt_dbg(pdata, "%s now is link down\n",
+ netdev_name(pdata->netdev));
+ }
+
+ phy_print_status(pdata->phydev);
+}
+
+static int fxgmac_phy_connect(struct fxgmac_pdata *pdata)
+{
+ struct phy_device *phydev = pdata->phydev;
+ int ret;
+
+ ret = phy_connect_direct(pdata->netdev, phydev, fxgmac_phylink_handler,
+ PHY_INTERFACE_MODE_RGMII);
+ if (ret)
+ return ret;
+
+ phy_attached_info(phydev);
+ return 0;
+}
+
+static void fxgmac_enable_msix_irqs(struct fxgmac_pdata *pdata)
+{
+ struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
+
+ for (u32 intid = 0; intid < MSIX_TBL_MAX_NUM; intid++)
+ hw_ops->enable_msix_one_irq(pdata, intid);
+}
+
+int fxgmac_phy_irq_enable(struct fxgmac_pdata *pdata, bool clear_phy_interrupt)
+{
+ struct phy_device *phydev = pdata->phydev;
+
+ if (clear_phy_interrupt &&
+ phy_read(phydev, PHY_INT_STATUS) < 0)
+ return -ETIMEDOUT;
+
+ return phy_modify(phydev, PHY_INT_MASK,
+ PHY_INT_MASK_LINK_UP |
+ PHY_INT_MASK_LINK_DOWN,
+ PHY_INT_MASK_LINK_UP |
+ PHY_INT_MASK_LINK_DOWN);
+}
+
+int fxgmac_start(struct fxgmac_pdata *pdata)
+{
+ struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
+ u32 val;
+ int ret;
+
+ if (pdata->dev_state != FXGMAC_DEV_OPEN &&
+ pdata->dev_state != FXGMAC_DEV_STOP &&
+ pdata->dev_state != FXGMAC_DEV_RESUME) {
+ yt_dbg(pdata, " dev_state err:%x\n", pdata->dev_state);
+ return 0;
+ }
+
+ if (pdata->dev_state != FXGMAC_DEV_STOP) {
+ hw_ops->reset_phy(pdata);
+ hw_ops->release_phy(pdata);
+ yt_dbg(pdata, "reset phy.\n");
+ }
+
+ if (pdata->dev_state == FXGMAC_DEV_OPEN) {
+ ret = fxgmac_phy_connect(pdata);
+ if (ret < 0)
+ return ret;
+
+ yt_dbg(pdata, "fxgmac_phy_connect.\n");
+ }
+
+ phy_init_hw(pdata->phydev);
+ phy_resume(pdata->phydev);
+
+ hw_ops->pcie_init(pdata);
+ if (test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->powerstate)) {
+ yt_err(pdata,
+ "fxgmac powerstate is %lu when config power up.\n",
+ pdata->powerstate);
+ }
+
+ hw_ops->config_power_up(pdata);
+ hw_ops->dismiss_all_int(pdata);
+ ret = hw_ops->init(pdata);
+ if (ret < 0) {
+ yt_err(pdata, "fxgmac hw init error.\n");
+ return ret;
+ }
+
+ fxgmac_napi_enable(pdata);
+ ret = fxgmac_request_irqs(pdata);
+ if (ret < 0)
+ return ret;
+
+ /* Config interrupt to level signal */
+ val = rd32_mac(pdata, DMA_MR);
+ fxgmac_set_bits(&val, DMA_MR_INTM_POS, DMA_MR_INTM_LEN, 2);
+ fxgmac_set_bits(&val, DMA_MR_QUREAD_POS, DMA_MR_QUREAD_LEN, 1);
+ wr32_mac(pdata, val, DMA_MR);
+
+ hw_ops->enable_mgm_irq(pdata);
+ hw_ops->set_interrupt_moderation(pdata);
+
+ if (pdata->per_channel_irq) {
+ fxgmac_enable_msix_irqs(pdata);
+ ret = fxgmac_phy_irq_enable(pdata, true);
+ if (ret < 0)
+ goto dis_napi;
+ }
+
+ fxgmac_enable_rx_tx_ints(pdata);
+ phy_speed_up(pdata->phydev);
+ genphy_soft_reset(pdata->phydev);
+
+ pdata->dev_state = FXGMAC_DEV_START;
+ phy_start(pdata->phydev);
+
+ return 0;
+
+dis_napi:
+ fxgmac_napi_disable(pdata);
+ hw_ops->exit(pdata);
+ yt_err(pdata, "%s irq err.\n", __func__);
+ return ret;
+}
+
static void fxgmac_disable_msix_irqs(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
@@ -540,4 +716,70 @@ static const struct net_device_ops fxgmac_netdev_ops = {
const struct net_device_ops *fxgmac_get_netdev_ops(void)
{
return &fxgmac_netdev_ops;
+
+static void fxgmac_napi_enable(struct fxgmac_pdata *pdata)
+{
+ u32 i, *flags = &pdata->int_flags;
+ struct fxgmac_channel *channel;
+ u32 misc_napi, tx, rx;
+
+ misc_napi = FIELD_GET(BIT(FXGMAC_FLAG_MISC_NAPI_POS), *flags);
+ tx = FXGMAC_GET_BITS(*flags, FXGMAC_FLAG_TX_NAPI_POS,
+ FXGMAC_FLAG_TX_NAPI_LEN);
+ rx = FXGMAC_GET_BITS(*flags, FXGMAC_FLAG_RX_NAPI_POS,
+ FXGMAC_FLAG_RX_NAPI_LEN);
+
+ if (!pdata->per_channel_irq) {
+ i = FIELD_GET(BIT(FXGMAC_FLAG_LEGACY_NAPI_POS), *flags);
+ if (i)
+ return;
+
+ netif_napi_add_weight(pdata->netdev, &pdata->napi,
+ fxgmac_all_poll,
+ NAPI_POLL_WEIGHT);
+
+ napi_enable(&pdata->napi);
+ fxgmac_set_bits(flags, FXGMAC_FLAG_LEGACY_NAPI_POS,
+ FXGMAC_FLAG_LEGACY_NAPI_LEN,
+ FXGMAC_NAPI_ENABLE);
+ return;
+ }
+
+ channel = pdata->channel_head;
+
+ for (i = 0; i < pdata->channel_count; i++, channel++) {
+ if (!FXGMAC_GET_BITS(rx, i, FXGMAC_FLAG_PER_RX_NAPI_LEN)) {
+ netif_napi_add_weight(pdata->netdev,
+ &channel->napi_rx,
+ fxgmac_one_poll_rx,
+ NAPI_POLL_WEIGHT);
+
+ napi_enable(&channel->napi_rx);
+ fxgmac_set_bits(flags, FXGMAC_FLAG_RX_NAPI_POS + i,
+ FXGMAC_FLAG_PER_RX_NAPI_LEN,
+ FXGMAC_NAPI_ENABLE);
+ }
+
+ if (FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i) && !tx) {
+ netif_napi_add_weight(pdata->netdev, &channel->napi_tx,
+ fxgmac_one_poll_tx,
+ NAPI_POLL_WEIGHT);
+ napi_enable(&channel->napi_tx);
+ fxgmac_set_bits(flags, FXGMAC_FLAG_TX_NAPI_POS,
+ FXGMAC_FLAG_TX_NAPI_LEN,
+ FXGMAC_NAPI_ENABLE);
+ }
+ if (netif_msg_drv(pdata))
+ yt_dbg(pdata, "msix ch%d napi enabled done.\n", i);
+ }
+
+ /* Misc */
+ if (!misc_napi) {
+ netif_napi_add_weight(pdata->netdev, &pdata->napi_misc,
+ fxgmac_misc_poll, NAPI_POLL_WEIGHT);
+
+ napi_enable(&pdata->napi_misc);
+ fxgmac_set_bits(flags, FXGMAC_FLAG_MISC_NAPI_POS,
+ FXGMAC_FLAG_MISC_NAPI_LEN, FXGMAC_NAPI_ENABLE);
+ }
}
--
2.34.1