Commit 61cec3bd authored by Olof Johansson's avatar Olof Johansson Committed by David S. Miller

pasemi_mac: Fix TX cleaning

pasemi_mac: Fix TX cleaning

This is a bit awkward. We don't have a timer-delayed interrupt on TX
complete, but we have a count threshold. So set that reasonably high
(32 packets), and schedule the NAPI poll when it goes off. Also bump a
regular timer that will take care of rotting packets for the last 1..31
ones in case we don't trigger a TX interrupt (and there's no RX activity
that would otherwise trigger the poll).

The longer-term fix is to separate TX from RX NAPI and do two separate
poll loops.
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 5c15332b
...@@ -805,26 +805,42 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) ...@@ -805,26 +805,42 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#define TX_CLEAN_INTERVAL HZ
static void pasemi_mac_tx_timer(unsigned long data)
{
struct pasemi_mac_txring *txring = (struct pasemi_mac_txring *)data;
struct pasemi_mac *mac = txring->mac;
pasemi_mac_clean_tx(txring);
mod_timer(&txring->clean_timer, jiffies + TX_CLEAN_INTERVAL);
pasemi_mac_restart_tx_intr(mac);
}
static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
{ {
struct pasemi_mac_txring *txring = data; struct pasemi_mac_txring *txring = data;
const struct pasemi_dmachan *chan = &txring->chan; const struct pasemi_dmachan *chan = &txring->chan;
unsigned int reg, pcnt; struct pasemi_mac *mac = txring->mac;
unsigned int reg;
if (!(*chan->status & PAS_STATUS_CAUSE_M)) if (!(*chan->status & PAS_STATUS_CAUSE_M))
return IRQ_NONE; return IRQ_NONE;
pasemi_mac_clean_tx(txring); reg = 0;
pcnt = *chan->status & PAS_STATUS_PCNT_M;
reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC;
if (*chan->status & PAS_STATUS_SOFT) if (*chan->status & PAS_STATUS_SOFT)
reg |= PAS_IOB_DMA_TXCH_RESET_SINTC; reg |= PAS_IOB_DMA_TXCH_RESET_SINTC;
if (*chan->status & PAS_STATUS_ERROR) if (*chan->status & PAS_STATUS_ERROR)
reg |= PAS_IOB_DMA_TXCH_RESET_DINTC; reg |= PAS_IOB_DMA_TXCH_RESET_DINTC;
mod_timer(&txring->clean_timer, jiffies + (TX_CLEAN_INTERVAL)*2);
netif_rx_schedule(mac->netdev, &mac->napi);
if (reg)
write_iob_reg(PAS_IOB_DMA_TXCH_RESET(chan->chno), reg); write_iob_reg(PAS_IOB_DMA_TXCH_RESET(chan->chno), reg);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -973,7 +989,7 @@ static int pasemi_mac_open(struct net_device *dev) ...@@ -973,7 +989,7 @@ static int pasemi_mac_open(struct net_device *dev)
PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno), write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno),
PAS_IOB_DMA_TXCH_CFG_CNTTH(128)); PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
write_mac_reg(mac, PAS_MAC_IPC_CHNL, write_mac_reg(mac, PAS_MAC_IPC_CHNL,
PAS_MAC_IPC_CHNL_DCHNO(mac->rx->chan.chno) | PAS_MAC_IPC_CHNL_DCHNO(mac->rx->chan.chno) |
...@@ -1054,6 +1070,12 @@ static int pasemi_mac_open(struct net_device *dev) ...@@ -1054,6 +1070,12 @@ static int pasemi_mac_open(struct net_device *dev)
if (mac->phydev) if (mac->phydev)
phy_start(mac->phydev); phy_start(mac->phydev);
init_timer(&mac->tx->clean_timer);
mac->tx->clean_timer.function = pasemi_mac_tx_timer;
mac->tx->clean_timer.data = (unsigned long)mac->tx;
mac->tx->clean_timer.expires = jiffies+HZ;
add_timer(&mac->tx->clean_timer);
return 0; return 0;
out_rx_int: out_rx_int:
...@@ -1087,6 +1109,8 @@ static int pasemi_mac_close(struct net_device *dev) ...@@ -1087,6 +1109,8 @@ static int pasemi_mac_close(struct net_device *dev)
phy_disconnect(mac->phydev); phy_disconnect(mac->phydev);
} }
del_timer_sync(&mac->tx->clean_timer);
netif_stop_queue(dev); netif_stop_queue(dev);
napi_disable(&mac->napi); napi_disable(&mac->napi);
...@@ -1304,6 +1328,7 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) ...@@ -1304,6 +1328,7 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget)
netif_rx_complete(dev, napi); netif_rx_complete(dev, napi);
pasemi_mac_restart_rx_intr(mac); pasemi_mac_restart_rx_intr(mac);
pasemi_mac_restart_tx_intr(mac);
} }
return pkts; return pkts;
} }
......
...@@ -34,6 +34,7 @@ struct pasemi_mac_txring { ...@@ -34,6 +34,7 @@ struct pasemi_mac_txring {
unsigned int next_to_clean; unsigned int next_to_clean;
struct pasemi_mac_buffer *ring_info; struct pasemi_mac_buffer *ring_info;
struct pasemi_mac *mac; /* Needed in intr handler */ struct pasemi_mac *mac; /* Needed in intr handler */
struct timer_list clean_timer;
}; };
struct pasemi_mac_rxring { struct pasemi_mac_rxring {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment