igb: Enable SR-IOV configuration via PCI sysfs interface
Implement callback in the driver for the new PCI bus driver interface that allows the user to enable/disable SR-IOV virtual functions in a device via the sysfs interface. Signed-off-by: Greg Rose <gregory.v.rose@intel.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
b67e191307
commit
fa44f2f185
|
@ -193,6 +193,7 @@ static const struct dev_pm_ops igb_pm_ops = {
|
|||
};
|
||||
#endif
|
||||
static void igb_shutdown(struct pci_dev *);
|
||||
static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
|
||||
#ifdef CONFIG_IGB_DCA
|
||||
static int igb_notify_dca(struct notifier_block *, unsigned long, void *);
|
||||
static struct notifier_block dca_notifier = {
|
||||
|
@ -234,6 +235,7 @@ static struct pci_driver igb_driver = {
|
|||
.driver.pm = &igb_pm_ops,
|
||||
#endif
|
||||
.shutdown = igb_shutdown,
|
||||
.sriov_configure = igb_pci_sriov_configure,
|
||||
.err_handler = &igb_err_handler
|
||||
};
|
||||
|
||||
|
@ -2195,6 +2197,99 @@ err_dma:
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
static int igb_disable_sriov(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
|
||||
/* reclaim resources allocated to VFs */
|
||||
if (adapter->vf_data) {
|
||||
/* disable iov and allow time for transactions to clear */
|
||||
if (igb_vfs_are_assigned(adapter)) {
|
||||
dev_warn(&pdev->dev,
|
||||
"Cannot deallocate SR-IOV virtual functions while they are assigned - VFs will not be deallocated\n");
|
||||
return -EPERM;
|
||||
} else {
|
||||
pci_disable_sriov(pdev);
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
kfree(adapter->vf_data);
|
||||
adapter->vf_data = NULL;
|
||||
adapter->vfs_allocated_count = 0;
|
||||
wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
|
||||
wrfl();
|
||||
msleep(100);
|
||||
dev_info(&pdev->dev, "IOV Disabled\n");
|
||||
|
||||
/* Re-enable DMA Coalescing flag since IOV is turned off */
|
||||
adapter->flags |= IGB_FLAG_DMAC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_enable_sriov(struct pci_dev *pdev, int num_vfs)
|
||||
{
|
||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||
int old_vfs = pci_num_vf(pdev);
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
if (!num_vfs)
|
||||
goto out;
|
||||
else if (old_vfs && old_vfs == num_vfs)
|
||||
goto out;
|
||||
else if (old_vfs && old_vfs != num_vfs)
|
||||
err = igb_disable_sriov(pdev);
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (num_vfs > 7) {
|
||||
err = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
adapter->vfs_allocated_count = num_vfs;
|
||||
|
||||
adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
|
||||
sizeof(struct vf_data_storage), GFP_KERNEL);
|
||||
|
||||
/* if allocation failed then we do not support SR-IOV */
|
||||
if (!adapter->vf_data) {
|
||||
adapter->vfs_allocated_count = 0;
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to allocate memory for VF Data Storage\n");
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = pci_enable_sriov(pdev, adapter->vfs_allocated_count);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
dev_info(&pdev->dev, "%d VFs allocated\n",
|
||||
adapter->vfs_allocated_count);
|
||||
for (i = 0; i < adapter->vfs_allocated_count; i++)
|
||||
igb_vf_configure(adapter, i);
|
||||
|
||||
/* DMA Coalescing is not supported in IOV mode. */
|
||||
adapter->flags &= ~IGB_FLAG_DMAC;
|
||||
goto out;
|
||||
|
||||
err_out:
|
||||
kfree(adapter->vf_data);
|
||||
adapter->vf_data = NULL;
|
||||
adapter->vfs_allocated_count = 0;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
/**
|
||||
* igb_remove - Device Removal Routine
|
||||
* @pdev: PCI device information struct
|
||||
|
@ -2242,23 +2337,7 @@ static void igb_remove(struct pci_dev *pdev)
|
|||
igb_clear_interrupt_scheme(adapter);
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
/* reclaim resources allocated to VFs */
|
||||
if (adapter->vf_data) {
|
||||
/* disable iov and allow time for transactions to clear */
|
||||
if (igb_vfs_are_assigned(adapter)) {
|
||||
dev_info(&pdev->dev, "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
|
||||
} else {
|
||||
pci_disable_sriov(pdev);
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
kfree(adapter->vf_data);
|
||||
adapter->vf_data = NULL;
|
||||
wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
|
||||
wrfl();
|
||||
msleep(100);
|
||||
dev_info(&pdev->dev, "IOV Disabled\n");
|
||||
}
|
||||
igb_disable_sriov(pdev);
|
||||
#endif
|
||||
|
||||
iounmap(hw->hw_addr);
|
||||
|
@ -2289,103 +2368,22 @@ static void igb_probe_vfs(struct igb_adapter *adapter)
|
|||
#ifdef CONFIG_PCI_IOV
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
int old_vfs = pci_num_vf(adapter->pdev);
|
||||
int i;
|
||||
|
||||
/* Virtualization features not supported on i210 family. */
|
||||
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
|
||||
return;
|
||||
|
||||
if (old_vfs) {
|
||||
dev_info(&pdev->dev, "%d pre-allocated VFs found - override "
|
||||
"max_vfs setting of %d\n", old_vfs, max_vfs);
|
||||
adapter->vfs_allocated_count = old_vfs;
|
||||
}
|
||||
igb_enable_sriov(pdev, max_vfs);
|
||||
pci_sriov_set_totalvfs(pdev, 7);
|
||||
|
||||
if (!adapter->vfs_allocated_count)
|
||||
return;
|
||||
|
||||
adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
|
||||
sizeof(struct vf_data_storage), GFP_KERNEL);
|
||||
|
||||
/* if allocation failed then we do not support SR-IOV */
|
||||
if (!adapter->vf_data) {
|
||||
adapter->vfs_allocated_count = 0;
|
||||
dev_err(&pdev->dev, "Unable to allocate memory for VF "
|
||||
"Data Storage\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!old_vfs) {
|
||||
if (pci_enable_sriov(pdev, adapter->vfs_allocated_count))
|
||||
goto err_out;
|
||||
}
|
||||
dev_info(&pdev->dev, "%d VFs allocated\n",
|
||||
adapter->vfs_allocated_count);
|
||||
for (i = 0; i < adapter->vfs_allocated_count; i++)
|
||||
igb_vf_configure(adapter, i);
|
||||
|
||||
/* DMA Coalescing is not supported in IOV mode. */
|
||||
adapter->flags &= ~IGB_FLAG_DMAC;
|
||||
goto out;
|
||||
err_out:
|
||||
kfree(adapter->vf_data);
|
||||
adapter->vf_data = NULL;
|
||||
adapter->vfs_allocated_count = 0;
|
||||
out:
|
||||
return;
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_sw_init - Initialize general software structures (struct igb_adapter)
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* igb_sw_init initializes the Adapter private data structure.
|
||||
* Fields are initialized based on PCI device information and
|
||||
* OS network device settings (MTU size).
|
||||
**/
|
||||
static int igb_sw_init(struct igb_adapter *adapter)
|
||||
static void igb_init_queue_configuration(struct igb_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
u32 max_rss_queues;
|
||||
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
|
||||
|
||||
/* set default ring sizes */
|
||||
adapter->tx_ring_count = IGB_DEFAULT_TXD;
|
||||
adapter->rx_ring_count = IGB_DEFAULT_RXD;
|
||||
|
||||
/* set default ITR values */
|
||||
adapter->rx_itr_setting = IGB_DEFAULT_ITR;
|
||||
adapter->tx_itr_setting = IGB_DEFAULT_ITR;
|
||||
|
||||
/* set default work limits */
|
||||
adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
|
||||
|
||||
adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
|
||||
VLAN_HLEN;
|
||||
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
|
||||
|
||||
spin_lock_init(&adapter->stats64_lock);
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82576:
|
||||
case e1000_i350:
|
||||
if (max_vfs > 7) {
|
||||
dev_warn(&pdev->dev,
|
||||
"Maximum of 7 VFs per PF, using max\n");
|
||||
adapter->vfs_allocated_count = 7;
|
||||
} else
|
||||
adapter->vfs_allocated_count = max_vfs;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
|
||||
/* Determine the maximum number of RSS queues supported. */
|
||||
switch (hw->mac.type) {
|
||||
case e1000_i211:
|
||||
|
@ -2444,6 +2442,60 @@ static int igb_sw_init(struct igb_adapter *adapter)
|
|||
adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_sw_init - Initialize general software structures (struct igb_adapter)
|
||||
* @adapter: board private structure to initialize
|
||||
*
|
||||
* igb_sw_init initializes the Adapter private data structure.
|
||||
* Fields are initialized based on PCI device information and
|
||||
* OS network device settings (MTU size).
|
||||
**/
|
||||
static int igb_sw_init(struct igb_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
|
||||
|
||||
/* set default ring sizes */
|
||||
adapter->tx_ring_count = IGB_DEFAULT_TXD;
|
||||
adapter->rx_ring_count = IGB_DEFAULT_RXD;
|
||||
|
||||
/* set default ITR values */
|
||||
adapter->rx_itr_setting = IGB_DEFAULT_ITR;
|
||||
adapter->tx_itr_setting = IGB_DEFAULT_ITR;
|
||||
|
||||
/* set default work limits */
|
||||
adapter->tx_work_limit = IGB_DEFAULT_TX_WORK;
|
||||
|
||||
adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN +
|
||||
VLAN_HLEN;
|
||||
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
|
||||
|
||||
spin_lock_init(&adapter->stats64_lock);
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82576:
|
||||
case e1000_i350:
|
||||
if (max_vfs > 7) {
|
||||
dev_warn(&pdev->dev,
|
||||
"Maximum of 7 VFs per PF, using max\n");
|
||||
adapter->vfs_allocated_count = 7;
|
||||
} else
|
||||
adapter->vfs_allocated_count = max_vfs;
|
||||
if (adapter->vfs_allocated_count)
|
||||
dev_warn(&pdev->dev,
|
||||
"Enabling SR-IOV VFs using the module parameter is deprecated - please use the pci sysfs interface.\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
|
||||
igb_init_queue_configuration(adapter);
|
||||
|
||||
/* Setup and initialize a copy of the hw vlan table array */
|
||||
adapter->shadow_vfta = kzalloc(sizeof(u32) *
|
||||
|
@ -6902,6 +6954,72 @@ static void igb_shutdown(struct pci_dev *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
static int igb_sriov_reinit(struct pci_dev *dev)
|
||||
{
|
||||
struct net_device *netdev = pci_get_drvdata(dev);
|
||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
if (netif_running(netdev))
|
||||
igb_close(netdev);
|
||||
|
||||
igb_clear_interrupt_scheme(adapter);
|
||||
|
||||
igb_init_queue_configuration(adapter);
|
||||
|
||||
if (igb_init_interrupt_scheme(adapter, true)) {
|
||||
dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (netif_running(netdev))
|
||||
igb_open(netdev);
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igb_pci_disable_sriov(struct pci_dev *dev)
|
||||
{
|
||||
int err = igb_disable_sriov(dev);
|
||||
|
||||
if (!err)
|
||||
err = igb_sriov_reinit(dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int igb_pci_enable_sriov(struct pci_dev *dev, int num_vfs)
|
||||
{
|
||||
int err = igb_enable_sriov(dev, num_vfs);
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = igb_sriov_reinit(dev);
|
||||
if (!err)
|
||||
return num_vfs;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
|
||||
{
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
if (num_vfs == 0)
|
||||
return igb_pci_disable_sriov(dev);
|
||||
else
|
||||
return igb_pci_enable_sriov(dev, num_vfs);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
/*
|
||||
* Polling 'interrupt' - used by things like netconsole to send skbs
|
||||
|
|
Loading…
Reference in New Issue