These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / octeon / ethernet-rgmii.c
index e36f9bc..613344b 100644 (file)
@@ -1,29 +1,13 @@
-/*********************************************************************
- * Author: Cavium Networks
- *
- * Contact: support@caviumnetworks.com
- * This file is part of the OCTEON SDK
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
  *
  * Copyright (c) 2003-2007 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
  * published by the Free Software Foundation.
- *
- * This file is distributed in the hope that it will be useful, but
- * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
- * NONINFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * or visit http://www.gnu.org/licenses/.
- *
- * This file may also be available under a different license from Cavium.
- * Contact Cavium Networks for more information
-**********************************************************************/
+ */
+
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
@@ -48,6 +32,37 @@ 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;
+       union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
+       union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
+       int interface = INTERFACE(priv->port);
+       int index = INDEX(priv->port);
+
+       /* Set preamble checking. */
+       gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
+                                                                  interface));
+       gmxx_rxx_frm_ctl.s.pre_chk = enable;
+       cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
+                      gmxx_rxx_frm_ctl.u64);
+
+       /* Set FCS stripping. */
+       ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
+       if (enable)
+               ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
+       else
+               ipd_sub_port_fcs.s.port_bit &=
+                                       0xffffffffull ^ (1ull << priv->port);
+       cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
+
+       /* Clear any error bits. */
+       gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
+                                                                  interface));
+       cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
+                      gmxx_rxx_int_reg.u64);
+}
+
 static void cvm_oct_rgmii_poll(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
@@ -68,14 +83,7 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
 
        link_info = cvmx_helper_link_get(priv->port);
        if (link_info.u64 == priv->link_info) {
-
-               /*
-                * If the 10Mbps preamble workaround is supported and we're
-                * at 10Mbps we may need to do some special checking.
-                */
-               if (USE_10MBPS_PREAMBLE_WORKAROUND &&
-                               (link_info.s.speed == 10)) {
-
+               if (link_info.s.speed == 10) {
                        /*
                         * Read the GMXX_RXX_INT_REG[PCTERR] bit and
                         * see if we are getting preamble errors.
@@ -88,7 +96,6 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
                            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
@@ -97,30 +104,7 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
                                 * packets we need to disable preamble
                                 * checking and do it in software.
                                 */
-                               union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
-                               union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
-
-                               /* Disable preamble checking */
-                               gmxx_rxx_frm_ctl.u64 =
-                                   cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
-                                                 (index, interface));
-                               gmxx_rxx_frm_ctl.s.pre_chk = 0;
-                               cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL
-                                              (index, interface),
-                                              gmxx_rxx_frm_ctl.u64);
-
-                               /* Disable FCS stripping */
-                               ipd_sub_port_fcs.u64 =
-                                   cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
-                               ipd_sub_port_fcs.s.port_bit &=
-                                   0xffffffffull ^ (1ull << priv->port);
-                               cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS,
-                                              ipd_sub_port_fcs.u64);
-
-                               /* Clear any error bits */
-                               cvmx_write_csr(CVMX_GMXX_RXX_INT_REG
-                                              (index, interface),
-                                              gmxx_rxx_int_reg.u64);
+                               cvm_oct_set_hw_preamble(priv, false);
                                printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
                                                   dev->name);
                        }
@@ -133,34 +117,13 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
                return;
        }
 
-       /* If the 10Mbps preamble workaround is allowed we need to on
-          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 (USE_10MBPS_PREAMBLE_WORKAROUND) {
-
-               union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
-               union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
-               union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
-               int interface = INTERFACE(priv->port);
-               int index = INDEX(priv->port);
-
-               /* Enable preamble checking */
-               gmxx_rxx_frm_ctl.u64 =
-                   cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
-               gmxx_rxx_frm_ctl.s.pre_chk = 1;
-               cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
-                              gmxx_rxx_frm_ctl.u64);
-               /* Enable FCS stripping */
-               ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
-               ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
-               cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
-               /* Clear any error bits */
-               gmxx_rxx_int_reg.u64 =
-                   cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, interface));
-               cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
-                              gmxx_rxx_int_reg.u64);
-       }
+       /* 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;
@@ -176,172 +139,75 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
                if (link_info.s.link_up) {
                        if (!netif_carrier_ok(dev))
                                netif_carrier_on(dev);
-                       if (priv->queue != -1)
-                               printk_ratelimited("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
-                                                  dev->name, link_info.s.speed,
-                                                  (link_info.s.full_duplex) ?
-                                                  "Full" : "Half",
-                                                  priv->port, priv->queue);
-                       else
-                               printk_ratelimited("%s: %u Mbps %s duplex, port %2d, POW\n",
-                                                  dev->name, link_info.s.speed,
-                                                  (link_info.s.full_duplex) ?
-                                                  "Full" : "Half",
-                                                  priv->port);
-               } else {
-                       if (netif_carrier_ok(dev))
-                               netif_carrier_off(dev);
-                       printk_ratelimited("%s: Link down\n", dev->name);
+               } else if (netif_carrier_ok(dev)) {
+                       netif_carrier_off(dev);
                }
+               cvm_oct_note_carrier(priv, link_info);
        }
 }
 
-static irqreturn_t cvm_oct_rgmii_rml_interrupt(int cpl, void *dev_id)
+static int cmv_oct_rgmii_gmx_interrupt(int interface)
 {
-       union cvmx_npi_rsl_int_blocks rsl_int_blocks;
        int index;
-       irqreturn_t return_status = IRQ_NONE;
+       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) {
-
-               int interface = 0;
-               /* Loop through every port of this interface */
-               for (index = 0;
-                    index < cvmx_helper_ports_on_interface(interface);
-                    index++) {
+       /* 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;
 
-                       /* Read the GMX interrupt status bits */
-                       union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
-
-                       gmx_rx_int_reg.u64 =
-                           cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
+               /* 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
+               gmx_rx_int_reg.u64 &= cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
                                          (index, interface));
-                       /* 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 =
+               /* 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);
-
-                               if (dev &&
-                               !atomic_read(&cvm_oct_poll_queue_stopping))
-                                       queue_work(cvm_oct_poll_queue,
-                                               &priv->port_work);
-
-                               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);
-                               return_status = IRQ_HANDLED;
-                       }
+                       struct octeon_ethernet *priv = netdev_priv(dev);
+
+                       if (dev && !atomic_read(&cvm_oct_poll_queue_stopping))
+                               queue_work(cvm_oct_poll_queue,
+                                          &priv->port_work);
+
+                       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++;
                }
        }
+       return count;
+}
 
-       /* Check and see if this interrupt was caused by the GMX1 block */
-       if (rsl_int_blocks.s.gmx1) {
+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;
 
-               int interface = 1;
-               /* Loop through every port of this interface */
-               for (index = 0;
-                    index < cvmx_helper_ports_on_interface(interface);
-                    index++) {
+       rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
 
-                       /* Read the GMX interrupt status bits */
-                       union cvmx_gmxx_rxx_int_reg gmx_rx_int_reg;
+       /* 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);
 
-                       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));
-                       /* 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) {
+       /* 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);
 
-                               struct net_device *dev =
-                                   cvm_oct_device[cvmx_helper_get_ipd_port
-                                                  (interface, index)];
-                               struct octeon_ethernet *priv = netdev_priv(dev);
-
-                               if (dev &&
-                               !atomic_read(&cvm_oct_poll_queue_stopping))
-                                       queue_work(cvm_oct_poll_queue,
-                                               &priv->port_work);
-
-                               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);
-                               return_status = IRQ_HANDLED;
-                       }
-               }
-       }
-       return return_status;
+       return count ? IRQ_HANDLED : IRQ_NONE;
 }
 
 int cvm_oct_rgmii_open(struct net_device *dev)
 {
-       union cvmx_gmxx_prtx_cfg gmx_cfg;
-       struct octeon_ethernet *priv = netdev_priv(dev);
-       int interface = INTERFACE(priv->port);
-       int index = INDEX(priv->port);
-       cvmx_helper_link_info_t link_info;
-       int rv;
-
-       rv = cvm_oct_phy_setup_device(dev);
-       if (rv)
-               return rv;
-
-       gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
-       gmx_cfg.s.en = 1;
-       cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
-
-       if (!octeon_is_simulation()) {
-               if (priv->phydev) {
-                       int r = phy_read_status(priv->phydev);
-
-                       if (r == 0 && priv->phydev->link == 0)
-                               netif_carrier_off(dev);
-                       cvm_oct_adjust_link(dev);
-               } else {
-                       link_info = cvmx_helper_link_get(priv->port);
-                       if (!link_info.s.link_up)
-                               netif_carrier_off(dev);
-                       priv->poll = cvm_oct_rgmii_poll;
-               }
-       }
-
-       return 0;
-}
-
-int cvm_oct_rgmii_stop(struct net_device *dev)
-{
-       union cvmx_gmxx_prtx_cfg gmx_cfg;
-       struct octeon_ethernet *priv = netdev_priv(dev);
-       int interface = INTERFACE(priv->port);
-       int index = INDEX(priv->port);
-
-       gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
-       gmx_cfg.s.en = 0;
-       cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
-       return cvm_oct_common_stop(dev);
+       return cvm_oct_common_open(dev, cvm_oct_rgmii_poll);
 }
 
 static void cvm_oct_rgmii_immediate_poll(struct work_struct *work)
@@ -357,7 +223,6 @@ int cvm_oct_rgmii_init(struct net_device *dev)
        int r;
 
        cvm_oct_common_init(dev);
-       dev->netdev_ops->ndo_stop(dev);
        INIT_WORK(&priv->port_work, cvm_oct_rgmii_immediate_poll);
        /*
         * Due to GMX errata in CN3XXX series chips, it is necessary