]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
net: stmmac: Uniformize the use of dma_init_* callbacks
[thirdparty/kernel/stable.git] / drivers / net / ethernet / stmicro / stmmac / stmmac_main.c
index 48b55407a953d3fa1dd6868953b2d62734bd235d..34c1fcc23fb6599c4e252b6ce223b9c346731966 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/seq_file.h>
 #endif /* CONFIG_DEBUG_FS */
 #include <linux/net_tstamp.h>
+#include <net/pkt_cls.h>
 #include "stmmac_ptp.h"
 #include "stmmac.h"
 #include <linux/reset.h>
@@ -769,7 +770,6 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
                netdev_info(priv->dev,
                            "IEEE 1588-2008 Advanced Timestamp supported\n");
 
-       priv->hw->ptp = &stmmac_ptp;
        priv->hwts_tx_en = 0;
        priv->hwts_rx_en = 0;
 
@@ -1156,10 +1156,7 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
                return -EINVAL;
        }
 
-       if (priv->synopsys_id >= DWMAC_CORE_4_00)
-               p->des0 = cpu_to_le32(rx_q->rx_skbuff_dma[i]);
-       else
-               p->des2 = cpu_to_le32(rx_q->rx_skbuff_dma[i]);
+       stmmac_set_desc_addr(priv, p, rx_q->rx_skbuff_dma[i]);
 
        if (priv->dma_buf_sz == BUF_SIZE_16KiB)
                stmmac_init_desc3(priv, p);
@@ -1344,14 +1341,7 @@ static int init_dma_tx_desc_rings(struct net_device *dev)
                        else
                                p = tx_q->dma_tx + i;
 
-                       if (priv->synopsys_id >= DWMAC_CORE_4_00) {
-                               p->des0 = 0;
-                               p->des1 = 0;
-                               p->des2 = 0;
-                               p->des3 = 0;
-                       } else {
-                               p->des2 = 0;
-                       }
+                       stmmac_clear_desc(priv, p);
 
                        tx_q->tx_skbuff_dma[i].buf = 0;
                        tx_q->tx_skbuff_dma[i].map_as_page = false;
@@ -1797,22 +1787,18 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
        }
 
        /* configure all channels */
-       if (priv->synopsys_id >= DWMAC_CORE_4_00) {
-               for (chan = 0; chan < rx_channels_count; chan++) {
-                       qmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
+       for (chan = 0; chan < rx_channels_count; chan++) {
+               qmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
 
-                       stmmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan,
-                                       rxfifosz, qmode);
-               }
+               stmmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan,
+                               rxfifosz, qmode);
+       }
 
-               for (chan = 0; chan < tx_channels_count; chan++) {
-                       qmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
+       for (chan = 0; chan < tx_channels_count; chan++) {
+               qmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
 
-                       stmmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan,
-                                       txfifosz, qmode);
-               }
-       } else {
-               stmmac_dma_mode(priv, priv->ioaddr, txmode, rxmode, rxfifosz);
+               stmmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan,
+                               txfifosz, qmode);
        }
 }
 
@@ -1981,23 +1967,14 @@ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
        rxfifosz /= rx_channels_count;
        txfifosz /= tx_channels_count;
 
-       if (priv->synopsys_id >= DWMAC_CORE_4_00) {
-               stmmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan, rxfifosz,
-                               rxqmode);
-               stmmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan, txfifosz,
-                               txqmode);
-       } else {
-               stmmac_dma_mode(priv, priv->ioaddr, txmode, rxmode, rxfifosz);
-       }
+       stmmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan, rxfifosz, rxqmode);
+       stmmac_dma_tx_mode(priv, priv->ioaddr, txmode, chan, txfifosz, txqmode);
 }
 
 static bool stmmac_safety_feat_interrupt(struct stmmac_priv *priv)
 {
-       int ret = false;
+       int ret;
 
-       /* Safety features are only available in cores >= 5.10 */
-       if (priv->synopsys_id < DWMAC_CORE_5_10)
-               return ret;
        ret = stmmac_safety_feat_irq_status(priv, priv->dev,
                        priv->ioaddr, priv->dma_cap.asp, &priv->sstats);
        if (ret && (ret != -EINVAL)) {
@@ -2023,7 +2000,11 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
                                tx_channel_count : rx_channel_count;
        u32 chan;
        bool poll_scheduled = false;
-       int status[channels_to_check];
+       int status[max_t(u32, MTL_MAX_TX_QUEUES, MTL_MAX_RX_QUEUES)];
+
+       /* Make sure we never check beyond our status buffer. */
+       if (WARN_ON_ONCE(channels_to_check > ARRAY_SIZE(status)))
+               channels_to_check = ARRAY_SIZE(status);
 
        /* Each DMA channel can be used for rx and tx simultaneously, yet
         * napi_struct is embedded in struct stmmac_rx_queue rather than in a
@@ -2104,14 +2085,6 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
        unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET |
                            MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
 
-       if (priv->synopsys_id >= DWMAC_CORE_4_00) {
-               priv->ptpaddr = priv->ioaddr + PTP_GMAC4_OFFSET;
-               priv->mmcaddr = priv->ioaddr + MMC_GMAC4_OFFSET;
-       } else {
-               priv->ptpaddr = priv->ioaddr + PTP_GMAC3_X_OFFSET;
-               priv->mmcaddr = priv->ioaddr + MMC_GMAC3_X_OFFSET;
-       }
-
        dwmac_mmc_intr_all_mask(priv->mmcaddr);
 
        if (priv->dma_cap.rmon) {
@@ -2121,32 +2094,6 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
                netdev_info(priv->dev, "No MAC Management Counters available\n");
 }
 
-/**
- * stmmac_selec_desc_mode - to select among: normal/alternate/extend descriptors
- * @priv: driver private structure
- * Description: select the Enhanced/Alternate or Normal descriptors.
- * In case of Enhanced/Alternate, it checks if the extended descriptors are
- * supported by the HW capability register.
- */
-static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
-{
-       if (priv->plat->enh_desc) {
-               dev_info(priv->device, "Enhanced/Alternate descriptors\n");
-
-               /* GMAC older than 3.50 has no extended descriptors */
-               if (priv->synopsys_id >= DWMAC_CORE_3_50) {
-                       dev_info(priv->device, "Enabled extended descriptors\n");
-                       priv->extend_desc = 1;
-               } else
-                       dev_warn(priv->device, "Extended descriptors not supported\n");
-
-               priv->hw->desc = &enh_desc_ops;
-       } else {
-               dev_info(priv->device, "Normal descriptors\n");
-               priv->hw->desc = &ndesc_ops;
-       }
-}
-
 /**
  * stmmac_get_hw_features - get MAC capabilities from the HW cap. register.
  * @priv: driver private structure
@@ -2191,10 +2138,9 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
 {
        u32 rx_channels_count = priv->plat->rx_queues_to_use;
        u32 tx_channels_count = priv->plat->tx_queues_to_use;
+       u32 dma_csr_ch = max(rx_channels_count, tx_channels_count);
        struct stmmac_rx_queue *rx_q;
        struct stmmac_tx_queue *tx_q;
-       u32 dummy_dma_rx_phy = 0;
-       u32 dummy_dma_tx_phy = 0;
        u32 chan = 0;
        int atds = 0;
        int ret = 0;
@@ -2213,48 +2159,39 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
                return ret;
        }
 
-       if (priv->synopsys_id >= DWMAC_CORE_4_00) {
-               /* DMA Configuration */
-               stmmac_dma_init(priv, priv->ioaddr, priv->plat->dma_cfg,
-                               dummy_dma_tx_phy, dummy_dma_rx_phy, atds);
-
-               /* DMA RX Channel Configuration */
-               for (chan = 0; chan < rx_channels_count; chan++) {
-                       rx_q = &priv->rx_queue[chan];
-
-                       stmmac_init_rx_chan(priv, priv->ioaddr,
-                                       priv->plat->dma_cfg, rx_q->dma_rx_phy,
-                                       chan);
-
-                       rx_q->rx_tail_addr = rx_q->dma_rx_phy +
-                                   (DMA_RX_SIZE * sizeof(struct dma_desc));
-                       stmmac_set_rx_tail_ptr(priv, priv->ioaddr,
-                                       rx_q->rx_tail_addr, chan);
-               }
-
-               /* DMA TX Channel Configuration */
-               for (chan = 0; chan < tx_channels_count; chan++) {
-                       tx_q = &priv->tx_queue[chan];
+       /* DMA RX Channel Configuration */
+       for (chan = 0; chan < rx_channels_count; chan++) {
+               rx_q = &priv->rx_queue[chan];
 
-                       stmmac_init_chan(priv, priv->ioaddr,
-                                       priv->plat->dma_cfg, chan);
+               stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg,
+                                   rx_q->dma_rx_phy, chan);
 
-                       stmmac_init_tx_chan(priv, priv->ioaddr,
-                                       priv->plat->dma_cfg, tx_q->dma_tx_phy,
-                                       chan);
+               rx_q->rx_tail_addr = rx_q->dma_rx_phy +
+                           (DMA_RX_SIZE * sizeof(struct dma_desc));
+               stmmac_set_rx_tail_ptr(priv, priv->ioaddr,
+                                      rx_q->rx_tail_addr, chan);
+       }
 
-                       tx_q->tx_tail_addr = tx_q->dma_tx_phy +
-                                   (DMA_TX_SIZE * sizeof(struct dma_desc));
-                       stmmac_set_tx_tail_ptr(priv, priv->ioaddr,
-                                       tx_q->tx_tail_addr, chan);
-               }
-       } else {
-               rx_q = &priv->rx_queue[chan];
+       /* DMA TX Channel Configuration */
+       for (chan = 0; chan < tx_channels_count; chan++) {
                tx_q = &priv->tx_queue[chan];
-               stmmac_dma_init(priv, priv->ioaddr, priv->plat->dma_cfg,
-                               tx_q->dma_tx_phy, rx_q->dma_rx_phy, atds);
+
+               stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg,
+                                   tx_q->dma_tx_phy, chan);
+
+               tx_q->tx_tail_addr = tx_q->dma_tx_phy +
+                           (DMA_TX_SIZE * sizeof(struct dma_desc));
+               stmmac_set_tx_tail_ptr(priv, priv->ioaddr,
+                                      tx_q->tx_tail_addr, chan);
        }
 
+       /* DMA CSR Channel configuration */
+       for (chan = 0; chan < dma_csr_ch; chan++)
+               stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan);
+
+       /* DMA Configuration */
+       stmmac_dma_init(priv, priv->ioaddr, priv->plat->dma_cfg, atds);
+
        if (priv->plat->axi)
                stmmac_axi(priv, priv->ioaddr, priv->plat->axi);
 
@@ -2537,12 +2474,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
        stmmac_core_init(priv, priv->hw, dev);
 
        /* Initialize MTL*/
-       if (priv->synopsys_id >= DWMAC_CORE_4_00)
-               stmmac_mtl_configuration(priv);
+       stmmac_mtl_configuration(priv);
 
        /* Initialize Safety Features */
-       if (priv->synopsys_id >= DWMAC_CORE_5_10)
-               stmmac_safety_feat_configuration(priv);
+       stmmac_safety_feat_configuration(priv);
 
        ret = stmmac_rx_ipc(priv, priv->hw);
        if (!ret) {
@@ -3096,10 +3031,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        if (enh_desc)
                is_jumbo = stmmac_is_jumbo_frm(priv, skb->len, enh_desc);
 
-       if (unlikely(is_jumbo) && likely(priv->synopsys_id <
-                                        DWMAC_CORE_4_00)) {
+       if (unlikely(is_jumbo)) {
                entry = stmmac_jumbo_frm(priv, tx_q, skb, csum_insertion);
-               if (unlikely(entry < 0))
+               if (unlikely(entry < 0) && (entry != -EINVAL))
                        goto dma_map_err;
        }
 
@@ -3122,10 +3056,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                        goto dma_map_err; /* should reuse desc w/o issues */
 
                tx_q->tx_skbuff_dma[entry].buf = des;
-               if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))
-                       desc->des0 = cpu_to_le32(des);
-               else
-                       desc->des2 = cpu_to_le32(des);
+
+               stmmac_set_desc_addr(priv, desc, des);
 
                tx_q->tx_skbuff_dma[entry].map_as_page = true;
                tx_q->tx_skbuff_dma[entry].len = len;
@@ -3180,13 +3112,16 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
         * element in case of no SG.
         */
        priv->tx_count_frames += nfrags + 1;
-       if (likely(priv->tx_coal_frames > priv->tx_count_frames)) {
+       if (likely(priv->tx_coal_frames > priv->tx_count_frames) &&
+           !priv->tx_timer_armed) {
                mod_timer(&priv->txtimer,
                          STMMAC_COAL_TIMER(priv->tx_coal_timer));
+               priv->tx_timer_armed = true;
        } else {
                priv->tx_count_frames = 0;
                stmmac_set_tx_ic(priv, desc);
                priv->xstats.tx_set_ic_bit++;
+               priv->tx_timer_armed = false;
        }
 
        skb_tx_timestamp(skb);
@@ -3204,10 +3139,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                        goto dma_map_err;
 
                tx_q->tx_skbuff_dma[first_entry].buf = des;
-               if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00))
-                       first->des0 = cpu_to_le32(des);
-               else
-                       first->des2 = cpu_to_le32(des);
+
+               stmmac_set_desc_addr(priv, first, des);
 
                tx_q->tx_skbuff_dma[first_entry].len = nopaged_len;
                tx_q->tx_skbuff_dma[first_entry].last_segment = last_segment;
@@ -3321,13 +3254,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
                                break;
                        }
 
-                       if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00)) {
-                               p->des0 = cpu_to_le32(rx_q->rx_skbuff_dma[entry]);
-                               p->des1 = 0;
-                       } else {
-                               p->des2 = cpu_to_le32(rx_q->rx_skbuff_dma[entry]);
-                       }
-
+                       stmmac_set_desc_addr(priv, p, rx_q->rx_skbuff_dma[entry]);
                        stmmac_refill_desc3(priv, rx_q, p);
 
                        if (rx_q->rx_zeroc_thresh > 0)
@@ -3813,6 +3740,58 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        return ret;
 }
 
+static int stmmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
+                                   void *cb_priv)
+{
+       struct stmmac_priv *priv = cb_priv;
+       int ret = -EOPNOTSUPP;
+
+       stmmac_disable_all_queues(priv);
+
+       switch (type) {
+       case TC_SETUP_CLSU32:
+               if (tc_cls_can_offload_and_chain0(priv->dev, type_data))
+                       ret = stmmac_tc_setup_cls_u32(priv, priv, type_data);
+               break;
+       default:
+               break;
+       }
+
+       stmmac_enable_all_queues(priv);
+       return ret;
+}
+
+static int stmmac_setup_tc_block(struct stmmac_priv *priv,
+                                struct tc_block_offload *f)
+{
+       if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+               return -EOPNOTSUPP;
+
+       switch (f->command) {
+       case TC_BLOCK_BIND:
+               return tcf_block_cb_register(f->block, stmmac_setup_tc_block_cb,
+                               priv, priv);
+       case TC_BLOCK_UNBIND:
+               tcf_block_cb_unregister(f->block, stmmac_setup_tc_block_cb, priv);
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+                          void *type_data)
+{
+       struct stmmac_priv *priv = netdev_priv(ndev);
+
+       switch (type) {
+       case TC_SETUP_BLOCK:
+               return stmmac_setup_tc_block(priv, type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static int stmmac_set_mac_address(struct net_device *ndev, void *addr)
 {
        struct stmmac_priv *priv = netdev_priv(ndev);
@@ -4051,6 +4030,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
        .ndo_set_rx_mode = stmmac_set_rx_mode,
        .ndo_tx_timeout = stmmac_tx_timeout,
        .ndo_do_ioctl = stmmac_ioctl,
+       .ndo_setup_tc = stmmac_setup_tc,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = stmmac_poll_controller,
 #endif
@@ -4098,49 +4078,17 @@ static void stmmac_service_task(struct work_struct *work)
  */
 static int stmmac_hw_init(struct stmmac_priv *priv)
 {
-       struct mac_device_info *mac;
-
-       /* Identify the MAC HW device */
-       if (priv->plat->setup) {
-               mac = priv->plat->setup(priv);
-       } else if (priv->plat->has_gmac) {
-               priv->dev->priv_flags |= IFF_UNICAST_FLT;
-               mac = dwmac1000_setup(priv->ioaddr,
-                                     priv->plat->multicast_filter_bins,
-                                     priv->plat->unicast_filter_entries,
-                                     &priv->synopsys_id);
-       } else if (priv->plat->has_gmac4) {
-               priv->dev->priv_flags |= IFF_UNICAST_FLT;
-               mac = dwmac4_setup(priv->ioaddr,
-                                  priv->plat->multicast_filter_bins,
-                                  priv->plat->unicast_filter_entries,
-                                  &priv->synopsys_id);
-       } else {
-               mac = dwmac100_setup(priv->ioaddr, &priv->synopsys_id);
-       }
-       if (!mac)
-               return -ENOMEM;
-
-       priv->hw = mac;
+       int ret;
 
        /* dwmac-sun8i only work in chain mode */
        if (priv->plat->has_sun8i)
                chain_mode = 1;
+       priv->chain_mode = chain_mode;
 
-       /* To use the chained or ring mode */
-       if (priv->synopsys_id >= DWMAC_CORE_4_00) {
-               priv->hw->mode = &dwmac4_ring_mode_ops;
-       } else {
-               if (chain_mode) {
-                       priv->hw->mode = &chain_mode_ops;
-                       dev_info(priv->device, "Chain mode enabled\n");
-                       priv->mode = STMMAC_CHAIN_MODE;
-               } else {
-                       priv->hw->mode = &ring_mode_ops;
-                       dev_info(priv->device, "Ring mode enabled\n");
-                       priv->mode = STMMAC_RING_MODE;
-               }
-       }
+       /* Initialize HW Interface */
+       ret = stmmac_hwif_init(priv);
+       if (ret)
+               return ret;
 
        /* Get the HW capability (new GMAC newer than 3.50a) */
        priv->hw_cap_support = stmmac_get_hw_features(priv);
@@ -4174,12 +4122,6 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
                dev_info(priv->device, "No HW DMA feature register supported\n");
        }
 
-       /* To use alternate (extended), normal or GMAC4 descriptor structures */
-       if (priv->synopsys_id >= DWMAC_CORE_4_00)
-               priv->hw->desc = &dwmac4_desc_ops;
-       else
-               stmmac_selec_desc_mode(priv);
-
        if (priv->plat->rx_coe) {
                priv->hw->rx_csum = priv->plat->rx_coe;
                dev_info(priv->device, "RX Checksum Offload Engine supported\n");
@@ -4288,6 +4230,11 @@ int stmmac_dvr_probe(struct device *device,
        ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                            NETIF_F_RXCSUM;
 
+       ret = stmmac_tc_init(priv, priv);
+       if (!ret) {
+               ndev->hw_features |= NETIF_F_HW_TC;
+       }
+
        if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) {
                ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
                priv->tso = true;