[patch V2 11/36] net: ionic: Replace in_interrupt() usage.

Shannon Nelson snelson at pensando.io
Tue Sep 29 19:06:59 EDT 2020


On 9/29/20 1:25 PM, Thomas Gleixner wrote:
> From: Sebastian Andrzej Siewior <bigeasy at linutronix.de>
>
> The in_interrupt() usage in this driver tries to figure out which context
> may sleep and which context may not sleep. in_interrupt() is not really
> suitable as it misses both preemption disabled and interrupt disabled
> invocations from task context.
>
> Conditionals like that in driver code are frowned upon in general because
> invocations of functions from invalid contexts might not be detected
> as the conditional papers over it.
>
> ionic_lif_addr() and _ionoc_lif_rx_mode() can be called from:
>
>   1) ->ndo_set_rx_mode() which is under netif_addr_lock_bh()) so it must not
>      sleep.
>
>   2) Init and setup functions which are in fully preemptible task context.
>
> ionic_link_status_check_request() has two call paths:
>
>   1) NAPI which obviously cannot sleep
>
>   2) Setup which is again fully preemptible task context
>
> Add arguments which convey the execution context to the affected functions
> and let the callers provide the context instead of letting the functions
> deduce it.
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy at linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
> ---
> V2: Treat _ionoc_lif_rx_mode() correclty (Shannon)

Is it fair to poke at the comments?
s/ionoc/ionic/
s/correclty/correctly/

> ---
>   drivers/net/ethernet/pensando/ionic/ionic_dev.c |    2
>   drivers/net/ethernet/pensando/ionic/ionic_lif.c |   64 ++++++++++++++++--------
>   drivers/net/ethernet/pensando/ionic/ionic_lif.h |    2
>   3 files changed, 47 insertions(+), 21 deletions(-)
>
> --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
> @@ -22,7 +22,7 @@ static void ionic_watchdog_cb(struct tim
>   	hb = ionic_heartbeat_check(ionic);
>   
>   	if (hb >= 0 && ionic->lif)
> -		ionic_link_status_check_request(ionic->lif);
> +		ionic_link_status_check_request(ionic->lif, false);
>   }
>   
>   void ionic_init_devinfo(struct ionic *ionic)
> --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
> @@ -151,7 +151,7 @@ static void ionic_link_status_check(stru
>   	clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
>   }
>   
> -void ionic_link_status_check_request(struct ionic_lif *lif)
> +void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep)
>   {
>   	struct ionic_deferred_work *work;
>   
> @@ -159,7 +159,7 @@ void ionic_link_status_check_request(str
>   	if (test_and_set_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
>   		return;
>   
> -	if (in_interrupt()) {
> +	if (!can_sleep) {
>   		work = kzalloc(sizeof(*work), GFP_ATOMIC);
>   		if (!work)
>   			return;
> @@ -798,7 +798,7 @@ static bool ionic_notifyq_service(struct
>   
>   	switch (le16_to_cpu(comp->event.ecode)) {
>   	case IONIC_EVENT_LINK_CHANGE:
> -		ionic_link_status_check_request(lif);
> +		ionic_link_status_check_request(lif, false);
>   		break;
>   	case IONIC_EVENT_RESET:
>   		work = kzalloc(sizeof(*work), GFP_ATOMIC);
> @@ -981,7 +981,8 @@ static int ionic_lif_addr_del(struct ion
>   	return 0;
>   }
>   
> -static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add)
> +static int ionic_lif_addr(struct ionic_lif *lif, const u8 *addr, bool add,
> +			  bool can_sleep)
>   {
>   	struct ionic *ionic = lif->ionic;
>   	struct ionic_deferred_work *work;
> @@ -1010,7 +1011,7 @@ static int ionic_lif_addr(struct ionic_l
>   			lif->nucast--;
>   	}
>   
> -	if (in_interrupt()) {
> +	if (!can_sleep) {
>   		work = kzalloc(sizeof(*work), GFP_ATOMIC);
>   		if (!work) {
>   			netdev_err(lif->netdev, "%s OOM\n", __func__);
> @@ -1036,12 +1037,22 @@ static int ionic_lif_addr(struct ionic_l
>   
>   static int ionic_addr_add(struct net_device *netdev, const u8 *addr)
>   {
> -	return ionic_lif_addr(netdev_priv(netdev), addr, true);
> +	return ionic_lif_addr(netdev_priv(netdev), addr, true, true);
> +}
> +
> +static int ionic_ndo_addr_add(struct net_device *netdev, const u8 *addr)
> +{
> +	return ionic_lif_addr(netdev_priv(netdev), addr, true, false);
>   }
>   
>   static int ionic_addr_del(struct net_device *netdev, const u8 *addr)
>   {
> -	return ionic_lif_addr(netdev_priv(netdev), addr, false);
> +	return ionic_lif_addr(netdev_priv(netdev), addr, false, true);
> +}
> +
> +static int ionic_ndo_addr_del(struct net_device *netdev, const u8 *addr)
> +{
> +	return ionic_lif_addr(netdev_priv(netdev), addr, false, false);
>   }

These changes are reasonable, tho' I'm not fond of parameter lists of 
"true" and "false" with no context.  I'd prefer to have some constants like
#define can_sleep true
so the code can be a little more readable.

Yes, I know we have this problem already in the call to 
ionic_lif_addr(), which I'm annoyed with but haven't addressed yet.

So, if you want to deal with this now, fine, otherwise I'll take care of 
them both later.

Meanwhile,

Acked-by: Shannon Nelson <snelson at pensando.io>




>   
>   static void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode)
> @@ -1081,11 +1092,12 @@ static void ionic_lif_rx_mode(struct ion
>   		lif->rx_mode = rx_mode;
>   }
>   
> -static void _ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode)
> +static void _ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode,
> +			       bool from_ndo)
>   {
>   	struct ionic_deferred_work *work;
>   
> -	if (in_interrupt()) {
> +	if (from_ndo) {
>   		work = kzalloc(sizeof(*work), GFP_ATOMIC);
>   		if (!work) {
>   			netdev_err(lif->netdev, "%s OOM\n", __func__);
> @@ -1100,7 +1112,16 @@ static void _ionic_lif_rx_mode(struct io
>   	}
>   }
>   
> -static void ionic_set_rx_mode(struct net_device *netdev)
> +static void ionic_dev_uc_sync(struct net_device *netdev, bool from_ndo)
> +{
> +	if (from_ndo)
> +		__dev_uc_sync(netdev, ionic_ndo_addr_add, ionic_ndo_addr_del);
> +	else
> +		__dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
> +
> +}
> +
> +static void ionic_set_rx_mode(struct net_device *netdev, bool from_ndo)
>   {
>   	struct ionic_lif *lif = netdev_priv(netdev);
>   	struct ionic_identity *ident;
> @@ -1122,7 +1143,7 @@ static void ionic_set_rx_mode(struct net
>   	 *       we remove our overflow flag and check the netdev flags
>   	 *       to see if we can disable NIC PROMISC
>   	 */
> -	__dev_uc_sync(netdev, ionic_addr_add, ionic_addr_del);
> +	ionic_dev_uc_sync(netdev, from_ndo);
>   	nfilters = le32_to_cpu(ident->lif.eth.max_ucast_filters);
>   	if (netdev_uc_count(netdev) + 1 > nfilters) {
>   		rx_mode |= IONIC_RX_MODE_F_PROMISC;
> @@ -1134,7 +1155,7 @@ static void ionic_set_rx_mode(struct net
>   	}
>   
>   	/* same for multicast */
> -	__dev_mc_sync(netdev, ionic_addr_add, ionic_addr_del);
> +	ionic_dev_uc_sync(netdev, from_ndo);
>   	nfilters = le32_to_cpu(ident->lif.eth.max_mcast_filters);
>   	if (netdev_mc_count(netdev) > nfilters) {
>   		rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
> @@ -1146,7 +1167,12 @@ static void ionic_set_rx_mode(struct net
>   	}
>   
>   	if (lif->rx_mode != rx_mode)
> -		_ionic_lif_rx_mode(lif, rx_mode);
> +		_ionic_lif_rx_mode(lif, rx_mode, from_ndo);
> +}
> +
> +static void ionic_ndo_set_rx_mode(struct net_device *netdev)
> +{
> +	ionic_set_rx_mode(netdev, true);
>   }
>   
>   static __le64 ionic_netdev_features_to_nic(netdev_features_t features)
> @@ -1391,7 +1417,7 @@ static int ionic_start_queues_reconfig(s
>   	 */
>   	err = ionic_txrx_init(lif);
>   	mutex_unlock(&lif->queue_lock);
> -	ionic_link_status_check_request(lif);
> +	ionic_link_status_check_request(lif, true);
>   	netif_device_attach(lif->netdev);
>   
>   	return err;
> @@ -1720,7 +1746,7 @@ static int ionic_txrx_init(struct ionic_
>   	if (lif->netdev->features & NETIF_F_RXHASH)
>   		ionic_lif_rss_init(lif);
>   
> -	ionic_set_rx_mode(lif->netdev);
> +	ionic_set_rx_mode(lif->netdev, false);
>   
>   	return 0;
>   
> @@ -2093,7 +2119,7 @@ static const struct net_device_ops ionic
>   	.ndo_stop               = ionic_stop,
>   	.ndo_start_xmit		= ionic_start_xmit,
>   	.ndo_get_stats64	= ionic_get_stats64,
> -	.ndo_set_rx_mode	= ionic_set_rx_mode,
> +	.ndo_set_rx_mode	= ionic_ndo_set_rx_mode,
>   	.ndo_set_features	= ionic_set_features,
>   	.ndo_set_mac_address	= ionic_set_mac_address,
>   	.ndo_validate_addr	= eth_validate_addr,
> @@ -2521,7 +2547,7 @@ static void ionic_lif_handle_fw_up(struc
>   	}
>   
>   	clear_bit(IONIC_LIF_F_FW_RESET, lif->state);
> -	ionic_link_status_check_request(lif);
> +	ionic_link_status_check_request(lif, true);
>   	netif_device_attach(lif->netdev);
>   	dev_info(ionic->dev, "FW Up: LIFs restarted\n");
>   
> @@ -2713,7 +2739,7 @@ static int ionic_station_set(struct ioni
>   		 */
>   		if (!ether_addr_equal(ctx.comp.lif_getattr.mac,
>   				      netdev->dev_addr))
> -			ionic_lif_addr(lif, netdev->dev_addr, true);
> +			ionic_lif_addr(lif, netdev->dev_addr, true, true);
>   	} else {
>   		/* Update the netdev mac with the device's mac */
>   		memcpy(addr.sa_data, ctx.comp.lif_getattr.mac, netdev->addr_len);
> @@ -2730,7 +2756,7 @@ static int ionic_station_set(struct ioni
>   
>   	netdev_dbg(lif->netdev, "adding station MAC addr %pM\n",
>   		   netdev->dev_addr);
> -	ionic_lif_addr(lif, netdev->dev_addr, true);
> +	ionic_lif_addr(lif, netdev->dev_addr, true, true);
>   
>   	return 0;
>   }
> --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
> +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
> @@ -245,7 +245,7 @@ static inline u32 ionic_coal_usec_to_hw(
>   
>   typedef void (*ionic_reset_cb)(struct ionic_lif *lif, void *arg);
>   
> -void ionic_link_status_check_request(struct ionic_lif *lif);
> +void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep);
>   void ionic_get_stats64(struct net_device *netdev,
>   		       struct rtnl_link_stats64 *ns);
>   void ionic_lif_deferred_enqueue(struct ionic_deferred *def,
>




More information about the libertas-dev mailing list