X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fsvn-archive%2Farchive.git;a=blobdiff_plain;f=target%2Flinux%2Far71xx%2Ffiles%2Fdrivers%2Fnet%2Fag71xx%2Fag71xx_main.c;h=5e31438b301ec56e9da6fd3e553a761faed85cd6;hp=53376fa817308a97e128c62177486e81bc9a9aa2;hb=9a1100e2e88d50ac2aaab3a26ac0b46f5dd21c0c;hpb=1ffcdf32eb63027b3c089e9ca7e88325a9f09bda diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c index 53376fa817..5e31438b30 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c @@ -28,6 +28,21 @@ static int ag71xx_debug = -1; module_param(ag71xx_debug, int, 0); MODULE_PARM_DESC(ag71xx_debug, "Debug level (-1=defaults,0=none,...,16=all)"); +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 void ag71xx_dump_regs(struct ag71xx *ag) { DBG("%s: mac_cfg1=%08x, mac_cfg2=%08x, ipg=%08x, hdx=%08x, mfl=%08x\n", @@ -47,13 +62,25 @@ static void ag71xx_dump_regs(struct ag71xx *ag) 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_cfg3=%08x, fifo_cfg5=%08x\n", + 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)); } +static inline void ag71xx_dump_intr(struct ag71xx *ag, char *label, u32 intr) +{ + DBG("%s: %s intr=%08x %s%s%s%s%s%s\n", + ag->dev->name, label, intr, + (intr & AG71XX_INT_TX_PS) ? "TXPS " : "", + (intr & AG71XX_INT_TX_UR) ? "TXUR " : "", + (intr & AG71XX_INT_TX_BE) ? "TXBE " : "", + (intr & AG71XX_INT_RX_PR) ? "RXPR " : "", + (intr & AG71XX_INT_RX_OF) ? "RXOF " : "", + (intr & AG71XX_INT_RX_BE) ? "RXBE " : ""); +} + static void ag71xx_ring_free(struct ag71xx_ring *ring) { kfree(ring->buf); @@ -169,6 +196,9 @@ static int ag71xx_ring_rx_init(struct ag71xx *ag) break; } + dma_map_single(NULL, skb->data, AG71XX_RX_PKT_SIZE, + DMA_FROM_DEVICE); + skb->dev = ag->dev; skb_reserve(skb, AG71XX_RX_PKT_RESERVE); @@ -207,8 +237,12 @@ static int ag71xx_ring_rx_refill(struct ag71xx *ag) break; } + dma_map_single(NULL, skb->data, AG71XX_RX_PKT_SIZE, + DMA_FROM_DEVICE); + skb_reserve(skb, AG71XX_RX_PKT_RESERVE); skb->dev = ag->dev; + ring->buf[i].skb = skb; ring->descs[i].data = virt_to_phys(skb->data); } @@ -257,7 +291,7 @@ static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac) u32 t; t = (((u32) mac[0]) << 24) | (((u32) mac[1]) << 16) - | (((u32) mac[2]) << 8) | ((u32) mac[2]); + | (((u32) mac[2]) << 8) | ((u32) mac[3]); ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t); @@ -265,11 +299,52 @@ static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac) ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t); } -#define MAC_CFG1_INIT (MAC_CFG1_RXE | MAC_CFG1_TXE | MAC_CFG1_SRX \ - | MAC_CFG1_STX) +#define AR71XX_MAC_CFG1_INIT (MAC_CFG1_RXE | MAC_CFG1_TXE | \ + MAC_CFG1_SRX | MAC_CFG1_STX) +#define AR71XX_FIFO_CFG5_INIT 0x0007ffef + +#define AR91XX_MAC_CFG1_INIT (MAC_CFG1_RXE | MAC_CFG1_TXE | \ + MAC_CFG1_SRX | MAC_CFG1_STX | \ + MAC_CFG1_TFC | MAC_CFG1_RFC) +#define AR91XX_FIFO_CFG5_INIT 0x0007efef #define FIFO_CFG0_INIT (FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT) +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 void ag71xx_hw_init(struct ag71xx *ag) { struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); @@ -282,21 +357,28 @@ static void ag71xx_hw_init(struct ag71xx *ag) ar71xx_device_start(pdata->reset_bit); mdelay(100); - ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT); - - /* TODO: set max packet size */ - + /* setup MAC configuration registers */ + ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, + pdata->is_ar91xx ? AR91XX_MAC_CFG1_INIT : AR71XX_MAC_CFG1_INIT); ag71xx_sb(ag, AG71XX_REG_MAC_CFG2, MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK); - ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT); + /* setup max frame length */ + ag71xx_wr(ag, AG71XX_REG_MAC_MFL, AG71XX_TX_MTU_LEN); + /* setup MII interface type */ ag71xx_mii_ctrl_set_if(ag, pdata->mii_if); + /* setup FIFO configuration registers */ + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, 0x0000ffff); - ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, 0x0007ffef); + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, + pdata->is_ar91xx ? AR91XX_FIFO_CFG5_INIT + : AR71XX_FIFO_CFG5_INIT); + + ag71xx_dma_reset(ag); } static void ag71xx_hw_start(struct ag71xx *ag) @@ -310,12 +392,10 @@ static void ag71xx_hw_start(struct ag71xx *ag) static void ag71xx_hw_stop(struct ag71xx *ag) { - /* stop RX and TX */ - ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); - ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); - /* disable all interrupts */ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0); + + ag71xx_dma_reset(ag); } static int ag71xx_open(struct net_device *dev) @@ -384,7 +464,7 @@ static int ag71xx_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) desc = &ring->descs[i]; spin_lock_irqsave(&ag->lock, flags); - ar71xx_ddr_flush(pdata->flush_reg); + pdata->ddr_flush(); spin_unlock_irqrestore(&ag->lock, flags); if (!ag71xx_desc_empty(desc)) @@ -395,7 +475,7 @@ static int ag71xx_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) goto err_drop; } - dma_cache_wback_inv((unsigned long)skb->data, skb->len); + dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); ring->buf[i].skb = skb; @@ -480,7 +560,7 @@ static void ag71xx_tx_packets(struct ag71xx *ag) DBG("%s: processing TX ring\n", ag->dev->name); #ifdef AG71XX_NAPI_TX - ar71xx_ddr_flush(pdata->flush_reg); + pdata->ddr_flush(); #endif sent = 0; @@ -523,7 +603,7 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) #ifndef AG71XX_NAPI_TX spin_lock_irqsave(&ag->lock, flags); - ar71xx_ddr_flush(pdata->flush_reg); + pdata->ddr_flush(); spin_unlock_irqrestore(&ag->lock, flags); #endif @@ -544,17 +624,17 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) break; } + ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); + skb = ring->buf[i].skb; pktlen = ag71xx_desc_pktlen(desc); pktlen -= ETH_FCS_LEN; - /* TODO: move it into the refill function */ - dma_cache_wback_inv((unsigned long)skb->data, pktlen); skb_put(skb, pktlen); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->ip_summed = CHECKSUM_NONE; netif_receive_skb(skb); @@ -565,8 +645,6 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) ring->buf[i].skb = NULL; done++; - ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); - ring->curr++; if ((ring->curr - ring->dirty) > (AG71XX_RX_RING_SIZE / 4)) ag71xx_ring_rx_refill(ag); @@ -592,7 +670,7 @@ static int ag71xx_poll(struct napi_struct *napi, int limit) int done; #ifdef AG71XX_NAPI_TX - ar71xx_ddr_flush(pdata->flush_reg); + pdata->ddr_flush(); ag71xx_tx_packets(ag); #endif @@ -601,10 +679,16 @@ static int ag71xx_poll(struct napi_struct *napi, int limit) /* TODO: add OOM handler */ - status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS); - status &= AG71XX_INT_POLL; + 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) && (!status)) { + if ((done < limit) && ((status & RX_STATUS_PR) == 0)) { DBG("%s: disable polling mode, done=%d, status=%x\n", dev->name, done, status); @@ -617,17 +701,6 @@ static int ag71xx_poll(struct napi_struct *napi, int limit) 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; @@ -640,7 +713,9 @@ static irqreturn_t ag71xx_interrupt(int irq, void *dev_id) u32 status; status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS); + ag71xx_dump_intr(ag, "raw", status); status &= ag71xx_rr(ag, AG71XX_REG_INT_ENABLE); + ag71xx_dump_intr(ag, "masked", status); if (unlikely(!status)) return IRQ_NONE; @@ -882,6 +957,7 @@ static int __init ag71xx_module_init(void) static void __exit ag71xx_module_exit(void) { platform_driver_unregister(&ag71xx_driver); + ag71xx_mdio_driver_exit(); } module_init(ag71xx_module_init);