diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/skge.c | 88 | ||||
-rw-r--r-- | drivers/net/sky2.c | 152 | ||||
-rw-r--r-- | drivers/net/sky2.h | 3 |
3 files changed, 129 insertions, 114 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 1b752141a4f3..a1fc04365e07 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -43,7 +43,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.6" +#define DRV_VERSION "1.7" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -827,7 +827,8 @@ static int skge_rx_fill(struct skge_port *skge) do { struct sk_buff *skb; - skb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_KERNEL); + skb = __dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, + GFP_KERNEL); if (!skb) return -ENOMEM; @@ -2609,7 +2610,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, goto error; if (len < RX_COPY_THRESHOLD) { - skb = alloc_skb(len + 2, GFP_ATOMIC); + skb = dev_alloc_skb(len + 2); if (!skb) goto resubmit; @@ -2624,7 +2625,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, skge_rx_reuse(e, skge->rx_buf_size); } else { struct sk_buff *nskb; - nskb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_ATOMIC); + nskb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN); if (!nskb) goto resubmit; @@ -2747,7 +2748,7 @@ static int skge_poll(struct net_device *dev, int *budget) spin_lock_irq(&hw->hw_lock); hw->intr_mask |= rxirqmask[skge->port]; skge_write32(hw, B0_IMSK, hw->intr_mask); - mmiowb(); + skge_read32(hw, B0_IMSK); spin_unlock_irq(&hw->hw_lock); return 0; @@ -2881,6 +2882,7 @@ static void skge_extirq(void *arg) spin_lock_irq(&hw->hw_lock); hw->intr_mask |= IS_EXT_REG; skge_write32(hw, B0_IMSK, hw->intr_mask); + skge_read32(hw, B0_IMSK); spin_unlock_irq(&hw->hw_lock); } @@ -2955,6 +2957,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) skge_error_irq(hw); skge_write32(hw, B0_IMSK, hw->intr_mask); + skge_read32(hw, B0_IMSK); spin_unlock(&hw->hw_lock); return IRQ_HANDLED; @@ -3106,7 +3109,6 @@ static int skge_reset(struct skge_hw *hw) else hw->ram_size = t8 * 4096; - spin_lock_init(&hw->hw_lock); hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1; if (hw->ports > 1) hw->intr_mask |= IS_PORT_2; @@ -3332,6 +3334,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, hw->pdev = pdev; mutex_init(&hw->phy_mutex); INIT_WORK(&hw->phy_work, skge_extirq, hw); + spin_lock_init(&hw->hw_lock); hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); if (!hw->regs) { @@ -3340,23 +3343,16 @@ static int __devinit skge_probe(struct pci_dev *pdev, goto err_out_free_hw; } - err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, DRV_NAME, hw); - if (err) { - printk(KERN_ERR PFX "%s: cannot assign irq %d\n", - pci_name(pdev), pdev->irq); - goto err_out_iounmap; - } - pci_set_drvdata(pdev, hw); - err = skge_reset(hw); if (err) - goto err_out_free_irq; + goto err_out_iounmap; printk(KERN_INFO PFX DRV_VERSION " addr 0x%llx irq %d chip %s rev %d\n", (unsigned long long)pci_resource_start(pdev, 0), pdev->irq, skge_board_name(hw), hw->chip_rev); - if ((dev = skge_devinit(hw, 0, using_dac)) == NULL) + dev = skge_devinit(hw, 0, using_dac); + if (!dev) goto err_out_led_off; if (!is_valid_ether_addr(dev->dev_addr)) { @@ -3366,7 +3362,6 @@ static int __devinit skge_probe(struct pci_dev *pdev, goto err_out_free_netdev; } - err = register_netdev(dev); if (err) { printk(KERN_ERR PFX "%s: cannot register net device\n", @@ -3374,6 +3369,12 @@ static int __devinit skge_probe(struct pci_dev *pdev, goto err_out_free_netdev; } + err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw); + if (err) { + printk(KERN_ERR PFX "%s: cannot assign irq %d\n", + dev->name, pdev->irq); + goto err_out_unregister; + } skge_show_addr(dev); if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) { @@ -3386,15 +3387,16 @@ static int __devinit skge_probe(struct pci_dev *pdev, free_netdev(dev1); } } + pci_set_drvdata(pdev, hw); return 0; +err_out_unregister: + unregister_netdev(dev); err_out_free_netdev: free_netdev(dev); err_out_led_off: skge_write16(hw, B0_LED, LED_STAT_OFF); -err_out_free_irq: - free_irq(pdev->irq, hw); err_out_iounmap: iounmap(hw->regs); err_out_free_hw: @@ -3424,6 +3426,7 @@ static void __devexit skge_remove(struct pci_dev *pdev) spin_lock_irq(&hw->hw_lock); hw->intr_mask = 0; skge_write32(hw, B0_IMSK, 0); + skge_read32(hw, B0_IMSK); spin_unlock_irq(&hw->hw_lock); skge_write16(hw, B0_LED, LED_STAT_OFF); @@ -3449,26 +3452,25 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state) struct skge_hw *hw = pci_get_drvdata(pdev); int i, wol = 0; - for (i = 0; i < 2; i++) { + pci_save_state(pdev); + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; - if (dev) { + if (netif_running(dev)) { struct skge_port *skge = netdev_priv(dev); - if (netif_running(dev)) { - netif_carrier_off(dev); - if (skge->wol) - netif_stop_queue(dev); - else - skge_down(dev); - } - netif_device_detach(dev); + + netif_carrier_off(dev); + if (skge->wol) + netif_stop_queue(dev); + else + skge_down(dev); wol |= skge->wol; } + netif_device_detach(dev); } - pci_save_state(pdev); + skge_write32(hw, B0_IMSK, 0); pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); - pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; @@ -3477,23 +3479,33 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state) static int skge_resume(struct pci_dev *pdev) { struct skge_hw *hw = pci_get_drvdata(pdev); - int i; + int i, err; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); pci_enable_wake(pdev, PCI_D0, 0); - skge_reset(hw); + err = skge_reset(hw); + if (err) + goto out; - for (i = 0; i < 2; i++) { + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; - if (dev) { - netif_device_attach(dev); - if (netif_running(dev) && skge_up(dev)) + + netif_device_attach(dev); + if (netif_running(dev)) { + err = skge_up(dev); + + if (err) { + printk(KERN_ERR PFX "%s: could not up: %d\n", + dev->name, err); dev_close(dev); + goto out; + } } } - return 0; +out: + return err; } #endif diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 805a7dcf5508..f37fe8fabe7b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.6" +#define DRV_VERSION "1.7" #define PFX DRV_NAME " " /* @@ -195,7 +195,6 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg) static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) { u16 power_control; - u32 reg1; int vaux; pr_debug("sky2_set_power_state %d\n", state); @@ -228,20 +227,9 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) else sky2_write8(hw, B2_Y2_CLK_GATE, 0); - /* Turn off phy power saving */ - reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); - reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); - - /* looks like this XL is back asswards .. */ - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) { - reg1 |= PCI_Y2_PHY1_COMA; - if (hw->ports > 1) - reg1 |= PCI_Y2_PHY2_COMA; - } - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - udelay(100); - if (hw->chip_id == CHIP_ID_YUKON_EC_U) { + u32 reg1; + sky2_pci_write32(hw, PCI_DEV_REG3, 0); reg1 = sky2_pci_read32(hw, PCI_DEV_REG4); reg1 &= P_ASPM_CONTROL_MSK; @@ -253,15 +241,6 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) case PCI_D3hot: case PCI_D3cold: - /* Turn on phy power saving */ - reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) - reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); - else - reg1 |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); - sky2_pci_write32(hw, PCI_DEV_REG1, reg1); - udelay(100); - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) sky2_write8(hw, B2_Y2_CLK_GATE, 0); else @@ -285,7 +264,7 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } -static void sky2_phy_reset(struct sky2_hw *hw, unsigned port) +static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) { u16 reg; @@ -533,6 +512,29 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); } +static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff) +{ + u32 reg1; + static const u32 phy_power[] + = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD }; + + /* looks like this XL is back asswards .. */ + if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + onoff = !onoff; + + reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + + if (onoff) + /* Turn off phy power saving */ + reg1 &= ~phy_power[port]; + else + reg1 |= phy_power[port]; + + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + sky2_pci_read32(hw, PCI_DEV_REG1); + udelay(100); +} + /* Force a renegotiation */ static void sky2_phy_reinit(struct sky2_port *sky2) { @@ -765,9 +767,10 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) /* Update chip's next pointer */ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) { + q = Y2_QADDR(q, PREF_UNIT_PUT_IDX); wmb(); - sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx); - mmiowb(); + sky2_write16(hw, q, idx); + sky2_read16(hw, q); } @@ -954,14 +957,16 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) /* * It appears the hardware has a bug in the FIFO logic that * cause it to hang if the FIFO gets overrun and the receive buffer - * is not aligned. ALso alloc_skb() won't align properly if slab - * debugging is enabled. + * is not 64 byte aligned. The buffer returned from netdev_alloc_skb is + * aligned except if slab debugging is enabled. */ -static inline struct sk_buff *sky2_alloc_skb(unsigned int size, gfp_t gfp_mask) +static inline struct sk_buff *sky2_alloc_skb(struct net_device *dev, + unsigned int length, + gfp_t gfp_mask) { struct sk_buff *skb; - skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask); + skb = __netdev_alloc_skb(dev, length + RX_SKB_ALIGN, gfp_mask); if (likely(skb)) { unsigned long p = (unsigned long) skb->data; skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p); @@ -997,7 +1002,8 @@ static int sky2_rx_start(struct sky2_port *sky2) for (i = 0; i < sky2->rx_pending; i++) { struct ring_info *re = sky2->rx_ring + i; - re->skb = sky2_alloc_skb(sky2->rx_bufsize, GFP_KERNEL); + re->skb = sky2_alloc_skb(sky2->netdev, sky2->rx_bufsize, + GFP_KERNEL); if (!re->skb) goto nomem; @@ -1085,6 +1091,8 @@ static int sky2_up(struct net_device *dev) if (!sky2->rx_ring) goto err_out; + sky2_phy_power(hw, port, 1); + sky2_mac_init(hw, port); /* Determine available ram buffer space (in 4K blocks). @@ -1189,7 +1197,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) struct sky2_tx_le *le = NULL; struct tx_ring_info *re; unsigned i, len; - int avail; dma_addr_t mapping; u32 addr64; u16 mss; @@ -1239,25 +1246,18 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Check for TCP Segmentation Offload */ mss = skb_shinfo(skb)->gso_size; if (mss != 0) { - /* just drop the packet if non-linear expansion fails */ - if (skb_header_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - goto out_unlock; - } - mss += ((skb->h.th->doff - 5) * 4); /* TCP options */ mss += (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr); mss += ETH_HLEN; - } - if (mss != sky2->tx_last_mss) { - le = get_tx_le(sky2); - le->tx.tso.size = cpu_to_le16(mss); - le->tx.tso.rsvd = 0; - le->opcode = OP_LRGLEN | HW_OWNER; - le->ctrl = 0; - sky2->tx_last_mss = mss; + if (mss != sky2->tx_last_mss) { + le = get_tx_le(sky2); + le->tx.tso.size = cpu_to_le16(mss); + le->tx.tso.rsvd = 0; + le->opcode = OP_LRGLEN | HW_OWNER; + le->ctrl = 0; + sky2->tx_last_mss = mss; + } } ctrl = 0; @@ -1285,12 +1285,17 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) if (skb->nh.iph->protocol == IPPROTO_UDP) ctrl |= UDPTCP; - le = get_tx_le(sky2); - le->tx.csum.start = cpu_to_le16(hdr); - le->tx.csum.offset = cpu_to_le16(offset); - le->length = 0; /* initial checksum value */ - le->ctrl = 1; /* one packet */ - le->opcode = OP_TCPLISW | HW_OWNER; + if (hdr != sky2->tx_csum_start || offset != sky2->tx_csum_offset) { + sky2->tx_csum_start = hdr; + sky2->tx_csum_offset = offset; + + le = get_tx_le(sky2); + le->tx.csum.start = cpu_to_le16(hdr); + le->tx.csum.offset = cpu_to_le16(offset); + le->length = 0; /* initial checksum value */ + le->ctrl = 1; /* one packet */ + le->opcode = OP_TCPLISW | HW_OWNER; + } } le = get_tx_le(sky2); @@ -1325,23 +1330,18 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->opcode = OP_BUFFER | HW_OWNER; fre = sky2->tx_ring - + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE); + + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE); pci_unmap_addr_set(fre, mapaddr, mapping); } re->idx = sky2->tx_prod; le->ctrl |= EOP; - avail = tx_avail(sky2); - if (mss != 0 || avail < TX_MIN_PENDING) { - le->ctrl |= FRC_STAT; - if (avail <= MAX_SKB_TX_LE) - netif_stop_queue(dev); - } + if (tx_avail(sky2) <= MAX_SKB_TX_LE) + netif_stop_queue(dev); sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod); -out_unlock: spin_unlock(&sky2->tx_lock); dev->trans_start = jiffies; @@ -1426,7 +1426,7 @@ static int sky2_down(struct net_device *dev) /* Stop more packets from being queued */ netif_stop_queue(dev); - sky2_phy_reset(hw, port); + sky2_gmac_reset(hw, port); /* Stop transmitter */ sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_STOP); @@ -1474,6 +1474,8 @@ static int sky2_down(struct net_device *dev) imask &= ~portirq_msk[port]; sky2_write32(hw, B0_IMSK, imask); + sky2_phy_power(hw, port, 0); + /* turn off LED's */ sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); @@ -1837,15 +1839,16 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) * For small packets or errors, just reuse existing skb. * For larger packets, get new buffer. */ -static struct sk_buff *sky2_receive(struct sky2_port *sky2, +static struct sk_buff *sky2_receive(struct net_device *dev, u16 length, u32 status) { + struct sky2_port *sky2 = netdev_priv(dev); struct ring_info *re = sky2->rx_ring + sky2->rx_next; struct sk_buff *skb = NULL; if (unlikely(netif_msg_rx_status(sky2))) printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n", - sky2->netdev->name, sky2->rx_next, status, length); + dev->name, sky2->rx_next, status, length); sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending; prefetch(sky2->rx_ring + sky2->rx_next); @@ -1856,11 +1859,11 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2, if (!(status & GMR_FS_RX_OK)) goto resubmit; - if (length > sky2->netdev->mtu + ETH_HLEN) + if (length > dev->mtu + ETH_HLEN) goto oversize; if (length < copybreak) { - skb = alloc_skb(length + 2, GFP_ATOMIC); + skb = netdev_alloc_skb(dev, length + 2); if (!skb) goto resubmit; @@ -1875,7 +1878,7 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2, } else { struct sk_buff *nskb; - nskb = sky2_alloc_skb(sky2->rx_bufsize, GFP_ATOMIC); + nskb = sky2_alloc_skb(dev, sky2->rx_bufsize, GFP_ATOMIC); if (!nskb) goto resubmit; @@ -1905,7 +1908,7 @@ error: if (netif_msg_rx_err(sky2) && net_ratelimit()) printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n", - sky2->netdev->name, status, length); + dev->name, status, length); if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE)) sky2->net_stats.rx_length_errors++; @@ -1959,11 +1962,10 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) switch (le->opcode & ~HW_OWNER) { case OP_RXSTAT: - skb = sky2_receive(sky2, length, status); + skb = sky2_receive(dev, length, status); if (!skb) break; - skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); dev->last_rx = jiffies; @@ -2408,7 +2410,7 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK); for (i = 0; i < hw->ports; i++) - sky2_phy_reset(hw, i); + sky2_gmac_reset(hw, i); memset(hw->st_le, 0, STATUS_LE_BYTES); hw->st_idx = 0; @@ -3199,6 +3201,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) struct pci_dev *pdev = hw->pdev; int err; + init_waitqueue_head (&hw->msi_wait); + sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW); err = request_irq(pdev->irq, sky2_test_intr, IRQF_SHARED, DRV_NAME, hw); @@ -3208,10 +3212,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) return err; } - init_waitqueue_head (&hw->msi_wait); - sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ); - wmb(); + sky2_read8(hw, B0_CTST); wait_event_timeout(hw->msi_wait, hw->msi_detected, HZ/10); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 2db8d19b22d1..fa8af9f503e4 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1748,7 +1748,6 @@ enum { INIT_SUM= 1<<3, LOCK_SUM= 1<<4, INS_VLAN= 1<<5, - FRC_STAT= 1<<6, EOP = 1<<7, }; @@ -1844,6 +1843,8 @@ struct sky2_port { u32 tx_addr64; u16 tx_pending; u16 tx_last_mss; + u16 tx_csum_start; + u16 tx_csum_offset; struct ring_info *rx_ring ____cacheline_aligned_in_smp; struct sky2_rx_le *rx_le; |