Thread (20 messages) 20 messages, 2 authors, 2013-09-02
STALE4652d

[PATCH net-next 06/16] sfc: Allow event queue initialisation to fail

From: Ben Hutchings <hidden>
Date: 2013-08-30 03:40:03
Subsystem: networking drivers, sfc network driver, the rest · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Edward Cree, Linus Torvalds

From: Jon Cooper <redacted>

On EF10, event queue initialisation requires an MCDI request which
may return failure.

Signed-off-by: Ben Hutchings <redacted>
---
 drivers/net/ethernet/sfc/efx.c        |  111 ++++++++++++++++++++++++++-------
 drivers/net/ethernet/sfc/farch.c      |    4 +-
 drivers/net/ethernet/sfc/net_driver.h |    2 +-
 drivers/net/ethernet/sfc/nic.h        |    6 +-
 4 files changed, 95 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 69150fa..84c47d3 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -189,7 +189,7 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
  *
  *************************************************************************/
 
-static void efx_soft_enable_interrupts(struct efx_nic *efx);
+static int efx_soft_enable_interrupts(struct efx_nic *efx);
 static void efx_soft_disable_interrupts(struct efx_nic *efx);
 static void efx_remove_channel(struct efx_channel *channel);
 static void efx_remove_channels(struct efx_nic *efx);
@@ -329,15 +329,21 @@ static int efx_probe_eventq(struct efx_channel *channel)
 }
 
 /* Prepare channel's event queue */
-static void efx_init_eventq(struct efx_channel *channel)
+static int efx_init_eventq(struct efx_channel *channel)
 {
+	int rc;
+
+	EFX_WARN_ON_PARANOID(channel->eventq_init);
+
 	netif_dbg(channel->efx, drv, channel->efx->net_dev,
 		  "chan %d init event queue\n", channel->channel);
 
-	channel->eventq_read_ptr = 0;
-
-	efx_nic_init_eventq(channel);
-	channel->eventq_init = true;
+	rc = efx_nic_init_eventq(channel);
+	if (rc == 0) {
+		channel->eventq_read_ptr = 0;
+		channel->eventq_init = true;
+	}
+	return rc;
 }
 
 /* Enable event queue processing and NAPI */
@@ -722,7 +728,7 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
 	struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel;
 	u32 old_rxq_entries, old_txq_entries;
 	unsigned i, next_buffer_table = 0;
-	int rc;
+	int rc, rc2;
 
 	rc = efx_check_disabled(efx);
 	if (rc)
@@ -802,9 +808,16 @@ out:
 		}
 	}
 
-	efx_soft_enable_interrupts(efx);
-	efx_start_all(efx);
-	netif_device_attach(efx->net_dev);
+	rc2 = efx_soft_enable_interrupts(efx);
+	if (rc2) {
+		rc = rc ? rc : rc2;
+		netif_err(efx, drv, efx->net_dev,
+			  "unable to restart interrupts on channel reallocation\n");
+		efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+	} else {
+		efx_start_all(efx);
+		netif_device_attach(efx->net_dev);
+	}
 	return rc;
 
 rollback:
@@ -1327,9 +1340,10 @@ static int efx_probe_interrupts(struct efx_nic *efx)
 	return 0;
 }
 
-static void efx_soft_enable_interrupts(struct efx_nic *efx)
+static int efx_soft_enable_interrupts(struct efx_nic *efx)
 {
-	struct efx_channel *channel;
+	struct efx_channel *channel, *end_channel;
+	int rc;
 
 	BUG_ON(efx->state == STATE_DISABLED);
 
@@ -1337,12 +1351,28 @@ static void efx_soft_enable_interrupts(struct efx_nic *efx)
 	smp_wmb();
 
 	efx_for_each_channel(channel, efx) {
-		if (!channel->type->keep_eventq)
-			efx_init_eventq(channel);
+		if (!channel->type->keep_eventq) {
+			rc = efx_init_eventq(channel);
+			if (rc)
+				goto fail;
+		}
 		efx_start_eventq(channel);
 	}
 
 	efx_mcdi_mode_event(efx);
+
+	return 0;
+fail:
+	end_channel = channel;
+	efx_for_each_channel(channel, efx) {
+		if (channel == end_channel)
+			break;
+		efx_stop_eventq(channel);
+		if (!channel->type->keep_eventq)
+			efx_fini_eventq(channel);
+	}
+
+	return rc;
 }
 
 static void efx_soft_disable_interrupts(struct efx_nic *efx)
@@ -1373,9 +1403,10 @@ static void efx_soft_disable_interrupts(struct efx_nic *efx)
 	efx_mcdi_flush_async(efx);
 }
 
-static void efx_enable_interrupts(struct efx_nic *efx)
+static int efx_enable_interrupts(struct efx_nic *efx)
 {
-	struct efx_channel *channel;
+	struct efx_channel *channel, *end_channel;
+	int rc;
 
 	BUG_ON(efx->state == STATE_DISABLED);
 
@@ -1387,11 +1418,31 @@ static void efx_enable_interrupts(struct efx_nic *efx)
 	efx->type->irq_enable_master(efx);
 
 	efx_for_each_channel(channel, efx) {
+		if (channel->type->keep_eventq) {
+			rc = efx_init_eventq(channel);
+			if (rc)
+				goto fail;
+		}
+	}
+
+	rc = efx_soft_enable_interrupts(efx);
+	if (rc)
+		goto fail;
+
+	return 0;
+
+fail:
+	end_channel = channel;
+	efx_for_each_channel(channel, efx) {
+		if (channel == end_channel)
+			break;
 		if (channel->type->keep_eventq)
-			efx_init_eventq(channel);
+			efx_fini_eventq(channel);
 	}
 
-	efx_soft_enable_interrupts(efx);
+	efx->type->irq_disable_non_ev(efx);
+
+	return rc;
 }
 
 static void efx_disable_interrupts(struct efx_nic *efx)
@@ -2205,7 +2256,9 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
 				  "could not restore PHY settings\n");
 	}
 
-	efx_enable_interrupts(efx);
+	rc = efx_enable_interrupts(efx);
+	if (rc)
+		goto fail;
 	efx_restore_filters(efx);
 	efx_sriov_reset(efx);
 
@@ -2649,10 +2702,14 @@ static int efx_pci_probe_main(struct efx_nic *efx)
 	rc = efx_nic_init_interrupt(efx);
 	if (rc)
 		goto fail5;
-	efx_enable_interrupts(efx);
+	rc = efx_enable_interrupts(efx);
+	if (rc)
+		goto fail6;
 
 	return 0;
 
+ fail6:
+	efx_nic_fini_interrupt(efx);
  fail5:
 	efx_fini_port(efx);
  fail4:
@@ -2780,12 +2837,15 @@ static int efx_pm_freeze(struct device *dev)
 
 static int efx_pm_thaw(struct device *dev)
 {
+	int rc;
 	struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
 
 	rtnl_lock();
 
 	if (efx->state != STATE_DISABLED) {
-		efx_enable_interrupts(efx);
+		rc = efx_enable_interrupts(efx);
+		if (rc)
+			goto fail;
 
 		mutex_lock(&efx->mac_lock);
 		efx->phy_op->reconfigure(efx);
@@ -2806,6 +2866,11 @@ static int efx_pm_thaw(struct device *dev)
 	queue_work(reset_workqueue, &efx->reset_work);
 
 	return 0;
+
+fail:
+	rtnl_unlock();
+
+	return rc;
 }
 
 static int efx_pm_poweroff(struct device *dev)
@@ -2842,8 +2907,8 @@ static int efx_pm_resume(struct device *dev)
 	rc = efx->type->init(efx);
 	if (rc)
 		return rc;
-	efx_pm_thaw(dev);
-	return 0;
+	rc = efx_pm_thaw(dev);
+	return rc;
 }
 
 static int efx_pm_suspend(struct device *dev)
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index d21483d..904af5c 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -1325,7 +1325,7 @@ int efx_farch_ev_probe(struct efx_channel *channel)
 					entries * sizeof(efx_qword_t));
 }
 
-void efx_farch_ev_init(struct efx_channel *channel)
+int efx_farch_ev_init(struct efx_channel *channel)
 {
 	efx_oword_t reg;
 	struct efx_nic *efx = channel->efx;
@@ -1358,6 +1358,8 @@ void efx_farch_ev_init(struct efx_channel *channel)
 			 channel->channel);
 
 	efx->type->push_irq_moderation(channel);
+
+	return 0;
 }
 
 void efx_farch_ev_fini(struct efx_channel *channel)
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index e85bed0..54900f3 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1087,7 +1087,7 @@ struct efx_nic_type {
 	void (*rx_write)(struct efx_rx_queue *rx_queue);
 	void (*rx_defer_refill)(struct efx_rx_queue *rx_queue);
 	int (*ev_probe)(struct efx_channel *channel);
-	void (*ev_init)(struct efx_channel *channel);
+	int (*ev_init)(struct efx_channel *channel);
 	void (*ev_fini)(struct efx_channel *channel);
 	void (*ev_remove)(struct efx_channel *channel);
 	int (*ev_process)(struct efx_channel *channel, int quota);
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 9afbf36..686ce7a 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -503,9 +503,9 @@ static inline int efx_nic_probe_eventq(struct efx_channel *channel)
 {
 	return channel->efx->type->ev_probe(channel);
 }
-static inline void efx_nic_init_eventq(struct efx_channel *channel)
+static inline int efx_nic_init_eventq(struct efx_channel *channel)
 {
-	channel->efx->type->ev_init(channel);
+	return channel->efx->type->ev_init(channel);
 }
 static inline void efx_nic_fini_eventq(struct efx_channel *channel)
 {
@@ -539,7 +539,7 @@ extern void efx_farch_rx_remove(struct efx_rx_queue *rx_queue);
 extern void efx_farch_rx_write(struct efx_rx_queue *rx_queue);
 extern void efx_farch_rx_defer_refill(struct efx_rx_queue *rx_queue);
 extern int efx_farch_ev_probe(struct efx_channel *channel);
-extern void efx_farch_ev_init(struct efx_channel *channel);
+extern int efx_farch_ev_init(struct efx_channel *channel);
 extern void efx_farch_ev_fini(struct efx_channel *channel);
 extern void efx_farch_ev_remove(struct efx_channel *channel);
 extern int efx_farch_ev_process(struct efx_channel *channel, int quota);

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help