aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c52
1 files changed, 41 insertions, 11 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 67b0eab16589..227df9876a2c 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -51,7 +51,7 @@
51#include "sky2.h" 51#include "sky2.h"
52 52
53#define DRV_NAME "sky2" 53#define DRV_NAME "sky2"
54#define DRV_VERSION "1.1" 54#define DRV_VERSION "1.2"
55#define PFX DRV_NAME " " 55#define PFX DRV_NAME " "
56 56
57/* 57/*
@@ -925,8 +925,7 @@ static inline struct sk_buff *sky2_alloc_skb(unsigned int size, gfp_t gfp_mask)
925 skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask); 925 skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask);
926 if (likely(skb)) { 926 if (likely(skb)) {
927 unsigned long p = (unsigned long) skb->data; 927 unsigned long p = (unsigned long) skb->data;
928 skb_reserve(skb, 928 skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
929 ((p + RX_SKB_ALIGN - 1) & ~(RX_SKB_ALIGN - 1)) - p);
930 } 929 }
931 930
932 return skb; 931 return skb;
@@ -1686,13 +1685,12 @@ static void sky2_tx_timeout(struct net_device *dev)
1686} 1685}
1687 1686
1688 1687
1689#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
1690/* Want receive buffer size to be multiple of 64 bits 1688/* Want receive buffer size to be multiple of 64 bits
1691 * and incl room for vlan and truncation 1689 * and incl room for vlan and truncation
1692 */ 1690 */
1693static inline unsigned sky2_buf_size(int mtu) 1691static inline unsigned sky2_buf_size(int mtu)
1694{ 1692{
1695 return roundup(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8; 1693 return ALIGN(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8;
1696} 1694}
1697 1695
1698static int sky2_change_mtu(struct net_device *dev, int new_mtu) 1696static int sky2_change_mtu(struct net_device *dev, int new_mtu)
@@ -2086,6 +2084,20 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port,
2086 } 2084 }
2087} 2085}
2088 2086
2087/* If idle then force a fake soft NAPI poll once a second
2088 * to work around cases where sharing an edge triggered interrupt.
2089 */
2090static void sky2_idle(unsigned long arg)
2091{
2092 struct net_device *dev = (struct net_device *) arg;
2093
2094 local_irq_disable();
2095 if (__netif_rx_schedule_prep(dev))
2096 __netif_rx_schedule(dev);
2097 local_irq_enable();
2098}
2099
2100
2089static int sky2_poll(struct net_device *dev0, int *budget) 2101static int sky2_poll(struct net_device *dev0, int *budget)
2090{ 2102{
2091 struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; 2103 struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
@@ -2093,6 +2105,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
2093 int work_done = 0; 2105 int work_done = 0;
2094 u32 status = sky2_read32(hw, B0_Y2_SP_EISR); 2106 u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
2095 2107
2108 restart_poll:
2096 if (unlikely(status & ~Y2_IS_STAT_BMU)) { 2109 if (unlikely(status & ~Y2_IS_STAT_BMU)) {
2097 if (status & Y2_IS_HW_ERR) 2110 if (status & Y2_IS_HW_ERR)
2098 sky2_hw_intr(hw); 2111 sky2_hw_intr(hw);
@@ -2123,7 +2136,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
2123 } 2136 }
2124 2137
2125 if (status & Y2_IS_STAT_BMU) { 2138 if (status & Y2_IS_STAT_BMU) {
2126 work_done = sky2_status_intr(hw, work_limit); 2139 work_done += sky2_status_intr(hw, work_limit - work_done);
2127 *budget -= work_done; 2140 *budget -= work_done;
2128 dev0->quota -= work_done; 2141 dev0->quota -= work_done;
2129 2142
@@ -2133,9 +2146,24 @@ static int sky2_poll(struct net_device *dev0, int *budget)
2133 sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); 2146 sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
2134 } 2147 }
2135 2148
2136 netif_rx_complete(dev0); 2149 mod_timer(&hw->idle_timer, jiffies + HZ);
2150
2151 local_irq_disable();
2152 __netif_rx_complete(dev0);
2137 2153
2138 status = sky2_read32(hw, B0_Y2_SP_LISR); 2154 status = sky2_read32(hw, B0_Y2_SP_LISR);
2155
2156 if (unlikely(status)) {
2157 /* More work pending, try and keep going */
2158 if (__netif_rx_schedule_prep(dev0)) {
2159 __netif_rx_reschedule(dev0, work_done);
2160 status = sky2_read32(hw, B0_Y2_SP_EISR);
2161 local_irq_enable();
2162 goto restart_poll;
2163 }
2164 }
2165
2166 local_irq_enable();
2139 return 0; 2167 return 0;
2140} 2168}
2141 2169
@@ -2153,8 +2181,6 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
2153 prefetch(&hw->st_le[hw->st_idx]); 2181 prefetch(&hw->st_le[hw->st_idx]);
2154 if (likely(__netif_rx_schedule_prep(dev0))) 2182 if (likely(__netif_rx_schedule_prep(dev0)))
2155 __netif_rx_schedule(dev0); 2183 __netif_rx_schedule(dev0);
2156 else
2157 printk(KERN_DEBUG PFX "irq race detected\n");
2158 2184
2159 return IRQ_HANDLED; 2185 return IRQ_HANDLED;
2160} 2186}
@@ -2193,7 +2219,7 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
2193} 2219}
2194 2220
2195 2221
2196static int sky2_reset(struct sky2_hw *hw) 2222static int __devinit sky2_reset(struct sky2_hw *hw)
2197{ 2223{
2198 u16 status; 2224 u16 status;
2199 u8 t8, pmd_type; 2225 u8 t8, pmd_type;
@@ -3276,6 +3302,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3276 3302
3277 sky2_write32(hw, B0_IMSK, Y2_IS_BASE); 3303 sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
3278 3304
3305 setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) dev);
3306
3279 pci_set_drvdata(pdev, hw); 3307 pci_set_drvdata(pdev, hw);
3280 3308
3281 return 0; 3309 return 0;
@@ -3311,13 +3339,15 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
3311 if (!hw) 3339 if (!hw)
3312 return; 3340 return;
3313 3341
3342 del_timer_sync(&hw->idle_timer);
3343
3344 sky2_write32(hw, B0_IMSK, 0);
3314 dev0 = hw->dev[0]; 3345 dev0 = hw->dev[0];
3315 dev1 = hw->dev[1]; 3346 dev1 = hw->dev[1];
3316 if (dev1) 3347 if (dev1)
3317 unregister_netdev(dev1); 3348 unregister_netdev(dev1);
3318 unregister_netdev(dev0); 3349 unregister_netdev(dev0);
3319 3350
3320 sky2_write32(hw, B0_IMSK, 0);
3321 sky2_set_power_state(hw, PCI_D3hot); 3351 sky2_set_power_state(hw, PCI_D3hot);
3322 sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); 3352 sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
3323 sky2_write8(hw, B0_CTST, CS_RST_SET); 3353 sky2_write8(hw, B0_CTST, CS_RST_SET);