diff options
Diffstat (limited to 'target')
-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 030811c3c6..6979d41bc0 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); |