1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #include <linux/netdevice.h> 4 #include <net/netdev_queues.h> 5 #include <net/netdev_rx_queue.h> 6 7 int netdev_rx_queue_restart(struct net_device *dev, unsigned int rxq_idx) 8 { 9 void *new_mem, *old_mem; 10 int err; 11 12 if (!dev->queue_mgmt_ops || !dev->queue_mgmt_ops->ndo_queue_stop || 13 !dev->queue_mgmt_ops->ndo_queue_mem_free || 14 !dev->queue_mgmt_ops->ndo_queue_mem_alloc || 15 !dev->queue_mgmt_ops->ndo_queue_start) 16 return -EOPNOTSUPP; 17 18 ASSERT_RTNL(); 19 20 new_mem = kvzalloc(dev->queue_mgmt_ops->ndo_queue_mem_size, GFP_KERNEL); 21 if (!new_mem) 22 return -ENOMEM; 23 24 old_mem = kvzalloc(dev->queue_mgmt_ops->ndo_queue_mem_size, GFP_KERNEL); 25 if (!old_mem) { 26 err = -ENOMEM; 27 goto err_free_new_mem; 28 } 29 30 err = dev->queue_mgmt_ops->ndo_queue_mem_alloc(dev, new_mem, rxq_idx); 31 if (err) 32 goto err_free_old_mem; 33 34 err = dev->queue_mgmt_ops->ndo_queue_stop(dev, old_mem, rxq_idx); 35 if (err) 36 goto err_free_new_queue_mem; 37 38 err = dev->queue_mgmt_ops->ndo_queue_start(dev, new_mem, rxq_idx); 39 if (err) 40 goto err_start_queue; 41 42 dev->queue_mgmt_ops->ndo_queue_mem_free(dev, old_mem); 43 44 kvfree(old_mem); 45 kvfree(new_mem); 46 47 return 0; 48 49 err_start_queue: 50 /* Restarting the queue with old_mem should be successful as we haven't 51 * changed any of the queue configuration, and there is not much we can 52 * do to recover from a failure here. 53 * 54 * WARN if we fail to recover the old rx queue, and at least free 55 * old_mem so we don't also leak that. 56 */ 57 if (dev->queue_mgmt_ops->ndo_queue_start(dev, old_mem, rxq_idx)) { 58 WARN(1, 59 "Failed to restart old queue in error path. RX queue %d may be unhealthy.", 60 rxq_idx); 61 dev->queue_mgmt_ops->ndo_queue_mem_free(dev, old_mem); 62 } 63 64 err_free_new_queue_mem: 65 dev->queue_mgmt_ops->ndo_queue_mem_free(dev, new_mem); 66 67 err_free_old_mem: 68 kvfree(old_mem); 69 70 err_free_new_mem: 71 kvfree(new_mem); 72 73 return err; 74 } 75