* by the Free Software Foundation.
*/
+#include <linux/cache.h>
#include "ag71xx.h"
#define AG71XX_DEFAULT_MSG_ENABLE \
| 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)
{
{
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;
}
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:
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++;
}
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;
}
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;
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 */
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++;
}
static void ag71xx_dma_reset(struct ag71xx *ag)
{
+ u32 val;
int i;
ag71xx_dump_dma_regs(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);
- if (ag71xx_rr(ag, AG71XX_REG_TX_STATUS))
- printk(KERN_ALERT "%s: unable to clear DMA Tx status\n",
- ag->dev->name);
+ /* 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);
}
/* 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);
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;
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)
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))
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;
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++;
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);
printk(KERN_DEBUG "%s: out of memory\n", dev->name);
mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL);
- netif_rx_complete(dev, napi);
+ napi_complete(napi);
return 0;
}
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;
/* 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;
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");
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);
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);
}
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);
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;
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);
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);