Re: [PATCH v2] net: arc_emac: restart stalled EMAC

2017-12-19 Thread David Miller
From: Alexander Kochetkov 
Date: Tue, 19 Dec 2017 14:03:57 +0300

> Under certain conditions EMAC stop reception of incoming packets and
> continuously increment R_MISS register instead of saving data into
> provided buffer. The commit implement workaround for such situation.
> Then the stall detected EMAC will be restarted.
> 
> On device the stall looks like the device lost it's dynamic IP address.
> ifconfig shows that interface error counter rapidly increments.
> At the same time on the DHCP server we can see continues DHCP-requests
> from device.
> 
> In real network stalls happen really rarely. To make them frequent the
> broadcast storm[1] should be simulated. For simulation it is necessary
> to make following connections:
> 1. connect radxarock to 1st port of switch
> 2. connect some PC to 2nd port of switch
> 3. connect two other free ports together using standard ethernet cable,
>in order to make a switching loop.
> 
> After that, is necessary to make a broadcast storm. For example, running on
> PC 'ping' to some IP address triggers ARP-request storm. After some
> time (~10sec), EMAC on rk3188 will stall.
> 
> Observed and tested on rk3188 radxarock.
> 
> [1] https://en.wikipedia.org/wiki/Broadcast_radiation
> 
> Signed-off-by: Alexander Kochetkov 

Applied.


Re: [PATCH v2] net: arc_emac: restart stalled EMAC

2017-12-19 Thread David Miller
From: Alexander Kochetkov 
Date: Tue, 19 Dec 2017 14:03:57 +0300

> Under certain conditions EMAC stop reception of incoming packets and
> continuously increment R_MISS register instead of saving data into
> provided buffer. The commit implement workaround for such situation.
> Then the stall detected EMAC will be restarted.
> 
> On device the stall looks like the device lost it's dynamic IP address.
> ifconfig shows that interface error counter rapidly increments.
> At the same time on the DHCP server we can see continues DHCP-requests
> from device.
> 
> In real network stalls happen really rarely. To make them frequent the
> broadcast storm[1] should be simulated. For simulation it is necessary
> to make following connections:
> 1. connect radxarock to 1st port of switch
> 2. connect some PC to 2nd port of switch
> 3. connect two other free ports together using standard ethernet cable,
>in order to make a switching loop.
> 
> After that, is necessary to make a broadcast storm. For example, running on
> PC 'ping' to some IP address triggers ARP-request storm. After some
> time (~10sec), EMAC on rk3188 will stall.
> 
> Observed and tested on rk3188 radxarock.
> 
> [1] https://en.wikipedia.org/wiki/Broadcast_radiation
> 
> Signed-off-by: Alexander Kochetkov 

Applied.


[PATCH v2] net: arc_emac: restart stalled EMAC

2017-12-19 Thread Alexander Kochetkov
Under certain conditions EMAC stop reception of incoming packets and
continuously increment R_MISS register instead of saving data into
provided buffer. The commit implement workaround for such situation.
Then the stall detected EMAC will be restarted.

On device the stall looks like the device lost it's dynamic IP address.
ifconfig shows that interface error counter rapidly increments.
At the same time on the DHCP server we can see continues DHCP-requests
from device.

In real network stalls happen really rarely. To make them frequent the
broadcast storm[1] should be simulated. For simulation it is necessary
to make following connections:
1. connect radxarock to 1st port of switch
2. connect some PC to 2nd port of switch
3. connect two other free ports together using standard ethernet cable,
   in order to make a switching loop.

After that, is necessary to make a broadcast storm. For example, running on
PC 'ping' to some IP address triggers ARP-request storm. After some
time (~10sec), EMAC on rk3188 will stall.

Observed and tested on rk3188 radxarock.

[1] https://en.wikipedia.org/wiki/Broadcast_radiation

Signed-off-by: Alexander Kochetkov 
---

Changes in v2:
- Rebased against stable linux-4.14.y branch

 drivers/net/ethernet/arc/emac.h  |2 +
 drivers/net/ethernet/arc/emac_main.c |  111 ++
 2 files changed, 113 insertions(+)

diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index 3c63b16..d9efbc8 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -159,6 +159,8 @@ struct arc_emac_priv {
unsigned int link;
unsigned int duplex;
unsigned int speed;
+
+   unsigned int rx_missed_errors;
 };
 
 /**
diff --git a/drivers/net/ethernet/arc/emac_main.c 
b/drivers/net/ethernet/arc/emac_main.c
index 3241af1..363d909 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -26,6 +26,8 @@
 
 #include "emac.h"
 
+static void arc_emac_restart(struct net_device *ndev);
+
 /**
  * arc_emac_tx_avail - Return the number of available slots in the tx ring.
  * @priv: Pointer to ARC EMAC private data structure.
@@ -259,6 +261,53 @@ static int arc_emac_rx(struct net_device *ndev, int budget)
 }
 
 /**
+ * arc_emac_rx_miss_handle - handle R_MISS register
+ * @ndev:  Pointer to the net_device structure.
+ */
+static void arc_emac_rx_miss_handle(struct net_device *ndev)
+{
+   struct arc_emac_priv *priv = netdev_priv(ndev);
+   struct net_device_stats *stats = >stats;
+   unsigned int miss;
+
+   miss = arc_reg_get(priv, R_MISS);
+   if (miss) {
+   stats->rx_errors += miss;
+   stats->rx_missed_errors += miss;
+   priv->rx_missed_errors += miss;
+   }
+}
+
+/**
+ * arc_emac_rx_stall_check - check RX stall
+ * @ndev:  Pointer to the net_device structure.
+ * @budget:How many BDs requested to process on 1 call.
+ * @work_done: How many BDs processed
+ *
+ * Under certain conditions EMAC stop reception of incoming packets and
+ * continuously increment R_MISS register instead of saving data into
+ * provided buffer. This function detect that condition and restart
+ * EMAC.
+ */
+static void arc_emac_rx_stall_check(struct net_device *ndev,
+   int budget, unsigned int work_done)
+{
+   struct arc_emac_priv *priv = netdev_priv(ndev);
+   struct arc_emac_bd *rxbd;
+
+   if (work_done)
+   priv->rx_missed_errors = 0;
+
+   if (priv->rx_missed_errors && budget) {
+   rxbd = >rxbd[priv->last_rx_bd];
+   if (le32_to_cpu(rxbd->info) & FOR_EMAC) {
+   arc_emac_restart(ndev);
+   priv->rx_missed_errors = 0;
+   }
+   }
+}
+
+/**
  * arc_emac_poll - NAPI poll handler.
  * @napi:  Pointer to napi_struct structure.
  * @budget:How many BDs to process on 1 call.
@@ -272,6 +321,7 @@ static int arc_emac_poll(struct napi_struct *napi, int 
budget)
unsigned int work_done;
 
arc_emac_tx_clean(ndev);
+   arc_emac_rx_miss_handle(ndev);
 
work_done = arc_emac_rx(ndev, budget);
if (work_done < budget) {
@@ -279,6 +329,8 @@ static int arc_emac_poll(struct napi_struct *napi, int 
budget)
arc_reg_or(priv, R_ENABLE, RXINT_MASK | TXINT_MASK);
}
 
+   arc_emac_rx_stall_check(ndev, budget, work_done);
+
return work_done;
 }
 
@@ -320,6 +372,8 @@ static irqreturn_t arc_emac_intr(int irq, void 
*dev_instance)
if (status & MSER_MASK) {
stats->rx_missed_errors += 0x100;
stats->rx_errors += 0x100;
+   priv->rx_missed_errors += 0x100;
+   napi_schedule(>napi);
}
 
if (status & RXCR_MASK) {
@@ -732,6 +786,63 @@ static int 

[PATCH v2] net: arc_emac: restart stalled EMAC

2017-12-19 Thread Alexander Kochetkov
Under certain conditions EMAC stop reception of incoming packets and
continuously increment R_MISS register instead of saving data into
provided buffer. The commit implement workaround for such situation.
Then the stall detected EMAC will be restarted.

On device the stall looks like the device lost it's dynamic IP address.
ifconfig shows that interface error counter rapidly increments.
At the same time on the DHCP server we can see continues DHCP-requests
from device.

In real network stalls happen really rarely. To make them frequent the
broadcast storm[1] should be simulated. For simulation it is necessary
to make following connections:
1. connect radxarock to 1st port of switch
2. connect some PC to 2nd port of switch
3. connect two other free ports together using standard ethernet cable,
   in order to make a switching loop.

After that, is necessary to make a broadcast storm. For example, running on
PC 'ping' to some IP address triggers ARP-request storm. After some
time (~10sec), EMAC on rk3188 will stall.

Observed and tested on rk3188 radxarock.

[1] https://en.wikipedia.org/wiki/Broadcast_radiation

Signed-off-by: Alexander Kochetkov 
---

Changes in v2:
- Rebased against stable linux-4.14.y branch

 drivers/net/ethernet/arc/emac.h  |2 +
 drivers/net/ethernet/arc/emac_main.c |  111 ++
 2 files changed, 113 insertions(+)

diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index 3c63b16..d9efbc8 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -159,6 +159,8 @@ struct arc_emac_priv {
unsigned int link;
unsigned int duplex;
unsigned int speed;
+
+   unsigned int rx_missed_errors;
 };
 
 /**
diff --git a/drivers/net/ethernet/arc/emac_main.c 
b/drivers/net/ethernet/arc/emac_main.c
index 3241af1..363d909 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -26,6 +26,8 @@
 
 #include "emac.h"
 
+static void arc_emac_restart(struct net_device *ndev);
+
 /**
  * arc_emac_tx_avail - Return the number of available slots in the tx ring.
  * @priv: Pointer to ARC EMAC private data structure.
@@ -259,6 +261,53 @@ static int arc_emac_rx(struct net_device *ndev, int budget)
 }
 
 /**
+ * arc_emac_rx_miss_handle - handle R_MISS register
+ * @ndev:  Pointer to the net_device structure.
+ */
+static void arc_emac_rx_miss_handle(struct net_device *ndev)
+{
+   struct arc_emac_priv *priv = netdev_priv(ndev);
+   struct net_device_stats *stats = >stats;
+   unsigned int miss;
+
+   miss = arc_reg_get(priv, R_MISS);
+   if (miss) {
+   stats->rx_errors += miss;
+   stats->rx_missed_errors += miss;
+   priv->rx_missed_errors += miss;
+   }
+}
+
+/**
+ * arc_emac_rx_stall_check - check RX stall
+ * @ndev:  Pointer to the net_device structure.
+ * @budget:How many BDs requested to process on 1 call.
+ * @work_done: How many BDs processed
+ *
+ * Under certain conditions EMAC stop reception of incoming packets and
+ * continuously increment R_MISS register instead of saving data into
+ * provided buffer. This function detect that condition and restart
+ * EMAC.
+ */
+static void arc_emac_rx_stall_check(struct net_device *ndev,
+   int budget, unsigned int work_done)
+{
+   struct arc_emac_priv *priv = netdev_priv(ndev);
+   struct arc_emac_bd *rxbd;
+
+   if (work_done)
+   priv->rx_missed_errors = 0;
+
+   if (priv->rx_missed_errors && budget) {
+   rxbd = >rxbd[priv->last_rx_bd];
+   if (le32_to_cpu(rxbd->info) & FOR_EMAC) {
+   arc_emac_restart(ndev);
+   priv->rx_missed_errors = 0;
+   }
+   }
+}
+
+/**
  * arc_emac_poll - NAPI poll handler.
  * @napi:  Pointer to napi_struct structure.
  * @budget:How many BDs to process on 1 call.
@@ -272,6 +321,7 @@ static int arc_emac_poll(struct napi_struct *napi, int 
budget)
unsigned int work_done;
 
arc_emac_tx_clean(ndev);
+   arc_emac_rx_miss_handle(ndev);
 
work_done = arc_emac_rx(ndev, budget);
if (work_done < budget) {
@@ -279,6 +329,8 @@ static int arc_emac_poll(struct napi_struct *napi, int 
budget)
arc_reg_or(priv, R_ENABLE, RXINT_MASK | TXINT_MASK);
}
 
+   arc_emac_rx_stall_check(ndev, budget, work_done);
+
return work_done;
 }
 
@@ -320,6 +372,8 @@ static irqreturn_t arc_emac_intr(int irq, void 
*dev_instance)
if (status & MSER_MASK) {
stats->rx_missed_errors += 0x100;
stats->rx_errors += 0x100;
+   priv->rx_missed_errors += 0x100;
+   napi_schedule(>napi);
}
 
if (status & RXCR_MASK) {
@@ -732,6 +786,63 @@ static int arc_emac_ioctl(struct net_device *dev,