diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 89 | 
1 files changed, 89 insertions, 0 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 89825c1eccdc..cc1d6bba017a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -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.  | 
