Skip to content

Commit

Permalink
igc: Add code for PHY support
Browse files Browse the repository at this point in the history
Add PHY's ID support
Add support for initialization, acquire and release of PHY
Enable register access

Signed-off-by: Sasha Neftin <[email protected]>
Signed-off-by: Alexander Duyck <[email protected]>
Tested-by: Aaron Brown <[email protected]>
Signed-off-by: Jeff Kirsher <[email protected]>
  • Loading branch information
aneftin authored and Jeff Kirsher committed Oct 17, 2018
1 parent ab40561 commit 5586838
Show file tree
Hide file tree
Showing 12 changed files with 820 additions and 1 deletion.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/intel/igc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@

obj-$(CONFIG_IGC) += igc.o

igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o
igc-objs := igc_main.o igc_mac.o igc_i225.o igc_base.o igc_nvm.o igc_phy.o
16 changes: 16 additions & 0 deletions drivers/net/ethernet/intel/igc/igc.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,22 @@ static inline u16 igc_desc_unused(const struct igc_ring *ring)
return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
}

static inline s32 igc_get_phy_info(struct igc_hw *hw)
{
if (hw->phy.ops.get_phy_info)
return hw->phy.ops.get_phy_info(hw);

return 0;
}

static inline s32 igc_reset_phy(struct igc_hw *hw)
{
if (hw->phy.ops.reset)
return hw->phy.ops.reset(hw);

return 0;
}

static inline struct netdev_queue *txring_txq(const struct igc_ring *tx_ring)
{
return netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index);
Expand Down
122 changes: 122 additions & 0 deletions drivers/net/ethernet/intel/igc/igc_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,22 @@ static s32 igc_reset_hw_base(struct igc_hw *hw)
return ret_val;
}

/**
* igc_get_phy_id_base - Retrieve PHY addr and id
* @hw: pointer to the HW structure
*
* Retrieves the PHY address and ID for both PHY's which do and do not use
* sgmi interface.
*/
static s32 igc_get_phy_id_base(struct igc_hw *hw)
{
s32 ret_val = 0;

ret_val = igc_get_phy_id(hw);

return ret_val;
}

/**
* igc_init_nvm_params_base - Init NVM func ptrs.
* @hw: pointer to the HW structure
Expand Down Expand Up @@ -187,6 +203,59 @@ static s32 igc_init_mac_params_base(struct igc_hw *hw)
return 0;
}

/**
* igc_init_phy_params_base - Init PHY func ptrs.
* @hw: pointer to the HW structure
*/
static s32 igc_init_phy_params_base(struct igc_hw *hw)
{
struct igc_phy_info *phy = &hw->phy;
s32 ret_val = 0;
u32 ctrl_ext;

if (hw->phy.media_type != igc_media_type_copper) {
phy->type = igc_phy_none;
goto out;
}

phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT_2500;
phy->reset_delay_us = 100;

ctrl_ext = rd32(IGC_CTRL_EXT);

/* set lan id */
hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
IGC_STATUS_FUNC_SHIFT;

/* Make sure the PHY is in a good state. Several people have reported
* firmware leaving the PHY's page select register set to something
* other than the default of zero, which causes the PHY ID read to
* access something other than the intended register.
*/
ret_val = hw->phy.ops.reset(hw);
if (ret_val) {
hw_dbg("Error resetting the PHY.\n");
goto out;
}

ret_val = igc_get_phy_id_base(hw);
if (ret_val)
return ret_val;

/* Verify phy id and set remaining function pointers */
switch (phy->id) {
case I225_I_PHY_ID:
phy->type = igc_phy_i225;
break;
default:
ret_val = -IGC_ERR_PHY;
goto out;
}

out:
return ret_val;
}

static s32 igc_get_invariants_base(struct igc_hw *hw)
{
u32 link_mode = 0;
Expand All @@ -211,13 +280,43 @@ static s32 igc_get_invariants_base(struct igc_hw *hw)
break;
}

/* setup PHY parameters */
ret_val = igc_init_phy_params_base(hw);
if (ret_val)
goto out;

out:
return ret_val;
}

/**
* igc_acquire_phy_base - Acquire rights to access PHY
* @hw: pointer to the HW structure
*
* Acquire access rights to the correct PHY. This is a
* function pointer entry point called by the api module.
*/
static s32 igc_acquire_phy_base(struct igc_hw *hw)
{
u16 mask = IGC_SWFW_PHY0_SM;

return hw->mac.ops.acquire_swfw_sync(hw, mask);
}

/**
* igc_release_phy_base - Release rights to access PHY
* @hw: pointer to the HW structure
*
* A wrapper to release access rights to the correct PHY. This is a
* function pointer entry point called by the api module.
*/
static void igc_release_phy_base(struct igc_hw *hw)
{
u16 mask = IGC_SWFW_PHY0_SM;

hw->mac.ops.release_swfw_sync(hw, mask);
}

/**
* igc_get_link_up_info_base - Get link speed/duplex info
* @hw: pointer to the HW structure
Expand Down Expand Up @@ -289,6 +388,20 @@ static s32 igc_read_mac_addr_base(struct igc_hw *hw)
return ret_val;
}

/**
* igc_power_down_phy_copper_base - Remove link during PHY power down
* @hw: pointer to the HW structure
*
* In the case of a PHY power down to save power, or to turn off link during a
* driver unload, or wake on lan is not enabled, remove the link.
*/
void igc_power_down_phy_copper_base(struct igc_hw *hw)
{
/* If the management interface is not enabled, then power down */
if (!(igc_enable_mng_pass_thru(hw) || igc_check_reset_block(hw)))
igc_power_down_phy_copper(hw);
}

/**
* igc_rx_fifo_flush_base - Clean rx fifo after Rx enable
* @hw: pointer to the HW structure
Expand Down Expand Up @@ -373,7 +486,16 @@ static struct igc_mac_operations igc_mac_ops_base = {
.get_speed_and_duplex = igc_get_link_up_info_base,
};

static const struct igc_phy_operations igc_phy_ops_base = {
.acquire = igc_acquire_phy_base,
.release = igc_release_phy_base,
.reset = igc_phy_hw_reset,
.read_reg = igc_read_phy_reg_gpy,
.write_reg = igc_write_phy_reg_gpy,
};

const struct igc_info igc_base_info = {
.get_invariants = igc_get_invariants_base,
.mac_ops = &igc_mac_ops_base,
.phy_ops = &igc_phy_ops_base,
};
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/igc/igc_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

/* forward declaration */
void igc_rx_fifo_flush_base(struct igc_hw *hw);
void igc_power_down_phy_copper_base(struct igc_hw *hw);

/* Transmit Descriptor - Advanced */
union igc_adv_tx_desc {
Expand Down
79 changes: 79 additions & 0 deletions drivers/net/ethernet/intel/igc/igc_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@
#define IGC_ERR_MAC_INIT 5
#define IGC_ERR_RESET 9
#define IGC_ERR_MASTER_REQUESTS_PENDING 10
#define IGC_ERR_BLK_PHY_RESET 12
#define IGC_ERR_SWFW_SYNC 13

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

#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */

/* PBA constants */
#define IGC_PBA_34K 0x0022

Expand Down Expand Up @@ -123,6 +126,22 @@
#define HALF_DUPLEX 1
#define FULL_DUPLEX 2

/* 1Gbps and 2.5Gbps half duplex is not supported, nor spec-compliant. */
#define ADVERTISE_10_HALF 0x0001
#define ADVERTISE_10_FULL 0x0002
#define ADVERTISE_100_HALF 0x0004
#define ADVERTISE_100_FULL 0x0008
#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
#define ADVERTISE_1000_FULL 0x0020
#define ADVERTISE_2500_HALF 0x0040 /* Not used, just FYI */
#define ADVERTISE_2500_FULL 0x0080

#define IGC_ALL_SPEED_DUPLEX_2500 ( \
ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \
ADVERTISE_100_FULL | ADVERTISE_1000_FULL | ADVERTISE_2500_FULL)

#define AUTONEG_ADVERTISE_SPEED_DEFAULT_2500 IGC_ALL_SPEED_DUPLEX_2500

/* Interrupt Cause Read */
#define IGC_ICR_TXDW BIT(0) /* Transmit desc written back */
#define IGC_ICR_TXQE BIT(1) /* Transmit Queue empty */
Expand Down Expand Up @@ -208,6 +227,7 @@

/* Management Control */
#define IGC_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
#define IGC_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */

/* Receive Control */
#define IGC_RCTL_RST 0x00000001 /* Software reset */
Expand Down Expand Up @@ -256,6 +276,65 @@
#define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */
#define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */

/* GPY211 - I225 defines */
#define GPY_MMD_MASK 0xFFFF0000
#define GPY_MMD_SHIFT 16
#define GPY_REG_MASK 0x0000FFFF

#define IGC_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */

/* MAC definitions */
#define IGC_FACTPS_MNGCG 0x20000000
#define IGC_FWSM_MODE_MASK 0xE
#define IGC_FWSM_MODE_SHIFT 1

/* Management Control */
#define IGC_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
#define IGC_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */

/* PHY */
#define PHY_REVISION_MASK 0xFFFFFFF0
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
#define IGC_GEN_POLL_TIMEOUT 1920

/* PHY Control Register */
#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
#define MII_CR_POWER_DOWN 0x0800 /* Power down */
#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
#define MII_CR_SPEED_1000 0x0040
#define MII_CR_SPEED_100 0x2000
#define MII_CR_SPEED_10 0x0000

/* PHY Status Register */
#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */

/* PHY 1000 MII Register/Bit Definitions */
/* PHY Registers defined by IEEE */
#define PHY_CONTROL 0x00 /* Control Register */
#define PHY_STATUS 0x01 /* Status Register */
#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */

/* Bit definitions for valid PHY IDs. I = Integrated E = External */
#define I225_I_PHY_ID 0x67C9DC00

/* MDI Control */
#define IGC_MDIC_DATA_MASK 0x0000FFFF
#define IGC_MDIC_REG_MASK 0x001F0000
#define IGC_MDIC_REG_SHIFT 16
#define IGC_MDIC_PHY_MASK 0x03E00000
#define IGC_MDIC_PHY_SHIFT 21
#define IGC_MDIC_OP_WRITE 0x04000000
#define IGC_MDIC_OP_READ 0x08000000
#define IGC_MDIC_READY 0x10000000
#define IGC_MDIC_INT_EN 0x20000000
#define IGC_MDIC_ERROR 0x40000000
#define IGC_MDIC_DEST 0x80000000

#define IGC_N0_QUEUE -1

#endif /* _IGC_DEFINES_H_ */
Loading

0 comments on commit 5586838

Please sign in to comment.