Commit c2ebf58b authored by Mark Einon's avatar Mark Einon Committed by Greg Kroah-Hartman

staging: et131x: Implement NAPI support

This implements NAPI support for et131x by:

-adding a napi_struct to the private adapter struct
-changing netfif_rx_skb() call to netif_receive_skb()
-changing et131x_handle_recv_interrupt() to et131x_handle_recv_pkts()
 and taking a budget allocation.
-changing et131x_handle_send_interrupt() to et131x_handle_send_pkts()
-replacing bottom half workqueue with poll function which handles
 send & receive of skbs.
-adding various other necessary standard napi calls.

Also remove this item from the README TODO list.
Signed-off-by: default avatarMark Einon <mark.einon@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent df7b3b8a
...@@ -10,7 +10,6 @@ driver as they did not build properly at the time. ...@@ -10,7 +10,6 @@ driver as they did not build properly at the time.
TODO: TODO:
- Look at reducing the number of spinlocks - Look at reducing the number of spinlocks
- Simplify code in nic_rx_pkts(), when determining multicast_pkts_rcvd - Simplify code in nic_rx_pkts(), when determining multicast_pkts_rcvd
- Implement NAPI support
- In et131x_tx(), don't return NETDEV_TX_BUSY, just drop the packet with kfree_skb(). - In et131x_tx(), don't return NETDEV_TX_BUSY, just drop the packet with kfree_skb().
- Reduce the number of split lines by careful consideration of variable names etc. - Reduce the number of split lines by careful consideration of variable names etc.
......
...@@ -470,7 +470,7 @@ struct et131x_adapter { ...@@ -470,7 +470,7 @@ struct et131x_adapter {
struct pci_dev *pdev; struct pci_dev *pdev;
struct mii_bus *mii_bus; struct mii_bus *mii_bus;
struct phy_device *phydev; struct phy_device *phydev;
struct work_struct task; struct napi_struct napi;
/* Flags that indicate current state of the adapter */ /* Flags that indicate current state of the adapter */
u32 flags; u32 flags;
...@@ -2551,26 +2551,30 @@ static struct rfd *nic_rx_pkts(struct et131x_adapter *adapter) ...@@ -2551,26 +2551,30 @@ static struct rfd *nic_rx_pkts(struct et131x_adapter *adapter)
skb->protocol = eth_type_trans(skb, adapter->netdev); skb->protocol = eth_type_trans(skb, adapter->netdev);
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
netif_rx_ni(skb); netif_receive_skb(skb);
out: out:
nic_return_rfd(adapter, rfd); nic_return_rfd(adapter, rfd);
return rfd; return rfd;
} }
/* et131x_handle_recv_interrupt - Interrupt handler for receive processing /* et131x_handle_recv_pkts - Interrupt handler for receive processing
* *
* Assumption, Rcv spinlock has been acquired. * Assumption, Rcv spinlock has been acquired.
*/ */
static void et131x_handle_recv_interrupt(struct et131x_adapter *adapter) static int et131x_handle_recv_pkts(struct et131x_adapter *adapter, int budget)
{ {
struct rfd *rfd = NULL; struct rfd *rfd = NULL;
u32 count = 0; int count = 0;
int limit = budget;
bool done = true; bool done = true;
struct rx_ring *rx_ring = &adapter->rx_ring; struct rx_ring *rx_ring = &adapter->rx_ring;
if (budget > MAX_PACKETS_HANDLED)
limit = MAX_PACKETS_HANDLED;
/* Process up to available RFD's */ /* Process up to available RFD's */
while (count < MAX_PACKETS_HANDLED) { while (count < limit) {
if (list_empty(&rx_ring->recv_list)) { if (list_empty(&rx_ring->recv_list)) {
WARN_ON(rx_ring->num_ready_recv != 0); WARN_ON(rx_ring->num_ready_recv != 0);
done = false; done = false;
...@@ -2602,13 +2606,15 @@ static void et131x_handle_recv_interrupt(struct et131x_adapter *adapter) ...@@ -2602,13 +2606,15 @@ static void et131x_handle_recv_interrupt(struct et131x_adapter *adapter)
count++; count++;
} }
if (count == MAX_PACKETS_HANDLED || !done) { if (count == limit || !done) {
rx_ring->unfinished_receives = true; rx_ring->unfinished_receives = true;
writel(PARM_TX_TIME_INT_DEF * NANO_IN_A_MICRO, writel(PARM_TX_TIME_INT_DEF * NANO_IN_A_MICRO,
&adapter->regs->global.watchdog_timer); &adapter->regs->global.watchdog_timer);
} else } else
/* Watchdog timer will disable itself if appropriate. */ /* Watchdog timer will disable itself if appropriate. */
rx_ring->unfinished_receives = false; rx_ring->unfinished_receives = false;
return count;
} }
/* et131x_tx_dma_memory_alloc /* et131x_tx_dma_memory_alloc
...@@ -3094,14 +3100,14 @@ static void et131x_free_busy_send_packets(struct et131x_adapter *adapter) ...@@ -3094,14 +3100,14 @@ static void et131x_free_busy_send_packets(struct et131x_adapter *adapter)
tx_ring->used = 0; tx_ring->used = 0;
} }
/* et131x_handle_send_interrupt - Interrupt handler for sending processing /* et131x_handle_send_pkts - Interrupt handler for sending processing
* *
* Re-claim the send resources, complete sends and get more to send from * Re-claim the send resources, complete sends and get more to send from
* the send wait queue. * the send wait queue.
* *
* Assumption - Send spinlock has been acquired * Assumption - Send spinlock has been acquired
*/ */
static void et131x_handle_send_interrupt(struct et131x_adapter *adapter) static void et131x_handle_send_pkts(struct et131x_adapter *adapter)
{ {
unsigned long flags; unsigned long flags;
u32 serviced; u32 serviced;
...@@ -3720,9 +3726,9 @@ static void et131x_pci_remove(struct pci_dev *pdev) ...@@ -3720,9 +3726,9 @@ static void et131x_pci_remove(struct pci_dev *pdev)
struct et131x_adapter *adapter = netdev_priv(netdev); struct et131x_adapter *adapter = netdev_priv(netdev);
unregister_netdev(netdev); unregister_netdev(netdev);
netif_napi_del(&adapter->napi);
phy_disconnect(adapter->phydev); phy_disconnect(adapter->phydev);
mdiobus_unregister(adapter->mii_bus); mdiobus_unregister(adapter->mii_bus);
cancel_work_sync(&adapter->task);
kfree(adapter->mii_bus->irq); kfree(adapter->mii_bus->irq);
mdiobus_free(adapter->mii_bus); mdiobus_free(adapter->mii_bus);
...@@ -3802,6 +3808,7 @@ static irqreturn_t et131x_isr(int irq, void *dev_id) ...@@ -3802,6 +3808,7 @@ static irqreturn_t et131x_isr(int irq, void *dev_id)
bool handled = true; bool handled = true;
struct net_device *netdev = (struct net_device *)dev_id; struct net_device *netdev = (struct net_device *)dev_id;
struct et131x_adapter *adapter = netdev_priv(netdev); struct et131x_adapter *adapter = netdev_priv(netdev);
struct address_map __iomem *iomem = adapter->regs;
struct rx_ring *rx_ring = &adapter->rx_ring; struct rx_ring *rx_ring = &adapter->rx_ring;
struct tx_ring *tx_ring = &adapter->tx_ring; struct tx_ring *tx_ring = &adapter->tx_ring;
u32 status; u32 status;
...@@ -3838,7 +3845,6 @@ static irqreturn_t et131x_isr(int irq, void *dev_id) ...@@ -3838,7 +3845,6 @@ static irqreturn_t et131x_isr(int irq, void *dev_id)
} }
/* This is our interrupt, so process accordingly */ /* This is our interrupt, so process accordingly */
if (status & ET_INTR_WATCHDOG) { if (status & ET_INTR_WATCHDOG) {
struct tcb *tcb = tx_ring->send_head; struct tcb *tcb = tx_ring->send_head;
...@@ -3854,54 +3860,8 @@ static irqreturn_t et131x_isr(int irq, void *dev_id) ...@@ -3854,54 +3860,8 @@ static irqreturn_t et131x_isr(int irq, void *dev_id)
status &= ~ET_INTR_WATCHDOG; status &= ~ET_INTR_WATCHDOG;
} }
if (!status) { if (status & (ET_INTR_RXDMA_XFR_DONE | ET_INTR_TXDMA_ISR))
/* This interrupt has in some way been "handled" by napi_schedule(&adapter->napi);
* the ISR. Either it was a spurious Rx interrupt, or
* it was a Tx interrupt that has been filtered by
* the ISR.
*/
et131x_enable_interrupts(adapter);
goto out;
}
/* We need to save the interrupt status value for use in our
* DPC. We will clear the software copy of that in that
* routine.
*/
adapter->stats.interrupt_status = status;
/* Schedule the ISR handler as a bottom-half task in the
* kernel's tq_immediate queue, and mark the queue for
* execution
*/
schedule_work(&adapter->task);
out:
return IRQ_RETVAL(handled);
}
/* et131x_isr_handler - The ISR handler
*
* scheduled to run in a deferred context by the ISR. This is where the ISR's
* work actually gets done.
*/
static void et131x_isr_handler(struct work_struct *work)
{
struct et131x_adapter *adapter =
container_of(work, struct et131x_adapter, task);
u32 status = adapter->stats.interrupt_status;
struct address_map __iomem *iomem = adapter->regs;
/* These first two are by far the most common. Once handled, we clear
* their two bits in the status word. If the word is now zero, we
* exit.
*/
/* Handle all the completed Transmit interrupts */
if (status & ET_INTR_TXDMA_ISR)
et131x_handle_send_interrupt(adapter);
/* Handle all the completed Receives interrupts */
if (status & ET_INTR_RXDMA_XFR_DONE)
et131x_handle_recv_interrupt(adapter);
status &= ~(ET_INTR_TXDMA_ISR | ET_INTR_RXDMA_XFR_DONE); status &= ~(ET_INTR_TXDMA_ISR | ET_INTR_RXDMA_XFR_DONE);
...@@ -4053,8 +4013,34 @@ static void et131x_isr_handler(struct work_struct *work) ...@@ -4053,8 +4013,34 @@ static void et131x_isr_handler(struct work_struct *work)
* addressed module is in a power-down state and can't respond. * addressed module is in a power-down state and can't respond.
*/ */
} }
if (!status) {
/* This interrupt has in some way been "handled" by
* the ISR. Either it was a spurious Rx interrupt, or
* it was a Tx interrupt that has been filtered by
* the ISR.
*/
et131x_enable_interrupts(adapter);
}
out: out:
return IRQ_RETVAL(handled);
}
static int et131x_poll(struct napi_struct *napi, int budget)
{
struct et131x_adapter *adapter =
container_of(napi, struct et131x_adapter, napi);
int work_done = et131x_handle_recv_pkts(adapter, budget);
et131x_handle_send_pkts(adapter);
if (work_done < budget) {
napi_complete(&adapter->napi);
et131x_enable_interrupts(adapter); et131x_enable_interrupts(adapter);
}
return work_done;
} }
/* et131x_stats - Return the current device statistics */ /* et131x_stats - Return the current device statistics */
...@@ -4123,6 +4109,8 @@ static int et131x_open(struct net_device *netdev) ...@@ -4123,6 +4109,8 @@ static int et131x_open(struct net_device *netdev)
adapter->flags |= FMP_ADAPTER_INTERRUPT_IN_USE; adapter->flags |= FMP_ADAPTER_INTERRUPT_IN_USE;
napi_enable(&adapter->napi);
et131x_up(netdev); et131x_up(netdev);
return result; return result;
...@@ -4134,6 +4122,7 @@ static int et131x_close(struct net_device *netdev) ...@@ -4134,6 +4122,7 @@ static int et131x_close(struct net_device *netdev)
struct et131x_adapter *adapter = netdev_priv(netdev); struct et131x_adapter *adapter = netdev_priv(netdev);
et131x_down(netdev); et131x_down(netdev);
napi_disable(&adapter->napi);
adapter->flags &= ~FMP_ADAPTER_INTERRUPT_IN_USE; adapter->flags &= ~FMP_ADAPTER_INTERRUPT_IN_USE;
free_irq(adapter->pdev->irq, netdev); free_irq(adapter->pdev->irq, netdev);
...@@ -4514,8 +4503,7 @@ static int et131x_pci_setup(struct pci_dev *pdev, ...@@ -4514,8 +4503,7 @@ static int et131x_pci_setup(struct pci_dev *pdev,
/* Init send data structures */ /* Init send data structures */
et131x_init_send(adapter); et131x_init_send(adapter);
/* Set up the task structure for the ISR's deferred handler */ netif_napi_add(netdev, &adapter->napi, et131x_poll, 64);
INIT_WORK(&adapter->task, et131x_isr_handler);
/* Copy address into the net_device struct */ /* Copy address into the net_device struct */
memcpy(netdev->dev_addr, adapter->addr, ETH_ALEN); memcpy(netdev->dev_addr, adapter->addr, ETH_ALEN);
......
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