diff options
author | Mitch Williams <mitch.a.williams@intel.com> | 2017-01-24 10:23:59 -0800 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2017-03-15 01:31:38 -0700 |
commit | ed0e894de7c1339be55ca0dcc11783d923ac5248 (patch) | |
tree | 2d08c7343e05bb1d1fc7a06a2a33ef58dee026fa /drivers/net/ethernet/intel/i40evf/i40evf_main.c | |
parent | d60be2ca9c42e127702a8fd556d696b101f3c09b (diff) | |
download | linux-ed0e894de7c1339be55ca0dcc11783d923ac5248.tar.bz2 |
i40evf: add client interface
In preparation for upcoming RDMA-capable hardware, add a client
interface to the VF driver. This is a slightly-simplified version
of the PF client interface, with the names changed to protect the
innocent.
Due to the nature of the VF<->PF interactions, the client interface
sometimes needs to call back into itself to pass messages. Because
of this, we can't use the coarse-grained locking like the PF's
client interface uses. Instead, we handle all client interactions
in a separate thread so the watchdog can still run and process
virtual channel messages.
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>
Signed-off-by: Avinash Dayanand <avinash.dayanand@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/i40evf/i40evf_main.c')
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40evf_main.c | 83 |
1 files changed, 78 insertions, 5 deletions
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index f35dcaac5bb7..9492b20da557 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -26,6 +26,7 @@ #include "i40evf.h" #include "i40e_prototype.h" +#include "i40evf_client.h" static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter); static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter); static int i40evf_close(struct net_device *netdev); @@ -1058,6 +1059,8 @@ static void i40evf_up_complete(struct i40evf_adapter *adapter) i40evf_napi_enable_all(adapter); adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_QUEUES; + if (CLIENT_ENABLED(adapter)) + adapter->flags |= I40EVF_FLAG_CLIENT_NEEDS_OPEN; mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); } @@ -1685,6 +1688,7 @@ static void i40evf_watchdog_task(struct work_struct *work) i40evf_set_promiscuous(adapter, 0); goto watchdog_done; } + schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5)); if (adapter->state == __I40EVF_RUNNING) i40evf_request_stats(adapter); @@ -1773,10 +1777,17 @@ static void i40evf_reset_task(struct work_struct *work) u32 reg_val; int i = 0, err; - while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section)) usleep_range(500, 1000); - + if (CLIENT_ENABLED(adapter)) { + adapter->flags &= ~(I40EVF_FLAG_CLIENT_NEEDS_OPEN | + I40EVF_FLAG_CLIENT_NEEDS_CLOSE | + I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS | + I40EVF_FLAG_SERVICE_CLIENT_REQUESTED); + cancel_delayed_work_sync(&adapter->client_task); + i40evf_notify_client_close(&adapter->vsi, true); + } i40evf_misc_irq_disable(adapter); if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) { adapter->flags &= ~I40EVF_FLAG_RESET_NEEDED; @@ -1819,6 +1830,7 @@ static void i40evf_reset_task(struct work_struct *work) dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", reg_val); i40evf_disable_vf(adapter); + clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section); return; /* Do not attempt to reinit. It's dead, Jim. */ } @@ -1861,9 +1873,8 @@ continue_reset: } adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; - /* Open RDMA Client again */ - adapter->aq_required |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED; clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section); i40evf_misc_irq_enable(adapter); mod_timer(&adapter->watchdog_timer, jiffies + 2); @@ -1980,6 +1991,48 @@ out: } /** + * i40evf_client_task - worker thread to perform client work + * @work: pointer to work_struct containing our data + * + * This task handles client interactions. Because client calls can be + * reentrant, we can't handle them in the watchdog. + **/ +static void i40evf_client_task(struct work_struct *work) +{ + struct i40evf_adapter *adapter = + container_of(work, struct i40evf_adapter, client_task.work); + + /* If we can't get the client bit, just give up. We'll be rescheduled + * later. + */ + + if (test_and_set_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section)) + return; + + if (adapter->flags & I40EVF_FLAG_SERVICE_CLIENT_REQUESTED) { + i40evf_client_subtask(adapter); + adapter->flags &= ~I40EVF_FLAG_SERVICE_CLIENT_REQUESTED; + goto out; + } + if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_CLOSE) { + i40evf_notify_client_close(&adapter->vsi, false); + adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_CLOSE; + goto out; + } + if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_OPEN) { + i40evf_notify_client_open(&adapter->vsi); + adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_OPEN; + goto out; + } + if (adapter->flags & I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS) { + i40evf_notify_client_l2_params(&adapter->vsi); + adapter->flags &= ~I40EVF_FLAG_CLIENT_NEEDS_L2_PARAMS; + } +out: + clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section); +} + +/** * i40evf_free_all_tx_resources - Free Tx Resources for All Queues * @adapter: board private structure * @@ -2148,6 +2201,8 @@ static int i40evf_close(struct net_device *netdev) set_bit(__I40E_DOWN, &adapter->vsi.state); + if (CLIENT_ENABLED(adapter)) + adapter->flags |= I40EVF_FLAG_CLIENT_NEEDS_CLOSE; i40evf_down(adapter); adapter->state = __I40EVF_DOWN_PENDING; @@ -2188,6 +2243,10 @@ static int i40evf_change_mtu(struct net_device *netdev, int new_mtu) struct i40evf_adapter *adapter = netdev_priv(netdev); netdev->mtu = new_mtu; + if (CLIENT_ENABLED(adapter)) { + i40evf_notify_client_l2_params(&adapter->vsi); + adapter->flags |= I40EVF_FLAG_SERVICE_CLIENT_REQUESTED; + } adapter->flags |= I40EVF_FLAG_RESET_NEEDED; schedule_work(&adapter->reset_task); @@ -2581,6 +2640,12 @@ static void i40evf_init_task(struct work_struct *work) adapter->netdev_registered = true; netif_tx_stop_all_queues(netdev); + if (CLIENT_ALLOWED(adapter)) { + err = i40evf_lan_add_device(adapter); + if (err) + dev_info(&pdev->dev, "Failed to add VF to client API service list: %d\n", + err); + } dev_info(&pdev->dev, "MAC address: %pM\n", adapter->hw.mac.addr); if (netdev->features & NETIF_F_GRO) @@ -2745,6 +2810,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&adapter->reset_task, i40evf_reset_task); INIT_WORK(&adapter->adminq_task, i40evf_adminq_task); INIT_WORK(&adapter->watchdog_task, i40evf_watchdog_task); + INIT_DELAYED_WORK(&adapter->client_task, i40evf_client_task); INIT_DELAYED_WORK(&adapter->init_task, i40evf_init_task); schedule_delayed_work(&adapter->init_task, msecs_to_jiffies(5 * (pdev->devfn & 0x07))); @@ -2857,14 +2923,21 @@ static void i40evf_remove(struct pci_dev *pdev) struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_mac_filter *f, *ftmp; struct i40e_hw *hw = &adapter->hw; + int err; cancel_delayed_work_sync(&adapter->init_task); cancel_work_sync(&adapter->reset_task); - + cancel_delayed_work_sync(&adapter->client_task); if (adapter->netdev_registered) { unregister_netdev(netdev); adapter->netdev_registered = false; } + if (CLIENT_ALLOWED(adapter)) { + err = i40evf_lan_del_device(adapter); + if (err) + dev_warn(&pdev->dev, "Failed to delete client device: %d\n", + err); + } /* Shut down all the garbage mashers on the detention level */ adapter->state = __I40EVF_REMOVE; |