mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-18 06:50:08 +00:00
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
|
#endif
|
||||||
static void igb_shutdown(struct pci_dev *);
|
static void igb_shutdown(struct pci_dev *);
|
||||||
|
static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
|
||||||
#ifdef CONFIG_IGB_DCA
|
#ifdef CONFIG_IGB_DCA
|
||||||
static int igb_notify_dca(struct notifier_block *, unsigned long, void *);
|
static int igb_notify_dca(struct notifier_block *, unsigned long, void *);
|
||||||
static struct notifier_block dca_notifier = {
|
static struct notifier_block dca_notifier = {
|
||||||
@ -234,6 +235,7 @@ static struct pci_driver igb_driver = {
|
|||||||
.driver.pm = &igb_pm_ops,
|
.driver.pm = &igb_pm_ops,
|
||||||
#endif
|
#endif
|
||||||
.shutdown = igb_shutdown,
|
.shutdown = igb_shutdown,
|
||||||
|
.sriov_configure = igb_pci_sriov_configure,
|
||||||
.err_handler = &igb_err_handler
|
.err_handler = &igb_err_handler
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2195,6 +2197,99 @@ err_dma:
|
|||||||
return err;
|
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
|
* igb_remove - Device Removal Routine
|
||||||
* @pdev: PCI device information struct
|
* @pdev: PCI device information struct
|
||||||
@ -2242,23 +2337,7 @@ static void igb_remove(struct pci_dev *pdev)
|
|||||||
igb_clear_interrupt_scheme(adapter);
|
igb_clear_interrupt_scheme(adapter);
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_IOV
|
#ifdef CONFIG_PCI_IOV
|
||||||
/* reclaim resources allocated to VFs */
|
igb_disable_sriov(pdev);
|
||||||
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");
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
iounmap(hw->hw_addr);
|
iounmap(hw->hw_addr);
|
||||||
@ -2289,103 +2368,22 @@ static void igb_probe_vfs(struct igb_adapter *adapter)
|
|||||||
#ifdef CONFIG_PCI_IOV
|
#ifdef CONFIG_PCI_IOV
|
||||||
struct pci_dev *pdev = adapter->pdev;
|
struct pci_dev *pdev = adapter->pdev;
|
||||||
struct e1000_hw *hw = &adapter->hw;
|
struct e1000_hw *hw = &adapter->hw;
|
||||||
int old_vfs = pci_num_vf(adapter->pdev);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Virtualization features not supported on i210 family. */
|
/* Virtualization features not supported on i210 family. */
|
||||||
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
|
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (old_vfs) {
|
igb_enable_sriov(pdev, max_vfs);
|
||||||
dev_info(&pdev->dev, "%d pre-allocated VFs found - override "
|
pci_sriov_set_totalvfs(pdev, 7);
|
||||||
"max_vfs setting of %d\n", old_vfs, max_vfs);
|
|
||||||
adapter->vfs_allocated_count = old_vfs;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
#endif /* CONFIG_PCI_IOV */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void igb_init_queue_configuration(struct igb_adapter *adapter)
|
||||||
* 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 e1000_hw *hw = &adapter->hw;
|
||||||
struct net_device *netdev = adapter->netdev;
|
|
||||||
struct pci_dev *pdev = adapter->pdev;
|
|
||||||
u32 max_rss_queues;
|
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. */
|
/* Determine the maximum number of RSS queues supported. */
|
||||||
switch (hw->mac.type) {
|
switch (hw->mac.type) {
|
||||||
case e1000_i211:
|
case e1000_i211:
|
||||||
@ -2444,6 +2442,60 @@ static int igb_sw_init(struct igb_adapter *adapter)
|
|||||||
adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
|
adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
|
||||||
break;
|
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 */
|
/* Setup and initialize a copy of the hw vlan table array */
|
||||||
adapter->shadow_vfta = kzalloc(sizeof(u32) *
|
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
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
/*
|
/*
|
||||||
* Polling 'interrupt' - used by things like netconsole to send skbs
|
* Polling 'interrupt' - used by things like netconsole to send skbs
|
||||||
|
Loading…
Reference in New Issue
Block a user