#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);
}
}
+static int ag71xx_rx_reserve(struct ag71xx *ag)
+{
+ int reserve = 0;
+
+ if (ag71xx_get_pdata(ag)->is_ar724x) {
+ if (!ag71xx_has_ar8216(ag))
+ reserve = 2;
+
+ if (ag->phy_dev)
+ reserve += 4 - (ag->phy_dev->pkt_align % 4);
+
+ reserve %= 4;
+ }
+
+ return reserve + AG71XX_RX_PKT_RESERVE;
+}
+
+
static int ag71xx_ring_rx_init(struct ag71xx *ag)
{
struct ag71xx_ring *ring = &ag->rx_ring;
+ unsigned int reserve = ag71xx_rx_reserve(ag);
unsigned int i;
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;
- skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + AG71XX_RX_PKT_RESERVE);
+ skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve);
if (!skb) {
ret = -ENOMEM;
break;
}
skb->dev = ag->dev;
- skb_reserve(skb, AG71XX_RX_PKT_RESERVE);
+ skb_reserve(skb, reserve);
dma_addr = dma_map_single(&ag->dev->dev, skb->data,
AG71XX_RX_PKT_SIZE,
static int ag71xx_ring_rx_refill(struct ag71xx *ag)
{
struct ag71xx_ring *ring = &ag->rx_ring;
+ unsigned int reserve = ag71xx_rx_reserve(ag);
unsigned int count;
count = 0;
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;
struct sk_buff *skb;
- skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE +
- AG71XX_RX_PKT_RESERVE);
+ skb = dev_alloc_skb(AG71XX_RX_PKT_SIZE + reserve);
if (skb == NULL)
break;
- skb_reserve(skb, AG71XX_RX_PKT_RESERVE);
+ skb_reserve(skb, reserve);
skb->dev = ag->dev;
dma_addr = dma_map_single(&ag->dev->dev, skb->data,
{
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 "?";
}
-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_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[3]);
+ t = (((u32) mac[5]) << 24) | (((u32) mac[4]) << 16)
+ | (((u32) mac[3]) << 8) | ((u32) mac[2]);
ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
- t = (((u32) mac[4]) << 24) | (((u32) mac[5]) << 16);
+ t = (((u32) mac[1]) << 24) | (((u32) mac[0]) << 16);
ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
}
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);
+ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->stop_desc_dma);
+ ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->stop_desc_dma);
/* clear pending RX/TX interrupts */
for (i = 0; i < 256; i++) {
FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \
FIFO_CFG5_17 | FIFO_CFG5_SF)
-static void ag71xx_hw_init(struct ag71xx *ag)
+static void ag71xx_hw_stop(struct ag71xx *ag)
{
- struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
-
- ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
- udelay(20);
+ /* disable all interrupts and stop the rx/tx engine */
+ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
+ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
+ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
+}
- ar71xx_device_stop(pdata->reset_bit);
- mdelay(100);
- ar71xx_device_start(pdata->reset_bit);
- mdelay(100);
+static void ag71xx_hw_setup(struct ag71xx *ag)
+{
+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
/* 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);
/* 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);
if (pdata->is_ar724x) {
}
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT);
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT);
+}
+
+static void ag71xx_hw_init(struct ag71xx *ag)
+{
+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+ u32 reset_mask = pdata->reset_bit;
+
+ ag71xx_hw_stop(ag);
+
+ if (pdata->is_ar724x) {
+ u32 reset_phy = reset_mask;
+
+ reset_phy &= RESET_MODULE_GE0_PHY | RESET_MODULE_GE1_PHY;
+ reset_mask &= ~(RESET_MODULE_GE0_PHY | RESET_MODULE_GE1_PHY);
+
+ ar71xx_device_stop(reset_phy);
+ mdelay(50);
+ ar71xx_device_start(reset_phy);
+ mdelay(200);
+ }
+
+ ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
+ udelay(20);
+
+ ar71xx_device_stop(reset_mask);
+ mdelay(100);
+ ar71xx_device_start(reset_mask);
+ mdelay(200);
+
+ ag71xx_hw_setup(ag);
ag71xx_dma_reset(ag);
}
+static void ag71xx_fast_reset(struct ag71xx *ag)
+{
+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+ struct net_device *dev = ag->dev;
+ u32 reset_mask = pdata->reset_bit;
+ u32 rx_ds, tx_ds;
+ u32 mii_reg;
+
+ reset_mask &= RESET_MODULE_GE0_MAC | RESET_MODULE_GE1_MAC;
+
+ mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG);
+ rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC);
+ tx_ds = ag71xx_rr(ag, AG71XX_REG_TX_DESC);
+
+ ar71xx_device_stop(reset_mask);
+ udelay(10);
+ ar71xx_device_start(reset_mask);
+ udelay(10);
+
+ ag71xx_dma_reset(ag);
+ ag71xx_hw_setup(ag);
+
+ ag71xx_wr(ag, AG71XX_REG_RX_DESC, rx_ds);
+ ag71xx_wr(ag, AG71XX_REG_TX_DESC, tx_ds);
+ ag71xx_wr(ag, AG71XX_REG_MII_CFG, mii_reg);
+
+ ag71xx_hw_set_macaddr(ag, dev->dev_addr);
+}
+
static void ag71xx_hw_start(struct ag71xx *ag)
{
/* start RX engine */
ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
}
-static void ag71xx_hw_stop(struct ag71xx *ag)
+void ag71xx_link_adjust(struct ag71xx *ag)
{
- /* disable all interrupts */
- ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
+ u32 cfg2;
+ u32 ifctl;
+ u32 fifo5;
- ag71xx_dma_reset(ag);
+ 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);
+ return;
+ }
+
+ if (pdata->is_ar724x)
+ ag71xx_fast_reset(ag);
+
+ 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:
+ cfg2 |= MAC_CFG2_IF_1000;
+ fifo5 |= FIFO_CFG5_BM;
+ break;
+ case SPEED_100:
+ cfg2 |= MAC_CFG2_IF_10_100;
+ ifctl |= MAC_IFCTL_SPEED;
+ break;
+ case 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_speed)
+ pdata->set_speed(ag->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);
+ ag71xx_hw_start(ag);
+
+ 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 int ag71xx_open(struct net_device *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;
}
struct ag71xx *ag = netdev_priv(dev);
unsigned long flags;
+ netif_carrier_off(dev);
+ ag71xx_phy_stop(ag);
+
spin_lock_irqsave(&ag->lock, flags);
netif_stop_queue(dev);
ag71xx_hw_stop(ag);
-
- netif_carrier_off(dev);
- ag71xx_phy_stop(ag);
+ ag71xx_dma_reset(ag);
napi_disable(&ag->napi);
del_timer_sync(&ag->oom_timer);
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))
goto err_drop;
- ag71xx_add_ar8216_header(ag, skb);
+ if (ag71xx_has_ar8216(ag))
+ ag71xx_add_ar8216_header(ag, skb);
if (skb->len <= 0) {
DBG("%s: packet len is too small\n", ag->dev->name);
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;
{
struct ag71xx *ag = container_of(work, struct ag71xx, restart_work);
+ if (ag71xx_get_pdata(ag)->is_ar724x) {
+ ag->link = 0;
+ ag71xx_link_adjust(ag);
+ return;
+ }
+
ag71xx_stop(ag->dev);
ag71xx_open(ag->dev);
}
+static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp)
+{
+ u32 rx_sm, tx_sm, rx_fd;
+
+ if (likely(time_before(jiffies, timestamp + HZ/10)))
+ return false;
+
+ if (!netif_carrier_ok(ag->dev))
+ return false;
+
+ rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM);
+ if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6)
+ return true;
+
+ tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM);
+ rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH);
+ if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) &&
+ ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0)
+ return true;
+
+ return false;
+}
+
static int ag71xx_tx_packets(struct ag71xx *ag)
{
struct ag71xx_ring *ring = &ag->tx_ring;
+ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
int sent;
DBG("%s: processing TX ring\n", ag->dev->name);
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;
- if (!ag71xx_desc_empty(desc))
+ if (!ag71xx_desc_empty(desc)) {
+ if (pdata->is_ar7240 &&
+ ag71xx_check_dma_stuck(ag, ring->buf[i].timestamp))
+ schedule_work(&ag->restart_work);
break;
+ }
ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
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;
+ int err = 0;
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;
}
dma_unmap_single(&dev->dev, ring->buf[i].dma_addr,
AG71XX_RX_PKT_SIZE, DMA_FROM_DEVICE);
- skb_put(skb, pktlen);
-
- skb->dev = dev;
- skb->ip_summed = CHECKSUM_NONE;
-
dev->last_rx = jiffies;
dev->stats.rx_packets++;
dev->stats.rx_bytes += pktlen;
- if (ag71xx_remove_ar8216_header(ag, skb) != 0) {
+ skb_put(skb, pktlen);
+ if (ag71xx_has_ar8216(ag))
+ err = ag71xx_remove_ar8216_header(ag, skb, pktlen);
+
+ if (err) {
dev->stats.rx_dropped++;
kfree_skb(skb);
} else {
- skb->protocol = eth_type_trans(skb, dev);
- netif_receive_skb(skb);
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_NONE;
+ if (ag->phy_dev) {
+ ag->phy_dev->netif_receive_skb(skb);
+ } else {
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_receive_skb(skb);
+ }
}
ring->buf[i].skb = NULL;
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);
/* TODO */
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void ag71xx_netpoll(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ ag71xx_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+}
+#endif
+
static const struct net_device_ops ag71xx_netdev_ops = {
.ndo_open = ag71xx_open,
.ndo_stop = ag71xx_stop,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ag71xx_netpoll,
+#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;
goto err_free_dev;
}
- 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_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_base;
- }
-
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);
- goto err_unmap_mii_ctrl;
+ goto err_unmap_base;
}
dev->base_addr = (unsigned long)ag->mac_base;
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;
+
+ ag->stop_desc = dma_alloc_coherent(NULL,
+ sizeof(struct ag71xx_desc), &ag->stop_desc_dma, GFP_KERNEL);
+
+ if (!ag->stop_desc)
+ goto err_free_irq;
+
+ ag->stop_desc->data = 0;
+ ag->stop_desc->ctrl = 0;
+ ag->stop_desc->next = (u32) ag->stop_desc_dma;
+
memcpy(dev->dev_addr, pdata->mac_addr, ETH_ALEN);
netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
err = register_netdev(dev);
if (err) {
dev_err(&pdev->dev, "unable to register net device\n");
- goto err_free_irq;
+ goto err_free_desc;
}
printk(KERN_INFO "%s: Atheros AG71xx at 0x%08lx, irq %d\n",
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_desc:
+ dma_free_coherent(NULL, sizeof(struct ag71xx_desc), ag->stop_desc,
+ ag->stop_desc_dma);
+err_free_irq:
free_irq(dev->irq, dev);
- 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);
ag71xx_phy_disconnect(ag);
unregister_netdev(dev);
free_irq(dev->irq, dev);
- iounmap(ag->mii_ctrl);
iounmap(ag->mac_base);
kfree(dev);
platform_set_drvdata(pdev, NULL);
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;
}