mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
Merge branch 'cxgb4-next'
Hariprasad Shenai says: ==================== cxgb4vf: Interrupt and queue configuration changes This series fixes some issues and some changes in the queue and interrupt configuration for cxgb4vf driver. We need to enable interrupts before we register our network device, so that we don't loose link up interrupts. Allocate rx queues based on interrupt type. Set number of tx/rx queues in probe function only. Also adds check for some invalid configurations. This patch series has been created against net-next tree and includes patches on cxgb4vf driver. We have included all the maintainers of respective drivers. Kindly review the change and let us know in case of any review comments. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
b795a213a4
1 changed files with 125 additions and 96 deletions
|
@ -790,10 +790,6 @@ static int cxgb4vf_open(struct net_device *dev)
|
||||||
/*
|
/*
|
||||||
* Note that this interface is up and start everything up ...
|
* Note that this interface is up and start everything up ...
|
||||||
*/
|
*/
|
||||||
netif_set_real_num_tx_queues(dev, pi->nqsets);
|
|
||||||
err = netif_set_real_num_rx_queues(dev, pi->nqsets);
|
|
||||||
if (err)
|
|
||||||
goto err_unwind;
|
|
||||||
err = link_start(dev);
|
err = link_start(dev);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_unwind;
|
goto err_unwind;
|
||||||
|
@ -2176,6 +2172,73 @@ static void cleanup_debugfs(struct adapter *adapter)
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Figure out how many Ports and Queue Sets we can support. This depends on
|
||||||
|
* knowing our Virtual Function Resources and may be called a second time if
|
||||||
|
* we fall back from MSI-X to MSI Interrupt Mode.
|
||||||
|
*/
|
||||||
|
static void size_nports_qsets(struct adapter *adapter)
|
||||||
|
{
|
||||||
|
struct vf_resources *vfres = &adapter->params.vfres;
|
||||||
|
unsigned int ethqsets, pmask_nports;
|
||||||
|
|
||||||
|
/* The number of "ports" which we support is equal to the number of
|
||||||
|
* Virtual Interfaces with which we've been provisioned.
|
||||||
|
*/
|
||||||
|
adapter->params.nports = vfres->nvi;
|
||||||
|
if (adapter->params.nports > MAX_NPORTS) {
|
||||||
|
dev_warn(adapter->pdev_dev, "only using %d of %d maximum"
|
||||||
|
" allowed virtual interfaces\n", MAX_NPORTS,
|
||||||
|
adapter->params.nports);
|
||||||
|
adapter->params.nports = MAX_NPORTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We may have been provisioned with more VIs than the number of
|
||||||
|
* ports we're allowed to access (our Port Access Rights Mask).
|
||||||
|
* This is obviously a configuration conflict but we don't want to
|
||||||
|
* crash the kernel or anything silly just because of that.
|
||||||
|
*/
|
||||||
|
pmask_nports = hweight32(adapter->params.vfres.pmask);
|
||||||
|
if (pmask_nports < adapter->params.nports) {
|
||||||
|
dev_warn(adapter->pdev_dev, "only using %d of %d provissioned"
|
||||||
|
" virtual interfaces; limited by Port Access Rights"
|
||||||
|
" mask %#x\n", pmask_nports, adapter->params.nports,
|
||||||
|
adapter->params.vfres.pmask);
|
||||||
|
adapter->params.nports = pmask_nports;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to reserve an Ingress Queue for the Asynchronous Firmware
|
||||||
|
* Event Queue. And if we're using MSI Interrupts, we'll also need to
|
||||||
|
* reserve an Ingress Queue for a Forwarded Interrupts.
|
||||||
|
*
|
||||||
|
* The rest of the FL/Intr-capable ingress queues will be matched up
|
||||||
|
* one-for-one with Ethernet/Control egress queues in order to form
|
||||||
|
* "Queue Sets" which will be aportioned between the "ports". For
|
||||||
|
* each Queue Set, we'll need the ability to allocate two Egress
|
||||||
|
* Contexts -- one for the Ingress Queue Free List and one for the TX
|
||||||
|
* Ethernet Queue.
|
||||||
|
*
|
||||||
|
* Note that even if we're currently configured to use MSI-X
|
||||||
|
* Interrupts (module variable msi == MSI_MSIX) we may get downgraded
|
||||||
|
* to MSI Interrupts if we can't get enough MSI-X Interrupts. If that
|
||||||
|
* happens we'll need to adjust things later.
|
||||||
|
*/
|
||||||
|
ethqsets = vfres->niqflint - 1 - (msi == MSI_MSI);
|
||||||
|
if (vfres->nethctrl != ethqsets)
|
||||||
|
ethqsets = min(vfres->nethctrl, ethqsets);
|
||||||
|
if (vfres->neq < ethqsets*2)
|
||||||
|
ethqsets = vfres->neq/2;
|
||||||
|
if (ethqsets > MAX_ETH_QSETS)
|
||||||
|
ethqsets = MAX_ETH_QSETS;
|
||||||
|
adapter->sge.max_ethqsets = ethqsets;
|
||||||
|
|
||||||
|
if (adapter->sge.max_ethqsets < adapter->params.nports) {
|
||||||
|
dev_warn(adapter->pdev_dev, "only using %d of %d available"
|
||||||
|
" virtual interfaces (too few Queue Sets)\n",
|
||||||
|
adapter->sge.max_ethqsets, adapter->params.nports);
|
||||||
|
adapter->params.nports = adapter->sge.max_ethqsets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform early "adapter" initialization. This is where we discover what
|
* Perform early "adapter" initialization. This is where we discover what
|
||||||
* adapter parameters we're going to be using and initialize basic adapter
|
* adapter parameters we're going to be using and initialize basic adapter
|
||||||
|
@ -2183,10 +2246,8 @@ static void cleanup_debugfs(struct adapter *adapter)
|
||||||
*/
|
*/
|
||||||
static int adap_init0(struct adapter *adapter)
|
static int adap_init0(struct adapter *adapter)
|
||||||
{
|
{
|
||||||
struct vf_resources *vfres = &adapter->params.vfres;
|
|
||||||
struct sge_params *sge_params = &adapter->params.sge;
|
struct sge_params *sge_params = &adapter->params.sge;
|
||||||
struct sge *s = &adapter->sge;
|
struct sge *s = &adapter->sge;
|
||||||
unsigned int ethqsets;
|
|
||||||
int err;
|
int err;
|
||||||
u32 param, val = 0;
|
u32 param, val = 0;
|
||||||
|
|
||||||
|
@ -2295,69 +2356,23 @@ static int adap_init0(struct adapter *adapter)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Check for various parameter sanity issues */
|
||||||
* The number of "ports" which we support is equal to the number of
|
if (adapter->params.vfres.pmask == 0) {
|
||||||
* Virtual Interfaces with which we've been provisioned.
|
dev_err(adapter->pdev_dev, "no port access configured\n"
|
||||||
*/
|
"usable!\n");
|
||||||
adapter->params.nports = vfres->nvi;
|
return -EINVAL;
|
||||||
if (adapter->params.nports > MAX_NPORTS) {
|
|
||||||
dev_warn(adapter->pdev_dev, "only using %d of %d allowed"
|
|
||||||
" virtual interfaces\n", MAX_NPORTS,
|
|
||||||
adapter->params.nports);
|
|
||||||
adapter->params.nports = MAX_NPORTS;
|
|
||||||
}
|
}
|
||||||
|
if (adapter->params.vfres.nvi == 0) {
|
||||||
/*
|
|
||||||
* We need to reserve a number of the ingress queues with Free List
|
|
||||||
* and Interrupt capabilities for special interrupt purposes (like
|
|
||||||
* asynchronous firmware messages, or forwarded interrupts if we're
|
|
||||||
* using MSI). The rest of the FL/Intr-capable ingress queues will be
|
|
||||||
* matched up one-for-one with Ethernet/Control egress queues in order
|
|
||||||
* to form "Queue Sets" which will be aportioned between the "ports".
|
|
||||||
* For each Queue Set, we'll need the ability to allocate two Egress
|
|
||||||
* Contexts -- one for the Ingress Queue Free List and one for the TX
|
|
||||||
* Ethernet Queue.
|
|
||||||
*/
|
|
||||||
ethqsets = vfres->niqflint - INGQ_EXTRAS;
|
|
||||||
if (vfres->nethctrl != ethqsets) {
|
|
||||||
dev_warn(adapter->pdev_dev, "unequal number of [available]"
|
|
||||||
" ingress/egress queues (%d/%d); using minimum for"
|
|
||||||
" number of Queue Sets\n", ethqsets, vfres->nethctrl);
|
|
||||||
ethqsets = min(vfres->nethctrl, ethqsets);
|
|
||||||
}
|
|
||||||
if (vfres->neq < ethqsets*2) {
|
|
||||||
dev_warn(adapter->pdev_dev, "Not enough Egress Contexts (%d)"
|
|
||||||
" to support Queue Sets (%d); reducing allowed Queue"
|
|
||||||
" Sets\n", vfres->neq, ethqsets);
|
|
||||||
ethqsets = vfres->neq/2;
|
|
||||||
}
|
|
||||||
if (ethqsets > MAX_ETH_QSETS) {
|
|
||||||
dev_warn(adapter->pdev_dev, "only using %d of %d allowed Queue"
|
|
||||||
" Sets\n", MAX_ETH_QSETS, adapter->sge.max_ethqsets);
|
|
||||||
ethqsets = MAX_ETH_QSETS;
|
|
||||||
}
|
|
||||||
if (vfres->niq != 0 || vfres->neq > ethqsets*2) {
|
|
||||||
dev_warn(adapter->pdev_dev, "unused resources niq/neq (%d/%d)"
|
|
||||||
" ignored\n", vfres->niq, vfres->neq - ethqsets*2);
|
|
||||||
}
|
|
||||||
adapter->sge.max_ethqsets = ethqsets;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for various parameter sanity issues. Most checks simply
|
|
||||||
* result in us using fewer resources than our provissioning but we
|
|
||||||
* do need at least one "port" with which to work ...
|
|
||||||
*/
|
|
||||||
if (adapter->sge.max_ethqsets < adapter->params.nports) {
|
|
||||||
dev_warn(adapter->pdev_dev, "only using %d of %d available"
|
|
||||||
" virtual interfaces (too few Queue Sets)\n",
|
|
||||||
adapter->sge.max_ethqsets, adapter->params.nports);
|
|
||||||
adapter->params.nports = adapter->sge.max_ethqsets;
|
|
||||||
}
|
|
||||||
if (adapter->params.nports == 0) {
|
|
||||||
dev_err(adapter->pdev_dev, "no virtual interfaces configured/"
|
dev_err(adapter->pdev_dev, "no virtual interfaces configured/"
|
||||||
"usable!\n");
|
"usable!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize nports and max_ethqsets now that we have our Virtual
|
||||||
|
* Function Resources.
|
||||||
|
*/
|
||||||
|
size_nports_qsets(adapter);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2771,6 +2786,40 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See what interrupts we'll be using. If we've been configured to
|
||||||
|
* use MSI-X interrupts, try to enable them but fall back to using
|
||||||
|
* MSI interrupts if we can't enable MSI-X interrupts. If we can't
|
||||||
|
* get MSI interrupts we bail with the error.
|
||||||
|
*/
|
||||||
|
if (msi == MSI_MSIX && enable_msix(adapter) == 0)
|
||||||
|
adapter->flags |= USING_MSIX;
|
||||||
|
else {
|
||||||
|
if (msi == MSI_MSIX) {
|
||||||
|
dev_info(adapter->pdev_dev,
|
||||||
|
"Unable to use MSI-X Interrupts; falling "
|
||||||
|
"back to MSI Interrupts\n");
|
||||||
|
|
||||||
|
/* We're going to need a Forwarded Interrupt Queue so
|
||||||
|
* that may cut into how many Queue Sets we can
|
||||||
|
* support.
|
||||||
|
*/
|
||||||
|
msi = MSI_MSI;
|
||||||
|
size_nports_qsets(adapter);
|
||||||
|
}
|
||||||
|
err = pci_enable_msi(pdev);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "Unable to allocate MSI Interrupts;"
|
||||||
|
" err=%d\n", err);
|
||||||
|
goto err_free_dev;
|
||||||
|
}
|
||||||
|
adapter->flags |= USING_MSI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now that we know how many "ports" we have and what interrupt
|
||||||
|
* mechanism we're going to use, we can configure our queue resources.
|
||||||
|
*/
|
||||||
|
cfg_queues(adapter);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The "card" is now ready to go. If any errors occur during device
|
* The "card" is now ready to go. If any errors occur during device
|
||||||
* registration we do not fail the whole "card" but rather proceed
|
* registration we do not fail the whole "card" but rather proceed
|
||||||
|
@ -2778,10 +2827,14 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
|
||||||
* must register at least one net device.
|
* must register at least one net device.
|
||||||
*/
|
*/
|
||||||
for_each_port(adapter, pidx) {
|
for_each_port(adapter, pidx) {
|
||||||
|
struct port_info *pi = netdev_priv(adapter->port[pidx]);
|
||||||
netdev = adapter->port[pidx];
|
netdev = adapter->port[pidx];
|
||||||
if (netdev == NULL)
|
if (netdev == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
netif_set_real_num_tx_queues(netdev, pi->nqsets);
|
||||||
|
netif_set_real_num_rx_queues(netdev, pi->nqsets);
|
||||||
|
|
||||||
err = register_netdev(netdev);
|
err = register_netdev(netdev);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_warn(&pdev->dev, "cannot register net device %s,"
|
dev_warn(&pdev->dev, "cannot register net device %s,"
|
||||||
|
@ -2793,7 +2846,7 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
|
||||||
}
|
}
|
||||||
if (adapter->registered_device_map == 0) {
|
if (adapter->registered_device_map == 0) {
|
||||||
dev_err(&pdev->dev, "could not register any net devices\n");
|
dev_err(&pdev->dev, "could not register any net devices\n");
|
||||||
goto err_free_dev;
|
goto err_disable_interrupts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2810,32 +2863,6 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
|
||||||
setup_debugfs(adapter);
|
setup_debugfs(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* See what interrupts we'll be using. If we've been configured to
|
|
||||||
* use MSI-X interrupts, try to enable them but fall back to using
|
|
||||||
* MSI interrupts if we can't enable MSI-X interrupts. If we can't
|
|
||||||
* get MSI interrupts we bail with the error.
|
|
||||||
*/
|
|
||||||
if (msi == MSI_MSIX && enable_msix(adapter) == 0)
|
|
||||||
adapter->flags |= USING_MSIX;
|
|
||||||
else {
|
|
||||||
err = pci_enable_msi(pdev);
|
|
||||||
if (err) {
|
|
||||||
dev_err(&pdev->dev, "Unable to allocate %s interrupts;"
|
|
||||||
" err=%d\n",
|
|
||||||
msi == MSI_MSIX ? "MSI-X or MSI" : "MSI", err);
|
|
||||||
goto err_free_debugfs;
|
|
||||||
}
|
|
||||||
adapter->flags |= USING_MSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now that we know how many "ports" we have and what their types are,
|
|
||||||
* and how many Queue Sets we can support, we can configure our queue
|
|
||||||
* resources.
|
|
||||||
*/
|
|
||||||
cfg_queues(adapter);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print a short notice on the existence and configuration of the new
|
* Print a short notice on the existence and configuration of the new
|
||||||
* VF network device ...
|
* VF network device ...
|
||||||
|
@ -2856,11 +2883,13 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
|
||||||
* Error recovery and exit code. Unwind state that's been created
|
* Error recovery and exit code. Unwind state that's been created
|
||||||
* so far and return the error.
|
* so far and return the error.
|
||||||
*/
|
*/
|
||||||
|
err_disable_interrupts:
|
||||||
err_free_debugfs:
|
if (adapter->flags & USING_MSIX) {
|
||||||
if (!IS_ERR_OR_NULL(adapter->debugfs_root)) {
|
pci_disable_msix(adapter->pdev);
|
||||||
cleanup_debugfs(adapter);
|
adapter->flags &= ~USING_MSIX;
|
||||||
debugfs_remove_recursive(adapter->debugfs_root);
|
} else if (adapter->flags & USING_MSI) {
|
||||||
|
pci_disable_msi(adapter->pdev);
|
||||||
|
adapter->flags &= ~USING_MSI;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_free_dev:
|
err_free_dev:
|
||||||
|
|
Loading…
Reference in a new issue