Browse Source

Merge branch 'Aquantia-atlantic-critical-fixes-04-2018'

Igor Russkikh says:

====================
Aquantia atlantic critical fixes 04/2018

Two regressions on latest 4.16 driver reported by users

Some of old FW (1.5.44) had a link management logic which prevents
driver to make clean reset. Driver of 4.16 has a full hardware reset
implemented and that broke the link and traffic on such a cards.

Second is oops on shutdown callback in case interface is already
closed or was never opened.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
David S. Miller 7 years ago
parent
commit
98239c9096

+ 5 - 3
drivers/net/ethernet/aquantia/atlantic/aq_nic.c

@@ -951,9 +951,11 @@ void aq_nic_shutdown(struct aq_nic_s *self)
 
 
 	netif_device_detach(self->ndev);
 	netif_device_detach(self->ndev);
 
 
-	err = aq_nic_stop(self);
-	if (err < 0)
-		goto err_exit;
+	if (netif_running(self->ndev)) {
+		err = aq_nic_stop(self);
+		if (err < 0)
+			goto err_exit;
+	}
 	aq_nic_deinit(self);
 	aq_nic_deinit(self);
 
 
 err_exit:
 err_exit:

+ 16 - 0
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c

@@ -48,6 +48,8 @@
 #define FORCE_FLASHLESS 0
 #define FORCE_FLASHLESS 0
 
 
 static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
 static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual);
+static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self,
+				      enum hal_atl_utils_fw_state_e state);
 
 
 int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
 int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
 {
 {
@@ -247,6 +249,20 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self)
 
 
 	self->rbl_enabled = (boot_exit_code != 0);
 	self->rbl_enabled = (boot_exit_code != 0);
 
 
+	/* FW 1.x may bootup in an invalid POWER state (WOL feature).
+	 * We should work around this by forcing its state back to DEINIT
+	 */
+	if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X,
+				    aq_hw_read_reg(self,
+						   HW_ATL_MPI_FW_VERSION))) {
+		int err = 0;
+
+		hw_atl_utils_mpi_set_state(self, MPI_DEINIT);
+		AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_MPI_STATE_ADR) &
+			       HW_ATL_MPI_STATE_MSK) == MPI_DEINIT,
+			       10, 1000U);
+	}
+
 	if (self->rbl_enabled)
 	if (self->rbl_enabled)
 		return hw_atl_utils_soft_reset_rbl(self);
 		return hw_atl_utils_soft_reset_rbl(self);
 	else
 	else