Commit 9dc0cad2 authored by Edward Cree's avatar Edward Cree Committed by David S. Miller

sfc: bind blocks for TC offload on EF100

Bind direct blocks for the MAE-admin PF and each VF representor.
Currently these connect to a stub efx_tc_flower() that only returns
 -EOPNOTSUPP; subsequent patches will implement flower offloads to the
 Match-Action Engine.
Signed-off-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c87e4ad1
...@@ -9,7 +9,7 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \ ...@@ -9,7 +9,7 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \
ef100_ethtool.o ef100_rx.o ef100_tx.o ef100_ethtool.o ef100_rx.o ef100_tx.o
sfc-$(CONFIG_SFC_MTD) += mtd.o sfc-$(CONFIG_SFC_MTD) += mtd.o
sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \ sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
mae.o tc.o mae.o tc.o tc_bindings.o
obj-$(CONFIG_SFC) += sfc.o obj-$(CONFIG_SFC) += sfc.o
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "mcdi_filters.h" #include "mcdi_filters.h"
#include "rx_common.h" #include "rx_common.h"
#include "ef100_sriov.h" #include "ef100_sriov.h"
#include "tc_bindings.h"
static void ef100_update_name(struct efx_nic *efx) static void ef100_update_name(struct efx_nic *efx)
{ {
...@@ -246,6 +247,9 @@ static const struct net_device_ops ef100_netdev_ops = { ...@@ -246,6 +247,9 @@ static const struct net_device_ops ef100_netdev_ops = {
#ifdef CONFIG_RFS_ACCEL #ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = efx_filter_rfs, .ndo_rx_flow_steer = efx_filter_rfs,
#endif #endif
#ifdef CONFIG_SFC_SRIOV
.ndo_setup_tc = efx_tc_setup,
#endif
}; };
/* Netdev registration /* Netdev registration
......
...@@ -1137,6 +1137,9 @@ int ef100_probe_netdev_pf(struct efx_nic *efx) ...@@ -1137,6 +1137,9 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
*/ */
netif_warn(efx, probe, net_dev, "Failed to probe MAE rc %d\n", netif_warn(efx, probe, net_dev, "Failed to probe MAE rc %d\n",
rc); rc);
} else {
net_dev->features |= NETIF_F_HW_TC;
efx->fixed_features |= NETIF_F_HW_TC;
} }
#endif #endif
return 0; return 0;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "ef100_nic.h" #include "ef100_nic.h"
#include "mae.h" #include "mae.h"
#include "rx_common.h" #include "rx_common.h"
#include "tc_bindings.h"
#define EFX_EF100_REP_DRIVER "efx_ef100_rep" #define EFX_EF100_REP_DRIVER "efx_ef100_rep"
...@@ -107,6 +108,20 @@ static int efx_ef100_rep_get_phys_port_name(struct net_device *dev, ...@@ -107,6 +108,20 @@ static int efx_ef100_rep_get_phys_port_name(struct net_device *dev,
return 0; return 0;
} }
static int efx_ef100_rep_setup_tc(struct net_device *net_dev,
enum tc_setup_type type, void *type_data)
{
struct efx_rep *efv = netdev_priv(net_dev);
struct efx_nic *efx = efv->parent;
if (type == TC_SETUP_CLSFLOWER)
return efx_tc_flower(efx, net_dev, type_data, efv);
if (type == TC_SETUP_BLOCK)
return efx_tc_setup_block(net_dev, efx, type_data, efv);
return -EOPNOTSUPP;
}
static void efx_ef100_rep_get_stats64(struct net_device *dev, static void efx_ef100_rep_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats) struct rtnl_link_stats64 *stats)
{ {
...@@ -127,6 +142,7 @@ static const struct net_device_ops efx_ef100_rep_netdev_ops = { ...@@ -127,6 +142,7 @@ static const struct net_device_ops efx_ef100_rep_netdev_ops = {
.ndo_get_port_parent_id = efx_ef100_rep_get_port_parent_id, .ndo_get_port_parent_id = efx_ef100_rep_get_port_parent_id,
.ndo_get_phys_port_name = efx_ef100_rep_get_phys_port_name, .ndo_get_phys_port_name = efx_ef100_rep_get_phys_port_name,
.ndo_get_stats64 = efx_ef100_rep_get_stats64, .ndo_get_stats64 = efx_ef100_rep_get_stats64,
.ndo_setup_tc = efx_ef100_rep_setup_tc,
}; };
static void efx_ef100_rep_get_drvinfo(struct net_device *dev, static void efx_ef100_rep_get_drvinfo(struct net_device *dev,
......
...@@ -58,6 +58,12 @@ static void efx_tc_delete_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rul ...@@ -58,6 +58,12 @@ static void efx_tc_delete_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rul
rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
} }
int efx_tc_flower(struct efx_nic *efx, struct net_device *net_dev,
struct flow_cls_offload *tc, struct efx_rep *efv)
{
return -EOPNOTSUPP;
}
static int efx_tc_configure_default_rule(struct efx_nic *efx, u32 ing_port, static int efx_tc_configure_default_rule(struct efx_nic *efx, u32 ing_port,
u32 eg_port, struct efx_tc_flow_rule *rule) u32 eg_port, struct efx_tc_flow_rule *rule)
{ {
...@@ -207,7 +213,11 @@ int efx_init_tc(struct efx_nic *efx) ...@@ -207,7 +213,11 @@ int efx_init_tc(struct efx_nic *efx)
rc = efx_tc_configure_default_rule_wire(efx); rc = efx_tc_configure_default_rule_wire(efx);
if (rc) if (rc)
return rc; return rc;
return efx_tc_configure_rep_mport(efx); rc = efx_tc_configure_rep_mport(efx);
if (rc)
return rc;
efx->tc->up = true;
return 0;
} }
void efx_fini_tc(struct efx_nic *efx) void efx_fini_tc(struct efx_nic *efx)
...@@ -218,6 +228,7 @@ void efx_fini_tc(struct efx_nic *efx) ...@@ -218,6 +228,7 @@ void efx_fini_tc(struct efx_nic *efx)
efx_tc_deconfigure_rep_mport(efx); efx_tc_deconfigure_rep_mport(efx);
efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf); efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf);
efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire); efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire);
efx->tc->up = false;
} }
int efx_init_struct_tc(struct efx_nic *efx) int efx_init_struct_tc(struct efx_nic *efx)
...@@ -228,6 +239,7 @@ int efx_init_struct_tc(struct efx_nic *efx) ...@@ -228,6 +239,7 @@ int efx_init_struct_tc(struct efx_nic *efx)
efx->tc = kzalloc(sizeof(*efx->tc), GFP_KERNEL); efx->tc = kzalloc(sizeof(*efx->tc), GFP_KERNEL);
if (!efx->tc) if (!efx->tc)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&efx->tc->block_list);
efx->tc->reps_filter_uc = -1; efx->tc->reps_filter_uc = -1;
efx->tc->reps_filter_mc = -1; efx->tc->reps_filter_mc = -1;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#ifndef EFX_TC_H #ifndef EFX_TC_H
#define EFX_TC_H #define EFX_TC_H
#include <net/flow_offload.h>
#include "net_driver.h" #include "net_driver.h"
struct efx_tc_action_set { struct efx_tc_action_set {
...@@ -49,6 +50,7 @@ enum efx_tc_rule_prios { ...@@ -49,6 +50,7 @@ enum efx_tc_rule_prios {
/** /**
* struct efx_tc_state - control plane data for TC offload * struct efx_tc_state - control plane data for TC offload
* *
* @block_list: List of &struct efx_tc_block_binding
* @reps_mport_id: MAE port allocated for representor RX * @reps_mport_id: MAE port allocated for representor RX
* @reps_filter_uc: VNIC filter for representor unicast RX (promisc) * @reps_filter_uc: VNIC filter for representor unicast RX (promisc)
* @reps_filter_mc: VNIC filter for representor multicast RX (allmulti) * @reps_filter_mc: VNIC filter for representor multicast RX (allmulti)
...@@ -57,14 +59,17 @@ enum efx_tc_rule_prios { ...@@ -57,14 +59,17 @@ enum efx_tc_rule_prios {
* %EFX_TC_PRIO_DFLT. Named by *ingress* port * %EFX_TC_PRIO_DFLT. Named by *ingress* port
* @dflt.pf: rule for traffic ingressing from PF (egresses to wire) * @dflt.pf: rule for traffic ingressing from PF (egresses to wire)
* @dflt.wire: rule for traffic ingressing from wire (egresses to PF) * @dflt.wire: rule for traffic ingressing from wire (egresses to PF)
* @up: have TC datastructures been set up?
*/ */
struct efx_tc_state { struct efx_tc_state {
struct list_head block_list;
u32 reps_mport_id, reps_mport_vport_id; u32 reps_mport_id, reps_mport_vport_id;
s32 reps_filter_uc, reps_filter_mc; s32 reps_filter_uc, reps_filter_mc;
struct { struct {
struct efx_tc_flow_rule pf; struct efx_tc_flow_rule pf;
struct efx_tc_flow_rule wire; struct efx_tc_flow_rule wire;
} dflt; } dflt;
bool up;
}; };
struct efx_rep; struct efx_rep;
...@@ -72,6 +77,8 @@ struct efx_rep; ...@@ -72,6 +77,8 @@ struct efx_rep;
int efx_tc_configure_default_rule_rep(struct efx_rep *efv); int efx_tc_configure_default_rule_rep(struct efx_rep *efv);
void efx_tc_deconfigure_default_rule(struct efx_nic *efx, void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
struct efx_tc_flow_rule *rule); struct efx_tc_flow_rule *rule);
int efx_tc_flower(struct efx_nic *efx, struct net_device *net_dev,
struct flow_cls_offload *tc, struct efx_rep *efv);
int efx_tc_insert_rep_filters(struct efx_nic *efx); int efx_tc_insert_rep_filters(struct efx_nic *efx);
void efx_tc_remove_rep_filters(struct efx_nic *efx); void efx_tc_remove_rep_filters(struct efx_nic *efx);
......
// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2022 Xilinx Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include "tc_bindings.h"
#include "tc.h"
struct efx_tc_block_binding {
struct list_head list;
struct efx_nic *efx;
struct efx_rep *efv;
struct net_device *otherdev; /* may actually be us */
struct flow_block *block;
};
static struct efx_tc_block_binding *efx_tc_find_binding(struct efx_nic *efx,
struct net_device *otherdev)
{
struct efx_tc_block_binding *binding;
ASSERT_RTNL();
list_for_each_entry(binding, &efx->tc->block_list, list)
if (binding->otherdev == otherdev)
return binding;
return NULL;
}
static int efx_tc_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv)
{
struct efx_tc_block_binding *binding = cb_priv;
struct flow_cls_offload *tcf = type_data;
switch (type) {
case TC_SETUP_CLSFLOWER:
return efx_tc_flower(binding->efx, binding->otherdev,
tcf, binding->efv);
default:
return -EOPNOTSUPP;
}
}
static void efx_tc_block_unbind(void *cb_priv)
{
struct efx_tc_block_binding *binding = cb_priv;
list_del(&binding->list);
kfree(binding);
}
static struct efx_tc_block_binding *efx_tc_create_binding(
struct efx_nic *efx, struct efx_rep *efv,
struct net_device *otherdev, struct flow_block *block)
{
struct efx_tc_block_binding *binding = kmalloc(sizeof(*binding), GFP_KERNEL);
if (!binding)
return ERR_PTR(-ENOMEM);
binding->efx = efx;
binding->efv = efv;
binding->otherdev = otherdev;
binding->block = block;
list_add(&binding->list, &efx->tc->block_list);
return binding;
}
int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,
struct flow_block_offload *tcb, struct efx_rep *efv)
{
struct efx_tc_block_binding *binding;
struct flow_block_cb *block_cb;
int rc;
if (tcb->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
if (WARN_ON(!efx->tc))
return -ENETDOWN;
switch (tcb->command) {
case FLOW_BLOCK_BIND:
binding = efx_tc_create_binding(efx, efv, net_dev, tcb->block);
if (IS_ERR(binding))
return PTR_ERR(binding);
block_cb = flow_block_cb_alloc(efx_tc_block_cb, binding,
binding, efx_tc_block_unbind);
rc = PTR_ERR_OR_ZERO(block_cb);
netif_dbg(efx, drv, efx->net_dev,
"bind %sdirect block for device %s, rc %d\n",
net_dev == efx->net_dev ? "" :
efv ? "semi" : "in",
net_dev ? net_dev->name : NULL, rc);
if (rc) {
list_del(&binding->list);
kfree(binding);
} else {
flow_block_cb_add(block_cb, tcb);
}
return rc;
case FLOW_BLOCK_UNBIND:
binding = efx_tc_find_binding(efx, net_dev);
if (binding) {
block_cb = flow_block_cb_lookup(tcb->block,
efx_tc_block_cb,
binding);
if (block_cb) {
flow_block_cb_remove(block_cb, tcb);
netif_dbg(efx, drv, efx->net_dev,
"unbound %sdirect block for device %s\n",
net_dev == efx->net_dev ? "" :
binding->efv ? "semi" : "in",
net_dev ? net_dev->name : NULL);
return 0;
}
}
/* If we're in driver teardown, then we expect to have
* already unbound all our blocks (we did it early while
* we still had MCDI to remove the filters), so getting
* unbind callbacks now isn't a problem.
*/
netif_cond_dbg(efx, drv, efx->net_dev,
!efx->tc->up, warn,
"%sdirect block unbind for device %s, was never bound\n",
net_dev == efx->net_dev ? "" : "in",
net_dev ? net_dev->name : NULL);
return -ENOENT;
default:
return -EOPNOTSUPP;
}
}
/* .ndo_setup_tc implementation
* Entry point for flower block and filter management.
*/
int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type,
void *type_data)
{
struct efx_nic *efx = efx_netdev_priv(net_dev);
if (efx->type->is_vf)
return -EOPNOTSUPP;
if (!efx->tc)
return -EOPNOTSUPP;
if (type == TC_SETUP_CLSFLOWER)
return efx_tc_flower(efx, net_dev, type_data, NULL);
if (type == TC_SETUP_BLOCK)
return efx_tc_setup_block(net_dev, efx, type_data, NULL);
return -EOPNOTSUPP;
}
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for Solarflare network controllers and boards
* Copyright 2022 Xilinx Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_TC_BINDINGS_H
#define EFX_TC_BINDINGS_H
#include "net_driver.h"
#include <net/sch_generic.h>
struct efx_rep;
int efx_tc_setup_block(struct net_device *net_dev, struct efx_nic *efx,
struct flow_block_offload *tcb, struct efx_rep *efv);
int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type,
void *type_data);
#endif /* EFX_TC_BINDINGS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment