1 // SPDX-License-Identifier: GPL-2.0-only
2 /****************************************************************************
3 * Driver for Solarflare network controllers and boards
4 * Copyright 2022 Xilinx Inc.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation, incorporated herein by reference.
11 #include "tc_bindings.h"
13 #include "tc_encap_actions.h"
15 struct efx_tc_block_binding
{
16 struct list_head list
;
19 struct net_device
*otherdev
; /* may actually be us */
20 struct flow_block
*block
;
23 static struct efx_tc_block_binding
*efx_tc_find_binding(struct efx_nic
*efx
,
24 struct net_device
*otherdev
)
26 struct efx_tc_block_binding
*binding
;
29 list_for_each_entry(binding
, &efx
->tc
->block_list
, list
)
30 if (binding
->otherdev
== otherdev
)
35 static int efx_tc_block_cb(enum tc_setup_type type
, void *type_data
,
38 struct efx_tc_block_binding
*binding
= cb_priv
;
39 struct flow_cls_offload
*tcf
= type_data
;
42 case TC_SETUP_CLSFLOWER
:
43 return efx_tc_flower(binding
->efx
, binding
->otherdev
,
50 void efx_tc_block_unbind(void *cb_priv
)
52 struct efx_tc_block_binding
*binding
= cb_priv
;
54 list_del(&binding
->list
);
58 static struct efx_tc_block_binding
*efx_tc_create_binding(
59 struct efx_nic
*efx
, struct efx_rep
*efv
,
60 struct net_device
*otherdev
, struct flow_block
*block
)
62 struct efx_tc_block_binding
*binding
= kmalloc(sizeof(*binding
), GFP_KERNEL
);
65 return ERR_PTR(-ENOMEM
);
68 binding
->otherdev
= otherdev
;
69 binding
->block
= block
;
70 list_add(&binding
->list
, &efx
->tc
->block_list
);
74 int efx_tc_setup_block(struct net_device
*net_dev
, struct efx_nic
*efx
,
75 struct flow_block_offload
*tcb
, struct efx_rep
*efv
)
77 struct efx_tc_block_binding
*binding
;
78 struct flow_block_cb
*block_cb
;
81 if (tcb
->binder_type
!= FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS
)
84 if (WARN_ON(!efx
->tc
))
87 switch (tcb
->command
) {
89 binding
= efx_tc_create_binding(efx
, efv
, net_dev
, tcb
->block
);
91 return PTR_ERR(binding
);
92 block_cb
= flow_block_cb_alloc(efx_tc_block_cb
, binding
,
93 binding
, efx_tc_block_unbind
);
94 rc
= PTR_ERR_OR_ZERO(block_cb
);
95 netif_dbg(efx
, drv
, efx
->net_dev
,
96 "bind %sdirect block for device %s, rc %d\n",
97 net_dev
== efx
->net_dev
? "" :
99 net_dev
? net_dev
->name
: NULL
, rc
);
101 list_del(&binding
->list
);
104 flow_block_cb_add(block_cb
, tcb
);
107 case FLOW_BLOCK_UNBIND
:
108 binding
= efx_tc_find_binding(efx
, net_dev
);
110 block_cb
= flow_block_cb_lookup(tcb
->block
,
114 flow_block_cb_remove(block_cb
, tcb
);
115 netif_dbg(efx
, drv
, efx
->net_dev
,
116 "unbound %sdirect block for device %s\n",
117 net_dev
== efx
->net_dev
? "" :
118 binding
->efv
? "semi" : "in",
119 net_dev
? net_dev
->name
: NULL
);
123 /* If we're in driver teardown, then we expect to have
124 * already unbound all our blocks (we did it early while
125 * we still had MCDI to remove the filters), so getting
126 * unbind callbacks now isn't a problem.
128 netif_cond_dbg(efx
, drv
, efx
->net_dev
,
130 "%sdirect block unbind for device %s, was never bound\n",
131 net_dev
== efx
->net_dev
? "" : "in",
132 net_dev
? net_dev
->name
: NULL
);
139 int efx_tc_indr_setup_cb(struct net_device
*net_dev
, struct Qdisc
*sch
,
140 void *cb_priv
, enum tc_setup_type type
,
141 void *type_data
, void *data
,
142 void (*cleanup
)(struct flow_block_cb
*block_cb
))
144 struct flow_block_offload
*tcb
= type_data
;
145 struct efx_tc_block_binding
*binding
;
146 struct flow_block_cb
*block_cb
;
147 struct efx_nic
*efx
= cb_priv
;
148 bool is_ovs_int_port
;
154 if (tcb
->binder_type
!= FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS
&&
155 tcb
->binder_type
!= FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS
)
158 is_ovs_int_port
= netif_is_ovs_master(net_dev
);
159 if (tcb
->binder_type
== FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS
&&
168 switch (tcb
->command
) {
169 case FLOW_BLOCK_BIND
:
170 binding
= efx_tc_create_binding(efx
, NULL
, net_dev
, tcb
->block
);
172 return PTR_ERR(binding
);
173 block_cb
= flow_indr_block_cb_alloc(efx_tc_block_cb
, binding
,
174 binding
, efx_tc_block_unbind
,
175 tcb
, net_dev
, sch
, data
, binding
,
177 rc
= PTR_ERR_OR_ZERO(block_cb
);
178 netif_dbg(efx
, drv
, efx
->net_dev
,
179 "bind indr block for device %s, rc %d\n",
180 net_dev
? net_dev
->name
: NULL
, rc
);
182 list_del(&binding
->list
);
185 flow_block_cb_add(block_cb
, tcb
);
188 case FLOW_BLOCK_UNBIND
:
189 binding
= efx_tc_find_binding(efx
, net_dev
);
192 block_cb
= flow_block_cb_lookup(tcb
->block
,
197 flow_indr_block_cb_remove(block_cb
, tcb
);
198 netif_dbg(efx
, drv
, efx
->net_dev
,
199 "unbind indr block for device %s\n",
200 net_dev
? net_dev
->name
: NULL
);
210 /* .ndo_setup_tc implementation
211 * Entry point for flower block and filter management.
213 int efx_tc_setup(struct net_device
*net_dev
, enum tc_setup_type type
,
216 struct efx_nic
*efx
= efx_netdev_priv(net_dev
);
218 if (efx
->type
->is_vf
)
223 if (type
== TC_SETUP_CLSFLOWER
)
224 return efx_tc_flower(efx
, net_dev
, type_data
, NULL
);
225 if (type
== TC_SETUP_BLOCK
)
226 return efx_tc_setup_block(net_dev
, efx
, type_data
, NULL
);
231 int efx_tc_netdev_event(struct efx_nic
*efx
, unsigned long event
,
232 struct net_device
*net_dev
)
234 if (efx
->type
->is_vf
)
237 if (event
== NETDEV_UNREGISTER
)
238 efx_tc_unregister_egdev(efx
, net_dev
);