mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	After many years of having a ~30 line copyright and license header to our source files, we are finally able to reduce that to one line with the advent of the SPDX identifier. Also caught a few files missing the SPDX license identifier, so fixed them up. Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Acked-by: Shannon Nelson <shannon.nelson@oracle.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
		
			
				
	
	
		
			524 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			524 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/* Copyright(c) 2013 - 2018 Intel Corporation. */
 | 
						|
 | 
						|
#include "fm10k_common.h"
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_get_bus_info_generic - Generic set PCI bus info
 | 
						|
 *  @hw: pointer to hardware structure
 | 
						|
 *
 | 
						|
 *  Gets the PCI bus info (speed, width, type) then calls helper function to
 | 
						|
 *  store this data within the fm10k_hw structure.
 | 
						|
 **/
 | 
						|
s32 fm10k_get_bus_info_generic(struct fm10k_hw *hw)
 | 
						|
{
 | 
						|
	u16 link_cap, link_status, device_cap, device_control;
 | 
						|
 | 
						|
	/* Get the maximum link width and speed from PCIe config space */
 | 
						|
	link_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_CAP);
 | 
						|
 | 
						|
	switch (link_cap & FM10K_PCIE_LINK_WIDTH) {
 | 
						|
	case FM10K_PCIE_LINK_WIDTH_1:
 | 
						|
		hw->bus_caps.width = fm10k_bus_width_pcie_x1;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_WIDTH_2:
 | 
						|
		hw->bus_caps.width = fm10k_bus_width_pcie_x2;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_WIDTH_4:
 | 
						|
		hw->bus_caps.width = fm10k_bus_width_pcie_x4;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_WIDTH_8:
 | 
						|
		hw->bus_caps.width = fm10k_bus_width_pcie_x8;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		hw->bus_caps.width = fm10k_bus_width_unknown;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	switch (link_cap & FM10K_PCIE_LINK_SPEED) {
 | 
						|
	case FM10K_PCIE_LINK_SPEED_2500:
 | 
						|
		hw->bus_caps.speed = fm10k_bus_speed_2500;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_SPEED_5000:
 | 
						|
		hw->bus_caps.speed = fm10k_bus_speed_5000;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_SPEED_8000:
 | 
						|
		hw->bus_caps.speed = fm10k_bus_speed_8000;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		hw->bus_caps.speed = fm10k_bus_speed_unknown;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Get the PCIe maximum payload size for the PCIe function */
 | 
						|
	device_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CAP);
 | 
						|
 | 
						|
	switch (device_cap & FM10K_PCIE_DEV_CAP_PAYLOAD) {
 | 
						|
	case FM10K_PCIE_DEV_CAP_PAYLOAD_128:
 | 
						|
		hw->bus_caps.payload = fm10k_bus_payload_128;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_DEV_CAP_PAYLOAD_256:
 | 
						|
		hw->bus_caps.payload = fm10k_bus_payload_256;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_DEV_CAP_PAYLOAD_512:
 | 
						|
		hw->bus_caps.payload = fm10k_bus_payload_512;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		hw->bus_caps.payload = fm10k_bus_payload_unknown;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Get the negotiated link width and speed from PCIe config space */
 | 
						|
	link_status = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_STATUS);
 | 
						|
 | 
						|
	switch (link_status & FM10K_PCIE_LINK_WIDTH) {
 | 
						|
	case FM10K_PCIE_LINK_WIDTH_1:
 | 
						|
		hw->bus.width = fm10k_bus_width_pcie_x1;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_WIDTH_2:
 | 
						|
		hw->bus.width = fm10k_bus_width_pcie_x2;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_WIDTH_4:
 | 
						|
		hw->bus.width = fm10k_bus_width_pcie_x4;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_WIDTH_8:
 | 
						|
		hw->bus.width = fm10k_bus_width_pcie_x8;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		hw->bus.width = fm10k_bus_width_unknown;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	switch (link_status & FM10K_PCIE_LINK_SPEED) {
 | 
						|
	case FM10K_PCIE_LINK_SPEED_2500:
 | 
						|
		hw->bus.speed = fm10k_bus_speed_2500;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_SPEED_5000:
 | 
						|
		hw->bus.speed = fm10k_bus_speed_5000;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_LINK_SPEED_8000:
 | 
						|
		hw->bus.speed = fm10k_bus_speed_8000;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		hw->bus.speed = fm10k_bus_speed_unknown;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Get the negotiated PCIe maximum payload size for the PCIe function */
 | 
						|
	device_control = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CTRL);
 | 
						|
 | 
						|
	switch (device_control & FM10K_PCIE_DEV_CTRL_PAYLOAD) {
 | 
						|
	case FM10K_PCIE_DEV_CTRL_PAYLOAD_128:
 | 
						|
		hw->bus.payload = fm10k_bus_payload_128;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_DEV_CTRL_PAYLOAD_256:
 | 
						|
		hw->bus.payload = fm10k_bus_payload_256;
 | 
						|
		break;
 | 
						|
	case FM10K_PCIE_DEV_CTRL_PAYLOAD_512:
 | 
						|
		hw->bus.payload = fm10k_bus_payload_512;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		hw->bus.payload = fm10k_bus_payload_unknown;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw)
 | 
						|
{
 | 
						|
	u16 msix_count;
 | 
						|
 | 
						|
	/* read in value from MSI-X capability register */
 | 
						|
	msix_count = fm10k_read_pci_cfg_word(hw, FM10K_PCI_MSIX_MSG_CTRL);
 | 
						|
	msix_count &= FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK;
 | 
						|
 | 
						|
	/* MSI-X count is zero-based in HW */
 | 
						|
	msix_count++;
 | 
						|
 | 
						|
	if (msix_count > FM10K_MAX_MSIX_VECTORS)
 | 
						|
		msix_count = FM10K_MAX_MSIX_VECTORS;
 | 
						|
 | 
						|
	return msix_count;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_get_invariants_generic - Inits constant values
 | 
						|
 *  @hw: pointer to the hardware structure
 | 
						|
 *
 | 
						|
 *  Initialize the common invariants for the device.
 | 
						|
 **/
 | 
						|
s32 fm10k_get_invariants_generic(struct fm10k_hw *hw)
 | 
						|
{
 | 
						|
	struct fm10k_mac_info *mac = &hw->mac;
 | 
						|
 | 
						|
	/* initialize GLORT state to avoid any false hits */
 | 
						|
	mac->dglort_map = FM10K_DGLORTMAP_NONE;
 | 
						|
 | 
						|
	/* record maximum number of MSI-X vectors */
 | 
						|
	mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_start_hw_generic - Prepare hardware for Tx/Rx
 | 
						|
 *  @hw: pointer to hardware structure
 | 
						|
 *
 | 
						|
 *  This function sets the Tx ready flag to indicate that the Tx path has
 | 
						|
 *  been initialized.
 | 
						|
 **/
 | 
						|
s32 fm10k_start_hw_generic(struct fm10k_hw *hw)
 | 
						|
{
 | 
						|
	/* set flag indicating we are beginning Tx */
 | 
						|
	hw->mac.tx_ready = true;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_disable_queues_generic - Stop Tx/Rx queues
 | 
						|
 *  @hw: pointer to hardware structure
 | 
						|
 *  @q_cnt: number of queues to be disabled
 | 
						|
 *
 | 
						|
 **/
 | 
						|
s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt)
 | 
						|
{
 | 
						|
	u32 reg;
 | 
						|
	u16 i, time;
 | 
						|
 | 
						|
	/* clear tx_ready to prevent any false hits for reset */
 | 
						|
	hw->mac.tx_ready = false;
 | 
						|
 | 
						|
	if (FM10K_REMOVED(hw->hw_addr))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	/* clear the enable bit for all rings */
 | 
						|
	for (i = 0; i < q_cnt; i++) {
 | 
						|
		reg = fm10k_read_reg(hw, FM10K_TXDCTL(i));
 | 
						|
		fm10k_write_reg(hw, FM10K_TXDCTL(i),
 | 
						|
				reg & ~FM10K_TXDCTL_ENABLE);
 | 
						|
		reg = fm10k_read_reg(hw, FM10K_RXQCTL(i));
 | 
						|
		fm10k_write_reg(hw, FM10K_RXQCTL(i),
 | 
						|
				reg & ~FM10K_RXQCTL_ENABLE);
 | 
						|
	}
 | 
						|
 | 
						|
	fm10k_write_flush(hw);
 | 
						|
	udelay(1);
 | 
						|
 | 
						|
	/* loop through all queues to verify that they are all disabled */
 | 
						|
	for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) {
 | 
						|
		/* if we are at end of rings all rings are disabled */
 | 
						|
		if (i == q_cnt)
 | 
						|
			return 0;
 | 
						|
 | 
						|
		/* if queue enables cleared, then move to next ring pair */
 | 
						|
		reg = fm10k_read_reg(hw, FM10K_TXDCTL(i));
 | 
						|
		if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) {
 | 
						|
			reg = fm10k_read_reg(hw, FM10K_RXQCTL(i));
 | 
						|
			if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) {
 | 
						|
				i++;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* decrement time and wait 1 usec */
 | 
						|
		time--;
 | 
						|
		if (time)
 | 
						|
			udelay(1);
 | 
						|
	}
 | 
						|
 | 
						|
	return FM10K_ERR_REQUESTS_PENDING;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_stop_hw_generic - Stop Tx/Rx units
 | 
						|
 *  @hw: pointer to hardware structure
 | 
						|
 *
 | 
						|
 **/
 | 
						|
s32 fm10k_stop_hw_generic(struct fm10k_hw *hw)
 | 
						|
{
 | 
						|
	return fm10k_disable_queues_generic(hw, hw->mac.max_queues);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_read_hw_stats_32b - Reads value of 32-bit registers
 | 
						|
 *  @hw: pointer to the hardware structure
 | 
						|
 *  @addr: address of register containing a 32-bit value
 | 
						|
 *  @stat: pointer to structure holding hw stat information
 | 
						|
 *
 | 
						|
 *  Function reads the content of the register and returns the delta
 | 
						|
 *  between the base and the current value.
 | 
						|
 *  **/
 | 
						|
u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr,
 | 
						|
			    struct fm10k_hw_stat *stat)
 | 
						|
{
 | 
						|
	u32 delta = fm10k_read_reg(hw, addr) - stat->base_l;
 | 
						|
 | 
						|
	if (FM10K_REMOVED(hw->hw_addr))
 | 
						|
		stat->base_h = 0;
 | 
						|
 | 
						|
	return delta;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_read_hw_stats_48b - Reads value of 48-bit registers
 | 
						|
 *  @hw: pointer to the hardware structure
 | 
						|
 *  @addr: address of register containing the lower 32-bit value
 | 
						|
 *  @stat: pointer to structure holding hw stat information
 | 
						|
 *
 | 
						|
 *  Function reads the content of 2 registers, combined to represent a 48-bit
 | 
						|
 *  statistical value. Extra processing is required to handle overflowing.
 | 
						|
 *  Finally, a delta value is returned representing the difference between the
 | 
						|
 *  values stored in registers and values stored in the statistic counters.
 | 
						|
 *  **/
 | 
						|
static u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr,
 | 
						|
				   struct fm10k_hw_stat *stat)
 | 
						|
{
 | 
						|
	u32 count_l;
 | 
						|
	u32 count_h;
 | 
						|
	u32 count_tmp;
 | 
						|
	u64 delta;
 | 
						|
 | 
						|
	count_h = fm10k_read_reg(hw, addr + 1);
 | 
						|
 | 
						|
	/* Check for overflow */
 | 
						|
	do {
 | 
						|
		count_tmp = count_h;
 | 
						|
		count_l = fm10k_read_reg(hw, addr);
 | 
						|
		count_h = fm10k_read_reg(hw, addr + 1);
 | 
						|
	} while (count_h != count_tmp);
 | 
						|
 | 
						|
	delta = ((u64)(count_h - stat->base_h) << 32) + count_l;
 | 
						|
	delta -= stat->base_l;
 | 
						|
 | 
						|
	return delta & FM10K_48_BIT_MASK;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_update_hw_base_48b - Updates 48-bit statistic base value
 | 
						|
 *  @stat: pointer to the hardware statistic structure
 | 
						|
 *  @delta: value to be updated into the hardware statistic structure
 | 
						|
 *
 | 
						|
 *  Function receives a value and determines if an update is required based on
 | 
						|
 *  a delta calculation. Only the base value will be updated.
 | 
						|
 **/
 | 
						|
static void fm10k_update_hw_base_48b(struct fm10k_hw_stat *stat, u64 delta)
 | 
						|
{
 | 
						|
	if (!delta)
 | 
						|
		return;
 | 
						|
 | 
						|
	/* update lower 32 bits */
 | 
						|
	delta += stat->base_l;
 | 
						|
	stat->base_l = (u32)delta;
 | 
						|
 | 
						|
	/* update upper 32 bits */
 | 
						|
	stat->base_h += (u32)(delta >> 32);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters
 | 
						|
 *  @hw: pointer to the hardware structure
 | 
						|
 *  @q: pointer to the ring of hardware statistics queue
 | 
						|
 *  @idx: index pointing to the start of the ring iteration
 | 
						|
 *
 | 
						|
 *  Function updates the TX queue statistics counters that are related to the
 | 
						|
 *  hardware.
 | 
						|
 **/
 | 
						|
static void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw,
 | 
						|
				       struct fm10k_hw_stats_q *q,
 | 
						|
				       u32 idx)
 | 
						|
{
 | 
						|
	u32 id_tx, id_tx_prev, tx_packets;
 | 
						|
	u64 tx_bytes = 0;
 | 
						|
 | 
						|
	/* Retrieve TX Owner Data */
 | 
						|
	id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx));
 | 
						|
 | 
						|
	/* Process TX Ring */
 | 
						|
	do {
 | 
						|
		tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx),
 | 
						|
						     &q->tx_packets);
 | 
						|
 | 
						|
		if (tx_packets)
 | 
						|
			tx_bytes = fm10k_read_hw_stats_48b(hw,
 | 
						|
							   FM10K_QBTC_L(idx),
 | 
						|
							   &q->tx_bytes);
 | 
						|
 | 
						|
		/* Re-Check Owner Data */
 | 
						|
		id_tx_prev = id_tx;
 | 
						|
		id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx));
 | 
						|
	} while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK);
 | 
						|
 | 
						|
	/* drop non-ID bits and set VALID ID bit */
 | 
						|
	id_tx &= FM10K_TXQCTL_ID_MASK;
 | 
						|
	id_tx |= FM10K_STAT_VALID;
 | 
						|
 | 
						|
	/* update packet counts */
 | 
						|
	if (q->tx_stats_idx == id_tx) {
 | 
						|
		q->tx_packets.count += tx_packets;
 | 
						|
		q->tx_bytes.count += tx_bytes;
 | 
						|
	}
 | 
						|
 | 
						|
	/* update bases and record ID */
 | 
						|
	fm10k_update_hw_base_32b(&q->tx_packets, tx_packets);
 | 
						|
	fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes);
 | 
						|
 | 
						|
	q->tx_stats_idx = id_tx;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters
 | 
						|
 *  @hw: pointer to the hardware structure
 | 
						|
 *  @q: pointer to the ring of hardware statistics queue
 | 
						|
 *  @idx: index pointing to the start of the ring iteration
 | 
						|
 *
 | 
						|
 *  Function updates the RX queue statistics counters that are related to the
 | 
						|
 *  hardware.
 | 
						|
 **/
 | 
						|
static void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw,
 | 
						|
				       struct fm10k_hw_stats_q *q,
 | 
						|
				       u32 idx)
 | 
						|
{
 | 
						|
	u32 id_rx, id_rx_prev, rx_packets, rx_drops;
 | 
						|
	u64 rx_bytes = 0;
 | 
						|
 | 
						|
	/* Retrieve RX Owner Data */
 | 
						|
	id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx));
 | 
						|
 | 
						|
	/* Process RX Ring */
 | 
						|
	do {
 | 
						|
		rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx),
 | 
						|
						   &q->rx_drops);
 | 
						|
 | 
						|
		rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx),
 | 
						|
						     &q->rx_packets);
 | 
						|
 | 
						|
		if (rx_packets)
 | 
						|
			rx_bytes = fm10k_read_hw_stats_48b(hw,
 | 
						|
							   FM10K_QBRC_L(idx),
 | 
						|
							   &q->rx_bytes);
 | 
						|
 | 
						|
		/* Re-Check Owner Data */
 | 
						|
		id_rx_prev = id_rx;
 | 
						|
		id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx));
 | 
						|
	} while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK);
 | 
						|
 | 
						|
	/* drop non-ID bits and set VALID ID bit */
 | 
						|
	id_rx &= FM10K_RXQCTL_ID_MASK;
 | 
						|
	id_rx |= FM10K_STAT_VALID;
 | 
						|
 | 
						|
	/* update packet counts */
 | 
						|
	if (q->rx_stats_idx == id_rx) {
 | 
						|
		q->rx_drops.count += rx_drops;
 | 
						|
		q->rx_packets.count += rx_packets;
 | 
						|
		q->rx_bytes.count += rx_bytes;
 | 
						|
	}
 | 
						|
 | 
						|
	/* update bases and record ID */
 | 
						|
	fm10k_update_hw_base_32b(&q->rx_drops, rx_drops);
 | 
						|
	fm10k_update_hw_base_32b(&q->rx_packets, rx_packets);
 | 
						|
	fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes);
 | 
						|
 | 
						|
	q->rx_stats_idx = id_rx;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_update_hw_stats_q - Updates queue statistics counters
 | 
						|
 *  @hw: pointer to the hardware structure
 | 
						|
 *  @q: pointer to the ring of hardware statistics queue
 | 
						|
 *  @idx: index pointing to the start of the ring iteration
 | 
						|
 *  @count: number of queues to iterate over
 | 
						|
 *
 | 
						|
 *  Function updates the queue statistics counters that are related to the
 | 
						|
 *  hardware.
 | 
						|
 **/
 | 
						|
void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q,
 | 
						|
			     u32 idx, u32 count)
 | 
						|
{
 | 
						|
	u32 i;
 | 
						|
 | 
						|
	for (i = 0; i < count; i++, idx++, q++) {
 | 
						|
		fm10k_update_hw_stats_tx_q(hw, q, idx);
 | 
						|
		fm10k_update_hw_stats_rx_q(hw, q, idx);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_unbind_hw_stats_q - Unbind the queue counters from their queues
 | 
						|
 *  @q: pointer to the ring of hardware statistics queue
 | 
						|
 *  @idx: index pointing to the start of the ring iteration
 | 
						|
 *  @count: number of queues to iterate over
 | 
						|
 *
 | 
						|
 *  Function invalidates the index values for the queues so any updates that
 | 
						|
 *  may have happened are ignored and the base for the queue stats is reset.
 | 
						|
 **/
 | 
						|
void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count)
 | 
						|
{
 | 
						|
	u32 i;
 | 
						|
 | 
						|
	for (i = 0; i < count; i++, idx++, q++) {
 | 
						|
		q->rx_stats_idx = 0;
 | 
						|
		q->tx_stats_idx = 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 *  fm10k_get_host_state_generic - Returns the state of the host
 | 
						|
 *  @hw: pointer to hardware structure
 | 
						|
 *  @host_ready: pointer to boolean value that will record host state
 | 
						|
 *
 | 
						|
 *  This function will check the health of the mailbox and Tx queue 0
 | 
						|
 *  in order to determine if we should report that the link is up or not.
 | 
						|
 **/
 | 
						|
s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready)
 | 
						|
{
 | 
						|
	struct fm10k_mbx_info *mbx = &hw->mbx;
 | 
						|
	struct fm10k_mac_info *mac = &hw->mac;
 | 
						|
	s32 ret_val = 0;
 | 
						|
	u32 txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(0));
 | 
						|
 | 
						|
	/* process upstream mailbox in case interrupts were disabled */
 | 
						|
	mbx->ops.process(hw, mbx);
 | 
						|
 | 
						|
	/* If Tx is no longer enabled link should come down */
 | 
						|
	if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE))
 | 
						|
		mac->get_host_state = true;
 | 
						|
 | 
						|
	/* exit if not checking for link, or link cannot be changed */
 | 
						|
	if (!mac->get_host_state || !(~txdctl))
 | 
						|
		goto out;
 | 
						|
 | 
						|
	/* if we somehow dropped the Tx enable we should reset */
 | 
						|
	if (mac->tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) {
 | 
						|
		ret_val = FM10K_ERR_RESET_REQUESTED;
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	/* if Mailbox timed out we should request reset */
 | 
						|
	if (!mbx->timeout) {
 | 
						|
		ret_val = FM10K_ERR_RESET_REQUESTED;
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	/* verify Mailbox is still open */
 | 
						|
	if (mbx->state != FM10K_STATE_OPEN)
 | 
						|
		goto out;
 | 
						|
 | 
						|
	/* interface cannot receive traffic without logical ports */
 | 
						|
	if (mac->dglort_map == FM10K_DGLORTMAP_NONE) {
 | 
						|
		if (mac->ops.request_lport_map)
 | 
						|
			ret_val = mac->ops.request_lport_map(hw);
 | 
						|
 | 
						|
		goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	/* if we passed all the tests above then the switch is ready and we no
 | 
						|
	 * longer need to check for link
 | 
						|
	 */
 | 
						|
	mac->get_host_state = false;
 | 
						|
 | 
						|
out:
 | 
						|
	*host_ready = !mac->get_host_state;
 | 
						|
	return ret_val;
 | 
						|
}
 |