igc: Refactor runtime power management flow
authorSasha Neftin <sasha.neftin@intel.com>
Sun, 11 Feb 2024 07:30:58 +0000 (09:30 +0200)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Fri, 29 Mar 2024 15:58:43 +0000 (08:58 -0700)
Following the corresponding discussion [1] and [2] refactor the 'igc_open'
method and avoid taking the rtnl_lock() during the 'igc_resume' method.
The rtnl_lock is held by the upper layer and could lead to the deadlock
during resuming from a runtime power management flow. Notify the stack of
the actual queue counts 'netif_set_real_num_*_queues' outside the
'_igc_open' wrapper. This notification doesn't have to be called on each
resume.

Test:
1. Disconnect the ethernet cable
2. Enable the runtime power management via file system:
echo auto > /sys/devices/pci0000\.../power/control
3. Check the device state (lspci -s <device> -vvv | grep -i Status)

Link: https://lore.kernel.org/netdev/20231206113934.8d7819857574.I2deb5804
ef1739a2af307283d320ef7d82456494@changeid/#r [1]
Link: https://lore.kernel.org/netdev/20211125074949.5f897431@kicinski-fedo
ra-pc1c0hjn.dhcp.thefacebook.com/t/ [2]
Signed-off-by: Sasha Neftin <sasha.neftin@intel.com>
Tested-by: Naama Meir <naamax.meir@linux.intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/igc/igc_main.c

index 998d8c3..d9bd001 100644 (file)
@@ -5929,15 +5929,6 @@ static int __igc_open(struct net_device *netdev, bool resuming)
        if (err)
                goto err_req_irq;
 
-       /* Notify the stack of the actual queue counts. */
-       err = netif_set_real_num_tx_queues(netdev, adapter->num_tx_queues);
-       if (err)
-               goto err_set_queues;
-
-       err = netif_set_real_num_rx_queues(netdev, adapter->num_rx_queues);
-       if (err)
-               goto err_set_queues;
-
        clear_bit(__IGC_DOWN, &adapter->state);
 
        for (i = 0; i < adapter->num_q_vectors; i++)
@@ -5958,8 +5949,6 @@ static int __igc_open(struct net_device *netdev, bool resuming)
 
        return IGC_SUCCESS;
 
-err_set_queues:
-       igc_free_irq(adapter);
 err_req_irq:
        igc_release_hw_control(adapter);
        igc_power_down_phy_copper_base(&adapter->hw);
@@ -5976,6 +5965,17 @@ err_setup_tx:
 
 int igc_open(struct net_device *netdev)
 {
+       struct igc_adapter *adapter = netdev_priv(netdev);
+       int err;
+
+       /* Notify the stack of the actual queue counts. */
+       err = netif_set_real_num_queues(netdev, adapter->num_tx_queues,
+                                       adapter->num_rx_queues);
+       if (err) {
+               netdev_err(netdev, "error setting real queue count\n");
+               return err;
+       }
+
        return __igc_open(netdev, false);
 }
 
@@ -7181,13 +7181,11 @@ static int igc_resume(struct device *dev)
 
        wr32(IGC_WUS, ~0);
 
-       rtnl_lock();
-       if (!err && netif_running(netdev))
+       if (netif_running(netdev)) {
                err = __igc_open(netdev, true);
-
-       if (!err)
-               netif_device_attach(netdev);
-       rtnl_unlock();
+               if (!err)
+                       netif_device_attach(netdev);
+       }
 
        return err;
 }