Merge branch 'upstream' of master.kernel.org:/pub/scm/linux/kernel/git/shemminger...
[deliverable/linux.git] / drivers / net / sky2.c
index 940ed699a70292ea47625d8660e4a5741a54f65b..ffd267fab21da998ed0a349716ba4594706b9aec 100644 (file)
@@ -51,7 +51,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.2"
+#define DRV_VERSION            "1.3"
 #define PFX                    DRV_NAME " "
 
 /*
@@ -128,6 +128,7 @@ MODULE_DEVICE_TABLE(pci, sky2_id_table);
 /* Avoid conditionals by using array */
 static const unsigned txqaddr[] = { Q_XA1, Q_XA2 };
 static const unsigned rxqaddr[] = { Q_R1, Q_R2 };
+static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
 
 /* This driver supports yukon2 chipset only */
 static const char *yukon2_name[] = {
@@ -304,7 +305,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
        struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
        u16 ctrl, ct1000, adv, pg, ledctrl, ledover;
 
-       if (sky2->autoneg == AUTONEG_ENABLE && hw->chip_id != CHIP_ID_YUKON_XL) {
+       if (sky2->autoneg == AUTONEG_ENABLE &&
+           (hw->chip_id != CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
                u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
 
                ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -332,7 +334,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                        ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
 
                        if (sky2->autoneg == AUTONEG_ENABLE &&
-                           hw->chip_id == CHIP_ID_YUKON_XL) {
+                           (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
                                ctrl &= ~PHY_M_PC_DSC_MSK;
                                ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
                        }
@@ -448,10 +450,11 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
 
                /* set LED Function Control register */
-               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, (PHY_M_LEDC_LOS_CTRL(1) |     /* LINK/ACT */
-                                                          PHY_M_LEDC_INIT_CTRL(7) |    /* 10 Mbps */
-                                                          PHY_M_LEDC_STA1_CTRL(7) |    /* 100 Mbps */
-                                                          PHY_M_LEDC_STA0_CTRL(7)));   /* 1000 Mbps */
+               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+                            (PHY_M_LEDC_LOS_CTRL(1) |  /* LINK/ACT */
+                             PHY_M_LEDC_INIT_CTRL(7) | /* 10 Mbps */
+                             PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */
+                             PHY_M_LEDC_STA0_CTRL(7)));        /* 1000 Mbps */
 
                /* set Polarity Control register */
                gm_phy_write(hw, port, PHY_MARV_PHY_STAT,
@@ -465,6 +468,25 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                /* restore page register */
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
                break;
+       case CHIP_ID_YUKON_EC_U:
+               pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+
+               /* select page 3 to access LED control register */
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
+
+               /* set LED Function Control register */
+               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL,
+                            (PHY_M_LEDC_LOS_CTRL(1) |  /* LINK/ACT */
+                             PHY_M_LEDC_INIT_CTRL(8) | /* 10 Mbps */
+                             PHY_M_LEDC_STA1_CTRL(7) | /* 100 Mbps */
+                             PHY_M_LEDC_STA0_CTRL(7)));/* 1000 Mbps */
+
+               /* set Blink Rate in LED Timer Control Register */
+               gm_phy_write(hw, port, PHY_MARV_INT_MASK,
+                            ledctrl | PHY_M_LED_BLINK_RT(BLINK_84MS));
+               /* restore page register */
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
+               break;
 
        default:
                /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
@@ -473,19 +495,21 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
        }
 
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev >= 2) {
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == CHIP_REV_YU_EC_A1) {
                /* apply fixes in PHY AFE */
-               gm_phy_write(hw, port, 22, 255);
+               pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 255);
+
                /* increase differential signal amplitude in 10BASE-T */
-               gm_phy_write(hw, port, 24, 0xaa99);
-               gm_phy_write(hw, port, 23, 0x2011);
+               gm_phy_write(hw, port, 0x18, 0xaa99);
+               gm_phy_write(hw, port, 0x17, 0x2011);
 
                /* fix for IEEE A/B Symmetry failure in 1000BASE-T */
-               gm_phy_write(hw, port, 24, 0xa204);
-               gm_phy_write(hw, port, 23, 0x2002);
+               gm_phy_write(hw, port, 0x18, 0xa204);
+               gm_phy_write(hw, port, 0x17, 0x2002);
 
                /* set page register to 0 */
-               gm_phy_write(hw, port, 22, 0);
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
        } else {
                gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
 
@@ -559,6 +583,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 
                if (sky2->duplex == DUPLEX_FULL)
                        reg |= GM_GPCR_DUP_FULL;
+
+               /* turn off pause in 10/100mbps half duplex */
+               else if (sky2->speed != SPEED_1000 &&
+                        hw->chip_id != CHIP_ID_YUKON_EC_U)
+                       sky2->tx_pause = sky2->rx_pause = 0;
        } else
                reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
 
@@ -1056,7 +1085,7 @@ static int sky2_up(struct net_device *dev)
 
        /* Enable interrupts from phy/mac for port */
        imask = sky2_read32(hw, B0_IMSK);
-       imask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
+       imask |= portirq_msk[port];
        sky2_write32(hw, B0_IMSK, imask);
 
        return 0;
@@ -1407,7 +1436,7 @@ static int sky2_down(struct net_device *dev)
 
        /* Disable port IRQ */
        imask = sky2_read32(hw, B0_IMSK);
-       imask &= ~(sky2->port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
+       imask &= ~portirq_msk[port];
        sky2_write32(hw, B0_IMSK, imask);
 
        /* turn off LED's */
@@ -1504,17 +1533,26 @@ static void sky2_link_up(struct sky2_port *sky2)
        sky2_write8(hw, SK_REG(port, LNK_LED_REG),
                    LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL) {
+       if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) {
                u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+               u16 led = PHY_M_LEDC_LOS_CTRL(1);       /* link active */
+
+               switch(sky2->speed) {
+               case SPEED_10:
+                       led |= PHY_M_LEDC_INIT_CTRL(7);
+                       break;
+
+               case SPEED_100:
+                       led |= PHY_M_LEDC_STA1_CTRL(7);
+                       break;
+
+               case SPEED_1000:
+                       led |= PHY_M_LEDC_STA0_CTRL(7);
+                       break;
+               }
 
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
-               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, PHY_M_LEDC_LOS_CTRL(1) |      /* LINK/ACT */
-                            PHY_M_LEDC_INIT_CTRL(sky2->speed ==
-                                                 SPEED_10 ? 7 : 0) |
-                            PHY_M_LEDC_STA1_CTRL(sky2->speed ==
-                                                 SPEED_100 ? 7 : 0) |
-                            PHY_M_LEDC_STA0_CTRL(sky2->speed ==
-                                                 SPEED_1000 ? 7 : 0));
+               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, led);
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
        }
 
@@ -1589,7 +1627,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
        sky2->speed = sky2_phy_speed(hw, aux);
 
        /* Pause bits are offset (9..8) */
-       if (hw->chip_id == CHIP_ID_YUKON_XL)
+       if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
                aux >>= 6;
 
        sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
@@ -1865,35 +1903,28 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
 static int sky2_status_intr(struct sky2_hw *hw, int to_do)
 {
        int work_done = 0;
+       u16 hwidx = sky2_read16(hw, STAT_PUT_IDX);
 
        rmb();
 
-       for(;;) {
+       while (hw->st_idx != hwidx) {
                struct sky2_status_le *le  = hw->st_le + hw->st_idx;
                struct net_device *dev;
                struct sky2_port *sky2;
                struct sk_buff *skb;
                u32 status;
                u16 length;
-               u8  link, opcode;
-
-               opcode = le->opcode;
-               if (!opcode)
-                       break;
-               opcode &= ~HW_OWNER;
 
                hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
-               le->opcode = 0;
 
-               link = le->link;
-               BUG_ON(link >= 2);
-               dev = hw->dev[link];
+               BUG_ON(le->link >= 2);
+               dev = hw->dev[le->link];
 
                sky2 = netdev_priv(dev);
                length = le->length;
                status = le->status;
 
-               switch (opcode) {
+               switch (le->opcode & ~HW_OWNER) {
                case OP_RXSTAT:
                        skb = sky2_receive(sky2, length, status);
                        if (!skb)
@@ -1944,8 +1975,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
                default:
                        if (net_ratelimit())
                                printk(KERN_WARNING PFX
-                                      "unknown status opcode 0x%x\n", opcode);
-                       break;
+                                      "unknown status opcode 0x%x\n", le->opcode);
+                       goto exit_loop;
                }
        }
 
@@ -2233,13 +2264,6 @@ static int __devinit sky2_reset(struct sky2_hw *hw)
                return -EOPNOTSUPP;
        }
 
-       /* This chip is new and not tested yet */
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
-               pr_info(PFX "%s: is a version of Yukon 2 chipset that has not been tested yet.\n",
-                       pci_name(hw->pdev));
-               pr_info("Please report success/failure to maintainer <shemminger@osdl.org>\n");
-       }
-
        /* disable ASF */
        if (hw->chip_id <= CHIP_ID_YUKON_EC) {
                sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
@@ -3334,6 +3358,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
        del_timer_sync(&hw->idle_timer);
 
        sky2_write32(hw, B0_IMSK, 0);
+       synchronize_irq(hw->pdev->irq);
+
        dev0 = hw->dev[0];
        dev1 = hw->dev[1];
        if (dev1)
This page took 0.033919 seconds and 5 git commands to generate.