[...]

>diff --git a/drivers/net/ethernet/marvell/prestera/prestera_dsa.c 
>b/drivers/net/ethernet/marvell/prestera/prestera_dsa.c
>new file mode 100644
>index 000000000000..c4f7d9f6edcb
>--- /dev/null
>+++ b/drivers/net/ethernet/marvell/prestera/prestera_dsa.c
>@@ -0,0 +1,134 @@
>+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
>+/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
>+
>+#include "prestera_dsa.h"
>+
>+#include <linux/string.h>
>+#include <linux/bitops.h>
>+#include <linux/bitfield.h>
>+#include <linux/errno.h>
>+
>+#define W0_MASK_IS_TAGGED     BIT(29)
>+
>+/* TrgDev[4:0] = {Word0[28:24]} */
>+#define W0_MASK_HW_DEV_NUM    GENMASK(28, 24)
>+
>+/* SrcPort/TrgPort extended to 8b
>+ * SrcPort/TrgPort[7:0] = {Word2[20], Word1[11:10], Word0[23:19]}
>+ */
>+#define W0_MASK_IFACE_PORT_NUM        GENMASK(23, 19)
>+
>+/* bits 30:31 - TagCommand 1 = FROM_CPU */
>+#define W0_MASK_DSA_CMD               GENMASK(31, 30)
>+
>+/* bits 13:15 -- UP */
>+#define W0_MASK_VPT           GENMASK(15, 13)
>+
>+#define W0_MASK_EXT_BIT               BIT(12)
>+
>+/* bits 0:11 -- VID */
>+#define W0_MASK_VID           GENMASK(11, 0)
>+
>+/* SrcPort/TrgPort extended to 8b
>+ * SrcPort/TrgPort[7:0] = {Word2[20], Word1[11:10], Word0[23:19]}
>+ */
>+#define W1_MASK_IFACE_PORT_NUM        GENMASK(11, 10)
>+
>+#define W1_MASK_EXT_BIT               BIT(31)
>+#define W1_MASK_CFI_BIT               BIT(30)
>+
>+/* SrcPort/TrgPort extended to 8b
>+ * SrcPort/TrgPort[7:0] = {Word2[20], Word1[11:10], Word0[23:19]}
>+ */
>+#define W2_MASK_IFACE_PORT_NUM        BIT(20)
>+
>+#define W2_MASK_EXT_BIT               BIT(31)
>+
>+/* trgHwDev and trgPort
>+ * TrgDev[11:5] = {Word3[6:0]}
>+ */
>+#define W3_MASK_HW_DEV_NUM    GENMASK(6, 0)
>+
>+/* VID 16b [15:0] = {Word3[30:27], Word0[11:0]} */
>+#define W3_MASK_VID           GENMASK(30, 27)
>+
>+/* TRGePort[16:0] = {Word3[23:7]} */
>+#define W3_MASK_DST_EPORT     GENMASK(23, 7)
>+
>+#define DEV_NUM_MASK          GENMASK(11, 5)
>+#define VID_MASK              GENMASK(15, 12)

Looks like you forgot to add the "prestera" prefix here.


>+
>+int prestera_dsa_parse(struct prestera_dsa *dsa, const u8 *dsa_buf)
>+{
>+      u32 *dsa_words = (u32 *)dsa_buf;
>+      enum prestera_dsa_cmd cmd;
>+      u32 words[4] = { 0 };
>+      u32 field;
>+
>+      words[0] = ntohl((__force __be32)dsa_words[0]);
>+      words[1] = ntohl((__force __be32)dsa_words[1]);
>+      words[2] = ntohl((__force __be32)dsa_words[2]);
>+      words[3] = ntohl((__force __be32)dsa_words[3]);
>+
>+      /* set the common parameters */
>+      cmd = (enum prestera_dsa_cmd)FIELD_GET(W0_MASK_DSA_CMD, words[0]);
>+
>+      /* only to CPU is supported */
>+      if (unlikely(cmd != PRESTERA_DSA_CMD_TO_CPU_E))
>+              return -EINVAL;
>+
>+      if (FIELD_GET(W0_MASK_EXT_BIT, words[0]) == 0)
>+              return -EINVAL;
>+      if (FIELD_GET(W1_MASK_EXT_BIT, words[1]) == 0)
>+              return -EINVAL;
>+      if (FIELD_GET(W2_MASK_EXT_BIT, words[2]) == 0)
>+              return -EINVAL;
>+
>+      field = FIELD_GET(W3_MASK_VID, words[3]);
>+
>+      dsa->vlan.is_tagged = (bool)FIELD_GET(W0_MASK_IS_TAGGED, words[0]);
>+      dsa->vlan.cfi_bit = (u8)FIELD_GET(W1_MASK_CFI_BIT, words[1]);
>+      dsa->vlan.vpt = (u8)FIELD_GET(W0_MASK_VPT, words[0]);
>+      dsa->vlan.vid = (u16)FIELD_GET(W0_MASK_VID, words[0]);
>+      dsa->vlan.vid &= ~VID_MASK;
>+      dsa->vlan.vid |= FIELD_PREP(VID_MASK, field);
>+
>+      field = FIELD_GET(W3_MASK_HW_DEV_NUM, words[3]);
>+
>+      dsa->hw_dev_num = FIELD_GET(W0_MASK_HW_DEV_NUM, words[0]);
>+      dsa->hw_dev_num &= W3_MASK_HW_DEV_NUM;
>+      dsa->hw_dev_num |= FIELD_PREP(DEV_NUM_MASK, field);
>+
>+      dsa->port_num = (FIELD_GET(W0_MASK_IFACE_PORT_NUM, words[0]) << 0) |
>+                      (FIELD_GET(W1_MASK_IFACE_PORT_NUM, words[1]) << 5) |
>+                      (FIELD_GET(W2_MASK_IFACE_PORT_NUM, words[2]) << 7);
>+      return 0;
>+}
>+
>+int prestera_dsa_build(const struct prestera_dsa *dsa, u8 *dsa_buf)
>+{
>+      __be32 *dsa_words = (__be32 *)dsa_buf;
>+      u32 words[4] = { 0 };
>+
>+      if (dsa->hw_dev_num >= BIT(12))
>+              return -EINVAL;
>+      if (dsa->port_num >= BIT(17))
>+              return -EINVAL;
>+
>+      words[0] |= FIELD_PREP(W0_MASK_DSA_CMD, PRESTERA_DSA_CMD_FROM_CPU_E);
>+
>+      words[0] |= FIELD_PREP(W0_MASK_HW_DEV_NUM, dsa->hw_dev_num);
>+      words[3] |= FIELD_PREP(W3_MASK_HW_DEV_NUM, (dsa->hw_dev_num >> 5));
>+      words[3] |= FIELD_PREP(W3_MASK_DST_EPORT, dsa->port_num);
>+
>+      words[0] |= FIELD_PREP(W0_MASK_EXT_BIT, 1);
>+      words[1] |= FIELD_PREP(W1_MASK_EXT_BIT, 1);
>+      words[2] |= FIELD_PREP(W2_MASK_EXT_BIT, 1);
>+
>+      dsa_words[0] = htonl(words[0]);
>+      dsa_words[1] = htonl(words[1]);
>+      dsa_words[2] = htonl(words[2]);
>+      dsa_words[3] = htonl(words[3]);
>+
>+      return 0;
>+}
>diff --git a/drivers/net/ethernet/marvell/prestera/prestera_dsa.h 
>b/drivers/net/ethernet/marvell/prestera/prestera_dsa.h
>new file mode 100644
>index 000000000000..34cb260f1a74
>--- /dev/null
>+++ b/drivers/net/ethernet/marvell/prestera/prestera_dsa.h
>@@ -0,0 +1,37 @@
>+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
>+ *
>+ * Copyright (c) 2020 Marvell International Ltd. All rights reserved.
>+ *
>+ */
>+#ifndef __PRESTERA_DSA_H_
>+#define __PRESTERA_DSA_H_
>+
>+#include <linux/types.h>
>+
>+#define PRESTERA_DSA_HLEN     16
>+
>+enum prestera_dsa_cmd {
>+      /* DSA command is "To CPU" */
>+      PRESTERA_DSA_CMD_TO_CPU_E = 0,
>+
>+      /* DSA command is "FROM CPU" */
>+      PRESTERA_DSA_CMD_FROM_CPU_E,
>+};
>+
>+struct prestera_dsa_vlan {
>+      u16 vid;
>+      u8 vpt;
>+      u8 cfi_bit;
>+      bool is_tagged;
>+};
>+
>+struct prestera_dsa {
>+      struct prestera_dsa_vlan vlan;
>+      u32 hw_dev_num;
>+      u32 port_num;
>+};
>+
>+int prestera_dsa_parse(struct prestera_dsa *dsa, const u8 *dsa_buf);
>+int prestera_dsa_build(const struct prestera_dsa *dsa, u8 *dsa_buf);
>+
>+#endif /* _PRESTERA_DSA_H_ */
>diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.c 
>b/drivers/net/ethernet/marvell/prestera/prestera_hw.c
>new file mode 100644
>index 000000000000..b4626cf288b6
>--- /dev/null
>+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.c
>@@ -0,0 +1,614 @@
>+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
>+/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
>+
>+#include <linux/etherdevice.h>
>+#include <linux/ethtool.h>
>+#include <linux/netdevice.h>
>+#include <linux/list.h>
>+
>+#include "prestera.h"
>+#include "prestera_hw.h"
>+
>+#define PRESTERA_SWITCH_INIT_TIMEOUT 30000000 /* 30sec */
>+#define PRESTERA_MIN_MTU 64
>+
>+enum prestera_cmd_type_t {
>+      PRESTERA_CMD_TYPE_SWITCH_INIT = 0x1,
>+      PRESTERA_CMD_TYPE_SWITCH_ATTR_SET = 0x2,
>+
>+      PRESTERA_CMD_TYPE_PORT_ATTR_SET = 0x100,
>+      PRESTERA_CMD_TYPE_PORT_ATTR_GET = 0x101,
>+      PRESTERA_CMD_TYPE_PORT_INFO_GET = 0x110,
>+
>+      PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,
>+      PRESTERA_CMD_TYPE_RXTX_PORT_INIT = 0x801,
>+
>+      PRESTERA_CMD_TYPE_ACK = 0x10000,
>+      PRESTERA_CMD_TYPE_MAX
>+};
>+
>+enum {
>+      PRESTERA_CMD_PORT_ATTR_ADMIN_STATE = 1,
>+      PRESTERA_CMD_PORT_ATTR_MTU = 3,
>+      PRESTERA_CMD_PORT_ATTR_MAC = 4,
>+      PRESTERA_CMD_PORT_ATTR_CAPABILITY = 9,
>+      PRESTERA_CMD_PORT_ATTR_AUTONEG = 15,
>+      PRESTERA_CMD_PORT_ATTR_STATS = 17,
>+};
>+
>+enum {
>+      PRESTERA_CMD_SWITCH_ATTR_MAC = 1,
>+};
>+
>+enum {
>+      PRESTERA_CMD_ACK_OK,
>+      PRESTERA_CMD_ACK_FAILED,
>+
>+      PRESTERA_CMD_ACK_MAX
>+};
>+
>+enum {
>+      PRESTERA_PORT_GOOD_OCTETS_RCV_CNT,
>+      PRESTERA_PORT_BAD_OCTETS_RCV_CNT,
>+      PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT,
>+      PRESTERA_PORT_BRDC_PKTS_RCV_CNT,
>+      PRESTERA_PORT_MC_PKTS_RCV_CNT,
>+      PRESTERA_PORT_PKTS_64L_CNT,
>+      PRESTERA_PORT_PKTS_65TO127L_CNT,
>+      PRESTERA_PORT_PKTS_128TO255L_CNT,
>+      PRESTERA_PORT_PKTS_256TO511L_CNT,
>+      PRESTERA_PORT_PKTS_512TO1023L_CNT,
>+      PRESTERA_PORT_PKTS_1024TOMAXL_CNT,
>+      PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT,
>+      PRESTERA_PORT_MC_PKTS_SENT_CNT,
>+      PRESTERA_PORT_BRDC_PKTS_SENT_CNT,
>+      PRESTERA_PORT_FC_SENT_CNT,
>+      PRESTERA_PORT_GOOD_FC_RCV_CNT,
>+      PRESTERA_PORT_DROP_EVENTS_CNT,
>+      PRESTERA_PORT_UNDERSIZE_PKTS_CNT,
>+      PRESTERA_PORT_FRAGMENTS_PKTS_CNT,
>+      PRESTERA_PORT_OVERSIZE_PKTS_CNT,
>+      PRESTERA_PORT_JABBER_PKTS_CNT,
>+      PRESTERA_PORT_MAC_RCV_ERROR_CNT,
>+      PRESTERA_PORT_BAD_CRC_CNT,
>+      PRESTERA_PORT_COLLISIONS_CNT,
>+      PRESTERA_PORT_LATE_COLLISIONS_CNT,
>+      PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT,
>+      PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT,
>+      PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT,
>+      PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT,
>+      PRESTERA_PORT_PKTS_1024TO1518L_CNT,
>+      PRESTERA_PORT_PKTS_1519TOMAXL_CNT,
>+      PRESTERA_PORT_GOOD_OCTETS_SENT_CNT,
>+
>+      PRESTERA_PORT_CNT_MAX,
>+};
>+
>+struct prestera_fw_event_handler {
>+      struct list_head list;
>+      enum prestera_event_type type;
>+      prestera_event_cb_t func;
>+      void *arg;
>+};
>+
>+struct prestera_msg_cmd {
>+      u32 type;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_ret {
>+      struct prestera_msg_cmd cmd;
>+      u32 status;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_common_req {
>+      struct prestera_msg_cmd cmd;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_common_resp {
>+      struct prestera_msg_ret ret;
>+} __packed __aligned(4);
>+
>+union prestera_msg_switch_param {
>+      u8 mac[ETH_ALEN];
>+};
>+
>+struct prestera_msg_switch_attr_req {
>+      struct prestera_msg_cmd cmd;
>+      u32 attr;
>+      union prestera_msg_switch_param param;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_switch_init_resp {
>+      struct prestera_msg_ret ret;
>+      u32 port_count;
>+      u32 mtu_max;
>+      u8  switch_id;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_port_autoneg_param {
>+      u64 link_mode;
>+      u8  enable;
>+      u8  fec;
>+};
>+
>+struct prestera_msg_port_cap_param {
>+      u64 link_mode;
>+      u8  type;
>+      u8  fec;
>+      u8  transceiver;
>+};
>+
>+union prestera_msg_port_param {
>+      u8  admin_state;
>+      u8  oper_state;
>+      u32 mtu;
>+      u8  mac[ETH_ALEN];
>+      struct prestera_msg_port_autoneg_param autoneg;
>+      struct prestera_msg_port_cap_param cap;
>+};
>+
>+struct prestera_msg_port_attr_req {
>+      struct prestera_msg_cmd cmd;
>+      u32 attr;
>+      u32 port;
>+      u32 dev;
>+      union prestera_msg_port_param param;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_port_attr_resp {
>+      struct prestera_msg_ret ret;
>+      union prestera_msg_port_param param;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_port_stats_resp {
>+      struct prestera_msg_ret ret;
>+      u64 stats[PRESTERA_PORT_CNT_MAX];
>+} __packed __aligned(4);
>+
>+struct prestera_msg_port_info_req {
>+      struct prestera_msg_cmd cmd;
>+      u32 port;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_port_info_resp {
>+      struct prestera_msg_ret ret;
>+      u32 hw_id;
>+      u32 dev_id;
>+      u16 fp_id;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_rxtx_req {
>+      struct prestera_msg_cmd cmd;
>+      u8 use_sdma;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_rxtx_resp {
>+      struct prestera_msg_ret ret;
>+      u32 map_addr;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_rxtx_port_req {
>+      struct prestera_msg_cmd cmd;
>+      u32 port;
>+      u32 dev;
>+} __packed __aligned(4);
>+
>+struct prestera_msg_event {
>+      u16 type;
>+      u16 id;
>+} __packed __aligned(4);
>+
>+union prestera_msg_event_port_param {
>+      u32 oper_state;
>+};
>+
>+struct prestera_msg_event_port {
>+      struct prestera_msg_event id;
>+      u32 port_id;
>+      union prestera_msg_event_port_param param;
>+} __packed __aligned(4);
>+
>+static int __prestera_cmd_ret(struct prestera_switch *sw,
>+                            enum prestera_cmd_type_t type,
>+                            struct prestera_msg_cmd *cmd, size_t clen,
>+                            struct prestera_msg_ret *ret, size_t rlen,
>+                            int wait)
>+{
>+      struct prestera_device *dev = sw->dev;
>+      int err;
>+
>+      cmd->type = type;
>+
>+      err = dev->send_req(dev, (u8 *)cmd, clen, (u8 *)ret, rlen, wait);
>+      if (err)
>+              return err;
>+
>+      if (ret->cmd.type != PRESTERA_CMD_TYPE_ACK)
>+              return -EBADE;
>+      if (ret->status != PRESTERA_CMD_ACK_OK)
>+              return -EINVAL;
>+
>+      return 0;
>+}
>+
>+static int prestera_cmd_ret(struct prestera_switch *sw,
>+                          enum prestera_cmd_type_t type,
>+                          struct prestera_msg_cmd *cmd, size_t clen,
>+                          struct prestera_msg_ret *ret, size_t rlen)
>+{
>+      return __prestera_cmd_ret(sw, type, cmd, clen, ret, rlen, 0);
>+}
>+
>+static int prestera_cmd_ret_wait(struct prestera_switch *sw,
>+                               enum prestera_cmd_type_t type,
>+                               struct prestera_msg_cmd *cmd, size_t clen,
>+                               struct prestera_msg_ret *ret, size_t rlen,
>+                               int wait)
>+{
>+      return __prestera_cmd_ret(sw, type, cmd, clen, ret, rlen, wait);
>+}
>+
>+static int prestera_cmd(struct prestera_switch *sw,
>+                      enum prestera_cmd_type_t type,
>+                      struct prestera_msg_cmd *cmd, size_t clen)
>+{
>+      struct prestera_msg_common_resp resp;
>+
>+      return prestera_cmd_ret(sw, type, cmd, clen, &resp.ret, sizeof(resp));
>+}
>+
>+static int prestera_fw_parse_port_evt(u8 *msg, struct prestera_event *evt)
>+{
>+      struct prestera_msg_event_port *hw_evt;
>+
>+      hw_evt = (struct prestera_msg_event_port *)msg;
>+
>+      evt->port_evt.port_id = hw_evt->port_id;
>+
>+      if (evt->id == PRESTERA_PORT_EVENT_STATE_CHANGED)
>+              evt->port_evt.data.oper_state = hw_evt->param.oper_state;
>+      else
>+              return -EINVAL;
>+
>+      return 0;
>+}
>+
>+static struct prestera_fw_evt_parser {
>+      int (*func)(u8 *msg, struct prestera_event *evt);
>+} fw_event_parsers[PRESTERA_EVENT_TYPE_MAX] = {
>+      [PRESTERA_EVENT_TYPE_PORT] = {.func = prestera_fw_parse_port_evt},
>+};
>+
>+static struct prestera_fw_event_handler *
>+__find_event_handler(const struct prestera_switch *sw,
>+                   enum prestera_event_type type)
>+{
>+      struct prestera_fw_event_handler *eh;
>+
>+      list_for_each_entry_rcu(eh, &sw->event_handlers, list) {
>+              if (eh->type == type)
>+                      return eh;
>+      }
>+
>+      return NULL;
>+}
>+
>+static int prestera_find_event_handler(const struct prestera_switch *sw,
>+                                     enum prestera_event_type type,
>+                                     struct prestera_fw_event_handler *eh)
>+{
>+      struct prestera_fw_event_handler *tmp;
>+      int err = 0;
>+
>+      rcu_read_lock();
>+      tmp = __find_event_handler(sw, type);
>+      if (tmp)
>+              *eh = *tmp;
>+      else
>+              err = -EEXIST;
>+      rcu_read_unlock();
>+
>+      return err;
>+}
>+
>+static int prestera_evt_recv(struct prestera_device *dev, u8 *buf, size_t 
>size)
>+{
>+      struct prestera_msg_event *msg = (struct prestera_msg_event *)buf;
>+      struct prestera_switch *sw = dev->priv;
>+      struct prestera_fw_event_handler eh;
>+      struct prestera_event evt;
>+      int err;
>+
>+      if (msg->type >= PRESTERA_EVENT_TYPE_MAX)
>+              return -EINVAL;
>+
>+      err = prestera_find_event_handler(sw, msg->type, &eh);
>+
>+      if (err || !fw_event_parsers[msg->type].func)
>+              return 0;
>+
>+      evt.id = msg->id;
>+
>+      err = fw_event_parsers[msg->type].func(buf, &evt);
>+      if (!err)
>+              eh.func(sw, &evt, eh.arg);
>+
>+      return err;
>+}
>+
>+static void prestera_pkt_recv(struct prestera_device *dev)
>+{
>+      struct prestera_switch *sw = dev->priv;
>+      struct prestera_fw_event_handler eh;
>+      struct prestera_event ev;
>+      int err;
>+
>+      ev.id = PRESTERA_RXTX_EVENT_RCV_PKT;
>+
>+      err = prestera_find_event_handler(sw, PRESTERA_EVENT_TYPE_RXTX, &eh);
>+      if (err)
>+              return;
>+
>+      eh.func(sw, &ev, eh.arg);
>+}
>+
>+int prestera_hw_port_info_get(const struct prestera_port *port,
>+                            u16 *fp_id, u32 *hw_id, u32 *dev_id)
>+{
>+      struct prestera_msg_port_info_resp resp;
>+      struct prestera_msg_port_info_req req = {
>+              .port = port->id
>+      };
>+      int err;
>+
>+      err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_INFO_GET,
>+                             &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
>+      if (err)
>+              return err;
>+
>+      *hw_id = resp.hw_id;
>+      *dev_id = resp.dev_id;
>+      *fp_id = resp.fp_id;
>+
>+      return 0;
>+}
>+
>+int prestera_hw_switch_mac_set(struct prestera_switch *sw, char *mac)
>+{
>+      struct prestera_msg_switch_attr_req req = {
>+              .attr = PRESTERA_CMD_SWITCH_ATTR_MAC,
>+      };
>+
>+      memcpy(req.param.mac, mac, sizeof(req.param.mac));
>+
>+      return prestera_cmd(sw, PRESTERA_CMD_TYPE_SWITCH_ATTR_SET,
>+                          &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_switch_init(struct prestera_switch *sw)
>+{
>+      struct prestera_msg_switch_init_resp resp;
>+      struct prestera_msg_common_req req;
>+      int err;
>+
>+      INIT_LIST_HEAD(&sw->event_handlers);
>+
>+      err = prestera_cmd_ret_wait(sw, PRESTERA_CMD_TYPE_SWITCH_INIT,
>+                                  &req.cmd, sizeof(req),
>+                                  &resp.ret, sizeof(resp),
>+                                  PRESTERA_SWITCH_INIT_TIMEOUT);
>+      if (err)
>+              return err;
>+
>+      sw->id = resp.switch_id;
>+      sw->port_count = resp.port_count;
>+      sw->mtu_min = PRESTERA_MIN_MTU;
>+      sw->mtu_max = resp.mtu_max;
>+      sw->dev->recv_msg = prestera_evt_recv;
>+      sw->dev->recv_pkt = prestera_pkt_recv;
>+
>+      return 0;
>+}
>+
>+int prestera_hw_port_state_set(const struct prestera_port *port,
>+                             bool admin_state)
>+{
>+      struct prestera_msg_port_attr_req req = {
>+              .attr = PRESTERA_CMD_PORT_ATTR_ADMIN_STATE,
>+              .port = port->hw_id,
>+              .dev = port->dev_id,
>+              .param = {.admin_state = admin_state}
>+      };
>+
>+      return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
>+                          &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_port_mtu_set(const struct prestera_port *port, u32 mtu)
>+{
>+      struct prestera_msg_port_attr_req req = {
>+              .attr = PRESTERA_CMD_PORT_ATTR_MTU,
>+              .port = port->hw_id,
>+              .dev = port->dev_id,
>+              .param = {.mtu = mtu}
>+      };
>+
>+      return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
>+                          &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_port_mac_set(const struct prestera_port *port, char *mac)
>+{
>+      struct prestera_msg_port_attr_req req = {
>+              .attr = PRESTERA_CMD_PORT_ATTR_MAC,
>+              .port = port->hw_id,
>+              .dev = port->dev_id
>+      };
>+      memcpy(&req.param.mac, mac, sizeof(req.param.mac));
>+
>+      return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
>+                          &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_port_cap_get(const struct prestera_port *port,
>+                           struct prestera_port_caps *caps)
>+{
>+      struct prestera_msg_port_attr_resp resp;
>+      struct prestera_msg_port_attr_req req = {
>+              .attr = PRESTERA_CMD_PORT_ATTR_CAPABILITY,
>+              .port = port->hw_id,
>+              .dev = port->dev_id
>+      };
>+      int err;
>+
>+      err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
>+                             &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
>+      if (err)
>+              return err;
>+
>+      caps->supp_link_modes = resp.param.cap.link_mode;
>+      caps->supp_fec = resp.param.cap.fec;
>+      caps->type = resp.param.cap.type;
>+      caps->transceiver = resp.param.cap.transceiver;
>+
>+      return err;
>+}
>+
>+int prestera_hw_port_autoneg_set(const struct prestera_port *port,
>+                               bool autoneg, u64 link_modes, u8 fec)
>+{
>+      struct prestera_msg_port_attr_req req = {
>+              .attr = PRESTERA_CMD_PORT_ATTR_AUTONEG,
>+              .port = port->hw_id,
>+              .dev = port->dev_id,
>+              .param = {.autoneg = {.link_mode = link_modes,
>+                                    .enable = autoneg,
>+                                    .fec = fec}
>+              }
>+      };
>+
>+      return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
>+                          &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_port_stats_get(const struct prestera_port *port,
>+                             struct prestera_port_stats *st)
>+{
>+      struct prestera_msg_port_stats_resp resp;
>+      struct prestera_msg_port_attr_req req = {
>+              .attr = PRESTERA_CMD_PORT_ATTR_STATS,
>+              .port = port->hw_id,
>+              .dev = port->dev_id
>+      };
>+      u64 *hw = resp.stats;
>+      int err;
>+
>+      err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
>+                             &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
>+      if (err)
>+              return err;
>+
>+      st->good_octets_received = hw[PRESTERA_PORT_GOOD_OCTETS_RCV_CNT];
>+      st->bad_octets_received = hw[PRESTERA_PORT_BAD_OCTETS_RCV_CNT];
>+      st->mac_trans_error = hw[PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT];
>+      st->broadcast_frames_received = hw[PRESTERA_PORT_BRDC_PKTS_RCV_CNT];
>+      st->multicast_frames_received = hw[PRESTERA_PORT_MC_PKTS_RCV_CNT];
>+      st->frames_64_octets = hw[PRESTERA_PORT_PKTS_64L_CNT];
>+      st->frames_65_to_127_octets = hw[PRESTERA_PORT_PKTS_65TO127L_CNT];
>+      st->frames_128_to_255_octets = hw[PRESTERA_PORT_PKTS_128TO255L_CNT];
>+      st->frames_256_to_511_octets = hw[PRESTERA_PORT_PKTS_256TO511L_CNT];
>+      st->frames_512_to_1023_octets = hw[PRESTERA_PORT_PKTS_512TO1023L_CNT];
>+      st->frames_1024_to_max_octets = hw[PRESTERA_PORT_PKTS_1024TOMAXL_CNT];
>+      st->excessive_collision = hw[PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT];
>+      st->multicast_frames_sent = hw[PRESTERA_PORT_MC_PKTS_SENT_CNT];
>+      st->broadcast_frames_sent = hw[PRESTERA_PORT_BRDC_PKTS_SENT_CNT];
>+      st->fc_sent = hw[PRESTERA_PORT_FC_SENT_CNT];
>+      st->fc_received = hw[PRESTERA_PORT_GOOD_FC_RCV_CNT];
>+      st->buffer_overrun = hw[PRESTERA_PORT_DROP_EVENTS_CNT];
>+      st->undersize = hw[PRESTERA_PORT_UNDERSIZE_PKTS_CNT];
>+      st->fragments = hw[PRESTERA_PORT_FRAGMENTS_PKTS_CNT];
>+      st->oversize = hw[PRESTERA_PORT_OVERSIZE_PKTS_CNT];
>+      st->jabber = hw[PRESTERA_PORT_JABBER_PKTS_CNT];
>+      st->rx_error_frame_received = hw[PRESTERA_PORT_MAC_RCV_ERROR_CNT];
>+      st->bad_crc = hw[PRESTERA_PORT_BAD_CRC_CNT];
>+      st->collisions = hw[PRESTERA_PORT_COLLISIONS_CNT];
>+      st->late_collision = hw[PRESTERA_PORT_LATE_COLLISIONS_CNT];
>+      st->unicast_frames_received = hw[PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT];
>+      st->unicast_frames_sent = hw[PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT];
>+      st->sent_multiple = hw[PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT];
>+      st->sent_deferred = hw[PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT];
>+      st->frames_1024_to_1518_octets = hw[PRESTERA_PORT_PKTS_1024TO1518L_CNT];
>+      st->frames_1519_to_max_octets = hw[PRESTERA_PORT_PKTS_1519TOMAXL_CNT];
>+      st->good_octets_sent = hw[PRESTERA_PORT_GOOD_OCTETS_SENT_CNT];
>+
>+      return 0;
>+}
>+
>+int prestera_hw_rxtx_init(struct prestera_switch *sw,
>+                        struct prestera_rxtx_params *params)
>+{
>+      struct prestera_msg_rxtx_resp resp;
>+      struct prestera_msg_rxtx_req req;
>+      int err;
>+
>+      req.use_sdma = params->use_sdma;
>+
>+      err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_RXTX_INIT,
>+                             &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
>+      if (err)
>+              return err;
>+
>+      params->map_addr = resp.map_addr;
>+      return 0;
>+}
>+
>+int prestera_hw_rxtx_port_init(struct prestera_port *port)
>+{
>+      struct prestera_msg_rxtx_port_req req = {
>+              .port = port->hw_id,
>+              .dev = port->dev_id,
>+      };
>+
>+      return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_RXTX_PORT_INIT,
>+                          &req.cmd, sizeof(req));
>+}
>+
>+int prestera_hw_event_handler_register(struct prestera_switch *sw,
>+                                     enum prestera_event_type type,
>+                                     prestera_event_cb_t fn,
>+                                     void *arg)
>+{
>+      struct prestera_fw_event_handler *eh;
>+
>+      eh = __find_event_handler(sw, type);
>+      if (eh)
>+              return -EEXIST;
>+      eh = kmalloc(sizeof(*eh), GFP_KERNEL);
>+      if (!eh)
>+              return -ENOMEM;
>+
>+      eh->type = type;
>+      eh->func = fn;
>+      eh->arg = arg;
>+
>+      INIT_LIST_HEAD(&eh->list);
>+
>+      list_add_rcu(&eh->list, &sw->event_handlers);
>+
>+      return 0;
>+}
>+
>+void prestera_hw_event_handler_unregister(struct prestera_switch *sw,
>+                                        enum prestera_event_type type,
>+                                        prestera_event_cb_t fn)
>+{
>+      struct prestera_fw_event_handler *eh;
>+
>+      eh = __find_event_handler(sw, type);
>+      if (!eh)
>+              return;
>+
>+      list_del_rcu(&eh->list);
>+      synchronize_rcu();
>+      kfree(eh);
>+}
>diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.h 
>b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
>new file mode 100644
>index 000000000000..acb0e31d6684
>--- /dev/null
>+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
>@@ -0,0 +1,71 @@
>+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
>+ *
>+ * Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved.
>+ *
>+ */
>+
>+#ifndef _PRESTERA_HW_H_
>+#define _PRESTERA_HW_H_
>+
>+#include <linux/types.h>
>+
>+enum {
>+      PRESTERA_PORT_TYPE_NONE,
>+      PRESTERA_PORT_TYPE_TP,
>+
>+      PRESTERA_PORT_TYPE_MAX,
>+};
>+
>+enum {
>+      PRESTERA_PORT_FEC_OFF,
>+
>+      PRESTERA_PORT_FEC_MAX,
>+};
>+
>+struct prestera_switch;
>+struct prestera_port;
>+struct prestera_port_stats;
>+struct prestera_port_caps;
>+enum prestera_event_type;
>+struct prestera_event;
>+
>+typedef void (*prestera_event_cb_t)
>+      (struct prestera_switch *sw, struct prestera_event *evt, void *arg);
>+
>+struct prestera_rxtx_params;
>+
>+/* Switch API */
>+int prestera_hw_switch_init(struct prestera_switch *sw);
>+int prestera_hw_switch_mac_set(struct prestera_switch *sw, char *mac);
>+
>+/* Port API */
>+int prestera_hw_port_info_get(const struct prestera_port *port,
>+                            u16 *fp_id, u32 *hw_id, u32 *dev_id);
>+int prestera_hw_port_state_set(const struct prestera_port *port,
>+                             bool admin_state);
>+int prestera_hw_port_mtu_set(const struct prestera_port *port, u32 mtu);
>+int prestera_hw_port_mtu_get(const struct prestera_port *port, u32 *mtu);
>+int prestera_hw_port_mac_set(const struct prestera_port *port, char *mac);
>+int prestera_hw_port_mac_get(const struct prestera_port *port, char *mac);
>+int prestera_hw_port_cap_get(const struct prestera_port *port,
>+                           struct prestera_port_caps *caps);
>+int prestera_hw_port_autoneg_set(const struct prestera_port *port,
>+                               bool autoneg, u64 link_modes, u8 fec);
>+int prestera_hw_port_stats_get(const struct prestera_port *port,
>+                             struct prestera_port_stats *stats);
>+
>+/* Event handlers */
>+int prestera_hw_event_handler_register(struct prestera_switch *sw,
>+                                     enum prestera_event_type type,
>+                                     prestera_event_cb_t fn,
>+                                     void *arg);
>+void prestera_hw_event_handler_unregister(struct prestera_switch *sw,
>+                                        enum prestera_event_type type,
>+                                        prestera_event_cb_t fn);
>+
>+/* RX/TX */
>+int prestera_hw_rxtx_init(struct prestera_switch *sw,
>+                        struct prestera_rxtx_params *params);
>+int prestera_hw_rxtx_port_init(struct prestera_port *port);
>+
>+#endif /* _PRESTERA_HW_H_ */
>diff --git a/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c 
>b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
>new file mode 100644
>index 000000000000..556941d97d4d
>--- /dev/null
>+++ b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.c
>@@ -0,0 +1,825 @@
>+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
>+/* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */
>+
>+#include <linux/platform_device.h>
>+#include <linux/of.h>
>+#include <linux/of_address.h>
>+#include <linux/of_device.h>
>+#include <linux/dmapool.h>
>+#include <linux/netdevice.h>
>+#include <linux/etherdevice.h>
>+#include <linux/if_vlan.h>
>+
>+#include "prestera.h"
>+#include "prestera_hw.h"
>+#include "prestera_dsa.h"
>+
>+struct prestera_sdma_desc {
>+      __le32 word1;
>+      __le32 word2;
>+      __le32 buff;
>+      __le32 next;
>+} __packed __aligned(16);
>+
>+#define SDMA_BUFF_SIZE_MAX    1544
>+
>+#define SDMA_RX_DESC_PKT_LEN(desc) \
>+      ((le32_to_cpu((desc)->word2) >> 16) & 0x3FFF)
>+
>+#define SDMA_RX_DESC_OWNER(desc) \
>+      ((le32_to_cpu((desc)->word1) & BIT(31)) >> 31)
>+
>+#define SDMA_RX_DESC_CPU_OWN  0
>+#define SDMA_RX_DESC_DMA_OWN  1
>+
>+#define SDMA_RX_QUEUE_NUM     8
>+
>+#define SDMA_RX_DESC_PER_Q    1000
>+
>+#define SDMA_TX_DESC_PER_Q    1000
>+#define SDMA_TX_MAX_BURST     64
>+
>+#define SDMA_TX_DESC_OWNER(desc) \
>+      ((le32_to_cpu((desc)->word1) & BIT(31)) >> 31)
>+
>+#define SDMA_TX_DESC_CPU_OWN  0
>+#define SDMA_TX_DESC_DMA_OWN  1
>+
>+#define SDMA_TX_DESC_IS_SENT(desc) \
>+      (SDMA_TX_DESC_OWNER(desc) == SDMA_TX_DESC_CPU_OWN)
>+
>+#define SDMA_TX_DESC_LAST     BIT(20)
>+#define SDMA_TX_DESC_FIRST    BIT(21)
>+#define SDMA_TX_DESC_SINGLE   (SDMA_TX_DESC_FIRST | SDMA_TX_DESC_LAST)
>+#define SDMA_TX_DESC_CALC_CRC BIT(12)
>+
>+#define SDMA_RX_INTR_MASK_REG         0x2814
>+#define SDMA_RX_QUEUE_STATUS_REG      0x2680
>+#define SDMA_RX_QUEUE_DESC_REG(n)     (0x260C + (n) * 16)
>+
>+#define SDMA_TX_QUEUE_DESC_REG                0x26C0
>+#define SDMA_TX_QUEUE_START_REG               0x2868

You forgot to prefix these.


>+
>+struct prestera_sdma_buf {
>+      struct prestera_sdma_desc *desc;
>+      dma_addr_t desc_dma;
>+      struct sk_buff *skb;
>+      dma_addr_t buf_dma;
>+      bool is_used;
>+};
>+
>+struct prestera_rx_ring {
>+      struct prestera_sdma_buf *bufs;
>+      int next_rx;
>+};
>+
>+struct prestera_tx_ring {
>+      struct prestera_sdma_buf *bufs;
>+      int next_tx;
>+      int max_burst;
>+      int burst;
>+};
>+
>+struct prestera_sdma {
>+      struct prestera_rx_ring rx_ring[SDMA_RX_QUEUE_NUM];
>+      struct prestera_tx_ring tx_ring;
>+      const struct prestera_switch *sw;
>+      struct dma_pool *desc_pool;
>+      struct work_struct tx_work;
>+      struct napi_struct rx_napi;
>+      struct net_device napi_dev;
>+      u32 map_addr;
>+      u64 dma_mask;
>+};
>+
>+struct prestera_rxtx {
>+      struct prestera_sdma sdma;
>+};
>+
>+static int prestera_sdma_buf_init(struct prestera_sdma *sdma,
>+                                struct prestera_sdma_buf *buf)
>+{
>+      struct device *dma_dev = sdma->sw->dev->dev;
>+      struct prestera_sdma_desc *desc;
>+      dma_addr_t dma;
>+
>+      desc = dma_pool_alloc(sdma->desc_pool, GFP_DMA | GFP_KERNEL, &dma);
>+      if (!desc)
>+              return -ENOMEM;
>+
>+      if (dma + sizeof(struct prestera_sdma_desc) > sdma->dma_mask) {
>+              dev_err(dma_dev, "failed to alloc desc\n");
>+              dma_pool_free(sdma->desc_pool, desc, dma);
>+              return -ENOMEM;
>+      }
>+
>+      buf->buf_dma = DMA_MAPPING_ERROR;
>+      buf->desc_dma = dma;
>+      buf->desc = desc;
>+      buf->skb = NULL;
>+
>+      return 0;
>+}
>+
>+static u32 prestera_sdma_map(struct prestera_sdma *sdma, dma_addr_t pa)
>+{
>+      return sdma->map_addr + pa;
>+}
>+
>+static void prestera_sdma_rx_desc_set_len(struct prestera_sdma_desc *desc,
>+                                        size_t val)
>+{
>+      u32 word = le32_to_cpu(desc->word2);
>+
>+      word = (word & ~GENMASK(15, 0)) | val;
>+      desc->word2 = cpu_to_le32(word);
>+}
>+
>+static void prestera_sdma_rx_desc_init(struct prestera_sdma *sdma,
>+                                     struct prestera_sdma_desc *desc,
>+                                     dma_addr_t buf)
>+{
>+      prestera_sdma_rx_desc_set_len(desc, SDMA_BUFF_SIZE_MAX);
>+      desc->buff = cpu_to_le32(prestera_sdma_map(sdma, buf));
>+
>+      /* make sure buffer is set before reset the descriptor */
>+      wmb();
>+
>+      desc->word1 = cpu_to_le32(0xA0000000);
>+}
>+
>+static void prestera_sdma_rx_desc_set_next(struct prestera_sdma *sdma,
>+                                         struct prestera_sdma_desc *desc,
>+                                         dma_addr_t next)
>+{
>+      desc->next = cpu_to_le32(prestera_sdma_map(sdma, next));
>+}
>+
>+static int prestera_sdma_rx_skb_alloc(struct prestera_sdma *sdma,
>+                                    struct prestera_sdma_buf *buf)
>+{
>+      struct device *dev = sdma->sw->dev->dev;
>+      struct sk_buff *skb;
>+      dma_addr_t dma;
>+
>+      skb = alloc_skb(SDMA_BUFF_SIZE_MAX, GFP_DMA | GFP_ATOMIC);
>+      if (!skb)
>+              return -ENOMEM;
>+
>+      dma = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE);
>+
>+      if (dma_mapping_error(dev, dma))
>+              goto err_dma_map;
>+      if (dma + skb->len > sdma->dma_mask)
>+              goto err_dma_range;
>+
>+      if (buf->skb)
>+              dma_unmap_single(dev, buf->buf_dma, buf->skb->len,
>+                               DMA_FROM_DEVICE);
>+
>+      buf->buf_dma = dma;
>+      buf->skb = skb;
>+      return 0;
>+
>+err_dma_range:
>+      dma_unmap_single(dev, dma, skb->len, DMA_FROM_DEVICE);
>+err_dma_map:
>+      kfree_skb(skb);
>+
>+      return -ENOMEM;
>+}
>+
>+static struct sk_buff *prestera_sdma_rx_skb_get(struct prestera_sdma *sdma,
>+                                              struct prestera_sdma_buf *buf)
>+{
>+      dma_addr_t buf_dma = buf->buf_dma;
>+      struct sk_buff *skb = buf->skb;
>+      u32 len = skb->len;
>+      int err;
>+
>+      err = prestera_sdma_rx_skb_alloc(sdma, buf);
>+      if (err) {
>+              buf->buf_dma = buf_dma;
>+              buf->skb = skb;
>+
>+              skb = alloc_skb(skb->len, GFP_ATOMIC);
>+              if (skb) {
>+                      skb_put(skb, len);
>+                      skb_copy_from_linear_data(buf->skb, skb->data, len);
>+              }
>+      }
>+
>+      prestera_sdma_rx_desc_init(sdma, buf->desc, buf->buf_dma);
>+
>+      return skb;
>+}
>+
>+static int prestera_rxtx_process_skb(struct sk_buff *skb)
>+{
>+      const struct prestera_port *port;
>+      struct prestera_dsa dsa;
>+      u32 hw_port, hw_id;
>+      int err;
>+
>+      skb_pull(skb, ETH_HLEN);
>+
>+      /* ethertype field is part of the dsa header */
>+      err = prestera_dsa_parse(&dsa, skb->data - ETH_TLEN);
>+      if (err)
>+              return err;
>+
>+      hw_port = dsa.port_num;
>+      hw_id = dsa.hw_dev_num;
>+
>+      port = prestera_port_find_by_hwid(hw_id, hw_port);
>+      if (unlikely(!port)) {
>+              pr_warn_ratelimited("prestera: received pkt for non-existent 
>port(%u, %u)\n",
>+                                  hw_id, hw_port);
>+              return -EEXIST;
>+      }
>+
>+      if (unlikely(!pskb_may_pull(skb, PRESTERA_DSA_HLEN)))
>+              return -EINVAL;
>+
>+      /* remove DSA tag and update checksum */
>+      skb_pull_rcsum(skb, PRESTERA_DSA_HLEN);
>+
>+      memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - PRESTERA_DSA_HLEN,
>+              ETH_ALEN * 2);
>+
>+      skb_push(skb, ETH_HLEN);
>+
>+      skb->protocol = eth_type_trans(skb, port->dev);
>+
>+      if (dsa.vlan.is_tagged) {
>+              u16 tci = dsa.vlan.vid & VLAN_VID_MASK;
>+
>+              tci |= dsa.vlan.vpt << VLAN_PRIO_SHIFT;
>+              if (dsa.vlan.cfi_bit)
>+                      tci |= VLAN_CFI_MASK;
>+
>+              __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tci);
>+      }
>+
>+      return 0;
>+}
>+
>+static int prestera_sdma_rx_poll(struct napi_struct *napi, int budget)
>+{
>+      unsigned int qmask = GENMASK(SDMA_RX_QUEUE_NUM - 1, 0);
>+      struct prestera_sdma *sdma;
>+      unsigned int rxq_done_map = 0;
>+      struct list_head rx_list;
>+      int pkts_done = 0;
>+      int q;
>+
>+      INIT_LIST_HEAD(&rx_list);
>+
>+      sdma = container_of(napi, struct prestera_sdma, rx_napi);
>+
>+      while (pkts_done < budget && rxq_done_map != qmask) {
>+              for (q = 0; q < SDMA_RX_QUEUE_NUM && pkts_done < budget; q++) {
>+                      struct prestera_rx_ring *ring = &sdma->rx_ring[q];
>+                      int buf_idx = ring->next_rx;
>+                      struct prestera_sdma_desc *desc;
>+                      struct prestera_sdma_buf *buf;
>+                      struct sk_buff *skb;
>+
>+                      buf = &ring->bufs[buf_idx];
>+                      desc = buf->desc;
>+
>+                      if (SDMA_RX_DESC_OWNER(desc) != SDMA_RX_DESC_CPU_OWN) {
>+                              rxq_done_map |= BIT(q);
>+                              continue;
>+                      } else {
>+                              rxq_done_map &= ~BIT(q);
>+                      }
>+
>+                      pkts_done++;
>+
>+                      __skb_trim(buf->skb, SDMA_RX_DESC_PKT_LEN(desc));
>+
>+                      skb = prestera_sdma_rx_skb_get(sdma, buf);
>+                      if (!skb)
>+                              goto rx_next_buf;
>+
>+                      if (unlikely(prestera_rxtx_process_skb(skb)))
>+                              goto rx_next_buf;
>+
>+                      list_add_tail(&skb->list, &rx_list);
>+rx_next_buf:
>+                      ring->next_rx = (buf_idx + 1) % SDMA_RX_DESC_PER_Q;
>+              }
>+      }
>+
>+      if (pkts_done < budget && napi_complete_done(napi, pkts_done))
>+              prestera_write(sdma->sw, SDMA_RX_INTR_MASK_REG, 0xff << 2);
>+
>+      netif_receive_skb_list(&rx_list);
>+
>+      return pkts_done;
>+}
>+
>+static void prestera_sdma_rx_fini(struct prestera_sdma *sdma)
>+{
>+      int q, b;
>+
>+      /* disable all rx queues */
>+      prestera_write(sdma->sw, SDMA_RX_QUEUE_STATUS_REG, 0xff00);
>+
>+      for (q = 0; q < SDMA_RX_QUEUE_NUM; q++) {
>+              struct prestera_rx_ring *ring = &sdma->rx_ring[q];
>+
>+              if (!ring->bufs)
>+                      break;
>+
>+              for (b = 0; b < SDMA_RX_DESC_PER_Q; b++) {
>+                      struct prestera_sdma_buf *buf = &ring->bufs[b];
>+
>+                      if (buf->desc_dma)
>+                              dma_pool_free(sdma->desc_pool, buf->desc,
>+                                            buf->desc_dma);
>+
>+                      if (!buf->skb)
>+                              continue;
>+
>+                      if (buf->buf_dma != DMA_MAPPING_ERROR)
>+                              dma_unmap_single(sdma->sw->dev->dev,
>+                                               buf->buf_dma, buf->skb->len,
>+                                               DMA_FROM_DEVICE);
>+                      kfree_skb(buf->skb);
>+              }
>+      }
>+}
>+
>+static int prestera_sdma_rx_init(struct prestera_sdma *sdma)
>+{
>+      int q, b;
>+      int err;
>+
>+      /* disable all rx queues */
>+      prestera_write(sdma->sw, SDMA_RX_QUEUE_STATUS_REG, 0xff00);
>+
>+      for (q = 0; q < SDMA_RX_QUEUE_NUM; q++) {
>+              struct prestera_rx_ring *ring = &sdma->rx_ring[q];
>+              struct prestera_sdma_buf *head;
>+
>+              ring->bufs = kmalloc_array(SDMA_RX_DESC_PER_Q, sizeof(*head),
>+                                         GFP_KERNEL);
>+              if (!ring->bufs)
>+                      return -ENOMEM;
>+
>+              head = &ring->bufs[0];
>+              ring->next_rx = 0;
>+
>+              for (b = 0; b < SDMA_RX_DESC_PER_Q; b++) {
>+                      struct prestera_sdma_buf *buf = &ring->bufs[b];
>+
>+                      err = prestera_sdma_buf_init(sdma, buf);
>+                      if (err)
>+                              return err;
>+
>+                      err = prestera_sdma_rx_skb_alloc(sdma, buf);
>+                      if (err)
>+                              return err;
>+
>+                      prestera_sdma_rx_desc_init(sdma, buf->desc,
>+                                                 buf->buf_dma);
>+
>+                      if (b == 0)
>+                              continue;
>+
>+                      prestera_sdma_rx_desc_set_next(sdma,
>+                                                     ring->bufs[b - 1].desc,
>+                                                     buf->desc_dma);
>+
>+                      if (b == SDMA_RX_DESC_PER_Q - 1)
>+                              prestera_sdma_rx_desc_set_next(sdma, buf->desc,
>+                                                             head->desc_dma);
>+              }
>+
>+              prestera_write(sdma->sw, SDMA_RX_QUEUE_DESC_REG(q),
>+                             prestera_sdma_map(sdma, head->desc_dma));
>+      }
>+
>+      /* make sure all rx descs are filled before enabling all rx queues */
>+      wmb();
>+
>+      prestera_write(sdma->sw, SDMA_RX_QUEUE_STATUS_REG, 0xff);
>+
>+      return 0;
>+}
>+
>+static void prestera_sdma_tx_desc_init(struct prestera_sdma *sdma,
>+                                     struct prestera_sdma_desc *desc)
>+{
>+      desc->word1 = cpu_to_le32(SDMA_TX_DESC_SINGLE | SDMA_TX_DESC_CALC_CRC);
>+      desc->word2 = 0;
>+}
>+
>+static void prestera_sdma_tx_desc_set_next(struct prestera_sdma *sdma,
>+                                         struct prestera_sdma_desc *desc,
>+                                         dma_addr_t next)
>+{
>+      desc->next = cpu_to_le32(prestera_sdma_map(sdma, next));
>+}
>+
>+static void prestera_sdma_tx_desc_set_buf(struct prestera_sdma *sdma,
>+                                        struct prestera_sdma_desc *desc,
>+                                        dma_addr_t buf, size_t len)
>+{
>+      u32 word = le32_to_cpu(desc->word2);
>+
>+      word = (word & ~GENMASK(30, 16)) | ((len + ETH_FCS_LEN) << 16);
>+
>+      desc->buff = cpu_to_le32(prestera_sdma_map(sdma, buf));
>+      desc->word2 = cpu_to_le32(word);
>+}
>+
>+static void prestera_sdma_tx_desc_xmit(struct prestera_sdma_desc *desc)
>+{
>+      u32 word = le32_to_cpu(desc->word1);
>+
>+      word |= (SDMA_TX_DESC_DMA_OWN << 31);

Drop the ()s here.


>+
>+      /* make sure everything is written before enable xmit */
>+      wmb();
>+
>+      desc->word1 = cpu_to_le32(word);
>+}
>+
>+static int prestera_sdma_tx_buf_map(struct prestera_sdma *sdma,
>+                                  struct prestera_sdma_buf *buf,
>+                                  struct sk_buff *skb)
>+{
>+      struct device *dma_dev = sdma->sw->dev->dev;
>+      struct sk_buff *new_skb;
>+      size_t len = skb->len;
>+      dma_addr_t dma;
>+
>+      dma = dma_map_single(dma_dev, skb->data, len, DMA_TO_DEVICE);
>+      if (!dma_mapping_error(dma_dev, dma) && dma + len <= sdma->dma_mask) {
>+              buf->buf_dma = dma;
>+              buf->skb = skb;
>+              return 0;
>+      }
>+
>+      if (!dma_mapping_error(dma_dev, dma))
>+              dma_unmap_single(dma_dev, dma, len, DMA_TO_DEVICE);
>+
>+      new_skb = alloc_skb(len, GFP_ATOMIC | GFP_DMA);
>+      if (!new_skb)
>+              goto err_alloc_skb;
>+
>+      dma = dma_map_single(dma_dev, new_skb->data, len, DMA_TO_DEVICE);
>+      if (dma_mapping_error(dma_dev, dma))
>+              goto err_dma_map;
>+      if (dma + len > sdma->dma_mask)
>+              goto err_dma_range;
>+
>+      skb_copy_from_linear_data(skb, skb_put(new_skb, len), len);
>+
>+      dev_consume_skb_any(skb);
>+
>+      buf->skb = new_skb;
>+      buf->buf_dma = dma;
>+
>+      return 0;
>+
>+err_dma_range:
>+      dma_unmap_single(dma_dev, dma, len, DMA_TO_DEVICE);
>+err_dma_map:
>+      dev_kfree_skb(new_skb);
>+err_alloc_skb:
>+      dev_kfree_skb(skb);
>+
>+      return -ENOMEM;
>+}
>+
>+static void prestera_sdma_tx_buf_unmap(struct prestera_sdma *sdma,
>+                                     struct prestera_sdma_buf *buf)
>+{
>+      struct device *dma_dev = sdma->sw->dev->dev;
>+
>+      dma_unmap_single(dma_dev, buf->buf_dma, buf->skb->len, DMA_TO_DEVICE);
>+}
>+
>+static void prestera_sdma_tx_recycle_work_fn(struct work_struct *work)
>+{
>+      struct prestera_tx_ring *tx_ring;
>+      struct prestera_sdma *sdma;
>+      struct device *dma_dev;
>+      int b;
>+
>+      sdma = container_of(work, struct prestera_sdma, tx_work);
>+
>+      dma_dev = sdma->sw->dev->dev;
>+      tx_ring = &sdma->tx_ring;
>+
>+      for (b = 0; b < SDMA_TX_DESC_PER_Q; b++) {
>+              struct prestera_sdma_buf *buf = &tx_ring->bufs[b];
>+
>+              if (!buf->is_used)
>+                      continue;
>+
>+              if (!SDMA_TX_DESC_IS_SENT(buf->desc))
>+                      continue;
>+
>+              prestera_sdma_tx_buf_unmap(sdma, buf);
>+              dev_consume_skb_any(buf->skb);
>+              buf->skb = NULL;
>+
>+              /* make sure everything is cleaned up */
>+              wmb();
>+
>+              buf->is_used = false;
>+      }
>+}
>+
>+static int prestera_sdma_tx_init(struct prestera_sdma *sdma)
>+{
>+      struct prestera_tx_ring *tx_ring = &sdma->tx_ring;
>+      struct prestera_sdma_buf *head;
>+      int err;
>+      int b;
>+
>+      INIT_WORK(&sdma->tx_work, prestera_sdma_tx_recycle_work_fn);
>+
>+      tx_ring->bufs = kmalloc_array(SDMA_TX_DESC_PER_Q, sizeof(*head),
>+                                    GFP_KERNEL);
>+      if (!tx_ring->bufs)
>+              return -ENOMEM;
>+
>+      head = &tx_ring->bufs[0];
>+
>+      tx_ring->max_burst = SDMA_TX_MAX_BURST;
>+      tx_ring->burst = tx_ring->max_burst;
>+      tx_ring->next_tx = 0;
>+
>+      for (b = 0; b < SDMA_TX_DESC_PER_Q; b++) {
>+              struct prestera_sdma_buf *buf = &tx_ring->bufs[b];
>+
>+              err = prestera_sdma_buf_init(sdma, buf);
>+              if (err)
>+                      return err;
>+
>+              prestera_sdma_tx_desc_init(sdma, buf->desc);
>+
>+              buf->is_used = false;
>+
>+              if (b == 0)
>+                      continue;
>+
>+              prestera_sdma_tx_desc_set_next(sdma, tx_ring->bufs[b - 1].desc,
>+                                             buf->desc_dma);
>+
>+              if (b == SDMA_TX_DESC_PER_Q - 1)
>+                      prestera_sdma_tx_desc_set_next(sdma, buf->desc,
>+                                                     head->desc_dma);
>+      }
>+
>+      /* make sure descriptors are written */
>+      wmb();
>+
>+      prestera_write(sdma->sw, SDMA_TX_QUEUE_DESC_REG,
>+                     prestera_sdma_map(sdma, head->desc_dma));
>+
>+      return 0;
>+}
>+
>+static void prestera_sdma_tx_fini(struct prestera_sdma *sdma)
>+{
>+      struct prestera_tx_ring *ring = &sdma->tx_ring;
>+      int b;
>+
>+      cancel_work_sync(&sdma->tx_work);
>+
>+      if (!ring->bufs)
>+              return;
>+
>+      for (b = 0; b < SDMA_TX_DESC_PER_Q; b++) {
>+              struct prestera_sdma_buf *buf = &ring->bufs[b];
>+
>+              if (buf->desc)
>+                      dma_pool_free(sdma->desc_pool, buf->desc,
>+                                    buf->desc_dma);
>+
>+              if (!buf->skb)
>+                      continue;
>+
>+              dma_unmap_single(sdma->sw->dev->dev, buf->buf_dma,
>+                               buf->skb->len, DMA_TO_DEVICE);
>+
>+              dev_consume_skb_any(buf->skb);
>+      }
>+}
>+
>+static void prestera_rxtx_handle_event(struct prestera_switch *sw,
>+                                     struct prestera_event *evt,
>+                                     void *arg)
>+{
>+      struct prestera_sdma *sdma = arg;
>+
>+      if (evt->id != PRESTERA_RXTX_EVENT_RCV_PKT)
>+              return;
>+
>+      prestera_write(sdma->sw, SDMA_RX_INTR_MASK_REG, 0);
>+      napi_schedule(&sdma->rx_napi);
>+}
>+
>+int prestera_sdma_switch_init(struct prestera_switch *sw)
>+{
>+      struct prestera_sdma *sdma = &sw->rxtx->sdma;
>+      struct device *dev = sw->dev->dev;
>+      struct prestera_rxtx_params p;
>+      int err;
>+
>+      p.use_sdma = true;
>+
>+      err = prestera_hw_rxtx_init(sw, &p);
>+      if (err) {
>+              dev_err(dev, "failed to init rxtx by hw\n");
>+              return err;
>+      }
>+
>+      sdma->dma_mask = dma_get_mask(dev);
>+      sdma->map_addr = p.map_addr;
>+      sdma->sw = sw;
>+
>+      sdma->desc_pool = dma_pool_create("desc_pool", dev,
>+                                        sizeof(struct prestera_sdma_desc),
>+                                        16, 0);
>+      if (!sdma->desc_pool)
>+              return -ENOMEM;
>+
>+      err = prestera_sdma_rx_init(sdma);
>+      if (err) {
>+              dev_err(dev, "failed to init rx ring\n");
>+              goto err_rx_init;
>+      }
>+
>+      err = prestera_sdma_tx_init(sdma);
>+      if (err) {
>+              dev_err(dev, "failed to init tx ring\n");
>+              goto err_tx_init;
>+      }
>+
>+      err = prestera_hw_event_handler_register(sw, PRESTERA_EVENT_TYPE_RXTX,
>+                                               prestera_rxtx_handle_event,
>+                                               sdma);
>+      if (err)
>+              goto err_evt_register;
>+
>+      init_dummy_netdev(&sdma->napi_dev);
>+
>+      netif_napi_add(&sdma->napi_dev, &sdma->rx_napi, prestera_sdma_rx_poll, 
>64);
>+      napi_enable(&sdma->rx_napi);
>+
>+      return 0;
>+
>+err_evt_register:
>+err_tx_init:
>+      prestera_sdma_tx_fini(sdma);
>+err_rx_init:
>+      prestera_sdma_rx_fini(sdma);
>+
>+      dma_pool_destroy(sdma->desc_pool);
>+      return err;
>+}
>+
>+void prestera_sdma_switch_fini(struct prestera_switch *sw)
>+{
>+      struct prestera_sdma *sdma = &sw->rxtx->sdma;
>+
>+      prestera_hw_event_handler_unregister(sw, PRESTERA_EVENT_TYPE_RXTX,
>+                                           prestera_rxtx_handle_event);
>+      napi_disable(&sdma->rx_napi);
>+      netif_napi_del(&sdma->rx_napi);
>+      prestera_sdma_rx_fini(sdma);
>+      prestera_sdma_tx_fini(sdma);
>+      dma_pool_destroy(sdma->desc_pool);
>+}
>+
>+static int prestera_sdma_tx_wait(struct prestera_sdma *sdma,
>+                               struct prestera_tx_ring *tx_ring)
>+{
>+      int tx_retry_num = 10 * tx_ring->max_burst;
>+
>+      while (--tx_retry_num) {
>+              if (!(prestera_read(sdma->sw, SDMA_TX_QUEUE_START_REG) & 1))
>+                      return 0;
>+
>+              udelay(1);
>+      }
>+
>+      return -EBUSY;
>+}
>+
>+static void prestera_sdma_tx_start(struct prestera_sdma *sdma)
>+{
>+      prestera_write(sdma->sw, SDMA_TX_QUEUE_START_REG, 1);
>+      schedule_work(&sdma->tx_work);
>+}
>+
>+netdev_tx_t prestera_sdma_xmit(struct prestera_sdma *sdma, struct sk_buff 
>*skb)
>+{
>+      struct device *dma_dev = sdma->sw->dev->dev;
>+      struct prestera_tx_ring *tx_ring;
>+      struct net_device *dev = skb->dev;
>+      struct prestera_sdma_buf *buf;
>+      int err;
>+
>+      tx_ring = &sdma->tx_ring;
>+
>+      buf = &tx_ring->bufs[tx_ring->next_tx];
>+      if (buf->is_used) {
>+              schedule_work(&sdma->tx_work);
>+              goto drop_skb;
>+      }

What is preventing 2 CPUs to get here and work with the same buf?



>+
>+      if (unlikely(eth_skb_pad(skb)))
>+              goto drop_skb_nofree;
>+
>+      err = prestera_sdma_tx_buf_map(sdma, buf, skb);
>+      if (err)
>+              goto drop_skb;
>+
>+      prestera_sdma_tx_desc_set_buf(sdma, buf->desc, buf->buf_dma, skb->len);
>+
>+      dma_sync_single_for_device(dma_dev, buf->buf_dma, skb->len,
>+                                 DMA_TO_DEVICE);
>+
>+      if (!tx_ring->burst--) {
>+              tx_ring->burst = tx_ring->max_burst;
>+
>+              err = prestera_sdma_tx_wait(sdma, tx_ring);
>+              if (err)
>+                      goto drop_skb_unmap;
>+      }
>+
>+      tx_ring->next_tx = (tx_ring->next_tx + 1) % SDMA_TX_DESC_PER_Q;
>+      prestera_sdma_tx_desc_xmit(buf->desc);
>+      buf->is_used = true;
>+
>+      prestera_sdma_tx_start(sdma);
>+
>+      return NETDEV_TX_OK;
>+
>+drop_skb_unmap:
>+      prestera_sdma_tx_buf_unmap(sdma, buf);
>+drop_skb:
>+      dev_consume_skb_any(skb);
>+drop_skb_nofree:
>+      dev->stats.tx_dropped++;
>+      return NETDEV_TX_OK;
>+}
>+
>+int prestera_rxtx_switch_init(struct prestera_switch *sw)
>+{
>+      struct prestera_rxtx *rxtx;
>+
>+      rxtx = kzalloc(sizeof(*rxtx), GFP_KERNEL);
>+      if (!rxtx)
>+              return -ENOMEM;
>+
>+      sw->rxtx = rxtx;
>+
>+      return prestera_sdma_switch_init(sw);
>+}
>+
>+void prestera_rxtx_switch_fini(struct prestera_switch *sw)
>+{
>+      prestera_sdma_switch_fini(sw);
>+      kfree(sw->rxtx);
>+}
>+
>+int prestera_rxtx_port_init(struct prestera_port *port)
>+{
>+      int err;
>+
>+      err = prestera_hw_rxtx_port_init(port);
>+      if (err)
>+              return err;
>+
>+      port->dev->needed_headroom = PRESTERA_DSA_HLEN + ETH_FCS_LEN;
>+      return 0;
>+}
>+
>+netdev_tx_t prestera_rxtx_xmit(struct prestera_port *port, struct sk_buff 
>*skb)

Why this has "rx" in the name??


>+{
>+      struct prestera_dsa dsa;
>+
>+      dsa.hw_dev_num = port->dev_id;
>+      dsa.port_num = port->hw_id;
>+
>+      if (skb_cow_head(skb, PRESTERA_DSA_HLEN) < 0)
>+              return NET_XMIT_DROP;
>+
>+      skb_push(skb, PRESTERA_DSA_HLEN);
>+      memmove(skb->data, skb->data + PRESTERA_DSA_HLEN, 2 * ETH_ALEN);
>+
>+      if (prestera_dsa_build(&dsa, skb->data + 2 * ETH_ALEN) != 0)
>+              return NET_XMIT_DROP;
>+
>+      return prestera_sdma_xmit(&port->sw->rxtx->sdma, skb);
>+}
>diff --git a/drivers/net/ethernet/marvell/prestera/prestera_rxtx.h 
>b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.h
>new file mode 100644
>index 000000000000..bbbadfa5accf
>--- /dev/null
>+++ b/drivers/net/ethernet/marvell/prestera/prestera_rxtx.h
>@@ -0,0 +1,21 @@
>+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
>+ *
>+ * Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved.
>+ *
>+ */
>+
>+#ifndef _PRESTERA_RXTX_H_
>+#define _PRESTERA_RXTX_H_
>+
>+#include <linux/netdevice.h>
>+
>+#include "prestera.h"
>+
>+int prestera_rxtx_switch_init(struct prestera_switch *sw);
>+void prestera_rxtx_switch_fini(struct prestera_switch *sw);
>+
>+int prestera_rxtx_port_init(struct prestera_port *port);
>+
>+netdev_tx_t prestera_rxtx_xmit(struct prestera_port *port, struct sk_buff 
>*skb);
>+
>+#endif /* _PRESTERA_RXTX_H_ */
>-- 
>2.17.1
>

Reply via email to