summaryrefslogtreecommitdiffstats
path: root/target/linux/ar71xx/files/drivers/net
diff options
context:
space:
mode:
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2011-08-13 22:30:14 +0000
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2011-08-13 22:30:14 +0000
commitdb5c8f65cad92980356baab0c8dd383357b6ff36 (patch)
treee4e4aca4d6efed85206aa1d9c8160b2eb661060f /target/linux/ar71xx/files/drivers/net
parent5051a6677f91837f475a98684b3c1a286a38e4db (diff)
ar71xx: add some code to detect DMA stuck conditions on ar7240
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@27975 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/ar71xx/files/drivers/net')
-rw-r--r--target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h4
-rw-r--r--target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c30
2 files changed, 33 insertions, 1 deletions
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
index d5cc46c42..0222cab79 100644
--- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
+++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
@@ -236,6 +236,10 @@ static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc)
#define AG71XX_REG_INT_ENABLE 0x0198
#define AG71XX_REG_INT_STATUS 0x019c
+#define AG71XX_REG_FIFO_DEPTH 0x01a8
+#define AG71XX_REG_RX_SM 0x01b0
+#define AG71XX_REG_TX_SM 0x01b4
+
#define MAC_CFG1_TXE BIT(0) /* Tx Enable */
#define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */
#define MAC_CFG1_RXE BIT(2) /* Rx Enable */
diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c
index ee76c9a03..c541933ce 100644
--- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c
+++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c
@@ -805,9 +805,33 @@ static void ag71xx_restart_work_func(struct work_struct *work)
ag71xx_open(ag->dev);
}
+static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp)
+{
+ u32 rx_sm, tx_sm, rx_fd;
+
+ if (likely(time_before(jiffies, timestamp + HZ/10)))
+ return false;
+
+ if (!netif_carrier_ok(ag->dev))
+ return false;
+
+ rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM);
+ if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6)
+ return true;
+
+ tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM);
+ rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH);
+ if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) &&
+ ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0)
+ return true;
+
+ return false;
+}
+
static int ag71xx_tx_packets(struct ag71xx *ag)
{
struct ag71xx_ring *ring = &ag->tx_ring;
+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
int sent;
DBG("%s: processing TX ring\n", ag->dev->name);
@@ -818,8 +842,12 @@ static int ag71xx_tx_packets(struct ag71xx *ag)
struct ag71xx_desc *desc = ring->buf[i].desc;
struct sk_buff *skb = ring->buf[i].skb;
- if (!ag71xx_desc_empty(desc))
+ if (!ag71xx_desc_empty(desc)) {
+ if (pdata->is_ar7240 &&
+ ag71xx_check_dma_stuck(ag, ring->buf[i].timestamp))
+ schedule_work(&ag->restart_work);
break;
+ }
ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);