Skip to content

Commit

Permalink
Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/…
Browse files Browse the repository at this point in the history
…jkirsher/next-queue

Jeff Kirsher says:

====================
1GbE Intel Wired LAN Driver Updates 2020-06-29

This series contains updates to only the igc driver.

Sasha added Energy Efficient Ethernet (EEE) support and Latency Tolerance
Reporting (LTR) support for the igc driver. Added Low Power Idle (LPI)
counters and cleaned up unused TCP segmentation counters. Removed
igc_power_down_link() and call igc_power_down_phy_copper_base()
directly. Removed unneeded copper media check.

Andre cleaned up timestamping by removing un-supported features and
duplicate code for i225. Fixed the timestamp check on the proper flag
instead of the skb for pending transmit timestamps. Refactored
igc_ptp_set_timestamp_mode() to simply the flow.

v2: Removed the log message in patch 1 as suggested by David Miller.
    Note: The locking issue Jakub Kicinski saw in patch 5, currently
    exists in the current net-next tree, so Andre will resolve the
    locking issue in a follow-on patch.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 30, 2020
2 parents 2dac017 + f637471 commit e25974a
Show file tree
Hide file tree
Showing 10 changed files with 414 additions and 223 deletions.
7 changes: 4 additions & 3 deletions drivers/net/ethernet/intel/igc/igc.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ struct igc_ring {
struct igc_adapter {
struct net_device *netdev;

struct ethtool_eee eee;
u16 eee_advert;

unsigned long state;
unsigned int flags;
unsigned int num_q_vectors;
Expand Down Expand Up @@ -207,8 +210,6 @@ struct igc_adapter {
struct sk_buff *ptp_tx_skb;
struct hwtstamp_config tstamp_config;
unsigned long ptp_tx_start;
unsigned long last_rx_ptp_check;
unsigned long last_rx_timestamp;
unsigned int ptp_flags;
/* System time value lock */
spinlock_t tmreg_lock;
Expand Down Expand Up @@ -255,6 +256,7 @@ extern char igc_driver_name[];
#define IGC_FLAG_MEDIA_RESET BIT(10)
#define IGC_FLAG_MAS_ENABLE BIT(12)
#define IGC_FLAG_HAS_MSIX BIT(13)
#define IGC_FLAG_EEE BIT(14)
#define IGC_FLAG_VLAN_PROMISC BIT(15)
#define IGC_FLAG_RX_LEGACY BIT(16)
#define IGC_FLAG_TSN_QBV_ENABLED BIT(17)
Expand Down Expand Up @@ -545,7 +547,6 @@ void igc_ptp_init(struct igc_adapter *adapter);
void igc_ptp_reset(struct igc_adapter *adapter);
void igc_ptp_suspend(struct igc_adapter *adapter);
void igc_ptp_stop(struct igc_adapter *adapter);
void igc_ptp_rx_rgtstamp(struct igc_q_vector *q_vector, struct sk_buff *skb);
void igc_ptp_rx_pktstamp(struct igc_q_vector *q_vector, void *va,
struct sk_buff *skb);
int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
Expand Down
39 changes: 37 additions & 2 deletions drivers/net/ethernet/intel/igc/igc_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,6 @@

/* Advanced Receive Descriptor bit definitions */
#define IGC_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */
#define IGC_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */

#define IGC_RXDEXT_STATERR_CE 0x01000000
#define IGC_RXDEXT_STATERR_SE 0x02000000
Expand Down Expand Up @@ -384,7 +383,6 @@
#define IGC_FTQF_MASK_PROTO_BP 0x10000000

/* Time Sync Receive Control bit definitions */
#define IGC_TSYNCRXCTL_VALID 0x00000001 /* Rx timestamp valid */
#define IGC_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
#define IGC_TSYNCRXCTL_TYPE_L2_V2 0x00
#define IGC_TSYNCRXCTL_TYPE_L4_V1 0x02
Expand Down Expand Up @@ -511,4 +509,41 @@
/* Maximum size of the MTA register table in all supported adapters */
#define MAX_MTA_REG 128

/* EEE defines */
#define IGC_IPCNFG_EEE_2_5G_AN 0x00000010 /* IPCNFG EEE Ena 2.5G AN */
#define IGC_IPCNFG_EEE_1G_AN 0x00000008 /* IPCNFG EEE Ena 1G AN */
#define IGC_IPCNFG_EEE_100M_AN 0x00000004 /* IPCNFG EEE Ena 100M AN */
#define IGC_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
#define IGC_EEER_TX_LPI_EN 0x00010000 /* EEER Tx LPI Enable */
#define IGC_EEER_RX_LPI_EN 0x00020000 /* EEER Rx LPI Enable */
#define IGC_EEER_LPI_FC 0x00040000 /* EEER Ena on Flow Cntrl */
#define IGC_EEE_SU_LPI_CLK_STP 0x00800000 /* EEE LPI Clock Stop */

/* LTR defines */
#define IGC_LTRC_EEEMS_EN 0x00000020 /* Enable EEE LTR max send */
#define IGC_RXPBS_SIZE_I225_MASK 0x0000003F /* Rx packet buffer size */
#define IGC_TW_SYSTEM_1000_MASK 0x000000FF
/* Minimum time for 100BASE-T where no data will be transmit following move out
* of EEE LPI Tx state
*/
#define IGC_TW_SYSTEM_100_MASK 0x0000FF00
#define IGC_TW_SYSTEM_100_SHIFT 8
#define IGC_DMACR_DMAC_EN 0x80000000 /* Enable DMA Coalescing */
#define IGC_DMACR_DMACTHR_MASK 0x00FF0000
#define IGC_DMACR_DMACTHR_SHIFT 16
/* Reg val to set scale to 1024 nsec */
#define IGC_LTRMINV_SCALE_1024 2
/* Reg val to set scale to 32768 nsec */
#define IGC_LTRMINV_SCALE_32768 3
/* Reg val to set scale to 1024 nsec */
#define IGC_LTRMAXV_SCALE_1024 2
/* Reg val to set scale to 32768 nsec */
#define IGC_LTRMAXV_SCALE_32768 3
#define IGC_LTRMINV_LTRV_MASK 0x000003FF /* LTR minimum value */
#define IGC_LTRMAXV_LTRV_MASK 0x000003FF /* LTR maximum value */
#define IGC_LTRMINV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
#define IGC_LTRMINV_SCALE_SHIFT 10
#define IGC_LTRMAXV_LSNP_REQ 0x00008000 /* LTR Snoop Requirement */
#define IGC_LTRMAXV_SCALE_SHIFT 10

#endif /* _IGC_DEFINES_H_ */
95 changes: 95 additions & 0 deletions drivers/net/ethernet/intel/igc/igc_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/* ethtool support for igc */
#include <linux/if_vlan.h>
#include <linux/pm_runtime.h>
#include <linux/mdio.h>

#include "igc.h"
#include "igc_diag.h"
Expand Down Expand Up @@ -1548,6 +1549,98 @@ static int igc_ethtool_set_priv_flags(struct net_device *netdev, u32 priv_flags)
return 0;
}

static int igc_ethtool_get_eee(struct net_device *netdev,
struct ethtool_eee *edata)
{
struct igc_adapter *adapter = netdev_priv(netdev);
struct igc_hw *hw = &adapter->hw;
u32 eeer;

if (hw->dev_spec._base.eee_enable)
edata->advertised =
mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert);

*edata = adapter->eee;
edata->supported = SUPPORTED_Autoneg;

eeer = rd32(IGC_EEER);

/* EEE status on negotiated link */
if (eeer & IGC_EEER_EEE_NEG)
edata->eee_active = true;

if (eeer & IGC_EEER_TX_LPI_EN)
edata->tx_lpi_enabled = true;

edata->eee_enabled = hw->dev_spec._base.eee_enable;

edata->advertised = SUPPORTED_Autoneg;
edata->lp_advertised = SUPPORTED_Autoneg;

/* Report correct negotiated EEE status for devices that
* wrongly report EEE at half-duplex
*/
if (adapter->link_duplex == HALF_DUPLEX) {
edata->eee_enabled = false;
edata->eee_active = false;
edata->tx_lpi_enabled = false;
edata->advertised &= ~edata->advertised;
}

return 0;
}

static int igc_ethtool_set_eee(struct net_device *netdev,
struct ethtool_eee *edata)
{
struct igc_adapter *adapter = netdev_priv(netdev);
struct igc_hw *hw = &adapter->hw;
struct ethtool_eee eee_curr;
s32 ret_val;

memset(&eee_curr, 0, sizeof(struct ethtool_eee));

ret_val = igc_ethtool_get_eee(netdev, &eee_curr);
if (ret_val) {
netdev_err(netdev,
"Problem setting EEE advertisement options\n");
return -EINVAL;
}

if (eee_curr.eee_enabled) {
if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
netdev_err(netdev,
"Setting EEE tx-lpi is not supported\n");
return -EINVAL;
}

/* Tx LPI timer is not implemented currently */
if (edata->tx_lpi_timer) {
netdev_err(netdev,
"Setting EEE Tx LPI timer is not supported\n");
return -EINVAL;
}
} else if (!edata->eee_enabled) {
netdev_err(netdev,
"Setting EEE options are not supported with EEE disabled\n");
return -EINVAL;
}

adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
if (hw->dev_spec._base.eee_enable != edata->eee_enabled) {
hw->dev_spec._base.eee_enable = edata->eee_enabled;
adapter->flags |= IGC_FLAG_EEE;

/* reset link */
if (netif_running(netdev))
igc_reinit_locked(adapter);
else
igc_reset(adapter);
}

return 0;
}

static int igc_ethtool_begin(struct net_device *netdev)
{
struct igc_adapter *adapter = netdev_priv(netdev);
Expand Down Expand Up @@ -1829,6 +1922,8 @@ static const struct ethtool_ops igc_ethtool_ops = {
.set_channels = igc_ethtool_set_channels,
.get_priv_flags = igc_ethtool_get_priv_flags,
.set_priv_flags = igc_ethtool_set_priv_flags,
.get_eee = igc_ethtool_get_eee,
.set_eee = igc_ethtool_set_eee,
.begin = igc_ethtool_begin,
.complete = igc_ethtool_complete,
.get_link_ksettings = igc_ethtool_get_link_ksettings,
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/igc/igc_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ struct igc_fc_info {

struct igc_dev_spec_base {
bool clear_semaphore_once;
bool eee_enable;
};

struct igc_hw {
Expand Down
156 changes: 156 additions & 0 deletions drivers/net/ethernet/intel/igc/igc_i225.c
Original file line number Diff line number Diff line change
Expand Up @@ -488,3 +488,159 @@ s32 igc_init_nvm_params_i225(struct igc_hw *hw)
}
return 0;
}

/**
* igc_set_eee_i225 - Enable/disable EEE support
* @hw: pointer to the HW structure
* @adv2p5G: boolean flag enabling 2.5G EEE advertisement
* @adv1G: boolean flag enabling 1G EEE advertisement
* @adv100M: boolean flag enabling 100M EEE advertisement
*
* Enable/disable EEE based on setting in dev_spec structure.
**/
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
bool adv100M)
{
u32 ipcnfg, eeer;

ipcnfg = rd32(IGC_IPCNFG);
eeer = rd32(IGC_EEER);

/* enable or disable per user setting */
if (hw->dev_spec._base.eee_enable) {
u32 eee_su = rd32(IGC_EEE_SU);

if (adv100M)
ipcnfg |= IGC_IPCNFG_EEE_100M_AN;
else
ipcnfg &= ~IGC_IPCNFG_EEE_100M_AN;

if (adv1G)
ipcnfg |= IGC_IPCNFG_EEE_1G_AN;
else
ipcnfg &= ~IGC_IPCNFG_EEE_1G_AN;

if (adv2p5G)
ipcnfg |= IGC_IPCNFG_EEE_2_5G_AN;
else
ipcnfg &= ~IGC_IPCNFG_EEE_2_5G_AN;

eeer |= (IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
IGC_EEER_LPI_FC);

/* This bit should not be set in normal operation. */
if (eee_su & IGC_EEE_SU_LPI_CLK_STP)
hw_dbg("LPI Clock Stop Bit should not be set!\n");
} else {
ipcnfg &= ~(IGC_IPCNFG_EEE_2_5G_AN | IGC_IPCNFG_EEE_1G_AN |
IGC_IPCNFG_EEE_100M_AN);
eeer &= ~(IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
IGC_EEER_LPI_FC);
}
wr32(IGC_IPCNFG, ipcnfg);
wr32(IGC_EEER, eeer);
rd32(IGC_IPCNFG);
rd32(IGC_EEER);

return IGC_SUCCESS;
}

/* igc_set_ltr_i225 - Set Latency Tolerance Reporting thresholds
* @hw: pointer to the HW structure
* @link: bool indicating link status
*
* Set the LTR thresholds based on the link speed (Mbps), EEE, and DMAC
* settings, otherwise specify that there is no LTR requirement.
*/
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
{
u32 tw_system, ltrc, ltrv, ltr_min, ltr_max, scale_min, scale_max;
u16 speed, duplex;
s32 size;

/* If we do not have link, LTR thresholds are zero. */
if (link) {
hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);

/* Check if using copper interface with EEE enabled or if the
* link speed is 10 Mbps.
*/
if (hw->dev_spec._base.eee_enable &&
speed != SPEED_10) {
/* EEE enabled, so send LTRMAX threshold. */
ltrc = rd32(IGC_LTRC) |
IGC_LTRC_EEEMS_EN;
wr32(IGC_LTRC, ltrc);

/* Calculate tw_system (nsec). */
if (speed == SPEED_100) {
tw_system = ((rd32(IGC_EEE_SU) &
IGC_TW_SYSTEM_100_MASK) >>
IGC_TW_SYSTEM_100_SHIFT) * 500;
} else {
tw_system = (rd32(IGC_EEE_SU) &
IGC_TW_SYSTEM_1000_MASK) * 500;
}
} else {
tw_system = 0;
}

/* Get the Rx packet buffer size. */
size = rd32(IGC_RXPBS) &
IGC_RXPBS_SIZE_I225_MASK;

/* Calculations vary based on DMAC settings. */
if (rd32(IGC_DMACR) & IGC_DMACR_DMAC_EN) {
size -= (rd32(IGC_DMACR) &
IGC_DMACR_DMACTHR_MASK) >>
IGC_DMACR_DMACTHR_SHIFT;
/* Convert size to bits. */
size *= 1024 * 8;
} else {
/* Convert size to bytes, subtract the MTU, and then
* convert the size to bits.
*/
size *= 1024;
size *= 8;
}

if (size < 0) {
hw_dbg("Invalid effective Rx buffer size %d\n",
size);
return -IGC_ERR_CONFIG;
}

/* Calculate the thresholds. Since speed is in Mbps, simplify
* the calculation by multiplying size/speed by 1000 for result
* to be in nsec before dividing by the scale in nsec. Set the
* scale such that the LTR threshold fits in the register.
*/
ltr_min = (1000 * size) / speed;
ltr_max = ltr_min + tw_system;
scale_min = (ltr_min / 1024) < 1024 ? IGC_LTRMINV_SCALE_1024 :
IGC_LTRMINV_SCALE_32768;
scale_max = (ltr_max / 1024) < 1024 ? IGC_LTRMAXV_SCALE_1024 :
IGC_LTRMAXV_SCALE_32768;
ltr_min /= scale_min == IGC_LTRMINV_SCALE_1024 ? 1024 : 32768;
ltr_min -= 1;
ltr_max /= scale_max == IGC_LTRMAXV_SCALE_1024 ? 1024 : 32768;
ltr_max -= 1;

/* Only write the LTR thresholds if they differ from before. */
ltrv = rd32(IGC_LTRMINV);
if (ltr_min != (ltrv & IGC_LTRMINV_LTRV_MASK)) {
ltrv = IGC_LTRMINV_LSNP_REQ | ltr_min |
(scale_min << IGC_LTRMINV_SCALE_SHIFT);
wr32(IGC_LTRMINV, ltrv);
}

ltrv = rd32(IGC_LTRMAXV);
if (ltr_max != (ltrv & IGC_LTRMAXV_LTRV_MASK)) {
ltrv = IGC_LTRMAXV_LSNP_REQ | ltr_max |
(scale_min << IGC_LTRMAXV_SCALE_SHIFT);
wr32(IGC_LTRMAXV, ltrv);
}
}

return IGC_SUCCESS;
}
3 changes: 3 additions & 0 deletions drivers/net/ethernet/intel/igc/igc_i225.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ void igc_release_swfw_sync_i225(struct igc_hw *hw, u16 mask);

s32 igc_init_nvm_params_i225(struct igc_hw *hw);
bool igc_get_flash_presence_i225(struct igc_hw *hw);
s32 igc_set_eee_i225(struct igc_hw *hw, bool adv2p5G, bool adv1G,
bool adv100M);
s32 igc_set_ltr_i225(struct igc_hw *hw, bool link);

#endif
Loading

0 comments on commit e25974a

Please sign in to comment.