linux/drivers/net/ethernet/mscc/ocelot_mrp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2/* Microsemi Ocelot Switch driver
   3 *
   4 * This contains glue logic between the switchdev driver operations and the
   5 * mscc_ocelot_switch_lib.
   6 *
   7 * Copyright (c) 2017, 2019 Microsemi Corporation
   8 * Copyright 2020-2021 NXP Semiconductors
   9 */
  10
  11#include <linux/if_bridge.h>
  12#include <linux/mrp_bridge.h>
  13#include <soc/mscc/ocelot_vcap.h>
  14#include <uapi/linux/mrp_bridge.h>
  15#include "ocelot.h"
  16#include "ocelot_vcap.h"
  17
  18static int ocelot_mrp_del_vcap(struct ocelot *ocelot, int port)
  19{
  20        struct ocelot_vcap_block *block_vcap_is2;
  21        struct ocelot_vcap_filter *filter;
  22
  23        block_vcap_is2 = &ocelot->block[VCAP_IS2];
  24        filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, port,
  25                                                     false);
  26        if (!filter)
  27                return 0;
  28
  29        return ocelot_vcap_filter_del(ocelot, filter);
  30}
  31
  32int ocelot_mrp_add(struct ocelot *ocelot, int port,
  33                   const struct switchdev_obj_mrp *mrp)
  34{
  35        struct ocelot_port *ocelot_port = ocelot->ports[port];
  36        struct ocelot_port_private *priv;
  37        struct net_device *dev;
  38
  39        if (!ocelot_port)
  40                return -EOPNOTSUPP;
  41
  42        priv = container_of(ocelot_port, struct ocelot_port_private, port);
  43        dev = priv->dev;
  44
  45        if (mrp->p_port != dev && mrp->s_port != dev)
  46                return 0;
  47
  48        if (ocelot->mrp_ring_id != 0 &&
  49            ocelot->mrp_s_port &&
  50            ocelot->mrp_p_port)
  51                return -EINVAL;
  52
  53        if (mrp->p_port == dev)
  54                ocelot->mrp_p_port = dev;
  55
  56        if (mrp->s_port == dev)
  57                ocelot->mrp_s_port = dev;
  58
  59        ocelot->mrp_ring_id = mrp->ring_id;
  60
  61        return 0;
  62}
  63EXPORT_SYMBOL(ocelot_mrp_add);
  64
  65int ocelot_mrp_del(struct ocelot *ocelot, int port,
  66                   const struct switchdev_obj_mrp *mrp)
  67{
  68        struct ocelot_port *ocelot_port = ocelot->ports[port];
  69        struct ocelot_port_private *priv;
  70        struct net_device *dev;
  71
  72        if (!ocelot_port)
  73                return -EOPNOTSUPP;
  74
  75        priv = container_of(ocelot_port, struct ocelot_port_private, port);
  76        dev = priv->dev;
  77
  78        if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev)
  79                return 0;
  80
  81        if (ocelot->mrp_ring_id == 0 &&
  82            !ocelot->mrp_s_port &&
  83            !ocelot->mrp_p_port)
  84                return -EINVAL;
  85
  86        if (ocelot_mrp_del_vcap(ocelot, priv->chip_port))
  87                return -EINVAL;
  88
  89        if (ocelot->mrp_p_port == dev)
  90                ocelot->mrp_p_port = NULL;
  91
  92        if (ocelot->mrp_s_port == dev)
  93                ocelot->mrp_s_port = NULL;
  94
  95        ocelot->mrp_ring_id = 0;
  96
  97        return 0;
  98}
  99EXPORT_SYMBOL(ocelot_mrp_del);
 100
 101int ocelot_mrp_add_ring_role(struct ocelot *ocelot, int port,
 102                             const struct switchdev_obj_ring_role_mrp *mrp)
 103{
 104        struct ocelot_port *ocelot_port = ocelot->ports[port];
 105        struct ocelot_vcap_filter *filter;
 106        struct ocelot_port_private *priv;
 107        struct net_device *dev;
 108        int err;
 109
 110        if (!ocelot_port)
 111                return -EOPNOTSUPP;
 112
 113        priv = container_of(ocelot_port, struct ocelot_port_private, port);
 114        dev = priv->dev;
 115
 116        if (ocelot->mrp_ring_id != mrp->ring_id)
 117                return -EINVAL;
 118
 119        if (!mrp->sw_backup)
 120                return -EOPNOTSUPP;
 121
 122        if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev)
 123                return 0;
 124
 125        filter = kzalloc(sizeof(*filter), GFP_ATOMIC);
 126        if (!filter)
 127                return -ENOMEM;
 128
 129        filter->key_type = OCELOT_VCAP_KEY_ETYPE;
 130        filter->prio = 1;
 131        filter->id.cookie = priv->chip_port;
 132        filter->id.tc_offload = false;
 133        filter->block_id = VCAP_IS2;
 134        filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
 135        filter->ingress_port_mask = BIT(priv->chip_port);
 136        *(__be16 *)filter->key.etype.etype.value = htons(ETH_P_MRP);
 137        *(__be16 *)filter->key.etype.etype.mask = htons(0xffff);
 138        filter->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
 139        filter->action.port_mask = 0x0;
 140        filter->action.cpu_copy_ena = true;
 141        filter->action.cpu_qu_num = OCELOT_MRP_CPUQ;
 142
 143        err = ocelot_vcap_filter_add(ocelot, filter, NULL);
 144        if (err)
 145                kfree(filter);
 146
 147        return err;
 148}
 149EXPORT_SYMBOL(ocelot_mrp_add_ring_role);
 150
 151int ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port,
 152                             const struct switchdev_obj_ring_role_mrp *mrp)
 153{
 154        struct ocelot_port *ocelot_port = ocelot->ports[port];
 155        struct ocelot_port_private *priv;
 156        struct net_device *dev;
 157
 158        if (!ocelot_port)
 159                return -EOPNOTSUPP;
 160
 161        priv = container_of(ocelot_port, struct ocelot_port_private, port);
 162        dev = priv->dev;
 163
 164        if (ocelot->mrp_ring_id != mrp->ring_id)
 165                return -EINVAL;
 166
 167        if (!mrp->sw_backup)
 168                return -EOPNOTSUPP;
 169
 170        if (ocelot->mrp_p_port != dev && ocelot->mrp_s_port != dev)
 171                return 0;
 172
 173        return ocelot_mrp_del_vcap(ocelot, priv->chip_port);
 174}
 175EXPORT_SYMBOL(ocelot_mrp_del_ring_role);
 176