mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
Tony Nguyen says: ==================== Intel Wired LAN Driver Updates 2026-07-01 (igc, igb) Kohei Enju adds ethtool support for get/set hash key on igc and adds setting of skb hash type based on values from Rx descriptor on igb. Takashi Kozu adds ethtool support for get/set hash key on igb. Faizal adds support for forcing link speed via ethtool when autonegotiation is disabled on the igc driver. * '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue: igc: add support for forcing link speed without autonegotiation igc: replace goto out with direct returns in igc_config_fc_after_link_up() igc: move autoneg-enabled settings into igc_handle_autoneg_enabled() igc: remove unused autoneg_failed field igb: set skb hash type from RSS_TYPE igb: allow configuring RSS key via ethtool set_rxfh igb: expose RSS key via ethtool get_rxfh igb: prepare for RSS key get/set support igc: allow configuring RSS key via ethtool set_rxfh igc: expose RSS key via ethtool get_rxfh igc: prepare for RSS key get/set support ==================== Link: https://patch.msgid.link/20260701210303.1745310-1-anthony.l.nguyen@intel.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
08030ddb87
|
|
@ -87,6 +87,27 @@ union e1000_adv_rx_desc {
|
|||
} wb; /* writeback */
|
||||
};
|
||||
|
||||
#define E1000_RSS_TYPE_NO_HASH 0
|
||||
#define E1000_RSS_TYPE_HASH_TCP_IPV4 1
|
||||
#define E1000_RSS_TYPE_HASH_IPV4 2
|
||||
#define E1000_RSS_TYPE_HASH_TCP_IPV6 3
|
||||
#define E1000_RSS_TYPE_HASH_IPV6_EX 4
|
||||
#define E1000_RSS_TYPE_HASH_IPV6 5
|
||||
#define E1000_RSS_TYPE_HASH_TCP_IPV6_EX 6
|
||||
#define E1000_RSS_TYPE_HASH_UDP_IPV4 7
|
||||
#define E1000_RSS_TYPE_HASH_UDP_IPV6 8
|
||||
#define E1000_RSS_TYPE_HASH_UDP_IPV6_EX 9
|
||||
|
||||
#define E1000_RSS_TYPE_MASK GENMASK(3, 0)
|
||||
|
||||
#define E1000_RSS_L4_TYPES_MASK \
|
||||
(BIT(E1000_RSS_TYPE_HASH_TCP_IPV4) | \
|
||||
BIT(E1000_RSS_TYPE_HASH_TCP_IPV6) | \
|
||||
BIT(E1000_RSS_TYPE_HASH_TCP_IPV6_EX) | \
|
||||
BIT(E1000_RSS_TYPE_HASH_UDP_IPV4) | \
|
||||
BIT(E1000_RSS_TYPE_HASH_UDP_IPV6) | \
|
||||
BIT(E1000_RSS_TYPE_HASH_UDP_IPV6_EX))
|
||||
|
||||
#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0
|
||||
#define E1000_RXDADV_HDRBUFLEN_SHIFT 5
|
||||
#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */
|
||||
|
|
|
|||
|
|
@ -495,6 +495,7 @@ struct hwmon_buff {
|
|||
#define IGB_N_PEROUT 2
|
||||
#define IGB_N_SDP 4
|
||||
#define IGB_RETA_SIZE 128
|
||||
#define IGB_RSS_KEY_SIZE 40
|
||||
|
||||
enum igb_filter_match_flags {
|
||||
IGB_FILTER_FLAG_ETHER_TYPE = 0x1,
|
||||
|
|
@ -655,6 +656,7 @@ struct igb_adapter {
|
|||
struct i2c_client *i2c_client;
|
||||
u32 rss_indir_tbl_init;
|
||||
u8 rss_indir_tbl[IGB_RETA_SIZE];
|
||||
u8 rss_key[IGB_RSS_KEY_SIZE];
|
||||
|
||||
unsigned long link_check_timeout;
|
||||
int copper_tries;
|
||||
|
|
@ -735,6 +737,7 @@ void igb_down(struct igb_adapter *);
|
|||
void igb_reinit_locked(struct igb_adapter *);
|
||||
void igb_reset(struct igb_adapter *);
|
||||
int igb_reinit_queues(struct igb_adapter *);
|
||||
void igb_write_rss_key(struct igb_adapter *adapter);
|
||||
void igb_write_rss_indir_tbl(struct igb_adapter *);
|
||||
int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
|
||||
int igb_setup_tx_resources(struct igb_ring *);
|
||||
|
|
|
|||
|
|
@ -3019,6 +3019,27 @@ static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_write_rss_key - Program the RSS key into device registers
|
||||
* @adapter: board private structure
|
||||
*
|
||||
* Write the RSS key stored in adapter->rss_key to the E1000 hardware registers.
|
||||
* Each 32-bit chunk of the key is read using get_unaligned_le32() and written
|
||||
* to the appropriate register.
|
||||
*/
|
||||
void igb_write_rss_key(struct igb_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
for (int i = 0; i < IGB_RSS_KEY_SIZE / 4; i++) {
|
||||
u32 val = get_unaligned_le32(&adapter->rss_key[i * 4]);
|
||||
|
||||
wr32(E1000_RSSRK(i), val);
|
||||
}
|
||||
}
|
||||
|
||||
static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata)
|
||||
{
|
||||
struct igb_adapter *adapter = netdev_priv(netdev);
|
||||
|
|
@ -3276,10 +3297,12 @@ static int igb_get_rxfh(struct net_device *netdev,
|
|||
int i;
|
||||
|
||||
rxfh->hfunc = ETH_RSS_HASH_TOP;
|
||||
if (!rxfh->indir)
|
||||
return 0;
|
||||
for (i = 0; i < IGB_RETA_SIZE; i++)
|
||||
rxfh->indir[i] = adapter->rss_indir_tbl[i];
|
||||
if (rxfh->indir)
|
||||
for (i = 0; i < IGB_RETA_SIZE; i++)
|
||||
rxfh->indir[i] = adapter->rss_indir_tbl[i];
|
||||
|
||||
if (rxfh->key)
|
||||
memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3319,6 +3342,11 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
|
|||
}
|
||||
}
|
||||
|
||||
static u32 igb_get_rxfh_key_size(struct net_device *netdev)
|
||||
{
|
||||
return IGB_RSS_KEY_SIZE;
|
||||
}
|
||||
|
||||
static int igb_set_rxfh(struct net_device *netdev,
|
||||
struct ethtool_rxfh_param *rxfh,
|
||||
struct netlink_ext_ack *extack)
|
||||
|
|
@ -3329,35 +3357,39 @@ static int igb_set_rxfh(struct net_device *netdev,
|
|||
u32 num_queues;
|
||||
|
||||
/* We do not allow change in unsupported parameters */
|
||||
if (rxfh->key ||
|
||||
(rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
|
||||
rxfh->hfunc != ETH_RSS_HASH_TOP))
|
||||
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
|
||||
rxfh->hfunc != ETH_RSS_HASH_TOP)
|
||||
return -EOPNOTSUPP;
|
||||
if (!rxfh->indir)
|
||||
return 0;
|
||||
|
||||
num_queues = adapter->rss_queues;
|
||||
if (rxfh->indir) {
|
||||
num_queues = adapter->rss_queues;
|
||||
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82576:
|
||||
/* 82576 supports 2 RSS queues for SR-IOV */
|
||||
if (adapter->vfs_allocated_count)
|
||||
num_queues = 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82576:
|
||||
/* 82576 supports 2 RSS queues for SR-IOV */
|
||||
if (adapter->vfs_allocated_count)
|
||||
num_queues = 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Verify user input. */
|
||||
for (i = 0; i < IGB_RETA_SIZE; i++)
|
||||
if (rxfh->indir[i] >= num_queues)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
for (i = 0; i < IGB_RETA_SIZE; i++)
|
||||
adapter->rss_indir_tbl[i] = rxfh->indir[i];
|
||||
|
||||
igb_write_rss_indir_tbl(adapter);
|
||||
}
|
||||
|
||||
/* Verify user input. */
|
||||
for (i = 0; i < IGB_RETA_SIZE; i++)
|
||||
if (rxfh->indir[i] >= num_queues)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
for (i = 0; i < IGB_RETA_SIZE; i++)
|
||||
adapter->rss_indir_tbl[i] = rxfh->indir[i];
|
||||
|
||||
igb_write_rss_indir_tbl(adapter);
|
||||
if (rxfh->key) {
|
||||
memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
|
||||
igb_write_rss_key(adapter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3483,6 +3515,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
|
|||
.get_module_eeprom = igb_get_module_eeprom,
|
||||
.get_rxfh_indir_size = igb_get_rxfh_indir_size,
|
||||
.get_rxfh = igb_get_rxfh,
|
||||
.get_rxfh_key_size = igb_get_rxfh_key_size,
|
||||
.set_rxfh = igb_set_rxfh,
|
||||
.get_rxfh_fields = igb_get_rxfh_fields,
|
||||
.set_rxfh_fields = igb_set_rxfh_fields,
|
||||
|
|
|
|||
|
|
@ -4048,6 +4048,9 @@ static int igb_sw_init(struct igb_adapter *adapter)
|
|||
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
|
||||
|
||||
/* init RSS key */
|
||||
netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
|
||||
|
||||
/* set default ring sizes */
|
||||
adapter->tx_ring_count = IGB_DEFAULT_TXD;
|
||||
adapter->rx_ring_count = IGB_DEFAULT_RXD;
|
||||
|
|
@ -4522,11 +4525,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
|
|||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 mrqc, rxcsum;
|
||||
u32 j, num_rx_queues;
|
||||
u32 rss_key[10];
|
||||
|
||||
netdev_rss_key_fill(rss_key, sizeof(rss_key));
|
||||
for (j = 0; j < 10; j++)
|
||||
wr32(E1000_RSSRK(j), rss_key[j]);
|
||||
igb_write_rss_key(adapter);
|
||||
|
||||
num_rx_queues = adapter->rss_queues;
|
||||
|
||||
|
|
@ -8820,10 +8820,19 @@ static inline void igb_rx_hash(struct igb_ring *ring,
|
|||
union e1000_adv_rx_desc *rx_desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (ring->netdev->features & NETIF_F_RXHASH)
|
||||
skb_set_hash(skb,
|
||||
le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
|
||||
PKT_HASH_TYPE_L3);
|
||||
u16 rss_type;
|
||||
|
||||
if (!(ring->netdev->features & NETIF_F_RXHASH))
|
||||
return;
|
||||
|
||||
rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.pkt_info) &
|
||||
E1000_RSS_TYPE_MASK;
|
||||
if (!rss_type)
|
||||
return;
|
||||
|
||||
skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
|
||||
(E1000_RSS_L4_TYPES_MASK & BIT(rss_type)) ?
|
||||
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ void igc_ethtool_set_ops(struct net_device *);
|
|||
|
||||
#define MAX_ETYPE_FILTER 8
|
||||
#define IGC_RETA_SIZE 128
|
||||
#define IGC_RSS_KEY_SIZE 40
|
||||
|
||||
/* SDP support */
|
||||
#define IGC_N_EXTTS 2
|
||||
|
|
@ -302,6 +303,7 @@ struct igc_adapter {
|
|||
unsigned int nfc_rule_count;
|
||||
|
||||
u8 rss_indir_tbl[IGC_RETA_SIZE];
|
||||
u8 rss_key[IGC_RSS_KEY_SIZE];
|
||||
|
||||
unsigned long link_check_timeout;
|
||||
struct igc_info ei;
|
||||
|
|
@ -361,6 +363,7 @@ unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
|
|||
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
|
||||
const u32 max_rss_queues);
|
||||
int igc_reinit_queues(struct igc_adapter *adapter);
|
||||
void igc_write_rss_key(struct igc_adapter *adapter);
|
||||
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
|
||||
bool igc_has_link(struct igc_adapter *adapter);
|
||||
void igc_reset(struct igc_adapter *adapter);
|
||||
|
|
|
|||
|
|
@ -114,11 +114,35 @@ static s32 igc_setup_copper_link_base(struct igc_hw *hw)
|
|||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_CTRL);
|
||||
ctrl |= IGC_CTRL_SLU;
|
||||
ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX);
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
ctrl &= ~(IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX |
|
||||
IGC_CTRL_SPEED_MASK | IGC_CTRL_FD);
|
||||
|
||||
ret_val = igc_setup_copper_link(hw);
|
||||
if (hw->mac.autoneg_enabled) {
|
||||
ctrl |= IGC_CTRL_SLU;
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
ret_val = igc_setup_copper_link(hw);
|
||||
} else {
|
||||
ctrl |= IGC_CTRL_SLU | IGC_CTRL_FRCSPD | IGC_CTRL_FRCDPX;
|
||||
|
||||
switch (hw->mac.forced_speed_duplex) {
|
||||
case IGC_FORCED_10H:
|
||||
ctrl |= IGC_CTRL_SPEED_10;
|
||||
break;
|
||||
case IGC_FORCED_10F:
|
||||
ctrl |= IGC_CTRL_SPEED_10 | IGC_CTRL_FD;
|
||||
break;
|
||||
case IGC_FORCED_100H:
|
||||
ctrl |= IGC_CTRL_SPEED_100;
|
||||
break;
|
||||
case IGC_FORCED_100F:
|
||||
ctrl |= IGC_CTRL_SPEED_100 | IGC_CTRL_FD;
|
||||
break;
|
||||
default:
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
wr32(IGC_CTRL, ctrl);
|
||||
ret_val = igc_setup_copper_link(hw);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
|
@ -443,6 +467,7 @@ static const struct igc_phy_operations igc_phy_ops_base = {
|
|||
.reset = igc_phy_hw_reset,
|
||||
.read_reg = igc_read_phy_reg_gpy,
|
||||
.write_reg = igc_write_phy_reg_gpy,
|
||||
.force_speed_duplex = igc_force_speed_duplex,
|
||||
};
|
||||
|
||||
const struct igc_info igc_base_info = {
|
||||
|
|
|
|||
|
|
@ -129,10 +129,13 @@
|
|||
#define IGC_ERR_SWFW_SYNC 13
|
||||
|
||||
/* Device Control */
|
||||
#define IGC_CTRL_FD BIT(0) /* Full Duplex */
|
||||
#define IGC_CTRL_RST 0x04000000 /* Global reset */
|
||||
|
||||
#define IGC_CTRL_PHY_RST 0x80000000 /* PHY Reset */
|
||||
#define IGC_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
|
||||
#define IGC_CTRL_SPEED_MASK GENMASK(10, 8)
|
||||
#define IGC_CTRL_SPEED_10 FIELD_PREP(IGC_CTRL_SPEED_MASK, 0)
|
||||
#define IGC_CTRL_SPEED_100 FIELD_PREP(IGC_CTRL_SPEED_MASK, 1)
|
||||
#define IGC_CTRL_FRCSPD 0x00000800 /* Force Speed */
|
||||
#define IGC_CTRL_FRCDPX 0x00001000 /* Force Duplex */
|
||||
#define IGC_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
|
||||
|
|
@ -673,6 +676,10 @@
|
|||
#define IGC_GEN_POLL_TIMEOUT 1920
|
||||
|
||||
/* PHY Control Register */
|
||||
#define MII_CR_SPEED_MASK (BIT(6) | BIT(13))
|
||||
#define MII_CR_SPEED_10 0x0000 /* SSM=0, SSL=0: 10 Mb/s */
|
||||
#define MII_CR_SPEED_100 BIT(13) /* SSM=0, SSL=1: 100 Mb/s */
|
||||
#define MII_CR_DUPLEX_EN BIT(8) /* 0 = Half Duplex, 1 = Full Duplex */
|
||||
#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 */
|
||||
|
|
|
|||
|
|
@ -1460,6 +1460,26 @@ static int igc_ethtool_set_rxnfc(struct net_device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_write_rss_key - Program the RSS key into device registers
|
||||
* @adapter: board private structure
|
||||
*
|
||||
* Write the RSS key stored in adapter->rss_key to the IGC_RSSRK registers.
|
||||
* Each 32-bit chunk of the key is read using get_unaligned_le32() and written
|
||||
* to the appropriate register.
|
||||
*/
|
||||
void igc_write_rss_key(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IGC_RSS_KEY_SIZE / 4; i++) {
|
||||
val = get_unaligned_le32(&adapter->rss_key[i * 4]);
|
||||
wr32(IGC_RSSRK(i), val);
|
||||
}
|
||||
}
|
||||
|
||||
void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
|
@ -1482,6 +1502,11 @@ void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
|
|||
}
|
||||
}
|
||||
|
||||
static u32 igc_ethtool_get_rxfh_key_size(struct net_device *netdev)
|
||||
{
|
||||
return IGC_RSS_KEY_SIZE;
|
||||
}
|
||||
|
||||
static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev)
|
||||
{
|
||||
return IGC_RETA_SIZE;
|
||||
|
|
@ -1494,10 +1519,13 @@ static int igc_ethtool_get_rxfh(struct net_device *netdev,
|
|||
int i;
|
||||
|
||||
rxfh->hfunc = ETH_RSS_HASH_TOP;
|
||||
if (!rxfh->indir)
|
||||
return 0;
|
||||
for (i = 0; i < IGC_RETA_SIZE; i++)
|
||||
rxfh->indir[i] = adapter->rss_indir_tbl[i];
|
||||
|
||||
if (rxfh->indir)
|
||||
for (i = 0; i < IGC_RETA_SIZE; i++)
|
||||
rxfh->indir[i] = adapter->rss_indir_tbl[i];
|
||||
|
||||
if (rxfh->key)
|
||||
memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1511,24 +1539,28 @@ static int igc_ethtool_set_rxfh(struct net_device *netdev,
|
|||
int i;
|
||||
|
||||
/* We do not allow change in unsupported parameters */
|
||||
if (rxfh->key ||
|
||||
(rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
|
||||
rxfh->hfunc != ETH_RSS_HASH_TOP))
|
||||
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
|
||||
rxfh->hfunc != ETH_RSS_HASH_TOP)
|
||||
return -EOPNOTSUPP;
|
||||
if (!rxfh->indir)
|
||||
return 0;
|
||||
|
||||
num_queues = adapter->rss_queues;
|
||||
if (rxfh->indir) {
|
||||
num_queues = adapter->rss_queues;
|
||||
|
||||
/* Verify user input. */
|
||||
for (i = 0; i < IGC_RETA_SIZE; i++)
|
||||
if (rxfh->indir[i] >= num_queues)
|
||||
return -EINVAL;
|
||||
/* Verify user input. */
|
||||
for (i = 0; i < IGC_RETA_SIZE; i++)
|
||||
if (rxfh->indir[i] >= num_queues)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < IGC_RETA_SIZE; i++)
|
||||
adapter->rss_indir_tbl[i] = rxfh->indir[i];
|
||||
for (i = 0; i < IGC_RETA_SIZE; i++)
|
||||
adapter->rss_indir_tbl[i] = rxfh->indir[i];
|
||||
|
||||
igc_write_rss_indir_tbl(adapter);
|
||||
igc_write_rss_indir_tbl(adapter);
|
||||
}
|
||||
|
||||
if (rxfh->key) {
|
||||
memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
|
||||
igc_write_rss_key(adapter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1914,44 +1946,58 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
|
|||
ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
|
||||
|
||||
/* advertising link modes */
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full);
|
||||
|
||||
/* set autoneg settings */
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
|
||||
if (hw->mac.autoneg_enabled) {
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
|
||||
cmd->base.autoneg = AUTONEG_ENABLE;
|
||||
|
||||
/* Set pause flow control settings */
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
|
||||
/* advertising link modes only apply when autoneg is on */
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
10baseT_Half);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
10baseT_Full);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
100baseT_Half);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
100baseT_Full);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
1000baseT_Full);
|
||||
if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
2500baseT_Full);
|
||||
|
||||
switch (hw->fc.requested_mode) {
|
||||
case igc_fc_full:
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Asym_Pause);
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Asym_Pause);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
/* Set pause flow control advertising */
|
||||
switch (hw->fc.requested_mode) {
|
||||
case igc_fc_full:
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Pause);
|
||||
break;
|
||||
case igc_fc_rx_pause:
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Pause);
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Asym_Pause);
|
||||
break;
|
||||
case igc_fc_tx_pause:
|
||||
ethtool_link_ksettings_add_link_mode(cmd, advertising,
|
||||
Asym_Pause);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cmd->base.autoneg = AUTONEG_DISABLE;
|
||||
}
|
||||
|
||||
/* Pause is always supported */
|
||||
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
|
||||
|
||||
status = pm_runtime_suspended(&adapter->pdev->dev) ?
|
||||
0 : rd32(IGC_STATUS);
|
||||
|
||||
|
|
@ -1983,7 +2029,6 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
|
|||
cmd->base.duplex = DUPLEX_UNKNOWN;
|
||||
}
|
||||
cmd->base.speed = speed;
|
||||
cmd->base.autoneg = AUTONEG_ENABLE;
|
||||
|
||||
/* MDI-X => 2; MDI =>1; Invalid =>0 */
|
||||
if (hw->phy.media_type == igc_media_type_copper)
|
||||
|
|
@ -2000,38 +2045,51 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
igc_ethtool_set_link_ksettings(struct net_device *netdev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
/**
|
||||
* igc_handle_autoneg_disabled - Configure forced speed/duplex settings
|
||||
* @adapter: private driver structure
|
||||
* @speed: requested speed (must be SPEED_10 or SPEED_100)
|
||||
* @duplex: requested duplex
|
||||
*
|
||||
* Records forced speed/duplex when autoneg is disabled.
|
||||
* Caller must validate speed before calling this function.
|
||||
*/
|
||||
static void igc_handle_autoneg_disabled(struct igc_adapter *adapter, u32 speed,
|
||||
u8 duplex)
|
||||
{
|
||||
struct igc_mac_info *mac = &adapter->hw.mac;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_10:
|
||||
mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ?
|
||||
IGC_FORCED_10F : IGC_FORCED_10H;
|
||||
break;
|
||||
case SPEED_100:
|
||||
mac->forced_speed_duplex = (duplex == DUPLEX_FULL) ?
|
||||
IGC_FORCED_100F : IGC_FORCED_100H;
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Unsupported speed %u\n", speed);
|
||||
return;
|
||||
}
|
||||
|
||||
mac->autoneg_enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_handle_autoneg_enabled - Configure autonegotiation advertisement
|
||||
* @adapter: private driver structure
|
||||
* @cmd: ethtool link ksettings from user
|
||||
*
|
||||
* Records advertised speeds and flow control settings when autoneg
|
||||
* is enabled.
|
||||
*/
|
||||
static void igc_handle_autoneg_enabled(struct igc_adapter *adapter,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct igc_adapter *adapter = netdev_priv(netdev);
|
||||
struct net_device *dev = adapter->netdev;
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u16 advertised = 0;
|
||||
|
||||
/* When adapter in resetting mode, autoneg/speed/duplex
|
||||
* cannot be changed
|
||||
*/
|
||||
if (igc_check_reset_block(hw)) {
|
||||
netdev_err(dev, "Cannot change link characteristics when reset is active\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* MDI setting is only allowed when autoneg enabled because
|
||||
* some hardware doesn't allow MDI setting when speed or
|
||||
* duplex is forced.
|
||||
*/
|
||||
if (cmd->base.eth_tp_mdix_ctrl) {
|
||||
if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&
|
||||
cmd->base.autoneg != AUTONEG_ENABLE) {
|
||||
netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
|
||||
2500baseT_Full))
|
||||
advertised |= ADVERTISE_2500_FULL;
|
||||
|
|
@ -2056,14 +2114,66 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
|
|||
10baseT_Half))
|
||||
advertised |= ADVERTISE_10_HALF;
|
||||
|
||||
if (cmd->base.autoneg == AUTONEG_ENABLE) {
|
||||
hw->phy.autoneg_advertised = advertised;
|
||||
if (adapter->fc_autoneg)
|
||||
hw->fc.requested_mode = igc_fc_default;
|
||||
} else {
|
||||
netdev_info(dev, "Force mode currently not supported\n");
|
||||
hw->mac.autoneg_enabled = true;
|
||||
hw->phy.autoneg_advertised = advertised;
|
||||
if (adapter->fc_autoneg)
|
||||
hw->fc.requested_mode = igc_fc_default;
|
||||
}
|
||||
|
||||
static int
|
||||
igc_ethtool_set_link_ksettings(struct net_device *netdev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct igc_adapter *adapter = netdev_priv(netdev);
|
||||
struct net_device *dev = adapter->netdev;
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
|
||||
/* When adapter in resetting mode, autoneg/speed/duplex
|
||||
* cannot be changed
|
||||
*/
|
||||
if (igc_check_reset_block(hw)) {
|
||||
netdev_err(dev, "Cannot change link characteristics when reset is active\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cmd->base.autoneg != AUTONEG_ENABLE &&
|
||||
cmd->base.autoneg != AUTONEG_DISABLE) {
|
||||
netdev_info(dev, "Unsupported autoneg setting\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* MDI setting is only allowed when autoneg enabled because
|
||||
* some hardware doesn't allow MDI setting when speed or
|
||||
* duplex is forced.
|
||||
*/
|
||||
if (cmd->base.eth_tp_mdix_ctrl) {
|
||||
if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO &&
|
||||
cmd->base.autoneg != AUTONEG_ENABLE) {
|
||||
netdev_err(dev, "Forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->base.autoneg == AUTONEG_DISABLE) {
|
||||
if (cmd->base.speed != SPEED_10 && cmd->base.speed != SPEED_100) {
|
||||
netdev_info(dev, "Unsupported speed for forced link\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL) {
|
||||
netdev_info(dev, "Duplex must be half or full for forced link\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
if (cmd->base.autoneg == AUTONEG_ENABLE)
|
||||
igc_handle_autoneg_enabled(adapter, cmd);
|
||||
else
|
||||
igc_handle_autoneg_disabled(adapter, cmd->base.speed,
|
||||
cmd->base.duplex);
|
||||
|
||||
/* MDI-X => 2; MDI => 1; Auto => 3 */
|
||||
if (cmd->base.eth_tp_mdix_ctrl) {
|
||||
/* fix up the value for auto (3 => 0) as zero is mapped
|
||||
|
|
@ -2175,6 +2285,7 @@ static const struct ethtool_ops igc_ethtool_ops = {
|
|||
.get_rxnfc = igc_ethtool_get_rxnfc,
|
||||
.set_rxnfc = igc_ethtool_set_rxnfc,
|
||||
.get_rx_ring_count = igc_ethtool_get_rx_ring_count,
|
||||
.get_rxfh_key_size = igc_ethtool_get_rxfh_key_size,
|
||||
.get_rxfh_indir_size = igc_ethtool_get_rxfh_indir_size,
|
||||
.get_rxfh = igc_ethtool_get_rxfh,
|
||||
.set_rxfh = igc_ethtool_set_rxfh,
|
||||
|
|
|
|||
|
|
@ -73,6 +73,13 @@ struct igc_info {
|
|||
|
||||
extern const struct igc_info igc_base_info;
|
||||
|
||||
enum igc_forced_speed_duplex {
|
||||
IGC_FORCED_10H,
|
||||
IGC_FORCED_10F,
|
||||
IGC_FORCED_100H,
|
||||
IGC_FORCED_100F,
|
||||
};
|
||||
|
||||
struct igc_mac_info {
|
||||
struct igc_mac_operations ops;
|
||||
|
||||
|
|
@ -92,8 +99,9 @@ struct igc_mac_info {
|
|||
bool asf_firmware_present;
|
||||
bool arc_subsystem_valid;
|
||||
|
||||
bool autoneg_failed;
|
||||
bool get_link_status;
|
||||
bool autoneg_enabled;
|
||||
enum igc_forced_speed_duplex forced_speed_duplex;
|
||||
};
|
||||
|
||||
struct igc_nvm_operations {
|
||||
|
|
|
|||
|
|
@ -438,26 +438,23 @@ void igc_config_collision_dist(struct igc_hw *hw)
|
|||
* Checks the status of auto-negotiation after link up to ensure that the
|
||||
* speed and duplex were not forced. If the link needed to be forced, then
|
||||
* flow control needs to be forced also. If auto-negotiation is enabled
|
||||
* and did not fail, then we configure flow control based on our link
|
||||
* partner.
|
||||
* then we configure flow control based on our link partner.
|
||||
*/
|
||||
s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
||||
{
|
||||
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
|
||||
struct igc_mac_info *mac = &hw->mac;
|
||||
u16 speed, duplex;
|
||||
s32 ret_val = 0;
|
||||
|
||||
/* Check for the case where we have fiber media and auto-neg failed
|
||||
* so we had to force link. In this case, we need to force the
|
||||
* configuration of the MAC to match the "fc" parameter.
|
||||
/* Without autoneg, flow control capability is not exchanged with the
|
||||
* link partner. IEEE 802.3 prohibits flow control in half-duplex mode.
|
||||
*/
|
||||
if (mac->autoneg_failed)
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
if (!hw->mac.autoneg_enabled) {
|
||||
if (hw->mac.forced_speed_duplex == IGC_FORCED_10H ||
|
||||
hw->mac.forced_speed_duplex == IGC_FORCED_100H)
|
||||
hw->fc.current_mode = igc_fc_none;
|
||||
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
goto force_fc;
|
||||
}
|
||||
|
||||
/* In auto-neg, we need to check and see if Auto-Neg has completed,
|
||||
|
|
@ -472,15 +469,15 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
|||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
return ret_val;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS,
|
||||
&mii_status_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
return ret_val;
|
||||
|
||||
if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
|
||||
hw_dbg("Copper PHY and Auto Neg has not completed.\n");
|
||||
goto out;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* The AutoNeg process has completed, so we now need to
|
||||
|
|
@ -492,11 +489,11 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
|||
ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
|
||||
&mii_nway_adv_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
return ret_val;
|
||||
ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
|
||||
&mii_nway_lp_ability_reg);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
return ret_val;
|
||||
/* Two bits in the Auto Negotiation Advertisement Register
|
||||
* (Address 4) and two bits in the Auto Negotiation Base
|
||||
* Page Ability Register (Address 5) determine flow control
|
||||
|
|
@ -612,7 +609,7 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
|||
ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error getting link speed and duplex\n");
|
||||
goto out;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
if (duplex == HALF_DUPLEX)
|
||||
|
|
@ -621,13 +618,13 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw)
|
|||
/* Now we call a subroutine to actually force the MAC
|
||||
* controller to use the correct flow control settings.
|
||||
*/
|
||||
force_fc:
|
||||
ret_val = igc_force_mac_fc(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error forcing flow control settings\n");
|
||||
goto out;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -785,11 +785,8 @@ static void igc_setup_mrqc(struct igc_adapter *adapter)
|
|||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 j, num_rx_queues;
|
||||
u32 mrqc, rxcsum;
|
||||
u32 rss_key[10];
|
||||
|
||||
netdev_rss_key_fill(rss_key, sizeof(rss_key));
|
||||
for (j = 0; j < 10; j++)
|
||||
wr32(IGC_RSSRK(j), rss_key[j]);
|
||||
igc_write_rss_key(adapter);
|
||||
|
||||
num_rx_queues = adapter->rss_queues;
|
||||
|
||||
|
|
@ -5048,6 +5045,9 @@ static int igc_sw_init(struct igc_adapter *adapter)
|
|||
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
|
||||
|
||||
/* init RSS key */
|
||||
netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
|
||||
|
||||
/* set default ring sizes */
|
||||
adapter->tx_ring_count = IGC_DEFAULT_TXD;
|
||||
adapter->rx_ring_count = IGC_DEFAULT_RXD;
|
||||
|
|
@ -7298,7 +7298,7 @@ static int igc_probe(struct pci_dev *pdev,
|
|||
/* Initialize link properties that are user-changeable */
|
||||
adapter->fc_autoneg = true;
|
||||
hw->phy.autoneg_advertised = 0xaf;
|
||||
|
||||
hw->mac.autoneg_enabled = true;
|
||||
hw->fc.requested_mode = igc_fc_default;
|
||||
hw->fc.current_mode = igc_fc_default;
|
||||
|
||||
|
|
|
|||
|
|
@ -494,12 +494,20 @@ s32 igc_setup_copper_link(struct igc_hw *hw)
|
|||
s32 ret_val = 0;
|
||||
bool link;
|
||||
|
||||
/* Setup autoneg and flow control advertisement and perform
|
||||
* autonegotiation.
|
||||
*/
|
||||
ret_val = igc_copper_link_autoneg(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
if (hw->mac.autoneg_enabled) {
|
||||
/* Setup autoneg and flow control advertisement and perform
|
||||
* autonegotiation.
|
||||
*/
|
||||
ret_val = igc_copper_link_autoneg(hw);
|
||||
if (ret_val)
|
||||
goto out;
|
||||
} else {
|
||||
ret_val = hw->phy.ops.force_speed_duplex(hw);
|
||||
if (ret_val) {
|
||||
hw_dbg("Error Forcing Speed/Duplex\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check link status. Wait up to 100 microseconds for link to become
|
||||
* valid.
|
||||
|
|
@ -778,3 +786,48 @@ u16 igc_read_phy_fw_version(struct igc_hw *hw)
|
|||
|
||||
return gphy_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_force_speed_duplex - Force PHY speed and duplex settings
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Programs the GPY PHY control register to disable autonegotiation
|
||||
* and force the speed/duplex indicated by hw->mac.forced_speed_duplex.
|
||||
*/
|
||||
s32 igc_force_speed_duplex(struct igc_hw *hw)
|
||||
{
|
||||
struct igc_phy_info *phy = &hw->phy;
|
||||
u16 phy_ctrl;
|
||||
s32 ret_val;
|
||||
|
||||
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
phy_ctrl &= ~(MII_CR_SPEED_MASK | MII_CR_DUPLEX_EN |
|
||||
MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
|
||||
|
||||
switch (hw->mac.forced_speed_duplex) {
|
||||
case IGC_FORCED_10H:
|
||||
phy_ctrl |= MII_CR_SPEED_10;
|
||||
break;
|
||||
case IGC_FORCED_10F:
|
||||
phy_ctrl |= MII_CR_SPEED_10 | MII_CR_DUPLEX_EN;
|
||||
break;
|
||||
case IGC_FORCED_100H:
|
||||
phy_ctrl |= MII_CR_SPEED_100;
|
||||
break;
|
||||
case IGC_FORCED_100F:
|
||||
phy_ctrl |= MII_CR_SPEED_100 | MII_CR_DUPLEX_EN;
|
||||
break;
|
||||
default:
|
||||
return -IGC_ERR_CONFIG;
|
||||
}
|
||||
|
||||
ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
hw->mac.get_link_status = true;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,5 +18,6 @@ void igc_power_down_phy_copper(struct igc_hw *hw);
|
|||
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data);
|
||||
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data);
|
||||
u16 igc_read_phy_fw_version(struct igc_hw *hw);
|
||||
s32 igc_force_speed_duplex(struct igc_hw *hw);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user