aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/sky2.c20
-rw-r--r--include/linux/netdevice.h18
2 files changed, 26 insertions, 12 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 67b0eab16589..618fde8622ca 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -2093,6 +2093,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
2093 int work_done = 0; 2093 int work_done = 0;
2094 u32 status = sky2_read32(hw, B0_Y2_SP_EISR); 2094 u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
2095 2095
2096 restart_poll:
2096 if (unlikely(status & ~Y2_IS_STAT_BMU)) { 2097 if (unlikely(status & ~Y2_IS_STAT_BMU)) {
2097 if (status & Y2_IS_HW_ERR) 2098 if (status & Y2_IS_HW_ERR)
2098 sky2_hw_intr(hw); 2099 sky2_hw_intr(hw);
@@ -2123,7 +2124,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
2123 } 2124 }
2124 2125
2125 if (status & Y2_IS_STAT_BMU) { 2126 if (status & Y2_IS_STAT_BMU) {
2126 work_done = sky2_status_intr(hw, work_limit); 2127 work_done += sky2_status_intr(hw, work_limit - work_done);
2127 *budget -= work_done; 2128 *budget -= work_done;
2128 dev0->quota -= work_done; 2129 dev0->quota -= work_done;
2129 2130
@@ -2133,9 +2134,22 @@ static int sky2_poll(struct net_device *dev0, int *budget)
2133 sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); 2134 sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
2134 } 2135 }
2135 2136
2136 netif_rx_complete(dev0); 2137 local_irq_disable();
2138 __netif_rx_complete(dev0);
2137 2139
2138 status = sky2_read32(hw, B0_Y2_SP_LISR); 2140 status = sky2_read32(hw, B0_Y2_SP_LISR);
2141
2142 if (unlikely(status)) {
2143 /* More work pending, try and keep going */
2144 if (__netif_rx_schedule_prep(dev0)) {
2145 __netif_rx_reschedule(dev0, work_done);
2146 status = sky2_read32(hw, B0_Y2_SP_EISR);
2147 local_irq_enable();
2148 goto restart_poll;
2149 }
2150 }
2151
2152 local_irq_enable();
2139 return 0; 2153 return 0;
2140} 2154}
2141 2155
@@ -2153,8 +2167,6 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
2153 prefetch(&hw->st_le[hw->st_idx]); 2167 prefetch(&hw->st_le[hw->st_idx]);
2154 if (likely(__netif_rx_schedule_prep(dev0))) 2168 if (likely(__netif_rx_schedule_prep(dev0)))
2155 __netif_rx_schedule(dev0); 2169 __netif_rx_schedule(dev0);
2156 else
2157 printk(KERN_DEBUG PFX "irq race detected\n");
2158 2170
2159 return IRQ_HANDLED; 2171 return IRQ_HANDLED;
2160} 2172}
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 40ccf8cc4239..01db7b88a2b1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -829,19 +829,21 @@ static inline void netif_rx_schedule(struct net_device *dev)
829 __netif_rx_schedule(dev); 829 __netif_rx_schedule(dev);
830} 830}
831 831
832/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). 832
833 * Do not inline this? 833static inline void __netif_rx_reschedule(struct net_device *dev, int undo)
834 */ 834{
835 dev->quota += undo;
836 list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
837 __raise_softirq_irqoff(NET_RX_SOFTIRQ);
838}
839
840/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). */
835static inline int netif_rx_reschedule(struct net_device *dev, int undo) 841static inline int netif_rx_reschedule(struct net_device *dev, int undo)
836{ 842{
837 if (netif_rx_schedule_prep(dev)) { 843 if (netif_rx_schedule_prep(dev)) {
838 unsigned long flags; 844 unsigned long flags;
839
840 dev->quota += undo;
841
842 local_irq_save(flags); 845 local_irq_save(flags);
843 list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); 846 __netif_rx_reschedule(dev, undo);
844 __raise_softirq_irqoff(NET_RX_SOFTIRQ);
845 local_irq_restore(flags); 847 local_irq_restore(flags);
846 return 1; 848 return 1;
847 } 849 }