uboot/drivers/net/mscc_eswitch/mscc_xfer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
   2/*
   3 * Copyright (c) 2018 Microsemi Corporation
   4 */
   5
   6#include <log.h>
   7#include <linux/bitops.h>
   8#include <linux/delay.h>
   9#include <linux/io.h>
  10#include "mscc_xfer.h"
  11
  12#define QS_XTR_FLUSH_FLUSH              GENMASK(1, 0)
  13#define QS_INJ_CTRL_GAP_SIZE(x)         ((x) << 21)
  14#define QS_INJ_CTRL_EOF                 BIT(19)
  15#define QS_INJ_CTRL_SOF                 BIT(18)
  16#define QS_INJ_CTRL_VLD_BYTES(x)        ((x) << 16)
  17
  18#define XTR_EOF_0     ntohl(0x80000000u)
  19#define XTR_EOF_1     ntohl(0x80000001u)
  20#define XTR_EOF_2     ntohl(0x80000002u)
  21#define XTR_EOF_3     ntohl(0x80000003u)
  22#define XTR_PRUNED    ntohl(0x80000004u)
  23#define XTR_ABORT     ntohl(0x80000005u)
  24#define XTR_ESCAPE    ntohl(0x80000006u)
  25#define XTR_NOT_READY ntohl(0x80000007u)
  26
  27#define BUF_CELL_SZ             60
  28#define XTR_VALID_BYTES(x)      (4 - ((x) & 3))
  29
  30int mscc_send(void __iomem *regs, const unsigned long *mscc_qs_offset,
  31              u32 *ifh, size_t ifh_len, u32 *buff, size_t buff_len)
  32{
  33        int i, count = (buff_len + 3) / 4, last = buff_len % 4;
  34
  35        writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
  36               regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
  37
  38        for (i = 0; i < ifh_len; i++)
  39                writel(ifh[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
  40
  41        for (i = 0; i < count; i++)
  42                writel(buff[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
  43
  44        /* Add padding */
  45        while (i < (BUF_CELL_SZ / 4)) {
  46                writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
  47                i++;
  48        }
  49
  50        /* Indicate EOF and valid bytes in last word */
  51        writel(QS_INJ_CTRL_GAP_SIZE(1) |
  52               QS_INJ_CTRL_VLD_BYTES(buff_len < BUF_CELL_SZ ? 0 : last) |
  53               QS_INJ_CTRL_EOF, regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
  54
  55        /* Add dummy CRC */
  56        writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
  57
  58        return 0;
  59}
  60
  61int mscc_recv(void __iomem *regs, const unsigned long *mscc_qs_offset,
  62              u32 *rxbuf, size_t ifh_len, bool byte_swap)
  63{
  64        u8 grp = 0; /* Recv everything on CPU group 0 */
  65        int i, byte_cnt = 0;
  66        bool eof_flag = false, pruned_flag = false, abort_flag = false;
  67
  68        if (!(readl(regs + mscc_qs_offset[MSCC_QS_XTR_DATA_PRESENT]) &
  69              BIT(grp)))
  70                return -EAGAIN;
  71
  72        /* skip IFH */
  73        for (i = 0; i < ifh_len; i++)
  74                readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
  75
  76        while (!eof_flag) {
  77                u32 val = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
  78                u32 cmp = val;
  79
  80                if (byte_swap)
  81                        cmp = ntohl(val);
  82
  83                switch (cmp) {
  84                case XTR_NOT_READY:
  85                        debug("%d NOT_READY...?\n", byte_cnt);
  86                        break;
  87                case XTR_ABORT:
  88                        *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
  89                        abort_flag = true;
  90                        eof_flag = true;
  91                        debug("XTR_ABORT\n");
  92                        break;
  93                case XTR_EOF_0:
  94                case XTR_EOF_1:
  95                case XTR_EOF_2:
  96                case XTR_EOF_3:
  97                        byte_cnt += XTR_VALID_BYTES(val);
  98                        *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
  99                        eof_flag = true;
 100                        debug("EOF\n");
 101                        break;
 102                case XTR_PRUNED:
 103                        /* But get the last 4 bytes as well */
 104                        eof_flag = true;
 105                        pruned_flag = true;
 106                        debug("PRUNED\n");
 107                        /* fallthrough */
 108                case XTR_ESCAPE:
 109                        *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
 110                        byte_cnt += 4;
 111                        rxbuf++;
 112                        debug("ESCAPED\n");
 113                        break;
 114                default:
 115                        *rxbuf = val;
 116                        byte_cnt += 4;
 117                        rxbuf++;
 118                }
 119        }
 120
 121        if (abort_flag || pruned_flag || !eof_flag) {
 122                debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
 123                      abort_flag, pruned_flag, eof_flag);
 124                return -EAGAIN;
 125        }
 126
 127        return byte_cnt;
 128}
 129
 130void mscc_flush(void __iomem *regs, const unsigned long *mscc_qs_offset)
 131{
 132        /* All Queues flush */
 133        setbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
 134                     QS_XTR_FLUSH_FLUSH);
 135
 136        /* Allow to drain */
 137        mdelay(1);
 138
 139        /* All Queues normal */
 140        clrbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
 141                     QS_XTR_FLUSH_FLUSH);
 142}
 143