cxgb4: Shutdown adapter if firmware times out or errors out
authorHariprasad Shenai <hariprasad@chelsio.com>
Fri, 13 Jan 2017 16:25:26 +0000 (21:55 +0530)
committerDavid S. Miller <davem@davemloft.net>
Mon, 16 Jan 2017 18:35:30 +0000 (13:35 -0500)
Perform an emergency shutdown of the adapter and stop it from
continuing any further communication on the ports or DMA to the
host. This is typically used when the adapter and/or firmware
have crashed and we want to prevent any further accidental
communication with the rest of the world. This will also force
the port Link Status to go down -- if register writes work --
which should help our peers figure out that we're down.

Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h

index ad0096e748134e80b2bb69d954fedda2d6d4fc3f..ccb455f14d08b94542252287f48ce24f81e5c4ab 100644 (file)
@@ -1501,6 +1501,7 @@ int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info,
               const u8 *fw_data, unsigned int fw_size,
               struct fw_hdr *card_fw, enum dev_state state, int *reset);
 int t4_prep_adapter(struct adapter *adapter);
+int t4_shutdown_adapter(struct adapter *adapter);
 
 enum t4_bar2_qtype { T4_BAR2_QTYPE_EGRESS, T4_BAR2_QTYPE_INGRESS };
 int t4_bar2_sge_qregs(struct adapter *adapter,
index e95bb6a0eca8f7ca177da7b67f1cd51721dca09b..fb16245440734ad4ea55a50da182af1bf648d81a 100644 (file)
@@ -2782,8 +2782,24 @@ static const struct ethtool_ops cxgb4_mgmt_ethtool_ops = {
 
 void t4_fatal_err(struct adapter *adap)
 {
-       t4_set_reg_field(adap, SGE_CONTROL_A, GLOBALENABLE_F, 0);
-       t4_intr_disable(adap);
+       int port;
+
+       /* Disable the SGE since ULDs are going to free resources that
+        * could be exposed to the adapter.  RDMA MWs for example...
+        */
+       t4_shutdown_adapter(adap);
+       for_each_port(adap, port) {
+               struct net_device *dev = adap->port[port];
+
+               /* If we get here in very early initialization the network
+                * devices may not have been set up yet.
+                */
+               if (!dev)
+                       continue;
+
+               netif_tx_stop_all_queues(dev);
+               netif_carrier_off(dev);
+       }
        dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n");
 }
 
index ac712acf256d69213679aeeea153c69548f855c8..87000cd397372ab999d25ea2c935f0385fa941ee 100644 (file)
@@ -330,11 +330,12 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
                 * mailbox access list but this is a start.  We very rearely
                 * contend on access to the mailbox ...
                 */
-               if (i > FW_CMD_MAX_TIMEOUT) {
+               pcie_fw = t4_read_reg(adap, PCIE_FW_A);
+               if (i > FW_CMD_MAX_TIMEOUT || (pcie_fw & PCIE_FW_ERR_F)) {
                        spin_lock(&adap->mbox_lock);
                        list_del(&entry.list);
                        spin_unlock(&adap->mbox_lock);
-                       ret = -EBUSY;
+                       ret = (pcie_fw & PCIE_FW_ERR_F) ? -ENXIO : -EBUSY;
                        t4_record_mbox(adap, cmd, size, access, ret);
                        return ret;
                }
@@ -432,6 +433,7 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
        spin_lock(&adap->mbox_lock);
        list_del(&entry.list);
        spin_unlock(&adap->mbox_lock);
+       t4_fatal_err(adap);
        return ret;
 }
 
@@ -7557,6 +7559,39 @@ int t4_prep_adapter(struct adapter *adapter)
        return 0;
 }
 
+/**
+ *     t4_shutdown_adapter - shut down adapter, host & wire
+ *     @adapter: the adapter
+ *
+ *     Perform an emergency shutdown of the adapter and stop it from
+ *     continuing any further communication on the ports or DMA to the
+ *     host.  This is typically used when the adapter and/or firmware
+ *     have crashed and we want to prevent any further accidental
+ *     communication with the rest of the world.  This will also force
+ *     the port Link Status to go down -- if register writes work --
+ *     which should help our peers figure out that we're down.
+ */
+int t4_shutdown_adapter(struct adapter *adapter)
+{
+       int port;
+
+       t4_intr_disable(adapter);
+       t4_write_reg(adapter, DBG_GPIO_EN_A, 0);
+       for_each_port(adapter, port) {
+               u32 a_port_cfg = PORT_REG(port,
+                                         is_t4(adapter->params.chip)
+                                         ? XGMAC_PORT_CFG_A
+                                         : MAC_PORT_CFG_A);
+
+               t4_write_reg(adapter, a_port_cfg,
+                            t4_read_reg(adapter, a_port_cfg)
+                            & ~SIGNAL_DET_V(1));
+       }
+       t4_set_reg_field(adapter, SGE_CONTROL_A, GLOBALENABLE_F, 0);
+
+       return 0;
+}
+
 /**
  *     t4_bar2_sge_qregs - return BAR2 SGE Queue register information
  *     @adapter: the adapter
index f71001d69c474f4686c361c8724acda160f10585..3348d33c36faca900e92bca25607ac79b0246908 100644 (file)
 #define PERR_INT_CAUSE_V(x) ((x) << PERR_INT_CAUSE_S)
 #define PERR_INT_CAUSE_F    PERR_INT_CAUSE_V(1U)
 
+#define DBG_GPIO_EN_A          0x6010
+#define XGMAC_PORT_CFG_A       0x1000
+#define MAC_PORT_CFG_A         0x800
+
+#define SIGNAL_DET_S    14
+#define SIGNAL_DET_V(x) ((x) << SIGNAL_DET_S)
+#define SIGNAL_DET_F    SIGNAL_DET_V(1U)
+
 #define MC_ECC_STATUS_A                0x751c
 #define MC_P_ECC_STATUS_A      0x4131c