#include "ag71xx.h"
#define AG71XX_DEFAULT_MSG_ENABLE \
- ( NETIF_MSG_DRV \
+ (NETIF_MSG_DRV \
| NETIF_MSG_PROBE \
| NETIF_MSG_LINK \
| NETIF_MSG_TIMER \
| NETIF_MSG_IFDOWN \
| NETIF_MSG_IFUP \
| NETIF_MSG_RX_ERR \
- | NETIF_MSG_TX_ERR )
+ | NETIF_MSG_TX_ERR)
static int ag71xx_msg_level = -1;
ring->descs_cpu, ring->descs_dma);
}
-static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size)
+static int ag71xx_ring_alloc(struct ag71xx_ring *ring)
{
int err;
int i;
ring->desc_size = roundup(ring->desc_size, cache_line_size());
}
- ring->descs_cpu = dma_alloc_coherent(NULL, size * ring->desc_size,
+ ring->descs_cpu = dma_alloc_coherent(NULL, ring->size * ring->desc_size,
&ring->descs_dma, GFP_ATOMIC);
if (!ring->descs_cpu) {
err = -ENOMEM;
goto err;
}
- ring->size = size;
- ring->buf = kzalloc(size * sizeof(*ring->buf), GFP_KERNEL);
+ ring->buf = kzalloc(ring->size * sizeof(*ring->buf), GFP_KERNEL);
if (!ring->buf) {
err = -ENOMEM;
goto err;
}
- for (i = 0; i < size; i++) {
- ring->buf[i].desc = (struct ag71xx_desc *)&ring->descs_cpu[i * ring->desc_size];
+ for (i = 0; i < ring->size; i++) {
+ int idx = i * ring->desc_size;
+ ring->buf[i].desc = (struct ag71xx_desc *)&ring->descs_cpu[idx];
DBG("ag71xx: ring %p, desc %d at %p\n",
ring, i, ring->buf[i].desc);
}
return 0;
- err:
+err:
return err;
}
struct net_device *dev = ag->dev;
while (ring->curr != ring->dirty) {
- u32 i = ring->dirty % AG71XX_TX_RING_SIZE;
+ u32 i = ring->dirty % ring->size;
if (!ag71xx_desc_empty(ring->buf[i].desc)) {
ring->buf[i].desc->ctrl = 0;
struct ag71xx_ring *ring = &ag->tx_ring;
int i;
- for (i = 0; i < AG71XX_TX_RING_SIZE; i++) {
+ for (i = 0; i < ring->size; i++) {
ring->buf[i].desc->next = (u32) (ring->descs_dma +
- ring->desc_size * ((i + 1) % AG71XX_TX_RING_SIZE));
+ ring->desc_size * ((i + 1) % ring->size));
ring->buf[i].desc->ctrl = DESC_EMPTY;
ring->buf[i].skb = NULL;
if (!ring->buf)
return;
- for (i = 0; i < AG71XX_RX_RING_SIZE; i++)
+ for (i = 0; i < ring->size; i++)
if (ring->buf[i].skb) {
dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr,
AG71XX_RX_PKT_SIZE, DMA_FROM_DEVICE);
int ret;
ret = 0;
- for (i = 0; i < AG71XX_RX_RING_SIZE; i++) {
+ for (i = 0; i < ring->size; i++) {
ring->buf[i].desc->next = (u32) (ring->descs_dma +
- ring->desc_size * ((i + 1) % AG71XX_RX_RING_SIZE));
+ ring->desc_size * ((i + 1) % 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++) {
+ for (i = 0; i < ring->size; i++) {
struct sk_buff *skb;
dma_addr_t dma_addr;
for (; ring->curr - ring->dirty > 0; ring->dirty++) {
unsigned int i;
- i = ring->dirty % AG71XX_RX_RING_SIZE;
+ i = ring->dirty % ring->size;
if (ring->buf[i].skb == NULL) {
dma_addr_t dma_addr;
{
int ret;
- ret = ag71xx_ring_alloc(&ag->tx_ring, AG71XX_TX_RING_SIZE);
+ ret = ag71xx_ring_alloc(&ag->tx_ring);
if (ret)
return ret;
ag71xx_ring_tx_init(ag);
- ret = ag71xx_ring_alloc(&ag->rx_ring, AG71XX_RX_RING_SIZE);
+ ret = ag71xx_ring_alloc(&ag->rx_ring);
if (ret)
return ret;
return "?";
}
+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 void ag71xx_hw_start(struct ag71xx *ag)
+{
+ /* start RX engine */
+ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
+
+ /* enable interrupts */
+ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
+}
+
+static void ag71xx_hw_stop(struct ag71xx *ag)
+{
+ /* disable all interrupts */
+ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
+
+ ag71xx_dma_reset(ag);
+}
+
void ag71xx_link_adjust(struct ag71xx *ag)
{
struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
u32 mii_speed;
if (!ag->link) {
+ ag71xx_hw_stop(ag);
netif_carrier_off(ag->dev);
if (netif_msg_link(ag))
printk(KERN_INFO "%s: link down\n", ag->dev->name);
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
+ ag71xx_hw_start(ag);
+
netif_carrier_on(ag->dev);
if (netif_msg_link(ag))
printk(KERN_INFO "%s: link up (%sMbps/%s duplex)\n",
ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
}
-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);
-}
-
#define MAC_CFG1_INIT (MAC_CFG1_RXE | MAC_CFG1_TXE | \
MAC_CFG1_SRX | MAC_CFG1_STX)
mdelay(100);
/* setup MAC configuration registers */
- if (pdata->is_ar724x)
- ag71xx_wr(ag, AG71XX_REG_MAC_CFG1,
- MAC_CFG1_INIT | MAC_CFG1_TFC | MAC_CFG1_RFC);
- else
- ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT);
+ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT);
ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
ag71xx_dma_reset(ag);
}
-static void ag71xx_hw_start(struct ag71xx *ag)
-{
- /* start RX engine */
- ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
-
- /* enable interrupts */
- ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
-}
-
-static void ag71xx_hw_stop(struct ag71xx *ag)
-{
- /* disable all interrupts */
- ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
-
- ag71xx_dma_reset(ag);
-}
-
static int ag71xx_open(struct net_device *dev)
{
struct ag71xx *ag = netdev_priv(dev);
ag71xx_hw_set_macaddr(ag, dev->dev_addr);
- ag71xx_hw_start(ag);
-
netif_start_queue(dev);
return 0;
- err:
+err:
ag71xx_rings_cleanup(ag);
return ret;
}
dma_addr_t dma_addr;
int i;
- i = ring->curr % AG71XX_TX_RING_SIZE;
+ i = ring->curr % ring->size;
desc = ring->buf[i].desc;
if (!ag71xx_desc_empty(desc))
DMA_TO_DEVICE);
ring->buf[i].skb = skb;
+ ring->buf[i].timestamp = jiffies;
/* setup descriptor fields */
desc->data = (u32) dma_addr;
wmb();
ring->curr++;
- if (ring->curr == (ring->dirty + AG71XX_TX_THRES_STOP)) {
+ if (ring->curr == (ring->dirty + ring->size)) {
DBG("%s: tx queue full\n", ag->dev->name);
netif_stop_queue(dev);
}
return NETDEV_TX_OK;
- err_drop:
+err_drop:
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
static int ag71xx_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct mii_ioctl_data *data = (struct mii_ioctl_data *) &ifr->ifr_data;
struct ag71xx *ag = netdev_priv(dev);
int ret;
if (ag->phy_dev == NULL)
break;
- return phy_mii_ioctl(ag->phy_dev, data, cmd);
+ return phy_mii_ioctl(ag->phy_dev, ifr, cmd);
default:
break;
static void ag71xx_restart_work_func(struct work_struct *work)
{
struct ag71xx *ag = container_of(work, struct ag71xx, restart_work);
+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
ag71xx_stop(ag->dev);
+
+ if (pdata->is_ar724x)
+ ag71xx_hw_init(ag);
+
ag71xx_open(ag->dev);
}
sent = 0;
while (ring->dirty != ring->curr) {
- unsigned int i = ring->dirty % AG71XX_TX_RING_SIZE;
+ unsigned int i = ring->dirty % ring->size;
struct ag71xx_desc *desc = ring->buf[i].desc;
struct sk_buff *skb = ring->buf[i].skb;
DBG("%s: %d packets sent out\n", ag->dev->name, sent);
- if ((ring->curr - ring->dirty) < AG71XX_TX_THRES_WAKEUP)
+ if ((ring->curr - ring->dirty) < (ring->size * 3) / 4)
netif_wake_queue(ag->dev);
return sent;
dev->name, limit, ring->curr, ring->dirty);
while (done < limit) {
- unsigned int i = ring->curr % AG71XX_RX_RING_SIZE;
+ unsigned int i = ring->curr % ring->size;
struct ag71xx_desc *desc = ring->buf[i].desc;
struct sk_buff *skb;
int pktlen;
if (ag71xx_desc_empty(desc))
break;
- if ((ring->dirty + AG71XX_RX_RING_SIZE) == ring->curr) {
+ if ((ring->dirty + ring->size) == ring->curr) {
ag71xx_assert(0);
break;
}
ag71xx_debugfs_update_napi_stats(ag, rx_done, tx_done);
rx_ring = &ag->rx_ring;
- if (rx_ring->buf[rx_ring->dirty % AG71XX_RX_RING_SIZE].skb == NULL)
+ if (rx_ring->buf[rx_ring->dirty % rx_ring->size].skb == NULL)
goto oom;
status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
return rx_done;
}
- more:
+more:
DBG("%s: stay in polling mode, rx=%d, tx=%d, limit=%d\n",
dev->name, rx_done, tx_done, limit);
return rx_done;
- oom:
+oom:
if (netif_msg_rx_err(ag))
printk(KERN_DEBUG "%s: out of memory\n", dev->name);
#endif
};
-static int __init ag71xx_probe(struct platform_device *pdev)
+static int __devinit ag71xx_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct resource *res;
dev->irq = platform_get_irq(pdev, 0);
err = request_irq(dev->irq, ag71xx_interrupt,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ IRQF_DISABLED,
dev->name, dev);
if (err) {
dev_err(&pdev->dev, "unable to request IRQ %d\n", dev->irq);
ag->oom_timer.data = (unsigned long) dev;
ag->oom_timer.function = ag71xx_oom_timer_handler;
+ ag->tx_ring.size = AG71XX_TX_RING_SIZE_DEFAULT;
+ ag->rx_ring.size = AG71XX_RX_RING_SIZE_DEFAULT;
+
memcpy(dev->dev_addr, pdata->mac_addr, ETH_ALEN);
netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
return 0;
- err_phy_disconnect:
+err_phy_disconnect:
ag71xx_phy_disconnect(ag);
- err_unregister_netdev:
+err_unregister_netdev:
unregister_netdev(dev);
- err_free_irq:
+err_free_irq:
free_irq(dev->irq, dev);
- err_unmap_mii_ctrl:
+err_unmap_mii_ctrl:
iounmap(ag->mii_ctrl);
- err_unmap_base:
+err_unmap_base:
iounmap(ag->mac_base);
- err_free_dev:
+err_free_dev:
kfree(dev);
- err_out:
+err_out:
platform_set_drvdata(pdev, NULL);
return err;
}
-static int __exit ag71xx_remove(struct platform_device *pdev)
+static int __devexit ag71xx_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
return 0;
- err_mdio_exit:
+err_mdio_exit:
ag71xx_mdio_driver_exit();
- err_debugfs_exit:
+err_debugfs_exit:
ag71xx_debugfs_root_exit();
- err_out:
+err_out:
return ret;
}