Skip to content

Commit d5b33d0

Browse files
hramamu1Jeff Kirsher
authored andcommitted
i40evf: add ndo_setup_tc callback to i40evf
This patch introduces the callback to the ndo_setup_tc function in the VF driver. We add a wrapper function to make room for the upcoming cloud filter patches which add calls to different functions from setup_tc. First, we add support for capability exchange for ADQ between the PF and VF. Next, we add support to take in the mqprio configuration and configure queues as per the traffic classes, rate limit and the priorities specified by the user. This is done by passing the channel config to the PF driver through a virtchannel message. The flags and bits added, track if ADq is enabled, set max number of traffic classes to 4 and provide ability to negotiate capability with the PF. Signed-off-by: Harshitha Ramamurthy <harshitha.ramamurthy@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
1 parent eb09f1f commit d5b33d0

File tree

3 files changed

+257
-1
lines changed

3 files changed

+257
-1
lines changed

drivers/net/ethernet/intel/i40evf/i40evf.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include <linux/socket.h>
5353
#include <linux/jiffies.h>
5454
#include <net/ip6_checksum.h>
55+
#include <net/pkt_cls.h>
5556
#include <net/udp.h>
5657

5758
#include "i40e_type.h"
@@ -168,6 +169,20 @@ struct i40evf_vlan_filter {
168169
bool add; /* filter needs to be added */
169170
};
170171

172+
#define I40EVF_MAX_TRAFFIC_CLASS 4
173+
/* State of traffic class creation */
174+
enum i40evf_tc_state_t {
175+
__I40EVF_TC_INVALID, /* no traffic class, default state */
176+
__I40EVF_TC_RUNNING, /* traffic classes have been created */
177+
};
178+
179+
/* channel info */
180+
struct i40evf_channel_config {
181+
struct virtchnl_channel_info ch_info[I40EVF_MAX_TRAFFIC_CLASS];
182+
enum i40evf_tc_state_t state;
183+
u8 total_qps;
184+
};
185+
171186
/* Driver state. The order of these is important! */
172187
enum i40evf_state_t {
173188
__I40EVF_STARTUP, /* driver loaded, probe complete */
@@ -269,6 +284,8 @@ struct i40evf_adapter {
269284
#define I40EVF_FLAG_AQ_RELEASE_ALLMULTI BIT(18)
270285
#define I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT(19)
271286
#define I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT(20)
287+
#define I40EVF_FLAG_AQ_ENABLE_CHANNELS BIT(21)
288+
#define I40EVF_FLAG_AQ_DISABLE_CHANNELS BIT(22)
272289

273290
/* OS defined structs */
274291
struct net_device *netdev;
@@ -314,6 +331,9 @@ struct i40evf_adapter {
314331
u16 rss_lut_size;
315332
u8 *rss_key;
316333
u8 *rss_lut;
334+
/* ADQ related members */
335+
struct i40evf_channel_config ch_config;
336+
u8 num_tc;
317337
};
318338

319339

@@ -380,4 +400,6 @@ void i40evf_notify_client_message(struct i40e_vsi *vsi, u8 *msg, u16 len);
380400
void i40evf_notify_client_l2_params(struct i40e_vsi *vsi);
381401
void i40evf_notify_client_open(struct i40e_vsi *vsi);
382402
void i40evf_notify_client_close(struct i40e_vsi *vsi, bool reset);
403+
void i40evf_enable_channels(struct i40evf_adapter *adapter);
404+
void i40evf_disable_channels(struct i40evf_adapter *adapter);
383405
#endif /* _I40EVF_H_ */

drivers/net/ethernet/intel/i40evf/i40evf_main.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,17 @@ static void i40evf_watchdog_task(struct work_struct *work)
17321732
i40evf_set_promiscuous(adapter, 0);
17331733
goto watchdog_done;
17341734
}
1735+
1736+
if (adapter->aq_required & I40EVF_FLAG_AQ_ENABLE_CHANNELS) {
1737+
i40evf_enable_channels(adapter);
1738+
goto watchdog_done;
1739+
}
1740+
1741+
if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_CHANNELS) {
1742+
i40evf_disable_channels(adapter);
1743+
goto watchdog_done;
1744+
}
1745+
17351746
schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5));
17361747

17371748
if (adapter->state == __I40EVF_RUNNING)
@@ -2211,6 +2222,148 @@ void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter)
22112222
i40evf_free_rx_resources(&adapter->rx_rings[i]);
22122223
}
22132224

2225+
/**
2226+
* i40evf_validate_channel_config - validate queue mapping info
2227+
* @adapter: board private structure
2228+
* @mqprio_qopt: queue parameters
2229+
*
2230+
* This function validates if the config provided by the user to
2231+
* configure queue channels is valid or not. Returns 0 on a valid
2232+
* config.
2233+
**/
2234+
static int i40evf_validate_ch_config(struct i40evf_adapter *adapter,
2235+
struct tc_mqprio_qopt_offload *mqprio_qopt)
2236+
{
2237+
int i, num_qps = 0;
2238+
2239+
if (mqprio_qopt->qopt.num_tc > I40EVF_MAX_TRAFFIC_CLASS ||
2240+
mqprio_qopt->qopt.num_tc < 1)
2241+
return -EINVAL;
2242+
2243+
for (i = 0; i <= mqprio_qopt->qopt.num_tc - 1; i++) {
2244+
if (!mqprio_qopt->qopt.count[i] ||
2245+
mqprio_qopt->min_rate[i] ||
2246+
mqprio_qopt->max_rate[i] ||
2247+
mqprio_qopt->qopt.offset[i] != num_qps)
2248+
return -EINVAL;
2249+
num_qps += mqprio_qopt->qopt.count[i];
2250+
}
2251+
if (num_qps > MAX_QUEUES)
2252+
return -EINVAL;
2253+
2254+
return 0;
2255+
}
2256+
2257+
/**
2258+
* __i40evf_setup_tc - configure multiple traffic classes
2259+
* @netdev: network interface device structure
2260+
* @type_date: tc offload data
2261+
*
2262+
* This function processes the config information provided by the
2263+
* user to configure traffic classes/queue channels and packages the
2264+
* information to request the PF to setup traffic classes.
2265+
*
2266+
* Returns 0 on success.
2267+
**/
2268+
static int __i40evf_setup_tc(struct net_device *netdev, void *type_data)
2269+
{
2270+
struct tc_mqprio_qopt_offload *mqprio_qopt = type_data;
2271+
struct i40evf_adapter *adapter = netdev_priv(netdev);
2272+
struct virtchnl_vf_resource *vfres = adapter->vf_res;
2273+
u8 num_tc = 0, total_qps = 0;
2274+
int ret = 0, netdev_tc = 0;
2275+
u16 mode;
2276+
int i;
2277+
2278+
num_tc = mqprio_qopt->qopt.num_tc;
2279+
mode = mqprio_qopt->mode;
2280+
2281+
/* delete queue_channel */
2282+
if (!mqprio_qopt->qopt.hw) {
2283+
if (adapter->ch_config.state == __I40EVF_TC_RUNNING) {
2284+
/* reset the tc configuration */
2285+
netdev_reset_tc(netdev);
2286+
adapter->num_tc = 0;
2287+
netif_tx_stop_all_queues(netdev);
2288+
netif_tx_disable(netdev);
2289+
adapter->aq_required = I40EVF_FLAG_AQ_DISABLE_CHANNELS;
2290+
goto exit;
2291+
} else {
2292+
return -EINVAL;
2293+
}
2294+
}
2295+
2296+
/* add queue channel */
2297+
if (mode == TC_MQPRIO_MODE_CHANNEL) {
2298+
if (!(vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ)) {
2299+
dev_err(&adapter->pdev->dev, "ADq not supported\n");
2300+
return -EOPNOTSUPP;
2301+
}
2302+
if (adapter->ch_config.state != __I40EVF_TC_INVALID) {
2303+
dev_err(&adapter->pdev->dev, "TC configuration already exists\n");
2304+
return -EINVAL;
2305+
}
2306+
2307+
ret = i40evf_validate_ch_config(adapter, mqprio_qopt);
2308+
if (ret)
2309+
return ret;
2310+
/* Return if same TC config is requested */
2311+
if (adapter->num_tc == num_tc)
2312+
return 0;
2313+
adapter->num_tc = num_tc;
2314+
2315+
for (i = 0; i < I40EVF_MAX_TRAFFIC_CLASS; i++) {
2316+
if (i < num_tc) {
2317+
adapter->ch_config.ch_info[i].count =
2318+
mqprio_qopt->qopt.count[i];
2319+
adapter->ch_config.ch_info[i].offset =
2320+
mqprio_qopt->qopt.offset[i];
2321+
total_qps += mqprio_qopt->qopt.count[i];
2322+
} else {
2323+
adapter->ch_config.ch_info[i].count = 1;
2324+
adapter->ch_config.ch_info[i].offset = 0;
2325+
}
2326+
}
2327+
adapter->ch_config.total_qps = total_qps;
2328+
netif_tx_stop_all_queues(netdev);
2329+
netif_tx_disable(netdev);
2330+
adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_CHANNELS;
2331+
netdev_reset_tc(netdev);
2332+
/* Report the tc mapping up the stack */
2333+
netdev_set_num_tc(adapter->netdev, num_tc);
2334+
for (i = 0; i < I40EVF_MAX_TRAFFIC_CLASS; i++) {
2335+
u16 qcount = mqprio_qopt->qopt.count[i];
2336+
u16 qoffset = mqprio_qopt->qopt.offset[i];
2337+
2338+
if (i < num_tc)
2339+
netdev_set_tc_queue(netdev, netdev_tc++, qcount,
2340+
qoffset);
2341+
}
2342+
}
2343+
exit:
2344+
return ret;
2345+
}
2346+
2347+
/**
2348+
* i40evf_setup_tc - configure multiple traffic classes
2349+
* @netdev: network interface device structure
2350+
* @type: type of offload
2351+
* @type_date: tc offload data
2352+
*
2353+
* This function is the callback to ndo_setup_tc in the
2354+
* netdev_ops.
2355+
*
2356+
* Returns 0 on success
2357+
**/
2358+
static int i40evf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
2359+
void *type_data)
2360+
{
2361+
if (type != TC_SETUP_QDISC_MQPRIO)
2362+
return -EOPNOTSUPP;
2363+
2364+
return __i40evf_setup_tc(netdev, type_data);
2365+
}
2366+
22142367
/**
22152368
* i40evf_open - Called when a network interface is made active
22162369
* @netdev: network interface device structure
@@ -2478,6 +2631,7 @@ static const struct net_device_ops i40evf_netdev_ops = {
24782631
#ifdef CONFIG_NET_POLL_CONTROLLER
24792632
.ndo_poll_controller = i40evf_netpoll,
24802633
#endif
2634+
.ndo_setup_tc = i40evf_setup_tc,
24812635
};
24822636

24832637
/**

drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter)
161161
VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 |
162162
VIRTCHNL_VF_OFFLOAD_ENCAP |
163163
VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |
164-
VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;
164+
VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |
165+
VIRTCHNL_VF_OFFLOAD_ADQ;
165166

166167
adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES;
167168
adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG;
@@ -972,6 +973,70 @@ static void i40evf_print_link_message(struct i40evf_adapter *adapter)
972973
netdev_info(netdev, "NIC Link is Up %sbps Full Duplex\n", speed);
973974
}
974975

976+
/**
977+
* i40evf_enable_channel
978+
* @adapter: adapter structure
979+
*
980+
* Request that the PF enable channels as specified by
981+
* the user via tc tool.
982+
**/
983+
void i40evf_enable_channels(struct i40evf_adapter *adapter)
984+
{
985+
struct virtchnl_tc_info *vti = NULL;
986+
u16 len;
987+
int i;
988+
989+
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
990+
/* bail because we already have a command pending */
991+
dev_err(&adapter->pdev->dev, "Cannot configure mqprio, command %d pending\n",
992+
adapter->current_op);
993+
return;
994+
}
995+
996+
len = (adapter->num_tc * sizeof(struct virtchnl_channel_info)) +
997+
sizeof(struct virtchnl_tc_info);
998+
999+
vti = kzalloc(len, GFP_KERNEL);
1000+
if (!vti)
1001+
return;
1002+
vti->num_tc = adapter->num_tc;
1003+
for (i = 0; i < vti->num_tc; i++) {
1004+
vti->list[i].count = adapter->ch_config.ch_info[i].count;
1005+
vti->list[i].offset = adapter->ch_config.ch_info[i].offset;
1006+
}
1007+
1008+
adapter->ch_config.state = __I40EVF_TC_RUNNING;
1009+
adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
1010+
adapter->current_op = VIRTCHNL_OP_ENABLE_CHANNELS;
1011+
adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_CHANNELS;
1012+
i40evf_send_pf_msg(adapter, VIRTCHNL_OP_ENABLE_CHANNELS,
1013+
(u8 *)vti, len);
1014+
kfree(vti);
1015+
}
1016+
1017+
/**
1018+
* i40evf_disable_channel
1019+
* @adapter: adapter structure
1020+
*
1021+
* Request that the PF disable channels that are configured
1022+
**/
1023+
void i40evf_disable_channels(struct i40evf_adapter *adapter)
1024+
{
1025+
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
1026+
/* bail because we already have a command pending */
1027+
dev_err(&adapter->pdev->dev, "Cannot configure mqprio, command %d pending\n",
1028+
adapter->current_op);
1029+
return;
1030+
}
1031+
1032+
adapter->ch_config.state = __I40EVF_TC_INVALID;
1033+
adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
1034+
adapter->current_op = VIRTCHNL_OP_DISABLE_CHANNELS;
1035+
adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_CHANNELS;
1036+
i40evf_send_pf_msg(adapter, VIRTCHNL_OP_DISABLE_CHANNELS,
1037+
NULL, 0);
1038+
}
1039+
9751040
/**
9761041
* i40evf_request_reset
9771042
* @adapter: adapter structure
@@ -1080,6 +1145,21 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
10801145
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
10811146
i40evf_stat_str(&adapter->hw, v_retval));
10821147
break;
1148+
case VIRTCHNL_OP_ENABLE_CHANNELS:
1149+
dev_err(&adapter->pdev->dev, "Failed to configure queue channels, error %s\n",
1150+
i40evf_stat_str(&adapter->hw, v_retval));
1151+
adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
1152+
adapter->ch_config.state = __I40EVF_TC_INVALID;
1153+
netdev_reset_tc(netdev);
1154+
netif_tx_start_all_queues(netdev);
1155+
break;
1156+
case VIRTCHNL_OP_DISABLE_CHANNELS:
1157+
dev_err(&adapter->pdev->dev, "Failed to disable queue channels, error %s\n",
1158+
i40evf_stat_str(&adapter->hw, v_retval));
1159+
adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
1160+
adapter->ch_config.state = __I40EVF_TC_RUNNING;
1161+
netif_tx_start_all_queues(netdev);
1162+
break;
10831163
default:
10841164
dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
10851165
v_retval,

0 commit comments

Comments
 (0)