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