root/drivers/net/ethernet/mscc/ocelot_tc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ocelot_setup_tc_cls_matchall
  2. ocelot_setup_tc_block_cb
  3. ocelot_setup_tc_block_cb_ig
  4. ocelot_setup_tc_block_cb_eg
  5. ocelot_setup_tc_block
  6. ocelot_setup_tc

   1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2 /* Microsemi Ocelot Switch TC driver
   3  *
   4  * Copyright (c) 2019 Microsemi Corporation
   5  */
   6 
   7 #include "ocelot_tc.h"
   8 #include "ocelot_police.h"
   9 #include "ocelot_ace.h"
  10 #include <net/pkt_cls.h>
  11 
  12 static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
  13                                         struct tc_cls_matchall_offload *f,
  14                                         bool ingress)
  15 {
  16         struct netlink_ext_ack *extack = f->common.extack;
  17         struct ocelot_policer pol = { 0 };
  18         struct flow_action_entry *action;
  19         int err;
  20 
  21         netdev_dbg(port->dev, "%s: port %u command %d cookie %lu\n",
  22                    __func__, port->chip_port, f->command, f->cookie);
  23 
  24         if (!ingress) {
  25                 NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported");
  26                 return -EOPNOTSUPP;
  27         }
  28 
  29         switch (f->command) {
  30         case TC_CLSMATCHALL_REPLACE:
  31                 if (!flow_offload_has_one_action(&f->rule->action)) {
  32                         NL_SET_ERR_MSG_MOD(extack,
  33                                            "Only one action is supported");
  34                         return -EOPNOTSUPP;
  35                 }
  36 
  37                 if (port->tc.block_shared) {
  38                         NL_SET_ERR_MSG_MOD(extack,
  39                                            "Rate limit is not supported on shared blocks");
  40                         return -EOPNOTSUPP;
  41                 }
  42 
  43                 action = &f->rule->action.entries[0];
  44 
  45                 if (action->id != FLOW_ACTION_POLICE) {
  46                         NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
  47                         return -EOPNOTSUPP;
  48                 }
  49 
  50                 if (port->tc.police_id && port->tc.police_id != f->cookie) {
  51                         NL_SET_ERR_MSG_MOD(extack,
  52                                            "Only one policer per port is supported\n");
  53                         return -EEXIST;
  54                 }
  55 
  56                 pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8;
  57                 pol.burst = (u32)div_u64(action->police.rate_bytes_ps *
  58                                          PSCHED_NS2TICKS(action->police.burst),
  59                                          PSCHED_TICKS_PER_SEC);
  60 
  61                 err = ocelot_port_policer_add(port, &pol);
  62                 if (err) {
  63                         NL_SET_ERR_MSG_MOD(extack, "Could not add policer\n");
  64                         return err;
  65                 }
  66 
  67                 port->tc.police_id = f->cookie;
  68                 port->tc.offload_cnt++;
  69                 return 0;
  70         case TC_CLSMATCHALL_DESTROY:
  71                 if (port->tc.police_id != f->cookie)
  72                         return -ENOENT;
  73 
  74                 err = ocelot_port_policer_del(port);
  75                 if (err) {
  76                         NL_SET_ERR_MSG_MOD(extack,
  77                                            "Could not delete policer\n");
  78                         return err;
  79                 }
  80                 port->tc.police_id = 0;
  81                 port->tc.offload_cnt--;
  82                 return 0;
  83         case TC_CLSMATCHALL_STATS: /* fall through */
  84         default:
  85                 return -EOPNOTSUPP;
  86         }
  87 }
  88 
  89 static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
  90                                     void *type_data,
  91                                     void *cb_priv, bool ingress)
  92 {
  93         struct ocelot_port *port = cb_priv;
  94 
  95         if (!tc_cls_can_offload_and_chain0(port->dev, type_data))
  96                 return -EOPNOTSUPP;
  97 
  98         switch (type) {
  99         case TC_SETUP_CLSMATCHALL:
 100                 netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
 101                            ingress ? "ingress" : "egress");
 102 
 103                 return ocelot_setup_tc_cls_matchall(port, type_data, ingress);
 104         case TC_SETUP_CLSFLOWER:
 105                 return 0;
 106         default:
 107                 netdev_dbg(port->dev, "tc_block_cb: type %d %s\n",
 108                            type,
 109                            ingress ? "ingress" : "egress");
 110 
 111                 return -EOPNOTSUPP;
 112         }
 113 }
 114 
 115 static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type,
 116                                        void *type_data,
 117                                        void *cb_priv)
 118 {
 119         return ocelot_setup_tc_block_cb(type, type_data,
 120                                         cb_priv, true);
 121 }
 122 
 123 static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
 124                                        void *type_data,
 125                                        void *cb_priv)
 126 {
 127         return ocelot_setup_tc_block_cb(type, type_data,
 128                                         cb_priv, false);
 129 }
 130 
 131 static LIST_HEAD(ocelot_block_cb_list);
 132 
 133 static int ocelot_setup_tc_block(struct ocelot_port *port,
 134                                  struct flow_block_offload *f)
 135 {
 136         struct flow_block_cb *block_cb;
 137         flow_setup_cb_t *cb;
 138         int err;
 139 
 140         netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
 141                    f->command, f->binder_type);
 142 
 143         if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
 144                 cb = ocelot_setup_tc_block_cb_ig;
 145                 port->tc.block_shared = f->block_shared;
 146         } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
 147                 cb = ocelot_setup_tc_block_cb_eg;
 148         } else {
 149                 return -EOPNOTSUPP;
 150         }
 151 
 152         f->driver_block_list = &ocelot_block_cb_list;
 153 
 154         switch (f->command) {
 155         case FLOW_BLOCK_BIND:
 156                 if (flow_block_cb_is_busy(cb, port, &ocelot_block_cb_list))
 157                         return -EBUSY;
 158 
 159                 block_cb = flow_block_cb_alloc(cb, port, port, NULL);
 160                 if (IS_ERR(block_cb))
 161                         return PTR_ERR(block_cb);
 162 
 163                 err = ocelot_setup_tc_block_flower_bind(port, f);
 164                 if (err < 0) {
 165                         flow_block_cb_free(block_cb);
 166                         return err;
 167                 }
 168                 flow_block_cb_add(block_cb, f);
 169                 list_add_tail(&block_cb->driver_list, f->driver_block_list);
 170                 return 0;
 171         case FLOW_BLOCK_UNBIND:
 172                 block_cb = flow_block_cb_lookup(f->block, cb, port);
 173                 if (!block_cb)
 174                         return -ENOENT;
 175 
 176                 ocelot_setup_tc_block_flower_unbind(port, f);
 177                 flow_block_cb_remove(block_cb, f);
 178                 list_del(&block_cb->driver_list);
 179                 return 0;
 180         default:
 181                 return -EOPNOTSUPP;
 182         }
 183 }
 184 
 185 int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
 186                     void *type_data)
 187 {
 188         struct ocelot_port *port = netdev_priv(dev);
 189 
 190         switch (type) {
 191         case TC_SETUP_BLOCK:
 192                 return ocelot_setup_tc_block(port, type_data);
 193         default:
 194                 return -EOPNOTSUPP;
 195         }
 196         return 0;
 197 }

/* [<][>][^][v][top][bottom][index][help] */