Commit 6015a6c1 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue

Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2015-09-22

This series contains updates to e1000, e1000e, igbvf, ixgbe, ixgbevf and
fm10k.

Jacob provides several updates for fm10k, which cleans up comments and
most notably a fix for a corner case issue with the PF/VF mailbox code.
The issue being fm10k_mbx_reset_work clears various states about the
mailbox, but does not clear the Tx FIFO head/tail pointers.  We also
are not able to simply clear these pointers, as we would drop
untransmitted messages without error.  Also adds support for extra debug
statistics, which provides the ability to see what the PF thinks the
VF mailboxes look like.

Don adds support for SFP+ in X550 and support for SCTP flow director
filters SCTP mask.

Francois Romieu dusts off the e1000 driver and removes some dead calls
to e1000_init_eeprom_params().

Toshiaki Makita provides three patches to enable TSO for stacked VLAN's
on e1000e, igbvf and ixgbevf.

Mark provides the first of several ixgbe updates.  First updates the
driver to accept SFP not present error for all devices, since an SFP
can still be inserted.  Adds support for SFP insertion interrupt on
X550EM devices with SPFs.  Adds I2C combined operations on X550EM
(not X550) devices.  Moved the setting of lan_id to before any I2C
eeprom access.  Lastly, set the bit bang mode in the hardware when
performing bit banding I2C operations on X550.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 16cfbae1 25b10297
...@@ -3900,10 +3900,6 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, ...@@ -3900,10 +3900,6 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
return E1000_SUCCESS; return E1000_SUCCESS;
} }
/* If eeprom is not yet detected, do so now */
if (eeprom->word_size == 0)
e1000_init_eeprom_params(hw);
/* A check for invalid values: offset too large, too many words, and /* A check for invalid values: offset too large, too many words, and
* not enough words. * not enough words.
*/ */
...@@ -4074,10 +4070,6 @@ static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, ...@@ -4074,10 +4070,6 @@ static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
return E1000_SUCCESS; return E1000_SUCCESS;
} }
/* If eeprom is not yet detected, do so now */
if (eeprom->word_size == 0)
e1000_init_eeprom_params(hw);
/* A check for invalid values: offset too large, too many words, and /* A check for invalid values: offset too large, too many words, and
* not enough words. * not enough words.
*/ */
......
...@@ -6952,6 +6952,7 @@ static const struct net_device_ops e1000e_netdev_ops = { ...@@ -6952,6 +6952,7 @@ static const struct net_device_ops e1000e_netdev_ops = {
#endif #endif
.ndo_set_features = e1000_set_features, .ndo_set_features = e1000_set_features,
.ndo_fix_features = e1000_fix_features, .ndo_fix_features = e1000_fix_features,
.ndo_features_check = passthru_features_check,
}; };
/** /**
......
...@@ -101,12 +101,19 @@ struct fm10k_tx_queue_stats { ...@@ -101,12 +101,19 @@ struct fm10k_tx_queue_stats {
u64 csum_err; u64 csum_err;
u64 tx_busy; u64 tx_busy;
u64 tx_done_old; u64 tx_done_old;
u64 csum_good;
}; };
struct fm10k_rx_queue_stats { struct fm10k_rx_queue_stats {
u64 alloc_failed; u64 alloc_failed;
u64 csum_err; u64 csum_err;
u64 errors; u64 errors;
u64 csum_good;
u64 switch_errors;
u64 drops;
u64 pp_errors;
u64 link_errors;
u64 length_errors;
}; };
struct fm10k_ring { struct fm10k_ring {
...@@ -251,6 +258,7 @@ struct fm10k_intfc { ...@@ -251,6 +258,7 @@ struct fm10k_intfc {
#define FM10K_FLAG_RSS_FIELD_IPV6_UDP (u32)(1 << 2) #define FM10K_FLAG_RSS_FIELD_IPV6_UDP (u32)(1 << 2)
#define FM10K_FLAG_RX_TS_ENABLED (u32)(1 << 3) #define FM10K_FLAG_RX_TS_ENABLED (u32)(1 << 3)
#define FM10K_FLAG_SWPRI_CONFIG (u32)(1 << 4) #define FM10K_FLAG_SWPRI_CONFIG (u32)(1 << 4)
#define FM10K_FLAG_DEBUG_STATS (u32)(1 << 5)
int xcast_mode; int xcast_mode;
/* Tx fast path data */ /* Tx fast path data */
...@@ -277,6 +285,17 @@ struct fm10k_intfc { ...@@ -277,6 +285,17 @@ struct fm10k_intfc {
u64 rx_drops_nic; u64 rx_drops_nic;
u64 rx_overrun_pf; u64 rx_overrun_pf;
u64 rx_overrun_vf; u64 rx_overrun_vf;
/* Debug Statistics */
u64 hw_sm_mbx_full;
u64 hw_csum_tx_good;
u64 hw_csum_rx_good;
u64 rx_switch_errors;
u64 rx_drops;
u64 rx_pp_errors;
u64 rx_link_errors;
u64 rx_length_errors;
u32 tx_timeout_count; u32 tx_timeout_count;
/* RX */ /* RX */
......
...@@ -76,19 +76,22 @@ static const struct fm10k_stats fm10k_gstrings_global_stats[] = { ...@@ -76,19 +76,22 @@ static const struct fm10k_stats fm10k_gstrings_global_stats[] = {
FM10K_STAT("mac_rules_used", hw.swapi.mac.used), FM10K_STAT("mac_rules_used", hw.swapi.mac.used),
FM10K_STAT("mac_rules_avail", hw.swapi.mac.avail), FM10K_STAT("mac_rules_avail", hw.swapi.mac.avail),
FM10K_STAT("mbx_tx_busy", hw.mbx.tx_busy),
FM10K_STAT("mbx_tx_oversized", hw.mbx.tx_dropped),
FM10K_STAT("mbx_tx_messages", hw.mbx.tx_messages),
FM10K_STAT("mbx_tx_dwords", hw.mbx.tx_dwords),
FM10K_STAT("mbx_rx_messages", hw.mbx.rx_messages),
FM10K_STAT("mbx_rx_dwords", hw.mbx.rx_dwords),
FM10K_STAT("mbx_rx_parse_err", hw.mbx.rx_parse_err),
FM10K_STAT("tx_hang_count", tx_timeout_count), FM10K_STAT("tx_hang_count", tx_timeout_count),
FM10K_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), FM10K_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
}; };
static const struct fm10k_stats fm10k_gstrings_debug_stats[] = {
FM10K_STAT("hw_sm_mbx_full", hw_sm_mbx_full),
FM10K_STAT("hw_csum_tx_good", hw_csum_tx_good),
FM10K_STAT("hw_csum_rx_good", hw_csum_rx_good),
FM10K_STAT("rx_switch_errors", rx_switch_errors),
FM10K_STAT("rx_drops", rx_drops),
FM10K_STAT("rx_pp_errors", rx_pp_errors),
FM10K_STAT("rx_link_errors", rx_link_errors),
FM10K_STAT("rx_length_errors", rx_length_errors),
};
static const struct fm10k_stats fm10k_gstrings_pf_stats[] = { static const struct fm10k_stats fm10k_gstrings_pf_stats[] = {
FM10K_STAT("timeout", stats.timeout.count), FM10K_STAT("timeout", stats.timeout.count),
FM10K_STAT("ur", stats.ur.count), FM10K_STAT("ur", stats.ur.count),
...@@ -100,14 +103,33 @@ static const struct fm10k_stats fm10k_gstrings_pf_stats[] = { ...@@ -100,14 +103,33 @@ static const struct fm10k_stats fm10k_gstrings_pf_stats[] = {
FM10K_STAT("nodesc_drop", stats.nodesc_drop.count), FM10K_STAT("nodesc_drop", stats.nodesc_drop.count),
}; };
#define FM10K_MBX_STAT(_name, _stat) { \
.stat_string = _name, \
.sizeof_stat = FIELD_SIZEOF(struct fm10k_mbx_info, _stat), \
.stat_offset = offsetof(struct fm10k_mbx_info, _stat) \
}
static const struct fm10k_stats fm10k_gstrings_mbx_stats[] = {
FM10K_MBX_STAT("mbx_tx_busy", tx_busy),
FM10K_MBX_STAT("mbx_tx_oversized", tx_dropped),
FM10K_MBX_STAT("mbx_tx_messages", tx_messages),
FM10K_MBX_STAT("mbx_tx_dwords", tx_dwords),
FM10K_MBX_STAT("mbx_rx_messages", rx_messages),
FM10K_MBX_STAT("mbx_rx_dwords", rx_dwords),
FM10K_MBX_STAT("mbx_rx_parse_err", rx_parse_err),
};
#define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats) #define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats)
#define FM10K_DEBUG_STATS_LEN ARRAY_SIZE(fm10k_gstrings_debug_stats)
#define FM10K_PF_STATS_LEN ARRAY_SIZE(fm10k_gstrings_pf_stats) #define FM10K_PF_STATS_LEN ARRAY_SIZE(fm10k_gstrings_pf_stats)
#define FM10K_MBX_STATS_LEN ARRAY_SIZE(fm10k_gstrings_mbx_stats)
#define FM10K_QUEUE_STATS_LEN(_n) \ #define FM10K_QUEUE_STATS_LEN(_n) \
( (_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64))) ( (_n) * 2 * (sizeof(struct fm10k_queue_stats) / sizeof(u64)))
#define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \ #define FM10K_STATIC_STATS_LEN (FM10K_GLOBAL_STATS_LEN + \
FM10K_NETDEV_STATS_LEN) FM10K_NETDEV_STATS_LEN + \
FM10K_MBX_STATS_LEN)
static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = { static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = {
"Mailbox test (on/offline)" "Mailbox test (on/offline)"
...@@ -120,29 +142,49 @@ enum fm10k_self_test_types { ...@@ -120,29 +142,49 @@ enum fm10k_self_test_types {
FM10K_TEST_MAX = FM10K_TEST_LEN FM10K_TEST_MAX = FM10K_TEST_LEN
}; };
static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data) enum {
FM10K_PRV_FLAG_DEBUG_STATS,
FM10K_PRV_FLAG_LEN,
};
static const char fm10k_prv_flags[FM10K_PRV_FLAG_LEN][ETH_GSTRING_LEN] = {
"debug-statistics",
};
static void fm10k_get_stat_strings(struct net_device *dev, u8 *data)
{ {
struct fm10k_intfc *interface = netdev_priv(dev); struct fm10k_intfc *interface = netdev_priv(dev);
struct fm10k_iov_data *iov_data = interface->iov_data;
char *p = (char *)data; char *p = (char *)data;
unsigned int i; unsigned int i;
unsigned int j;
switch (stringset) {
case ETH_SS_TEST:
memcpy(data, *fm10k_gstrings_test,
FM10K_TEST_LEN * ETH_GSTRING_LEN);
break;
case ETH_SS_STATS:
for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) { for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_net_stats[i].stat_string, memcpy(p, fm10k_gstrings_net_stats[i].stat_string,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) { for (i = 0; i < FM10K_GLOBAL_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_global_stats[i].stat_string, memcpy(p, fm10k_gstrings_global_stats[i].stat_string,
ETH_GSTRING_LEN); ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
if (interface->flags & FM10K_FLAG_DEBUG_STATS) {
for (i = 0; i < FM10K_DEBUG_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_debug_stats[i].stat_string,
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
}
for (i = 0; i < FM10K_MBX_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_mbx_stats[i].stat_string,
ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
if (interface->hw.mac.type != fm10k_mac_vf) { if (interface->hw.mac.type != fm10k_mac_vf) {
for (i = 0; i < FM10K_PF_STATS_LEN; i++) { for (i = 0; i < FM10K_PF_STATS_LEN; i++) {
memcpy(p, fm10k_gstrings_pf_stats[i].stat_string, memcpy(p, fm10k_gstrings_pf_stats[i].stat_string,
...@@ -151,6 +193,18 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data) ...@@ -151,6 +193,18 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data)
} }
} }
if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) {
for (i = 0; i < iov_data->num_vfs; i++) {
for (j = 0; j < FM10K_MBX_STATS_LEN; j++) {
snprintf(p,
ETH_GSTRING_LEN,
"vf_%u_%s", i,
fm10k_gstrings_mbx_stats[j].stat_string);
p += ETH_GSTRING_LEN;
}
}
}
for (i = 0; i < interface->hw.mac.max_queues; i++) { for (i = 0; i < interface->hw.mac.max_queues; i++) {
sprintf(p, "tx_queue_%u_packets", i); sprintf(p, "tx_queue_%u_packets", i);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
...@@ -161,6 +215,24 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data) ...@@ -161,6 +215,24 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data)
sprintf(p, "rx_queue_%u_bytes", i); sprintf(p, "rx_queue_%u_bytes", i);
p += ETH_GSTRING_LEN; p += ETH_GSTRING_LEN;
} }
}
static void fm10k_get_strings(struct net_device *dev,
u32 stringset, u8 *data)
{
char *p = (char *)data;
switch (stringset) {
case ETH_SS_TEST:
memcpy(data, *fm10k_gstrings_test,
FM10K_TEST_LEN * ETH_GSTRING_LEN);
break;
case ETH_SS_STATS:
fm10k_get_stat_strings(dev, data);
break;
case ETH_SS_PRIV_FLAGS:
memcpy(p, fm10k_prv_flags,
FM10K_PRV_FLAG_LEN * ETH_GSTRING_LEN);
break; break;
} }
} }
...@@ -168,6 +240,7 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data) ...@@ -168,6 +240,7 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, u8 *data)
static int fm10k_get_sset_count(struct net_device *dev, int sset) static int fm10k_get_sset_count(struct net_device *dev, int sset)
{ {
struct fm10k_intfc *interface = netdev_priv(dev); struct fm10k_intfc *interface = netdev_priv(dev);
struct fm10k_iov_data *iov_data = interface->iov_data;
struct fm10k_hw *hw = &interface->hw; struct fm10k_hw *hw = &interface->hw;
int stats_len = FM10K_STATIC_STATS_LEN; int stats_len = FM10K_STATIC_STATS_LEN;
...@@ -180,7 +253,16 @@ static int fm10k_get_sset_count(struct net_device *dev, int sset) ...@@ -180,7 +253,16 @@ static int fm10k_get_sset_count(struct net_device *dev, int sset)
if (hw->mac.type != fm10k_mac_vf) if (hw->mac.type != fm10k_mac_vf)
stats_len += FM10K_PF_STATS_LEN; stats_len += FM10K_PF_STATS_LEN;
if (interface->flags & FM10K_FLAG_DEBUG_STATS) {
stats_len += FM10K_DEBUG_STATS_LEN;
if (iov_data)
stats_len += FM10K_MBX_STATS_LEN * iov_data->num_vfs;
}
return stats_len; return stats_len;
case ETH_SS_PRIV_FLAGS:
return FM10K_PRV_FLAG_LEN;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -192,6 +274,7 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev, ...@@ -192,6 +274,7 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev,
{ {
const int stat_count = sizeof(struct fm10k_queue_stats) / sizeof(u64); const int stat_count = sizeof(struct fm10k_queue_stats) / sizeof(u64);
struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_intfc *interface = netdev_priv(netdev);
struct fm10k_iov_data *iov_data = interface->iov_data;
struct net_device_stats *net_stats = &netdev->stats; struct net_device_stats *net_stats = &netdev->stats;
char *p; char *p;
int i, j; int i, j;
...@@ -211,13 +294,47 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev, ...@@ -211,13 +294,47 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev,
sizeof(u64)) ? *(u64 *)p : *(u32 *)p; sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
} }
if (interface->hw.mac.type != fm10k_mac_vf) if (interface->flags & FM10K_FLAG_DEBUG_STATS) {
for (i = 0; i < FM10K_DEBUG_STATS_LEN; i++) {
p = (char *)interface + fm10k_gstrings_debug_stats[i].stat_offset;
*(data++) = (fm10k_gstrings_debug_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
}
for (i = 0; i < FM10K_MBX_STATS_LEN; i++) {
p = (char *)&interface->hw.mbx + fm10k_gstrings_mbx_stats[i].stat_offset;
*(data++) = (fm10k_gstrings_mbx_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
if (interface->hw.mac.type != fm10k_mac_vf) {
for (i = 0; i < FM10K_PF_STATS_LEN; i++) { for (i = 0; i < FM10K_PF_STATS_LEN; i++) {
p = (char *)interface + p = (char *)interface +
fm10k_gstrings_pf_stats[i].stat_offset; fm10k_gstrings_pf_stats[i].stat_offset;
*(data++) = (fm10k_gstrings_pf_stats[i].sizeof_stat == *(data++) = (fm10k_gstrings_pf_stats[i].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p; sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
} }
}
if ((interface->flags & FM10K_FLAG_DEBUG_STATS) && iov_data) {
for (i = 0; i < iov_data->num_vfs; i++) {
struct fm10k_vf_info *vf_info;
vf_info = &iov_data->vf_info[i];
/* skip stats if we don't have a vf info */
if (!vf_info) {
data += FM10K_MBX_STATS_LEN;
continue;
}
for (j = 0; j < FM10K_MBX_STATS_LEN; j++) {
p = (char *)&vf_info->mbx + fm10k_gstrings_mbx_stats[j].stat_offset;
*(data++) = (fm10k_gstrings_mbx_stats[j].sizeof_stat ==
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
}
}
for (i = 0; i < interface->hw.mac.max_queues; i++) { for (i = 0; i < interface->hw.mac.max_queues; i++) {
struct fm10k_ring *ring; struct fm10k_ring *ring;
...@@ -881,6 +998,33 @@ static void fm10k_self_test(struct net_device *dev, ...@@ -881,6 +998,33 @@ static void fm10k_self_test(struct net_device *dev,
eth_test->flags |= ETH_TEST_FL_FAILED; eth_test->flags |= ETH_TEST_FL_FAILED;
} }
static u32 fm10k_get_priv_flags(struct net_device *netdev)
{
struct fm10k_intfc *interface = netdev_priv(netdev);
u32 priv_flags = 0;
if (interface->flags & FM10K_FLAG_DEBUG_STATS)
priv_flags |= 1 << FM10K_PRV_FLAG_DEBUG_STATS;
return priv_flags;
}
static int fm10k_set_priv_flags(struct net_device *netdev, u32 priv_flags)
{
struct fm10k_intfc *interface = netdev_priv(netdev);
if (priv_flags >= (1 << FM10K_PRV_FLAG_LEN))
return -EINVAL;
if (priv_flags & (1 << FM10K_PRV_FLAG_DEBUG_STATS))
interface->flags |= FM10K_FLAG_DEBUG_STATS;
else
interface->flags &= ~FM10K_FLAG_DEBUG_STATS;
return 0;
}
static u32 fm10k_get_reta_size(struct net_device __always_unused *netdev) static u32 fm10k_get_reta_size(struct net_device __always_unused *netdev)
{ {
return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG; return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG;
...@@ -1094,6 +1238,8 @@ static const struct ethtool_ops fm10k_ethtool_ops = { ...@@ -1094,6 +1238,8 @@ static const struct ethtool_ops fm10k_ethtool_ops = {
.get_regs = fm10k_get_regs, .get_regs = fm10k_get_regs,
.get_regs_len = fm10k_get_regs_len, .get_regs_len = fm10k_get_regs_len,
.self_test = fm10k_self_test, .self_test = fm10k_self_test,
.get_priv_flags = fm10k_get_priv_flags,
.set_priv_flags = fm10k_set_priv_flags,
.get_rxfh_indir_size = fm10k_get_reta_size, .get_rxfh_indir_size = fm10k_get_reta_size,
.get_rxfh_key_size = fm10k_get_rssrk_size, .get_rxfh_key_size = fm10k_get_rssrk_size,
.get_rxfh = fm10k_get_rssh, .get_rxfh = fm10k_get_rssh,
......
...@@ -137,8 +137,11 @@ s32 fm10k_iov_mbx(struct fm10k_intfc *interface) ...@@ -137,8 +137,11 @@ s32 fm10k_iov_mbx(struct fm10k_intfc *interface)
} }
/* guarantee we have free space in the SM mailbox */ /* guarantee we have free space in the SM mailbox */
if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) {
/* keep track of how many times this occurs */
interface->hw_sm_mbx_full++;
break; break;
}
/* cleanup mailbox and process received messages */ /* cleanup mailbox and process received messages */
mbx->ops.process(hw, mbx); mbx->ops.process(hw, mbx);
......
...@@ -398,6 +398,8 @@ static inline void fm10k_rx_checksum(struct fm10k_ring *ring, ...@@ -398,6 +398,8 @@ static inline void fm10k_rx_checksum(struct fm10k_ring *ring,
return; return;
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
ring->rx_stats.csum_good++;
} }
#define FM10K_RSS_L4_TYPES_MASK \ #define FM10K_RSS_L4_TYPES_MASK \
...@@ -556,6 +558,18 @@ static bool fm10k_cleanup_headers(struct fm10k_ring *rx_ring, ...@@ -556,6 +558,18 @@ static bool fm10k_cleanup_headers(struct fm10k_ring *rx_ring,
{ {
if (unlikely((fm10k_test_staterr(rx_desc, if (unlikely((fm10k_test_staterr(rx_desc,
FM10K_RXD_STATUS_RXE)))) { FM10K_RXD_STATUS_RXE)))) {
#define FM10K_TEST_RXD_BIT(rxd, bit) \
((rxd)->w.csum_err & cpu_to_le16(bit))
if (FM10K_TEST_RXD_BIT(rx_desc, FM10K_RXD_ERR_SWITCH_ERROR))
rx_ring->rx_stats.switch_errors++;
if (FM10K_TEST_RXD_BIT(rx_desc, FM10K_RXD_ERR_NO_DESCRIPTOR))
rx_ring->rx_stats.drops++;
if (FM10K_TEST_RXD_BIT(rx_desc, FM10K_RXD_ERR_PP_ERROR))
rx_ring->rx_stats.pp_errors++;
if (FM10K_TEST_RXD_BIT(rx_desc, FM10K_RXD_ERR_SWITCH_READY))
rx_ring->rx_stats.link_errors++;
if (FM10K_TEST_RXD_BIT(rx_desc, FM10K_RXD_ERR_TOO_BIG))
rx_ring->rx_stats.length_errors++;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
rx_ring->rx_stats.errors++; rx_ring->rx_stats.errors++;
return true; return true;
...@@ -881,6 +895,7 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring, ...@@ -881,6 +895,7 @@ static void fm10k_tx_csum(struct fm10k_ring *tx_ring,
/* update TX checksum flag */ /* update TX checksum flag */
first->tx_flags |= FM10K_TX_FLAGS_CSUM; first->tx_flags |= FM10K_TX_FLAGS_CSUM;
tx_ring->tx_stats.csum_good++;
no_csum: no_csum:
/* populate Tx descriptor header size and mss */ /* populate Tx descriptor header size and mss */
......
...@@ -129,8 +129,8 @@ static u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo) ...@@ -129,8 +129,8 @@ static u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo)
* fm10k_fifo_drop_all - Drop all messages in FIFO * fm10k_fifo_drop_all - Drop all messages in FIFO
* @fifo: pointer to FIFO * @fifo: pointer to FIFO
* *
* This function resets the head pointer to drop all messages in the FIFO, * This function resets the head pointer to drop all messages in the FIFO and
* and ensure the FIFO is empty. * ensure the FIFO is empty.
**/ **/
static void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo) static void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
{ {
...@@ -898,6 +898,27 @@ static void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx) ...@@ -898,6 +898,27 @@ static void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC); mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
} }
/**
* fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mailbox header
* @mbx: pointer to mailbox
*
* This function creates a fake disconnect header for loading into remote
* mailbox header. The primary purpose is to prevent errors on immediate
* start up after mbx->connect.
**/
static void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
{
u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
mbx->mbx_lock |= FM10K_MBX_ACK;
/* load header to memory to be written */
mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
}
/** /**
* fm10k_mbx_create_error_msg - Generate a error message * fm10k_mbx_create_error_msg - Generate a error message
* @mbx: pointer to mailbox * @mbx: pointer to mailbox
...@@ -1046,9 +1067,26 @@ static s32 fm10k_mbx_create_reply(struct fm10k_hw *hw, ...@@ -1046,9 +1067,26 @@ static s32 fm10k_mbx_create_reply(struct fm10k_hw *hw,
**/ **/
static void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx) static void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx)
{ {
u16 len, head, ack;
/* reset our outgoing max size back to Rx limits */ /* reset our outgoing max size back to Rx limits */
mbx->max_size = mbx->rx.size - 1; mbx->max_size = mbx->rx.size - 1;
/* update mbx->pulled to account for tail_len and ack */
head = FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, HEAD);
ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
mbx->pulled += mbx->tail_len - ack;
/* now drop any messages which have started or finished transmitting */
while (fm10k_fifo_head_len(&mbx->tx) && mbx->pulled) {
len = fm10k_fifo_head_drop(&mbx->tx);
mbx->tx_dropped++;
if (mbx->pulled >= len)
mbx->pulled -= len;
else
mbx->pulled = 0;
}
/* just do a quick resysnc to start of message */ /* just do a quick resysnc to start of message */
mbx->pushed = 0; mbx->pushed = 0;
mbx->pulled = 0; mbx->pulled = 0;
...@@ -1418,8 +1456,10 @@ static s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx) ...@@ -1418,8 +1456,10 @@ static s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
/* Place mbx in ready to connect state */ /* Place mbx in ready to connect state */
mbx->state = FM10K_STATE_CONNECT; mbx->state = FM10K_STATE_CONNECT;
fm10k_mbx_reset_work(mbx);
/* initialize header of remote mailbox */ /* initialize header of remote mailbox */
fm10k_mbx_create_disconnect_hdr(mbx); fm10k_mbx_create_fake_disconnect_hdr(mbx);
fm10k_write_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr); fm10k_write_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr);
/* enable interrupt and notify other party of new message */ /* enable interrupt and notify other party of new message */
...@@ -1725,7 +1765,7 @@ static void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw, ...@@ -1725,7 +1765,7 @@ static void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw,
mbx->state = FM10K_STATE_CLOSED; mbx->state = FM10K_STATE_CLOSED;
mbx->remote = 0; mbx->remote = 0;
fm10k_mbx_reset_work(mbx); fm10k_mbx_reset_work(mbx);
fm10k_mbx_update_max_size(mbx, 0); fm10k_fifo_drop_all(&mbx->tx);
fm10k_write_reg(hw, mbx->mbmem_reg, 0); fm10k_write_reg(hw, mbx->mbmem_reg, 0);
} }
......
...@@ -274,8 +274,6 @@ static void fm10k_watchdog_update_host_state(struct fm10k_intfc *interface) ...@@ -274,8 +274,6 @@ static void fm10k_watchdog_update_host_state(struct fm10k_intfc *interface)
* @interface: board private structure * @interface: board private structure
* *
* This function will process both the upstream and downstream mailboxes. * This function will process both the upstream and downstream mailboxes.
* It is necessary for us to hold the rtnl_lock while doing this as the
* mailbox accesses are protected by this lock.
**/ **/
static void fm10k_mbx_subtask(struct fm10k_intfc *interface) static void fm10k_mbx_subtask(struct fm10k_intfc *interface)
{ {
...@@ -330,6 +328,9 @@ void fm10k_update_stats(struct fm10k_intfc *interface) ...@@ -330,6 +328,9 @@ void fm10k_update_stats(struct fm10k_intfc *interface)
{ {
struct net_device_stats *net_stats = &interface->netdev->stats; struct net_device_stats *net_stats = &interface->netdev->stats;
struct fm10k_hw *hw = &interface->hw; struct fm10k_hw *hw = &interface->hw;
u64 hw_csum_tx_good = 0, hw_csum_rx_good = 0, rx_length_errors = 0;
u64 rx_switch_errors = 0, rx_drops = 0, rx_pp_errors = 0;
u64 rx_link_errors = 0;
u64 rx_errors = 0, rx_csum_errors = 0, tx_csum_errors = 0; u64 rx_errors = 0, rx_csum_errors = 0, tx_csum_errors = 0;
u64 restart_queue = 0, tx_busy = 0, alloc_failed = 0; u64 restart_queue = 0, tx_busy = 0, alloc_failed = 0;
u64 rx_bytes_nic = 0, rx_pkts_nic = 0, rx_drops_nic = 0; u64 rx_bytes_nic = 0, rx_pkts_nic = 0, rx_drops_nic = 0;
...@@ -349,6 +350,7 @@ void fm10k_update_stats(struct fm10k_intfc *interface) ...@@ -349,6 +350,7 @@ void fm10k_update_stats(struct fm10k_intfc *interface)
tx_csum_errors += tx_ring->tx_stats.csum_err; tx_csum_errors += tx_ring->tx_stats.csum_err;
bytes += tx_ring->stats.bytes; bytes += tx_ring->stats.bytes;
pkts += tx_ring->stats.packets; pkts += tx_ring->stats.packets;
hw_csum_tx_good += tx_ring->tx_stats.csum_good;
} }
interface->restart_queue = restart_queue; interface->restart_queue = restart_queue;
...@@ -356,6 +358,8 @@ void fm10k_update_stats(struct fm10k_intfc *interface) ...@@ -356,6 +358,8 @@ void fm10k_update_stats(struct fm10k_intfc *interface)
net_stats->tx_bytes = bytes; net_stats->tx_bytes = bytes;
net_stats->tx_packets = pkts; net_stats->tx_packets = pkts;
interface->tx_csum_errors = tx_csum_errors; interface->tx_csum_errors = tx_csum_errors;
interface->hw_csum_tx_good = hw_csum_tx_good;
/* gather some stats to the interface struct that are per queue */ /* gather some stats to the interface struct that are per queue */
for (bytes = 0, pkts = 0, i = 0; i < interface->num_rx_queues; i++) { for (bytes = 0, pkts = 0, i = 0; i < interface->num_rx_queues; i++) {
struct fm10k_ring *rx_ring = interface->rx_ring[i]; struct fm10k_ring *rx_ring = interface->rx_ring[i];
...@@ -365,12 +369,24 @@ void fm10k_update_stats(struct fm10k_intfc *interface) ...@@ -365,12 +369,24 @@ void fm10k_update_stats(struct fm10k_intfc *interface)
alloc_failed += rx_ring->rx_stats.alloc_failed; alloc_failed += rx_ring->rx_stats.alloc_failed;
rx_csum_errors += rx_ring->rx_stats.csum_err; rx_csum_errors += rx_ring->rx_stats.csum_err;
rx_errors += rx_ring->rx_stats.errors; rx_errors += rx_ring->rx_stats.errors;
hw_csum_rx_good += rx_ring->rx_stats.csum_good;
rx_switch_errors += rx_ring->rx_stats.switch_errors;
rx_drops += rx_ring->rx_stats.drops;
rx_pp_errors += rx_ring->rx_stats.pp_errors;
rx_link_errors += rx_ring->rx_stats.link_errors;
rx_length_errors += rx_ring->rx_stats.length_errors;
} }
net_stats->rx_bytes = bytes; net_stats->rx_bytes = bytes;
net_stats->rx_packets = pkts; net_stats->rx_packets = pkts;
interface->alloc_failed = alloc_failed; interface->alloc_failed = alloc_failed;
interface->rx_csum_errors = rx_csum_errors; interface->rx_csum_errors = rx_csum_errors;
interface->hw_csum_rx_good = hw_csum_rx_good;
interface->rx_switch_errors = rx_switch_errors;
interface->rx_drops = rx_drops;
interface->rx_pp_errors = rx_pp_errors;
interface->rx_link_errors = rx_link_errors;
interface->rx_length_errors = rx_length_errors;
hw->mac.ops.update_hw_stats(hw, &interface->stats); hw->mac.ops.update_hw_stats(hw, &interface->stats);
...@@ -498,7 +514,7 @@ static void fm10k_service_task(struct work_struct *work) ...@@ -498,7 +514,7 @@ static void fm10k_service_task(struct work_struct *work)
interface = container_of(work, struct fm10k_intfc, service_task); interface = container_of(work, struct fm10k_intfc, service_task);
/* tasks always capable of running, but must be rtnl protected */ /* tasks run even when interface is down */
fm10k_mbx_subtask(interface); fm10k_mbx_subtask(interface);
fm10k_detach_subtask(interface); fm10k_detach_subtask(interface);
fm10k_reset_subtask(interface); fm10k_reset_subtask(interface);
......
...@@ -762,6 +762,12 @@ enum fm10k_rxdesc_xc { ...@@ -762,6 +762,12 @@ enum fm10k_rxdesc_xc {
#define FM10K_RXD_STATUS_L4E 0x4000 /* L4 csum error */ #define FM10K_RXD_STATUS_L4E 0x4000 /* L4 csum error */
#define FM10K_RXD_STATUS_IPE 0x8000 /* IPv4 csum error */ #define FM10K_RXD_STATUS_IPE 0x8000 /* IPv4 csum error */
#define FM10K_RXD_ERR_SWITCH_ERROR 0x0001 /* Switch found bad packet */
#define FM10K_RXD_ERR_NO_DESCRIPTOR 0x0002 /* No descriptor available */
#define FM10K_RXD_ERR_PP_ERROR 0x0004 /* RAM error during processing */
#define FM10K_RXD_ERR_SWITCH_READY 0x0008 /* Link transition mid-packet */
#define FM10K_RXD_ERR_TOO_BIG 0x0010 /* Pkt too big for single buf */
struct fm10k_ftag { struct fm10k_ftag {
__be16 swpri_type_user; __be16 swpri_type_user;
__be16 vlan; __be16 vlan;
......
...@@ -2615,6 +2615,7 @@ static const struct net_device_ops igbvf_netdev_ops = { ...@@ -2615,6 +2615,7 @@ static const struct net_device_ops igbvf_netdev_ops = {
.ndo_poll_controller = igbvf_netpoll, .ndo_poll_controller = igbvf_netpoll,
#endif #endif
.ndo_set_features = igbvf_set_features, .ndo_set_features = igbvf_set_features,
.ndo_features_check = passthru_features_check,
}; };
/** /**
......
...@@ -1766,6 +1766,16 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw, ...@@ -1766,6 +1766,16 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw,
IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, ~fdirtcpm); IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, ~fdirtcpm);
IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, ~fdirtcpm); IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, ~fdirtcpm);
/* also use it for SCTP */
switch (hw->mac.type) {
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, ~fdirtcpm);
break;
default:
break;
}
/* store source and destination IP masks (big-enian) */ /* store source and destination IP masks (big-enian) */
IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIP4M, IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIP4M,
~input_mask->formatted.src_ip[0]); ~input_mask->formatted.src_ip[0]);
......
...@@ -2631,6 +2631,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues, ...@@ -2631,6 +2631,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues,
case ixgbe_mac_X540: case ixgbe_mac_X540:
case ixgbe_mac_X550: case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x: case ixgbe_mac_X550EM_x:
if (adapter->hw.device_id == IXGBE_DEV_ID_X550EM_X_SFP)
mask |= IXGBE_EIMS_GPI_SDP0(&adapter->hw);
if (adapter->hw.phy.type == ixgbe_phy_x550em_ext_t) if (adapter->hw.phy.type == ixgbe_phy_x550em_ext_t)
mask |= IXGBE_EICR_GPI_SDP0_X540; mask |= IXGBE_EICR_GPI_SDP0_X540;
mask |= IXGBE_EIMS_ECC; mask |= IXGBE_EIMS_ECC;
...@@ -4904,9 +4906,15 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter) ...@@ -4904,9 +4906,15 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
gpie |= IXGBE_SDP1_GPIEN(hw); gpie |= IXGBE_SDP1_GPIEN(hw);
if (hw->mac.type == ixgbe_mac_82599EB) { switch (hw->mac.type) {
gpie |= IXGBE_SDP1_GPIEN_8259X; case ixgbe_mac_82599EB:
gpie |= IXGBE_SDP2_GPIEN_8259X; gpie |= IXGBE_SDP1_GPIEN_8259X | IXGBE_SDP2_GPIEN_8259X;
break;
case ixgbe_mac_X550EM_x:
gpie |= IXGBE_SDP0_GPIEN_X540;
break;
default:
break;
} }
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
...@@ -8704,8 +8712,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -8704,8 +8712,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->phy.reset_if_overtemp = true; hw->phy.reset_if_overtemp = true;
err = hw->mac.ops.reset_hw(hw); err = hw->mac.ops.reset_hw(hw);
hw->phy.reset_if_overtemp = false; hw->phy.reset_if_overtemp = false;
if (err == IXGBE_ERR_SFP_NOT_PRESENT && if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
hw->mac.type == ixgbe_mac_82598EB) {
err = 0; err = 0;
} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
e_dev_err("failed to load because an unsupported SFP+ or QSFP module type was detected.\n"); e_dev_err("failed to load because an unsupported SFP+ or QSFP module type was detected.\n");
......
...@@ -100,16 +100,17 @@ static u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2) ...@@ -100,16 +100,17 @@ static u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2)
} }
/** /**
* ixgbe_read_i2c_combined_generic - Perform I2C read combined operation * ixgbe_read_i2c_combined_generic_int - Perform I2C read combined operation
* @hw: pointer to the hardware structure * @hw: pointer to the hardware structure
* @addr: I2C bus address to read from * @addr: I2C bus address to read from
* @reg: I2C device register to read from * @reg: I2C device register to read from
* @val: pointer to location to receive read value * @val: pointer to location to receive read value
* @lock: true if to take and release semaphore
* *
* Returns an error code on error. * Returns an error code on error.
**/ */
s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, static s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr,
u16 reg, u16 *val) u16 reg, u16 *val, bool lock)
{ {
u32 swfw_mask = hw->phy.phy_semaphore_mask; u32 swfw_mask = hw->phy.phy_semaphore_mask;
int max_retry = 10; int max_retry = 10;
...@@ -124,7 +125,7 @@ s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, ...@@ -124,7 +125,7 @@ s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF);
csum = ~csum; csum = ~csum;
do { do {
if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
return IXGBE_ERR_SWFW_SYNC; return IXGBE_ERR_SWFW_SYNC;
ixgbe_i2c_start(hw); ixgbe_i2c_start(hw);
/* Device Address and write indication */ /* Device Address and write indication */
...@@ -157,12 +158,14 @@ s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, ...@@ -157,12 +158,14 @@ s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
if (ixgbe_clock_out_i2c_bit(hw, false)) if (ixgbe_clock_out_i2c_bit(hw, false))
goto fail; goto fail;
ixgbe_i2c_stop(hw); ixgbe_i2c_stop(hw);
if (lock)
hw->mac.ops.release_swfw_sync(hw, swfw_mask); hw->mac.ops.release_swfw_sync(hw, swfw_mask);
*val = (high_bits << 8) | low_bits; *val = (high_bits << 8) | low_bits;
return 0; return 0;
fail: fail:
ixgbe_i2c_bus_clear(hw); ixgbe_i2c_bus_clear(hw);
if (lock)
hw->mac.ops.release_swfw_sync(hw, swfw_mask); hw->mac.ops.release_swfw_sync(hw, swfw_mask);
retry++; retry++;
if (retry < max_retry) if (retry < max_retry)
...@@ -175,17 +178,49 @@ s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, ...@@ -175,17 +178,49 @@ s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
} }
/** /**
* ixgbe_write_i2c_combined_generic - Perform I2C write combined operation * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation
* @hw: pointer to the hardware structure
* @addr: I2C bus address to read from
* @reg: I2C device register to read from
* @val: pointer to location to receive read value
*
* Returns an error code on error.
*/
s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
u16 reg, u16 *val)
{
return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, true);
}
/**
* ixgbe_read_i2c_combined_generic_unlocked - Unlocked I2C read combined
* @hw: pointer to the hardware structure
* @addr: I2C bus address to read from
* @reg: I2C device register to read from
* @val: pointer to location to receive read value
*
* Returns an error code on error.
*/
s32 ixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr,
u16 reg, u16 *val)
{
return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, false);
}
/**
* ixgbe_write_i2c_combined_generic_int - Perform I2C write combined operation
* @hw: pointer to the hardware structure * @hw: pointer to the hardware structure
* @addr: I2C bus address to write to * @addr: I2C bus address to write to
* @reg: I2C device register to write to * @reg: I2C device register to write to
* @val: value to write * @val: value to write
* @lock: true if to take and release semaphore
* *
* Returns an error code on error. * Returns an error code on error.
**/ */
s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, static s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr,
u8 addr, u16 reg, u16 val) u16 reg, u16 val, bool lock)
{ {
u32 swfw_mask = hw->phy.phy_semaphore_mask;
int max_retry = 1; int max_retry = 1;
int retry = 0; int retry = 0;
u8 reg_high; u8 reg_high;
...@@ -197,6 +232,8 @@ s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, ...@@ -197,6 +232,8 @@ s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF); csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF);
csum = ~csum; csum = ~csum;
do { do {
if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
return IXGBE_ERR_SWFW_SYNC;
ixgbe_i2c_start(hw); ixgbe_i2c_start(hw);
/* Device Address and write indication */ /* Device Address and write indication */
if (ixgbe_out_i2c_byte_ack(hw, addr)) if (ixgbe_out_i2c_byte_ack(hw, addr))
...@@ -217,10 +254,14 @@ s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, ...@@ -217,10 +254,14 @@ s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
if (ixgbe_out_i2c_byte_ack(hw, csum)) if (ixgbe_out_i2c_byte_ack(hw, csum))
goto fail; goto fail;
ixgbe_i2c_stop(hw); ixgbe_i2c_stop(hw);
if (lock)
hw->mac.ops.release_swfw_sync(hw, swfw_mask);
return 0; return 0;
fail: fail:
ixgbe_i2c_bus_clear(hw); ixgbe_i2c_bus_clear(hw);
if (lock)
hw->mac.ops.release_swfw_sync(hw, swfw_mask);
retry++; retry++;
if (retry < max_retry) if (retry < max_retry)
hw_dbg(hw, "I2C byte write combined error - Retry.\n"); hw_dbg(hw, "I2C byte write combined error - Retry.\n");
...@@ -231,6 +272,36 @@ s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, ...@@ -231,6 +272,36 @@ s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
return IXGBE_ERR_I2C; return IXGBE_ERR_I2C;
} }
/**
* ixgbe_write_i2c_combined_generic - Perform I2C write combined operation
* @hw: pointer to the hardware structure
* @addr: I2C bus address to write to
* @reg: I2C device register to write to
* @val: value to write
*
* Returns an error code on error.
*/
s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw,
u8 addr, u16 reg, u16 val)
{
return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, true);
}
/**
* ixgbe_write_i2c_combined_generic_unlocked - Unlocked I2C write combined
* @hw: pointer to the hardware structure
* @addr: I2C bus address to write to
* @reg: I2C device register to write to
* @val: value to write
*
* Returns an error code on error.
*/
s32 ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw,
u8 addr, u16 reg, u16 val)
{
return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, false);
}
/** /**
* ixgbe_identify_phy_generic - Get physical layer module * ixgbe_identify_phy_generic - Get physical layer module
* @hw: pointer to hardware structure * @hw: pointer to hardware structure
...@@ -1100,6 +1171,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) ...@@ -1100,6 +1171,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
return IXGBE_ERR_SFP_NOT_PRESENT; return IXGBE_ERR_SFP_NOT_PRESENT;
} }
/* LAN ID is needed for sfp_type determination */
hw->mac.ops.set_lan_id(hw);
status = hw->phy.ops.read_i2c_eeprom(hw, status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_IDENTIFIER, IXGBE_SFF_IDENTIFIER,
&identifier); &identifier);
...@@ -1107,9 +1181,6 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) ...@@ -1107,9 +1181,6 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
if (status) if (status)
goto err_read_i2c_eeprom; goto err_read_i2c_eeprom;
/* LAN ID is needed for sfp_type determination */
hw->mac.ops.set_lan_id(hw);
if (identifier != IXGBE_SFF_IDENTIFIER_SFP) { if (identifier != IXGBE_SFF_IDENTIFIER_SFP) {
hw->phy.type = ixgbe_phy_sfp_unsupported; hw->phy.type = ixgbe_phy_sfp_unsupported;
return IXGBE_ERR_SFP_NOT_SUPPORTED; return IXGBE_ERR_SFP_NOT_SUPPORTED;
...@@ -1660,26 +1731,28 @@ s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, ...@@ -1660,26 +1731,28 @@ s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
} }
/** /**
* ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C * ixgbe_read_i2c_byte_generic_int - Reads 8 bit word over I2C
* @hw: pointer to hardware structure * @hw: pointer to hardware structure
* @byte_offset: byte offset to read * @byte_offset: byte offset to read
* @data: value read * @data: value read
* @lock: true if to take and release semaphore
* *
* Performs byte read operation to SFP module's EEPROM over I2C interface at * Performs byte read operation to SFP module's EEPROM over I2C interface at
* a specified device address. * a specified device address.
**/ */
s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, static s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data) u8 dev_addr, u8 *data, bool lock)
{ {
s32 status; s32 status;
u32 max_retry = 10; u32 max_retry = 10;
u32 retry = 0; u32 retry = 0;
u32 swfw_mask = hw->phy.phy_semaphore_mask; u32 swfw_mask = hw->phy.phy_semaphore_mask;
bool nack = true; bool nack = true;
*data = 0; *data = 0;
do { do {
if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
return IXGBE_ERR_SWFW_SYNC; return IXGBE_ERR_SWFW_SYNC;
ixgbe_i2c_start(hw); ixgbe_i2c_start(hw);
...@@ -1721,12 +1794,16 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, ...@@ -1721,12 +1794,16 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
goto fail; goto fail;
ixgbe_i2c_stop(hw); ixgbe_i2c_stop(hw);
break; if (lock)
hw->mac.ops.release_swfw_sync(hw, swfw_mask);
return 0;
fail: fail:
ixgbe_i2c_bus_clear(hw); ixgbe_i2c_bus_clear(hw);
if (lock) {
hw->mac.ops.release_swfw_sync(hw, swfw_mask); hw->mac.ops.release_swfw_sync(hw, swfw_mask);
msleep(100); msleep(100);
}
retry++; retry++;
if (retry < max_retry) if (retry < max_retry)
hw_dbg(hw, "I2C byte read error - Retrying.\n"); hw_dbg(hw, "I2C byte read error - Retrying.\n");
...@@ -1735,29 +1812,60 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, ...@@ -1735,29 +1812,60 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
} while (retry < max_retry); } while (retry < max_retry);
hw->mac.ops.release_swfw_sync(hw, swfw_mask);
return status; return status;
} }
/** /**
* ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to read
* @data: value read
*
* Performs byte read operation to SFP module's EEPROM over I2C interface at
* a specified device address.
*/
s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data)
{
return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
data, true);
}
/**
* ixgbe_read_i2c_byte_generic_unlocked - Reads 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to read
* @data: value read
*
* Performs byte read operation to SFP module's EEPROM over I2C interface at
* a specified device address.
*/
s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data)
{
return ixgbe_read_i2c_byte_generic_int(hw, byte_offset, dev_addr,
data, false);
}
/**
* ixgbe_write_i2c_byte_generic_int - Writes 8 bit word over I2C
* @hw: pointer to hardware structure * @hw: pointer to hardware structure
* @byte_offset: byte offset to write * @byte_offset: byte offset to write
* @data: value to write * @data: value to write
* @lock: true if to take and release semaphore
* *
* Performs byte write operation to SFP module's EEPROM over I2C interface at * Performs byte write operation to SFP module's EEPROM over I2C interface at
* a specified device address. * a specified device address.
**/ */
s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, static s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data) u8 dev_addr, u8 data, bool lock)
{ {
s32 status; s32 status;
u32 max_retry = 1; u32 max_retry = 1;
u32 retry = 0; u32 retry = 0;
u32 swfw_mask = hw->phy.phy_semaphore_mask; u32 swfw_mask = hw->phy.phy_semaphore_mask;
if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
return IXGBE_ERR_SWFW_SYNC; return IXGBE_ERR_SWFW_SYNC;
do { do {
...@@ -1788,7 +1896,9 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, ...@@ -1788,7 +1896,9 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
goto fail; goto fail;
ixgbe_i2c_stop(hw); ixgbe_i2c_stop(hw);
break; if (lock)
hw->mac.ops.release_swfw_sync(hw, swfw_mask);
return 0;
fail: fail:
ixgbe_i2c_bus_clear(hw); ixgbe_i2c_bus_clear(hw);
...@@ -1799,21 +1909,57 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, ...@@ -1799,21 +1909,57 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
hw_dbg(hw, "I2C byte write error.\n"); hw_dbg(hw, "I2C byte write error.\n");
} while (retry < max_retry); } while (retry < max_retry);
if (lock)
hw->mac.ops.release_swfw_sync(hw, swfw_mask); hw->mac.ops.release_swfw_sync(hw, swfw_mask);
return status; return status;
} }
/**
* ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to write
* @data: value to write
*
* Performs byte write operation to SFP module's EEPROM over I2C interface at
* a specified device address.
*/
s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data)
{
return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
data, true);
}
/**
* ixgbe_write_i2c_byte_generic_unlocked - Writes 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to write
* @data: value to write
*
* Performs byte write operation to SFP module's EEPROM over I2C interface at
* a specified device address.
*/
s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data)
{
return ixgbe_write_i2c_byte_generic_int(hw, byte_offset, dev_addr,
data, false);
}
/** /**
* ixgbe_i2c_start - Sets I2C start condition * ixgbe_i2c_start - Sets I2C start condition
* @hw: pointer to hardware structure * @hw: pointer to hardware structure
* *
* Sets I2C start condition (High -> Low on SDA while SCL is High) * Sets I2C start condition (High -> Low on SDA while SCL is High)
* Set bit-bang mode on X550 hardware.
**/ **/
static void ixgbe_i2c_start(struct ixgbe_hw *hw) static void ixgbe_i2c_start(struct ixgbe_hw *hw)
{ {
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
i2cctl |= IXGBE_I2C_BB_EN(hw);
/* Start condition must begin with data and clock high */ /* Start condition must begin with data and clock high */
ixgbe_set_i2c_data(hw, &i2cctl, 1); ixgbe_set_i2c_data(hw, &i2cctl, 1);
ixgbe_raise_i2c_clk(hw, &i2cctl); ixgbe_raise_i2c_clk(hw, &i2cctl);
...@@ -1838,10 +1984,15 @@ static void ixgbe_i2c_start(struct ixgbe_hw *hw) ...@@ -1838,10 +1984,15 @@ static void ixgbe_i2c_start(struct ixgbe_hw *hw)
* @hw: pointer to hardware structure * @hw: pointer to hardware structure
* *
* Sets I2C stop condition (Low -> High on SDA while SCL is High) * Sets I2C stop condition (Low -> High on SDA while SCL is High)
* Disables bit-bang mode and negates data output enable on X550
* hardware.
**/ **/
static void ixgbe_i2c_stop(struct ixgbe_hw *hw) static void ixgbe_i2c_stop(struct ixgbe_hw *hw)
{ {
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN(hw);
u32 bb_en_bit = IXGBE_I2C_BB_EN(hw);
/* Stop condition must begin with data low and clock high */ /* Stop condition must begin with data low and clock high */
ixgbe_set_i2c_data(hw, &i2cctl, 0); ixgbe_set_i2c_data(hw, &i2cctl, 0);
...@@ -1854,6 +2005,13 @@ static void ixgbe_i2c_stop(struct ixgbe_hw *hw) ...@@ -1854,6 +2005,13 @@ static void ixgbe_i2c_stop(struct ixgbe_hw *hw)
/* bus free time between stop and start (4.7us)*/ /* bus free time between stop and start (4.7us)*/
udelay(IXGBE_I2C_T_BUF); udelay(IXGBE_I2C_T_BUF);
if (bb_en_bit || data_oe_bit || clk_oe_bit) {
i2cctl &= ~bb_en_bit;
i2cctl |= data_oe_bit | clk_oe_bit;
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
IXGBE_WRITE_FLUSH(hw);
}
} }
/** /**
...@@ -1901,6 +2059,7 @@ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) ...@@ -1901,6 +2059,7 @@ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
/* Release SDA line (set high) */ /* Release SDA line (set high) */
i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
i2cctl |= IXGBE_I2C_DATA_OUT(hw); i2cctl |= IXGBE_I2C_DATA_OUT(hw);
i2cctl |= IXGBE_I2C_DATA_OE_N_EN(hw);
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl); IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
IXGBE_WRITE_FLUSH(hw); IXGBE_WRITE_FLUSH(hw);
...@@ -1915,15 +2074,21 @@ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data) ...@@ -1915,15 +2074,21 @@ static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
**/ **/
static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
{ {
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
s32 status = 0; s32 status = 0;
u32 i = 0; u32 i = 0;
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
u32 timeout = 10; u32 timeout = 10;
bool ack = true; bool ack = true;
if (data_oe_bit) {
i2cctl |= IXGBE_I2C_DATA_OUT(hw);
i2cctl |= data_oe_bit;
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
IXGBE_WRITE_FLUSH(hw);
}
ixgbe_raise_i2c_clk(hw, &i2cctl); ixgbe_raise_i2c_clk(hw, &i2cctl);
/* Minimum high period of clock is 4us */ /* Minimum high period of clock is 4us */
udelay(IXGBE_I2C_T_HIGH); udelay(IXGBE_I2C_T_HIGH);
...@@ -1961,7 +2126,14 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) ...@@ -1961,7 +2126,14 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
{ {
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
if (data_oe_bit) {
i2cctl |= IXGBE_I2C_DATA_OUT(hw);
i2cctl |= data_oe_bit;
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
IXGBE_WRITE_FLUSH(hw);
}
ixgbe_raise_i2c_clk(hw, &i2cctl); ixgbe_raise_i2c_clk(hw, &i2cctl);
/* Minimum high period of clock is 4us */ /* Minimum high period of clock is 4us */
...@@ -2016,13 +2188,20 @@ static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) ...@@ -2016,13 +2188,20 @@ static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
* @i2cctl: Current value of I2CCTL register * @i2cctl: Current value of I2CCTL register
* *
* Raises the I2C clock line '0'->'1' * Raises the I2C clock line '0'->'1'
* Negates the I2C clock output enable on X550 hardware.
**/ **/
static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
{ {
u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN(hw);
u32 i = 0; u32 i = 0;
u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT; u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT;
u32 i2cctl_r = 0; u32 i2cctl_r = 0;
if (clk_oe_bit) {
*i2cctl |= clk_oe_bit;
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
}
for (i = 0; i < timeout; i++) { for (i = 0; i < timeout; i++) {
*i2cctl |= IXGBE_I2C_CLK_OUT(hw); *i2cctl |= IXGBE_I2C_CLK_OUT(hw);
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
...@@ -2042,11 +2221,13 @@ static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) ...@@ -2042,11 +2221,13 @@ static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
* @i2cctl: Current value of I2CCTL register * @i2cctl: Current value of I2CCTL register
* *
* Lowers the I2C clock line '1'->'0' * Lowers the I2C clock line '1'->'0'
* Asserts the I2C clock output enable on X550 hardware.
**/ **/
static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
{ {
*i2cctl &= ~IXGBE_I2C_CLK_OUT(hw); *i2cctl &= ~IXGBE_I2C_CLK_OUT(hw);
*i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN(hw);
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw); IXGBE_WRITE_FLUSH(hw);
...@@ -2062,13 +2243,17 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) ...@@ -2062,13 +2243,17 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
* @data: I2C data value (0 or 1) to set * @data: I2C data value (0 or 1) to set
* *
* Sets the I2C data bit * Sets the I2C data bit
* Asserts the I2C data output enable on X550 hardware.
**/ **/
static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
{ {
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
if (data) if (data)
*i2cctl |= IXGBE_I2C_DATA_OUT(hw); *i2cctl |= IXGBE_I2C_DATA_OUT(hw);
else else
*i2cctl &= ~IXGBE_I2C_DATA_OUT(hw); *i2cctl &= ~IXGBE_I2C_DATA_OUT(hw);
*i2cctl &= ~data_oe_bit;
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl); IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw); IXGBE_WRITE_FLUSH(hw);
...@@ -2076,6 +2261,14 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) ...@@ -2076,6 +2261,14 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
/* Data rise/fall (1000ns/300ns) and set-up time (250ns) */ /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA); udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
if (!data) /* Can't verify data in this case */
return 0;
if (data_oe_bit) {
*i2cctl |= data_oe_bit;
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw);
}
/* Verify data was set correctly */ /* Verify data was set correctly */
*i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
if (data != ixgbe_get_i2c_data(hw, i2cctl)) { if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
...@@ -2092,9 +2285,19 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) ...@@ -2092,9 +2285,19 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
* @i2cctl: Current value of I2CCTL register * @i2cctl: Current value of I2CCTL register
* *
* Returns the I2C data bit value * Returns the I2C data bit value
* Negates the I2C data output enable on X550 hardware.
**/ **/
static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl) static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
{ {
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN(hw);
if (data_oe_bit) {
*i2cctl |= data_oe_bit;
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), *i2cctl);
IXGBE_WRITE_FLUSH(hw);
udelay(IXGBE_I2C_T_FALL);
}
if (*i2cctl & IXGBE_I2C_DATA_IN(hw)) if (*i2cctl & IXGBE_I2C_DATA_IN(hw))
return true; return true;
return false; return false;
...@@ -2109,10 +2312,11 @@ static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl) ...@@ -2109,10 +2312,11 @@ static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl)
**/ **/
static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
{ {
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw)); u32 i2cctl;
u32 i; u32 i;
ixgbe_i2c_start(hw); ixgbe_i2c_start(hw);
i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
ixgbe_set_i2c_data(hw, &i2cctl, 1); ixgbe_set_i2c_data(hw, &i2cctl, 1);
......
...@@ -154,8 +154,12 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, ...@@ -154,8 +154,12 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw); s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw);
s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data); u8 dev_addr, u8 *data);
s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data);
s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data); u8 dev_addr, u8 data);
s32 ixgbe_write_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 data);
s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 *eeprom_data); u8 *eeprom_data);
s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset,
...@@ -164,6 +168,10 @@ s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, ...@@ -164,6 +168,10 @@ s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 eeprom_data); u8 eeprom_data);
s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
u16 reg, u16 *val); u16 reg, u16 *val);
s32 ixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr,
u16 reg, u16 *val);
s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr,
u16 reg, u16 val); u16 reg, u16 val);
s32 ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr,
u16 reg, u16 val);
#endif /* _IXGBE_PHY_H_ */ #endif /* _IXGBE_PHY_H_ */
...@@ -402,6 +402,7 @@ struct ixgbe_thermal_sensor_data { ...@@ -402,6 +402,7 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_FDIRSIP4M 0x0EE40 #define IXGBE_FDIRSIP4M 0x0EE40
#define IXGBE_FDIRTCPM 0x0EE44 #define IXGBE_FDIRTCPM 0x0EE44
#define IXGBE_FDIRUDPM 0x0EE48 #define IXGBE_FDIRUDPM 0x0EE48
#define IXGBE_FDIRSCTPM 0x0EE78
#define IXGBE_FDIRIP6M 0x0EE74 #define IXGBE_FDIRIP6M 0x0EE74
#define IXGBE_FDIRM 0x0EE70 #define IXGBE_FDIRM 0x0EE70
...@@ -3328,6 +3329,10 @@ struct ixgbe_phy_operations { ...@@ -3328,6 +3329,10 @@ struct ixgbe_phy_operations {
s32 (*set_phy_power)(struct ixgbe_hw *, bool on); s32 (*set_phy_power)(struct ixgbe_hw *, bool on);
s32 (*enter_lplu)(struct ixgbe_hw *); s32 (*enter_lplu)(struct ixgbe_hw *);
s32 (*handle_lasi)(struct ixgbe_hw *hw); s32 (*handle_lasi)(struct ixgbe_hw *hw);
s32 (*read_i2c_combined_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg,
u16 *value);
s32 (*write_i2c_combined_unlocked)(struct ixgbe_hw *, u8 addr, u16 reg,
u16 value);
}; };
struct ixgbe_eeprom_info { struct ixgbe_eeprom_info {
......
...@@ -2039,14 +2039,17 @@ static struct ixgbe_phy_operations phy_ops_X550 = { ...@@ -2039,14 +2039,17 @@ static struct ixgbe_phy_operations phy_ops_X550 = {
X550_COMMON_PHY X550_COMMON_PHY
.init = NULL, .init = NULL,
.identify = &ixgbe_identify_phy_generic, .identify = &ixgbe_identify_phy_generic,
.read_i2c_combined = &ixgbe_read_i2c_combined_generic,
.write_i2c_combined = &ixgbe_write_i2c_combined_generic,
}; };
static struct ixgbe_phy_operations phy_ops_X550EM_x = { static struct ixgbe_phy_operations phy_ops_X550EM_x = {
X550_COMMON_PHY X550_COMMON_PHY
.init = &ixgbe_init_phy_ops_X550em, .init = &ixgbe_init_phy_ops_X550em,
.identify = &ixgbe_identify_phy_x550em, .identify = &ixgbe_identify_phy_x550em,
.read_i2c_combined = &ixgbe_read_i2c_combined_generic,
.write_i2c_combined = &ixgbe_write_i2c_combined_generic,
.read_i2c_combined_unlocked = &ixgbe_read_i2c_combined_generic_unlocked,
.write_i2c_combined_unlocked =
&ixgbe_write_i2c_combined_generic_unlocked,
}; };
static const u32 ixgbe_mvals_X550[IXGBE_MVALS_IDX_LIMIT] = { static const u32 ixgbe_mvals_X550[IXGBE_MVALS_IDX_LIMIT] = {
......
...@@ -3896,6 +3896,7 @@ static const struct net_device_ops ixgbevf_netdev_ops = { ...@@ -3896,6 +3896,7 @@ static const struct net_device_ops ixgbevf_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ixgbevf_netpoll, .ndo_poll_controller = ixgbevf_netpoll,
#endif #endif
.ndo_features_check = passthru_features_check,
}; };
static void ixgbevf_assign_netdev_ops(struct net_device *dev) static void ixgbevf_assign_netdev_ops(struct net_device *dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment