diff options
Diffstat (limited to 'drivers/net/ethernet/intel/iavf/iavf_main.c')
| -rw-r--r-- | drivers/net/ethernet/intel/iavf/iavf_main.c | 248 | 
1 files changed, 156 insertions, 92 deletions
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index a483eb185c99..9610ca770349 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -167,6 +167,45 @@ static struct iavf_adapter *iavf_pdev_to_adapter(struct pci_dev *pdev)  }  /** + * iavf_is_reset_in_progress - Check if a reset is in progress + * @adapter: board private structure + */ +static bool iavf_is_reset_in_progress(struct iavf_adapter *adapter) +{ +	if (adapter->state == __IAVF_RESETTING || +	    adapter->flags & (IAVF_FLAG_RESET_PENDING | +			      IAVF_FLAG_RESET_NEEDED)) +		return true; + +	return false; +} + +/** + * iavf_wait_for_reset - Wait for reset to finish. + * @adapter: board private structure + * + * Returns 0 if reset finished successfully, negative on timeout or interrupt. + */ +int iavf_wait_for_reset(struct iavf_adapter *adapter) +{ +	int ret = wait_event_interruptible_timeout(adapter->reset_waitqueue, +					!iavf_is_reset_in_progress(adapter), +					msecs_to_jiffies(5000)); + +	/* If ret < 0 then it means wait was interrupted. +	 * If ret == 0 then it means we got a timeout while waiting +	 * for reset to finish. +	 * If ret > 0 it means reset has finished. +	 */ +	if (ret > 0) +		return 0; +	else if (ret < 0) +		return -EINTR; +	else +		return -EBUSY; +} + +/**   * iavf_allocate_dma_mem_d - OS specific memory alloc for shared code   * @hw:   pointer to the HW structure   * @mem:  ptr to mem struct to fill out @@ -262,12 +301,14 @@ static int iavf_lock_timeout(struct mutex *lock, unsigned int msecs)  /**   * iavf_schedule_reset - Set the flags and schedule a reset event   * @adapter: board private structure + * @flags: IAVF_FLAG_RESET_PENDING or IAVF_FLAG_RESET_NEEDED   **/ -void iavf_schedule_reset(struct iavf_adapter *adapter) +void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags)  { -	if (!(adapter->flags & -	      (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) { -		adapter->flags |= IAVF_FLAG_RESET_NEEDED; +	if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) && +	    !(adapter->flags & +	    (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) { +		adapter->flags |= flags;  		queue_work(adapter->wq, &adapter->reset_task);  	}  } @@ -295,7 +336,7 @@ static void iavf_tx_timeout(struct net_device *netdev, unsigned int txqueue)  	struct iavf_adapter *adapter = netdev_priv(netdev);  	adapter->tx_timeout_count++; -	iavf_schedule_reset(adapter); +	iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);  }  /** @@ -1651,10 +1692,10 @@ static int iavf_set_interrupt_capability(struct iavf_adapter *adapter)  		adapter->msix_entries[vector].entry = vector;  	err = iavf_acquire_msix_vectors(adapter, v_budget); +	if (!err) +		iavf_schedule_finish_config(adapter);  out: -	netif_set_real_num_rx_queues(adapter->netdev, pairs); -	netif_set_real_num_tx_queues(adapter->netdev, pairs);  	return err;  } @@ -1828,19 +1869,16 @@ static int iavf_alloc_q_vectors(struct iavf_adapter *adapter)  static void iavf_free_q_vectors(struct iavf_adapter *adapter)  {  	int q_idx, num_q_vectors; -	int napi_vectors;  	if (!adapter->q_vectors)  		return;  	num_q_vectors = adapter->num_msix_vectors - NONQ_VECS; -	napi_vectors = adapter->num_active_queues;  	for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {  		struct iavf_q_vector *q_vector = &adapter->q_vectors[q_idx]; -		if (q_idx < napi_vectors) -			netif_napi_del(&q_vector->napi); +		netif_napi_del(&q_vector->napi);  	}  	kfree(adapter->q_vectors);  	adapter->q_vectors = NULL; @@ -1877,9 +1915,7 @@ static int iavf_init_interrupt_scheme(struct iavf_adapter *adapter)  		goto err_alloc_queues;  	} -	rtnl_lock();  	err = iavf_set_interrupt_capability(adapter); -	rtnl_unlock();  	if (err) {  		dev_err(&adapter->pdev->dev,  			"Unable to setup interrupt capabilities\n"); @@ -1932,15 +1968,16 @@ static void iavf_free_rss(struct iavf_adapter *adapter)  /**   * iavf_reinit_interrupt_scheme - Reallocate queues and vectors   * @adapter: board private structure + * @running: true if adapter->state == __IAVF_RUNNING   *   * Returns 0 on success, negative on failure   **/ -static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter) +static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter, bool running)  {  	struct net_device *netdev = adapter->netdev;  	int err; -	if (netif_running(netdev)) +	if (running)  		iavf_free_traffic_irqs(adapter);  	iavf_free_misc_irq(adapter);  	iavf_reset_interrupt_capability(adapter); @@ -1965,6 +2002,78 @@ err:  }  /** + * iavf_finish_config - do all netdev work that needs RTNL + * @work: our work_struct + * + * Do work that needs both RTNL and crit_lock. + **/ +static void iavf_finish_config(struct work_struct *work) +{ +	struct iavf_adapter *adapter; +	int pairs, err; + +	adapter = container_of(work, struct iavf_adapter, finish_config); + +	/* Always take RTNL first to prevent circular lock dependency */ +	rtnl_lock(); +	mutex_lock(&adapter->crit_lock); + +	if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) && +	    adapter->netdev_registered && +	    !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) { +		netdev_update_features(adapter->netdev); +		adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES; +	} + +	switch (adapter->state) { +	case __IAVF_DOWN: +		if (!adapter->netdev_registered) { +			err = register_netdevice(adapter->netdev); +			if (err) { +				dev_err(&adapter->pdev->dev, "Unable to register netdev (%d)\n", +					err); + +				/* go back and try again.*/ +				iavf_free_rss(adapter); +				iavf_free_misc_irq(adapter); +				iavf_reset_interrupt_capability(adapter); +				iavf_change_state(adapter, +						  __IAVF_INIT_CONFIG_ADAPTER); +				goto out; +			} +			adapter->netdev_registered = true; +		} + +		/* Set the real number of queues when reset occurs while +		 * state == __IAVF_DOWN +		 */ +		fallthrough; +	case __IAVF_RUNNING: +		pairs = adapter->num_active_queues; +		netif_set_real_num_rx_queues(adapter->netdev, pairs); +		netif_set_real_num_tx_queues(adapter->netdev, pairs); +		break; + +	default: +		break; +	} + +out: +	mutex_unlock(&adapter->crit_lock); +	rtnl_unlock(); +} + +/** + * iavf_schedule_finish_config - Set the flags and schedule a reset event + * @adapter: board private structure + **/ +void iavf_schedule_finish_config(struct iavf_adapter *adapter) +{ +	if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) +		queue_work(adapter->wq, &adapter->finish_config); +} + +/**   * iavf_process_aq_command - process aq_required flags   * and sends aq command   * @adapter: pointer to iavf adapter structure @@ -2371,7 +2480,7 @@ int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)  			adapter->vsi_res->num_queue_pairs);  		adapter->flags |= IAVF_FLAG_REINIT_MSIX_NEEDED;  		adapter->num_req_queues = adapter->vsi_res->num_queue_pairs; -		iavf_schedule_reset(adapter); +		iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);  		return -EAGAIN;  	} @@ -2601,22 +2710,8 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)  	netif_carrier_off(netdev);  	adapter->link_up = false; - -	/* set the semaphore to prevent any callbacks after device registration -	 * up to time when state of driver will be set to __IAVF_DOWN -	 */ -	rtnl_lock(); -	if (!adapter->netdev_registered) { -		err = register_netdevice(netdev); -		if (err) { -			rtnl_unlock(); -			goto err_register; -		} -	} - -	adapter->netdev_registered = true; -  	netif_tx_stop_all_queues(netdev); +  	if (CLIENT_ALLOWED(adapter)) {  		err = iavf_lan_add_device(adapter);  		if (err) @@ -2629,7 +2724,6 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)  	iavf_change_state(adapter, __IAVF_DOWN);  	set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); -	rtnl_unlock();  	iavf_misc_irq_enable(adapter);  	wake_up(&adapter->down_waitqueue); @@ -2649,10 +2743,11 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)  		/* request initial VLAN offload settings */  		iavf_set_vlan_offload_features(adapter, 0, netdev->features); +	iavf_schedule_finish_config(adapter);  	return; +  err_mem:  	iavf_free_rss(adapter); -err_register:  	iavf_free_misc_irq(adapter);  err_sw_init:  	iavf_reset_interrupt_capability(adapter); @@ -2679,26 +2774,9 @@ static void iavf_watchdog_task(struct work_struct *work)  		goto restart_watchdog;  	} -	if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) && -	    adapter->netdev_registered && -	    !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) && -	    rtnl_trylock()) { -		netdev_update_features(adapter->netdev); -		rtnl_unlock(); -		adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES; -	} -  	if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)  		iavf_change_state(adapter, __IAVF_COMM_FAILED); -	if (adapter->flags & IAVF_FLAG_RESET_NEEDED) { -		adapter->aq_required = 0; -		adapter->current_op = VIRTCHNL_OP_UNKNOWN; -		mutex_unlock(&adapter->crit_lock); -		queue_work(adapter->wq, &adapter->reset_task); -		return; -	} -  	switch (adapter->state) {  	case __IAVF_STARTUP:  		iavf_startup(adapter); @@ -2826,11 +2904,10 @@ static void iavf_watchdog_task(struct work_struct *work)  	/* check for hw reset */  	reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;  	if (!reg_val) { -		adapter->flags |= IAVF_FLAG_RESET_PENDING;  		adapter->aq_required = 0;  		adapter->current_op = VIRTCHNL_OP_UNKNOWN;  		dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); -		queue_work(adapter->wq, &adapter->reset_task); +		iavf_schedule_reset(adapter, IAVF_FLAG_RESET_PENDING);  		mutex_unlock(&adapter->crit_lock);  		queue_delayed_work(adapter->wq,  				   &adapter->watchdog_task, HZ * 2); @@ -2940,11 +3017,6 @@ static void iavf_reset_task(struct work_struct *work)  	int i = 0, err;  	bool running; -	/* Detach interface to avoid subsequent NDO callbacks */ -	rtnl_lock(); -	netif_device_detach(netdev); -	rtnl_unlock(); -  	/* When device is being removed it doesn't make sense to run the reset  	 * task, just return in such a case.  	 */ @@ -2952,7 +3024,7 @@ static void iavf_reset_task(struct work_struct *work)  		if (adapter->state != __IAVF_REMOVE)  			queue_work(adapter->wq, &adapter->reset_task); -		goto reset_finish; +		return;  	}  	while (!mutex_trylock(&adapter->client_lock)) @@ -3010,11 +3082,6 @@ static void iavf_reset_task(struct work_struct *work)  		iavf_disable_vf(adapter);  		mutex_unlock(&adapter->client_lock);  		mutex_unlock(&adapter->crit_lock); -		if (netif_running(netdev)) { -			rtnl_lock(); -			dev_close(netdev); -			rtnl_unlock(); -		}  		return; /* Do not attempt to reinit. It's dead, Jim. */  	} @@ -3056,7 +3123,7 @@ continue_reset:  	if ((adapter->flags & IAVF_FLAG_REINIT_MSIX_NEEDED) ||  	    (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED)) { -		err = iavf_reinit_interrupt_scheme(adapter); +		err = iavf_reinit_interrupt_scheme(adapter, running);  		if (err)  			goto reset_err;  	} @@ -3151,10 +3218,11 @@ continue_reset:  	adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; +	wake_up(&adapter->reset_waitqueue);  	mutex_unlock(&adapter->client_lock);  	mutex_unlock(&adapter->crit_lock); -	goto reset_finish; +	return;  reset_err:  	if (running) {  		set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); @@ -3164,21 +3232,7 @@ reset_err:  	mutex_unlock(&adapter->client_lock);  	mutex_unlock(&adapter->crit_lock); - -	if (netif_running(netdev)) { -		/* Close device to ensure that Tx queues will not be started -		 * during netif_device_attach() at the end of the reset task. -		 */ -		rtnl_lock(); -		dev_close(netdev); -		rtnl_unlock(); -	} -  	dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); -reset_finish: -	rtnl_lock(); -	netif_device_attach(netdev); -	rtnl_unlock();  }  /** @@ -3196,9 +3250,6 @@ static void iavf_adminq_task(struct work_struct *work)  	u32 val, oldval;  	u16 pending; -	if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) -		goto out; -  	if (!mutex_trylock(&adapter->crit_lock)) {  		if (adapter->state == __IAVF_REMOVE)  			return; @@ -3207,10 +3258,13 @@ static void iavf_adminq_task(struct work_struct *work)  		goto out;  	} +	if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) +		goto unlock; +  	event.buf_len = IAVF_MAX_AQ_BUF_SIZE;  	event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);  	if (!event.msg_buf) -		goto out; +		goto unlock;  	do {  		ret = iavf_clean_arq_element(hw, &event, &pending); @@ -3225,11 +3279,8 @@ static void iavf_adminq_task(struct work_struct *work)  		if (pending != 0)  			memset(event.msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE);  	} while (pending); -	mutex_unlock(&adapter->crit_lock); -	if ((adapter->flags & -	     (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) || -	    adapter->state == __IAVF_RESETTING) +	if (iavf_is_reset_in_progress(adapter))  		goto freedom;  	/* check for error indications */ @@ -3271,6 +3322,8 @@ static void iavf_adminq_task(struct work_struct *work)  freedom:  	kfree(event.msg_buf); +unlock: +	mutex_unlock(&adapter->crit_lock);  out:  	/* re-enable Admin queue interrupt cause */  	iavf_misc_irq_enable(adapter); @@ -4315,6 +4368,7 @@ static int iavf_close(struct net_device *netdev)  static int iavf_change_mtu(struct net_device *netdev, int new_mtu)  {  	struct iavf_adapter *adapter = netdev_priv(netdev); +	int ret = 0;  	netdev_dbg(netdev, "changing MTU from %d to %d\n",  		   netdev->mtu, new_mtu); @@ -4325,11 +4379,15 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)  	}  	if (netif_running(netdev)) { -		adapter->flags |= IAVF_FLAG_RESET_NEEDED; -		queue_work(adapter->wq, &adapter->reset_task); +		iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED); +		ret = iavf_wait_for_reset(adapter); +		if (ret < 0) +			netdev_warn(netdev, "MTU change interrupted waiting for reset"); +		else if (ret) +			netdev_warn(netdev, "MTU change timed out waiting for reset");  	} -	return 0; +	return ret;  }  #define NETIF_VLAN_OFFLOAD_FEATURES	(NETIF_F_HW_VLAN_CTAG_RX | \ @@ -4922,6 +4980,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	INIT_WORK(&adapter->reset_task, iavf_reset_task);  	INIT_WORK(&adapter->adminq_task, iavf_adminq_task); +	INIT_WORK(&adapter->finish_config, iavf_finish_config);  	INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task);  	INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task);  	queue_delayed_work(adapter->wq, &adapter->watchdog_task, @@ -4930,6 +4989,9 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	/* Setup the wait queue for indicating transition to down status */  	init_waitqueue_head(&adapter->down_waitqueue); +	/* Setup the wait queue for indicating transition to running state */ +	init_waitqueue_head(&adapter->reset_waitqueue); +  	/* Setup the wait queue for indicating virtchannel events */  	init_waitqueue_head(&adapter->vc_waitqueue); @@ -5061,13 +5123,15 @@ static void iavf_remove(struct pci_dev *pdev)  		usleep_range(500, 1000);  	}  	cancel_delayed_work_sync(&adapter->watchdog_task); +	cancel_work_sync(&adapter->finish_config); +	rtnl_lock();  	if (adapter->netdev_registered) { -		rtnl_lock();  		unregister_netdevice(netdev);  		adapter->netdev_registered = false; -		rtnl_unlock();  	} +	rtnl_unlock(); +  	if (CLIENT_ALLOWED(adapter)) {  		err = iavf_lan_del_device(adapter);  		if (err)  |