Skip to content

Commit 184c449

Browse files
Alexander Duyckdavem330
authored andcommitted
net: Add support for XPS with QoS via traffic classes
This patch adds support for setting and using XPS when QoS via traffic classes is enabled. With this change we will factor in the priority and traffic class mapping of the packet and use that information to correctly select the queue. This allows us to define a set of queues for a given traffic class via mqprio and then configure the XPS mapping for those queues so that the traffic flows can avoid head-of-line blocking between the individual CPUs if so desired. Signed-off-by: Alexander Duyck <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6234f87 commit 184c449

File tree

3 files changed

+105
-47
lines changed

3 files changed

+105
-47
lines changed

include/linux/netdevice.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,8 +732,8 @@ struct xps_dev_maps {
732732
struct rcu_head rcu;
733733
struct xps_map __rcu *cpu_map[0];
734734
};
735-
#define XPS_DEV_MAPS_SIZE (sizeof(struct xps_dev_maps) + \
736-
(nr_cpu_ids * sizeof(struct xps_map *)))
735+
#define XPS_DEV_MAPS_SIZE(_tcs) (sizeof(struct xps_dev_maps) + \
736+
(nr_cpu_ids * (_tcs) * sizeof(struct xps_map *)))
737737
#endif /* CONFIG_XPS */
738738

739739
#define TC_MAX_QUEUE 16

net/core/dev.c

Lines changed: 83 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,14 +2002,22 @@ static bool remove_xps_queue_cpu(struct net_device *dev,
20022002
struct xps_dev_maps *dev_maps,
20032003
int cpu, u16 offset, u16 count)
20042004
{
2005-
int i, j;
2005+
int num_tc = dev->num_tc ? : 1;
2006+
bool active = false;
2007+
int tci;
20062008

2007-
for (i = count, j = offset; i--; j++) {
2008-
if (!remove_xps_queue(dev_maps, cpu, j))
2009-
break;
2009+
for (tci = cpu * num_tc; num_tc--; tci++) {
2010+
int i, j;
2011+
2012+
for (i = count, j = offset; i--; j++) {
2013+
if (!remove_xps_queue(dev_maps, cpu, j))
2014+
break;
2015+
}
2016+
2017+
active |= i < 0;
20102018
}
20112019

2012-
return i < 0;
2020+
return active;
20132021
}
20142022

20152023
static void netif_reset_xps_queues(struct net_device *dev, u16 offset,
@@ -2086,46 +2094,67 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
20862094
u16 index)
20872095
{
20882096
struct xps_dev_maps *dev_maps, *new_dev_maps = NULL;
2097+
int i, cpu, tci, numa_node_id = -2;
2098+
int maps_sz, num_tc = 1, tc = 0;
20892099
struct xps_map *map, *new_map;
2090-
int maps_sz = max_t(unsigned int, XPS_DEV_MAPS_SIZE, L1_CACHE_BYTES);
2091-
int cpu, numa_node_id = -2;
20922100
bool active = false;
20932101

2102+
if (dev->num_tc) {
2103+
num_tc = dev->num_tc;
2104+
tc = netdev_txq_to_tc(dev, index);
2105+
if (tc < 0)
2106+
return -EINVAL;
2107+
}
2108+
2109+
maps_sz = XPS_DEV_MAPS_SIZE(num_tc);
2110+
if (maps_sz < L1_CACHE_BYTES)
2111+
maps_sz = L1_CACHE_BYTES;
2112+
20942113
mutex_lock(&xps_map_mutex);
20952114

20962115
dev_maps = xmap_dereference(dev->xps_maps);
20972116

20982117
/* allocate memory for queue storage */
2099-
for_each_online_cpu(cpu) {
2100-
if (!cpumask_test_cpu(cpu, mask))
2101-
continue;
2102-
2118+
for_each_cpu_and(cpu, cpu_online_mask, mask) {
21032119
if (!new_dev_maps)
21042120
new_dev_maps = kzalloc(maps_sz, GFP_KERNEL);
21052121
if (!new_dev_maps) {
21062122
mutex_unlock(&xps_map_mutex);
21072123
return -ENOMEM;
21082124
}
21092125

2110-
map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) :
2126+
tci = cpu * num_tc + tc;
2127+
map = dev_maps ? xmap_dereference(dev_maps->cpu_map[tci]) :
21112128
NULL;
21122129

21132130
map = expand_xps_map(map, cpu, index);
21142131
if (!map)
21152132
goto error;
21162133

2117-
RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], map);
2134+
RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map);
21182135
}
21192136

21202137
if (!new_dev_maps)
21212138
goto out_no_new_maps;
21222139

21232140
for_each_possible_cpu(cpu) {
2141+
/* copy maps belonging to foreign traffic classes */
2142+
for (i = tc, tci = cpu * num_tc; dev_maps && i--; tci++) {
2143+
/* fill in the new device map from the old device map */
2144+
map = xmap_dereference(dev_maps->cpu_map[tci]);
2145+
RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map);
2146+
}
2147+
2148+
/* We need to explicitly update tci as prevous loop
2149+
* could break out early if dev_maps is NULL.
2150+
*/
2151+
tci = cpu * num_tc + tc;
2152+
21242153
if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu)) {
21252154
/* add queue to CPU maps */
21262155
int pos = 0;
21272156

2128-
map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
2157+
map = xmap_dereference(new_dev_maps->cpu_map[tci]);
21292158
while ((pos < map->len) && (map->queues[pos] != index))
21302159
pos++;
21312160

@@ -2139,26 +2168,36 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
21392168
#endif
21402169
} else if (dev_maps) {
21412170
/* fill in the new device map from the old device map */
2142-
map = xmap_dereference(dev_maps->cpu_map[cpu]);
2143-
RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], map);
2171+
map = xmap_dereference(dev_maps->cpu_map[tci]);
2172+
RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map);
21442173
}
21452174

2175+
/* copy maps belonging to foreign traffic classes */
2176+
for (i = num_tc - tc, tci++; dev_maps && --i; tci++) {
2177+
/* fill in the new device map from the old device map */
2178+
map = xmap_dereference(dev_maps->cpu_map[tci]);
2179+
RCU_INIT_POINTER(new_dev_maps->cpu_map[tci], map);
2180+
}
21462181
}
21472182

21482183
rcu_assign_pointer(dev->xps_maps, new_dev_maps);
21492184

21502185
/* Cleanup old maps */
2151-
if (dev_maps) {
2152-
for_each_possible_cpu(cpu) {
2153-
new_map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
2154-
map = xmap_dereference(dev_maps->cpu_map[cpu]);
2186+
if (!dev_maps)
2187+
goto out_no_old_maps;
2188+
2189+
for_each_possible_cpu(cpu) {
2190+
for (i = num_tc, tci = cpu * num_tc; i--; tci++) {
2191+
new_map = xmap_dereference(new_dev_maps->cpu_map[tci]);
2192+
map = xmap_dereference(dev_maps->cpu_map[tci]);
21552193
if (map && map != new_map)
21562194
kfree_rcu(map, rcu);
21572195
}
2158-
2159-
kfree_rcu(dev_maps, rcu);
21602196
}
21612197

2198+
kfree_rcu(dev_maps, rcu);
2199+
2200+
out_no_old_maps:
21622201
dev_maps = new_dev_maps;
21632202
active = true;
21642203

@@ -2173,11 +2212,12 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
21732212

21742213
/* removes queue from unused CPUs */
21752214
for_each_possible_cpu(cpu) {
2176-
if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu))
2177-
continue;
2178-
2179-
if (remove_xps_queue(dev_maps, cpu, index))
2180-
active = true;
2215+
for (i = tc, tci = cpu * num_tc; i--; tci++)
2216+
active |= remove_xps_queue(dev_maps, tci, index);
2217+
if (!cpumask_test_cpu(cpu, mask) || !cpu_online(cpu))
2218+
active |= remove_xps_queue(dev_maps, tci, index);
2219+
for (i = num_tc - tc, tci++; --i; tci++)
2220+
active |= remove_xps_queue(dev_maps, tci, index);
21812221
}
21822222

21832223
/* free map if not active */
@@ -2193,11 +2233,14 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
21932233
error:
21942234
/* remove any maps that we added */
21952235
for_each_possible_cpu(cpu) {
2196-
new_map = xmap_dereference(new_dev_maps->cpu_map[cpu]);
2197-
map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) :
2198-
NULL;
2199-
if (new_map && new_map != map)
2200-
kfree(new_map);
2236+
for (i = num_tc, tci = cpu * num_tc; i--; tci++) {
2237+
new_map = xmap_dereference(new_dev_maps->cpu_map[tci]);
2238+
map = dev_maps ?
2239+
xmap_dereference(dev_maps->cpu_map[tci]) :
2240+
NULL;
2241+
if (new_map && new_map != map)
2242+
kfree(new_map);
2243+
}
22012244
}
22022245

22032246
mutex_unlock(&xps_map_mutex);
@@ -3158,8 +3201,14 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
31583201
rcu_read_lock();
31593202
dev_maps = rcu_dereference(dev->xps_maps);
31603203
if (dev_maps) {
3161-
map = rcu_dereference(
3162-
dev_maps->cpu_map[skb->sender_cpu - 1]);
3204+
unsigned int tci = skb->sender_cpu - 1;
3205+
3206+
if (dev->num_tc) {
3207+
tci *= dev->num_tc;
3208+
tci += netdev_get_prio_tc_map(dev, skb->priority);
3209+
}
3210+
3211+
map = rcu_dereference(dev_maps->cpu_map[tci]);
31633212
if (map) {
31643213
if (map->len == 1)
31653214
queue_index = map->queues[0];

net/core/net-sysfs.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,29 +1210,38 @@ static ssize_t show_xps_map(struct netdev_queue *queue,
12101210
struct netdev_queue_attribute *attribute, char *buf)
12111211
{
12121212
struct net_device *dev = queue->dev;
1213+
int cpu, len, num_tc = 1, tc = 0;
12131214
struct xps_dev_maps *dev_maps;
12141215
cpumask_var_t mask;
12151216
unsigned long index;
1216-
int i, len;
12171217

12181218
if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
12191219
return -ENOMEM;
12201220

12211221
index = get_netdev_queue_index(queue);
12221222

1223+
if (dev->num_tc) {
1224+
num_tc = dev->num_tc;
1225+
tc = netdev_txq_to_tc(dev, index);
1226+
if (tc < 0)
1227+
return -EINVAL;
1228+
}
1229+
12231230
rcu_read_lock();
12241231
dev_maps = rcu_dereference(dev->xps_maps);
12251232
if (dev_maps) {
1226-
for_each_possible_cpu(i) {
1227-
struct xps_map *map =
1228-
rcu_dereference(dev_maps->cpu_map[i]);
1229-
if (map) {
1230-
int j;
1231-
for (j = 0; j < map->len; j++) {
1232-
if (map->queues[j] == index) {
1233-
cpumask_set_cpu(i, mask);
1234-
break;
1235-
}
1233+
for_each_possible_cpu(cpu) {
1234+
int i, tci = cpu * num_tc + tc;
1235+
struct xps_map *map;
1236+
1237+
map = rcu_dereference(dev_maps->cpu_map[tci]);
1238+
if (!map)
1239+
continue;
1240+
1241+
for (i = map->len; i--;) {
1242+
if (map->queues[i] == index) {
1243+
cpumask_set_cpu(cpu, mask);
1244+
break;
12361245
}
12371246
}
12381247
}

0 commit comments

Comments
 (0)