forked from luck/tmp_suning_uos_patched
net: mscc: ocelot: Implement port policers via tc command
Hardware offload of matchall classifier and police action are now supported via the tc command. Supported police parameters are: rate and burst. Example: Add: tc qdisc add dev eth3 handle ffff: ingress tc filter add dev eth3 parent ffff: prio 1 handle 2 \ matchall skip_sw \ action police rate 100Mbit burst 10000 Show: tc -s -d qdisc show dev eth3 tc -s -d filter show dev eth3 ingress Delete: tc filter del dev eth3 parent ffff: prio 1 tc qdisc del dev eth3 handle ffff: ingress Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7da33a8f87
commit
2c1d029a01
|
@ -1,5 +1,5 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
|
||||
mscc_ocelot_common-y := ocelot.o ocelot_io.o
|
||||
mscc_ocelot_common-y += ocelot_regs.o
|
||||
mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o
|
||||
obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
|
||||
|
|
|
@ -910,6 +910,13 @@ static int ocelot_set_features(struct net_device *dev,
|
|||
struct ocelot_port *port = netdev_priv(dev);
|
||||
netdev_features_t changed = dev->features ^ features;
|
||||
|
||||
if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) &&
|
||||
port->tc.offload_cnt) {
|
||||
netdev_err(dev,
|
||||
"Cannot disable HW TC offload while offloads active\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (changed & NETIF_F_HW_VLAN_CTAG_FILTER)
|
||||
ocelot_vlan_mode(port, features);
|
||||
|
||||
|
@ -943,6 +950,7 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
|
|||
.ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
|
||||
.ndo_set_features = ocelot_set_features,
|
||||
.ndo_get_port_parent_id = ocelot_get_port_parent_id,
|
||||
.ndo_setup_tc = ocelot_setup_tc,
|
||||
};
|
||||
|
||||
static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
|
||||
|
@ -1663,8 +1671,9 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
|
|||
dev->netdev_ops = &ocelot_port_netdev_ops;
|
||||
dev->ethtool_ops = &ocelot_ethtool_ops;
|
||||
|
||||
dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS;
|
||||
dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS |
|
||||
NETIF_F_HW_TC;
|
||||
dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
|
||||
|
||||
memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN);
|
||||
dev->dev_addr[ETH_ALEN - 1] += port;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "ocelot_rew.h"
|
||||
#include "ocelot_sys.h"
|
||||
#include "ocelot_qs.h"
|
||||
#include "ocelot_tc.h"
|
||||
|
||||
#define PGID_AGGR 64
|
||||
#define PGID_SRC 80
|
||||
|
@ -458,6 +459,8 @@ struct ocelot_port {
|
|||
|
||||
phy_interface_t phy_mode;
|
||||
struct phy *serdes;
|
||||
|
||||
struct ocelot_port_tc tc;
|
||||
};
|
||||
|
||||
u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
|
||||
|
|
227
drivers/net/ethernet/mscc/ocelot_police.c
Normal file
227
drivers/net/ethernet/mscc/ocelot_police.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/* Microsemi Ocelot Switch driver
|
||||
*
|
||||
* Copyright (c) 2019 Microsemi Corporation
|
||||
*/
|
||||
|
||||
#include "ocelot_police.h"
|
||||
|
||||
enum mscc_qos_rate_mode {
|
||||
MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
|
||||
MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
|
||||
MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
|
||||
MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
|
||||
__MSCC_QOS_RATE_MODE_END,
|
||||
NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
|
||||
MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
|
||||
};
|
||||
|
||||
/* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
|
||||
#define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
|
||||
#define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
|
||||
#define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
|
||||
#define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
|
||||
|
||||
/* Policer indexes */
|
||||
#define POL_IX_PORT 0 /* 0-11 : Port policers */
|
||||
#define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
|
||||
|
||||
/* Default policer order */
|
||||
#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
|
||||
|
||||
struct qos_policer_conf {
|
||||
enum mscc_qos_rate_mode mode;
|
||||
bool dlb; /* Enable DLB (dual leaky bucket mode */
|
||||
bool cf; /* Coupling flag (ignored in SLB mode) */
|
||||
u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
|
||||
u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
|
||||
u32 pir; /* PIR in kbps/fps */
|
||||
u32 pbs; /* PBS in bytes/frames */
|
||||
u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
|
||||
};
|
||||
|
||||
static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix,
|
||||
struct qos_policer_conf *conf)
|
||||
{
|
||||
u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
|
||||
u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
|
||||
bool cir_discard = 0, pir_discard = 0;
|
||||
struct ocelot *ocelot = port->ocelot;
|
||||
u32 pbs_max = 0, cbs_max = 0;
|
||||
u8 ipg = 20;
|
||||
u32 value;
|
||||
|
||||
pir = conf->pir;
|
||||
pbs = conf->pbs;
|
||||
|
||||
switch (conf->mode) {
|
||||
case MSCC_QOS_RATE_MODE_LINE:
|
||||
case MSCC_QOS_RATE_MODE_DATA:
|
||||
if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
|
||||
frm_mode = POL_MODE_LINERATE;
|
||||
ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
|
||||
} else {
|
||||
frm_mode = POL_MODE_DATARATE;
|
||||
}
|
||||
if (conf->dlb) {
|
||||
cir_ena = 1;
|
||||
cir = conf->cir;
|
||||
cbs = conf->cbs;
|
||||
if (cir == 0 && cbs == 0) {
|
||||
/* Discard cir frames */
|
||||
cir_discard = 1;
|
||||
} else {
|
||||
cir = DIV_ROUND_UP(cir, 100);
|
||||
cir *= 3; /* 33 1/3 kbps */
|
||||
cbs = DIV_ROUND_UP(cbs, 4096);
|
||||
cbs = (cbs ? cbs : 1); /* No zero burst size */
|
||||
cbs_max = 60; /* Limit burst size */
|
||||
cf = conf->cf;
|
||||
if (cf)
|
||||
pir += conf->cir;
|
||||
}
|
||||
}
|
||||
if (pir == 0 && pbs == 0) {
|
||||
/* Discard PIR frames */
|
||||
pir_discard = 1;
|
||||
} else {
|
||||
pir = DIV_ROUND_UP(pir, 100);
|
||||
pir *= 3; /* 33 1/3 kbps */
|
||||
pbs = DIV_ROUND_UP(pbs, 4096);
|
||||
pbs = (pbs ? pbs : 1); /* No zero burst size */
|
||||
pbs_max = 60; /* Limit burst size */
|
||||
}
|
||||
break;
|
||||
case MSCC_QOS_RATE_MODE_FRAME:
|
||||
if (pir >= 100) {
|
||||
frm_mode = POL_MODE_FRMRATE_HI;
|
||||
pir = DIV_ROUND_UP(pir, 100);
|
||||
pir *= 3; /* 33 1/3 fps */
|
||||
pbs = (pbs * 10) / 328; /* 32.8 frames */
|
||||
pbs = (pbs ? pbs : 1); /* No zero burst size */
|
||||
pbs_max = GENMASK(6, 0); /* Limit burst size */
|
||||
} else {
|
||||
frm_mode = POL_MODE_FRMRATE_LO;
|
||||
if (pir == 0 && pbs == 0) {
|
||||
/* Discard all frames */
|
||||
pir_discard = 1;
|
||||
cir_discard = 1;
|
||||
} else {
|
||||
pir *= 3; /* 1/3 fps */
|
||||
pbs = (pbs * 10) / 3; /* 0.3 frames */
|
||||
pbs = (pbs ? pbs : 1); /* No zero burst size */
|
||||
pbs_max = 61; /* Limit burst size */
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: /* MSCC_QOS_RATE_MODE_DISABLED */
|
||||
/* Disable policer using maximum rate and zero burst */
|
||||
pir = GENMASK(15, 0);
|
||||
pbs = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check limits */
|
||||
if (pir > GENMASK(15, 0)) {
|
||||
netdev_err(port->dev, "Invalid pir\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cir > GENMASK(15, 0)) {
|
||||
netdev_err(port->dev, "Invalid cir\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pbs > pbs_max) {
|
||||
netdev_err(port->dev, "Invalid pbs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cbs > cbs_max) {
|
||||
netdev_err(port->dev, "Invalid cbs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
|
||||
ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
|
||||
(cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
|
||||
(cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
|
||||
ANA_POL_MODE_CFG_OVERSHOOT_ENA);
|
||||
|
||||
ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
|
||||
|
||||
ocelot_write_gix(ocelot,
|
||||
ANA_POL_PIR_CFG_PIR_RATE(pir) |
|
||||
ANA_POL_PIR_CFG_PIR_BURST(pbs),
|
||||
ANA_POL_PIR_CFG, pol_ix);
|
||||
|
||||
ocelot_write_gix(ocelot,
|
||||
(pir_discard ? GENMASK(22, 0) : 0),
|
||||
ANA_POL_PIR_STATE, pol_ix);
|
||||
|
||||
ocelot_write_gix(ocelot,
|
||||
ANA_POL_CIR_CFG_CIR_RATE(cir) |
|
||||
ANA_POL_CIR_CFG_CIR_BURST(cbs),
|
||||
ANA_POL_CIR_CFG, pol_ix);
|
||||
|
||||
ocelot_write_gix(ocelot,
|
||||
(cir_discard ? GENMASK(22, 0) : 0),
|
||||
ANA_POL_CIR_STATE, pol_ix);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ocelot_port_policer_add(struct ocelot_port *port,
|
||||
struct ocelot_policer *pol)
|
||||
{
|
||||
struct ocelot *ocelot = port->ocelot;
|
||||
struct qos_policer_conf pp = { 0 };
|
||||
int err;
|
||||
|
||||
if (!pol)
|
||||
return -EINVAL;
|
||||
|
||||
pp.mode = MSCC_QOS_RATE_MODE_DATA;
|
||||
pp.pir = pol->rate;
|
||||
pp.pbs = pol->burst;
|
||||
|
||||
netdev_dbg(port->dev,
|
||||
"%s: port %u pir %u kbps, pbs %u bytes\n",
|
||||
__func__, port->chip_port, pp.pir, pp.pbs);
|
||||
|
||||
err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ocelot_rmw_gix(ocelot,
|
||||
ANA_PORT_POL_CFG_PORT_POL_ENA |
|
||||
ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
|
||||
ANA_PORT_POL_CFG_PORT_POL_ENA |
|
||||
ANA_PORT_POL_CFG_POL_ORDER_M,
|
||||
ANA_PORT_POL_CFG, port->chip_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ocelot_port_policer_del(struct ocelot_port *port)
|
||||
{
|
||||
struct ocelot *ocelot = port->ocelot;
|
||||
struct qos_policer_conf pp = { 0 };
|
||||
int err;
|
||||
|
||||
netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
|
||||
|
||||
pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
|
||||
|
||||
err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ocelot_rmw_gix(ocelot,
|
||||
ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
|
||||
ANA_PORT_POL_CFG_PORT_POL_ENA |
|
||||
ANA_PORT_POL_CFG_POL_ORDER_M,
|
||||
ANA_PORT_POL_CFG, port->chip_port);
|
||||
|
||||
return 0;
|
||||
}
|
22
drivers/net/ethernet/mscc/ocelot_police.h
Normal file
22
drivers/net/ethernet/mscc/ocelot_police.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
/* Microsemi Ocelot Switch driver
|
||||
*
|
||||
* Copyright (c) 2019 Microsemi Corporation
|
||||
*/
|
||||
|
||||
#ifndef _MSCC_OCELOT_POLICE_H_
|
||||
#define _MSCC_OCELOT_POLICE_H_
|
||||
|
||||
#include "ocelot.h"
|
||||
|
||||
struct ocelot_policer {
|
||||
u32 rate; /* kilobit per second */
|
||||
u32 burst; /* bytes */
|
||||
};
|
||||
|
||||
int ocelot_port_policer_add(struct ocelot_port *port,
|
||||
struct ocelot_policer *pol);
|
||||
|
||||
int ocelot_port_policer_del(struct ocelot_port *port);
|
||||
|
||||
#endif /* _MSCC_OCELOT_POLICE_H_ */
|
174
drivers/net/ethernet/mscc/ocelot_tc.c
Normal file
174
drivers/net/ethernet/mscc/ocelot_tc.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
/* Microsemi Ocelot Switch TC driver
|
||||
*
|
||||
* Copyright (c) 2019 Microsemi Corporation
|
||||
*/
|
||||
|
||||
#include "ocelot_tc.h"
|
||||
#include "ocelot_police.h"
|
||||
#include <net/pkt_cls.h>
|
||||
|
||||
static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
|
||||
struct tc_cls_matchall_offload *f,
|
||||
bool ingress)
|
||||
{
|
||||
struct netlink_ext_ack *extack = f->common.extack;
|
||||
struct ocelot_policer pol = { 0 };
|
||||
struct flow_action_entry *action;
|
||||
int err;
|
||||
|
||||
netdev_dbg(port->dev, "%s: port %u command %d cookie %lu\n",
|
||||
__func__, port->chip_port, f->command, f->cookie);
|
||||
|
||||
if (!ingress) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
switch (f->command) {
|
||||
case TC_CLSMATCHALL_REPLACE:
|
||||
if (!flow_offload_has_one_action(&f->rule->action)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Only one action is supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (port->tc.block_shared) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Rate limit is not supported on shared blocks");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
action = &f->rule->action.entries[0];
|
||||
|
||||
if (action->id != FLOW_ACTION_POLICE) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (port->tc.police_id && port->tc.police_id != f->cookie) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Only one policer per port is supported\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8;
|
||||
pol.burst = (u32)div_u64(action->police.rate_bytes_ps *
|
||||
PSCHED_NS2TICKS(action->police.burst),
|
||||
PSCHED_TICKS_PER_SEC);
|
||||
|
||||
err = ocelot_port_policer_add(port, &pol);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Could not add policer\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
port->tc.police_id = f->cookie;
|
||||
port->tc.offload_cnt++;
|
||||
return 0;
|
||||
case TC_CLSMATCHALL_DESTROY:
|
||||
if (port->tc.police_id != f->cookie)
|
||||
return -ENOENT;
|
||||
|
||||
err = ocelot_port_policer_del(port);
|
||||
if (err) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Could not delete policer\n");
|
||||
return err;
|
||||
}
|
||||
port->tc.police_id = 0;
|
||||
port->tc.offload_cnt--;
|
||||
return 0;
|
||||
case TC_CLSMATCHALL_STATS: /* fall through */
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
|
||||
void *type_data,
|
||||
void *cb_priv, bool ingress)
|
||||
{
|
||||
struct ocelot_port *port = cb_priv;
|
||||
|
||||
if (!tc_cls_can_offload_and_chain0(port->dev, type_data))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (type) {
|
||||
case TC_SETUP_CLSMATCHALL:
|
||||
netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
|
||||
ingress ? "ingress" : "egress");
|
||||
|
||||
return ocelot_setup_tc_cls_matchall(port, type_data, ingress);
|
||||
case TC_SETUP_CLSFLOWER:
|
||||
netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSFLOWER %s\n",
|
||||
ingress ? "ingress" : "egress");
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
netdev_dbg(port->dev, "tc_block_cb: type %d %s\n",
|
||||
type,
|
||||
ingress ? "ingress" : "egress");
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type,
|
||||
void *type_data,
|
||||
void *cb_priv)
|
||||
{
|
||||
return ocelot_setup_tc_block_cb(type, type_data,
|
||||
cb_priv, true);
|
||||
}
|
||||
|
||||
static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
|
||||
void *type_data,
|
||||
void *cb_priv)
|
||||
{
|
||||
return ocelot_setup_tc_block_cb(type, type_data,
|
||||
cb_priv, false);
|
||||
}
|
||||
|
||||
static int ocelot_setup_tc_block(struct ocelot_port *port,
|
||||
struct tc_block_offload *f)
|
||||
{
|
||||
tc_setup_cb_t *cb;
|
||||
|
||||
netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
|
||||
f->command, f->binder_type);
|
||||
|
||||
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
|
||||
cb = ocelot_setup_tc_block_cb_ig;
|
||||
port->tc.block_shared = tcf_block_shared(f->block);
|
||||
} else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
|
||||
cb = ocelot_setup_tc_block_cb_eg;
|
||||
} else {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
switch (f->command) {
|
||||
case TC_BLOCK_BIND:
|
||||
return tcf_block_cb_register(f->block, cb, port,
|
||||
port, f->extack);
|
||||
case TC_BLOCK_UNBIND:
|
||||
tcf_block_cb_unregister(f->block, cb, port);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data)
|
||||
{
|
||||
struct ocelot_port *port = netdev_priv(dev);
|
||||
|
||||
switch (type) {
|
||||
case TC_SETUP_BLOCK:
|
||||
return ocelot_setup_tc_block(port, type_data);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
return 0;
|
||||
}
|
22
drivers/net/ethernet/mscc/ocelot_tc.h
Normal file
22
drivers/net/ethernet/mscc/ocelot_tc.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
/* Microsemi Ocelot Switch driver
|
||||
*
|
||||
* Copyright (c) 2019 Microsemi Corporation
|
||||
*/
|
||||
|
||||
#ifndef _MSCC_OCELOT_TC_H_
|
||||
#define _MSCC_OCELOT_TC_H_
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
struct ocelot_port_tc {
|
||||
bool block_shared;
|
||||
unsigned long offload_cnt;
|
||||
|
||||
unsigned long police_id;
|
||||
};
|
||||
|
||||
int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data);
|
||||
|
||||
#endif /* _MSCC_OCELOT_TC_H_ */
|
Loading…
Reference in New Issue
Block a user