[PATCH net-next v4 06/14] yt6801: Implement the fxgmac_start function
From: Frank Sae
Date: Tue Apr 08 2025 - 06:26:07 EST
Implement the fxgmac_start function to connect phy, enable napi,
phy and msix irq.
Signed-off-by: Frank Sae <Frank.Sae@xxxxxxxxxxxxxx>
---
.../ethernet/motorcomm/yt6801/yt6801_main.c | 339 ++++++++++++++++++
.../ethernet/motorcomm/yt6801/yt6801_type.h | 72 ++++
2 files changed, 411 insertions(+)
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
index dce712306..34ccefdf9 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_main.c
@@ -22,6 +22,7 @@
#include "yt6801_desc.h"
const struct net_device_ops *fxgmac_get_netdev_ops(void);
+static void fxgmac_napi_enable(struct fxgmac_pdata *priv);
#define PHY_WR_CONFIG(reg_offset) (0x8000205 + ((reg_offset) * 0x10000))
static int fxgmac_phy_write_reg(struct fxgmac_pdata *priv, u32 reg_id, u32 data)
@@ -109,6 +110,11 @@ static int fxgmac_mdio_register(struct fxgmac_pdata *priv)
return 0;
}
+static void fxgmac_enable_msix_one_irq(struct fxgmac_pdata *priv, u32 int_id)
+{
+ fxgmac_io_wr(priv, MSIX_TBL_MASK + int_id * 16, 0);
+}
+
static void fxgmac_disable_mgm_irq(struct fxgmac_pdata *priv)
{
fxgmac_io_wr_bits(priv, MGMT_INT_CTRL0, MGMT_INT_CTRL0_INT_MASK,
@@ -173,6 +179,75 @@ static void fxgmac_free_irqs(struct fxgmac_pdata *priv)
}
}
+static int fxgmac_request_irqs(struct fxgmac_pdata *priv)
+{
+ u32 rx_irq[] = {INT_FLAG_RX0_IRQ, INT_FLAG_RX1_IRQ,
+ INT_FLAG_RX2_IRQ, INT_FLAG_RX3_IRQ};
+ u32 i = 0, msi = FIELD_GET(INT_FLAG_MSI, priv->int_flag);
+ struct fxgmac_channel *channel = priv->channel_head;
+ struct net_device *ndev = priv->ndev;
+ int ret;
+
+ if (!FIELD_GET(INT_FLAG_MSIX, priv->int_flag) &&
+ !FIELD_GET(INT_FLAG_LEGACY_IRQ, priv->int_flag)) {
+ priv->int_flag |= INT_FLAG_LEGACY_IRQ;
+ ret = devm_request_irq(priv->dev, priv->dev_irq, fxgmac_isr,
+ msi ? 0 : IRQF_SHARED, ndev->name,
+ priv);
+ if (ret) {
+ dev_err(priv->dev, "Requesting irq:%d, failed:%d\n",
+ priv->dev_irq, ret);
+ return ret;
+ }
+ }
+
+ if (!priv->per_channel_irq)
+ return 0;
+
+ if (!FIELD_GET(INT_FLAG_TX_IRQ, priv->int_flag)) {
+ snprintf(channel->dma_irq_tx_name,
+ sizeof(channel->dma_irq_tx_name) - 1,
+ "%s-ch%d-Tx-%u", netdev_name(ndev), 0,
+ channel->queue_index);
+ priv->int_flag |= INT_FLAG_TX_IRQ;
+ ret = devm_request_irq(priv->dev, channel->dma_irq_tx,
+ fxgmac_dma_isr, 0,
+ channel->dma_irq_tx_name, channel);
+ if (ret) {
+ dev_err(priv->dev, "dev:%p, channel:%p\n",
+ priv->dev, channel);
+
+ dev_err(priv->dev, "Requesting tx irq:%d, failed:%d\n",
+ channel->dma_irq_tx, ret);
+ goto err_irq;
+ }
+ }
+
+ for (i = 0; i < priv->channel_count; i++, channel++) {
+ snprintf(channel->dma_irq_rx_name,
+ sizeof(channel->dma_irq_rx_name) - 1, "%s-ch%d-Rx-%u",
+ netdev_name(ndev), i, channel->queue_index);
+
+ if ((priv->int_flag & rx_irq[i]) != rx_irq[i]) {
+ priv->int_flag |= rx_irq[i];
+ ret = devm_request_irq(priv->dev, channel->dma_irq_rx,
+ fxgmac_dma_isr, 0,
+ channel->dma_irq_rx_name,
+ channel);
+ if (ret) {
+ dev_err(priv->dev, "Requesting rx irq:%d, failed:%d\n",
+ channel->dma_irq_rx, ret);
+ goto err_irq;
+ }
+ }
+ }
+
+ return 0;
+
+err_irq:
+ fxgmac_free_irqs(priv);
+ return ret;
+}
static void fxgmac_free_tx_data(struct fxgmac_pdata *priv)
{
struct fxgmac_channel *channel = priv->channel_head;
@@ -205,6 +280,20 @@ static void fxgmac_free_rx_data(struct fxgmac_pdata *priv)
}
}
+static void fxgmac_enable_tx(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ /* Enable Tx DMA channel */
+ fxgmac_dma_wr_bits(channel, DMA_CH_TCR, DMA_CH_TCR_ST, 1);
+
+ /* Enable Tx queue */
+ fxgmac_mtl_wr_bits(priv, 0, MTL_Q_TQOMR, MTL_Q_TQOMR_TXQEN,
+ MTL_Q_ENABLED);
+ /* Enable MAC Tx */
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_TE, 1);
+}
+
static void fxgmac_prepare_tx_stop(struct fxgmac_pdata *priv,
struct fxgmac_channel *channel)
{
@@ -248,6 +337,27 @@ static void fxgmac_disable_tx(struct fxgmac_pdata *priv)
fxgmac_dma_wr_bits(channel, DMA_CH_TCR, DMA_CH_TCR_ST, 0);
}
+static void fxgmac_enable_rx(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ u32 val = 0, i;
+
+ /* Enable each Rx DMA channel */
+ for (i = 0; i < priv->channel_count; i++, channel++)
+ fxgmac_dma_wr_bits(channel, DMA_CH_RCR, DMA_CH_RCR_SR, 1);
+
+ /* Enable each Rx queue */
+ for (i = 0; i < priv->rx_q_count; i++)
+ val |= (0x02 << (i << 1));
+
+ fxgmac_io_wr(priv, MAC_RQC0R, val);
+
+ /* Enable MAC Rx */
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_CST, 1);
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_ACS, 1);
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_RE, 1);
+}
+
static void fxgmac_prepare_rx_stop(struct fxgmac_pdata *priv,
unsigned int queue)
{
@@ -301,6 +411,144 @@ static void fxgmac_default_speed_duplex_config(struct fxgmac_pdata *priv)
priv->mac_speed = SPEED_1000;
}
+static void fxgmac_config_mac_speed(struct fxgmac_pdata *priv)
+{
+ if (priv->mac_duplex == DUPLEX_UNKNOWN &&
+ priv->mac_speed == SPEED_UNKNOWN)
+ fxgmac_default_speed_duplex_config(priv);
+
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_DM, priv->mac_duplex);
+
+ switch (priv->mac_speed) {
+ case SPEED_1000:
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_PS, 0);
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_FES, 0);
+ break;
+ case SPEED_100:
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_PS, 1);
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_FES, 1);
+ break;
+ case SPEED_10:
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_PS, 1);
+ fxgmac_io_wr_bits(priv, MAC_CR, MAC_CR_FES, 0);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+static void fxgmac_phylink_handler(struct net_device *ndev)
+{
+ struct fxgmac_pdata *priv = netdev_priv(ndev);
+
+ priv->mac_speed = priv->phydev->speed;
+ priv->mac_duplex = priv->phydev->duplex;
+
+ if (priv->phydev->link) {
+ fxgmac_config_mac_speed(priv);
+ fxgmac_enable_rx(priv);
+ fxgmac_enable_tx(priv);
+ if (netif_running(priv->ndev))
+ netif_tx_wake_all_queues(priv->ndev);
+ } else {
+ netif_tx_stop_all_queues(priv->ndev);
+ fxgmac_disable_rx(priv);
+ fxgmac_disable_tx(priv);
+ }
+
+ phy_print_status(priv->phydev);
+}
+
+static int fxgmac_phy_connect(struct fxgmac_pdata *priv)
+{
+ struct phy_device *phydev = priv->phydev;
+ int ret;
+
+ priv->phydev->irq = PHY_POLL;
+ ret = phy_connect_direct(priv->ndev, phydev, fxgmac_phylink_handler,
+ PHY_INTERFACE_MODE_INTERNAL);
+ if (ret)
+ return ret;
+
+ phy_support_asym_pause(phydev);
+ priv->phydev->mac_managed_pm = 1;
+ phy_attached_info(phydev);
+
+ return 0;
+}
+
+static void fxgmac_enable_msix_irqs(struct fxgmac_pdata *priv)
+{
+ for (u32 intid = 0; intid < MSIX_TBL_MAX_NUM; intid++)
+ fxgmac_enable_msix_one_irq(priv, intid);
+}
+
+static void fxgmac_enable_dma_interrupts(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ u32 ch_sr;
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++) {
+ /* Clear all the interrupts which are set */
+ ch_sr = fxgmac_dma_io_rd(channel, DMA_CH_SR);
+ fxgmac_dma_io_wr(channel, DMA_CH_SR, ch_sr);
+
+ ch_sr = 0;
+ /* Enable Normal Interrupt Summary Enable and Fatal Bus Error
+ * Enable interrupts.
+ */
+ ch_sr |= (DMA_CH_IER_NIE | DMA_CH_IER_FBEE);
+
+ /* only one tx, enable Transmit Interrupt Enable interrupts */
+ if (i == 0 && channel->tx_ring)
+ ch_sr |= DMA_CH_IER_TIE;
+
+ /* Enable Receive Buffer Unavailable Enable and Receive
+ * Interrupt Enable interrupts.
+ */
+ if (channel->rx_ring)
+ ch_sr |= (DMA_CH_IER_RBUE | DMA_CH_IER_RIE);
+
+ fxgmac_dma_io_wr(channel, DMA_CH_IER, ch_sr);
+ }
+}
+
+static void fxgmac_dismiss_all_int(struct fxgmac_pdata *priv)
+{
+ struct fxgmac_channel *channel = priv->channel_head;
+ u32 i;
+
+ /* Clear all the interrupts which are set */
+ for (i = 0; i < priv->channel_count; i++, channel++)
+ fxgmac_dma_io_wr(channel, DMA_CH_SR,
+ fxgmac_dma_io_rd(channel, DMA_CH_SR));
+
+ for (i = 0; i < priv->hw_feat.rx_q_cnt; i++)
+ fxgmac_mtl_io_wr(priv, i, MTL_Q_IR,
+ fxgmac_mtl_io_rd(priv, i, MTL_Q_IR));
+
+ fxgmac_io_rd(priv, MAC_ISR); /* Clear all MAC interrupts */
+ fxgmac_io_rd(priv, MAC_TX_RX_STA);/* Clear tx/rx error interrupts */
+ fxgmac_io_rd(priv, MAC_PMT_STA);
+ fxgmac_io_rd(priv, MAC_LPI_STA);
+
+ fxgmac_io_wr(priv, MAC_DBG_STA, fxgmac_io_rd(priv, MAC_DBG_STA));
+}
+
+static void fxgmac_set_interrupt_moderation(struct fxgmac_pdata *priv)
+{
+ fxgmac_io_wr_bits(priv, INT_MOD, INT_MOD_TX, priv->tx_usecs);
+ fxgmac_io_wr_bits(priv, INT_MOD, INT_MOD_RX, priv->rx_usecs);
+}
+
+static void fxgmac_enable_mgm_irq(struct fxgmac_pdata *priv)
+{
+ fxgmac_io_wr_bits(priv, MGMT_INT_CTRL0, MGMT_INT_CTRL0_INT_STATUS, 0);
+ fxgmac_io_wr_bits(priv, MGMT_INT_CTRL0, MGMT_INT_CTRL0_INT_MASK,
+ MGMT_INT_CTRL0_INT_MASK_MISC);
+}
+
/**
* fxgmac_set_oob_wol - disable or enable oob wol crtl function
* @priv: driver private struct
@@ -378,6 +626,63 @@ static void fxgmac_phy_reset(struct fxgmac_pdata *priv)
fsleep(1500);
}
+static int fxgmac_start(struct fxgmac_pdata *priv)
+{
+ int ret;
+
+ if (priv->dev_state != FXGMAC_DEV_OPEN &&
+ priv->dev_state != FXGMAC_DEV_STOP &&
+ priv->dev_state != FXGMAC_DEV_RESUME) {
+ return 0;
+ }
+
+ if (priv->dev_state != FXGMAC_DEV_STOP) {
+ fxgmac_phy_reset(priv);
+ fxgmac_phy_release(priv);
+ }
+
+ if (priv->dev_state == FXGMAC_DEV_OPEN) {
+ ret = fxgmac_phy_connect(priv);
+ if (ret < 0)
+ return ret;
+ }
+
+ fxgmac_pcie_init(priv);
+ if (test_bit(FXGMAC_POWER_STATE_DOWN, &priv->power_state)) {
+ dev_err(priv->dev, "fxgmac powerstate is %lu when config power up.\n",
+ priv->power_state);
+ }
+
+ fxgmac_config_powerup(priv);
+ fxgmac_dismiss_all_int(priv);
+ ret = fxgmac_hw_init(priv);
+ if (ret < 0) {
+ dev_err(priv->dev, "fxgmac hw init failed.\n");
+ return ret;
+ }
+
+ fxgmac_napi_enable(priv);
+ ret = fxgmac_request_irqs(priv);
+ if (ret < 0)
+ return ret;
+
+ /* Config interrupt to level signal */
+ fxgmac_io_wr_bits(priv, DMA_MR, DMA_MR_INTM, 2);
+ fxgmac_io_wr_bits(priv, DMA_MR, DMA_MR_QUREAD, 1);
+
+ fxgmac_enable_mgm_irq(priv);
+ fxgmac_set_interrupt_moderation(priv);
+
+ if (priv->per_channel_irq)
+ fxgmac_enable_msix_irqs(priv);
+
+ fxgmac_enable_dma_interrupts(priv);
+ priv->dev_state = FXGMAC_DEV_START;
+ phy_start(priv->phydev);
+
+ return 0;
+}
+
static void fxgmac_disable_msix_irqs(struct fxgmac_pdata *priv)
{
for (u32 intid = 0; intid < MSIX_TBL_MAX_NUM; intid++)
@@ -1033,6 +1338,40 @@ const struct net_device_ops *fxgmac_get_netdev_ops(void)
return &fxgmac_netdev_ops;
}
+static void napi_add_enable(struct fxgmac_pdata *priv, struct napi_struct *napi,
+ int (*poll)(struct napi_struct *, int),
+ u32 flag)
+{
+ netif_napi_add(priv->ndev, napi, poll);
+ napi_enable(napi);
+ priv->int_flag |= flag;
+}
+
+static void fxgmac_napi_enable(struct fxgmac_pdata *priv)
+{
+ u32 rx_napi[] = {INT_FLAG_RX0_NAPI, INT_FLAG_RX1_NAPI,
+ INT_FLAG_RX2_NAPI, INT_FLAG_RX3_NAPI};
+ struct fxgmac_channel *channel = priv->channel_head;
+
+ if (!priv->per_channel_irq) {
+ if (FIELD_GET(INT_FLAG_LEGACY_NAPI, priv->int_flag))
+ return;
+
+ napi_add_enable(priv, &priv->napi, fxgmac_all_poll,
+ INT_FLAG_LEGACY_NAPI);
+ return;
+ }
+
+ if (!FIELD_GET(INT_FLAG_TX_NAPI, priv->int_flag))
+ napi_add_enable(priv, &channel->napi_tx, fxgmac_one_poll_tx,
+ INT_FLAG_TX_NAPI);
+
+ for (u32 i = 0; i < priv->channel_count; i++, channel++)
+ if (!(priv->int_flag & rx_napi[i]))
+ napi_add_enable(priv, &channel->napi_rx,
+ fxgmac_one_poll_rx, rx_napi[i]);
+}
+
static int fxgmac_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
{
struct fxgmac_resources res;
diff --git a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
index d52de4482..4afc6d4cd 100644
--- a/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
+++ b/drivers/net/ethernet/motorcomm/yt6801/yt6801_type.h
@@ -55,6 +55,12 @@
#define MGMT_INT_CTRL0_INT_MASK_DISABLE 0xf000
#define MGMT_INT_CTRL0_INT_MASK_MASK 0xffff
+/* Interrupt Moderation */
+#define INT_MOD 0x1108
+#define INT_MOD_RX GENMASK(11, 0)
+#define INT_MOD_200_US 200
+#define INT_MOD_TX GENMASK(27, 16)
+
/* LTR_CTRL3, LTR latency message, only for System IDLE Start. */
#define LTR_IDLE_ENTER 0x113c
#define LTR_IDLE_ENTER_ENTER GENMASK(9, 0)
@@ -74,6 +80,9 @@
#define LTR_IDLE_EXIT_171_US 171
#define LTR_IDLE_EXIT_SCALE GENMASK(14, 10)
#define LTR_IDLE_EXIT_REQUIRE BIT(15)
+
+#define MSIX_TBL_MASK 0x120c
+
/* msi table */
#define MSI_ID_RXQ0 0
#define MSI_ID_RXQ1 1
@@ -131,6 +140,24 @@
#define MAC_RQC2_INC 4
#define MAC_RQC2_Q_PER_REG 4
+#define MAC_ISR 0x20b0
+#define MAC_ISR_PHYIF_STA BIT(0)
+#define MAC_ISR_AN_SR GENMASK(3, 1)
+#define MAC_ISR_PMT_STA BIT(4)
+#define MAC_ISR_LPI_STA BIT(5)
+#define MAC_ISR_MMC_STA BIT(8)
+#define MAC_ISR_RX_MMC_STA BIT(9)
+#define MAC_ISR_TX_MMC_STA BIT(10)
+#define MAC_ISR_IPC_RXINT BIT(11)
+#define MAC_ISR_TSIS BIT(12)
+#define MAC_ISR_TX_RX_STA GENMASK(14, 13)
+#define MAC_ISR_GPIO_SR GENMASK(25, 15)
+
+#define MAC_IER 0x20b4
+#define MAC_IER_TSIE BIT(12)
+
+#define MAC_TX_RX_STA 0x20b8
+
#define MAC_PMT_STA 0x20c0
#define MAC_PMT_STA_PWRDWN BIT(0)
#define MAC_PMT_STA_MGKPKTEN BIT(1)
@@ -141,6 +168,20 @@
#define MAC_PMT_STA_RWKPTR GENMASK(27, 24)
#define MAC_PMT_STA_RWKFILTERST BIT(31)
+#define MAC_RWK_PAC 0x20c4
+#define MAC_LPI_STA 0x20d0
+#define MAC_LPI_CONTROL 0x20d4
+#define MAC_LPI_TIMER 0x20d8
+#define MAC_MS_TIC_COUNTER 0x20dc
+#define MAC_AN_CR 0x20e0
+#define MAC_AN_SR 0x20e4
+#define MAC_AN_ADV 0x20e8
+#define MAC_AN_LPA 0x20ec
+#define MAC_AN_EXP 0x20f0
+#define MAC_PHYIF_STA 0x20f8
+#define MAC_VR 0x2110
+#define MAC_DBG_STA 0x2114
+
#define MAC_HWF0R 0x211c
#define MAC_HWF0R_VLHASH BIT(4)
#define MAC_HWF0R_SMASEL BIT(5)
@@ -180,6 +221,7 @@
#define MAC_HWF2R_AUXSNAPNUM GENMASK(30, 28)
#define MAC_HWF3R 0x2128
+
#define MAC_MDIO_ADDR 0x2200
#define MAC_MDIO_ADDR_BUSY BIT(0)
#define MAC_MDIO_ADDR_GOC GENMASK(3, 2)
@@ -200,10 +242,20 @@
#define MTL_Q_EN_IF_AV 0x01
#define MTL_Q_ENABLED 0x02
+#define MTL_Q_IR 0x2c /* Interrupt control status */
#define MTL_Q_RQDR 0x38
#define MTL_Q_RQDR_RXQSTS GENMASK(5, 4)
#define MTL_Q_RQDR_PRXQ GENMASK(29, 16)
+/* DMA registers */
+#define DMA_MR 0x3000
+#define DMA_MR_SWR BIT(0)
+#define DMA_MR_TXPR BIT(11)
+#define DMA_MR_INTM GENMASK(17, 16)
+#define DMA_MR_QUREAD BIT(19)
+#define DMA_MR_TNDF GENMASK(21, 20)
+#define DMA_MR_RNDF GENMASK(23, 22)
+
#define DMA_DSRX_INC 4
#define DMA_DSR0 0x300c
#define DMA_DSR0_TPS GENMASK(15, 12)
@@ -234,6 +286,26 @@
#define DMA_CH_RCR_RBSZ GENMASK(14, 1)
#define DMA_CH_RCR_PBL GENMASK(21, 16)
+#define DMA_CH_IER 0x34
+#define DMA_CH_IER_TIE BIT(0)
+#define DMA_CH_IER_TXSE BIT(1)
+#define DMA_CH_IER_TBUE BIT(2)
+#define DMA_CH_IER_RIE BIT(6)
+#define DMA_CH_IER_RBUE BIT(7)
+#define DMA_CH_IER_RSE BIT(8)
+#define DMA_CH_IER_FBEE BIT(12)
+#define DMA_CH_IER_AIE BIT(14)
+#define DMA_CH_IER_NIE BIT(15)
+
+#define DMA_CH_SR 0x60
+#define DMA_CH_SR_TI BIT(0)
+#define DMA_CH_SR_TPS BIT(1)
+#define DMA_CH_SR_TBU BIT(2)
+#define DMA_CH_SR_RI BIT(6)
+#define DMA_CH_SR_RBU BIT(7)
+#define DMA_CH_SR_RPS BIT(8)
+#define DMA_CH_SR_FBE BIT(12)
+
struct fxgmac_ring_buf {
struct sk_buff *skb;
dma_addr_t skb_dma;
--
2.34.1