diff options
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 87 |
1 files changed, 60 insertions, 27 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 60779ebf2ff6..418f169a6a31 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -23,7 +23,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/crc32.h> #include <linux/kernel.h> #include <linux/version.h> @@ -187,12 +186,11 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg) return v; } -static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) +static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) { u16 power_control; u32 reg1; int vaux; - int ret = 0; pr_debug("sky2_set_power_state %d\n", state); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); @@ -275,12 +273,10 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) break; default: printk(KERN_ERR PFX "Unknown power state %d\n", state); - ret = -1; } sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - return ret; } static void sky2_phy_reset(struct sky2_hw *hw, unsigned port) @@ -979,6 +975,7 @@ static int sky2_rx_start(struct sky2_port *sky2) struct sky2_hw *hw = sky2->hw; unsigned rxq = rxqaddr[sky2->port]; int i; + unsigned thresh; sky2->rx_put = sky2->rx_next = 0; sky2_qset(hw, rxq); @@ -1003,9 +1000,21 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2_rx_add(sky2, re->mapaddr); } - /* Truncate oversize frames */ - sky2_write16(hw, SK_REG(sky2->port, RX_GMF_TR_THR), sky2->rx_bufsize - 8); - sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON); + + /* + * The receiver hangs if it receives frames larger than the + * packet buffer. As a workaround, truncate oversize frames, but + * the register is limited to 9 bits, so if you do frames > 2052 + * you better get the MTU right! + */ + thresh = (sky2->rx_bufsize - 8) / sizeof(u32); + if (thresh > 0x1ff) + sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF); + else { + sky2_write16(hw, SK_REG(sky2->port, RX_GMF_TR_THR), thresh); + sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON); + } + /* Tell chip about available buffers */ sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put); @@ -1150,7 +1159,7 @@ static unsigned tx_le_req(const struct sk_buff *skb) count = sizeof(dma_addr_t) / sizeof(u32); count += skb_shinfo(skb)->nr_frags * count; - if (skb_shinfo(skb)->tso_size) + if (skb_shinfo(skb)->gso_size) ++count; if (skb->ip_summed == CHECKSUM_HW) @@ -1222,7 +1231,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) } /* Check for TCP Segmentation Offload */ - mss = skb_shinfo(skb)->tso_size; + mss = skb_shinfo(skb)->gso_size; if (mss != 0) { /* just drop the packet if non-linear expansion fails */ if (skb_header_cloned(skb) && @@ -2151,6 +2160,13 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port, /* If idle then force a fake soft NAPI poll once a second * to work around cases where sharing an edge triggered interrupt. */ +static inline void sky2_idle_start(struct sky2_hw *hw) +{ + if (idle_timeout > 0) + mod_timer(&hw->idle_timer, + jiffies + msecs_to_jiffies(idle_timeout)); +} + static void sky2_idle(unsigned long arg) { struct sky2_hw *hw = (struct sky2_hw *) arg; @@ -2170,6 +2186,9 @@ static int sky2_poll(struct net_device *dev0, int *budget) int work_done = 0; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); + if (!~status) + goto out; + if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); @@ -2206,7 +2225,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) if (sky2_more_work(hw)) return 1; - +out: netif_rx_complete(dev0); sky2_read32(hw, B0_Y2_SP_LISR); @@ -2235,8 +2254,10 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) static void sky2_netpoll(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); + struct net_device *dev0 = sky2->hw->dev[0]; - sky2_intr(sky2->hw->pdev->irq, sky2->hw, NULL); + if (netif_running(dev) && __netif_rx_schedule_prep(dev0)) + __netif_rx_schedule(dev0); } #endif @@ -3167,7 +3188,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW); - err = request_irq(pdev->irq, sky2_test_intr, SA_SHIRQ, DRV_NAME, hw); + err = request_irq(pdev->irq, sky2_test_intr, IRQF_SHARED, DRV_NAME, hw); if (err) { printk(KERN_ERR PFX "%s: cannot assign irq %d\n", pci_name(pdev), pdev->irq); @@ -3289,9 +3310,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev, if (err) goto err_out_iounmap; - printk(KERN_INFO PFX "v%s addr 0x%lx irq %d Yukon-%s (0x%x) rev %d\n", - DRV_VERSION, pci_resource_start(pdev, 0), pdev->irq, - yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], + printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n", + DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0), + pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], hw->chip_id, hw->chip_rev); dev = sky2_init_netdev(hw, 0, using_dac); @@ -3327,7 +3348,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out_unregister; } - err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw); + err = request_irq(pdev->irq, sky2_intr, IRQF_SHARED, DRV_NAME, hw); if (err) { printk(KERN_ERR PFX "%s: cannot assign irq %d\n", pci_name(pdev), pdev->irq); @@ -3337,9 +3358,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, sky2_write32(hw, B0_IMSK, Y2_IS_BASE); setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); - if (idle_timeout > 0) - mod_timer(&hw->idle_timer, - jiffies + msecs_to_jiffies(idle_timeout)); + sky2_idle_start(hw); pci_set_drvdata(pdev, hw); @@ -3412,8 +3431,14 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) { struct sky2_hw *hw = pci_get_drvdata(pdev); int i; + pci_power_t pstate = pci_choose_state(pdev, state); - for (i = 0; i < 2; i++) { + if (!(pstate == PCI_D3hot || pstate == PCI_D3cold)) + return -EINVAL; + + del_timer_sync(&hw->idle_timer); + + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; if (dev) { @@ -3422,10 +3447,14 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) sky2_down(dev); netif_device_detach(dev); + netif_poll_disable(dev); } } - return sky2_set_power_state(hw, pci_choose_state(pdev, state)); + sky2_write32(hw, B0_IMSK, 0); + pci_save_state(pdev); + sky2_set_power_state(hw, pstate); + return 0; } static int sky2_resume(struct pci_dev *pdev) @@ -3435,27 +3464,31 @@ static int sky2_resume(struct pci_dev *pdev) pci_restore_state(pdev); pci_enable_wake(pdev, PCI_D0, 0); - err = sky2_set_power_state(hw, PCI_D0); - if (err) - goto out; + sky2_set_power_state(hw, PCI_D0); err = sky2_reset(hw); if (err) goto out; - for (i = 0; i < 2; i++) { + sky2_write32(hw, B0_IMSK, Y2_IS_BASE); + + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; if (dev && netif_running(dev)) { netif_device_attach(dev); + netif_poll_enable(dev); + err = sky2_up(dev); if (err) { printk(KERN_ERR PFX "%s: could not up: %d\n", dev->name, err); dev_close(dev); - break; + goto out; } } } + + sky2_idle_start(hw); out: return err; } |