Commit 37d6017b authored by Fugang Duan's avatar Fugang Duan Committed by David S. Miller

net: fec: Workaround for imx6sx enet tx hang when enable three queues

When enable three queues on imx6sx enet, and then do tx performance
test with iperf tool, after some time running, tx hang.

Found that:
	If uDMA is running, software set TDAR may cause tx hang.
	If uDMA is in idle, software set TDAR don't cause tx hang.

There is a TDAR race condition for mutliQ when the software sets TDAR
and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles).
This will cause the udma_tx and udma_tx_arbiter state machines to hang.
The issue exist at i.MX6SX enet IP.

So, the Workaround is checking TDAR status four time, if TDAR cleared by
hardware and then write TDAR, otherwise don't set TDAR.

The patch is only one Workaround for the issue ERR007885.
Signed-off-by: default avatarFugang Duan <B38611@freescale.com>
Signed-off-by: default avatarFrank Li <Frank.Li@freescale.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 73e72289
...@@ -111,6 +111,12 @@ static void fec_enet_itr_coal_init(struct net_device *ndev); ...@@ -111,6 +111,12 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);
* independent rings * independent rings
*/ */
#define FEC_QUIRK_HAS_AVB (1 << 8) #define FEC_QUIRK_HAS_AVB (1 << 8)
/* There is a TDAR race condition for mutliQ when the software sets TDAR
* and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles).
* This will cause the udma_tx and udma_tx_arbiter state machines to hang.
* The issue exist at i.MX6SX enet IP.
*/
#define FEC_QUIRK_ERR007885 (1 << 9)
static struct platform_device_id fec_devtype[] = { static struct platform_device_id fec_devtype[] = {
{ {
...@@ -139,7 +145,7 @@ static struct platform_device_id fec_devtype[] = { ...@@ -139,7 +145,7 @@ static struct platform_device_id fec_devtype[] = {
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
FEC_QUIRK_HAS_AVB, FEC_QUIRK_HAS_AVB | FEC_QUIRK_ERR007885,
}, { }, {
/* sentinel */ /* sentinel */
} }
...@@ -709,6 +715,8 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq, ...@@ -709,6 +715,8 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
struct tso_t tso; struct tso_t tso;
unsigned int index = 0; unsigned int index = 0;
int ret; int ret;
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) { if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
...@@ -770,6 +778,11 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq, ...@@ -770,6 +778,11 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
txq->cur_tx = bdp; txq->cur_tx = bdp;
/* Trigger transmission start */ /* Trigger transmission start */
if (!(id_entry->driver_data & FEC_QUIRK_ERR007885) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)))
writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue)); writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
return 0; return 0;
......
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