These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / octeon / ethernet.c
index fbbe866..f69fb5c 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/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -102,19 +86,19 @@ int rx_napi_weight = 32;
 module_param(rx_napi_weight, int, 0444);
 MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter.");
 
-/**
+/*
  * cvm_oct_poll_queue - Workqueue for polling operations.
  */
 struct workqueue_struct *cvm_oct_poll_queue;
 
-/**
+/*
  * cvm_oct_poll_queue_stopping - flag to indicate polling should stop.
  *
  * Set to one right before cvm_oct_poll_queue is destroyed.
  */
 atomic_t cvm_oct_poll_queue_stopping = ATOMIC_INIT(0);
 
-/**
+/*
  * Array of every ethernet device owned by this driver indexed by
  * the ipd input port number.
  */
@@ -168,11 +152,12 @@ static void cvm_oct_configure_common_hw(void)
                             num_packet_buffers);
        if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
                cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
-                                    CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
+                                    CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 1024);
 
 #ifdef __LITTLE_ENDIAN
        {
                union cvmx_ipd_ctl_status ipd_ctl_status;
+
                ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
                ipd_ctl_status.s.pkt_lend = 1;
                ipd_ctl_status.s.wqe_lend = 1;
@@ -180,10 +165,7 @@ static void cvm_oct_configure_common_hw(void)
        }
 #endif
 
-       if (USE_RED)
-               cvmx_helper_setup_red(num_packet_buffers / 4,
-                                     num_packet_buffers / 8);
-
+       cvmx_helper_setup_red(num_packet_buffers / 4, num_packet_buffers / 8);
 }
 
 /**
@@ -206,11 +188,10 @@ int cvm_oct_free_work(void *work_queue_entry)
                if (unlikely(!segment_ptr.s.i))
                        cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr),
                                      segment_ptr.s.pool,
-                                     DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE /
-                                                    128));
+                                     CVMX_FPA_PACKET_POOL_SIZE / 128);
                segment_ptr = next_ptr;
        }
-       cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
+       cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, 1);
 
        return 0;
 }
@@ -383,13 +364,6 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
        }
 }
 
-/**
- * cvm_oct_common_set_mac_address - set the hardware MAC address for a device
- * @dev:    The device in question.
- * @addr:   Address structure to change it too.
-
- * Returns Zero on success
- */
 static int cvm_oct_set_mac_filter(struct net_device *dev)
 {
        struct octeon_ethernet *priv = netdev_priv(dev);
@@ -401,11 +375,11 @@ static int cvm_oct_set_mac_filter(struct net_device *dev)
            && (cvmx_helper_interface_get_mode(interface) !=
                CVMX_HELPER_INTERFACE_MODE_SPI)) {
                int i;
-               uint8_t *ptr = dev->dev_addr;
-               uint64_t mac = 0;
+               u8 *ptr = dev->dev_addr;
+               u64 mac = 0;
 
                for (i = 0; i < 6; i++)
-                       mac = (mac << 8) | (uint64_t)ptr[i];
+                       mac = (mac << 8) | (u64)ptr[i];
 
                gmx_cfg.u64 =
                    cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
@@ -432,6 +406,13 @@ static int cvm_oct_set_mac_filter(struct net_device *dev)
        return 0;
 }
 
+/**
+ * cvm_oct_common_set_mac_address - set the hardware MAC address for a device
+ * @dev:    The device in question.
+ * @addr:   Socket address.
+ *
+ * Returns Zero on success
+ */
 static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
 {
        int r = eth_mac_addr(dev, addr);
@@ -468,11 +449,8 @@ int cvm_oct_common_init(struct net_device *dev)
            && (always_use_pow || strstr(pow_send_list, dev->name)))
                priv->queue = -1;
 
-       if (priv->queue != -1) {
-               dev->features |= NETIF_F_SG;
-               if (USE_HW_TCPUDP_CHECKSUM)
-                       dev->features |= NETIF_F_IP_CSUM;
-       }
+       if (priv->queue != -1)
+               dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 
        /* We do our own locking, Linux doesn't need to */
        dev->features |= NETIF_F_LLTX;
@@ -488,6 +466,9 @@ int cvm_oct_common_init(struct net_device *dev)
        memset(dev->netdev_ops->ndo_get_stats(dev), 0,
               sizeof(struct net_device_stats));
 
+       if (dev->netdev_ops->ndo_stop)
+               dev->netdev_ops->ndo_stop(dev);
+
        return 0;
 }
 
@@ -499,6 +480,70 @@ void cvm_oct_common_uninit(struct net_device *dev)
                phy_disconnect(priv->phydev);
 }
 
+int cvm_oct_common_open(struct net_device *dev,
+                       void (*link_poll)(struct net_device *))
+{
+       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())
+               return 0;
+
+       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 = link_poll;
+               link_poll(dev);
+       }
+
+       return 0;
+}
+
+void cvm_oct_link_poll(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       cvmx_helper_link_info_t link_info;
+
+       link_info = cvmx_helper_link_get(priv->port);
+       if (link_info.u64 == priv->link_info)
+               return;
+
+       link_info = cvmx_helper_link_autoconf(priv->port);
+       priv->link_info = link_info.u64;
+
+       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);
+}
+
+static int cvm_oct_xaui_open(struct net_device *dev)
+{
+       return cvm_oct_common_open(dev, cvm_oct_link_poll);
+}
+
 static const struct net_device_ops cvm_oct_npi_netdev_ops = {
        .ndo_init               = cvm_oct_common_init,
        .ndo_uninit             = cvm_oct_common_uninit,
@@ -513,10 +558,10 @@ static const struct net_device_ops cvm_oct_npi_netdev_ops = {
 #endif
 };
 static const struct net_device_ops cvm_oct_xaui_netdev_ops = {
-       .ndo_init               = cvm_oct_xaui_init,
-       .ndo_uninit             = cvm_oct_xaui_uninit,
+       .ndo_init               = cvm_oct_common_init,
+       .ndo_uninit             = cvm_oct_common_uninit,
        .ndo_open               = cvm_oct_xaui_open,
-       .ndo_stop               = cvm_oct_xaui_stop,
+       .ndo_stop               = cvm_oct_common_stop,
        .ndo_start_xmit         = cvm_oct_xmit,
        .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
        .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
@@ -529,9 +574,9 @@ static const struct net_device_ops cvm_oct_xaui_netdev_ops = {
 };
 static const struct net_device_ops cvm_oct_sgmii_netdev_ops = {
        .ndo_init               = cvm_oct_sgmii_init,
-       .ndo_uninit             = cvm_oct_sgmii_uninit,
+       .ndo_uninit             = cvm_oct_common_uninit,
        .ndo_open               = cvm_oct_sgmii_open,
-       .ndo_stop               = cvm_oct_sgmii_stop,
+       .ndo_stop               = cvm_oct_common_stop,
        .ndo_start_xmit         = cvm_oct_xmit,
        .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
        .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
@@ -559,7 +604,7 @@ static const struct net_device_ops cvm_oct_rgmii_netdev_ops = {
        .ndo_init               = cvm_oct_rgmii_init,
        .ndo_uninit             = cvm_oct_rgmii_uninit,
        .ndo_open               = cvm_oct_rgmii_open,
-       .ndo_stop               = cvm_oct_rgmii_stop,
+       .ndo_stop               = cvm_oct_common_stop,
        .ndo_start_xmit         = cvm_oct_xmit,
        .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
        .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
@@ -625,7 +670,6 @@ static int cvm_oct_probe(struct platform_device *pdev)
        struct device_node *pip;
 
        octeon_mdiobus_force_mod_depencency();
-       pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION);
 
        pip = pdev->dev.of_node;
        if (!pip) {
@@ -634,7 +678,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
        }
 
        cvm_oct_poll_queue = create_singlethread_workqueue("octeon-ethernet");
-       if (cvm_oct_poll_queue == NULL) {
+       if (!cvm_oct_poll_queue) {
                pr_err("octeon-ethernet: Cannot create workqueue");
                return -ENOMEM;
        }
@@ -795,7 +839,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
                                cvm_oct_device[priv->port] = dev;
                                fau -=
                                    cvmx_pko_get_num_queues(priv->port) *
-                                   sizeof(uint32_t);
+                                   sizeof(u32);
                                queue_delayed_work(cvm_oct_poll_queue,
                                                &priv->port_periodic_work, HZ);
                        }
@@ -820,7 +864,10 @@ static int cvm_oct_remove(struct platform_device *pdev)
        int port;
 
        /* Disable POW interrupt */
-       cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0);
+       if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+               cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), 0);
+       else
+               cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0);
 
        cvmx_ipd_disable();