mirror of https://github.com/hak5/openwrt.git
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> SVN-Revision: 48228lede-17.01
parent
cf2cf43717
commit
5c5c60fec4
|
@ -538,7 +538,8 @@ static void ag71xx_hw_start(struct ag71xx *ag)
|
||||||
netif_wake_queue(ag->dev);
|
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);
|
struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
|
||||||
u32 cfg2;
|
u32 cfg2;
|
||||||
|
@ -546,7 +547,7 @@ void ag71xx_link_adjust(struct ag71xx *ag)
|
||||||
u32 fifo5;
|
u32 fifo5;
|
||||||
u32 fifo3;
|
u32 fifo3;
|
||||||
|
|
||||||
if (!ag->link) {
|
if (!ag->link && update) {
|
||||||
ag71xx_hw_stop(ag);
|
ag71xx_hw_stop(ag);
|
||||||
netif_carrier_off(ag->dev);
|
netif_carrier_off(ag->dev);
|
||||||
if (netif_msg_link(ag))
|
if (netif_msg_link(ag))
|
||||||
|
@ -598,7 +599,7 @@ void ag71xx_link_adjust(struct ag71xx *ag)
|
||||||
|
|
||||||
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, fifo3);
|
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, fifo3);
|
||||||
|
|
||||||
if (pdata->set_speed)
|
if (update && pdata->set_speed)
|
||||||
pdata->set_speed(ag->speed);
|
pdata->set_speed(ag->speed);
|
||||||
|
|
||||||
ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
|
ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
|
||||||
|
@ -607,7 +608,7 @@ void ag71xx_link_adjust(struct ag71xx *ag)
|
||||||
ag71xx_hw_start(ag);
|
ag71xx_hw_start(ag);
|
||||||
|
|
||||||
netif_carrier_on(ag->dev);
|
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",
|
pr_info("%s: link up (%sMbps/%s duplex)\n",
|
||||||
ag->dev->name,
|
ag->dev->name,
|
||||||
ag71xx_speed_str(ag),
|
ag71xx_speed_str(ag),
|
||||||
|
@ -631,34 +632,66 @@ void ag71xx_link_adjust(struct ag71xx *ag)
|
||||||
ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL));
|
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)
|
static int ag71xx_open(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct ag71xx *ag = netdev_priv(dev);
|
struct ag71xx *ag = netdev_priv(dev);
|
||||||
unsigned int max_frame_len;
|
unsigned int max_frame_len;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
netif_carrier_off(dev);
|
||||||
max_frame_len = ag71xx_max_frame_len(dev->mtu);
|
max_frame_len = ag71xx_max_frame_len(dev->mtu);
|
||||||
ag->rx_buf_size = max_frame_len + NET_SKB_PAD + NET_IP_ALIGN;
|
ag->rx_buf_size = max_frame_len + NET_SKB_PAD + NET_IP_ALIGN;
|
||||||
|
|
||||||
/* setup max frame length */
|
/* setup max frame length */
|
||||||
ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len);
|
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)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
napi_enable(&ag->napi);
|
|
||||||
|
|
||||||
netif_carrier_off(dev);
|
|
||||||
ag71xx_phy_start(ag);
|
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;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -669,24 +702,10 @@ err:
|
||||||
static int ag71xx_stop(struct net_device *dev)
|
static int ag71xx_stop(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct ag71xx *ag = netdev_priv(dev);
|
struct ag71xx *ag = netdev_priv(dev);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
netif_carrier_off(dev);
|
netif_carrier_off(dev);
|
||||||
ag71xx_phy_stop(ag);
|
ag71xx_phy_stop(ag);
|
||||||
|
ag71xx_hw_disable(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);
|
|
||||||
|
|
||||||
return 0;
|
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);
|
struct ag71xx *ag = container_of(work, struct ag71xx, restart_work);
|
||||||
|
|
||||||
if (ag71xx_get_pdata(ag)->is_ar724x) {
|
rtnl_lock();
|
||||||
ag->link = 0;
|
ag71xx_hw_disable(ag);
|
||||||
ag71xx_link_adjust(ag);
|
ag71xx_hw_enable(ag);
|
||||||
return;
|
if (ag->link)
|
||||||
}
|
__ag71xx_link_adjust(ag, false);
|
||||||
|
rtnl_unlock();
|
||||||
ag71xx_stop(ag->dev);
|
|
||||||
ag71xx_open(ag->dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp)
|
static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp)
|
||||||
|
|
Loading…
Reference in New Issue