Auto merge with /home/aegl/GIT/linus
[powerpc.git] / drivers / net / skge.c
index 7be569d..5cacc7a 100644 (file)
@@ -7,7 +7,7 @@
  * of the original driver such as link fail-over and link management because
  * those should be done at higher levels.
  *
- * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
+ * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include "skge.h"
 
 #define DRV_NAME               "skge"
-#define DRV_VERSION            "0.6"
+#define DRV_VERSION            "0.7"
 #define PFX                    DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE   128
 #define DEFAULT_RX_RING_SIZE   512
 #define MAX_TX_RING_SIZE       1024
 #define MAX_RX_RING_SIZE       4096
+#define RX_COPY_THRESHOLD      128
+#define RX_BUF_SIZE            1536
 #define PHY_RETRIES            1000
 #define ETH_JUMBO_MTU          9000
 #define TX_WATCHDOG            (5 * HZ)
 #define NAPI_WEIGHT            64
 #define BLINK_HZ               (HZ/4)
-#define LINK_POLL_HZ           (HZ/10)
 
 MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
 MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
@@ -96,11 +97,14 @@ static void yukon_init(struct skge_hw *hw, int port);
 static void yukon_reset(struct skge_hw *hw, int port);
 static void genesis_mac_init(struct skge_hw *hw, int port);
 static void genesis_reset(struct skge_hw *hw, int port);
+static void genesis_link_up(struct skge_port *skge);
 
+/* Avoid conditionals by using array */
 static const int txqaddr[] = { Q_XA1, Q_XA2 };
 static const int rxqaddr[] = { Q_R1, Q_R2 };
 static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
 static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
+static const u32 portirqmask[] = { IS_PORT_1, IS_PORT_2 };
 
 /* Don't need to look at whole 16K.
  * last interesting register is descriptor poll timer.
@@ -179,6 +183,36 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        return 0;
 }
 
+/* Determine supported/adverised modes based on hardware.
+ * Note: ethtoool ADVERTISED_xxx == SUPPORTED_xxx
+ */
+static u32 skge_supported_modes(const struct skge_hw *hw)
+{
+       u32 supported;
+
+       if (iscopper(hw)) {
+               supported = SUPPORTED_10baseT_Half
+                       | SUPPORTED_10baseT_Full
+                       | SUPPORTED_100baseT_Half
+                       | SUPPORTED_100baseT_Full
+                       | SUPPORTED_1000baseT_Half
+                       | SUPPORTED_1000baseT_Full
+                       | SUPPORTED_Autoneg| SUPPORTED_TP;
+
+               if (hw->chip_id == CHIP_ID_GENESIS)
+                       supported &= ~(SUPPORTED_10baseT_Half
+                                            | SUPPORTED_10baseT_Full
+                                            | SUPPORTED_100baseT_Half
+                                            | SUPPORTED_100baseT_Full);
+
+               else if (hw->chip_id == CHIP_ID_YUKON)
+                       supported &= ~SUPPORTED_1000baseT_Half;
+       } else
+               supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+                       | SUPPORTED_Autoneg;
+
+       return supported;
+}
 
 static int skge_get_settings(struct net_device *dev,
                             struct ethtool_cmd *ecmd)
@@ -187,38 +221,13 @@ static int skge_get_settings(struct net_device *dev,
        struct skge_hw *hw = skge->hw;
 
        ecmd->transceiver = XCVR_INTERNAL;
+       ecmd->supported = skge_supported_modes(hw);
 
        if (iscopper(hw)) {
-               if (hw->chip_id == CHIP_ID_GENESIS)
-                       ecmd->supported = SUPPORTED_1000baseT_Full
-                               | SUPPORTED_1000baseT_Half
-                               | SUPPORTED_Autoneg | SUPPORTED_TP;
-               else {
-                       ecmd->supported = SUPPORTED_10baseT_Half
-                               | SUPPORTED_10baseT_Full
-                               | SUPPORTED_100baseT_Half
-                               | SUPPORTED_100baseT_Full
-                               | SUPPORTED_1000baseT_Half
-                               | SUPPORTED_1000baseT_Full
-                               | SUPPORTED_Autoneg| SUPPORTED_TP;
-
-                       if (hw->chip_id == CHIP_ID_YUKON)
-                               ecmd->supported &= ~SUPPORTED_1000baseT_Half;
-
-                       else if (hw->chip_id == CHIP_ID_YUKON_FE)
-                               ecmd->supported &= ~(SUPPORTED_1000baseT_Half
-                                                    | SUPPORTED_1000baseT_Full);
-               }
-
                ecmd->port = PORT_TP;
                ecmd->phy_address = hw->phy_addr;
-       } else {
-               ecmd->supported = SUPPORTED_1000baseT_Full
-                       | SUPPORTED_FIBRE
-                       | SUPPORTED_Autoneg;
-
+       } else
                ecmd->port = PORT_FIBRE;
-       }
 
        ecmd->advertising = skge->advertising;
        ecmd->autoneg = skge->autoneg;
@@ -227,65 +236,57 @@ static int skge_get_settings(struct net_device *dev,
        return 0;
 }
 
-static u32 skge_modes(const struct skge_hw *hw)
-{
-       u32 modes = ADVERTISED_Autoneg
-               | ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half
-               | ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half
-               | ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half;
-
-       if (iscopper(hw)) {
-               modes |= ADVERTISED_TP;
-               switch (hw->chip_id) {
-               case CHIP_ID_GENESIS:
-                       modes &= ~(ADVERTISED_100baseT_Full
-                                  | ADVERTISED_100baseT_Half
-                                  | ADVERTISED_10baseT_Full
-                                  | ADVERTISED_10baseT_Half);
-                       break;
-
-               case CHIP_ID_YUKON:
-                       modes &= ~ADVERTISED_1000baseT_Half;
-                       break;
-
-               case CHIP_ID_YUKON_FE:
-                       modes &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
-                       break;
-               }
-       } else {
-               modes |= ADVERTISED_FIBRE;
-               modes &= ~ADVERTISED_1000baseT_Half;
-       }
-       return modes;
-}
-
 static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct skge_port *skge = netdev_priv(dev);
        const struct skge_hw *hw = skge->hw;
+       u32 supported = skge_supported_modes(hw);
 
        if (ecmd->autoneg == AUTONEG_ENABLE) {
-               if (ecmd->advertising & skge_modes(hw))
-                       return -EINVAL;
+               ecmd->advertising = supported;
+               skge->duplex = -1;
+               skge->speed = -1;
        } else {
-               switch (ecmd->speed) {
+               u32 setting;
+
+               switch(ecmd->speed) {
                case SPEED_1000:
-                       if (hw->chip_id == CHIP_ID_YUKON_FE)
+                       if (ecmd->duplex == DUPLEX_FULL)
+                               setting = SUPPORTED_1000baseT_Full;
+                       else if (ecmd->duplex == DUPLEX_HALF)
+                               setting = SUPPORTED_1000baseT_Half;
+                       else
                                return -EINVAL;
                        break;
                case SPEED_100:
+                       if (ecmd->duplex == DUPLEX_FULL)
+                               setting = SUPPORTED_100baseT_Full;
+                       else if (ecmd->duplex == DUPLEX_HALF)
+                               setting = SUPPORTED_100baseT_Half;
+                       else
+                               return -EINVAL;
+                       break;
+
                case SPEED_10:
-                       if (iscopper(hw) || hw->chip_id == CHIP_ID_GENESIS)
+                       if (ecmd->duplex == DUPLEX_FULL)
+                               setting = SUPPORTED_10baseT_Full;
+                       else if (ecmd->duplex == DUPLEX_HALF)
+                               setting = SUPPORTED_10baseT_Half;
+                       else
                                return -EINVAL;
                        break;
                default:
                        return -EINVAL;
                }
+
+               if ((setting & supported) == 0)
+                       return -EINVAL;
+
+               skge->speed = ecmd->speed;
+               skge->duplex = ecmd->duplex;
        }
 
        skge->autoneg = ecmd->autoneg;
-       skge->speed = ecmd->speed;
-       skge->duplex = ecmd->duplex;
        skge->advertising = ecmd->advertising;
 
        if (netif_running(dev)) {
@@ -540,8 +541,6 @@ static inline u32 hwkhz(const struct skge_hw *hw)
 {
        if (hw->chip_id == CHIP_ID_GENESIS)
                return 53215; /* or:  53.125 MHz */
-       else if (hw->chip_id == CHIP_ID_YUKON_EC)
-               return 125000; /* or: 125.000 MHz */
        else
                return 78215; /* or:  78.125 MHz */
 }
@@ -631,20 +630,8 @@ static void skge_led_on(struct skge_hw *hw, int port)
                skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
                skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
 
-               switch (hw->phy_type) {
-               case SK_PHY_BCOM:
-                       xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
-                                         PHY_B_PEC_LED_ON);
-                       break;
-               case SK_PHY_LONE:
-                       xm_phy_write(hw, port, PHY_LONE_LED_CFG,
-                                         0x0800);
-                       break;
-               default:
-                       skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON);
-                       skge_write32(hw, SK_REG(port, TX_LED_VAL), 100);
-                       skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
-               }
+               /* For Broadcom Phy only */
+               xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
        } else {
                gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
                gm_phy_write(hw, port, PHY_MARV_LED_OVER,
@@ -665,19 +652,8 @@ static void skge_led_off(struct skge_hw *hw, int port)
                skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
                skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
 
-               switch (hw->phy_type) {
-               case SK_PHY_BCOM:
-                       xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
-                                         PHY_B_PEC_LED_OFF);
-                       break;
-               case SK_PHY_LONE:
-                       xm_phy_write(hw, port, PHY_LONE_LED_CFG,
-                                         PHY_L_LC_LEDT);
-                       break;
-               default:
-                       skge_write32(hw, SK_REG(port, TX_LED_VAL), 0);
-                       skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF);
-               }
+               /* Broadcom only */
+               xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
        } else {
                gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
                gm_phy_write(hw, port, PHY_MARV_LED_OVER,
@@ -772,6 +748,7 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
 
        for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) {
                e->desc = d;
+               e->skb = NULL;
                if (i == ring->count - 1) {
                        e->next = ring->start;
                        d->next_offset = base;
@@ -785,24 +762,23 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
        return 0;
 }
 
-/* Setup buffer for receiving */
-static inline int skge_rx_alloc(struct skge_port *skge,
-                               struct skge_element *e)
+static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size)
 {
-       unsigned long bufsize = skge->netdev->mtu + ETH_HLEN; /* VLAN? */
-       struct skge_rx_desc *rd = e->desc;
-       struct sk_buff *skb;
-       u64 map;
+       struct sk_buff *skb = dev_alloc_skb(size);
 
-       skb = dev_alloc_skb(bufsize + NET_IP_ALIGN);
-       if (unlikely(!skb)) {
-               printk(KERN_DEBUG PFX "%s: out of memory for receive\n",
-                      skge->netdev->name);
-               return -ENOMEM;
+       if (likely(skb)) {
+               skb->dev = dev;
+               skb_reserve(skb, NET_IP_ALIGN);
        }
+       return skb;
+}
 
-       skb->dev = skge->netdev;
-       skb_reserve(skb, NET_IP_ALIGN);
+/* Allocate and setup a new buffer for receiving */
+static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
+                         struct sk_buff *skb, unsigned int bufsize)
+{
+       struct skge_rx_desc *rd = e->desc;
+       u64 map;
 
        map = pci_map_single(skge->hw->pdev, skb->data, bufsize,
                             PCI_DMA_FROMDEVICE);
@@ -820,55 +796,69 @@ static inline int skge_rx_alloc(struct skge_port *skge,
        rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
        pci_unmap_addr_set(e, mapaddr, map);
        pci_unmap_len_set(e, maplen, bufsize);
-       return 0;
 }
 
-/* Free all unused buffers in receive ring, assumes receiver stopped */
+/* Resume receiving using existing skb,
+ * Note: DMA address is not changed by chip.
+ *      MTU not changed while receiver active.
+ */
+static void skge_rx_reuse(struct skge_element *e, unsigned int size)
+{
+       struct skge_rx_desc *rd = e->desc;
+
+       rd->csum2 = 0;
+       rd->csum2_start = ETH_HLEN;
+
+       wmb();
+
+       rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size;
+}
+
+
+/* Free all  buffers in receive ring, assumes receiver stopped */
 static void skge_rx_clean(struct skge_port *skge)
 {
        struct skge_hw *hw = skge->hw;
        struct skge_ring *ring = &skge->rx_ring;
        struct skge_element *e;
 
-       for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+       e = ring->start;
+       do {
                struct skge_rx_desc *rd = e->desc;
                rd->control = 0;
-
-               pci_unmap_single(hw->pdev,
-                                pci_unmap_addr(e, mapaddr),
-                                pci_unmap_len(e, maplen),
-                                PCI_DMA_FROMDEVICE);
-               dev_kfree_skb(e->skb);
-               e->skb = NULL;
-       }
-       ring->to_clean = e;
+               if (e->skb) {
+                       pci_unmap_single(hw->pdev,
+                                        pci_unmap_addr(e, mapaddr),
+                                        pci_unmap_len(e, maplen),
+                                        PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(e->skb);
+                       e->skb = NULL;
+               }
+       } while ((e = e->next) != ring->start);
 }
 
+
 /* Allocate buffers for receive ring
- * For receive: to_use   is refill location
- *              to_clean is next received frame.
- *
- * if (to_use == to_clean)
- *      then ring all frames in ring need buffers
- * if (to_use->next == to_clean)
- *      then ring all frames in ring have buffers
+ * For receive:  to_clean is next received frame.
  */
 static int skge_rx_fill(struct skge_port *skge)
 {
        struct skge_ring *ring = &skge->rx_ring;
        struct skge_element *e;
-       int ret = 0;
+       unsigned int bufsize = skge->rx_buf_size;
 
-       for (e = ring->to_use; e->next != ring->to_clean; e = e->next) {
-               if (skge_rx_alloc(skge, e)) {
-                       ret = 1;
-                       break;
-               }
+       e = ring->start;
+       do {
+               struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize);
 
-       }
-       ring->to_use = e;
+               if (!skb)
+                       return -ENOMEM;
+
+               skge_rx_setup(skge, e, skb, bufsize);
+       } while ( (e = e->next) != ring->start);
 
-       return ret;
+       ring->to_clean = ring->start;
+       return 0;
 }
 
 static void skge_link_up(struct skge_port *skge)
@@ -905,21 +895,21 @@ static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
 
        xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
        v = xm_read16(hw, port, XM_PHY_DATA);
-       if (hw->phy_type != SK_PHY_XMAC) {
-               for (i = 0; i < PHY_RETRIES; i++) {
-                       udelay(1);
-                       if (xm_read16(hw, port, XM_MMU_CMD)
-                           & XM_MMU_PHY_RDY)
-                               goto ready;
-               }
 
-               printk(KERN_WARNING PFX "%s: phy read timed out\n",
-                      hw->dev[port]->name);
-               return 0;
-       ready:
-               v = xm_read16(hw, port, XM_PHY_DATA);
+       /* Need to wait for external PHY */
+       for (i = 0; i < PHY_RETRIES; i++) {
+               udelay(1);
+               if (xm_read16(hw, port, XM_MMU_CMD)
+                   & XM_MMU_PHY_RDY)
+                       goto ready;
        }
 
+       printk(KERN_WARNING PFX "%s: phy read timed out\n",
+              hw->dev[port]->name);
+       return 0;
+ ready:
+       v = xm_read16(hw, port, XM_PHY_DATA);
+
        return v;
 }
 
@@ -931,7 +921,7 @@ static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
        for (i = 0; i < PHY_RETRIES; i++) {
                if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
                        goto ready;
-               cpu_relax();
+               udelay(1);
        }
        printk(KERN_WARNING PFX "%s: phy write failed to come ready\n",
               hw->dev[port]->name);
@@ -978,8 +968,7 @@ static void genesis_init(struct skge_hw *hw)
 
 static void genesis_reset(struct skge_hw *hw, int port)
 {
-       int i;
-       u64 zero = 0;
+       const u8 zero[8]  = { 0 };
 
        /* reset the statistics module */
        xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
@@ -988,24 +977,103 @@ static void genesis_reset(struct skge_hw *hw, int port)
        xm_write16(hw, port, XM_TX_CMD, 0);     /* reset TX CMD Reg */
        xm_write16(hw, port, XM_RX_CMD, 0);     /* reset RX CMD Reg */
 
-       /* disable all PHY IRQs */
-       if  (hw->phy_type == SK_PHY_BCOM)
-               xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+       /* disable Broadcom PHY IRQ */
+       xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
 
-       xm_outhash(hw, port, XM_HSM, (u8 *) &zero);
-       for (i = 0; i < 15; i++)
-               xm_outaddr(hw, port, XM_EXM(i), (u8 *) &zero);
-       xm_outhash(hw, port, XM_SRC_CHK, (u8 *) &zero);
+       xm_outhash(hw, port, XM_HSM, zero);
 }
 
 
-static void genesis_mac_init(struct skge_hw *hw, int port)
+/* Convert mode to MII values  */
+static const u16 phy_pause_map[] = {
+       [FLOW_MODE_NONE] =      0,
+       [FLOW_MODE_LOC_SEND] =  PHY_AN_PAUSE_ASYM,
+       [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP,
+       [FLOW_MODE_REM_SEND]  = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM,
+};
+
+
+/* Check status of Broadcom phy link */
+static void bcom_check_link(struct skge_hw *hw, int port)
 {
-       struct skge_port *skge = netdev_priv(hw->dev[port]);
+       struct net_device *dev = hw->dev[port];
+       struct skge_port *skge = netdev_priv(dev);
+       u16 status;
+
+       /* read twice because of latch */
+       (void) xm_phy_read(hw, port, PHY_BCOM_STAT);
+       status = xm_phy_read(hw, port, PHY_BCOM_STAT);
+
+       pr_debug("bcom_check_link status=0x%x\n", status);
+
+       if ((status & PHY_ST_LSYNC) == 0) {
+               u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
+               cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+               xm_write16(hw, port, XM_MMU_CMD, cmd);
+               /* dummy read to ensure writing */
+               (void) xm_read16(hw, port, XM_MMU_CMD);
+
+               if (netif_carrier_ok(dev))
+                       skge_link_down(skge);
+       } else {
+               if (skge->autoneg == AUTONEG_ENABLE &&
+                   (status & PHY_ST_AN_OVER)) {
+                       u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP);
+                       u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
+
+                       if (lpa & PHY_B_AN_RF) {
+                               printk(KERN_NOTICE PFX "%s: remote fault\n",
+                                      dev->name);
+                               return;
+                       }
+
+                       /* Check Duplex mismatch */
+                       switch(aux & PHY_B_AS_AN_RES_MSK) {
+                       case PHY_B_RES_1000FD:
+                               skge->duplex = DUPLEX_FULL;
+                               break;
+                       case PHY_B_RES_1000HD:
+                               skge->duplex = DUPLEX_HALF;
+                               break;
+                       default:
+                               printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
+                                      dev->name);
+                               return;
+                       }
+
+
+                       /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+                       switch (aux & PHY_B_AS_PAUSE_MSK) {
+                       case PHY_B_AS_PAUSE_MSK:
+                               skge->flow_control = FLOW_MODE_SYMMETRIC;
+                               break;
+                       case PHY_B_AS_PRR:
+                               skge->flow_control = FLOW_MODE_REM_SEND;
+                               break;
+                       case PHY_B_AS_PRT:
+                               skge->flow_control = FLOW_MODE_LOC_SEND;
+                               break;
+                       default:
+                               skge->flow_control = FLOW_MODE_NONE;
+                       }
+
+                       skge->speed = SPEED_1000;
+               }
+
+               if (!netif_carrier_ok(dev))
+                       genesis_link_up(skge);
+       }
+}
+
+/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
+ * Phy on for 100 or 10Mbit operation
+ */
+static void bcom_phy_init(struct skge_port *skge, int jumbo)
+{
+       struct skge_hw *hw = skge->hw;
+       int port = skge->port;
        int i;
-       u32 r;
-       u16 id1;
-       u16 ctrl1, ctrl2, ctrl3, ctrl4, ctrl5;
+       u16 id1, r, ext, ctl;
 
        /* magic workaround patterns for Broadcom */
        static const struct {
@@ -1021,6 +1089,110 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
                { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 },
        };
 
+       pr_debug("bcom_phy_init\n");
+
+       /* read Id from external PHY (all have the same address) */
+       id1 = xm_phy_read(hw, port, PHY_XMAC_ID1);
+
+       /* Optimize MDIO transfer by suppressing preamble. */
+       r = xm_read16(hw, port, XM_MMU_CMD);
+       r |=  XM_MMU_NO_PRE;
+       xm_write16(hw, port, XM_MMU_CMD,r);
+
+       switch(id1) {
+       case PHY_BCOM_ID1_C0:
+               /*
+                * Workaround BCOM Errata for the C0 type.
+                * Write magic patterns to reserved registers.
+                */
+               for (i = 0; i < ARRAY_SIZE(C0hack); i++)
+                       xm_phy_write(hw, port,
+                                    C0hack[i].reg, C0hack[i].val);
+
+               break;
+       case PHY_BCOM_ID1_A1:
+               /*
+                * Workaround BCOM Errata for the A1 type.
+                * Write magic patterns to reserved registers.
+                */
+               for (i = 0; i < ARRAY_SIZE(A1hack); i++)
+                       xm_phy_write(hw, port,
+                                    A1hack[i].reg, A1hack[i].val);
+               break;
+       }
+
+       /*
+        * Workaround BCOM Errata (#10523) for all BCom PHYs.
+        * Disable Power Management after reset.
+        */
+       r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
+       r |= PHY_B_AC_DIS_PM;
+       xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r);
+
+       /* Dummy read */
+       xm_read16(hw, port, XM_ISRC);
+
+       ext = PHY_B_PEC_EN_LTR; /* enable tx led */
+       ctl = PHY_CT_SP1000;    /* always 1000mbit */
+
+       if (skge->autoneg == AUTONEG_ENABLE) {
+               /*
+                * Workaround BCOM Errata #1 for the C5 type.
+                * 1000Base-T Link Acquisition Failure in Slave Mode
+                * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+                */
+               u16 adv = PHY_B_1000C_RD;
+               if (skge->advertising & ADVERTISED_1000baseT_Half)
+                       adv |= PHY_B_1000C_AHD;
+               if (skge->advertising & ADVERTISED_1000baseT_Full)
+                       adv |= PHY_B_1000C_AFD;
+               xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, adv);
+
+               ctl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+       } else {
+               if (skge->duplex == DUPLEX_FULL)
+                       ctl |= PHY_CT_DUP_MD;
+               /* Force to slave */
+               xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, PHY_B_1000C_MSE);
+       }
+
+       /* Set autonegotiation pause parameters */
+       xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV,
+                    phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
+
+       /* Handle Jumbo frames */
+       if (jumbo) {
+               xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+                            PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
+
+               ext |= PHY_B_PEC_HIGH_LA;
+
+       }
+
+       xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext);
+       xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl);
+
+       /* Use link status change interrrupt */
+       xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+
+       bcom_check_link(hw, port);
+}
+
+static void genesis_mac_init(struct skge_hw *hw, int port)
+{
+       struct net_device *dev = hw->dev[port];
+       struct skge_port *skge = netdev_priv(dev);
+       int jumbo = hw->dev[port]->mtu > ETH_DATA_LEN;
+       int i;
+       u32 r;
+       const u8 zero[6]  = { 0 };
+
+       /* Clear MIB counters */
+       xm_write16(hw, port, XM_STAT_CMD,
+                       XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+       /* Clear two times according to Errata #3 */
+       xm_write16(hw, port, XM_STAT_CMD,
+                       XM_SC_CLR_RXC | XM_SC_CLR_TXC);
 
        /* initialize Rx, Tx and Link LED */
        skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
@@ -1038,67 +1210,56 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
         * GMII mode.
         */
        spin_lock_bh(&hw->phy_lock);
-       if (hw->phy_type != SK_PHY_XMAC) {
-               /* Take PHY out of reset. */
-               r = skge_read32(hw, B2_GP_IO);
-               if (port == 0)
-                       r |= GP_DIR_0|GP_IO_0;
-               else
-                       r |= GP_DIR_2|GP_IO_2;
-
-               skge_write32(hw, B2_GP_IO, r);
-               skge_read32(hw, B2_GP_IO);
-
-               /* Enable GMII mode on the XMAC. */
-               xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
-
-               id1 = xm_phy_read(hw, port, PHY_XMAC_ID1);
-
-               /* Optimize MDIO transfer by suppressing preamble. */
-               xm_write16(hw, port, XM_MMU_CMD,
-                               xm_read16(hw, port, XM_MMU_CMD)
-                               | XM_MMU_NO_PRE);
-
-               if (id1 == PHY_BCOM_ID1_C0) {
-                       /*
-                        * Workaround BCOM Errata for the C0 type.
-                        * Write magic patterns to reserved registers.
-                        */
-                       for (i = 0; i < ARRAY_SIZE(C0hack); i++)
-                               xm_phy_write(hw, port,
-                                         C0hack[i].reg, C0hack[i].val);
-
-               } else if (id1 == PHY_BCOM_ID1_A1) {
-                       /*
-                        * Workaround BCOM Errata for the A1 type.
-                        * Write magic patterns to reserved registers.
-                        */
-                       for (i = 0; i < ARRAY_SIZE(A1hack); i++)
-                               xm_phy_write(hw, port,
-                                         A1hack[i].reg, A1hack[i].val);
-               }
+       /* Take external Phy out of reset */
+       r = skge_read32(hw, B2_GP_IO);
+       if (port == 0)
+               r |= GP_DIR_0|GP_IO_0;
+       else
+               r |= GP_DIR_2|GP_IO_2;
 
-               /*
-                * Workaround BCOM Errata (#10523) for all BCom PHYs.
-                * Disable Power Management after reset.
-                */
-               r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
-               xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r | PHY_B_AC_DIS_PM);
-       }
+       skge_write32(hw, B2_GP_IO, r);
+       skge_read32(hw, B2_GP_IO);
+       spin_unlock_bh(&hw->phy_lock);
 
-       /* Dummy read */
-       xm_read16(hw, port, XM_ISRC);
+       /* Enable GMII interfac */
+       xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+
+       bcom_phy_init(skge, jumbo);
+
+       /* Set Station Address */
+       xm_outaddr(hw, port, XM_SA, dev->dev_addr);
+
+       /* We don't use match addresses so clear */
+       for (i = 1; i < 16; i++)
+               xm_outaddr(hw, port, XM_EXM(i), zero);
 
-       r = xm_read32(hw, port, XM_MODE);
-       xm_write32(hw, port, XM_MODE, r|XM_MD_CSA);
+       /* configure Rx High Water Mark (XM_RX_HI_WM) */
+       xm_write16(hw, port, XM_RX_HI_WM, 1450);
 
        /* We don't need the FCS appended to the packet. */
-       r = xm_read16(hw, port, XM_RX_CMD);
-       xm_write16(hw, port, XM_RX_CMD, r | XM_RX_STRIP_FCS);
+       r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS;
+       if (jumbo)
+               r |= XM_RX_BIG_PK_OK;
+
+       if (skge->duplex == DUPLEX_HALF) {
+               /*
+                * If in manual half duplex mode the other side might be in
+                * full duplex mode, so ignore if a carrier extension is not seen
+                * on frames received
+                */
+               r |= XM_RX_DIS_CEXT;
+       }
+       xm_write16(hw, port, XM_RX_CMD, r);
+
 
        /* We want short frames padded to 60 bytes. */
-       r = xm_read16(hw, port, XM_TX_CMD);
-       xm_write16(hw, port, XM_TX_CMD, r | XM_TX_AUTO_PAD);
+       xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+       /*
+        * Bump up the transmit threshold. This helps hold off transmit
+        * underruns when we're blasting traffic from both ports at once.
+        */
+       xm_write16(hw, port, XM_TX_THR, 512);
 
        /*
         * Enable the reception of all error frames. This is is
@@ -1114,19 +1275,22 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
         * case the XMAC will start transfering frames out of the
         * RX FIFO as soon as the FIFO threshold is reached.
         */
-       r = xm_read32(hw, port, XM_MODE);
-       xm_write32(hw, port, XM_MODE,
-                    XM_MD_RX_CRCE|XM_MD_RX_LONG|XM_MD_RX_RUNT|
-                    XM_MD_RX_ERR|XM_MD_RX_IRLE);
+       xm_write32(hw, port, XM_MODE, XM_DEF_MODE);
 
-       xm_outaddr(hw, port, XM_SA, hw->dev[port]->dev_addr);
-       xm_outaddr(hw, port, XM_EXM(0), hw->dev[port]->dev_addr);
 
        /*
-        * Bump up the transmit threshold. This helps hold off transmit
-        * underruns when we're blasting traffic from both ports at once.
+        * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+        *      - Enable all bits excepting 'Octets Rx OK Low CntOv'
+        *        and 'Octets Rx OK Hi Cnt Ov'.
         */
-       xm_write16(hw, port, XM_TX_THR, 512);
+       xm_write32(hw, port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+       /*
+        * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+        *      - Enable all bits excepting 'Octets Tx OK Low CntOv'
+        *        and 'Octets Tx OK Hi Cnt Ov'.
+        */
+       xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK);
 
        /* Configure MAC arbiter */
        skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
@@ -1152,128 +1316,21 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
        skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
        skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
 
-       if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+       if (jumbo) {
                /* Enable frame flushing if jumbo frames used */
                skge_write16(hw, SK_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
        } else {
                /* enable timeout timers if normal frames */
                skge_write16(hw, B3_PA_CTRL,
-                            port == 0 ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
+                            (port == 0) ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
        }
-
-
-       r = xm_read16(hw, port, XM_RX_CMD);
-       if (hw->dev[port]->mtu > ETH_DATA_LEN)
-               xm_write16(hw, port, XM_RX_CMD, r | XM_RX_BIG_PK_OK);
-       else
-               xm_write16(hw, port, XM_RX_CMD, r & ~(XM_RX_BIG_PK_OK));
-
-       switch (hw->phy_type) {
-       case SK_PHY_XMAC:
-               if (skge->autoneg == AUTONEG_ENABLE) {
-                       ctrl1 = PHY_X_AN_FD | PHY_X_AN_HD;
-
-                       switch (skge->flow_control) {
-                       case FLOW_MODE_NONE:
-                               ctrl1 |= PHY_X_P_NO_PAUSE;
-                               break;
-                       case FLOW_MODE_LOC_SEND:
-                               ctrl1 |= PHY_X_P_ASYM_MD;
-                               break;
-                       case FLOW_MODE_SYMMETRIC:
-                               ctrl1 |= PHY_X_P_SYM_MD;
-                               break;
-                       case FLOW_MODE_REM_SEND:
-                               ctrl1 |= PHY_X_P_BOTH_MD;
-                               break;
-                       }
-
-                       xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl1);
-                       ctrl2 = PHY_CT_ANE | PHY_CT_RE_CFG;
-               } else {
-                       ctrl2 = 0;
-                       if (skge->duplex == DUPLEX_FULL)
-                               ctrl2 |= PHY_CT_DUP_MD;
-               }
-
-               xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl2);
-               break;
-
-       case SK_PHY_BCOM:
-               ctrl1 = PHY_CT_SP1000;
-               ctrl2 = 0;
-               ctrl3 = PHY_SEL_TYPE;
-               ctrl4 = PHY_B_PEC_EN_LTR;
-               ctrl5 = PHY_B_AC_TX_TST;
-
-               if (skge->autoneg == AUTONEG_ENABLE) {
-                       /*
-                        * Workaround BCOM Errata #1 for the C5 type.
-                        * 1000Base-T Link Acquisition Failure in Slave Mode
-                        * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
-                        */
-                       ctrl2 |= PHY_B_1000C_RD;
-                       if (skge->advertising & ADVERTISED_1000baseT_Half)
-                               ctrl2 |= PHY_B_1000C_AHD;
-                       if (skge->advertising & ADVERTISED_1000baseT_Full)
-                               ctrl2 |= PHY_B_1000C_AFD;
-
-                       /* Set Flow-control capabilities */
-                       switch (skge->flow_control) {
-                       case FLOW_MODE_NONE:
-                               ctrl3 |= PHY_B_P_NO_PAUSE;
-                               break;
-                       case FLOW_MODE_LOC_SEND:
-                               ctrl3 |= PHY_B_P_ASYM_MD;
-                               break;
-                       case FLOW_MODE_SYMMETRIC:
-                               ctrl3 |= PHY_B_P_SYM_MD;
-                               break;
-                       case FLOW_MODE_REM_SEND:
-                               ctrl3 |= PHY_B_P_BOTH_MD;
-                               break;
-                       }
-
-                       /* Restart Auto-negotiation */
-                       ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
-               } else {
-                       if (skge->duplex == DUPLEX_FULL)
-                               ctrl1 |= PHY_CT_DUP_MD;
-
-                       ctrl2 |= PHY_B_1000C_MSE;       /* set it to Slave */
-               }
-
-               xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, ctrl2);
-               xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, ctrl3);
-
-               if (skge->netdev->mtu > ETH_DATA_LEN) {
-                       ctrl4 |= PHY_B_PEC_HIGH_LA;
-                       ctrl5 |= PHY_B_AC_LONG_PACK;
-
-                       xm_phy_write(hw, port,PHY_BCOM_AUX_CTRL, ctrl5);
-               }
-
-               xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ctrl4);
-               xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl1);
-               break;
-       }
-       spin_unlock_bh(&hw->phy_lock);
-
-       /* Clear MIB counters */
-       xm_write16(hw, port, XM_STAT_CMD,
-                       XM_SC_CLR_RXC | XM_SC_CLR_TXC);
-       /* Clear two times according to Errata #3 */
-       xm_write16(hw, port, XM_STAT_CMD,
-                       XM_SC_CLR_RXC | XM_SC_CLR_TXC);
-
-       /* Start polling for link status */
-       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
 }
 
 static void genesis_stop(struct skge_port *skge)
 {
        struct skge_hw *hw = skge->hw;
        int port = skge->port;
+       u32 reg;
 
        /* Clear Tx packet arbiter timeout IRQ */
        skge_write16(hw, B3_PA_CTRL,
@@ -1291,19 +1348,16 @@ static void genesis_stop(struct skge_port *skge)
        skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
 
        /* For external PHYs there must be special handling */
-       if (hw->phy_type != SK_PHY_XMAC) {
-               u32 reg = skge_read32(hw, B2_GP_IO);
-
-               if (port == 0) {
-                       reg |= GP_DIR_0;
-                       reg &= ~GP_IO_0;
-               } else {
-                       reg |= GP_DIR_2;
-                       reg &= ~GP_IO_2;
-               }
-               skge_write32(hw, B2_GP_IO, reg);
-               skge_read32(hw, B2_GP_IO);
+       reg = skge_read32(hw, B2_GP_IO);
+       if (port == 0) {
+               reg |= GP_DIR_0;
+               reg &= ~GP_IO_0;
+       } else {
+               reg |= GP_DIR_2;
+               reg &= ~GP_IO_2;
        }
+       skge_write32(hw, B2_GP_IO, reg);
+       skge_read32(hw, B2_GP_IO);
 
        xm_write16(hw, port, XM_MMU_CMD,
                        xm_read16(hw, port, XM_MMU_CMD)
@@ -1346,17 +1400,9 @@ static void genesis_mac_intr(struct skge_hw *hw, int port)
        struct skge_port *skge = netdev_priv(hw->dev[port]);
        u16 status = xm_read16(hw, port, XM_ISRC);
 
-       pr_debug("genesis_intr status %x\n", status);
-       if (hw->phy_type == SK_PHY_XMAC) {
-               /* LInk down, start polling for state change */
-               if (status & XM_IS_INP_ASS) {
-                       xm_write16(hw, port, XM_IMSK,
-                                       xm_read16(hw, port, XM_IMSK) | XM_IS_INP_ASS);
-                       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
-               }
-               else if (status & XM_IS_AND)
-                       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
-       }
+       if (netif_msg_intr(skge))
+               printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+                      skge->netdev->name, status);
 
        if (status & XM_IS_TXF_UR) {
                xm_write32(hw, port, XM_MODE, XM_MD_FTF);
@@ -1404,23 +1450,6 @@ static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
        return gma_read16(hw, port, GM_SMI_DATA);
 }
 
-static void genesis_link_down(struct skge_port *skge)
-{
-       struct skge_hw *hw = skge->hw;
-       int port = skge->port;
-
-       pr_debug("genesis_link_down\n");
-
-       xm_write16(hw, port, XM_MMU_CMD,
-                       xm_read16(hw, port, XM_MMU_CMD)
-                       & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
-
-       /* dummy read to ensure writing */
-       (void) xm_read16(hw, port, XM_MMU_CMD);
-
-       skge_link_down(skge);
-}
-
 static void genesis_link_up(struct skge_port *skge)
 {
        struct skge_hw *hw = skge->hw;
@@ -1437,6 +1466,7 @@ static void genesis_link_up(struct skge_port *skge)
         */
        if (skge->flow_control == FLOW_MODE_NONE ||
            skge->flow_control == FLOW_MODE_LOC_SEND)
+               /* Disable Pause Frame Reception */
                cmd |= XM_MMU_IGN_PF;
        else
                /* Enable Pause Frame Reception */
@@ -1476,28 +1506,25 @@ static void genesis_link_up(struct skge_port *skge)
        xm_write32(hw, port, XM_MODE, mode);
 
        msk = XM_DEF_MSK;
-       if (hw->phy_type != SK_PHY_XMAC)
-               msk |= XM_IS_INP_ASS;   /* disable GP0 interrupt bit */
+       /* disable GP0 interrupt bit for external Phy */
+       msk |= XM_IS_INP_ASS;
 
        xm_write16(hw, port, XM_IMSK, msk);
        xm_read16(hw, port, XM_ISRC);
 
        /* get MMU Command Reg. */
        cmd = xm_read16(hw, port, XM_MMU_CMD);
-       if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
+       if (skge->duplex == DUPLEX_FULL)
                cmd |= XM_MMU_GMII_FD;
 
-       if (hw->phy_type == SK_PHY_BCOM) {
-               /*
-                * Workaround BCOM Errata (#10523) for all BCom Phys
-                * Enable Power Management after link up
-                */
-               xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
-                                 xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
-                                 & ~PHY_B_AC_DIS_PM);
-               xm_phy_write(hw, port, PHY_BCOM_INT_MASK,
-                                 PHY_B_DEF_MSK);
-       }
+       /*
+        * Workaround BCOM Errata (#10523) for all BCom Phys
+        * Enable Power Management after link up
+        */
+       xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+                    xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
+                    & ~PHY_B_AC_DIS_PM);
+       xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
 
        /* enable Rx/Tx */
        xm_write16(hw, port, XM_MMU_CMD,
@@ -1506,18 +1533,25 @@ static void genesis_link_up(struct skge_port *skge)
 }
 
 
-static void genesis_bcom_intr(struct skge_port *skge)
+static inline void bcom_phy_intr(struct skge_port *skge)
 {
        struct skge_hw *hw = skge->hw;
        int port = skge->port;
-       u16 stat = xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+       u16 isrc;
+
+       isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+       if (netif_msg_intr(skge))
+               printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x\n",
+                      skge->netdev->name, isrc);
 
-       pr_debug("genesis_bcom intr stat=%x\n", stat);
+       if (isrc & PHY_B_IS_PSE)
+               printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n",
+                      hw->dev[port]->name);
 
        /* Workaround BCom Errata:
         *      enable and disable loopback mode if "NO HCD" occurs.
         */
-       if (stat & PHY_B_IS_NO_HDCL) {
+       if (isrc & PHY_B_IS_NO_HDCL) {
                u16 ctrl = xm_phy_read(hw, port, PHY_BCOM_CTRL);
                xm_phy_write(hw, port, PHY_BCOM_CTRL,
                                  ctrl | PHY_CT_LOOP);
@@ -1525,70 +1559,9 @@ static void genesis_bcom_intr(struct skge_port *skge)
                                  ctrl & ~PHY_CT_LOOP);
        }
 
-       stat = xm_phy_read(hw, port, PHY_BCOM_STAT);
-       if (stat & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) {
-               u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
-               if ( !(aux & PHY_B_AS_LS) && netif_carrier_ok(skge->netdev))
-                       genesis_link_down(skge);
-
-               else if (stat & PHY_B_IS_LST_CHANGE) {
-                       if (aux & PHY_B_AS_AN_C) {
-                               switch (aux & PHY_B_AS_AN_RES_MSK) {
-                               case PHY_B_RES_1000FD:
-                                       skge->duplex = DUPLEX_FULL;
-                                       break;
-                               case PHY_B_RES_1000HD:
-                                       skge->duplex = DUPLEX_HALF;
-                                       break;
-                               }
-
-                               switch (aux & PHY_B_AS_PAUSE_MSK) {
-                               case PHY_B_AS_PAUSE_MSK:
-                                       skge->flow_control = FLOW_MODE_SYMMETRIC;
-                                       break;
-                               case PHY_B_AS_PRR:
-                                       skge->flow_control = FLOW_MODE_REM_SEND;
-                                       break;
-                               case PHY_B_AS_PRT:
-                                       skge->flow_control = FLOW_MODE_LOC_SEND;
-                                       break;
-                               default:
-                                       skge->flow_control = FLOW_MODE_NONE;
-                               }
-                               skge->speed = SPEED_1000;
-                       }
-                       genesis_link_up(skge);
-               }
-               else
-                       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
-       }
-}
+       if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+               bcom_check_link(hw, port);
 
-/* Perodic poll of phy status to check for link transistion  */
-static void skge_link_timer(unsigned long __arg)
-{
-       struct skge_port *skge = (struct skge_port *) __arg;
-       struct skge_hw *hw = skge->hw;
-       int port = skge->port;
-
-       if (hw->chip_id != CHIP_ID_GENESIS || !netif_running(skge->netdev))
-               return;
-
-       spin_lock_bh(&hw->phy_lock);
-       if (hw->phy_type == SK_PHY_BCOM)
-               genesis_bcom_intr(skge);
-       else {
-               int i;
-               for (i = 0; i < 3; i++)
-                       if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
-                               break;
-
-               if (i == 3)
-                       mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
-               else
-                       genesis_link_up(skge);
-       }
-       spin_unlock_bh(&hw->phy_lock);
 }
 
 /* Marvell Phy Initailization */
@@ -1606,11 +1579,7 @@ static void yukon_init(struct skge_hw *hw, int port)
                          PHY_M_EC_MAC_S_MSK);
                ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
 
-               /* on PHY 88E1111 there is a change for downshift control */
-               if (hw->chip_id == CHIP_ID_YUKON_EC)
-                       ectrl |= PHY_M_EC_M_DSC_2(0) | PHY_M_EC_DOWN_S_ENA;
-               else
-                       ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+               ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
 
                gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
        }
@@ -1624,7 +1593,7 @@ static void yukon_init(struct skge_hw *hw, int port)
 
        ctrl = 0;
        ct1000 = 0;
-       adv = PHY_SEL_TYPE;
+       adv = PHY_AN_CSMA;
 
        if (skge->autoneg == AUTONEG_ENABLE) {
                if (iscopper(hw)) {
@@ -1640,41 +1609,12 @@ static void yukon_init(struct skge_hw *hw, int port)
                                adv |= PHY_M_AN_10_FD;
                        if (skge->advertising & ADVERTISED_10baseT_Half)
                                adv |= PHY_M_AN_10_HD;
-
-                       /* Set Flow-control capabilities */
-                       switch (skge->flow_control) {
-                       case FLOW_MODE_NONE:
-                               adv |= PHY_B_P_NO_PAUSE;
-                               break;
-                       case FLOW_MODE_LOC_SEND:
-                               adv |= PHY_B_P_ASYM_MD;
-                               break;
-                       case FLOW_MODE_SYMMETRIC:
-                               adv |= PHY_B_P_SYM_MD;
-                               break;
-                       case FLOW_MODE_REM_SEND:
-                               adv |= PHY_B_P_BOTH_MD;
-                               break;
-                       }
-               } else {        /* special defines for FIBER (88E1011S only) */
+               } else  /* special defines for FIBER (88E1011S only) */
                        adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
 
-                       /* Set Flow-control capabilities */
-                       switch (skge->flow_control) {
-                       case FLOW_MODE_NONE:
-                               adv |= PHY_M_P_NO_PAUSE_X;
-                               break;
-                       case FLOW_MODE_LOC_SEND:
-                               adv |= PHY_M_P_ASYM_MD_X;
-                               break;
-                       case FLOW_MODE_SYMMETRIC:
-                               adv |= PHY_M_P_SYM_MD_X;
-                               break;
-                       case FLOW_MODE_REM_SEND:
-                               adv |= PHY_M_P_BOTH_MD_X;
-                               break;
-                       }
-               }
+               /* Set Flow-control capabilities */
+               adv |= phy_pause_map[skge->flow_control];
+
                /* Restart Auto-negotiation */
                ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
        } else {
@@ -1696,8 +1636,7 @@ static void yukon_init(struct skge_hw *hw, int port)
                ctrl |= PHY_CT_RESET;
        }
 
-       if (hw->chip_id != CHIP_ID_YUKON_FE)
-               gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
+       gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
 
        gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
        gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
@@ -1706,22 +1645,10 @@ static void yukon_init(struct skge_hw *hw, int port)
        ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS);
        ledover = 0;
 
-       if (hw->chip_id == CHIP_ID_YUKON_FE) {
-               /* on 88E3082 these bits are at 11..9 (shifted left) */
-               ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1;
+       ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
 
-               gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR,
-                                 ((gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR)
-
-                                   & ~PHY_M_FELP_LED1_MSK)
-                                  | PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL)));
-       } else {
-               /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
-               ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
-
-               /* turn off the Rx LED (LED_RX) */
-               ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
-       }
+       /* turn off the Rx LED (LED_RX) */
+       ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
 
        /* disable blink mode (LED_DUPLEX) on collisions */
        ctrl |= PHY_M_LEDC_DP_CTRL;
@@ -1919,10 +1846,14 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data)
 
 static void yukon_mac_intr(struct skge_hw *hw, int port)
 {
-       struct skge_port *skge = netdev_priv(hw->dev[port]);
+       struct net_device *dev = hw->dev[port];
+       struct skge_port *skge = netdev_priv(dev);
        u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC));
 
-       pr_debug("yukon_intr status %x\n", status);
+       if (netif_msg_intr(skge))
+               printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+                      dev->name, status);
+
        if (status & GM_IS_RX_FF_OR) {
                ++skge->net_stats.rx_fifo_errors;
                gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
@@ -1936,9 +1867,6 @@ static void yukon_mac_intr(struct skge_hw *hw, int port)
 
 static u16 yukon_speed(const struct skge_hw *hw, u16 aux)
 {
-       if (hw->chip_id == CHIP_ID_YUKON_FE)
-               return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
-
        switch (aux & PHY_M_PS_SPEED_MSK) {
        case PHY_M_PS_SPEED_1000:
                return SPEED_1000;
@@ -1983,8 +1911,7 @@ static void yukon_link_down(struct skge_port *skge)
                          gm_phy_read(hw, port, GM_GP_CTRL)
                          & ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA));
 
-       if (hw->chip_id != CHIP_ID_YUKON_FE &&
-           skge->flow_control == FLOW_MODE_REM_SEND) {
+       if (skge->flow_control == FLOW_MODE_REM_SEND) {
                /* restore Asymmetric Pause bit */
                gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
                                  gm_phy_read(hw, port,
@@ -2008,7 +1935,10 @@ static void yukon_phy_intr(struct skge_port *skge)
 
        istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
        phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
-       pr_debug("yukon phy intr istat=%x phy_stat=%x\n", istatus, phystat);
+
+       if (netif_msg_intr(skge))
+               printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x 0x%x\n",
+                      skge->netdev->name, istatus, phystat);
 
        if (istatus & PHY_M_IS_AN_COMPL) {
                if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
@@ -2017,9 +1947,7 @@ static void yukon_phy_intr(struct skge_port *skge)
                        goto failed;
                }
 
-               if (!(hw->chip_id == CHIP_ID_YUKON_FE || hw->chip_id == CHIP_ID_YUKON_EC)
-                   && (gm_phy_read(hw, port, PHY_MARV_1000T_STAT)
-                       & PHY_B_1000S_MSF)) {
+               if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) {
                        reason = "master/slave fault";
                        goto failed;
                }
@@ -2033,10 +1961,6 @@ static void yukon_phy_intr(struct skge_port *skge)
                        ? DUPLEX_FULL : DUPLEX_HALF;
                skge->speed = yukon_speed(hw, phystat);
 
-               /* Tx & Rx Pause Enabled bits are at 9..8 */
-               if (hw->chip_id == CHIP_ID_YUKON_XL)
-                       phystat >>= 6;
-
                /* We are using IEEE 802.3z/D5.0 Table 37-4 */
                switch (phystat & PHY_M_PS_PAUSE_MSK) {
                case PHY_M_PS_PAUSE_MSK:
@@ -2140,6 +2064,12 @@ static int skge_up(struct net_device *dev)
        if (netif_msg_ifup(skge))
                printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
 
+       if (dev->mtu > RX_BUF_SIZE)
+               skge->rx_buf_size = dev->mtu + ETH_HLEN + NET_IP_ALIGN;
+       else
+               skge->rx_buf_size = RX_BUF_SIZE;
+
+
        rx_size = skge->rx_ring.count * sizeof(struct skge_rx_desc);
        tx_size = skge->tx_ring.count * sizeof(struct skge_tx_desc);
        skge->mem_size = tx_size + rx_size;
@@ -2152,7 +2082,8 @@ static int skge_up(struct net_device *dev)
        if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma)))
                goto free_pci_mem;
 
-       if (skge_rx_fill(skge))
+       err = skge_rx_fill(skge);
+       if (err)
                goto free_rx_ring;
 
        if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size,
@@ -2161,6 +2092,10 @@ static int skge_up(struct net_device *dev)
 
        skge->tx_avail = skge->tx_ring.count - 1;
 
+       /* Enable IRQ from port */
+       hw->intr_mask |= portirqmask[port];
+       skge_write32(hw, B0_IMSK, hw->intr_mask);
+
        /* Initialze MAC */
        if (hw->chip_id == CHIP_ID_GENESIS)
                genesis_mac_init(hw, port);
@@ -2206,7 +2141,6 @@ static int skge_down(struct net_device *dev)
        netif_stop_queue(dev);
 
        del_timer_sync(&skge->led_blink);
-       del_timer_sync(&skge->link_check);
 
        /* Stop transmitter */
        skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP);
@@ -2373,6 +2307,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
 static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e)
 {
+       /* This ring element can be skb or fragment */
        if (e->skb) {
                pci_unmap_single(hw->pdev,
                               pci_unmap_addr(e, mapaddr),
@@ -2417,16 +2352,17 @@ static void skge_tx_timeout(struct net_device *dev)
 static int skge_change_mtu(struct net_device *dev, int new_mtu)
 {
        int err = 0;
+       int running = netif_running(dev);
 
        if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
                return -EINVAL;
 
-       dev->mtu = new_mtu;
 
-       if (netif_running(dev)) {
+       if (running)
                skge_down(dev);
+       dev->mtu = new_mtu;
+       if (running)
                skge_up(dev);
-       }
 
        return err;
 }
@@ -2441,6 +2377,8 @@ static void genesis_set_multicast(struct net_device *dev)
        u32 mode;
        u8 filter[8];
 
+       pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count);
+
        mode = xm_read32(hw, port, XM_MODE);
        mode |= XM_MD_ENA_HASH;
        if (dev->flags & IFF_PROMISC)
@@ -2453,16 +2391,15 @@ static void genesis_set_multicast(struct net_device *dev)
        else {
                memset(filter, 0, sizeof(filter));
                for (i = 0; list && i < count; i++, list = list->next) {
-                       u32 crc = crc32_le(~0, list->dmi_addr, ETH_ALEN);
-                       u8 bit = 63 - (crc & 63);
-
+                       u32 crc, bit;
+                       crc = ether_crc_le(ETH_ALEN, list->dmi_addr);
+                       bit = ~crc & 0x3f;
                        filter[bit/8] |= 1 << (bit%8);
                }
        }
 
-       xm_outhash(hw, port, XM_HSM, filter);
-
        xm_write32(hw, port, XM_MODE, mode);
+       xm_outhash(hw, port, XM_HSM, filter);
 }
 
 static void yukon_set_multicast(struct net_device *dev)
@@ -2524,28 +2461,76 @@ static void skge_rx_error(struct skge_port *skge, int slot,
                printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n",
                       skge->netdev->name, slot, control, status);
 
-       if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
-           || (control & BMU_BBC) > skge->netdev->mtu + VLAN_ETH_HLEN)
+       if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF))
                skge->net_stats.rx_length_errors++;
-       else {
-               if (skge->hw->chip_id == CHIP_ID_GENESIS) {
-                       if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
-                               skge->net_stats.rx_length_errors++;
-                       if (status & XMR_FS_FRA_ERR)
-                               skge->net_stats.rx_frame_errors++;
-                       if (status & XMR_FS_FCS_ERR)
-                               skge->net_stats.rx_crc_errors++;
-               } else {
-                       if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
-                               skge->net_stats.rx_length_errors++;
-                       if (status & GMR_FS_FRAGMENT)
-                               skge->net_stats.rx_frame_errors++;
-                       if (status & GMR_FS_CRC_ERR)
-                               skge->net_stats.rx_crc_errors++;
+       else if (skge->hw->chip_id == CHIP_ID_GENESIS) {
+               if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
+                       skge->net_stats.rx_length_errors++;
+               if (status & XMR_FS_FRA_ERR)
+                       skge->net_stats.rx_frame_errors++;
+               if (status & XMR_FS_FCS_ERR)
+                       skge->net_stats.rx_crc_errors++;
+       } else {
+               if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
+                       skge->net_stats.rx_length_errors++;
+               if (status & GMR_FS_FRAGMENT)
+                       skge->net_stats.rx_frame_errors++;
+               if (status & GMR_FS_CRC_ERR)
+                       skge->net_stats.rx_crc_errors++;
+       }
+}
+
+/* Get receive buffer from descriptor.
+ * Handles copy of small buffers and reallocation failures
+ */
+static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
+                                         struct skge_element *e,
+                                         unsigned int len)
+{
+       struct sk_buff *nskb, *skb;
+
+       if (len < RX_COPY_THRESHOLD) {
+               nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN);
+               if (unlikely(!nskb))
+                       return NULL;
+
+               pci_dma_sync_single_for_cpu(skge->hw->pdev,
+                                           pci_unmap_addr(e, mapaddr),
+                                           len, PCI_DMA_FROMDEVICE);
+               memcpy(nskb->data, e->skb->data, len);
+               pci_dma_sync_single_for_device(skge->hw->pdev,
+                                              pci_unmap_addr(e, mapaddr),
+                                              len, PCI_DMA_FROMDEVICE);
+
+               if (skge->rx_csum) {
+                       struct skge_rx_desc *rd = e->desc;
+                       nskb->csum = le16_to_cpu(rd->csum2);
+                       nskb->ip_summed = CHECKSUM_HW;
                }
+               skge_rx_reuse(e, skge->rx_buf_size);
+               return nskb;
+       } else {
+               nskb = skge_rx_alloc(skge->netdev, skge->rx_buf_size);
+               if (unlikely(!nskb))
+                       return NULL;
+
+               pci_unmap_single(skge->hw->pdev,
+                                pci_unmap_addr(e, mapaddr),
+                                pci_unmap_len(e, maplen),
+                                PCI_DMA_FROMDEVICE);
+               skb = e->skb;
+               if (skge->rx_csum) {
+                       struct skge_rx_desc *rd = e->desc;
+                       skb->csum = le16_to_cpu(rd->csum2);
+                       skb->ip_summed = CHECKSUM_HW;
+               }
+
+               skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
+               return skb;
        }
 }
 
+
 static int skge_poll(struct net_device *dev, int *budget)
 {
        struct skge_port *skge = netdev_priv(dev);
@@ -2554,13 +2539,12 @@ static int skge_poll(struct net_device *dev, int *budget)
        struct skge_element *e;
        unsigned int to_do = min(dev->quota, *budget);
        unsigned int work_done = 0;
-       int done;
-       static const u32 irqmask[] = { IS_PORT_1, IS_PORT_2 };
 
-       for (e = ring->to_clean; e != ring->to_use && work_done < to_do;
-            e = e->next) {
+       pr_debug("skge_poll\n");
+
+       for (e = ring->to_clean; work_done < to_do; e = e->next) {
                struct skge_rx_desc *rd = e->desc;
-               struct sk_buff *skb = e->skb;
+               struct sk_buff *skb;
                u32 control, len, status;
 
                rmb();
@@ -2569,19 +2553,12 @@ static int skge_poll(struct net_device *dev, int *budget)
                        break;
 
                len = control & BMU_BBC;
-               e->skb = NULL;
-
-               pci_unmap_single(hw->pdev,
-                                pci_unmap_addr(e, mapaddr),
-                                pci_unmap_len(e, maplen),
-                                PCI_DMA_FROMDEVICE);
-
                status = rd->status;
-               if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
-                    || len > dev->mtu + VLAN_ETH_HLEN
-                    || bad_phy_status(hw, status)) {
+
+               if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
+                            || bad_phy_status(hw, status))) {
                        skge_rx_error(skge, e - ring->start, control, status);
-                       dev_kfree_skb(skb);
+                       skge_rx_reuse(e, skge->rx_buf_size);
                        continue;
                }
 
@@ -2589,43 +2566,37 @@ static int skge_poll(struct net_device *dev, int *budget)
                    printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
                           dev->name, e - ring->start, rd->status, len);
 
-               skb_put(skb, len);
-               skb->protocol = eth_type_trans(skb, dev);
+               skb = skge_rx_get(skge, e, len);
+               if (likely(skb)) {
+                       skb_put(skb, len);
+                       skb->protocol = eth_type_trans(skb, dev);
 
-               if (skge->rx_csum) {
-                       skb->csum = le16_to_cpu(rd->csum2);
-                       skb->ip_summed = CHECKSUM_HW;
-               }
-
-               dev->last_rx = jiffies;
-               netif_receive_skb(skb);
+                       dev->last_rx = jiffies;
+                       netif_receive_skb(skb);
 
-               ++work_done;
+                       ++work_done;
+               } else
+                       skge_rx_reuse(e, skge->rx_buf_size);
        }
        ring->to_clean = e;
 
-       *budget -= work_done;
-       dev->quota -= work_done;
-       done = work_done < to_do;
-
-       if (skge_rx_fill(skge))
-               done = 0;
-
        /* restart receiver */
        wmb();
        skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR),
                    CSR_START | CSR_IRQ_CL_F);
 
-       if (done) {
-               local_irq_disable();
-               hw->intr_mask |= irqmask[skge->port];
-               /* Order is important since data can get interrupted */
-               skge_write32(hw, B0_IMSK, hw->intr_mask);
-               __netif_rx_complete(dev);
-               local_irq_enable();
-       }
+       *budget -= work_done;
+       dev->quota -= work_done;
 
-       return !done;
+       if (work_done >=  to_do)
+               return 1; /* not done */
+
+       local_irq_disable();
+       __netif_rx_complete(dev);
+       hw->intr_mask |= portirqmask[skge->port];
+       skge_write32(hw, B0_IMSK, hw->intr_mask);
+       local_irq_enable();
+       return 0;
 }
 
 static inline void skge_tx_intr(struct net_device *dev)
@@ -2782,8 +2753,8 @@ static void skge_extirq(unsigned long data)
 
                        if (hw->chip_id != CHIP_ID_GENESIS)
                                yukon_phy_intr(skge);
-                       else if (hw->phy_type == SK_PHY_BCOM)
-                               genesis_bcom_intr(skge);
+                       else
+                               bcom_phy_intr(skge);
                }
        }
        spin_unlock(&hw->phy_lock);
@@ -2803,19 +2774,14 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
                return IRQ_NONE;
 
        status &= hw->intr_mask;
-
-       if ((status & IS_R1_F) && netif_rx_schedule_prep(hw->dev[0])) {
-               status &= ~IS_R1_F;
+       if (status & IS_R1_F) {
                hw->intr_mask &= ~IS_R1_F;
-               skge_write32(hw, B0_IMSK, hw->intr_mask);
-               __netif_rx_schedule(hw->dev[0]);
+               netif_rx_schedule(hw->dev[0]);
        }
 
-       if ((status & IS_R2_F) && netif_rx_schedule_prep(hw->dev[1])) {
-               status &= ~IS_R2_F;
+       if (status & IS_R2_F) {
                hw->intr_mask &= ~IS_R2_F;
-               skge_write32(hw, B0_IMSK, hw->intr_mask);
-               __netif_rx_schedule(hw->dev[1]);
+               netif_rx_schedule(hw->dev[1]);
        }
 
        if (status & IS_XA1_F)
@@ -2824,6 +2790,24 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
        if (status & IS_XA2_F)
                skge_tx_intr(hw->dev[1]);
 
+       if (status & IS_PA_TO_RX1) {
+               struct skge_port *skge = netdev_priv(hw->dev[0]);
+               ++skge->net_stats.rx_over_errors;
+               skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1);
+       }
+
+       if (status & IS_PA_TO_RX2) {
+               struct skge_port *skge = netdev_priv(hw->dev[1]);
+               ++skge->net_stats.rx_over_errors;
+               skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
+       }
+
+       if (status & IS_PA_TO_TX1)
+               skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1);
+
+       if (status & IS_PA_TO_TX2)
+               skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX2);
+
        if (status & IS_MAC1)
                skge_mac_intr(hw, 0);
 
@@ -2838,8 +2822,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
                tasklet_schedule(&hw->ext_tasklet);
        }
 
-       if (status)
-               skge_write32(hw, B0_IMSK, hw->intr_mask);
+       skge_write32(hw, B0_IMSK, hw->intr_mask);
 
        return IRQ_HANDLED;
 }
@@ -2883,9 +2866,6 @@ static const struct {
        { CHIP_ID_YUKON,         "Yukon" },
        { CHIP_ID_YUKON_LITE,    "Yukon-Lite"},
        { CHIP_ID_YUKON_LP,      "Yukon-LP"},
-       { CHIP_ID_YUKON_XL,      "Yukon-2 XL"},
-       { CHIP_ID_YUKON_EC,      "YUKON-2 EC"},
-       { CHIP_ID_YUKON_FE,      "YUKON-2 FE"},
 };
 
 static const char *skge_board_name(const struct skge_hw *hw)
@@ -2934,9 +2914,6 @@ static int skge_reset(struct skge_hw *hw)
        switch (hw->chip_id) {
        case CHIP_ID_GENESIS:
                switch (hw->phy_type) {
-               case SK_PHY_XMAC:
-                       hw->phy_addr = PHY_ADDR_XMAC;
-                       break;
                case SK_PHY_BCOM:
                        hw->phy_addr = PHY_ADDR_BCOM;
                        break;
@@ -3030,9 +3007,7 @@ static int skge_reset(struct skge_hw *hw)
        skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
        skge_write32(hw, B2_IRQM_CTRL, TIM_START);
 
-       hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
-       if (hw->ports > 1)
-               hw->intr_mask |= IS_PORT_2;
+       hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
        skge_write32(hw, B0_IMSK, hw->intr_mask);
 
        if (hw->chip_id != CHIP_ID_GENESIS)
@@ -3100,7 +3075,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
        skge->flow_control = FLOW_MODE_SYMMETRIC;
        skge->duplex = -1;
        skge->speed = -1;
-       skge->advertising = skge_modes(hw);
+       skge->advertising = skge_supported_modes(hw);
 
        hw->dev[port] = dev;
 
@@ -3108,10 +3083,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
 
        spin_lock_init(&skge->tx_lock);
 
-       init_timer(&skge->link_check);
-       skge->link_check.function = skge_link_timer;
-       skge->link_check.data = (unsigned long) skge;
-
        init_timer(&skge->led_blink);
        skge->led_blink.function = skge_blink_timer;
        skge->led_blink.data = (unsigned long) skge;
@@ -3288,7 +3259,7 @@ static void __devexit skge_remove(struct pci_dev *pdev)
 }
 
 #ifdef CONFIG_PM
-static int skge_suspend(struct pci_dev *pdev, u32 state)
+static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct skge_hw *hw  = pci_get_drvdata(pdev);
        int i, wol = 0;
@@ -3308,7 +3279,7 @@ static int skge_suspend(struct pci_dev *pdev, u32 state)
        }
 
        pci_save_state(pdev);
-       pci_enable_wake(pdev, state, wol);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));