[PATCH net-next v9 4/7] e1000: Implement ndo_set_rx_mode_async callback

I Viswanath posted 7 patches 3 weeks, 2 days ago
[PATCH net-next v9 4/7] e1000: Implement ndo_set_rx_mode_async callback
Posted by I Viswanath 3 weeks, 2 days ago
Implement the ndo_set_rx_mode_async callback and update
the driver to use the snapshot/commit model for RX mode update.

Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
---

Call paths involving netif_set_rx_mode in e1000

netif_set_rx_mode
|-- __e1000_shutdown (lock added)
|
`-- e1000_configure
    |-- e1000_open (ndo_open, takes lock)
    |
    `-- e1000_up
        |-- e1000_reinit_locked
        |   |-- e1000_set_features (ndo_set_features, takes lock)
        |   |-- e1000_reset_task (ethtool callback, takes lock)
        |   |-- e1000_mii_ioctl
        |   |   `-- e1000_ioctl (ndo_do_ioctl, takes lock)
        |   `-- e1000_nway_reset (ethtool callback, takes lock)
        |
        |-- e1000_change_mtu (ndo_change_mtu, takes lock)
        |-- e1000_resume (lock added)
        |-- e1000_io_resume (lock added)
        |
        |-- e1000_set_link_ksettings (ethtool callback, takes lock)
        |-- e1000_set_pauseparam (ethtool callback, takes lock)
        `-- e1000_set_ringparam (ethtool callback, takes lock)

 drivers/net/ethernet/intel/e1000/e1000_main.c | 77 ++++++++++++++-----
 1 file changed, 59 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 9b09eb144b81..ec25b41c63b7 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -99,6 +99,7 @@ static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
 static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
 				struct e1000_rx_ring *rx_ring);
 static void e1000_set_rx_mode(struct net_device *netdev);
+static void e1000_set_rx_mode_async(struct net_device *netdev);
 static void e1000_update_phy_info_task(struct work_struct *work);
 static void e1000_watchdog(struct work_struct *work);
 static void e1000_82547_tx_fifo_stall_task(struct work_struct *work);
@@ -359,7 +360,7 @@ static void e1000_configure(struct e1000_adapter *adapter)
 	struct net_device *netdev = adapter->netdev;
 	int i;
 
-	e1000_set_rx_mode(netdev);
+	netif_set_rx_mode(netdev);
 
 	e1000_restore_vlan(adapter);
 	e1000_init_manageability(adapter);
@@ -823,6 +824,7 @@ static const struct net_device_ops e1000_netdev_ops = {
 	.ndo_stop		= e1000_close,
 	.ndo_start_xmit		= e1000_xmit_frame,
 	.ndo_set_rx_mode	= e1000_set_rx_mode,
+	.ndo_set_rx_mode_async	= e1000_set_rx_mode_async,
 	.ndo_set_mac_address	= e1000_set_mac,
 	.ndo_tx_timeout		= e1000_tx_timeout,
 	.ndo_change_mtu		= e1000_change_mtu,
@@ -2223,23 +2225,44 @@ static int e1000_set_mac(struct net_device *netdev, void *p)
 }
 
 /**
- * e1000_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
+ * e1000_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode
+ * config.
  * @netdev: network interface device structure
  *
  * The set_rx_mode entry point is called whenever the unicast or multicast
  * address lists or the network interface flags are updated. This routine is
- * responsible for configuring the hardware for proper unicast, multicast,
- * promiscuous mode, and all-multi behavior.
+ * responsible for preparing the rx mode config and scheduling the rx_mode
+ * work which invokes the set_rx_mode_async callback.
  **/
 static void e1000_set_rx_mode(struct net_device *netdev)
+{
+	bool allmulti = !!(netdev->flags & IFF_ALLMULTI);
+	bool promisc = !!(netdev->flags & IFF_PROMISC);
+
+	netif_set_rx_mode_flag(netdev, NETIF_RX_MODE_UC_SKIP, promisc);
+
+	netif_set_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_ALLMULTI, allmulti);
+	netif_set_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_PROMISC, promisc);
+}
+
+/**
+ * e1000_set_rx_mode_async - Secondary Unicast, Multicast and Promiscuous mode
+ * confirm.
+ * @netdev: network interface device structure
+ *
+ * The set_rx_mode_async callback is responsible for actually updating the
+ * hardware. This routine is responsible for configuring the hardware for
+ * proper unicast, multicast, promiscuous mode, and all-multi behavior.
+ **/
+static void e1000_set_rx_mode_async(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	struct netdev_hw_addr *ha;
 	bool use_uc = false;
+	char *ha_addr;
 	u32 rctl;
 	u32 hash_value;
-	int i, rar_entries = E1000_RAR_ENTRIES;
+	int i, rar_entries = E1000_RAR_ENTRIES, ni;
 	int mta_reg_count = E1000_NUM_MTA_REGISTERS;
 	u32 *mcarray = kcalloc(mta_reg_count, sizeof(u32), GFP_ATOMIC);
 
@@ -2250,11 +2273,11 @@ static void e1000_set_rx_mode(struct net_device *netdev)
 
 	rctl = er32(RCTL);
 
-	if (netdev->flags & IFF_PROMISC) {
+	if (netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_PROMISC)) {
 		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
 		rctl &= ~E1000_RCTL_VFE;
 	} else {
-		if (netdev->flags & IFF_ALLMULTI)
+		if (netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_ALLMULTI))
 			rctl |= E1000_RCTL_MPE;
 		else
 			rctl &= ~E1000_RCTL_MPE;
@@ -2263,9 +2286,9 @@ static void e1000_set_rx_mode(struct net_device *netdev)
 			rctl |= E1000_RCTL_VFE;
 	}
 
-	if (netdev_uc_count(netdev) > rar_entries - 1) {
+	if (netif_rx_mode_uc_count(netdev) > rar_entries - 1) {
 		rctl |= E1000_RCTL_UPE;
-	} else if (!(netdev->flags & IFF_PROMISC)) {
+	} else if (!netif_get_rx_mode_cfg(netdev, NETIF_RX_MODE_CFG_PROMISC)) {
 		rctl &= ~E1000_RCTL_UPE;
 		use_uc = true;
 	}
@@ -2286,23 +2309,23 @@ static void e1000_set_rx_mode(struct net_device *netdev)
 	 */
 	i = 1;
 	if (use_uc)
-		netdev_for_each_uc_addr(ha, netdev) {
+		netif_rx_mode_for_each_uc_addr(ha_addr, netdev, ni) {
 			if (i == rar_entries)
 				break;
-			e1000_rar_set(hw, ha->addr, i++);
+			e1000_rar_set(hw, ha_addr, i++);
 		}
 
-	netdev_for_each_mc_addr(ha, netdev) {
+	netif_rx_mode_for_each_mc_addr(ha_addr, netdev, ni) {
 		if (i == rar_entries) {
 			/* load any remaining addresses into the hash table */
 			u32 hash_reg, hash_bit, mta;
-			hash_value = e1000_hash_mc_addr(hw, ha->addr);
+			hash_value = e1000_hash_mc_addr(hw, ha_addr);
 			hash_reg = (hash_value >> 5) & 0x7F;
 			hash_bit = hash_value & 0x1F;
 			mta = (1 << hash_bit);
 			mcarray[hash_reg] |= mta;
 		} else {
-			e1000_rar_set(hw, ha->addr, i++);
+			e1000_rar_set(hw, ha_addr, i++);
 		}
 	}
 
@@ -5092,7 +5115,10 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
 
 	if (wufc) {
 		e1000_setup_rctl(adapter);
-		e1000_set_rx_mode(netdev);
+
+		rtnl_lock();
+		netif_set_rx_mode(netdev);
+		rtnl_unlock();
 
 		rctl = er32(RCTL);
 
@@ -5150,11 +5176,13 @@ static int e1000_suspend(struct device *dev)
 {
 	int retval;
 	struct pci_dev *pdev = to_pci_dev(dev);
+	struct net_device *netdev = pci_get_drvdata(pdev);
 	bool wake;
 
 	retval = __e1000_shutdown(pdev, &wake);
 	device_set_wakeup_enable(dev, wake);
 
+	netif_disable_async_ops(netdev);
 	return retval;
 }
 
@@ -5166,6 +5194,8 @@ static int e1000_resume(struct device *dev)
 	struct e1000_hw *hw = &adapter->hw;
 	u32 err;
 
+	netif_enable_async_ops(netdev);
+
 	if (adapter->need_ioport)
 		err = pci_enable_device(pdev);
 	else
@@ -5195,8 +5225,11 @@ static int e1000_resume(struct device *dev)
 
 	e1000_init_manageability(adapter);
 
-	if (netif_running(netdev))
+	if (netif_running(netdev)) {
+		rtnl_lock();
 		e1000_up(adapter);
+		rtnl_unlock();
+	}
 
 	netif_device_attach(netdev);
 
@@ -5205,6 +5238,7 @@ static int e1000_resume(struct device *dev)
 
 static void e1000_shutdown(struct pci_dev *pdev)
 {
+	struct net_device *netdev = pci_get_drvdata(pdev);
 	bool wake;
 
 	__e1000_shutdown(pdev, &wake);
@@ -5213,6 +5247,8 @@ static void e1000_shutdown(struct pci_dev *pdev)
 		pci_wake_from_d3(pdev, wake);
 		pci_set_power_state(pdev, PCI_D3hot);
 	}
+
+	netif_disable_async_ops(netdev);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -5312,11 +5348,16 @@ static void e1000_io_resume(struct pci_dev *pdev)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev_priv(netdev);
+	int rc;
 
 	e1000_init_manageability(adapter);
 
 	if (netif_running(netdev)) {
-		if (e1000_up(adapter)) {
+		rtnl_lock();
+		rc = e1000_up(adapter);
+		rtnl_unlock();
+
+		if (rc) {
 			pr_info("can't bring device back up after reset\n");
 			return;
 		}
-- 
2.47.3
RE: [Intel-wired-lan] [PATCH net-next v9 4/7] e1000: Implement ndo_set_rx_mode_async callback
Posted by Loktionov, Aleksandr 3 weeks, 1 day ago

> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of I Viswanath
> Sent: Saturday, March 14, 2026 7:28 PM
> To: stfomichev@gmail.com; horms@kernel.org; edumazet@google.com;
> pabeni@redhat.com; andrew+netdev@lunn.ch; kuba@kernel.org;
> davem@davemloft.net; eperezma@redhat.com; xuanzhuo@linux.alibaba.com;
> jasowang@redhat.com; mst@redhat.com; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Keller, Jacob E
> <jacob.e.keller@intel.com>; ronak.doshi@broadcom.com;
> pcnet32@frontier.com
> Cc: bcm-kernel-feedback-list@broadcom.com; netdev@vger.kernel.org;
> virtualization@lists.linux.dev; intel-wired-lan@lists.osuosl.org;
> linux-kernel@vger.kernel.org; I Viswanath
> <viswanathiyyappan@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net-next v9 4/7] e1000: Implement
> ndo_set_rx_mode_async callback
> 
> Implement the ndo_set_rx_mode_async callback and update the driver to
> use the snapshot/commit model for RX mode update.
> 
> Signed-off-by: I Viswanath <viswanathiyyappan@gmail.com>
> ---
> 
> Call paths involving netif_set_rx_mode in e1000
> 
> netif_set_rx_mode
> |-- __e1000_shutdown (lock added)
> |
> `-- e1000_configure
>     |-- e1000_open (ndo_open, takes lock)
>     |
>     `-- e1000_up
>         |-- e1000_reinit_locked
>         |   |-- e1000_set_features (ndo_set_features, takes lock)
>         |   |-- e1000_reset_task (ethtool callback, takes lock)
>         |   |-- e1000_mii_ioctl
>         |   |   `-- e1000_ioctl (ndo_do_ioctl, takes lock)
>         |   `-- e1000_nway_reset (ethtool callback, takes lock)
>         |
>         |-- e1000_change_mtu (ndo_change_mtu, takes lock)
>         |-- e1000_resume (lock added)
>         |-- e1000_io_resume (lock added)
>         |
>         |-- e1000_set_link_ksettings (ethtool callback, takes lock)
>         |-- e1000_set_pauseparam (ethtool callback, takes lock)
>         `-- e1000_set_ringparam (ethtool callback, takes lock)
> 
>  drivers/net/ethernet/intel/e1000/e1000_main.c | 77 ++++++++++++++----
> -
>  1 file changed, 59 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c
> b/drivers/net/ethernet/intel/e1000/e1000_main.c
> index 9b09eb144b81..ec25b41c63b7 100644
> --- a/drivers/net/ethernet/intel/e1000/e1000_main.c
> +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
> @@ -99,6 +99,7 @@ static void e1000_clean_tx_ring(struct e1000_adapter
> *adapter,  static void e1000_clean_rx_ring(struct e1000_adapter
> *adapter,
>  				struct e1000_rx_ring *rx_ring);
>  static void e1000_set_rx_mode(struct net_device *netdev);
> +static void e1000_set_rx_mode_async(struct net_device *netdev);
>  static void e1000_update_phy_info_task(struct work_struct *work);
> static void e1000_watchdog(struct work_struct *work);  static void
> e1000_82547_tx_fifo_stall_task(struct work_struct *work); @@ -359,7
> +360,7 @@ static void e1000_configure(struct e1000_adapter *adapter)
>  	struct net_device *netdev = adapter->netdev;
>  	int i;
> 

...

>  		}
> --
> 2.47.3

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>