Merge tag 'driver-core-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / freescale / fec_main.c
index 5b937c6cfe77af800ab4a93d0679af2031c9f549..ebf76c496e7aab472c1c0ca740213b1624146a20 100644 (file)
@@ -287,15 +287,23 @@ static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep,
        return entries > 0 ? entries : entries + txq->tx_ring_size;
 }
 
-static void *swap_buffer(void *bufaddr, int len)
+static void swap_buffer(void *bufaddr, int len)
 {
        int i;
        unsigned int *buf = bufaddr;
 
-       for (i = 0; i < DIV_ROUND_UP(len, 4); i++, buf++)
-               *buf = cpu_to_be32(*buf);
+       for (i = 0; i < len; i += 4, buf++)
+               swab32s(buf);
+}
 
-       return bufaddr;
+static void swap_buffer2(void *dst_buf, void *src_buf, int len)
+{
+       int i;
+       unsigned int *src = src_buf;
+       unsigned int *dst = dst_buf;
+
+       for (i = 0; i < len; i += 4, src++, dst++)
+               *dst = swab32p(src);
 }
 
 static void fec_dump(struct net_device *ndev)
@@ -351,8 +359,6 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
                             struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        struct bufdesc *bdp = txq->cur_tx;
        struct bufdesc_ex *ebdp;
        int nr_frags = skb_shinfo(skb)->nr_frags;
@@ -388,7 +394,7 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
                }
 
                if (fep->bufdesc_ex) {
-                       if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+                       if (fep->quirks & FEC_QUIRK_HAS_AVB)
                                estatus |= FEC_TX_BD_FTYPE(queue);
                        if (skb->ip_summed == CHECKSUM_PARTIAL)
                                estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -400,11 +406,11 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
 
                index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
                if (((unsigned long) bufaddr) & fep->tx_align ||
-                       id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+                       fep->quirks & FEC_QUIRK_SWAP_FRAME) {
                        memcpy(txq->tx_bounce[index], bufaddr, frag_len);
                        bufaddr = txq->tx_bounce[index];
 
-                       if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+                       if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
                                swap_buffer(bufaddr, frag_len);
                }
 
@@ -440,8 +446,6 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
                                   struct sk_buff *skb, struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        int nr_frags = skb_shinfo(skb)->nr_frags;
        struct bufdesc *bdp, *last_bdp;
        void *bufaddr;
@@ -480,11 +484,11 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
        queue = skb_get_queue_mapping(skb);
        index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
        if (((unsigned long) bufaddr) & fep->tx_align ||
-               id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+               fep->quirks & FEC_QUIRK_SWAP_FRAME) {
                memcpy(txq->tx_bounce[index], skb->data, buflen);
                bufaddr = txq->tx_bounce[index];
 
-               if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+               if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
                        swap_buffer(bufaddr, buflen);
        }
 
@@ -519,7 +523,7 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
                        fep->hwts_tx_en))
                        skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 
-               if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+               if (fep->quirks & FEC_QUIRK_HAS_AVB)
                        estatus |= FEC_TX_BD_FTYPE(queue);
 
                if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -563,8 +567,6 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
                          int size, bool last_tcp, bool is_last)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
        unsigned short queue = skb_get_queue_mapping(skb);
        unsigned short status;
@@ -577,11 +579,11 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
        status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
 
        if (((unsigned long) data) & fep->tx_align ||
-               id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+               fep->quirks & FEC_QUIRK_SWAP_FRAME) {
                memcpy(txq->tx_bounce[index], data, size);
                data = txq->tx_bounce[index];
 
-               if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+               if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
                        swap_buffer(data, size);
        }
 
@@ -597,7 +599,7 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
        bdp->cbd_bufaddr = addr;
 
        if (fep->bufdesc_ex) {
-               if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+               if (fep->quirks & FEC_QUIRK_HAS_AVB)
                        estatus |= FEC_TX_BD_FTYPE(queue);
                if (skb->ip_summed == CHECKSUM_PARTIAL)
                        estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -625,8 +627,6 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
                         struct bufdesc *bdp, int index)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
        struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
        unsigned short queue = skb_get_queue_mapping(skb);
@@ -642,11 +642,11 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
        bufaddr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
        dmabuf = txq->tso_hdrs_dma + index * TSO_HEADER_SIZE;
        if (((unsigned long)bufaddr) & fep->tx_align ||
-               id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+               fep->quirks & FEC_QUIRK_SWAP_FRAME) {
                memcpy(txq->tx_bounce[index], skb->data, hdr_len);
                bufaddr = txq->tx_bounce[index];
 
-               if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+               if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
                        swap_buffer(bufaddr, hdr_len);
 
                dmabuf = dma_map_single(&fep->pdev->dev, bufaddr,
@@ -663,7 +663,7 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
        bdp->cbd_datlen = hdr_len;
 
        if (fep->bufdesc_ex) {
-               if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+               if (fep->quirks & FEC_QUIRK_HAS_AVB)
                        estatus |= FEC_TX_BD_FTYPE(queue);
                if (skb->ip_summed == CHECKSUM_PARTIAL)
                        estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -688,8 +688,6 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
        struct tso_t tso;
        unsigned int index = 0;
        int ret;
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
 
        if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
                dev_kfree_skb_any(skb);
@@ -751,7 +749,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
        txq->cur_tx = bdp;
 
        /* Trigger transmission start */
-       if (!(id_entry->driver_data & FEC_QUIRK_ERR007885) ||
+       if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
            !readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
            !readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
            !readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
@@ -869,6 +867,7 @@ static void fec_enet_enable_ring(struct net_device *ndev)
        for (i = 0; i < fep->num_rx_queues; i++) {
                rxq = fep->rx_queue[i];
                writel(rxq->bd_dma, fep->hwp + FEC_R_DES_START(i));
+               writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE(i));
 
                /* enable DMA1/2 */
                if (i)
@@ -914,8 +913,6 @@ static void
 fec_restart(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        u32 val;
        u32 temp_mac[2];
        u32 rcntl = OPT_FRAME_SIZE | 0x04;
@@ -925,7 +922,7 @@ fec_restart(struct net_device *ndev)
         * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
         * instead of reset MAC itself.
         */
-       if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+       if (fep->quirks & FEC_QUIRK_HAS_AVB) {
                writel(0, fep->hwp + FEC_ECNTRL);
        } else {
                writel(1, fep->hwp + FEC_ECNTRL);
@@ -936,17 +933,14 @@ fec_restart(struct net_device *ndev)
         * enet-mac reset will reset mac address registers too,
         * so need to reconfigure it.
         */
-       if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+       if (fep->quirks & FEC_QUIRK_ENET_MAC) {
                memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
                writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
                writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
        }
 
        /* Clear any outstanding interrupt. */
-       writel(0xffc00000, fep->hwp + FEC_IEVENT);
-
-       /* Set maximum receive buffer size. */
-       writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
+       writel(0xffffffff, fep->hwp + FEC_IEVENT);
 
        fec_enet_bd_init(ndev);
 
@@ -982,7 +976,7 @@ fec_restart(struct net_device *ndev)
         * The phy interface and speed need to get configured
         * differently on enet-mac.
         */
-       if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+       if (fep->quirks & FEC_QUIRK_ENET_MAC) {
                /* Enable flow control and length check */
                rcntl |= 0x40000000 | 0x00000020;
 
@@ -1005,7 +999,7 @@ fec_restart(struct net_device *ndev)
                }
        } else {
 #ifdef FEC_MIIGSK_ENR
-               if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
+               if (fep->quirks & FEC_QUIRK_USE_GASKET) {
                        u32 cfgr;
                        /* disable the gasket and wait */
                        writel(0, fep->hwp + FEC_MIIGSK_ENR);
@@ -1058,7 +1052,7 @@ fec_restart(struct net_device *ndev)
        writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
 #endif
 
-       if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+       if (fep->quirks & FEC_QUIRK_ENET_MAC) {
                /* enable ENET endian swap */
                ecntl |= (1 << 8);
                /* enable ENET store and forward mode */
@@ -1081,7 +1075,10 @@ fec_restart(struct net_device *ndev)
                fec_ptp_start_cyclecounter(ndev);
 
        /* Enable interrupts we wish to service */
-       writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+       if (fep->link)
+               writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+       else
+               writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
 
        /* Init the interrupt coalescing */
        fec_enet_itr_coal_init(ndev);
@@ -1092,8 +1089,6 @@ static void
 fec_stop(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
 
        /* We cannot expect a graceful transmit stop without link !!! */
@@ -1108,7 +1103,7 @@ fec_stop(struct net_device *ndev)
         * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
         * instead of reset MAC itself.
         */
-       if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+       if (fep->quirks & FEC_QUIRK_HAS_AVB) {
                writel(0, fep->hwp + FEC_ECNTRL);
        } else {
                writel(1, fep->hwp + FEC_ECNTRL);
@@ -1118,7 +1113,7 @@ fec_stop(struct net_device *ndev)
        writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 
        /* We have to keep ENET enabled to have MII interrupt stay working */
-       if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+       if (fep->quirks & FEC_QUIRK_ENET_MAC) {
                writel(2, fep->hwp + FEC_ECNTRL);
                writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
        }
@@ -1307,7 +1302,7 @@ fec_enet_new_rxbdp(struct net_device *ndev, struct bufdesc *bdp, struct sk_buff
 }
 
 static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
-                              struct bufdesc *bdp, u32 length)
+                              struct bufdesc *bdp, u32 length, bool swap)
 {
        struct  fec_enet_private *fep = netdev_priv(ndev);
        struct sk_buff *new_skb;
@@ -1322,7 +1317,10 @@ static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
        dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
                                FEC_ENET_RX_FRSIZE - fep->rx_align,
                                DMA_FROM_DEVICE);
-       memcpy(new_skb->data, (*skb)->data, length);
+       if (!swap)
+               memcpy(new_skb->data, (*skb)->data, length);
+       else
+               swap_buffer2(new_skb->data, (*skb)->data, length);
        *skb = new_skb;
 
        return true;
@@ -1337,8 +1335,6 @@ static int
 fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        struct fec_enet_priv_rx_q *rxq;
        struct bufdesc *bdp;
        unsigned short status;
@@ -1352,6 +1348,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
        u16     vlan_tag;
        int     index = 0;
        bool    is_copybreak;
+       bool    need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME;
 
 #ifdef CONFIG_M532x
        flush_cache_all();
@@ -1415,7 +1412,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
                 * include that when passing upstream as it messes up
                 * bridging applications.
                 */
-               is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4);
+               is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4,
+                                                 need_swap);
                if (!is_copybreak) {
                        skb_new = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
                        if (unlikely(!skb_new)) {
@@ -1430,7 +1428,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
                prefetch(skb->data - NET_IP_ALIGN);
                skb_put(skb, pkt_len - 4);
                data = skb->data;
-               if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+               if (!is_copybreak && need_swap)
                        swap_buffer(data, pkt_len);
 
                /* Extract the enhanced buffer descriptor */
@@ -1865,8 +1863,6 @@ failed_clk_ipg:
 static int fec_enet_mii_probe(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        struct phy_device *phy_dev = NULL;
        char mdio_bus_id[MII_BUS_ID_SIZE];
        char phy_name[MII_BUS_ID_SIZE + 3];
@@ -1879,6 +1875,8 @@ static int fec_enet_mii_probe(struct net_device *ndev)
                phy_dev = of_phy_connect(ndev, fep->phy_node,
                                         &fec_enet_adjust_link, 0,
                                         fep->phy_interface);
+               if (!phy_dev)
+                       return -ENODEV;
        } else {
                /* check for attached phy */
                for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {
@@ -1912,7 +1910,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
        }
 
        /* mask with MAC supported features */
-       if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
+       if (fep->quirks & FEC_QUIRK_HAS_GBIT) {
                phy_dev->supported &= PHY_GBIT_FEATURES;
                phy_dev->supported &= ~SUPPORTED_1000baseT_Half;
 #if !defined(CONFIG_M5272)
@@ -1940,8 +1938,6 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        static struct mii_bus *fec0_mii_bus;
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        struct device_node *node;
        int err = -ENXIO, i;
 
@@ -1961,7 +1957,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
         * mdio interface in board design, and need to be configured by
         * fec0 mii_bus.
         */
-       if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {
+       if ((fep->quirks & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {
                /* fec1 uses fec0 mii_bus */
                if (mii_cnt && fec0_mii_bus) {
                        fep->mii_bus = fec0_mii_bus;
@@ -1982,7 +1978,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
         * document.
         */
        fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
-       if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+       if (fep->quirks & FEC_QUIRK_ENET_MAC)
                fep->phy_speed--;
        fep->phy_speed <<= 1;
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
@@ -2024,7 +2020,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        mii_cnt++;
 
        /* save fec0 mii_bus */
-       if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+       if (fep->quirks & FEC_QUIRK_ENET_MAC)
                fec0_mii_bus = fep->mii_bus;
 
        return 0;
@@ -2293,11 +2289,9 @@ static int fec_enet_us_to_itr_clock(struct net_device *ndev, int us)
 static void fec_enet_itr_coal_set(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        int rx_itr, tx_itr;
 
-       if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+       if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
                return;
 
        /* Must be greater than zero to avoid unpredictable behavior */
@@ -2332,10 +2326,8 @@ static int
 fec_enet_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
 
-       if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+       if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
                return -EOPNOTSUPP;
 
        ec->rx_coalesce_usecs = fep->rx_time_itr;
@@ -2351,12 +2343,9 @@ static int
 fec_enet_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
-
        unsigned int cycle;
 
-       if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+       if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
                return -EOPNOTSUPP;
 
        if (ec->rx_max_coalesced_frames > 255) {
@@ -2936,8 +2925,6 @@ static const struct net_device_ops fec_netdev_ops = {
 static int fec_enet_init(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       const struct platform_device_id *id_entry =
-                               platform_get_device_id(fep->pdev);
        struct fec_enet_priv_tx_q *txq;
        struct fec_enet_priv_rx_q *rxq;
        struct bufdesc *cbd_base;
@@ -3016,11 +3003,11 @@ static int fec_enet_init(struct net_device *ndev)
        writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
        netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT);
 
-       if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN)
+       if (fep->quirks & FEC_QUIRK_HAS_VLAN)
                /* enable hw VLAN support */
                ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
 
-       if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
+       if (fep->quirks & FEC_QUIRK_HAS_CSUM) {
                ndev->gso_max_segs = FEC_MAX_TSO_SEGS;
 
                /* enable hw accelerator */
@@ -3029,7 +3016,7 @@ static int fec_enet_init(struct net_device *ndev)
                fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
        }
 
-       if (id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+       if (fep->quirks & FEC_QUIRK_HAS_AVB) {
                fep->tx_align = 0;
                fep->rx_align = 0x3f;
        }
@@ -3129,10 +3116,6 @@ fec_probe(struct platform_device *pdev)
        int num_tx_qs;
        int num_rx_qs;
 
-       of_id = of_match_device(fec_dt_ids, &pdev->dev);
-       if (of_id)
-               pdev->id_entry = of_id->data;
-
        fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
 
        /* Init network device */
@@ -3146,13 +3129,17 @@ fec_probe(struct platform_device *pdev)
        /* setup board info structure */
        fep = netdev_priv(ndev);
 
+       of_id = of_match_device(fec_dt_ids, &pdev->dev);
+       if (of_id)
+               pdev->id_entry = of_id->data;
+       fep->quirks = pdev->id_entry->driver_data;
+
        fep->num_rx_queues = num_rx_qs;
        fep->num_tx_queues = num_tx_qs;
 
 #if !defined(CONFIG_M5272)
        /* default enable pause frame auto negotiation */
-       if (pdev->id_entry &&
-           (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
+       if (fep->quirks & FEC_QUIRK_HAS_GBIT)
                fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
 #endif
 
@@ -3169,8 +3156,6 @@ fec_probe(struct platform_device *pdev)
        fep->pdev = pdev;
        fep->dev_id = dev_id++;
 
-       fep->bufdesc_ex = 0;
-
        platform_set_drvdata(pdev, ndev);
 
        phy_node = of_parse_phandle(np, "phy-handle", 0);
@@ -3223,12 +3208,11 @@ fec_probe(struct platform_device *pdev)
        if (IS_ERR(fep->clk_ref))
                fep->clk_ref = NULL;
 
+       fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
        fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
-       fep->bufdesc_ex =
-               pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
        if (IS_ERR(fep->clk_ptp)) {
                fep->clk_ptp = NULL;
-               fep->bufdesc_ex = 0;
+               fep->bufdesc_ex = false;
        }
 
        ret = fec_enet_clk_enable(ndev, true);
@@ -3343,15 +3327,20 @@ static int __maybe_unused fec_suspend(struct device *dev)
                netif_device_detach(ndev);
                netif_tx_unlock_bh(ndev);
                fec_stop(ndev);
+               fec_enet_clk_enable(ndev, false);
+               pinctrl_pm_select_sleep_state(&fep->pdev->dev);
        }
        rtnl_unlock();
 
-       fec_enet_clk_enable(ndev, false);
-       pinctrl_pm_select_sleep_state(&fep->pdev->dev);
-
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
 
+       /* SOC supply clock to phy, when clock is disabled, phy link down
+        * SOC control phy regulator, when regulator is disabled, phy link down
+        */
+       if (fep->clk_enet_out || fep->reg_phy)
+               fep->link = 0;
+
        return 0;
 }
 
@@ -3367,13 +3356,14 @@ static int __maybe_unused fec_resume(struct device *dev)
                        return ret;
        }
 
-       pinctrl_pm_select_default_state(&fep->pdev->dev);
-       ret = fec_enet_clk_enable(ndev, true);
-       if (ret)
-               goto failed_clk;
-
        rtnl_lock();
        if (netif_running(ndev)) {
+               pinctrl_pm_select_default_state(&fep->pdev->dev);
+               ret = fec_enet_clk_enable(ndev, true);
+               if (ret) {
+                       rtnl_unlock();
+                       goto failed_clk;
+               }
                fec_restart(ndev);
                netif_tx_lock_bh(ndev);
                netif_device_attach(ndev);