X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/a101c79bb0735e1dd5c90abc899ff7f7027ccadd..07282cf2232fe3fef7b66e2a6694c2aec6250463:/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c 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 db1855b9a..ebcb907cb 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c @@ -11,6 +11,7 @@ * by the Free Software Foundation. */ +#include #include "ag71xx.h" #define AG71XX_DEFAULT_MSG_ENABLE \ @@ -23,10 +24,10 @@ | NETIF_MSG_RX_ERR \ | NETIF_MSG_TX_ERR ) -static int ag71xx_debug = -1; +static int ag71xx_msg_level = -1; -module_param(ag71xx_debug, int, 0); -MODULE_PARM_DESC(ag71xx_debug, "Debug level (-1=defaults,0=none,...,16=all)"); +module_param_named(msg_level, ag71xx_msg_level, int, 0); +MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); static void ag71xx_dump_dma_regs(struct ag71xx *ag) { @@ -85,19 +86,27 @@ static void ag71xx_ring_free(struct ag71xx_ring *ring) { kfree(ring->buf); - if (ring->descs) - dma_free_coherent(NULL, ring->size * sizeof(*ring->descs), - ring->descs, ring->descs_dma); + if (ring->descs_cpu) + dma_free_coherent(NULL, ring->size * ring->desc_size, + ring->descs_cpu, ring->descs_dma); } static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size) { int err; + int i; + + ring->desc_size = sizeof(struct ag71xx_desc); + if (ring->desc_size % cache_line_size()) { + DBG("ag71xx: ring %p, desc size %u rounded to %u\n", + ring, ring->desc_size, + roundup(ring->desc_size, cache_line_size())); + ring->desc_size = roundup(ring->desc_size, cache_line_size()); + } - ring->descs = dma_alloc_coherent(NULL, size * sizeof(*ring->descs), - &ring->descs_dma, - GFP_ATOMIC); - if (!ring->descs) { + ring->descs_cpu = dma_alloc_coherent(NULL, size * ring->desc_size, + &ring->descs_dma, GFP_ATOMIC); + if (!ring->descs_cpu) { err = -ENOMEM; goto err; } @@ -110,6 +119,12 @@ static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size) goto err; } + for (i = 0; i < size; i++) { + ring->buf[i].desc = (struct ag71xx_desc *)&ring->descs_cpu[i * ring->desc_size]; + DBG("ag71xx: ring %p, desc %d at %p\n", + ring, i, ring->buf[i].desc); + } + return 0; err: @@ -124,8 +139,8 @@ static void ag71xx_ring_tx_clean(struct ag71xx *ag) while (ring->curr != ring->dirty) { u32 i = ring->dirty % AG71XX_TX_RING_SIZE; - if (!ag71xx_desc_empty(&ring->descs[i])) { - ring->descs[i].ctrl = 0; + if (!ag71xx_desc_empty(ring->buf[i].desc)) { + ring->buf[i].desc->ctrl = 0; dev->stats.tx_errors++; } @@ -148,10 +163,10 @@ static void ag71xx_ring_tx_init(struct ag71xx *ag) int i; for (i = 0; i < AG71XX_TX_RING_SIZE; i++) { - ring->descs[i].next = (u32) (ring->descs_dma + - sizeof(*ring->descs) * ((i + 1) % AG71XX_TX_RING_SIZE)); + ring->buf[i].desc->next = (u32) (ring->descs_dma + + ring->desc_size * ((i + 1) % AG71XX_TX_RING_SIZE)); - ring->descs[i].ctrl = DESC_EMPTY; + ring->buf[i].desc->ctrl = DESC_EMPTY; ring->buf[i].skb = NULL; } @@ -183,9 +198,14 @@ static int ag71xx_ring_rx_init(struct ag71xx *ag) int ret; ret = 0; - for (i = 0; i < AG71XX_RX_RING_SIZE; i++) - ring->descs[i].next = (u32) (ring->descs_dma + - sizeof(*ring->descs) * ((i + 1) % AG71XX_RX_RING_SIZE)); + for (i = 0; i < AG71XX_RX_RING_SIZE; i++) { + ring->buf[i].desc->next = (u32) (ring->descs_dma + + ring->desc_size * ((i + 1) % AG71XX_RX_RING_SIZE)); + + DBG("ag71xx: RX desc at %p, next is %08x\n", + ring->buf[i].desc, + ring->buf[i].desc->next); + } for (i = 0; i < AG71XX_RX_RING_SIZE; i++) { struct sk_buff *skb; @@ -203,8 +223,8 @@ static int ag71xx_ring_rx_init(struct ag71xx *ag) skb_reserve(skb, AG71XX_RX_PKT_RESERVE); ring->buf[i].skb = skb; - ring->descs[i].data = virt_to_phys(skb->data); - ring->descs[i].ctrl = DESC_EMPTY; + ring->buf[i].desc->data = virt_to_phys(skb->data); + ring->buf[i].desc->ctrl = DESC_EMPTY; } /* flush descriptors */ @@ -241,10 +261,10 @@ static int ag71xx_ring_rx_refill(struct ag71xx *ag) skb->dev = ag->dev; ring->buf[i].skb = skb; - ring->descs[i].data = virt_to_phys(skb->data); + ring->buf[i].desc->data = virt_to_phys(skb->data); } - ring->descs[i].ctrl = DESC_EMPTY; + ring->buf[i].desc->ctrl = DESC_EMPTY; count++; } @@ -298,6 +318,7 @@ static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac) static void ag71xx_dma_reset(struct ag71xx *ag) { + u32 val; int i; ag71xx_dump_dma_regs(ag); @@ -320,13 +341,19 @@ static void ag71xx_dma_reset(struct ag71xx *ag) 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); + 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 (ag71xx_rr(ag, AG71XX_REG_TX_STATUS)) - printk(KERN_ALERT "%s: unable to clear DMA Tx status\n", - ag->dev->name); + if (val) + printk(KERN_ALERT "%s: unable to clear DMA Tx status: %08x\n", + ag->dev->name, val); ag71xx_dump_dma_regs(ag); } @@ -375,8 +402,13 @@ static void ag71xx_hw_init(struct ag71xx *ag) /* 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); + if (pdata->is_ar724x) { + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, pdata->fifo_cfg1); + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, pdata->fifo_cfg2); + } else { + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000); + ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff); + } ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT); ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT); @@ -403,12 +435,16 @@ static void ag71xx_hw_stop(struct ag71xx *ag) static int ag71xx_open(struct net_device *dev) { struct ag71xx *ag = netdev_priv(dev); - int ret; + int err; - ret = ag71xx_rings_init(ag); - if (ret) + err = ag71xx_phy_connect(ag); + if (err) goto err; + err = ag71xx_rings_init(ag); + if (err) + goto err_ring_cleanup; + napi_enable(&ag->napi); netif_carrier_off(dev); @@ -425,9 +461,10 @@ static int ag71xx_open(struct net_device *dev) return 0; - err: + err_ring_cleanup: ag71xx_rings_cleanup(ag); - return ret; + err: + return err; } static int ag71xx_stop(struct net_device *dev) @@ -450,6 +487,7 @@ static int ag71xx_stop(struct net_device *dev) spin_unlock_irqrestore(&ag->lock, flags); ag71xx_rings_cleanup(ag); + ag71xx_phy_disconnect(ag); return 0; } @@ -457,22 +495,18 @@ static int ag71xx_stop(struct net_device *dev) static int ag71xx_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ag71xx *ag = netdev_priv(dev); - struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); struct ag71xx_ring *ring = &ag->tx_ring; struct ag71xx_desc *desc; - unsigned long flags; int i; i = ring->curr % AG71XX_TX_RING_SIZE; - desc = &ring->descs[i]; - - spin_lock_irqsave(&ag->lock, flags); - pdata->ddr_flush(); - spin_unlock_irqrestore(&ag->lock, flags); + desc = ring->buf[i].desc; if (!ag71xx_desc_empty(desc)) goto err_drop; + ag71xx_add_ar8216_header(ag, skb); + if (skb->len <= 0) { DBG("%s: packet len is too small\n", ag->dev->name); goto err_drop; @@ -559,7 +593,7 @@ static void ag71xx_oom_timer_handler(unsigned long data) struct net_device *dev = (struct net_device *) data; struct ag71xx *ag = netdev_priv(dev); - netif_rx_schedule(dev, &ag->napi); + napi_schedule(&ag->napi); } static void ag71xx_tx_timeout(struct net_device *dev) @@ -590,7 +624,7 @@ static void ag71xx_tx_packets(struct ag71xx *ag) sent = 0; while (ring->dirty != ring->curr) { unsigned int i = ring->dirty % AG71XX_TX_RING_SIZE; - struct ag71xx_desc *desc = &ring->descs[i]; + struct ag71xx_desc *desc = ring->buf[i].desc; struct sk_buff *skb = ring->buf[i].skb; if (!ag71xx_desc_empty(desc)) @@ -626,7 +660,7 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) while (done < limit) { unsigned int i = ring->curr % AG71XX_RX_RING_SIZE; - struct ag71xx_desc *desc = &ring->descs[i]; + struct ag71xx_desc *desc = ring->buf[i].desc; struct sk_buff *skb; int pktlen; @@ -647,15 +681,20 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) skb_put(skb, pktlen); skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; - netif_receive_skb(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pktlen; + if (ag71xx_remove_ar8216_header(ag, skb) != 0) { + dev->stats.rx_dropped++; + kfree_skb(skb); + } else { + skb->protocol = eth_type_trans(skb, dev); + netif_receive_skb(skb); + } + ring->buf[i].skb = NULL; done++; @@ -710,7 +749,7 @@ static int ag71xx_poll(struct napi_struct *napi, int limit) DBG("%s: disable polling mode, done=%d, limit=%d\n", dev->name, done, limit); - netif_rx_complete(dev, napi); + napi_complete(napi); /* enable interrupts */ spin_lock_irqsave(&ag->lock, flags); @@ -729,8 +768,8 @@ static int ag71xx_poll(struct napi_struct *napi, int limit) 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 done; + napi_complete(napi); + return 0; } static irqreturn_t ag71xx_interrupt(int irq, void *dev_id) @@ -759,7 +798,7 @@ static irqreturn_t ag71xx_interrupt(int irq, void *dev_id) 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); + napi_schedule(&ag->napi); } return IRQ_HANDLED; @@ -770,6 +809,18 @@ static void ag71xx_set_multicast_list(struct net_device *dev) /* TODO */ } +static const struct net_device_ops ag71xx_netdev_ops = { + .ndo_open = ag71xx_open, + .ndo_stop = ag71xx_stop, + .ndo_start_xmit = ag71xx_hard_start_xmit, + .ndo_set_multicast_list = ag71xx_set_multicast_list, + .ndo_do_ioctl = ag71xx_do_ioctl, + .ndo_tx_timeout = ag71xx_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __init ag71xx_probe(struct platform_device *pdev) { struct net_device *dev; @@ -785,6 +836,12 @@ static int __init ag71xx_probe(struct platform_device *pdev) goto err_out; } + if (pdata->mii_bus_dev == NULL) { + dev_err(&pdev->dev, "no MII bus device specified\n"); + err = -EINVAL; + goto err_out; + } + dev = alloc_etherdev(sizeof(*ag)); if (!dev) { dev_err(&pdev->dev, "alloc_etherdev failed\n"); @@ -797,8 +854,7 @@ static int __init ag71xx_probe(struct platform_device *pdev) ag = netdev_priv(dev); ag->pdev = pdev; ag->dev = dev; - ag->mii_bus = &ag71xx_mdio_bus->mii_bus; - ag->msg_enable = netif_msg_init(ag71xx_debug, + ag->msg_enable = netif_msg_init(ag71xx_msg_level, AG71XX_DEFAULT_MSG_ENABLE); spin_lock_init(&ag->lock); @@ -816,32 +872,18 @@ static int __init ag71xx_probe(struct platform_device *pdev) goto err_free_dev; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac_base2"); - if (!res) { - dev_err(&pdev->dev, "no mac_base2 resource found\n"); - err = -ENXIO; - goto err_unmap_base1; - } - - ag->mac_base2 = ioremap_nocache(res->start, res->end - res->start + 1); - if (!ag->mac_base) { - dev_err(&pdev->dev, "unable to ioremap mac_base2\n"); - err = -ENOMEM; - goto err_unmap_base1; - } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mii_ctrl"); if (!res) { dev_err(&pdev->dev, "no mii_ctrl resource found\n"); err = -ENXIO; - goto err_unmap_base2; + goto err_unmap_base; } ag->mii_ctrl = ioremap_nocache(res->start, res->end - res->start + 1); if (!ag->mii_ctrl) { dev_err(&pdev->dev, "unable to ioremap mii_ctrl\n"); err = -ENOMEM; - goto err_unmap_base2; + goto err_unmap_base; } dev->irq = platform_get_irq(pdev, 0); @@ -854,14 +896,9 @@ static int __init ag71xx_probe(struct platform_device *pdev) } dev->base_addr = (unsigned long)ag->mac_base; - dev->open = ag71xx_open; - dev->stop = ag71xx_stop; - dev->hard_start_xmit = ag71xx_hard_start_xmit; - dev->set_multicast_list = ag71xx_set_multicast_list; - dev->do_ioctl = ag71xx_do_ioctl; + dev->netdev_ops = &ag71xx_netdev_ops; dev->ethtool_ops = &ag71xx_ethtool_ops; - dev->tx_timeout = ag71xx_tx_timeout; INIT_WORK(&ag->restart_work, ag71xx_restart_work_func); init_timer(&ag->oom_timer); @@ -887,30 +924,15 @@ static int __init ag71xx_probe(struct platform_device *pdev) ag71xx_dump_regs(ag); - /* Reset the mdio bus explicitly */ - if (ag->mii_bus) { - mutex_lock(&ag->mii_bus->mdio_lock); - ag->mii_bus->reset(ag->mii_bus); - mutex_unlock(&ag->mii_bus->mdio_lock); - } - - err = ag71xx_phy_connect(ag); - if (err) - goto err_unregister_netdev; - platform_set_drvdata(pdev, dev); return 0; - err_unregister_netdev: - unregister_netdev(dev); err_free_irq: free_irq(dev->irq, dev); err_unmap_mii_ctrl: iounmap(ag->mii_ctrl); - err_unmap_base2: - iounmap(ag->mac_base2); - err_unmap_base1: + err_unmap_base: iounmap(ag->mac_base); err_free_dev: kfree(dev); @@ -926,11 +948,9 @@ static int __exit ag71xx_remove(struct platform_device *pdev) if (dev) { struct ag71xx *ag = netdev_priv(dev); - ag71xx_phy_disconnect(ag); unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(ag->mii_ctrl); - iounmap(ag->mac_base2); iounmap(ag->mac_base); kfree(dev); platform_set_drvdata(pdev, NULL);