static void ag71xx_dma_reset(struct ag71xx *ag) { int i; ag71xx_dump_dma_regs(ag); /* stop RX and TX */ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); /* clear descriptor addresses */ ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0); ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0); /* clear pending RX/TX interrupts */ for (i = 0; i < 256; i++) { ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); } /* clear pending errors */ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF); ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR); if (ag71xx_rr(ag, AG71XX_REG_RX_STATUS)) printk(KERN_ALERT "%s: unable to clear DMA Rx status\n", ag->dev->name); if (ag71xx_rr(ag, AG71XX_REG_TX_STATUS)) printk(KERN_ALERT "%s: unable to clear DMA Tx status\n", ag->dev->name); ag71xx_dump_dma_regs(ag); }
static irqreturn_t ag71xx_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct ag71xx *ag = netdev_priv(dev); u32 status; status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS); ag71xx_dump_intr(ag, "raw", status); if (unlikely(!status)) return IRQ_NONE; if (unlikely(status & AG71XX_INT_ERR)) { if (status & AG71XX_INT_TX_BE) { ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE); dev_err(&dev->dev, "TX BUS error\n"); } if (status & AG71XX_INT_RX_BE) { ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE); dev_err(&dev->dev, "RX BUS error\n"); } } if (likely(status & AG71XX_INT_POLL)) { ag71xx_int_disable(ag, AG71XX_INT_POLL); DBG("%s: enable polling mode\n", dev->name); netif_rx_schedule(dev, &ag->napi); } return IRQ_HANDLED; }
static void ag71xx_dma_reset(struct ag71xx *ag) { u32 val; int i; ag71xx_dump_dma_regs(ag); /* stop RX and TX */ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); /* * give the hardware some time to really stop all rx/tx activity * clearing the descriptors too early causes random memory corruption */ mdelay(1); /* clear descriptor addresses */ ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0); ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0); /* clear pending RX/TX interrupts */ for (i = 0; i < 256; i++) { ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); } /* clear pending errors */ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF); ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR); val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS); if (val) printk(KERN_ALERT "%s: unable to clear DMA Rx status: %08x\n", ag->dev->name, val); val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS); /* mask out reserved bits */ val &= ~0xff000000; if (val) printk(KERN_ALERT "%s: unable to clear DMA Tx status: %08x\n", ag->dev->name, val); ag71xx_dump_dma_regs(ag); }
static ssize_t read_file_ring(struct file *file, char __user *user_buf, size_t count, loff_t *ppos, struct ag71xx *ag, struct ag71xx_ring *ring, unsigned desc_reg) { int ring_size = BIT(ring->order); int ring_mask = ring_size - 1; char *buf; unsigned int buflen; unsigned int len = 0; unsigned long flags; ssize_t ret; int curr; int dirty; u32 desc_hw; int i; buflen = (ring_size * DESC_PRINT_LEN); buf = kmalloc(buflen, GFP_KERNEL); if (!buf) return -ENOMEM; len += snprintf(buf + len, buflen - len, "Idx ... %-8s %-8s %-8s %-8s . %-10s\n", "desc", "next", "data", "ctrl", "timestamp"); spin_lock_irqsave(&ag->lock, flags); curr = (ring->curr & ring_mask); dirty = (ring->dirty & ring_mask); desc_hw = ag71xx_rr(ag, desc_reg); for (i = 0; i < ring_size; i++) { struct ag71xx_buf *ab = &ring->buf[i]; struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i); u32 desc_dma = ((u32) ring->descs_dma) + i * AG71XX_DESC_SIZE; len += snprintf(buf + len, buflen - len, "%3d %c%c%c %08x %08x %08x %08x %c %10lu\n", i, (i == curr) ? 'C' : ' ', (i == dirty) ? 'D' : ' ', (desc_hw == desc_dma) ? 'H' : ' ', desc_dma, desc->next, desc->data, desc->ctrl, (desc->ctrl & DESC_EMPTY) ? 'E' : '*', ab->timestamp); } spin_unlock_irqrestore(&ag->lock, flags); ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return ret; }
static irqreturn_t ag71xx_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct ag71xx *ag = netdev_priv(dev); u32 status; status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS); status &= ag71xx_rr(ag, AG71XX_REG_INT_ENABLE); if (unlikely(!status)) return IRQ_NONE; if (unlikely(status & AG71XX_INT_ERR)) { if (status & AG71XX_INT_TX_BE) { ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE); dev_err(&dev->dev, "TX BUS error\n"); } if (status & AG71XX_INT_RX_BE) { ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE); dev_err(&dev->dev, "RX BUS error\n"); } } #if 0 if (unlikely(status & AG71XX_INT_TX_UR)) { ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_UR); DBG("%s: TX underrun\n", dev->name); } #endif #ifndef AG71XX_NAPI_TX if (likely(status & AG71XX_INT_TX_PS)) ag71xx_tx_packets(ag); #endif if (likely(status & AG71XX_INT_POLL)) { ag71xx_int_disable(ag, AG71XX_INT_POLL); DBG("%s: enable polling mode\n", dev->name); netif_rx_schedule(dev, &ag->napi); } return IRQ_HANDLED; }
static int ag71xx_poll(struct napi_struct *napi, int limit) { struct ag71xx *ag = container_of(napi, struct ag71xx, napi); #ifdef AG71XX_NAPI_TX struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); #endif struct net_device *dev = ag->dev; unsigned long flags; u32 status; int done; #ifdef AG71XX_NAPI_TX ar71xx_ddr_flush(pdata->flush_reg); ag71xx_tx_packets(ag); #endif DBG("%s: processing RX ring\n", dev->name); done = ag71xx_rx_packets(ag, limit); /* TODO: add OOM handler */ status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS); status &= AG71XX_INT_POLL; if ((done < limit) && (!status)) { DBG("%s: disable polling mode, done=%d, status=%x\n", dev->name, done, status); netif_rx_complete(dev, napi); /* enable interrupts */ spin_lock_irqsave(&ag->lock, flags); ag71xx_int_enable(ag, AG71XX_INT_POLL); spin_unlock_irqrestore(&ag->lock, flags); return 0; } if (status & AG71XX_INT_RX_OF) { if (netif_msg_rx_err(ag)) printk(KERN_ALERT "%s: rx owerflow, restarting dma\n", dev->name); /* ack interrupt */ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF); /* restart RX */ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE); } DBG("%s: stay in polling mode, done=%d, status=%x\n", dev->name, done, status); return 1; }
static void ag71xx_dump_dma_regs(struct ag71xx *ag) { DBG("%s: dma_tx_ctrl=%08x, dma_tx_desc=%08x, dma_tx_status=%08x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_TX_CTRL), ag71xx_rr(ag, AG71XX_REG_TX_DESC), ag71xx_rr(ag, AG71XX_REG_TX_STATUS)); DBG("%s: dma_rx_ctrl=%08x, dma_rx_desc=%08x, dma_rx_status=%08x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_RX_CTRL), ag71xx_rr(ag, AG71XX_REG_RX_DESC), ag71xx_rr(ag, AG71XX_REG_RX_STATUS)); }
static int ag71xx_poll(struct napi_struct *napi, int limit) { struct ag71xx *ag = container_of(napi, struct ag71xx, napi); struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); struct net_device *dev = ag->dev; struct ag71xx_ring *rx_ring; unsigned long flags; u32 status; int done; pdata->ddr_flush(); ag71xx_tx_packets(ag); DBG("%s: processing RX ring\n", dev->name); done = ag71xx_rx_packets(ag, limit); rx_ring = &ag->rx_ring; if (rx_ring->buf[rx_ring->dirty % AG71XX_RX_RING_SIZE].skb == NULL) goto oom; status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS); if (unlikely(status & RX_STATUS_OF)) { ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF); dev->stats.rx_fifo_errors++; /* restart RX */ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE); } if (done < limit) { if (status & RX_STATUS_PR) goto more; status = ag71xx_rr(ag, AG71XX_REG_TX_STATUS); if (status & TX_STATUS_PS) goto more; DBG("%s: disable polling mode, done=%d, limit=%d\n", dev->name, done, limit); netif_rx_complete(dev, napi); /* enable interrupts */ spin_lock_irqsave(&ag->lock, flags); ag71xx_int_enable(ag, AG71XX_INT_POLL); spin_unlock_irqrestore(&ag->lock, flags); return done; } more: DBG("%s: stay in polling mode, done=%d, limit=%d\n", dev->name, done, limit); return done; oom: if (netif_msg_rx_err(ag)) printk(KERN_DEBUG "%s: out of memory\n", dev->name); mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL); netif_rx_complete(dev, napi); return 0; }
static void ag71xx_dump_regs(struct ag71xx *ag) { DBG("%s: mac_cfg1=%08x, mac_cfg2=%08x, ipg=%08x, hdx=%08x, mfl=%08x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_MAC_CFG1), ag71xx_rr(ag, AG71XX_REG_MAC_CFG2), ag71xx_rr(ag, AG71XX_REG_MAC_IPG), ag71xx_rr(ag, AG71XX_REG_MAC_HDX), ag71xx_rr(ag, AG71XX_REG_MAC_MFL)); DBG("%s: mac_ifctl=%08x, mac_addr1=%08x, mac_addr2=%08x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL), ag71xx_rr(ag, AG71XX_REG_MAC_ADDR1), ag71xx_rr(ag, AG71XX_REG_MAC_ADDR2)); DBG("%s: fifo_cfg0=%08x, fifo_cfg1=%08x, fifo_cfg2=%08x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2)); DBG("%s: fifo_cfg3=%08x, fifo_cfg4=%08x, fifo_cfg5=%08x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5)); }
void ag71xx_link_adjust(struct ag71xx *ag) { struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); u32 cfg2; u32 ifctl; u32 fifo5; u32 mii_speed; if (!ag->link) { netif_carrier_off(ag->dev); if (netif_msg_link(ag)) printk(KERN_INFO "%s: link down\n", ag->dev->name); return; } cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2); cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX); cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0; ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL); ifctl &= ~(MAC_IFCTL_SPEED); fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5); fifo5 &= ~FIFO_CFG5_BM; switch (ag->speed) { case SPEED_1000: mii_speed = MII_CTRL_SPEED_1000; cfg2 |= MAC_CFG2_IF_1000; fifo5 |= FIFO_CFG5_BM; break; case SPEED_100: mii_speed = MII_CTRL_SPEED_100; cfg2 |= MAC_CFG2_IF_10_100; ifctl |= MAC_IFCTL_SPEED; break; case SPEED_10: mii_speed = MII_CTRL_SPEED_10; cfg2 |= MAC_CFG2_IF_10_100; break; default: BUG(); return; } if (pdata->is_ar91xx) ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff); else if (pdata->is_ar724x) ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, pdata->fifo_cfg3); else ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff); if (pdata->set_pll) pdata->set_pll(ag->speed); ag71xx_mii_ctrl_set_speed(ag, mii_speed); ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5); ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl); netif_carrier_on(ag->dev); if (netif_msg_link(ag)) printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n", ag->dev->name, ag71xx_speed_str(ag), (DUPLEX_FULL == ag->duplex) ? "Full" : "Half"); DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2)); DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5)); DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x, mii_ctrl=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_MAC_CFG2), ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL), ag71xx_mii_ctrl_rr(ag)); }
static void ag71xx_phy_link_update(struct ag71xx *ag) { u32 cfg2; u32 ifctl; u32 pll; u32 fifo5; u32 mii_speed; if (!ag->link) { netif_carrier_off(ag->dev); if (netif_msg_link(ag)) printk(KERN_INFO "%s: link down\n", ag->dev->name); return; } cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2); cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX); cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0; ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL); ifctl &= ~(MAC_IFCTL_SPEED); fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5); fifo5 &= ~FIFO_CFG5_BYTE_PER_CLK; switch (ag->speed) { case SPEED_1000: mii_speed = MII_CTRL_SPEED_1000; cfg2 |= MAC_CFG2_IF_1000; pll = PLL_VAL_1000; fifo5 |= FIFO_CFG5_BYTE_PER_CLK; break; case SPEED_100: mii_speed = MII_CTRL_SPEED_100; cfg2 |= MAC_CFG2_IF_10_100; ifctl |= MAC_IFCTL_SPEED; pll = PLL_VAL_100; break; case SPEED_10: mii_speed = MII_CTRL_SPEED_10; cfg2 |= MAC_CFG2_IF_10_100; pll = PLL_VAL_10; break; default: BUG(); return; } ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff); ag71xx_set_pll(ag, pll); ag71xx_mii_ctrl_set_speed(ag, mii_speed); ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5); ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl); netif_carrier_on(ag->dev); if (netif_msg_link(ag)) printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n", ag->dev->name, ag71xx_speed_str(ag), (DUPLEX_FULL == ag->duplex) ? "Full" : "Half"); DBG("%s: fifo1=%#x, fifo2=%#x, fifo3=%#x, fifo4=%#x, fifo5=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4), ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5)); DBG("%s: mac_cfg2=%#x, ifctl=%#x, mii_ctrl=%#x\n", ag->dev->name, ag71xx_rr(ag, AG71XX_REG_MAC_CFG2), ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL), ag71xx_mii_ctrl_rr(ag)); }