sfc: work around TRIGGER_INTERRUPT command not working on SFC9140
authorJon Cooper <jcooper@solarflare.com>
Fri, 26 Aug 2016 14:13:30 +0000 (15:13 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sat, 27 Aug 2016 04:43:52 +0000 (21:43 -0700)
MC_CMD_TRIGGER_INTERRUPT does not work on the SFC9140, as used in the
sfn7x42q and sfn7x24f.
Check for this using the MCDI workaround mechanism.
The command is only used during self test.  If it's not supported, skip
the interrupt test.

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/farch.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/nic.c
drivers/net/ethernet/sfc/nic.h
drivers/net/ethernet/sfc/selftest.c
drivers/net/ethernet/sfc/selftest.h

index c4cd6b08acd14d1b9901b904d407fbe6b95e2700..6fe1d0ba78b223eb448d6b8f6f0091faabefb439 100644 (file)
@@ -2048,14 +2048,18 @@ static irqreturn_t efx_ef10_legacy_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void efx_ef10_irq_test_generate(struct efx_nic *efx)
+static int efx_ef10_irq_test_generate(struct efx_nic *efx)
 {
        MCDI_DECLARE_BUF(inbuf, MC_CMD_TRIGGER_INTERRUPT_IN_LEN);
 
+       if (efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG41750, true,
+                                   NULL) == 0)
+               return -ENOTSUPP;
+
        BUILD_BUG_ON(MC_CMD_TRIGGER_INTERRUPT_OUT_LEN != 0);
 
        MCDI_SET_DWORD(inbuf, TRIGGER_INTERRUPT_IN_INTR_LEVEL, efx->irq_level);
-       (void) efx_mcdi_rpc(efx, MC_CMD_TRIGGER_INTERRUPT,
+       return efx_mcdi_rpc(efx, MC_CMD_TRIGGER_INTERRUPT,
                            inbuf, sizeof(inbuf), NULL, 0, NULL);
 }
 
index 4c83739d158f1d36714b40d4eedfbec34c942882..4762ec444cb8ee985cbc09985d07fade1027208b 100644 (file)
@@ -1477,9 +1477,10 @@ void efx_farch_irq_disable_master(struct efx_nic *efx)
  * Interrupt must already have been enabled, otherwise nasty things
  * may happen.
  */
-void efx_farch_irq_test_generate(struct efx_nic *efx)
+int efx_farch_irq_test_generate(struct efx_nic *efx)
 {
        efx_farch_interrupts(efx, true, true);
+       return 0;
 }
 
 /* Process a fatal interrupt
index 13b7f52e6724f4027b5fb23ccc6eef1d60464f75..0a2504b5dad53f0e6f2018ac18c3bfd0124bd67c 100644 (file)
@@ -1275,7 +1275,7 @@ struct efx_nic_type {
        int (*mcdi_poll_reboot)(struct efx_nic *efx);
        void (*mcdi_reboot_detected)(struct efx_nic *efx);
        void (*irq_enable_master)(struct efx_nic *efx);
-       void (*irq_test_generate)(struct efx_nic *efx);
+       int (*irq_test_generate)(struct efx_nic *efx);
        void (*irq_disable_non_ev)(struct efx_nic *efx);
        irqreturn_t (*irq_handle_msi)(int irq, void *dev_id);
        irqreturn_t (*irq_handle_legacy)(int irq, void *dev_id);
index 89b83e59e1dc601898ddd60bd0fa704fdd7b6d43..aa1945a858d5e2984aa8f70a9027e36450a3cb5f 100644 (file)
@@ -66,11 +66,11 @@ void efx_nic_event_test_start(struct efx_channel *channel)
        channel->efx->type->ev_test_generate(channel);
 }
 
-void efx_nic_irq_test_start(struct efx_nic *efx)
+int efx_nic_irq_test_start(struct efx_nic *efx)
 {
        efx->last_irq_cpu = -1;
        smp_wmb();
-       efx->type->irq_test_generate(efx);
+       return efx->type->irq_test_generate(efx);
 }
 
 /* Hook interrupt handler(s)
index d8b1694638cd63b2b5e008c407cfa93c1c295bed..73bee7ea332a9178ae663fa040ec518345af22a6 100644 (file)
@@ -746,12 +746,12 @@ static inline void efx_update_diff_stat(u64 *stat, u64 diff)
 
 /* Interrupts */
 int efx_nic_init_interrupt(struct efx_nic *efx);
-void efx_nic_irq_test_start(struct efx_nic *efx);
+int efx_nic_irq_test_start(struct efx_nic *efx);
 void efx_nic_fini_interrupt(struct efx_nic *efx);
 
 /* Falcon/Siena interrupts */
 void efx_farch_irq_enable_master(struct efx_nic *efx);
-void efx_farch_irq_test_generate(struct efx_nic *efx);
+int efx_farch_irq_test_generate(struct efx_nic *efx);
 void efx_farch_irq_disable_master(struct efx_nic *efx);
 irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id);
 irqreturn_t efx_farch_legacy_interrupt(int irq, void *dev_id);
index 9d78830da6097ff1e6a42873f580734c7f970180..cd38b44ae23af330bca1c1b49d60a89b26438814 100644 (file)
@@ -135,11 +135,19 @@ static int efx_test_interrupts(struct efx_nic *efx,
 {
        unsigned long timeout, wait;
        int cpu;
+       int rc;
 
        netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n");
        tests->interrupt = -1;
 
-       efx_nic_irq_test_start(efx);
+       rc = efx_nic_irq_test_start(efx);
+       if (rc == -ENOTSUPP) {
+               netif_dbg(efx, drv, efx->net_dev,
+                         "direct interrupt testing not supported\n");
+               tests->interrupt = 0;
+               return 0;
+       }
+
        timeout = jiffies + IRQ_TIMEOUT;
        wait = 1;
 
index 009dbe88f3be7f0eb661355e2c9819d51ec9a9b1..32a427253a0331f3ec27e932c4078dad60fe2026 100644 (file)
@@ -28,7 +28,7 @@ struct efx_loopback_self_tests {
 
 /* Efx self test results
  * For fields which are not counters, 1 indicates success and -1
- * indicates failure.
+ * indicates failure; 0 indicates test could not be run.
  */
 struct efx_self_tests {
        /* online tests */