diff options
| author | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-06-20 21:57:49 +0000 | 
|---|---|---|
| committer | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-06-20 21:57:49 +0000 | 
| commit | ee556c7f7b62647304f3395ddf723eaf880262b6 (patch) | |
| tree | fea0470970e99ddb23f3dc55ccdb47293484cab7 /target/linux/mcs814x/files-3.3/drivers/net/ethernet/mcs8140 | |
| parent | 3a5b7c7629c57edb6063c839ccad36ab48353726 (diff) | |
[mcs814x] improve ethernet driver debugging
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@32471 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/mcs814x/files-3.3/drivers/net/ethernet/mcs8140')
| -rw-r--r-- | target/linux/mcs814x/files-3.3/drivers/net/ethernet/mcs8140/nuport_mac.c | 121 | 
1 files changed, 102 insertions, 19 deletions
diff --git a/target/linux/mcs814x/files-3.3/drivers/net/ethernet/mcs8140/nuport_mac.c b/target/linux/mcs814x/files-3.3/drivers/net/ethernet/mcs8140/nuport_mac.c index 030811c3c..6979d41bc 100644 --- a/target/linux/mcs814x/files-3.3/drivers/net/ethernet/mcs8140/nuport_mac.c +++ b/target/linux/mcs814x/files-3.3/drivers/net/ethernet/mcs8140/nuport_mac.c @@ -139,6 +139,7 @@ struct nuport_mac_priv {  	struct phy_device	*phydev;  	int			old_link;  	int			old_duplex; +	u32			msg_level;  };  void dcache_invalidate_only(unsigned long start, unsigned long end) @@ -231,8 +232,10 @@ static int nuport_mac_start_tx_dma(struct nuport_mac_priv *priv,  	while (timeout--) {  		reg = nuport_mac_readl(TX_START_DMA); -		if (!(reg & 0x01)) +		if (!(reg & 0x01)) { +			netdev_dbg(priv->dev, "dma ready\n");  			break; +		}  		cpu_relax();  	} @@ -243,7 +246,7 @@ static int nuport_mac_start_tx_dma(struct nuport_mac_priv *priv,  			skb->len, DMA_TO_DEVICE);  	/* enable enhanced mode */ -	nuport_mac_writel(0x03, TX_DMA_ENH); +	nuport_mac_writel(0x01, TX_DMA_ENH);  	nuport_mac_writel(p, TX_BUFFER_ADDR);  	nuport_mac_writel((skb->len) - 1, TX_PKT_BYTES);  	wmb(); @@ -261,10 +264,24 @@ static void nuport_mac_reset_tx_dma(struct nuport_mac_priv *priv)  	nuport_mac_writel(reg, TX_START_DMA);  } -static void nuport_mac_start_rx_dma(struct nuport_mac_priv *priv, +static int nuport_mac_start_rx_dma(struct nuport_mac_priv *priv,  					struct sk_buff *skb)  {  	dma_addr_t p; +	u32 reg; +	unsigned int timeout = 2048; + +	while (timeout--) { +		reg = nuport_mac_readl(RX_START_DMA); +		if (!(reg & 0x01)) { +			netdev_dbg(priv->dev, "dma ready\n"); +			break; +		} +		cpu_relax(); +	} + +	if (!timeout) +		return -EBUSY;  	p = dma_map_single(&priv->pdev->dev, skb->data,  				RX_ALLOC_SIZE, DMA_FROM_DEVICE); @@ -272,6 +289,8 @@ static void nuport_mac_start_rx_dma(struct nuport_mac_priv *priv,  	nuport_mac_writel(p, RX_BUFFER_ADDR);  	wmb();  	nuport_mac_writel(0x01, RX_START_DMA); + +	return 0;  }  static void nuport_mac_reset_rx_dma(struct nuport_mac_priv *priv) @@ -309,11 +328,16 @@ static int nuport_mac_start_xmit(struct sk_buff *skb, struct net_device *dev)  	struct nuport_mac_priv *priv = netdev_priv(dev);  	int ret; -	dcache_clean_range((u32) skb->data, (u32)(skb->data + skb->len)); +	if (netif_queue_stopped(dev)) { +		netdev_warn(dev, "netif queue was stopped, restarting\n"); +		netif_start_queue(dev); +	} +  	spin_lock_irqsave(&priv->lock, flags);  	if (priv->first_pkt) {  		ret = nuport_mac_start_tx_dma(priv, skb);  		if (ret) { +			netif_stop_queue(dev);  			spin_unlock_irqrestore(&priv->lock, flags);  			netdev_err(dev, "transmit path busy\n");  			return NETDEV_TX_BUSY; @@ -335,6 +359,7 @@ static int nuport_mac_start_xmit(struct sk_buff *skb, struct net_device *dev)  	if (priv->valid_txskb[priv->cur_tx]) {  		priv->tx_full = 1; +		netdev_err(dev, "stopping queue\n");  		netif_stop_queue(dev);  	} @@ -407,8 +432,20 @@ static irqreturn_t nuport_mac_tx_interrupt(int irq, void *dev_id)  	struct sk_buff *skb;  	unsigned long flags;  	int ret; +	u32 reg;  	spin_lock_irqsave(&priv->lock, flags); +	/* clear status word available if ready */ +	reg = nuport_mac_readl(TX_START_DMA); +	if (reg & (1 << 18)) { +		nuport_mac_writel(reg, TX_START_DMA); +		reg = nuport_mac_readl(TX_DMA_STATUS); + +		if (reg & 1) +			dev->stats.tx_errors++; +	} else +		netdev_dbg(dev, "no status word: %08x\n", reg); +  	skb = priv->tx_skb[priv->dma_tx];  	priv->tx_skb[priv->dma_tx] = NULL;  	priv->valid_txskb[priv->dma_tx] = 0; @@ -427,7 +464,7 @@ static irqreturn_t nuport_mac_tx_interrupt(int irq, void *dev_id)  	}  	if (priv->tx_full) { -		netdev_err(dev, "restarting transmit queue\n"); +		netdev_dbg(dev, "restarting transmit queue\n");  		netif_wake_queue(dev);  		priv->tx_full = 0;  	} @@ -442,7 +479,7 @@ static unsigned int nuport_mac_has_work(struct nuport_mac_priv *priv)  	unsigned int i;  	for (i = 0; i < RX_RING_SIZE; i++) -		if (priv->irq_rxskb[i]) +		if (priv->rx_skb[i])  			return 1;  	return 0; @@ -453,24 +490,33 @@ static irqreturn_t nuport_mac_rx_interrupt(int irq, void *dev_id)  	struct net_device *dev = (struct net_device *)dev_id;  	struct nuport_mac_priv *priv = netdev_priv(dev);  	unsigned long flags; +	int ret;  	spin_lock_irqsave(&priv->lock, flags); -	priv->pkt_len[priv->dma_rx] = nuport_mac_readl(RX_ACT_BYTES) - 4; -	priv->irq_rxskb[priv->dma_rx] = 0; -	priv->dma_rx++; - -	if (priv->dma_rx >= RX_RING_SIZE) -		priv->dma_rx = 0; - -	if (priv->irq_rxskb[priv->dma_rx] == 1) -		nuport_mac_start_rx_dma(priv, priv->rx_skb[priv->dma_rx]); +	if (!priv->rx_full) { +		priv->pkt_len[priv->dma_rx] = nuport_mac_readl(RX_ACT_BYTES) - 4; +		priv->irq_rxskb[priv->dma_rx] = 0; +		priv->dma_rx++; + +		if (priv->dma_rx >= RX_RING_SIZE) +			priv->dma_rx = 0; +	} else +		priv->rx_full = 0; + +	if (priv->irq_rxskb[priv->dma_rx] == 1) { +		ret = nuport_mac_start_rx_dma(priv, priv->rx_skb[priv->dma_rx]); +		if (ret) +			netdev_err(dev, "failed to start rx dma\n"); +	} else { +		priv->rx_full = 1; +		netdev_dbg(dev, "RX ring full\n"); +	}  	if (likely(nuport_mac_has_work(priv))) {  		/* find a way to disable DMA rx irq */  		nuport_mac_disable_rx_dma(priv);  		napi_schedule(&priv->napi);  	} -  	spin_unlock_irqrestore(&priv->lock, flags);  	return IRQ_HANDLED; @@ -742,9 +788,7 @@ static int nuport_mac_open(struct net_device *dev)  	nuport_mac_reset_rx_dma(priv);  	/* Start RX DMA */ -	nuport_mac_start_rx_dma(priv, priv->rx_skb[0]); - -	return 0; +	return nuport_mac_start_rx_dma(priv, priv->rx_skb[0]);  out_rx_skb:  	nuport_mac_free_rx_ring(priv); @@ -782,6 +826,26 @@ static int nuport_mac_close(struct net_device *dev)  	return 0;  } +static void nuport_mac_tx_timeout(struct net_device *dev) +{ +	struct nuport_mac_priv *priv = netdev_priv(dev); +	unsigned int i; + +	netdev_warn(dev, "transmit timeout, attempting recovery\n"); + +	netdev_info(dev, "TX DMA regs\n"); +	for (i = 0; i < DMA_CHAN_WIDTH; i += 4) +		netdev_info(dev, "[%02x]: 0x%08x\n", i, nuport_mac_readl(TX_DMA_BASE + i)); +	netdev_info(dev, "RX DMA regs\n"); +	for (i = 0; i < DMA_CHAN_WIDTH; i += 4) +		netdev_info(dev, "[%02x]: 0x%08x\n", i, nuport_mac_readl(RX_DMA_BASE + i)); + +	nuport_mac_init_tx_ring(priv); +	nuport_mac_reset_tx_dma(priv); + +	netif_wake_queue(dev); +} +  static int nuport_mac_mii_probe(struct net_device *dev)  {  	struct nuport_mac_priv *priv = netdev_priv(dev); @@ -864,11 +928,27 @@ static int nuport_mac_ethtool_set_settings(struct net_device *dev,  	return -EINVAL;  } +static void nuport_mac_set_msglevel(struct net_device *dev, u32 msg_level) +{ +	struct nuport_mac_priv *priv = netdev_priv(dev); + +	priv->msg_level = msg_level; +} + +static u32 nuport_mac_get_msglevel(struct net_device *dev) +{ +	struct nuport_mac_priv *priv = netdev_priv(dev); + +	return priv->msg_level; +} +  static const struct ethtool_ops nuport_mac_ethtool_ops = {  	.get_drvinfo		= nuport_mac_ethtool_drvinfo,  	.get_link		= ethtool_op_get_link,  	.get_settings		= nuport_mac_ethtool_get_settings,  	.set_settings		= nuport_mac_ethtool_set_settings, +	.set_msglevel		= nuport_mac_set_msglevel, +	.get_msglevel		= nuport_mac_get_msglevel,  };  static const struct net_device_ops nuport_mac_ops = { @@ -878,6 +958,7 @@ static const struct net_device_ops nuport_mac_ops = {  	.ndo_change_mtu		= eth_change_mtu,  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_set_mac_address	= nuport_mac_change_mac_address, +	.ndo_tx_timeout		= nuport_mac_tx_timeout,  };  static int __init nuport_mac_probe(struct platform_device *pdev) @@ -951,10 +1032,12 @@ static int __init nuport_mac_probe(struct platform_device *pdev)  	priv->link_irq = link_irq;  	priv->rx_irq = rx_irq;  	priv->tx_irq = tx_irq; +	priv->msg_level = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK;  	dev->netdev_ops = &nuport_mac_ops;  	dev->ethtool_ops = &nuport_mac_ethtool_ops;  	dev->watchdog_timeo = HZ;  	dev->flags = IFF_BROADCAST;	/* Supports Broadcast */ +	dev->tx_queue_len = TX_RING_SIZE / 2;  	netif_napi_add(dev, &priv->napi, nuport_mac_poll, 64);  | 
