[PATCH] sky2: more pci device id's
[pandora-kernel.git] / drivers / net / sky2.c
index 67ebc05..7ce0663 100644 (file)
@@ -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 " "
 
 /*
@@ -106,6 +106,7 @@ static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
        { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) },    /* DGE-560T */
+       { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) },    /* DGE-550SX */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) },
@@ -117,6 +118,7 @@ static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4350) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) },
@@ -126,6 +128,7 @@ static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) },
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) },
        { 0 }
 };
 
@@ -195,7 +198,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 +230,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 +244,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 +267,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 +515,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 +770,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 +960,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 +1005,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 +1094,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 +1200,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;
@@ -1242,15 +1252,15 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
                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;
@@ -1278,12 +1288,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);
@@ -1318,19 +1333,15 @@ 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);
 
@@ -1418,7 +1429,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);
@@ -1466,6 +1477,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);
 
@@ -1829,15 +1842,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);
@@ -1848,11 +1862,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;
 
@@ -1867,7 +1881,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;
 
@@ -1897,7 +1911,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++;
@@ -1951,11 +1965,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;
 
@@ -2400,7 +2413,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;
@@ -3191,6 +3204,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);
@@ -3200,10 +3215,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);