static DEFINE_SPINLOCK(global_register_lock);
 
-static int number_rgmii_ports;
-
 static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
 {
        union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
                       gmxx_rxx_int_reg.u64);
 }
 
-static void cvm_oct_rgmii_poll(struct net_device *dev)
+static void cvm_oct_check_preamble_errors(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
-       unsigned long flags = 0;
        cvmx_helper_link_info_t link_info;
-       int use_global_register_lock = (priv->phydev == NULL);
+       unsigned long flags;
+
+       link_info.u64 = priv->link_info;
 
-       BUG_ON(in_interrupt());
-       if (use_global_register_lock) {
+       /*
+        * Take the global register lock since we are going to
+        * touch registers that affect more than one port.
+        */
+       spin_lock_irqsave(&global_register_lock, flags);
+
+       if (link_info.s.speed == 10 && priv->last_speed == 10) {
                /*
-                * Take the global register lock since we are going to
-                * touch registers that affect more than one port.
+                * Read the GMXX_RXX_INT_REG[PCTERR] bit and see if we are
+                * getting preamble errors.
                 */
-               spin_lock_irqsave(&global_register_lock, flags);
-       } else {
-               mutex_lock(&priv->phydev->mdio.bus->mdio_lock);
-       }
+               int interface = INTERFACE(priv->port);
+               int index = INDEX(priv->port);
+               union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
 
-       link_info = cvmx_helper_link_get(priv->port);
-       if (link_info.u64 == priv->link_info) {
-               if (link_info.s.speed == 10) {
+               gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
+                                                       (index, interface));
+               if (gmxx_rxx_int_reg.s.pcterr) {
                        /*
-                        * Read the GMXX_RXX_INT_REG[PCTERR] bit and
-                        * see if we are getting preamble errors.
+                        * We are getting preamble errors at 10Mbps. Most
+                        * likely the PHY is giving us packets with misaligned
+                        * preambles. In order to get these packets we need to
+                        * disable preamble checking and do it in software.
                         */
-                       int interface = INTERFACE(priv->port);
-                       int index = INDEX(priv->port);
-                       union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
-
-                       gmxx_rxx_int_reg.u64 =
-                           cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
-                                         (index, interface));
-                       if (gmxx_rxx_int_reg.s.pcterr) {
-                               /*
-                                * We are getting preamble errors at
-                                * 10Mbps.  Most likely the PHY is
-                                * giving us packets with mis aligned
-                                * preambles. In order to get these
-                                * packets we need to disable preamble
-                                * checking and do it in software.
-                                */
-                               cvm_oct_set_hw_preamble(priv, false);
-                               printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
-                                                  dev->name);
-                       }
+                       cvm_oct_set_hw_preamble(priv, false);
+                       printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
+                                          dev->name);
                }
-
-               if (use_global_register_lock)
-                       spin_unlock_irqrestore(&global_register_lock, flags);
-               else
-                       mutex_unlock(&priv->phydev->mdio.bus->mdio_lock);
-               return;
-       }
-
-       /* Since the 10Mbps preamble workaround is allowed we need to enable
-        * preamble checking, FCS stripping, and clear error bits on
-        * every speed change. If errors occur during 10Mbps operation
-        * the above code will change this stuff
-        */
-       cvm_oct_set_hw_preamble(priv, true);
-
-       if (priv->phydev == NULL) {
-               link_info = cvmx_helper_link_autoconf(priv->port);
-               priv->link_info = link_info.u64;
-       }
-
-       if (use_global_register_lock)
-               spin_unlock_irqrestore(&global_register_lock, flags);
-       else
-               mutex_unlock(&priv->phydev->mdio.bus->mdio_lock);
-
-       if (priv->phydev == NULL) {
-               /* Tell core. */
-               if (link_info.s.link_up) {
-                       if (!netif_carrier_ok(dev))
-                               netif_carrier_on(dev);
-               } else if (netif_carrier_ok(dev)) {
-                       netif_carrier_off(dev);
-               }
-               cvm_oct_note_carrier(priv, link_info);
+       } else {
+               /*
+                * Since the 10Mbps preamble workaround is allowed we need to
+                * enable preamble checking, FCS stripping, and clear error
+                * bits on every speed change. If errors occur during 10Mbps
+                * operation the above code will change this stuff
+                */
+               if (priv->last_speed != link_info.s.speed)
+                       cvm_oct_set_hw_preamble(priv, true);
+               priv->last_speed = link_info.s.speed;
        }
+       spin_unlock_irqrestore(&global_register_lock, flags);
 }
 
-static int cmv_oct_rgmii_gmx_interrupt(int interface)
+static void cvm_oct_rgmii_poll(struct net_device *dev)
 {
-       int index;
-       int count = 0;
-
-       /* Loop through every port of this interface */
-       for (index = 0;
-            index < cvmx_helper_ports_on_interface(interface);
-            index++) {
-               union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       cvmx_helper_link_info_t link_info;
+       bool status_change;
 
-               /* Read the GMX interrupt status bits */
-               gmx_rx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
-                                         (index, interface));
-               gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
-                                         (index, interface));
+       link_info = cvmx_helper_link_autoconf(priv->port);
+       status_change = priv->link_info != link_info.u64;
+       priv->link_info = link_info.u64;
 
-               /* Poll the port if inband status changed */
-               if (gmx_rx_int_reg.s.phy_dupx || gmx_rx_int_reg.s.phy_link ||
-                   gmx_rx_int_reg.s.phy_spd) {
-                       struct net_device *dev =
-                                   cvm_oct_device[cvmx_helper_get_ipd_port
-                                                  (interface, index)];
-                       struct octeon_ethernet *priv = netdev_priv(dev);
+       cvm_oct_check_preamble_errors(dev);
 
-                       if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
-                               queue_work(cvm_oct_poll_queue,
-                                          &priv->port_work);
+       if (likely(!status_change))
+               return;
 
-                       gmx_rx_int_reg.u64 = 0;
-                       gmx_rx_int_reg.s.phy_dupx = 1;
-                       gmx_rx_int_reg.s.phy_link = 1;
-                       gmx_rx_int_reg.s.phy_spd = 1;
-                       cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
-                                      gmx_rx_int_reg.u64);
-                       count++;
-               }
+       /* Tell core. */
+       if (link_info.s.link_up) {
+               if (!netif_carrier_ok(dev))
+                       netif_carrier_on(dev);
+       } else if (netif_carrier_ok(dev)) {
+               netif_carrier_off(dev);
        }
-       return count;
-}
-
-static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
-{
-       union cvmx_npi_rsl_int_blocks rsl_int_blocks;
-       int count = 0;
-
-       rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
-
-       /* Check and see if this interrupt was caused by the GMX0 block */
-       if (rsl_int_blocks.s.gmx0)
-               count += cmv_oct_rgmii_gmx_interrupt(0);
-
-       /* Check and see if this interrupt was caused by the GMX1 block */
-       if (rsl_int_blocks.s.gmx1)
-               count += cmv_oct_rgmii_gmx_interrupt(1);
-
-       return count ? IRQ_HANDLED : IRQ_NONE;
+       cvm_oct_note_carrier(priv, link_info);
 }
 
 int cvm_oct_rgmii_open(struct net_device *dev)
-{
-       return cvm_oct_common_open(dev, cvm_oct_rgmii_poll);
-}
-
-static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
-{
-       struct octeon_ethernet *priv =
-               container_of(work, struct octeon_ethernet, port_work);
-       cvm_oct_rgmii_poll(cvm_oct_device[priv->port]);
-}
-
-int cvm_oct_rgmii_init(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
-       int r;
+       int ret;
 
-       cvm_oct_common_init(dev);
-       INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
-       /*
-        * Due to GMX errata in CN3XXX series chips, it is necessary
-        * to take the link down immediately when the PHY changes
-        * state. In order to do this we call the poll function every
-        * time the RGMII inband status changes.  This may cause
-        * problems if the PHY doesn't implement inband status
-        * properly.
-        */
-       if (number_rgmii_ports == 0) {
-               r = request_irq(OCTEON_IRQ_RML, cvm_oct_rgmii_rml_interrupt,
-                               IRQF_SHARED, "RGMII", &number_rgmii_ports);
-               if (r != 0)
-                       return r;
-       }
-       number_rgmii_ports++;
-
-       /*
-        * Only true RGMII ports need to be polled. In GMII mode, port
-        * 0 is really a RGMII port.
-        */
-       if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
-            && (priv->port == 0))
-           || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
-               if (!octeon_is_simulation()) {
-                       union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
-                       int interface = INTERFACE(priv->port);
-                       int index = INDEX(priv->port);
+       ret = cvm_oct_common_open(dev, cvm_oct_rgmii_poll);
+       if (ret)
+               return ret;
 
-                       /*
-                        * Enable interrupts on inband status changes
-                        * for this port.
-                        */
-                       gmx_rx_int_en.u64 = 0;
-                       gmx_rx_int_en.s.phy_dupx = 1;
-                       gmx_rx_int_en.s.phy_link = 1;
-                       gmx_rx_int_en.s.phy_spd = 1;
-                       cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
-                                      gmx_rx_int_en.u64);
+       if (priv->phydev) {
+               /*
+                * In phydev mode, we need still periodic polling for the
+                * preamble error checking, and we also need to call this
+                * function on every link state change.
+                *
+                * Only true RGMII ports need to be polled. In GMII mode, port
+                * 0 is really a RGMII port.
+                */
+               if ((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII &&
+                    priv->port  == 0) ||
+                   (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
+                       priv->poll = cvm_oct_check_preamble_errors;
+                       cvm_oct_check_preamble_errors(dev);
                }
        }
 
        return 0;
 }
-
-void cvm_oct_rgmii_uninit(struct net_device *dev)
-{
-       struct octeon_ethernet *priv = netdev_priv(dev);
-
-       cvm_oct_common_uninit(dev);
-
-       /*
-        * Only true RGMII ports need to be polled. In GMII mode, port
-        * 0 is really a RGMII port.
-        */
-       if (((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
-            && (priv->port == 0))
-           || (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
-               if (!octeon_is_simulation()) {
-                       union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
-                       int interface = INTERFACE(priv->port);
-                       int index = INDEX(priv->port);
-
-                       /*
-                        * Disable interrupts on inband status changes
-                        * for this port.
-                        */
-                       gmx_rx_int_en.u64 =
-                           cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
-                                         (index, interface));
-                       gmx_rx_int_en.s.phy_dupx = 0;
-                       gmx_rx_int_en.s.phy_link = 0;
-                       gmx_rx_int_en.s.phy_spd = 0;
-                       cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, interface),
-                                      gmx_rx_int_en.u64);
-               }
-       }
-
-       /* Remove the interrupt handler when the last port is removed. */
-       number_rgmii_ports--;
-       if (number_rgmii_ports == 0)
-               free_irq(OCTEON_IRQ_RML, &number_rgmii_ports);
-       cancel_work_sync(&priv->port_work);
-}