root/drivers/staging/octeon/ethernet-rgmii.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cvm_oct_set_hw_preamble
  2. cvm_oct_check_preamble_errors
  3. cvm_oct_rgmii_poll
  4. cvm_oct_rgmii_open

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * This file is based on code from OCTEON SDK by Cavium Networks.
   4  *
   5  * Copyright (c) 2003-2007 Cavium Networks
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/netdevice.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/phy.h>
  12 #include <linux/ratelimit.h>
  13 #include <net/dst.h>
  14 
  15 #include "octeon-ethernet.h"
  16 #include "ethernet-defines.h"
  17 #include "ethernet-util.h"
  18 #include "ethernet-mdio.h"
  19 
  20 static DEFINE_SPINLOCK(global_register_lock);
  21 
  22 static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
  23 {
  24         union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
  25         union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
  26         union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
  27         int interface = INTERFACE(priv->port);
  28         int index = INDEX(priv->port);
  29 
  30         /* Set preamble checking. */
  31         gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
  32                                                                    interface));
  33         gmxx_rxx_frm_ctl.s.pre_chk = enable;
  34         cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
  35                        gmxx_rxx_frm_ctl.u64);
  36 
  37         /* Set FCS stripping. */
  38         ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
  39         if (enable)
  40                 ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
  41         else
  42                 ipd_sub_port_fcs.s.port_bit &=
  43                                         0xffffffffull ^ (1ull << priv->port);
  44         cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
  45 
  46         /* Clear any error bits. */
  47         gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
  48                                                                    interface));
  49         cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
  50                        gmxx_rxx_int_reg.u64);
  51 }
  52 
  53 static void cvm_oct_check_preamble_errors(struct net_device *dev)
  54 {
  55         struct octeon_ethernet *priv = netdev_priv(dev);
  56         cvmx_helper_link_info_t link_info;
  57         unsigned long flags;
  58 
  59         link_info.u64 = priv->link_info;
  60 
  61         /*
  62          * Take the global register lock since we are going to
  63          * touch registers that affect more than one port.
  64          */
  65         spin_lock_irqsave(&global_register_lock, flags);
  66 
  67         if (link_info.s.speed == 10 && priv->last_speed == 10) {
  68                 /*
  69                  * Read the GMXX_RXX_INT_REG[PCTERR] bit and see if we are
  70                  * getting preamble errors.
  71                  */
  72                 int interface = INTERFACE(priv->port);
  73                 int index = INDEX(priv->port);
  74                 union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
  75 
  76                 gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
  77                                                         (index, interface));
  78                 if (gmxx_rxx_int_reg.s.pcterr) {
  79                         /*
  80                          * We are getting preamble errors at 10Mbps. Most
  81                          * likely the PHY is giving us packets with misaligned
  82                          * preambles. In order to get these packets we need to
  83                          * disable preamble checking and do it in software.
  84                          */
  85                         cvm_oct_set_hw_preamble(priv, false);
  86                         printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
  87                                            dev->name);
  88                 }
  89         } else {
  90                 /*
  91                  * Since the 10Mbps preamble workaround is allowed we need to
  92                  * enable preamble checking, FCS stripping, and clear error
  93                  * bits on every speed change. If errors occur during 10Mbps
  94                  * operation the above code will change this stuff
  95                  */
  96                 if (priv->last_speed != link_info.s.speed)
  97                         cvm_oct_set_hw_preamble(priv, true);
  98                 priv->last_speed = link_info.s.speed;
  99         }
 100         spin_unlock_irqrestore(&global_register_lock, flags);
 101 }
 102 
 103 static void cvm_oct_rgmii_poll(struct net_device *dev)
 104 {
 105         struct octeon_ethernet *priv = netdev_priv(dev);
 106         cvmx_helper_link_info_t link_info;
 107         bool status_change;
 108 
 109         link_info = cvmx_helper_link_get(priv->port);
 110         if (priv->link_info != link_info.u64 &&
 111             cvmx_helper_link_set(priv->port, link_info))
 112                 link_info.u64 = priv->link_info;
 113         status_change = priv->link_info != link_info.u64;
 114         priv->link_info = link_info.u64;
 115 
 116         cvm_oct_check_preamble_errors(dev);
 117 
 118         if (likely(!status_change))
 119                 return;
 120 
 121         /* Tell core. */
 122         if (link_info.s.link_up) {
 123                 if (!netif_carrier_ok(dev))
 124                         netif_carrier_on(dev);
 125         } else if (netif_carrier_ok(dev)) {
 126                 netif_carrier_off(dev);
 127         }
 128         cvm_oct_note_carrier(priv, link_info);
 129 }
 130 
 131 int cvm_oct_rgmii_open(struct net_device *dev)
 132 {
 133         struct octeon_ethernet *priv = netdev_priv(dev);
 134         int ret;
 135 
 136         ret = cvm_oct_common_open(dev, cvm_oct_rgmii_poll);
 137         if (ret)
 138                 return ret;
 139 
 140         if (dev->phydev) {
 141                 /*
 142                  * In phydev mode, we need still periodic polling for the
 143                  * preamble error checking, and we also need to call this
 144                  * function on every link state change.
 145                  *
 146                  * Only true RGMII ports need to be polled. In GMII mode, port
 147                  * 0 is really a RGMII port.
 148                  */
 149                 if ((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII &&
 150                      priv->port  == 0) ||
 151                     (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
 152                         priv->poll = cvm_oct_check_preamble_errors;
 153                         cvm_oct_check_preamble_errors(dev);
 154                 }
 155         }
 156 
 157         return 0;
 158 }

/* [<][>][^][v][top][bottom][index][help] */