From: Alexander Duyck <hidden> Date: 2012-06-30 00:15:54
The following patch series makes it so that the ixgbe driver can support
ATR even when the number of queues is less than the number of CPUs. To do
this I have updated the kernel to support letting drivers set their own XPS
configuration. To do this it was necessary to move the code out of the
sysfs specific code and into the dev specific regions.
I am still working out a few issues such as the fact that with routing I
only ever seem to be able to get the first queue that is mapped to the CPU
when XPS is enabled.
Also I am looking for input on if it is acceptable to only let the
set_channels/get_channels calls report/set the number of queues per traffic
class as I implemented the code this way to avoid any significant conflicts
between the DCB traffic classes code and these functions.
---
Alexander Duyck (10):
ixgbe: Add support for set_channels ethtool operation
ixgbe: Add support for displaying the number of Tx/Rx channels
ixgbe: Update ixgbe driver to use __dev_pick_tx in ixgbe_select_queue
ixgbe: Add function for setting XPS queue mapping
ixgbe: Define FCoE and Flow director limits much sooner to allow for changes
net: Add support for XPS without SYSFS being defined
net: Rewrite netif_set_xps_queues to address several issues
net: Rewrite netif_reset_xps_queue to allow for better code reuse
net: Add functions netif_reset_xps_queue and netif_set_xps_queue
net: Split core bits of dev_pick_tx into __dev_pick_tx
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 112 +++++++++
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 10 -
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 48 +++-
include/linux/netdevice.h | 15 +
net/Kconfig | 2
net/core/dev.c | 283 ++++++++++++++++++++--
net/core/net-sysfs.c | 160 ------------
7 files changed, 428 insertions(+), 202 deletions(-)
--
Thanks,
Alex
From: Alexander Duyck <hidden> Date: 2012-06-30 00:15:59
This change splits the core bits of dev_pick_tx into a separate function.
The main idea behind this is to make this code accessible to select queue
functions when they decide to process the standard path instead of their
own custom path in their select queue routine.
Signed-off-by: Alexander Duyck <redacted>
---
include/linux/netdevice.h | 3 +++
net/core/dev.c | 51 ++++++++++++++++++++++++++-------------------
2 files changed, 33 insertions(+), 21 deletions(-)
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:04
This patch adds two functions, netif_reset_xps_queue and
netif_set_xps_queue. The main idea behind these to functions is to provide
a mechanism through which drivers can update their defaults in regards to
XPS.
Currently no such mechanism exists and as a result we cannot use XPS for
things such as ATR which would require a basic configuration to start in
which the Tx queues are mapped to CPUs via a 1:1 mapping. With this change
I am making it possible for drivers such as ixgbe to be able to use the XPS
feature by controlling the default configuration.
Signed-off-by: Alexander Duyck <redacted>
---
include/linux/netdevice.h | 13 ++++
net/core/dev.c | 155 +++++++++++++++++++++++++++++++++++++++++++++
net/core/net-sysfs.c | 148 +------------------------------------------
3 files changed, 173 insertions(+), 143 deletions(-)
@@ -1728,6 +1728,161 @@ static void netif_setup_tc(struct net_device *dev, unsigned int txq)}}+#ifdef CONFIG_XPS+staticDEFINE_MUTEX(xps_map_mutex);+#define xmap_dereference(P) \+rcu_dereference_protected((P),lockdep_is_held(&xps_map_mutex))++voidnetif_reset_xps_queue(structnet_device*dev,u16index)+{+structxps_dev_maps*dev_maps;+structxps_map*map;+inti,pos,nonempty=0;++mutex_lock(&xps_map_mutex);+dev_maps=xmap_dereference(dev->xps_maps);++if(!dev_maps)+gotoout_no_maps;++for_each_possible_cpu(i){+map=xmap_dereference(dev_maps->cpu_map[i]);+if(!map)+continue;++for(pos=0;pos<map->len;pos++)+if(map->queues[pos]==index)+break;++if(pos<map->len){+if(map->len>1){+map->queues[pos]=map->queues[--map->len];+}else{+RCU_INIT_POINTER(dev_maps->cpu_map[i],NULL);+kfree_rcu(map,rcu);+map=NULL;+}+}+if(map)+nonempty=1;+}++if(!nonempty){+RCU_INIT_POINTER(dev->xps_maps,NULL);+kfree_rcu(dev_maps,rcu);+}++out_no_maps:+mutex_unlock(&xps_map_mutex);+}++intnetif_set_xps_queue(structnet_device*dev,structcpumask*mask,u16index)+{+inti,cpu,pos,map_len,alloc_len,need_set;+structxps_map*map,*new_map;+structxps_dev_maps*dev_maps,*new_dev_maps;+intnonempty=0;+intnuma_node_id=-2;+intmaps_sz=max_t(unsignedint,XPS_DEV_MAPS_SIZE,L1_CACHE_BYTES);++new_dev_maps=kzalloc(maps_sz,GFP_KERNEL);+if(!new_dev_maps)+return-ENOMEM;++mutex_lock(&xps_map_mutex);++dev_maps=xmap_dereference(dev->xps_maps);++for_each_possible_cpu(cpu){+map=dev_maps?+xmap_dereference(dev_maps->cpu_map[cpu]):NULL;+new_map=map;+if(map){+for(pos=0;pos<map->len;pos++)+if(map->queues[pos]==index)+break;+map_len=map->len;+alloc_len=map->alloc_len;+}else+pos=map_len=alloc_len=0;++need_set=cpumask_test_cpu(cpu,mask)&&cpu_online(cpu);+#ifdef CONFIG_NUMA+if(need_set){+if(numa_node_id==-2)+numa_node_id=cpu_to_node(cpu);+elseif(numa_node_id!=cpu_to_node(cpu))+numa_node_id=-1;+}+#endif+if(need_set&&pos>=map_len){+/* Need to add queue to this CPU's map */+if(map_len>=alloc_len){+alloc_len=alloc_len?+2*alloc_len:XPS_MIN_MAP_ALLOC;+new_map=kzalloc_node(XPS_MAP_SIZE(alloc_len),+GFP_KERNEL,+cpu_to_node(cpu));+if(!new_map)+gotoerror;+new_map->alloc_len=alloc_len;+for(i=0;i<map_len;i++)+new_map->queues[i]=map->queues[i];+new_map->len=map_len;+}+new_map->queues[new_map->len++]=index;+}elseif(!need_set&&pos<map_len){+/* Need to remove queue from this CPU's map */+if(map_len>1)+new_map->queues[pos]=+new_map->queues[--new_map->len];+else+new_map=NULL;+}+RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu],new_map);+}++/* Cleanup old maps */+for_each_possible_cpu(cpu){+map=dev_maps?+xmap_dereference(dev_maps->cpu_map[cpu]):NULL;+if(map&&xmap_dereference(new_dev_maps->cpu_map[cpu])!=map)+kfree_rcu(map,rcu);+if(new_dev_maps->cpu_map[cpu])+nonempty=1;+}++if(nonempty){+rcu_assign_pointer(dev->xps_maps,new_dev_maps);+}else{+kfree(new_dev_maps);+RCU_INIT_POINTER(dev->xps_maps,NULL);+}++if(dev_maps)+kfree_rcu(dev_maps,rcu);++netdev_queue_numa_node_write(netdev_get_tx_queue(dev,index),+(numa_node_id>=0)?numa_node_id:+NUMA_NO_NODE);++mutex_unlock(&xps_map_mutex);++return0;+error:+mutex_unlock(&xps_map_mutex);++if(new_dev_maps)+for_each_possible_cpu(i)+kfree(rcu_dereference_protected(+new_dev_maps->cpu_map[i],+1));+kfree(new_dev_maps);+return-ENOMEM;+}+EXPORT_SYMBOL(netif_set_xps_queue);++#endif/**Routinetohelpsetreal_num_tx_queues.Toavoidskbsmappedtoqueues*greaterthenreal_num_tx_queuesstaleskbsontheqdiscmustbeflushed.
@@ -1040,105 +996,11 @@ static ssize_t store_xps_map(struct netdev_queue *queue,returnerr;}-new_dev_maps=kzalloc(max_t(unsignedint,-XPS_DEV_MAPS_SIZE,L1_CACHE_BYTES),GFP_KERNEL);-if(!new_dev_maps){-free_cpumask_var(mask);-return-ENOMEM;-}--mutex_lock(&xps_map_mutex);--dev_maps=xmap_dereference(dev->xps_maps);--for_each_possible_cpu(cpu){-map=dev_maps?-xmap_dereference(dev_maps->cpu_map[cpu]):NULL;-new_map=map;-if(map){-for(pos=0;pos<map->len;pos++)-if(map->queues[pos]==index)-break;-map_len=map->len;-alloc_len=map->alloc_len;-}else-pos=map_len=alloc_len=0;--need_set=cpumask_test_cpu(cpu,mask)&&cpu_online(cpu);-#ifdef CONFIG_NUMA-if(need_set){-if(numa_node_id==-2)-numa_node_id=cpu_to_node(cpu);-elseif(numa_node_id!=cpu_to_node(cpu))-numa_node_id=-1;-}-#endif-if(need_set&&pos>=map_len){-/* Need to add queue to this CPU's map */-if(map_len>=alloc_len){-alloc_len=alloc_len?-2*alloc_len:XPS_MIN_MAP_ALLOC;-new_map=kzalloc_node(XPS_MAP_SIZE(alloc_len),-GFP_KERNEL,-cpu_to_node(cpu));-if(!new_map)-gotoerror;-new_map->alloc_len=alloc_len;-for(i=0;i<map_len;i++)-new_map->queues[i]=map->queues[i];-new_map->len=map_len;-}-new_map->queues[new_map->len++]=index;-}elseif(!need_set&&pos<map_len){-/* Need to remove queue from this CPU's map */-if(map_len>1)-new_map->queues[pos]=-new_map->queues[--new_map->len];-else-new_map=NULL;-}-RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu],new_map);-}--/* Cleanup old maps */-for_each_possible_cpu(cpu){-map=dev_maps?-xmap_dereference(dev_maps->cpu_map[cpu]):NULL;-if(map&&xmap_dereference(new_dev_maps->cpu_map[cpu])!=map)-kfree_rcu(map,rcu);-if(new_dev_maps->cpu_map[cpu])-nonempty=1;-}--if(nonempty){-rcu_assign_pointer(dev->xps_maps,new_dev_maps);-}else{-kfree(new_dev_maps);-RCU_INIT_POINTER(dev->xps_maps,NULL);-}--if(dev_maps)-kfree_rcu(dev_maps,rcu);--netdev_queue_numa_node_write(queue,(numa_node_id>=0)?numa_node_id:-NUMA_NO_NODE);--mutex_unlock(&xps_map_mutex);+err=netif_set_xps_queue(dev,mask,index);free_cpumask_var(mask);-returnlen;-error:-mutex_unlock(&xps_map_mutex);--if(new_dev_maps)-for_each_possible_cpu(i)-kfree(rcu_dereference_protected(-new_dev_maps->cpu_map[i],-1));-kfree(new_dev_maps);-free_cpumask_var(mask);-return-ENOMEM;+returnerr?:len;}staticstructnetdev_queue_attributexps_cpus_attribute=
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:09
This patch does a minor refactor on netif_reset_xps_queue to address a few
items I noticed.
First is the fact that we are doing removal of queues in both
netif_reset_xps_queue and netif_set_xps_queue. Since there is no need to
have the code in two places I am pushing it out into a separate function
and will come back in another patch and reuse the code in
netif_set_xps_queue.
The second item this change addresses is the fact that the Tx queues were
not getting their numa_node value cleared as a part of the XPS queue reset.
This patch resolves that by resetting the numa_node value if the dev_maps
value is set.
Signed-off-by: Alexander Duyck <redacted>
---
net/core/dev.c | 56 +++++++++++++++++++++++++++++++++-----------------------
1 files changed, 33 insertions(+), 23 deletions(-)
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:15
This change is meant to address several issues I found within the
netif_set_xps_queues function.
If the allocation of one of the maps to be assigned to new_dev_maps failed
we could end up with the device map in an inconsistent state since we had
already worked through a number of CPUs and removed or added the queue. To
address that I split the process into several steps. The first of which is
just the allocation of updated maps for CPUs that will need larger maps to
store the queue. By doing this we can fail gracefully without actually
altering the contents of the current device map.
The second issue I found was the fact that we were always allocating a new
device map even if we were not adding any queues. I have updated the code
so that we only allocate a new device map if we are adding queues,
otherwise if we are not adding any queues to CPUs we just skip to the
removal process.
The last change I made was to reuse the code from remove_xps_queue to remove
the queue from the CPU. By making this change we can be consistent in how
we go about adding and removing the queues from the CPUs.
Signed-off-by: Alexander Duyck <redacted>
---
net/core/dev.c | 183 ++++++++++++++++++++++++++++++++++++--------------------
1 files changed, 117 insertions(+), 66 deletions(-)
@@ -1786,107 +1786,158 @@ out_no_maps:mutex_unlock(&xps_map_mutex);}+staticstructxps_map*expand_xps_map(structxps_map*map,+intcpu,u16index)+{+structxps_map*new_map;+intalloc_len=XPS_MIN_MAP_ALLOC;+inti,pos;++for(pos=0;map&&pos<map->len;pos++){+if(map->queues[pos]!=index)+continue;+returnmap;+}++/* Need to add queue to this CPU's existing map */+if(map){+if(pos<map->alloc_len)+returnmap;++alloc_len=map->alloc_len*2;+}++/* Need to allocate new map to store queue on this CPU's map */+new_map=kzalloc_node(XPS_MAP_SIZE(alloc_len),GFP_KERNEL,+cpu_to_node(cpu));+if(!new_map)+returnNULL;++for(i=0;i<pos;i++)+new_map->queues[i]=map->queues[i];+new_map->alloc_len=alloc_len;+new_map->len=pos;++returnnew_map;+}+intnetif_set_xps_queue(structnet_device*dev,structcpumask*mask,u16index){-inti,cpu,pos,map_len,alloc_len,need_set;+structxps_dev_maps*dev_maps,*new_dev_maps=NULL;structxps_map*map,*new_map;-structxps_dev_maps*dev_maps,*new_dev_maps;-intnonempty=0;-intnuma_node_id=-2;intmaps_sz=max_t(unsignedint,XPS_DEV_MAPS_SIZE,L1_CACHE_BYTES);--new_dev_maps=kzalloc(maps_sz,GFP_KERNEL);-if(!new_dev_maps)-return-ENOMEM;+intcpu,numa_node_id=-2;+boolactive=false;mutex_lock(&xps_map_mutex);dev_maps=xmap_dereference(dev->xps_maps);+/* allocate memory for queue storage */+for_each_online_cpu(cpu){+if(!cpumask_test_cpu(cpu,mask))+continue;++if(!new_dev_maps)+new_dev_maps=kzalloc(maps_sz,GFP_KERNEL);+if(!new_dev_maps)+return-ENOMEM;++map=dev_maps?xmap_dereference(dev_maps->cpu_map[cpu]):+NULL;++map=expand_xps_map(map,cpu,index);+if(!map)+gotoerror;++RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu],map);+}++if(!new_dev_maps)+gotoout_no_new_maps;+for_each_possible_cpu(cpu){-map=dev_maps?-xmap_dereference(dev_maps->cpu_map[cpu]):NULL;-new_map=map;-if(map){-for(pos=0;pos<map->len;pos++)-if(map->queues[pos]==index)-break;-map_len=map->len;-alloc_len=map->alloc_len;-}else-pos=map_len=alloc_len=0;+if(cpumask_test_cpu(cpu,mask)&&cpu_online(cpu)){+/* add queue to CPU maps */+intpos=0;-need_set=cpumask_test_cpu(cpu,mask)&&cpu_online(cpu);+map=xmap_dereference(new_dev_maps->cpu_map[cpu]);+while((pos<map->len)&&(map->queues[pos]!=index))+pos++;++if(pos==map->len)+map->queues[map->len++]=index;#ifdef CONFIG_NUMA-if(need_set){if(numa_node_id==-2)numa_node_id=cpu_to_node(cpu);elseif(numa_node_id!=cpu_to_node(cpu))numa_node_id=-1;-}#endif-if(need_set&&pos>=map_len){-/* Need to add queue to this CPU's map */-if(map_len>=alloc_len){-alloc_len=alloc_len?-2*alloc_len:XPS_MIN_MAP_ALLOC;-new_map=kzalloc_node(XPS_MAP_SIZE(alloc_len),-GFP_KERNEL,-cpu_to_node(cpu));-if(!new_map)-gotoerror;-new_map->alloc_len=alloc_len;-for(i=0;i<map_len;i++)-new_map->queues[i]=map->queues[i];-new_map->len=map_len;-}-new_map->queues[new_map->len++]=index;-}elseif(!need_set&&pos<map_len){-/* Need to remove queue from this CPU's map */-if(map_len>1)-new_map->queues[pos]=-new_map->queues[--new_map->len];-else-new_map=NULL;+}elseif(dev_maps){+/* fill in the new device map from the old device map */+map=xmap_dereference(dev_maps->cpu_map[cpu]);+RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu],map);}-RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu],new_map);+}+rcu_assign_pointer(dev->xps_maps,new_dev_maps);+/* Cleanup old maps */-for_each_possible_cpu(cpu){-map=dev_maps?-xmap_dereference(dev_maps->cpu_map[cpu]):NULL;-if(map&&xmap_dereference(new_dev_maps->cpu_map[cpu])!=map)-kfree_rcu(map,rcu);-if(new_dev_maps->cpu_map[cpu])-nonempty=1;-}+if(dev_maps){+for_each_possible_cpu(cpu){+new_map=xmap_dereference(new_dev_maps->cpu_map[cpu]);+map=xmap_dereference(dev_maps->cpu_map[cpu]);+if(map&&map!=new_map)+kfree_rcu(map,rcu);+}-if(nonempty){-rcu_assign_pointer(dev->xps_maps,new_dev_maps);-}else{-kfree(new_dev_maps);-RCU_INIT_POINTER(dev->xps_maps,NULL);+kfree_rcu(dev_maps,rcu);}-if(dev_maps)-kfree_rcu(dev_maps,rcu);+dev_maps=new_dev_maps;+active=true;+out_no_new_maps:+/* update Tx queue numa node */netdev_queue_numa_node_write(netdev_get_tx_queue(dev,index),(numa_node_id>=0)?numa_node_id:NUMA_NO_NODE);+if(!dev_maps)+gotoout_no_maps;++/* removes queue from unused CPUs */+for_each_possible_cpu(cpu){+if(cpumask_test_cpu(cpu,mask)&&cpu_online(cpu))+continue;++if(remove_xps_queue(dev_maps,cpu,index))+active=true;+}++/* free map if not active */+if(!active){+RCU_INIT_POINTER(dev->xps_maps,NULL);+kfree_rcu(dev_maps,rcu);+}++out_no_maps:mutex_unlock(&xps_map_mutex);return0;error:+/* remove any maps that we added */+for_each_possible_cpu(cpu){+new_map=xmap_dereference(new_dev_maps->cpu_map[cpu]);+map=dev_maps?xmap_dereference(dev_maps->cpu_map[cpu]):+NULL;+if(new_map&&new_map!=map)+kfree(new_map);+}+mutex_unlock(&xps_map_mutex);-if(new_dev_maps)-for_each_possible_cpu(i)-kfree(rcu_dereference_protected(-new_dev_maps->cpu_map[i],-1));kfree(new_dev_maps);return-ENOMEM;}
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:20
This patch makes it so that we can support transmit packet steering without
sysfs needing to be enabled. The reason for making this change is to make
it so that a driver can make use of the XPS even while the sysfs portion of
the interface is not present.
Signed-off-by: Alexander Duyck <redacted>
---
include/linux/netdevice.h | 1 -
net/Kconfig | 2 +-
net/core/dev.c | 26 ++++++++++++++++++++------
net/core/net-sysfs.c | 14 --------------
4 files changed, 21 insertions(+), 22 deletions(-)
@@ -1967,8 +1973,12 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)if(dev->num_tc)netif_setup_tc(dev,txq);-if(txq<dev->real_num_tx_queues)+if(txq<dev->real_num_tx_queues){qdisc_reset_all_tx_gt(dev,txq);+#ifdef CONFIG_XPS+netif_reset_xps_queues_gt(dev,txq);+#endif+}}dev->real_num_tx_queues=txq;
@@ -5460,6 +5470,10 @@ static void rollback_registered_many(struct list_head *head)/* Remove entries from kobject tree */netdev_unregister_kobject(dev);+#ifdef CONFIG_XPS+/* Remove XPS queueing entries */+netif_reset_xps_queues_gt(dev,0);+#endif}/* Process any work delayed until the end of the batch */
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:25
Instead of adjusting the FCoE and Flow director limits based on the number
of CPUs we can define them much sooner. This allows the user to come
through later and adjust them once we have updated the code to support the
set_channels ethtool operation.
I am still allowing for FCoE and RSS queues to be separated if the number
queues is less than the number of CPUs. This essentially treats the two
groupings like they are two separate traffic classes.
Signed-off-by: Alexander Duyck <redacted>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 7 +------
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 12 ++++++++----
2 files changed, 9 insertions(+), 10 deletions(-)
@@ -386,7 +386,6 @@ static bool ixgbe_set_dcb_sriov_queues(struct ixgbe_adapter *adapter)fcoe=&adapter->ring_feature[RING_F_FCOE];/* limit ourselves based on feature limits */-fcoe_i=min_t(u16,fcoe_i,num_online_cpus());fcoe_i=min_t(u16,fcoe_i,fcoe->limit);if(fcoe_i){
@@ -562,9 +561,6 @@ static bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter)fcoe_i=min_t(u16,fcoe_i,fcoe->limit);if(vmdq_i>1&&fcoe_i){-/* reserve no more than number of CPUs */-fcoe_i=min_t(u16,fcoe_i,num_online_cpus());-/* alloc queues for FCoE separately */fcoe->indices=fcoe_i;fcoe->offset=vmdq_i*rss_i;
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:30
This change adds support for ixgbe to configure the XPS queue mapping on
load. The result of this change is that on open we will now be resetting
the number of Tx queues, and then setting the default configuration for XPS
based on if ATR is enabled or disabled.
Signed-off-by: Alexander Duyck <redacted>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 3 +--
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 18 ++++++++++++++++++
2 files changed, 19 insertions(+), 2 deletions(-)
@@ -797,8 +797,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,/* setup affinity mask and node */if(cpu!=-1)cpumask_set_cpu(cpu,&q_vector->affinity_mask);-else-cpumask_copy(&q_vector->affinity_mask,cpu_online_mask);+q_vector->numa_node=node;/* initialize CPU for DCA */
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:35
This change updates the ixgbe driver to use __dev_pick_tx instead of the
current logic it is using to select a queue. The main result of this
change is that ixgbe can now fully support XPS.
Signed-off-by: Alexander Duyck <redacted>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 18 +++++++-----------
1 files changed, 7 insertions(+), 11 deletions(-)
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:40
This patch adds support for the ethtool get_channels operation.
Since the ixgbe driver has to support DCB as well as the other modes the
assumption I made here is that the number of channels in DCB modes refers
to the number of queues per traffic class, not the number of queues total.
Signed-off-by: Alexander Duyck <redacted>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 72 ++++++++++++++++++++++
1 files changed, 72 insertions(+), 0 deletions(-)
@@ -2703,6 +2703,77 @@ static int ixgbe_get_ts_info(struct net_device *dev,return0;}+staticunsignedintixgbe_max_channels(structixgbe_adapter*adapter)+{+unsignedintmax_combined;+u8tcs=netdev_get_num_tc(adapter->netdev);++if(!(adapter->flags&IXGBE_FLAG_MSIX_ENABLED)){+/* We only support one q_vector without MSI-X */+max_combined=1;+}elseif(adapter->flags&IXGBE_FLAG_SRIOV_ENABLED){+/* SR-IOV currently only allows one queue on the PF */+max_combined=1;+}elseif(tcs>1){+/* For DCB report channels per traffic class */+if(adapter->hw.mac.type==ixgbe_mac_82598EB){+/* 8 TC w/ 4 queues per TC */+max_combined=4;+}elseif(tcs>4){+/* 8 TC w/ 8 queues per TC */+max_combined=8;+}else{+/* 4 TC w/ 16 queues per TC */+max_combined=16;+}+}elseif(adapter->atr_sample_rate){+/* support up to 64 queues with ATR */+max_combined=IXGBE_MAX_FDIR_INDICES;+}else{+/* support up to 16 queues with RSS */+max_combined=IXGBE_MAX_RSS_INDICES;+}++returnmax_combined;+}++staticvoidixgbe_get_channels(structnet_device*dev,+structethtool_channels*ch)+{+structixgbe_adapter*adapter=netdev_priv(dev);++/* report maximum channels */+ch->max_combined=ixgbe_max_channels(adapter);++/* report info for other vector */+if(adapter->flags&IXGBE_FLAG_MSIX_ENABLED){+ch->max_other=NON_Q_VECTORS;+ch->other_count=NON_Q_VECTORS;+}++/* record RSS queues */+ch->combined_count=adapter->ring_feature[RING_F_RSS].indices;++/* nothing else to report if RSS is disabled */+if(ch->combined_count==1)+return;++/* we do not support ATR queueing if SR-IOV is enabled */+if(adapter->flags&IXGBE_FLAG_SRIOV_ENABLED)+return;++/* same thing goes for being DCB enabled */+if(netdev_get_num_tc(dev)>1)+return;++/* if ATR is disabled we can exit */+if(!adapter->atr_sample_rate)+return;++/* report flow director queues as maximum channels */+ch->combined_count=adapter->ring_feature[RING_F_FDIR].indices;+}+staticconststructethtool_opsixgbe_ethtool_ops={.get_settings=ixgbe_get_settings,.set_settings=ixgbe_set_settings,
From: Alexander Duyck <hidden> Date: 2012-06-30 00:16:45
This change adds support for the ethtool set_channels operation.
Since the ixgbe driver has to support DCB as well as the other modes the
assumption I made here is that the number of channels in DCB modes refers
to the number of queues per traffic class, not the number of queues total.
Signed-off-by: Alexander Duyck <redacted>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 40 ++++++++++++++++++++++
1 files changed, 40 insertions(+), 0 deletions(-)
@@ -2774,6 +2774,45 @@ static void ixgbe_get_channels(struct net_device *dev,ch->combined_count=adapter->ring_feature[RING_F_FDIR].indices;}+staticintixgbe_set_channels(structnet_device*dev,+structethtool_channels*ch)+{+structixgbe_adapter*adapter=netdev_priv(dev);+unsignedintcount=ch->combined_count;++/* verify they are not requesting separate vectors */+if(ch->rx_count||ch->tx_count)+return-EINVAL;++/* ignore other_count since it is not changeable */++/* verify we have at least one channel requested */+if(!count)+return-EINVAL;++/* verify the number of channels does not exceed hardware limits */+if(count>ixgbe_max_channels(adapter))+return-EINVAL;++/* update feature limits from largest to smallest supported values */+adapter->ring_feature[RING_F_FDIR].limit=count;++/* cap RSS limit at 16 */+if(count>IXGBE_MAX_RSS_INDICES)+count=IXGBE_MAX_RSS_INDICES;+adapter->ring_feature[RING_F_RSS].limit=count;++#ifdef IXGBE_FCOE+/* cap FCoE limit at 8 */+if(count>IXGBE_FCRETA_SIZE)+count=IXGBE_FCRETA_SIZE;+adapter->ring_feature[RING_F_FCOE].limit=count;++#endif+/* use setup TC to update any traffic class queue mapping */+returnixgbe_setup_tc(dev,netdev_get_num_tc(dev));+}+staticconststructethtool_opsixgbe_ethtool_ops={.get_settings=ixgbe_get_settings,.set_settings=ixgbe_set_settings,
From: Tom Herbert <hidden> Date: 2012-07-03 22:30:34
Hi Alexander,
Thanks for this work!
Some general comments:
1) skb_tx_hash is called from a handful of drivers (bnx2x, ixgbe,
mlx4, and bonding). Would it make sent to call xps_get_cpu from that
function (unfortunately the use of ndo_select_queue is likely
bypassing xps unnecessarily in these drivers).
2) Instead of (or maybe in addition to) allowing driver to program xps
maps, we could parameterize get_xps_cpu to optionally include a bit
map of acceptable queues. This would be useful to define a
hierarchical queue selection (like first choose a set for QoS, then
amongst those chose one base on xps).
Tom
On Fri, Jun 29, 2012 at 5:16 PM, Alexander Duyck
[off-list ref] wrote:
The following patch series makes it so that the ixgbe driver can support
ATR even when the number of queues is less than the number of CPUs. To do
this I have updated the kernel to support letting drivers set their own XPS
configuration. To do this it was necessary to move the code out of the
sysfs specific code and into the dev specific regions.
I am still working out a few issues such as the fact that with routing I
only ever seem to be able to get the first queue that is mapped to the CPU
when XPS is enabled.
Also I am looking for input on if it is acceptable to only let the
set_channels/get_channels calls report/set the number of queues per traffic
class as I implemented the code this way to avoid any significant conflicts
between the DCB traffic classes code and these functions.
---
Alexander Duyck (10):
ixgbe: Add support for set_channels ethtool operation
ixgbe: Add support for displaying the number of Tx/Rx channels
ixgbe: Update ixgbe driver to use __dev_pick_tx in ixgbe_select_queue
ixgbe: Add function for setting XPS queue mapping
ixgbe: Define FCoE and Flow director limits much sooner to allow for changes
net: Add support for XPS without SYSFS being defined
net: Rewrite netif_set_xps_queues to address several issues
net: Rewrite netif_reset_xps_queue to allow for better code reuse
net: Add functions netif_reset_xps_queue and netif_set_xps_queue
net: Split core bits of dev_pick_tx into __dev_pick_tx
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 112 +++++++++
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 10 -
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 48 +++-
include/linux/netdevice.h | 15 +
net/Kconfig | 2
net/core/dev.c | 283 ++++++++++++++++++++--
net/core/net-sysfs.c | 160 ------------
7 files changed, 428 insertions(+), 202 deletions(-)
--
Thanks,
Alex
From: John Fastabend <hidden> Date: 2012-07-03 22:42:00
On 7/3/2012 3:30 PM, Tom Herbert wrote:
Hi Alexander,
Thanks for this work!
Some general comments:
1) skb_tx_hash is called from a handful of drivers (bnx2x, ixgbe,
mlx4, and bonding). Would it make sent to call xps_get_cpu from that
function (unfortunately the use of ndo_select_queue is likely
bypassing xps unnecessarily in these drivers).
I suspect we can get rid of the select_queue cases for at least
bnx2x, ixgbe, and mlx4. We might need to be a bit clever to resolve
the mlx4 case but should be doable.
Anyways I would like to see these cases refactored away.
2) Instead of (or maybe in addition to) allowing driver to program xps
maps, we could parameterize get_xps_cpu to optionally include a bit
map of acceptable queues. This would be useful to define a
hierarchical queue selection (like first choose a set for QoS, then
amongst those chose one base on xps).
Agreed.
We likely need something like (2) to get this to work with mqprio and
other QOS schemes in use.
.John
From: Ben Hutchings <hidden> Date: 2012-07-07 00:03:27
On Fri, 2012-06-29 at 17:16 -0700, Alexander Duyck wrote:
This change splits the core bits of dev_pick_tx into a separate function.
The main idea behind this is to make this code accessible to select queue
functions when they decide to process the standard path instead of their
own custom path in their select queue routine.
[...]
I like this. Uninlining that code is going to cost some cycles, but
hopefully not enough to worry about.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
From: Ben Hutchings <hidden> Date: 2012-07-11 18:15:12
On Fri, 2012-06-29 at 17:16 -0700, Alexander Duyck wrote:
This change adds support for ixgbe to configure the XPS queue mapping on
load. The result of this change is that on open we will now be resetting
the number of Tx queues, and then setting the default configuration for XPS
based on if ATR is enabled or disabled.
[...]
I didn't see where you're resetting the number of TX queues; was that
actually added in an earlier patch?
It seems strange to be resetting XPS configuration on open; normally net
device configuration persists as long as the device is registered.
Maybe only do this if the number of TX queues has to change?
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
From: Ben Hutchings <hidden> Date: 2012-07-11 18:21:47
On Fri, 2012-06-29 at 17:16 -0700, Alexander Duyck wrote:
This patch adds support for the ethtool get_channels operation.
Since the ixgbe driver has to support DCB as well as the other modes the
assumption I made here is that the number of channels in DCB modes refers
to the number of queues per traffic class, not the number of queues total.
[...]
When MSI-X is enabled, a 'channel' is an MSI-X vector and the associated
queues, i.e. total number of channels reported should be the total
number of MSI-X vectors in use. (That was my intended interpretation,
anyway. It may be that there is too much variation in the way queues
and interrupts are associated for these operations to be defined in a
general way.)
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
From: Alexander Duyck <hidden> Date: 2012-07-11 21:00:03
On 07/11/2012 11:21 AM, Ben Hutchings wrote:
On Fri, 2012-06-29 at 17:16 -0700, Alexander Duyck wrote:
quoted
This patch adds support for the ethtool get_channels operation.
Since the ixgbe driver has to support DCB as well as the other modes the
assumption I made here is that the number of channels in DCB modes refers
to the number of queues per traffic class, not the number of queues total.
[...]
When MSI-X is enabled, a 'channel' is an MSI-X vector and the associated
queues, i.e. total number of channels reported should be the total
number of MSI-X vectors in use. (That was my intended interpretation,
anyway. It may be that there is too much variation in the way queues
and interrupts are associated for these operations to be defined in a
general way.)
Ben.
The problem with the MSI-X interpretation is that ixgbe has that type of
control reversed. We base everything on the number of queues, and then
from that you can end up determining the number of MSI-X vectors. So
for example we could tell ixgbe via this interface to generate 64
queues, but if the system only has 8 CPUs we would end up with 8 MSI-X
vectors each with 8 queues.
Also as I mentioned in the case of DCB things get even more
complicated. We need to have a symmetric number of queues per traffic
class based on the way we currently have DCB implemented. The way I saw
it I could go two routes, the first being to force channels to be a
multiple of TCs which would have been complicated to deal with, or the
simpler approach I chose which was to apply 'channel' to be per TC.
This way if DCB is then disabled we can easily revert to the standard
interpretation which would mean we would only have as many queues as the
channels specified.
Thanks,
Alex
From: Alexander Duyck <hidden> Date: 2012-07-11 21:12:58
On 07/11/2012 11:15 AM, Ben Hutchings wrote:
On Fri, 2012-06-29 at 17:16 -0700, Alexander Duyck wrote:
quoted
This change adds support for ixgbe to configure the XPS queue mapping on
load. The result of this change is that on open we will now be resetting
the number of Tx queues, and then setting the default configuration for XPS
based on if ATR is enabled or disabled.
[...]
I didn't see where you're resetting the number of TX queues; was that
actually added in an earlier patch?
It seems strange to be resetting XPS configuration on open; normally net
device configuration persists as long as the device is registered.
Maybe only do this if the number of TX queues has to change?
Ben.
Actually I am working on top of a set of patches for ixgbe that haven't
been submitted upstream. In one of those patches I moved our call to
netif_set_real_num_tx_queues into ixgbe_open. The call is only one or
two lines above the call I make to ixgbe_set_xps_mapping.
I will see what I can do about resetting the settings only when we
change the number of queues.
Thanks,
Alex