Commit 4a7a3860 authored by Timur Tabi's avatar Timur Tabi Committed by David S. Miller

net: qcom/emac: add software control for pause frame mode

The EMAC has the option of sending only a single pause frame when
flow control is enabled and the RX queue is full.  Although sending
only one pause frame has little value, this would allow admins to
enable automatic flow control without having to worry about the EMAC
flooding nearby switches with pause frames if the kernel hangs.

The option is enabled by using the single-pause-mode private flag.
Signed-off-by: default avatarTimur Tabi <timur@codeaurora.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0ab09bef
...@@ -88,6 +88,8 @@ static void emac_set_msglevel(struct net_device *netdev, u32 data) ...@@ -88,6 +88,8 @@ static void emac_set_msglevel(struct net_device *netdev, u32 data)
static int emac_get_sset_count(struct net_device *netdev, int sset) static int emac_get_sset_count(struct net_device *netdev, int sset)
{ {
switch (sset) { switch (sset) {
case ETH_SS_PRIV_FLAGS:
return 1;
case ETH_SS_STATS: case ETH_SS_STATS:
return EMAC_STATS_LEN; return EMAC_STATS_LEN;
default: default:
...@@ -100,6 +102,10 @@ static void emac_get_strings(struct net_device *netdev, u32 stringset, u8 *data) ...@@ -100,6 +102,10 @@ static void emac_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
unsigned int i; unsigned int i;
switch (stringset) { switch (stringset) {
case ETH_SS_PRIV_FLAGS:
strcpy(data, "single-pause-mode");
break;
case ETH_SS_STATS: case ETH_SS_STATS:
for (i = 0; i < EMAC_STATS_LEN; i++) { for (i = 0; i < EMAC_STATS_LEN; i++) {
strlcpy(data, emac_ethtool_stat_strings[i], strlcpy(data, emac_ethtool_stat_strings[i],
...@@ -230,6 +236,27 @@ static int emac_get_regs_len(struct net_device *netdev) ...@@ -230,6 +236,27 @@ static int emac_get_regs_len(struct net_device *netdev)
return EMAC_MAX_REG_SIZE * sizeof(u32); return EMAC_MAX_REG_SIZE * sizeof(u32);
} }
#define EMAC_PRIV_ENABLE_SINGLE_PAUSE BIT(0)
static int emac_set_priv_flags(struct net_device *netdev, u32 flags)
{
struct emac_adapter *adpt = netdev_priv(netdev);
adpt->single_pause_mode = !!(flags & EMAC_PRIV_ENABLE_SINGLE_PAUSE);
if (netif_running(netdev))
return emac_reinit_locked(adpt);
return 0;
}
static u32 emac_get_priv_flags(struct net_device *netdev)
{
struct emac_adapter *adpt = netdev_priv(netdev);
return adpt->single_pause_mode ? EMAC_PRIV_ENABLE_SINGLE_PAUSE : 0;
}
static const struct ethtool_ops emac_ethtool_ops = { static const struct ethtool_ops emac_ethtool_ops = {
.get_link_ksettings = phy_ethtool_get_link_ksettings, .get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings,
...@@ -253,6 +280,9 @@ static const struct ethtool_ops emac_ethtool_ops = { ...@@ -253,6 +280,9 @@ static const struct ethtool_ops emac_ethtool_ops = {
.get_regs_len = emac_get_regs_len, .get_regs_len = emac_get_regs_len,
.get_regs = emac_get_regs, .get_regs = emac_get_regs,
.set_priv_flags = emac_set_priv_flags,
.get_priv_flags = emac_get_priv_flags,
}; };
void emac_set_ethtool_ops(struct net_device *netdev) void emac_set_ethtool_ops(struct net_device *netdev)
......
...@@ -551,6 +551,28 @@ static void emac_mac_start(struct emac_adapter *adpt) ...@@ -551,6 +551,28 @@ static void emac_mac_start(struct emac_adapter *adpt)
mac &= ~(HUGEN | VLAN_STRIP | TPAUSE | SIMR | HUGE | MULTI_ALL | mac &= ~(HUGEN | VLAN_STRIP | TPAUSE | SIMR | HUGE | MULTI_ALL |
DEBUG_MODE | SINGLE_PAUSE_MODE); DEBUG_MODE | SINGLE_PAUSE_MODE);
/* Enable single-pause-frame mode if requested.
*
* If enabled, the EMAC will send a single pause frame when the RX
* queue is full. This normally leads to packet loss because
* the pause frame disables the remote MAC only for 33ms (the quanta),
* and then the remote MAC continues sending packets even though
* the RX queue is still full.
*
* If disabled, the EMAC sends a pause frame every 31ms until the RX
* queue is no longer full. Normally, this is the preferred
* method of operation. However, when the system is hung (e.g.
* cores are halted), the EMAC interrupt handler is never called
* and so the RX queue fills up quickly and stays full. The resuling
* non-stop "flood" of pause frames sometimes has the effect of
* disabling nearby switches. In some cases, other nearby switches
* are also affected, shutting down the entire network.
*
* The user can enable or disable single-pause-frame mode
* via ethtool.
*/
mac |= adpt->single_pause_mode ? SINGLE_PAUSE_MODE : 0;
writel_relaxed(csr1, adpt->csr + EMAC_EMAC_WRAPPER_CSR1); writel_relaxed(csr1, adpt->csr + EMAC_EMAC_WRAPPER_CSR1);
writel_relaxed(mac, adpt->base + EMAC_MAC_CTRL); writel_relaxed(mac, adpt->base + EMAC_MAC_CTRL);
......
...@@ -443,6 +443,9 @@ static void emac_init_adapter(struct emac_adapter *adpt) ...@@ -443,6 +443,9 @@ static void emac_init_adapter(struct emac_adapter *adpt)
/* default to automatic flow control */ /* default to automatic flow control */
adpt->automatic = true; adpt->automatic = true;
/* Disable single-pause-frame mode by default */
adpt->single_pause_mode = false;
} }
/* Get the clock */ /* Get the clock */
......
...@@ -363,6 +363,9 @@ struct emac_adapter { ...@@ -363,6 +363,9 @@ struct emac_adapter {
bool tx_flow_control; bool tx_flow_control;
bool rx_flow_control; bool rx_flow_control;
/* True == use single-pause-frame mode. */
bool single_pause_mode;
/* Ring parameter */ /* Ring parameter */
u8 tpd_burst; u8 tpd_burst;
u8 rfd_burst; u8 rfd_burst;
......
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