net: stmmac: Add descriptor related callbacks for XGMAC2
authorJose Abreu <Jose.Abreu@synopsys.com>
Wed, 8 Aug 2018 08:04:32 +0000 (09:04 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 9 Aug 2018 18:16:28 +0000 (11:16 -0700)
Add the descriptor related callbacks for the new IP block XGMAC2.

Signed-off-by: Jose Abreu <joabreu@synopsys.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Joao Pinto <jpinto@synopsys.com>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre Torgue <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/Makefile
drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c [new file with mode: 0644]
drivers/net/ethernet/stmicro/stmmac/hwif.c
drivers/net/ethernet/stmicro/stmmac/hwif.h

index da40d3b..99967a8 100644 (file)
@@ -5,7 +5,8 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o  \
              dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o     \
              mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o  \
              dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
-             stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o $(stmmac-y)
+             stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
+             $(stmmac-y)
 
 # Ordering matters. Generic driver must be last.
 obj-$(CONFIG_STMMAC_PLATFORM)  += stmmac-platform.o
index a699233..0a80fa2 100644 (file)
 #define XGMAC_TPS                      BIT(1)
 #define XGMAC_TI                       BIT(0)
 
+/* Descriptors */
+#define XGMAC_TDES2_IOC                        BIT(31)
+#define XGMAC_TDES2_TTSE               BIT(30)
+#define XGMAC_TDES2_B2L                        GENMASK(29, 16)
+#define XGMAC_TDES2_B2L_SHIFT          16
+#define XGMAC_TDES2_B1L                        GENMASK(13, 0)
+#define XGMAC_TDES3_OWN                        BIT(31)
+#define XGMAC_TDES3_CTXT               BIT(30)
+#define XGMAC_TDES3_FD                 BIT(29)
+#define XGMAC_TDES3_LD                 BIT(28)
+#define XGMAC_TDES3_CPC                        GENMASK(27, 26)
+#define XGMAC_TDES3_CPC_SHIFT          26
+#define XGMAC_TDES3_TCMSSV             BIT(26)
+#define XGMAC_TDES3_THL                        GENMASK(22, 19)
+#define XGMAC_TDES3_THL_SHIFT          19
+#define XGMAC_TDES3_TSE                        BIT(18)
+#define XGMAC_TDES3_CIC                        GENMASK(17, 16)
+#define XGMAC_TDES3_CIC_SHIFT          16
+#define XGMAC_TDES3_TPL                        GENMASK(17, 0)
+#define XGMAC_TDES3_FL                 GENMASK(14, 0)
+#define XGMAC_RDES3_OWN                        BIT(31)
+#define XGMAC_RDES3_CTXT               BIT(30)
+#define XGMAC_RDES3_IOC                        BIT(30)
+#define XGMAC_RDES3_LD                 BIT(28)
+#define XGMAC_RDES3_CDA                        BIT(27)
+#define XGMAC_RDES3_ES                 BIT(15)
+#define XGMAC_RDES3_PL                 GENMASK(13, 0)
+#define XGMAC_RDES3_TSD                        BIT(6)
+#define XGMAC_RDES3_TSA                        BIT(4)
+
 #endif /* __STMMAC_DWXGMAC2_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
new file mode 100644 (file)
index 0000000..1d858fd
--- /dev/null
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
+ * stmmac XGMAC support.
+ */
+
+#include <linux/stmmac.h>
+#include "common.h"
+#include "dwxgmac2.h"
+
+static int dwxgmac2_get_tx_status(void *data, struct stmmac_extra_stats *x,
+                                 struct dma_desc *p, void __iomem *ioaddr)
+{
+       unsigned int tdes3 = le32_to_cpu(p->des3);
+       int ret = tx_done;
+
+       if (unlikely(tdes3 & XGMAC_TDES3_OWN))
+               return tx_dma_own;
+       if (likely(!(tdes3 & XGMAC_TDES3_LD)))
+               return tx_not_ls;
+
+       return ret;
+}
+
+static int dwxgmac2_get_rx_status(void *data, struct stmmac_extra_stats *x,
+                                 struct dma_desc *p)
+{
+       unsigned int rdes3 = le32_to_cpu(p->des3);
+       int ret = good_frame;
+
+       if (unlikely(rdes3 & XGMAC_RDES3_OWN))
+               return dma_own;
+       if (likely(!(rdes3 & XGMAC_RDES3_LD)))
+               return discard_frame;
+       if (unlikely(rdes3 & XGMAC_RDES3_ES))
+               ret = discard_frame;
+
+       return ret;
+}
+
+static int dwxgmac2_get_tx_len(struct dma_desc *p)
+{
+       return (le32_to_cpu(p->des2) & XGMAC_TDES2_B1L);
+}
+
+static int dwxgmac2_get_tx_owner(struct dma_desc *p)
+{
+       return (le32_to_cpu(p->des3) & XGMAC_TDES3_OWN) > 0;
+}
+
+static void dwxgmac2_set_tx_owner(struct dma_desc *p)
+{
+       p->des3 |= cpu_to_le32(XGMAC_TDES3_OWN);
+}
+
+static void dwxgmac2_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
+{
+       p->des3 = cpu_to_le32(XGMAC_RDES3_OWN);
+
+       if (!disable_rx_ic)
+               p->des3 |= cpu_to_le32(XGMAC_RDES3_IOC);
+}
+
+static int dwxgmac2_get_tx_ls(struct dma_desc *p)
+{
+       return (le32_to_cpu(p->des3) & XGMAC_RDES3_LD) > 0;
+}
+
+static int dwxgmac2_get_rx_frame_len(struct dma_desc *p, int rx_coe)
+{
+       return (le32_to_cpu(p->des3) & XGMAC_RDES3_PL);
+}
+
+static void dwxgmac2_enable_tx_timestamp(struct dma_desc *p)
+{
+       p->des2 |= cpu_to_le32(XGMAC_TDES2_TTSE);
+}
+
+static int dwxgmac2_get_tx_timestamp_status(struct dma_desc *p)
+{
+       return 0; /* Not supported */
+}
+
+static inline void dwxgmac2_get_timestamp(void *desc, u32 ats, u64 *ts)
+{
+       struct dma_desc *p = (struct dma_desc *)desc;
+       u64 ns = 0;
+
+       ns += le32_to_cpu(p->des1) * 1000000000ULL;
+       ns += le32_to_cpu(p->des0);
+
+       *ts = ns;
+}
+
+static int dwxgmac2_rx_check_timestamp(void *desc)
+{
+       struct dma_desc *p = (struct dma_desc *)desc;
+       unsigned int rdes3 = le32_to_cpu(p->des3);
+       bool desc_valid, ts_valid;
+
+       desc_valid = !(rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT);
+       ts_valid = !(rdes3 & XGMAC_RDES3_TSD) && (rdes3 & XGMAC_RDES3_TSA);
+
+       if (likely(desc_valid && ts_valid))
+               return 0;
+       return -EINVAL;
+}
+
+static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
+                                           u32 ats)
+{
+       struct dma_desc *p = (struct dma_desc *)desc;
+       unsigned int rdes3 = le32_to_cpu(p->des3);
+       int ret = -EBUSY;
+
+       if (likely(rdes3 & XGMAC_RDES3_CDA)) {
+               ret = dwxgmac2_rx_check_timestamp(next_desc);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
+                                 int mode, int end)
+{
+       dwxgmac2_set_rx_owner(p, disable_rx_ic);
+}
+
+static void dwxgmac2_init_tx_desc(struct dma_desc *p, int mode, int end)
+{
+       p->des0 = 0;
+       p->des1 = 0;
+       p->des2 = 0;
+       p->des3 = 0;
+}
+
+static void dwxgmac2_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+                                    bool csum_flag, int mode, bool tx_own,
+                                    bool ls, unsigned int tot_pkt_len)
+{
+       unsigned int tdes3 = le32_to_cpu(p->des3);
+
+       p->des2 |= cpu_to_le32(len & XGMAC_TDES2_B1L);
+
+       tdes3 = tot_pkt_len & XGMAC_TDES3_FL;
+       if (is_fs)
+               tdes3 |= XGMAC_TDES3_FD;
+       else
+               tdes3 &= ~XGMAC_TDES3_FD;
+
+       if (csum_flag)
+               tdes3 |= 0x3 << XGMAC_TDES3_CIC_SHIFT;
+       else
+               tdes3 &= ~XGMAC_TDES3_CIC;
+
+       if (ls)
+               tdes3 |= XGMAC_TDES3_LD;
+       else
+               tdes3 &= ~XGMAC_TDES3_LD;
+
+       /* Finally set the OWN bit. Later the DMA will start! */
+       if (tx_own)
+               tdes3 |= XGMAC_TDES3_OWN;
+
+       if (is_fs && tx_own)
+               /* When the own bit, for the first frame, has to be set, all
+                * descriptors for the same frame has to be set before, to
+                * avoid race condition.
+                */
+               dma_wmb();
+
+       p->des3 = cpu_to_le32(tdes3);
+}
+
+static void dwxgmac2_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
+                                        int len1, int len2, bool tx_own,
+                                        bool ls, unsigned int tcphdrlen,
+                                        unsigned int tcppayloadlen)
+{
+       unsigned int tdes3 = le32_to_cpu(p->des3);
+
+       if (len1)
+               p->des2 |= cpu_to_le32(len1 & XGMAC_TDES2_B1L);
+       if (len2)
+               p->des2 |= cpu_to_le32((len2 << XGMAC_TDES2_B2L_SHIFT) &
+                               XGMAC_TDES2_B2L);
+       if (is_fs) {
+               tdes3 |= XGMAC_TDES3_FD | XGMAC_TDES3_TSE;
+               tdes3 |= (tcphdrlen << XGMAC_TDES3_THL_SHIFT) &
+                       XGMAC_TDES3_THL;
+               tdes3 |= tcppayloadlen & XGMAC_TDES3_TPL;
+       } else {
+               tdes3 &= ~XGMAC_TDES3_FD;
+       }
+
+       if (ls)
+               tdes3 |= XGMAC_TDES3_LD;
+       else
+               tdes3 &= ~XGMAC_TDES3_LD;
+
+       /* Finally set the OWN bit. Later the DMA will start! */
+       if (tx_own)
+               tdes3 |= XGMAC_TDES3_OWN;
+
+       if (is_fs && tx_own)
+               /* When the own bit, for the first frame, has to be set, all
+                * descriptors for the same frame has to be set before, to
+                * avoid race condition.
+                */
+               dma_wmb();
+
+       p->des3 = cpu_to_le32(tdes3);
+}
+
+static void dwxgmac2_release_tx_desc(struct dma_desc *p, int mode)
+{
+       p->des0 = 0;
+       p->des1 = 0;
+       p->des2 = 0;
+       p->des3 = 0;
+}
+
+static void dwxgmac2_set_tx_ic(struct dma_desc *p)
+{
+       p->des2 |= cpu_to_le32(XGMAC_TDES2_IOC);
+}
+
+static void dwxgmac2_set_mss(struct dma_desc *p, unsigned int mss)
+{
+       p->des0 = 0;
+       p->des1 = 0;
+       p->des2 = cpu_to_le32(mss);
+       p->des3 = cpu_to_le32(XGMAC_TDES3_CTXT | XGMAC_TDES3_TCMSSV);
+}
+
+static void dwxgmac2_get_addr(struct dma_desc *p, unsigned int *addr)
+{
+       *addr = le32_to_cpu(p->des0);
+}
+
+static void dwxgmac2_set_addr(struct dma_desc *p, dma_addr_t addr)
+{
+       p->des0 = cpu_to_le32(addr);
+       p->des1 = 0;
+}
+
+static void dwxgmac2_clear(struct dma_desc *p)
+{
+       p->des0 = 0;
+       p->des1 = 0;
+       p->des2 = 0;
+       p->des3 = 0;
+}
+
+const struct stmmac_desc_ops dwxgmac210_desc_ops = {
+       .tx_status = dwxgmac2_get_tx_status,
+       .rx_status = dwxgmac2_get_rx_status,
+       .get_tx_len = dwxgmac2_get_tx_len,
+       .get_tx_owner = dwxgmac2_get_tx_owner,
+       .set_tx_owner = dwxgmac2_set_tx_owner,
+       .set_rx_owner = dwxgmac2_set_rx_owner,
+       .get_tx_ls = dwxgmac2_get_tx_ls,
+       .get_rx_frame_len = dwxgmac2_get_rx_frame_len,
+       .enable_tx_timestamp = dwxgmac2_enable_tx_timestamp,
+       .get_tx_timestamp_status = dwxgmac2_get_tx_timestamp_status,
+       .get_rx_timestamp_status = dwxgmac2_get_rx_timestamp_status,
+       .get_timestamp = dwxgmac2_get_timestamp,
+       .set_tx_ic = dwxgmac2_set_tx_ic,
+       .prepare_tx_desc = dwxgmac2_prepare_tx_desc,
+       .prepare_tso_tx_desc = dwxgmac2_prepare_tso_tx_desc,
+       .release_tx_desc = dwxgmac2_release_tx_desc,
+       .init_rx_desc = dwxgmac2_init_rx_desc,
+       .init_tx_desc = dwxgmac2_init_tx_desc,
+       .set_mss = dwxgmac2_set_mss,
+       .get_addr = dwxgmac2_get_addr,
+       .set_addr = dwxgmac2_set_addr,
+       .clear = dwxgmac2_clear,
+};
index 4030199..4b4ba1c 100644 (file)
@@ -196,7 +196,7 @@ static const struct stmmac_hwif_entry {
                        .ptp_off = 0,
                        .mmc_off = 0,
                },
-               .desc = NULL,
+               .desc = &dwxgmac210_desc_ops,
                .dma = &dwxgmac210_dma_ops,
                .mac = &dwxgmac210_ops,
                .hwtimestamp = NULL,
index 3106eac..92b8944 100644 (file)
@@ -481,6 +481,7 @@ extern const struct stmmac_ops dwmac510_ops;
 extern const struct stmmac_tc_ops dwmac510_tc_ops;
 extern const struct stmmac_ops dwxgmac210_ops;
 extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
+extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
 
 #define GMAC_VERSION           0x00000020      /* GMAC CORE Version */
 #define GMAC4_VERSION          0x00000110      /* GMAC4+ CORE Version */