aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/sfc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/efx.c39
-rw-r--r--drivers/net/sfc/falcon.c12
-rw-r--r--drivers/net/sfc/net_driver.h5
3 files changed, 42 insertions, 14 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 7b2015f9e46..45c72eebb3a 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -19,6 +19,7 @@
#include <linux/in.h>
#include <linux/crc32.h>
#include <linux/ethtool.h>
+#include <linux/topology.h>
#include "net_driver.h"
#include "gmii.h"
#include "ethtool.h"
@@ -832,7 +833,23 @@ static void efx_probe_interrupts(struct efx_nic *efx)
if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX));
- efx->rss_queues = rss_cpus ? rss_cpus : num_online_cpus();
+ if (rss_cpus == 0) {
+ cpumask_t core_mask;
+ int cpu;
+
+ cpus_clear(core_mask);
+ efx->rss_queues = 0;
+ for_each_online_cpu(cpu) {
+ if (!cpu_isset(cpu, core_mask)) {
+ ++efx->rss_queues;
+ cpus_or(core_mask, core_mask,
+ topology_core_siblings(cpu));
+ }
+ }
+ } else {
+ efx->rss_queues = rss_cpus;
+ }
+
efx->rss_queues = min(efx->rss_queues, max_channel + 1);
efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS);
@@ -1762,7 +1779,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
efx->reset_pending = method;
- queue_work(efx->workqueue, &efx->reset_work);
+ queue_work(efx->reset_workqueue, &efx->reset_work);
}
/**************************************************************************
@@ -1907,14 +1924,28 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
goto fail1;
}
+ efx->reset_workqueue = create_singlethread_workqueue("sfc_reset");
+ if (!efx->reset_workqueue) {
+ rc = -ENOMEM;
+ goto fail2;
+ }
+
return 0;
+ fail2:
+ destroy_workqueue(efx->workqueue);
+ efx->workqueue = NULL;
+
fail1:
return rc;
}
static void efx_fini_struct(struct efx_nic *efx)
{
+ if (efx->reset_workqueue) {
+ destroy_workqueue(efx->reset_workqueue);
+ efx->reset_workqueue = NULL;
+ }
if (efx->workqueue) {
destroy_workqueue(efx->workqueue);
efx->workqueue = NULL;
@@ -1977,7 +2008,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
* scheduled from this point because efx_stop_all() has been
* called, we are no longer registered with driverlink, and
* the net_device's have been removed. */
- flush_workqueue(efx->workqueue);
+ flush_workqueue(efx->reset_workqueue);
efx_pci_remove_main(efx);
@@ -2098,7 +2129,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
* scheduled since efx_stop_all() has been called, and we
* have not and never have been registered with either
* the rtnetlink or driverlink layers. */
- cancel_work_sync(&efx->reset_work);
+ flush_workqueue(efx->reset_workqueue);
/* Retry if a recoverably reset event has been scheduled */
if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 630406e142e..9138ee5b7b7 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -223,13 +223,8 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = {
.getsda = falcon_getsda,
.getscl = falcon_getscl,
.udelay = 5,
- /*
- * This is the number of system clock ticks after which
- * i2c-algo-bit gives up waiting for SCL to become high.
- * It must be at least 2 since the first tick can happen
- * immediately after it starts waiting.
- */
- .timeout = 2,
+ /* Wait up to 50 ms for slave to let us pull SCL high */
+ .timeout = DIV_ROUND_UP(HZ, 20),
};
/**************************************************************************
@@ -2479,12 +2474,11 @@ int falcon_probe_nic(struct efx_nic *efx)
/* Initialise I2C adapter */
efx->i2c_adap.owner = THIS_MODULE;
- efx->i2c_adap.class = I2C_CLASS_HWMON;
nic_data->i2c_data = falcon_i2c_bit_operations;
nic_data->i2c_data.data = efx;
efx->i2c_adap.algo_data = &nic_data->i2c_data;
efx->i2c_adap.dev.parent = &efx->pci_dev->dev;
- strcpy(efx->i2c_adap.name, "SFC4000 GPIO");
+ strlcpy(efx->i2c_adap.name, "SFC4000 GPIO", sizeof(efx->i2c_adap.name));
rc = i2c_bit_add_bus(&efx->i2c_adap);
if (rc)
goto fail5;
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index d803b86c647..219c74a772c 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -616,7 +616,9 @@ union efx_multicast_hash {
* @pci_dev: The PCI device
* @type: Controller type attributes
* @legacy_irq: IRQ number
- * @workqueue: Workqueue for resets, port reconfigures and the HW monitor
+ * @workqueue: Workqueue for port reconfigures and the HW monitor.
+ * Work items do not hold and must not acquire RTNL.
+ * @reset_workqueue: Workqueue for resets. Work item will acquire RTNL.
* @reset_work: Scheduled reset workitem
* @monitor_work: Hardware monitor workitem
* @membase_phys: Memory BAR value as physical address
@@ -684,6 +686,7 @@ struct efx_nic {
const struct efx_nic_type *type;
int legacy_irq;
struct workqueue_struct *workqueue;
+ struct workqueue_struct *reset_workqueue;
struct work_struct reset_work;
struct delayed_work monitor_work;
resource_size_t membase_phys;