Commit c0071c7a authored by Sasha Neftin's avatar Sasha Neftin Committed by Jeff Kirsher
Browse files

igc: Add HW initialization code



Add code for hardware initialization and reset
Add code for semaphore handling

Signed-off-by: default avatarSasha Neftin <sasha.neftin@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 0507ef8a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -7,4 +7,4 @@

obj-$(CONFIG_IGC) += igc.o

igc-objs := igc_main.o igc_mac.o igc_base.o
igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o
+187 −0
Original line number Diff line number Diff line
@@ -5,6 +5,184 @@

#include "igc_hw.h"
#include "igc_i225.h"
#include "igc_mac.h"
#include "igc_base.h"
#include "igc.h"

/**
 * igc_set_pcie_completion_timeout - set pci-e completion timeout
 * @hw: pointer to the HW structure
 */
static s32 igc_set_pcie_completion_timeout(struct igc_hw *hw)
{
	u32 gcr = rd32(IGC_GCR);
	u16 pcie_devctl2;
	s32 ret_val = 0;

	/* only take action if timeout value is defaulted to 0 */
	if (gcr & IGC_GCR_CMPL_TMOUT_MASK)
		goto out;

	/* if capabilities version is type 1 we can write the
	 * timeout of 10ms to 200ms through the GCR register
	 */
	if (!(gcr & IGC_GCR_CAP_VER2)) {
		gcr |= IGC_GCR_CMPL_TMOUT_10ms;
		goto out;
	}

	/* for version 2 capabilities we need to write the config space
	 * directly in order to set the completion timeout value for
	 * 16ms to 55ms
	 */
	ret_val = igc_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
					&pcie_devctl2);
	if (ret_val)
		goto out;

	pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;

	ret_val = igc_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
					 &pcie_devctl2);
out:
	/* disable completion timeout resend */
	gcr &= ~IGC_GCR_CMPL_TMOUT_RESEND;

	wr32(IGC_GCR, gcr);

	return ret_val;
}

/**
 * igc_reset_hw_base - Reset hardware
 * @hw: pointer to the HW structure
 *
 * This resets the hardware into a known state.  This is a
 * function pointer entry point called by the api module.
 */
static s32 igc_reset_hw_base(struct igc_hw *hw)
{
	s32 ret_val;
	u32 ctrl;

	/* Prevent the PCI-E bus from sticking if there is no TLP connection
	 * on the last TLP read/write transaction when MAC is reset.
	 */
	ret_val = igc_disable_pcie_master(hw);
	if (ret_val)
		hw_dbg("PCI-E Master disable polling has failed.\n");

	/* set the completion timeout for interface */
	ret_val = igc_set_pcie_completion_timeout(hw);
	if (ret_val)
		hw_dbg("PCI-E Set completion timeout has failed.\n");

	hw_dbg("Masking off all interrupts\n");
	wr32(IGC_IMC, 0xffffffff);

	wr32(IGC_RCTL, 0);
	wr32(IGC_TCTL, IGC_TCTL_PSP);
	wrfl();

	usleep_range(10000, 20000);

	ctrl = rd32(IGC_CTRL);

	hw_dbg("Issuing a global reset to MAC\n");
	wr32(IGC_CTRL, ctrl | IGC_CTRL_RST);

	ret_val = igc_get_auto_rd_done(hw);
	if (ret_val) {
		/* When auto config read does not complete, do not
		 * return with an error. This can happen in situations
		 * where there is no eeprom and prevents getting link.
		 */
		hw_dbg("Auto Read Done did not complete\n");
	}

	/* Clear any pending interrupt events. */
	wr32(IGC_IMC, 0xffffffff);
	rd32(IGC_ICR);

	return ret_val;
}

/**
 * igc_init_mac_params_base - Init MAC func ptrs.
 * @hw: pointer to the HW structure
 */
static s32 igc_init_mac_params_base(struct igc_hw *hw)
{
	struct igc_mac_info *mac = &hw->mac;

	/* Set mta register count */
	mac->mta_reg_count = 128;
	mac->rar_entry_count = IGC_RAR_ENTRIES;

	/* reset */
	mac->ops.reset_hw = igc_reset_hw_base;

	mac->ops.acquire_swfw_sync = igc_acquire_swfw_sync_i225;
	mac->ops.release_swfw_sync = igc_release_swfw_sync_i225;

	return 0;
}

static s32 igc_get_invariants_base(struct igc_hw *hw)
{
	u32 link_mode = 0;
	u32 ctrl_ext = 0;
	s32 ret_val = 0;

	ctrl_ext = rd32(IGC_CTRL_EXT);
	link_mode = ctrl_ext & IGC_CTRL_EXT_LINK_MODE_MASK;

	/* mac initialization and operations */
	ret_val = igc_init_mac_params_base(hw);
	if (ret_val)
		goto out;

out:
	return ret_val;
}

/**
 * igc_init_hw_base - Initialize hardware
 * @hw: pointer to the HW structure
 *
 * This inits the hardware readying it for operation.
 */
static s32 igc_init_hw_base(struct igc_hw *hw)
{
	struct igc_mac_info *mac = &hw->mac;
	u16 i, rar_count = mac->rar_entry_count;
	s32 ret_val = 0;

	/* Setup the receive address */
	igc_init_rx_addrs(hw, rar_count);

	/* Zero out the Multicast HASH table */
	hw_dbg("Zeroing the MTA\n");
	for (i = 0; i < mac->mta_reg_count; i++)
		array_wr32(IGC_MTA, i, 0);

	/* Zero out the Unicast HASH table */
	hw_dbg("Zeroing the UTA\n");
	for (i = 0; i < mac->uta_reg_count; i++)
		array_wr32(IGC_UTA, i, 0);

	/* Setup link and flow control */
	ret_val = igc_setup_link(hw);

	/* Clear all of the statistics registers (clear on read).  It is
	 * important that we do this after we have tried to establish link
	 * because the symbol error count will increment wildly if there
	 * is no link.
	 */
	igc_clear_hw_cntrs_base(hw);

	return ret_val;
}

/**
 * igc_rx_fifo_flush_base - Clean rx fifo after Rx enable
@@ -81,3 +259,12 @@ void igc_rx_fifo_flush_base(struct igc_hw *hw)
	rd32(IGC_RNBC);
	rd32(IGC_MPC);
}

static struct igc_mac_operations igc_mac_ops_base = {
	.init_hw		= igc_init_hw_base,
};

const struct igc_info igc_base_info = {
	.get_invariants		= igc_get_invariants_base,
	.mac_ops		= &igc_mac_ops_base,
};
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ union igc_adv_tx_desc {
#define IGC_ADVTXD_DCMD_TSE	0x80000000 /* TCP Seg enable */
#define IGC_ADVTXD_PAYLEN_SHIFT	14 /* Adv desc PAYLEN shift */

#define IGC_RAR_ENTRIES		16

struct igc_adv_data_desc {
	__le64 buffer_addr;    /* Address of the descriptor's data buffer */
	union {
+36 −0
Original line number Diff line number Diff line
@@ -10,6 +10,22 @@
#define PCIE_DEVICE_CONTROL2		0x28
#define PCIE_DEVICE_CONTROL2_16ms	0x0005

/* Physical Func Reset Done Indication */
#define IGC_CTRL_EXT_LINK_MODE_MASK	0x00C00000

/* Number of 100 microseconds we wait for PCI Express master disable */
#define MASTER_DISABLE_TIMEOUT		800
/*Blocks new Master requests */
#define IGC_CTRL_GIO_MASTER_DISABLE	0x00000004
/* Status of Master requests. */
#define IGC_STATUS_GIO_MASTER_ENABLE	0x00080000

/* PCI Express Control */
#define IGC_GCR_CMPL_TMOUT_MASK		0x0000F000
#define IGC_GCR_CMPL_TMOUT_10ms		0x00001000
#define IGC_GCR_CMPL_TMOUT_RESEND	0x00010000
#define IGC_GCR_CAP_VER2		0x00040000

/* Receive Address
 * Number of high/low register pairs in the RAR. The RAR (Receive Address
 * Registers) holds the directed and multicast addresses that we monitor.
@@ -28,10 +44,23 @@
#define IGC_ERR_PARAM			4
#define IGC_ERR_MAC_INIT		5
#define IGC_ERR_RESET			9
#define IGC_ERR_MASTER_REQUESTS_PENDING	10
#define IGC_ERR_SWFW_SYNC		13

/* Device Control */
#define IGC_CTRL_RST		0x04000000  /* Global reset */

/* PBA constants */
#define IGC_PBA_34K		0x0022

/* SW Semaphore Register */
#define IGC_SWSM_SMBI		0x00000001 /* Driver Semaphore bit */
#define IGC_SWSM_SWESMBI	0x00000002 /* FW Semaphore bit */

/* Number of milliseconds for NVM auto read done after MAC reset. */
#define AUTO_READ_DONE_TIMEOUT		10
#define IGC_EECD_AUTO_RD		0x00000200  /* NVM Auto Read done */

/* Device Status */
#define IGC_STATUS_FD		0x00000001      /* Full duplex.0=half,1=full */
#define IGC_STATUS_LU		0x00000002      /* Link up.0=no,1=link */
@@ -118,6 +147,13 @@
#define IGC_CT_SHIFT			4
#define IGC_COLLISION_THRESHOLD		15

/* Flow Control Constants */
#define FLOW_CONTROL_ADDRESS_LOW	0x00C28001
#define FLOW_CONTROL_ADDRESS_HIGH	0x00000100
#define FLOW_CONTROL_TYPE		0x8808
/* Enable XON frame transmission */
#define IGC_FCRTL_XONE			0x80000000

/* Management Control */
#define IGC_MANC_RCV_TCO_EN	0x00020000 /* Receive TCO Packets Enabled */

+85 −0
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@

#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>

#include "igc_regs.h"
#include "igc_defines.h"
#include "igc_mac.h"
@@ -17,6 +19,16 @@

/* Function pointers for the MAC. */
struct igc_mac_operations {
	s32 (*check_for_link)(struct igc_hw *hw);
	s32 (*reset_hw)(struct igc_hw *hw);
	s32 (*init_hw)(struct igc_hw *hw);
	s32 (*setup_physical_interface)(struct igc_hw *hw);
	void (*rar_set)(struct igc_hw *hw, u8 *address, u32 index);
	s32 (*read_mac_addr)(struct igc_hw *hw);
	s32 (*get_speed_and_duplex)(struct igc_hw *hw, u16 *speed,
				    u16 *duplex);
	s32 (*acquire_swfw_sync)(struct igc_hw *hw, u16 mask);
	void (*release_swfw_sync)(struct igc_hw *hw, u16 mask);
};

enum igc_mac_type {
@@ -31,6 +43,19 @@ enum igc_phy_type {
	igc_phy_i225,
};

enum igc_nvm_type {
	igc_nvm_unknown = 0,
	igc_nvm_flash_hw,
	igc_nvm_invm,
};

struct igc_info {
	s32 (*get_invariants)(struct igc_hw *hw);
	struct igc_mac_operations *mac_ops;
	const struct igc_phy_operations *phy_ops;
	struct igc_nvm_operations *nvm_ops;
};

struct igc_mac_info {
	struct igc_mac_operations ops;

@@ -63,11 +88,61 @@ struct igc_mac_info {
	bool get_link_status;
};

struct igc_nvm_operations {
	s32 (*acquire)(struct igc_hw *hw);
	s32 (*read)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
	void (*release)(struct igc_hw *hw);
	s32 (*write)(struct igc_hw *hw, u16 offset, u16 i, u16 *data);
	s32 (*update)(struct igc_hw *hw);
	s32 (*validate)(struct igc_hw *hw);
	s32 (*valid_led_default)(struct igc_hw *hw, u16 *data);
};

struct igc_nvm_info {
	struct igc_nvm_operations ops;
	enum igc_nvm_type type;

	u32 flash_bank_size;
	u32 flash_base_addr;

	u16 word_size;
	u16 delay_usec;
	u16 address_bits;
	u16 opcode_bits;
	u16 page_size;
};

struct igc_bus_info {
	u16 func;
	u16 pci_cmd_word;
};

enum igc_fc_mode {
	igc_fc_none = 0,
	igc_fc_rx_pause,
	igc_fc_tx_pause,
	igc_fc_full,
	igc_fc_default = 0xFF
};

struct igc_fc_info {
	u32 high_water;     /* Flow control high-water mark */
	u32 low_water;      /* Flow control low-water mark */
	u16 pause_time;     /* Flow control pause timer */
	bool send_xon;      /* Flow control send XON */
	bool strict_ieee;   /* Strict IEEE mode */
	enum igc_fc_mode current_mode; /* Type of flow control */
	enum igc_fc_mode requested_mode;
};

struct igc_dev_spec_base {
	bool global_device_reset;
	bool eee_disable;
	bool clear_semaphore_once;
	bool module_plugged;
	u8 media_port;
};

struct igc_hw {
	void *back;

@@ -75,9 +150,15 @@ struct igc_hw {
	unsigned long io_base;

	struct igc_mac_info  mac;
	struct igc_fc_info   fc;
	struct igc_nvm_info  nvm;

	struct igc_bus_info bus;

	union {
		struct igc_dev_spec_base	_base;
	} dev_spec;

	u16 device_id;
	u16 subsystem_vendor_id;
	u16 subsystem_device_id;
@@ -170,6 +251,10 @@ struct igc_hw_stats {
	u64 b2ogprc;
};

struct net_device *igc_get_hw_dev(struct igc_hw *hw);
#define hw_dbg(format, arg...) \
	netdev_dbg(igc_get_hw_dev(hw), format, ##arg)

s32  igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value);
s32  igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value);
void igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value);
Loading