linux/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2/*
   3 * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
   4 * stmmac XGMAC support.
   5 */
   6
   7#include <linux/stmmac.h>
   8#include "common.h"
   9#include "dwxgmac2.h"
  10
  11static int dwxgmac2_get_tx_status(void *data, struct stmmac_extra_stats *x,
  12                                  struct dma_desc *p, void __iomem *ioaddr)
  13{
  14        unsigned int tdes3 = le32_to_cpu(p->des3);
  15        int ret = tx_done;
  16
  17        if (unlikely(tdes3 & XGMAC_TDES3_OWN))
  18                return tx_dma_own;
  19        if (likely(!(tdes3 & XGMAC_TDES3_LD)))
  20                return tx_not_ls;
  21
  22        return ret;
  23}
  24
  25static int dwxgmac2_get_rx_status(void *data, struct stmmac_extra_stats *x,
  26                                  struct dma_desc *p)
  27{
  28        unsigned int rdes3 = le32_to_cpu(p->des3);
  29        int ret = good_frame;
  30
  31        if (unlikely(rdes3 & XGMAC_RDES3_OWN))
  32                return dma_own;
  33        if (likely(!(rdes3 & XGMAC_RDES3_LD)))
  34                return discard_frame;
  35        if (unlikely(rdes3 & XGMAC_RDES3_ES))
  36                ret = discard_frame;
  37
  38        return ret;
  39}
  40
  41static int dwxgmac2_get_tx_len(struct dma_desc *p)
  42{
  43        return (le32_to_cpu(p->des2) & XGMAC_TDES2_B1L);
  44}
  45
  46static int dwxgmac2_get_tx_owner(struct dma_desc *p)
  47{
  48        return (le32_to_cpu(p->des3) & XGMAC_TDES3_OWN) > 0;
  49}
  50
  51static void dwxgmac2_set_tx_owner(struct dma_desc *p)
  52{
  53        p->des3 |= cpu_to_le32(XGMAC_TDES3_OWN);
  54}
  55
  56static void dwxgmac2_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
  57{
  58        p->des3 = cpu_to_le32(XGMAC_RDES3_OWN);
  59
  60        if (!disable_rx_ic)
  61                p->des3 |= cpu_to_le32(XGMAC_RDES3_IOC);
  62}
  63
  64static int dwxgmac2_get_tx_ls(struct dma_desc *p)
  65{
  66        return (le32_to_cpu(p->des3) & XGMAC_RDES3_LD) > 0;
  67}
  68
  69static int dwxgmac2_get_rx_frame_len(struct dma_desc *p, int rx_coe)
  70{
  71        return (le32_to_cpu(p->des3) & XGMAC_RDES3_PL);
  72}
  73
  74static void dwxgmac2_enable_tx_timestamp(struct dma_desc *p)
  75{
  76        p->des2 |= cpu_to_le32(XGMAC_TDES2_TTSE);
  77}
  78
  79static int dwxgmac2_get_tx_timestamp_status(struct dma_desc *p)
  80{
  81        return 0; /* Not supported */
  82}
  83
  84static inline void dwxgmac2_get_timestamp(void *desc, u32 ats, u64 *ts)
  85{
  86        struct dma_desc *p = (struct dma_desc *)desc;
  87        u64 ns = 0;
  88
  89        ns += le32_to_cpu(p->des1) * 1000000000ULL;
  90        ns += le32_to_cpu(p->des0);
  91
  92        *ts = ns;
  93}
  94
  95static int dwxgmac2_rx_check_timestamp(void *desc)
  96{
  97        struct dma_desc *p = (struct dma_desc *)desc;
  98        unsigned int rdes3 = le32_to_cpu(p->des3);
  99        bool desc_valid, ts_valid;
 100
 101        desc_valid = !(rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT);
 102        ts_valid = !(rdes3 & XGMAC_RDES3_TSD) && (rdes3 & XGMAC_RDES3_TSA);
 103
 104        if (likely(desc_valid && ts_valid))
 105                return 0;
 106        return -EINVAL;
 107}
 108
 109static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
 110                                            u32 ats)
 111{
 112        struct dma_desc *p = (struct dma_desc *)desc;
 113        unsigned int rdes3 = le32_to_cpu(p->des3);
 114        int ret = -EBUSY;
 115
 116        if (likely(rdes3 & XGMAC_RDES3_CDA)) {
 117                ret = dwxgmac2_rx_check_timestamp(next_desc);
 118                if (ret)
 119                        return ret;
 120        }
 121
 122        return ret;
 123}
 124
 125static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
 126                                  int mode, int end, int bfsize)
 127{
 128        dwxgmac2_set_rx_owner(p, disable_rx_ic);
 129}
 130
 131static void dwxgmac2_init_tx_desc(struct dma_desc *p, int mode, int end)
 132{
 133        p->des0 = 0;
 134        p->des1 = 0;
 135        p->des2 = 0;
 136        p->des3 = 0;
 137}
 138
 139static void dwxgmac2_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 140                                     bool csum_flag, int mode, bool tx_own,
 141                                     bool ls, unsigned int tot_pkt_len)
 142{
 143        unsigned int tdes3 = le32_to_cpu(p->des3);
 144
 145        p->des2 |= cpu_to_le32(len & XGMAC_TDES2_B1L);
 146
 147        tdes3 = tot_pkt_len & XGMAC_TDES3_FL;
 148        if (is_fs)
 149                tdes3 |= XGMAC_TDES3_FD;
 150        else
 151                tdes3 &= ~XGMAC_TDES3_FD;
 152
 153        if (csum_flag)
 154                tdes3 |= 0x3 << XGMAC_TDES3_CIC_SHIFT;
 155        else
 156                tdes3 &= ~XGMAC_TDES3_CIC;
 157
 158        if (ls)
 159                tdes3 |= XGMAC_TDES3_LD;
 160        else
 161                tdes3 &= ~XGMAC_TDES3_LD;
 162
 163        /* Finally set the OWN bit. Later the DMA will start! */
 164        if (tx_own)
 165                tdes3 |= XGMAC_TDES3_OWN;
 166
 167        if (is_fs && tx_own)
 168                /* When the own bit, for the first frame, has to be set, all
 169                 * descriptors for the same frame has to be set before, to
 170                 * avoid race condition.
 171                 */
 172                dma_wmb();
 173
 174        p->des3 = cpu_to_le32(tdes3);
 175}
 176
 177static void dwxgmac2_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
 178                                         int len1, int len2, bool tx_own,
 179                                         bool ls, unsigned int tcphdrlen,
 180                                         unsigned int tcppayloadlen)
 181{
 182        unsigned int tdes3 = le32_to_cpu(p->des3);
 183
 184        if (len1)
 185                p->des2 |= cpu_to_le32(len1 & XGMAC_TDES2_B1L);
 186        if (len2)
 187                p->des2 |= cpu_to_le32((len2 << XGMAC_TDES2_B2L_SHIFT) &
 188                                XGMAC_TDES2_B2L);
 189        if (is_fs) {
 190                tdes3 |= XGMAC_TDES3_FD | XGMAC_TDES3_TSE;
 191                tdes3 |= (tcphdrlen << XGMAC_TDES3_THL_SHIFT) &
 192                        XGMAC_TDES3_THL;
 193                tdes3 |= tcppayloadlen & XGMAC_TDES3_TPL;
 194        } else {
 195                tdes3 &= ~XGMAC_TDES3_FD;
 196        }
 197
 198        if (ls)
 199                tdes3 |= XGMAC_TDES3_LD;
 200        else
 201                tdes3 &= ~XGMAC_TDES3_LD;
 202
 203        /* Finally set the OWN bit. Later the DMA will start! */
 204        if (tx_own)
 205                tdes3 |= XGMAC_TDES3_OWN;
 206
 207        if (is_fs && tx_own)
 208                /* When the own bit, for the first frame, has to be set, all
 209                 * descriptors for the same frame has to be set before, to
 210                 * avoid race condition.
 211                 */
 212                dma_wmb();
 213
 214        p->des3 = cpu_to_le32(tdes3);
 215}
 216
 217static void dwxgmac2_release_tx_desc(struct dma_desc *p, int mode)
 218{
 219        p->des0 = 0;
 220        p->des1 = 0;
 221        p->des2 = 0;
 222        p->des3 = 0;
 223}
 224
 225static void dwxgmac2_set_tx_ic(struct dma_desc *p)
 226{
 227        p->des2 |= cpu_to_le32(XGMAC_TDES2_IOC);
 228}
 229
 230static void dwxgmac2_set_mss(struct dma_desc *p, unsigned int mss)
 231{
 232        p->des0 = 0;
 233        p->des1 = 0;
 234        p->des2 = cpu_to_le32(mss);
 235        p->des3 = cpu_to_le32(XGMAC_TDES3_CTXT | XGMAC_TDES3_TCMSSV);
 236}
 237
 238static void dwxgmac2_get_addr(struct dma_desc *p, unsigned int *addr)
 239{
 240        *addr = le32_to_cpu(p->des0);
 241}
 242
 243static void dwxgmac2_set_addr(struct dma_desc *p, dma_addr_t addr)
 244{
 245        p->des0 = cpu_to_le32(lower_32_bits(addr));
 246        p->des1 = cpu_to_le32(upper_32_bits(addr));
 247}
 248
 249static void dwxgmac2_clear(struct dma_desc *p)
 250{
 251        p->des0 = 0;
 252        p->des1 = 0;
 253        p->des2 = 0;
 254        p->des3 = 0;
 255}
 256
 257const struct stmmac_desc_ops dwxgmac210_desc_ops = {
 258        .tx_status = dwxgmac2_get_tx_status,
 259        .rx_status = dwxgmac2_get_rx_status,
 260        .get_tx_len = dwxgmac2_get_tx_len,
 261        .get_tx_owner = dwxgmac2_get_tx_owner,
 262        .set_tx_owner = dwxgmac2_set_tx_owner,
 263        .set_rx_owner = dwxgmac2_set_rx_owner,
 264        .get_tx_ls = dwxgmac2_get_tx_ls,
 265        .get_rx_frame_len = dwxgmac2_get_rx_frame_len,
 266        .enable_tx_timestamp = dwxgmac2_enable_tx_timestamp,
 267        .get_tx_timestamp_status = dwxgmac2_get_tx_timestamp_status,
 268        .get_rx_timestamp_status = dwxgmac2_get_rx_timestamp_status,
 269        .get_timestamp = dwxgmac2_get_timestamp,
 270        .set_tx_ic = dwxgmac2_set_tx_ic,
 271        .prepare_tx_desc = dwxgmac2_prepare_tx_desc,
 272        .prepare_tso_tx_desc = dwxgmac2_prepare_tso_tx_desc,
 273        .release_tx_desc = dwxgmac2_release_tx_desc,
 274        .init_rx_desc = dwxgmac2_init_rx_desc,
 275        .init_tx_desc = dwxgmac2_init_tx_desc,
 276        .set_mss = dwxgmac2_set_mss,
 277        .get_addr = dwxgmac2_get_addr,
 278        .set_addr = dwxgmac2_set_addr,
 279        .clear = dwxgmac2_clear,
 280};
 281