Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 224519
b: refs/heads/master
c: fa98eb0
h: refs/heads/master
i:
  224517: 2d239f1
  224515: 2335cc0
  224511: 44fef57
v: v3
  • Loading branch information
Jonas Bonn authored and David S. Miller committed Nov 28, 2010
1 parent 10da88a commit 5a79edb
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 28 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 20f70ddd6558a39a89dba4af675686c5a8dbd7b3
refs/heads/master: fa98eb0e867c6c16e239545d4deb7ad8f40631b3
76 changes: 49 additions & 27 deletions trunk/drivers/net/ethoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,62 +495,81 @@ static int ethoc_update_tx_stats(struct ethoc *dev, struct ethoc_bd *bd)
return 0;
}

static void ethoc_tx(struct net_device *dev)
static int ethoc_tx(struct net_device *dev, int limit)
{
struct ethoc *priv = netdev_priv(dev);
int count;
struct ethoc_bd bd;

spin_lock(&priv->lock);
for (count = 0; count < limit; ++count) {
unsigned int entry;

while (priv->dty_tx != priv->cur_tx) {
unsigned int entry = priv->dty_tx % priv->num_tx;
struct ethoc_bd bd;
entry = priv->dty_tx % priv->num_tx;

ethoc_read_bd(priv, entry, &bd);
if (bd.stat & TX_BD_READY)
break;

entry = (++priv->dty_tx) % priv->num_tx;
if (bd.stat & TX_BD_READY || (priv->dty_tx == priv->cur_tx)) {
ethoc_ack_irq(priv, INT_MASK_TX);
/* If interrupt came in between reading in the BD
* and clearing the interrupt source, then we risk
* missing the event as the TX interrupt won't trigger
* right away when we reenable it; hence, check
* BD_EMPTY here again to make sure there isn't such an
* event pending...
*/
ethoc_read_bd(priv, entry, &bd);
if (bd.stat & TX_BD_READY ||
(priv->dty_tx == priv->cur_tx))
break;
}

(void)ethoc_update_tx_stats(priv, &bd);
priv->dty_tx++;
}

if ((priv->cur_tx - priv->dty_tx) <= (priv->num_tx / 2))
netif_wake_queue(dev);

ethoc_ack_irq(priv, INT_MASK_TX);
spin_unlock(&priv->lock);
return count;
}

static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct ethoc *priv = netdev_priv(dev);
u32 pending;

ethoc_disable_irq(priv, INT_MASK_ALL);
u32 mask;

/* Figure out what triggered the interrupt...
* The tricky bit here is that the interrupt source bits get
* set in INT_SOURCE for an event irregardless of whether that
* event is masked or not. Thus, in order to figure out what
* triggered the interrupt, we need to remove the sources
* for all events that are currently masked. This behaviour
* is not particularly well documented but reasonable...
*/
mask = ethoc_read(priv, INT_MASK);
pending = ethoc_read(priv, INT_SOURCE);
pending &= mask;

if (unlikely(pending == 0)) {
ethoc_enable_irq(priv, INT_MASK_ALL);
return IRQ_NONE;
}

ethoc_ack_irq(priv, pending);

/* We always handle the dropped packet interrupt */
if (pending & INT_MASK_BUSY) {
dev_err(&dev->dev, "packet dropped\n");
dev->stats.rx_dropped++;
}

if (pending & INT_MASK_RX) {
if (napi_schedule_prep(&priv->napi))
__napi_schedule(&priv->napi);
} else {
ethoc_enable_irq(priv, INT_MASK_RX);
/* Handle receive/transmit event by switching to polling */
if (pending & (INT_MASK_TX | INT_MASK_RX)) {
ethoc_disable_irq(priv, INT_MASK_TX | INT_MASK_RX);
napi_schedule(&priv->napi);
}

if (pending & INT_MASK_TX)
ethoc_tx(dev);

ethoc_enable_irq(priv, INT_MASK_ALL & ~INT_MASK_RX);
return IRQ_HANDLED;
}

Expand All @@ -576,15 +595,18 @@ static int ethoc_get_mac_address(struct net_device *dev, void *addr)
static int ethoc_poll(struct napi_struct *napi, int budget)
{
struct ethoc *priv = container_of(napi, struct ethoc, napi);
int work_done = 0;
int rx_work_done = 0;
int tx_work_done = 0;

rx_work_done = ethoc_rx(priv->netdev, budget);
tx_work_done = ethoc_tx(priv->netdev, budget);

work_done = ethoc_rx(priv->netdev, budget);
if (work_done < budget) {
if (rx_work_done < budget && tx_work_done < budget) {
napi_complete(napi);
ethoc_enable_irq(priv, INT_MASK_RX);
ethoc_enable_irq(priv, INT_MASK_TX | INT_MASK_RX);
}

return work_done;
return rx_work_done;
}

static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
Expand Down

0 comments on commit 5a79edb

Please sign in to comment.