aboutsummaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2016-01-15 12:59:30 +0000
committerFelix Fietkau <nbd@openwrt.org>2016-01-15 12:59:30 +0000
commite31260baa76865bc69c435d33b8685d131a52be7 (patch)
tree6ba7ec5063ca79ceb683c66a7718073cd860231b /target
parent05eac4ae0bbbea9cda98a22d36aac4cc8fec9bdd (diff)
downloadupstream-e31260baa76865bc69c435d33b8685d131a52be7.tar.gz
upstream-e31260baa76865bc69c435d33b8685d131a52be7.tar.bz2
upstream-e31260baa76865bc69c435d33b8685d131a52be7.zip
ar71xx: fix ethernet MAC reset on DMA hang
Fully reset the chip like on a full up/down, but without the PHY statemachine restart. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Backport of r48228 git-svn-id: svn://svn.openwrt.org/openwrt/branches/chaos_calmer@48246 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target')
-rw-r--r--target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c93
1 files changed, 55 insertions, 38 deletions
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
index 9bb099c8a6..fbd6bef63d 100644
--- a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
+++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
@@ -538,7 +538,8 @@ static void ag71xx_hw_start(struct ag71xx *ag)
netif_wake_queue(ag->dev);
}
-void ag71xx_link_adjust(struct ag71xx *ag)
+static void
+__ag71xx_link_adjust(struct ag71xx *ag, bool update)
{
struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
u32 cfg2;
@@ -546,7 +547,7 @@ void ag71xx_link_adjust(struct ag71xx *ag)
u32 fifo5;
u32 fifo3;
- if (!ag->link) {
+ if (!ag->link && update) {
ag71xx_hw_stop(ag);
netif_carrier_off(ag->dev);
if (netif_msg_link(ag))
@@ -598,7 +599,7 @@ void ag71xx_link_adjust(struct ag71xx *ag)
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, fifo3);
- if (pdata->set_speed)
+ if (update && pdata->set_speed)
pdata->set_speed(ag->speed);
ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
@@ -607,7 +608,7 @@ void ag71xx_link_adjust(struct ag71xx *ag)
ag71xx_hw_start(ag);
netif_carrier_on(ag->dev);
- if (netif_msg_link(ag))
+ if (update && netif_msg_link(ag))
pr_info("%s: link up (%sMbps/%s duplex)\n",
ag->dev->name,
ag71xx_speed_str(ag),
@@ -631,34 +632,66 @@ void ag71xx_link_adjust(struct ag71xx *ag)
ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL));
}
+void ag71xx_link_adjust(struct ag71xx *ag)
+{
+ __ag71xx_link_adjust(ag, true);
+}
+
+static int ag71xx_hw_enable(struct ag71xx *ag)
+{
+ int ret;
+
+ ret = ag71xx_rings_init(ag);
+ if (ret)
+ return ret;
+
+ napi_enable(&ag->napi);
+ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
+ ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
+ netif_start_queue(ag->dev);
+
+ return 0;
+}
+
+static void ag71xx_hw_disable(struct ag71xx *ag)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ag->lock, flags);
+
+ netif_stop_queue(ag->dev);
+
+ ag71xx_hw_stop(ag);
+ ag71xx_dma_reset(ag);
+
+ napi_disable(&ag->napi);
+ del_timer_sync(&ag->oom_timer);
+
+ spin_unlock_irqrestore(&ag->lock, flags);
+
+ ag71xx_rings_cleanup(ag);
+}
+
static int ag71xx_open(struct net_device *dev)
{
struct ag71xx *ag = netdev_priv(dev);
unsigned int max_frame_len;
int ret;
+ netif_carrier_off(dev);
max_frame_len = ag71xx_max_frame_len(dev->mtu);
ag->rx_buf_size = max_frame_len + NET_SKB_PAD + NET_IP_ALIGN;
/* setup max frame length */
ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len);
+ ag71xx_hw_set_macaddr(ag, dev->dev_addr);
- ret = ag71xx_rings_init(ag);
+ ret = ag71xx_hw_enable(ag);
if (ret)
goto err;
- napi_enable(&ag->napi);
-
- netif_carrier_off(dev);
ag71xx_phy_start(ag);
- ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
- ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
-
- ag71xx_hw_set_macaddr(ag, dev->dev_addr);
-
- netif_start_queue(dev);
-
return 0;
err:
@@ -669,24 +702,10 @@ err:
static int ag71xx_stop(struct net_device *dev)
{
struct ag71xx *ag = netdev_priv(dev);
- unsigned long flags;
netif_carrier_off(dev);
ag71xx_phy_stop(ag);
-
- spin_lock_irqsave(&ag->lock, flags);
-
- netif_stop_queue(dev);
-
- ag71xx_hw_stop(ag);
- ag71xx_dma_reset(ag);
-
- napi_disable(&ag->napi);
- del_timer_sync(&ag->oom_timer);
-
- spin_unlock_irqrestore(&ag->lock, flags);
-
- ag71xx_rings_cleanup(ag);
+ ag71xx_hw_disable(ag);
return 0;
}
@@ -870,14 +889,12 @@ static void ag71xx_restart_work_func(struct work_struct *work)
{
struct ag71xx *ag = container_of(work, struct ag71xx, restart_work);
- if (ag71xx_get_pdata(ag)->is_ar724x) {
- ag->link = 0;
- ag71xx_link_adjust(ag);
- return;
- }
-
- ag71xx_stop(ag->dev);
- ag71xx_open(ag->dev);
+ rtnl_lock();
+ ag71xx_hw_disable(ag);
+ ag71xx_hw_enable(ag);
+ if (ag->link)
+ __ag71xx_link_adjust(ag, false);
+ rtnl_unlock();
}
static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp)