diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0191-dpaa2-eth-Avoid-unbounded-while-loops.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/701-net-0191-dpaa2-eth-Avoid-unbounded-while-loops.patch | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0191-dpaa2-eth-Avoid-unbounded-while-loops.patch b/target/linux/layerscape/patches-5.4/701-net-0191-dpaa2-eth-Avoid-unbounded-while-loops.patch new file mode 100644 index 0000000000..72b41a45bb --- /dev/null +++ b/target/linux/layerscape/patches-5.4/701-net-0191-dpaa2-eth-Avoid-unbounded-while-loops.patch @@ -0,0 +1,160 @@ +From 3420c5bf9d08df074b67c7feda8a37d951d0b232 Mon Sep 17 00:00:00 2001 +From: Ioana Radulescu <ruxandra.radulescu@nxp.com> +Date: Wed, 18 Sep 2019 13:31:07 +0300 +Subject: [PATCH] dpaa2-eth: Avoid unbounded while loops + +Throughout the driver there are several places where we wait +indefinitely for DPIO portal commands to be executed, while +the portal returns a busy response code. + +Even though in theory we are guaranteed the portals become +available eventually, in practice the QBMan hardware module +may become unresponsive in various corner cases. + +Make sure we can never get stuck in an infinite while loop +by adding a retry counter for all portal commands. + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com> +--- + drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 30 ++++++++++++++++++++---- + drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 8 +++++++ + 2 files changed, 33 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c ++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +@@ -221,6 +221,7 @@ static void xdp_release_buf(struct dpaa2 + struct dpaa2_eth_channel *ch, + dma_addr_t addr) + { ++ int retries = 0; + int err; + + ch->xdp.drop_bufs[ch->xdp.drop_cnt++] = addr; +@@ -229,8 +230,11 @@ static void xdp_release_buf(struct dpaa2 + + while ((err = dpaa2_io_service_release(ch->dpio, priv->bpid, + ch->xdp.drop_bufs, +- ch->xdp.drop_cnt)) == -EBUSY) ++ ch->xdp.drop_cnt)) == -EBUSY) { ++ if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) ++ break; + cpu_relax(); ++ } + + if (err) { + free_bufs(priv, ch->xdp.drop_bufs, ch->xdp.drop_cnt); +@@ -458,7 +462,7 @@ static int consume_frames(struct dpaa2_e + struct dpaa2_eth_fq *fq = NULL; + struct dpaa2_dq *dq; + const struct dpaa2_fd *fd; +- int cleaned = 0; ++ int cleaned = 0, retries = 0; + int is_last; + + do { +@@ -469,6 +473,11 @@ static int consume_frames(struct dpaa2_e + * the store until we get some sort of valid response + * token (either a valid frame or an "empty dequeue") + */ ++ if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) { ++ netdev_err_once(priv->net_dev, ++ "Unable to read a valid dequeue response\n"); ++ return 0; ++ } + continue; + } + +@@ -477,6 +486,7 @@ static int consume_frames(struct dpaa2_e + + fq->consume(priv, ch, fd, fq); + cleaned++; ++ retries = 0; + } while (!is_last); + + if (!cleaned) +@@ -949,6 +959,7 @@ static int add_bufs(struct dpaa2_eth_pri + u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; + struct page *page; + dma_addr_t addr; ++ int retries = 0; + int i, err; + + for (i = 0; i < DPAA2_ETH_BUFS_PER_CMD; i++) { +@@ -980,8 +991,11 @@ static int add_bufs(struct dpaa2_eth_pri + release_bufs: + /* In case the portal is busy, retry until successful */ + while ((err = dpaa2_io_service_release(ch->dpio, bpid, +- buf_array, i)) == -EBUSY) ++ buf_array, i)) == -EBUSY) { ++ if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) ++ break; + cpu_relax(); ++ } + + /* If release command failed, clean up and bail out; + * not much else we can do about it +@@ -1032,16 +1046,21 @@ static int seed_pool(struct dpaa2_eth_pr + static void drain_bufs(struct dpaa2_eth_priv *priv, int count) + { + u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; ++ int retries = 0; + int ret; + + do { + ret = dpaa2_io_service_acquire(NULL, priv->bpid, + buf_array, count); + if (ret < 0) { ++ if (ret == -EBUSY && ++ retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) ++ continue; + netdev_err(priv->net_dev, "dpaa2_io_service_acquire() failed\n"); + return; + } + free_bufs(priv, buf_array, ret); ++ retries = 0; + } while (ret); + } + +@@ -1094,7 +1113,7 @@ static int pull_channel(struct dpaa2_eth + ch->store); + dequeues++; + cpu_relax(); +- } while (err == -EBUSY); ++ } while (err == -EBUSY && dequeues < DPAA2_ETH_SWP_BUSY_RETRIES); + + ch->stats.dequeue_portal_busy += dequeues; + if (unlikely(err)) +@@ -1118,6 +1137,7 @@ static int dpaa2_eth_poll(struct napi_st + struct netdev_queue *nq; + int store_cleaned, work_done; + struct list_head rx_list; ++ int retries = 0; + int err; + + ch = container_of(napi, struct dpaa2_eth_channel, napi); +@@ -1163,7 +1183,7 @@ static int dpaa2_eth_poll(struct napi_st + do { + err = dpaa2_io_service_rearm(ch->dpio, &ch->nctx); + cpu_relax(); +- } while (err == -EBUSY); ++ } while (err == -EBUSY && retries++ < DPAA2_ETH_SWP_BUSY_RETRIES); + WARN_ONCE(err, "CDAN notifications rearm failed on core %d", + ch->nctx.desired_cpu); + +--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h ++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +@@ -245,6 +245,14 @@ static inline struct dpaa2_faead *dpaa2_ + */ + #define DPAA2_ETH_ENQUEUE_RETRIES 10 + ++/* Number of times to retry DPIO portal operations while waiting ++ * for portal to finish executing current command and become ++ * available. We want to avoid being stuck in a while loop in case ++ * hardware becomes unresponsive, but not give up too easily if ++ * the portal really is busy for valid reasons ++ */ ++#define DPAA2_ETH_SWP_BUSY_RETRIES 1000 ++ + /* Driver statistics, other than those in struct rtnl_link_stats64. + * These are usually collected per-CPU and aggregated by ethtool. + */ |