Module Name:    src
Committed By:   msaitoh
Date:           Thu Dec  6 13:25:02 UTC 2018

Modified Files:
        src/sys/dev/pci/ixgbe: if_sriov.c ixgbe.c ixgbe.h ixgbe_82599.c
            ixgbe_api.c ixgbe_api.h ixgbe_features.h ixgbe_netbsd.c
            ixgbe_netbsd.h ixgbe_phy.c ixgbe_type.h ixgbe_x550.c ixgbe_x550.h

Log Message:
 Apply FreeBSD ix-3.3.6.tar.gz's change to NetBSD. Tested on C3000 and X550-T1,
but not tested on Xeon D:
- Add firmware recovery mode for X550, X550A(Xeon D) and X550EM (C3000):
  - FreeBSD always set IXGBE_FEATURE_RECOVERY_MODE without checking the
    NVM image version. We compare it against 2.0 to not to make new callout and
    not to call extra atomic operations.
  - In some FreeBSD's sysctl functions, atomic_load_acq_int() is called
    before a null pointer check. We call it after null pointer check.
  - Before calling atomic_load_acq_uint(), check adapter->feat_en flags
    to save atomic operation call.
  - We don't check recovery_mode in ixgbe_set_sysctl_value() because this
    function doesn't touch any hardware register.
  - NetBSD don't have FreeBSD's atomic_load_acq_int()-like function, so do it
    with membar_sync(). Thanks riastradh@ for the advice.
- FreeBSD's ix-3.3.6 changed ixgbe_enable_aim from TRUE to FALSE, but we will
  keep it as TRUE because we have already fixed some bugs.
- Remove IXGBE_DEV_ID_82599_LS(0x154f) support again. I don't know why. This
  was added in ix-3.2.18.tar.gz(NetBSD: ixgbe_82599.c rev. 1.20) and removed in
  ix-3.3.6.tar.gz.
- On X550EMU, use ixgbe_identify_sfp_module_X550em() instead of
  ixgbe_identify_module_generic(). ixgbe_identify_sfp_module_X550em() has
  extra check (e.g. exclude 1G copper).
- if_sriov.c's change doesn't affect to NetBSD because we don't support
  SR-IOV PF function.


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/pci/ixgbe/if_sriov.c \
    src/sys/dev/pci/ixgbe/ixgbe_x550.h
cvs rdiff -u -r1.168 -r1.169 src/sys/dev/pci/ixgbe/ixgbe.c
cvs rdiff -u -r1.52 -r1.53 src/sys/dev/pci/ixgbe/ixgbe.h
cvs rdiff -u -r1.20 -r1.21 src/sys/dev/pci/ixgbe/ixgbe_82599.c
cvs rdiff -u -r1.21 -r1.22 src/sys/dev/pci/ixgbe/ixgbe_api.c
cvs rdiff -u -r1.13 -r1.14 src/sys/dev/pci/ixgbe/ixgbe_api.h \
    src/sys/dev/pci/ixgbe/ixgbe_x550.c
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/pci/ixgbe/ixgbe_features.h
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/pci/ixgbe/ixgbe_netbsd.c \
    src/sys/dev/pci/ixgbe/ixgbe_netbsd.h
cvs rdiff -u -r1.17 -r1.18 src/sys/dev/pci/ixgbe/ixgbe_phy.c
cvs rdiff -u -r1.36 -r1.37 src/sys/dev/pci/ixgbe/ixgbe_type.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/ixgbe/if_sriov.c
diff -u src/sys/dev/pci/ixgbe/if_sriov.c:1.4 src/sys/dev/pci/ixgbe/if_sriov.c:1.5
--- src/sys/dev/pci/ixgbe/if_sriov.c:1.4	Mon Sep  3 16:29:33 2018
+++ src/sys/dev/pci/ixgbe/if_sriov.c	Thu Dec  6 13:25:02 2018
@@ -250,6 +250,64 @@ ixgbe_vf_set_default_vlan(struct adapter
 } /* ixgbe_vf_set_default_vlan */
 
 
+static void
+ixgbe_clear_vfmbmem(struct ixgbe_hw *hw, struct ixgbe_vf *vf)
+{
+	uint32_t vf_index = IXGBE_VF_INDEX(vf->pool);
+	uint16_t mbx_size = hw->mbx.size;
+	uint16_t i;
+
+	IXGBE_CORE_LOCK_ASSERT(adapter);
+
+	for (i = 0; i < mbx_size; ++i)
+		IXGBE_WRITE_REG_ARRAY(hw, IXGBE_PFMBMEM(vf_index), i, 0x0);
+} /* ixgbe_clear_vfmbmem */
+
+
+static void
+ixgbe_toggle_txdctl(struct ixgbe_hw *hw, struct ixgbe_vf *vf)
+{
+	uint32_t vf_index, offset, reg;
+	uint8_t  queue_count, i;
+
+	IXGBE_CORE_LOCK_ASSERT(adapter);
+
+	vf_index = IXGBE_VF_INDEX(vf->pool);
+
+	/* Determine number of queues by checking
+	 * number of virtual functions */
+	reg = IXGBE_READ_REG(hw, IXGBE_GCR_EXT);
+	switch (reg & IXGBE_GCR_EXT_VT_MODE_MASK) {
+	case IXGBE_GCR_EXT_VT_MODE_64:
+		queue_count = 2;
+		break;
+	case IXGBE_GCR_EXT_VT_MODE_32:
+		queue_count = 4;
+		break;
+	default:
+		return;
+	}
+
+	/* Toggle queues */
+	for (i = 0; i < queue_count; ++i) {
+		/* Calculate offset of current queue */
+		offset = queue_count * vf_index + i;
+
+		/* Enable queue */
+		reg = IXGBE_READ_REG(hw, IXGBE_PVFTXDCTL(offset));
+		reg |= IXGBE_TXDCTL_ENABLE;
+		IXGBE_WRITE_REG(hw, IXGBE_PVFTXDCTL(offset), reg);
+		IXGBE_WRITE_FLUSH(hw);
+
+		/* Disable queue */
+		reg = IXGBE_READ_REG(hw, IXGBE_PVFTXDCTL(offset));
+		reg &= ~IXGBE_TXDCTL_ENABLE;
+		IXGBE_WRITE_REG(hw, IXGBE_PVFTXDCTL(offset), reg);
+		IXGBE_WRITE_FLUSH(hw);
+	}
+} /* ixgbe_toggle_txdctl */
+
+
 static boolean_t
 ixgbe_vf_frame_size_compatible(struct adapter *adapter, struct ixgbe_vf *vf)
 {
@@ -305,6 +363,8 @@ ixgbe_process_vf_reset(struct adapter *a
 	// XXX clear multicast addresses
 
 	ixgbe_clear_rar(&adapter->hw, vf->rar_index);
+	ixgbe_clear_vfmbmem(&adapter->hw, vf);
+	ixgbe_toggle_txdctl(&adapter->hw, vf);
 
 	vf->api_ver = IXGBE_API_VER_UNKNOWN;
 } /* ixgbe_process_vf_reset */
Index: src/sys/dev/pci/ixgbe/ixgbe_x550.h
diff -u src/sys/dev/pci/ixgbe/ixgbe_x550.h:1.4 src/sys/dev/pci/ixgbe/ixgbe_x550.h:1.5
--- src/sys/dev/pci/ixgbe/ixgbe_x550.h:1.4	Fri Mar 30 06:44:30 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_x550.h	Thu Dec  6 13:25:02 2018
@@ -119,4 +119,5 @@ s32 ixgbe_reset_phy_t_X550em(struct ixgb
 s32 ixgbe_identify_sfp_module_X550em(struct ixgbe_hw *hw);
 s32 ixgbe_led_on_t_X550em(struct ixgbe_hw *hw, u32 led_idx);
 s32 ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, u32 led_idx);
+bool ixgbe_fw_recovery_mode_X550(struct ixgbe_hw *hw);
 #endif /* _IXGBE_X550_H_ */

Index: src/sys/dev/pci/ixgbe/ixgbe.c
diff -u src/sys/dev/pci/ixgbe/ixgbe.c:1.168 src/sys/dev/pci/ixgbe/ixgbe.c:1.169
--- src/sys/dev/pci/ixgbe/ixgbe.c:1.168	Mon Dec  3 04:39:44 2018
+++ src/sys/dev/pci/ixgbe/ixgbe.c	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe.c,v 1.168 2018/12/03 04:39:44 msaitoh Exp $ */
+/* $NetBSD: ixgbe.c,v 1.169 2018/12/06 13:25:02 msaitoh Exp $ */
 
 /******************************************************************************
 
@@ -81,7 +81,7 @@
  * Driver version
  ************************************************************************/
 static const char ixgbe_driver_version[] = "4.0.1-k";
-
+/* XXX NetBSD: + 3.3.6 */
 
 /************************************************************************
  * PCI Device ID Table
@@ -184,6 +184,7 @@ static void	ixgbe_free_pciintr_resources
 static void	ixgbe_free_pci_resources(struct adapter *);
 static void	ixgbe_local_timer(void *);
 static void	ixgbe_local_timer1(void *);
+static void     ixgbe_recovery_mode_timer(void *);
 static int	ixgbe_setup_interface(device_t, struct adapter *);
 static void	ixgbe_config_gpie(struct adapter *);
 static void	ixgbe_config_dmac(struct adapter *);
@@ -971,6 +972,7 @@ ixgbe_attach(device_t parent, device_t d
 
 	aprint_normal("%s:", device_xname(dev));
 	/* NVM Image Version */
+	high = low = 0;
 	switch (hw->mac.type) {
 	case ixgbe_mac_X540:
 	case ixgbe_mac_X550EM_a:
@@ -1000,6 +1002,8 @@ ixgbe_attach(device_t parent, device_t d
 	default:
 		break;
 	}
+	hw->eeprom.nvm_image_ver_high = high;
+	hw->eeprom.nvm_image_ver_low = low;
 
 	/* PHY firmware revision */
 	switch (hw->mac.type) {
@@ -1072,6 +1076,21 @@ ixgbe_attach(device_t parent, device_t d
 			}
 		}
 	}
+	/* Recovery mode */
+	switch (adapter->hw.mac.type) {
+	case ixgbe_mac_X550:
+	case ixgbe_mac_X550EM_x:
+	case ixgbe_mac_X550EM_a:
+		/* >= 2.00 */
+		if (hw->eeprom.nvm_image_ver_high >= 2) {
+			adapter->feat_cap |= IXGBE_FEATURE_RECOVERY_MODE;
+			adapter->feat_en |= IXGBE_FEATURE_RECOVERY_MODE;
+		}
+		break;
+	default:
+		break;
+	}
+
 	if ((adapter->feat_en & IXGBE_FEATURE_MSIX) == 0)
 		error = ixgbe_allocate_legacy(adapter, pa);
 	if (error) 
@@ -1194,6 +1213,19 @@ ixgbe_attach(device_t parent, device_t d
 	else
 		aprint_error_dev(dev, "couldn't establish power handler\n");
 
+	/* Init recovery mode timer and state variable */
+	if (adapter->feat_en & IXGBE_FEATURE_RECOVERY_MODE) {
+		adapter->recovery_mode = 0;
+
+		/* Set up the timer callout */
+		callout_init(&adapter->recovery_mode_timer,
+		    IXGBE_CALLOUT_FLAGS);
+
+		/* Start the task */
+		callout_reset(&adapter->recovery_mode_timer, hz,
+		    ixgbe_recovery_mode_timer, adapter);
+	}
+
 	INIT_DEBUGOUT("ixgbe_attach: end");
 	adapter->osdep.attached = true;
 
@@ -2156,12 +2188,17 @@ ixgbe_sysctl_tdh_handler(SYSCTLFN_ARGS)
 {
 	struct sysctlnode node = *rnode;
 	struct tx_ring *txr = (struct tx_ring *)node.sysctl_data;
+	struct adapter *adapter;
 	uint32_t val;
 
 	if (!txr)
 		return (0);
 
-	val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me));
+	adapter = txr->adapter;
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
+	val = IXGBE_READ_REG(&adapter->hw, IXGBE_TDH(txr->me));
 	node.sysctl_data = &val;
 	return sysctl_lookup(SYSCTLFN_CALL(&node));
 } /* ixgbe_sysctl_tdh_handler */
@@ -2176,12 +2213,17 @@ ixgbe_sysctl_tdt_handler(SYSCTLFN_ARGS)
 {
 	struct sysctlnode node = *rnode;
 	struct tx_ring *txr = (struct tx_ring *)node.sysctl_data;
+	struct adapter *adapter;
 	uint32_t val;
 
 	if (!txr)
 		return (0);
 
-	val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me));
+	adapter = txr->adapter;
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
+	val = IXGBE_READ_REG(&adapter->hw, IXGBE_TDT(txr->me));
 	node.sysctl_data = &val;
 	return sysctl_lookup(SYSCTLFN_CALL(&node));
 } /* ixgbe_sysctl_tdt_handler */
@@ -2197,11 +2239,16 @@ ixgbe_sysctl_next_to_check_handler(SYSCT
 {
 	struct sysctlnode node = *rnode;
 	struct rx_ring *rxr = (struct rx_ring *)node.sysctl_data;
+	struct adapter *adapter;
 	uint32_t val;
 
 	if (!rxr)
 		return (0);
 
+	adapter = rxr->adapter;
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	val = rxr->next_to_check;
 	node.sysctl_data = &val;
 	return sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -2217,12 +2264,17 @@ ixgbe_sysctl_rdh_handler(SYSCTLFN_ARGS)
 {
 	struct sysctlnode node = *rnode;
 	struct rx_ring *rxr = (struct rx_ring *)node.sysctl_data;
+	struct adapter *adapter;
 	uint32_t val;
 
 	if (!rxr)
 		return (0);
 
-	val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me));
+	adapter = rxr->adapter;
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
+	val = IXGBE_READ_REG(&adapter->hw, IXGBE_RDH(rxr->me));
 	node.sysctl_data = &val;
 	return sysctl_lookup(SYSCTLFN_CALL(&node));
 } /* ixgbe_sysctl_rdh_handler */
@@ -2237,12 +2289,17 @@ ixgbe_sysctl_rdt_handler(SYSCTLFN_ARGS)
 {
 	struct sysctlnode node = *rnode;
 	struct rx_ring *rxr = (struct rx_ring *)node.sysctl_data;
+	struct adapter *adapter;
 	uint32_t val;
 
 	if (!rxr)
 		return (0);
 
-	val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me));
+	adapter = rxr->adapter;
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
+	val = IXGBE_READ_REG(&adapter->hw, IXGBE_RDT(rxr->me));
 	node.sysctl_data = &val;
 	return sysctl_lookup(SYSCTLFN_CALL(&node));
 } /* ixgbe_sysctl_rdt_handler */
@@ -3127,13 +3184,18 @@ ixgbe_sysctl_interrupt_rate_handler(SYSC
 {
 	struct sysctlnode node = *rnode;
 	struct ix_queue *que = (struct ix_queue *)node.sysctl_data;
-	struct adapter  *adapter = que->adapter;
+	struct adapter  *adapter;
 	uint32_t reg, usec, rate;
 	int error;
 
 	if (que == NULL)
 		return 0;
-	reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix));
+
+	adapter = que->adapter;
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
+	reg = IXGBE_READ_REG(&adapter->hw, IXGBE_EITR(que->msix));
 	usec = ((reg & 0x0FF8) >> 3);
 	if (usec > 0)
 		rate = 500000 / usec;
@@ -3504,6 +3566,7 @@ ixgbe_detach(device_t dev, int flags)
 	IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext);
 
 	callout_halt(&adapter->timer, NULL);
+	callout_halt(&adapter->recovery_mode_timer, NULL);
 
 	if (adapter->feat_en & IXGBE_FEATURE_NETMAP)
 		netmap_detach(adapter->ifp);
@@ -4448,6 +4511,32 @@ watchdog:
 } /* ixgbe_local_timer */
 
 /************************************************************************
+ * ixgbe_recovery_mode_timer - Recovery mode timer routine
+ ************************************************************************/
+static void
+ixgbe_recovery_mode_timer(void *arg)
+{
+	struct adapter *adapter = arg;
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	IXGBE_CORE_LOCK(adapter);
+	if (ixgbe_fw_recovery_mode(hw)) {
+		if (atomic_cas_uint(&adapter->recovery_mode, 0, 1)) {
+			/* Firmware error detected, entering recovery mode */
+			device_printf(adapter->dev, "Firmware recovery mode detected. Limiting functionality. Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n");
+
+			if (hw->adapter_stopped == FALSE)
+				ixgbe_stop(adapter);
+		}
+	} else
+		atomic_cas_uint(&adapter->recovery_mode, 1, 0);
+
+	callout_reset(&adapter->recovery_mode_timer, hz,
+	    ixgbe_recovery_mode_timer, adapter);
+	IXGBE_CORE_UNLOCK(adapter);
+} /* ixgbe_recovery_mode_timer */
+
+/************************************************************************
  * ixgbe_sfp_probe
  *
  *   Determine if a port had optics inserted.
@@ -4544,6 +4633,7 @@ ixgbe_handle_msf(void *context)
 	u32             autoneg;
 	bool            negotiate;
 
+	IXGBE_CORE_LOCK(adapter);
 	++adapter->msf_sicount.ev_count;
 	/* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */
 	adapter->phy_layer = ixgbe_get_supported_physical_layer(hw);
@@ -4560,6 +4650,7 @@ ixgbe_handle_msf(void *context)
 	ifmedia_removeall(&adapter->media);
 	ixgbe_add_media_types(adapter);
 	ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
+	IXGBE_CORE_UNLOCK(adapter);
 } /* ixgbe_handle_msf */
 
 /************************************************************************
@@ -5036,6 +5127,11 @@ ixgbe_set_sysctl_value(struct adapter *a
 	struct sysctllog **log;
 	const struct sysctlnode *rnode, *cnode;
 
+	/*
+	 * It's not required to check recovery mode because this function never
+	 * touches hardware.
+	 */
+
 	log = &adapter->sysctllog;
 	if ((rnode = ixgbe_sysctl_instance(adapter)) == NULL) {
 		aprint_error_dev(dev, "could not create sysctl root\n");
@@ -5061,6 +5157,9 @@ ixgbe_sysctl_flowcntl(SYSCTLFN_ARGS)
 	struct adapter *adapter = (struct adapter *)node.sysctl_data;
 	int error, fc;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	fc = adapter->hw.fc.current_mode;
 	node.sysctl_data = &fc;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -5179,6 +5278,9 @@ ixgbe_sysctl_advertise(SYSCTLFN_ARGS)
 	struct adapter *adapter = (struct adapter *)node.sysctl_data;
 	int            error = 0, advertise;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	advertise = adapter->advertise;
 	node.sysctl_data = &advertise;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -5361,6 +5463,9 @@ ixgbe_sysctl_dmac(SYSCTLFN_ARGS)
 	int            error;
 	int            newval;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	newval = adapter->dmac;
 	node.sysctl_data = &newval;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -5418,6 +5523,9 @@ ixgbe_sysctl_power_state(SYSCTLFN_ARGS)
 	device_t       dev =  adapter->dev;
 	int            curr_ps, new_ps, error = 0;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	curr_ps = new_ps = pci_get_powerstate(dev);
 
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -5462,6 +5570,10 @@ ixgbe_sysctl_wol_enable(SYSCTLFN_ARGS)
 	bool            new_wol_enabled;
 	int             error = 0;
 
+	/*
+	 * It's not required to check recovery mode because this function never
+	 * touches hardware.
+	 */
 	new_wol_enabled = hw->wol_enabled;
 	node.sysctl_data = &new_wol_enabled;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -5503,6 +5615,10 @@ ixgbe_sysctl_wufc(SYSCTLFN_ARGS)
 	int error = 0;
 	u32 new_wufc;
 
+	/*
+	 * It's not required to check recovery mode because this function never
+	 * touches hardware.
+	 */
 	new_wufc = adapter->wufc;
 	node.sysctl_data = &new_wufc;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -5537,6 +5653,9 @@ ixgbe_sysctl_print_rss_config(SYSCTLFN_A
 	int             error = 0, reta_size;
 	u32             reg;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	buf = sbuf_new_for_sysctl(NULL, NULL, 128, req);
 	if (!buf) {
 		device_printf(dev, "Could not allocate sbuf for output.\n");
@@ -5595,6 +5714,9 @@ ixgbe_sysctl_phy_temp(SYSCTLFN_ARGS)
 	u16 reg;
 	int		error;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
 		device_printf(adapter->dev,
 		    "Device has no supported external thermal sensor.\n");
@@ -5635,6 +5757,9 @@ ixgbe_sysctl_phy_overtemp_occurred(SYSCT
 	int val, error;
 	u16 reg;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) {
 		device_printf(adapter->dev,
 		    "Device has no supported external thermal sensor.\n");
@@ -5679,6 +5804,9 @@ ixgbe_sysctl_eee_state(SYSCTLFN_ARGS)
 	int            curr_eee, new_eee, error = 0;
 	s32            retval;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	curr_eee = new_eee = !!(adapter->feat_en & IXGBE_FEATURE_EEE);
 	node.sysctl_data = &new_eee;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
@@ -5814,6 +5942,9 @@ ixgbe_sysctl_debug(SYSCTLFN_ARGS)
 	struct adapter *adapter = (struct adapter *)node.sysctl_data;
 	int            error, result = 0;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	node.sysctl_data = &result;
 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
 
@@ -5853,17 +5984,29 @@ ixgbe_init_device_features(struct adapte
 			adapter->feat_cap |= IXGBE_FEATURE_BYPASS;
 		break;
 	case ixgbe_mac_X550:
+		/*
+		 * IXGBE_FEATURE_RECOVERY_MODE will be set after reading
+		 * NVM Image version.
+		 */
 		adapter->feat_cap |= IXGBE_FEATURE_TEMP_SENSOR;
 		adapter->feat_cap |= IXGBE_FEATURE_SRIOV;
 		adapter->feat_cap |= IXGBE_FEATURE_FDIR;
 		break;
 	case ixgbe_mac_X550EM_x:
+		/*
+		 * IXGBE_FEATURE_RECOVERY_MODE will be set after reading
+		 * NVM Image version.
+		 */
 		adapter->feat_cap |= IXGBE_FEATURE_SRIOV;
 		adapter->feat_cap |= IXGBE_FEATURE_FDIR;
 		if (adapter->hw.device_id == IXGBE_DEV_ID_X550EM_X_KR)
 			adapter->feat_cap |= IXGBE_FEATURE_EEE;
 		break;
 	case ixgbe_mac_X550EM_a:
+		/*
+		 * IXGBE_FEATURE_RECOVERY_MODE will be set after reading
+		 * NVM Image version.
+		 */
 		adapter->feat_cap |= IXGBE_FEATURE_SRIOV;
 		adapter->feat_cap |= IXGBE_FEATURE_FDIR;
 		adapter->feat_cap &= ~IXGBE_FEATURE_LEGACY_IRQ;
@@ -5899,6 +6042,11 @@ ixgbe_init_device_features(struct adapte
 	/* Thermal Sensor */
 	if (adapter->feat_cap & IXGBE_FEATURE_TEMP_SENSOR)
 		adapter->feat_en |= IXGBE_FEATURE_TEMP_SENSOR;
+	/*
+	 * Recovery mode:
+	 * NetBSD: IXGBE_FEATURE_RECOVERY_MODE will be controlled after reading
+	 * NVM Image version.
+	 */
 
 	/* Enabled via global sysctl... */
 	/* Flow Director */
@@ -6019,6 +6167,9 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c
 	const int l4csum = IFCAP_CSUM_TCPv4_Rx|IFCAP_CSUM_UDPv4_Rx|
 	     IFCAP_CSUM_TCPv6_Rx|IFCAP_CSUM_UDPv6_Rx;
 
+	if (ixgbe_fw_recovery_mode_swflag(adapter))
+		return (EPERM);
+
 	switch (command) {
 	case SIOCSIFFLAGS:
 		IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)");

Index: src/sys/dev/pci/ixgbe/ixgbe.h
diff -u src/sys/dev/pci/ixgbe/ixgbe.h:1.52 src/sys/dev/pci/ixgbe/ixgbe.h:1.53
--- src/sys/dev/pci/ixgbe/ixgbe.h:1.52	Mon Dec  3 04:39:44 2018
+++ src/sys/dev/pci/ixgbe/ixgbe.h	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe.h,v 1.52 2018/12/03 04:39:44 msaitoh Exp $ */
+/* $NetBSD: ixgbe.h,v 1.53 2018/12/06 13:25:02 msaitoh Exp $ */
 
 /******************************************************************************
   SPDX-License-Identifier: BSD-3-Clause
@@ -574,6 +574,10 @@ struct adapter {
 	void 			(*init_locked)(struct adapter *);
 	void 			(*stop_locked)(void *);
 
+	/* Firmware error check */
+	u_int                   recovery_mode;
+	struct callout          recovery_mode_timer;
+
 	/* Misc stats maintained by the driver */
 	struct evcnt	   	efbig_tx_dma_setup;
 	struct evcnt   		mbuf_defrag_failed;
@@ -745,6 +749,18 @@ ixv_check_ether_addr(u8 *addr)
 	return (status);
 }
 
+/*
+ * This checks the adapter->recovery_mode software flag which is
+ * set by ixgbe_fw_recovery_mode().
+ *
+ */
+static inline bool
+ixgbe_fw_recovery_mode_swflag(struct adapter *adapter)
+{
+	return (adapter->feat_en & IXGBE_FEATURE_RECOVERY_MODE) &&
+	    atomic_load_acq_uint(&adapter->recovery_mode);
+}
+
 /* Shared Prototypes */
 void ixgbe_legacy_start(struct ifnet *);
 int  ixgbe_legacy_start_locked(struct ifnet *, struct tx_ring *);

Index: src/sys/dev/pci/ixgbe/ixgbe_82599.c
diff -u src/sys/dev/pci/ixgbe/ixgbe_82599.c:1.20 src/sys/dev/pci/ixgbe/ixgbe_82599.c:1.21
--- src/sys/dev/pci/ixgbe/ixgbe_82599.c:1.20	Mon Jun 11 10:34:18 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_82599.c	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe_82599.c,v 1.20 2018/06/11 10:34:18 msaitoh Exp $ */
+/* $NetBSD: ixgbe_82599.c,v 1.21 2018/12/06 13:25:02 msaitoh Exp $ */
 
 /******************************************************************************
   SPDX-License-Identifier: BSD-3-Clause
@@ -566,9 +566,6 @@ enum ixgbe_media_type ixgbe_get_media_ty
 	case IXGBE_DEV_ID_82599_T3_LOM:
 		media_type = ixgbe_media_type_copper;
 		break;
-	case IXGBE_DEV_ID_82599_LS:
-		media_type = ixgbe_media_type_fiber_lco;
-		break;
 	case IXGBE_DEV_ID_82599_QSFP_SF_QP:
 		media_type = ixgbe_media_type_fiber_qsfp;
 		break;

Index: src/sys/dev/pci/ixgbe/ixgbe_api.c
diff -u src/sys/dev/pci/ixgbe/ixgbe_api.c:1.21 src/sys/dev/pci/ixgbe/ixgbe_api.c:1.22
--- src/sys/dev/pci/ixgbe/ixgbe_api.c:1.21	Mon Jun 11 10:34:18 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_api.c	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe_api.c,v 1.21 2018/06/11 10:34:18 msaitoh Exp $ */
+/* $NetBSD: ixgbe_api.c,v 1.22 2018/12/06 13:25:02 msaitoh Exp $ */
 
 /******************************************************************************
   SPDX-License-Identifier: BSD-3-Clause
@@ -173,7 +173,6 @@ s32 ixgbe_set_mac_type(struct ixgbe_hw *
 	case IXGBE_DEV_ID_82599_SFP_SF_QP:
 	case IXGBE_DEV_ID_82599_QSFP_SF_QP:
 	case IXGBE_DEV_ID_82599EN_SFP:
-	case IXGBE_DEV_ID_82599_LS:
 	case IXGBE_DEV_ID_82599_CX4:
 	case IXGBE_DEV_ID_82599_BYPASS:
 	case IXGBE_DEV_ID_82599_T3_LOM:
@@ -1310,6 +1309,18 @@ void ixgbe_restore_mdd_vf(struct ixgbe_h
 }
 
 /**
+ *  ixgbe_fw_recovery_mode - Check if in FW NVM recovery mode
+ *  @hw: pointer to hardware structure
+ *
+ **/
+bool ixgbe_fw_recovery_mode(struct ixgbe_hw *hw)
+{
+	if (hw->mac.ops.fw_recovery_mode)
+		return hw->mac.ops.fw_recovery_mode(hw);
+	return FALSE;
+}
+
+/**
  *  ixgbe_enter_lplu - Transition to low power states
  *  @hw: pointer to hardware structure
  *

Index: src/sys/dev/pci/ixgbe/ixgbe_api.h
diff -u src/sys/dev/pci/ixgbe/ixgbe_api.h:1.13 src/sys/dev/pci/ixgbe/ixgbe_api.h:1.14
--- src/sys/dev/pci/ixgbe/ixgbe_api.h:1.13	Wed Apr  4 08:13:07 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_api.h	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe_api.h,v 1.13 2018/04/04 08:13:07 msaitoh Exp $ */
+/* $NetBSD: ixgbe_api.h,v 1.14 2018/12/06 13:25:02 msaitoh Exp $ */
 
 /******************************************************************************
   SPDX-License-Identifier: BSD-3-Clause
@@ -219,6 +219,7 @@ void ixgbe_disable_mdd(struct ixgbe_hw *
 void ixgbe_enable_mdd(struct ixgbe_hw *hw);
 void ixgbe_mdd_event(struct ixgbe_hw *hw, u32 *vf_bitmap);
 void ixgbe_restore_mdd_vf(struct ixgbe_hw *hw, u32 vf);
+bool ixgbe_fw_recovery_mode(struct ixgbe_hw *hw);
 s32 ixgbe_enter_lplu(struct ixgbe_hw *hw);
 s32 ixgbe_handle_lasi(struct ixgbe_hw *hw);
 void ixgbe_set_rate_select_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed);
Index: src/sys/dev/pci/ixgbe/ixgbe_x550.c
diff -u src/sys/dev/pci/ixgbe/ixgbe_x550.c:1.13 src/sys/dev/pci/ixgbe/ixgbe_x550.c:1.14
--- src/sys/dev/pci/ixgbe/ixgbe_x550.c:1.13	Fri Jul  6 02:36:35 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_x550.c	Thu Dec  6 13:25:02 2018
@@ -87,6 +87,7 @@ s32 ixgbe_init_ops_X550(struct ixgbe_hw 
 	mac->ops.enable_mdd = ixgbe_enable_mdd_X550;
 	mac->ops.mdd_event = ixgbe_mdd_event_X550;
 	mac->ops.restore_mdd_vf = ixgbe_restore_mdd_vf_X550;
+	mac->ops.fw_recovery_mode = ixgbe_fw_recovery_mode_X550;
 	mac->ops.disable_rx = ixgbe_disable_rx_x550;
 	/* Manageability interface */
 	mac->ops.set_fw_drv_ver = ixgbe_set_fw_drv_ver_x550;
@@ -446,7 +447,7 @@ static s32 ixgbe_identify_phy_x550em(str
 
 	switch (hw->device_id) {
 	case IXGBE_DEV_ID_X550EM_A_SFP:
-		return ixgbe_identify_module_generic(hw);
+		return ixgbe_identify_sfp_module_X550em(hw);
 	case IXGBE_DEV_ID_X550EM_X_SFP:
 		/* set up for CS4227 usage */
 		ixgbe_setup_mux_ctl(hw);
@@ -454,7 +455,7 @@ static s32 ixgbe_identify_phy_x550em(str
 		/* Fallthrough */
 
 	case IXGBE_DEV_ID_X550EM_A_SFP_N:
-		return ixgbe_identify_module_generic(hw);
+		return ixgbe_identify_sfp_module_X550em(hw);
 		break;
 	case IXGBE_DEV_ID_X550EM_X_KX4:
 		hw->phy.type = ixgbe_phy_x550em_kx4;
@@ -4817,3 +4818,19 @@ s32 ixgbe_set_fw_drv_ver_x550(struct ixg
 
 	return ret_val;
 }
+
+/**
+ * ixgbe_fw_recovery_mode_X550 - Check FW NVM recovery mode
+ * @hw: pointer t hardware structure
+ *
+ * Returns TRUE if in FW NVM recovery mode.
+ **/
+bool ixgbe_fw_recovery_mode_X550(struct ixgbe_hw *hw)
+{
+	u32 fwsm;
+
+	fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM_BY_MAC(hw));
+
+	return !!(fwsm & IXGBE_FWSM_FW_NVM_RECOVERY_MODE);
+}
+

Index: src/sys/dev/pci/ixgbe/ixgbe_features.h
diff -u src/sys/dev/pci/ixgbe/ixgbe_features.h:1.1 src/sys/dev/pci/ixgbe/ixgbe_features.h:1.2
--- src/sys/dev/pci/ixgbe/ixgbe_features.h:1.1	Wed Aug 30 08:49:18 2017
+++ src/sys/dev/pci/ixgbe/ixgbe_features.h	Thu Dec  6 13:25:02 2018
@@ -57,12 +57,13 @@
 #define IXGBE_FEATURE_EEE                       (u32)(1 << 11)
 #define IXGBE_FEATURE_LEGACY_IRQ                (u32)(1 << 12)
 #define IXGBE_FEATURE_NEEDS_CTXD                (u32)(1 << 13)
+#define IXGBE_FEATURE_RECOVERY_MODE             (u32)(1 << 15)
 
 #define IXGBE_FEATURE_FLAGS "\20" \
 	"\1" "VF"	"\2" "SRIOV"	"\3" "RSS"	"\4" "NETMAP"	\
 	"\5" "FAN_FAIL"	"\6" "TEMP_SENSOR" "\7" "BYPASS" "\10" "LEGACY_TX" \
 	"\11" "FDIR"	"\12" "MSI"	"\13" "MSIX"	"\14" "EEE"	\
-	"\15" "LEGACY_IRQ" "\16" "NEEDS_CTXD"
+	"\15" "LEGACY_IRQ" "\16" "NEEDS_CTXD"		"\20" "RECOVERY_MODE"
 
 /* Check for OS support.  Undefine features if not included in the OS */
 #ifndef PCI_IOV

Index: src/sys/dev/pci/ixgbe/ixgbe_netbsd.c
diff -u src/sys/dev/pci/ixgbe/ixgbe_netbsd.c:1.8 src/sys/dev/pci/ixgbe/ixgbe_netbsd.c:1.9
--- src/sys/dev/pci/ixgbe/ixgbe_netbsd.c:1.8	Tue Jul 31 09:19:34 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_netbsd.c	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe_netbsd.c,v 1.8 2018/07/31 09:19:34 msaitoh Exp $ */
+/* $NetBSD: ixgbe_netbsd.c,v 1.9 2018/12/06 13:25:02 msaitoh Exp $ */
 /*
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -273,3 +273,19 @@ ixgbe_pci_enable_busmaster(pci_chipset_t
 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, pci_cmd_word);
 	}
 }
+
+u_int
+atomic_load_acq_uint(volatile u_int *p)
+{
+	u_int rv;
+
+	rv = *p;
+	/*
+	 * XXX
+	 * membar_sync() is far more than we need on most CPUs;
+	 * we just don't have an MI load-acqure operation.
+	 */
+	membar_sync();
+
+	return rv;
+}
Index: src/sys/dev/pci/ixgbe/ixgbe_netbsd.h
diff -u src/sys/dev/pci/ixgbe/ixgbe_netbsd.h:1.8 src/sys/dev/pci/ixgbe/ixgbe_netbsd.h:1.9
--- src/sys/dev/pci/ixgbe/ixgbe_netbsd.h:1.8	Wed Apr 25 08:46:19 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_netbsd.h	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/*$NetBSD: ixgbe_netbsd.h,v 1.8 2018/04/25 08:46:19 msaitoh Exp $*/
+/*$NetBSD: ixgbe_netbsd.h,v 1.9 2018/12/06 13:25:02 msaitoh Exp $*/
 /*
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -96,4 +96,6 @@ void ixgbe_dmamap_unload(ixgbe_dma_tag_t
 struct mbuf *ixgbe_getjcl(ixgbe_extmem_head_t *, int, int, int, size_t);
 void ixgbe_pci_enable_busmaster(pci_chipset_tag_t, pcitag_t);
 
+u_int atomic_load_acq_uint(volatile u_int *);
+
 #endif /* _IXGBE_NETBSD_H */

Index: src/sys/dev/pci/ixgbe/ixgbe_phy.c
diff -u src/sys/dev/pci/ixgbe/ixgbe_phy.c:1.17 src/sys/dev/pci/ixgbe/ixgbe_phy.c:1.18
--- src/sys/dev/pci/ixgbe/ixgbe_phy.c:1.17	Wed Apr  4 08:59:22 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_phy.c	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe_phy.c,v 1.17 2018/04/04 08:59:22 msaitoh Exp $ */
+/* $NetBSD: ixgbe_phy.c,v 1.18 2018/12/06 13:25:02 msaitoh Exp $ */
 
 /******************************************************************************
   SPDX-License-Identifier: BSD-3-Clause
@@ -2612,7 +2612,6 @@ static bool ixgbe_get_i2c_data(struct ix
 {
 	u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw);
 	bool data;
-	UNREFERENCED_1PARAMETER(hw);
 
 	DEBUGFUNC("ixgbe_get_i2c_data");
 

Index: src/sys/dev/pci/ixgbe/ixgbe_type.h
diff -u src/sys/dev/pci/ixgbe/ixgbe_type.h:1.36 src/sys/dev/pci/ixgbe/ixgbe_type.h:1.37
--- src/sys/dev/pci/ixgbe/ixgbe_type.h:1.36	Fri Jul  6 02:36:35 2018
+++ src/sys/dev/pci/ixgbe/ixgbe_type.h	Thu Dec  6 13:25:02 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe_type.h,v 1.36 2018/07/06 02:36:35 msaitoh Exp $ */
+/* $NetBSD: ixgbe_type.h,v 1.37 2018/12/06 13:25:02 msaitoh Exp $ */
 
 /******************************************************************************
   SPDX-License-Identifier: BSD-3-Clause
@@ -131,7 +131,6 @@
 #define IXGBE_SUBDEV_ID_82599EN_SFP_OCP1	0x0001
 #define IXGBE_DEV_ID_82599_XAUI_LOM		PCI_PRODUCT_INTEL_82599_XAUI_LOM
 #define IXGBE_DEV_ID_82599_T3_LOM		0x151C
-#define IXGBE_DEV_ID_82599_LS			0x154F
 #define IXGBE_DEV_ID_82599_VF			0x10ED
 #define IXGBE_DEV_ID_82599_VF_HV		0x152E
 #define IXGBE_DEV_ID_82599_BYPASS		0x155D
@@ -1096,6 +1095,9 @@ struct ixgbe_dmac_config {
 #define IXGBE_FWSM_MODE_MASK	0xE
 #define IXGBE_FWSM_TS_ENABLED	0x1
 #define IXGBE_FWSM_FW_MODE_PT	0x4
+#define IXGBE_FWSM_FW_NVM_RECOVERY_MODE (1 << 5)
+#define IXGBE_FWSM_EXT_ERR_IND_MASK 0x01F80000
+#define IXGBE_FWSM_FW_VAL_BIT	(1 << 15)
 
 /* ARC Subsystem registers */
 #define IXGBE_HICR		0x15F00
@@ -3759,7 +3761,6 @@ enum ixgbe_media_type {
 	ixgbe_media_type_fiber,
 	ixgbe_media_type_fiber_fixed,
 	ixgbe_media_type_fiber_qsfp,
-	ixgbe_media_type_fiber_lco,
 	ixgbe_media_type_copper,
 	ixgbe_media_type_backplane,
 	ixgbe_media_type_cx4,
@@ -4063,6 +4064,7 @@ struct ixgbe_mac_operations {
 	void (*enable_mdd)(struct ixgbe_hw *hw);
 	void (*mdd_event)(struct ixgbe_hw *hw, u32 *vf_bitmap);
 	void (*restore_mdd_vf)(struct ixgbe_hw *hw, u32 vf);
+	bool (*fw_recovery_mode)(struct ixgbe_hw *hw);
 };
 
 struct ixgbe_phy_operations {
@@ -4117,6 +4119,8 @@ struct ixgbe_eeprom_info {
 	u16				address_bits;
 	u16 word_page_size;
 	u16 ctrl_word_3;
+	u8  nvm_image_ver_high;
+	u8  nvm_image_ver_low;
 };
 
 #define IXGBE_FLAGS_DOUBLE_RESET_REQUIRED	0x01

Reply via email to