|
@@ -2067,11 +2067,13 @@ int netdev_txq_to_tc(struct net_device *dev, unsigned int txq)
|
|
|
struct netdev_tc_txq *tc = &dev->tc_to_txq[0];
|
|
|
int i;
|
|
|
|
|
|
+ /* walk through the TCs and see if it falls into any of them */
|
|
|
for (i = 0; i < TC_MAX_QUEUE; i++, tc++) {
|
|
|
if ((txq - tc->offset) < tc->count)
|
|
|
return i;
|
|
|
}
|
|
|
|
|
|
+ /* didn't find it, just return -1 to indicate no match */
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
@@ -2260,7 +2262,14 @@ int __netif_set_xps_queue(struct net_device *dev, const unsigned long *mask,
|
|
|
unsigned int nr_ids;
|
|
|
|
|
|
if (dev->num_tc) {
|
|
|
+ /* Do not allow XPS on subordinate device directly */
|
|
|
num_tc = dev->num_tc;
|
|
|
+ if (num_tc < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* If queue belongs to subordinate dev use its map */
|
|
|
+ dev = netdev_get_tx_queue(dev, index)->sb_dev ? : dev;
|
|
|
+
|
|
|
tc = netdev_txq_to_tc(dev, index);
|
|
|
if (tc < 0)
|
|
|
return -EINVAL;
|
|
@@ -2448,11 +2457,25 @@ int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask,
|
|
|
EXPORT_SYMBOL(netif_set_xps_queue);
|
|
|
|
|
|
#endif
|
|
|
+static void netdev_unbind_all_sb_channels(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct netdev_queue *txq = &dev->_tx[dev->num_tx_queues];
|
|
|
+
|
|
|
+ /* Unbind any subordinate channels */
|
|
|
+ while (txq-- != &dev->_tx[0]) {
|
|
|
+ if (txq->sb_dev)
|
|
|
+ netdev_unbind_sb_channel(dev, txq->sb_dev);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void netdev_reset_tc(struct net_device *dev)
|
|
|
{
|
|
|
#ifdef CONFIG_XPS
|
|
|
netif_reset_xps_queues_gt(dev, 0);
|
|
|
#endif
|
|
|
+ netdev_unbind_all_sb_channels(dev);
|
|
|
+
|
|
|
+ /* Reset TC configuration of device */
|
|
|
dev->num_tc = 0;
|
|
|
memset(dev->tc_to_txq, 0, sizeof(dev->tc_to_txq));
|
|
|
memset(dev->prio_tc_map, 0, sizeof(dev->prio_tc_map));
|
|
@@ -2481,11 +2504,77 @@ int netdev_set_num_tc(struct net_device *dev, u8 num_tc)
|
|
|
#ifdef CONFIG_XPS
|
|
|
netif_reset_xps_queues_gt(dev, 0);
|
|
|
#endif
|
|
|
+ netdev_unbind_all_sb_channels(dev);
|
|
|
+
|
|
|
dev->num_tc = num_tc;
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(netdev_set_num_tc);
|
|
|
|
|
|
+void netdev_unbind_sb_channel(struct net_device *dev,
|
|
|
+ struct net_device *sb_dev)
|
|
|
+{
|
|
|
+ struct netdev_queue *txq = &dev->_tx[dev->num_tx_queues];
|
|
|
+
|
|
|
+#ifdef CONFIG_XPS
|
|
|
+ netif_reset_xps_queues_gt(sb_dev, 0);
|
|
|
+#endif
|
|
|
+ memset(sb_dev->tc_to_txq, 0, sizeof(sb_dev->tc_to_txq));
|
|
|
+ memset(sb_dev->prio_tc_map, 0, sizeof(sb_dev->prio_tc_map));
|
|
|
+
|
|
|
+ while (txq-- != &dev->_tx[0]) {
|
|
|
+ if (txq->sb_dev == sb_dev)
|
|
|
+ txq->sb_dev = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(netdev_unbind_sb_channel);
|
|
|
+
|
|
|
+int netdev_bind_sb_channel_queue(struct net_device *dev,
|
|
|
+ struct net_device *sb_dev,
|
|
|
+ u8 tc, u16 count, u16 offset)
|
|
|
+{
|
|
|
+ /* Make certain the sb_dev and dev are already configured */
|
|
|
+ if (sb_dev->num_tc >= 0 || tc >= dev->num_tc)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* We cannot hand out queues we don't have */
|
|
|
+ if ((offset + count) > dev->real_num_tx_queues)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* Record the mapping */
|
|
|
+ sb_dev->tc_to_txq[tc].count = count;
|
|
|
+ sb_dev->tc_to_txq[tc].offset = offset;
|
|
|
+
|
|
|
+ /* Provide a way for Tx queue to find the tc_to_txq map or
|
|
|
+ * XPS map for itself.
|
|
|
+ */
|
|
|
+ while (count--)
|
|
|
+ netdev_get_tx_queue(dev, count + offset)->sb_dev = sb_dev;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(netdev_bind_sb_channel_queue);
|
|
|
+
|
|
|
+int netdev_set_sb_channel(struct net_device *dev, u16 channel)
|
|
|
+{
|
|
|
+ /* Do not use a multiqueue device to represent a subordinate channel */
|
|
|
+ if (netif_is_multiqueue(dev))
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ /* We allow channels 1 - 32767 to be used for subordinate channels.
|
|
|
+ * Channel 0 is meant to be "native" mode and used only to represent
|
|
|
+ * the main root device. We allow writing 0 to reset the device back
|
|
|
+ * to normal mode after being used as a subordinate channel.
|
|
|
+ */
|
|
|
+ if (channel > S16_MAX)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ dev->num_tc = -channel;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(netdev_set_sb_channel);
|
|
|
+
|
|
|
/*
|
|
|
* Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
|
|
|
* greater than real_num_tx_queues stale skbs on the qdisc must be flushed.
|